@timber-js/app 0.2.0-alpha.8 → 0.2.0-alpha.80
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-Dg-ANYHb.js +421 -0
- package/dist/_chunks/actions-Dg-ANYHb.js.map +1 -0
- package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
- package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
- package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
- package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
- package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
- package/dist/_chunks/define-C77ScO0m.js +106 -0
- package/dist/_chunks/define-C77ScO0m.js.map +1 -0
- package/dist/_chunks/define-CZqDwhSu.js +199 -0
- package/dist/_chunks/define-CZqDwhSu.js.map +1 -0
- package/dist/_chunks/define-cookie-C2IkoFGN.js +94 -0
- package/dist/_chunks/define-cookie-C2IkoFGN.js.map +1 -0
- package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
- package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
- package/dist/_chunks/format-CYBGxKtc.js +14 -0
- package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-Dpn_UfAD.js} +171 -97
- package/dist/_chunks/interception-Dpn_UfAD.js.map +1 -0
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
- package/dist/_chunks/request-context-qMsWgy9C.js +478 -0
- package/dist/_chunks/request-context-qMsWgy9C.js.map +1 -0
- package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
- package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
- package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
- package/dist/_chunks/stale-reload-C2plcNtG.js +64 -0
- package/dist/_chunks/stale-reload-C2plcNtG.js.map +1 -0
- package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
- package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
- package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
- package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-Lo_s_pw2.js} +4 -4
- package/dist/_chunks/use-query-states-Lo_s_pw2.js.map +1 -0
- package/dist/_chunks/wrappers-_DTmImGt.js +63 -0
- package/dist/_chunks/wrappers-_DTmImGt.js.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 +135 -11
- 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 +56 -13
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.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 +142 -80
- 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 +6 -1
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +27 -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 +10 -4
- 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 +2 -2
- 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 +7 -21
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +210 -1017
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +18 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +890 -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 +90 -32
- 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 +13 -2
- 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-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/top-loader.d.ts +5 -5
- package/dist/client/top-loader.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-params.d.ts +6 -4
- package/dist/client/use-params.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/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 +210 -0
- package/dist/config-types.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 +35 -14
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -83
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/index.d.ts +45 -192
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12296 -11901
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +84 -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 +3 -3
- package/dist/plugins/build-report.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-browser-logs.d.ts +84 -0
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
- package/dist/plugins/dev-error-overlay.d.ts +26 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/dev-logs.d.ts +1 -1
- package/dist/plugins/dev-logs.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 +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +19 -5
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +1 -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.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/index.d.ts +2 -0
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -2
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +46 -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 +16 -4
- package/dist/routing/types.d.ts.map +1 -1
- 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 +139 -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 +4 -474
- 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 +78 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +6 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +4 -0
- package/dist/server/access-gate.d.ts +4 -0
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +12 -1
- 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.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 +32 -4
- package/dist/server/als-registry.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/debug.d.ts +1 -1
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-page-resolver.d.ts +52 -0
- package/dist/server/deny-page-resolver.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-holding-server.d.ts +52 -0
- package/dist/server/dev-holding-server.d.ts.map +1 -0
- package/dist/server/dev-warnings.d.ts +1 -21
- package/dist/server/dev-warnings.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 +4 -3
- 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-injectors.d.ts +51 -11
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +6 -43
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +38 -2798
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +46 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +2883 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +25 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +19 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +113 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/page-deny-boundary.d.ts +31 -0
- package/dist/server/page-deny-boundary.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.d.ts +42 -10
- package/dist/server/pipeline.d.ts.map +1 -1
- 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 +112 -43
- 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 +9 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- 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 +48 -5
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +8 -3
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- 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 +4 -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/safe-load.d.ts +46 -0
- package/dist/server/safe-load.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 +22 -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/status-code-resolver.d.ts +1 -1
- 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 +4 -4
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +22 -19
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- 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 +1 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +3 -2
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/directive-parser.d.ts +5 -2
- 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 +53 -23
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/adapters/cloudflare.ts +342 -28
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +52 -8
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +38 -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 +24 -20
- package/src/cli.ts +6 -1
- package/src/client/browser-dev.ts +128 -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 +138 -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 +48 -16
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +2 -2
- package/src/client/history.ts +26 -4
- package/src/client/index.ts +19 -38
- package/src/client/internal.ts +57 -0
- package/src/client/link-pending-store.ts +111 -0
- package/src/client/link.tsx +329 -97
- 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 +31 -6
- 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 +299 -72
- package/src/client/rsc-fetch.ts +97 -8
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/stale-reload.ts +72 -3
- package/src/client/top-loader.tsx +16 -8
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-params.ts +7 -5
- package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
- package/src/client/use-query-states.ts +3 -3
- package/src/client/use-router.ts +1 -1
- package/src/codec.ts +49 -0
- package/src/config-types.ts +208 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +78 -25
- package/src/cookies/index.ts +8 -0
- package/src/fonts/css.ts +2 -1
- package/src/index.ts +258 -354
- package/src/plugin-context.ts +200 -0
- package/src/plugins/adapter-build.ts +8 -2
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +3 -3
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-browser-logs.ts +288 -0
- package/src/plugins/dev-error-overlay.ts +70 -1
- package/src/plugins/dev-logs.ts +1 -1
- package/src/plugins/dev-server.ts +70 -9
- package/src/plugins/entries.ts +71 -10
- package/src/plugins/fonts.ts +168 -61
- package/src/plugins/mdx.ts +1 -1
- package/src/plugins/routing.ts +57 -17
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +135 -35
- package/src/plugins/static-build.ts +17 -11
- package/src/routing/codegen.ts +165 -105
- package/src/routing/index.ts +2 -0
- package/src/routing/scanner.ts +93 -23
- package/src/routing/segment-classify.ts +89 -0
- package/src/routing/status-file-lint.ts +3 -2
- package/src/routing/types.ts +17 -4
- 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 +482 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +85 -0
- package/src/segment-params/define.ts +279 -0
- package/src/segment-params/index.ts +29 -0
- package/src/server/access-gate.tsx +70 -29
- package/src/server/action-client.ts +21 -2
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +21 -4
- package/src/server/actions.ts +10 -9
- package/src/server/als-registry.ts +34 -6
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/debug.ts +1 -1
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-page-resolver.ts +154 -0
- package/src/server/deny-renderer.ts +24 -38
- package/src/server/dev-holding-server.ts +185 -0
- package/src/server/dev-warnings.ts +4 -49
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +74 -22
- package/src/server/fallback-error.ts +31 -15
- 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-injectors.ts +280 -120
- package/src/server/index.ts +26 -177
- package/src/server/internal.ts +169 -0
- package/src/server/logger.ts +44 -36
- package/src/server/middleware-runner.ts +31 -4
- package/src/server/node-stream-transforms.ts +509 -0
- package/src/server/page-deny-boundary.tsx +56 -0
- package/src/server/pipeline-interception.ts +17 -16
- package/src/server/pipeline-metadata.ts +13 -0
- package/src/server/pipeline.ts +227 -62
- package/src/server/primitives.ts +111 -28
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +293 -132
- package/src/server/route-element-builder.ts +283 -191
- package/src/server/route-handler.ts +24 -4
- package/src/server/route-matcher.ts +24 -20
- package/src/server/rsc-entry/api-handler.ts +15 -16
- package/src/server/rsc-entry/error-renderer.ts +300 -89
- package/src/server/rsc-entry/helpers.ts +134 -5
- package/src/server/rsc-entry/index.ts +200 -112
- package/src/server/rsc-entry/rsc-payload.ts +65 -18
- package/src/server/rsc-entry/rsc-stream.ts +65 -13
- package/src/server/rsc-entry/ssr-bridge.ts +14 -5
- package/src/server/rsc-entry/ssr-renderer.ts +168 -38
- package/src/server/safe-load.ts +60 -0
- package/src/server/sitemap-generator.ts +338 -0
- package/src/server/sitemap-handler.ts +126 -0
- package/src/server/slot-resolver.ts +244 -229
- package/src/server/ssr-entry.ts +211 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/status-code-resolver.ts +1 -1
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +20 -9
- package/src/server/tree-builder.ts +92 -58
- package/src/server/types.ts +3 -6
- package/src/server/version-skew.ts +104 -0
- 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 +1 -1
- package/src/shims/navigation.ts +7 -2
- package/src/utils/directive-parser.ts +5 -2
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
- package/dist/_chunks/format-DviM89f0.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
- package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
- package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/_chunks/use-query-states-D5KaffOK.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 -21
- package/dist/client/browser-entry.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/cookies/index.js.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/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/search-params/index.js.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/response-cache.d.ts +0 -54
- package/dist/server/response-cache.d.ts.map +0 -1
- package/src/cache/register-cached-function.ts +0 -103
- package/src/client/browser-entry.ts +0 -678
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/transition-root.tsx +0 -166
- package/src/plugins/cache-transform.ts +0 -199
- 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/prerender.ts +0 -139
- package/src/server/response-cache.ts +0 -410
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Initialization — creates the timber router with all dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Wires up RouterDeps (fetch, history, scroll, RSC decoding, render
|
|
5
|
+
* callbacks) and optionally sets up Navigation API integration.
|
|
6
|
+
*
|
|
7
|
+
* See design/19-client-navigation.md §"Navigation API Integration"
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createElement } from 'react';
|
|
11
|
+
import { createFromFetch } from '../../rsc-runtime/browser.js';
|
|
12
|
+
import { createRouter, setGlobalRouter } from '#client-internal';
|
|
13
|
+
import type { RouterDeps, RouterInstance } from '#client-internal';
|
|
14
|
+
import type { NavigationState } from '#client-internal';
|
|
15
|
+
import { applyHeadElements } from '../head.js';
|
|
16
|
+
import { TimberNuqsAdapter } from '../nuqs-adapter.js';
|
|
17
|
+
import { NavigationProvider } from '../navigation-context.js';
|
|
18
|
+
import { transitionRender, navigateTransition } from '../navigation-root.js';
|
|
19
|
+
import { isStaleClientReference, triggerStaleReload } from '../stale-reload.js';
|
|
20
|
+
import {
|
|
21
|
+
hasNavigationApi,
|
|
22
|
+
setupNavigationApi,
|
|
23
|
+
type NavigationApiController,
|
|
24
|
+
} from '../navigation-api.js';
|
|
25
|
+
import { getScrollY } from './scroll.js';
|
|
26
|
+
|
|
27
|
+
export interface RouterInitResult {
|
|
28
|
+
router: RouterInstance;
|
|
29
|
+
navApiController: NavigationApiController | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create and register the global timber router.
|
|
34
|
+
*
|
|
35
|
+
* Must be called before hydrateRoot so `useRouter()` works during
|
|
36
|
+
* the initial render (methods lazily resolve the router at invocation,
|
|
37
|
+
* not render time, but initRouter must still run first).
|
|
38
|
+
*/
|
|
39
|
+
export function createTimberRouter(): RouterInitResult {
|
|
40
|
+
// Feature-detect Navigation API. When available, the navigate event
|
|
41
|
+
// replaces popstate for back/forward and catches external navigations.
|
|
42
|
+
// See design/19-client-navigation.md §"Navigation API Integration"
|
|
43
|
+
const useNavApi = hasNavigationApi();
|
|
44
|
+
|
|
45
|
+
const deps: RouterDeps = {
|
|
46
|
+
fetch: (url, init) => window.fetch(url, init),
|
|
47
|
+
pushState: (data, unused, url) => window.history.pushState(data, unused, url),
|
|
48
|
+
replaceState: (data, unused, url) => window.history.replaceState(data, unused, url),
|
|
49
|
+
navigationApiActive: useNavApi,
|
|
50
|
+
scrollTo: (x, y) => {
|
|
51
|
+
// Scroll the document viewport.
|
|
52
|
+
window.scrollTo(x, y);
|
|
53
|
+
document.documentElement.scrollTop = y;
|
|
54
|
+
document.body.scrollTop = y;
|
|
55
|
+
// Scroll any element explicitly marked as a scroll container.
|
|
56
|
+
// With segment tree merging, shared layouts (sidebars, nav bars)
|
|
57
|
+
// are reconciled in place via cloneElement — React preserves their
|
|
58
|
+
// DOM and scroll state naturally. We no longer auto-detect overflow
|
|
59
|
+
// containers, which previously found the wrong element (e.g.,
|
|
60
|
+
// scrolling a sidebar instead of the main content area).
|
|
61
|
+
// Use `data-timber-scroll-restoration` to opt in specific containers.
|
|
62
|
+
for (const el of document.querySelectorAll('[data-timber-scroll-restoration]')) {
|
|
63
|
+
(el as HTMLElement).scrollTop = y;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
getCurrentUrl: () => window.location.pathname + window.location.search,
|
|
67
|
+
getScrollY,
|
|
68
|
+
|
|
69
|
+
// Decode RSC Flight stream using createFromFetch.
|
|
70
|
+
// createFromFetch takes a Promise<Response> and progressively
|
|
71
|
+
// parses the RSC stream as chunks arrive.
|
|
72
|
+
//
|
|
73
|
+
// Wrapped with stale client reference detection: if the server
|
|
74
|
+
// has been redeployed with new bundles, the RSC payload may
|
|
75
|
+
// reference module IDs that don't exist in the old client bundle.
|
|
76
|
+
// We catch "Could not find the module" errors and trigger a full
|
|
77
|
+
// page reload so the browser fetches the new bundle.
|
|
78
|
+
decodeRsc: async (fetchPromise: Promise<Response>) => {
|
|
79
|
+
try {
|
|
80
|
+
// Wait for the full RSC stream to arrive before decoding.
|
|
81
|
+
// createFromFetch resolves on the first Flight chunk (the shell),
|
|
82
|
+
// but we need the transition to stay pending for the full response
|
|
83
|
+
// so useOptimistic (per-link pending) persists during slow navigations.
|
|
84
|
+
// Buffer the complete response, then decode from the buffered stream.
|
|
85
|
+
const response = await fetchPromise;
|
|
86
|
+
const body = await response.arrayBuffer();
|
|
87
|
+
const buffered = new Response(body, {
|
|
88
|
+
headers: response.headers,
|
|
89
|
+
status: response.status,
|
|
90
|
+
});
|
|
91
|
+
return await createFromFetch(Promise.resolve(buffered));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (isStaleClientReference(error)) {
|
|
94
|
+
triggerStaleReload();
|
|
95
|
+
return new Promise(() => {});
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
// Render decoded RSC tree via NavigationRoot's state-based mechanism.
|
|
102
|
+
// Used for non-navigation renders (popstate cached replay, applyRevalidation).
|
|
103
|
+
// Wraps with NavigationProvider + TimberNuqsAdapter.
|
|
104
|
+
//
|
|
105
|
+
// For navigation renders (navigate, refresh, popstate-with-fetch),
|
|
106
|
+
// navigateTransition is used instead — it wraps the entire navigation
|
|
107
|
+
// in a React transition with useOptimistic for the pending URL.
|
|
108
|
+
//
|
|
109
|
+
// navState is passed explicitly by the router — no temporal coupling
|
|
110
|
+
// with getNavigationState().
|
|
111
|
+
renderRoot: (element: unknown, navState: NavigationState) => {
|
|
112
|
+
const withNav = createElement(
|
|
113
|
+
NavigationProvider,
|
|
114
|
+
{ value: navState },
|
|
115
|
+
element as React.ReactNode
|
|
116
|
+
);
|
|
117
|
+
const wrapped = createElement(TimberNuqsAdapter, null, withNav);
|
|
118
|
+
transitionRender(wrapped);
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
// Run a navigation inside a React transition with optimistic pending URL.
|
|
122
|
+
// The entire fetch + state update runs inside startTransition. useOptimistic
|
|
123
|
+
// shows the pending URL immediately and reverts to null when the transition
|
|
124
|
+
// commits (atomic with the new tree + params).
|
|
125
|
+
//
|
|
126
|
+
// The perform callback receives a wrapPayload function that wraps the
|
|
127
|
+
// decoded RSC payload with NavigationProvider + NuqsAdapter. navState
|
|
128
|
+
// is passed explicitly by the router — no getNavigationState() needed.
|
|
129
|
+
navigateTransition: (pendingUrl: string, perform) => {
|
|
130
|
+
return navigateTransition(pendingUrl, async () => {
|
|
131
|
+
const payload = await perform((rawPayload: unknown, navState: NavigationState) => {
|
|
132
|
+
const withNav = createElement(
|
|
133
|
+
NavigationProvider,
|
|
134
|
+
{ value: navState },
|
|
135
|
+
rawPayload as React.ReactNode
|
|
136
|
+
);
|
|
137
|
+
return createElement(TimberNuqsAdapter, null, withNav);
|
|
138
|
+
});
|
|
139
|
+
return payload as React.ReactNode;
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Schedule a callback after the next paint so scroll operations
|
|
144
|
+
// happen after React commits the new content to the DOM.
|
|
145
|
+
// Double-rAF ensures the browser has painted the new frame.
|
|
146
|
+
afterPaint: (callback: () => void) => {
|
|
147
|
+
requestAnimationFrame(() => {
|
|
148
|
+
requestAnimationFrame(callback);
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// Apply resolved head elements (title, meta tags) to the DOM after
|
|
153
|
+
// SPA navigation. See design/16-metadata.md.
|
|
154
|
+
applyHead: applyHeadElements,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const router = createRouter(deps);
|
|
158
|
+
setGlobalRouter(router);
|
|
159
|
+
|
|
160
|
+
// Set up Navigation API integration after router is created.
|
|
161
|
+
// The navigate event listener delegates to router.navigate and
|
|
162
|
+
// router.handlePopState for external navigations and traversals.
|
|
163
|
+
let navApiController: NavigationApiController | null = null;
|
|
164
|
+
if (useNavApi) {
|
|
165
|
+
navApiController = setupNavigationApi({
|
|
166
|
+
onExternalNavigate: async (url, { replace, signal, scroll }) => {
|
|
167
|
+
// Navigation intercepted by the Navigation API. Covers both
|
|
168
|
+
// Link <a> clicks (user-initiated) and external navigations.
|
|
169
|
+
// The Navigation API handles the URL update via intercept(),
|
|
170
|
+
// so pass _skipHistory to avoid double pushState.
|
|
171
|
+
await router.navigate(url, {
|
|
172
|
+
replace,
|
|
173
|
+
scroll,
|
|
174
|
+
_signal: signal,
|
|
175
|
+
_skipHistory: true,
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
onTraverse: async (url, scrollY, signal) => {
|
|
179
|
+
// Back/forward — delegate to the router's popstate handler.
|
|
180
|
+
await router.handlePopState(url, scrollY, signal);
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Wire the router-navigating flag into RouterDeps.
|
|
185
|
+
// This must be done after setupNavigationApi returns the controller.
|
|
186
|
+
deps.setRouterNavigating = (v) => navApiController!.setRouterNavigating(v);
|
|
187
|
+
deps.saveNavigationEntryScroll = (y) => navApiController!.saveScrollPosition(y);
|
|
188
|
+
deps.completeRouterNavigation = () => navApiController!.completeRouterNavigation();
|
|
189
|
+
deps.navigationNavigate = (url, replace) => navApiController!.navigate(url, replace);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return { router, navApiController };
|
|
193
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSC Stream Bootstrap — decodes the server-inlined RSC payload.
|
|
3
|
+
*
|
|
4
|
+
* The RSC payload is embedded in the HTML as progressive inline script
|
|
5
|
+
* tags that call `self.__timber_f.push([type, data])` as RSC chunks arrive.
|
|
6
|
+
* Typed tuples: [0] = bootstrap signal, [1, string] = Flight data chunk.
|
|
7
|
+
*
|
|
8
|
+
* This module sets up a ReadableStream fed by those push() calls so
|
|
9
|
+
* `createFromReadableStream` can decode the Flight protocol progressively.
|
|
10
|
+
*
|
|
11
|
+
* See design/18-build-system.md §"Entry Files"
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createFromReadableStream } from '../../rsc-runtime/browser.js';
|
|
15
|
+
import { isPageUnloading } from '../unload-guard.js';
|
|
16
|
+
|
|
17
|
+
type FlightSegment = [isBootstrap: 0] | [isData: 1, data: string];
|
|
18
|
+
|
|
19
|
+
export interface RscStreamResult {
|
|
20
|
+
/** The decoded RSC element (thenable/lazy — resolved by React during render) */
|
|
21
|
+
element: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create the RSC payload stream from server-inlined `__timber_f` chunks.
|
|
26
|
+
*
|
|
27
|
+
* Returns null if no RSC payload was inlined (e.g., JS-only client).
|
|
28
|
+
* When a payload exists, returns the decoded element for hydration.
|
|
29
|
+
*/
|
|
30
|
+
export function createRscPayloadStream(): RscStreamResult | null {
|
|
31
|
+
// __timber_f is initialized in <head> via flightInitScript() (see
|
|
32
|
+
// flight-scripts.ts). If it doesn't exist, skip Flight decoding
|
|
33
|
+
// entirely and fall through to the createRoot branch.
|
|
34
|
+
// Do NOT defensively create it here: that would cause
|
|
35
|
+
// createFromReadableStream to be called on an empty stream, producing
|
|
36
|
+
// a "Connection closed" error on hydration. See TIM-552.
|
|
37
|
+
const timberChunks = (self as unknown as Record<string, FlightSegment[] | undefined>).__timber_f;
|
|
38
|
+
if (!timberChunks) return null;
|
|
39
|
+
|
|
40
|
+
const encoder = new TextEncoder();
|
|
41
|
+
|
|
42
|
+
// Buffer to hold string data until the stream writer is ready.
|
|
43
|
+
// Scripts that execute before hydration starts push data here.
|
|
44
|
+
let dataBuffer: string[] | undefined = [];
|
|
45
|
+
let streamWriter: ReadableStreamDefaultController<Uint8Array> | null = null;
|
|
46
|
+
let streamFlushed = false;
|
|
47
|
+
|
|
48
|
+
/** Process a typed tuple from __timber_f. */
|
|
49
|
+
function handleSegment(seg: FlightSegment): void {
|
|
50
|
+
if (seg[0] === 0) {
|
|
51
|
+
// Bootstrap signal — initialize buffer (already done above)
|
|
52
|
+
if (!dataBuffer) dataBuffer = [];
|
|
53
|
+
} else if (seg[0] === 1) {
|
|
54
|
+
// Flight data chunk
|
|
55
|
+
if (streamWriter) {
|
|
56
|
+
streamWriter.enqueue(encoder.encode(seg[1]));
|
|
57
|
+
} else if (dataBuffer) {
|
|
58
|
+
dataBuffer.push(seg[1]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Process any chunks that arrived before this script executed.
|
|
64
|
+
for (const seg of timberChunks) {
|
|
65
|
+
handleSegment(seg);
|
|
66
|
+
}
|
|
67
|
+
// Clear the array to release memory.
|
|
68
|
+
timberChunks.length = 0;
|
|
69
|
+
|
|
70
|
+
// Patch push() so subsequent script tags feed data in real time.
|
|
71
|
+
(timberChunks as unknown as { push: (seg: FlightSegment) => void }).push = handleSegment;
|
|
72
|
+
|
|
73
|
+
const rscPayload = new ReadableStream<Uint8Array>({
|
|
74
|
+
start(controller) {
|
|
75
|
+
streamWriter = controller;
|
|
76
|
+
// Flush buffered data into the stream.
|
|
77
|
+
if (dataBuffer) {
|
|
78
|
+
for (const data of dataBuffer) {
|
|
79
|
+
controller.enqueue(encoder.encode(data));
|
|
80
|
+
}
|
|
81
|
+
dataBuffer = undefined;
|
|
82
|
+
}
|
|
83
|
+
// If DOM already loaded (non-streaming or fast page), close now.
|
|
84
|
+
if (streamFlushed) {
|
|
85
|
+
controller.close();
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Close the stream when the document finishes loading.
|
|
91
|
+
// DOMContentLoaded fires after the HTML parser has processed all
|
|
92
|
+
// inline scripts (including streamed Suspense replacements and
|
|
93
|
+
// RSC data), so all push() calls have completed by this point.
|
|
94
|
+
//
|
|
95
|
+
// If the page is unloading (user refreshed or navigated away),
|
|
96
|
+
// do NOT close the stream. When the connection drops mid-stream,
|
|
97
|
+
// DOMContentLoaded fires because the parser finishes. Closing an
|
|
98
|
+
// incomplete RSC stream causes React's Flight client to throw
|
|
99
|
+
// "Connection closed." — a jarring error on a page being replaced.
|
|
100
|
+
// Leaving the stream open is harmless: the page is being torn down.
|
|
101
|
+
function onDOMContentLoaded(): void {
|
|
102
|
+
if (isPageUnloading()) return;
|
|
103
|
+
|
|
104
|
+
// In dev mode, do NOT close the stream. React's RSC renderer
|
|
105
|
+
// includes debug owner/stack references ($1, $14, etc.) in the
|
|
106
|
+
// Flight payload that point to rows delivered through the debug
|
|
107
|
+
// channel, not the main Flight stream. The browser Flight client
|
|
108
|
+
// tracks these as pending chunks. Closing the stream with
|
|
109
|
+
// unresolved chunks triggers reportGlobalError("Connection closed")
|
|
110
|
+
// which kills the entire React tree.
|
|
111
|
+
//
|
|
112
|
+
// Leaving the stream open is harmless: React has already received
|
|
113
|
+
// all data rows and can hydrate fully. The pending debug chunks
|
|
114
|
+
// just remain unresolved (they're only used for React DevTools
|
|
115
|
+
// component stacks, not rendering).
|
|
116
|
+
//
|
|
117
|
+
// In production, debug rows are not emitted, so closing is safe.
|
|
118
|
+
if (process.env.NODE_ENV === 'development') {
|
|
119
|
+
// Mark as flushed so no more data is buffered, but don't close.
|
|
120
|
+
streamFlushed = true;
|
|
121
|
+
dataBuffer = undefined;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (streamWriter && !streamFlushed) {
|
|
126
|
+
streamWriter.close();
|
|
127
|
+
streamFlushed = true;
|
|
128
|
+
dataBuffer = undefined;
|
|
129
|
+
}
|
|
130
|
+
streamFlushed = true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (document.readyState === 'loading') {
|
|
134
|
+
document.addEventListener('DOMContentLoaded', onDOMContentLoaded, false);
|
|
135
|
+
} else {
|
|
136
|
+
// DOM already parsed. All inline RSC <script> tags have already
|
|
137
|
+
// executed and pushed their data into the buffer. The buffer was
|
|
138
|
+
// flushed into the stream during start() above.
|
|
139
|
+
//
|
|
140
|
+
// Close via queueMicrotask rather than setTimeout. setTimeout
|
|
141
|
+
// defers to the next macrotask, which can race with React's
|
|
142
|
+
// Flight client read loop — if React finishes reading all queued
|
|
143
|
+
// chunks and issues a reader.read() that pends, the stream is
|
|
144
|
+
// NOT closed yet (setTimeout hasn't fired), so React sees an
|
|
145
|
+
// open stream and waits. Then setTimeout fires and closes it.
|
|
146
|
+
// This works in theory but some React Flight builds interpret
|
|
147
|
+
// a mid-read close as "Connection closed" rather than clean EOF.
|
|
148
|
+
// queueMicrotask fires at the end of the current microtask
|
|
149
|
+
// checkpoint — after start() and createFromReadableStream
|
|
150
|
+
// initialization but before any macrotask, giving React a
|
|
151
|
+
// consistent close signal. See TIM-524.
|
|
152
|
+
queueMicrotask(onDOMContentLoaded);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const element = createFromReadableStream(rscPayload);
|
|
156
|
+
return { element };
|
|
157
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll position helpers for the browser entry.
|
|
3
|
+
*
|
|
4
|
+
* Reads scroll position from the document viewport or explicitly marked
|
|
5
|
+
* `data-timber-scroll-restoration` containers.
|
|
6
|
+
*
|
|
7
|
+
* See design/19-client-navigation.md §"Overflow Scroll Containers".
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Read the current scroll position.
|
|
12
|
+
*
|
|
13
|
+
* Checks window scroll first, then explicit `data-timber-scroll-restoration`
|
|
14
|
+
* containers. With segment tree merging, shared layouts are reconciled in
|
|
15
|
+
* place via `cloneElement` — React preserves their DOM and scroll state
|
|
16
|
+
* naturally. We don't need to auto-detect overflow containers; only
|
|
17
|
+
* explicitly marked containers are tracked.
|
|
18
|
+
*/
|
|
19
|
+
export function getScrollY(): number {
|
|
20
|
+
if (window.scrollY || document.documentElement.scrollTop || document.body.scrollTop) {
|
|
21
|
+
return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop;
|
|
22
|
+
}
|
|
23
|
+
for (const el of document.querySelectorAll('[data-timber-scroll-restoration]')) {
|
|
24
|
+
if ((el as HTMLElement).scrollTop > 0) return (el as HTMLElement).scrollTop;
|
|
25
|
+
}
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
@@ -65,17 +65,24 @@ type ParsedDigest = DenyDigest | RenderErrorDigest | RedirectDigest;
|
|
|
65
65
|
|
|
66
66
|
export interface TimberErrorBoundaryProps {
|
|
67
67
|
/** The component to render when an error is caught. */
|
|
68
|
-
fallbackComponent
|
|
68
|
+
fallbackComponent?: (...args: unknown[]) => ReactNode;
|
|
69
|
+
/**
|
|
70
|
+
* Pre-rendered fallback element. Used for MDX status files which are server
|
|
71
|
+
* components and cannot be passed as function props across the RSC→client
|
|
72
|
+
* boundary. When set, rendered directly instead of calling fallbackComponent.
|
|
73
|
+
*
|
|
74
|
+
* See design/10-error-handling.md §"Status-Code File Variants" — MDX status
|
|
75
|
+
* files are server components by default (zero client JS).
|
|
76
|
+
*/
|
|
77
|
+
fallbackElement?: ReactNode;
|
|
69
78
|
/**
|
|
70
79
|
* Status code filter. If set, only catches errors matching this status.
|
|
71
80
|
* 400 = any 4xx, 500 = any 5xx, specific number = exact match.
|
|
72
81
|
*/
|
|
73
82
|
status?: number;
|
|
74
83
|
/**
|
|
75
|
-
* When true,
|
|
76
|
-
*
|
|
77
|
-
* boundaries should set this — segment boundaries (403.tsx, 4xx.tsx,
|
|
78
|
-
* error.tsx) must NOT, otherwise normal page denies get swallowed.
|
|
84
|
+
* When true, this boundary wraps a parallel slot. Slot denials are
|
|
85
|
+
* graceful degradation — they must NOT change the HTTP status code.
|
|
79
86
|
*/
|
|
80
87
|
isSlotBoundary?: boolean;
|
|
81
88
|
children: ReactNode;
|
|
@@ -148,20 +155,45 @@ export class TimberErrorBoundary extends Component<
|
|
|
148
155
|
}
|
|
149
156
|
}
|
|
150
157
|
|
|
151
|
-
// Report DenySignal handling
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
// Report DenySignal handling so the pipeline skips the redundant
|
|
159
|
+
// renderDenyPage() re-render — but ONLY when this boundary can fully
|
|
160
|
+
// handle the deny in-tree:
|
|
161
|
+
//
|
|
162
|
+
// ✅ TSX boundaries (fallbackComponent) — can receive runtime props
|
|
163
|
+
// (status, dangerouslyPassData) dynamically in render()
|
|
164
|
+
// ❌ MDX boundaries (fallbackElement) — pre-rendered at tree-build time,
|
|
165
|
+
// cannot receive runtime deny props. Must fall through to re-render.
|
|
166
|
+
//
|
|
167
|
+
// For qualifying segment boundaries: also set the HTTP status code from
|
|
168
|
+
// the DenySignal so the Response has the correct 4xx status. This runs
|
|
169
|
+
// synchronously during Fizz rendering, BEFORE onShellReady.
|
|
170
|
+
//
|
|
171
|
+
// For slot boundaries: set _denyHandledByBoundary but do NOT change
|
|
172
|
+
// statusCode — slot denials are graceful degradation.
|
|
173
|
+
//
|
|
174
|
+
// See TIM-664, LOCAL-298.
|
|
175
|
+
if (parsed?.type === 'deny') {
|
|
176
|
+
const canHandleInTree = this.props.fallbackElement == null;
|
|
177
|
+
|
|
178
|
+
if (canHandleInTree || this.props.isSlotBoundary) {
|
|
179
|
+
const ssrData = getSsrData();
|
|
180
|
+
if (ssrData?._navContext) {
|
|
181
|
+
ssrData._navContext._denyHandledByBoundary = true;
|
|
182
|
+
if (!this.props.isSlotBoundary) {
|
|
183
|
+
ssrData._navContext.statusCode = parsed.status;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
162
186
|
}
|
|
163
187
|
}
|
|
164
188
|
|
|
189
|
+
// Pre-rendered fallback element (MDX status files) — render directly.
|
|
190
|
+
// MDX components are server components that cannot be passed as function
|
|
191
|
+
// props across the RSC→client boundary. Instead, they are pre-rendered
|
|
192
|
+
// as elements in the RSC environment and passed here as fallbackElement.
|
|
193
|
+
if (this.props.fallbackElement != null) {
|
|
194
|
+
return this.props.fallbackElement;
|
|
195
|
+
}
|
|
196
|
+
|
|
165
197
|
// Render the fallback component with the right props shape.
|
|
166
198
|
if (parsed?.type === 'deny') {
|
|
167
199
|
return createElement(this.props.fallbackComponent as never, {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reconstitutes a SerializableError into a real Error instance before
|
|
5
|
+
* passing to the user's error component.
|
|
6
|
+
*
|
|
7
|
+
* TSX error pages are 'use client' components that receive { error: Error, digest, reset }.
|
|
8
|
+
* Error objects are not RSC-serializable (React Flight throws "Only plain objects
|
|
9
|
+
* can be passed to Client Components"). This wrapper receives the error as a plain
|
|
10
|
+
* SerializableError object, reconstitutes a real Error instance, and passes it
|
|
11
|
+
* to the user's error component — ensuring error instanceof Error works correctly.
|
|
12
|
+
*
|
|
13
|
+
* See design/spike-TIM-565-unify-error-pages.md §"Edge Case B"
|
|
14
|
+
* See design/10-error-handling.md §"RSC → SSR for Error Pages via SerializableError"
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { createElement, type ReactNode, type ComponentType } from 'react';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Plain-object representation of an Error that can cross the RSC → client boundary.
|
|
21
|
+
* Stack is only included in dev mode (gated by isDevMode() on the server).
|
|
22
|
+
*/
|
|
23
|
+
export interface SerializableError {
|
|
24
|
+
message: string;
|
|
25
|
+
name: string;
|
|
26
|
+
stack?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Props for the ErrorReconstituter wrapper component.
|
|
31
|
+
* All props are RSC-serializable:
|
|
32
|
+
* - error: plain object (SerializableError)
|
|
33
|
+
* - digest: plain JSON or null
|
|
34
|
+
* - reset: undefined (only meaningful on client after boundary catch)
|
|
35
|
+
* - component: client module reference (RSC Flight serializes as opaque ref)
|
|
36
|
+
*/
|
|
37
|
+
interface ErrorReconstituterProps {
|
|
38
|
+
error: SerializableError;
|
|
39
|
+
digest: { code: string; data: unknown } | null;
|
|
40
|
+
reset: undefined;
|
|
41
|
+
component: ComponentType<{
|
|
42
|
+
error: Error;
|
|
43
|
+
digest: { code: string; data: unknown } | null;
|
|
44
|
+
reset: (() => void) | undefined;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Reconstitute a SerializableError into a real Error instance and render
|
|
50
|
+
* the user's error component with the proper props.
|
|
51
|
+
*/
|
|
52
|
+
export function ErrorReconstituter({
|
|
53
|
+
error: serialized,
|
|
54
|
+
digest,
|
|
55
|
+
reset,
|
|
56
|
+
component,
|
|
57
|
+
}: ErrorReconstituterProps): ReactNode {
|
|
58
|
+
// Reconstitute a real Error so instanceof checks work in user code
|
|
59
|
+
const error = Object.assign(new Error(serialized.message), {
|
|
60
|
+
name: serialized.name,
|
|
61
|
+
...(serialized.stack != null ? { stack: serialized.stack } : {}),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return createElement(component, { error, digest, reset });
|
|
65
|
+
}
|
package/src/client/form.tsx
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { useActionState as reactUseActionState, useTransition } from 'react';
|
|
15
|
-
import type { ActionResult, ValidationErrors } from '
|
|
16
|
-
import type { FormFlashData } from '
|
|
15
|
+
import type { ActionResult, ValidationErrors } from '../server/action-client';
|
|
16
|
+
import type { FormFlashData } from '../server/form-flash';
|
|
17
17
|
|
|
18
18
|
// ─── Types ───────────────────────────────────────────────────────────────
|
|
19
19
|
|
package/src/client/history.ts
CHANGED
|
@@ -23,20 +23,42 @@ export interface HistoryEntry {
|
|
|
23
23
|
* On forward navigation, the new page's payload is pushed onto the stack.
|
|
24
24
|
* On popstate, the cached payload is replayed instantly.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* Supports two keying modes:
|
|
27
|
+
* - **URL-keyed** (default): entries keyed by pathname + search.
|
|
28
|
+
* Used with the History API fallback.
|
|
29
|
+
* - **Entry-key + URL**: when the Navigation API is available,
|
|
30
|
+
* entries can also be stored by Navigation entry key for
|
|
31
|
+
* disambiguation of duplicate URLs in the history stack.
|
|
32
|
+
* Falls back to URL lookup when entry key is not found.
|
|
33
|
+
*
|
|
34
|
+
* Scroll positions are stored in history.state or Navigation API entry
|
|
35
|
+
* state, not in this stack — see design/19-client-navigation.md §Scroll Restoration.
|
|
28
36
|
*
|
|
29
37
|
* Entries persist for the session duration (no expiry) and are cleared
|
|
30
38
|
* when the tab is closed — matching browser back-button behavior.
|
|
31
39
|
*/
|
|
32
40
|
export class HistoryStack {
|
|
33
41
|
private entries = new Map<string, HistoryEntry>();
|
|
42
|
+
/** Entries keyed by Navigation API entry key for duplicate URL disambiguation. */
|
|
43
|
+
private entryKeyMap = new Map<string, HistoryEntry>();
|
|
34
44
|
|
|
35
|
-
push(url: string, entry: HistoryEntry): void {
|
|
45
|
+
push(url: string, entry: HistoryEntry, entryKey?: string): void {
|
|
36
46
|
this.entries.set(url, entry);
|
|
47
|
+
if (entryKey) {
|
|
48
|
+
this.entryKeyMap.set(entryKey, entry);
|
|
49
|
+
}
|
|
37
50
|
}
|
|
38
51
|
|
|
39
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Get an entry. When an entry key is provided (Navigation API),
|
|
54
|
+
* tries the entry-key map first for accurate disambiguation of
|
|
55
|
+
* duplicate URLs, then falls back to URL lookup.
|
|
56
|
+
*/
|
|
57
|
+
get(url: string, entryKey?: string): HistoryEntry | undefined {
|
|
58
|
+
if (entryKey) {
|
|
59
|
+
const byKey = this.entryKeyMap.get(entryKey);
|
|
60
|
+
if (byKey) return byKey;
|
|
61
|
+
}
|
|
40
62
|
return this.entries.get(url);
|
|
41
63
|
}
|
|
42
64
|
|