@nifrajs/web 4.0.2 → 5.1.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 +19 -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 +6 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +46 -18
- 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-port.d.ts +3 -2
- package/dist/dev-port.d.ts.map +1 -1
- package/dist/dev-port.js +2 -6
- package/dist/dev-port.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 +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- 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/package-entries.d.ts +34 -0
- package/dist/internal/package-entries.d.ts.map +1 -0
- package/dist/internal/package-entries.js +324 -0
- package/dist/internal/package-entries.js.map +1 -0
- 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 +437 -114
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/parity.d.ts.map +1 -1
- package/dist/internal/parity.js +15 -2
- package/dist/internal/parity.js.map +1 -1
- package/dist/internal/private-env.d.ts +8 -0
- package/dist/internal/private-env.d.ts.map +1 -1
- package/dist/internal/private-env.js +25 -10
- package/dist/internal/private-env.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 +5 -44
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +51 -63
- 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 +14 -0
- package/dist/internal/route-path.d.ts.map +1 -0
- package/dist/internal/route-path.js +19 -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 +190 -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 +25 -18
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +81 -24
- 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/without-query.d.ts +4 -0
- package/dist/internal/without-query.d.ts.map +1 -0
- package/dist/internal/without-query.js +9 -0
- package/dist/internal/without-query.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 +71 -20
- package/dist/internal/zone-graph.js.map +1 -1
- package/dist/isr.d.ts +59 -3
- package/dist/isr.d.ts.map +1 -1
- package/dist/isr.js +311 -41
- 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 +37 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +4 -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 +9 -1
- package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
- package/dist/plugins/vite-leak-guard.js +84 -7
- package/dist/plugins/vite-leak-guard.js.map +1 -1
- package/dist/plugins/vite-zone-guard.d.ts.map +1 -1
- package/dist/plugins/vite-zone-guard.js +17 -21
- package/dist/plugins/vite-zone-guard.js.map +1 -1
- package/dist/plugins/zone-guard.d.ts.map +1 -1
- package/dist/plugins/zone-guard.js +44 -3
- package/dist/plugins/zone-guard.js.map +1 -1
- package/dist/prerender.d.ts +5 -1
- package/dist/prerender.d.ts.map +1 -1
- package/dist/prerender.js +41 -19
- package/dist/prerender.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 +25 -2
- 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 +47 -50
- package/dist/router.js.map +1 -1
- package/dist/seo.d.ts +49 -0
- package/dist/seo.d.ts.map +1 -0
- package/dist/seo.js +48 -0
- package/dist/seo.js.map +1 -0
- 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 +64 -2
- package/dist/zones.d.ts.map +1 -1
- package/dist/zones.js +331 -28
- package/dist/zones.js.map +1 -1
- package/package.json +102 -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 -17
- package/src/deferred.ts +27 -9
- package/src/dev-feed.ts +24 -5
- package/src/dev-port.ts +4 -10
- 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 +5 -6
- 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/package-entries.ts +331 -0
- package/src/internal/page-execution.ts +573 -114
- package/src/internal/parity.ts +15 -2
- package/src/internal/private-env.ts +27 -13
- package/src/internal/progressive-cookies.ts +60 -0
- package/src/internal/public-env.ts +14 -0
- package/src/internal/render-document.ts +66 -89
- package/src/internal/response-controls.ts +31 -14
- package/src/internal/revive-dates.ts +35 -0
- package/src/internal/route-path.ts +24 -0
- package/src/internal/secret-scan.ts +190 -18
- package/src/internal/server-boundary.ts +29 -5
- package/src/internal/web-app.ts +126 -42
- package/src/internal/wire-date.ts +16 -0
- package/src/internal/without-query.ts +8 -0
- package/src/internal/zone-graph.ts +78 -25
- package/src/isr.ts +364 -45
- package/src/llms-txt.ts +32 -3
- package/src/manifest.ts +38 -4
- package/src/open-resolved.ts +64 -0
- package/src/plugins/kit.ts +31 -11
- package/src/plugins/vite-leak-guard.ts +104 -8
- package/src/plugins/vite-zone-guard.ts +21 -19
- package/src/plugins/zone-guard.ts +41 -2
- package/src/prerender.ts +39 -18
- package/src/public-dir.ts +27 -8
- package/src/query.ts +107 -26
- package/src/render-seam.ts +30 -2
- package/src/route-types.ts +34 -7
- package/src/router.ts +66 -59
- package/src/seo.ts +68 -0
- 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 +418 -32
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NIFRA_BACKEND_BIND_PLATFORM, NIFRA_PLATFORM_CLIENT_IP_DERIVED, } from "@nifrajs/core/mount";
|
|
2
|
-
import { status as statusResult } from "@nifrajs/core/server";
|
|
2
|
+
import { isSameOriginForm, status as statusResult, } from "@nifrajs/core/server";
|
|
3
3
|
import { boundaryDescriptors, resolveStaticBoundaries, startDynamicBoundaries, } from "../boundary.js";
|
|
4
4
|
import { DEFAULT_CSS_LOADING, normalizeCssLoading } from "../css-contract.js";
|
|
5
5
|
import { defer, ndjsonStream, prepareDeferred } from "../deferred.js";
|
|
@@ -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";
|
|
@@ -92,9 +92,12 @@ function appTarget(location, requestUrl) {
|
|
|
92
92
|
catch {
|
|
93
93
|
return location; // the browser fails on it the same way when it loads it
|
|
94
94
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
if (target.origin !== new URL(requestUrl).origin)
|
|
96
|
+
return location;
|
|
97
|
+
// A path starting `//` (from `/.//host`) is a protocol-relative URL to whoever resolves it next.
|
|
98
|
+
return target.pathname.startsWith("//")
|
|
99
|
+
? target.href
|
|
100
|
+
: target.pathname + target.search + target.hash;
|
|
98
101
|
}
|
|
99
102
|
/**
|
|
100
103
|
* Own the page request program behind one private seam.
|
|
@@ -107,6 +110,8 @@ function appTarget(location, requestUrl) {
|
|
|
107
110
|
*/
|
|
108
111
|
export function createPageRequestExecutor(options) {
|
|
109
112
|
const { adapter, manifest, clientEntry, api } = options;
|
|
113
|
+
// The action result is request-local; a browser cannot manufacture this handoff.
|
|
114
|
+
const progressiveActionData = new WeakMap();
|
|
110
115
|
// Bound once per render, so every loader, action and boundary in that render shares one view of the
|
|
111
116
|
// in-process client carrying the visitor's platform. An `api` without the seam passes through as-is.
|
|
112
117
|
const bindApi = platformBinderOf(api);
|
|
@@ -165,9 +170,7 @@ export function createPageRequestExecutor(options) {
|
|
|
165
170
|
return chunks ? { preload: chunks } : {};
|
|
166
171
|
};
|
|
167
172
|
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;
|
|
173
|
+
const stylesFrom = (styles) => {
|
|
171
174
|
if (styles === undefined || styles.length === 0)
|
|
172
175
|
return {};
|
|
173
176
|
return {
|
|
@@ -175,6 +178,7 @@ export function createPageRequestExecutor(options) {
|
|
|
175
178
|
...(cssLoading === "deferred" ? { cssLoading } : {}),
|
|
176
179
|
};
|
|
177
180
|
};
|
|
181
|
+
const stylesOf = (id) => stylesFrom(options.routeStyles?.[id] ?? options.styles);
|
|
178
182
|
// Load a route's layout modules once for the current execution. The render path needs each whole
|
|
179
183
|
// module for its component + meta, while the data path also needs loader/gate/boundary declarations.
|
|
180
184
|
const loadLayoutModules = async (route) => {
|
|
@@ -194,11 +198,49 @@ export function createPageRequestExecutor(options) {
|
|
|
194
198
|
retained: [],
|
|
195
199
|
pending: undefined,
|
|
196
200
|
};
|
|
197
|
-
/**
|
|
198
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Await one gate. A returned redirect, status or Response refuses the request exactly as a thrown
|
|
203
|
+
* one does: stored as layout data it would let the page loader and the action run.
|
|
204
|
+
*/
|
|
205
|
+
const runGate = async (route, index, loader, ctx) => {
|
|
206
|
+
let value;
|
|
207
|
+
try {
|
|
208
|
+
value = await loader(ctx);
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
212
|
+
throw tagLayoutError(err, route.layoutIds[index]);
|
|
213
|
+
}
|
|
214
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
215
|
+
if (isControlFlow(value))
|
|
216
|
+
throw tagLayoutError(value, route.layoutIds[index]);
|
|
217
|
+
return value;
|
|
218
|
+
};
|
|
219
|
+
// Development only. A layout loader that refuses access reads as a guard, and is not one: a client
|
|
220
|
+
// navigation can skip it and an action below it runs without it.
|
|
221
|
+
const warnsUngatedRefusal = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
222
|
+
const warnedUngated = new Set();
|
|
223
|
+
const warnUngatedRefusal = (layoutId, outcome) => {
|
|
224
|
+
if (warnedUngated.has(layoutId))
|
|
225
|
+
return;
|
|
226
|
+
// notFound() and gone() say the record is missing, which a layout may decide without guarding.
|
|
227
|
+
const refusesAccess = isStatusSignal(outcome)
|
|
228
|
+
? outcome.status === 401 || outcome.status === 403
|
|
229
|
+
: isControlFlow(outcome);
|
|
230
|
+
if (!refusesAccess)
|
|
231
|
+
return;
|
|
232
|
+
warnedUngated.add(layoutId);
|
|
233
|
+
const file = manifest.layouts?.[layoutId]?.file ?? layoutId;
|
|
234
|
+
console.warn(`[nifra/web] the loader in "${file}" refused a request, but that layout is not a gate. A client navigation that keeps the layout on screen can skip its loader, and an action below it runs without it, so it does not protect the pages under it. Export \`gate = true\` from that file, or move the check into middleware. (Shown in development only.)`);
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* Run layout loaders, awaiting gates before starting the page loader and retaining only safe data.
|
|
238
|
+
* `gated` carries gates that already ran for this request, so none runs twice.
|
|
239
|
+
*/
|
|
240
|
+
const runLayoutChain = async (route, ctx, controls, retain, gated) => {
|
|
199
241
|
if (route.layoutIds.length === 0)
|
|
200
242
|
return emptyLayoutRun;
|
|
201
|
-
const modules = await loadLayoutModules(route);
|
|
243
|
+
const modules = gated?.modules ?? (await loadLayoutModules(route));
|
|
202
244
|
if (!modules.some((m) => m.loader !== undefined)) {
|
|
203
245
|
return { modules, layoutData: undefined, retained: [], pending: undefined };
|
|
204
246
|
}
|
|
@@ -216,6 +258,7 @@ export function createPageRequestExecutor(options) {
|
|
|
216
258
|
keep = keepsLayoutData(route, i, layout, ctx.params, retain);
|
|
217
259
|
}
|
|
218
260
|
catch (err) {
|
|
261
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
219
262
|
throw tagLayoutError(err, route.layoutIds[i]);
|
|
220
263
|
}
|
|
221
264
|
if (keep) {
|
|
@@ -229,12 +272,7 @@ export function createPageRequestExecutor(options) {
|
|
|
229
272
|
set: controls.scope(i),
|
|
230
273
|
};
|
|
231
274
|
if (modules[i]?.gate === true) {
|
|
232
|
-
|
|
233
|
-
results[i] = await loader(scoped);
|
|
234
|
-
}
|
|
235
|
-
catch (err) {
|
|
236
|
-
throw tagLayoutError(err, route.layoutIds[i]);
|
|
237
|
-
}
|
|
275
|
+
results[i] = gated === undefined ? await runGate(route, i, loader, scoped) : gated.gates[i];
|
|
238
276
|
continue;
|
|
239
277
|
}
|
|
240
278
|
const layoutId = route.layoutIds[i];
|
|
@@ -245,18 +283,31 @@ export function createPageRequestExecutor(options) {
|
|
|
245
283
|
// assimilation: property-presence and prototype probes are unsafe for proxies.
|
|
246
284
|
if (value !== null && (typeof value === "object" || typeof value === "function")) {
|
|
247
285
|
pending.push((async () => {
|
|
286
|
+
let settled;
|
|
248
287
|
try {
|
|
249
|
-
|
|
288
|
+
settled = await value;
|
|
250
289
|
}
|
|
251
290
|
catch (err) {
|
|
291
|
+
if (warnsUngatedRefusal)
|
|
292
|
+
warnUngatedRefusal(layoutId, err);
|
|
252
293
|
throw tagLayoutError(err, layoutId);
|
|
253
294
|
}
|
|
295
|
+
// A returned redirect or Response refuses exactly as a thrown one: kept as layout data,
|
|
296
|
+
// it would ship beside the page loader's data.
|
|
297
|
+
if (isControlFlow(settled)) {
|
|
298
|
+
if (warnsUngatedRefusal)
|
|
299
|
+
warnUngatedRefusal(layoutId, settled);
|
|
300
|
+
throw tagLayoutError(settled, layoutId);
|
|
301
|
+
}
|
|
302
|
+
results[index] = settled;
|
|
254
303
|
})());
|
|
255
304
|
}
|
|
256
305
|
else
|
|
257
306
|
results[index] = value;
|
|
258
307
|
}
|
|
259
308
|
catch (err) {
|
|
309
|
+
if (warnsUngatedRefusal)
|
|
310
|
+
warnUngatedRefusal(layoutId, err);
|
|
260
311
|
// Preserve a synchronous throw as a pending layout failure, just like the async lane.
|
|
261
312
|
pending.push(Promise.reject(tagLayoutError(err, layoutId)));
|
|
262
313
|
}
|
|
@@ -271,22 +322,18 @@ export function createPageRequestExecutor(options) {
|
|
|
271
322
|
/** Run only authorization gates before an action; ordinary layout data runs after a native action. */
|
|
272
323
|
const runLayoutGates = async (route, ctx, controls) => {
|
|
273
324
|
const modules = await loadLayoutModules(route);
|
|
325
|
+
const gates = [];
|
|
274
326
|
for (let i = 0; i < modules.length; i++) {
|
|
275
327
|
const mod = modules[i];
|
|
276
328
|
if (mod?.gate !== true || mod.loader === undefined)
|
|
277
329
|
continue;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
throw tagLayoutError(err, route.layoutIds[i]);
|
|
287
|
-
}
|
|
330
|
+
gates[i] = await runGate(route, i, mod.loader, {
|
|
331
|
+
...ctx,
|
|
332
|
+
params: scopeParams(ctx.params, route.layoutParams?.[i]),
|
|
333
|
+
set: controls.scope(i),
|
|
334
|
+
});
|
|
288
335
|
}
|
|
289
|
-
return modules;
|
|
336
|
+
return { modules, gates };
|
|
290
337
|
};
|
|
291
338
|
/** Outermost first; a failure carries its directory so the nearest `_error` above it renders. */
|
|
292
339
|
const runMiddleware = async (route, ctx, controls) => {
|
|
@@ -400,13 +447,10 @@ export function createPageRequestExecutor(options) {
|
|
|
400
447
|
}
|
|
401
448
|
return mod.HydrateFallback ?? EMPTY_LEAF;
|
|
402
449
|
};
|
|
403
|
-
const resolveChainAndHead = (layoutModules, page, metaArgs, leaf = page.default) => {
|
|
450
|
+
const resolveChainAndHead = (layoutModules, layoutData, page, metaArgs, leaf = page.default) => {
|
|
404
451
|
const chain = [...layoutModules.map((m) => m.default), leaf];
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
resolveMeta(page.meta, metaArgs),
|
|
408
|
-
];
|
|
409
|
-
return { chain, head: mergeHeads(heads) };
|
|
452
|
+
const metas = [...layoutModules.map((m) => m.meta), page.meta];
|
|
453
|
+
return { chain, head: mergeHeads(resolveChainMeta(metas, layoutData, metaArgs)) };
|
|
410
454
|
};
|
|
411
455
|
/** What `useMatches` reports for a chain: the layouts' ids and `handle`s, then the page's. */
|
|
412
456
|
const matchChainOf = (layoutIds, layoutModules, pageId, page) => ({
|
|
@@ -444,34 +488,128 @@ export function createPageRequestExecutor(options) {
|
|
|
444
488
|
return "/";
|
|
445
489
|
}
|
|
446
490
|
};
|
|
447
|
-
|
|
491
|
+
/** What a status or error page's `meta` receives: no route params, and its own data. */
|
|
492
|
+
const statusMetaArgs = (req, data, nonce) => nonce === undefined
|
|
493
|
+
? { data, pageData: data, params: {}, origin: originOf(req) }
|
|
494
|
+
: { data, pageData: data, params: {}, origin: originOf(req), nonce };
|
|
495
|
+
const renderError = async (req, route, errorId, err, personalized, nonce, layouts) => {
|
|
448
496
|
const errDir = dirOfId(errorId, "_error");
|
|
449
497
|
const keptLayoutIds = route.layoutIds.filter((id) => {
|
|
450
498
|
const ld = dirOfId(id, "_layout");
|
|
451
499
|
return ld === "" || ld === errDir || errDir.startsWith(`${ld}/`);
|
|
452
500
|
});
|
|
453
|
-
const
|
|
454
|
-
const { default: errComp } = await (manifest.errors?.[errorId]).load();
|
|
501
|
+
const errorModule = await (manifest.errors?.[errorId]).load();
|
|
455
502
|
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
|
-
|
|
503
|
+
// An error's text can carry a connection string or a query, so only a run that says it is
|
|
504
|
+
// development or test shows it; an unset NODE_ENV (an unbuilt `bun app.ts`) counts as production.
|
|
505
|
+
const nodeEnv = typeof process === "undefined" ? undefined : process.env.NODE_ENV;
|
|
506
|
+
const data = nodeEnv === "development" || nodeEnv === "test"
|
|
507
|
+
? { name: e.name, message: e.message }
|
|
508
|
+
: { name: "Error", message: "Internal Server Error" };
|
|
509
|
+
const inLayouts = errorModule.inLayouts !== false;
|
|
510
|
+
const chain = inLayouts && layouts !== undefined && keptLayoutIds.length > 0
|
|
511
|
+
? await layouts(errorModule, keptLayoutIds.length)
|
|
512
|
+
: undefined;
|
|
513
|
+
const render = (components, wrapped) => {
|
|
514
|
+
const layoutData = wrapped?.chain.layoutData;
|
|
515
|
+
return renderPageResult({
|
|
516
|
+
adapter,
|
|
517
|
+
chain: components,
|
|
518
|
+
data,
|
|
519
|
+
...(wrapped === undefined ? {} : { head: wrapped.head }),
|
|
520
|
+
clientEntry,
|
|
521
|
+
routeId: errorId,
|
|
522
|
+
status: 500,
|
|
523
|
+
hydrate: false,
|
|
524
|
+
...(layoutData === undefined ? {} : { layoutData }),
|
|
525
|
+
...(personalized || layoutData !== undefined ? { headers: PRIVATE_PAGE_HEADERS } : {}),
|
|
526
|
+
...(nonce === undefined ? {} : { nonce }),
|
|
527
|
+
...cspOption,
|
|
528
|
+
...titleOption,
|
|
529
|
+
});
|
|
530
|
+
};
|
|
531
|
+
if (chain !== undefined) {
|
|
532
|
+
const resolved = resolveChainAndHead(chain.modules, chain.layoutData, errorModule, statusMetaArgs(req, data, nonce));
|
|
533
|
+
try {
|
|
534
|
+
return await render(resolved.chain, { head: resolved.head, chain });
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
// A layout that fails to render leaves the error page alone, never a second error.
|
|
538
|
+
return render([errorModule.default]);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
// Layouts whose data did not settle still frame the error page, without their data.
|
|
542
|
+
const layoutComponents = await Promise.all(keptLayoutIds.map((id) => manifest.layouts[id].load().then((m) => m.default)));
|
|
543
|
+
return render([...layoutComponents, errorModule.default]);
|
|
473
544
|
};
|
|
474
|
-
|
|
545
|
+
/** The leading `count` layouts of `modules`, unless one of them answered with a status or redirect. */
|
|
546
|
+
const settledLayouts = (modules, layoutData, count) => {
|
|
547
|
+
if (modules.length < count)
|
|
548
|
+
return undefined;
|
|
549
|
+
const data = layoutData?.slice(0, count);
|
|
550
|
+
if (data?.some((value) => isControlFlow(value) || isStatusSignal(value)))
|
|
551
|
+
return undefined;
|
|
552
|
+
return { modules: modules.slice(0, count), layoutData: data };
|
|
553
|
+
};
|
|
554
|
+
/** A run's leading layouts once all of its loaders settle - never when a layout or middleware refused. */
|
|
555
|
+
const leadingLayouts = (run, err) => async (_page, count) => {
|
|
556
|
+
if (run === undefined || (err !== undefined && layoutErrorId(err) !== undefined)) {
|
|
557
|
+
return undefined;
|
|
558
|
+
}
|
|
559
|
+
try {
|
|
560
|
+
await run.pending;
|
|
561
|
+
}
|
|
562
|
+
catch {
|
|
563
|
+
return undefined;
|
|
564
|
+
}
|
|
565
|
+
return settledLayouts(run.modules, run.layoutData, count);
|
|
566
|
+
};
|
|
567
|
+
const rootLayoutIds = manifest.layouts._layout === undefined ? [] : ["_layout"];
|
|
568
|
+
const rootMiddlewareIds = manifest.middlewares?._middleware === undefined ? [] : ["_middleware"];
|
|
569
|
+
/**
|
|
570
|
+
* Run the root middleware and layouts for a request no route ran them for (an unmatched URL), as a
|
|
571
|
+
* nested `_404` runs its own. Any refusal or failure renders the page alone.
|
|
572
|
+
*/
|
|
573
|
+
const rootLayoutsFor = (c, controls) => async (page) => {
|
|
574
|
+
const entry = manifest.statusPages?.["404"] ?? manifest.notFound;
|
|
575
|
+
if (rootLayoutIds.length === 0 || entry === undefined)
|
|
576
|
+
return undefined;
|
|
577
|
+
const layoutsOnly = {
|
|
578
|
+
id: "_404",
|
|
579
|
+
pattern: "/*",
|
|
580
|
+
layoutIds: rootLayoutIds,
|
|
581
|
+
errorIds: [],
|
|
582
|
+
file: entry.file,
|
|
583
|
+
load: entry.load,
|
|
584
|
+
};
|
|
585
|
+
const route = rootMiddlewareIds.length === 0
|
|
586
|
+
? layoutsOnly
|
|
587
|
+
: { ...layoutsOnly, middlewareIds: rootMiddlewareIds };
|
|
588
|
+
try {
|
|
589
|
+
const draft = await draftFlag(c.req);
|
|
590
|
+
if (draft)
|
|
591
|
+
controls.personalize();
|
|
592
|
+
const ctx = {
|
|
593
|
+
params: {},
|
|
594
|
+
request: c.req,
|
|
595
|
+
req: c.req,
|
|
596
|
+
api: apiFor(c),
|
|
597
|
+
env: c.env,
|
|
598
|
+
draft,
|
|
599
|
+
search: loaderSearch(page.searchSchema, c.req),
|
|
600
|
+
set: controls.scope(PAGE_SCOPE),
|
|
601
|
+
};
|
|
602
|
+
if (route.middlewareIds !== undefined)
|
|
603
|
+
await runMiddleware(route, ctx, controls);
|
|
604
|
+
const run = await runLayoutChain(route, ctx, controls);
|
|
605
|
+
await run.pending;
|
|
606
|
+
return settledLayouts(run.modules, run.layoutData, rootLayoutIds.length);
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
const renderTerminalStatus = async (status, req, extraHeaders, nonce, layouts) => {
|
|
475
613
|
const page = manifest.statusPages?.[String(status)] ?? manifest.notFound;
|
|
476
614
|
if (page === undefined) {
|
|
477
615
|
const headers = new Headers(extraHeaders);
|
|
@@ -479,31 +617,55 @@ export function createPageRequestExecutor(options) {
|
|
|
479
617
|
return new Response(STATUS_TEXT[status] ?? "Error", { status, headers });
|
|
480
618
|
}
|
|
481
619
|
const routeId = manifest.statusPages?.[String(status)] !== undefined ? `_${status}` : "_404";
|
|
482
|
-
const loaded =
|
|
483
|
-
|
|
620
|
+
const loaded = await page.load();
|
|
621
|
+
const wraps = loaded.inLayouts !== false && rootLayoutIds.length > 0;
|
|
622
|
+
const chain = wraps && layouts !== undefined ? await layouts(loaded, rootLayoutIds.length) : undefined;
|
|
623
|
+
const modules = chain?.modules ?? [];
|
|
624
|
+
const layoutIds = chain === undefined ? [] : rootLayoutIds;
|
|
625
|
+
const layoutData = chain?.layoutData;
|
|
626
|
+
const { chain: components, head } = resolveChainAndHead(modules, layoutData, loaded, statusMetaArgs(req, null, nonce));
|
|
627
|
+
let headers = extraHeaders;
|
|
628
|
+
if (layoutData !== undefined) {
|
|
629
|
+
// The page now shows what a layout loaded for this visitor.
|
|
630
|
+
const privateHeaders = new Headers(extraHeaders);
|
|
631
|
+
privateHeaders.set("cache-control", PRIVATE_NO_STORE);
|
|
632
|
+
headers = privateHeaders;
|
|
633
|
+
}
|
|
634
|
+
const statusPage = {
|
|
484
635
|
adapter,
|
|
485
|
-
chain:
|
|
636
|
+
chain: components,
|
|
486
637
|
data: null,
|
|
638
|
+
head,
|
|
487
639
|
clientEntry,
|
|
488
640
|
routeId,
|
|
489
|
-
matchChain:
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
search: searchOf(loaded.searchSchema, path.includes("?") ? path.slice(path.indexOf("?")) : ""),
|
|
493
|
-
}
|
|
494
|
-
: {}),
|
|
495
|
-
...(path !== undefined ? { path } : {}),
|
|
641
|
+
matchChain: matchChainOf(layoutIds, modules, routeId, loaded),
|
|
642
|
+
search: searchChainOf(modules, loaded, req),
|
|
643
|
+
path: pathOf(req),
|
|
496
644
|
status,
|
|
497
|
-
|
|
645
|
+
// The browser renders this page inside the root layout, so a page that had to render alone
|
|
646
|
+
// stays server-only, as a nested `_404` does.
|
|
647
|
+
...(wraps && chain === undefined ? { hydrate: false } : {}),
|
|
648
|
+
...(layoutData === undefined ? {} : { layoutData }),
|
|
649
|
+
...(headers !== undefined ? { headers } : {}),
|
|
498
650
|
...(nonce === undefined ? {} : { nonce }),
|
|
499
651
|
...cspOption,
|
|
500
652
|
...preloadOf(routeId),
|
|
501
|
-
|
|
653
|
+
// The build keys stylesheets by route, so a page inside the root layout links the whole-app one.
|
|
654
|
+
...(chain === undefined ? stylesOf(routeId) : stylesFrom(options.styles)),
|
|
502
655
|
...prerenderedHandover,
|
|
503
656
|
...titleOption,
|
|
504
|
-
}
|
|
657
|
+
};
|
|
658
|
+
if (chain === undefined)
|
|
659
|
+
return renderPageResult(statusPage);
|
|
660
|
+
try {
|
|
661
|
+
return await renderPageResult(statusPage);
|
|
662
|
+
}
|
|
663
|
+
catch {
|
|
664
|
+
// A layout that fails to render leaves the status page alone, never a second error.
|
|
665
|
+
return renderTerminalStatus(status, req, extraHeaders, nonce);
|
|
666
|
+
}
|
|
505
667
|
};
|
|
506
|
-
const renderStatusSignal = async (req, env, signal, personalized) => {
|
|
668
|
+
const renderStatusSignal = async (req, env, signal, personalized, layouts) => {
|
|
507
669
|
const { status, headers } = signal[STATUS_SIGNAL];
|
|
508
670
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
509
671
|
// Same URL as the status page, so it is never storable: a cache keyed on the URL alone would
|
|
@@ -516,7 +678,7 @@ export function createPageRequestExecutor(options) {
|
|
|
516
678
|
}
|
|
517
679
|
const nonce = await resolveNonce(req, env);
|
|
518
680
|
if (headers === undefined && !personalized) {
|
|
519
|
-
return renderTerminalStatus(status,
|
|
681
|
+
return renderTerminalStatus(status, req, undefined, nonce, layouts);
|
|
520
682
|
}
|
|
521
683
|
const documentHeaders = new Headers(headers);
|
|
522
684
|
if (headers !== undefined) {
|
|
@@ -525,7 +687,7 @@ export function createPageRequestExecutor(options) {
|
|
|
525
687
|
// A cookie queued before the signal makes the status page specific to this visitor.
|
|
526
688
|
if (personalized)
|
|
527
689
|
documentHeaders.set("cache-control", PRIVATE_NO_STORE);
|
|
528
|
-
return renderTerminalStatus(status,
|
|
690
|
+
return renderTerminalStatus(status, req, documentHeaders, nonce, layouts);
|
|
529
691
|
};
|
|
530
692
|
const reportLoaderError = (route, req, params, err) => {
|
|
531
693
|
if (options.onLoaderError === undefined)
|
|
@@ -537,9 +699,11 @@ export function createPageRequestExecutor(options) {
|
|
|
537
699
|
// A faulty reporter must never break error rendering.
|
|
538
700
|
}
|
|
539
701
|
};
|
|
540
|
-
const handleDataOrDocument = async (req, env, route, params, mod, data, layoutData, layoutModules, layoutRetained, boundaryStates, assemblyCache, responseHeaders, personalized) => {
|
|
702
|
+
const handleDataOrDocument = async (req, env, route, params, mod, data, layoutData, layoutModules, layoutRetained, boundaryStates, assemblyCache, responseHeaders, personalized, serverComponents) => {
|
|
703
|
+
// Every layout loader settled before the page rendered, so a status or error page can reuse them.
|
|
704
|
+
const settled = async (_page, count) => settledLayouts(layoutModules, layoutData, count);
|
|
541
705
|
if (isStatusSignal(data))
|
|
542
|
-
return renderStatusSignal(req, env, data, personalized);
|
|
706
|
+
return renderStatusSignal(req, env, data, personalized, settled);
|
|
543
707
|
if (isControlFlow(data))
|
|
544
708
|
return data;
|
|
545
709
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
@@ -557,7 +721,7 @@ export function createPageRequestExecutor(options) {
|
|
|
557
721
|
...deferred,
|
|
558
722
|
...(boundarySplit === undefined ? [] : boundarySplit.deferred),
|
|
559
723
|
];
|
|
560
|
-
const payload = layoutData === undefined && boundarySplit === undefined
|
|
724
|
+
const payload = layoutData === undefined && boundarySplit === undefined && serverComponents === undefined
|
|
561
725
|
? pageSplit.forClient
|
|
562
726
|
: {
|
|
563
727
|
v: 1,
|
|
@@ -565,6 +729,7 @@ export function createPageRequestExecutor(options) {
|
|
|
565
729
|
layoutData: layoutSplits.map((split) => split.forClient),
|
|
566
730
|
retained: layoutRetained,
|
|
567
731
|
...(boundarySplit === undefined ? {} : { boundaries: boundarySplit.forClient }),
|
|
732
|
+
...(serverComponents === undefined ? {} : { serverComponents }),
|
|
568
733
|
};
|
|
569
734
|
if (allDeferred.length === 0) {
|
|
570
735
|
return Response.json(payload ?? null, { headers: DATA_RESPONSE_HEADERS });
|
|
@@ -577,8 +742,9 @@ export function createPageRequestExecutor(options) {
|
|
|
577
742
|
});
|
|
578
743
|
}
|
|
579
744
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(req, env);
|
|
580
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
745
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
581
746
|
data,
|
|
747
|
+
pageData: data,
|
|
582
748
|
params,
|
|
583
749
|
origin: originOf(req),
|
|
584
750
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -595,6 +761,8 @@ export function createPageRequestExecutor(options) {
|
|
|
595
761
|
path: pathOf(req),
|
|
596
762
|
search: searchChainOf(layoutModules, mod, req),
|
|
597
763
|
matchChain: matchChainOf(route.layoutIds, layoutModules, route.id, mod),
|
|
764
|
+
...(serverComponents === undefined ? {} : { serverComponents }),
|
|
765
|
+
...(progressiveActionData.has(req) ? { actionData: progressiveActionData.get(req) } : {}),
|
|
598
766
|
hydrate: mod.hydrate !== false,
|
|
599
767
|
...(layoutData !== undefined ? { layoutData } : {}),
|
|
600
768
|
...(boundaryStates !== undefined ? { boundaries: boundaryStates } : {}),
|
|
@@ -622,31 +790,33 @@ export function createPageRequestExecutor(options) {
|
|
|
622
790
|
}
|
|
623
791
|
catch (err) {
|
|
624
792
|
if (isStatusSignal(err))
|
|
625
|
-
return renderStatusSignal(req, env, err, personalized);
|
|
793
|
+
return renderStatusSignal(req, env, err, personalized, settled);
|
|
626
794
|
if (isControlFlow(err))
|
|
627
795
|
throw err;
|
|
628
796
|
reportLoaderError(route, req, { ...params }, err);
|
|
629
797
|
const errorId = boundaryFor(route, err);
|
|
630
798
|
if (errorId === undefined)
|
|
631
799
|
throw err;
|
|
632
|
-
|
|
800
|
+
options.logBoundaryError?.(err, req);
|
|
801
|
+
return renderError(req, route, errorId, withDuplicateInstanceHint(err), personalized, nonce, settled);
|
|
633
802
|
}
|
|
634
803
|
};
|
|
635
804
|
/** What a failed loader answers with, once a status signal has been ruled out. */
|
|
636
|
-
const renderLoaderFailure = async (route, req, env, params, err, personalized) => {
|
|
805
|
+
const renderLoaderFailure = async (route, req, env, params, err, personalized, layouts) => {
|
|
637
806
|
if (isControlFlow(err))
|
|
638
807
|
throw err;
|
|
639
808
|
reportLoaderError(route, req, params, err);
|
|
640
809
|
const errorId = boundaryFor(route, err);
|
|
641
810
|
if (errorId === undefined)
|
|
642
811
|
throw err;
|
|
812
|
+
options.logBoundaryError?.(err, req);
|
|
643
813
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
644
814
|
return new Response("Internal Server Error", {
|
|
645
815
|
status: 500,
|
|
646
816
|
headers: { "content-type": "text/plain; charset=utf-8" },
|
|
647
817
|
});
|
|
648
818
|
}
|
|
649
|
-
return renderError(route, errorId, withDuplicateInstanceHint(err), personalized, options.nonce === undefined ? undefined : await resolveNonce(req, env));
|
|
819
|
+
return renderError(req, route, errorId, withDuplicateInstanceHint(err), personalized, options.nonce === undefined ? undefined : await resolveNonce(req, env), layouts);
|
|
650
820
|
};
|
|
651
821
|
/**
|
|
652
822
|
* Render a nested `_404` inside its layouts. `layoutModules` and `layoutData` are exactly the
|
|
@@ -665,8 +835,9 @@ export function createPageRequestExecutor(options) {
|
|
|
665
835
|
}
|
|
666
836
|
const mod = await page.load();
|
|
667
837
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(req, env);
|
|
668
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
838
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
669
839
|
data: null,
|
|
840
|
+
pageData: null,
|
|
670
841
|
params,
|
|
671
842
|
origin: originOf(req),
|
|
672
843
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -721,11 +892,11 @@ export function createPageRequestExecutor(options) {
|
|
|
721
892
|
const kept = page.layoutIds.length;
|
|
722
893
|
return renderNestedNotFound(req, env, id, page, params, run.modules.slice(0, kept), run.layoutData?.slice(0, kept), personalized, signal[STATUS_SIGNAL].headers);
|
|
723
894
|
};
|
|
724
|
-
const renderNotFound = async (
|
|
895
|
+
const renderNotFound = async (c, controls) => {
|
|
725
896
|
const page = manifest.statusPages?.["404"] ?? manifest.notFound;
|
|
726
897
|
if (page === undefined)
|
|
727
|
-
return renderTerminalStatus(404,
|
|
728
|
-
return renderTerminalStatus(404,
|
|
898
|
+
return renderTerminalStatus(404, c.req);
|
|
899
|
+
return renderTerminalStatus(404, c.req, undefined, options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env), rootLayoutsFor(c, controls));
|
|
729
900
|
};
|
|
730
901
|
/**
|
|
731
902
|
* Run a page handler with the request's `ctx.set`, sealed once the handler settles - whatever it
|
|
@@ -779,8 +950,19 @@ export function createPageRequestExecutor(options) {
|
|
|
779
950
|
return assemblySlot;
|
|
780
951
|
};
|
|
781
952
|
return withResponseControls(async (c, controls) => {
|
|
782
|
-
|
|
783
|
-
|
|
953
|
+
const componentRuntime = options.serverComponents;
|
|
954
|
+
const componentOwner = componentRuntime?.owns(route.id) === true;
|
|
955
|
+
let componentRequest;
|
|
956
|
+
try {
|
|
957
|
+
componentRequest = componentRuntime?.classify(c.req, route.id);
|
|
958
|
+
}
|
|
959
|
+
catch (error) {
|
|
960
|
+
return componentRuntime.failure(error);
|
|
961
|
+
}
|
|
962
|
+
if (componentOwner || componentRequest !== undefined)
|
|
963
|
+
controls.personalize();
|
|
964
|
+
if (!componentOwner && is404Fallback && !prerenderedSet.has(urlPartsFor(c.req).pathname)) {
|
|
965
|
+
return renderNotFound(c, controls);
|
|
784
966
|
}
|
|
785
967
|
const mod = await route.load();
|
|
786
968
|
const draft = await draftFlag(c.req);
|
|
@@ -793,6 +975,7 @@ export function createPageRequestExecutor(options) {
|
|
|
793
975
|
let layoutModules;
|
|
794
976
|
let layoutRetained = [];
|
|
795
977
|
let responseHeaders;
|
|
978
|
+
let componentState;
|
|
796
979
|
const requestApi = apiFor(c);
|
|
797
980
|
let run;
|
|
798
981
|
try {
|
|
@@ -808,13 +991,15 @@ export function createPageRequestExecutor(options) {
|
|
|
808
991
|
};
|
|
809
992
|
if (route.middlewareIds !== undefined)
|
|
810
993
|
await runMiddleware(route, ctx, controls);
|
|
811
|
-
run = await runLayoutChain(route, ctx, controls, retainContextOf(c.req));
|
|
994
|
+
run = await runLayoutChain(route, ctx, controls, componentOwner ? undefined : retainContextOf(c.req));
|
|
812
995
|
layoutModules = run.modules;
|
|
813
996
|
layoutRetained = run.retained;
|
|
814
|
-
const boundaryDefinitions =
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
997
|
+
const boundaryDefinitions = componentRequest === undefined
|
|
998
|
+
? [
|
|
999
|
+
...run.modules.flatMap((layout) => layout.boundaries ?? []),
|
|
1000
|
+
...(mod.boundaries ?? []),
|
|
1001
|
+
]
|
|
1002
|
+
: [];
|
|
818
1003
|
if (boundaryDefinitions.length > 0)
|
|
819
1004
|
boundaryDescriptors(boundaryDefinitions);
|
|
820
1005
|
const effectiveSearch = searchChainOf(run.modules, mod, c.req);
|
|
@@ -840,6 +1025,25 @@ export function createPageRequestExecutor(options) {
|
|
|
840
1025
|
: await Promise.all([pageResult, run.pending, staticBoundaryPromise]);
|
|
841
1026
|
data = pageData;
|
|
842
1027
|
layoutData = run.layoutData;
|
|
1028
|
+
if (componentOwner) {
|
|
1029
|
+
for (let i = 0; i < (layoutData?.length ?? 0); i++) {
|
|
1030
|
+
const outcome = layoutData?.[i];
|
|
1031
|
+
if (isControlFlow(outcome) || isStatusSignal(outcome))
|
|
1032
|
+
throw tagLayoutError(outcome, route.layoutIds[i]);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
if (componentRequest !== undefined && (isControlFlow(data) || isStatusSignal(data)))
|
|
1036
|
+
return componentRuntime.failure(data);
|
|
1037
|
+
if (componentOwner && !isControlFlow(data) && !isStatusSignal(data)) {
|
|
1038
|
+
const componentContext = Object.create(c, Object.getOwnPropertyDescriptors({
|
|
1039
|
+
...ctx,
|
|
1040
|
+
search: effectiveSearch,
|
|
1041
|
+
signal: c.signal === undefined ? c.req.signal : AbortSignal.any([c.signal, c.req.signal]),
|
|
1042
|
+
data,
|
|
1043
|
+
layoutData: layoutData ?? [],
|
|
1044
|
+
}));
|
|
1045
|
+
componentState = await componentRuntime.execute(route.id, componentContext, componentRequest, options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env));
|
|
1046
|
+
}
|
|
843
1047
|
if (boundaryBatch !== undefined) {
|
|
844
1048
|
const streamed = { ...boundaryBatch.initial, ...(staticBoundaries ?? {}) };
|
|
845
1049
|
for (const entry of boundaryBatch.pending) {
|
|
@@ -857,17 +1061,28 @@ export function createPageRequestExecutor(options) {
|
|
|
857
1061
|
responseHeaders = controls.documentHeaders();
|
|
858
1062
|
}
|
|
859
1063
|
catch (err) {
|
|
1064
|
+
if (componentRequest !== undefined)
|
|
1065
|
+
return componentRuntime.failure(err);
|
|
860
1066
|
if (isStatusSignal(err)) {
|
|
861
|
-
return ((await renderRouteNotFound(c.req, c.env, route, c.params, err, run, controls.personalized)) ??
|
|
1067
|
+
return ((await renderRouteNotFound(c.req, c.env, route, c.params, err, run, controls.personalized)) ??
|
|
1068
|
+
renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err)));
|
|
862
1069
|
}
|
|
863
|
-
return renderLoaderFailure(route, c.req, c.env, c.params, err, controls.personalized);
|
|
1070
|
+
return renderLoaderFailure(route, c.req, c.env, c.params, err, controls.personalized, leadingLayouts(run, err));
|
|
1071
|
+
}
|
|
1072
|
+
if (componentRequest !== undefined && componentState !== undefined) {
|
|
1073
|
+
const answer = componentRuntime.response(componentState, componentRequest);
|
|
1074
|
+
const headers = new Headers(answer.headers);
|
|
1075
|
+
for (const [name, value] of Object.entries(responseHeaders ?? {}))
|
|
1076
|
+
if (name !== "cache-control" && name !== "content-type" && name !== "vary")
|
|
1077
|
+
headers.set(name, value);
|
|
1078
|
+
return new Response(answer.body, { status: answer.status, headers });
|
|
864
1079
|
}
|
|
865
1080
|
if (isStatusSignal(data)) {
|
|
866
1081
|
const nested = await renderRouteNotFound(c.req, c.env, route, c.params, data, run, controls.personalized);
|
|
867
1082
|
if (nested !== undefined)
|
|
868
1083
|
return nested;
|
|
869
1084
|
}
|
|
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);
|
|
1085
|
+
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
1086
|
});
|
|
872
1087
|
},
|
|
873
1088
|
post: (route) => withResponseControls(async (c, controls) => {
|
|
@@ -881,6 +1096,28 @@ export function createPageRequestExecutor(options) {
|
|
|
881
1096
|
headers: { allow: "GET", "content-type": "text/plain; charset=utf-8" },
|
|
882
1097
|
});
|
|
883
1098
|
}
|
|
1099
|
+
const isDataRequest = c.req.headers.get(DATA_HEADER) !== null;
|
|
1100
|
+
// Before anything runs: a form posts cross-site without a preflight and carries the visitor's
|
|
1101
|
+
// cookies, so an action is a CSRF target unless its route names the origins it accepts.
|
|
1102
|
+
const origin = c.req.headers.get("origin");
|
|
1103
|
+
const allowedOrigins = mod.allowedOrigins;
|
|
1104
|
+
const allowed = allowedOrigins === undefined
|
|
1105
|
+
? origin === null ||
|
|
1106
|
+
isSameOriginForm(origin, c.req.headers.get("sec-fetch-site"), c.req)
|
|
1107
|
+
: typeof allowedOrigins === "function"
|
|
1108
|
+
? allowedOrigins(origin) === true
|
|
1109
|
+
: origin !== null && allowedOrigins.includes(origin);
|
|
1110
|
+
if (!allowed) {
|
|
1111
|
+
return isDataRequest
|
|
1112
|
+
? Response.json({ ok: false, error: "forbidden_origin" }, { status: 403, headers: { "cache-control": PRIVATE_NO_STORE } })
|
|
1113
|
+
: new Response("Forbidden", {
|
|
1114
|
+
status: 403,
|
|
1115
|
+
headers: {
|
|
1116
|
+
"content-type": "text/plain; charset=utf-8",
|
|
1117
|
+
"cache-control": PRIVATE_NO_STORE,
|
|
1118
|
+
},
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
884
1121
|
const requestApi = apiFor(c);
|
|
885
1122
|
const actionContext = {
|
|
886
1123
|
params: c.params,
|
|
@@ -892,13 +1129,12 @@ export function createPageRequestExecutor(options) {
|
|
|
892
1129
|
search: loaderSearch(mod.searchSchema, c.req),
|
|
893
1130
|
set: controls.scope(ACTION_SCOPE),
|
|
894
1131
|
};
|
|
895
|
-
|
|
896
|
-
let layoutModules;
|
|
1132
|
+
let gated;
|
|
897
1133
|
let result;
|
|
898
1134
|
try {
|
|
899
1135
|
if (route.middlewareIds !== undefined)
|
|
900
1136
|
await runMiddleware(route, actionContext, controls);
|
|
901
|
-
|
|
1137
|
+
gated = await runLayoutGates(route, actionContext, controls);
|
|
902
1138
|
result = await mod.action(actionContext);
|
|
903
1139
|
}
|
|
904
1140
|
catch (err) {
|
|
@@ -933,23 +1169,109 @@ export function createPageRequestExecutor(options) {
|
|
|
933
1169
|
},
|
|
934
1170
|
});
|
|
935
1171
|
}
|
|
1172
|
+
if (options.serverComponents?.owns(route.id)) {
|
|
1173
|
+
if (options.rerenderOwnerGET === undefined)
|
|
1174
|
+
throw new Error("component_contract");
|
|
1175
|
+
const actionHeaders = controls.documentHeaders();
|
|
1176
|
+
if (controls.progressiveRedirect(c.req)) {
|
|
1177
|
+
// Relative, so a browser behind a TLS terminator stays on its own scheme. A `//` path
|
|
1178
|
+
// would read as another host, so that one keeps the absolute URL.
|
|
1179
|
+
const { pathname, search } = new URL(c.req.url);
|
|
1180
|
+
const location = pathname.startsWith("//") ? c.req.url : pathname + search;
|
|
1181
|
+
return new Response(null, {
|
|
1182
|
+
status: 303,
|
|
1183
|
+
headers: { ...actionHeaders, location, "cache-control": PRIVATE_NO_STORE },
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
const headers = new Headers(c.req.headers);
|
|
1187
|
+
for (const name of [
|
|
1188
|
+
DATA_HEADER,
|
|
1189
|
+
RETAIN_HEADER,
|
|
1190
|
+
NAV_FROM_HEADER,
|
|
1191
|
+
"x-nifra-component",
|
|
1192
|
+
"content-type",
|
|
1193
|
+
"content-length",
|
|
1194
|
+
"transfer-encoding",
|
|
1195
|
+
])
|
|
1196
|
+
headers.delete(name);
|
|
1197
|
+
const cookie = controls.progressiveCookies(c.req);
|
|
1198
|
+
if (cookie)
|
|
1199
|
+
headers.set("cookie", cookie);
|
|
1200
|
+
else
|
|
1201
|
+
headers.delete("cookie");
|
|
1202
|
+
const request = new Request(c.req.url, {
|
|
1203
|
+
method: "GET",
|
|
1204
|
+
headers,
|
|
1205
|
+
signal: c.signal === undefined ? c.req.signal : AbortSignal.any([c.signal, c.req.signal]),
|
|
1206
|
+
});
|
|
1207
|
+
progressiveActionData.set(request, actionResult);
|
|
1208
|
+
try {
|
|
1209
|
+
const response = await options.rerenderOwnerGET(request, c);
|
|
1210
|
+
const merged = new Headers(response.headers);
|
|
1211
|
+
for (const [name, value] of Object.entries(actionHeaders ?? {}))
|
|
1212
|
+
if (!merged.has(name))
|
|
1213
|
+
merged.set(name, value);
|
|
1214
|
+
merged.set("cache-control", PRIVATE_NO_STORE);
|
|
1215
|
+
return new Response(response.body, {
|
|
1216
|
+
status: response.status,
|
|
1217
|
+
statusText: response.statusText,
|
|
1218
|
+
headers: merged,
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
finally {
|
|
1222
|
+
progressiveActionData.delete(request);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
const layoutModules = gated.modules;
|
|
936
1226
|
const search = searchChainOf(layoutModules, mod, c.req);
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1227
|
+
let run;
|
|
1228
|
+
let data;
|
|
1229
|
+
let responseHeaders;
|
|
1230
|
+
// The ordinary layout loaders run now, after the mutation, as a GET of this page would.
|
|
1231
|
+
try {
|
|
1232
|
+
run = await runLayoutChain(route, actionContext, controls, undefined, gated);
|
|
1233
|
+
const pageResult = mod.loader
|
|
1234
|
+
? mod.loader({
|
|
1235
|
+
params: c.params,
|
|
1236
|
+
request: c.req,
|
|
1237
|
+
req: c.req,
|
|
1238
|
+
api: requestApi,
|
|
1239
|
+
env: c.env,
|
|
1240
|
+
draft,
|
|
1241
|
+
search,
|
|
1242
|
+
set: controls.scope(PAGE_SCOPE),
|
|
1243
|
+
})
|
|
1244
|
+
: null;
|
|
1245
|
+
const [pageData] = run.pending === undefined
|
|
1246
|
+
? [await pageResult]
|
|
1247
|
+
: await Promise.all([pageResult, run.pending]);
|
|
1248
|
+
data = pageData;
|
|
1249
|
+
responseHeaders = controls.documentHeaders();
|
|
1250
|
+
}
|
|
1251
|
+
catch (err) {
|
|
1252
|
+
if (isStatusSignal(err)) {
|
|
1253
|
+
return ((await renderRouteNotFound(c.req, c.env, route, c.params, err, run, controls.personalized)) ??
|
|
1254
|
+
renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err)));
|
|
1255
|
+
}
|
|
1256
|
+
return renderLoaderFailure(route, c.req, c.env, c.params, err, controls.personalized, leadingLayouts(run, err));
|
|
1257
|
+
}
|
|
1258
|
+
// The re-render answers a returned redirect or status the way the page's GET does.
|
|
1259
|
+
if (isStatusSignal(data))
|
|
1260
|
+
return ((await renderRouteNotFound(c.req, c.env, route, c.params, data, run, controls.personalized)) ??
|
|
1261
|
+
renderStatusSignal(c.req, c.env, data, controls.personalized, leadingLayouts(run, data)));
|
|
1262
|
+
if (isControlFlow(data))
|
|
1263
|
+
return data;
|
|
1264
|
+
const layoutData = run.layoutData;
|
|
1265
|
+
const layoutProps = {};
|
|
1266
|
+
if (layoutData !== undefined) {
|
|
1267
|
+
layoutProps.layoutData = layoutData;
|
|
1268
|
+
// The page now shows what a layout loaded for this visitor.
|
|
1269
|
+
responseHeaders = { ...responseHeaders, ...PRIVATE_PAGE_HEADERS };
|
|
1270
|
+
}
|
|
950
1271
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env);
|
|
951
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
1272
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
952
1273
|
data,
|
|
1274
|
+
pageData: data,
|
|
953
1275
|
params: c.params,
|
|
954
1276
|
origin: originOf(c.req),
|
|
955
1277
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -967,6 +1289,7 @@ export function createPageRequestExecutor(options) {
|
|
|
967
1289
|
search,
|
|
968
1290
|
matchChain: matchChainOf(route.layoutIds, layoutModules, route.id, mod),
|
|
969
1291
|
hydrate: mod.hydrate !== false,
|
|
1292
|
+
...layoutProps,
|
|
970
1293
|
...preloadOf(route.id),
|
|
971
1294
|
...stylesOf(route.id),
|
|
972
1295
|
...prerenderedHandover,
|
|
@@ -980,7 +1303,7 @@ export function createPageRequestExecutor(options) {
|
|
|
980
1303
|
const match = matchNotFoundScope?.(pathOf(c.req)) ?? null;
|
|
981
1304
|
const target = match === null ? undefined : notFoundTargets[Number(match.routeId)];
|
|
982
1305
|
if (match === null || target === undefined) {
|
|
983
|
-
return renderNotFound(c
|
|
1306
|
+
return renderNotFound(c, controls);
|
|
984
1307
|
}
|
|
985
1308
|
const params = {};
|
|
986
1309
|
for (let i = 0; i < target.names.length; i++) {
|
|
@@ -1010,9 +1333,9 @@ export function createPageRequestExecutor(options) {
|
|
|
1010
1333
|
}
|
|
1011
1334
|
catch (err) {
|
|
1012
1335
|
if (isStatusSignal(err)) {
|
|
1013
|
-
return renderStatusSignal(c.req, c.env, err, controls.personalized);
|
|
1336
|
+
return renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err));
|
|
1014
1337
|
}
|
|
1015
|
-
return renderLoaderFailure(target.route, c.req, c.env, params, err, controls.personalized);
|
|
1338
|
+
return renderLoaderFailure(target.route, c.req, c.env, params, err, controls.personalized, leadingLayouts(run, err));
|
|
1016
1339
|
}
|
|
1017
1340
|
return renderNestedNotFound(c.req, c.env, target.id, target.page, params, run.modules, run.layoutData, controls.personalized);
|
|
1018
1341
|
}),
|