@timber-js/app 0.2.0-alpha.13 → 0.2.0-alpha.131
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-BNhpxrnV.js +1104 -0
- package/dist/_chunks/actions-BNhpxrnV.js.map +1 -0
- package/dist/_chunks/build-output-helper-K7oUCRqU.js +102 -0
- package/dist/_chunks/build-output-helper-K7oUCRqU.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-CObqjGWF.js +2 -0
- package/dist/_chunks/cli-schema-sync-q-Ce6-iG.js +785 -0
- package/dist/_chunks/cli-schema-sync-q-Ce6-iG.js.map +1 -0
- package/dist/_chunks/codec-registry-DqkeAydt.js +21 -0
- package/dist/_chunks/codec-registry-DqkeAydt.js.map +1 -0
- package/dist/_chunks/define-DMq-Yjp7.js +112 -0
- package/dist/_chunks/define-DMq-Yjp7.js.map +1 -0
- package/dist/_chunks/define-jeHDXZGq.js +195 -0
- package/dist/_chunks/define-jeHDXZGq.js.map +1 -0
- package/dist/_chunks/format-BjN9HLu9.js +14 -0
- package/dist/_chunks/format-BjN9HLu9.js.map +1 -0
- package/dist/_chunks/handler-store-bIAstrxQ.js +54 -0
- package/dist/_chunks/handler-store-bIAstrxQ.js.map +1 -0
- package/dist/_chunks/logger-CMd9P1xQ.js +291 -0
- package/dist/_chunks/logger-CMd9P1xQ.js.map +1 -0
- package/dist/_chunks/merge-search-params-Cm1j99HC.js +41 -0
- package/dist/_chunks/merge-search-params-Cm1j99HC.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DESG8uk5.js} +32 -19
- package/dist/_chunks/metadata-routes-DESG8uk5.js.map +1 -0
- package/dist/_chunks/navigation-root-B5-RmsPi.js +103 -0
- package/dist/_chunks/navigation-root-B5-RmsPi.js.map +1 -0
- package/dist/_chunks/registry-BI9cgCt7.js +20 -0
- package/dist/_chunks/registry-BI9cgCt7.js.map +1 -0
- package/dist/_chunks/resolve-schema-DU2nbVOi.js +77 -0
- package/dist/_chunks/resolve-schema-DU2nbVOi.js.map +1 -0
- package/dist/_chunks/router-ref-B2-2kIIC.js +28 -0
- package/dist/_chunks/router-ref-B2-2kIIC.js.map +1 -0
- package/dist/_chunks/schema-bridge-o0SwFtXW.js +86 -0
- package/dist/_chunks/schema-bridge-o0SwFtXW.js.map +1 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js +137 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -0
- package/dist/_chunks/segment-context-Bg0pFbLT.js +34 -0
- package/dist/_chunks/segment-context-Bg0pFbLT.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DVX8S7vj.js} +1 -1
- package/dist/_chunks/ssr-data-DVX8S7vj.js.map +1 -0
- package/dist/_chunks/stale-reload-CCqb62Z3.js +84 -0
- package/dist/_chunks/stale-reload-CCqb62Z3.js.map +1 -0
- package/dist/_chunks/tracing-DP5djRq5.js +358 -0
- package/dist/_chunks/tracing-DP5djRq5.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-C9G6LP0F.js} +7 -20
- package/dist/_chunks/use-query-states-C9G6LP0F.js.map +1 -0
- package/dist/_chunks/use-segment-params-CIeinIx2.js +151 -0
- package/dist/_chunks/use-segment-params-CIeinIx2.js.map +1 -0
- package/dist/_chunks/validation-AfEFM5ze.js +84 -0
- package/dist/_chunks/validation-AfEFM5ze.js.map +1 -0
- package/dist/_chunks/walkers-BbEu2_Pp.js +724 -0
- package/dist/_chunks/walkers-BbEu2_Pp.js.map +1 -0
- package/dist/_chunks/{format-DviM89f0.js → warnings-CAzunaGo.js} +6 -45
- package/dist/_chunks/warnings-CAzunaGo.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +28 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +73 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +95 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +148 -12
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +142 -38
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +17 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +143 -45
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +16 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/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 +151 -81
- 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-schema-sync.d.ts +39 -0
- package/dist/cli-schema-sync.d.ts.map +1 -0
- package/dist/cli.d.ts +14 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +48 -6
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +34 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +46 -0
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
- package/dist/client/browser-entry/index.d.ts +30 -0
- package/dist/client/browser-entry/index.d.ts.map +1 -0
- package/dist/client/browser-entry/post-hydration.d.ts +26 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +26 -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 +29 -6
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +54 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +16 -27
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/history.d.ts +19 -4
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +10 -24
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +180 -1119
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +19 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +845 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link-pending-store.d.ts +65 -0
- package/dist/client/link-pending-store.d.ts.map +1 -0
- package/dist/client/link.d.ts +67 -56
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/nav-link-store.d.ts +27 -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 +14 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +46 -9
- 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 +79 -10
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +46 -3
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +3 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +49 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/segment-update-context.d.ts +21 -0
- package/dist/client/segment-update-context.d.ts.map +1 -0
- package/dist/client/shallow-url.d.ts +10 -0
- package/dist/client/shallow-url.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +13 -4
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/state.d.ts +1 -1
- package/dist/client/top-loader.d.ts +5 -5
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts +12 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-link-status.d.ts +5 -5
- package/dist/client/use-link-status.d.ts.map +1 -1
- package/dist/client/use-pending-navigation.d.ts +23 -0
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/client/use-search-params.d.ts +7 -5
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +8 -6
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +69 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +75 -0
- package/dist/codec.js.map +1 -0
- package/dist/config-types.d.ts +294 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-validation.d.ts +51 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts +58 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +2 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +251 -36
- package/dist/cookies/index.js.map +1 -1
- package/dist/cookies/json-cookie.d.ts +64 -0
- package/dist/cookies/json-cookie.d.ts.map +1 -0
- package/dist/cookies/validation.d.ts +46 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +46 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +84 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +58 -0
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/dev-tools/holding-server.d.ts +54 -0
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
- package/dist/dev-tools/instrumentation.d.ts.map +1 -0
- package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
- package/dist/dev-tools/logger.d.ts.map +1 -0
- package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +2 -2
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/dev-tools/overlay.d.ts +91 -0
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/dev-tools/terminal.d.ts +28 -0
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +2 -22
- package/dist/dev-tools/warnings.d.ts.map +1 -0
- package/dist/fonts/ast.d.ts +98 -6
- package/dist/fonts/ast.d.ts.map +1 -1
- package/dist/fonts/bundle.d.ts +48 -0
- package/dist/fonts/bundle.d.ts.map +1 -0
- package/dist/fonts/dev-middleware.d.ts +22 -0
- package/dist/fonts/dev-middleware.d.ts.map +1 -0
- package/dist/fonts/local.d.ts +1 -1
- package/dist/fonts/pipeline.d.ts +167 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +78 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +45 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +94 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +46 -164
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5584 -13386
- package/dist/index.js.map +1 -1
- package/dist/params/codec-registry.d.ts +26 -0
- package/dist/params/codec-registry.d.ts.map +1 -0
- package/dist/params/define-schema.d.ts +81 -0
- package/dist/params/define-schema.d.ts.map +1 -0
- package/dist/params/index.d.ts +5 -0
- package/dist/params/index.d.ts.map +1 -0
- package/dist/params/index.js +34 -0
- package/dist/params/index.js.map +1 -0
- package/dist/params/resolve-schema.d.ts +34 -0
- package/dist/params/resolve-schema.d.ts.map +1 -0
- package/dist/plugin-context.d.ts +107 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +2 -2
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +9 -7
- 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/cloudflare-wasm.d.ts +18 -0
- package/dist/plugins/cloudflare-wasm.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +17 -73
- 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 +5 -26
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +67 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +60 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +7 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts +41 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/index.d.ts +7 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +4 -2
- package/dist/routing/link-codegen.d.ts +90 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +1 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/schema-validation.d.ts +35 -0
- package/dist/routing/schema-validation.d.ts.map +1 -0
- package/dist/routing/segment-classify.d.ts +75 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/segment-codegen.d.ts +38 -0
- package/dist/routing/segment-codegen.d.ts.map +1 -0
- package/dist/routing/types.d.ts +77 -25
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +51 -0
- package/dist/routing/walkers.d.ts.map +1 -0
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +76 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +157 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +34 -441
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/registry.d.ts +2 -2
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/segment-params/define.d.ts +89 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +3 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +2 -0
- package/dist/server/access-gate.d.ts +8 -3
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +41 -6
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts +35 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +6 -14
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +70 -11
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +1 -15
- package/dist/server/asset-headers.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +8 -2
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/coalesce-tick.d.ts +40 -0
- package/dist/server/coalesce-tick.d.ts.map +1 -0
- package/dist/server/cookie-context.d.ts +170 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +51 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/debug.d.ts +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-boundary.d.ts +90 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-source-map.d.ts +22 -0
- package/dist/server/dev-source-map.d.ts.map +1 -0
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +12 -7
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/flush.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +213 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +81 -41
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +10 -46
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +155 -2905
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +48 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +3027 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +39 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/metadata-routes.d.ts +23 -7
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +36 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +112 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +54 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +95 -0
- package/dist/server/pipeline-helpers.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +6 -0
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +52 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +118 -23
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +117 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/primitives.d.ts +69 -18
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +62 -107
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +28 -2
- 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 +25 -36
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts +2 -2
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +50 -6
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +19 -8
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +50 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +17 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +119 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/sensitive-fields.d.ts +74 -0
- package/dist/server/sensitive-fields.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +129 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +121 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -0
- package/dist/server/ssr-entry.d.ts +2 -43
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +64 -21
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +50 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/state-tree-diff.d.ts +12 -5
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +16 -11
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +36 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +5 -5
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +62 -30
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/tree-match.d.ts +49 -0
- package/dist/server/tree-match.d.ts.map +1 -0
- package/dist/server/types.d.ts +49 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.d.ts +26 -0
- package/dist/shims/font-local.d.ts.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +3 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +11 -5
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/package.json +61 -22
- package/src/adapters/build-output-helper.ts +139 -0
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/adapters/cloudflare.ts +350 -76
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +142 -59
- package/src/adapters/shared.ts +40 -0
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +38 -0
- package/src/cache/handler-store.ts +68 -0
- package/src/cache/index.ts +81 -18
- package/src/cache/singleflight.ts +62 -4
- package/src/cache/sizeof.ts +33 -0
- package/src/cache/timber-cache.ts +25 -20
- package/src/cli-schema-sync.ts +295 -0
- package/src/cli.ts +76 -8
- package/src/client/browser-dev.ts +153 -1
- package/src/client/browser-entry/action-dispatch.ts +125 -0
- package/src/client/browser-entry/hmr.ts +81 -0
- package/src/client/browser-entry/hydrate.ts +153 -0
- package/src/client/browser-entry/index.ts +151 -0
- package/src/client/browser-entry/post-hydration.ts +113 -0
- package/src/client/browser-entry/router-init.ts +219 -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 +99 -22
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +31 -32
- package/src/client/history.ts +26 -4
- package/src/client/index.ts +66 -45
- package/src/client/internal.ts +58 -0
- package/src/client/link-pending-store.ts +116 -0
- package/src/client/link.tsx +336 -119
- package/src/client/nav-link-store.ts +37 -0
- package/src/client/navigation-api-types.ts +112 -0
- package/src/client/navigation-api.ts +332 -0
- package/src/client/navigation-context.ts +33 -7
- package/src/client/navigation-root.tsx +347 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +418 -128
- package/src/client/rsc-fetch.ts +208 -10
- package/src/client/segment-cache.ts +6 -3
- package/src/client/segment-outlet.tsx +77 -0
- package/src/client/segment-update-context.ts +42 -0
- package/src/client/shallow-url.ts +22 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/stale-reload.ts +72 -3
- package/src/client/state.ts +2 -2
- package/src/client/top-loader.tsx +11 -9
- package/src/client/use-cookie.ts +31 -2
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-pending-navigation.ts +40 -0
- package/src/client/use-query-states.ts +9 -3
- package/src/client/use-router.ts +1 -1
- package/src/client/use-search-params.ts +25 -44
- package/src/client/{use-params.ts → use-segment-params.ts} +8 -6
- package/src/codec.ts +147 -0
- package/src/config-types.ts +292 -0
- package/src/config-validation.ts +303 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +233 -53
- package/src/cookies/index.ts +12 -1
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +134 -0
- package/src/dev-tools/404-page.ts +387 -0
- package/src/dev-tools/browser-logs.ts +291 -0
- package/src/dev-tools/error-page.ts +506 -0
- package/src/dev-tools/holding-server.ts +187 -0
- package/src/dev-tools/index.ts +90 -0
- package/src/dev-tools/instrumentation.ts +176 -0
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +9 -5
- package/src/dev-tools/overlay.ts +469 -0
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +183 -0
- package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +5 -50
- package/src/fonts/ast.ts +525 -16
- package/src/fonts/bundle.ts +142 -0
- package/src/fonts/dev-middleware.ts +74 -0
- package/src/fonts/local.ts +1 -1
- package/src/fonts/pipeline.ts +314 -0
- package/src/fonts/transform.ts +317 -0
- package/src/fonts/types.ts +50 -1
- package/src/fonts/virtual-modules.ts +233 -0
- package/src/index.ts +411 -329
- package/src/params/codec-registry.ts +34 -0
- package/src/params/define-schema.ts +114 -0
- package/src/params/index.ts +17 -0
- package/src/params/resolve-schema.ts +116 -0
- package/src/plugin-context.ts +240 -0
- package/src/plugins/adapter-build.ts +12 -4
- package/src/plugins/build-manifest.ts +69 -6
- package/src/plugins/build-report.ts +16 -25
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/cloudflare-wasm.ts +103 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-server.ts +179 -37
- package/src/plugins/entries.ts +111 -8
- package/src/plugins/fonts.ts +165 -654
- package/src/plugins/mdx.ts +47 -10
- package/src/plugins/routing.ts +386 -47
- package/src/plugins/server-bundle.ts +59 -3
- package/src/plugins/shims.ts +136 -35
- package/src/plugins/static-build.ts +15 -89
- package/src/routing/codegen-shared.ts +115 -0
- package/src/routing/codegen-types.ts +61 -0
- package/src/routing/codegen.ts +321 -177
- package/src/routing/convention-lint.ts +357 -0
- package/src/routing/index.ts +10 -1
- package/src/routing/interception.ts +1 -1
- package/src/routing/link-codegen.ts +308 -0
- package/src/routing/scanner.ts +165 -110
- package/src/routing/schema-validation.ts +149 -0
- package/src/routing/segment-classify.ts +188 -0
- package/src/routing/segment-codegen.ts +98 -0
- package/src/routing/types.ts +78 -25
- package/src/routing/walkers.ts +90 -0
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
- package/src/search-params/define.ts +538 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +92 -0
- package/src/segment-params/define.ts +309 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +76 -34
- package/src/server/action-client.ts +88 -15
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +112 -14
- package/src/server/actions.ts +14 -23
- package/src/server/als-registry.ts +108 -20
- package/src/server/asset-headers.ts +8 -34
- package/src/server/build-manifest.ts +17 -4
- package/src/server/coalesce-tick.ts +75 -0
- package/src/server/compress.ts +25 -7
- package/src/server/cookie-context.ts +468 -0
- package/src/server/cookie-parsing.ts +135 -0
- package/src/server/debug.ts +1 -1
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-boundary.ts +218 -0
- package/src/server/deny-renderer.ts +32 -51
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +74 -22
- package/src/server/fallback-error.ts +74 -102
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +101 -5
- package/src/server/html-injector-core.ts +417 -0
- package/src/server/html-injectors.ts +235 -223
- package/src/server/index.ts +29 -183
- package/src/server/internal.ts +182 -0
- package/src/server/logger.ts +67 -36
- package/src/server/metadata-routes.ts +44 -19
- package/src/server/middleware-runner.ts +75 -4
- package/src/server/node-stream-transforms.ts +361 -0
- package/src/server/param-coercion.ts +206 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +17 -16
- package/src/server/pipeline-metadata.ts +13 -0
- package/src/server/pipeline-outcome.ts +197 -0
- package/src/server/pipeline-phases.ts +468 -0
- package/src/server/pipeline.ts +154 -394
- package/src/server/port-resolution.ts +215 -0
- package/src/server/primitives.ts +111 -28
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +168 -337
- package/src/server/route-element-builder.ts +435 -208
- package/src/server/route-handler.ts +24 -4
- package/src/server/route-matcher.ts +128 -277
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +16 -17
- package/src/server/rsc-entry/error-renderer.ts +315 -89
- package/src/server/rsc-entry/helpers.ts +155 -26
- package/src/server/rsc-entry/index.ts +316 -327
- package/src/server/rsc-entry/render-route.ts +313 -0
- package/src/server/rsc-entry/rsc-payload.ts +65 -18
- package/src/server/rsc-entry/rsc-stream.ts +85 -13
- package/src/server/rsc-entry/ssr-bridge.ts +18 -5
- package/src/server/rsc-entry/ssr-renderer.ts +193 -40
- package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -0
- package/src/server/safe-load.ts +60 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/sitemap-generator.ts +338 -0
- package/src/server/sitemap-handler.ts +126 -0
- package/src/server/slot-resolver.ts +228 -246
- package/src/server/ssr-bridge-types.ts +124 -0
- package/src/server/ssr-entry.ts +217 -78
- package/src/server/ssr-render.ts +344 -71
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/state-tree-diff.ts +30 -23
- package/src/server/status-code-resolver.ts +112 -128
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +21 -10
- package/src/server/tree-builder.ts +202 -90
- package/src/server/tree-match.ts +210 -0
- package/src/server/types.ts +55 -6
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/version-skew.ts +104 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +5 -1
- package/src/shims/navigation-client.ts +4 -3
- package/src/shims/navigation.ts +14 -7
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js +0 -41
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-gwlJkDuf.js +0 -108
- package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
- package/dist/_chunks/format-DviM89f0.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js +0 -676
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/metadata-routes-Cjmvi3rQ.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/ssr-data-MjmprTmO.js.map +0 -1
- package/dist/_chunks/tracing-CemImE6h.js +0 -187
- 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/segment-merger.d.ts +0 -119
- package/dist/client/segment-merger.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts +0 -26
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts +0 -60
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/plugins/server-action-exports.d.ts +0 -26
- package/dist/plugins/server-action-exports.d.ts.map +0 -1
- package/dist/routing/status-file-lint.d.ts +0 -33
- package/dist/routing/status-file-lint.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/codecs.d.ts +0 -53
- package/dist/search-params/codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
- package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/manifest-status-resolver.d.ts +0 -58
- package/dist/server/manifest-status-resolver.d.ts.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/utils/directive-parser.d.ts +0 -70
- package/dist/utils/directive-parser.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/segment-merger.ts +0 -339
- package/src/client/transition-root.tsx +0 -166
- package/src/client/use-navigation-pending.ts +0 -38
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dev-error-overlay.ts +0 -230
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/plugins/server-action-exports.ts +0 -220
- package/src/routing/status-file-lint.ts +0 -112
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/prerender.ts +0 -139
- package/src/utils/directive-parser.ts +0 -529
- /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
package/src/client/rsc-fetch.ts
CHANGED
|
@@ -20,10 +20,18 @@ import type { RouterDeps } from './router';
|
|
|
20
20
|
/** Result of fetching an RSC payload — includes head elements and segment metadata. */
|
|
21
21
|
export interface FetchResult {
|
|
22
22
|
payload: unknown;
|
|
23
|
+
/**
|
|
24
|
+
* Promise that settles when the RSC decode completes or fails.
|
|
25
|
+
* The payload thenable is NOT awaited before returning (for streaming),
|
|
26
|
+
* so callers must monitor this to catch async decode errors
|
|
27
|
+
* (truncated streams, Flight parse failures) that would otherwise
|
|
28
|
+
* become unhandled rejections.
|
|
29
|
+
*/
|
|
30
|
+
decodePromise: Promise<void> | null;
|
|
23
31
|
headElements: HeadElement[] | null;
|
|
24
32
|
/** Segment metadata from X-Timber-Segments header for populating the segment cache. */
|
|
25
33
|
segmentInfo: SegmentInfo[] | null;
|
|
26
|
-
/** Route params from X-Timber-Params header for populating
|
|
34
|
+
/** Route params from X-Timber-Params header for populating useSegmentParams(). */
|
|
27
35
|
params: Record<string, string | string[]> | null;
|
|
28
36
|
/** Segment paths that were skipped by the server (for client-side merging). */
|
|
29
37
|
skippedSegments: string[] | null;
|
|
@@ -58,6 +66,43 @@ function appendRscParam(url: string): string {
|
|
|
58
66
|
return `${url}${separator}_rsc=${generateCacheBustId()}`;
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
// ─── Deployment ID ───────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The client's deployment ID, set at bootstrap from the runtime config.
|
|
73
|
+
* Sent with every RSC/action request for version skew detection.
|
|
74
|
+
* Null in dev mode. See TIM-446.
|
|
75
|
+
*/
|
|
76
|
+
let clientDeploymentId: string | null = null;
|
|
77
|
+
|
|
78
|
+
/** Set the client deployment ID. Called once at bootstrap. */
|
|
79
|
+
export function setClientDeploymentId(id: string | null): void {
|
|
80
|
+
clientDeploymentId = id;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Get the client deployment ID. */
|
|
84
|
+
export function getClientDeploymentId(): string | null {
|
|
85
|
+
return clientDeploymentId;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ─── Reload Signal ───────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
/** Header name used by the server to signal a version skew reload. */
|
|
91
|
+
export const RELOAD_HEADER = 'X-Timber-Reload';
|
|
92
|
+
|
|
93
|
+
/** Header name for the client's deployment ID. */
|
|
94
|
+
export const DEPLOYMENT_ID_HEADER = 'X-Timber-Deployment-Id';
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Check if a response signals a version skew reload.
|
|
98
|
+
* Triggers a full page reload if the server indicates the client is stale.
|
|
99
|
+
*/
|
|
100
|
+
export function checkReloadSignal(response: Response): boolean {
|
|
101
|
+
return response.headers.get(RELOAD_HEADER) === '1';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ─── Header Builder ──────────────────────────────────────────────
|
|
105
|
+
|
|
61
106
|
export function buildRscHeaders(
|
|
62
107
|
stateTree: { segments: string[] } | undefined,
|
|
63
108
|
currentUrl?: string
|
|
@@ -75,11 +120,29 @@ export function buildRscHeaders(
|
|
|
75
120
|
if (currentUrl) {
|
|
76
121
|
headers['X-Timber-URL'] = currentUrl;
|
|
77
122
|
}
|
|
123
|
+
// Send deployment ID for version skew detection (TIM-446).
|
|
124
|
+
// The server compares this against the current build's ID.
|
|
125
|
+
// On mismatch, the server signals a reload instead of returning
|
|
126
|
+
// an RSC payload with mismatched module references.
|
|
127
|
+
if (clientDeploymentId) {
|
|
128
|
+
headers[DEPLOYMENT_ID_HEADER] = clientDeploymentId;
|
|
129
|
+
}
|
|
78
130
|
return headers;
|
|
79
131
|
}
|
|
80
132
|
|
|
81
133
|
// ─── Response Header Extraction ──────────────────────────────────
|
|
82
134
|
|
|
135
|
+
/** Dev-only warning for malformed framework headers. Tree-shaken in production. */
|
|
136
|
+
function warnMalformedHeader(headerName: string, raw: string): void {
|
|
137
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
138
|
+
const preview = raw.length > 200 ? raw.slice(0, 200) + '…' : raw;
|
|
139
|
+
console.warn(
|
|
140
|
+
`[timber] Malformed ${headerName} header \u2014 JSON.parse failed. ` +
|
|
141
|
+
`This indicates a framework bug or header corruption. Raw (first 200 chars): ${preview}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
83
146
|
/**
|
|
84
147
|
* Extract head elements from the X-Timber-Head response header.
|
|
85
148
|
* Returns null if the header is missing or malformed.
|
|
@@ -90,6 +153,7 @@ export function extractHeadElements(response: Response): HeadElement[] | null {
|
|
|
90
153
|
try {
|
|
91
154
|
return JSON.parse(decodeURIComponent(header));
|
|
92
155
|
} catch {
|
|
156
|
+
warnMalformedHeader('X-Timber-Head', header);
|
|
93
157
|
return null;
|
|
94
158
|
}
|
|
95
159
|
}
|
|
@@ -108,6 +172,7 @@ export function extractSegmentInfo(response: Response): SegmentInfo[] | null {
|
|
|
108
172
|
try {
|
|
109
173
|
return JSON.parse(header);
|
|
110
174
|
} catch {
|
|
175
|
+
warnMalformedHeader('X-Timber-Segments', header);
|
|
111
176
|
return null;
|
|
112
177
|
}
|
|
113
178
|
}
|
|
@@ -127,6 +192,7 @@ export function extractSkippedSegments(response: Response): string[] | null {
|
|
|
127
192
|
const parsed = JSON.parse(header);
|
|
128
193
|
return Array.isArray(parsed) ? parsed : null;
|
|
129
194
|
} catch {
|
|
195
|
+
warnMalformedHeader('X-Timber-Skipped-Segments', header);
|
|
130
196
|
return null;
|
|
131
197
|
}
|
|
132
198
|
}
|
|
@@ -135,7 +201,7 @@ export function extractSkippedSegments(response: Response): string[] | null {
|
|
|
135
201
|
* Extract route params from the X-Timber-Params response header.
|
|
136
202
|
* Returns null if the header is missing or malformed.
|
|
137
203
|
*
|
|
138
|
-
* Used to populate
|
|
204
|
+
* Used to populate useSegmentParams() after client-side navigation.
|
|
139
205
|
*/
|
|
140
206
|
export function extractParams(response: Response): Record<string, string | string[]> | null {
|
|
141
207
|
const header = response.headers.get('X-Timber-Params');
|
|
@@ -143,6 +209,7 @@ export function extractParams(response: Response): Record<string, string | strin
|
|
|
143
209
|
try {
|
|
144
210
|
return JSON.parse(header);
|
|
145
211
|
} catch {
|
|
212
|
+
warnMalformedHeader('X-Timber-Params', header);
|
|
146
213
|
return null;
|
|
147
214
|
}
|
|
148
215
|
}
|
|
@@ -161,6 +228,84 @@ export class RedirectError extends Error {
|
|
|
161
228
|
}
|
|
162
229
|
}
|
|
163
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Thrown when the server signals a version skew (X-Timber-Reload header).
|
|
233
|
+
* Caught in navigate() to trigger a full page reload via triggerStaleReload().
|
|
234
|
+
* See TIM-446.
|
|
235
|
+
*/
|
|
236
|
+
export class VersionSkewError extends Error {
|
|
237
|
+
constructor() {
|
|
238
|
+
super('Version skew detected — server has been redeployed');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Thrown when the server returns an error for an RSC payload request.
|
|
244
|
+
* The server sends X-Timber-Error header and a JSON body instead of a
|
|
245
|
+
* broken RSC stream for any RenderError (4xx or 5xx). Caught in
|
|
246
|
+
* navigate() to trigger a hard navigation so the server can render
|
|
247
|
+
* the error page as HTML.
|
|
248
|
+
*
|
|
249
|
+
* See design/10-error-handling.md §"Error Page Rendering for Client Navigation"
|
|
250
|
+
*/
|
|
251
|
+
export class ServerErrorResponse extends Error {
|
|
252
|
+
readonly status: number;
|
|
253
|
+
readonly url: string;
|
|
254
|
+
constructor(status: number, url: string) {
|
|
255
|
+
super(`Server error ${status} during navigation to ${url}`);
|
|
256
|
+
this.status = status;
|
|
257
|
+
this.url = url;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ─── Stream Completion Tracking ───────────────────────────────────
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Wrap a response body stream to track when it's fully consumed.
|
|
265
|
+
* Returns a new body that passes all chunks through unchanged, plus
|
|
266
|
+
* a `done` promise that resolves when the last chunk is read (or
|
|
267
|
+
* rejects if the stream errors).
|
|
268
|
+
*
|
|
269
|
+
* Used to keep React transitions open for the full RSC stream
|
|
270
|
+
* duration — createFromFetch's thenable resolves on shell arrival,
|
|
271
|
+
* but we need stream completion for useOptimistic pending state.
|
|
272
|
+
*/
|
|
273
|
+
function trackStreamCompletion(body: ReadableStream<Uint8Array>): {
|
|
274
|
+
body: ReadableStream<Uint8Array>;
|
|
275
|
+
done: Promise<void>;
|
|
276
|
+
} {
|
|
277
|
+
let resolveDone!: () => void;
|
|
278
|
+
let rejectDone!: (e: unknown) => void;
|
|
279
|
+
const done = new Promise<void>((res, rej) => {
|
|
280
|
+
resolveDone = res;
|
|
281
|
+
rejectDone = rej;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const reader = body.getReader();
|
|
285
|
+
const tracked = new ReadableStream<Uint8Array>({
|
|
286
|
+
async pull(controller) {
|
|
287
|
+
try {
|
|
288
|
+
const result = await reader.read();
|
|
289
|
+
if (result.done) {
|
|
290
|
+
controller.close();
|
|
291
|
+
resolveDone();
|
|
292
|
+
} else {
|
|
293
|
+
controller.enqueue(result.value);
|
|
294
|
+
}
|
|
295
|
+
} catch (error) {
|
|
296
|
+
controller.error(error);
|
|
297
|
+
rejectDone(error);
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
cancel(reason) {
|
|
301
|
+
reader.cancel(reason);
|
|
302
|
+
resolveDone();
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return { body: tracked, done };
|
|
307
|
+
}
|
|
308
|
+
|
|
164
309
|
// ─── Fetch ───────────────────────────────────────────────────────
|
|
165
310
|
|
|
166
311
|
/**
|
|
@@ -175,7 +320,8 @@ export async function fetchRscPayload(
|
|
|
175
320
|
url: string,
|
|
176
321
|
deps: RouterDeps,
|
|
177
322
|
stateTree?: { segments: string[] },
|
|
178
|
-
currentUrl?: string
|
|
323
|
+
currentUrl?: string,
|
|
324
|
+
signal?: AbortSignal
|
|
179
325
|
): Promise<FetchResult> {
|
|
180
326
|
const rscUrl = appendRscParam(url);
|
|
181
327
|
const headers = buildRscHeaders(stateTree, currentUrl);
|
|
@@ -186,12 +332,23 @@ export async function fetchRscPayload(
|
|
|
186
332
|
//
|
|
187
333
|
// Intercept the response to read X-Timber-Head before createFromFetch
|
|
188
334
|
// consumes the body. Reading headers does NOT consume the body stream.
|
|
189
|
-
const fetchPromise = deps.fetch(rscUrl, { headers, redirect: 'manual' });
|
|
335
|
+
const fetchPromise = deps.fetch(rscUrl, { headers, redirect: 'manual', signal });
|
|
190
336
|
let headElements: HeadElement[] | null = null;
|
|
191
337
|
let segmentInfo: SegmentInfo[] | null = null;
|
|
192
338
|
let params: Record<string, string | string[]> | null = null;
|
|
193
339
|
let skippedSegments: string[] | null = null;
|
|
340
|
+
// Track when the full RSC body stream is consumed (not just shell).
|
|
341
|
+
// Initialized to resolved for bodyless responses; overwritten when
|
|
342
|
+
// the response has a body.
|
|
343
|
+
let streamDone: Promise<void> = Promise.resolve();
|
|
344
|
+
|
|
194
345
|
const wrappedPromise = fetchPromise.then((response) => {
|
|
346
|
+
// Version skew detection (TIM-446): if the server signals a reload,
|
|
347
|
+
// throw VersionSkewError so the caller (router navigate) can trigger
|
|
348
|
+
// a full page reload via triggerStaleReload().
|
|
349
|
+
if (checkReloadSignal(response)) {
|
|
350
|
+
throw new VersionSkewError();
|
|
351
|
+
}
|
|
195
352
|
// Detect server-side redirects. The server returns 204 + X-Timber-Redirect
|
|
196
353
|
// for RSC payload requests instead of a raw 302, because fetch with
|
|
197
354
|
// redirect: "manual" turns 302s into opaque redirects (status 0, null body)
|
|
@@ -202,21 +359,61 @@ export async function fetchRscPayload(
|
|
|
202
359
|
if (redirectLocation) {
|
|
203
360
|
throw new RedirectError(redirectLocation);
|
|
204
361
|
}
|
|
362
|
+
// Detect server error responses. The server returns X-Timber-Error header
|
|
363
|
+
// with a JSON body instead of a broken RSC stream for any RenderError
|
|
364
|
+
// (4xx or 5xx). Hard-navigate so the server renders the error page as HTML.
|
|
365
|
+
// See design/10-error-handling.md §"Error Page Rendering for Client Navigation"
|
|
366
|
+
if (response.headers.get('X-Timber-Error') === '1') {
|
|
367
|
+
throw new ServerErrorResponse(response.status, url);
|
|
368
|
+
}
|
|
205
369
|
headElements = extractHeadElements(response);
|
|
206
370
|
segmentInfo = extractSegmentInfo(response);
|
|
207
371
|
params = extractParams(response);
|
|
208
372
|
skippedSegments = extractSkippedSegments(response);
|
|
373
|
+
|
|
374
|
+
// Wrap the body to track full stream consumption. createFromFetch's
|
|
375
|
+
// thenable resolves when the root model (shell) arrives, but we need
|
|
376
|
+
// to know when ALL chunks are read so the React transition stays
|
|
377
|
+
// open for the full streaming duration (keeps useOptimistic alive).
|
|
378
|
+
if (response.body) {
|
|
379
|
+
const tracked = trackStreamCompletion(response.body);
|
|
380
|
+
streamDone = tracked.done;
|
|
381
|
+
streamDone.catch(() => {}); // prevent unhandled rejection
|
|
382
|
+
return new Response(tracked.body, {
|
|
383
|
+
headers: response.headers,
|
|
384
|
+
status: response.status,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
209
387
|
return response;
|
|
210
388
|
});
|
|
211
|
-
// Await so headElements/segmentInfo/params are populated
|
|
212
|
-
// Also await the decoded payload — createFromFetch returns a thenable
|
|
213
|
-
// that resolves to the React element tree.
|
|
389
|
+
// Await headers so headElements/segmentInfo/params are populated.
|
|
214
390
|
await wrappedPromise;
|
|
215
|
-
|
|
216
|
-
|
|
391
|
+
// Start decoding but do NOT await — return the in-progress thenable.
|
|
392
|
+
// React can render a Flight thenable directly: it suspends on unresolved
|
|
393
|
+
// parts and progressively renders as chunks arrive, spreading work across
|
|
394
|
+
// frames instead of blocking the main thread in one burst.
|
|
395
|
+
const payload = deps.decodeRsc(wrappedPromise);
|
|
396
|
+
// Combine stream completion with payload error propagation.
|
|
397
|
+
// streamDone keeps the transition open for the full RSC stream
|
|
398
|
+
// duration (useOptimistic pending state). payloadError propagates
|
|
399
|
+
// decode failures (stale client references, Flight parse errors)
|
|
400
|
+
// so the router's catch block can trigger recovery (stale reload).
|
|
401
|
+
const payloadError = new Promise<void>((_, reject) => {
|
|
402
|
+
Promise.resolve(payload).then(() => {}, reject);
|
|
403
|
+
});
|
|
404
|
+
payloadError.catch(() => {});
|
|
405
|
+
const decodePromise = Promise.race([streamDone, payloadError]);
|
|
406
|
+
return {
|
|
407
|
+
payload,
|
|
408
|
+
decodePromise,
|
|
409
|
+
headElements,
|
|
410
|
+
segmentInfo,
|
|
411
|
+
params,
|
|
412
|
+
skippedSegments,
|
|
413
|
+
};
|
|
217
414
|
}
|
|
218
415
|
// Test/fallback path: return raw text
|
|
219
|
-
const response = await deps.fetch(rscUrl, { headers, redirect: 'manual' });
|
|
416
|
+
const response = await deps.fetch(rscUrl, { headers, redirect: 'manual', signal });
|
|
220
417
|
// Check for redirect in test path too
|
|
221
418
|
if (response.status >= 300 && response.status < 400) {
|
|
222
419
|
const location = response.headers.get('Location');
|
|
@@ -226,6 +423,7 @@ export async function fetchRscPayload(
|
|
|
226
423
|
}
|
|
227
424
|
return {
|
|
228
425
|
payload: await response.text(),
|
|
426
|
+
decodePromise: null,
|
|
229
427
|
headElements: extractHeadElements(response),
|
|
230
428
|
segmentInfo: extractSegmentInfo(response),
|
|
231
429
|
params: extractParams(response),
|
|
@@ -11,7 +11,7 @@ export interface PrefetchResult {
|
|
|
11
11
|
headElements: HeadElement[] | null;
|
|
12
12
|
/** Segment metadata from X-Timber-Segments header for populating the segment cache. */
|
|
13
13
|
segmentInfo?: SegmentInfo[] | null;
|
|
14
|
-
/** Route params from X-Timber-Params header for populating
|
|
14
|
+
/** Route params from X-Timber-Params header for populating useSegmentParams(). */
|
|
15
15
|
params?: Record<string, string | string[]> | null;
|
|
16
16
|
/** Segment paths skipped by the server (for client-side merging). */
|
|
17
17
|
skippedSegments?: string[] | null;
|
|
@@ -111,6 +111,8 @@ function collectSyncSegments(
|
|
|
111
111
|
*/
|
|
112
112
|
export interface SegmentInfo {
|
|
113
113
|
path: string;
|
|
114
|
+
/** Outlet key — includes route group name when applicable (e.g., "/(marketing)"). */
|
|
115
|
+
segmentId?: string;
|
|
114
116
|
isAsync: boolean;
|
|
115
117
|
}
|
|
116
118
|
|
|
@@ -137,8 +139,9 @@ export function buildSegmentTree(segments: SegmentInfo[]): SegmentNode | undefin
|
|
|
137
139
|
let parent: SegmentNode | undefined;
|
|
138
140
|
|
|
139
141
|
for (const info of layouts) {
|
|
142
|
+
const id = info.segmentId ?? info.path;
|
|
140
143
|
const node: SegmentNode = {
|
|
141
|
-
segment:
|
|
144
|
+
segment: id,
|
|
142
145
|
payload: null,
|
|
143
146
|
isAsync: info.isAsync,
|
|
144
147
|
children: new Map(),
|
|
@@ -149,7 +152,7 @@ export function buildSegmentTree(segments: SegmentInfo[]): SegmentNode | undefin
|
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
if (parent) {
|
|
152
|
-
parent.children.set(
|
|
155
|
+
parent.children.set(id, node);
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
parent = node;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SegmentOutlet — client component boundary at each layout segment.
|
|
3
|
+
*
|
|
4
|
+
* Each layout in the segment tree is wrapped with a SegmentOutlet that:
|
|
5
|
+
* 1. Knows its segment path (prop from the server)
|
|
6
|
+
* 2. Reads from SegmentUpdateContext for partial navigation updates
|
|
7
|
+
* 3. Caches its rendered content in a ref across navigations
|
|
8
|
+
*
|
|
9
|
+
* On full navigation: receives new children via props, caches and renders them.
|
|
10
|
+
* On partial navigation (this segment skipped): the context map has no entry
|
|
11
|
+
* for this path, so the outlet returns cached content — preserving layout state.
|
|
12
|
+
* On partial navigation (this segment updated): the context map has content
|
|
13
|
+
* for this path, so the outlet renders the update.
|
|
14
|
+
*
|
|
15
|
+
* Uses React context instead of useSyncExternalStore to stay compatible
|
|
16
|
+
* with concurrent rendering (transitions). All outlets re-render when the
|
|
17
|
+
* context value changes, but each bails out quickly if its segment has
|
|
18
|
+
* no update — same approach as Next.js LayoutRouter.
|
|
19
|
+
*
|
|
20
|
+
* Security: performance optimization only. The server always runs all
|
|
21
|
+
* access.ts files regardless of segment skipping.
|
|
22
|
+
* See design/13-security.md §"State tree manipulation".
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
'use client';
|
|
26
|
+
|
|
27
|
+
import { useContext, useRef, type ReactNode } from 'react';
|
|
28
|
+
import { SegmentUpdateContext } from './segment-update-context.js';
|
|
29
|
+
|
|
30
|
+
export interface SegmentOutletProps {
|
|
31
|
+
/**
|
|
32
|
+
* Unique identifier for this segment. For normal segments this is the
|
|
33
|
+
* urlPath (e.g., "/", "/dashboard"). For route groups this includes the
|
|
34
|
+
* group name (e.g., "/(marketing)") to distinguish siblings that share
|
|
35
|
+
* the same urlPath. Must match the segmentId used in state-tree-diff.ts.
|
|
36
|
+
*/
|
|
37
|
+
segmentPath: string;
|
|
38
|
+
|
|
39
|
+
/** The segment's React subtree (layout + inner content). */
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Client component boundary at each layout segment in the element tree.
|
|
45
|
+
*
|
|
46
|
+
* On full navigation (context map is empty): renders children, caches in ref.
|
|
47
|
+
* On partial navigation: checks the context map for an update at segmentPath.
|
|
48
|
+
* - Update found → renders update, caches in ref.
|
|
49
|
+
* - No update → returns cached content (layout state preserved).
|
|
50
|
+
*
|
|
51
|
+
* React preserves component instances across reactRoot.render() calls
|
|
52
|
+
* when the same type appears at the same tree position. The ref persists
|
|
53
|
+
* across navigations because SegmentOutlet is reconciled, not remounted.
|
|
54
|
+
*/
|
|
55
|
+
export function SegmentOutlet({ segmentPath, children }: SegmentOutletProps) {
|
|
56
|
+
const updates = useContext(SegmentUpdateContext);
|
|
57
|
+
const contentRef = useRef<ReactNode>(null);
|
|
58
|
+
|
|
59
|
+
const update = updates.get(segmentPath);
|
|
60
|
+
|
|
61
|
+
if (update !== undefined) {
|
|
62
|
+
contentRef.current = update;
|
|
63
|
+
return update;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (contentRef.current === null) {
|
|
67
|
+
contentRef.current = children;
|
|
68
|
+
return children;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (children !== contentRef.current) {
|
|
72
|
+
contentRef.current = children;
|
|
73
|
+
return children;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return contentRef.current;
|
|
77
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SegmentUpdateContext — React context for partial navigation updates.
|
|
3
|
+
*
|
|
4
|
+
* During partial navigation (server skips unchanged sync layouts), the
|
|
5
|
+
* router builds a Map of segment path → ReactNode updates and passes it
|
|
6
|
+
* as the context value. Mounted SegmentOutlet components read from this
|
|
7
|
+
* context to decide whether to render the update or their cached content.
|
|
8
|
+
*
|
|
9
|
+
* SINGLETON GUARANTEE: Uses globalThis + Symbol.for — same pattern as
|
|
10
|
+
* NavigationContext. The RSC client bundler can duplicate this module
|
|
11
|
+
* across chunks (browser-entry graph + client-reference graph). With
|
|
12
|
+
* ESM output, each chunk gets its own module scope — a bare createContext
|
|
13
|
+
* at module level would create separate instances per chunk. globalThis
|
|
14
|
+
* guarantees a single instance regardless of duplication.
|
|
15
|
+
*
|
|
16
|
+
* See design/19-client-navigation.md §"Singleton Guarantee via globalThis"
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use client';
|
|
20
|
+
|
|
21
|
+
import React, { type ReactNode } from 'react';
|
|
22
|
+
|
|
23
|
+
export const EMPTY_SEGMENT_UPDATES = new Map<string, ReactNode>();
|
|
24
|
+
|
|
25
|
+
const CTX_KEY = Symbol.for('__timber_segment_update_ctx');
|
|
26
|
+
|
|
27
|
+
function getOrCreateContext(): React.Context<Map<string, ReactNode>> {
|
|
28
|
+
const existing = (globalThis as Record<symbol, unknown>)[CTX_KEY] as
|
|
29
|
+
| React.Context<Map<string, ReactNode>>
|
|
30
|
+
| undefined;
|
|
31
|
+
if (existing !== undefined) return existing;
|
|
32
|
+
if (typeof React.createContext === 'function') {
|
|
33
|
+
const ctx = React.createContext<Map<string, ReactNode>>(EMPTY_SEGMENT_UPDATES);
|
|
34
|
+
(globalThis as Record<symbol, unknown>)[CTX_KEY] = ctx;
|
|
35
|
+
return ctx;
|
|
36
|
+
}
|
|
37
|
+
// RSC environment — createContext not available. Return a dummy that
|
|
38
|
+
// won't be used (outlets only render on the client).
|
|
39
|
+
return undefined as unknown as React.Context<Map<string, ReactNode>>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const SegmentUpdateContext = getOrCreateContext();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shallow URL replacement — update the browser URL bar without triggering
|
|
3
|
+
* RSC navigation, TopLoader, or any server round-trip.
|
|
4
|
+
*
|
|
5
|
+
* Uses the Navigation API's `info: { shallow: true }` when available (Chrome),
|
|
6
|
+
* which the navigate event handler intercepts with a no-op handler. Falls back
|
|
7
|
+
* to raw `history.replaceState` (Safari/Firefox — no navigate event fired).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getNavigationApi } from './navigation-api.js';
|
|
11
|
+
|
|
12
|
+
export function replaceUrl(url: string): void {
|
|
13
|
+
const nav = getNavigationApi();
|
|
14
|
+
if (nav) {
|
|
15
|
+
nav.navigate(url, {
|
|
16
|
+
history: 'replace',
|
|
17
|
+
info: { shallow: true },
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
history.replaceState(history.state, '', url);
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/client/ssr-data.ts
CHANGED
|
@@ -41,12 +41,20 @@ export interface SsrData {
|
|
|
41
41
|
/** The request's route params (e.g. { id: '123' }) */
|
|
42
42
|
params: Record<string, string | string[]>;
|
|
43
43
|
/**
|
|
44
|
-
* Mutable reference to NavContext for error boundary →
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
44
|
+
* Mutable reference to NavContext for error boundary → pipeline communication.
|
|
45
|
+
*
|
|
46
|
+
* When TimberErrorBoundary catches a DenySignal during SSR, it:
|
|
47
|
+
* 1. Sets `statusCode` to the deny status (e.g., 403) — so the HTTP
|
|
48
|
+
* Response has the correct status code without a re-render.
|
|
49
|
+
* 2. Sets `_denyHandledByBoundary = true` — so the pipeline skips
|
|
50
|
+
* the redundant renderDenyPage() re-render.
|
|
51
|
+
*
|
|
52
|
+
* This runs synchronously during Fizz rendering, BEFORE onShellReady,
|
|
53
|
+
* so the status code is committed before any bytes are sent.
|
|
54
|
+
*
|
|
55
|
+
* See TIM-664, design/04-authorization.md §"React.cache Scope in Deny/Error Re-renders"
|
|
48
56
|
*/
|
|
49
|
-
_navContext?: { _denyHandledByBoundary?: boolean };
|
|
57
|
+
_navContext?: { statusCode?: number; _denyHandledByBoundary?: boolean };
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
// ─── ALS-Backed Provider ─────────────────────────────────────────
|
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
|
|
17
17
|
const RELOAD_FLAG_KEY = '__timber_stale_reload';
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* In-memory fallback counter for environments where sessionStorage is
|
|
21
|
+
* unavailable (private browsing, storage full, extension interference).
|
|
22
|
+
* Incremented each time triggerStaleReload() falls into the catch path.
|
|
23
|
+
* If the counter exceeds 0 on a subsequent call, the reload is suppressed
|
|
24
|
+
* to prevent an infinite loop. Resets naturally on page load (module
|
|
25
|
+
* re-evaluates) and can be manually reset via clearStaleReloadFlag().
|
|
26
|
+
*/
|
|
27
|
+
let memoryReloadCount = 0;
|
|
28
|
+
|
|
19
29
|
/**
|
|
20
30
|
* Check if an error is a stale client reference error from React's
|
|
21
31
|
* Flight client. These errors have the message pattern:
|
|
@@ -32,6 +42,34 @@ export function isStaleClientReference(error: unknown): boolean {
|
|
|
32
42
|
return msg.includes('Could not find the module') || msg.includes('client reference not found');
|
|
33
43
|
}
|
|
34
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Check if an error is a chunk load failure from a dynamic import.
|
|
47
|
+
*
|
|
48
|
+
* After a deployment, old chunk filenames no longer exist. When the client
|
|
49
|
+
* tries to dynamically import a chunk that's been replaced, the browser
|
|
50
|
+
* throws one of these errors:
|
|
51
|
+
*
|
|
52
|
+
* - Chromium: "Failed to fetch dynamically imported module: <url>"
|
|
53
|
+
* - Firefox: "error loading dynamically imported module: <url>"
|
|
54
|
+
* - Safari: "Importing a module script failed."
|
|
55
|
+
* - Vite/Rollup: "Unable to preload CSS for <url>"
|
|
56
|
+
*
|
|
57
|
+
* See TIM-446
|
|
58
|
+
*/
|
|
59
|
+
export function isChunkLoadError(error: unknown): boolean {
|
|
60
|
+
if (!(error instanceof Error)) return false;
|
|
61
|
+
const msg = error.message.toLowerCase();
|
|
62
|
+
return (
|
|
63
|
+
msg.includes('failed to fetch dynamically imported module') ||
|
|
64
|
+
msg.includes('error loading dynamically imported module') ||
|
|
65
|
+
msg.includes('importing a module script failed') ||
|
|
66
|
+
msg.includes('unable to preload css') ||
|
|
67
|
+
// Webpack-style chunk load errors (unlikely in Vite but defensive)
|
|
68
|
+
msg.includes('loading chunk') ||
|
|
69
|
+
msg.includes('loading css chunk')
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
35
73
|
/**
|
|
36
74
|
* Trigger a full page reload to pick up new bundles.
|
|
37
75
|
*
|
|
@@ -65,9 +103,33 @@ export function triggerStaleReload(): boolean {
|
|
|
65
103
|
window.location.reload();
|
|
66
104
|
return true;
|
|
67
105
|
} catch {
|
|
68
|
-
// sessionStorage
|
|
69
|
-
//
|
|
70
|
-
|
|
106
|
+
// sessionStorage unavailable (private browsing, storage full, etc.)
|
|
107
|
+
// Use document.cookie as a reload-persistent fallback loop guard.
|
|
108
|
+
// Module-level memoryReloadCount resets on every reload, so it can't
|
|
109
|
+
// detect cross-reload loops. Cookies persist across reloads and are
|
|
110
|
+
// available even when sessionStorage is blocked (TIM-576).
|
|
111
|
+
const cookieFlag = document.cookie.includes(RELOAD_FLAG_KEY + '=1');
|
|
112
|
+
if (cookieFlag || memoryReloadCount > 0) {
|
|
113
|
+
console.warn(
|
|
114
|
+
'[timber] Stale client reference detected again after reload. ' +
|
|
115
|
+
'Not reloading to prevent infinite loop. ' +
|
|
116
|
+
'This may indicate a deployment issue — try a hard refresh.'
|
|
117
|
+
);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
memoryReloadCount++;
|
|
122
|
+
// Set a short-lived cookie (60s) as the persistent loop guard.
|
|
123
|
+
// It auto-expires so it won't block future legitimate reloads.
|
|
124
|
+
try {
|
|
125
|
+
document.cookie = `${RELOAD_FLAG_KEY}=1; max-age=60; path=/; SameSite=Lax`;
|
|
126
|
+
} catch {
|
|
127
|
+
// Cookie API unavailable — proceed anyway, memoryReloadCount guards same-page loops
|
|
128
|
+
}
|
|
129
|
+
console.warn(
|
|
130
|
+
'[timber] Stale client reference detected — the server has been ' +
|
|
131
|
+
'redeployed with new bundles. Reloading to pick up the new version.'
|
|
132
|
+
);
|
|
71
133
|
window.location.reload();
|
|
72
134
|
return true;
|
|
73
135
|
}
|
|
@@ -79,9 +141,16 @@ export function triggerStaleReload(): boolean {
|
|
|
79
141
|
* reference error should trigger a fresh reload attempt.
|
|
80
142
|
*/
|
|
81
143
|
export function clearStaleReloadFlag(): void {
|
|
144
|
+
memoryReloadCount = 0;
|
|
82
145
|
try {
|
|
83
146
|
sessionStorage.removeItem(RELOAD_FLAG_KEY);
|
|
84
147
|
} catch {
|
|
85
148
|
// sessionStorage unavailable — nothing to clear
|
|
86
149
|
}
|
|
150
|
+
// Also clear the cookie fallback
|
|
151
|
+
try {
|
|
152
|
+
document.cookie = `${RELOAD_FLAG_KEY}=; max-age=0; path=/; SameSite=Lax`;
|
|
153
|
+
} catch {
|
|
154
|
+
// Cookie API unavailable
|
|
155
|
+
}
|
|
87
156
|
}
|
package/src/client/state.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ALL mutable module-level state that must have singleton semantics across
|
|
5
5
|
* the client bundle lives here. Individual modules (router-ref.ts, ssr-data.ts,
|
|
6
|
-
* use-params.ts, use-search-params.ts, unload-guard.ts) import from this file
|
|
6
|
+
* use-segment-params.ts, use-search-params.ts, unload-guard.ts) import from this file
|
|
7
7
|
* and re-export thin wrapper functions.
|
|
8
8
|
*
|
|
9
9
|
* Why: In Vite dev, a module is instantiated separately if reached via different
|
|
@@ -50,7 +50,7 @@ export function _setCurrentSsrData(data: SsrData | undefined): void {
|
|
|
50
50
|
currentSsrData = data;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
// ─── Route Params (from use-params.ts) ──────────────────────────────────────
|
|
53
|
+
// ─── Route Params (from use-segment-params.ts) ──────────────────────────────────────
|
|
54
54
|
|
|
55
55
|
/** Current route params snapshot — replaced (not mutated) on each navigation. */
|
|
56
56
|
export let currentParams: Record<string, string | string[]> = {};
|