@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
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
decodeReply,
|
|
19
19
|
decodeAction,
|
|
20
20
|
renderToReadableStream,
|
|
21
|
-
} from '
|
|
21
|
+
} from '../rsc-runtime/rsc.js';
|
|
22
22
|
|
|
23
23
|
import { validateCsrf, type CsrfConfig } from './csrf.js';
|
|
24
24
|
import { executeAction, type RevalidateRenderer } from './actions.js';
|
|
@@ -31,6 +31,8 @@ import { handleActionError } from './action-client.js';
|
|
|
31
31
|
import { enforceBodyLimits, enforceFieldLimit, type BodyLimitsConfig } from './body-limits.js';
|
|
32
32
|
import { parseFormData } from './form-data.js';
|
|
33
33
|
import type { FormFlashData } from './form-flash.js';
|
|
34
|
+
import { checkVersionSkew, applyReloadHeaders } from './version-skew.js';
|
|
35
|
+
import { logActionError } from './logger.js';
|
|
34
36
|
|
|
35
37
|
// ─── Types ────────────────────────────────────────────────────────────────
|
|
36
38
|
|
|
@@ -90,6 +92,21 @@ export async function handleActionRequest(
|
|
|
90
92
|
req: Request,
|
|
91
93
|
config: ActionDispatchConfig
|
|
92
94
|
): Promise<Response | FormRerender | null> {
|
|
95
|
+
// Version skew detection — reject actions from stale clients (TIM-446).
|
|
96
|
+
// On mismatch, return a structured RSC error response that the client
|
|
97
|
+
// handles by showing a brief "App updated" message and reloading.
|
|
98
|
+
const skewCheck = checkVersionSkew(req);
|
|
99
|
+
if (!skewCheck.ok) {
|
|
100
|
+
const reloadHeaders = new Headers({
|
|
101
|
+
'Content-Type': RSC_CONTENT_TYPE,
|
|
102
|
+
});
|
|
103
|
+
applyReloadHeaders(reloadHeaders);
|
|
104
|
+
// Return the reload signal as an RSC stream so createFromFetch can
|
|
105
|
+
// decode it. The client checks X-Timber-Reload before processing.
|
|
106
|
+
const rscStream = renderToReadableStream({ _versionSkew: true });
|
|
107
|
+
return new Response(rscStream, { status: 200, headers: reloadHeaders });
|
|
108
|
+
}
|
|
109
|
+
|
|
93
110
|
// CSRF validation — reject cross-origin mutation requests.
|
|
94
111
|
const csrfResult = validateCsrf(req, config.csrf);
|
|
95
112
|
if (!csrfResult.ok) {
|
|
@@ -106,7 +123,7 @@ export async function handleActionRequest(
|
|
|
106
123
|
return new Response(null, { status: limitsResult.status });
|
|
107
124
|
}
|
|
108
125
|
|
|
109
|
-
// Run inside request context so
|
|
126
|
+
// Run inside request context so getHeaders(), getCookies() work in actions.
|
|
110
127
|
// Actions are a mutable context — they can set cookies (design/29-cookies.md).
|
|
111
128
|
return runWithRequestContext(req, async () => {
|
|
112
129
|
setMutableCookieContext(true);
|
|
@@ -177,7 +194,7 @@ async function handleRscAction(
|
|
|
177
194
|
});
|
|
178
195
|
} catch (error) {
|
|
179
196
|
// Log full error server-side for debugging
|
|
180
|
-
|
|
197
|
+
logActionError({ method: req.method, path: new URL(req.url).pathname, error });
|
|
181
198
|
|
|
182
199
|
// Return structured error response — ActionError gets its code/data,
|
|
183
200
|
// unexpected errors get sanitized { code: 'INTERNAL_ERROR' }
|
|
@@ -293,7 +310,7 @@ async function handleFormAction(
|
|
|
293
310
|
renderer: config.revalidateRenderer,
|
|
294
311
|
});
|
|
295
312
|
} catch (error) {
|
|
296
|
-
|
|
313
|
+
logActionError({ method: req.method, path: new URL(req.url).pathname, error });
|
|
297
314
|
|
|
298
315
|
// Return the error as flash data for re-render.
|
|
299
316
|
// handleActionError produces { serverError } for ActionErrors
|
package/src/server/actions.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* - revalidatePath(path) re-renders the route at that path and returns the RSC
|
|
5
5
|
* flight payload for inline reconciliation.
|
|
6
|
-
* - revalidateTag(tag) invalidates
|
|
6
|
+
* - revalidateTag(tag) invalidates timber.cache entries by tag.
|
|
7
7
|
*
|
|
8
8
|
* Both are callable from anywhere on the server — actions, API routes, handlers.
|
|
9
9
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See design/08-forms-and-actions.md
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import
|
|
17
|
+
import { getCacheHandler } from '../cache/handler-store';
|
|
18
18
|
import { RedirectSignal } from './primitives';
|
|
19
19
|
import { withSpan } from './tracing';
|
|
20
20
|
import { revalidationAls, type RevalidationState } from './als-registry.js';
|
|
@@ -37,8 +37,6 @@ export type { RevalidationState } from './als-registry.js';
|
|
|
37
37
|
|
|
38
38
|
/** Options for creating the action handler. */
|
|
39
39
|
export interface ActionHandlerConfig {
|
|
40
|
-
/** Cache handler for tag invalidation. */
|
|
41
|
-
cacheHandler?: CacheHandler;
|
|
42
40
|
/** Renderer for producing RSC payloads during revalidation. */
|
|
43
41
|
renderer?: RevalidateRenderer;
|
|
44
42
|
}
|
|
@@ -112,8 +110,8 @@ export function revalidatePath(path: string): void {
|
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
/**
|
|
115
|
-
* Invalidate all
|
|
116
|
-
* Does not return a payload — the next request for an invalidated
|
|
113
|
+
* Invalidate all timber.cache entries tagged with `tag`.
|
|
114
|
+
* Does not return a payload — the next request for an invalidated entry re-executes.
|
|
117
115
|
*
|
|
118
116
|
* @param tag - The cache tag to invalidate (e.g. 'products', 'user:123').
|
|
119
117
|
*/
|
|
@@ -172,9 +170,12 @@ export async function executeAction(
|
|
|
172
170
|
}
|
|
173
171
|
});
|
|
174
172
|
|
|
175
|
-
// Process tag invalidation
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
// Process tag invalidation via the module-level cache handler singleton.
|
|
174
|
+
// setCacheHandler() is called at boot from rsc-entry when timber.config.ts
|
|
175
|
+
// provides a cacheHandler; otherwise falls back to in-memory LRU (TIM-599).
|
|
176
|
+
if (state.tags.length > 0) {
|
|
177
|
+
const handler = getCacheHandler();
|
|
178
|
+
await Promise.all(state.tags.map((tag) => handler.invalidate({ tag })));
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
// Process path revalidation — build element tree (not yet serialized)
|
|
@@ -21,9 +21,10 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
24
|
+
import type { DebugComponentEntry } from './rsc-entry/helpers.js';
|
|
24
25
|
|
|
25
26
|
// ─── Request Context ──────────────────────────────────────────────────────
|
|
26
|
-
// Used by: request-context.ts (
|
|
27
|
+
// Used by: request-context.ts (getHeaders(), getCookies(), getSearchParams())
|
|
27
28
|
// Design doc: design/04-authorization.md
|
|
28
29
|
|
|
29
30
|
/** @internal — import via request-context.ts public API */
|
|
@@ -39,17 +40,44 @@ export interface RequestContextStore {
|
|
|
39
40
|
/** Original (pre-overlay) frozen headers, kept for overlay merging. */
|
|
40
41
|
originalHeaders: Headers;
|
|
41
42
|
/**
|
|
42
|
-
* Promise resolving to the
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* Promise resolving to the raw URLSearchParams for the current request.
|
|
44
|
+
* To get typed parsed params, import a search params definition and
|
|
45
|
+
* call `.parse(searchParams())`.
|
|
45
46
|
*/
|
|
46
|
-
searchParamsPromise: Promise<URLSearchParams
|
|
47
|
+
searchParamsPromise: Promise<URLSearchParams>;
|
|
48
|
+
/**
|
|
49
|
+
* Raw search string from the request URL (e.g. "?foo=bar&baz=1").
|
|
50
|
+
* Available synchronously for use in `redirect()` with `preserveSearchParams`.
|
|
51
|
+
*/
|
|
52
|
+
searchString: string;
|
|
53
|
+
/**
|
|
54
|
+
* Promise resolving to the coerced segment params for the current request.
|
|
55
|
+
* Set by the pipeline after route matching and param coercion, before
|
|
56
|
+
* middleware and rendering. Pages and layouts read params via
|
|
57
|
+
* `getSegmentParams()` instead of receiving them as a prop.
|
|
58
|
+
*
|
|
59
|
+
* See design/07-routing.md §"params.ts — Convention File for Typed Params"
|
|
60
|
+
*/
|
|
61
|
+
segmentParamsPromise?: Promise<Record<string, string | string[]>>;
|
|
47
62
|
/** Outgoing Set-Cookie entries (name → serialized value + options). Last write wins. */
|
|
48
63
|
cookieJar: Map<string, CookieEntry>;
|
|
49
64
|
/** Whether the response has flushed (headers committed). */
|
|
50
65
|
flushed: boolean;
|
|
51
66
|
/** Whether the current context allows cookie mutation. */
|
|
52
67
|
mutableContext: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Set by AccessGate or PageDenyBoundary when a DenySignal is caught
|
|
70
|
+
* server-side (inside the React tree, before React Flight sees it).
|
|
71
|
+
* The pipeline reads this after render to set the HTTP status code.
|
|
72
|
+
* See TIM-666.
|
|
73
|
+
*/
|
|
74
|
+
denyStatus?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Dev-only: getter for the current request's RSC debug components.
|
|
77
|
+
* Set by renderRoute() so onPipelineError can include component tree
|
|
78
|
+
* context for render-phase errors without module-level shared state.
|
|
79
|
+
*/
|
|
80
|
+
debugComponentsGetter?: () => DebugComponentEntry[];
|
|
53
81
|
}
|
|
54
82
|
|
|
55
83
|
/** A single outgoing cookie entry in the cookie jar. */
|
|
@@ -60,7 +88,7 @@ export interface CookieEntry {
|
|
|
60
88
|
}
|
|
61
89
|
|
|
62
90
|
// ─── Tracing ──────────────────────────────────────────────────────────────
|
|
63
|
-
// Used by: tracing.ts (
|
|
91
|
+
// Used by: tracing.ts (getTraceId(), getSpanId())
|
|
64
92
|
// Design doc: design/17-logging.md
|
|
65
93
|
|
|
66
94
|
export interface TraceStore {
|
|
@@ -85,6 +85,12 @@ export function collectRouteCss(segments: SegmentWithFiles[], manifest: BuildMan
|
|
|
85
85
|
* via injectHead() before </head>.
|
|
86
86
|
*/
|
|
87
87
|
export function buildCssLinkTags(cssUrls: string[]): string {
|
|
88
|
+
// Emit <link rel="stylesheet"> tags as a fallback for platforms where
|
|
89
|
+
// React's Float system (via @vitejs/plugin-rsc preinit with
|
|
90
|
+
// data-precedence) doesn't handle CSS injection. In practice, Float
|
|
91
|
+
// deduplicates and these may be dropped. No preload hints — Float
|
|
92
|
+
// already starts the fetch via preinit(), and redundant preloads
|
|
93
|
+
// cause "ignored due to unknown as/type" browser warnings.
|
|
88
94
|
return cssUrls.map((url) => `<link rel="stylesheet" href="${url}">`).join('');
|
|
89
95
|
}
|
|
90
96
|
|
|
@@ -95,10 +101,10 @@ export function buildCssLinkTags(cssUrls: string[]): string {
|
|
|
95
101
|
* into 103 Early Hints responses. This avoids platform-specific 103
|
|
96
102
|
* sending code.
|
|
97
103
|
*
|
|
98
|
-
* Example output: `</assets/root.css>;
|
|
104
|
+
* Example output: `</assets/root.css>; as=style; rel=preload, </assets/page.css>; as=style; rel=preload`
|
|
99
105
|
*/
|
|
100
106
|
export function buildLinkHeaders(cssUrls: string[]): string {
|
|
101
|
-
return cssUrls.map((url) => `<${url}>;
|
|
107
|
+
return cssUrls.map((url) => `<${url}>; as=style; rel=preload`).join(', ');
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
// ─── Font utilities ──────────────────────────────────────────────────────
|
|
@@ -153,10 +159,10 @@ export function buildFontPreloadTags(fonts: ManifestFontEntry[]): string {
|
|
|
153
159
|
*
|
|
154
160
|
* Cloudflare CDN converts Link headers with rel=preload into 103 Early Hints.
|
|
155
161
|
*
|
|
156
|
-
* Example: `</fonts/inter.woff2>;
|
|
162
|
+
* Example: `</fonts/inter.woff2>; as=font; rel=preload; crossorigin`
|
|
157
163
|
*/
|
|
158
164
|
export function buildFontLinkHeaders(fonts: ManifestFontEntry[]): string {
|
|
159
|
-
return fonts.map((f) => `<${f.href}>;
|
|
165
|
+
return fonts.map((f) => `<${f.href}>; as=font; rel=preload; crossorigin`).join(', ');
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
// ─── JS chunk utilities ──────────────────────────────────────────────────
|
package/src/server/compress.ts
CHANGED
|
@@ -160,15 +160,33 @@ export function compressResponse(request: Request, response: Response): Response
|
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
// ─── Gzip (
|
|
163
|
+
// ─── Gzip (node:zlib with Z_SYNC_FLUSH) ──────────────────────────────────
|
|
164
|
+
//
|
|
165
|
+
// Uses node:zlib's createGzip with Z_SYNC_FLUSH so each chunk is flushed
|
|
166
|
+
// to the output immediately. The Web Platform CompressionStream API buffers
|
|
167
|
+
// internally and does NOT flush per-chunk — this kills streaming because
|
|
168
|
+
// the browser doesn't receive the HTML shell until the gzip stream closes
|
|
169
|
+
// (i.e. after all Suspense boundaries resolve).
|
|
170
|
+
//
|
|
171
|
+
// Z_SYNC_FLUSH adds ~2–5% size overhead vs Z_NO_FLUSH but preserves
|
|
172
|
+
// correct streaming behavior: the shell renders instantly, Suspense
|
|
173
|
+
// fallbacks are visible immediately, and streamed content appears
|
|
174
|
+
// progressively.
|
|
175
|
+
|
|
176
|
+
import { createGzip, constants } from 'node:zlib';
|
|
177
|
+
import { Readable } from 'node:stream';
|
|
164
178
|
|
|
165
179
|
/**
|
|
166
|
-
* Compress a ReadableStream with gzip
|
|
167
|
-
*
|
|
180
|
+
* Compress a ReadableStream with gzip, flushing each chunk immediately.
|
|
181
|
+
*
|
|
182
|
+
* Uses node:zlib's createGzip with Z_SYNC_FLUSH to ensure each HTML chunk
|
|
183
|
+
* (shell, Suspense resolution, RSC payload) is delivered to the browser
|
|
184
|
+
* as soon as it's available — preserving streaming semantics.
|
|
168
185
|
*/
|
|
169
186
|
function compressWithGzip(body: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
187
|
+
const gzip = createGzip({ flush: constants.Z_SYNC_FLUSH });
|
|
188
|
+
const nodeInput = Readable.fromWeb(body as import('stream/web').ReadableStream);
|
|
189
|
+
nodeInput.pipe(gzip);
|
|
190
|
+
|
|
191
|
+
return Readable.toWeb(gzip) as ReadableStream<Uint8Array>;
|
|
174
192
|
}
|
package/src/server/debug.ts
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
*
|
|
49
49
|
* This is the ONLY function that should gate client-visible dev behavior:
|
|
50
50
|
* - Dev error pages with stack traces
|
|
51
|
-
* -
|
|
51
|
+
* - Server-Timing mode default (`'detailed'` in dev, `'total'` in prod)
|
|
52
52
|
* - Error messages in action `INTERNAL_ERROR` payloads
|
|
53
53
|
* - Pipeline error handler wiring (Vite overlay)
|
|
54
54
|
*
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DefaultLogger — human-readable stderr logging when no custom logger is configured.
|
|
3
|
+
*
|
|
4
|
+
* Ships as the fallback so production deployments always have error visibility,
|
|
5
|
+
* even without an `instrumentation.ts` logger export. Output is one line per
|
|
6
|
+
* event, designed for `fly logs`, `kubectl logs`, Cloudflare dashboard tails, etc.
|
|
7
|
+
*
|
|
8
|
+
* Format:
|
|
9
|
+
* [timber] ERROR message key=value key=value trace_id=4bf92f35
|
|
10
|
+
* [timber] WARN message key=value key=value trace_id=4bf92f35
|
|
11
|
+
* [timber] INFO message method=GET path=/dashboard status=200 durationMs=43 trace_id=4bf92f35
|
|
12
|
+
*
|
|
13
|
+
* Behavior:
|
|
14
|
+
* - Suppressed entirely in dev mode (dev logging handles all output)
|
|
15
|
+
* - `debug` suppressed unless TIMBER_DEBUG is set
|
|
16
|
+
* - Replaced entirely when a custom logger is set via `setLogger()`
|
|
17
|
+
*
|
|
18
|
+
* See design/17-logging.md §"DefaultLogger"
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { isDevMode, isDebug } from './debug.js';
|
|
22
|
+
import { formatSsrError } from './error-formatter.js';
|
|
23
|
+
import type { TimberLogger } from './logger.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Format data fields as `key=value` pairs for human-readable output.
|
|
27
|
+
* - `error` key is serialized via formatSsrError for stack trace cleanup
|
|
28
|
+
* - `trace_id` is truncated to 8 chars for readability (full ID in OTEL)
|
|
29
|
+
* - Other values are stringified inline
|
|
30
|
+
*/
|
|
31
|
+
function formatDataFields(data?: Record<string, unknown>): string {
|
|
32
|
+
if (!data) return '';
|
|
33
|
+
|
|
34
|
+
const parts: string[] = [];
|
|
35
|
+
let traceId: string | undefined;
|
|
36
|
+
|
|
37
|
+
for (const [key, value] of Object.entries(data)) {
|
|
38
|
+
if (key === 'trace_id') {
|
|
39
|
+
// Defer trace_id to the end
|
|
40
|
+
traceId = typeof value === 'string' ? value : String(value);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (key === 'error') {
|
|
44
|
+
// Serialize errors with formatSsrError for clean output
|
|
45
|
+
parts.push(`error=${formatSsrError(value)}`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (value === undefined || value === null) continue;
|
|
49
|
+
parts.push(`${key}=${value}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// trace_id always last, truncated to 8 chars for readability
|
|
53
|
+
if (traceId) {
|
|
54
|
+
parts.push(`trace_id=${traceId.slice(0, 8)}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return parts.length > 0 ? ' ' + parts.join(' ') : '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Pad level string to fixed width for alignment. */
|
|
61
|
+
function padLevel(level: string): string {
|
|
62
|
+
return level.padEnd(5);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createDefaultLogger(): TimberLogger {
|
|
66
|
+
return {
|
|
67
|
+
error(msg: string, data?: Record<string, unknown>): void {
|
|
68
|
+
// Errors are ALWAYS logged, including dev mode. Suppressing errors
|
|
69
|
+
// in dev causes silent 500s with no stack trace, making route.ts
|
|
70
|
+
// and render errors impossible to debug. See TIM-555.
|
|
71
|
+
const fields = formatDataFields(data);
|
|
72
|
+
process.stderr.write(`[timber] ${padLevel('ERROR')} ${msg}${fields}\n`);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
warn(msg: string, data?: Record<string, unknown>): void {
|
|
76
|
+
// Warnings are always logged — same rationale as errors.
|
|
77
|
+
const fields = formatDataFields(data);
|
|
78
|
+
process.stderr.write(`[timber] ${padLevel('WARN')} ${msg}${fields}\n`);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
info(msg: string, data?: Record<string, unknown>): void {
|
|
82
|
+
// info is suppressed by default — per-request lines are too noisy
|
|
83
|
+
// without a custom logger. Enable with TIMBER_DEBUG.
|
|
84
|
+
if (isDevMode()) return;
|
|
85
|
+
if (!isDebug()) return;
|
|
86
|
+
const fields = formatDataFields(data);
|
|
87
|
+
process.stderr.write(`[timber] ${padLevel('INFO')} ${msg}${fields}\n`);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
debug(msg: string, data?: Record<string, unknown>): void {
|
|
91
|
+
// debug is suppressed in dev (dev logger handles it) and in
|
|
92
|
+
// production unless TIMBER_DEBUG is explicitly set.
|
|
93
|
+
if (isDevMode()) return;
|
|
94
|
+
if (!isDebug()) return;
|
|
95
|
+
const fields = formatDataFields(data);
|
|
96
|
+
process.stderr.write(`[timber] ${padLevel('DEBUG')} ${msg}${fields}\n`);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deny Page Resolver — resolves status-code file components for in-tree deny handling.
|
|
3
|
+
*
|
|
4
|
+
* When AccessGate or PageDenyBoundary catches a DenySignal, they need to
|
|
5
|
+
* render the matching deny page (403.tsx, 4xx.tsx, error.tsx) as a normal
|
|
6
|
+
* element in the React tree. This module resolves the deny page chain from
|
|
7
|
+
* the segment chain — a list of fallback components ordered by specificity.
|
|
8
|
+
*
|
|
9
|
+
* The chain is built during buildRouteElement and passed as a prop to
|
|
10
|
+
* AccessGate and PageDenyBoundary. At catch time, the first matching
|
|
11
|
+
* component is rendered.
|
|
12
|
+
*
|
|
13
|
+
* See design/10-error-handling.md §"Status-Code Files", TIM-666.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createElement } from 'react';
|
|
17
|
+
|
|
18
|
+
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
19
|
+
import { loadModule } from './safe-load.js';
|
|
20
|
+
import { requestContextAls } from './als-registry.js';
|
|
21
|
+
|
|
22
|
+
// ─── Types ────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/** A single entry in the deny page fallback chain. */
|
|
25
|
+
export interface DenyPageEntry {
|
|
26
|
+
/** Status code filter: specific (403), category (400 = any 4xx), or null (catch-all). */
|
|
27
|
+
status: number | null;
|
|
28
|
+
/** The component to render (server or client — both work). */
|
|
29
|
+
component: (...args: unknown[]) => unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── Resolver ─────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Build the deny page fallback chain from the segment chain.
|
|
36
|
+
*
|
|
37
|
+
* Walks segments from `startIndex` outward (toward root) and collects
|
|
38
|
+
* status-code file components in fallback order:
|
|
39
|
+
* 1. Specific status files (403.tsx, 404.tsx) — exact match
|
|
40
|
+
* 2. Category catch-alls (4xx.tsx) — matches any 4xx
|
|
41
|
+
* 3. error.tsx — catches everything
|
|
42
|
+
*
|
|
43
|
+
* Each segment is checked in this order. The chain is ordered so the
|
|
44
|
+
* FIRST match wins at catch time.
|
|
45
|
+
*/
|
|
46
|
+
export async function buildDenyPageChain(
|
|
47
|
+
segments: ManifestSegmentNode[],
|
|
48
|
+
startIndex: number
|
|
49
|
+
): Promise<DenyPageEntry[]> {
|
|
50
|
+
const chain: DenyPageEntry[] = [];
|
|
51
|
+
|
|
52
|
+
// Pass 1: Status files (specific + category) across ALL segments.
|
|
53
|
+
// These have higher priority than error.tsx — a root 4xx.tsx should
|
|
54
|
+
// match before a leaf error.tsx. Walking inner → outer ensures the
|
|
55
|
+
// nearest match wins within each priority tier.
|
|
56
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
57
|
+
const segment = segments[i];
|
|
58
|
+
if (!segment.statusFiles) continue;
|
|
59
|
+
|
|
60
|
+
// Specific status files (403.tsx, 404.tsx, etc.)
|
|
61
|
+
for (const [key, file] of Object.entries(segment.statusFiles)) {
|
|
62
|
+
if (key !== '4xx' && key !== '5xx') {
|
|
63
|
+
const status = parseInt(key, 10);
|
|
64
|
+
if (!isNaN(status)) {
|
|
65
|
+
const mod = await loadModule(file).catch(() => null);
|
|
66
|
+
if (mod?.default) {
|
|
67
|
+
chain.push({ status, component: mod.default as (...args: unknown[]) => unknown });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Category catch-alls (4xx.tsx, 5xx.tsx)
|
|
74
|
+
for (const [key, file] of Object.entries(segment.statusFiles)) {
|
|
75
|
+
if (key === '4xx' || key === '5xx') {
|
|
76
|
+
const mod = await loadModule(file).catch(() => null);
|
|
77
|
+
if (mod?.default) {
|
|
78
|
+
const categoryStatus = key === '4xx' ? 400 : 500;
|
|
79
|
+
chain.push({
|
|
80
|
+
status: categoryStatus,
|
|
81
|
+
component: mod.default as (...args: unknown[]) => unknown,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Pass 2: error.tsx files — lowest priority catch-all.
|
|
89
|
+
// Only added AFTER all status files so they never shadow a specific
|
|
90
|
+
// or category status file from an ancestor segment.
|
|
91
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
92
|
+
const segment = segments[i];
|
|
93
|
+
if (segment.error) {
|
|
94
|
+
const mod = await loadModule(segment.error).catch(() => null);
|
|
95
|
+
if (mod?.default) {
|
|
96
|
+
chain.push({ status: null, component: mod.default as (...args: unknown[]) => unknown });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return chain;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ─── Matcher ──────────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Find the first deny page in the chain that matches the given status code.
|
|
108
|
+
* Returns a React element for the matching component, or null if no match.
|
|
109
|
+
*/
|
|
110
|
+
export function renderMatchingDenyPage(
|
|
111
|
+
chain: DenyPageEntry[],
|
|
112
|
+
status: number,
|
|
113
|
+
data: unknown
|
|
114
|
+
): React.ReactElement | null {
|
|
115
|
+
const h = createElement as (...args: unknown[]) => React.ReactElement;
|
|
116
|
+
|
|
117
|
+
for (const entry of chain) {
|
|
118
|
+
if (entry.status === status) {
|
|
119
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
120
|
+
}
|
|
121
|
+
if (entry.status === 400 && status >= 400 && status <= 499) {
|
|
122
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
123
|
+
}
|
|
124
|
+
if (entry.status === 500 && status >= 500 && status <= 599) {
|
|
125
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
126
|
+
}
|
|
127
|
+
if (entry.status === null) {
|
|
128
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ─── ALS Helper ───────────────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Set the deny status in the request context ALS.
|
|
138
|
+
* Called from AccessGate / PageDenyBoundary when a DenySignal is caught.
|
|
139
|
+
* The pipeline reads this after render to set the HTTP status code.
|
|
140
|
+
*/
|
|
141
|
+
export function setDenyStatus(status: number): void {
|
|
142
|
+
const store = requestContextAls.getStore();
|
|
143
|
+
if (store) {
|
|
144
|
+
store.denyStatus = status;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Read the deny status from the request context ALS.
|
|
150
|
+
* Returns undefined if no deny was caught during render.
|
|
151
|
+
*/
|
|
152
|
+
export function getDenyStatus(): number | undefined {
|
|
153
|
+
return requestContextAls.getStore()?.denyStatus;
|
|
154
|
+
}
|