@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
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform files the static build is allowed to overwrite in the output.
|
|
3
|
+
*
|
|
4
|
+
* The build merges two trees into the deployed directory — the client bundle
|
|
5
|
+
* (which carries everything the user put in `public/`) and the pre-rendered
|
|
6
|
+
* site. That merge otherwise refuses overlaps, because a silent overwrite
|
|
7
|
+
* leaves one of two artifacts deployed with nothing recording which
|
|
8
|
+
* (TIM-1266).
|
|
9
|
+
*
|
|
10
|
+
* These names are the exception, and only because the pre-rendered copy is
|
|
11
|
+
* *derived from* the one it replaces rather than competing with it:
|
|
12
|
+
* `plugins/static-build.ts` reads `public/_redirects` and writes the
|
|
13
|
+
* generated rules plus the user's, so the winner is a superset of the loser.
|
|
14
|
+
*
|
|
15
|
+
* That holds only for a file the current pass produced, which is why
|
|
16
|
+
* `cleanConditionalArtifacts` deletes a previous build's `_redirects` before
|
|
17
|
+
* generation: written only when a pass finds redirects, it would otherwise
|
|
18
|
+
* survive into a pass that produced nothing and claim an exemption it no
|
|
19
|
+
* longer earns.
|
|
20
|
+
*
|
|
21
|
+
* `_headers` is NOT here. It is not written into the pre-rendered tree at
|
|
22
|
+
* all — adapters generate it directly into the output, folding in the
|
|
23
|
+
* user's copy as they go (TIM-1326).
|
|
24
|
+
*
|
|
25
|
+
* Declared once so the code that performs the merge and the code that
|
|
26
|
+
* produces the merged file cannot disagree about which names are exempt.
|
|
27
|
+
*
|
|
28
|
+
* Isomorphic: no server, client, or build-time imports.
|
|
29
|
+
*/
|
|
30
|
+
/** Platform redirect rules (Cloudflare Pages, Netlify). See TIM-1245/TIM-1249. */
|
|
31
|
+
export declare const REDIRECTS_FILE = "_redirects";
|
|
32
|
+
/** Platform header rules (Cloudflare Pages, Netlify). See TIM-1241/TIM-1326. */
|
|
33
|
+
export declare const HEADERS_FILE = "_headers";
|
|
34
|
+
/**
|
|
35
|
+
* Where a user authors platform files. Stated once because two modules read
|
|
36
|
+
* from here — `plugins/static-build.ts` for `_redirects`, adapters for
|
|
37
|
+
* `_headers` — and they must look in the same place.
|
|
38
|
+
*
|
|
39
|
+
* Both read the **project source**, never the build output. The generated
|
|
40
|
+
* file lands under the same name in the output directory, so a reader aimed
|
|
41
|
+
* there would fold the previous build's generated rules back in and compound
|
|
42
|
+
* them on every rebuild.
|
|
43
|
+
*/
|
|
44
|
+
export declare const USER_PLATFORM_DIR = "public";
|
|
45
|
+
/** Output-relative paths whose pre-rendered copy subsumes the `public/` one. */
|
|
46
|
+
export declare const USER_MERGED_PLATFORM_FILES: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* Output paths the framework writes itself, which no route may claim.
|
|
49
|
+
*
|
|
50
|
+
* These are written outside the per-entry writer — `_redirects` after
|
|
51
|
+
* generation, `_headers` by the adapter after the copy — so the collision
|
|
52
|
+
* tracker never sees them and a route rendering to one of these paths is
|
|
53
|
+
* overwritten with nothing recording it.
|
|
54
|
+
*
|
|
55
|
+
* Reserved rather than tracked, because there is no version of "serve a route
|
|
56
|
+
* at `/_headers`" that works: Cloudflare Pages and Netlify read these two
|
|
57
|
+
* files themselves and never serve them, so the route is unservable however
|
|
58
|
+
* the conflict is resolved.
|
|
59
|
+
*
|
|
60
|
+
* That justification is per-file, not per-mechanism. `.nojekyll` is written
|
|
61
|
+
* the same way and is deliberately NOT here: only the `github-pages` target
|
|
62
|
+
* writes it, and everywhere else `/.nojekyll` is an ordinary servable path,
|
|
63
|
+
* so reserving it globally would refuse a valid Cloudflare site. Its write
|
|
64
|
+
* site skips the write when a file is already there instead — GitHub Pages
|
|
65
|
+
* only cares that the file exists.
|
|
66
|
+
*
|
|
67
|
+
* Same reasoning as the synthetic 404 entry using an internal urlPath so a
|
|
68
|
+
* real `/404` route cannot collide with `404.html`.
|
|
69
|
+
*/
|
|
70
|
+
export declare const RESERVED_OUTPUT_PATHS: readonly string[];
|
|
71
|
+
//# sourceMappingURL=static-platform-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-platform-files.d.ts","sourceRoot":"","sources":["../../src/shared/static-platform-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,kFAAkF;AAClF,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,gFAAgF;AAChF,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,gFAAgF;AAChF,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAAqB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAmC,CAAC"}
|
|
@@ -161,7 +161,7 @@ interface RouteContext {
|
|
|
161
161
|
}
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
Segment params and query params are **not** on `RouteContext`. Read them
|
|
164
|
+
Segment params and query params are **not** on `RouteContext`. Read them the same way pages do — `getSegmentParams(SEGMENT_PATH)` (importing `SEGMENT_PATH` from the route's `./$segment` module) and `searchParams.get()` on an imported definition. For the raw query string, use `new URL(ctx.req.url).searchParams`.
|
|
165
165
|
|
|
166
166
|
### `MiddlewareContext`
|
|
167
167
|
|
|
@@ -28,7 +28,7 @@ import { Link } from '@timber-js/app/client';
|
|
|
28
28
|
| ------------ | ------------------- | ------------------------------------------- |
|
|
29
29
|
| `href` | `string` | Target URL (type-checked against route map) |
|
|
30
30
|
| `replace` | `boolean` | Use `replaceState` instead of `pushState` |
|
|
31
|
-
| `prefetch` | `boolean` | Prefetch on hover
|
|
31
|
+
| `prefetch` | `boolean` | Prefetch the RSC payload on hover |
|
|
32
32
|
| `onNavigate` | `OnNavigateHandler` | Intercept navigation before routing |
|
|
33
33
|
|
|
34
34
|
### `<TimberErrorBoundary>`
|
|
@@ -60,6 +60,8 @@ router.forward();
|
|
|
60
60
|
| `back()` | Go back |
|
|
61
61
|
| `forward()` | Go forward |
|
|
62
62
|
|
|
63
|
+
If the server answers a navigation or a `refresh()` with an error, the router hands the URL back to the server as a full page load so it can render the error page as HTML with the right status code. That applies to back/forward too. None of these methods report the failure to your code — there is nothing to catch, and nothing to render a fallback for.
|
|
64
|
+
|
|
63
65
|
### `usePathname()`
|
|
64
66
|
|
|
65
67
|
Returns the current pathname as a string.
|
|
@@ -97,7 +99,7 @@ const pending = usePendingNavigation();
|
|
|
97
99
|
Per-link pending state. Must be used inside a `<Link>` component's children.
|
|
98
100
|
|
|
99
101
|
```tsx
|
|
100
|
-
const {
|
|
102
|
+
const { isPending } = useLinkStatus();
|
|
101
103
|
```
|
|
102
104
|
|
|
103
105
|
### `useSegmentParams(segmentPath?)`
|
|
@@ -45,9 +45,8 @@ Note: `z.coerce.*` schemas declare input `unknown`, so a coerce schema without `
|
|
|
45
45
|
| `.useQueryStates(opts?)` | Client hook — read and update typed search params |
|
|
46
46
|
| `.extend(codecs)` | Add additional params |
|
|
47
47
|
| `.pick(...keys)` | Create a subset |
|
|
48
|
-
| `.serialize(values)` | Convert typed values to URL search string |
|
|
49
48
|
| `.href(base, values)` | Build a full URL with params |
|
|
50
|
-
| `.
|
|
49
|
+
| `.buildSearchParams(values)` | Serialize to a query string — pass to `<Link searchParams>` |
|
|
51
50
|
| `.codecs` | Read-only codec map |
|
|
52
51
|
| `.urlKeys` | Read-only URL key alias map |
|
|
53
52
|
|
|
@@ -110,31 +109,52 @@ The codec protocol shared across search params, segment params, and cookies. See
|
|
|
110
109
|
interface SearchParamCodec<T> {
|
|
111
110
|
parse(value: string | string[] | undefined): T;
|
|
112
111
|
serialize(value: T): string | null;
|
|
112
|
+
urlKey?: string;
|
|
113
|
+
// optional total entry point — preferred over parse when present
|
|
114
|
+
parseServerSide?(value: string | string[] | undefined): T;
|
|
113
115
|
}
|
|
114
116
|
```
|
|
115
117
|
|
|
118
|
+
`parse` receives the **raw** URL value — `string | string[] | undefined` — because a param may be absent (`/products`) or repeated (`?q=a&q=b`). A codec must handle all three.
|
|
119
|
+
|
|
120
|
+
If handling all three in `parse` is awkward — as it is for a nuqs parser, whose `parse` is written for a present scalar — publish `parseServerSide` instead. Timber calls it wherever it invokes the codec, and its return type is the field's type: a codec that answers `null` for an absent param is a `SearchParamCodec<T | null>`.
|
|
121
|
+
|
|
116
122
|
Compatible codecs:
|
|
117
123
|
|
|
118
|
-
- **Zod/Valibot/ArkType schemas** — auto-detected via Standard Schema
|
|
119
|
-
- **nuqs parsers** — `parseAsInteger`, `parseAsString`, `parseAsBoolean`
|
|
124
|
+
- **Zod/Valibot/ArkType schemas** — auto-detected via Standard Schema. Total over absent and repeated input, so this is the safe default.
|
|
120
125
|
- **Custom** — any object implementing the interface
|
|
126
|
+
- **nuqs parsers** — total through timber, with one exception. See below.
|
|
127
|
+
|
|
128
|
+
## Parsers come from nuqs
|
|
129
|
+
|
|
130
|
+
Timber does not ship or re-export `parseAs*` parsers. Import them from [nuqs](https://nuqs.47ng.com/), which is a peer dependency; timber ships the wrappers (`withDefault`, `withUrlKey`) and the schema bridge.
|
|
131
|
+
|
|
132
|
+
nuqs checks whether a param is present before calling `parse`, so a parser's `parse` assumes a present scalar. Timber calls the parser's `parseServerSide` instead — nuqs's own adapter for the raw URL value — so every **single**-value parser is total:
|
|
133
|
+
|
|
134
|
+
| Raw value | Result |
|
|
135
|
+
| --------------------- | ------------------------------------------------------------- |
|
|
136
|
+
| absent (`/products`) | `null`, or the parser's own default if it declares one |
|
|
137
|
+
| repeated (`?v=a&v=b`) | the **first** value, matching `URLSearchParams.get()` |
|
|
138
|
+
| present | whatever the parser returns; if it **throws**, `null` |
|
|
121
139
|
|
|
122
|
-
|
|
140
|
+
So `?page=1&page=2` gives `1`, `parseAsBoolean` on a missing `?debug=` gives `null` rather than an HTTP 500, and `parseAsString` on `?q=a&q=b` gives `'a'` rather than an array its type forbids.
|
|
123
141
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
A present value is not validated for you — each parser decides. `parseAsBoolean` on `?v=maybe` is `false`, and `parseAsInteger` on `?v=12abc` is `12`. Use a schema when you need the value rejected rather than coerced.
|
|
143
|
+
|
|
144
|
+
The exception is `parseAsNativeArrayOf`, nuqs's *multi*-value parser for repeated keys. It is **not usable in `defineSearchParams`**: its `parse` is declared over `readonly string[]`, so the field is a compile error, and forcing it through leaves the client hook reading it as empty. Use an array schema for repeated keys. Tracked as TIM-1355.
|
|
145
|
+
|
|
146
|
+
Two consequences worth knowing:
|
|
147
|
+
|
|
148
|
+
- **`parseAsArrayOf` reads one key, not repeated keys.** It is a comma-separated list inside a single value, so `?tags=a,b` gives `['a','b']` but `?tags=a&tags=b` gives `['a']`. For repeated keys use an array schema — `tags: z.array(z.string()).default([])` reads both `?tags=a` and `?tags=a&tags=b`.
|
|
149
|
+
- **`parseAsJson` requires a validator argument** — `parseAsJson(z.object({ … }).parse)`. Called bare it does not type-check, and at runtime returns `null` for every value.
|
|
150
|
+
|
|
151
|
+
A field typed by a bare parser is nullable (`parseAsString` → `string | null`). Use `withDefault()` — timber's or the parser's own — to make it non-nullable.
|
|
132
152
|
|
|
133
153
|
## Codec Wrappers
|
|
134
154
|
|
|
135
155
|
### `withDefault(codec, value)`
|
|
136
156
|
|
|
137
|
-
Wrap a codec to
|
|
157
|
+
Wrap a codec to supply a value whenever the inner codec produces none — `null` or `undefined`. The field is non-nullable.
|
|
138
158
|
|
|
139
159
|
```ts
|
|
140
160
|
import { withDefault } from '@timber-js/app/search-params';
|
|
@@ -142,13 +162,15 @@ import { parseAsInteger } from 'nuqs';
|
|
|
142
162
|
const page = withDefault(parseAsInteger, 1); // number (never null)
|
|
143
163
|
```
|
|
144
164
|
|
|
165
|
+
A **present** value is left alone, including a falsy one: `?page=0` is `0`, and `?q=` is `''`, not the default.
|
|
166
|
+
|
|
145
167
|
### `withUrlKey(codec, key)`
|
|
146
168
|
|
|
147
169
|
Attach a URL key alias to a codec.
|
|
148
170
|
|
|
149
171
|
```ts
|
|
150
172
|
import { withUrlKey } from '@timber-js/app/search-params';
|
|
151
|
-
import {
|
|
152
|
-
const query = withUrlKey(
|
|
173
|
+
import { z } from 'zod/v4';
|
|
174
|
+
const query = withUrlKey(z.string().nullable().default(null), 'q');
|
|
153
175
|
// ?q=shoes → { query: 'shoes' }
|
|
154
176
|
```
|
|
@@ -107,10 +107,10 @@ Without `SEGMENT_PATH`, params are `Partial<AllSegmentParams>` — all optional.
|
|
|
107
107
|
|
|
108
108
|
## Typed Search Params
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
Search params are typed by the definition you create and import — there is no convention file:
|
|
111
111
|
|
|
112
112
|
```ts
|
|
113
|
-
// app/products/params.ts
|
|
113
|
+
// app/products/search-params.ts — any module you like
|
|
114
114
|
import { defineSearchParams } from '@timber-js/app/search-params';
|
|
115
115
|
import { z } from 'zod/v4';
|
|
116
116
|
|
|
@@ -135,7 +135,7 @@ export async function GET(ctx: RouteContext) {
|
|
|
135
135
|
}
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
Query params are read via `searchParams.get()` on an imported definition — the same accessor pages use. Segment params come from `getSegmentParams(SEGMENT_PATH)`. For the raw query string, use `new URL(ctx.req.url).searchParams`.
|
|
139
139
|
|
|
140
140
|
### `MiddlewareContext`
|
|
141
141
|
|
package/docs/api/36-cli.mdx
CHANGED
|
@@ -9,7 +9,7 @@ slug: 'cli'
|
|
|
9
9
|
timber.js provides four commands. All are thin wrappers around Vite with timber-specific behavior.
|
|
10
10
|
|
|
11
11
|
```tsx
|
|
12
|
-
timber < command > [--config<path>];
|
|
12
|
+
timber < command > [--config<path>][--project<path>];
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Commands
|
|
@@ -40,7 +40,7 @@ To override the default, use any of the following (highest precedence first):
|
|
|
40
40
|
1. `server.port` in `vite.config.ts`
|
|
41
41
|
2. `PORT=4000 timber dev` — the `PORT` environment variable
|
|
42
42
|
|
|
43
|
-
> **Note:** `timber dev --port 4000` is an error, not a silent no-op.
|
|
43
|
+
> **Note:** `timber dev --port 4000` is an error, not a silent no-op. `timber dev` accepts only `--config` — use `PORT` or `server.port` to change the port.
|
|
44
44
|
|
|
45
45
|
When you set the port explicitly, timber **does not** auto-bump — a conflict produces an `EADDRINUSE` error so you find out immediately rather than connecting to the wrong port. This same behavior applies to `timber preview` and the production Node preview server.
|
|
46
46
|
|
|
@@ -84,13 +84,39 @@ Always run `timber build` before `timber preview`.
|
|
|
84
84
|
|
|
85
85
|
### `timber check`
|
|
86
86
|
|
|
87
|
-
Validate
|
|
87
|
+
Validate routes and types without producing build output.
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
90
|
timber check
|
|
91
|
+
timber check --config ./custom-vite.config.ts --project ./tsconfig.build.json
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
Two passes, in order:
|
|
95
|
+
|
|
96
|
+
1. **Routes.** Resolves your project through Vite exactly as `timber build` does — same root, app directory and `pageExtensions`, same `production` mode and `NODE_ENV`, and including config passed inline to `timber()` in `vite.config.ts`. A config that branches on `mode` or reads `.env.production` therefore resolves the same way under both commands. It then scans, runs the route convention linter, and regenerates the route types (`.timber/timber-routes.d.ts`, `.timber/segment-types.d.ts`, `timber-env.d.ts`). Convention *errors* — the proven-fatal misconfigurations that also fail `timber build`, such as an `error.tsx` that is a server component — fail the command. Warnings print and do not.
|
|
97
|
+
2. **Types.** `tsgo --noEmit`, run from the root the route pass resolved — so it type-checks the same project whose routes were just validated, and finds the declarations that pass just wrote. A relative `--project` is interpreted from the directory you ran the command in.
|
|
98
|
+
|
|
99
|
+
Codegen runs first on purpose: the generated declarations are what type `<Link href>`, `useSegmentParams()`, and `MiddlewareContext`. On a fresh clone that has never run `timber dev` or `timber build` they do not exist yet, so a bare type check would report errors about correct code.
|
|
100
|
+
|
|
101
|
+
Your `tsconfig.json` must pull in `timber-env.d.ts` — that file is what references the generated route map. If your `include` lists only source directories, add it:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"include": ["app", "*.config.ts", "timber-env.d.ts"]
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`timber check` warns when the generated types are not part of the resolved program, because the type check would otherwise pass while measuring `<Link href>` against an empty placeholder. Projects created with `create-timber-app` are configured correctly.
|
|
110
|
+
|
|
111
|
+
`timber check` requires **`@typescript/native-preview`** (which provides `tsgo`). It is an optional peer dependency — install it as a dev dependency:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pnpm add -D @typescript/native-preview
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If it is missing, `timber check` fails with that instruction. It never passes by skipping the type check.
|
|
118
|
+
|
|
119
|
+
Useful in CI pipelines and pre-commit hooks to catch type and routing errors without a full build.
|
|
94
120
|
|
|
95
121
|
### `timber init`
|
|
96
122
|
|
|
@@ -108,11 +134,12 @@ The generated `AGENTS.md` includes project structure, key imports, common patter
|
|
|
108
134
|
|
|
109
135
|
| Flag | Short | Description |
|
|
110
136
|
| ----------------- | ----- | --------------------------------------------------------------------------------------------------------- |
|
|
111
|
-
| `--config <path>`
|
|
137
|
+
| `--config <path>` | `-c` | Path to a custom Vite config file. Means the same thing for every command, `check` included. |
|
|
138
|
+
| `--project <path>` | | `timber check` only — the `tsconfig.json` to type-check. |
|
|
112
139
|
|
|
113
|
-
> **Note:**
|
|
140
|
+
> **Note:** `timber check` resolves your app through Vite, so `--config` names the Vite config there too, exactly as it does for `dev` and `build`. The tsconfig has its own flag, `--project`, spelled the way `tsc` and `tsgo` spell it. `check` needs a Vite config that lists the timber plugin and fails with an actionable message if it cannot find one.
|
|
114
141
|
|
|
115
|
-
|
|
142
|
+
Those are the only flags. Any other produces an error rather than being silently ignored, with a hint at the supported alternative (e.g. `--port` points you to the `PORT` env var or `server.port` in `vite.config.ts`). Passing `--project` to a command with no type pass is an error too, pointing you at `--config`.
|
|
116
143
|
|
|
117
144
|
## Package Manager Scripts
|
|
118
145
|
|
|
@@ -69,7 +69,7 @@ const [sp, setSearchParams] = searchParams.useQueryStates();
|
|
|
69
69
|
All routing in timber is fully typed and integrated. So you can write a `<Link>` as:
|
|
70
70
|
|
|
71
71
|
```tsx
|
|
72
|
-
<Link href="/blog/[slug]" segmentParams={{ slug: 'a-post' }}
|
|
72
|
+
<Link href="/blog/[slug]" segmentParams={{ slug: 'a-post' }}>Page</Link>
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
Or just normal `<a>` tags work too.
|
|
@@ -94,7 +94,7 @@ Each directory is called a **segment** and can contain these files:
|
|
|
94
94
|
| `layout.tsx` | Persistent UI shell — wraps children, survives navigation |
|
|
95
95
|
| `access.ts` | Authorization gate — runs before the layout renders |
|
|
96
96
|
| `middleware.ts` | Pre-render hook for headers, redirects, and cache warming |
|
|
97
|
-
| `
|
|
97
|
+
| _(none)_ | Segment param codecs live in `app/schema.ts`; search params in any module you import — see [Typed Params](/docs/typed-params) |
|
|
98
98
|
| `error.tsx` | Error boundary catching failures in this subtree |
|
|
99
99
|
| `404.tsx` | Denial page for 404 status code (must be a client component) |
|
|
100
100
|
|
|
@@ -140,7 +140,7 @@ app/
|
|
|
140
140
|
timber produces build errors for ambiguous route configurations:
|
|
141
141
|
|
|
142
142
|
- **Duplicate convention files** — `page.tsx` and `page.jsx` in the same directory is an error, not a silent winner-by-filesystem-order
|
|
143
|
-
- **Route
|
|
143
|
+
- **Route collisions** — two pages (or a page and a `route.ts`) that answer the same URL are caught at build time. Routes are compared by the URLs they match, not by how they are spelled: `x/(a)/[id]/page.tsx` and `x/(b)/[slug]/page.tsx` collide, and so do `x/(a)/page.tsx` and `x/(b)/[[...rest]]/page.tsx`, since an optional catch-all also matches with zero segments. Different segment _kinds_ don't collide — `[id]` beside `[...rest]` is ordered deterministically and keeps building
|
|
144
144
|
|
|
145
145
|
This behavior is deterministic regardless of filesystem `readdir` order. In Next.js, the result of these ambiguities depends on the OS and filesystem, which can produce different behavior between local development and CI.
|
|
146
146
|
|
|
@@ -112,9 +112,9 @@ const params = getSegmentParams();
|
|
|
112
112
|
|
|
113
113
|
## Search Params
|
|
114
114
|
|
|
115
|
-
Declare typed search params with `defineSearchParams
|
|
115
|
+
Declare typed search params with `defineSearchParams` in any module, then import it where you need it. Unlike segment params, there is no convention file and nothing is scanned:
|
|
116
116
|
|
|
117
|
-
```ts title="app/products/params.ts" id="search-params"
|
|
117
|
+
```ts title="app/products/search-params.ts" id="search-params"
|
|
118
118
|
import { defineSearchParams, withDefault } from '@timber-js/app/search-params';
|
|
119
119
|
import { parseAsInteger } from 'nuqs';
|
|
120
120
|
import { z } from 'zod/v4';
|
|
@@ -129,7 +129,7 @@ export const searchParams = defineSearchParams({
|
|
|
129
129
|
### Server Usage
|
|
130
130
|
|
|
131
131
|
```tsx title="app/products/page.tsx" use="search-params"
|
|
132
|
-
import { searchParams } from './params';
|
|
132
|
+
import { searchParams } from './search-params';
|
|
133
133
|
|
|
134
134
|
export default async function ProductsPage() {
|
|
135
135
|
const { page, sort, q } = searchParams.get();
|
|
@@ -142,7 +142,7 @@ export default async function ProductsPage() {
|
|
|
142
142
|
|
|
143
143
|
```tsx title="app/products/filters.tsx" use="search-params"
|
|
144
144
|
'use client';
|
|
145
|
-
import { searchParams } from './params';
|
|
145
|
+
import { searchParams } from './search-params';
|
|
146
146
|
|
|
147
147
|
export function ProductFilters() {
|
|
148
148
|
const [params, setParams] = searchParams.useQueryStates();
|
|
@@ -231,7 +231,7 @@ For segment params, use the `codec` namespace:
|
|
|
231
231
|
| `codec.catchAll(inner)` | `T[]` | Wraps scalar codec for catch-all segments |
|
|
232
232
|
| `codec.optionalCatchAll(inner)` | `T[] \| undefined` | Wraps scalar codec for optional catch-all segments |
|
|
233
233
|
|
|
234
|
-
Use `withDefault()` to get a non-nullable type for search params. [nuqs](https://nuqs.47ng.com/) parsers
|
|
234
|
+
Use `withDefault()` to get a non-nullable type for search params. [nuqs](https://nuqs.47ng.com/) parsers all work as codecs: an absent param is `null` and a repeated one takes the first value. Note that `parseAsArrayOf` reads a comma-separated list from a single key — for repeated keys (`?ids=1&ids=2`) use an array schema, e.g. `z.array(z.string()).default([])`. */}
|
|
235
235
|
|
|
236
236
|
## Composition
|
|
237
237
|
|
|
@@ -247,7 +247,7 @@ export const pagination = {
|
|
|
247
247
|
};
|
|
248
248
|
```
|
|
249
249
|
|
|
250
|
-
```ts title="app/products/params.ts"
|
|
250
|
+
```ts title="app/products/search-params.ts"
|
|
251
251
|
import { defineSearchParams } from '@timber-js/app/search-params';
|
|
252
252
|
import { pagination } from '@/lib/search-params/pagination';
|
|
253
253
|
import { z } from 'zod/v4';
|
|
@@ -264,10 +264,10 @@ Map a property name to a different URL key with `withUrlKey`:
|
|
|
264
264
|
|
|
265
265
|
```ts
|
|
266
266
|
import { defineSearchParams, withUrlKey } from '@timber-js/app/search-params';
|
|
267
|
-
import {
|
|
267
|
+
import { z } from 'zod/v4';
|
|
268
268
|
|
|
269
269
|
export const searchParams = defineSearchParams({
|
|
270
|
-
query: withUrlKey(
|
|
270
|
+
query: withUrlKey(z.string().nullable().default(null), 'q'),
|
|
271
271
|
});
|
|
272
272
|
// ?q=shoes → { query: 'shoes' }
|
|
273
273
|
```
|
|
@@ -84,23 +84,23 @@ Add `rootDirs` so TypeScript can resolve `$segment` imports:
|
|
|
84
84
|
|
|
85
85
|
## Typed Search Params
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Define search params with `defineSearchParams()` in any module and import it — there is no convention file. Search params are then fully typed throughout the stack:
|
|
88
88
|
|
|
89
|
-
```ts title="app/products/params.ts"
|
|
89
|
+
```ts title="app/products/search-params.ts"
|
|
90
90
|
import { defineSearchParams, withDefault, withUrlKey } from '@timber-js/app/search-params';
|
|
91
|
-
import { parseAsInteger,
|
|
91
|
+
import { parseAsInteger, parseAsStringEnum } from 'nuqs';
|
|
92
92
|
import { z } from 'zod/v4';
|
|
93
93
|
|
|
94
94
|
export const searchParams = defineSearchParams({
|
|
95
95
|
page: withDefault(parseAsInteger, 1),
|
|
96
|
-
q: withUrlKey(
|
|
96
|
+
q: withUrlKey(z.string().nullable().default(null), 'search'),
|
|
97
97
|
category: z.string().nullable().default(null),
|
|
98
98
|
sort: withDefault(parseAsStringEnum(['price-asc', 'price-desc', 'newest']), 'newest'),
|
|
99
99
|
});
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
```tsx title="app/products/page.tsx"
|
|
103
|
-
import { searchParams } from './params';
|
|
103
|
+
import { searchParams } from './search-params';
|
|
104
104
|
|
|
105
105
|
export default async function ProductsPage() {
|
|
106
106
|
const { page, q, category, sort } = await searchParams.get();
|
|
@@ -108,16 +108,21 @@ export default async function ProductsPage() {
|
|
|
108
108
|
}
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
`<Link>`
|
|
111
|
+
Pass them to `<Link>` by building them from the definition. `buildSearchParams` type-checks the values and applies the definition's codecs and URL-key aliases:
|
|
112
112
|
|
|
113
113
|
```tsx
|
|
114
|
+
import { searchParams } from './search-params';
|
|
115
|
+
|
|
114
116
|
<Link
|
|
115
117
|
href="/products/[id]"
|
|
116
118
|
segmentParams={{ id }}
|
|
117
|
-
searchParams={{ sort: 'newest', q: 'boots' }}
|
|
119
|
+
searchParams={searchParams.buildSearchParams({ sort: 'newest', q: 'boots' })}
|
|
118
120
|
/>
|
|
121
|
+
// → /products/42?sort=newest&search=boots (q is aliased to search)
|
|
119
122
|
```
|
|
120
123
|
|
|
124
|
+
A plain object also works as an untyped escape hatch for one-off params with no definition — but it skips codecs and aliases, so do not use it for keys a definition owns.
|
|
125
|
+
|
|
121
126
|
See [Typed Params](/docs/typed-params) for the full search params API.
|
|
122
127
|
|
|
123
128
|
## Codegen
|
|
@@ -73,6 +73,20 @@ Priority order (innermost to outermost):
|
|
|
73
73
|
3. `error.tsx` — catches anything unmatched
|
|
74
74
|
4. Parent segments → framework default
|
|
75
75
|
|
|
76
|
+
Component status files (`.tsx`, `.jsx`, `.ts`, `.js`) and `error.tsx` **must start with `'use client'`**:
|
|
77
|
+
|
|
78
|
+
```tsx title="app/404.tsx"
|
|
79
|
+
'use client';
|
|
80
|
+
|
|
81
|
+
export default function NotFound({ status }: { status: number }) {
|
|
82
|
+
return <h1>Page not found</h1>;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
timber hands these components to its error boundary — a client component — as a prop, so a server component there cannot cross the RSC boundary. It is not a degraded error page: every page under that segment fails to render. The build catches it and names the file, so you will not discover it as a serialization error on a page you did not touch. MDX status files (`404.mdx`) are the exception — they are server components, rendered ahead of time.
|
|
87
|
+
|
|
88
|
+
If nothing in the chain matches, timber renders a built-in status page: a plain document with the status code and its reason phrase, and nothing else — no request URL, no error message. It is what a static build writes to `404.html` when your app has no not-found page, so a static deploy always ships one. Add a root `app/404.tsx` (or `4xx.tsx` / `error.tsx`) to replace it.
|
|
89
|
+
|
|
76
90
|
## `error.tsx`
|
|
77
91
|
|
|
78
92
|
The general error boundary. It's a client component:
|
|
@@ -99,6 +113,10 @@ export default function DashboardError({
|
|
|
99
113
|
|
|
100
114
|
Error boundaries wrap page content inside layouts — the layout shell (nav, sidebar) stays visible when an error fires.
|
|
101
115
|
|
|
116
|
+
A status page renders inside the layouts **above and including the segment it lives in**, and none below it. A root `404.tsx` serving a `deny(404)` from `app/docs/[slug]/page.tsx` renders inside the root layout only — `docs/layout.tsx` and `[slug]/layout.tsx` do not appear, because the file that matched lives above them. Co-locate the status file with the segment whose chrome you want kept: move that `404.tsx` to `app/docs/` and the docs layout comes with it.
|
|
117
|
+
|
|
118
|
+
One exception: **the segment that denied never contributes its own layout**, even when it owns the matched status file. If its `access.ts` denied, that layout sits behind the failed auth check, so running it would let it fetch and serialize data the request was not allowed to see. If the layout itself called `deny()`, it threw instead of returning its chrome, so there is nothing to render. A `deny()` from a page is unaffected — the page's own layout still renders.
|
|
119
|
+
|
|
102
120
|
When a `deny()` has no matching status-code file, it falls through to the nearest `error.tsx`. The component still receives a real `error` (its message is `Access denied with status <N>`), and additionally receives `status` and `dangerouslyPassData` so you can render denial-specific UI:
|
|
103
121
|
|
|
104
122
|
```tsx title="app/error.tsx"
|
|
@@ -93,8 +93,8 @@ Track per-link pending state during navigation:
|
|
|
93
93
|
import { Link, useLinkStatus } from '@timber-js/app/client';
|
|
94
94
|
|
|
95
95
|
function NavItemInner({ children }: { children: React.ReactNode }) {
|
|
96
|
-
const {
|
|
97
|
-
return <span className={
|
|
96
|
+
const { isPending } = useLinkStatus();
|
|
97
|
+
return <span className={isPending ? 'opacity-50' : ''}>{children}</span>;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export function NavItem({ href, children }: { href: string; children: React.ReactNode }) {
|
|
@@ -200,6 +200,29 @@ export default {
|
|
|
200
200
|
|
|
201
201
|
Pre-renders every route to HTML at build time. Add `clientJavascript: false` for zero-JavaScript output. Deploy to any static file host — S3, CloudFront, Cloudflare Pages, GitHub Pages, Netlify, or any HTTP server.
|
|
202
202
|
|
|
203
|
+
### Serving from a sub-path
|
|
204
|
+
|
|
205
|
+
To deploy under a path instead of a domain root — `https://user.github.io/repo/` on GitHub Pages, for example — set Vite's `base`:
|
|
206
|
+
|
|
207
|
+
```ts title="vite.config.ts"
|
|
208
|
+
export default defineConfig({
|
|
209
|
+
base: '/repo/',
|
|
210
|
+
plugins: [timber()],
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Every URL timber emits picks up the prefix: client assets, fonts, and the RSC payloads behind client-side navigation.
|
|
215
|
+
|
|
216
|
+
Your own links are not rewritten. `base` prefixes emitted assets, not application URLs, so an `href` must include the prefix itself:
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
<Link href={`${import.meta.env.BASE_URL}about`}>About</Link>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
A plain `href="/about"` points at the domain root, outside your deployment.
|
|
223
|
+
|
|
224
|
+
A relative base (`'./'`) can't tell timber where the site lives, so payload URLs fall back to the domain root and client-side navigation degrades to full page loads on a sub-path deployment. The build warns when it sees one — use an absolute base like `'/repo/'`.
|
|
225
|
+
|
|
203
226
|
## CDN Integration
|
|
204
227
|
|
|
205
228
|
timber.js provides typed helpers for CDN caching headers and tag-based purging. CDN caching is always developer-elected — the framework never sets cache headers automatically.
|