@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/router.ts
CHANGED
|
@@ -5,10 +5,21 @@ import { SegmentCache, PrefetchCache, buildSegmentTree } from './segment-cache';
|
|
|
5
5
|
import type { SegmentInfo } from './segment-cache';
|
|
6
6
|
import { HistoryStack } from './history';
|
|
7
7
|
import type { HeadElement } from './head';
|
|
8
|
-
import { setCurrentParams } from './use-params.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import { setCurrentParams } from './use-segment-params.js';
|
|
9
|
+
import {
|
|
10
|
+
setNavigationState,
|
|
11
|
+
getNavigationState,
|
|
12
|
+
type NavigationState,
|
|
13
|
+
} from './navigation-context.js';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
fetchRscPayload,
|
|
17
|
+
RedirectError,
|
|
18
|
+
ServerErrorResponse,
|
|
19
|
+
VersionSkewError,
|
|
20
|
+
} from './rsc-fetch.js';
|
|
21
|
+
import { setHardNavigating } from './navigation-root.js';
|
|
22
|
+
import { isStaleClientReference, triggerStaleReload } from './stale-reload.js';
|
|
12
23
|
import type { FetchResult } from './rsc-fetch.js';
|
|
13
24
|
|
|
14
25
|
// ─── Types ───────────────────────────────────────────────────────
|
|
@@ -18,6 +29,19 @@ export interface NavigationOptions {
|
|
|
18
29
|
scroll?: boolean;
|
|
19
30
|
/** Use replaceState instead of pushState (replaces current history entry) */
|
|
20
31
|
replace?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* @internal AbortSignal from the Navigation API's NavigateEvent.
|
|
34
|
+
* When provided, the signal is linked to the router's per-navigation
|
|
35
|
+
* AbortController so in-flight RSC fetches are cancelled when a new
|
|
36
|
+
* navigation starts.
|
|
37
|
+
*/
|
|
38
|
+
_signal?: AbortSignal;
|
|
39
|
+
/**
|
|
40
|
+
* @internal Skip pushState/replaceState — the Navigation API has already
|
|
41
|
+
* updated the URL via event.intercept(). Used for external navigations
|
|
42
|
+
* intercepted by the navigate event handler.
|
|
43
|
+
*/
|
|
44
|
+
_skipHistory?: boolean;
|
|
21
45
|
}
|
|
22
46
|
|
|
23
47
|
/**
|
|
@@ -31,8 +55,12 @@ export type RscDecoder = (fetchPromise: Promise<Response>) => unknown;
|
|
|
31
55
|
* Function that renders a decoded RSC element tree into the DOM.
|
|
32
56
|
* In production: reactRoot.render(element).
|
|
33
57
|
* In tests: a no-op or mock.
|
|
58
|
+
*
|
|
59
|
+
* Receives the current NavigationState explicitly — no temporal
|
|
60
|
+
* coupling with setNavigationState/getNavigationState. The renderer
|
|
61
|
+
* wraps the element in NavigationProvider with this state.
|
|
34
62
|
*/
|
|
35
|
-
export type RootRenderer = (element: unknown) => void;
|
|
63
|
+
export type RootRenderer = (element: unknown, navState: NavigationState) => void;
|
|
36
64
|
|
|
37
65
|
/**
|
|
38
66
|
* Platform dependencies injected for testability. In production these
|
|
@@ -64,14 +92,65 @@ export interface RouterDeps {
|
|
|
64
92
|
*
|
|
65
93
|
* The `perform` callback receives a `wrapPayload` function to wrap the
|
|
66
94
|
* decoded RSC payload with NavigationProvider + NuqsAdapter before
|
|
67
|
-
*
|
|
95
|
+
* NavigationRoot sets it as the new element. The `wrapPayload` function
|
|
96
|
+
* receives the NavigationState explicitly — no temporal coupling with
|
|
97
|
+
* getNavigationState().
|
|
68
98
|
*
|
|
69
99
|
* If not provided (tests), the router falls back to renderRoot.
|
|
70
100
|
*/
|
|
71
101
|
navigateTransition?: (
|
|
72
102
|
pendingUrl: string,
|
|
73
|
-
perform: (
|
|
103
|
+
perform: (
|
|
104
|
+
wrapPayload: (
|
|
105
|
+
payload: unknown,
|
|
106
|
+
navState: NavigationState,
|
|
107
|
+
segmentUpdates?: Map<string, unknown>
|
|
108
|
+
) => unknown
|
|
109
|
+
) => Promise<{ element: unknown; decodePromise: Promise<void> | null }>
|
|
74
110
|
) => Promise<void>;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Whether the Navigation API is active and handling traversals.
|
|
114
|
+
* When true, the popstate handler is a no-op — the Navigation API's
|
|
115
|
+
* navigate event covers back/forward button presses.
|
|
116
|
+
*/
|
|
117
|
+
navigationApiActive?: boolean;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Called around pushState/replaceState to set a flag that prevents
|
|
121
|
+
* the Navigation API's navigate listener from double-handling
|
|
122
|
+
* router-initiated navigations.
|
|
123
|
+
*/
|
|
124
|
+
setRouterNavigating?: (value: boolean) => void;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Save scroll position via the Navigation API's per-entry state.
|
|
128
|
+
* When provided, used instead of history.replaceState for scroll storage.
|
|
129
|
+
*/
|
|
130
|
+
saveNavigationEntryScroll?: (scrollY: number) => void;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Signal that a router-initiated navigation has completed. Resolves the
|
|
134
|
+
* deferred promise that ties the browser's native loading state to the
|
|
135
|
+
* navigation lifecycle. Called in the finally block of navigate/refresh,
|
|
136
|
+
* aligned with when the TopLoader's pendingUrl clears.
|
|
137
|
+
*/
|
|
138
|
+
completeRouterNavigation?: () => void;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get the current unwrapped RSC payload element. Used for partial
|
|
142
|
+
* navigation: the router re-wraps the same element with new
|
|
143
|
+
* NavigationProvider context so mounted SegmentOutlets are preserved.
|
|
144
|
+
*/
|
|
145
|
+
_getCurrentPayload?: () => unknown;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Initiate a navigation via the Navigation API (`navigation.navigate()`).
|
|
149
|
+
* Fires the navigate event BEFORE committing the URL, allowing Chrome
|
|
150
|
+
* to show its native loading indicator. Falls back to pushState when
|
|
151
|
+
* unavailable.
|
|
152
|
+
*/
|
|
153
|
+
navigationNavigate?: (url: string, replace: boolean) => void;
|
|
75
154
|
}
|
|
76
155
|
|
|
77
156
|
export interface RouterInstance {
|
|
@@ -80,7 +159,7 @@ export interface RouterInstance {
|
|
|
80
159
|
/** Full re-render of the current URL — no state tree sent */
|
|
81
160
|
refresh(): Promise<void>;
|
|
82
161
|
/** Handle a popstate event (back/forward button). scrollY is read from history.state. */
|
|
83
|
-
handlePopState(url: string, scrollY?: number): Promise<void>;
|
|
162
|
+
handlePopState(url: string, scrollY?: number, externalSignal?: AbortSignal): Promise<void>;
|
|
84
163
|
/** Whether a navigation is currently in flight */
|
|
85
164
|
isPending(): boolean;
|
|
86
165
|
/** The URL currently being navigated to, or null if idle */
|
|
@@ -100,12 +179,7 @@ export interface RouterInstance {
|
|
|
100
179
|
* Called on initial hydration with segment info embedded in the HTML.
|
|
101
180
|
*/
|
|
102
181
|
initSegmentCache(segments: SegmentInfo[]): void;
|
|
103
|
-
|
|
104
|
-
* Cache segment elements from a decoded RSC element tree.
|
|
105
|
-
* Called on initial hydration to populate the element cache so the
|
|
106
|
-
* first client navigation can use partial payloads.
|
|
107
|
-
*/
|
|
108
|
-
cacheElementTree(element: unknown): void;
|
|
182
|
+
|
|
109
183
|
/** The segment cache (exposed for tests and <Link> prefetch) */
|
|
110
184
|
segmentCache: SegmentCache;
|
|
111
185
|
/** The prefetch cache (exposed for tests and <Link> prefetch) */
|
|
@@ -130,24 +204,71 @@ function isAbortError(error: unknown): boolean {
|
|
|
130
204
|
* Create a router instance. In production, called once at app hydration
|
|
131
205
|
* with real browser APIs. In tests, called with mock dependencies.
|
|
132
206
|
*/
|
|
207
|
+
/**
|
|
208
|
+
* Router navigation phase — discriminated union replacing scattered
|
|
209
|
+
* `pending` + `pendingUrl` boolean flags.
|
|
210
|
+
*
|
|
211
|
+
* - `idle`: No navigation in flight. The committed params/pathname
|
|
212
|
+
* are current.
|
|
213
|
+
* - `navigating`: A fetch or render is in progress. `targetUrl` is
|
|
214
|
+
* the destination being navigated to.
|
|
215
|
+
*/
|
|
216
|
+
export type RouterPhase = { phase: 'idle' } | { phase: 'navigating'; targetUrl: string };
|
|
217
|
+
|
|
133
218
|
export function createRouter(deps: RouterDeps): RouterInstance {
|
|
134
219
|
const segmentCache = new SegmentCache();
|
|
135
220
|
const prefetchCache = new PrefetchCache();
|
|
136
221
|
const historyStack = new HistoryStack();
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
let pending = false;
|
|
140
|
-
let pendingUrl: string | null = null;
|
|
222
|
+
let routerPhase: RouterPhase = { phase: 'idle' };
|
|
141
223
|
const pendingListeners = new Set<(pending: boolean) => void>();
|
|
142
224
|
|
|
225
|
+
// AbortController for the current in-flight navigation.
|
|
226
|
+
// When a new navigation starts, the previous controller is aborted,
|
|
227
|
+
// cancelling any in-progress RSC fetch. This provides automatic
|
|
228
|
+
// cancellation of stale fetches regardless of Navigation API support.
|
|
229
|
+
let currentNavAbort: AbortController | null = null;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Create a new AbortController for a navigation, aborting any
|
|
233
|
+
* previous in-flight navigation. Optionally links to an external
|
|
234
|
+
* signal (e.g., from the Navigation API's NavigateEvent.signal).
|
|
235
|
+
*/
|
|
236
|
+
function createNavAbort(externalSignal?: AbortSignal): AbortController {
|
|
237
|
+
// Abort previous navigation's fetch
|
|
238
|
+
currentNavAbort?.abort();
|
|
239
|
+
const controller = new AbortController();
|
|
240
|
+
currentNavAbort = controller;
|
|
241
|
+
|
|
242
|
+
// If an external signal is provided (e.g., Navigation API),
|
|
243
|
+
// forward its abort to our controller.
|
|
244
|
+
if (externalSignal) {
|
|
245
|
+
if (externalSignal.aborted) {
|
|
246
|
+
controller.abort();
|
|
247
|
+
} else {
|
|
248
|
+
externalSignal.addEventListener('abort', () => controller.abort(), { once: true });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return controller;
|
|
253
|
+
}
|
|
254
|
+
|
|
143
255
|
function setPending(value: boolean, url?: string): void {
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
256
|
+
const next: RouterPhase =
|
|
257
|
+
value && url ? { phase: 'navigating', targetUrl: url } : { phase: 'idle' };
|
|
258
|
+
// Skip no-op updates
|
|
259
|
+
if (
|
|
260
|
+
routerPhase.phase === next.phase &&
|
|
261
|
+
(routerPhase.phase === 'idle' ||
|
|
262
|
+
(routerPhase.phase === 'navigating' &&
|
|
263
|
+
next.phase === 'navigating' &&
|
|
264
|
+
routerPhase.targetUrl === next.targetUrl))
|
|
265
|
+
) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
routerPhase = next;
|
|
148
269
|
// Notify external store listeners (non-React consumers).
|
|
149
270
|
// React-facing pending state is handled by useOptimistic in
|
|
150
|
-
//
|
|
271
|
+
// NavigationRoot via navigateTransition — not this function.
|
|
151
272
|
for (const listener of pendingListeners) {
|
|
152
273
|
listener(value);
|
|
153
274
|
}
|
|
@@ -163,94 +284,139 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
163
284
|
}
|
|
164
285
|
|
|
165
286
|
/** Render a decoded RSC payload into the DOM if a renderer is available. */
|
|
166
|
-
function renderPayload(payload: unknown): void {
|
|
287
|
+
function renderPayload(payload: unknown, navState: NavigationState): void {
|
|
167
288
|
if (deps.renderRoot) {
|
|
168
|
-
deps.renderRoot(payload);
|
|
289
|
+
deps.renderRoot(payload, navState);
|
|
169
290
|
}
|
|
170
291
|
}
|
|
171
292
|
|
|
293
|
+
function isPartialNavigation(skippedSegments: string[] | null | undefined): boolean {
|
|
294
|
+
return skippedSegments != null && skippedSegments.length > 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
172
297
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* Returns the merged payload ready for rendering.
|
|
298
|
+
* Build a segment updates map for partial navigation. Identifies the
|
|
299
|
+
* first non-skipped segment and maps it to the payload content.
|
|
176
300
|
*/
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
301
|
+
function buildSegmentUpdates(result: FetchResult): Map<string, unknown> {
|
|
302
|
+
const skipped = new Set(result.skippedSegments!);
|
|
303
|
+
const segmentInfo = result.segmentInfo;
|
|
304
|
+
const updates = new Map<string, unknown>();
|
|
305
|
+
if (segmentInfo) {
|
|
306
|
+
for (const info of segmentInfo) {
|
|
307
|
+
if (!skipped.has(info.segmentId ?? info.path)) {
|
|
308
|
+
// Use segmentId (outlet key) when available — route groups
|
|
309
|
+
// use a disambiguated key like "/(marketing)" instead of "/".
|
|
310
|
+
updates.set(info.segmentId ?? info.path, result.payload);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
186
314
|
}
|
|
187
|
-
|
|
188
|
-
// Cache segment elements from the (merged) payload for future merges
|
|
189
|
-
cacheSegmentElements(merged, segmentElementCache);
|
|
190
|
-
|
|
191
|
-
return merged;
|
|
315
|
+
return updates;
|
|
192
316
|
}
|
|
193
317
|
|
|
194
318
|
/**
|
|
195
319
|
* Update navigation state (params + pathname) for the next render.
|
|
196
320
|
*
|
|
197
|
-
* Sets
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
321
|
+
* Sets the module-level fallback (for tests and SSR) and the
|
|
322
|
+
* globalThis bridge, then returns the NavigationState so callers
|
|
323
|
+
* can pass it explicitly to renderRoot/wrapPayload — eliminating
|
|
324
|
+
* temporal coupling with getNavigationState().
|
|
201
325
|
*/
|
|
202
326
|
function updateNavigationState(
|
|
203
327
|
params: Record<string, string | string[]> | null | undefined,
|
|
204
328
|
url: string
|
|
205
|
-
):
|
|
329
|
+
): NavigationState {
|
|
206
330
|
const resolvedParams = params ?? {};
|
|
207
331
|
// Module-level fallback for tests (no NavigationProvider) and SSR
|
|
208
332
|
setCurrentParams(resolvedParams);
|
|
209
|
-
//
|
|
210
|
-
const
|
|
211
|
-
|
|
333
|
+
// globalThis bridge — kept for backward compat
|
|
334
|
+
const parsed = new URL(url, 'http://localhost');
|
|
335
|
+
const pathname = parsed.pathname || '/';
|
|
336
|
+
const search = parsed.search;
|
|
337
|
+
const navState: NavigationState = { params: resolvedParams, pathname, search };
|
|
338
|
+
setNavigationState(navState);
|
|
339
|
+
return navState;
|
|
212
340
|
}
|
|
213
341
|
|
|
214
342
|
/**
|
|
215
343
|
* Render a payload via navigateTransition (production) or renderRoot (tests).
|
|
216
|
-
* The perform callback should fetch data, update state, and return the
|
|
217
|
-
*
|
|
218
|
-
*
|
|
344
|
+
* The perform callback should fetch data, update state, and return the
|
|
345
|
+
* FetchResult plus the NavigationState (so it can be passed explicitly
|
|
346
|
+
* to wrapPayload/renderRoot without temporal coupling).
|
|
219
347
|
*/
|
|
348
|
+
interface TransitionResult {
|
|
349
|
+
headElements: HeadElement[] | null;
|
|
350
|
+
decodePromise: Promise<void> | null;
|
|
351
|
+
}
|
|
352
|
+
|
|
220
353
|
async function renderViaTransition(
|
|
221
354
|
url: string,
|
|
222
|
-
perform: () => Promise<FetchResult>
|
|
223
|
-
): Promise<
|
|
355
|
+
perform: () => Promise<FetchResult & { navState: NavigationState }>
|
|
356
|
+
): Promise<TransitionResult> {
|
|
224
357
|
if (deps.navigateTransition) {
|
|
225
358
|
let headElements: HeadElement[] | null = null;
|
|
226
359
|
await deps.navigateTransition(url, async (wrapPayload) => {
|
|
227
360
|
const result = await perform();
|
|
228
361
|
headElements = result.headElements;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
362
|
+
|
|
363
|
+
if (isPartialNavigation(result.skippedSegments)) {
|
|
364
|
+
const segmentUpdates = buildSegmentUpdates(result);
|
|
365
|
+
|
|
366
|
+
historyStack.push(url, {
|
|
367
|
+
payload: null,
|
|
368
|
+
headElements: result.headElements,
|
|
369
|
+
params: result.params,
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// Re-wrap the CURRENT element with new context values.
|
|
373
|
+
// SegmentOutlets read updates from SegmentUpdateContext;
|
|
374
|
+
// NavigationProvider gets new params/pathname.
|
|
375
|
+
const element = wrapPayload(
|
|
376
|
+
deps._getCurrentPayload?.() ?? result.payload,
|
|
377
|
+
result.navState,
|
|
378
|
+
segmentUpdates
|
|
379
|
+
);
|
|
380
|
+
return { element, decodePromise: result.decodePromise };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Full navigation — empty updates, render the new tree.
|
|
233
384
|
historyStack.push(url, {
|
|
234
|
-
payload:
|
|
385
|
+
payload: result.payload,
|
|
235
386
|
headElements: result.headElements,
|
|
236
387
|
params: result.params,
|
|
237
388
|
});
|
|
238
|
-
|
|
389
|
+
const element = wrapPayload(result.payload, result.navState);
|
|
390
|
+
return { element, decodePromise: result.decodePromise };
|
|
239
391
|
});
|
|
240
|
-
|
|
392
|
+
// decodePromise is awaited inside the transition's startTransition
|
|
393
|
+
// callback (NavigationRoot), so we don't need it here.
|
|
394
|
+
return { headElements, decodePromise: null };
|
|
241
395
|
}
|
|
242
396
|
// Fallback: no transition (tests, no React tree)
|
|
243
397
|
const result = await perform();
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
398
|
+
if (isPartialNavigation(result.skippedSegments)) {
|
|
399
|
+
historyStack.push(url, {
|
|
400
|
+
payload: null,
|
|
401
|
+
headElements: result.headElements,
|
|
402
|
+
params: result.params,
|
|
403
|
+
});
|
|
404
|
+
} else {
|
|
405
|
+
// Resolve thenables before storing/rendering in the fallback path
|
|
406
|
+
// (tests without navigateTransition). In production, React handles
|
|
407
|
+
// thenables via Suspense; in tests, renderRoot expects resolved values.
|
|
408
|
+
const payload =
|
|
409
|
+
result.payload != null && typeof result.payload === 'object' && 'then' in result.payload
|
|
410
|
+
? await (result.payload as PromiseLike<unknown>)
|
|
411
|
+
: result.payload;
|
|
412
|
+
historyStack.push(url, {
|
|
413
|
+
payload,
|
|
414
|
+
headElements: result.headElements,
|
|
415
|
+
params: result.params,
|
|
416
|
+
});
|
|
417
|
+
renderPayload(payload, result.navState);
|
|
418
|
+
}
|
|
419
|
+
return { headElements: result.headElements, decodePromise: result.decodePromise };
|
|
254
420
|
}
|
|
255
421
|
|
|
256
422
|
/** Apply head elements (title, meta tags) to the DOM if available. */
|
|
@@ -269,20 +435,32 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
269
435
|
}
|
|
270
436
|
}
|
|
271
437
|
|
|
438
|
+
/**
|
|
439
|
+
* Schedule scroll restoration after the next paint and fire the
|
|
440
|
+
* scroll-restored event. Used by navigate, popstate, and refresh.
|
|
441
|
+
*/
|
|
442
|
+
function restoreScrollAfterPaint(scrollY: number): void {
|
|
443
|
+
afterPaint(() => {
|
|
444
|
+
deps.scrollTo(0, scrollY);
|
|
445
|
+
window.dispatchEvent(new Event('timber:scroll-restored'));
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
272
449
|
/**
|
|
273
450
|
* Core navigation logic shared between the transition and fallback paths.
|
|
274
451
|
* Fetches the RSC payload, updates all state, and returns the result.
|
|
275
452
|
*/
|
|
276
453
|
async function performNavigationFetch(
|
|
277
454
|
url: string,
|
|
278
|
-
options: { replace: boolean }
|
|
279
|
-
): Promise<FetchResult> {
|
|
455
|
+
options: { replace: boolean; signal?: AbortSignal; skipHistory?: boolean }
|
|
456
|
+
): Promise<FetchResult & { navState: NavigationState }> {
|
|
280
457
|
// Check prefetch cache first. PrefetchResult has optional segmentInfo/params
|
|
281
458
|
// fields — normalize to null for FetchResult compatibility.
|
|
282
459
|
const prefetched = prefetchCache.consume(url);
|
|
283
460
|
let result: FetchResult | undefined = prefetched
|
|
284
461
|
? {
|
|
285
462
|
payload: prefetched.payload,
|
|
463
|
+
decodePromise: null,
|
|
286
464
|
headElements: prefetched.headElements,
|
|
287
465
|
segmentInfo: prefetched.segmentInfo ?? null,
|
|
288
466
|
params: prefetched.params ?? null,
|
|
@@ -293,19 +471,26 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
293
471
|
if (result === undefined) {
|
|
294
472
|
// Fetch RSC payload with state tree for partial rendering.
|
|
295
473
|
// Send current URL for intercepting route resolution (modal pattern).
|
|
296
|
-
const stateTree = segmentCache.serializeStateTree(
|
|
474
|
+
const stateTree = segmentCache.serializeStateTree();
|
|
297
475
|
const rawCurrentUrl = deps.getCurrentUrl();
|
|
298
476
|
const currentUrl = rawCurrentUrl.startsWith('http')
|
|
299
477
|
? new URL(rawCurrentUrl).pathname
|
|
300
478
|
: new URL(rawCurrentUrl, 'http://localhost').pathname;
|
|
301
|
-
result = await fetchRscPayload(url, deps, stateTree, currentUrl);
|
|
479
|
+
result = await fetchRscPayload(url, deps, stateTree, currentUrl, options.signal);
|
|
302
480
|
}
|
|
303
481
|
|
|
304
|
-
// Update the browser history —
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
482
|
+
// Update the browser history — skip when the Navigation API has already
|
|
483
|
+
// updated the URL via event.intercept() (external navigations).
|
|
484
|
+
if (!options.skipHistory) {
|
|
485
|
+
// Set the router-navigating flag so the Navigation API's navigate
|
|
486
|
+
// listener doesn't double-intercept this pushState/replaceState.
|
|
487
|
+
deps.setRouterNavigating?.(true);
|
|
488
|
+
if (options.replace) {
|
|
489
|
+
deps.replaceState({ timber: true, scrollY: 0 }, '', url);
|
|
490
|
+
} else {
|
|
491
|
+
deps.pushState({ timber: true, scrollY: 0 }, '', url);
|
|
492
|
+
}
|
|
493
|
+
deps.setRouterNavigating?.(false);
|
|
309
494
|
}
|
|
310
495
|
|
|
311
496
|
// NOTE: History push is deferred — the merged payload (after segment
|
|
@@ -316,29 +501,57 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
316
501
|
// Update the segment cache with the new route's segment tree.
|
|
317
502
|
updateSegmentCache(result.segmentInfo);
|
|
318
503
|
|
|
319
|
-
// Update navigation state
|
|
320
|
-
updateNavigationState(result.params, url);
|
|
504
|
+
// Update navigation state and capture it for explicit passing.
|
|
505
|
+
const navState = updateNavigationState(result.params, url);
|
|
321
506
|
|
|
322
|
-
return result;
|
|
507
|
+
return { ...result, navState };
|
|
323
508
|
}
|
|
324
509
|
|
|
325
510
|
async function navigate(url: string, options: NavigationOptions = {}): Promise<void> {
|
|
326
511
|
const scroll = options.scroll !== false;
|
|
327
512
|
const replace = options.replace === true;
|
|
513
|
+
const externalSignal = options._signal as AbortSignal | undefined;
|
|
514
|
+
const skipHistory = options._skipHistory === true;
|
|
515
|
+
|
|
516
|
+
// Create an abort controller for this navigation. Links to the external
|
|
517
|
+
// signal (Navigation API's event.signal) when provided.
|
|
518
|
+
const navAbort = createNavAbort(externalSignal);
|
|
328
519
|
|
|
329
520
|
// Capture the departing page's scroll position for scroll={false} preservation.
|
|
330
521
|
const currentScrollY = deps.getScrollY();
|
|
331
522
|
|
|
332
|
-
// Save the departing page's scroll position
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
523
|
+
// Save the departing page's scroll position — use Navigation API entry
|
|
524
|
+
// state when available, otherwise fall back to history.state.
|
|
525
|
+
if (deps.saveNavigationEntryScroll) {
|
|
526
|
+
deps.saveNavigationEntryScroll(currentScrollY);
|
|
527
|
+
} else {
|
|
528
|
+
deps.replaceState({ timber: true, scrollY: currentScrollY }, '', deps.getCurrentUrl());
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// When Navigation API is active, initiate the navigation via
|
|
532
|
+
// navigation.navigate() BEFORE the fetch. Unlike history.pushState()
|
|
533
|
+
// which commits the URL synchronously (so Chrome sees it as "done"),
|
|
534
|
+
// navigation.navigate() fires the navigate event before committing.
|
|
535
|
+
// Our handler intercepts with a deferred promise, and Chrome shows
|
|
536
|
+
// its native loading indicator until completeRouterNavigation()
|
|
537
|
+
// resolves it in the finally block (same time as TopLoader clears).
|
|
538
|
+
let effectiveSkipHistory = skipHistory;
|
|
539
|
+
if (!skipHistory && deps.navigationNavigate) {
|
|
540
|
+
deps.setRouterNavigating?.(true);
|
|
541
|
+
deps.navigationNavigate(url, replace);
|
|
542
|
+
deps.setRouterNavigating?.(false);
|
|
543
|
+
effectiveSkipHistory = true;
|
|
544
|
+
}
|
|
336
545
|
|
|
337
546
|
setPending(true, url);
|
|
338
547
|
|
|
339
548
|
try {
|
|
340
|
-
const headElements = await renderViaTransition(url, () =>
|
|
341
|
-
performNavigationFetch(url, {
|
|
549
|
+
const { headElements } = await renderViaTransition(url, () =>
|
|
550
|
+
performNavigationFetch(url, {
|
|
551
|
+
replace,
|
|
552
|
+
signal: navAbort.signal,
|
|
553
|
+
skipHistory: effectiveSkipHistory,
|
|
554
|
+
})
|
|
342
555
|
);
|
|
343
556
|
|
|
344
557
|
// Update document.title and <meta> tags with the new page's metadata
|
|
@@ -350,51 +563,117 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
350
563
|
// Scroll-to-top on forward navigation, or restore captured position
|
|
351
564
|
// for scroll={false}. React's render() on the document root can reset
|
|
352
565
|
// scroll during DOM reconciliation, so all scroll must be actively managed.
|
|
353
|
-
|
|
354
|
-
if (scroll) {
|
|
355
|
-
deps.scrollTo(0, 0);
|
|
356
|
-
} else {
|
|
357
|
-
deps.scrollTo(0, currentScrollY);
|
|
358
|
-
}
|
|
359
|
-
window.dispatchEvent(new Event('timber:scroll-restored'));
|
|
360
|
-
});
|
|
566
|
+
restoreScrollAfterPaint(scroll ? 0 : currentScrollY);
|
|
361
567
|
} catch (error) {
|
|
568
|
+
// Version skew — server has been redeployed. Trigger full page reload
|
|
569
|
+
// so the browser fetches the new bundle. See TIM-446.
|
|
570
|
+
// Set hard-navigating flag to prevent Navigation API interception
|
|
571
|
+
// and React from rendering during page teardown. See TIM-626.
|
|
572
|
+
if (error instanceof VersionSkewError) {
|
|
573
|
+
setHardNavigating(true);
|
|
574
|
+
// Import triggerStaleReload dynamically to avoid circular deps
|
|
575
|
+
// and keep the reload logic centralized with its loop guard.
|
|
576
|
+
const { triggerStaleReload } = await import('./stale-reload.js');
|
|
577
|
+
triggerStaleReload();
|
|
578
|
+
// Return a never-resolving promise — page is reloading.
|
|
579
|
+
return new Promise(() => {}) as never;
|
|
580
|
+
}
|
|
362
581
|
// Server-side redirect during RSC fetch → soft router navigation.
|
|
582
|
+
// The redirect navigate will push/replace its own URL.
|
|
363
583
|
if (error instanceof RedirectError) {
|
|
364
584
|
setPending(false);
|
|
585
|
+
deps.completeRouterNavigation?.();
|
|
365
586
|
await navigate(error.redirectUrl, { replace: true });
|
|
366
587
|
return;
|
|
367
588
|
}
|
|
589
|
+
// Server 5xx error — hard-navigate so the server renders the
|
|
590
|
+
// error page as HTML. See design/10-error-handling.md
|
|
591
|
+
// §"Error Page Rendering for Client Navigation".
|
|
592
|
+
//
|
|
593
|
+
// Set hard-navigating flag BEFORE setting window.location.href:
|
|
594
|
+
// 1. Prevents Navigation API from intercepting → infinite loop
|
|
595
|
+
// 2. Causes NavigationRoot to throw unresolvedThenable → prevents
|
|
596
|
+
// React from rendering children during page teardown (avoids
|
|
597
|
+
// "Rendered more hooks" crashes). See TIM-626.
|
|
598
|
+
if (error instanceof ServerErrorResponse) {
|
|
599
|
+
setHardNavigating(true);
|
|
600
|
+
window.location.href = error.url;
|
|
601
|
+
return new Promise(() => {}) as never;
|
|
602
|
+
}
|
|
603
|
+
// Stale client reference from streaming RSC decode — the server
|
|
604
|
+
// was redeployed with new bundles. Same recovery as VersionSkewError.
|
|
605
|
+
if (isStaleClientReference(error)) {
|
|
606
|
+
setHardNavigating(true);
|
|
607
|
+
triggerStaleReload();
|
|
608
|
+
return new Promise(() => {}) as never;
|
|
609
|
+
}
|
|
368
610
|
// Abort errors are not application errors — swallow silently.
|
|
369
611
|
if (isAbortError(error)) return;
|
|
370
612
|
throw error;
|
|
371
613
|
} finally {
|
|
614
|
+
// Clear the abort controller so we don't abort a completed navigation
|
|
615
|
+
// when the next one starts. In dev mode, the RSC body stream stays
|
|
616
|
+
// open after data arrives (React's Flight client waits for debug rows).
|
|
617
|
+
// Aborting a "completed" navigation kills the open stream reader →
|
|
618
|
+
// "BodyStreamBuffer was aborted". By clearing the controller here,
|
|
619
|
+
// createNavAbort() becomes a no-op for completed navigations.
|
|
620
|
+
if (currentNavAbort === navAbort) {
|
|
621
|
+
currentNavAbort = null;
|
|
622
|
+
}
|
|
372
623
|
setPending(false);
|
|
624
|
+
// Resolve the Navigation API deferred — clears the browser's native
|
|
625
|
+
// loading state (tab spinner) at the same time as the TopLoader.
|
|
626
|
+
deps.completeRouterNavigation?.();
|
|
373
627
|
}
|
|
374
628
|
}
|
|
375
629
|
|
|
376
630
|
async function refresh(): Promise<void> {
|
|
377
631
|
const currentUrl = deps.getCurrentUrl();
|
|
632
|
+
const navAbort = createNavAbort();
|
|
378
633
|
|
|
379
634
|
setPending(true, currentUrl);
|
|
380
635
|
|
|
381
636
|
try {
|
|
382
|
-
const headElements = await renderViaTransition(currentUrl, async () => {
|
|
637
|
+
const { headElements } = await renderViaTransition(currentUrl, async () => {
|
|
383
638
|
// No state tree sent — server renders the complete RSC payload
|
|
384
|
-
const result = await fetchRscPayload(
|
|
639
|
+
const result = await fetchRscPayload(
|
|
640
|
+
currentUrl,
|
|
641
|
+
deps,
|
|
642
|
+
undefined,
|
|
643
|
+
undefined,
|
|
644
|
+
navAbort.signal
|
|
645
|
+
);
|
|
385
646
|
// History push handled by renderViaTransition (stores merged payload)
|
|
386
647
|
updateSegmentCache(result.segmentInfo);
|
|
387
|
-
updateNavigationState(result.params, currentUrl);
|
|
388
|
-
return result;
|
|
648
|
+
const navState = updateNavigationState(result.params, currentUrl);
|
|
649
|
+
return { ...result, navState };
|
|
389
650
|
});
|
|
390
651
|
|
|
391
652
|
applyHead(headElements);
|
|
653
|
+
} catch (error) {
|
|
654
|
+
if (isStaleClientReference(error)) {
|
|
655
|
+
setHardNavigating(true);
|
|
656
|
+
triggerStaleReload();
|
|
657
|
+
return new Promise(() => {}) as never;
|
|
658
|
+
}
|
|
659
|
+
// Stale transition (superseded by a newer navigation) or aborted
|
|
660
|
+
// fetch — silently ignore. See TIM-629.
|
|
661
|
+
if (isAbortError(error)) return;
|
|
662
|
+
throw error;
|
|
392
663
|
} finally {
|
|
664
|
+
if (currentNavAbort === navAbort) {
|
|
665
|
+
currentNavAbort = null;
|
|
666
|
+
}
|
|
393
667
|
setPending(false);
|
|
668
|
+
deps.completeRouterNavigation?.();
|
|
394
669
|
}
|
|
395
670
|
}
|
|
396
671
|
|
|
397
|
-
async function handlePopState(
|
|
672
|
+
async function handlePopState(
|
|
673
|
+
url: string,
|
|
674
|
+
scrollY: number = 0,
|
|
675
|
+
externalSignal?: AbortSignal
|
|
676
|
+
): Promise<void> {
|
|
398
677
|
// Scroll position is read from history.state by the caller (browser-entry.ts)
|
|
399
678
|
// and passed in. This is more reliable than tracking scroll per-URL in memory
|
|
400
679
|
// because the browser maintains per-entry state even with duplicate URLs.
|
|
@@ -402,37 +681,43 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
402
681
|
|
|
403
682
|
if (entry && entry.payload !== null) {
|
|
404
683
|
// Replay cached payload — no server roundtrip
|
|
405
|
-
updateNavigationState(entry.params, url);
|
|
406
|
-
renderPayload(entry.payload);
|
|
684
|
+
const navState = updateNavigationState(entry.params, url);
|
|
685
|
+
renderPayload(entry.payload, navState);
|
|
407
686
|
applyHead(entry.headElements);
|
|
408
|
-
|
|
409
|
-
deps.scrollTo(0, scrollY);
|
|
410
|
-
window.dispatchEvent(new Event('timber:scroll-restored'));
|
|
411
|
-
});
|
|
687
|
+
restoreScrollAfterPaint(scrollY);
|
|
412
688
|
} else {
|
|
413
689
|
// No cached payload — fetch from server.
|
|
414
690
|
// This happens when navigating back to the initial SSR'd page
|
|
415
691
|
// (its payload is null since it was rendered via SSR, not RSC fetch)
|
|
416
692
|
// or when the entry doesn't exist at all.
|
|
693
|
+
const navAbort = createNavAbort(externalSignal);
|
|
417
694
|
setPending(true, url);
|
|
418
695
|
try {
|
|
419
|
-
const headElements = await renderViaTransition(url, async () => {
|
|
420
|
-
const stateTree = segmentCache.serializeStateTree(
|
|
421
|
-
|
|
422
|
-
);
|
|
423
|
-
const result = await fetchRscPayload(url, deps, stateTree);
|
|
696
|
+
const { headElements } = await renderViaTransition(url, async () => {
|
|
697
|
+
const stateTree = segmentCache.serializeStateTree();
|
|
698
|
+
const result = await fetchRscPayload(url, deps, stateTree, undefined, navAbort.signal);
|
|
424
699
|
updateSegmentCache(result.segmentInfo);
|
|
425
|
-
updateNavigationState(result.params, url);
|
|
700
|
+
const navState = updateNavigationState(result.params, url);
|
|
426
701
|
// History push handled by renderViaTransition (stores merged payload)
|
|
427
|
-
return result;
|
|
702
|
+
return { ...result, navState };
|
|
428
703
|
});
|
|
429
704
|
|
|
430
705
|
applyHead(headElements);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
706
|
+
restoreScrollAfterPaint(scrollY);
|
|
707
|
+
} catch (error) {
|
|
708
|
+
if (isStaleClientReference(error)) {
|
|
709
|
+
setHardNavigating(true);
|
|
710
|
+
triggerStaleReload();
|
|
711
|
+
return new Promise(() => {}) as never;
|
|
712
|
+
}
|
|
713
|
+
// Stale transition (superseded by a newer navigation) or aborted
|
|
714
|
+
// fetch — silently ignore. See TIM-629.
|
|
715
|
+
if (isAbortError(error)) return;
|
|
716
|
+
throw error;
|
|
435
717
|
} finally {
|
|
718
|
+
if (currentNavAbort === navAbort) {
|
|
719
|
+
currentNavAbort = null;
|
|
720
|
+
}
|
|
436
721
|
setPending(false);
|
|
437
722
|
}
|
|
438
723
|
}
|
|
@@ -448,9 +733,10 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
448
733
|
if (historyStack.has(url)) return;
|
|
449
734
|
|
|
450
735
|
// Fire-and-forget fetch
|
|
451
|
-
const stateTree = segmentCache.serializeStateTree(
|
|
736
|
+
const stateTree = segmentCache.serializeStateTree();
|
|
452
737
|
void fetchRscPayload(url, deps, stateTree).then(
|
|
453
738
|
(result) => {
|
|
739
|
+
result.decodePromise?.catch(() => {});
|
|
454
740
|
prefetchCache.set(url, result);
|
|
455
741
|
},
|
|
456
742
|
() => {
|
|
@@ -463,8 +749,8 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
463
749
|
navigate,
|
|
464
750
|
refresh,
|
|
465
751
|
handlePopState,
|
|
466
|
-
isPending: () =>
|
|
467
|
-
getPendingUrl: () =>
|
|
752
|
+
isPending: () => routerPhase.phase === 'navigating',
|
|
753
|
+
getPendingUrl: () => (routerPhase.phase === 'navigating' ? routerPhase.targetUrl : null),
|
|
468
754
|
onPendingChange(listener) {
|
|
469
755
|
pendingListeners.add(listener);
|
|
470
756
|
return () => pendingListeners.delete(listener);
|
|
@@ -474,18 +760,22 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
474
760
|
// Render the piggybacked element tree from a server action response.
|
|
475
761
|
// Updates the current history entry with the fresh payload and applies
|
|
476
762
|
// head elements — same as refresh() but without a server fetch.
|
|
477
|
-
//
|
|
763
|
+
// Revalidation payloads are already resolved (no Flight thenable),
|
|
764
|
+
// so no segment merging is needed — just cache and render.
|
|
478
765
|
const currentUrl = deps.getCurrentUrl();
|
|
479
|
-
const merged = mergeAndCachePayload(element, null);
|
|
480
766
|
historyStack.push(currentUrl, {
|
|
481
|
-
payload:
|
|
767
|
+
payload: element,
|
|
482
768
|
headElements,
|
|
483
769
|
});
|
|
484
|
-
|
|
770
|
+
|
|
771
|
+
// Revalidation doesn't change params/pathname — preserve current state.
|
|
772
|
+
// DO NOT call updateNavigationState(null, ...) here: that normalizes
|
|
773
|
+
// params to {}, clearing dynamic route params on every action response.
|
|
774
|
+
const navState = getNavigationState();
|
|
775
|
+
renderPayload(element, navState);
|
|
485
776
|
applyHead(headElements);
|
|
486
777
|
},
|
|
487
778
|
initSegmentCache: (segments: SegmentInfo[]) => updateSegmentCache(segments),
|
|
488
|
-
cacheElementTree: (element: unknown) => cacheSegmentElements(element, segmentElementCache),
|
|
489
779
|
segmentCache,
|
|
490
780
|
prefetchCache,
|
|
491
781
|
historyStack,
|