@timber-js/app 0.2.0-alpha.185 → 0.2.0-alpha.187
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/dist/_chunks/{actions-O_LsyCE4.js → actions-35jnMdeJ.js} +4 -3
- package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-35jnMdeJ.js.map} +1 -1
- package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
- package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
- package/dist/_chunks/base-path-DaQrzbez.js +80 -0
- package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/build-output-helper-C3DrfzZR.js +369 -0
- package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +1 -0
- package/dist/_chunks/{cache-api-B-lhk9p4.js → cache-api-DjNrIWRR.js} +8 -14
- package/dist/_chunks/cache-api-DjNrIWRR.js.map +1 -0
- package/dist/_chunks/cli-check-CpmN7Nh-.js +256 -0
- package/dist/_chunks/cli-check-CpmN7Nh-.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-CGMp_Psg.js +298 -0
- package/dist/_chunks/cli-schema-sync-CGMp_Psg.js.map +1 -0
- package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-CGP6BZKO.js} +92 -14
- package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-CGP6BZKO.js.map} +1 -1
- package/dist/_chunks/convention-lint-kXsgc_-7.js +784 -0
- package/dist/_chunks/convention-lint-kXsgc_-7.js.map +1 -0
- package/dist/_chunks/error-boundary-D-ODYX41.js +353 -0
- package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -0
- package/dist/_chunks/{fast-hash-D6hIVt1Y.js → fast-hash-C-tVYrLb.js} +6 -1
- package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
- package/dist/_chunks/file-cache-DmX7OqZP.js +454 -0
- package/dist/_chunks/file-cache-DmX7OqZP.js.map +1 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
- package/dist/_chunks/{logger-AWfuX-KJ.js → logger-D8xJZXIN.js} +34 -51
- package/dist/_chunks/logger-D8xJZXIN.js.map +1 -0
- package/dist/_chunks/mdx-file-C005ay-P.js +25 -0
- package/dist/_chunks/mdx-file-C005ay-P.js.map +1 -0
- package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-rCinWLiE.js} +8 -2
- package/dist/_chunks/plugin-context-rCinWLiE.js.map +1 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
- package/dist/_chunks/{resolve-schema-Dz3fcFUo.js → resolve-schema-5ma5pp1b.js} +2 -2
- package/dist/_chunks/{resolve-schema-Dz3fcFUo.js.map → resolve-schema-5ma5pp1b.js.map} +1 -1
- package/dist/_chunks/{router-ref-CtmF-aPv.js → router-ref-DuYuV_0Q.js} +2 -2
- package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -0
- package/dist/_chunks/rsc-cache-key-DD0fl_-s.js +243 -0
- package/dist/_chunks/rsc-cache-key-DD0fl_-s.js.map +1 -0
- package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js +40 -0
- package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js.map +1 -0
- package/dist/_chunks/rsc-media-type-DRqE_lD_.js +46 -0
- package/dist/_chunks/rsc-media-type-DRqE_lD_.js.map +1 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
- package/dist/_chunks/scanner-C8b0Gcw3.js +1564 -0
- package/dist/_chunks/scanner-C8b0Gcw3.js.map +1 -0
- package/dist/_chunks/schema-bridge-Cc2Gngu1.js +199 -0
- package/dist/_chunks/schema-bridge-Cc2Gngu1.js.map +1 -0
- package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
- package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
- package/dist/_chunks/segment-context-CjOlyB8Y.js +97 -0
- package/dist/_chunks/segment-context-CjOlyB8Y.js.map +1 -0
- package/dist/_chunks/{canonicalize-DQHyFClh.js → segment-keys-BawYuNFO.js} +61 -2
- package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -0
- package/dist/_chunks/slot-params-BCTmZkQB.js +76 -0
- package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -0
- package/dist/_chunks/{ssr-data-BOWsq18U.js → ssr-data-14MXm7Pj.js} +17 -2
- package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -0
- package/dist/_chunks/{use-query-states-DFvWd-EA.js → use-query-states-BbU5Ge1V.js} +74 -26
- package/dist/_chunks/use-query-states-BbU5Ge1V.js.map +1 -0
- package/dist/_chunks/use-segment-params-C4r4BD9T.js +398 -0
- package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -0
- package/dist/_chunks/walkers-RzN6AFjr.js +141 -0
- package/dist/_chunks/walkers-RzN6AFjr.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +37 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -1
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +1 -1
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +1 -1
- package/dist/adapters/compress-module.d.ts +12 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +64 -0
- package/dist/adapters/fs-identity.d.ts.map +1 -0
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +56 -5
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +57 -1
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +13 -1
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/fast-hash.d.ts +5 -0
- package/dist/cache/fast-hash.d.ts.map +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cdn/cloudflare-purge.js +30 -0
- package/dist/cdn/cloudflare-purge.js.map +1 -0
- package/dist/cdn/fastly-purge.js +33 -0
- package/dist/cdn/fastly-purge.js.map +1 -0
- package/dist/cdn/index.js +94 -0
- package/dist/cdn/index.js.map +1 -0
- package/dist/cdn/workers-cache-purge.js +35 -0
- package/dist/cdn/workers-cache-purge.js.map +1 -0
- package/dist/cli-check.d.ts +153 -0
- package/dist/cli-check.d.ts.map +1 -0
- package/dist/cli.d.ts +34 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +46 -21
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/hydrate.d.ts +20 -9
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
- package/dist/client/browser-entry/index.d.ts +1 -1
- package/dist/client/browser-entry/index.d.ts.map +1 -1
- package/dist/client/browser-entry/post-hydration.d.ts +4 -1
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts +3 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/browser-entry/rsc-stream.d.ts +8 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +7 -0
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -162
- package/dist/client/history.d.ts +13 -6
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +42 -41
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +4 -3
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +877 -311
- package/dist/client/internal.js.map +1 -1
- package/dist/client/link.d.ts +1 -7
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-api.d.ts +2 -2
- package/dist/client/navigation-commit.d.ts +87 -0
- package/dist/client/navigation-commit.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +37 -20
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +63 -23
- package/dist/client/navigation-root.d.ts.map +1 -1
- package/dist/client/params-context.d.ts +81 -0
- package/dist/client/params-context.d.ts.map +1 -0
- package/dist/client/router-effects.d.ts +129 -0
- package/dist/client/router-effects.d.ts.map +1 -0
- package/dist/client/router-lifecycle.d.ts +55 -0
- package/dist/client/router-lifecycle.d.ts.map +1 -0
- package/dist/client/router-pipeline.d.ts +84 -0
- package/dist/client/router-pipeline.d.ts.map +1 -0
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/router-ref.d.ts.map +1 -1
- package/dist/client/router-skew.d.ts +21 -0
- package/dist/client/router-skew.d.ts.map +1 -0
- package/dist/client/router-types.d.ts +207 -0
- package/dist/client/router-types.d.ts.map +1 -0
- package/dist/client/router.d.ts +1 -182
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +47 -26
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +87 -34
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/ssr-data.d.ts +6 -0
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-client.d.ts +69 -0
- package/dist/client/stale-client.d.ts.map +1 -0
- package/dist/client/state.d.ts +10 -1
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +2 -1
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/unload-guard.d.ts +5 -0
- package/dist/client/unload-guard.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts +9 -3
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/client/use-segment-params.d.ts +18 -8
- package/dist/client/use-segment-params.d.ts.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +5 -5
- package/dist/cookies/index.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1009 -759
- package/dist/index.js.map +1 -1
- package/dist/params/index.js +1 -1
- package/dist/plugin-context.d.ts +46 -0
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/request-dep/analysis.d.ts +106 -0
- package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
- package/dist/plugins/request-dep/index.d.ts +75 -0
- package/dist/plugins/request-dep/index.d.ts.map +1 -0
- package/dist/plugins/request-dep/origin.d.ts +61 -0
- package/dist/plugins/request-dep/origin.d.ts.map +1 -0
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +160 -8
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +3 -44
- package/dist/routing/codegen-shared.d.ts.map +1 -1
- package/dist/routing/codegen-types.d.ts +28 -31
- package/dist/routing/codegen-types.d.ts.map +1 -1
- package/dist/routing/codegen-write.d.ts +51 -0
- package/dist/routing/codegen-write.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/collision-probe.d.ts +104 -0
- package/dist/routing/collision-probe.d.ts.map +1 -0
- package/dist/routing/collision-spaces.d.ts +26 -0
- package/dist/routing/collision-spaces.d.ts.map +1 -0
- package/dist/routing/convention-lint.d.ts +18 -4
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/export-detect.d.ts +16 -0
- package/dist/routing/export-detect.d.ts.map +1 -1
- package/dist/routing/index.js +4 -3
- package/dist/routing/interception.d.ts +235 -6
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +19 -4
- package/dist/routing/link-codegen.d.ts.map +1 -1
- package/dist/routing/manifest-codegen.d.ts +1 -7
- package/dist/routing/manifest-codegen.d.ts.map +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +33 -0
- package/dist/routing/segment-classify.d.ts.map +1 -1
- package/dist/routing/segment-keys.d.ts +95 -0
- package/dist/routing/segment-keys.d.ts.map +1 -0
- package/dist/routing/slot-placement.d.ts +48 -0
- package/dist/routing/slot-placement.d.ts.map +1 -0
- package/dist/routing/types.d.ts +0 -6
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +6 -0
- package/dist/routing/walkers.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +60 -9
- package/dist/schema-bridge.d.ts.map +1 -1
- package/dist/search-params/define.d.ts +62 -14
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.d.ts +0 -1
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +221 -10
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/parse-total.d.ts +70 -0
- package/dist/search-params/parse-total.d.ts.map +1 -0
- package/dist/search-params/wrappers.d.ts +26 -3
- package/dist/search-params/wrappers.d.ts.map +1 -1
- package/dist/server/access-gate.d.ts +19 -8
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +6 -3
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +18 -1
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +13 -1
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/chain-url-parts.d.ts +82 -0
- package/dist/server/chain-url-parts.d.ts.map +1 -0
- package/dist/server/children-interception.d.ts +49 -0
- package/dist/server/children-interception.d.ts.map +1 -0
- package/dist/server/compress.d.ts.map +1 -1
- package/dist/server/default-status-page.d.ts +45 -0
- package/dist/server/default-status-page.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +148 -15
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +15 -4
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +85 -15
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/head-response.d.ts +35 -0
- package/dist/server/head-response.d.ts.map +1 -0
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +3 -1
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +712 -418
- package/dist/server/internal.js.map +1 -1
- package/dist/server/metadata-collector.d.ts +52 -0
- package/dist/server/metadata-collector.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +22 -6
- package/dist/server/param-coercion.d.ts.map +1 -1
- package/dist/server/pipeline-helpers.d.ts +0 -18
- package/dist/server/pipeline-helpers.d.ts.map +1 -1
- package/dist/server/pipeline-interception.d.ts +59 -9
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +11 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +23 -0
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/publish-params.d.ts +33 -0
- package/dist/server/publish-params.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +48 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +22 -3
- 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 +13 -0
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-cache-key-guard.d.ts +78 -0
- package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +15 -3
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +2 -17
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +0 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +1 -2
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +15 -2
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/skippable-prefix.d.ts +23 -0
- package/dist/server/skippable-prefix.d.ts.map +1 -0
- package/dist/server/slot-interception.d.ts +80 -0
- package/dist/server/slot-interception.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +70 -8
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +17 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +0 -1
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +24 -13
- package/dist/server/ssr-wrappers.d.ts.map +1 -1
- package/dist/server/state-tree-diff.d.ts +6 -27
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/static-generator.d.ts +6 -0
- package/dist/server/static-generator.d.ts.map +1 -1
- package/dist/server/static-not-found.d.ts +52 -0
- package/dist/server/static-not-found.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +8 -1
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +28 -36
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +12 -7
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/element-type.d.ts +40 -0
- package/dist/server/utils/element-type.d.ts.map +1 -0
- package/dist/shared/als-slots.d.ts +41 -0
- package/dist/shared/als-slots.d.ts.map +1 -0
- package/dist/shared/base-path.d.ts +56 -0
- package/dist/shared/base-path.d.ts.map +1 -0
- package/dist/shared/param-value.d.ts +80 -0
- package/dist/shared/param-value.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +108 -0
- package/dist/shared/payload-root.d.ts.map +1 -0
- package/dist/shared/rsc-cache-key.d.ts +163 -0
- package/dist/shared/rsc-cache-key.d.ts.map +1 -0
- package/dist/shared/rsc-error-envelope.d.ts +25 -0
- package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
- package/dist/shared/rsc-manifest.d.ts +28 -0
- package/dist/shared/rsc-manifest.d.ts.map +1 -0
- package/dist/shared/rsc-media-type.d.ts +40 -0
- package/dist/shared/rsc-media-type.d.ts.map +1 -0
- package/dist/shared/rsc-payload-path.d.ts +42 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -0
- package/dist/shared/segment-info.d.ts +59 -0
- package/dist/shared/segment-info.d.ts.map +1 -0
- package/dist/shared/slot-params.d.ts +51 -0
- package/dist/shared/slot-params.d.ts.map +1 -0
- package/dist/shared/static-platform-files.d.ts +71 -0
- package/dist/shared/static-platform-files.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +1 -1
- package/docs/api/31-api-client.mdx +4 -2
- package/docs/api/33-api-search-params.mdx +38 -16
- package/docs/api/35-api-typescript.mdx +3 -3
- package/docs/api/36-cli.mdx +34 -7
- package/docs/learn/00-introduction.mdx +1 -1
- package/docs/learn/02-pages-and-layouts.mdx +2 -2
- package/docs/learn/05-typed-params.mdx +8 -8
- package/docs/learn/07-typed-routes.mdx +12 -7
- package/docs/learn/11-error-handling.mdx +18 -0
- package/docs/learn/12-client-navigation.mdx +2 -2
- package/docs/learn/14-deploying.mdx +23 -0
- package/docs/more/01-advanced-routing.mdx +173 -3
- package/docs/more/03-coming-from-nextjs.mdx +2 -2
- package/docs/more/04-metadata-and-fonts.mdx +1 -1
- package/docs/more/50-ai-agent-instructions.mdx +6 -4
- package/package.json +9 -6
- package/src/adapters/build-output-helper.ts +116 -3
- package/src/adapters/cloudflare.ts +90 -12
- package/src/adapters/compress-module.ts +79 -1
- package/src/adapters/fs-identity.ts +156 -0
- package/src/adapters/nitro.ts +6 -6
- package/src/adapters/shared.ts +196 -21
- package/src/adapters/types.ts +13 -1
- package/src/cache/fast-hash.ts +5 -0
- package/src/cli-check.ts +458 -0
- package/src/cli.ts +59 -24
- package/src/client/browser-entry/action-dispatch.ts +11 -5
- package/src/client/browser-entry/hydrate.ts +40 -29
- package/src/client/browser-entry/index.ts +15 -6
- package/src/client/browser-entry/post-hydration.ts +10 -9
- package/src/client/browser-entry/router-init.ts +104 -48
- package/src/client/browser-entry/rsc-stream.ts +11 -2
- package/src/client/error-boundary.tsx +85 -16
- package/src/client/history.ts +13 -6
- package/src/client/index.ts +14 -3
- package/src/client/internal.ts +4 -3
- package/src/client/link.tsx +120 -72
- package/src/client/navigation-api.ts +3 -3
- package/src/client/navigation-commit.ts +197 -0
- package/src/client/navigation-context.ts +40 -67
- package/src/client/navigation-root.tsx +326 -101
- package/src/client/params-context.ts +192 -0
- package/src/client/router-effects.ts +231 -0
- package/src/client/router-lifecycle.ts +288 -0
- package/src/client/router-pipeline.ts +393 -0
- package/src/client/router-ref.ts +1 -1
- package/src/client/router-skew.ts +30 -0
- package/src/client/router-types.ts +230 -0
- package/src/client/router.ts +243 -707
- package/src/client/rsc-fetch.ts +183 -106
- package/src/client/segment-cache.ts +129 -44
- package/src/client/ssr-data.ts +6 -0
- package/src/client/stale-client.ts +191 -0
- package/src/client/state.ts +14 -1
- package/src/client/top-loader.tsx +2 -1
- package/src/client/unload-guard.ts +34 -2
- package/src/client/use-cookie.ts +9 -2
- package/src/client/use-query-states.ts +102 -39
- package/src/client/use-router.ts +1 -1
- package/src/client/use-segment-params.ts +41 -18
- package/src/cookies/define-cookie.ts +6 -1
- package/src/index.ts +25 -4
- package/src/plugin-context.ts +58 -0
- package/src/plugins/adapter-build.ts +4 -0
- package/src/plugins/build-manifest.ts +34 -13
- package/src/plugins/entries.ts +4 -0
- package/src/plugins/fonts.ts +11 -8
- package/src/plugins/request-dep/analysis.ts +447 -0
- package/src/plugins/request-dep/index.ts +376 -0
- package/src/plugins/request-dep/origin.ts +310 -0
- package/src/plugins/routing.ts +97 -102
- package/src/plugins/shims.ts +0 -1
- package/src/plugins/static-build.ts +391 -95
- package/src/routing/codegen-shared.ts +3 -79
- package/src/routing/codegen-types.ts +28 -31
- package/src/routing/codegen-write.ts +139 -0
- package/src/routing/codegen.ts +86 -172
- package/src/routing/collision-probe.ts +438 -0
- package/src/routing/collision-spaces.ts +281 -0
- package/src/routing/convention-lint.ts +139 -40
- package/src/routing/export-detect.ts +151 -7
- package/src/routing/interception.ts +896 -50
- package/src/routing/link-codegen.ts +32 -65
- package/src/routing/manifest-codegen.ts +6 -62
- package/src/routing/scanner.ts +117 -92
- package/src/routing/segment-classify.ts +57 -0
- package/src/routing/segment-keys.ts +146 -0
- package/src/routing/slot-placement.ts +97 -0
- package/src/routing/types.ts +0 -6
- package/src/routing/walkers.ts +8 -0
- package/src/schema-bridge.ts +180 -58
- package/src/search-params/define.ts +108 -66
- package/src/search-params/index.ts +0 -1
- package/src/search-params/parse-total.ts +78 -0
- package/src/search-params/wrappers.ts +60 -11
- package/src/server/access-gate.tsx +60 -40
- package/src/server/action-handler.ts +4 -5
- package/src/server/actions.ts +6 -3
- package/src/server/als-registry.ts +18 -1
- package/src/server/build-manifest.ts +14 -1
- package/src/server/chain-url-parts.ts +163 -0
- package/src/server/children-interception.ts +115 -0
- package/src/server/compress.ts +9 -1
- package/src/server/default-status-page.ts +127 -0
- package/src/server/deny-boundary.ts +269 -41
- package/src/server/deny-renderer.ts +111 -39
- package/src/server/error-boundary-wrapper.ts +166 -79
- package/src/server/head-response.ts +54 -0
- package/src/server/index.ts +1 -3
- package/src/server/internal.ts +2 -2
- package/src/server/metadata-collector.ts +115 -0
- package/src/server/param-coercion.ts +51 -69
- package/src/server/pipeline-helpers.ts +2 -47
- package/src/server/pipeline-interception.ts +81 -32
- package/src/server/pipeline-outcome.ts +4 -5
- package/src/server/pipeline-phases.ts +77 -25
- package/src/server/pipeline.ts +57 -10
- package/src/server/prebuilt-runtime.ts +4 -4
- package/src/server/primitives.ts +25 -0
- package/src/server/publish-params.ts +42 -0
- package/src/server/request-context.ts +97 -18
- package/src/server/route-element-builder.ts +241 -253
- package/src/server/route-handler.ts +8 -8
- package/src/server/route-matcher.ts +21 -9
- package/src/server/rsc-cache-key-guard.ts +164 -0
- package/src/server/rsc-entry/api-handler.ts +6 -8
- package/src/server/rsc-entry/deny-fallback.ts +3 -2
- package/src/server/rsc-entry/error-renderer.ts +94 -35
- package/src/server/rsc-entry/helpers.ts +33 -28
- package/src/server/rsc-entry/index.ts +36 -33
- package/src/server/rsc-entry/render-route.ts +18 -10
- package/src/server/rsc-entry/revalidate-renderer.ts +3 -2
- package/src/server/rsc-entry/rsc-payload.ts +113 -40
- package/src/server/rsc-entry/rsc-stream.ts +29 -5
- package/src/server/rsc-entry/ssr-renderer.ts +38 -22
- package/src/server/skippable-prefix.ts +92 -0
- package/src/server/slot-interception.ts +168 -0
- package/src/server/slot-resolver.ts +263 -158
- package/src/server/ssr-bridge-types.ts +18 -0
- package/src/server/ssr-entry.ts +20 -10
- package/src/server/ssr-wrappers.tsx +33 -32
- package/src/server/state-tree-diff.ts +14 -55
- package/src/server/static-generator.ts +68 -29
- package/src/server/static-not-found.ts +134 -0
- package/src/server/status-code-resolver.ts +28 -11
- package/src/server/tree-builder.ts +35 -218
- package/src/server/types.ts +12 -7
- package/src/server/utils/element-type.ts +72 -0
- package/src/shared/als-slots.ts +72 -0
- package/src/shared/base-path.ts +80 -0
- package/src/shared/param-value.ts +244 -0
- package/src/shared/payload-root.ts +151 -0
- package/src/shared/rsc-cache-key.ts +269 -0
- package/src/shared/rsc-error-envelope.ts +31 -0
- package/src/shared/rsc-manifest.ts +29 -0
- package/src/shared/rsc-media-type.ts +43 -0
- package/src/shared/rsc-payload-path.ts +45 -0
- package/src/shared/segment-info.ts +60 -0
- package/src/shared/slot-params.ts +111 -0
- package/src/shared/static-platform-files.ts +75 -0
- package/dist/_chunks/build-output-helper-DOGYFb_X.js +0 -196
- package/dist/_chunks/build-output-helper-DOGYFb_X.js.map +0 -1
- package/dist/_chunks/cache-api-B-lhk9p4.js.map +0 -1
- package/dist/_chunks/canonicalize-DQHyFClh.js.map +0 -1
- package/dist/_chunks/cli-schema-sync-BTWEKJXo.js +0 -668
- package/dist/_chunks/cli-schema-sync-BTWEKJXo.js.map +0 -1
- package/dist/_chunks/define-COtkxMRT.js +0 -191
- package/dist/_chunks/define-COtkxMRT.js.map +0 -1
- package/dist/_chunks/define-c4au4I9R.js +0 -82
- package/dist/_chunks/define-c4au4I9R.js.map +0 -1
- package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +0 -1
- package/dist/_chunks/logger-AWfuX-KJ.js.map +0 -1
- package/dist/_chunks/navigation-root-bUDZLw74.js +0 -124
- package/dist/_chunks/navigation-root-bUDZLw74.js.map +0 -1
- package/dist/_chunks/plugin-context---kTF5v8.js.map +0 -1
- package/dist/_chunks/registry-DbJPKoBp.js +0 -20
- package/dist/_chunks/registry-DbJPKoBp.js.map +0 -1
- package/dist/_chunks/router-ref-CtmF-aPv.js.map +0 -1
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +0 -119
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +0 -1
- package/dist/_chunks/segment-classify-Byy425ng.js.map +0 -1
- package/dist/_chunks/segment-context-ZDnXDkbz.js +0 -34
- package/dist/_chunks/segment-context-ZDnXDkbz.js.map +0 -1
- package/dist/_chunks/ssr-data-BOWsq18U.js.map +0 -1
- package/dist/_chunks/use-query-states-DFvWd-EA.js.map +0 -1
- package/dist/_chunks/use-segment-params-D1CzlgBo.js +0 -151
- package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +0 -1
- package/dist/_chunks/walkers-_6zKFlch.js +0 -1002
- package/dist/_chunks/walkers-_6zKFlch.js.map +0 -1
- package/dist/client/error-boundary.js.map +0 -1
- package/dist/plugins/request-dep.d.ts +0 -32
- package/dist/plugins/request-dep.d.ts.map +0 -1
- package/dist/search-params/registry.d.ts +0 -20
- package/dist/search-params/registry.d.ts.map +0 -1
- package/dist/segment-params/define.d.ts +0 -89
- package/dist/segment-params/define.d.ts.map +0 -1
- package/dist/segment-params/index.d.ts +0 -3
- package/dist/segment-params/index.d.ts.map +0 -1
- package/dist/segment-params/index.js +0 -2
- package/src/plugins/request-dep.ts +0 -499
- package/src/search-params/registry.ts +0 -31
- package/src/segment-params/define.ts +0 -249
- package/src/segment-params/index.ts +0 -9
package/src/client/index.ts
CHANGED
|
@@ -75,11 +75,22 @@ export { useSelectedLayoutSegment, useSelectedLayoutSegments } from './use-selec
|
|
|
75
75
|
export { useActionState, useFormAction } from './form';
|
|
76
76
|
export type { UseActionStateFn, UseActionStateReturn, FormErrorsResult } from './form';
|
|
77
77
|
|
|
78
|
-
// Params
|
|
78
|
+
// Params. Called with no argument this returns the untyped accumulated params;
|
|
79
|
+
// pass the route's SEGMENT_PATH (from its generated `./$segment` module) to get
|
|
80
|
+
// the exact types `app/schema.ts` declares — `useSegmentParams(SEGMENT_PATH)`.
|
|
79
81
|
export { useSegmentParams } from './use-segment-params';
|
|
80
82
|
|
|
81
|
-
// Query states
|
|
82
|
-
//
|
|
83
|
+
// Query states. `definition.useQueryStates()` is the usual form; this standalone
|
|
84
|
+
// export is the inline codec-map form, for shared param bundles reused across
|
|
85
|
+
// routes (design/23-search-params.md §"Client Access").
|
|
86
|
+
//
|
|
87
|
+
// Until TIM-1341 this export did not exist, yet four doc sites told users to
|
|
88
|
+
// import it from here. It type-checked only because the generated `.d.ts`
|
|
89
|
+
// augmented this module with a `useQueryStates` overload — so TypeScript
|
|
90
|
+
// believed in a binding that was never emitted, and the documented import
|
|
91
|
+
// failed at build time. Deleting that overload removed the lie; exporting the
|
|
92
|
+
// hook makes the docs true.
|
|
93
|
+
export { useQueryStates } from './use-query-states';
|
|
83
94
|
|
|
84
95
|
// Cookies — useCookie lives on defineCookie().useCookie().
|
|
85
96
|
// Types still exported for advanced use.
|
package/src/client/internal.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type {
|
|
|
19
19
|
RouterPhase,
|
|
20
20
|
RscDecoder,
|
|
21
21
|
RootRenderer,
|
|
22
|
-
} from './router.js';
|
|
22
|
+
} from './router-types.js';
|
|
23
23
|
export { getRouter, getRouterOrNull, setGlobalRouter } from './router-ref.js';
|
|
24
24
|
|
|
25
25
|
// ── SSR bridge ───────────────────────────────────────────────────────────
|
|
@@ -32,14 +32,15 @@ export type { SegmentContextValue } from './segment-context.js';
|
|
|
32
32
|
|
|
33
33
|
// ── Segment cache ────────────────────────────────────────────────────────
|
|
34
34
|
export { SegmentCache, PrefetchCache } from './segment-cache.js';
|
|
35
|
-
export type { SegmentNode,
|
|
35
|
+
export type { SegmentNode, PrefetchKey } from './segment-cache.js';
|
|
36
|
+
export type { SegmentInfo, StateTree } from '../shared/segment-info.js';
|
|
36
37
|
|
|
37
38
|
// ── History ──────────────────────────────────────────────────────────────
|
|
38
39
|
export { HistoryStack } from './history.js';
|
|
39
40
|
export type { HistoryEntry } from './history.js';
|
|
40
41
|
|
|
41
42
|
// ── Params (internal setter + raw hooks) ─────────────────────────────────
|
|
42
|
-
export { setCurrentParams } from './use-segment-params.js';
|
|
43
|
+
export { setCurrentParams, setCurrentSlotParams } from './use-segment-params.js';
|
|
43
44
|
export { useSearchParams } from './use-search-params.js';
|
|
44
45
|
|
|
45
46
|
// ── Navigation context ───────────────────────────────────────────────────
|
package/src/client/link.tsx
CHANGED
|
@@ -14,18 +14,18 @@
|
|
|
14
14
|
// Typed Link: design/09-typescript.md §"Typed Link"
|
|
15
15
|
// - href validated against known routes (via codegen overloads, not runtime)
|
|
16
16
|
// - params prop typed per-route, URL interpolated at runtime
|
|
17
|
-
// - searchParams prop
|
|
17
|
+
// - searchParams prop is a query string (from `definition.buildSearchParams()`)
|
|
18
|
+
// or a plain object whose values are String()-coerced
|
|
18
19
|
// - params and fully-resolved string href are mutually exclusive
|
|
19
20
|
// - searchParams and inline query string are mutually exclusive
|
|
20
21
|
|
|
21
22
|
import {
|
|
22
|
-
|
|
23
|
+
useRef,
|
|
24
|
+
useState,
|
|
23
25
|
type AnchorHTMLAttributes,
|
|
24
26
|
type ReactNode,
|
|
25
27
|
type MouseEvent as ReactMouseEvent,
|
|
26
28
|
} from 'react';
|
|
27
|
-
import type { SearchParamsDefinition } from '../search-params/define.js';
|
|
28
|
-
import { getSearchParamsDefinition } from '../search-params/registry.js';
|
|
29
29
|
import type { LinkFunction } from './index.js';
|
|
30
30
|
import { classifyUrlSegment, type UrlSegment } from '../routing/segment-classify.js';
|
|
31
31
|
import {
|
|
@@ -130,26 +130,37 @@ export type LinkSegmentParams<T> = {
|
|
|
130
130
|
|
|
131
131
|
// ─── searchParams prop shapes ────────────────────────────────────
|
|
132
132
|
//
|
|
133
|
-
//
|
|
134
|
-
// searchParams={{ page: 2, q: 'boots' }}
|
|
135
|
-
// The framework looks up the route's SearchParamsDefinition from the
|
|
136
|
-
// search-params registry at runtime (see TIM-830).
|
|
133
|
+
// Two shapes, discriminated at runtime by `typeof === 'string'`:
|
|
137
134
|
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
135
|
+
// 1. Codec-aware (preferred) — a query string built from a definition:
|
|
136
|
+
// searchParams={productParams.buildSearchParams({ page: 2, search: 'boots' })}
|
|
137
|
+
// `buildSearchParams` applies each codec, honours `withUrlKey` aliases,
|
|
138
|
+
// and omits values equal to their default. It is typed `Partial<T>` at
|
|
139
|
+
// the call site, so the definition supplies the type checking.
|
|
142
140
|
//
|
|
143
|
-
//
|
|
141
|
+
// 2. Plain object (escape hatch) — every value is String()-coerced:
|
|
142
|
+
// searchParams={{ ref: 'email' }}
|
|
143
|
+
// No codecs, no aliases. This is for one-off params that have no
|
|
144
|
+
// definition. Passing a *definition's* keys this way is a mistake the
|
|
145
|
+
// types cannot catch: `{ search: 'x' }` emits `?search=x`, where the
|
|
146
|
+
// definition would emit `?q=x`. Prefer (1) whenever a definition exists.
|
|
147
|
+
//
|
|
148
|
+
// Why a STRING and not a URLSearchParams: a Link is routinely rendered by a
|
|
149
|
+
// Server Component, so this prop crosses the RSC Flight boundary before the
|
|
150
|
+
// client Link runs. `URLSearchParams` is iterable, and React serializes any
|
|
151
|
+
// iterable as an array — so the prop arrived as `[['pg','2'], …]`, fell into
|
|
152
|
+
// the plain-object branch, and rendered `?0=pg&0=2`. Strings survive Flight
|
|
153
|
+
// unchanged. (Codex P1 on PR #1021; reproduced against a live dev server.)
|
|
154
|
+
//
|
|
155
|
+
// TIM-1343 removed the third shape — a flat values object resolved against a
|
|
156
|
+
// runtime registry keyed by href. It required scanning a `params.ts`
|
|
157
|
+
// convention file, a generated registry module, and eager imports of every
|
|
158
|
+
// route's definition into all three entries, to save one `.buildSearchParams`
|
|
159
|
+
// call. See design/23-search-params.md §"Link Integration".
|
|
144
160
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
145
161
|
export type ParamValue = string | number | string[] | { toString(): string; [key: string]: any };
|
|
146
162
|
|
|
147
|
-
type
|
|
148
|
-
definition: SearchParamsDefinition<Record<string, unknown>>;
|
|
149
|
-
values: Record<string, unknown>;
|
|
150
|
-
};
|
|
151
|
-
type FlatSearchParamsProp = Record<string, unknown>;
|
|
152
|
-
type LinkSearchParamsProp = WrappedSearchParamsProp | FlatSearchParamsProp;
|
|
163
|
+
type LinkSearchParamsProp = string | Record<string, unknown>;
|
|
153
164
|
|
|
154
165
|
/**
|
|
155
166
|
* Runtime-only loose props used internally by the Link implementation.
|
|
@@ -302,16 +313,35 @@ export function interpolateParams(pattern: string, params: Record<string, ParamV
|
|
|
302
313
|
*
|
|
303
314
|
* Handles:
|
|
304
315
|
* - params interpolation into route patterns
|
|
305
|
-
* - searchParams serialization
|
|
316
|
+
* - searchParams serialization (see the two shapes documented above)
|
|
306
317
|
* - Validation that searchParams and inline query strings are exclusive
|
|
307
318
|
*/
|
|
308
319
|
/**
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
320
|
+
* Tolerate a leading '?'. `buildSearchParams()` never emits one, but callers
|
|
321
|
+
* hand-rolling a query string reasonably might, and silently producing
|
|
322
|
+
* `?%3Fa=b` for it would be a worse failure than accepting both.
|
|
323
|
+
*/
|
|
324
|
+
function stripLeadingQuestionMark(qs: string): string {
|
|
325
|
+
return qs.startsWith('?') ? qs.slice(1) : qs;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Escape-hatch serialization for a plain object: String()-coerce every
|
|
330
|
+
* value, append arrays as repeated keys, skip null/undefined.
|
|
331
|
+
*
|
|
332
|
+
* Deliberately codec-free and alias-free — see the shape docs above.
|
|
312
333
|
*/
|
|
313
|
-
function
|
|
314
|
-
|
|
334
|
+
function coerceToQueryString(values: Record<string, unknown>): string {
|
|
335
|
+
const usp = new URLSearchParams();
|
|
336
|
+
for (const [key, val] of Object.entries(values)) {
|
|
337
|
+
if (val === undefined || val === null) continue;
|
|
338
|
+
if (Array.isArray(val)) {
|
|
339
|
+
for (const item of val) usp.append(key, String(item));
|
|
340
|
+
} else {
|
|
341
|
+
usp.set(key, String(val));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return usp.toString();
|
|
315
345
|
}
|
|
316
346
|
|
|
317
347
|
export function resolveHref(
|
|
@@ -336,46 +366,18 @@ export function resolveHref(
|
|
|
336
366
|
);
|
|
337
367
|
}
|
|
338
368
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// virtual:timber-search-params-registry module generated by the
|
|
352
|
-
// timber-routing Vite plugin.
|
|
353
|
-
definition = getSearchParamsDefinition(href) as
|
|
354
|
-
| SearchParamsDefinition<Record<string, unknown>>
|
|
355
|
-
| undefined;
|
|
356
|
-
values = searchParams;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (definition) {
|
|
360
|
-
const qs = definition.serialize(values);
|
|
361
|
-
if (qs) {
|
|
362
|
-
resolvedPath = `${resolvedPath}?${qs}`;
|
|
363
|
-
}
|
|
364
|
-
} else {
|
|
365
|
-
// No registered definition — serialize flat object as plain query params.
|
|
366
|
-
const usp = new URLSearchParams();
|
|
367
|
-
for (const [key, val] of Object.entries(values)) {
|
|
368
|
-
if (val === undefined || val === null) continue;
|
|
369
|
-
if (Array.isArray(val)) {
|
|
370
|
-
for (const item of val) usp.append(key, String(item));
|
|
371
|
-
} else {
|
|
372
|
-
usp.set(key, String(val));
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
const qs = usp.toString();
|
|
376
|
-
if (qs) {
|
|
377
|
-
resolvedPath = `${resolvedPath}?${qs}`;
|
|
378
|
-
}
|
|
369
|
+
// A string is already a serialized query (from
|
|
370
|
+
// `definition.buildSearchParams()`), so it passes through untouched.
|
|
371
|
+
// `typeof` is the only discriminator that survives the RSC Flight
|
|
372
|
+
// boundary — see the shape docs above for what happened when this was
|
|
373
|
+
// an object test.
|
|
374
|
+
const qs =
|
|
375
|
+
typeof searchParams === 'string'
|
|
376
|
+
? stripLeadingQuestionMark(searchParams)
|
|
377
|
+
: coerceToQueryString(searchParams);
|
|
378
|
+
|
|
379
|
+
if (qs) {
|
|
380
|
+
resolvedPath = `${resolvedPath}?${qs}`;
|
|
379
381
|
}
|
|
380
382
|
}
|
|
381
383
|
|
|
@@ -472,11 +474,38 @@ export const Link: LinkFunction = function LinkImpl(props: any) {
|
|
|
472
474
|
const { href: baseHref } = buildLinkProps({ href, params: segmentParams, searchParams });
|
|
473
475
|
|
|
474
476
|
// ─── Per-link pending state ─────────────────────────────────────────
|
|
475
|
-
//
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
|
|
477
|
+
// Local `useState`, deliberately NOT `useTransition` (TIM-1307).
|
|
478
|
+
//
|
|
479
|
+
// Either shape keeps the re-render local — the state lives on this Link's
|
|
480
|
+
// own fiber, so no sibling link is touched. The difference is what wrapping
|
|
481
|
+
// `router.navigate()` in a transition does to the REST of the app: returning
|
|
482
|
+
// a thenable from `startTransition` hands it to `ReactSharedInternals.S`,
|
|
483
|
+
// which calls react-dom's `entangleAsyncAction`. That opens an action scope
|
|
484
|
+
// whose `currentEntangledLane` collects every transition update scheduled
|
|
485
|
+
// while it is open — including `NavigationRoot`'s `setRendered`, which is a
|
|
486
|
+
// fully synchronous `startTransition` in a different component — and
|
|
487
|
+
// rendering that lane suspends on `currentEntangledActionThenable` until the
|
|
488
|
+
// action settles. `navigateTransition` awaits `decodePromise`, so a Link
|
|
489
|
+
// navigation used to commit only after the whole Flight stream had decoded,
|
|
490
|
+
// while `useRouter().push()` committed as soon as React could render it.
|
|
491
|
+
//
|
|
492
|
+
// Two commit-timing regimes, and the slower one was the dominant path: no
|
|
493
|
+
// streaming reveal, and the TIM-1301 publish (address bar, segment cache,
|
|
494
|
+
// `timber:navigation-end`) waited for full decode. Not opening an action
|
|
495
|
+
// scope is what collapses them into one.
|
|
496
|
+
//
|
|
497
|
+
// `isPending` runs from the click until `router.navigate()` settles, which
|
|
498
|
+
// is after `decodePromise` — the same lifecycle the router's pending store
|
|
499
|
+
// and the TopLoader use.
|
|
500
|
+
//
|
|
501
|
+
// `clickSeq` exists because a superseded navigation RESOLVES rather than
|
|
502
|
+
// rejecting: `runNavigation` swallows AbortErrors. So clicking the same link
|
|
503
|
+
// twice in quick succession settles the first promise while the second is
|
|
504
|
+
// still in flight, and an unguarded clear would report idle mid-navigation.
|
|
505
|
+
// Only the newest click for this link may clear its flag. Written on click
|
|
506
|
+
// and nowhere else, so there is no reset for a settle handler to race.
|
|
507
|
+
const [isPending, setIsPending] = useState(false);
|
|
508
|
+
const clickSeq = useRef(0);
|
|
480
509
|
const linkStatus = isPending ? LINK_PENDING : LINK_IDLE;
|
|
481
510
|
|
|
482
511
|
// Preserve search params from the current URL when requested.
|
|
@@ -544,8 +573,27 @@ export const Link: LinkFunction = function LinkImpl(props: any) {
|
|
|
544
573
|
// from the RSC fetch URL inside the router (TIM-1035).
|
|
545
574
|
const absoluteHref = resolved.pathname + resolved.search + resolved.hash;
|
|
546
575
|
|
|
547
|
-
|
|
548
|
-
|
|
576
|
+
const seq = ++clickSeq.current;
|
|
577
|
+
const settle = () => {
|
|
578
|
+
if (clickSeq.current === seq) setIsPending(false);
|
|
579
|
+
};
|
|
580
|
+
setIsPending(true);
|
|
581
|
+
router.navigate(absoluteHref, { scroll: shouldScroll }).then(settle, (error: unknown) => {
|
|
582
|
+
settle();
|
|
583
|
+
// Rethrow, so a navigation error that the router did not already
|
|
584
|
+
// recover from surfaces as an unhandled rejection — the same
|
|
585
|
+
// regime as `useRouter().push()`'s `void router.navigate(...)`.
|
|
586
|
+
//
|
|
587
|
+
// It used to reach the nearest error boundary instead: React
|
|
588
|
+
// re-throws a rejected async action during render (measured on
|
|
589
|
+
// 19.2.7). That replaced the departing page with the app's error
|
|
590
|
+
// UI, which contradicts what every other failure path here
|
|
591
|
+
// promises — a navigation that fails leaves the user on the page
|
|
592
|
+
// they were already looking at (TIM-1306). Recoverable failures
|
|
593
|
+
// never get here anyway; `runNavigation` swallows AbortErrors and
|
|
594
|
+
// `recoverFromNavigationError` turns a failed fetch into a full
|
|
595
|
+
// document load.
|
|
596
|
+
throw error;
|
|
549
597
|
});
|
|
550
598
|
}
|
|
551
599
|
: userOnClick; // External links — just pass through user's onClick
|
|
@@ -97,8 +97,8 @@ export interface NavigationApiController {
|
|
|
97
97
|
/**
|
|
98
98
|
* Resolve the deferred promise created by setRouterNavigating(true),
|
|
99
99
|
* clearing the browser's native loading state. Call this when the
|
|
100
|
-
* navigation fully completes —
|
|
101
|
-
*
|
|
100
|
+
* navigation fully completes — the same finally block in router.navigate
|
|
101
|
+
* that clears the router's pending store.
|
|
102
102
|
*/
|
|
103
103
|
completeRouterNavigation: () => void;
|
|
104
104
|
|
|
@@ -147,7 +147,7 @@ export function setupNavigationApi(callbacks: NavigationApiCallbacks): Navigatio
|
|
|
147
147
|
// setRouterNavigating(true) is called, resolved by completeRouterNavigation().
|
|
148
148
|
// The navigate event handler intercepts with this promise so the browser's
|
|
149
149
|
// native loading state (tab spinner) stays active until the navigation
|
|
150
|
-
// completes —
|
|
150
|
+
// completes — the same lifecycle the TopLoader is driven by.
|
|
151
151
|
let routerNavDeferred: { promise: Promise<void>; resolve: () => void } | null = null;
|
|
152
152
|
|
|
153
153
|
function handleNavigate(event: NavigateEvent): void {
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What it means for a page to be "current" on the client.
|
|
3
|
+
*
|
|
4
|
+
* One module owns every write that makes a navigation's destination the
|
|
5
|
+
* current page, and the read that describes the current page back to the
|
|
6
|
+
* server. Keeping them together is the point: `X-Timber-State-Tree` is
|
|
7
|
+
* derived from the segment cache, so the thing that publishes and the thing
|
|
8
|
+
* that reports have to agree about when a page becomes current.
|
|
9
|
+
*
|
|
10
|
+
* See design/19-client-navigation.md §"State Update Invariants".
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { buildSegmentTree, type SegmentCache } from './segment-cache.js';
|
|
14
|
+
import type { HistoryStack } from './history.js';
|
|
15
|
+
import type { SegmentInfo, StateTree } from '../shared/segment-info.js';
|
|
16
|
+
import type { ParamsSource } from '../shared/payload-root.js';
|
|
17
|
+
import { setNavigationState, type NavigationState } from './navigation-context.js';
|
|
18
|
+
|
|
19
|
+
/** Everything a commit needs to describe the page it makes current. */
|
|
20
|
+
export interface NavigationCommitInput {
|
|
21
|
+
payload: unknown;
|
|
22
|
+
/** The params that payload published — replayed with it on popstate. */
|
|
23
|
+
params: ParamsSource;
|
|
24
|
+
/**
|
|
25
|
+
* The rendered chain's metadata, or null/undefined when this commit
|
|
26
|
+
* carries none at all — a revalidation payload, or a history entry
|
|
27
|
+
* stored before the channel existed.
|
|
28
|
+
*
|
|
29
|
+
* An empty *array* is a different statement from an absent one: the
|
|
30
|
+
* server rendered a route with no layout-bearing segments (a layoutless
|
|
31
|
+
* app — the missing-root-layout check is a warning, not an error), so
|
|
32
|
+
* the correct tree is the empty one. Collapsing the two left the
|
|
33
|
+
* departing route's tree in place, which `treePaths` then reported as
|
|
34
|
+
* mounted — enough to select an intercepting rewrite whose slot is not
|
|
35
|
+
* on screen (TIM-1282).
|
|
36
|
+
*/
|
|
37
|
+
segmentInfo?: SegmentInfo[] | null;
|
|
38
|
+
/** When true, clear the segment cache if segmentInfo is absent
|
|
39
|
+
* (popstate replay for entries without layout metadata). */
|
|
40
|
+
clearSegmentCacheOnEmpty?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* HTTP status of the response this navigation rendered, when it came from a
|
|
43
|
+
* fetch. Omitted by replays, which re-publish a tree already judged.
|
|
44
|
+
*
|
|
45
|
+
* An error response rendered a status page, and a status page replaces a
|
|
46
|
+
* subtree: the deny page lands at the segment owning the matched file and
|
|
47
|
+
* nothing below it mounts. `segmentInfo` nonetheless describes the whole
|
|
48
|
+
* chain the payload was built against — it must, because the merge point is
|
|
49
|
+
* chosen out of it — so the cache has to be told not to learn from this one.
|
|
50
|
+
*
|
|
51
|
+
* Enforced here rather than at the call sites because there are three of
|
|
52
|
+
* them (`performNavigationFetch`, `refresh()`, and uncached traversal, the
|
|
53
|
+
* last two through `fetchCommitAndRender`) and only one had the check.
|
|
54
|
+
* See TIM-1356.
|
|
55
|
+
*/
|
|
56
|
+
status?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A navigation's destination, split into what a render needs and what a
|
|
61
|
+
* commit publishes.
|
|
62
|
+
*/
|
|
63
|
+
export interface PreparedNavigation {
|
|
64
|
+
/** The state the incoming tree renders with. Pure — safe before winning. */
|
|
65
|
+
navState: NavigationState;
|
|
66
|
+
/** Publishes the destination. Call only once the render has won. */
|
|
67
|
+
commit: () => void;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface NavigationCommitter {
|
|
71
|
+
prepareNavigation(url: string, opts: NavigationCommitInput): PreparedNavigation;
|
|
72
|
+
currentStateTree(): StateTree | undefined;
|
|
73
|
+
updateSegmentCache(segmentInfo: SegmentInfo[] | null | undefined): void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Derive the navigation state (pathname + search) a URL renders with.
|
|
78
|
+
*
|
|
79
|
+
* Pure: publishing it — the module-level fallback for tests and SSR, and the
|
|
80
|
+
* globalThis bridge — is `prepareNavigation`'s commit, which runs only once
|
|
81
|
+
* the render is known to have won (TIM-1301). Callers pass the returned value
|
|
82
|
+
* explicitly to renderRoot/wrapPayload, so a render never depends on the
|
|
83
|
+
* publish having happened first.
|
|
84
|
+
*/
|
|
85
|
+
export function deriveNavigationState(url: string): NavigationState {
|
|
86
|
+
// Params are not part of it. They travel with the payload and are published
|
|
87
|
+
// by the one client-owned `ParamsProvider` as the new tree renders, which is
|
|
88
|
+
// also what clears the previous route's — a route with no params of its own
|
|
89
|
+
// still publishes an empty record (TIM-1294/TIM-1297, and the clearing
|
|
90
|
+
// requirement from TIM-1285).
|
|
91
|
+
const parsed = new URL(url, 'http://localhost');
|
|
92
|
+
return { pathname: parsed.pathname || '/', search: parsed.search };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function createNavigationCommitter(deps: {
|
|
96
|
+
segmentCache: SegmentCache;
|
|
97
|
+
historyStack: HistoryStack;
|
|
98
|
+
/** Read at call time — the router's `clientSegmentCache` opt-in. */
|
|
99
|
+
clientSegmentCache: () => boolean | undefined;
|
|
100
|
+
}): NavigationCommitter {
|
|
101
|
+
const { segmentCache, historyStack } = deps;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Update the segment cache from server-provided segment metadata.
|
|
105
|
+
*
|
|
106
|
+
* Runs whether or not `clientSegmentCache` is enabled: the tree is also
|
|
107
|
+
* where the mounted tree paths come from, and those cross on every
|
|
108
|
+
* navigation. What the flag gates is which parts get serialized — see
|
|
109
|
+
* `currentStateTree`.
|
|
110
|
+
*/
|
|
111
|
+
function updateSegmentCache(segmentInfo: SegmentInfo[] | null | undefined): void {
|
|
112
|
+
if (!segmentInfo || segmentInfo.length === 0) return;
|
|
113
|
+
const tree = buildSegmentTree(segmentInfo);
|
|
114
|
+
if (tree) {
|
|
115
|
+
segmentCache.set('/', tree);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
updateSegmentCache,
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The X-Timber-State-Tree to send with the next RSC request.
|
|
124
|
+
*
|
|
125
|
+
* Two different things travel on one header. `segments`/`slots` are the
|
|
126
|
+
* caching opt-in and are omitted unless `clientSegmentCache` is on.
|
|
127
|
+
* `treePaths` is how the server learns which route is actually mounted,
|
|
128
|
+
* which stops being derivable from the address bar as soon as a modal is
|
|
129
|
+
* open — so it crosses regardless (TIM-1282). Undefined when there is
|
|
130
|
+
* nothing to say, so a no-op header never enters the `_rsc` cache key.
|
|
131
|
+
*
|
|
132
|
+
* Reads what the last *committed* navigation published, so a superseded
|
|
133
|
+
* navigation's destination can never end up describing the mounted tree
|
|
134
|
+
* (TIM-1301).
|
|
135
|
+
*/
|
|
136
|
+
currentStateTree(): StateTree | undefined {
|
|
137
|
+
const tree = segmentCache.serializeStateTree();
|
|
138
|
+
if (deps.clientSegmentCache()) return tree;
|
|
139
|
+
return tree.treePaths ? { segments: [], treePaths: tree.treePaths } : undefined;
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Prepare all navigation-owned state for a new page — without publishing
|
|
144
|
+
* any of it. Every code path that changes the "current page" must go
|
|
145
|
+
* through this function, which is what makes "forgot a field" impossible
|
|
146
|
+
* by construction.
|
|
147
|
+
*
|
|
148
|
+
* Returns the destination's `NavigationState`, which is a pure function of
|
|
149
|
+
* the URL and is what the incoming tree is *rendered* with, plus a
|
|
150
|
+
* `commit` thunk that performs the writes that make a page current:
|
|
151
|
+
* 1. Segment cache — update from server-provided segment metadata
|
|
152
|
+
* 2. Navigation state — pathname/search for usePathname/useSearchParams
|
|
153
|
+
* 3. History stack — store the payload for instant back/forward replay
|
|
154
|
+
*
|
|
155
|
+
* Nothing is written until `commit()` runs, and on a transitioned
|
|
156
|
+
* navigation it runs only once the transition is known to have won — see
|
|
157
|
+
* `renderViaTransition` and `NavigationRoot`. A navigation superseded
|
|
158
|
+
* while its payload was in flight never calls it, so the cache, the
|
|
159
|
+
* pathname the client reports and the history stack all keep describing
|
|
160
|
+
* the route still on screen (TIM-1301).
|
|
161
|
+
*
|
|
162
|
+
* Callers with state of their own to publish — the address bar, the
|
|
163
|
+
* client's record of the mounted tree — wrap this thunk rather than
|
|
164
|
+
* commit beside it, so there stays exactly one moment at which a page
|
|
165
|
+
* becomes current.
|
|
166
|
+
*/
|
|
167
|
+
prepareNavigation(url: string, opts: NavigationCommitInput): PreparedNavigation {
|
|
168
|
+
const navState = deriveNavigationState(url);
|
|
169
|
+
|
|
170
|
+
// A tree rendered by an error response is not one to cache — see
|
|
171
|
+
// `status` on NavigationCommitInput. Normalized here, once, so no fetch
|
|
172
|
+
// caller can forget it; the history entry records the same thing, or a
|
|
173
|
+
// traversal back to this URL would replay the metadata this drops.
|
|
174
|
+
const cacheable = opts.status === undefined || opts.status < 400;
|
|
175
|
+
const segmentInfo = cacheable ? opts.segmentInfo : [];
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
navState,
|
|
179
|
+
commit() {
|
|
180
|
+
if (segmentInfo && segmentInfo.length > 0) {
|
|
181
|
+
updateSegmentCache(segmentInfo);
|
|
182
|
+
} else if (segmentInfo?.length === 0 || opts.clearSegmentCacheOnEmpty) {
|
|
183
|
+
segmentCache.clear();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
setNavigationState(navState);
|
|
187
|
+
|
|
188
|
+
historyStack.push(url, {
|
|
189
|
+
payload: opts.payload,
|
|
190
|
+
params: opts.params,
|
|
191
|
+
segmentInfo,
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|