@timber-js/app 0.2.0-alpha.1 → 0.2.0-alpha.100
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/LICENSE +8 -0
- package/dist/_chunks/actions-CQ8Z8VGL.js +1061 -0
- package/dist/_chunks/actions-CQ8Z8VGL.js.map +1 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js +61 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js.map +1 -0
- package/dist/_chunks/chunk-BYIpzuS7.js +39 -0
- package/dist/_chunks/define-B-Q_UMOD.js +195 -0
- package/dist/_chunks/define-B-Q_UMOD.js.map +1 -0
- package/dist/_chunks/define-CfBPoJb0.js +123 -0
- package/dist/_chunks/define-CfBPoJb0.js.map +1 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js +194 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js.map +1 -0
- package/dist/_chunks/format-Bcn-Iv1x.js +14 -0
- package/dist/_chunks/format-Bcn-Iv1x.js.map +1 -0
- package/dist/_chunks/handler-store-B-lqaGyh.js +54 -0
- package/dist/_chunks/handler-store-B-lqaGyh.js.map +1 -0
- package/dist/_chunks/logger-0m8MsKdc.js +291 -0
- package/dist/_chunks/logger-0m8MsKdc.js.map +1 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js +122 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js.map +1 -0
- package/dist/_chunks/{metadata-routes-CQCnF4VK.js → metadata-routes-BU684ls2.js} +1 -1
- package/dist/_chunks/{metadata-routes-CQCnF4VK.js.map → metadata-routes-BU684ls2.js.map} +1 -1
- package/dist/_chunks/navigation-root-BCYczjml.js +96 -0
- package/dist/_chunks/navigation-root-BCYczjml.js.map +1 -0
- package/dist/_chunks/registry-I2ss-lvy.js +20 -0
- package/dist/_chunks/registry-I2ss-lvy.js.map +1 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js +28 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js.map +1 -0
- package/dist/_chunks/schema-bridge-Cxu4l-7p.js +86 -0
- package/dist/_chunks/schema-bridge-Cxu4l-7p.js.map +1 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js +137 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -0
- package/dist/_chunks/segment-context-Dx_OizxD.js +34 -0
- package/dist/_chunks/segment-context-Dx_OizxD.js.map +1 -0
- package/dist/_chunks/{ssr-data-DLnbYpj1.js → ssr-data-B4CdH7rE.js} +1 -1
- package/dist/_chunks/ssr-data-B4CdH7rE.js.map +1 -0
- package/dist/_chunks/stale-reload-Bab885FO.js +64 -0
- package/dist/_chunks/stale-reload-Bab885FO.js.map +1 -0
- package/dist/_chunks/tracing-C8V-YGsP.js +329 -0
- package/dist/_chunks/tracing-C8V-YGsP.js.map +1 -0
- package/dist/_chunks/{use-query-states-DAhgj8Gx.js → use-query-states-B2XTqxDR.js} +7 -20
- package/dist/_chunks/use-query-states-B2XTqxDR.js.map +1 -0
- package/dist/_chunks/use-segment-params-BkpKAQ7D.js +185 -0
- package/dist/_chunks/use-segment-params-BkpKAQ7D.js.map +1 -0
- package/dist/_chunks/walkers-Tg0Alwcg.js +850 -0
- package/dist/_chunks/walkers-Tg0Alwcg.js.map +1 -0
- package/dist/_chunks/{format-DNt20Kt8.js → warnings-Cg47l5sk.js} +7 -45
- package/dist/_chunks/warnings-Cg47l5sk.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +28 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +73 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +95 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +148 -12
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +142 -38
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +17 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +143 -45
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +16 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/fast-hash.d.ts +22 -0
- package/dist/cache/fast-hash.d.ts.map +1 -0
- package/dist/cache/handler-store.d.ts +31 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +23 -7
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +195 -84
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/singleflight.d.ts +18 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts +22 -0
- package/dist/cache/sizeof.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +34 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +46 -0
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
- package/dist/client/browser-entry/index.d.ts +30 -0
- package/dist/client/browser-entry/index.d.ts.map +1 -0
- package/dist/client/browser-entry/post-hydration.d.ts +26 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +23 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +19 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/error-boundary.d.ts +12 -5
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +26 -5
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +54 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +16 -27
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/history.d.ts +19 -4
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +9 -24
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +312 -1109
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +19 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +964 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link-pending-store.d.ts +63 -0
- package/dist/client/link-pending-store.d.ts.map +1 -0
- package/dist/client/link.d.ts +73 -63
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/nav-link-store.d.ts +36 -0
- package/dist/client/nav-link-store.d.ts.map +1 -0
- package/dist/client/navigation-api-types.d.ts +90 -0
- package/dist/client/navigation-api-types.d.ts.map +1 -0
- package/dist/client/navigation-api.d.ts +115 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +22 -5
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/router.d.ts +70 -4
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +38 -3
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-merger.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +63 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +13 -4
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/state.d.ts +1 -1
- package/dist/client/top-loader.d.ts +5 -5
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts +8 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-link-status.d.ts +5 -5
- package/dist/client/use-link-status.d.ts.map +1 -1
- package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +7 -5
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +33 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +2 -0
- package/dist/config-types.d.ts +294 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-validation.d.ts +51 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts +98 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +2 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +36 -72
- package/dist/cookies/index.js.map +1 -1
- package/dist/cookies/json-cookie.d.ts +64 -0
- package/dist/cookies/json-cookie.d.ts.map +1 -0
- package/dist/cookies/validation.d.ts +46 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +46 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +84 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +58 -0
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/dev-tools/holding-server.d.ts +54 -0
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
- package/dist/dev-tools/instrumentation.d.ts.map +1 -0
- package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
- package/dist/dev-tools/logger.d.ts.map +1 -0
- package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +2 -2
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/dev-tools/overlay.d.ts +91 -0
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/dev-tools/terminal.d.ts +28 -0
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +2 -22
- package/dist/dev-tools/warnings.d.ts.map +1 -0
- package/dist/fonts/bundle.d.ts +48 -0
- package/dist/fonts/bundle.d.ts.map +1 -0
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/fonts/dev-middleware.d.ts +22 -0
- package/dist/fonts/dev-middleware.d.ts.map +1 -0
- package/dist/fonts/local.d.ts +4 -2
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/pipeline.d.ts +167 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +64 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +45 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +103 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +46 -152
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14702 -12350
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +107 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +2 -2
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +16 -4
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/chunks.d.ts +9 -1
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +32 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +8 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +17 -65
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +7 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts +6 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +4 -4
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +55 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +52 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts +41 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/index.d.ts +5 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -2
- package/dist/routing/link-codegen.d.ts +90 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +1 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +75 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/status-file-lint.d.ts +2 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +77 -25
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +51 -0
- package/dist/routing/walkers.d.ts.map +1 -0
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +76 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +157 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +34 -441
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/registry.d.ts +2 -2
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/segment-params/define.d.ts +95 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +3 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +2 -0
- package/dist/server/access-gate.d.ts +8 -3
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +41 -6
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts +35 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +3 -6
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +33 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +1 -15
- package/dist/server/asset-headers.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +170 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +51 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/debug.d.ts +82 -0
- package/dist/server/debug.d.ts.map +1 -0
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +90 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-source-map.d.ts +22 -0
- package/dist/server/dev-source-map.d.ts.map +1 -0
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +12 -7
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/flush.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +212 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +81 -41
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +9 -46
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +158 -2899
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +48 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +2900 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +39 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +36 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +110 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +26 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +95 -0
- package/dist/server/pipeline-helpers.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +6 -0
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +52 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +93 -23
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +117 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/primitives.d.ts +69 -18
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +41 -109
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +27 -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 +21 -34
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts +2 -2
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +49 -6
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +20 -3
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +50 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +20 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +119 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
- package/dist/server/rsc-prop-warnings.d.ts.map +1 -1
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/sensitive-fields.d.ts +74 -0
- package/dist/server/sensitive-fields.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +129 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +23 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +39 -21
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +50 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +16 -11
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +36 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +15 -5
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +62 -30
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +49 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/waituntil-bridge.d.ts.map +1 -1
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.d.ts +26 -0
- package/dist/shims/font-local.d.ts.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +3 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +11 -5
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/directive-parser.d.ts +1 -43
- package/dist/utils/directive-parser.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/package.json +56 -22
- package/src/adapters/build-output-helper.ts +77 -0
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/adapters/cloudflare.ts +350 -76
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +148 -60
- package/src/adapters/shared.ts +40 -0
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +38 -0
- package/src/cache/fast-hash.ts +34 -0
- package/src/cache/handler-store.ts +68 -0
- package/src/cache/index.ts +81 -18
- package/src/cache/singleflight.ts +62 -4
- package/src/cache/sizeof.ts +31 -0
- package/src/cache/timber-cache.ts +41 -29
- package/src/cli.ts +16 -6
- package/src/client/browser-dev.ts +153 -1
- package/src/client/browser-entry/action-dispatch.ts +116 -0
- package/src/client/browser-entry/hmr.ts +81 -0
- package/src/client/browser-entry/hydrate.ts +145 -0
- package/src/client/browser-entry/index.ts +143 -0
- package/src/client/browser-entry/post-hydration.ts +119 -0
- package/src/client/browser-entry/router-init.ts +193 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +27 -0
- package/src/client/error-boundary.tsx +97 -20
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +31 -32
- package/src/client/history.ts +26 -4
- package/src/client/index.ts +77 -43
- package/src/client/internal.ts +58 -0
- package/src/client/link-pending-store.ts +111 -0
- package/src/client/link.tsx +432 -140
- package/src/client/nav-link-store.ts +47 -0
- package/src/client/navigation-api-types.ts +112 -0
- package/src/client/navigation-api.ts +332 -0
- package/src/client/navigation-context.ts +83 -18
- package/src/client/navigation-root.tsx +342 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +303 -78
- package/src/client/rsc-fetch.ts +112 -8
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-context.ts +6 -1
- package/src/client/segment-merger.ts +2 -8
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/stale-reload.ts +74 -7
- package/src/client/state.ts +2 -2
- package/src/client/top-loader.tsx +41 -25
- package/src/client/use-cookie.ts +29 -0
- package/src/client/use-link-status.ts +7 -7
- package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
- package/src/client/use-query-states.ts +9 -3
- package/src/client/use-router.ts +1 -1
- package/src/client/{use-params.ts → use-segment-params.ts} +7 -5
- package/src/codec.ts +45 -0
- package/src/config-types.ts +292 -0
- package/src/config-validation.ts +303 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +301 -55
- package/src/cookies/index.ts +12 -1
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +134 -0
- package/src/dev-tools/404-page.ts +387 -0
- package/src/dev-tools/browser-logs.ts +288 -0
- package/src/dev-tools/error-page.ts +509 -0
- package/src/dev-tools/holding-server.ts +187 -0
- package/src/dev-tools/index.ts +90 -0
- package/src/dev-tools/instrumentation.ts +176 -0
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +3 -3
- package/src/dev-tools/overlay.ts +456 -0
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +183 -0
- package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +6 -50
- package/src/fonts/bundle.ts +142 -0
- package/src/fonts/css.ts +2 -1
- package/src/fonts/dev-middleware.ts +74 -0
- package/src/fonts/local.ts +7 -3
- package/src/fonts/pipeline.ts +314 -0
- package/src/fonts/transform.ts +406 -0
- package/src/fonts/types.ts +50 -1
- package/src/fonts/virtual-modules.ts +227 -0
- package/src/index.ts +376 -315
- package/src/plugin-context.ts +240 -0
- package/src/plugins/adapter-build.ts +12 -4
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +32 -21
- package/src/plugins/chunks.ts +9 -1
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-server.ts +154 -21
- package/src/plugins/entries.ts +119 -12
- package/src/plugins/fonts.ts +177 -524
- package/src/plugins/mdx.ts +52 -15
- package/src/plugins/routing.ts +225 -41
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +36 -1
- package/src/plugins/shims.ts +136 -35
- package/src/plugins/static-build.ts +17 -11
- package/src/routing/codegen-shared.ts +98 -0
- package/src/routing/codegen-types.ts +53 -0
- package/src/routing/codegen.ts +143 -176
- package/src/routing/convention-lint.ts +357 -0
- package/src/routing/index.ts +5 -1
- package/src/routing/interception.ts +1 -1
- package/src/routing/link-codegen.ts +294 -0
- package/src/routing/scanner.ts +107 -110
- package/src/routing/segment-classify.ts +188 -0
- package/src/routing/status-file-lint.ts +10 -7
- package/src/routing/types.ts +78 -25
- package/src/routing/walkers.ts +90 -0
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
- package/src/search-params/define.ts +538 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +92 -0
- package/src/segment-params/define.ts +332 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +79 -36
- package/src/server/action-client.ts +103 -20
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +112 -14
- package/src/server/actions.ts +10 -9
- package/src/server/als-registry.ts +35 -7
- package/src/server/asset-headers.ts +8 -34
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/cookie-context.ts +468 -0
- package/src/server/cookie-parsing.ts +135 -0
- package/src/server/debug.ts +137 -0
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-boundary.ts +218 -0
- package/src/server/deny-renderer.ts +33 -51
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +74 -22
- package/src/server/fallback-error.ts +74 -102
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injector-core.ts +403 -0
- package/src/server/html-injectors.ts +244 -223
- package/src/server/index.ts +31 -184
- package/src/server/internal.ts +176 -0
- package/src/server/logger.ts +67 -35
- package/src/server/middleware-runner.ts +75 -4
- package/src/server/node-stream-transforms.ts +369 -0
- package/src/server/param-coercion.ts +76 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +17 -16
- package/src/server/pipeline-metadata.ts +13 -0
- package/src/server/pipeline-outcome.ts +167 -0
- package/src/server/pipeline-phases.ts +409 -0
- package/src/server/pipeline.ts +128 -387
- package/src/server/port-resolution.ts +215 -0
- package/src/server/primitives.ts +113 -29
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +94 -337
- package/src/server/route-element-builder.ts +289 -198
- package/src/server/route-handler.ts +24 -4
- package/src/server/route-matcher.ts +44 -65
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +16 -17
- package/src/server/rsc-entry/error-renderer.ts +305 -89
- package/src/server/rsc-entry/helpers.ts +136 -12
- package/src/server/rsc-entry/index.ts +330 -312
- package/src/server/rsc-entry/render-route.ts +304 -0
- package/src/server/rsc-entry/rsc-payload.ts +100 -18
- package/src/server/rsc-entry/rsc-stream.ts +90 -17
- package/src/server/rsc-entry/ssr-bridge.ts +14 -5
- package/src/server/rsc-entry/ssr-renderer.ts +177 -37
- package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -0
- package/src/server/rsc-prop-warnings.ts +3 -1
- package/src/server/safe-load.ts +60 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/sitemap-generator.ts +338 -0
- package/src/server/sitemap-handler.ts +126 -0
- package/src/server/slot-resolver.ts +245 -230
- package/src/server/ssr-entry.ts +215 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/state-tree-diff.ts +4 -1
- package/src/server/status-code-resolver.ts +112 -128
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +44 -10
- package/src/server/tree-builder.ts +202 -90
- package/src/server/types.ts +55 -6
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/waituntil-bridge.ts +4 -1
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +5 -1
- package/src/shims/navigation-client.ts +4 -3
- package/src/shims/navigation.ts +14 -7
- package/src/utils/directive-parser.ts +1 -390
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-k-AtAQ9R.js +0 -41
- package/dist/_chunks/als-registry-k-AtAQ9R.js.map +0 -1
- package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
- package/dist/_chunks/interception-DGDIjDbR.js +0 -676
- package/dist/_chunks/interception-DGDIjDbR.js.map +0 -1
- package/dist/_chunks/request-context-CRj2Zh1E.js +0 -329
- package/dist/_chunks/request-context-CRj2Zh1E.js.map +0 -1
- package/dist/_chunks/ssr-data-DLnbYpj1.js.map +0 -1
- package/dist/_chunks/tracing-DF0G3FB7.js +0 -173
- package/dist/_chunks/tracing-DF0G3FB7.js.map +0 -1
- package/dist/_chunks/use-cookie-dDbpCTx-.js +0 -91
- package/dist/_chunks/use-cookie-dDbpCTx-.js.map +0 -1
- package/dist/_chunks/use-query-states-DAhgj8Gx.js.map +0 -1
- package/dist/cache/register-cached-function.d.ts +0 -17
- package/dist/cache/register-cached-function.d.ts.map +0 -1
- package/dist/client/browser-entry.d.ts +0 -22
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/browser-links.d.ts +0 -32
- package/dist/client/browser-links.d.ts.map +0 -1
- package/dist/client/link-navigate-interceptor.d.ts +0 -28
- package/dist/client/link-navigate-interceptor.d.ts.map +0 -1
- package/dist/client/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts +0 -60
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/codecs.d.ts +0 -53
- package/dist/search-params/codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
- package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/manifest-status-resolver.d.ts +0 -58
- package/dist/server/manifest-status-resolver.d.ts.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/src/cache/register-cached-function.ts +0 -99
- package/src/client/browser-entry.ts +0 -686
- package/src/client/browser-links.ts +0 -90
- package/src/client/link-navigate-interceptor.tsx +0 -62
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/transition-root.tsx +0 -160
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dev-error-overlay.ts +0 -230
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/prerender.ts +0 -139
- /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route renderer — turns a matched route into a Response.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `rsc-entry/index.ts` so the entry can stay focused on
|
|
5
|
+
* pipeline construction. This module owns the steps that happen *after*
|
|
6
|
+
* the pipeline has matched a route and before it commits a response:
|
|
7
|
+
* element-tree build, RSC Flight render, and dispatch to either the SSR
|
|
8
|
+
* HTML path or the RSC payload path. It also handles the
|
|
9
|
+
* synchronous-signal escape hatches (deny / redirect / render error
|
|
10
|
+
* thrown during stream creation) so the entry doesn't carry that logic.
|
|
11
|
+
*
|
|
12
|
+
* The function is parameterized over its dependencies — `clientBootstrap`,
|
|
13
|
+
* `clientJsDisabled`, `rootSegment`, `globalError` — so the entry passes
|
|
14
|
+
* them in once at handler-construction time and they ride along on every
|
|
15
|
+
* call. No globals, no closures over the entry's createRequestHandler
|
|
16
|
+
* scope.
|
|
17
|
+
*
|
|
18
|
+
* Design docs: 02-rendering-pipeline.md, 19-client-navigation.md.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { BuildManifest } from '../build-manifest.js';
|
|
22
|
+
import {
|
|
23
|
+
buildFontPreloadTags,
|
|
24
|
+
buildModulepreloadTags,
|
|
25
|
+
collectRouteFonts,
|
|
26
|
+
collectRouteModulepreloads,
|
|
27
|
+
} from '../build-manifest.js';
|
|
28
|
+
import { isDevMode } from '../debug.js';
|
|
29
|
+
import type { LayoutEntry } from '../deny-renderer.js';
|
|
30
|
+
import { renderDenyPage, renderDenyPageAsRsc } from '../deny-renderer.js';
|
|
31
|
+
import type { ClientBootstrapConfig } from '../html-injectors.js';
|
|
32
|
+
import type { InterceptionContext, RouteMatch } from '../pipeline.js';
|
|
33
|
+
import { buildRouteElement, ParamCoercionError } from '../route-element-builder.js';
|
|
34
|
+
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
35
|
+
import { recordTiming } from '../server-timing.js';
|
|
36
|
+
import { requestContextAls } from '../als-registry.js';
|
|
37
|
+
import { parseClientStateTree } from '../state-tree-diff.js';
|
|
38
|
+
|
|
39
|
+
import { handleApiRoute } from './api-handler.js';
|
|
40
|
+
import { renderErrorPage, renderNoMatchPage } from './error-renderer.js';
|
|
41
|
+
import {
|
|
42
|
+
buildRedirectResponse,
|
|
43
|
+
createDebugChannelSink,
|
|
44
|
+
escapeHtml,
|
|
45
|
+
isRscPayloadRequest,
|
|
46
|
+
} from './helpers.js';
|
|
47
|
+
import { buildRscPayloadResponse } from './rsc-payload.js';
|
|
48
|
+
import { renderRscStream } from './rsc-stream.js';
|
|
49
|
+
import { renderSsrResponse } from './ssr-renderer.js';
|
|
50
|
+
import { callSsr } from './ssr-bridge.js';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Static-per-handler dependencies for `renderRoute` — captured once at
|
|
54
|
+
* handler construction so each per-request call site only has to pass
|
|
55
|
+
* the request-specific arguments.
|
|
56
|
+
*/
|
|
57
|
+
export interface RenderRouteDeps {
|
|
58
|
+
clientBootstrap: ClientBootstrapConfig;
|
|
59
|
+
clientJsDisabled: boolean;
|
|
60
|
+
rootSegment: ManifestSegmentNode;
|
|
61
|
+
buildManifest: BuildManifest;
|
|
62
|
+
globalError?: { load: () => Promise<unknown>; filePath: string };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Render a matched route to an HTML Response via RSC → SSR pipeline,
|
|
67
|
+
* or return a raw RSC Flight stream for client-side navigation requests.
|
|
68
|
+
*
|
|
69
|
+
* 1. Load page/layout components from the segment chain
|
|
70
|
+
* 2. Resolve metadata
|
|
71
|
+
* 3. Render to RSC Flight stream (serializes "use client" as references)
|
|
72
|
+
* 4. If Accept: text/x-component → return RSC stream directly
|
|
73
|
+
* Otherwise → pass RSC stream to SSR entry for HTML rendering
|
|
74
|
+
*/
|
|
75
|
+
export async function renderRoute(
|
|
76
|
+
req: Request,
|
|
77
|
+
match: RouteMatch,
|
|
78
|
+
responseHeaders: Headers,
|
|
79
|
+
deps: RenderRouteDeps,
|
|
80
|
+
interception?: InterceptionContext
|
|
81
|
+
): Promise<Response> {
|
|
82
|
+
const { clientBootstrap, clientJsDisabled, rootSegment, buildManifest, globalError } = deps;
|
|
83
|
+
const segments = match.segments;
|
|
84
|
+
const leaf = segments[segments.length - 1];
|
|
85
|
+
|
|
86
|
+
// API routes (route.ts) — run access.ts standalone then dispatch to handler.
|
|
87
|
+
// No React render pass — AccessGate is not used, React.cache is not active.
|
|
88
|
+
// See design/04-authorization.md §"Auth in API Routes".
|
|
89
|
+
if (leaf.route && !leaf.page) {
|
|
90
|
+
return handleApiRoute(req, match, segments, responseHeaders);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Parse X-Timber-State-Tree for RSC payload requests (client navigation).
|
|
94
|
+
// The state tree lists sync segments the client has cached — the server
|
|
95
|
+
// skips re-rendering those layouts for a smaller, faster RSC payload.
|
|
96
|
+
// Only used for RSC requests — HTML requests always get a full render.
|
|
97
|
+
// See design/19-client-navigation.md §"X-Timber-State-Tree Header"
|
|
98
|
+
const clientStateTree = isRscPayloadRequest(req) ? parseClientStateTree(req) : null;
|
|
99
|
+
|
|
100
|
+
// Build the React element tree — loads modules, collects access checks,
|
|
101
|
+
// resolves metadata. Access checks are NOT run here — they run inside
|
|
102
|
+
// AccessPreRunner during renderToReadableStream so that access.ts and
|
|
103
|
+
// render components share the same React.cache scope (TIM-662).
|
|
104
|
+
//
|
|
105
|
+
// DenySignal/RedirectSignal from access checks are caught by onError
|
|
106
|
+
// during stream consumption and handled by renderSsrResponse /
|
|
107
|
+
// buildRscPayloadResponse.
|
|
108
|
+
let routeResult;
|
|
109
|
+
const _buildStart = performance.now();
|
|
110
|
+
try {
|
|
111
|
+
routeResult = await buildRouteElement(req, match, interception, clientStateTree);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
// Param coercion failed — render the custom 404 page (status files / not-found).
|
|
114
|
+
// Previously returned a bare Response(null, { status: 404 }) which bypassed
|
|
115
|
+
// custom not-found pages. Now routes through renderNoMatchPage so apps with
|
|
116
|
+
// 404.tsx / not-found status files render their custom page.
|
|
117
|
+
if (error instanceof ParamCoercionError) {
|
|
118
|
+
return renderNoMatchPage(req, rootSegment, responseHeaders, clientBootstrap);
|
|
119
|
+
}
|
|
120
|
+
// No PageComponent found — same treatment as param coercion: render custom 404.
|
|
121
|
+
if (error instanceof Error && error.message.startsWith('No page component')) {
|
|
122
|
+
return renderNoMatchPage(req, rootSegment, responseHeaders, clientBootstrap);
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const _buildEnd = performance.now();
|
|
128
|
+
recordTiming({
|
|
129
|
+
name: 'build',
|
|
130
|
+
dur: Math.round(_buildEnd - _buildStart),
|
|
131
|
+
desc: 'build element tree',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const { element, headElements, layoutComponents, deferSuspenseFor, skippedSegments } =
|
|
135
|
+
routeResult;
|
|
136
|
+
|
|
137
|
+
// Build head HTML for injection into the SSR output.
|
|
138
|
+
// Collects CSS, fonts, and modulepreload from the build manifest for matched segments.
|
|
139
|
+
// In dev mode the manifest is empty — Vite HMR handles CSS/JS.
|
|
140
|
+
//
|
|
141
|
+
// Link headers (for 103 Early Hints) are emitted by the earlyHints pipeline
|
|
142
|
+
// stage before middleware runs. Here we only emit the <head> HTML fallback tags
|
|
143
|
+
// — these ensure resources load even on platforms without Early Hints support.
|
|
144
|
+
let headHtml = '';
|
|
145
|
+
|
|
146
|
+
// CSS is handled by the RSC plugin via ReactDOM.preinit() with
|
|
147
|
+
// data-precedence attributes. This injects <link rel="stylesheet">
|
|
148
|
+
// tags during the RSC render phase — before our headHtml injection.
|
|
149
|
+
// We do NOT emit additional <link rel="stylesheet"> tags here because:
|
|
150
|
+
// 1. React's Float system deduplicates them, making ours redundant
|
|
151
|
+
// 2. The duplicate reference confuses React's client-side preload
|
|
152
|
+
// deduplication, causing "preload ignored" browser warnings
|
|
153
|
+
//
|
|
154
|
+
// CSS URLs are still collected for Early Hints (Link headers) in
|
|
155
|
+
// buildEarlyHintsHeaders() — those are HTTP headers, not DOM elements,
|
|
156
|
+
// so they don't conflict with Float.
|
|
157
|
+
|
|
158
|
+
// Font CSS is NOT inlined here anymore (TIM-828). The transform hook
|
|
159
|
+
// injects a side-effect `import 'virtual:timber-font-css/<hash>.css'`
|
|
160
|
+
// into each file that calls a font function. @vitejs/plugin-rsc's
|
|
161
|
+
// `collectCss` walks the RSC module graph, finds the virtual CSS
|
|
162
|
+
// module, and React Float `preinit()`s it as
|
|
163
|
+
// `<link rel="stylesheet" data-rsc-css-href=...>` — the same path
|
|
164
|
+
// component CSS rides on. Dev and production share a single path,
|
|
165
|
+
// with no `globalThis` channel and no dev/prod skew.
|
|
166
|
+
//
|
|
167
|
+
// Font preload hints (distinct from the @font-face CSS) still flow
|
|
168
|
+
// through `BuildManifest.fonts[importer]` and are emitted below plus
|
|
169
|
+
// as 103 Early Hints via `buildEarlyHintsHeaders()`.
|
|
170
|
+
const fontEntries = collectRouteFonts(segments, buildManifest);
|
|
171
|
+
if (fontEntries.length > 0) {
|
|
172
|
+
headHtml += buildFontPreloadTags(fontEntries);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Skip modulepreload tags when client JavaScript is disabled — no JS to preload.
|
|
176
|
+
if (!clientJsDisabled) {
|
|
177
|
+
const preloadUrls = collectRouteModulepreloads(segments, buildManifest);
|
|
178
|
+
if (preloadUrls.length > 0) {
|
|
179
|
+
headHtml += buildModulepreloadTags(preloadUrls);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
for (const el of headElements) {
|
|
184
|
+
if (el.tag === 'title' && el.content) {
|
|
185
|
+
headHtml += `<title>${escapeHtml(el.content)}</title>`;
|
|
186
|
+
} else if (el.attrs) {
|
|
187
|
+
const attrs = Object.entries(el.attrs)
|
|
188
|
+
.filter(([, v]) => v != null)
|
|
189
|
+
.map(([k, v]) => `${k}="${escapeHtml(v as string)}"`)
|
|
190
|
+
.join(' ');
|
|
191
|
+
headHtml += `<${el.tag} ${attrs}>`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// In dev mode, inject the browser log forwarding script so console
|
|
196
|
+
// errors/warnings from the browser appear in the server terminal.
|
|
197
|
+
// Set by timber-dev-browser-logs plugin via globalThis (TIM-575).
|
|
198
|
+
if (isDevMode()) {
|
|
199
|
+
const devLogScript = (globalThis as Record<string, unknown>).__timber_dev_browser_log_script as
|
|
200
|
+
| string
|
|
201
|
+
| undefined;
|
|
202
|
+
if (devLogScript) {
|
|
203
|
+
headHtml += devLogScript;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Render to RSC Flight stream with signal tracking.
|
|
208
|
+
const _rscStart = performance.now();
|
|
209
|
+
const { rscStream, signals, getDebugComponents } = renderRscStream(element, req);
|
|
210
|
+
|
|
211
|
+
// Store the debug components getter in ALS so onPipelineError can
|
|
212
|
+
// include component tree context for render-phase errors (dev mode only).
|
|
213
|
+
// Per-request via ALS — no cross-request race. See TIM-557.
|
|
214
|
+
const alsStore = requestContextAls.getStore();
|
|
215
|
+
if (alsStore) {
|
|
216
|
+
alsStore.debugComponentsGetter = getDebugComponents;
|
|
217
|
+
}
|
|
218
|
+
recordTiming({
|
|
219
|
+
name: 'rsc-init',
|
|
220
|
+
dur: Math.round(performance.now() - _rscStart),
|
|
221
|
+
desc: 'RSC stream init',
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Synchronous redirect — redirect() in access.ts or a non-async component
|
|
225
|
+
// throws during renderToReadableStream creation. Return HTTP redirect.
|
|
226
|
+
if (signals.redirectSignal) {
|
|
227
|
+
return buildRedirectResponse(req, signals.redirectSignal, responseHeaders);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Synchronous deny — deny() in a non-async component throws during
|
|
231
|
+
// renderToReadableStream creation, caught in the try/catch above.
|
|
232
|
+
if (signals.denySignal) {
|
|
233
|
+
if (isRscPayloadRequest(req)) {
|
|
234
|
+
return renderDenyPageAsRsc(
|
|
235
|
+
signals.denySignal,
|
|
236
|
+
segments,
|
|
237
|
+
layoutComponents as LayoutEntry[],
|
|
238
|
+
responseHeaders,
|
|
239
|
+
createDebugChannelSink
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
return renderDenyPage(
|
|
243
|
+
signals.denySignal,
|
|
244
|
+
segments,
|
|
245
|
+
layoutComponents as LayoutEntry[],
|
|
246
|
+
req,
|
|
247
|
+
match,
|
|
248
|
+
responseHeaders,
|
|
249
|
+
clientBootstrap,
|
|
250
|
+
createDebugChannelSink,
|
|
251
|
+
callSsr
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Synchronous render error — renderToReadableStream threw before
|
|
256
|
+
// creating the stream. Render the error page with correct 5xx status.
|
|
257
|
+
// (Async render errors are tracked in onError and handled after SSR.)
|
|
258
|
+
if (signals.renderError && !rscStream) {
|
|
259
|
+
return renderErrorPage(
|
|
260
|
+
signals.renderError.error,
|
|
261
|
+
signals.renderError.status,
|
|
262
|
+
segments,
|
|
263
|
+
layoutComponents as LayoutEntry[],
|
|
264
|
+
req,
|
|
265
|
+
match,
|
|
266
|
+
responseHeaders,
|
|
267
|
+
clientBootstrap,
|
|
268
|
+
globalError
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// For RSC payload requests (client navigation), return the RSC Flight
|
|
273
|
+
// stream directly — skip SSR HTML rendering entirely.
|
|
274
|
+
// See design/19-client-navigation.md §"RSC Payload Handling"
|
|
275
|
+
if (isRscPayloadRequest(req)) {
|
|
276
|
+
return buildRscPayloadResponse(
|
|
277
|
+
req,
|
|
278
|
+
rscStream!,
|
|
279
|
+
signals,
|
|
280
|
+
segments,
|
|
281
|
+
layoutComponents,
|
|
282
|
+
headElements,
|
|
283
|
+
match,
|
|
284
|
+
responseHeaders,
|
|
285
|
+
skippedSegments
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Pipe through SSR for HTML rendering with streaming Suspense support.
|
|
290
|
+
return renderSsrResponse({
|
|
291
|
+
req,
|
|
292
|
+
rscStream: rscStream!,
|
|
293
|
+
signals,
|
|
294
|
+
segments,
|
|
295
|
+
layoutComponents,
|
|
296
|
+
match,
|
|
297
|
+
responseHeaders,
|
|
298
|
+
clientBootstrap,
|
|
299
|
+
clientJsDisabled,
|
|
300
|
+
headHtml,
|
|
301
|
+
deferSuspenseFor,
|
|
302
|
+
globalError,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
* 16-metadata.md §"Head Elements"
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { LayoutEntry } from '
|
|
13
|
-
import { renderDenyPageAsRsc } from '
|
|
14
|
-
import type { RouteMatch } from '
|
|
15
|
-
import type { RedirectSignal } from '
|
|
16
|
-
import type { HeadElement, LayoutComponentEntry } from '
|
|
17
|
-
import type { ManifestSegmentNode } from '
|
|
12
|
+
import type { LayoutEntry } from '../deny-renderer.js';
|
|
13
|
+
import { renderDenyPageAsRsc } from '../deny-renderer.js';
|
|
14
|
+
import type { RouteMatch } from '../pipeline.js';
|
|
15
|
+
import type { RedirectSignal } from '../primitives.js';
|
|
16
|
+
import type { HeadElement, LayoutComponentEntry } from '../route-element-builder.js';
|
|
17
|
+
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
20
|
buildRedirectResponse,
|
|
@@ -45,15 +45,60 @@ export async function buildRscPayloadResponse(
|
|
|
45
45
|
skippedSegments?: string[]
|
|
46
46
|
): Promise<Response> {
|
|
47
47
|
// Read the first chunk from the RSC stream before committing headers.
|
|
48
|
+
// Race the first read against signal detection — if an async component
|
|
49
|
+
// throws a RedirectSignal or DenySignal, the onError callback fires
|
|
50
|
+
// signals.onSignal() and we can react immediately without waiting for
|
|
51
|
+
// the full macrotask queue.
|
|
52
|
+
//
|
|
53
|
+
// The rejection chain for an async-wrapped page component:
|
|
54
|
+
// 1. PageComponent throws RedirectSignal
|
|
55
|
+
// 2. withSpan catches and re-throws (microtask 1)
|
|
56
|
+
// 3. TracedPage promise rejects (microtask 2)
|
|
57
|
+
// 4. React Flight rejection handler → onError (microtask 3+)
|
|
58
|
+
//
|
|
59
|
+
// Promise.race reacts the instant onError fires, eliminating the
|
|
60
|
+
// per-request setTimeout(0) macrotask delay for the common case
|
|
61
|
+
// (no signal). A 50ms ceiling timeout guards against edge cases
|
|
62
|
+
// where onError never fires.
|
|
48
63
|
const reader = rscStream.getReader();
|
|
49
|
-
const
|
|
64
|
+
const signalDetected = new Promise<void>((resolve) => {
|
|
65
|
+
signals.onSignal = resolve;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
type RaceResult =
|
|
69
|
+
| { type: 'data'; chunk: ReadableStreamReadResult<Uint8Array> }
|
|
70
|
+
| { type: 'signal' };
|
|
71
|
+
|
|
72
|
+
let first: RaceResult;
|
|
73
|
+
try {
|
|
74
|
+
first = await Promise.race([
|
|
75
|
+
reader.read().then((chunk) => ({ type: 'data' as const, chunk })),
|
|
76
|
+
signalDetected.then(() => ({ type: 'signal' as const })),
|
|
77
|
+
]);
|
|
78
|
+
} catch (_readError) {
|
|
79
|
+
// RSC stream failed on first read — unhandled error in the page component.
|
|
80
|
+
// Return an error response so the client can hard-navigate for the
|
|
81
|
+
// SSR-rendered error page. See design/10-error-handling.md.
|
|
82
|
+
reader.cancel().catch(() => {});
|
|
83
|
+
signals.onSignal = undefined;
|
|
84
|
+
responseHeaders.set('X-Timber-Error', '1');
|
|
85
|
+
responseHeaders.set('content-type', 'application/json; charset=utf-8');
|
|
86
|
+
return new Response(JSON.stringify({ error: true, status: 500 }), {
|
|
87
|
+
status: 500,
|
|
88
|
+
headers: responseHeaders,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// If data arrived first, still check signals — they may have fired
|
|
93
|
+
// concurrently. Also do a final ceiling timeout check for edge cases
|
|
94
|
+
// where the signal fires just after the first read resolves.
|
|
95
|
+
if (first.type === 'data' && !signals.redirectSignal && !signals.denySignal) {
|
|
96
|
+
// Brief yield to let any in-flight microtask rejections complete.
|
|
97
|
+
await new Promise<void>((r) => setTimeout(r, 0));
|
|
98
|
+
}
|
|
50
99
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
// propagate to the onError callback before we check the signals.
|
|
54
|
-
// The rejected Promise from an async component resolves in the next
|
|
55
|
-
// microtask after read(), so we need at least one tick.
|
|
56
|
-
await new Promise<void>((r) => setTimeout(r, 0));
|
|
100
|
+
// Detach the callback — no longer needed after this point.
|
|
101
|
+
signals.onSignal = undefined;
|
|
57
102
|
|
|
58
103
|
// Check for redirect/deny signals detected during initial rendering
|
|
59
104
|
const trackedRedirect = signals.redirectSignal as RedirectSignal | null;
|
|
@@ -72,6 +117,37 @@ export async function buildRscPayloadResponse(
|
|
|
72
117
|
);
|
|
73
118
|
}
|
|
74
119
|
|
|
120
|
+
// Check for unhandled errors (RenderError or plain Error).
|
|
121
|
+
// These aren't redirect/deny signals but the RSC stream will be broken.
|
|
122
|
+
// Return an error response so the client can hard-navigate for the
|
|
123
|
+
// SSR-rendered error page. See design/10-error-handling.md
|
|
124
|
+
// §"Error Page Rendering for Client Navigation".
|
|
125
|
+
if (signals.renderError) {
|
|
126
|
+
reader.cancel().catch(() => {});
|
|
127
|
+
responseHeaders.set('X-Timber-Error', '1');
|
|
128
|
+
responseHeaders.set('content-type', 'application/json; charset=utf-8');
|
|
129
|
+
return new Response(
|
|
130
|
+
JSON.stringify({
|
|
131
|
+
error: true,
|
|
132
|
+
status: signals.renderError.status,
|
|
133
|
+
}),
|
|
134
|
+
{ status: signals.renderError.status, headers: responseHeaders }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Extract the first chunk from the race result.
|
|
139
|
+
// If the signal won the race but neither redirect nor deny was detected
|
|
140
|
+
// (edge case), cancel the reader immediately rather than issuing a bare
|
|
141
|
+
// read() that could hang forever if the RSC stream has stalled.
|
|
142
|
+
// See TIM-519.
|
|
143
|
+
let firstRead: ReadableStreamReadResult<Uint8Array>;
|
|
144
|
+
if (first.type === 'data') {
|
|
145
|
+
firstRead = first.chunk;
|
|
146
|
+
} else {
|
|
147
|
+
await reader.cancel();
|
|
148
|
+
firstRead = { done: true, value: undefined };
|
|
149
|
+
}
|
|
150
|
+
|
|
75
151
|
// Reconstruct the stream: prepend the buffered first chunk,
|
|
76
152
|
// then continue piping from the original reader.
|
|
77
153
|
const patchedStream = new ReadableStream<Uint8Array>({
|
|
@@ -120,14 +196,20 @@ export async function buildRscPayloadResponse(
|
|
|
120
196
|
responseHeaders.set('X-Timber-Skipped-Segments', JSON.stringify(skippedSegments));
|
|
121
197
|
}
|
|
122
198
|
|
|
123
|
-
// Send route params so the client can populate
|
|
124
|
-
// SPA navigation. Without this,
|
|
125
|
-
if (Object.keys(match.
|
|
126
|
-
responseHeaders.set('X-Timber-Params', JSON.stringify(match.
|
|
199
|
+
// Send route params so the client can populate useSegmentParams() after
|
|
200
|
+
// SPA navigation. Without this, useSegmentParams() returns {}.
|
|
201
|
+
if (Object.keys(match.segmentParams).length > 0) {
|
|
202
|
+
responseHeaders.set('X-Timber-Params', JSON.stringify(match.segmentParams));
|
|
127
203
|
}
|
|
128
204
|
|
|
205
|
+
// Check if a DenySignal was caught in-tree by AccessGate or
|
|
206
|
+
// PageDenyBoundary. The deny page is in the Flight stream as a normal
|
|
207
|
+
// element — use the deny status for the HTTP response. See TIM-666.
|
|
208
|
+
const { getDenyStatus } = await import('../deny-boundary.js');
|
|
209
|
+
const denyStatus = getDenyStatus();
|
|
210
|
+
|
|
129
211
|
return new Response(patchedStream, {
|
|
130
|
-
status: 200,
|
|
212
|
+
status: denyStatus ?? 200,
|
|
131
213
|
headers: responseHeaders,
|
|
132
214
|
});
|
|
133
215
|
}
|
|
@@ -10,29 +10,56 @@
|
|
|
10
10
|
* 13-security.md §"Errors don't leak"
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { renderToReadableStream } from '
|
|
13
|
+
import { renderToReadableStream } from '../../rsc-runtime/rsc.js';
|
|
14
14
|
|
|
15
|
-
import {
|
|
16
|
-
import { DenySignal, RedirectSignal, RenderError } from '#/server/primitives.js';
|
|
17
|
-
import { checkAndWarnRscPropError } from '#/server/rsc-prop-warnings.js';
|
|
15
|
+
import { randomUUID } from 'node:crypto';
|
|
18
16
|
|
|
19
|
-
import {
|
|
17
|
+
import { logRenderError } from '../logger.js';
|
|
18
|
+
import { DenySignal, RedirectSignal, RenderError } from '../primitives.js';
|
|
19
|
+
import { checkAndWarnRscPropError } from '../rsc-prop-warnings.js';
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
createDebugChannelSink,
|
|
23
|
+
createDebugChannelCollector,
|
|
24
|
+
isAbortError,
|
|
25
|
+
type DebugComponentEntry,
|
|
26
|
+
} from './helpers.js';
|
|
27
|
+
import { isDebug } from '../debug.js';
|
|
28
|
+
import { isDevMode } from '../debug.js';
|
|
20
29
|
|
|
21
30
|
/**
|
|
22
31
|
* Mutable signal state captured during RSC rendering.
|
|
23
32
|
*
|
|
24
33
|
* Signals fire asynchronously via `onError` during stream consumption.
|
|
25
34
|
* The first signal of each type wins — subsequent signals are ignored.
|
|
35
|
+
*
|
|
36
|
+
* `onSignal` is an optional callback fired when a DenySignal or
|
|
37
|
+
* RedirectSignal is captured. Consumers use it with Promise.race to
|
|
38
|
+
* react immediately instead of polling with setTimeout/queueMicrotask.
|
|
26
39
|
*/
|
|
27
40
|
export interface RenderSignals {
|
|
28
41
|
denySignal: DenySignal | null;
|
|
29
42
|
redirectSignal: RedirectSignal | null;
|
|
30
43
|
renderError: { error: unknown; status: number } | null;
|
|
44
|
+
/**
|
|
45
|
+
* The last unhandled error seen by RSC onError that isn't a signal.
|
|
46
|
+
* Used as a fallback when SSR fails (SsrStreamError) but no structured
|
|
47
|
+
* signal was captured — provides the original error for the error page
|
|
48
|
+
* instead of relying on SsrStreamError.cause extraction.
|
|
49
|
+
*
|
|
50
|
+
* NOT used for page-level error detection (that would break Suspense
|
|
51
|
+
* error isolation). Only consumed when SSR actually fails.
|
|
52
|
+
*/
|
|
53
|
+
lastUnhandledError: unknown | null;
|
|
54
|
+
/** Callback fired when a redirect or deny signal is captured in onError. */
|
|
55
|
+
onSignal?: () => void;
|
|
31
56
|
}
|
|
32
57
|
|
|
33
58
|
export interface RscStreamResult {
|
|
34
59
|
rscStream: ReadableStream<Uint8Array> | undefined;
|
|
35
60
|
signals: RenderSignals;
|
|
61
|
+
/** Dev-only: server component debug info from the Flight debug channel. */
|
|
62
|
+
getDebugComponents?: () => DebugComponentEntry[];
|
|
36
63
|
}
|
|
37
64
|
|
|
38
65
|
/**
|
|
@@ -51,10 +78,15 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
51
78
|
denySignal: null,
|
|
52
79
|
redirectSignal: null,
|
|
53
80
|
renderError: null,
|
|
81
|
+
lastUnhandledError: null,
|
|
54
82
|
};
|
|
55
83
|
|
|
56
84
|
let rscStream: ReadableStream<Uint8Array> | undefined;
|
|
57
85
|
|
|
86
|
+
// In dev mode, collect debug channel data for the error overlay.
|
|
87
|
+
// In production, use the discard sink (no overhead).
|
|
88
|
+
const debugChannel = isDevMode() ? createDebugChannelCollector() : createDebugChannelSink();
|
|
89
|
+
|
|
58
90
|
try {
|
|
59
91
|
rscStream = renderToReadableStream(
|
|
60
92
|
element,
|
|
@@ -66,11 +98,13 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
66
98
|
if (isAbortError(error) || req.signal?.aborted) return;
|
|
67
99
|
if (error instanceof DenySignal) {
|
|
68
100
|
signals.denySignal = error;
|
|
101
|
+
signals.onSignal?.();
|
|
69
102
|
// Return structured digest for client-side error boundaries
|
|
70
103
|
return JSON.stringify({ type: 'deny', status: error.status, data: error.data });
|
|
71
104
|
}
|
|
72
105
|
if (error instanceof RedirectSignal) {
|
|
73
106
|
signals.redirectSignal = error;
|
|
107
|
+
signals.onSignal?.();
|
|
74
108
|
return JSON.stringify({
|
|
75
109
|
type: 'redirect',
|
|
76
110
|
location: error.location,
|
|
@@ -97,11 +131,7 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
97
131
|
// directive isn't at the very top of the file, or the component is
|
|
98
132
|
// re-exported through a barrel file without 'use client'.
|
|
99
133
|
// See LOCAL-297.
|
|
100
|
-
if (
|
|
101
|
-
process.env.NODE_ENV !== 'production' &&
|
|
102
|
-
error instanceof Error &&
|
|
103
|
-
error.message.includes('Invalid hook call')
|
|
104
|
-
) {
|
|
134
|
+
if (isDebug() && error instanceof Error && error.message.includes('Invalid hook call')) {
|
|
105
135
|
console.error(
|
|
106
136
|
'[timber] A React hook was called during RSC rendering. This usually means a ' +
|
|
107
137
|
"'use client' component is being executed as a server component instead of " +
|
|
@@ -121,13 +151,47 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
121
151
|
checkAndWarnRscPropError(error, new URL(req.url).pathname);
|
|
122
152
|
}
|
|
123
153
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
154
|
+
// Log the error but do NOT track it as a page-level render error.
|
|
155
|
+
// If this error is inside a <Suspense> boundary, React will emit
|
|
156
|
+
// an error row in the Flight stream and the Suspense fallback will
|
|
157
|
+
// render on the client. Tracking it as signals.renderError would
|
|
158
|
+
// cause the pipeline to treat the entire page as a 500, even though
|
|
159
|
+
// the shell rendered successfully. See TIM-524.
|
|
160
|
+
//
|
|
161
|
+
// Only track as renderError if no Suspense boundary contains it —
|
|
162
|
+
// React will call onShellError for truly unrecoverable errors.
|
|
163
|
+
|
|
164
|
+
// Track the last unhandled error so the pipeline can use it
|
|
165
|
+
// if SSR fails (SsrStreamError). This is NOT used for page-level
|
|
166
|
+
// error detection — only as a fallback when SSR actually fails.
|
|
167
|
+
signals.lastUnhandledError = error;
|
|
168
|
+
|
|
169
|
+
// Return a digest so React emits a per-row error in the Flight
|
|
170
|
+
// stream instead of leaving the lazy reference unresolved.
|
|
171
|
+
//
|
|
172
|
+
// SECURITY: Never include error.message in the digest — it may
|
|
173
|
+
// contain SQL queries, filesystem paths, secret fragments, or
|
|
174
|
+
// internal IDs. Use a generic message with a correlation ID so
|
|
175
|
+
// the error can be matched to server logs.
|
|
176
|
+
// See design/13-security.md §"Errors don't leak".
|
|
177
|
+
const errorId = randomUUID();
|
|
178
|
+
logRenderError({
|
|
179
|
+
method: req.method,
|
|
180
|
+
path: new URL(req.url).pathname,
|
|
181
|
+
error,
|
|
182
|
+
errorId,
|
|
183
|
+
});
|
|
184
|
+
return JSON.stringify({
|
|
185
|
+
type: 'error',
|
|
186
|
+
message: isDevMode()
|
|
187
|
+
? error instanceof Error
|
|
188
|
+
? error.message
|
|
189
|
+
: String(error)
|
|
190
|
+
: 'An unexpected error occurred.',
|
|
191
|
+
errorId,
|
|
192
|
+
});
|
|
129
193
|
},
|
|
130
|
-
debugChannel
|
|
194
|
+
debugChannel,
|
|
131
195
|
},
|
|
132
196
|
{
|
|
133
197
|
onClientReference(info: { id: string; name: string; deps: unknown }) {
|
|
@@ -155,5 +219,14 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
155
219
|
}
|
|
156
220
|
}
|
|
157
221
|
|
|
158
|
-
return {
|
|
222
|
+
return {
|
|
223
|
+
rscStream,
|
|
224
|
+
signals,
|
|
225
|
+
// Expose the debug channel collector's getComponents in dev mode.
|
|
226
|
+
// The caller can retrieve component tree info when handling errors.
|
|
227
|
+
getDebugComponents:
|
|
228
|
+
'getComponents' in debugChannel
|
|
229
|
+
? (debugChannel as { getComponents: () => DebugComponentEntry[] }).getComponents
|
|
230
|
+
: undefined,
|
|
231
|
+
};
|
|
159
232
|
}
|
|
@@ -4,15 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
/// <reference types="@vitejs/plugin-rsc/types" />
|
|
6
6
|
|
|
7
|
-
import type { NavContext } from '
|
|
7
|
+
import type { NavContext } from '../ssr-entry.js';
|
|
8
8
|
|
|
9
9
|
export async function callSsr(
|
|
10
10
|
rscStream: ReadableStream<Uint8Array>,
|
|
11
11
|
navContext: NavContext
|
|
12
12
|
): Promise<Response> {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
let ssrEntry: typeof import('../ssr-entry.js');
|
|
14
|
+
try {
|
|
15
|
+
ssrEntry = await import.meta.viteRsc.import<typeof import('../ssr-entry.js')>(
|
|
16
|
+
'../ssr-entry.js',
|
|
17
|
+
{ environment: 'ssr' }
|
|
18
|
+
);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
const original = error instanceof Error ? error.message : String(error);
|
|
21
|
+
throw new Error(
|
|
22
|
+
`[timber] Failed to load SSR entry from RSC environment.\n ${original}\n This usually means a module evaluation error in the SSR bundle.`,
|
|
23
|
+
{ cause: error }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
17
26
|
return ssrEntry.handleSsr(rscStream, navContext);
|
|
18
27
|
}
|