@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,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Segment key computation — the stable identity of a segment in the route tree.
|
|
3
|
+
*
|
|
4
|
+
* A segment key is the string that names a segment across the RSC/SSR/client
|
|
5
|
+
* boundary: it appears in the X-Timber-State-Tree header, the X-Timber-Segments
|
|
6
|
+
* header, SegmentOutlet props, the client segment cache, and (since TIM-1279)
|
|
7
|
+
* interception scoping.
|
|
8
|
+
*
|
|
9
|
+
* This module lives in `routing/` rather than `server/` because the keys are a
|
|
10
|
+
* property of the route tree itself — both the build-time scanner tree and the
|
|
11
|
+
* runtime manifest tree produce identical keys for the same directory, which is
|
|
12
|
+
* what lets a build-time value (an interception scope) be compared against a
|
|
13
|
+
* request-time matched chain.
|
|
14
|
+
*
|
|
15
|
+
* See design/19-client-navigation.md §"X-Timber-State-Tree Header"
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Segment node shape expected by computeSegmentKeys.
|
|
20
|
+
*
|
|
21
|
+
* Structurally satisfied by both `SegmentNode` (build time) and
|
|
22
|
+
* `ManifestSegmentNode` (request time) — keys depend only on the
|
|
23
|
+
* URL path and the segment classification, never on file payloads.
|
|
24
|
+
*/
|
|
25
|
+
export interface SegmentKeyInput {
|
|
26
|
+
urlPath: string;
|
|
27
|
+
segmentName?: string;
|
|
28
|
+
segmentType?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Compute state-tree keys for a segment chain.
|
|
33
|
+
*
|
|
34
|
+
* Non-group segments use their urlPath as-is. Route groups accumulate
|
|
35
|
+
* ancestor group names to produce globally unique keys:
|
|
36
|
+
* app/(a)/(shared)/dashboard → keys: ['/', '/(a)', '/(a)/(shared)', '/dashboard']
|
|
37
|
+
*
|
|
38
|
+
* **An intercepting segment switches the chain to name accumulation for good.**
|
|
39
|
+
* A children-path interception (TIM-1280) puts an intercepting node and its
|
|
40
|
+
* descendants into the *main* rendered chain, and their `urlPath`s are not
|
|
41
|
+
* URLs: interception adds no URL depth, so `app/(browse)/(...)[artistSlug]/[year]`
|
|
42
|
+
* carries `/` and `/[year]`. Keyed by urlPath the intercepting node would
|
|
43
|
+
* collide with its own owner, and `[year]` with any top-level `[year]` route —
|
|
44
|
+
* so a client that had one mounted would reuse the wrong cached layout. The
|
|
45
|
+
* switch is sticky rather than per-node because the *descendants* are where
|
|
46
|
+
* the false URLs are; the intercepting node alone is not the problem.
|
|
47
|
+
*
|
|
48
|
+
* This is the single source of truth for segment keys — used by the
|
|
49
|
+
* element builder (skip decisions, SegmentOutlet props), segment info
|
|
50
|
+
* (X-Timber-Segments header), the client cache/state tree, and
|
|
51
|
+
* interception scoping (`routing/interception.ts`).
|
|
52
|
+
*/
|
|
53
|
+
export function computeSegmentKeys(segments: SegmentKeyInput[]): string[] {
|
|
54
|
+
const keys: string[] = [];
|
|
55
|
+
let prevKey = '';
|
|
56
|
+
let insideIntercepting = false;
|
|
57
|
+
|
|
58
|
+
for (const segment of segments) {
|
|
59
|
+
if (segment.segmentType === 'intercepting') insideIntercepting = true;
|
|
60
|
+
if (segment.segmentType === 'group' || insideIntercepting) {
|
|
61
|
+
const base = prevKey === '/' ? '' : prevKey;
|
|
62
|
+
const key = `${base}/${segment.segmentName}`;
|
|
63
|
+
keys.push(key);
|
|
64
|
+
prevKey = key;
|
|
65
|
+
} else {
|
|
66
|
+
keys.push(segment.urlPath);
|
|
67
|
+
prevKey = segment.urlPath;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return keys;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Compute tree paths for a segment chain — the directory path of each segment
|
|
76
|
+
* with slots elided, e.g. `app/(browse)/feed` → `/(browse)/feed`.
|
|
77
|
+
*
|
|
78
|
+
* This is `computeSegmentKeys` with the group branch applied to *every*
|
|
79
|
+
* segment rather than only to groups. That one difference is the whole point:
|
|
80
|
+
* `computeSegmentKeys` resets to `urlPath` at each URL-visible segment, so
|
|
81
|
+
* `(browse)/feed` and `(landing)/feed` both key as `/feed`. Two directories
|
|
82
|
+
* that render different layouts must not share an identity.
|
|
83
|
+
*
|
|
84
|
+
* Used for interception scoping (`routing/interception.ts`), where the
|
|
85
|
+
* question is "does this route pass through *that* directory?" — not "does it
|
|
86
|
+
* render this URL?". Not interchangeable with `computeSegmentKeys`: the state
|
|
87
|
+
* tree is keyed by URL on purpose, because the client caches by URL.
|
|
88
|
+
*/
|
|
89
|
+
export function computeSegmentTreePaths(segments: SegmentKeyInput[]): string[] {
|
|
90
|
+
const paths: string[] = [];
|
|
91
|
+
let prev = '';
|
|
92
|
+
|
|
93
|
+
for (const segment of segments) {
|
|
94
|
+
const name = segment.segmentName ?? '';
|
|
95
|
+
if (!name) {
|
|
96
|
+
// The app root — no directory name of its own.
|
|
97
|
+
paths.push('/');
|
|
98
|
+
prev = '/';
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const base = prev === '/' ? '' : prev;
|
|
102
|
+
const path = `${base}/${name}`;
|
|
103
|
+
paths.push(path);
|
|
104
|
+
prev = path;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return paths;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The directory names a tree path is built from — `/` is none, `/feed/(a)` is
|
|
112
|
+
* `['feed', '(a)']`.
|
|
113
|
+
*
|
|
114
|
+
* The inverse of the walk above, and it lives beside it so the format is
|
|
115
|
+
* stated once: `findChainByTreePath` (`server/children-interception.ts`) walks
|
|
116
|
+
* these names back down the tree to the directory the path addresses, and
|
|
117
|
+
* `treePathDepth` counts them. Both are readings of the same string, and a
|
|
118
|
+
* reader that disagreed with the producer about what separates two names
|
|
119
|
+
* resolves an interception to the wrong node or to none.
|
|
120
|
+
*/
|
|
121
|
+
export function treePathNames(treePath: string): string[] {
|
|
122
|
+
return treePath === '/' ? [] : treePath.slice(1).split('/');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* How many directories a tree path names — `/` is 0, `/feed` is 1,
|
|
127
|
+
* `/feed/(a)` is 2.
|
|
128
|
+
*
|
|
129
|
+
* Two tree paths on a single rendered chain are strictly nested, so on that
|
|
130
|
+
* chain depth orders them totally — which is what makes it usable as "the
|
|
131
|
+
* deeper of these two directories" wherever a route passes through both
|
|
132
|
+
* (`routing/interception.ts`).
|
|
133
|
+
*/
|
|
134
|
+
export function treePathDepth(treePath: string): number {
|
|
135
|
+
return treePathNames(treePath).length;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Compute a unique key for a parallel route slot.
|
|
140
|
+
* Format: `{parentSegmentId}/@{slotName}`, e.g. `/@sidebar` or `/dashboard/@modal`.
|
|
141
|
+
*/
|
|
142
|
+
export function computeSlotKey(parentSegmentId: string, slotName: string): string {
|
|
143
|
+
const name = slotName.startsWith('@') ? slotName : `@${slotName}`;
|
|
144
|
+
const prefix = parentSegmentId === '/' ? '' : parentSegmentId;
|
|
145
|
+
return `${prefix}/${name}`;
|
|
146
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parallel slot placement.
|
|
3
|
+
*
|
|
4
|
+
* One rule: a slot is resolved only for a segment on the **matched route
|
|
5
|
+
* chain**, and a slot's own subtree is never on that chain. So a slot declared
|
|
6
|
+
* anywhere inside another slot's subtree can never render, and is rejected at
|
|
7
|
+
* build time rather than left as a directory the author will keep editing.
|
|
8
|
+
*
|
|
9
|
+
* See design/07-routing.md §"Parallel Routes".
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { SegmentNode } from './types.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Reject every parallel slot that no renderer reaches.
|
|
16
|
+
*
|
|
17
|
+
* **Where slots are resolved.** Two places read `segment.slots`, and both walk
|
|
18
|
+
* the main route chain: `route-element-builder.ts` (the RSC render) and
|
|
19
|
+
* `tree-builder.ts`. Neither is reachable from inside a slot. The slot's own
|
|
20
|
+
* subtree is rendered by `slot-resolver.ts`, which walks the slot's matched
|
|
21
|
+
* chain to apply that chain's layouts, error boundaries and access gates
|
|
22
|
+
* (`wrapWithIntermediateSegments`, `wrapWithLayout`) and never reads `.slots`
|
|
23
|
+
* on any of those nodes. So `app/feed/@modal/photo/@side/page.tsx` and
|
|
24
|
+
* everything below it is dead: the file is scanned, typed, code-split and
|
|
25
|
+
* shipped, and no request can render it.
|
|
26
|
+
*
|
|
27
|
+
* That is the TIM-1278 failure — a directory that silently never renders —
|
|
28
|
+
* and the reason it is a build error rather than a documented limit is that
|
|
29
|
+
* nothing at request time can report it. A slot that does not match renders
|
|
30
|
+
* `default.tsx` or `null`, which is exactly what a slot the resolver never
|
|
31
|
+
* looked at also produces, so the author sees the *designed* behaviour of a
|
|
32
|
+
* non-matching slot and has no signal to distinguish it from a slot that
|
|
33
|
+
* cannot match at all.
|
|
34
|
+
*
|
|
35
|
+
* **Interception is incidental.** TIM-1311 arrived as
|
|
36
|
+
* `feed/@modal/(.)photo/@side`, and the interception contributes nothing: the
|
|
37
|
+
* identical `feed/@modal/photo/@side` never renders either, for the same
|
|
38
|
+
* reason and with no marker anywhere. Rejecting only the intercepting spelling
|
|
39
|
+
* would have drawn a line the author cannot see from the directory names.
|
|
40
|
+
*
|
|
41
|
+
* The children-path interception shape is **not** affected and must not be:
|
|
42
|
+
* its intercepting node joins the main chain (`server/children-interception.ts`
|
|
43
|
+
* splices `[…owner ancestors, interceptingNode, …descendants]` into an ordinary
|
|
44
|
+
* `RouteMatch`), so `route-element-builder.ts` resolves slots on it and below
|
|
45
|
+
* it exactly as it does for any other chain segment. `(browse)/(...)photo/[id]/@side`
|
|
46
|
+
* renders; `feed/@modal/(.)photo/@side` does not. The discriminator is the slot
|
|
47
|
+
* boundary, which is what this walk tracks — not the marker.
|
|
48
|
+
*/
|
|
49
|
+
export function validateSlotPlacement(root: SegmentNode): void {
|
|
50
|
+
walkForSlotPlacement(root, '', null);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* `enclosingSlotPath` is the `app/`-relative path of the nearest slot at or
|
|
55
|
+
* above `node`, or null on the main chain. It is carried rather than recomputed
|
|
56
|
+
* so the error can name the slot that swallows the offender — "this is inside
|
|
57
|
+
* @modal" is the part of the diagnosis the author cannot see from the offending
|
|
58
|
+
* path alone.
|
|
59
|
+
*/
|
|
60
|
+
function walkForSlotPlacement(
|
|
61
|
+
node: SegmentNode,
|
|
62
|
+
path: string,
|
|
63
|
+
enclosingSlotPath: string | null
|
|
64
|
+
): void {
|
|
65
|
+
for (const [slotName, slotNode] of Object.entries(node.slots)) {
|
|
66
|
+
const slotPath = path ? `${path}/@${slotName}` : `@${slotName}`;
|
|
67
|
+
if (enclosingSlotPath !== null) {
|
|
68
|
+
throwNestedSlot(slotPath, enclosingSlotPath);
|
|
69
|
+
}
|
|
70
|
+
walkForSlotPlacement(slotNode, slotPath, slotPath);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const child of node.children) {
|
|
74
|
+
walkForSlotPlacement(
|
|
75
|
+
child,
|
|
76
|
+
path ? `${path}/${child.segmentName}` : child.segmentName,
|
|
77
|
+
enclosingSlotPath
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function throwNestedSlot(slotPath: string, enclosingSlotPath: string): never {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Build error: parallel slot nested inside another parallel slot.\n` +
|
|
85
|
+
` Directory: app/${slotPath}\n` +
|
|
86
|
+
` Inside: app/${enclosingSlotPath}\n` +
|
|
87
|
+
`A parallel slot is resolved only for a segment on the matched route chain, and a ` +
|
|
88
|
+
`slot's own subtree is never on that chain — the slot resolver walks the slot's ` +
|
|
89
|
+
`matched chain to apply its layouts, error boundaries and access gates, and never ` +
|
|
90
|
+
`looks at slots declared inside it. So app/${slotPath} and everything below it can ` +
|
|
91
|
+
`never render, and no request-time signal can tell you: an unreachable slot ` +
|
|
92
|
+
`produces exactly what a slot that simply did not match produces.\n` +
|
|
93
|
+
`Declare the slot on a segment of the main route chain instead, or move its pages ` +
|
|
94
|
+
`into app/${enclosingSlotPath}'s own subtree.\n` +
|
|
95
|
+
`See design/07-routing.md §"Parallel Routes".`
|
|
96
|
+
);
|
|
97
|
+
}
|
package/src/routing/types.ts
CHANGED
|
@@ -96,12 +96,6 @@ export interface SegmentNode<TFile = RouteFile> {
|
|
|
96
96
|
middleware?: TFile;
|
|
97
97
|
access?: TFile;
|
|
98
98
|
route?: TFile;
|
|
99
|
-
/**
|
|
100
|
-
* params.ts — isomorphic convention file exporting segmentParams and/or searchParams.
|
|
101
|
-
* Discovered by the scanner like middleware.ts and access.ts.
|
|
102
|
-
* See design/07-routing.md §"params.ts Convention File"
|
|
103
|
-
*/
|
|
104
|
-
params?: TFile;
|
|
105
99
|
error?: TFile;
|
|
106
100
|
default?: TFile;
|
|
107
101
|
/** Status-code files: 4xx.tsx, 5xx.tsx, {status}.tsx (component format) */
|
package/src/routing/walkers.ts
CHANGED
|
@@ -49,6 +49,12 @@ export interface CollectLeafRoutesOptions {
|
|
|
49
49
|
* entries (the build report deduplicates by URL afterward).
|
|
50
50
|
* - Parallel slots are skipped unless `includeSlots: true` (slots
|
|
51
51
|
* share their parent's URL and are not addressable on their own).
|
|
52
|
+
* - Intercepting subtrees are skipped unconditionally. They render only
|
|
53
|
+
* on soft navigation and add no URL depth, so their computed `urlPath`s
|
|
54
|
+
* are not addresses — listing them would advertise routes (`/[year]`)
|
|
55
|
+
* that no request can reach. This matches every other consumer of the
|
|
56
|
+
* tree that produces URLs: the sitemap generator, the static generator,
|
|
57
|
+
* prerendering and the prebuilt-payload builder all skip them too.
|
|
52
58
|
* - Result is sorted by `urlPath` for deterministic output.
|
|
53
59
|
*/
|
|
54
60
|
export function collectLeafRoutes<TFile>(
|
|
@@ -68,6 +74,8 @@ function walk<TFile>(
|
|
|
68
74
|
result: LeafRoute<TFile>[],
|
|
69
75
|
includeSlots: boolean
|
|
70
76
|
): void {
|
|
77
|
+
if (node.segmentType === 'intercepting') return;
|
|
78
|
+
|
|
71
79
|
const currentChain = [...chain, node];
|
|
72
80
|
const path = node.urlPath || '/';
|
|
73
81
|
|
package/src/schema-bridge.ts
CHANGED
|
@@ -5,8 +5,17 @@
|
|
|
5
5
|
* This module is the single source of truth for:
|
|
6
6
|
* - StandardSchemaV1 interface (subset of the Standard Schema spec)
|
|
7
7
|
* - validateSync() helper
|
|
8
|
-
* - fromSchema() — bridge
|
|
9
|
-
* - fromArraySchema() —
|
|
8
|
+
* - fromSchema() — search-param bridge; scalar shape first, array second
|
|
9
|
+
* - fromArraySchema() — same loop, array shape first
|
|
10
|
+
* - fromCookieSchema() — scalar shape only; a cookie has no array shape
|
|
11
|
+
* - fromParamSchema() — route params; throws on failure (invalid param → 404)
|
|
12
|
+
*
|
|
13
|
+
* One parse loop, four candidate orders. Which shapes a bridge offers, and
|
|
14
|
+
* in what order, is the ONLY thing that differs — see §"Shape tolerance"
|
|
15
|
+
* below and in design/23-search-params.md. `serialize` is deliberately NOT
|
|
16
|
+
* shared: `null` means "omit the key" for a search param and "delete the
|
|
17
|
+
* cookie" for a cookie, so unifying it silently changed what
|
|
18
|
+
* `cookie.set([])` did (TIM-1352).
|
|
10
19
|
*
|
|
11
20
|
* These are re-exported from @timber-js/app/search-params, @timber-js/app/segment-params,
|
|
12
21
|
* and @timber-js/app/cookies for convenience. The canonical import is
|
|
@@ -122,18 +131,21 @@ export function fromParamSchema<T>(fieldName: string, schema: StandardSchemaV1<T
|
|
|
122
131
|
* @param fieldName - used in error messages
|
|
123
132
|
* @param value - the codec or schema to resolve
|
|
124
133
|
* @param mode - 'param' uses fromParamSchema (throws on parse failure),
|
|
125
|
-
* 'search' uses fromSchema (falls back to default on failure
|
|
134
|
+
* 'search' uses fromSchema (falls back to default on failure,
|
|
135
|
+
* tolerant of the repeated-key array shape),
|
|
136
|
+
* 'cookie' uses fromCookieSchema (same, minus the array shape,
|
|
137
|
+
* which a cookie value cannot have)
|
|
126
138
|
*/
|
|
127
139
|
export function resolveCodecOrSchema(
|
|
128
140
|
fieldName: string,
|
|
129
141
|
value: unknown,
|
|
130
|
-
mode: 'param' | 'search' = 'search'
|
|
142
|
+
mode: 'param' | 'search' | 'cookie' = 'search'
|
|
131
143
|
): Codec<unknown> {
|
|
132
144
|
if (isCodec(value)) return value;
|
|
133
145
|
if (isStandardSchema(value)) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
146
|
+
if (mode === 'param') return fromParamSchema(fieldName, value);
|
|
147
|
+
if (mode === 'cookie') return fromCookieSchema(value) as Codec<unknown>;
|
|
148
|
+
return fromSchema(value) as Codec<unknown>;
|
|
137
149
|
}
|
|
138
150
|
throw new Error(
|
|
139
151
|
`[timber] Field '${fieldName}' is not a valid codec or Standard Schema. ` +
|
|
@@ -146,51 +158,169 @@ export function resolveCodecOrSchema(
|
|
|
146
158
|
// fromSchema — bridge from Standard Schema to Codec<T>
|
|
147
159
|
// ---------------------------------------------------------------------------
|
|
148
160
|
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// Shape tolerance — the shared parse loop for both bridges
|
|
163
|
+
//
|
|
164
|
+
// A URL value is `string | string[] | undefined`, but a schema is written
|
|
165
|
+
// against ONE of those: `z.string()` wants `'a'`, `z.array(z.string())`
|
|
166
|
+
// wants `['a']`. Nothing in Standard Schema says which — `~standard.types`
|
|
167
|
+
// exists at the type level only, and probing at runtime is not reliable
|
|
168
|
+
// (design/23-search-params.md §"Shape tolerance"). So a bridge tries BOTH
|
|
169
|
+
// shapes rather than committing to one and discarding the value when it
|
|
170
|
+
// guessed wrong.
|
|
171
|
+
//
|
|
172
|
+
// Each bridge only chooses WHICH candidates, and in what order. The first
|
|
173
|
+
// candidate is always the shape that bridge already passed, so nothing that
|
|
174
|
+
// parses today changes meaning; a later one is reached only where the old
|
|
175
|
+
// code fell through to the default. `fromCookieSchema` offers ONE candidate,
|
|
176
|
+
// because a cookie has no array shape at all.
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The scalar shape, and only it. A value that cannot be repeated — a cookie —
|
|
181
|
+
* has no array shape to tolerate, so its bridge stays exactly where it was.
|
|
182
|
+
*/
|
|
183
|
+
function scalarOnly(value: string | string[] | undefined): unknown[] {
|
|
184
|
+
return [Array.isArray(value) ? value[0] : value];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Candidate inputs for the scalar bridge: scalar first, array second. */
|
|
188
|
+
function scalarFirst(value: string | string[] | undefined): unknown[] {
|
|
189
|
+
if (value === undefined) return [undefined];
|
|
190
|
+
if (typeof value === 'string') return [value, [value]];
|
|
191
|
+
// Repeated keys: `value[0]` matches URLSearchParams.get().
|
|
192
|
+
//
|
|
193
|
+
// A raw `[]` carries no value at all. `value[0]` is `undefined`, which is
|
|
194
|
+
// the shape the scalar bridge has always passed for it, so `undefined`
|
|
195
|
+
// stays FIRST — an empty array must keep meaning "absent" and land on the
|
|
196
|
+
// schema's default. Only `defineSearchParams().parse({ tags: [] })`, the
|
|
197
|
+
// record form, can produce one: URLSearchParams never yields an empty list.
|
|
198
|
+
return value.length > 0 ? [value[0], value] : [undefined, value];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Candidate inputs for the array bridge: array first, scalar second. */
|
|
202
|
+
function arrayFirst(value: string | string[] | undefined): unknown[] {
|
|
203
|
+
if (value === undefined) return [undefined];
|
|
204
|
+
if (typeof value === 'string') return [[value], value];
|
|
205
|
+
// `[]` first here for the same reason, inverted: the array bridge has
|
|
206
|
+
// always passed the empty array straight through.
|
|
207
|
+
return value.length > 0 ? [value, value[0]] : [value, undefined];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Validate `value` against `schema` in each candidate shape, then fall back
|
|
212
|
+
* to the schema's default. Shared by every bridge — they differ only in
|
|
213
|
+
* which candidates they offer, and in what order.
|
|
214
|
+
*/
|
|
215
|
+
function parseThroughSchema<T>(
|
|
216
|
+
schema: StandardSchemaV1<T>,
|
|
217
|
+
candidates: (value: string | string[] | undefined) => unknown[],
|
|
218
|
+
value: string | string[] | undefined
|
|
219
|
+
): T {
|
|
220
|
+
const inputs = candidates(value);
|
|
221
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
222
|
+
// A throw from the FIRST candidate propagates, unchanged: that is the
|
|
223
|
+
// shape the schema was written against, and a throw from it is the
|
|
224
|
+
// deliberate signal design/23 protects — an app schema may `redirect()`
|
|
225
|
+
// or `notFound()` on a value it refuses, and `validateSync` throws on
|
|
226
|
+
// an async schema.
|
|
227
|
+
//
|
|
228
|
+
// A throw from a LATER candidate is ours, not the app's. We invented
|
|
229
|
+
// that shape; the schema never agreed to receive it. A scalar-only
|
|
230
|
+
// hand-written validator doing `value.toUpperCase()`, or a schema that
|
|
231
|
+
// is async for the array shape only, would turn a field that used to
|
|
232
|
+
// fall back to its default into a render-phase 500. Treat it as "this
|
|
233
|
+
// shape does not fit" and keep going.
|
|
234
|
+
let result: StandardSchemaResult<T>;
|
|
235
|
+
try {
|
|
236
|
+
result = validateSync(schema, inputs[i]);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (i === 0) throw error;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (!result.issues) {
|
|
242
|
+
return result.value;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// No shape validated — try parsing undefined to get the default.
|
|
247
|
+
// Re-validate each time so factory defaults (e.g. .default(() => []))
|
|
248
|
+
// produce fresh values.
|
|
249
|
+
const defaultResult = validateSync(schema, undefined);
|
|
250
|
+
if (!defaultResult.issues) {
|
|
251
|
+
return defaultResult.value;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// No default available — the field is implicitly optional. Return
|
|
255
|
+
// undefined; defineSearchParams widens the field's inferred type to
|
|
256
|
+
// T | undefined via InferField so this doesn't lie.
|
|
257
|
+
// design/23-search-params.md §"Implicit Optionality"
|
|
258
|
+
return undefined as T;
|
|
259
|
+
}
|
|
260
|
+
|
|
149
261
|
/**
|
|
150
262
|
* Bridge a Standard Schema-compatible schema (Zod, Valibot, ArkType) to a
|
|
151
263
|
* Codec<T>.
|
|
152
264
|
*
|
|
153
|
-
* Parse: coerces the raw
|
|
154
|
-
*
|
|
155
|
-
*
|
|
265
|
+
* Parse: coerces the raw URL value through the schema, trying the scalar
|
|
266
|
+
* shape and then the array shape (see `scalarFirst`), so an array schema
|
|
267
|
+
* works bare: `z.array(z.string()).default([])` yields `[]` when absent,
|
|
268
|
+
* `['a']` for `?tags=a`, and `['a','b']` for `?tags=a&tags=b`. When no
|
|
269
|
+
* shape validates, parses `undefined` to get the schema's default (the
|
|
270
|
+
* schema should have a `.default()` call). If that also fails, returns
|
|
271
|
+
* `undefined`.
|
|
156
272
|
*
|
|
157
|
-
* Serialize:
|
|
273
|
+
* Serialize: `String()` for primitives, `null` for null/undefined. Note
|
|
274
|
+
* that `String(['a','b'])` is `'a,b'` — the same string `fromArraySchema`
|
|
275
|
+
* writes — so a bare array schema round-trips exactly as design/09
|
|
276
|
+
* §"Array params" describes.
|
|
277
|
+
*
|
|
278
|
+
* This is the SEARCH-PARAM bridge. Cookies use `fromCookieSchema`; a
|
|
279
|
+
* cookie has no array shape (see below).
|
|
158
280
|
*
|
|
159
281
|
* ```ts
|
|
160
|
-
* import { fromSchema } from '@timber-js/app/codec'
|
|
161
282
|
* import { z } from 'zod/v4'
|
|
162
283
|
*
|
|
163
284
|
* const pageCodec = fromSchema(z.coerce.number().int().min(1).default(1))
|
|
285
|
+
* const tagsCodec = fromSchema(z.array(z.string()).default([]))
|
|
164
286
|
* ```
|
|
165
287
|
*/
|
|
166
288
|
export function fromSchema<T>(schema: StandardSchemaV1<T>): Codec<T> {
|
|
167
289
|
return {
|
|
168
|
-
parse(value: string | string[] | undefined): T
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
// Try parsing the raw value
|
|
174
|
-
const result = validateSync(schema, input);
|
|
175
|
-
if (!result.issues) {
|
|
176
|
-
return result.value;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// On failure, try parsing undefined to get the default.
|
|
180
|
-
// Re-validate each time so factory defaults (e.g. .default(() => []))
|
|
181
|
-
// produce fresh values.
|
|
182
|
-
const defaultResult = validateSync(schema, undefined);
|
|
183
|
-
if (!defaultResult.issues) {
|
|
184
|
-
return defaultResult.value;
|
|
290
|
+
parse: (value: string | string[] | undefined): T =>
|
|
291
|
+
parseThroughSchema(schema, scalarFirst, value),
|
|
292
|
+
serialize(value: T): string | null {
|
|
293
|
+
if (value === null || value === undefined) {
|
|
294
|
+
return null;
|
|
185
295
|
}
|
|
186
|
-
|
|
187
|
-
// No default available — the field is implicitly optional. Return
|
|
188
|
-
// undefined; defineSearchParams widens the field's inferred type to
|
|
189
|
-
// T | undefined via InferField so this doesn't lie.
|
|
190
|
-
// design/23-search-params.md §"Implicit Optionality"
|
|
191
|
-
return undefined as T;
|
|
296
|
+
return String(value);
|
|
192
297
|
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
193
300
|
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
// fromCookieSchema — bridge for cookie values
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Bridge a Standard Schema for a COOKIE value.
|
|
307
|
+
*
|
|
308
|
+
* Identical to `fromSchema` minus the array shape, because a cookie cannot
|
|
309
|
+
* carry one: `Cookie:` headers and `document.cookie` yield a single string
|
|
310
|
+
* per name, and there is no repeated-key concept to be tolerant of. Sharing
|
|
311
|
+
* the search-param bridge here meant a cookie written by this very codec —
|
|
312
|
+
* `serialize(['a','b'])` → `a,b` — read back as the one-element array
|
|
313
|
+
* `['a,b']` instead of failing to its default: no repeated key in sight,
|
|
314
|
+
* just a delimiter reinterpreted as data.
|
|
315
|
+
*
|
|
316
|
+
* The `serialize` contract also differs by domain and must not be unified:
|
|
317
|
+
* for a search param `null` means "omit the key", for a cookie it means
|
|
318
|
+
* **delete the cookie** (design/29-cookies.md).
|
|
319
|
+
*/
|
|
320
|
+
export function fromCookieSchema<T>(schema: StandardSchemaV1<T>): Codec<T> {
|
|
321
|
+
return {
|
|
322
|
+
parse: (value: string | string[] | undefined): T =>
|
|
323
|
+
parseThroughSchema(schema, scalarOnly, value),
|
|
194
324
|
serialize(value: T): string | null {
|
|
195
325
|
if (value === null || value === undefined) {
|
|
196
326
|
return null;
|
|
@@ -214,32 +344,24 @@ export function fromSchema<T>(schema: StandardSchemaV1<T>): Codec<T> {
|
|
|
214
344
|
*
|
|
215
345
|
* const tagsCodec = fromArraySchema(z.array(z.string()).default([]))
|
|
216
346
|
* ```
|
|
347
|
+
*
|
|
348
|
+
* Since TIM-1352 a bare array schema works through `fromSchema` too, so
|
|
349
|
+
* this is no longer required to make an array field parse. Two cases still
|
|
350
|
+
* want it, both listed in design/23 §"Shape tolerance":
|
|
351
|
+
*
|
|
352
|
+
* 1. A **permissive** schema meant as an array — one that accepts a string
|
|
353
|
+
* as readily as an array (`z.any()`, a hand-written coercing validator)
|
|
354
|
+
* — where scalar-first ordering would settle on the scalar shape.
|
|
355
|
+
* 2. An array schema wrapped in `.catch([])`, which swallows the failure
|
|
356
|
+
* that would otherwise trigger the array attempt.
|
|
357
|
+
*
|
|
358
|
+
* It also serializes an empty array to `null` (omitting the key) where
|
|
359
|
+
* `fromSchema` writes `''`.
|
|
217
360
|
*/
|
|
218
361
|
export function fromArraySchema<T>(schema: StandardSchemaV1<T>): Codec<T> {
|
|
219
362
|
return {
|
|
220
|
-
parse(value: string | string[] | undefined): T
|
|
221
|
-
|
|
222
|
-
let input: unknown = value;
|
|
223
|
-
if (typeof value === 'string') {
|
|
224
|
-
input = [value];
|
|
225
|
-
} else if (value === undefined) {
|
|
226
|
-
input = undefined;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const result = validateSync(schema, input);
|
|
230
|
-
if (!result.issues) {
|
|
231
|
-
return result.value;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// On failure, try undefined for default
|
|
235
|
-
const defaultResult = validateSync(schema, undefined);
|
|
236
|
-
if (!defaultResult.issues) {
|
|
237
|
-
return defaultResult.value;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return undefined as T;
|
|
241
|
-
},
|
|
242
|
-
|
|
363
|
+
parse: (value: string | string[] | undefined): T =>
|
|
364
|
+
parseThroughSchema(schema, arrayFirst, value),
|
|
243
365
|
serialize(value: T): string | null {
|
|
244
366
|
if (value === null || value === undefined) {
|
|
245
367
|
return null;
|