@timber-js/app 0.2.0-alpha.18 → 0.2.0-alpha.181
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/agent-skill.md +344 -0
- package/dist/_chunks/actions-O_LsyCE4.js +317 -0
- package/dist/_chunks/actions-O_LsyCE4.js.map +1 -0
- package/dist/_chunks/build-output-helper-DF5uScqS.js +158 -0
- package/dist/_chunks/build-output-helper-DF5uScqS.js.map +1 -0
- package/dist/_chunks/cache-api-B-lhk9p4.js +1202 -0
- package/dist/_chunks/cache-api-B-lhk9p4.js.map +1 -0
- package/dist/_chunks/canonicalize-DQHyFClh.js +248 -0
- package/dist/_chunks/canonicalize-DQHyFClh.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-D3naS3eH.js +688 -0
- package/dist/_chunks/cli-schema-sync-D3naS3eH.js.map +1 -0
- package/dist/_chunks/cloudflare-AHoWYTYr.js +1188 -0
- package/dist/_chunks/cloudflare-AHoWYTYr.js.map +1 -0
- package/dist/_chunks/codec-registry-oOUxugz3.js +21 -0
- package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -0
- package/dist/_chunks/define-COtkxMRT.js +191 -0
- package/dist/_chunks/define-COtkxMRT.js.map +1 -0
- package/dist/_chunks/define-c4au4I9R.js +82 -0
- package/dist/_chunks/define-c4au4I9R.js.map +1 -0
- package/dist/_chunks/dist-BA3u1z3W.js +423 -0
- package/dist/_chunks/dist-BA3u1z3W.js.map +1 -0
- package/dist/_chunks/fast-hash-D6hIVt1Y.js +36 -0
- package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +1 -0
- package/dist/_chunks/format-CfwjgPz9.js +14 -0
- package/dist/_chunks/format-CfwjgPz9.js.map +1 -0
- package/dist/_chunks/href-validation-CMc5JRls.js +141 -0
- package/dist/_chunks/href-validation-CMc5JRls.js.map +1 -0
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js +63 -0
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +1 -0
- package/dist/_chunks/logger-AWfuX-KJ.js +1468 -0
- package/dist/_chunks/logger-AWfuX-KJ.js.map +1 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js +124 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -0
- package/dist/_chunks/plugin-context---kTF5v8.js +315 -0
- package/dist/_chunks/plugin-context---kTF5v8.js.map +1 -0
- package/dist/_chunks/registry-DbJPKoBp.js +20 -0
- package/dist/_chunks/registry-DbJPKoBp.js.map +1 -0
- package/dist/_chunks/resolve-schema-Dz3fcFUo.js +50 -0
- package/dist/_chunks/resolve-schema-Dz3fcFUo.js.map +1 -0
- package/dist/_chunks/router-ref-CtmF-aPv.js +28 -0
- package/dist/_chunks/router-ref-CtmF-aPv.js.map +1 -0
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +119 -0
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +1 -0
- package/dist/_chunks/segment-classify-Byy425ng.js +176 -0
- package/dist/_chunks/segment-classify-Byy425ng.js.map +1 -0
- package/dist/_chunks/segment-context-ZDnXDkbz.js +34 -0
- package/dist/_chunks/segment-context-ZDnXDkbz.js.map +1 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js +35 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-BOWsq18U.js} +1 -1
- package/dist/_chunks/ssr-data-BOWsq18U.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-DFvWd-EA.js} +71 -26
- package/dist/_chunks/use-query-states-DFvWd-EA.js.map +1 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js +151 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -0
- package/dist/_chunks/walkers-BtTlKviE.js +1002 -0
- package/dist/_chunks/walkers-BtTlKviE.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +29 -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 +65 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +124 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +189 -21
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -188
- package/dist/adapters/compress-module.d.ts +5 -4
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +41 -3
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +224 -172
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/types.d.ts +2 -6
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/cache-api.d.ts +48 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/handler-store.d.ts +33 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +31 -8
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -326
- package/dist/cache/invalidation-epoch.d.ts +43 -0
- package/dist/cache/invalidation-epoch.d.ts.map +1 -0
- package/dist/cache/json-lossy-check.d.ts +11 -0
- package/dist/cache/json-lossy-check.d.ts.map +1 -0
- package/dist/cache/redis-handler.d.ts +140 -8
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +19 -2
- 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/stable-stringify.d.ts +9 -0
- package/dist/cache/stable-stringify.d.ts.map +1 -1
- package/dist/cache/store.d.ts +53 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
- package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.js +29 -0
- package/dist/cache/stores/cloudflare-kv.js.map +1 -0
- package/dist/cache/stores/memory.d.ts +42 -0
- package/dist/cache/stores/memory.d.ts.map +1 -0
- package/dist/cache/stores/memory.js +90 -0
- package/dist/cache/stores/memory.js.map +1 -0
- package/dist/cache/stores/redis.d.ts +69 -0
- package/dist/cache/stores/redis.d.ts.map +1 -0
- package/dist/cache/stores/redis.js +35 -0
- package/dist/cache/stores/redis.js.map +1 -0
- package/dist/cache/stores/vercel.d.ts +36 -0
- package/dist/cache/stores/vercel.d.ts.map +1 -0
- package/dist/cache/stores/vercel.js +33 -0
- package/dist/cache/stores/vercel.js.map +1 -0
- package/dist/cache/tag-aware-handler.d.ts +52 -0
- package/dist/cache/tag-aware-handler.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts +20 -10
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cdn/cloudflare-purge.d.ts +23 -0
- package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
- package/dist/cdn/fastly-purge.d.ts +25 -0
- package/dist/cdn/fastly-purge.d.ts.map +1 -0
- package/dist/cdn/headers.d.ts +97 -0
- package/dist/cdn/headers.d.ts.map +1 -0
- package/dist/cdn/index.d.ts +5 -0
- package/dist/cdn/index.d.ts.map +1 -0
- package/dist/cdn/purge-store.d.ts +23 -0
- package/dist/cdn/purge-store.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.d.ts +16 -0
- package/dist/cdn/workers-cache-purge.d.ts.map +1 -0
- package/dist/cli-schema-sync.d.ts +59 -0
- package/dist/cli-schema-sync.d.ts.map +1 -0
- package/dist/cli.d.ts +35 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +113 -34
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +37 -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 +29 -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 +27 -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 +28 -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 +47 -10
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +61 -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 +21 -6
- 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 +185 -1134
- 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 +938 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link.d.ts +69 -60
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-api.d.ts +121 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +3 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +119 -0
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts +1 -1
- 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 +99 -14
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +62 -15
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +30 -7
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +57 -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/slot-context.d.ts +31 -0
- package/dist/client/slot-context.d.ts.map +1 -0
- package/dist/client/slot-outlet.d.ts +16 -0
- package/dist/client/slot-outlet.d.ts.map +1 -0
- package/dist/client/slot-provider.d.ts +25 -0
- package/dist/client/slot-provider.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/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-pathname.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-router.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +12 -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 +76 -0
- package/dist/codec.js.map +1 -0
- package/dist/config-types.d.ts +284 -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 +257 -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 +34 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +50 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +40 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/dev-page-shell.d.ts +78 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +32 -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/hydration-overlay.d.ts +11 -0
- package/dist/dev-tools/hydration-overlay.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/dev-tools/instrumentation.d.ts +59 -0
- 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} +17 -3
- 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/fonts/ast-walk.d.ts +68 -0
- package/dist/fonts/ast-walk.d.ts.map +1 -0
- package/dist/fonts/ast.d.ts +110 -6
- package/dist/fonts/ast.d.ts.map +1 -1
- package/dist/fonts/bundle.d.ts +50 -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/fallbacks.d.ts +0 -7
- package/dist/fonts/fallbacks.d.ts.map +1 -1
- package/dist/fonts/google.d.ts +4 -2
- package/dist/fonts/google.d.ts.map +1 -1
- package/dist/fonts/local.d.ts +4 -4
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/paths.d.ts +43 -0
- package/dist/fonts/paths.d.ts.map +1 -0
- package/dist/fonts/pipeline.d.ts +177 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +82 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +47 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +77 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +46 -180
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9243 -14093
- 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 +217 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +21 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +7 -3
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +43 -7
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/cache.d.ts +64 -0
- package/dist/plugins/cache.d.ts.map +1 -0
- package/dist/plugins/callsite-ast.d.ts +117 -0
- package/dist/plugins/callsite-ast.d.ts.map +1 -0
- package/dist/plugins/callsite-jsx.d.ts +35 -0
- package/dist/plugins/callsite-jsx.d.ts.map +1 -0
- package/dist/plugins/chunks.d.ts +11 -4
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +40 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/cloudflare-wasm.d.ts +21 -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 +17 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +28 -4
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +16 -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/prebuilt-capture.d.ts +60 -0
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts +40 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts.map +1 -0
- package/dist/plugins/prebuilt.d.ts +82 -0
- package/dist/plugins/prebuilt.d.ts.map +1 -0
- package/dist/plugins/prerender-sugar.d.ts +42 -0
- package/dist/plugins/prerender-sugar.d.ts.map +1 -0
- package/dist/plugins/request-dep.d.ts +21 -0
- package/dist/plugins/request-dep.d.ts.map +1 -0
- 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 +29 -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 +64 -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/export-detect.d.ts +56 -0
- package/dist/routing/export-detect.d.ts.map +1 -0
- package/dist/routing/file-cache.d.ts +8 -0
- package/dist/routing/file-cache.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/interception.d.ts +0 -5
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +90 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/manifest-codegen.d.ts +32 -0
- package/dist/routing/manifest-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 +81 -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 +81 -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 +91 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +188 -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 +42 -7
- 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 -30
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +93 -11
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +8 -18
- package/dist/server/asset-headers.d.ts.map +1 -1
- package/dist/server/body-limits.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +12 -29
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/canonicalize.d.ts +10 -0
- package/dist/server/canonicalize.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 +65 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/csrf.d.ts +3 -2
- package/dist/server/csrf.d.ts.map +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 +117 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +2 -2
- 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 -11
- 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/form-data.d.ts +41 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +242 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +82 -41
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +11 -47
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +182 -2906
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +49 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +3892 -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 +60 -11
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata.d.ts +8 -0
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +19 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +119 -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 +59 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +140 -19
- 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/prebuilt/cache-key.d.ts +62 -0
- package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +57 -0
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
- package/dist/server/prebuilt/key-discipline.d.ts +23 -0
- package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
- package/dist/server/prebuilt/overlay.d.ts +100 -0
- package/dist/server/prebuilt/overlay.d.ts.map +1 -0
- package/dist/server/prebuilt/payload-source.d.ts +78 -0
- package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +99 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -0
- package/dist/server/prebuilt/synthetic-store.d.ts +66 -0
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts +120 -0
- package/dist/server/prebuilt-builder.d.ts.map +1 -0
- package/dist/server/prebuilt-runtime.d.ts +111 -0
- package/dist/server/prebuilt-runtime.d.ts.map +1 -0
- package/dist/server/primitives.d.ts +88 -43
- 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/render-utils.d.ts +25 -0
- package/dist/server/render-utils.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/request-dep.d.ts +15 -0
- package/dist/server/request-dep.d.ts.map +1 -0
- package/dist/server/route-element-builder.d.ts +53 -25
- 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 +12 -3
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +29 -0
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
- 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 +69 -37
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +28 -6
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +51 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +108 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts +6 -6
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +25 -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 +36 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +89 -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 +66 -5
- 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 +72 -9
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +22 -11
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +47 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +44 -9
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +69 -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 +71 -6
- 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/utils/mdx-file.d.ts +15 -0
- package/dist/server/utils/mdx-file.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/server/workers-cache-bridge.d.ts +26 -0
- package/dist/server/workers-cache-bridge.d.ts.map +1 -0
- package/dist/shared/href-validation.d.ts +49 -0
- package/dist/shared/href-validation.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/shared/redirect-type.d.ts +17 -0
- package/dist/shared/redirect-type.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 +53 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/image.d.ts +120 -120
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +35 -11
- 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/docs/api/30-api-server.mdx +233 -0
- package/docs/api/31-api-client.mdx +161 -0
- package/docs/api/32-api-cache.mdx +311 -0
- package/docs/api/33-api-search-params.mdx +154 -0
- package/docs/api/34-api-config.mdx +325 -0
- package/docs/api/35-api-typescript.mdx +170 -0
- package/docs/api/36-cli.mdx +143 -0
- package/docs/learn/00-introduction.mdx +109 -0
- package/docs/learn/01-quick-start.mdx +94 -0
- package/docs/learn/02-pages-and-layouts.mdx +147 -0
- package/docs/learn/03-fetching-data.mdx +211 -0
- package/docs/learn/03b-access-control.mdx +130 -0
- package/docs/learn/04-loading-states.mdx +67 -0
- package/docs/learn/04b-the-flush-point.mdx +115 -0
- package/docs/learn/05-typed-params.mdx +275 -0
- package/docs/learn/06-forms-and-actions.mdx +146 -0
- package/docs/learn/07-typed-routes.mdx +127 -0
- package/docs/learn/08-streaming.mdx +146 -0
- package/docs/learn/09-caching.mdx +252 -0
- package/docs/learn/10-middleware.mdx +157 -0
- package/docs/learn/11-error-handling.mdx +156 -0
- package/docs/learn/12-client-navigation.mdx +176 -0
- package/docs/learn/13-configuration.mdx +162 -0
- package/docs/learn/14-deploying.mdx +264 -0
- package/docs/more/01-advanced-routing.mdx +173 -0
- package/docs/more/02-advanced-forms.mdx +137 -0
- package/docs/more/03-coming-from-nextjs.mdx +186 -0
- package/docs/more/04-metadata-and-fonts.mdx +193 -0
- package/docs/more/04b-mdx.mdx +209 -0
- package/docs/more/05-content-collections.mdx +90 -0
- package/docs/more/06-instrumentation.mdx +214 -0
- package/docs/more/07-security.mdx +129 -0
- package/docs/more/08-developer-experience.mdx +134 -0
- package/docs/more/40-why-timber.mdx +50 -0
- package/docs/more/41-timber-vs-nextjs.mdx +81 -0
- package/docs/more/42-timber-vs-others.mdx +68 -0
- package/docs/more/50-ai-agent-instructions.mdx +169 -0
- package/llms.txt +55 -0
- package/package.json +105 -26
- package/src/adapters/build-output-helper.ts +199 -0
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +204 -0
- package/src/adapters/cloudflare.ts +620 -129
- package/src/adapters/compress-module.ts +27 -92
- package/src/adapters/nitro.ts +266 -122
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/adapters/shared.ts +68 -0
- package/src/adapters/types.ts +2 -7
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +107 -0
- package/src/cache/handler-store.ts +76 -0
- package/src/cache/index.ts +114 -21
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/json-lossy-check.ts +75 -0
- package/src/cache/redis-handler.ts +197 -19
- package/src/cache/singleflight.ts +64 -6
- package/src/cache/sizeof.ts +33 -0
- package/src/cache/stable-stringify.ts +65 -2
- package/src/cache/store.ts +71 -0
- package/src/cache/stores/cloudflare-kv.ts +52 -0
- package/src/cache/stores/memory.ts +125 -0
- package/src/cache/stores/redis.ts +97 -0
- package/src/cache/stores/vercel.ts +59 -0
- package/src/cache/tag-aware-handler.ts +237 -0
- package/src/cache/timber-cache.ts +161 -36
- package/src/cdn/cloudflare-purge.ts +50 -0
- package/src/cdn/fastly-purge.ts +63 -0
- package/src/cdn/headers.ts +153 -0
- package/src/cdn/index.ts +17 -0
- package/src/cdn/purge-store.ts +34 -0
- package/src/cdn/workers-cache-purge.ts +30 -0
- package/src/cli-schema-sync.ts +401 -0
- package/src/cli.ts +167 -34
- package/src/client/browser-dev.ts +156 -1
- package/src/client/browser-entry/action-dispatch.ts +124 -0
- package/src/client/browser-entry/hmr.ts +70 -0
- package/src/client/browser-entry/hydrate.ts +187 -0
- package/src/client/browser-entry/index.ts +113 -0
- package/src/client/browser-entry/post-hydration.ts +110 -0
- package/src/client/browser-entry/router-init.ts +286 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +50 -0
- package/src/client/error-boundary.tsx +127 -22
- package/src/client/error-reconstituter.tsx +79 -0
- package/src/client/form.tsx +31 -32
- package/src/client/history.ts +21 -6
- package/src/client/index.ts +67 -45
- package/src/client/internal.ts +58 -0
- package/src/client/link.tsx +349 -150
- package/src/client/navigation-api.ts +345 -0
- package/src/client/navigation-context.ts +15 -7
- package/src/client/navigation-root.tsx +355 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +589 -215
- package/src/client/rsc-fetch.ts +251 -34
- package/src/client/segment-cache.ts +105 -17
- package/src/client/segment-outlet.tsx +141 -0
- package/src/client/segment-update-context.ts +42 -0
- package/src/client/shallow-url.ts +22 -0
- package/src/client/slot-context.ts +50 -0
- package/src/client/slot-outlet.tsx +22 -0
- package/src/client/slot-provider.tsx +32 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/state.ts +2 -2
- package/src/client/top-loader.tsx +11 -9
- package/src/client/use-cookie.ts +60 -15
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-pathname.ts +1 -0
- package/src/client/use-pending-navigation.ts +40 -0
- package/src/client/use-query-states.ts +108 -10
- package/src/client/use-router.ts +4 -1
- package/src/client/use-search-params.ts +31 -44
- package/src/client/{use-params.ts → use-segment-params.ts} +9 -6
- package/src/codec.ts +149 -0
- package/src/config-types.ts +282 -0
- package/src/config-validation.ts +330 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +217 -53
- package/src/cookies/index.ts +12 -1
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +192 -0
- package/src/dev-tools/404-page.ts +286 -0
- package/src/dev-tools/browser-logs.ts +55 -0
- package/src/dev-tools/dev-page-shell.ts +260 -0
- package/src/dev-tools/error-page.ts +331 -0
- package/src/dev-tools/holding-server.ts +187 -0
- package/src/dev-tools/hydration-overlay.ts +158 -0
- package/src/dev-tools/index.ts +83 -0
- package/src/dev-tools/instrumentation.ts +213 -0
- package/src/{server/dev-logger.ts → dev-tools/logger.ts} +33 -51
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +122 -26
- package/src/dev-tools/overlay.ts +469 -0
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +182 -0
- package/src/fonts/ast-walk.ts +235 -0
- package/src/fonts/ast.ts +477 -126
- package/src/fonts/bundle.ts +138 -0
- package/src/fonts/dev-middleware.ts +85 -0
- package/src/fonts/fallbacks.ts +0 -23
- package/src/fonts/google.ts +100 -18
- package/src/fonts/local.ts +9 -8
- package/src/fonts/paths.ts +58 -0
- package/src/fonts/pipeline.ts +348 -0
- package/src/fonts/transform.ts +311 -0
- package/src/fonts/types.ts +52 -1
- package/src/fonts/virtual-modules.ts +179 -0
- package/src/index.ts +446 -352
- package/src/params/codec-registry.ts +34 -0
- package/src/params/define-schema.ts +115 -0
- package/src/params/index.ts +17 -0
- package/src/params/resolve-schema.ts +84 -0
- package/src/plugin-context.ts +432 -0
- package/src/plugins/adapter-build.ts +220 -7
- package/src/plugins/build-manifest.ts +177 -23
- package/src/plugins/build-report.ts +253 -35
- package/src/plugins/cache.ts +243 -0
- package/src/plugins/callsite-ast.ts +472 -0
- package/src/plugins/callsite-jsx.ts +243 -0
- package/src/plugins/chunks.ts +74 -5
- package/src/plugins/client-chunks.ts +185 -0
- package/src/plugins/cloudflare-wasm.ts +141 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-server.ts +284 -94
- package/src/plugins/entries.ts +134 -16
- package/src/plugins/fonts.ts +225 -660
- package/src/plugins/mdx.ts +47 -10
- package/src/plugins/prebuilt-capture.ts +217 -0
- package/src/plugins/prebuilt-options-analysis.ts +175 -0
- package/src/plugins/prebuilt.ts +655 -0
- package/src/plugins/prerender-sugar.ts +328 -0
- package/src/plugins/request-dep.ts +458 -0
- package/src/plugins/routing.ts +237 -241
- package/src/plugins/server-bundle.ts +89 -12
- package/src/plugins/shims.ts +241 -64
- package/src/plugins/static-build.ts +15 -90
- package/src/routing/codegen-shared.ts +115 -0
- package/src/routing/codegen-types.ts +65 -0
- package/src/routing/codegen.ts +372 -178
- package/src/routing/convention-lint.ts +394 -0
- package/src/routing/export-detect.ts +304 -0
- package/src/routing/file-cache.ts +23 -0
- package/src/routing/index.ts +10 -1
- package/src/routing/interception.ts +3 -22
- package/src/routing/link-codegen.ts +313 -0
- package/src/routing/manifest-codegen.ts +287 -0
- package/src/routing/scanner.ts +338 -189
- package/src/routing/schema-validation.ts +155 -0
- package/src/routing/segment-classify.ts +223 -0
- package/src/routing/segment-codegen.ts +98 -0
- package/src/routing/types.ts +82 -25
- package/src/routing/walkers.ts +90 -0
- package/src/rsc-runtime/rsc.ts +9 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/schema-bridge.ts +253 -0
- package/src/search-params/define.ts +576 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +101 -0
- package/src/segment-params/define.ts +249 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +111 -34
- package/src/server/action-client.ts +120 -29
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +123 -33
- package/src/server/actions.ts +48 -54
- package/src/server/als-registry.ts +137 -20
- package/src/server/asset-headers.ts +15 -37
- package/src/server/body-limits.ts +10 -2
- package/src/server/build-manifest.ts +19 -56
- package/src/server/canonicalize.ts +6 -3
- package/src/server/coalesce-tick.ts +75 -0
- package/src/server/compress.ts +34 -7
- package/src/server/cookie-context.ts +484 -0
- package/src/server/cookie-parsing.ts +163 -0
- package/src/server/csrf.ts +39 -6
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-boundary.ts +314 -0
- package/src/server/deny-renderer.ts +85 -77
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/early-hints.ts +37 -27
- package/src/server/error-boundary-wrapper.ts +61 -22
- package/src/server/fallback-error.ts +79 -102
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/form-data.ts +124 -12
- package/src/server/html-injector-core.ts +495 -0
- package/src/server/html-injectors.ts +271 -254
- package/src/server/index.ts +31 -185
- package/src/server/internal.ts +181 -0
- package/src/server/logger.ts +72 -36
- package/src/server/metadata-routes.ts +205 -24
- package/src/server/metadata.ts +21 -0
- package/src/server/middleware-runner.ts +31 -4
- package/src/server/node-stream-transforms.ts +336 -0
- package/src/server/param-coercion.ts +207 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +45 -18
- package/src/server/pipeline-metadata.ts +14 -0
- package/src/server/pipeline-outcome.ts +197 -0
- package/src/server/pipeline-phases.ts +545 -0
- package/src/server/pipeline.ts +274 -382
- package/src/server/port-resolution.ts +215 -0
- package/src/server/prebuilt/cache-key.ts +298 -0
- package/src/server/prebuilt/capture-state.ts +89 -0
- package/src/server/prebuilt/key-discipline.ts +53 -0
- package/src/server/prebuilt/manifest-tag-index.ts +46 -0
- package/src/server/prebuilt/overlay.ts +256 -0
- package/src/server/prebuilt/payload-source.ts +201 -0
- package/src/server/prebuilt/slots.ts +190 -0
- package/src/server/prebuilt/synthetic-store.ts +121 -0
- package/src/server/prebuilt-builder.ts +809 -0
- package/src/server/prebuilt-runtime.ts +815 -0
- package/src/server/primitives.ts +160 -83
- package/src/server/render-timeout.ts +108 -0
- package/src/server/render-utils.ts +31 -0
- package/src/server/request-context.ts +170 -337
- package/src/server/request-dep.ts +37 -0
- package/src/server/route-element-builder.ts +699 -295
- package/src/server/route-handler.ts +31 -4
- package/src/server/route-matcher.ts +158 -277
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +69 -32
- package/src/server/rsc-entry/deny-fallback.ts +92 -0
- package/src/server/rsc-entry/error-renderer.ts +306 -89
- package/src/server/rsc-entry/helpers.ts +210 -85
- package/src/server/rsc-entry/index.ts +332 -332
- package/src/server/rsc-entry/render-route.ts +300 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +349 -0
- package/src/server/rsc-entry/rsc-payload.ts +102 -42
- package/src/server/rsc-entry/rsc-stream.ts +93 -13
- package/src/server/rsc-entry/ssr-bridge.ts +18 -5
- package/src/server/rsc-entry/ssr-renderer.ts +275 -43
- package/src/server/rsc-entry/wrap-action-dispatch.ts +186 -0
- package/src/server/safe-load.ts +60 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/server-only-guard-noop.js +3 -0
- package/src/server/sitemap-generator.ts +345 -0
- package/src/server/sitemap-handler.ts +157 -0
- package/src/server/slot-resolver.ts +574 -250
- package/src/server/ssr-bridge-types.ts +124 -0
- package/src/server/ssr-entry.ts +206 -86
- package/src/server/ssr-render.ts +345 -86
- package/src/server/ssr-wrappers.tsx +141 -0
- package/src/server/state-tree-diff.ts +177 -30
- package/src/server/status-code-resolver.ts +115 -130
- package/src/server/stream-utils.ts +288 -0
- package/src/server/tracing.ts +126 -14
- package/src/server/tree-builder.ts +214 -90
- package/src/server/tree-match.ts +262 -0
- package/src/server/types.ts +78 -9
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/utils/mdx-file.ts +22 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/workers-cache-bridge.ts +33 -0
- package/src/shared/href-validation.ts +159 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shared/redirect-type.ts +17 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +122 -1
- package/src/shims/navigation-client.ts +51 -29
- 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-B3Gypr3D.js +0 -108
- package/dist/_chunks/debug-B3Gypr3D.js.map +0 -1
- package/dist/_chunks/format-RyoGQL74.js +0 -164
- package/dist/_chunks/format-RyoGQL74.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 +0 -153
- package/dist/_chunks/metadata-routes-Cjmvi3rQ.js.map +0 -1
- package/dist/_chunks/request-context-BQUC8PHn.js +0 -330
- package/dist/_chunks/request-context-BQUC8PHn.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/adapters/cloudflare.js.map +0 -1
- package/dist/cache/index.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/head.d.ts +0 -16
- package/dist/client/head.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/stale-reload.d.ts +0 -44
- package/dist/client/stale-reload.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts +0 -74
- 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/client-module-map.d.ts +0 -47
- package/dist/server/client-module-map.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 +0 -29
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts +0 -129
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/flush.d.ts +0 -74
- package/dist/server/flush.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/head.ts +0 -61
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/segment-merger.ts +0 -339
- package/src/client/stale-reload.ts +0 -87
- 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/codecs.ts +0 -153
- package/src/search-params/create.ts +0 -321
- package/src/server/client-module-map.ts +0 -58
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/dev-warnings.ts +0 -283
- package/src/server/flush.ts +0 -182
- 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/client/router.ts
CHANGED
|
@@ -4,11 +4,21 @@
|
|
|
4
4
|
import { SegmentCache, PrefetchCache, buildSegmentTree } from './segment-cache';
|
|
5
5
|
import type { SegmentInfo } from './segment-cache';
|
|
6
6
|
import { HistoryStack } from './history';
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
import { setCurrentParams } from './use-segment-params.js';
|
|
8
|
+
import {
|
|
9
|
+
setNavigationState,
|
|
10
|
+
getNavigationState,
|
|
11
|
+
type NavigationState,
|
|
12
|
+
} from './navigation-context.js';
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
fetchRscPayload,
|
|
16
|
+
RedirectError,
|
|
17
|
+
ServerErrorResponse,
|
|
18
|
+
VersionSkewError,
|
|
19
|
+
NonRscResponse,
|
|
20
|
+
} from './rsc-fetch.js';
|
|
21
|
+
import { setHardNavigating, supersedeNavigationTransitions } from './navigation-root.js';
|
|
12
22
|
import type { FetchResult } from './rsc-fetch.js';
|
|
13
23
|
|
|
14
24
|
// ─── Types ───────────────────────────────────────────────────────
|
|
@@ -18,6 +28,25 @@ export interface NavigationOptions {
|
|
|
18
28
|
scroll?: boolean;
|
|
19
29
|
/** Use replaceState instead of pushState (replaces current history entry) */
|
|
20
30
|
replace?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* @internal AbortSignal from the Navigation API's NavigateEvent.
|
|
33
|
+
* When provided, the signal is linked to the router's per-navigation
|
|
34
|
+
* AbortController so in-flight RSC fetches are cancelled when a new
|
|
35
|
+
* navigation starts.
|
|
36
|
+
*/
|
|
37
|
+
_signal?: AbortSignal;
|
|
38
|
+
/**
|
|
39
|
+
* @internal Skip pushState/replaceState — the Navigation API has already
|
|
40
|
+
* updated the URL via event.intercept(). Used for external navigations
|
|
41
|
+
* intercepted by the navigate event handler.
|
|
42
|
+
*/
|
|
43
|
+
_skipHistory?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* @internal The URL the user is navigating FROM, captured before the
|
|
46
|
+
* Navigation API commits the destination. Sent as X-Timber-URL for
|
|
47
|
+
* slot skip comparison on the server (TIM-1232).
|
|
48
|
+
*/
|
|
49
|
+
_departingUrl?: string;
|
|
21
50
|
}
|
|
22
51
|
|
|
23
52
|
/**
|
|
@@ -31,8 +60,12 @@ export type RscDecoder = (fetchPromise: Promise<Response>) => unknown;
|
|
|
31
60
|
* Function that renders a decoded RSC element tree into the DOM.
|
|
32
61
|
* In production: reactRoot.render(element).
|
|
33
62
|
* In tests: a no-op or mock.
|
|
63
|
+
*
|
|
64
|
+
* Receives the current NavigationState explicitly — no temporal
|
|
65
|
+
* coupling with setNavigationState/getNavigationState. The renderer
|
|
66
|
+
* wraps the element in NavigationProvider with this state.
|
|
34
67
|
*/
|
|
35
|
-
export type RootRenderer = (element: unknown) => void;
|
|
68
|
+
export type RootRenderer = (element: unknown, navState: NavigationState) => void;
|
|
36
69
|
|
|
37
70
|
/**
|
|
38
71
|
* Platform dependencies injected for testability. In production these
|
|
@@ -55,8 +88,6 @@ export interface RouterDeps {
|
|
|
55
88
|
* In tests, this runs the callback synchronously.
|
|
56
89
|
*/
|
|
57
90
|
afterPaint?: (callback: () => void) => void;
|
|
58
|
-
/** Apply resolved head elements (title, meta tags) to the DOM after navigation. */
|
|
59
|
-
applyHead?: (elements: HeadElement[]) => void;
|
|
60
91
|
/**
|
|
61
92
|
* Run a navigation inside a React transition with optimistic pending URL.
|
|
62
93
|
* The pending URL shows immediately (useOptimistic urgent update) and
|
|
@@ -64,14 +95,80 @@ export interface RouterDeps {
|
|
|
64
95
|
*
|
|
65
96
|
* The `perform` callback receives a `wrapPayload` function to wrap the
|
|
66
97
|
* decoded RSC payload with NavigationProvider + NuqsAdapter before
|
|
67
|
-
*
|
|
98
|
+
* NavigationRoot sets it as the new element. The `wrapPayload` function
|
|
99
|
+
* receives the NavigationState explicitly — no temporal coupling with
|
|
100
|
+
* getNavigationState().
|
|
68
101
|
*
|
|
69
102
|
* If not provided (tests), the router falls back to renderRoot.
|
|
70
103
|
*/
|
|
71
104
|
navigateTransition?: (
|
|
72
105
|
pendingUrl: string,
|
|
73
|
-
perform: (
|
|
106
|
+
perform: (
|
|
107
|
+
wrapPayload: (
|
|
108
|
+
payload: unknown,
|
|
109
|
+
navState: NavigationState,
|
|
110
|
+
segmentUpdates?: Map<string, unknown>
|
|
111
|
+
) => unknown
|
|
112
|
+
) => Promise<{ element: unknown; decodePromise: Promise<void> | null }>
|
|
74
113
|
) => Promise<void>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Whether the Navigation API is active and handling traversals.
|
|
117
|
+
* When true, the popstate handler is a no-op — the Navigation API's
|
|
118
|
+
* navigate event covers back/forward button presses.
|
|
119
|
+
*/
|
|
120
|
+
navigationApiActive?: boolean;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Called around pushState/replaceState to set a flag that prevents
|
|
124
|
+
* the Navigation API's navigate listener from double-handling
|
|
125
|
+
* router-initiated navigations.
|
|
126
|
+
*/
|
|
127
|
+
setRouterNavigating?: (value: boolean) => void;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Save scroll position via the Navigation API's per-entry state.
|
|
131
|
+
* When provided, used instead of history.replaceState for scroll storage.
|
|
132
|
+
*/
|
|
133
|
+
saveNavigationEntryScroll?: (scrollY: number) => void;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Signal that a router-initiated navigation has completed. Resolves the
|
|
137
|
+
* deferred promise that ties the browser's native loading state to the
|
|
138
|
+
* navigation lifecycle. Called in the finally block of navigate/refresh,
|
|
139
|
+
* aligned with when the TopLoader's pendingUrl clears.
|
|
140
|
+
*/
|
|
141
|
+
completeRouterNavigation?: () => void;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get the current unwrapped RSC payload element. Used for partial
|
|
145
|
+
* navigation: the router re-wraps the same element with new
|
|
146
|
+
* NavigationProvider context so mounted SegmentOutlets are preserved.
|
|
147
|
+
*/
|
|
148
|
+
_getCurrentPayload?: () => unknown;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Initiate a navigation via the Navigation API (`navigation.navigate()`).
|
|
152
|
+
* Fires the navigate event BEFORE committing the URL, allowing Chrome
|
|
153
|
+
* to show its native loading indicator. Falls back to pushState when
|
|
154
|
+
* unavailable.
|
|
155
|
+
*/
|
|
156
|
+
navigationNavigate?: (url: string, replace: boolean) => void;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Scroll the element matching a URL #fragment into view. Returns true
|
|
160
|
+
* when a matching element was found and scrolled. When absent or false,
|
|
161
|
+
* the router falls back to scroll-to-top on forward navigation — same
|
|
162
|
+
* as a full page load with an unknown fragment landing at the top.
|
|
163
|
+
*/
|
|
164
|
+
scrollToHash?: (hash: string) => boolean;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Whether the client segment cache is enabled. When false (the default),
|
|
168
|
+
* the router does not send X-Timber-State-Tree headers and does not
|
|
169
|
+
* populate the segment cache. Every navigation gets a full RSC payload.
|
|
170
|
+
*/
|
|
171
|
+
clientSegmentCache?: boolean;
|
|
75
172
|
}
|
|
76
173
|
|
|
77
174
|
export interface RouterInstance {
|
|
@@ -80,7 +177,7 @@ export interface RouterInstance {
|
|
|
80
177
|
/** Full re-render of the current URL — no state tree sent */
|
|
81
178
|
refresh(): Promise<void>;
|
|
82
179
|
/** Handle a popstate event (back/forward button). scrollY is read from history.state. */
|
|
83
|
-
handlePopState(url: string, scrollY?: number): Promise<void>;
|
|
180
|
+
handlePopState(url: string, scrollY?: number, externalSignal?: AbortSignal): Promise<void>;
|
|
84
181
|
/** Whether a navigation is currently in flight */
|
|
85
182
|
isPending(): boolean;
|
|
86
183
|
/** The URL currently being navigated to, or null if idle */
|
|
@@ -94,18 +191,13 @@ export interface RouterInstance {
|
|
|
94
191
|
* Renders the element tree and updates head elements without a server fetch.
|
|
95
192
|
* See design/08-forms-and-actions.md §"Single-Roundtrip Revalidation".
|
|
96
193
|
*/
|
|
97
|
-
applyRevalidation(element: unknown
|
|
194
|
+
applyRevalidation(element: unknown): void;
|
|
98
195
|
/**
|
|
99
196
|
* Populate the segment cache from server-provided segment metadata.
|
|
100
197
|
* Called on initial hydration with segment info embedded in the HTML.
|
|
101
198
|
*/
|
|
102
199
|
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;
|
|
200
|
+
|
|
109
201
|
/** The segment cache (exposed for tests and <Link> prefetch) */
|
|
110
202
|
segmentCache: SegmentCache;
|
|
111
203
|
/** The prefetch cache (exposed for tests and <Link> prefetch) */
|
|
@@ -130,24 +222,83 @@ function isAbortError(error: unknown): boolean {
|
|
|
130
222
|
* Create a router instance. In production, called once at app hydration
|
|
131
223
|
* with real browser APIs. In tests, called with mock dependencies.
|
|
132
224
|
*/
|
|
225
|
+
/**
|
|
226
|
+
* Router navigation phase — discriminated union replacing scattered
|
|
227
|
+
* `pending` + `pendingUrl` boolean flags.
|
|
228
|
+
*
|
|
229
|
+
* - `idle`: No navigation in flight. The committed params/pathname
|
|
230
|
+
* are current.
|
|
231
|
+
* - `navigating`: A fetch or render is in progress. `targetUrl` is
|
|
232
|
+
* the destination being navigated to.
|
|
233
|
+
*/
|
|
234
|
+
export type RouterPhase = { phase: 'idle' } | { phase: 'navigating'; targetUrl: string };
|
|
235
|
+
|
|
133
236
|
export function createRouter(deps: RouterDeps): RouterInstance {
|
|
134
237
|
const segmentCache = new SegmentCache();
|
|
135
238
|
const prefetchCache = new PrefetchCache();
|
|
136
239
|
const historyStack = new HistoryStack();
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
let pending = false;
|
|
140
|
-
let pendingUrl: string | null = null;
|
|
240
|
+
let routerPhase: RouterPhase = { phase: 'idle' };
|
|
141
241
|
const pendingListeners = new Set<(pending: boolean) => void>();
|
|
142
242
|
|
|
243
|
+
// AbortController for the current in-flight navigation.
|
|
244
|
+
// When a new navigation starts, the previous controller is aborted,
|
|
245
|
+
// cancelling any in-progress RSC fetch. This provides automatic
|
|
246
|
+
// cancellation of stale fetches regardless of Navigation API support.
|
|
247
|
+
let currentNavAbort: AbortController | null = null;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Create a new AbortController for a navigation, superseding any
|
|
251
|
+
* previous in-flight navigation. Optionally links to an external
|
|
252
|
+
* signal (e.g., from the Navigation API's NavigateEvent.signal).
|
|
253
|
+
*
|
|
254
|
+
* Superseding is one operation with three parts:
|
|
255
|
+
* 1. Abort the previous navigation's fetch.
|
|
256
|
+
* 2. Invalidate its render transition so a response that already
|
|
257
|
+
* arrived can't commit a stale tree (NavigationRoot's transId guard).
|
|
258
|
+
* 3. Resolve its Navigation API deferred — the superseded navigation's
|
|
259
|
+
* finally block is staleness-guarded (see TIM-1034) and no longer
|
|
260
|
+
* cleans up after itself, so the browser's native loading state for
|
|
261
|
+
* the dead navigation is cleared here.
|
|
262
|
+
*/
|
|
263
|
+
function createNavAbort(externalSignal?: AbortSignal): AbortController {
|
|
264
|
+
if (currentNavAbort) {
|
|
265
|
+
currentNavAbort.abort();
|
|
266
|
+
supersedeNavigationTransitions();
|
|
267
|
+
deps.completeRouterNavigation?.();
|
|
268
|
+
}
|
|
269
|
+
const controller = new AbortController();
|
|
270
|
+
currentNavAbort = controller;
|
|
271
|
+
|
|
272
|
+
// If an external signal is provided (e.g., Navigation API),
|
|
273
|
+
// forward its abort to our controller.
|
|
274
|
+
if (externalSignal) {
|
|
275
|
+
if (externalSignal.aborted) {
|
|
276
|
+
controller.abort();
|
|
277
|
+
} else {
|
|
278
|
+
externalSignal.addEventListener('abort', () => controller.abort(), { once: true });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return controller;
|
|
283
|
+
}
|
|
284
|
+
|
|
143
285
|
function setPending(value: boolean, url?: string): void {
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
286
|
+
const next: RouterPhase =
|
|
287
|
+
value && url ? { phase: 'navigating', targetUrl: url } : { phase: 'idle' };
|
|
288
|
+
// Skip no-op updates
|
|
289
|
+
if (
|
|
290
|
+
routerPhase.phase === next.phase &&
|
|
291
|
+
(routerPhase.phase === 'idle' ||
|
|
292
|
+
(routerPhase.phase === 'navigating' &&
|
|
293
|
+
next.phase === 'navigating' &&
|
|
294
|
+
routerPhase.targetUrl === next.targetUrl))
|
|
295
|
+
) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
routerPhase = next;
|
|
148
299
|
// Notify external store listeners (non-React consumers).
|
|
149
300
|
// React-facing pending state is handled by useOptimistic in
|
|
150
|
-
//
|
|
301
|
+
// NavigationRoot via navigateTransition — not this function.
|
|
151
302
|
for (const listener of pendingListeners) {
|
|
152
303
|
listener(value);
|
|
153
304
|
}
|
|
@@ -155,6 +306,7 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
155
306
|
|
|
156
307
|
/** Update the segment cache from server-provided segment metadata. */
|
|
157
308
|
function updateSegmentCache(segmentInfo: SegmentInfo[] | null | undefined): void {
|
|
309
|
+
if (!deps.clientSegmentCache) return;
|
|
158
310
|
if (!segmentInfo || segmentInfo.length === 0) return;
|
|
159
311
|
const tree = buildSegmentTree(segmentInfo);
|
|
160
312
|
if (tree) {
|
|
@@ -163,100 +315,182 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
163
315
|
}
|
|
164
316
|
|
|
165
317
|
/** Render a decoded RSC payload into the DOM if a renderer is available. */
|
|
166
|
-
function renderPayload(payload: unknown): void {
|
|
318
|
+
function renderPayload(payload: unknown, navState: NavigationState): void {
|
|
167
319
|
if (deps.renderRoot) {
|
|
168
|
-
deps.renderRoot(payload);
|
|
320
|
+
deps.renderRoot(payload, navState);
|
|
169
321
|
}
|
|
170
322
|
}
|
|
171
323
|
|
|
172
324
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
325
|
+
* Atomically update all navigation-owned state for a new page. Every
|
|
326
|
+
* code path that changes the "current page" must go through this
|
|
327
|
+
* function — making "forgot a field" impossible by construction.
|
|
328
|
+
*
|
|
329
|
+
* The three operations:
|
|
330
|
+
* 1. Segment cache — update from server-provided segment metadata
|
|
331
|
+
* 2. Navigation state — params + pathname for useSegmentParams/usePathname
|
|
332
|
+
* 3. History stack — store the payload for instant back/forward replay
|
|
176
333
|
*/
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
334
|
+
function commitNavigation(
|
|
335
|
+
url: string,
|
|
336
|
+
opts: {
|
|
337
|
+
payload: unknown;
|
|
338
|
+
params?: Record<string, string | string[]> | null;
|
|
339
|
+
segmentInfo?: SegmentInfo[] | null;
|
|
340
|
+
/** When true, clear the segment cache if segmentInfo is empty
|
|
341
|
+
* (popstate replay for entries without layout metadata). */
|
|
342
|
+
clearSegmentCacheOnEmpty?: boolean;
|
|
343
|
+
}
|
|
344
|
+
): NavigationState {
|
|
345
|
+
if (opts.segmentInfo && opts.segmentInfo.length > 0) {
|
|
346
|
+
updateSegmentCache(opts.segmentInfo);
|
|
347
|
+
} else if (opts.clearSegmentCacheOnEmpty) {
|
|
348
|
+
segmentCache.clear();
|
|
186
349
|
}
|
|
187
350
|
|
|
188
|
-
|
|
189
|
-
|
|
351
|
+
const navState = updateNavigationState(opts.params, url);
|
|
352
|
+
|
|
353
|
+
historyStack.push(url, {
|
|
354
|
+
payload: opts.payload,
|
|
355
|
+
params: navState.params,
|
|
356
|
+
segmentInfo: opts.segmentInfo,
|
|
357
|
+
});
|
|
190
358
|
|
|
191
|
-
return
|
|
359
|
+
return navState;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Wrap a navigation in the standard abort/pending/cleanup lifecycle.
|
|
364
|
+
* Consolidates the createNavAbort + setPending + staleness-guarded
|
|
365
|
+
* finally that was duplicated across navigate, refresh, and both
|
|
366
|
+
* handlePopState paths. AbortErrors are swallowed (not application
|
|
367
|
+
* errors); all other errors propagate to the caller.
|
|
368
|
+
*/
|
|
369
|
+
async function runNavigation(
|
|
370
|
+
url: string,
|
|
371
|
+
fn: (navAbort: AbortController) => Promise<void>,
|
|
372
|
+
externalSignal?: AbortSignal
|
|
373
|
+
): Promise<void> {
|
|
374
|
+
const navAbort = createNavAbort(externalSignal);
|
|
375
|
+
setPending(true, url);
|
|
376
|
+
try {
|
|
377
|
+
await fn(navAbort);
|
|
378
|
+
} catch (error) {
|
|
379
|
+
if (isAbortError(error)) return;
|
|
380
|
+
throw error;
|
|
381
|
+
} finally {
|
|
382
|
+
if (currentNavAbort === navAbort) {
|
|
383
|
+
currentNavAbort = null;
|
|
384
|
+
setPending(false);
|
|
385
|
+
deps.completeRouterNavigation?.();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Resolve thenable payloads in the test/fallback path (no navigateTransition).
|
|
392
|
+
* In production, React handles thenables from createFromFetch directly via
|
|
393
|
+
* Suspense. In tests, renderRoot is a plain mock that expects resolved values.
|
|
394
|
+
*/
|
|
395
|
+
async function resolveForFallback(payload: unknown): Promise<unknown> {
|
|
396
|
+
if (
|
|
397
|
+
!deps.navigateTransition &&
|
|
398
|
+
payload != null &&
|
|
399
|
+
typeof payload === 'object' &&
|
|
400
|
+
'then' in payload
|
|
401
|
+
) {
|
|
402
|
+
return await (payload as PromiseLike<unknown>);
|
|
403
|
+
}
|
|
404
|
+
return payload;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function isPartialNavigation(skippedSegments: string[] | null | undefined): boolean {
|
|
408
|
+
return skippedSegments != null && skippedSegments.length > 0;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Build a segment updates map for partial navigation. Identifies the
|
|
413
|
+
* first non-skipped segment and maps it to the payload content.
|
|
414
|
+
*/
|
|
415
|
+
function buildSegmentUpdates(result: FetchResult): Map<string, unknown> {
|
|
416
|
+
const skipped = new Set(result.skippedSegments!);
|
|
417
|
+
const segmentInfo = result.segmentInfo;
|
|
418
|
+
const updates = new Map<string, unknown>();
|
|
419
|
+
if (segmentInfo) {
|
|
420
|
+
for (const info of segmentInfo) {
|
|
421
|
+
if (!skipped.has(info.segmentId ?? info.path)) {
|
|
422
|
+
updates.set(info.segmentId ?? info.path, result.payload);
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return updates;
|
|
192
428
|
}
|
|
193
429
|
|
|
194
430
|
/**
|
|
195
431
|
* Update navigation state (params + pathname) for the next render.
|
|
196
432
|
*
|
|
197
|
-
* Sets
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
433
|
+
* Sets the module-level fallback (for tests and SSR) and the
|
|
434
|
+
* globalThis bridge, then returns the NavigationState so callers
|
|
435
|
+
* can pass it explicitly to renderRoot/wrapPayload — eliminating
|
|
436
|
+
* temporal coupling with getNavigationState().
|
|
201
437
|
*/
|
|
202
438
|
function updateNavigationState(
|
|
203
439
|
params: Record<string, string | string[]> | null | undefined,
|
|
204
440
|
url: string
|
|
205
|
-
):
|
|
441
|
+
): NavigationState {
|
|
206
442
|
const resolvedParams = params ?? {};
|
|
207
443
|
// Module-level fallback for tests (no NavigationProvider) and SSR
|
|
208
444
|
setCurrentParams(resolvedParams);
|
|
209
|
-
//
|
|
210
|
-
const
|
|
211
|
-
|
|
445
|
+
// globalThis bridge — kept for backward compat
|
|
446
|
+
const parsed = new URL(url, 'http://localhost');
|
|
447
|
+
const pathname = parsed.pathname || '/';
|
|
448
|
+
const search = parsed.search;
|
|
449
|
+
const navState: NavigationState = { params: resolvedParams, pathname, search };
|
|
450
|
+
setNavigationState(navState);
|
|
451
|
+
return navState;
|
|
212
452
|
}
|
|
213
453
|
|
|
214
454
|
/**
|
|
215
455
|
* Render a payload via navigateTransition (production) or renderRoot (tests).
|
|
216
|
-
* The perform callback should fetch data,
|
|
217
|
-
*
|
|
218
|
-
*
|
|
456
|
+
* The perform callback should fetch data, call commitNavigation, and return
|
|
457
|
+
* the FetchResult plus the NavigationState.
|
|
458
|
+
*
|
|
459
|
+
* State management (segmentCache, navState, historyStack) is handled by
|
|
460
|
+
* commitNavigation inside perform — this function only handles rendering.
|
|
219
461
|
*/
|
|
220
462
|
async function renderViaTransition(
|
|
221
463
|
url: string,
|
|
222
|
-
perform: () => Promise<FetchResult>
|
|
223
|
-
): Promise<
|
|
464
|
+
perform: () => Promise<FetchResult & { navState: NavigationState }>
|
|
465
|
+
): Promise<void> {
|
|
224
466
|
if (deps.navigateTransition) {
|
|
225
|
-
let headElements: HeadElement[] | null = null;
|
|
226
467
|
await deps.navigateTransition(url, async (wrapPayload) => {
|
|
227
468
|
const result = await perform();
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
469
|
+
|
|
470
|
+
if (isPartialNavigation(result.skippedSegments)) {
|
|
471
|
+
const segmentUpdates = buildSegmentUpdates(result);
|
|
472
|
+
|
|
473
|
+
// Re-wrap the CURRENT element with new context values.
|
|
474
|
+
// SegmentOutlets read updates from SegmentUpdateContext;
|
|
475
|
+
// NavigationProvider gets new params/pathname.
|
|
476
|
+
const element = wrapPayload(
|
|
477
|
+
deps._getCurrentPayload?.() ?? result.payload,
|
|
478
|
+
result.navState,
|
|
479
|
+
segmentUpdates
|
|
480
|
+
);
|
|
481
|
+
return { element, decodePromise: result.decodePromise };
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Full navigation — empty updates, render the new tree.
|
|
485
|
+
const element = wrapPayload(result.payload, result.navState);
|
|
486
|
+
return { element, decodePromise: result.decodePromise };
|
|
239
487
|
});
|
|
240
|
-
return
|
|
488
|
+
return;
|
|
241
489
|
}
|
|
242
490
|
// Fallback: no transition (tests, no React tree)
|
|
243
491
|
const result = await perform();
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Store merged payload in history
|
|
247
|
-
historyStack.push(url, {
|
|
248
|
-
payload: merged,
|
|
249
|
-
headElements: result.headElements,
|
|
250
|
-
params: result.params,
|
|
251
|
-
});
|
|
252
|
-
renderPayload(merged);
|
|
253
|
-
return result.headElements;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/** Apply head elements (title, meta tags) to the DOM if available. */
|
|
257
|
-
function applyHead(elements: HeadElement[] | null | undefined): void {
|
|
258
|
-
if (elements && deps.applyHead) {
|
|
259
|
-
deps.applyHead(elements);
|
|
492
|
+
if (!isPartialNavigation(result.skippedSegments)) {
|
|
493
|
+
renderPayload(result.payload, result.navState);
|
|
260
494
|
}
|
|
261
495
|
}
|
|
262
496
|
|
|
@@ -269,21 +503,61 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
269
503
|
}
|
|
270
504
|
}
|
|
271
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Schedule scroll restoration after the next paint and fire the
|
|
508
|
+
* scroll-restored event. Used by navigate, popstate, and refresh.
|
|
509
|
+
*/
|
|
510
|
+
function restoreScrollAfterPaint(scrollY: number): void {
|
|
511
|
+
afterPaint(() => {
|
|
512
|
+
deps.scrollTo(0, scrollY);
|
|
513
|
+
window.dispatchEvent(new Event('timber:scroll-restored'));
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Scroll to the element matching the URL #fragment after paint, falling
|
|
519
|
+
* back to scroll-to-top when no element matches (matching full-page-load
|
|
520
|
+
* behavior for an unknown fragment). Used by forward navigation to a
|
|
521
|
+
* hash-bearing URL (TIM-1035).
|
|
522
|
+
*/
|
|
523
|
+
function scrollToHashAfterPaint(hash: string): void {
|
|
524
|
+
afterPaint(() => {
|
|
525
|
+
if (deps.scrollToHash?.(hash) !== true) {
|
|
526
|
+
deps.scrollTo(0, 0);
|
|
527
|
+
}
|
|
528
|
+
window.dispatchEvent(new Event('timber:scroll-restored'));
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
272
532
|
/**
|
|
273
533
|
* Core navigation logic shared between the transition and fallback paths.
|
|
274
534
|
* Fetches the RSC payload, updates all state, and returns the result.
|
|
275
535
|
*/
|
|
276
536
|
async function performNavigationFetch(
|
|
277
537
|
url: string,
|
|
278
|
-
options: {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
538
|
+
options: {
|
|
539
|
+
replace: boolean;
|
|
540
|
+
commitUrl?: string;
|
|
541
|
+
signal?: AbortSignal;
|
|
542
|
+
skipHistory?: boolean;
|
|
543
|
+
departingUrl?: string;
|
|
544
|
+
}
|
|
545
|
+
): Promise<FetchResult & { navState: NavigationState }> {
|
|
546
|
+
// Check prefetch cache first. A negative entry means a prior prefetch
|
|
547
|
+
// determined this URL is not a route (non-RSC Content-Type). Hard-navigate
|
|
548
|
+
// immediately without a second fetch. See TIM-1231.
|
|
549
|
+
if (prefetchCache.isNegative(url)) {
|
|
550
|
+
prefetchCache.consume(url);
|
|
551
|
+
throw new NonRscResponse(url);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// PrefetchResult has optional segmentInfo/params fields — normalize
|
|
555
|
+
// to null for FetchResult compatibility.
|
|
282
556
|
const prefetched = prefetchCache.consume(url);
|
|
283
557
|
let result: FetchResult | undefined = prefetched
|
|
284
558
|
? {
|
|
285
559
|
payload: prefetched.payload,
|
|
286
|
-
|
|
560
|
+
decodePromise: null,
|
|
287
561
|
segmentInfo: prefetched.segmentInfo ?? null,
|
|
288
562
|
params: prefetched.params ?? null,
|
|
289
563
|
skippedSegments: prefetched.skippedSegments ?? null,
|
|
@@ -292,149 +566,237 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
292
566
|
|
|
293
567
|
if (result === undefined) {
|
|
294
568
|
// Fetch RSC payload with state tree for partial rendering.
|
|
295
|
-
// Send
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
569
|
+
// Send departing URL (pre-navigation) for slot skip comparison.
|
|
570
|
+
// getCurrentUrl() can't be used here because the Navigation API
|
|
571
|
+
// may have already committed the destination URL (TIM-1232).
|
|
572
|
+
const stateTree = deps.clientSegmentCache ? segmentCache.serializeStateTree() : undefined;
|
|
573
|
+
const rawDepartingUrl = options.departingUrl ?? deps.getCurrentUrl();
|
|
574
|
+
const currentUrl = rawDepartingUrl.startsWith('http')
|
|
575
|
+
? new URL(rawDepartingUrl).pathname
|
|
576
|
+
: new URL(rawDepartingUrl, 'http://localhost').pathname;
|
|
577
|
+
result = await fetchRscPayload(url, deps, stateTree, currentUrl, options.signal);
|
|
302
578
|
}
|
|
303
579
|
|
|
304
|
-
// Update the browser history —
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
580
|
+
// Update the browser history — skip when the Navigation API has already
|
|
581
|
+
// updated the URL via event.intercept() (external navigations).
|
|
582
|
+
// The committed URL keeps the #fragment (commitUrl) even though the
|
|
583
|
+
// fetch/history-stack URL is hash-less (TIM-1035).
|
|
584
|
+
if (!options.skipHistory) {
|
|
585
|
+
const commitUrl = options.commitUrl ?? url;
|
|
586
|
+
// Set the router-navigating flag so the Navigation API's navigate
|
|
587
|
+
// listener doesn't double-intercept this pushState/replaceState.
|
|
588
|
+
deps.setRouterNavigating?.(true);
|
|
589
|
+
if (options.replace) {
|
|
590
|
+
deps.replaceState({ timber: true, scrollY: 0 }, '', commitUrl);
|
|
591
|
+
} else {
|
|
592
|
+
deps.pushState({ timber: true, scrollY: 0 }, '', commitUrl);
|
|
593
|
+
}
|
|
594
|
+
deps.setRouterNavigating?.(false);
|
|
309
595
|
}
|
|
310
596
|
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
597
|
+
// Resolve thenable payloads in the test path so popstate replay
|
|
598
|
+
// and renderPayload receive plain values (see resolveForFallback).
|
|
599
|
+
const payload = await resolveForFallback(result.payload);
|
|
600
|
+
|
|
601
|
+
// Atomically update all navigation state via commitNavigation.
|
|
602
|
+
// Partial navigations and slot-skip navigations store null payload —
|
|
603
|
+
// the RSC tree contains skip holes that can't be replayed standalone;
|
|
604
|
+
// popstate will fetch fresh.
|
|
605
|
+
const isPartial = isPartialNavigation(result.skippedSegments);
|
|
606
|
+
const hasSkippedSlots = result.segmentInfo?.some((s) => s.slot && s.skipped) ?? false;
|
|
607
|
+
const navState = commitNavigation(url, {
|
|
608
|
+
payload: isPartial || hasSkippedSlots ? null : payload,
|
|
609
|
+
params: result.params,
|
|
610
|
+
segmentInfo: result.segmentInfo,
|
|
611
|
+
});
|
|
321
612
|
|
|
322
|
-
return result;
|
|
613
|
+
return { ...result, payload, navState };
|
|
323
614
|
}
|
|
324
615
|
|
|
325
616
|
async function navigate(url: string, options: NavigationOptions = {}): Promise<void> {
|
|
326
617
|
const scroll = options.scroll !== false;
|
|
327
618
|
const replace = options.replace === true;
|
|
619
|
+
const externalSignal = options._signal as AbortSignal | undefined;
|
|
620
|
+
const skipHistory = options._skipHistory === true;
|
|
621
|
+
|
|
622
|
+
// Split the #fragment off the navigation URL (TIM-1035). The full URL
|
|
623
|
+
// (with hash) is committed to the address bar; the hash-less URL is used
|
|
624
|
+
// for the RSC fetch (fragments are client-only — keeping it would also
|
|
625
|
+
// swallow the ?_rsc cache-bust param into the fragment) and for
|
|
626
|
+
// history-stack/prefetch keys (popstate lookups use pathname + search).
|
|
627
|
+
const hashIndex = url.indexOf('#');
|
|
628
|
+
const hash = hashIndex === -1 ? '' : url.slice(hashIndex);
|
|
629
|
+
const fetchUrl = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
630
|
+
|
|
631
|
+
// Use the pre-intercept departing URL when the Navigation API has already
|
|
632
|
+
// committed the destination (_departingUrl from navigation-api.ts). Otherwise
|
|
633
|
+
// capture it now — getCurrentUrl() is still the departing URL at this point
|
|
634
|
+
// for non-Navigation-API navigations (TIM-1232).
|
|
635
|
+
const departingUrl = options._departingUrl ?? deps.getCurrentUrl();
|
|
328
636
|
|
|
329
637
|
// Capture the departing page's scroll position for scroll={false} preservation.
|
|
330
638
|
const currentScrollY = deps.getScrollY();
|
|
331
639
|
|
|
332
|
-
// Save the departing page's scroll position
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
try {
|
|
340
|
-
const headElements = await renderViaTransition(url, () =>
|
|
341
|
-
performNavigationFetch(url, { replace })
|
|
342
|
-
);
|
|
640
|
+
// Save the departing page's scroll position — use Navigation API entry
|
|
641
|
+
// state when available, otherwise fall back to history.state.
|
|
642
|
+
if (deps.saveNavigationEntryScroll) {
|
|
643
|
+
deps.saveNavigationEntryScroll(currentScrollY);
|
|
644
|
+
} else {
|
|
645
|
+
deps.replaceState({ timber: true, scrollY: currentScrollY }, '', deps.getCurrentUrl());
|
|
646
|
+
}
|
|
343
647
|
|
|
344
|
-
|
|
345
|
-
|
|
648
|
+
let effectiveSkipHistory = skipHistory;
|
|
649
|
+
|
|
650
|
+
await runNavigation(
|
|
651
|
+
url,
|
|
652
|
+
async (navAbort) => {
|
|
653
|
+
// When Navigation API is active, initiate the navigation via
|
|
654
|
+
// navigation.navigate() BEFORE the fetch. Must happen after
|
|
655
|
+
// createNavAbort supersedes the previous navigation (done by
|
|
656
|
+
// runNavigation) so the old deferred is resolved first.
|
|
657
|
+
if (!effectiveSkipHistory && deps.navigationNavigate) {
|
|
658
|
+
deps.setRouterNavigating?.(true);
|
|
659
|
+
deps.navigationNavigate(url, replace);
|
|
660
|
+
deps.setRouterNavigating?.(false);
|
|
661
|
+
effectiveSkipHistory = true;
|
|
662
|
+
}
|
|
346
663
|
|
|
347
|
-
|
|
348
|
-
|
|
664
|
+
try {
|
|
665
|
+
await renderViaTransition(fetchUrl, () =>
|
|
666
|
+
performNavigationFetch(fetchUrl, {
|
|
667
|
+
replace,
|
|
668
|
+
commitUrl: url,
|
|
669
|
+
signal: navAbort.signal,
|
|
670
|
+
skipHistory: effectiveSkipHistory,
|
|
671
|
+
departingUrl,
|
|
672
|
+
})
|
|
673
|
+
);
|
|
349
674
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
675
|
+
// Notify nuqs adapter (and any other listeners) that navigation completed.
|
|
676
|
+
window.dispatchEvent(new Event('timber:navigation-end'));
|
|
677
|
+
|
|
678
|
+
// Scroll-to-top on forward navigation, scroll to the #fragment target
|
|
679
|
+
// when the URL has one, or restore captured position for scroll={false}.
|
|
680
|
+
if (scroll && hash) {
|
|
681
|
+
scrollToHashAfterPaint(hash);
|
|
682
|
+
} else {
|
|
683
|
+
restoreScrollAfterPaint(scroll ? 0 : currentScrollY);
|
|
684
|
+
}
|
|
685
|
+
} catch (error) {
|
|
686
|
+
if (error instanceof VersionSkewError) {
|
|
687
|
+
setHardNavigating(true);
|
|
688
|
+
window.location.reload();
|
|
689
|
+
await new Promise(() => {});
|
|
690
|
+
}
|
|
691
|
+
if (error instanceof RedirectError) {
|
|
692
|
+
if (currentNavAbort !== navAbort) return;
|
|
693
|
+
await navigate(error.redirectUrl, { replace: true });
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (error instanceof ServerErrorResponse) {
|
|
697
|
+
setHardNavigating(true);
|
|
698
|
+
window.location.href = error.url;
|
|
699
|
+
await new Promise(() => {});
|
|
700
|
+
}
|
|
701
|
+
if (error instanceof NonRscResponse) {
|
|
702
|
+
setHardNavigating(true);
|
|
703
|
+
// Use the original `url` (with #fragment), not error.url which
|
|
704
|
+
// is hash-stripped. Preserves fragment on hard navigation (e.g.,
|
|
705
|
+
// /manual.pdf#page=5). Matches no-JS <a> behavior.
|
|
706
|
+
window.location.href = url;
|
|
707
|
+
await new Promise(() => {});
|
|
708
|
+
}
|
|
709
|
+
throw error;
|
|
358
710
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
// Server-side redirect during RSC fetch → soft router navigation.
|
|
363
|
-
if (error instanceof RedirectError) {
|
|
364
|
-
setPending(false);
|
|
365
|
-
await navigate(error.redirectUrl, { replace: true });
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
// Abort errors are not application errors — swallow silently.
|
|
369
|
-
if (isAbortError(error)) return;
|
|
370
|
-
throw error;
|
|
371
|
-
} finally {
|
|
372
|
-
setPending(false);
|
|
373
|
-
}
|
|
711
|
+
},
|
|
712
|
+
externalSignal
|
|
713
|
+
);
|
|
374
714
|
}
|
|
375
715
|
|
|
376
716
|
async function refresh(): Promise<void> {
|
|
377
717
|
const currentUrl = deps.getCurrentUrl();
|
|
378
718
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
try {
|
|
382
|
-
const headElements = await renderViaTransition(currentUrl, async () => {
|
|
719
|
+
await runNavigation(currentUrl, async (navAbort) => {
|
|
720
|
+
await renderViaTransition(currentUrl, async () => {
|
|
383
721
|
// No state tree sent — server renders the complete RSC payload
|
|
384
|
-
const result = await fetchRscPayload(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
722
|
+
const result = await fetchRscPayload(
|
|
723
|
+
currentUrl,
|
|
724
|
+
deps,
|
|
725
|
+
undefined,
|
|
726
|
+
undefined,
|
|
727
|
+
navAbort.signal
|
|
728
|
+
);
|
|
729
|
+
const payload = await resolveForFallback(result.payload);
|
|
730
|
+
const navState = commitNavigation(currentUrl, {
|
|
731
|
+
payload,
|
|
732
|
+
params: result.params,
|
|
733
|
+
segmentInfo: result.segmentInfo,
|
|
734
|
+
});
|
|
735
|
+
return { ...result, payload, navState };
|
|
389
736
|
});
|
|
390
|
-
|
|
391
|
-
applyHead(headElements);
|
|
392
|
-
} finally {
|
|
393
|
-
setPending(false);
|
|
394
|
-
}
|
|
737
|
+
});
|
|
395
738
|
}
|
|
396
739
|
|
|
397
|
-
async function handlePopState(
|
|
740
|
+
async function handlePopState(
|
|
741
|
+
url: string,
|
|
742
|
+
scrollY: number = 0,
|
|
743
|
+
externalSignal?: AbortSignal
|
|
744
|
+
): Promise<void> {
|
|
398
745
|
// Scroll position is read from history.state by the caller (browser-entry.ts)
|
|
399
746
|
// and passed in. This is more reliable than tracking scroll per-URL in memory
|
|
400
747
|
// because the browser maintains per-entry state even with duplicate URLs.
|
|
401
748
|
const entry = historyStack.get(url);
|
|
402
749
|
|
|
403
750
|
if (entry && entry.payload !== null) {
|
|
404
|
-
// Replay cached payload — no server roundtrip
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
751
|
+
// Replay cached payload — no server roundtrip.
|
|
752
|
+
//
|
|
753
|
+
// runNavigation supersedes any in-flight forward navigation (TIM-1022):
|
|
754
|
+
// aborts its fetch and invalidates its render transition so the stale
|
|
755
|
+
// forward payload can't commit over this replay. The replay itself is
|
|
756
|
+
// synchronous — the fn resolves immediately.
|
|
757
|
+
await runNavigation(
|
|
758
|
+
url,
|
|
759
|
+
async () => {
|
|
760
|
+
// clearSegmentCacheOnEmpty: popstate to an entry without layout
|
|
761
|
+
// metadata (e.g., initial SSR page) clears the cache so the next
|
|
762
|
+
// forward navigation gets a full render.
|
|
763
|
+
const navState = commitNavigation(url, {
|
|
764
|
+
payload: entry.payload,
|
|
765
|
+
params: entry.params,
|
|
766
|
+
segmentInfo: entry.segmentInfo,
|
|
767
|
+
clearSegmentCacheOnEmpty: true,
|
|
768
|
+
});
|
|
769
|
+
renderPayload(entry.payload, navState);
|
|
770
|
+
restoreScrollAfterPaint(scrollY);
|
|
771
|
+
},
|
|
772
|
+
externalSignal
|
|
773
|
+
);
|
|
412
774
|
} else {
|
|
413
775
|
// No cached payload — fetch from server.
|
|
414
776
|
// This happens when navigating back to the initial SSR'd page
|
|
415
777
|
// (its payload is null since it was rendered via SSR, not RSC fetch)
|
|
416
778
|
// or when the entry doesn't exist at all.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
779
|
+
await runNavigation(
|
|
780
|
+
url,
|
|
781
|
+
async (navAbort) => {
|
|
782
|
+
await renderViaTransition(url, async () => {
|
|
783
|
+
const stateTree = deps.clientSegmentCache
|
|
784
|
+
? segmentCache.serializeStateTree()
|
|
785
|
+
: undefined;
|
|
786
|
+
const result = await fetchRscPayload(url, deps, stateTree, undefined, navAbort.signal);
|
|
787
|
+
const payload = await resolveForFallback(result.payload);
|
|
788
|
+
const navState = commitNavigation(url, {
|
|
789
|
+
payload,
|
|
790
|
+
params: result.params,
|
|
791
|
+
segmentInfo: result.segmentInfo,
|
|
792
|
+
});
|
|
793
|
+
return { ...result, payload, navState };
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
restoreScrollAfterPaint(scrollY);
|
|
797
|
+
},
|
|
798
|
+
externalSignal
|
|
799
|
+
);
|
|
438
800
|
}
|
|
439
801
|
}
|
|
440
802
|
|
|
@@ -443,17 +805,27 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
443
805
|
* Called on hover of <Link prefetch> elements.
|
|
444
806
|
*/
|
|
445
807
|
function prefetch(url: string): void {
|
|
808
|
+
// Strip fragment — it's client-only and would swallow the _rsc cache-bust
|
|
809
|
+
// param into the hash. The hash-less key also matches navigate()'s fetchUrl.
|
|
810
|
+
const hashIndex = url.indexOf('#');
|
|
811
|
+
const fetchUrl = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
812
|
+
|
|
446
813
|
// Don't prefetch if already cached
|
|
447
|
-
if (prefetchCache.get(
|
|
448
|
-
if (historyStack.has(
|
|
814
|
+
if (prefetchCache.get(fetchUrl) !== undefined) return;
|
|
815
|
+
if (historyStack.has(fetchUrl)) return;
|
|
449
816
|
|
|
450
817
|
// Fire-and-forget fetch
|
|
451
|
-
const stateTree = segmentCache.serializeStateTree(
|
|
452
|
-
void fetchRscPayload(
|
|
818
|
+
const stateTree = deps.clientSegmentCache ? segmentCache.serializeStateTree() : undefined;
|
|
819
|
+
void fetchRscPayload(fetchUrl, deps, stateTree).then(
|
|
453
820
|
(result) => {
|
|
454
|
-
|
|
821
|
+
result.decodePromise?.catch(() => {});
|
|
822
|
+
prefetchCache.set(fetchUrl, result);
|
|
455
823
|
},
|
|
456
|
-
() => {
|
|
824
|
+
(error) => {
|
|
825
|
+
if (error instanceof NonRscResponse) {
|
|
826
|
+
prefetchCache.setNegative(fetchUrl);
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
457
829
|
// Prefetch failure is non-fatal — navigation will fetch fresh
|
|
458
830
|
}
|
|
459
831
|
);
|
|
@@ -463,29 +835,31 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
463
835
|
navigate,
|
|
464
836
|
refresh,
|
|
465
837
|
handlePopState,
|
|
466
|
-
isPending: () =>
|
|
467
|
-
getPendingUrl: () =>
|
|
838
|
+
isPending: () => routerPhase.phase === 'navigating',
|
|
839
|
+
getPendingUrl: () => (routerPhase.phase === 'navigating' ? routerPhase.targetUrl : null),
|
|
468
840
|
onPendingChange(listener) {
|
|
469
841
|
pendingListeners.add(listener);
|
|
470
842
|
return () => pendingListeners.delete(listener);
|
|
471
843
|
},
|
|
472
844
|
prefetch,
|
|
473
|
-
applyRevalidation(element: unknown
|
|
845
|
+
applyRevalidation(element: unknown): void {
|
|
474
846
|
// Render the piggybacked element tree from a server action response.
|
|
475
|
-
// Updates the current history entry with the fresh payload
|
|
476
|
-
//
|
|
477
|
-
// Cache segment elements for future partial merges.
|
|
847
|
+
// Updates the current history entry with the fresh payload —
|
|
848
|
+
// same as refresh() but without a server fetch.
|
|
478
849
|
const currentUrl = deps.getCurrentUrl();
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
850
|
+
|
|
851
|
+
// Preserve existing segmentInfo so away-and-back navigation replays
|
|
852
|
+
// with a correct segment cache (TIM-1037). Preserve current params
|
|
853
|
+
// so dynamic route params aren't cleared to {}.
|
|
854
|
+
const existingEntry = historyStack.get(currentUrl);
|
|
855
|
+
const navState = commitNavigation(currentUrl, {
|
|
856
|
+
payload: element,
|
|
857
|
+
params: getNavigationState().params,
|
|
858
|
+
segmentInfo: existingEntry?.segmentInfo,
|
|
483
859
|
});
|
|
484
|
-
renderPayload(
|
|
485
|
-
applyHead(headElements);
|
|
860
|
+
renderPayload(element, navState);
|
|
486
861
|
},
|
|
487
862
|
initSegmentCache: (segments: SegmentInfo[]) => updateSegmentCache(segments),
|
|
488
|
-
cacheElementTree: (element: unknown) => cacheSegmentElements(element, segmentElementCache),
|
|
489
863
|
segmentCache,
|
|
490
864
|
prefetchCache,
|
|
491
865
|
historyStack,
|