@timber-js/app 0.2.0-alpha.208 → 0.2.0-alpha.209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{primitives-DLAnvsrk.js → actions-BerlqoXA.js} +640 -410
- package/dist/_chunks/actions-BerlqoXA.js.map +1 -0
- package/dist/_chunks/{als-registry-C6kcfprT.js → als-registry-DaxkVjt5.js} +6 -2
- package/dist/_chunks/als-registry-DaxkVjt5.js.map +1 -0
- package/dist/_chunks/{build-manifest-DTmSGLRz.js → build-manifest-DWppEdLB.js} +2 -51
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/{build-output-helper-9dqCv1pZ.js → build-output-helper-RV_BRcF1.js} +50 -53
- package/dist/_chunks/build-output-helper-RV_BRcF1.js.map +1 -0
- package/dist/_chunks/{cache-api-CUD9Ezaq.js → cache-api-CR23J_NC.js} +64 -32
- package/dist/_chunks/cache-api-CR23J_NC.js.map +1 -0
- package/dist/_chunks/{chains-B4bgOl2g.js → chains-CpFg56UB.js} +2 -2
- package/dist/_chunks/{chains-B4bgOl2g.js.map → chains-CpFg56UB.js.map} +1 -1
- package/dist/_chunks/{cli-check-G8o30ldg.js → cli-check-C6Ev6wBO.js} +11 -52
- package/dist/_chunks/cli-check-C6Ev6wBO.js.map +1 -0
- package/dist/_chunks/cli-context-By7k2xVo.js +70 -0
- package/dist/_chunks/cli-context-By7k2xVo.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js → cli-schema-sync-CbT2AUUI.js} +3 -3
- package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js.map → cli-schema-sync-CbT2AUUI.js.map} +1 -1
- package/dist/_chunks/{cloudflare-BFb__LYG.js → cloudflare-Byxl8FWP.js} +96 -53
- package/dist/_chunks/{cloudflare-BFb__LYG.js.map → cloudflare-Byxl8FWP.js.map} +1 -1
- package/dist/_chunks/{convention-lint-5KzoMg_A.js → convention-lint-jKTwKwPe.js} +21 -6
- package/dist/_chunks/convention-lint-jKTwKwPe.js.map +1 -0
- package/dist/_chunks/{dev-server-BzBxgYAV.js → dev-server-C4WZdB7L.js} +15 -167
- package/dist/_chunks/dev-server-C4WZdB7L.js.map +1 -0
- package/dist/_chunks/{error-boundary-BrHmG-2X.js → error-boundary-tA7kVfs4.js} +84 -104
- package/dist/_chunks/error-boundary-tA7kVfs4.js.map +1 -0
- package/dist/_chunks/{fs-identity-D7vb6GdI.js → fs-identity-BRKuL215.js} +3 -4
- package/dist/_chunks/fs-identity-BRKuL215.js.map +1 -0
- package/dist/_chunks/{graph-cache-CP4GEmf9.js → graph-cache-CYiUS2aS.js} +4 -5
- package/dist/_chunks/graph-cache-CYiUS2aS.js.map +1 -0
- package/dist/_chunks/{json-lossy-check-ClNvBM_3.js → json-lossy-check-ip0Qi0MT.js} +6 -3
- package/dist/_chunks/json-lossy-check-ip0Qi0MT.js.map +1 -0
- package/dist/_chunks/{live-graph-Bm5WTvcr.js → live-graph-Dv-JJCZw.js} +3 -3
- package/dist/_chunks/{live-graph-Bm5WTvcr.js.map → live-graph-Dv-JJCZw.js.map} +1 -1
- package/dist/_chunks/{logger-k2DQ4EUf.js → logger-DiDt5ppH.js} +192 -51
- package/dist/_chunks/logger-DiDt5ppH.js.map +1 -0
- package/dist/_chunks/{navigation-root-mHSK9psY.js → navigation-root-BQfo1-kG.js} +2 -2
- package/dist/_chunks/{navigation-root-mHSK9psY.js.map → navigation-root-BQfo1-kG.js.map} +1 -1
- package/dist/_chunks/{plugin-context-8idfR3UZ.js → plugin-context-BPBPc3lL.js} +28 -4
- package/dist/_chunks/plugin-context-BPBPc3lL.js.map +1 -0
- package/dist/_chunks/{poison-scan-DG5eI2_z.js → poison-scan-CpeT6_OJ.js} +2 -2
- package/dist/_chunks/{poison-scan-DG5eI2_z.js.map → poison-scan-CpeT6_OJ.js.map} +1 -1
- package/dist/_chunks/render-timeout-DOf_BBcO.js +46 -0
- package/dist/_chunks/render-timeout-DOf_BBcO.js.map +1 -0
- package/dist/_chunks/{rsc-payload-path-B_LBodc2.js → rsc-payload-path-dffcs4jp.js} +9 -3
- package/dist/_chunks/{rsc-payload-path-B_LBodc2.js.map → rsc-payload-path-dffcs4jp.js.map} +1 -1
- package/dist/_chunks/{scanner-BQ5sPIJ7.js → scanner-Bw0oq1HB.js} +2 -2
- package/dist/_chunks/{scanner-BQ5sPIJ7.js.map → scanner-Bw0oq1HB.js.map} +1 -1
- package/dist/_chunks/{navigation-context-D0TU0Jog.js → segment-context-xtPUGfdq.js} +36 -34
- package/dist/_chunks/segment-context-xtPUGfdq.js.map +1 -0
- package/dist/_chunks/{singleflight-2lUWfcAk.js → singleflight-BeVMMKi0.js} +4 -3
- package/dist/_chunks/{singleflight-2lUWfcAk.js.map → singleflight-BeVMMKi0.js.map} +1 -1
- package/dist/_chunks/{sizeof-lXffQ1Vr.js → sizeof-UwzwB1uM.js} +3 -2
- package/dist/_chunks/sizeof-UwzwB1uM.js.map +1 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js +49 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js.map +1 -0
- package/dist/_chunks/{state-FippDgxN.js → state-BhNGPsdi.js} +6 -8
- package/dist/_chunks/state-BhNGPsdi.js.map +1 -0
- package/dist/_chunks/{status-page-marker-CNbpUOPB.js → status-page-marker-gaihi0KZ.js} +53 -20
- package/dist/_chunks/status-page-marker-gaihi0KZ.js.map +1 -0
- package/dist/_chunks/{walkers-CN2N_bA-.js → walkers-BXExhzzk.js} +2 -2
- package/dist/_chunks/{walkers-CN2N_bA-.js.map → walkers-BXExhzzk.js.map} +1 -1
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js +32 -0
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +7 -7
- package/dist/adapters/build-output-helper.d.ts.map +1 -1
- package/dist/adapters/canonicalize-module.d.ts +8 -0
- package/dist/adapters/canonicalize-module.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +2 -2
- package/dist/adapters/cloudflare.d.ts +30 -8
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -2
- package/dist/adapters/compress-module.d.ts +8 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +2 -3
- package/dist/adapters/fs-identity.d.ts.map +1 -1
- package/dist/adapters/nitro-presets.d.ts +0 -6
- package/dist/adapters/nitro-presets.d.ts.map +1 -1
- package/dist/adapters/nitro-preview.d.ts +43 -11
- package/dist/adapters/nitro-preview.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +1 -13
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +291 -176
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +7 -2
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +105 -21
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js +0 -0
- package/dist/analyze/crawl-entry.js +3 -3
- package/dist/analyze/graph-cache.d.ts.map +1 -1
- package/dist/analyze/graph-command.js +4 -4
- package/dist/cache/index.js +2 -2
- package/dist/cache/json-lossy-check.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts.map +1 -1
- package/dist/cache/stores/memory.js +1 -1
- package/dist/cache/tag-aware-handler.d.ts.map +1 -1
- package/dist/cdn/workers-cache-purge.js +1 -1
- package/dist/cli-check.d.ts +7 -37
- package/dist/cli-check.d.ts.map +1 -1
- package/dist/cli-context.d.ts +54 -0
- package/dist/cli-context.d.ts.map +1 -0
- package/dist/cli.d.ts +9 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -24
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/hydrate.d.ts +19 -29
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
- package/dist/client/browser-entry/index.d.ts +7 -7
- package/dist/client/browser-entry/post-hydration.d.ts +6 -9
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts +6 -11
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +4 -3
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/error-reconstituter.d.ts +3 -9
- package/dist/client/error-reconstituter.d.ts.map +1 -1
- package/dist/client/history.d.ts +12 -11
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +5 -6
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +3 -3
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +68 -104
- package/dist/client/internal.js.map +1 -1
- package/dist/client/navigation-commit.d.ts +16 -7
- package/dist/client/navigation-commit.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +3 -5
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/react-root.d.ts +3 -2
- package/dist/client/react-root.d.ts.map +1 -1
- package/dist/client/router-pipeline.d.ts +1 -6
- package/dist/client/router-pipeline.d.ts.map +1 -1
- package/dist/client/router-types.d.ts +45 -39
- package/dist/client/router-types.d.ts.map +1 -1
- package/dist/client/router-url.d.ts +24 -0
- package/dist/client/router-url.d.ts.map +1 -0
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +8 -4
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/ssr-data.d.ts +18 -64
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/state.d.ts +2 -5
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts +1 -1
- package/dist/config-types.d.ts +2 -1
- package/dist/config-types.d.ts.map +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/dev-tools/dev-page-shell.d.ts +17 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
- package/dist/dev-tools/index.d.ts +1 -1
- package/dist/dev-tools/index.d.ts.map +1 -1
- package/dist/dev-tools/instrumentation.d.ts +17 -2
- package/dist/dev-tools/instrumentation.d.ts.map +1 -1
- package/dist/dev-tools/overlay.d.ts +6 -27
- package/dist/dev-tools/overlay.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +531 -373
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +26 -40
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +15 -2
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +19 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/post-build.d.ts +110 -0
- package/dist/plugins/post-build.d.ts.map +1 -0
- package/dist/plugins/prebuilt-capture.d.ts +11 -4
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -1
- package/dist/plugins/prebuilt.d.ts +17 -1
- package/dist/plugins/prebuilt.d.ts.map +1 -1
- package/dist/plugins/prerender-sugar.d.ts.map +1 -1
- package/dist/plugins/rsc-assets-manifest.d.ts +33 -0
- package/dist/plugins/rsc-assets-manifest.d.ts.map +1 -0
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +32 -9
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-write.d.ts +0 -9
- package/dist/routing/codegen-write.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/routing/segment-codegen.d.ts.map +1 -1
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts +5 -4
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +46 -7
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +58 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/children-interception.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +2 -23
- package/dist/server/cookie-context.d.ts.map +1 -1
- package/dist/server/csp-nonce.d.ts +0 -9
- package/dist/server/csp-nonce.d.ts.map +1 -1
- package/dist/server/csrf.d.ts +27 -4
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/debug.d.ts +0 -1
- package/dist/server/debug.d.ts.map +1 -1
- package/dist/server/default-logger.d.ts +2 -1
- package/dist/server/default-logger.d.ts.map +1 -1
- package/dist/server/deny-boundary.d.ts +12 -6
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +2 -2
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -3
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +9 -2
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/head-response.d.ts +4 -4
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +10 -3
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/internal.d.ts +1 -4
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +961 -581
- package/dist/server/internal.js.map +1 -1
- package/dist/server/json-status-response.d.ts +34 -0
- package/dist/server/json-status-response.d.ts.map +1 -0
- package/dist/server/logger.d.ts +26 -0
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +11 -6
- package/dist/server/param-coercion.d.ts.map +1 -1
- package/dist/server/pipeline-helpers.d.ts +95 -7
- package/dist/server/pipeline-helpers.d.ts.map +1 -1
- package/dist/server/pipeline-interception.d.ts +11 -0
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +11 -1
- package/dist/server/pipeline-outcome.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts +2 -2
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +23 -35
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/prebuilt/capture-render.d.ts +25 -0
- package/dist/server/prebuilt/capture-render.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-routes.d.ts +37 -0
- package/dist/server/prebuilt/capture-routes.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +79 -35
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -1
- package/dist/server/prebuilt/lifetime.d.ts +38 -0
- package/dist/server/prebuilt/lifetime.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +7 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -1
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -1
- package/dist/server/prebuilt-builder.d.ts.map +1 -1
- package/dist/server/prebuilt-runtime.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +6 -81
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/react-cache-bridge.d.ts +59 -0
- package/dist/server/react-cache-bridge.d.ts.map +1 -0
- package/dist/server/react-cache-scope.d.ts +49 -0
- package/dist/server/react-cache-scope.d.ts.map +1 -0
- package/dist/server/render-timeout.d.ts +15 -0
- package/dist/server/render-timeout.d.ts.map +1 -1
- package/dist/server/render-utils.d.ts +9 -0
- package/dist/server/render-utils.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +26 -5
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +7 -0
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +22 -22
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +7 -0
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +32 -6
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +11 -18
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +0 -1
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +5 -15
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +5 -6
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-signals.d.ts +65 -0
- package/dist/server/rsc-entry/render-signals.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +6 -16
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +7 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +8 -53
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +2 -2
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +9 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -1
- package/dist/server/signal-identity.d.ts +43 -0
- package/dist/server/signal-identity.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +4 -3
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/slot-subtree-contain.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +91 -53
- package/dist/server/ssr-bridge-types.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +8 -5
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +26 -40
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +1 -1
- package/dist/server/static-generator.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +12 -0
- package/dist/server/stream-utils.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +12 -16
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -1
- package/dist/server/version-skew.d.ts +3 -3
- package/dist/shared/csrf-reject.d.ts +16 -0
- package/dist/shared/csrf-reject.d.ts.map +1 -0
- package/dist/shared/error-digest.d.ts +28 -0
- package/dist/shared/error-digest.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +11 -10
- package/dist/shared/payload-root.d.ts.map +1 -1
- package/dist/shared/rsc-payload-path.d.ts +6 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -1
- package/dist/utils/write-file-atomic.d.ts +17 -0
- package/dist/utils/write-file-atomic.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +17 -14
- package/docs/api/32-api-cache.mdx +51 -23
- package/docs/api/34-api-config.mdx +34 -6
- package/docs/api/36-cli.mdx +11 -1
- package/docs/learn/03-fetching-data.mdx +17 -1
- package/docs/learn/04-access-control.mdx +1 -1
- package/docs/learn/10-caching.mdx +29 -11
- package/docs/learn/11-middleware.mdx +8 -2
- package/docs/learn/12-error-handling.mdx +6 -1
- package/package.json +5 -1
- package/src/adapters/build-output-helper.ts +55 -53
- package/src/adapters/canonicalize-module.ts +29 -0
- package/src/adapters/cloudflare.ts +105 -63
- package/src/adapters/compress-module.ts +16 -5
- package/src/adapters/fs-identity.ts +2 -3
- package/src/adapters/nitro-presets.ts +0 -15
- package/src/adapters/nitro-preview.ts +272 -136
- package/src/adapters/nitro.ts +119 -82
- package/src/adapters/shared.ts +23 -14
- package/src/adapters/types.ts +110 -21
- package/src/analyze/graph-cache.ts +3 -4
- package/src/cache/json-lossy-check.ts +3 -9
- package/src/cache/singleflight.ts +5 -2
- package/src/cache/sizeof.ts +3 -1
- package/src/cache/tag-aware-handler.ts +43 -26
- package/src/cli-check.ts +8 -98
- package/src/cli-context.ts +119 -0
- package/src/cli.ts +19 -28
- package/src/client/browser-dev.ts +1 -1
- package/src/client/browser-entry/action-dispatch.ts +26 -4
- package/src/client/browser-entry/hydrate.ts +53 -58
- package/src/client/browser-entry/index.ts +16 -27
- package/src/client/browser-entry/post-hydration.ts +6 -40
- package/src/client/browser-entry/router-init.ts +66 -84
- package/src/client/error-boundary.tsx +9 -41
- package/src/client/error-reconstituter.tsx +10 -5
- package/src/client/history.ts +18 -21
- package/src/client/index.ts +0 -1
- package/src/client/internal.ts +2 -7
- package/src/client/navigation-commit.ts +35 -18
- package/src/client/navigation-context.ts +3 -39
- package/src/client/react-root.ts +3 -2
- package/src/client/router-pipeline.ts +65 -128
- package/src/client/router-types.ts +46 -44
- package/src/client/router-url.ts +32 -0
- package/src/client/router.ts +43 -22
- package/src/client/rsc-fetch.ts +117 -155
- package/src/client/ssr-data.ts +19 -80
- package/src/client/state.ts +2 -9
- package/src/client/use-pathname.ts +1 -1
- package/src/config-types.ts +2 -1
- package/src/config-validation.ts +2 -1
- package/src/dev-tools/dev-page-shell.ts +18 -0
- package/src/dev-tools/index.ts +0 -2
- package/src/dev-tools/instrumentation.ts +50 -2
- package/src/dev-tools/overlay.ts +8 -238
- package/src/index.ts +24 -14
- package/src/plugin-context.ts +39 -40
- package/src/plugins/build-manifest.ts +4 -11
- package/src/plugins/build-report.ts +70 -70
- package/src/plugins/dev-server.ts +24 -44
- package/src/plugins/entries.ts +2 -1
- package/src/plugins/fonts.ts +35 -7
- package/src/plugins/post-build.ts +327 -0
- package/src/plugins/prebuilt-capture.ts +28 -32
- package/src/plugins/prebuilt.ts +54 -39
- package/src/plugins/prerender-sugar.ts +0 -4
- package/src/plugins/{adapter-build.ts → rsc-assets-manifest.ts} +20 -109
- package/src/plugins/shims.ts +1 -0
- package/src/plugins/static-build.ts +42 -74
- package/src/routing/codegen-write.ts +25 -3
- package/src/routing/segment-codegen.ts +3 -2
- package/src/rsc-runtime/vendor-types.d.ts +8 -0
- package/src/server/access-gate.tsx +2 -1
- package/src/server/action-client.ts +1 -1
- package/src/server/action-handler.ts +253 -110
- package/src/server/actions.ts +73 -25
- package/src/server/als-registry.ts +73 -5
- package/src/server/chain-url-parts.ts +1 -1
- package/src/server/children-interception.ts +2 -1
- package/src/server/cookie-context.ts +18 -48
- package/src/server/csp-nonce.ts +0 -12
- package/src/server/csrf.ts +140 -8
- package/src/server/debug.ts +0 -1
- package/src/server/default-logger.ts +2 -1
- package/src/server/deny-boundary.ts +25 -13
- package/src/server/deny-renderer.ts +30 -97
- package/src/server/error-boundary-wrapper.ts +7 -3
- package/src/server/fallback-error.ts +26 -11
- package/src/server/flight-scripts.ts +1 -1
- package/src/server/head-response.ts +4 -4
- package/src/server/html-injector-core.ts +2 -2
- package/src/server/html-injectors.ts +2 -4
- package/src/server/index.ts +0 -4
- package/src/server/instrumentation.ts +10 -3
- package/src/server/internal.ts +1 -6
- package/src/server/json-status-response.ts +105 -0
- package/src/server/logger.ts +39 -3
- package/src/server/param-coercion.ts +15 -12
- package/src/server/pipeline-helpers.ts +257 -12
- package/src/server/pipeline-interception.ts +133 -0
- package/src/server/pipeline-outcome.ts +103 -31
- package/src/server/pipeline-phases.ts +127 -237
- package/src/server/pipeline.ts +204 -207
- package/src/server/prebuilt/capture-render.ts +118 -0
- package/src/server/prebuilt/capture-routes.ts +104 -0
- package/src/server/prebuilt/capture-state.ts +155 -48
- package/src/server/prebuilt/lifetime.ts +151 -0
- package/src/server/prebuilt/slots.ts +14 -2
- package/src/server/prebuilt/synthetic-store.ts +3 -0
- package/src/server/prebuilt-builder.ts +30 -320
- package/src/server/prebuilt-runtime.ts +125 -129
- package/src/server/primitives.ts +8 -168
- package/src/server/react-cache-bridge.ts +124 -0
- package/src/server/react-cache-scope.ts +104 -0
- package/src/server/render-timeout.ts +20 -0
- package/src/server/render-utils.ts +11 -1
- package/src/server/request-context.ts +36 -9
- package/src/server/route-element-builder.ts +11 -6
- package/src/server/route-handler.ts +36 -23
- package/src/server/route-matcher.ts +15 -1
- package/src/server/rsc-entry/action-middleware-runner.ts +79 -123
- package/src/server/rsc-entry/api-handler.ts +27 -103
- package/src/server/rsc-entry/deny-fallback.ts +93 -26
- package/src/server/rsc-entry/error-renderer.ts +39 -91
- package/src/server/rsc-entry/helpers.ts +2 -4
- package/src/server/rsc-entry/index.ts +64 -58
- package/src/server/rsc-entry/render-route.ts +15 -80
- package/src/server/rsc-entry/render-signals.ts +108 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +56 -57
- package/src/server/rsc-entry/rsc-payload.ts +28 -61
- package/src/server/rsc-entry/rsc-stream.ts +113 -213
- package/src/server/rsc-entry/ssr-bridge.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +182 -263
- package/src/server/rsc-entry/wrap-action-dispatch.ts +12 -14
- package/src/server/signal-identity.ts +112 -0
- package/src/server/slot-resolver.ts +18 -18
- package/src/server/slot-subtree-contain.ts +2 -1
- package/src/server/ssr-bridge-types.ts +92 -56
- package/src/server/ssr-entry.ts +87 -111
- package/src/server/ssr-render.ts +55 -64
- package/src/server/ssr-wrappers.tsx +2 -2
- package/src/server/static-generator.ts +7 -42
- package/src/server/static-not-found.ts +3 -3
- package/src/server/stream-utils.ts +51 -0
- package/src/server/tracing.ts +58 -75
- package/src/server/types.ts +1 -1
- package/src/server/version-skew.ts +5 -5
- package/src/shared/csrf-reject.ts +15 -0
- package/src/shared/error-digest.ts +46 -0
- package/src/shared/payload-root.ts +11 -10
- package/src/shared/rsc-payload-path.ts +8 -1
- package/src/utils/write-file-atomic.ts +32 -0
- package/dist/_chunks/actions-jNrXdzgs.js +0 -346
- package/dist/_chunks/actions-jNrXdzgs.js.map +0 -1
- package/dist/_chunks/als-registry-C6kcfprT.js.map +0 -1
- package/dist/_chunks/build-manifest-DTmSGLRz.js.map +0 -1
- package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +0 -1
- package/dist/_chunks/cache-api-CUD9Ezaq.js.map +0 -1
- package/dist/_chunks/cli-check-G8o30ldg.js.map +0 -1
- package/dist/_chunks/convention-lint-5KzoMg_A.js.map +0 -1
- package/dist/_chunks/dev-server-BzBxgYAV.js.map +0 -1
- package/dist/_chunks/error-boundary-BrHmG-2X.js.map +0 -1
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +0 -1
- package/dist/_chunks/graph-cache-CP4GEmf9.js.map +0 -1
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +0 -1
- package/dist/_chunks/logger-k2DQ4EUf.js.map +0 -1
- package/dist/_chunks/navigation-context-D0TU0Jog.js.map +0 -1
- package/dist/_chunks/plugin-context-8idfR3UZ.js.map +0 -1
- package/dist/_chunks/primitives-DLAnvsrk.js.map +0 -1
- package/dist/_chunks/segment-context-D9_89u34.js +0 -34
- package/dist/_chunks/segment-context-D9_89u34.js.map +0 -1
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +0 -1
- package/dist/_chunks/ssr-data-D6T6Y3ef.js +0 -60
- package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +0 -1
- package/dist/_chunks/state-FippDgxN.js.map +0 -1
- package/dist/_chunks/status-page-marker-CNbpUOPB.js.map +0 -1
- package/dist/client/types.d.ts +0 -14
- package/dist/client/types.d.ts.map +0 -1
- package/dist/plugins/adapter-build.d.ts +0 -38
- package/dist/plugins/adapter-build.d.ts.map +0 -1
- package/dist/server/asset-headers.d.ts +0 -32
- package/dist/server/asset-headers.d.ts.map +0 -1
- package/dist/server/dev-source-map.d.ts +0 -22
- package/dist/server/dev-source-map.d.ts.map +0 -1
- package/src/client/types.ts +0 -21
- package/src/server/asset-headers.ts +0 -59
- package/src/server/dev-source-map.ts +0 -31
package/src/server/ssr-entry.ts
CHANGED
|
@@ -33,15 +33,15 @@ import {
|
|
|
33
33
|
nodeReadableToWeb,
|
|
34
34
|
useNodeStreams,
|
|
35
35
|
buildSsrResponse,
|
|
36
|
+
type SsrStreamOptions,
|
|
36
37
|
} from './ssr-render.ts';
|
|
37
|
-
import {
|
|
38
|
-
import { SsrStreamError } from './primitives.ts';
|
|
38
|
+
import { SsrStreamError } from './signal-identity.ts';
|
|
39
39
|
import { createBufferedTransformStream, injectHead, injectRscPayload } from './html-injectors.ts';
|
|
40
40
|
import { wrapSsrElement } from './ssr-wrappers.tsx';
|
|
41
41
|
import { withSpan } from './tracing.ts';
|
|
42
42
|
import { registerSsrDataProvider, type SsrData } from '../client/ssr-data.ts';
|
|
43
43
|
import { splitPayloadRoot } from '../shared/payload-root.ts';
|
|
44
|
-
import type { NavContext } from './ssr-bridge-types.ts';
|
|
44
|
+
import type { NavContext, SsrRenderResult } from './ssr-bridge-types.ts';
|
|
45
45
|
|
|
46
46
|
// Pre-import Node.js stream modules at module load time — not per-request.
|
|
47
47
|
// Dynamic imports of node-stream-transforms and node:stream/promises were
|
|
@@ -99,34 +99,35 @@ registerSsrDataProvider(() => ssrDataAls.getStore());
|
|
|
99
99
|
* 2. Render the decoded tree to HTML via renderToReadableStream (streaming)
|
|
100
100
|
* 3. Wait for onShellReady before flushing (handled by renderSsrStream)
|
|
101
101
|
* 4. Inject metadata into <head> and client scripts before </body>
|
|
102
|
-
* 5. Return Response
|
|
102
|
+
* 5. Return the Response (navContext.statusCode, navContext.responseHeaders)
|
|
103
|
+
* with the SSR sub-phase timings and whether Fizz allReady settled
|
|
104
|
+
* within the hold window
|
|
103
105
|
*
|
|
104
106
|
* The RSC stream is piped progressively — not buffered. For deny() outside
|
|
105
107
|
* Suspense, the RSC stream encodes an error in the shell region, causing
|
|
106
108
|
* renderToReadableStream to reject. The error propagates back to the RSC
|
|
107
|
-
* entry which
|
|
109
|
+
* entry, which rethrows the captured DenySignal for the pipeline to render
|
|
110
|
+
* the deny page. For deny() inside Suspense, the shell
|
|
108
111
|
* succeeds and the error streams as a React error boundary after flush.
|
|
109
112
|
*
|
|
110
113
|
* @param rscStream - The ReadableStream from the RSC environment
|
|
111
114
|
* @param navContext - Per-request state passed across RSC→SSR boundary
|
|
112
|
-
* @returns
|
|
115
|
+
* @returns The HTML Response with hydration markers, plus SSR diagnostics
|
|
113
116
|
*/
|
|
114
117
|
export async function handleSsr(
|
|
115
118
|
rscStream: ReadableStream<Uint8Array>,
|
|
116
119
|
navContext: NavContext
|
|
117
|
-
): Promise<
|
|
120
|
+
): Promise<SsrRenderResult> {
|
|
118
121
|
return withSpan('timber.ssr', { 'timber.environment': 'ssr' }, async () => {
|
|
119
122
|
const _runtimeConfig = config;
|
|
120
123
|
|
|
121
|
-
//
|
|
122
|
-
//
|
|
124
|
+
// Per-request SSR data for the client code with no React context to
|
|
125
|
+
// read during SSR (useCookie, <Link preserveSearchParams>; useSearchParams
|
|
126
|
+
// uses it only to detect SSR). Route params reach client components through
|
|
127
|
+
// ParamsContext, decoded from the payload root, not through here.
|
|
123
128
|
const ssrData: SsrData = {
|
|
124
|
-
pathname: navContext.pathname,
|
|
125
129
|
search: navContext.search,
|
|
126
130
|
cookies: navContext.cookies ?? new Map(),
|
|
127
|
-
params: navContext.segmentParams,
|
|
128
|
-
slotParams: navContext.slotParams,
|
|
129
|
-
_navContext: navContext,
|
|
130
131
|
};
|
|
131
132
|
|
|
132
133
|
// Run the entire render inside the SSR data ALS scope.
|
|
@@ -188,6 +189,36 @@ export async function handleSsr(
|
|
|
188
189
|
// Entire pipeline stays in C++ native streams until the Response boundary.
|
|
189
190
|
// - Workers: renderToReadableStream → Web TransformStream pipeline → Response
|
|
190
191
|
// Web Streams are V8-native C++ built-ins on Workers.
|
|
192
|
+
//
|
|
193
|
+
// `onFizzAllReadyResolved` fires synchronously before the render
|
|
194
|
+
// promise resolves, so the flag is settled once the render is awaited.
|
|
195
|
+
const renderTimeoutMs = _runtimeConfig.renderTimeoutMs ?? undefined;
|
|
196
|
+
const requestInfo = { method: 'GET', path: navContext.pathname };
|
|
197
|
+
let fizzAllReadyResolved = false;
|
|
198
|
+
const renderOptions: SsrStreamOptions = {
|
|
199
|
+
bootstrapScriptContent: navContext.bootstrapScriptContent || undefined,
|
|
200
|
+
nonce,
|
|
201
|
+
deferSuspenseFor: navContext.deferSuspenseFor,
|
|
202
|
+
signal: navContext.signal,
|
|
203
|
+
renderTimeoutMs,
|
|
204
|
+
requestInfo,
|
|
205
|
+
onFizzAllReadyResolved: (resolved) => {
|
|
206
|
+
fizzAllReadyResolved = resolved;
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
// Not logged here. Fizz's onError (ssr-render.ts) has already logged a
|
|
210
|
+
// shell error SSR produced itself, and skips one Flight relayed,
|
|
211
|
+
// which the RSC onError (rsc-stream.ts) logged. Logging the rejection
|
|
212
|
+
// again doubled every shell failure (TIM-1537).
|
|
213
|
+
const renderFailed = (renderError: unknown): never => {
|
|
214
|
+
throw new SsrStreamError(
|
|
215
|
+
'SSR renderToReadableStream failed due to RSC stream error',
|
|
216
|
+
renderError
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
let outputStream: ReadableStream<Uint8Array>;
|
|
221
|
+
let _renderEnd: number;
|
|
191
222
|
if (_nodeStreamImports) {
|
|
192
223
|
// Node.js fast path: full pipeline in native streams
|
|
193
224
|
const {
|
|
@@ -198,30 +229,10 @@ export async function handleSsr(
|
|
|
198
229
|
runNodePipelineWithErrorHandling,
|
|
199
230
|
} = _nodeStreamImports;
|
|
200
231
|
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
nodeHtmlStream = await renderSsrNodeStream(wrappedElement, {
|
|
207
|
-
bootstrapScriptContent: navContext.bootstrapScriptContent || undefined,
|
|
208
|
-
nonce,
|
|
209
|
-
deferSuspenseFor: navContext.deferSuspenseFor,
|
|
210
|
-
signal: navContext.signal,
|
|
211
|
-
renderTimeoutMs,
|
|
212
|
-
requestInfo,
|
|
213
|
-
onFizzAllReadyResolved: (resolved) => {
|
|
214
|
-
navContext._fizzAllReadyResolved = resolved;
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
} catch (renderError) {
|
|
218
|
-
logRenderError({ ...requestInfo, error: renderError });
|
|
219
|
-
throw new SsrStreamError(
|
|
220
|
-
'SSR renderToReadableStream failed due to RSC stream error',
|
|
221
|
-
renderError
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
const _renderEnd = performance.now();
|
|
232
|
+
const nodeHtmlStream = await renderSsrNodeStream(wrappedElement, renderOptions).catch(
|
|
233
|
+
renderFailed
|
|
234
|
+
);
|
|
235
|
+
_renderEnd = performance.now();
|
|
225
236
|
|
|
226
237
|
// React 19.3+ emits <!DOCTYPE html> automatically when the root
|
|
227
238
|
// element is <html>, so no framework-level doctype prepend needed.
|
|
@@ -240,92 +251,57 @@ export async function handleSsr(
|
|
|
240
251
|
// Resolve the lazy segment script now that the shell is ready
|
|
241
252
|
// (AccessGates have settled, ALS deny index is authoritative).
|
|
242
253
|
const resolvedHeadHtml = navContext.headHtml + (navContext.getHeadSegmentScript?.() ?? '');
|
|
243
|
-
const bufferedTransform = createNodeBufferedTransform();
|
|
244
|
-
const headInjector = createNodeHeadInjector(resolvedHeadHtml);
|
|
245
|
-
const flightInjector = createNodeFlightInjector(navContext.rscStream, {
|
|
246
|
-
renderTimeoutMs,
|
|
247
|
-
errorSignal: navContext._errorSignal,
|
|
248
|
-
nonce,
|
|
249
|
-
});
|
|
250
|
-
const moveSuffix = createNodeMoveSuffixTransform();
|
|
251
|
-
|
|
252
254
|
const output = runNodePipelineWithErrorHandling(
|
|
253
255
|
nodeHtmlStream,
|
|
254
|
-
[
|
|
256
|
+
[
|
|
257
|
+
createNodeBufferedTransform(),
|
|
258
|
+
createNodeHeadInjector(resolvedHeadHtml),
|
|
259
|
+
createNodeFlightInjector(navContext.rscStream, {
|
|
260
|
+
renderTimeoutMs,
|
|
261
|
+
errorSignal: navContext._errorSignal,
|
|
262
|
+
nonce,
|
|
263
|
+
}),
|
|
264
|
+
createNodeMoveSuffixTransform(),
|
|
265
|
+
],
|
|
255
266
|
navContext.signal,
|
|
256
267
|
nonce
|
|
257
268
|
);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
shellMs: Math.round(_renderEnd - _decodeEnd),
|
|
264
|
-
pipeMs: 0, // pipe() timing is inside renderSsrNodeStream
|
|
265
|
-
pipelineMs: Math.round(_pipelineEnd - _renderEnd),
|
|
266
|
-
totalMs: Math.round(_pipelineEnd - _ssrStart),
|
|
267
|
-
nodeStreams: true,
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const webStream = nodeReadableToWeb(output);
|
|
271
|
-
return buildSsrResponse(webStream, navContext.statusCode, navContext.responseHeaders);
|
|
272
|
-
}
|
|
269
|
+
outputStream = nodeReadableToWeb(output);
|
|
270
|
+
} else {
|
|
271
|
+
// Web Streams path (CF Workers / fallback)
|
|
272
|
+
const htmlStream = await renderSsrStream(wrappedElement, renderOptions).catch(renderFailed);
|
|
273
|
+
_renderEnd = performance.now();
|
|
273
274
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
275
|
+
// Pipeline: buffer → injectHead → injectRscPayload
|
|
276
|
+
//
|
|
277
|
+
// The buffered transform coalesces Fizz micro-chunks into coherent
|
|
278
|
+
// HTML fragments so downstream transforms never see chunk boundaries
|
|
279
|
+
// mid-tag. This prevents RSC script injection from breaking HTML
|
|
280
|
+
// structure (TIM-527).
|
|
281
|
+
// Resolve the lazy segment script now that the shell is ready
|
|
282
|
+
// (AccessGates have settled, ALS deny index is authoritative).
|
|
283
|
+
const resolvedHeadHtml = navContext.headHtml + (navContext.getHeadSegmentScript?.() ?? '');
|
|
284
|
+
outputStream = htmlStream.pipeThrough(createBufferedTransformStream());
|
|
285
|
+
outputStream = injectHead(outputStream, resolvedHeadHtml);
|
|
286
|
+
outputStream = injectRscPayload(outputStream, navContext.rscStream, {
|
|
284
287
|
renderTimeoutMs,
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
navContext._fizzAllReadyResolved = resolved;
|
|
288
|
-
},
|
|
288
|
+
errorSignal: navContext._errorSignal,
|
|
289
|
+
nonce,
|
|
289
290
|
});
|
|
290
|
-
} catch (renderError) {
|
|
291
|
-
logRenderError({ ...requestInfo, error: renderError });
|
|
292
|
-
throw new SsrStreamError(
|
|
293
|
-
'SSR renderToReadableStream failed due to RSC stream error',
|
|
294
|
-
renderError
|
|
295
|
-
);
|
|
296
291
|
}
|
|
297
|
-
|
|
298
|
-
const _renderEnd = performance.now();
|
|
299
|
-
|
|
300
|
-
// Pipeline: buffer → injectHead → injectRscPayload
|
|
301
|
-
//
|
|
302
|
-
// The buffered transform coalesces Fizz micro-chunks into coherent
|
|
303
|
-
// HTML fragments so downstream transforms never see chunk boundaries
|
|
304
|
-
// mid-tag. This prevents RSC script injection from breaking HTML
|
|
305
|
-
// structure (TIM-527).
|
|
306
|
-
// Resolve the lazy segment script now that the shell is ready
|
|
307
|
-
// (AccessGates have settled, ALS deny index is authoritative).
|
|
308
|
-
const resolvedHeadHtml = navContext.headHtml + (navContext.getHeadSegmentScript?.() ?? '');
|
|
309
|
-
let outputStream = htmlStream.pipeThrough(createBufferedTransformStream());
|
|
310
|
-
outputStream = injectHead(outputStream, resolvedHeadHtml);
|
|
311
|
-
outputStream = injectRscPayload(outputStream, navContext.rscStream, {
|
|
312
|
-
renderTimeoutMs,
|
|
313
|
-
errorSignal: navContext._errorSignal,
|
|
314
|
-
nonce,
|
|
315
|
-
});
|
|
316
292
|
const _pipelineEnd = performance.now();
|
|
317
293
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
294
|
+
return {
|
|
295
|
+
response: buildSsrResponse(outputStream, navContext.statusCode, navContext.responseHeaders),
|
|
296
|
+
timings: {
|
|
297
|
+
decodeMs: Math.round(_decodeEnd - _ssrStart),
|
|
298
|
+
shellMs: Math.round(_renderEnd - _decodeEnd),
|
|
299
|
+
pipelineMs: Math.round(_pipelineEnd - _renderEnd),
|
|
300
|
+
totalMs: Math.round(_pipelineEnd - _ssrStart),
|
|
301
|
+
nodeStreams: _nodeStreamImports !== null,
|
|
302
|
+
},
|
|
303
|
+
fizzAllReadyResolved,
|
|
325
304
|
};
|
|
326
|
-
|
|
327
|
-
// Build and return the Response.
|
|
328
|
-
return buildSsrResponse(outputStream, navContext.statusCode, navContext.responseHeaders);
|
|
329
305
|
});
|
|
330
306
|
});
|
|
331
307
|
}
|
package/src/server/ssr-render.ts
CHANGED
|
@@ -36,12 +36,24 @@ import { isAbortError, noindexScript } from './render-utils.ts';
|
|
|
36
36
|
const REACT_PROD_ERROR_PREFIX = 'An error occurred in the Server Components render';
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Returns true if
|
|
40
|
-
*
|
|
41
|
-
* with the full original message
|
|
39
|
+
* Returns true if this error was thrown in the RSC render and relayed by
|
|
40
|
+
* Flight, which means the RSC onError handler (rsc-stream.ts) already logged
|
|
41
|
+
* it with the full original message. Logging it again in SSR is a duplicate.
|
|
42
|
+
*
|
|
43
|
+
* In production React replaces a relayed error's message with a fixed
|
|
44
|
+
* sanitized one. In development it keeps the message, stamps the revived
|
|
45
|
+
* Error with the `environmentName` it was thrown in, and copies the digest
|
|
46
|
+
* our onError returned (`resolveErrorDev` and the `E` row in the Flight
|
|
47
|
+
* client). Both are needed: an Error passed as a *value* (a prop, `$Z`) is
|
|
48
|
+
* stamped with `environmentName` too but has no digest, and nothing logged
|
|
49
|
+
* it. When a client component throws one during SSR, it is logged here once,
|
|
50
|
+
* like any other error SSR throws itself (TIM-1537).
|
|
42
51
|
*/
|
|
43
|
-
function
|
|
44
|
-
|
|
52
|
+
function isFlightRelayedError(error: unknown): boolean {
|
|
53
|
+
if (!(error instanceof Error)) return false;
|
|
54
|
+
if (error.message.startsWith(REACT_PROD_ERROR_PREFIX)) return true;
|
|
55
|
+
const digest: unknown = Reflect.get(error, 'digest');
|
|
56
|
+
return 'environmentName' in error && typeof digest === 'string' && digest !== '';
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
/**
|
|
@@ -106,6 +118,26 @@ try {
|
|
|
106
118
|
// node:stream or renderToPipeableStream not available — use Web Streams path
|
|
107
119
|
}
|
|
108
120
|
|
|
121
|
+
/** Options shared by both SSR render paths (Node streams and Web Streams). */
|
|
122
|
+
export interface SsrStreamOptions {
|
|
123
|
+
bootstrapScriptContent?: string;
|
|
124
|
+
/** Request CSP nonce — stamped by Fizz on the bootstrap and runtime scripts. */
|
|
125
|
+
nonce?: string;
|
|
126
|
+
deferSuspenseFor?: number;
|
|
127
|
+
signal?: AbortSignal;
|
|
128
|
+
renderTimeoutMs?: number;
|
|
129
|
+
/** Request info threaded into render-error logs (method/path). */
|
|
130
|
+
requestInfo?: { method: string; path: string };
|
|
131
|
+
/**
|
|
132
|
+
* Fired synchronously when the render function is about to resolve
|
|
133
|
+
* (i.e. at hold-end / shell-ready). `resolved` reports whether Fizz's
|
|
134
|
+
* allReady had already settled by that moment. The SSR entry returns it
|
|
135
|
+
* as `SsrRenderResult.fizzAllReadyResolved` so the RSC renderer can
|
|
136
|
+
* decide whether signal promotion can be short-circuited.
|
|
137
|
+
*/
|
|
138
|
+
onFizzAllReadyResolved?: (resolved: boolean) => void;
|
|
139
|
+
}
|
|
140
|
+
|
|
109
141
|
/**
|
|
110
142
|
* Render a React element tree to a ReadableStream of HTML.
|
|
111
143
|
*
|
|
@@ -122,24 +154,7 @@ try {
|
|
|
122
154
|
*/
|
|
123
155
|
export async function renderSsrStream(
|
|
124
156
|
element: ReactNode,
|
|
125
|
-
options?:
|
|
126
|
-
bootstrapScriptContent?: string;
|
|
127
|
-
/** Request CSP nonce — stamped by Fizz on the bootstrap and runtime scripts. */
|
|
128
|
-
nonce?: string;
|
|
129
|
-
deferSuspenseFor?: number;
|
|
130
|
-
signal?: AbortSignal;
|
|
131
|
-
renderTimeoutMs?: number;
|
|
132
|
-
/** Request info threaded into render-error logs (method/path). */
|
|
133
|
-
requestInfo?: { method: string; path: string };
|
|
134
|
-
/**
|
|
135
|
-
* Fired synchronously when the render function is about to resolve
|
|
136
|
-
* (i.e. at hold-end / shell-ready). `resolved` reports whether Fizz's
|
|
137
|
-
* `stream.allReady` had already settled by that moment. Callers use
|
|
138
|
-
* this to decide whether signal promotion can be short-circuited.
|
|
139
|
-
* See NavContext._fizzAllReadyResolved.
|
|
140
|
-
*/
|
|
141
|
-
onFizzAllReadyResolved?: (resolved: boolean) => void;
|
|
142
|
-
}
|
|
157
|
+
options?: SsrStreamOptions
|
|
143
158
|
): Promise<ReadableStream<Uint8Array>> {
|
|
144
159
|
return renderViaReadableStream(element, options);
|
|
145
160
|
}
|
|
@@ -164,23 +179,7 @@ export const useNodeStreams = _useNodeStreams;
|
|
|
164
179
|
*/
|
|
165
180
|
export async function renderSsrNodeStream(
|
|
166
181
|
element: ReactNode,
|
|
167
|
-
options?:
|
|
168
|
-
bootstrapScriptContent?: string;
|
|
169
|
-
/** Request CSP nonce — stamped by Fizz on the bootstrap and runtime scripts. */
|
|
170
|
-
nonce?: string;
|
|
171
|
-
deferSuspenseFor?: number;
|
|
172
|
-
signal?: AbortSignal;
|
|
173
|
-
renderTimeoutMs?: number;
|
|
174
|
-
/** Request info threaded into render-error logs (method/path). */
|
|
175
|
-
requestInfo?: { method: string; path: string };
|
|
176
|
-
/**
|
|
177
|
-
* Fired synchronously at the moment `renderSsrNodeStream`'s returned
|
|
178
|
-
* Promise is about to resolve. `resolved` reports whether Fizz's
|
|
179
|
-
* `onAllReady` had already fired by then. See the twin callback on
|
|
180
|
-
* `renderSsrStream`.
|
|
181
|
-
*/
|
|
182
|
-
onFizzAllReadyResolved?: (resolved: boolean) => void;
|
|
183
|
-
}
|
|
182
|
+
options?: SsrStreamOptions
|
|
184
183
|
): Promise<import('node:stream').Readable> {
|
|
185
184
|
const signal = options?.signal;
|
|
186
185
|
const deferMs = options?.deferSuspenseFor;
|
|
@@ -235,9 +234,9 @@ export async function renderSsrNodeStream(
|
|
|
235
234
|
|
|
236
235
|
onError(error: unknown) {
|
|
237
236
|
if (isAbortError(error) || signal?.aborted) return;
|
|
238
|
-
// Skip
|
|
239
|
-
//
|
|
240
|
-
if (
|
|
237
|
+
// Skip errors Flight relayed — the original was already logged by
|
|
238
|
+
// the RSC onError with full details.
|
|
239
|
+
if (isFlightRelayedError(error)) return;
|
|
241
240
|
logRenderError({
|
|
242
241
|
method: requestInfo?.method ?? '',
|
|
243
242
|
path: requestInfo?.path ?? '',
|
|
@@ -301,16 +300,7 @@ export function nodeReadableToWeb(
|
|
|
301
300
|
|
|
302
301
|
async function renderViaReadableStream(
|
|
303
302
|
element: ReactNode,
|
|
304
|
-
options?:
|
|
305
|
-
bootstrapScriptContent?: string;
|
|
306
|
-
/** Request CSP nonce — stamped by Fizz on the bootstrap and runtime scripts. */
|
|
307
|
-
nonce?: string;
|
|
308
|
-
deferSuspenseFor?: number;
|
|
309
|
-
signal?: AbortSignal;
|
|
310
|
-
renderTimeoutMs?: number;
|
|
311
|
-
requestInfo?: { method: string; path: string };
|
|
312
|
-
onFizzAllReadyResolved?: (resolved: boolean) => void;
|
|
313
|
-
}
|
|
303
|
+
options?: SsrStreamOptions
|
|
314
304
|
): Promise<ReadableStream<Uint8Array>> {
|
|
315
305
|
const signal = options?.signal;
|
|
316
306
|
const timeoutMs = options?.renderTimeoutMs;
|
|
@@ -345,9 +335,9 @@ async function renderViaReadableStream(
|
|
|
345
335
|
});
|
|
346
336
|
return;
|
|
347
337
|
}
|
|
348
|
-
// Skip
|
|
349
|
-
//
|
|
350
|
-
if (
|
|
338
|
+
// Skip errors Flight relayed — the original was already logged by
|
|
339
|
+
// the RSC onError with full details.
|
|
340
|
+
if (isFlightRelayedError(error)) return;
|
|
351
341
|
logRenderError({
|
|
352
342
|
method: requestInfo?.method ?? '',
|
|
353
343
|
path: requestInfo?.path ?? '',
|
|
@@ -378,7 +368,7 @@ async function renderViaReadableStream(
|
|
|
378
368
|
//
|
|
379
369
|
// While we're holding, also track whether `stream.allReady` settled
|
|
380
370
|
// before the timer. That boolean is the Option-1 signal-promotion
|
|
381
|
-
// short-circuit key — see
|
|
371
|
+
// short-circuit key — see SsrRenderResult.fizzAllReadyResolved and
|
|
382
372
|
// design/spike-signal-promotion-protocol.md.
|
|
383
373
|
let fizzAllReadyResolved = false;
|
|
384
374
|
const allReadyTap = stream.allReady.then(
|
|
@@ -454,19 +444,20 @@ export function wrapStreamWithErrorHandling(
|
|
|
454
444
|
* React 19.3+ automatically emits `<!DOCTYPE html>` when the root
|
|
455
445
|
* element is `<html>`, so no framework-level doctype prepending is needed.
|
|
456
446
|
*
|
|
457
|
-
* Sets content-type to text/html if not already set by middleware.
|
|
447
|
+
* Sets content-type to text/html if not already set by middleware. The
|
|
448
|
+
* default goes on a response-local copy: `responseHeaders` is the
|
|
449
|
+
* pipeline's shared bag, handed over on `NavContext`, and SSR only reads
|
|
450
|
+
* it (design/49 §"A2").
|
|
458
451
|
*/
|
|
459
452
|
export function buildSsrResponse(
|
|
460
453
|
htmlStream: ReadableStream<Uint8Array>,
|
|
461
454
|
statusCode: number,
|
|
462
455
|
responseHeaders: Headers
|
|
463
456
|
): Response {
|
|
464
|
-
|
|
465
|
-
|
|
457
|
+
const headers = new Headers(responseHeaders);
|
|
458
|
+
if (!headers.has('content-type')) {
|
|
459
|
+
headers.set('content-type', 'text/html; charset=utf-8');
|
|
466
460
|
}
|
|
467
461
|
|
|
468
|
-
return new Response(htmlStream, {
|
|
469
|
-
status: statusCode,
|
|
470
|
-
headers: responseHeaders,
|
|
471
|
-
});
|
|
462
|
+
return new Response(htmlStream, { status: statusCode, headers });
|
|
472
463
|
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* Per-request isolation is by construction: the provider values are part
|
|
31
31
|
* of this request's element tree, so concurrent requests cannot observe
|
|
32
32
|
* each other's values — stronger than the ALS path, which remains for
|
|
33
|
-
* `useCookie()
|
|
33
|
+
* `useCookie()`.
|
|
34
34
|
*
|
|
35
35
|
* **What actually shifts a useId is a fork, not depth.** `useId` derives from
|
|
36
36
|
* React's tree context, which only changes where a fiber has more than one
|
|
@@ -142,7 +142,7 @@ export interface SsrWrapOptions {
|
|
|
142
142
|
*/
|
|
143
143
|
export function wrapSsrElement(element: ReactNode, opts: SsrWrapOptions): ReactNode {
|
|
144
144
|
// Build inside-out to match the client's createElement chain in
|
|
145
|
-
//
|
|
145
|
+
// browser-entry/router-init.ts renderTree(), which hydration builds with too.
|
|
146
146
|
|
|
147
147
|
// 1. Innermost: PayloadRoot publishes the payload's params over the tree.
|
|
148
148
|
const withParams = createElement(PayloadRoot, { source: opts.paramsSource }, element);
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
import type { ManifestRoot, ManifestSegmentNode, ManifestFile } from './route-matcher.ts';
|
|
23
23
|
import { hasDynamicSegments, hasUserSitemap, resolvePathWithParams } from './sitemap-generator.ts';
|
|
24
24
|
import { loadModule } from './safe-load.ts';
|
|
25
|
+
import { readAllBytesWithDeadline } from './stream-utils.ts';
|
|
26
|
+
import { DEFAULT_RENDER_TIMEOUT_MS, resolveRenderTimeoutMs } from './render-timeout.ts';
|
|
25
27
|
import { METADATA_ROUTE_CONVENTIONS, resolveServePathForFile } from './metadata-routes.ts';
|
|
26
28
|
import { RSC_CONTENT_TYPE } from '../shared/rsc-media-type.ts';
|
|
27
29
|
import {
|
|
@@ -346,8 +348,6 @@ function normalizeRedirectTarget(rawLocation: string): string {
|
|
|
346
348
|
|
|
347
349
|
// ─── Rendering ───────────────────────────────────────────────────────────
|
|
348
350
|
|
|
349
|
-
const DEFAULT_RENDER_TIMEOUT_MS = 30_000;
|
|
350
|
-
|
|
351
351
|
async function loadModuleWithTimeout(
|
|
352
352
|
file: ManifestFile,
|
|
353
353
|
timeoutMs: number
|
|
@@ -365,44 +365,6 @@ async function loadModuleWithTimeout(
|
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
async function drainResponse(response: Response, timeoutMs: number): Promise<Uint8Array> {
|
|
369
|
-
if (!response.body) return new Uint8Array(0);
|
|
370
|
-
|
|
371
|
-
const reader = response.body.getReader();
|
|
372
|
-
const chunks: Uint8Array[] = [];
|
|
373
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
374
|
-
let timedOut = false;
|
|
375
|
-
|
|
376
|
-
const deadline = new Promise<never>((_, reject) => {
|
|
377
|
-
timer = setTimeout(() => {
|
|
378
|
-
timedOut = true;
|
|
379
|
-
reject(new Error(`response did not complete within ${timeoutMs}ms`));
|
|
380
|
-
}, timeoutMs);
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
try {
|
|
384
|
-
for (;;) {
|
|
385
|
-
const { done, value } = await Promise.race([reader.read(), deadline]);
|
|
386
|
-
if (done) break;
|
|
387
|
-
chunks.push(value as Uint8Array);
|
|
388
|
-
}
|
|
389
|
-
} finally {
|
|
390
|
-
clearTimeout(timer);
|
|
391
|
-
// Always cancel — design/13-security.md A3: never leave a reader open.
|
|
392
|
-
await reader.cancel().catch(() => {});
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
let total = 0;
|
|
396
|
-
for (const c of chunks) total += c.byteLength;
|
|
397
|
-
const out = new Uint8Array(total);
|
|
398
|
-
let off = 0;
|
|
399
|
-
for (const c of chunks) {
|
|
400
|
-
out.set(c, off);
|
|
401
|
-
off += c.byteLength;
|
|
402
|
-
}
|
|
403
|
-
return out;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
368
|
function headersToRecord(headers: Headers): Record<string, string> {
|
|
407
369
|
const record: Record<string, string> = {};
|
|
408
370
|
headers.forEach((value, key) => {
|
|
@@ -428,7 +390,7 @@ export async function generateStaticSite(
|
|
|
428
390
|
options: StaticGenerationOptions
|
|
429
391
|
): Promise<StaticGenerationSummary> {
|
|
430
392
|
const log = options.log ?? ((msg: string) => console.log(msg));
|
|
431
|
-
const timeoutMs = options.renderTimeoutMs
|
|
393
|
+
const timeoutMs = resolveRenderTimeoutMs(options.renderTimeoutMs);
|
|
432
394
|
const summary: StaticGenerationSummary = {
|
|
433
395
|
rendered: 0,
|
|
434
396
|
errors: [],
|
|
@@ -705,7 +667,10 @@ async function renderUrl(
|
|
|
705
667
|
clearTimeout(timer);
|
|
706
668
|
}
|
|
707
669
|
|
|
708
|
-
|
|
670
|
+
// The reader is cancelled on every exit — design/13-security.md A3.
|
|
671
|
+
const body = response.body
|
|
672
|
+
? await readAllBytesWithDeadline(response.body, timeoutMs, 'response')
|
|
673
|
+
: new Uint8Array(0);
|
|
709
674
|
|
|
710
675
|
return {
|
|
711
676
|
status: response.status,
|
|
@@ -51,9 +51,9 @@ export interface NotFoundResult {
|
|
|
51
51
|
/**
|
|
52
52
|
* Whether the not-found chain has anything to render for this root.
|
|
53
53
|
*
|
|
54
|
-
* Asks the resolver rather than inspecting file names:
|
|
55
|
-
*
|
|
56
|
-
* these two calls, so this cannot drift from what the request path does. A
|
|
54
|
+
* Asks the resolver rather than inspecting file names: the no-match 404 (the
|
|
55
|
+
* deny fallback with no match, `rsc-entry/deny-fallback.ts`) builds its chain
|
|
56
|
+
* from the root segment alone and resolves through exactly these two calls, so this cannot drift from what the request path does. A
|
|
57
57
|
* hand-rolled key check gets it wrong — a root that declares only `500.tsx`
|
|
58
58
|
* has status files but nothing a 404 can select.
|
|
59
59
|
*/
|
|
@@ -290,3 +290,54 @@ function formatBytes(bytes: number): string {
|
|
|
290
290
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
|
|
291
291
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
292
292
|
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Read a byte stream to completion under one overall deadline and return
|
|
296
|
+
* the concatenated bytes. Every read is raced against the time remaining,
|
|
297
|
+
* and the reader is cancelled on every exit, so a stalled upstream never
|
|
298
|
+
* outlives the deadline. See design/02-rendering-pipeline.md §"Always
|
|
299
|
+
* Timeout-Guard Stream Reads".
|
|
300
|
+
*
|
|
301
|
+
* @param label - Prefix for the timeout error message. Both ways the deadline
|
|
302
|
+
* can pass (between reads, or while a read is pending) reject with the same
|
|
303
|
+
* `${label} did not complete within ${timeoutMs}ms`.
|
|
304
|
+
*/
|
|
305
|
+
export async function readAllBytesWithDeadline(
|
|
306
|
+
stream: ReadableStream<Uint8Array>,
|
|
307
|
+
timeoutMs: number,
|
|
308
|
+
label: string
|
|
309
|
+
): Promise<Uint8Array> {
|
|
310
|
+
const reader = stream.getReader();
|
|
311
|
+
const chunks: Uint8Array[] = [];
|
|
312
|
+
let totalLength = 0;
|
|
313
|
+
const deadline = Date.now() + timeoutMs;
|
|
314
|
+
const deadlineError = () => new Error(`${label} did not complete within ${timeoutMs}ms`);
|
|
315
|
+
try {
|
|
316
|
+
for (;;) {
|
|
317
|
+
const remaining = deadline - Date.now();
|
|
318
|
+
if (remaining <= 0) throw deadlineError();
|
|
319
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
320
|
+
const timeout = new Promise<never>((_, reject) => {
|
|
321
|
+
timer = setTimeout(() => reject(deadlineError()), remaining);
|
|
322
|
+
});
|
|
323
|
+
let result: ReadableStreamReadResult<Uint8Array>;
|
|
324
|
+
try {
|
|
325
|
+
result = await Promise.race([reader.read(), timeout]);
|
|
326
|
+
} finally {
|
|
327
|
+
clearTimeout(timer);
|
|
328
|
+
}
|
|
329
|
+
if (result.done) break;
|
|
330
|
+
chunks.push(result.value);
|
|
331
|
+
totalLength += result.value.byteLength;
|
|
332
|
+
}
|
|
333
|
+
} finally {
|
|
334
|
+
reader.cancel().catch(() => {});
|
|
335
|
+
}
|
|
336
|
+
const bytes = new Uint8Array(totalLength);
|
|
337
|
+
let offset = 0;
|
|
338
|
+
for (const chunk of chunks) {
|
|
339
|
+
bytes.set(chunk, offset);
|
|
340
|
+
offset += chunk.byteLength;
|
|
341
|
+
}
|
|
342
|
+
return bytes;
|
|
343
|
+
}
|