@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
|
@@ -16,18 +16,21 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { createElement } from 'react';
|
|
19
|
-
import { renderToReadableStream } from '
|
|
19
|
+
import { renderToReadableStream } from '../rsc-runtime/rsc.js';
|
|
20
20
|
|
|
21
21
|
import { DenySignal } from './primitives.js';
|
|
22
22
|
import { logRenderError } from './logger.js';
|
|
23
|
+
import { loadModule } from './safe-load.js';
|
|
23
24
|
import { isDebug } from './debug.js';
|
|
24
25
|
import { resolveMetadata, renderMetadataToElements } from './metadata.js';
|
|
25
26
|
import { resolveManifestStatusFile } from './manifest-status-resolver.js';
|
|
26
27
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
27
28
|
import type { RouteMatch } from './pipeline.js';
|
|
28
29
|
import type { NavContext } from './ssr-entry.js';
|
|
30
|
+
import { flightInitScript } from './flight-scripts.js';
|
|
29
31
|
import type { ClientBootstrapConfig } from './html-injectors.js';
|
|
30
32
|
import type { Metadata } from './types.js';
|
|
33
|
+
import { teeWithErrorPropagation } from './stream-utils.js';
|
|
31
34
|
|
|
32
35
|
/** RSC content type for client navigation payload requests. */
|
|
33
36
|
const RSC_CONTENT_TYPE = 'text/x-component';
|
|
@@ -108,7 +111,7 @@ export async function renderDenyPage(
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
// Load the status-code page component
|
|
111
|
-
const mod =
|
|
114
|
+
const mod = await loadModule(resolution.file);
|
|
112
115
|
if (!mod.default) {
|
|
113
116
|
return new Response(null, { status: deny.status, headers: responseHeaders });
|
|
114
117
|
}
|
|
@@ -116,9 +119,6 @@ export async function renderDenyPage(
|
|
|
116
119
|
const ErrorPageComponent = mod.default as (...args: unknown[]) => unknown;
|
|
117
120
|
const h = createElement as (...args: unknown[]) => React.ReactElement;
|
|
118
121
|
|
|
119
|
-
// Check shell opt-out: export const shell = false
|
|
120
|
-
const shellEnabled = mod.shell !== false;
|
|
121
|
-
|
|
122
122
|
// 4xx status-code pages receive { status, dangerouslyPassData }
|
|
123
123
|
// per design/10-error-handling.md §"Status-Code File Props"
|
|
124
124
|
let element = h(ErrorPageComponent, {
|
|
@@ -126,23 +126,14 @@ export async function renderDenyPage(
|
|
|
126
126
|
dangerouslyPassData: deny.data,
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
} else if (isDebug()) {
|
|
138
|
-
// Dev-mode: warn if shell=false might conflict with Suspense
|
|
139
|
-
// The actual Suspense boundary check happens at render time in the pipeline.
|
|
140
|
-
// This is a preemptive log for developer awareness.
|
|
141
|
-
console.warn(
|
|
142
|
-
`[timber] Status-code file ${resolution.file.filePath} exports shell = false. ` +
|
|
143
|
-
'If deny() fires inside a Suspense boundary, layouts are already committed and ' +
|
|
144
|
-
'cannot be unwrapped. The shell opt-out will be ignored in that case.'
|
|
145
|
-
);
|
|
129
|
+
// Always wrap in layout shell.
|
|
130
|
+
// NOTE: Shell opt-out (export const shell = false) is a future feature
|
|
131
|
+
// pending a proper design doc. See design backlog.
|
|
132
|
+
const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
|
|
133
|
+
const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
|
|
134
|
+
for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
|
|
135
|
+
const { component } = layoutsToWrap[i];
|
|
136
|
+
element = h(component, null, element);
|
|
146
137
|
}
|
|
147
138
|
|
|
148
139
|
// Build head HTML from error page metadata (if any)
|
|
@@ -170,15 +161,15 @@ export async function renderDenyPage(
|
|
|
170
161
|
debugChannel: createDebugChannelSink(),
|
|
171
162
|
});
|
|
172
163
|
|
|
173
|
-
const [ssrStream, inlineStream] = rscStream
|
|
164
|
+
const [ssrStream, inlineStream] = teeWithErrorPropagation(rscStream);
|
|
174
165
|
|
|
175
166
|
const navContext: NavContext = {
|
|
176
167
|
pathname: new URL(req.url).pathname,
|
|
177
|
-
params: match.
|
|
168
|
+
params: match.segmentParams,
|
|
178
169
|
searchParams: Object.fromEntries(new URL(req.url).searchParams),
|
|
179
170
|
statusCode: deny.status,
|
|
180
171
|
responseHeaders,
|
|
181
|
-
headHtml,
|
|
172
|
+
headHtml: headHtml + flightInitScript(),
|
|
182
173
|
bootstrapScriptContent: clientBootstrap.bootstrapScriptContent,
|
|
183
174
|
rscStream: inlineStream,
|
|
184
175
|
};
|
|
@@ -206,7 +197,7 @@ export async function renderDenyPageAsRsc(
|
|
|
206
197
|
return new Response(null, { status: deny.status, headers: responseHeaders });
|
|
207
198
|
}
|
|
208
199
|
|
|
209
|
-
const mod =
|
|
200
|
+
const mod = await loadModule(resolution.file);
|
|
210
201
|
if (!mod.default) {
|
|
211
202
|
responseHeaders.set('content-type', `${RSC_CONTENT_TYPE}; charset=utf-8`);
|
|
212
203
|
return new Response(null, { status: deny.status, headers: responseHeaders });
|
|
@@ -215,22 +206,17 @@ export async function renderDenyPageAsRsc(
|
|
|
215
206
|
const ErrorPageComponent = mod.default as (...args: unknown[]) => unknown;
|
|
216
207
|
const h = createElement as (...args: unknown[]) => React.ReactElement;
|
|
217
208
|
|
|
218
|
-
// Check shell opt-out
|
|
219
|
-
const shellEnabled = mod.shell !== false;
|
|
220
|
-
|
|
221
209
|
let element = h(ErrorPageComponent, {
|
|
222
210
|
status: deny.status,
|
|
223
211
|
dangerouslyPassData: deny.data,
|
|
224
212
|
});
|
|
225
213
|
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
element = h(component, null, element);
|
|
233
|
-
}
|
|
214
|
+
// Always wrap in layout shell.
|
|
215
|
+
const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
|
|
216
|
+
const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
|
|
217
|
+
for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
|
|
218
|
+
const { component } = layoutsToWrap[i];
|
|
219
|
+
element = h(component, null, element);
|
|
234
220
|
}
|
|
235
221
|
|
|
236
222
|
const rscStream = renderToReadableStream(element, {
|
|
@@ -272,7 +258,7 @@ async function renderDenyPageJson(
|
|
|
272
258
|
// JSON status files are loaded as modules that export the JSON content.
|
|
273
259
|
// The manifest's load() imports the .json file, which Vite handles as a
|
|
274
260
|
// default export of the parsed JSON object.
|
|
275
|
-
const mod =
|
|
261
|
+
const mod = await loadModule(resolution.file);
|
|
276
262
|
const jsonContent = mod.default ?? mod;
|
|
277
263
|
|
|
278
264
|
responseHeaders.set('content-type', 'application/json; charset=utf-8');
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev holding server — serves a loading page while Vite initializes.
|
|
3
|
+
*
|
|
4
|
+
* When `timber dev` (or `vite dev`) starts, Vite takes several seconds
|
|
5
|
+
* to initialize all plugins, scan routes, and boot the RSC environment.
|
|
6
|
+
* During this window, the port is unbound and browsers get
|
|
7
|
+
* ERR_CONNECTION_REFUSED.
|
|
8
|
+
*
|
|
9
|
+
* This module creates a lightweight HTTP server that binds the port
|
|
10
|
+
* immediately and serves a branded holding page with auto-refresh.
|
|
11
|
+
* Once Vite is ready, the holding server is closed and Vite's server
|
|
12
|
+
* takes over the port.
|
|
13
|
+
*
|
|
14
|
+
* The holding server is started in rootSync's config() hook (the
|
|
15
|
+
* earliest Vite plugin lifecycle point where we know the port) and
|
|
16
|
+
* closed in timber-dev-server's configureServer() hook (the last
|
|
17
|
+
* plugin, right before Vite calls server.listen()).
|
|
18
|
+
*
|
|
19
|
+
* Browser requests (Accept: text/html) get the HTML holding page.
|
|
20
|
+
* API requests (Accept: application/json) get a 503 JSON response.
|
|
21
|
+
* All responses include Retry-After: 1.
|
|
22
|
+
*
|
|
23
|
+
* See design/21-dev-server.md, TIM-665.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import http from 'node:http';
|
|
27
|
+
|
|
28
|
+
// ─── Types ────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
export interface HoldingServer {
|
|
31
|
+
/**
|
|
32
|
+
* Start listening on the given port.
|
|
33
|
+
* Returns the actual bound port (useful when port is 0 for OS assignment).
|
|
34
|
+
*/
|
|
35
|
+
listen(port: number): Promise<number>;
|
|
36
|
+
|
|
37
|
+
/** Gracefully close the server and stop accepting connections. */
|
|
38
|
+
close(): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─── Holding Page HTML ────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Minimal self-contained HTML holding page.
|
|
45
|
+
*
|
|
46
|
+
* Matches the timber.js docs site theme:
|
|
47
|
+
* - Light mode: warm stone/grain background, timber/bark text
|
|
48
|
+
* - Dark mode: stone-900 background, stone-200 text
|
|
49
|
+
* - 🪵 timber.js branding
|
|
50
|
+
*
|
|
51
|
+
* Uses meta-refresh (1s) for auto-reload — works without JavaScript.
|
|
52
|
+
* Inline CSS only, no external dependencies.
|
|
53
|
+
*/
|
|
54
|
+
const HOLDING_PAGE_HTML = [
|
|
55
|
+
'<!DOCTYPE html>',
|
|
56
|
+
'<html lang="en">',
|
|
57
|
+
'<head>',
|
|
58
|
+
' <meta charset="utf-8">',
|
|
59
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
60
|
+
' <meta http-equiv="refresh" content="2">',
|
|
61
|
+
' <title>timber — starting...</title>',
|
|
62
|
+
' <style>',
|
|
63
|
+
' *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }',
|
|
64
|
+
' body {',
|
|
65
|
+
' font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;',
|
|
66
|
+
' background: #fafaf9;',
|
|
67
|
+
' color: #44403c;',
|
|
68
|
+
' display: flex;',
|
|
69
|
+
' align-items: center;',
|
|
70
|
+
' justify-content: center;',
|
|
71
|
+
' min-height: 100vh;',
|
|
72
|
+
' -webkit-font-smoothing: antialiased;',
|
|
73
|
+
' }',
|
|
74
|
+
' @media (prefers-color-scheme: dark) {',
|
|
75
|
+
' body { background: #1c1917; color: #e7e5e4; }',
|
|
76
|
+
' .message { color: #a8a29e; }',
|
|
77
|
+
' .spinner { border-color: #57534e; border-top-color: #a1887f; }',
|
|
78
|
+
' .logo { color: #e7e5e4; }',
|
|
79
|
+
' }',
|
|
80
|
+
' .container { text-align: center; padding: 2rem; }',
|
|
81
|
+
' .logo {',
|
|
82
|
+
' font-size: 1.5rem;',
|
|
83
|
+
' font-weight: 700;',
|
|
84
|
+
' letter-spacing: -0.02em;',
|
|
85
|
+
' color: #5c3d2e;',
|
|
86
|
+
' margin-bottom: 1.5rem;',
|
|
87
|
+
' }',
|
|
88
|
+
' .message {',
|
|
89
|
+
' font-size: 0.95rem;',
|
|
90
|
+
' color: #78716c;',
|
|
91
|
+
' margin-bottom: 2rem;',
|
|
92
|
+
' }',
|
|
93
|
+
' .spinner {',
|
|
94
|
+
' width: 24px;',
|
|
95
|
+
' height: 24px;',
|
|
96
|
+
' border: 2.5px solid #d7ccc8;',
|
|
97
|
+
' border-top-color: #6d4c41;',
|
|
98
|
+
' border-radius: 50%;',
|
|
99
|
+
' animation: spin 0.8s linear infinite;',
|
|
100
|
+
' margin: 0 auto;',
|
|
101
|
+
' }',
|
|
102
|
+
' @keyframes spin { to { transform: rotate(360deg); } }',
|
|
103
|
+
' </style>',
|
|
104
|
+
'</head>',
|
|
105
|
+
'<body>',
|
|
106
|
+
' <div class="container">',
|
|
107
|
+
' <div class="logo">\u{1FAB5} timber.js</div>',
|
|
108
|
+
' <p class="message">Dev server starting…</p>',
|
|
109
|
+
' <div class="spinner"></div>',
|
|
110
|
+
' </div>',
|
|
111
|
+
'</body>',
|
|
112
|
+
'</html>',
|
|
113
|
+
].join('\n');
|
|
114
|
+
|
|
115
|
+
// ─── Factory ──────────────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create a holding HTTP server that serves a loading page during startup.
|
|
119
|
+
*
|
|
120
|
+
* Usage (inside Vite plugin):
|
|
121
|
+
* ```ts
|
|
122
|
+
* // In config() hook — earliest point where port is known
|
|
123
|
+
* const holding = createHoldingServer();
|
|
124
|
+
* holding.listen(config.server?.port ?? 5173);
|
|
125
|
+
*
|
|
126
|
+
* // In last plugin's configureServer() — wrap listen for seamless handoff
|
|
127
|
+
* const originalListen = server.listen.bind(server);
|
|
128
|
+
* server.listen = async (...args) => {
|
|
129
|
+
* await holding.close();
|
|
130
|
+
* return originalListen(...args);
|
|
131
|
+
* };
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export function createHoldingServer(): HoldingServer {
|
|
135
|
+
const server = http.createServer((req, res) => {
|
|
136
|
+
const accept = req.headers.accept ?? '';
|
|
137
|
+
|
|
138
|
+
// API requests: JSON 503
|
|
139
|
+
if (accept.includes('application/json') && !accept.includes('text/html')) {
|
|
140
|
+
res.writeHead(503, {
|
|
141
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
142
|
+
'Retry-After': '1',
|
|
143
|
+
'Cache-Control': 'no-store',
|
|
144
|
+
});
|
|
145
|
+
res.end(
|
|
146
|
+
JSON.stringify({
|
|
147
|
+
error: 'Service Unavailable',
|
|
148
|
+
message: 'timber dev server is starting — please retry shortly',
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Browser and other requests: HTML holding page
|
|
155
|
+
res.writeHead(503, {
|
|
156
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
157
|
+
'Retry-After': '1',
|
|
158
|
+
'Cache-Control': 'no-store',
|
|
159
|
+
});
|
|
160
|
+
res.end(HOLDING_PAGE_HTML);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
listen(port: number): Promise<number> {
|
|
165
|
+
return new Promise((resolve, reject) => {
|
|
166
|
+
server.once('error', reject);
|
|
167
|
+
server.listen(port, () => {
|
|
168
|
+
server.removeListener('error', reject);
|
|
169
|
+
const addr = server.address();
|
|
170
|
+
const boundPort = typeof addr === 'object' && addr ? addr.port : port;
|
|
171
|
+
resolve(boundPort);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
close(): Promise<void> {
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
server.close((err) => {
|
|
179
|
+
if (err) reject(err);
|
|
180
|
+
else resolve();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
@@ -25,7 +25,6 @@ export const WarningId = {
|
|
|
25
25
|
REDIRECT_IN_SUSPENSE: 'REDIRECT_IN_SUSPENSE',
|
|
26
26
|
REDIRECT_IN_ACCESS: 'REDIRECT_IN_ACCESS',
|
|
27
27
|
STATIC_REQUEST_API: 'STATIC_REQUEST_API',
|
|
28
|
-
CACHE_REQUEST_PROPS: 'CACHE_REQUEST_PROPS',
|
|
29
28
|
SLOW_SLOT_NO_SUSPENSE: 'SLOW_SLOT_NO_SUSPENSE',
|
|
30
29
|
} as const;
|
|
31
30
|
|
|
@@ -111,7 +110,7 @@ export function warnSuspenseWrappingChildren(layoutFile: string): void {
|
|
|
111
110
|
'warn',
|
|
112
111
|
`Layout at ${layoutFile} wraps {children} in <Suspense>. ` +
|
|
113
112
|
'This prevents child pages from setting HTTP status codes. ' +
|
|
114
|
-
'Use
|
|
113
|
+
'Use usePendingNavigation() for loading states instead.'
|
|
115
114
|
);
|
|
116
115
|
}
|
|
117
116
|
|
|
@@ -179,7 +178,7 @@ export function warnRedirectInAccess(accessFile: string, line?: number): void {
|
|
|
179
178
|
}
|
|
180
179
|
|
|
181
180
|
/**
|
|
182
|
-
* Warn when
|
|
181
|
+
* Warn when getCookies() or getHeaders() is called during a static build.
|
|
183
182
|
*
|
|
184
183
|
* In output: 'static' mode, there is no per-request context — these APIs
|
|
185
184
|
* read build-time values only. This is almost always a mistake.
|
|
@@ -197,33 +196,8 @@ export function warnStaticRequestApi(api: 'cookies' | 'headers', file: string):
|
|
|
197
196
|
);
|
|
198
197
|
}
|
|
199
198
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
*
|
|
203
|
-
* Cached components should not depend on per-request data — a userId or
|
|
204
|
-
* sessionId in the props means the cache will either be ineffective
|
|
205
|
-
* (key per user) or dangerous (serve one user's data to another).
|
|
206
|
-
*
|
|
207
|
-
* @param componentName - Name of the cached component
|
|
208
|
-
* @param propName - Name of the suspicious prop
|
|
209
|
-
* @param file - Relative path to the component file
|
|
210
|
-
* @param line - Line number
|
|
211
|
-
*/
|
|
212
|
-
export function warnCacheRequestProps(
|
|
213
|
-
componentName: string,
|
|
214
|
-
propName: string,
|
|
215
|
-
file: string,
|
|
216
|
-
line?: number
|
|
217
|
-
): void {
|
|
218
|
-
const location = line ? `${file}:${line}` : file;
|
|
219
|
-
emitOnce(
|
|
220
|
-
WarningId.CACHE_REQUEST_PROPS,
|
|
221
|
-
`${componentName}:${propName}:${location}`,
|
|
222
|
-
'warn',
|
|
223
|
-
`Cached component ${componentName} receives prop "${propName}" which appears request-specific. ` +
|
|
224
|
-
'Cached components should not depend on per-request data.'
|
|
225
|
-
);
|
|
226
|
-
}
|
|
199
|
+
// NOTE: warnCacheRequestProps removed — 'use cache' directive is a future feature.
|
|
200
|
+
// See design/06-caching.md.
|
|
227
201
|
|
|
228
202
|
/**
|
|
229
203
|
* Warn when a parallel slot resolves slowly without a <Suspense> wrapper.
|
|
@@ -245,25 +219,6 @@ export function warnSlowSlotWithoutSuspense(slotName: string, durationMs: number
|
|
|
245
219
|
);
|
|
246
220
|
}
|
|
247
221
|
|
|
248
|
-
// ─── Legacy aliases ─────────────────────────────────────────────────────────
|
|
249
|
-
|
|
250
|
-
/** @deprecated Use warnStaticRequestApi instead */
|
|
251
|
-
export const warnDynamicApiInStaticBuild = warnStaticRequestApi;
|
|
252
|
-
|
|
253
|
-
/** @deprecated Use warnRedirectInAccess instead */
|
|
254
|
-
export function warnRedirectInSlotAccess(slotName: string): void {
|
|
255
|
-
warnRedirectInAccess(`${slotName}/access.ts`);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/** @deprecated Use warnDenyInSuspense / warnRedirectInSuspense instead */
|
|
259
|
-
export function warnDenyAfterFlush(signal: 'deny' | 'redirect'): void {
|
|
260
|
-
if (signal === 'deny') {
|
|
261
|
-
warnDenyInSuspense('unknown');
|
|
262
|
-
} else {
|
|
263
|
-
warnRedirectInSuspense('unknown');
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
222
|
// ─── Testing ────────────────────────────────────────────────────────────────
|
|
268
223
|
|
|
269
224
|
/**
|
|
@@ -58,15 +58,31 @@ export interface EarlyHint {
|
|
|
58
58
|
/**
|
|
59
59
|
* Format a single EarlyHint as a Link header value.
|
|
60
60
|
*
|
|
61
|
+
* Attribute order: `as` before `rel` to match Cloudflare CDN's cached
|
|
62
|
+
* Early Hints format. Cloudflare caches Link headers from 200 responses
|
|
63
|
+
* and re-emits them as 103 Early Hints on subsequent requests. If our
|
|
64
|
+
* attribute order differs from Cloudflare's cached copy, the browser
|
|
65
|
+
* sees two preload headers for the same URL (different attribute order)
|
|
66
|
+
* and warns "Preload was ignored." Matching the order ensures the
|
|
67
|
+
* browser deduplicates them correctly.
|
|
68
|
+
*
|
|
61
69
|
* Examples:
|
|
62
|
-
* `</styles/root.css>;
|
|
63
|
-
* `</fonts/inter.woff2>;
|
|
70
|
+
* `</styles/root.css>; as=style; rel=preload`
|
|
71
|
+
* `</fonts/inter.woff2>; as=font; rel=preload; crossorigin=anonymous`
|
|
64
72
|
* `</_timber/client.js>; rel=modulepreload`
|
|
65
73
|
* `<https://fonts.googleapis.com>; rel=preconnect`
|
|
66
74
|
*/
|
|
67
75
|
export function formatLinkHeader(hint: EarlyHint): string {
|
|
76
|
+
// For preload hints, emit `as` before `rel` to match Cloudflare's
|
|
77
|
+
// cached header format and avoid duplicate preload warnings.
|
|
78
|
+
if (hint.as !== undefined) {
|
|
79
|
+
let value = `<${hint.href}>; as=${hint.as}; rel=${hint.rel}`;
|
|
80
|
+
if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;
|
|
81
|
+
if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
// For modulepreload / preconnect (no `as`), emit rel first.
|
|
68
85
|
let value = `<${hint.href}>; rel=${hint.rel}`;
|
|
69
|
-
if (hint.as !== undefined) value += `; as=${hint.as}`;
|
|
70
86
|
if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;
|
|
71
87
|
if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;
|
|
72
88
|
return value;
|
|
@@ -84,8 +100,8 @@ export interface EarlyHintOptions {
|
|
|
84
100
|
* Collect all Link header strings for a matched route's segment chain.
|
|
85
101
|
*
|
|
86
102
|
* Walks the build manifest to emit hints for:
|
|
87
|
-
* - CSS stylesheets (
|
|
88
|
-
* - Font assets (
|
|
103
|
+
* - CSS stylesheets (as=style; rel=preload)
|
|
104
|
+
* - Font assets (as=font; rel=preload; crossorigin)
|
|
89
105
|
* - JS modulepreload hints (rel=modulepreload) — unless skipJs is set
|
|
90
106
|
*
|
|
91
107
|
* Also emits global CSS from the `_global` manifest key. Route files
|
|
@@ -94,7 +110,7 @@ export interface EarlyHintOptions {
|
|
|
94
110
|
* key contains all CSS assets from the client build — fine for early
|
|
95
111
|
* hints since they're just prefetch signals.
|
|
96
112
|
*
|
|
97
|
-
* Returns formatted Link header strings, deduplicated, root → leaf order.
|
|
113
|
+
* Returns formatted Link header strings, deduplicated by URL, root → leaf order.
|
|
98
114
|
* Returns an empty array in dev mode (manifest is empty).
|
|
99
115
|
*/
|
|
100
116
|
export function collectEarlyHintHeaders(
|
|
@@ -103,30 +119,35 @@ export function collectEarlyHintHeaders(
|
|
|
103
119
|
options?: EarlyHintOptions
|
|
104
120
|
): string[] {
|
|
105
121
|
const result: string[] = [];
|
|
106
|
-
|
|
122
|
+
// Dedup by URL (href), not by full formatted header string.
|
|
123
|
+
// Different code paths can produce the same URL with different attribute
|
|
124
|
+
// ordering, which would bypass a full-string dedup and produce duplicate
|
|
125
|
+
// Link headers that trigger browser "preload was ignored" warnings.
|
|
126
|
+
const seenUrls = new Set<string>();
|
|
107
127
|
|
|
108
|
-
const add = (header: string) => {
|
|
109
|
-
if (!
|
|
110
|
-
|
|
128
|
+
const add = (url: string, header: string) => {
|
|
129
|
+
if (!seenUrls.has(url)) {
|
|
130
|
+
seenUrls.add(url);
|
|
111
131
|
result.push(header);
|
|
112
132
|
}
|
|
113
133
|
};
|
|
114
134
|
|
|
115
|
-
// Per-route CSS —
|
|
135
|
+
// Per-route CSS — as=style; rel=preload
|
|
116
136
|
for (const url of collectRouteCss(segments, manifest)) {
|
|
117
|
-
add(formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
|
|
137
|
+
add(url, formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
|
|
118
138
|
}
|
|
119
139
|
|
|
120
140
|
// Global CSS — all CSS assets from the client bundle.
|
|
121
141
|
// Covers CSS that the RSC plugin injects via data-rsc-css-href,
|
|
122
142
|
// which isn't keyed to route segments in our manifest.
|
|
123
143
|
for (const url of manifest.css['_global'] ?? []) {
|
|
124
|
-
add(formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
|
|
144
|
+
add(url, formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
|
|
125
145
|
}
|
|
126
146
|
|
|
127
|
-
// Fonts —
|
|
147
|
+
// Fonts — as=font; rel=preload; crossorigin (crossorigin required per spec)
|
|
128
148
|
for (const font of collectRouteFonts(segments, manifest)) {
|
|
129
149
|
add(
|
|
150
|
+
font.href,
|
|
130
151
|
formatLinkHeader({ href: font.href, rel: 'preload', as: 'font', crossOrigin: 'anonymous' })
|
|
131
152
|
);
|
|
132
153
|
}
|
|
@@ -134,7 +155,7 @@ export function collectEarlyHintHeaders(
|
|
|
134
155
|
// JS chunks — rel=modulepreload (skip when client JS is disabled)
|
|
135
156
|
if (!options?.skipJs) {
|
|
136
157
|
for (const url of collectRouteModulepreloads(segments, manifest)) {
|
|
137
|
-
add(formatLinkHeader({ href: url, rel: 'modulepreload' }));
|
|
158
|
+
add(url, formatLinkHeader({ href: url, rel: 'modulepreload' }));
|
|
138
159
|
}
|
|
139
160
|
}
|
|
140
161
|
|
|
@@ -5,8 +5,23 @@
|
|
|
5
5
|
* See design/10-error-handling.md.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { TimberErrorBoundary } from '
|
|
8
|
+
import { TimberErrorBoundary } from '../client/error-boundary.js';
|
|
9
9
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
10
|
+
import { loadModule } from './safe-load.js';
|
|
11
|
+
|
|
12
|
+
/** MDX/markdown extensions — server components that cannot be passed as function props. */
|
|
13
|
+
const MDX_EXTENSIONS = new Set(['.mdx', '.md']);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if a manifest file path ends with an MDX/markdown extension.
|
|
17
|
+
* MDX components are server components and cannot cross the RSC→client
|
|
18
|
+
* boundary as function props to TimberErrorBoundary.
|
|
19
|
+
*/
|
|
20
|
+
function isMdxFilePath(filePath: string): boolean {
|
|
21
|
+
const dotIndex = filePath.lastIndexOf('.');
|
|
22
|
+
if (dotIndex === -1) return false;
|
|
23
|
+
return MDX_EXTENSIONS.has(filePath.slice(dotIndex));
|
|
24
|
+
}
|
|
10
25
|
|
|
11
26
|
/**
|
|
12
27
|
* Wrap an element in error boundaries defined by a route segment.
|
|
@@ -15,11 +30,17 @@ import type { ManifestSegmentNode } from './route-matcher.js';
|
|
|
15
30
|
* 1. Specific status files (e.g., 404.tsx, 500.tsx) — highest priority at runtime
|
|
16
31
|
* 2. Category catch-alls (4xx.tsx, 5xx.tsx)
|
|
17
32
|
* 3. error.tsx — catches anything not matched by status files
|
|
33
|
+
*
|
|
34
|
+
* MDX status files are server components and cannot be passed as function
|
|
35
|
+
* props to TimberErrorBoundary (a 'use client' component). Instead, they
|
|
36
|
+
* are pre-rendered as elements and passed as fallbackElement. See TIM-503.
|
|
18
37
|
*/
|
|
19
38
|
export async function wrapSegmentWithErrorBoundaries(
|
|
20
39
|
segment: ManifestSegmentNode,
|
|
21
40
|
element: React.ReactElement,
|
|
22
|
-
h: (...args: unknown[]) => React.ReactElement
|
|
41
|
+
h: (...args: unknown[]) => React.ReactElement,
|
|
42
|
+
/** When true, skip 4xx error boundaries — deny catching handles them in-tree. See TIM-666. */
|
|
43
|
+
skipDenyBoundaries = false
|
|
23
44
|
): Promise<React.ReactElement> {
|
|
24
45
|
// Specific status files (innermost — highest priority at runtime)
|
|
25
46
|
if (segment.statusFiles) {
|
|
@@ -27,13 +48,27 @@ export async function wrapSegmentWithErrorBoundaries(
|
|
|
27
48
|
if (key !== '4xx' && key !== '5xx') {
|
|
28
49
|
const status = parseInt(key, 10);
|
|
29
50
|
if (!isNaN(status)) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
// Skip 4xx boundaries when deny catching is active — the deny
|
|
52
|
+
// page is rendered by AccessGate/PageDenyBoundary instead.
|
|
53
|
+
if (skipDenyBoundaries && status >= 400 && status <= 499) continue;
|
|
54
|
+
// .catch: error boundary construction must not fail if the
|
|
55
|
+
// error page module has a syntax error — skip this boundary.
|
|
56
|
+
const mod = await loadModule(file).catch(() => null);
|
|
57
|
+
if (mod?.default) {
|
|
58
|
+
if (isMdxFilePath(file.filePath)) {
|
|
59
|
+
// MDX: pre-render as element (server component can't be a function prop)
|
|
60
|
+
element = h(TimberErrorBoundary, {
|
|
61
|
+
fallbackElement: h(mod.default as never, { status }),
|
|
62
|
+
status,
|
|
63
|
+
children: element,
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
element = h(TimberErrorBoundary, {
|
|
67
|
+
fallbackComponent: mod.default,
|
|
68
|
+
status,
|
|
69
|
+
children: element,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
37
72
|
}
|
|
38
73
|
}
|
|
39
74
|
}
|
|
@@ -41,14 +76,24 @@ export async function wrapSegmentWithErrorBoundaries(
|
|
|
41
76
|
|
|
42
77
|
// Category catch-alls (4xx.tsx, 5xx.tsx)
|
|
43
78
|
for (const [key, file] of Object.entries(segment.statusFiles)) {
|
|
79
|
+
if (skipDenyBoundaries && key === '4xx') continue;
|
|
44
80
|
if (key === '4xx' || key === '5xx') {
|
|
45
|
-
const mod =
|
|
46
|
-
if (mod
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
const mod = await loadModule(file).catch(() => null);
|
|
82
|
+
if (mod?.default) {
|
|
83
|
+
const categoryStatus = key === '4xx' ? 400 : 500;
|
|
84
|
+
if (isMdxFilePath(file.filePath)) {
|
|
85
|
+
element = h(TimberErrorBoundary, {
|
|
86
|
+
fallbackElement: h(mod.default as never, {}),
|
|
87
|
+
status: categoryStatus,
|
|
88
|
+
children: element,
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
element = h(TimberErrorBoundary, {
|
|
92
|
+
fallbackComponent: mod.default,
|
|
93
|
+
status: categoryStatus,
|
|
94
|
+
children: element,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
52
97
|
}
|
|
53
98
|
}
|
|
54
99
|
}
|
|
@@ -56,12 +101,19 @@ export async function wrapSegmentWithErrorBoundaries(
|
|
|
56
101
|
|
|
57
102
|
// error.tsx (outermost — catches anything not matched by status files)
|
|
58
103
|
if (segment.error) {
|
|
59
|
-
const mod =
|
|
60
|
-
if (mod
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
104
|
+
const mod = await loadModule(segment.error).catch(() => null);
|
|
105
|
+
if (mod?.default) {
|
|
106
|
+
if (isMdxFilePath(segment.error.filePath)) {
|
|
107
|
+
element = h(TimberErrorBoundary, {
|
|
108
|
+
fallbackElement: h(mod.default as never, {}),
|
|
109
|
+
children: element,
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
element = h(TimberErrorBoundary, {
|
|
113
|
+
fallbackComponent: mod.default,
|
|
114
|
+
children: element,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
65
117
|
}
|
|
66
118
|
}
|
|
67
119
|
|