@nifrajs/web 4.0.0 → 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 +49 -26
- 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 +105 -19
- 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 +14 -3
- 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/plugins/zone-guard.d.ts.map +1 -1
- package/dist/plugins/zone-guard.js +10 -2
- package/dist/plugins/zone-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 +77 -17
- 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 +48 -23
- 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 +104 -17
- 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 +43 -7
- 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/plugins/zone-guard.ts +11 -2
- 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 +68 -17
- package/src/zones.ts +208 -7
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
STATUS_HEADER,
|
|
41
41
|
} from "../router.ts"
|
|
42
42
|
import { searchOf, searchOfChain } from "../search.ts"
|
|
43
|
-
import { mergeHeads,
|
|
43
|
+
import { mergeHeads, resolveChainMeta } from "./head-merge.ts"
|
|
44
44
|
import {
|
|
45
45
|
EMPTY_RETAIN,
|
|
46
46
|
type HeadersLike,
|
|
@@ -78,6 +78,7 @@ export type { NonceResolver } from "../nonce.ts"
|
|
|
78
78
|
|
|
79
79
|
/** Structural context supplied by the core server to one page route handler. */
|
|
80
80
|
export interface PageRouteContext<Env = unknown> {
|
|
81
|
+
readonly signal?: AbortSignal
|
|
81
82
|
readonly params: Record<string, string>
|
|
82
83
|
readonly req: Request
|
|
83
84
|
readonly env: Env
|
|
@@ -172,6 +173,11 @@ function appTarget(location: string, requestUrl: string): string {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
export interface PageExecutionOptions<Env = unknown> {
|
|
176
|
+
readonly serverComponents?: import("../server-components/types.ts").ServerComponentRuntime
|
|
177
|
+
readonly rerenderOwnerGET?: (
|
|
178
|
+
request: Request,
|
|
179
|
+
context: PageRouteContext<Env>,
|
|
180
|
+
) => Promise<Response>
|
|
175
181
|
readonly adapter: RenderAdapter
|
|
176
182
|
readonly manifest: Manifest
|
|
177
183
|
readonly clientEntry: string
|
|
@@ -201,6 +207,9 @@ export interface PageExecutionOptions<Env = unknown> {
|
|
|
201
207
|
readonly route: string
|
|
202
208
|
},
|
|
203
209
|
) => void
|
|
210
|
+
/** Logs a failure an `_error` boundary answered. Without a boundary the error propagates and the
|
|
211
|
+
* server logs it, so this runs only where the server never sees the throw. */
|
|
212
|
+
readonly logBoundaryError?: (error: unknown, request: Request) => void
|
|
204
213
|
}
|
|
205
214
|
|
|
206
215
|
type PageResponse = Response | ResponseResult | RenderedPage
|
|
@@ -238,6 +247,24 @@ type LayoutRun = {
|
|
|
238
247
|
readonly pending: Promise<unknown> | undefined
|
|
239
248
|
}
|
|
240
249
|
|
|
250
|
+
/** A route's layouts after only their gates ran: `gates[i]` is gate `i`'s value. */
|
|
251
|
+
type GatedLayouts = {
|
|
252
|
+
readonly modules: LoadedLayoutModules
|
|
253
|
+
readonly gates: readonly unknown[]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Layouts whose loaders settled for this request: what a status or error page renders in. */
|
|
257
|
+
type LayoutChain = {
|
|
258
|
+
readonly modules: LoadedLayoutModules
|
|
259
|
+
readonly layoutData: readonly unknown[] | undefined
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Not called for a page that exports `inLayouts = false`, so such a page runs no layout loader.
|
|
264
|
+
* `undefined` renders the page alone.
|
|
265
|
+
*/
|
|
266
|
+
type LayoutChainSource = (page: RouteModule, count: number) => Promise<LayoutChain | undefined>
|
|
267
|
+
|
|
241
268
|
/**
|
|
242
269
|
* Own the page request program behind one private seam.
|
|
243
270
|
*
|
|
@@ -251,6 +278,8 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
251
278
|
options: PageExecutionOptions<Env>,
|
|
252
279
|
): PageRequestExecutor<Env> {
|
|
253
280
|
const { adapter, manifest, clientEntry, api } = options
|
|
281
|
+
// The action result is request-local; a browser cannot manufacture this handoff.
|
|
282
|
+
const progressiveActionData = new WeakMap<Request, unknown>()
|
|
254
283
|
// Bound once per render, so every loader, action and boundary in that render shares one view of the
|
|
255
284
|
// in-process client carrying the visitor's platform. An `api` without the seam passes through as-is.
|
|
256
285
|
const bindApi = platformBinderOf(api)
|
|
@@ -327,9 +356,9 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
327
356
|
): string | undefined | Promise<string | undefined> =>
|
|
328
357
|
options.nonce === undefined ? undefined : options.nonce({ request, env })
|
|
329
358
|
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
359
|
+
const stylesFrom = (
|
|
360
|
+
styles: readonly string[] | undefined,
|
|
361
|
+
): { styles?: readonly string[]; cssLoading?: CssLoadingMode } => {
|
|
333
362
|
if (styles === undefined || styles.length === 0) return {}
|
|
334
363
|
return {
|
|
335
364
|
styles,
|
|
@@ -337,6 +366,9 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
337
366
|
}
|
|
338
367
|
}
|
|
339
368
|
|
|
369
|
+
const stylesOf = (id: string): { styles?: readonly string[]; cssLoading?: CssLoadingMode } =>
|
|
370
|
+
stylesFrom(options.routeStyles?.[id] ?? options.styles)
|
|
371
|
+
|
|
340
372
|
// Load a route's layout modules once for the current execution. The render path needs each whole
|
|
341
373
|
// module for its component + meta, while the data path also needs loader/gate/boundary declarations.
|
|
342
374
|
const loadLayoutModules = async (route: RouteEntry): Promise<LoadedLayoutModules> => {
|
|
@@ -361,15 +393,41 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
361
393
|
pending: undefined,
|
|
362
394
|
}
|
|
363
395
|
|
|
364
|
-
/**
|
|
396
|
+
/**
|
|
397
|
+
* Await one gate. A returned redirect, status or Response refuses the request exactly as a thrown
|
|
398
|
+
* one does: stored as layout data it would let the page loader and the action run.
|
|
399
|
+
*/
|
|
400
|
+
const runGate = async (
|
|
401
|
+
route: RouteEntry,
|
|
402
|
+
index: number,
|
|
403
|
+
loader: NonNullable<LoadedLayoutModules[number]["loader"]>,
|
|
404
|
+
ctx: LoaderContext,
|
|
405
|
+
): Promise<unknown> => {
|
|
406
|
+
let value: unknown
|
|
407
|
+
try {
|
|
408
|
+
value = await loader(ctx)
|
|
409
|
+
} catch (err) {
|
|
410
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
411
|
+
throw tagLayoutError(err, route.layoutIds[index] as string)
|
|
412
|
+
}
|
|
413
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
414
|
+
if (isControlFlow(value)) throw tagLayoutError(value, route.layoutIds[index] as string)
|
|
415
|
+
return value
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Run layout loaders, awaiting gates before starting the page loader and retaining only safe data.
|
|
420
|
+
* `gated` carries gates that already ran for this request, so none runs twice.
|
|
421
|
+
*/
|
|
365
422
|
const runLayoutChain = async (
|
|
366
423
|
route: RouteEntry,
|
|
367
424
|
ctx: LoaderContext,
|
|
368
425
|
controls: PageResponseControls,
|
|
369
426
|
retain?: RetainContext,
|
|
427
|
+
gated?: GatedLayouts,
|
|
370
428
|
): Promise<LayoutRun> => {
|
|
371
429
|
if (route.layoutIds.length === 0) return emptyLayoutRun
|
|
372
|
-
const modules = await loadLayoutModules(route)
|
|
430
|
+
const modules = gated?.modules ?? (await loadLayoutModules(route))
|
|
373
431
|
if (!modules.some((m) => m.loader !== undefined)) {
|
|
374
432
|
return { modules, layoutData: undefined, retained: [], pending: undefined }
|
|
375
433
|
}
|
|
@@ -385,6 +443,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
385
443
|
try {
|
|
386
444
|
keep = keepsLayoutData(route, i, layout, ctx.params, retain)
|
|
387
445
|
} catch (err) {
|
|
446
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
388
447
|
throw tagLayoutError(err, route.layoutIds[i] as string)
|
|
389
448
|
}
|
|
390
449
|
if (keep) {
|
|
@@ -398,11 +457,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
398
457
|
set: controls.scope(i),
|
|
399
458
|
}
|
|
400
459
|
if (modules[i]?.gate === true) {
|
|
401
|
-
|
|
402
|
-
results[i] = await loader(scoped)
|
|
403
|
-
} catch (err) {
|
|
404
|
-
throw tagLayoutError(err, route.layoutIds[i] as string)
|
|
405
|
-
}
|
|
460
|
+
results[i] = gated === undefined ? await runGate(route, i, loader, scoped) : gated.gates[i]
|
|
406
461
|
continue
|
|
407
462
|
}
|
|
408
463
|
const layoutId = route.layoutIds[i] as string
|
|
@@ -441,22 +496,19 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
441
496
|
route: RouteEntry,
|
|
442
497
|
ctx: LoaderContext,
|
|
443
498
|
controls: PageResponseControls,
|
|
444
|
-
): Promise<
|
|
499
|
+
): Promise<GatedLayouts> => {
|
|
445
500
|
const modules = await loadLayoutModules(route)
|
|
501
|
+
const gates: unknown[] = []
|
|
446
502
|
for (let i = 0; i < modules.length; i++) {
|
|
447
503
|
const mod = modules[i]
|
|
448
504
|
if (mod?.gate !== true || mod.loader === undefined) continue
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
})
|
|
455
|
-
} catch (err) {
|
|
456
|
-
throw tagLayoutError(err, route.layoutIds[i] as string)
|
|
457
|
-
}
|
|
505
|
+
gates[i] = await runGate(route, i, mod.loader, {
|
|
506
|
+
...ctx,
|
|
507
|
+
params: scopeParams(ctx.params, route.layoutParams?.[i]),
|
|
508
|
+
set: controls.scope(i),
|
|
509
|
+
})
|
|
458
510
|
}
|
|
459
|
-
return modules
|
|
511
|
+
return { modules, gates }
|
|
460
512
|
}
|
|
461
513
|
|
|
462
514
|
/** Outermost first; a failure carries its directory so the nearest `_error` above it renders. */
|
|
@@ -594,16 +646,14 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
594
646
|
|
|
595
647
|
const resolveChainAndHead = (
|
|
596
648
|
layoutModules: LoadedLayoutModules,
|
|
649
|
+
layoutData: readonly unknown[] | undefined,
|
|
597
650
|
page: RouteModule,
|
|
598
651
|
metaArgs: MetaArgs,
|
|
599
652
|
leaf: unknown = page.default,
|
|
600
653
|
): { chain: unknown[]; head: Meta } => {
|
|
601
654
|
const chain = [...layoutModules.map((m) => m.default), leaf]
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
resolveMeta(page.meta, metaArgs),
|
|
605
|
-
]
|
|
606
|
-
return { chain, head: mergeHeads(heads) }
|
|
655
|
+
const metas = [...layoutModules.map((m) => m.meta), page.meta]
|
|
656
|
+
return { chain, head: mergeHeads(resolveChainMeta(metas, layoutData, metaArgs)) }
|
|
607
657
|
}
|
|
608
658
|
|
|
609
659
|
/** What `useMatches` reports for a chain: the layouts' ids and `handle`s, then the page's. */
|
|
@@ -649,49 +699,160 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
649
699
|
}
|
|
650
700
|
}
|
|
651
701
|
|
|
702
|
+
/** What a status or error page's `meta` receives: no route params, and its own data. */
|
|
703
|
+
const statusMetaArgs = (req: Request, data: unknown, nonce: string | undefined): MetaArgs =>
|
|
704
|
+
nonce === undefined
|
|
705
|
+
? { data, pageData: data, params: {}, origin: originOf(req) }
|
|
706
|
+
: { data, pageData: data, params: {}, origin: originOf(req), nonce }
|
|
707
|
+
|
|
652
708
|
const renderError = async (
|
|
709
|
+
req: Request,
|
|
653
710
|
route: RouteEntry,
|
|
654
711
|
errorId: string,
|
|
655
712
|
err: unknown,
|
|
656
713
|
personalized: boolean,
|
|
657
714
|
nonce?: string,
|
|
715
|
+
layouts?: LayoutChainSource,
|
|
658
716
|
): Promise<PageResponse> => {
|
|
659
717
|
const errDir = dirOfId(errorId, "_error")
|
|
660
718
|
const keptLayoutIds = route.layoutIds.filter((id) => {
|
|
661
719
|
const ld = dirOfId(id, "_layout")
|
|
662
720
|
return ld === "" || ld === errDir || errDir.startsWith(`${ld}/`)
|
|
663
721
|
})
|
|
664
|
-
const
|
|
722
|
+
const errorModule = await (manifest.errors?.[errorId] as LayoutEntry).load()
|
|
723
|
+
const e = err instanceof Error ? err : new Error(String(err))
|
|
724
|
+
// An error's text can carry a connection string or a query, so only a run that says it is
|
|
725
|
+
// development or test shows it; an unset NODE_ENV (an unbuilt `bun app.ts`) counts as production.
|
|
726
|
+
const nodeEnv = typeof process === "undefined" ? undefined : process.env.NODE_ENV
|
|
727
|
+
const data =
|
|
728
|
+
nodeEnv === "development" || nodeEnv === "test"
|
|
729
|
+
? { name: e.name, message: e.message }
|
|
730
|
+
: { name: "Error", message: "Internal Server Error" }
|
|
731
|
+
const inLayouts = errorModule.inLayouts !== false
|
|
732
|
+
const chain =
|
|
733
|
+
inLayouts && layouts !== undefined && keptLayoutIds.length > 0
|
|
734
|
+
? await layouts(errorModule, keptLayoutIds.length)
|
|
735
|
+
: undefined
|
|
736
|
+
const render = (components: unknown[], wrapped?: { head: Meta; chain: LayoutChain }) => {
|
|
737
|
+
const layoutData = wrapped?.chain.layoutData
|
|
738
|
+
return renderPageResult({
|
|
739
|
+
adapter,
|
|
740
|
+
chain: components,
|
|
741
|
+
data,
|
|
742
|
+
...(wrapped === undefined ? {} : { head: wrapped.head }),
|
|
743
|
+
clientEntry,
|
|
744
|
+
routeId: errorId,
|
|
745
|
+
status: 500,
|
|
746
|
+
hydrate: false,
|
|
747
|
+
...(layoutData === undefined ? {} : { layoutData }),
|
|
748
|
+
...(personalized || layoutData !== undefined ? { headers: PRIVATE_PAGE_HEADERS } : {}),
|
|
749
|
+
...(nonce === undefined ? {} : { nonce }),
|
|
750
|
+
...cspOption,
|
|
751
|
+
...titleOption,
|
|
752
|
+
})
|
|
753
|
+
}
|
|
754
|
+
if (chain !== undefined) {
|
|
755
|
+
const resolved = resolveChainAndHead(
|
|
756
|
+
chain.modules,
|
|
757
|
+
chain.layoutData,
|
|
758
|
+
errorModule,
|
|
759
|
+
statusMetaArgs(req, data, nonce),
|
|
760
|
+
)
|
|
761
|
+
try {
|
|
762
|
+
return await render(resolved.chain, { head: resolved.head, chain })
|
|
763
|
+
} catch {
|
|
764
|
+
// A layout that fails to render leaves the error page alone, never a second error.
|
|
765
|
+
return render([errorModule.default])
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
// Layouts whose data did not settle still frame the error page, without their data.
|
|
769
|
+
const layoutComponents = await Promise.all(
|
|
665
770
|
keptLayoutIds.map((id) =>
|
|
666
771
|
(manifest.layouts[id] as LayoutEntry).load().then((m) => m.default),
|
|
667
772
|
),
|
|
668
773
|
)
|
|
669
|
-
|
|
670
|
-
const e = err instanceof Error ? err : new Error(String(err))
|
|
671
|
-
// An error's text can carry a connection string or a query, so a production page gets neither.
|
|
672
|
-
const production = typeof process === "undefined" || process.env.NODE_ENV === "production"
|
|
673
|
-
return renderPageResult({
|
|
674
|
-
adapter,
|
|
675
|
-
chain: [...layouts, errComp],
|
|
676
|
-
data: production
|
|
677
|
-
? { name: "Error", message: "Internal Server Error" }
|
|
678
|
-
: { name: e.name, message: e.message },
|
|
679
|
-
clientEntry,
|
|
680
|
-
routeId: errorId,
|
|
681
|
-
status: 500,
|
|
682
|
-
hydrate: false,
|
|
683
|
-
...(personalized ? { headers: PRIVATE_PAGE_HEADERS } : {}),
|
|
684
|
-
...(nonce === undefined ? {} : { nonce }),
|
|
685
|
-
...cspOption,
|
|
686
|
-
...titleOption,
|
|
687
|
-
})
|
|
774
|
+
return render([...layoutComponents, errorModule.default])
|
|
688
775
|
}
|
|
689
776
|
|
|
777
|
+
/** The leading `count` layouts of `modules`, unless one of them answered with a status or redirect. */
|
|
778
|
+
const settledLayouts = (
|
|
779
|
+
modules: LoadedLayoutModules,
|
|
780
|
+
layoutData: readonly unknown[] | undefined,
|
|
781
|
+
count: number,
|
|
782
|
+
): LayoutChain | undefined => {
|
|
783
|
+
if (modules.length < count) return undefined
|
|
784
|
+
const data = layoutData?.slice(0, count)
|
|
785
|
+
if (data?.some((value) => isControlFlow(value) || isStatusSignal(value))) return undefined
|
|
786
|
+
return { modules: modules.slice(0, count), layoutData: data }
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/** A run's leading layouts once all of its loaders settle - never when a layout or middleware refused. */
|
|
790
|
+
const leadingLayouts =
|
|
791
|
+
(run: LayoutRun | undefined, err?: unknown): LayoutChainSource =>
|
|
792
|
+
async (_page, count) => {
|
|
793
|
+
if (run === undefined || (err !== undefined && layoutErrorId(err) !== undefined)) {
|
|
794
|
+
return undefined
|
|
795
|
+
}
|
|
796
|
+
try {
|
|
797
|
+
await run.pending
|
|
798
|
+
} catch {
|
|
799
|
+
return undefined
|
|
800
|
+
}
|
|
801
|
+
return settledLayouts(run.modules, run.layoutData, count)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const rootLayoutIds: readonly string[] = manifest.layouts._layout === undefined ? [] : ["_layout"]
|
|
805
|
+
const rootMiddlewareIds: readonly string[] =
|
|
806
|
+
manifest.middlewares?._middleware === undefined ? [] : ["_middleware"]
|
|
807
|
+
/**
|
|
808
|
+
* Run the root middleware and layouts for a request no route ran them for (an unmatched URL), as a
|
|
809
|
+
* nested `_404` runs its own. Any refusal or failure renders the page alone.
|
|
810
|
+
*/
|
|
811
|
+
const rootLayoutsFor =
|
|
812
|
+
(c: PageRouteContext<Env>, controls: PageResponseControls): LayoutChainSource =>
|
|
813
|
+
async (page) => {
|
|
814
|
+
const entry = manifest.statusPages?.["404"] ?? manifest.notFound
|
|
815
|
+
if (rootLayoutIds.length === 0 || entry === undefined) return undefined
|
|
816
|
+
const layoutsOnly: RouteEntry = {
|
|
817
|
+
id: "_404",
|
|
818
|
+
pattern: "/*",
|
|
819
|
+
layoutIds: rootLayoutIds,
|
|
820
|
+
errorIds: [],
|
|
821
|
+
file: entry.file,
|
|
822
|
+
load: entry.load,
|
|
823
|
+
}
|
|
824
|
+
const route: RouteEntry =
|
|
825
|
+
rootMiddlewareIds.length === 0
|
|
826
|
+
? layoutsOnly
|
|
827
|
+
: { ...layoutsOnly, middlewareIds: rootMiddlewareIds }
|
|
828
|
+
try {
|
|
829
|
+
const draft = await draftFlag(c.req)
|
|
830
|
+
if (draft) controls.personalize()
|
|
831
|
+
const ctx: LoaderContext = {
|
|
832
|
+
params: {},
|
|
833
|
+
request: c.req,
|
|
834
|
+
req: c.req,
|
|
835
|
+
api: apiFor(c),
|
|
836
|
+
env: c.env,
|
|
837
|
+
draft,
|
|
838
|
+
search: loaderSearch(page.searchSchema, c.req),
|
|
839
|
+
set: controls.scope(PAGE_SCOPE),
|
|
840
|
+
}
|
|
841
|
+
if (route.middlewareIds !== undefined) await runMiddleware(route, ctx, controls)
|
|
842
|
+
const run = await runLayoutChain(route, ctx, controls)
|
|
843
|
+
await run.pending
|
|
844
|
+
return settledLayouts(run.modules, run.layoutData, rootLayoutIds.length)
|
|
845
|
+
} catch {
|
|
846
|
+
return undefined
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
690
850
|
const renderTerminalStatus = async (
|
|
691
851
|
status: number,
|
|
692
|
-
|
|
852
|
+
req: Request,
|
|
693
853
|
extraHeaders?: HeadersLike,
|
|
694
854
|
nonce?: string,
|
|
855
|
+
layouts?: LayoutChainSource,
|
|
695
856
|
): Promise<PageResponse> => {
|
|
696
857
|
const page = manifest.statusPages?.[String(status)] ?? manifest.notFound
|
|
697
858
|
if (page === undefined) {
|
|
@@ -700,36 +861,57 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
700
861
|
return new Response(STATUS_TEXT[status] ?? "Error", { status, headers })
|
|
701
862
|
}
|
|
702
863
|
const routeId = manifest.statusPages?.[String(status)] !== undefined ? `_${status}` : "_404"
|
|
703
|
-
const loaded =
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
864
|
+
const loaded = await page.load()
|
|
865
|
+
const wraps = loaded.inLayouts !== false && rootLayoutIds.length > 0
|
|
866
|
+
const chain =
|
|
867
|
+
wraps && layouts !== undefined ? await layouts(loaded, rootLayoutIds.length) : undefined
|
|
868
|
+
const modules = chain?.modules ?? []
|
|
869
|
+
const layoutIds = chain === undefined ? [] : rootLayoutIds
|
|
870
|
+
const layoutData = chain?.layoutData
|
|
871
|
+
const { chain: components, head } = resolveChainAndHead(
|
|
872
|
+
modules,
|
|
873
|
+
layoutData,
|
|
874
|
+
loaded,
|
|
875
|
+
statusMetaArgs(req, null, nonce),
|
|
876
|
+
)
|
|
877
|
+
let headers = extraHeaders
|
|
878
|
+
if (layoutData !== undefined) {
|
|
879
|
+
// The page now shows what a layout loaded for this visitor.
|
|
880
|
+
const privateHeaders = new Headers(extraHeaders)
|
|
881
|
+
privateHeaders.set("cache-control", PRIVATE_NO_STORE)
|
|
882
|
+
headers = privateHeaders
|
|
707
883
|
}
|
|
708
|
-
|
|
884
|
+
const statusPage = {
|
|
709
885
|
adapter,
|
|
710
|
-
chain:
|
|
886
|
+
chain: components,
|
|
711
887
|
data: null,
|
|
888
|
+
head,
|
|
712
889
|
clientEntry,
|
|
713
890
|
routeId,
|
|
714
|
-
matchChain:
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
search: searchOf(
|
|
718
|
-
loaded.searchSchema,
|
|
719
|
-
path.includes("?") ? path.slice(path.indexOf("?")) : "",
|
|
720
|
-
),
|
|
721
|
-
}
|
|
722
|
-
: {}),
|
|
723
|
-
...(path !== undefined ? { path } : {}),
|
|
891
|
+
matchChain: matchChainOf(layoutIds, modules, routeId, loaded),
|
|
892
|
+
search: searchChainOf(modules, loaded, req),
|
|
893
|
+
path: pathOf(req),
|
|
724
894
|
status,
|
|
725
|
-
|
|
895
|
+
// The browser renders this page inside the root layout, so a page that had to render alone
|
|
896
|
+
// stays server-only, as a nested `_404` does.
|
|
897
|
+
...(wraps && chain === undefined ? { hydrate: false } : {}),
|
|
898
|
+
...(layoutData === undefined ? {} : { layoutData }),
|
|
899
|
+
...(headers !== undefined ? { headers } : {}),
|
|
726
900
|
...(nonce === undefined ? {} : { nonce }),
|
|
727
901
|
...cspOption,
|
|
728
902
|
...preloadOf(routeId),
|
|
729
|
-
|
|
903
|
+
// The build keys stylesheets by route, so a page inside the root layout links the whole-app one.
|
|
904
|
+
...(chain === undefined ? stylesOf(routeId) : stylesFrom(options.styles)),
|
|
730
905
|
...prerenderedHandover,
|
|
731
906
|
...titleOption,
|
|
732
|
-
}
|
|
907
|
+
}
|
|
908
|
+
if (chain === undefined) return renderPageResult(statusPage)
|
|
909
|
+
try {
|
|
910
|
+
return await renderPageResult(statusPage)
|
|
911
|
+
} catch {
|
|
912
|
+
// A layout that fails to render leaves the status page alone, never a second error.
|
|
913
|
+
return renderTerminalStatus(status, req, extraHeaders, nonce)
|
|
914
|
+
}
|
|
733
915
|
}
|
|
734
916
|
|
|
735
917
|
const renderStatusSignal = async (
|
|
@@ -737,6 +919,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
737
919
|
env: Env,
|
|
738
920
|
signal: StatusSignal,
|
|
739
921
|
personalized: boolean,
|
|
922
|
+
layouts?: LayoutChainSource,
|
|
740
923
|
): Promise<PageResponse> => {
|
|
741
924
|
const { status, headers } = signal[STATUS_SIGNAL]
|
|
742
925
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
@@ -750,7 +933,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
750
933
|
}
|
|
751
934
|
const nonce = await resolveNonce(req, env)
|
|
752
935
|
if (headers === undefined && !personalized) {
|
|
753
|
-
return renderTerminalStatus(status,
|
|
936
|
+
return renderTerminalStatus(status, req, undefined, nonce, layouts)
|
|
754
937
|
}
|
|
755
938
|
const documentHeaders = new Headers(headers)
|
|
756
939
|
if (headers !== undefined) {
|
|
@@ -758,7 +941,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
758
941
|
}
|
|
759
942
|
// A cookie queued before the signal makes the status page specific to this visitor.
|
|
760
943
|
if (personalized) documentHeaders.set("cache-control", PRIVATE_NO_STORE)
|
|
761
|
-
return renderTerminalStatus(status,
|
|
944
|
+
return renderTerminalStatus(status, req, documentHeaders, nonce, layouts)
|
|
762
945
|
}
|
|
763
946
|
|
|
764
947
|
const reportLoaderError = (
|
|
@@ -789,8 +972,12 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
789
972
|
assemblyCache: RenderAssemblyCache | undefined,
|
|
790
973
|
responseHeaders: Record<string, string> | undefined,
|
|
791
974
|
personalized: boolean,
|
|
975
|
+
serverComponents?: import("../server-components/types.ts").ComponentState,
|
|
792
976
|
): Promise<PageResponse> => {
|
|
793
|
-
|
|
977
|
+
// Every layout loader settled before the page rendered, so a status or error page can reuse them.
|
|
978
|
+
const settled: LayoutChainSource = async (_page, count) =>
|
|
979
|
+
settledLayouts(layoutModules, layoutData, count)
|
|
980
|
+
if (isStatusSignal(data)) return renderStatusSignal(req, env, data, personalized, settled)
|
|
794
981
|
if (isControlFlow(data)) return data
|
|
795
982
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
796
983
|
const pageSplit = prepareDeferred(data)
|
|
@@ -809,7 +996,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
809
996
|
...(boundarySplit === undefined ? [] : boundarySplit.deferred),
|
|
810
997
|
]
|
|
811
998
|
const payload =
|
|
812
|
-
layoutData === undefined && boundarySplit === undefined
|
|
999
|
+
layoutData === undefined && boundarySplit === undefined && serverComponents === undefined
|
|
813
1000
|
? pageSplit.forClient
|
|
814
1001
|
: {
|
|
815
1002
|
v: 1 as const,
|
|
@@ -817,6 +1004,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
817
1004
|
layoutData: layoutSplits.map((split) => split.forClient),
|
|
818
1005
|
retained: layoutRetained,
|
|
819
1006
|
...(boundarySplit === undefined ? {} : { boundaries: boundarySplit.forClient }),
|
|
1007
|
+
...(serverComponents === undefined ? {} : { serverComponents }),
|
|
820
1008
|
}
|
|
821
1009
|
if (allDeferred.length === 0) {
|
|
822
1010
|
return Response.json(payload ?? null, { headers: DATA_RESPONSE_HEADERS })
|
|
@@ -832,9 +1020,11 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
832
1020
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(req, env)
|
|
833
1021
|
const { chain, head } = resolveChainAndHead(
|
|
834
1022
|
layoutModules,
|
|
1023
|
+
layoutData,
|
|
835
1024
|
mod,
|
|
836
1025
|
{
|
|
837
1026
|
data,
|
|
1027
|
+
pageData: data,
|
|
838
1028
|
params,
|
|
839
1029
|
origin: originOf(req),
|
|
840
1030
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -853,6 +1043,8 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
853
1043
|
path: pathOf(req),
|
|
854
1044
|
search: searchChainOf(layoutModules, mod, req),
|
|
855
1045
|
matchChain: matchChainOf(route.layoutIds, layoutModules, route.id, mod),
|
|
1046
|
+
...(serverComponents === undefined ? {} : { serverComponents }),
|
|
1047
|
+
...(progressiveActionData.has(req) ? { actionData: progressiveActionData.get(req) } : {}),
|
|
856
1048
|
hydrate: mod.hydrate !== false,
|
|
857
1049
|
...(layoutData !== undefined ? { layoutData } : {}),
|
|
858
1050
|
...(boundaryStates !== undefined ? { boundaries: boundaryStates } : {}),
|
|
@@ -882,12 +1074,21 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
882
1074
|
...(assemblyCache === undefined ? {} : { assemblyCache }),
|
|
883
1075
|
})
|
|
884
1076
|
} catch (err) {
|
|
885
|
-
if (isStatusSignal(err)) return renderStatusSignal(req, env, err, personalized)
|
|
1077
|
+
if (isStatusSignal(err)) return renderStatusSignal(req, env, err, personalized, settled)
|
|
886
1078
|
if (isControlFlow(err)) throw err
|
|
887
1079
|
reportLoaderError(route, req, { ...params }, err)
|
|
888
1080
|
const errorId = boundaryFor(route, err)
|
|
889
1081
|
if (errorId === undefined) throw err
|
|
890
|
-
|
|
1082
|
+
options.logBoundaryError?.(err, req)
|
|
1083
|
+
return renderError(
|
|
1084
|
+
req,
|
|
1085
|
+
route,
|
|
1086
|
+
errorId,
|
|
1087
|
+
withDuplicateInstanceHint(err),
|
|
1088
|
+
personalized,
|
|
1089
|
+
nonce,
|
|
1090
|
+
settled,
|
|
1091
|
+
)
|
|
891
1092
|
}
|
|
892
1093
|
}
|
|
893
1094
|
|
|
@@ -899,11 +1100,13 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
899
1100
|
params: Record<string, string>,
|
|
900
1101
|
err: unknown,
|
|
901
1102
|
personalized: boolean,
|
|
1103
|
+
layouts?: LayoutChainSource,
|
|
902
1104
|
): Promise<PageResponse> => {
|
|
903
1105
|
if (isControlFlow(err)) throw err
|
|
904
1106
|
reportLoaderError(route, req, params, err)
|
|
905
1107
|
const errorId = boundaryFor(route, err)
|
|
906
1108
|
if (errorId === undefined) throw err
|
|
1109
|
+
options.logBoundaryError?.(err, req)
|
|
907
1110
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
908
1111
|
return new Response("Internal Server Error", {
|
|
909
1112
|
status: 500,
|
|
@@ -911,11 +1114,13 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
911
1114
|
})
|
|
912
1115
|
}
|
|
913
1116
|
return renderError(
|
|
1117
|
+
req,
|
|
914
1118
|
route,
|
|
915
1119
|
errorId,
|
|
916
1120
|
withDuplicateInstanceHint(err),
|
|
917
1121
|
personalized,
|
|
918
1122
|
options.nonce === undefined ? undefined : await resolveNonce(req, env),
|
|
1123
|
+
layouts,
|
|
919
1124
|
)
|
|
920
1125
|
}
|
|
921
1126
|
|
|
@@ -946,8 +1151,9 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
946
1151
|
}
|
|
947
1152
|
const mod = await page.load()
|
|
948
1153
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(req, env)
|
|
949
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
1154
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
950
1155
|
data: null,
|
|
1156
|
+
pageData: null,
|
|
951
1157
|
params,
|
|
952
1158
|
origin: originOf(req),
|
|
953
1159
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -1018,17 +1224,17 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1018
1224
|
}
|
|
1019
1225
|
|
|
1020
1226
|
const renderNotFound = async (
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
path?: string,
|
|
1227
|
+
c: PageRouteContext<Env>,
|
|
1228
|
+
controls: PageResponseControls,
|
|
1024
1229
|
): Promise<PageResponse> => {
|
|
1025
1230
|
const page = manifest.statusPages?.["404"] ?? manifest.notFound
|
|
1026
|
-
if (page === undefined) return renderTerminalStatus(404,
|
|
1231
|
+
if (page === undefined) return renderTerminalStatus(404, c.req)
|
|
1027
1232
|
return renderTerminalStatus(
|
|
1028
1233
|
404,
|
|
1029
|
-
|
|
1234
|
+
c.req,
|
|
1030
1235
|
undefined,
|
|
1031
|
-
options.nonce === undefined ? undefined : await resolveNonce(
|
|
1236
|
+
options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env),
|
|
1237
|
+
rootLayoutsFor(c, controls),
|
|
1032
1238
|
)
|
|
1033
1239
|
}
|
|
1034
1240
|
|
|
@@ -1084,8 +1290,19 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1084
1290
|
}
|
|
1085
1291
|
|
|
1086
1292
|
return withResponseControls(async (c, controls) => {
|
|
1087
|
-
|
|
1088
|
-
|
|
1293
|
+
const componentRuntime = options.serverComponents
|
|
1294
|
+
const componentOwner = componentRuntime?.owns(route.id) === true
|
|
1295
|
+
let componentRequest:
|
|
1296
|
+
| import("../server-components/protocol.ts").ComponentRequest
|
|
1297
|
+
| undefined
|
|
1298
|
+
try {
|
|
1299
|
+
componentRequest = componentRuntime?.classify(c.req, route.id)
|
|
1300
|
+
} catch (error) {
|
|
1301
|
+
return componentRuntime!.failure(error)
|
|
1302
|
+
}
|
|
1303
|
+
if (componentOwner || componentRequest !== undefined) controls.personalize()
|
|
1304
|
+
if (!componentOwner && is404Fallback && !prerenderedSet.has(urlPartsFor(c.req).pathname)) {
|
|
1305
|
+
return renderNotFound(c, controls)
|
|
1089
1306
|
}
|
|
1090
1307
|
const mod = await route.load()
|
|
1091
1308
|
const draft = await draftFlag(c.req)
|
|
@@ -1097,6 +1314,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1097
1314
|
let layoutModules: LoadedLayoutModules | undefined
|
|
1098
1315
|
let layoutRetained: readonly number[] = []
|
|
1099
1316
|
let responseHeaders: Record<string, string> | undefined
|
|
1317
|
+
let componentState: import("../server-components/types.ts").ComponentState | undefined
|
|
1100
1318
|
const requestApi = apiFor(c)
|
|
1101
1319
|
let run: LayoutRun | undefined
|
|
1102
1320
|
try {
|
|
@@ -1111,13 +1329,21 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1111
1329
|
set: controls.scope(PAGE_SCOPE),
|
|
1112
1330
|
}
|
|
1113
1331
|
if (route.middlewareIds !== undefined) await runMiddleware(route, ctx, controls)
|
|
1114
|
-
run = await runLayoutChain(
|
|
1332
|
+
run = await runLayoutChain(
|
|
1333
|
+
route,
|
|
1334
|
+
ctx,
|
|
1335
|
+
controls,
|
|
1336
|
+
componentOwner ? undefined : retainContextOf(c.req),
|
|
1337
|
+
)
|
|
1115
1338
|
layoutModules = run.modules
|
|
1116
1339
|
layoutRetained = run.retained
|
|
1117
|
-
const boundaryDefinitions =
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1340
|
+
const boundaryDefinitions =
|
|
1341
|
+
componentRequest === undefined
|
|
1342
|
+
? [
|
|
1343
|
+
...run.modules.flatMap((layout) => layout.boundaries ?? []),
|
|
1344
|
+
...(mod.boundaries ?? []),
|
|
1345
|
+
]
|
|
1346
|
+
: []
|
|
1121
1347
|
if (boundaryDefinitions.length > 0) boundaryDescriptors(boundaryDefinitions)
|
|
1122
1348
|
const effectiveSearch = searchChainOf(run.modules, mod, c.req)
|
|
1123
1349
|
const boundaryBatch =
|
|
@@ -1149,6 +1375,34 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1149
1375
|
: await Promise.all([pageResult, run.pending, staticBoundaryPromise])
|
|
1150
1376
|
data = pageData
|
|
1151
1377
|
layoutData = run.layoutData
|
|
1378
|
+
if (componentOwner) {
|
|
1379
|
+
for (let i = 0; i < (layoutData?.length ?? 0); i++) {
|
|
1380
|
+
const outcome = layoutData?.[i]
|
|
1381
|
+
if (isControlFlow(outcome) || isStatusSignal(outcome))
|
|
1382
|
+
throw tagLayoutError(outcome, route.layoutIds[i] as string)
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
if (componentRequest !== undefined && (isControlFlow(data) || isStatusSignal(data)))
|
|
1386
|
+
return componentRuntime!.failure(data)
|
|
1387
|
+
if (componentOwner && !isControlFlow(data) && !isStatusSignal(data)) {
|
|
1388
|
+
const componentContext = Object.create(
|
|
1389
|
+
c,
|
|
1390
|
+
Object.getOwnPropertyDescriptors({
|
|
1391
|
+
...ctx,
|
|
1392
|
+
search: effectiveSearch,
|
|
1393
|
+
signal:
|
|
1394
|
+
c.signal === undefined ? c.req.signal : AbortSignal.any([c.signal, c.req.signal]),
|
|
1395
|
+
data,
|
|
1396
|
+
layoutData: layoutData ?? [],
|
|
1397
|
+
}),
|
|
1398
|
+
)
|
|
1399
|
+
componentState = await componentRuntime!.execute(
|
|
1400
|
+
route.id,
|
|
1401
|
+
componentContext,
|
|
1402
|
+
componentRequest,
|
|
1403
|
+
options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env),
|
|
1404
|
+
)
|
|
1405
|
+
}
|
|
1152
1406
|
if (boundaryBatch !== undefined) {
|
|
1153
1407
|
const streamed = { ...boundaryBatch.initial, ...(staticBoundaries ?? {}) }
|
|
1154
1408
|
for (const entry of boundaryBatch.pending) {
|
|
@@ -1164,6 +1418,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1164
1418
|
// by the same boundary as one.
|
|
1165
1419
|
responseHeaders = controls.documentHeaders()
|
|
1166
1420
|
} catch (err) {
|
|
1421
|
+
if (componentRequest !== undefined) return componentRuntime!.failure(err)
|
|
1167
1422
|
if (isStatusSignal(err)) {
|
|
1168
1423
|
return (
|
|
1169
1424
|
(await renderRouteNotFound(
|
|
@@ -1174,10 +1429,27 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1174
1429
|
err,
|
|
1175
1430
|
run,
|
|
1176
1431
|
controls.personalized,
|
|
1177
|
-
)) ??
|
|
1432
|
+
)) ??
|
|
1433
|
+
renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err))
|
|
1178
1434
|
)
|
|
1179
1435
|
}
|
|
1180
|
-
return renderLoaderFailure(
|
|
1436
|
+
return renderLoaderFailure(
|
|
1437
|
+
route,
|
|
1438
|
+
c.req,
|
|
1439
|
+
c.env,
|
|
1440
|
+
c.params,
|
|
1441
|
+
err,
|
|
1442
|
+
controls.personalized,
|
|
1443
|
+
leadingLayouts(run, err),
|
|
1444
|
+
)
|
|
1445
|
+
}
|
|
1446
|
+
if (componentRequest !== undefined && componentState !== undefined) {
|
|
1447
|
+
const answer = componentRuntime!.response(componentState, componentRequest)
|
|
1448
|
+
const headers = new Headers(answer.headers)
|
|
1449
|
+
for (const [name, value] of Object.entries(responseHeaders ?? {}))
|
|
1450
|
+
if (name !== "cache-control" && name !== "content-type" && name !== "vary")
|
|
1451
|
+
headers.set(name, value)
|
|
1452
|
+
return new Response(answer.body, { status: answer.status, headers })
|
|
1181
1453
|
}
|
|
1182
1454
|
if (isStatusSignal(data)) {
|
|
1183
1455
|
const nested = await renderRouteNotFound(
|
|
@@ -1205,6 +1477,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1205
1477
|
layoutModules === undefined ? undefined : assemblyCacheFor(mod, layoutModules),
|
|
1206
1478
|
responseHeaders,
|
|
1207
1479
|
controls.personalized,
|
|
1480
|
+
componentState,
|
|
1208
1481
|
)
|
|
1209
1482
|
})
|
|
1210
1483
|
},
|
|
@@ -1232,11 +1505,11 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1232
1505
|
set: controls.scope(ACTION_SCOPE),
|
|
1233
1506
|
}
|
|
1234
1507
|
const isDataRequest = c.req.headers.get(DATA_HEADER) !== null
|
|
1235
|
-
let
|
|
1508
|
+
let gated: GatedLayouts
|
|
1236
1509
|
let result: unknown
|
|
1237
1510
|
try {
|
|
1238
1511
|
if (route.middlewareIds !== undefined) await runMiddleware(route, actionContext, controls)
|
|
1239
|
-
|
|
1512
|
+
gated = await runLayoutGates(route, actionContext, controls)
|
|
1240
1513
|
result = await mod.action(actionContext)
|
|
1241
1514
|
} catch (err) {
|
|
1242
1515
|
if (isControlFlow(err)) return err
|
|
@@ -1271,26 +1544,136 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1271
1544
|
},
|
|
1272
1545
|
})
|
|
1273
1546
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1547
|
+
if (options.serverComponents?.owns(route.id)) {
|
|
1548
|
+
if (options.rerenderOwnerGET === undefined) throw new Error("component_contract")
|
|
1549
|
+
const actionHeaders = controls.documentHeaders()
|
|
1550
|
+
if (controls.progressiveRedirect(c.req)) {
|
|
1551
|
+
// Relative, so a browser behind a TLS terminator stays on its own scheme. A `//` path
|
|
1552
|
+
// would read as another host, so that one keeps the absolute URL.
|
|
1553
|
+
const { pathname, search } = new URL(c.req.url)
|
|
1554
|
+
const location = pathname.startsWith("//") ? c.req.url : pathname + search
|
|
1555
|
+
return new Response(null, {
|
|
1556
|
+
status: 303,
|
|
1557
|
+
headers: { ...actionHeaders, location, "cache-control": PRIVATE_NO_STORE },
|
|
1558
|
+
})
|
|
1559
|
+
}
|
|
1560
|
+
const headers = new Headers(c.req.headers)
|
|
1561
|
+
for (const name of [
|
|
1562
|
+
DATA_HEADER,
|
|
1563
|
+
RETAIN_HEADER,
|
|
1564
|
+
NAV_FROM_HEADER,
|
|
1565
|
+
"x-nifra-component",
|
|
1566
|
+
"content-type",
|
|
1567
|
+
"content-length",
|
|
1568
|
+
"transfer-encoding",
|
|
1569
|
+
])
|
|
1570
|
+
headers.delete(name)
|
|
1571
|
+
const cookie = controls.progressiveCookies(c.req)
|
|
1572
|
+
if (cookie) headers.set("cookie", cookie)
|
|
1573
|
+
else headers.delete("cookie")
|
|
1574
|
+
const request = new Request(c.req.url, {
|
|
1575
|
+
method: "GET",
|
|
1576
|
+
headers,
|
|
1577
|
+
signal:
|
|
1578
|
+
c.signal === undefined ? c.req.signal : AbortSignal.any([c.signal, c.req.signal]),
|
|
1579
|
+
})
|
|
1580
|
+
progressiveActionData.set(request, actionResult)
|
|
1581
|
+
try {
|
|
1582
|
+
const response = await options.rerenderOwnerGET(request, c)
|
|
1583
|
+
const merged = new Headers(response.headers)
|
|
1584
|
+
for (const [name, value] of Object.entries(actionHeaders ?? {}))
|
|
1585
|
+
if (!merged.has(name)) merged.set(name, value)
|
|
1586
|
+
merged.set("cache-control", PRIVATE_NO_STORE)
|
|
1587
|
+
return new Response(response.body, {
|
|
1588
|
+
status: response.status,
|
|
1589
|
+
statusText: response.statusText,
|
|
1590
|
+
headers: merged,
|
|
1285
1591
|
})
|
|
1286
|
-
|
|
1287
|
-
|
|
1592
|
+
} finally {
|
|
1593
|
+
progressiveActionData.delete(request)
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
const layoutModules = gated.modules
|
|
1597
|
+
const search = searchChainOf(layoutModules, mod, c.req)
|
|
1598
|
+
let run: LayoutRun | undefined
|
|
1599
|
+
let data: unknown
|
|
1600
|
+
let responseHeaders: Record<string, string> | undefined
|
|
1601
|
+
// The ordinary layout loaders run now, after the mutation, as a GET of this page would.
|
|
1602
|
+
try {
|
|
1603
|
+
run = await runLayoutChain(route, actionContext, controls, undefined, gated)
|
|
1604
|
+
const pageResult = mod.loader
|
|
1605
|
+
? mod.loader({
|
|
1606
|
+
params: c.params,
|
|
1607
|
+
request: c.req,
|
|
1608
|
+
req: c.req,
|
|
1609
|
+
api: requestApi,
|
|
1610
|
+
env: c.env,
|
|
1611
|
+
draft,
|
|
1612
|
+
search,
|
|
1613
|
+
set: controls.scope(PAGE_SCOPE),
|
|
1614
|
+
})
|
|
1615
|
+
: null
|
|
1616
|
+
const [pageData] =
|
|
1617
|
+
run.pending === undefined
|
|
1618
|
+
? ([await pageResult] as const)
|
|
1619
|
+
: await Promise.all([pageResult, run.pending])
|
|
1620
|
+
data = pageData
|
|
1621
|
+
responseHeaders = controls.documentHeaders()
|
|
1622
|
+
} catch (err) {
|
|
1623
|
+
if (isStatusSignal(err)) {
|
|
1624
|
+
return (
|
|
1625
|
+
(await renderRouteNotFound(
|
|
1626
|
+
c.req,
|
|
1627
|
+
c.env,
|
|
1628
|
+
route,
|
|
1629
|
+
c.params,
|
|
1630
|
+
err,
|
|
1631
|
+
run,
|
|
1632
|
+
controls.personalized,
|
|
1633
|
+
)) ??
|
|
1634
|
+
renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err))
|
|
1635
|
+
)
|
|
1636
|
+
}
|
|
1637
|
+
return renderLoaderFailure(
|
|
1638
|
+
route,
|
|
1639
|
+
c.req,
|
|
1640
|
+
c.env,
|
|
1641
|
+
c.params,
|
|
1642
|
+
err,
|
|
1643
|
+
controls.personalized,
|
|
1644
|
+
leadingLayouts(run, err),
|
|
1645
|
+
)
|
|
1646
|
+
}
|
|
1647
|
+
// The re-render answers a returned redirect or status the way the page's GET does.
|
|
1648
|
+
if (isStatusSignal(data))
|
|
1649
|
+
return (
|
|
1650
|
+
(await renderRouteNotFound(
|
|
1651
|
+
c.req,
|
|
1652
|
+
c.env,
|
|
1653
|
+
route,
|
|
1654
|
+
c.params,
|
|
1655
|
+
data,
|
|
1656
|
+
run,
|
|
1657
|
+
controls.personalized,
|
|
1658
|
+
)) ??
|
|
1659
|
+
renderStatusSignal(c.req, c.env, data, controls.personalized, leadingLayouts(run, data))
|
|
1660
|
+
)
|
|
1661
|
+
if (isControlFlow(data)) return data
|
|
1662
|
+
const layoutData = run.layoutData
|
|
1663
|
+
const layoutProps: { layoutData?: Exclude<typeof layoutData, undefined> } = {}
|
|
1664
|
+
if (layoutData !== undefined) {
|
|
1665
|
+
layoutProps.layoutData = layoutData
|
|
1666
|
+
// The page now shows what a layout loaded for this visitor.
|
|
1667
|
+
responseHeaders = { ...responseHeaders, ...PRIVATE_PAGE_HEADERS }
|
|
1668
|
+
}
|
|
1288
1669
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env)
|
|
1289
1670
|
const { chain, head } = resolveChainAndHead(
|
|
1290
1671
|
layoutModules,
|
|
1672
|
+
layoutData,
|
|
1291
1673
|
mod,
|
|
1292
1674
|
{
|
|
1293
1675
|
data,
|
|
1676
|
+
pageData: data,
|
|
1294
1677
|
params: c.params,
|
|
1295
1678
|
origin: originOf(c.req),
|
|
1296
1679
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -1310,6 +1693,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1310
1693
|
search,
|
|
1311
1694
|
matchChain: matchChainOf(route.layoutIds, layoutModules, route.id, mod),
|
|
1312
1695
|
hydrate: mod.hydrate !== false,
|
|
1696
|
+
...layoutProps,
|
|
1313
1697
|
...preloadOf(route.id),
|
|
1314
1698
|
...stylesOf(route.id),
|
|
1315
1699
|
...prerenderedHandover,
|
|
@@ -1324,7 +1708,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1324
1708
|
const match = matchNotFoundScope?.(pathOf(c.req)) ?? null
|
|
1325
1709
|
const target = match === null ? undefined : notFoundTargets[Number(match.routeId)]
|
|
1326
1710
|
if (match === null || target === undefined) {
|
|
1327
|
-
return renderNotFound(c
|
|
1711
|
+
return renderNotFound(c, controls)
|
|
1328
1712
|
}
|
|
1329
1713
|
const params: Record<string, string> = {}
|
|
1330
1714
|
for (let i = 0; i < target.names.length; i++) {
|
|
@@ -1333,7 +1717,7 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1333
1717
|
const mod = await target.page.load()
|
|
1334
1718
|
const draft = await draftFlag(c.req)
|
|
1335
1719
|
if (draft) controls.personalize()
|
|
1336
|
-
let run: LayoutRun
|
|
1720
|
+
let run: LayoutRun | undefined
|
|
1337
1721
|
try {
|
|
1338
1722
|
const ctx: LoaderContext = {
|
|
1339
1723
|
params,
|
|
@@ -1352,9 +1736,23 @@ export function createPageRequestExecutor<Env = unknown>(
|
|
|
1352
1736
|
await run.pending
|
|
1353
1737
|
} catch (err) {
|
|
1354
1738
|
if (isStatusSignal(err)) {
|
|
1355
|
-
return renderStatusSignal(
|
|
1739
|
+
return renderStatusSignal(
|
|
1740
|
+
c.req,
|
|
1741
|
+
c.env,
|
|
1742
|
+
err,
|
|
1743
|
+
controls.personalized,
|
|
1744
|
+
leadingLayouts(run, err),
|
|
1745
|
+
)
|
|
1356
1746
|
}
|
|
1357
|
-
return renderLoaderFailure(
|
|
1747
|
+
return renderLoaderFailure(
|
|
1748
|
+
target.route,
|
|
1749
|
+
c.req,
|
|
1750
|
+
c.env,
|
|
1751
|
+
params,
|
|
1752
|
+
err,
|
|
1753
|
+
controls.personalized,
|
|
1754
|
+
leadingLayouts(run, err),
|
|
1755
|
+
)
|
|
1358
1756
|
}
|
|
1359
1757
|
return renderNestedNotFound(
|
|
1360
1758
|
c.req,
|