@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
|
@@ -14,35 +14,13 @@ import { useQueryStates as clientUseQueryStates } from '../client/use-query-stat
|
|
|
14
14
|
import { fromSchema, isStandardSchema, isCodec } from '../schema-bridge.js';
|
|
15
15
|
import type { StandardSchemaV1 } from '../schema-bridge.js';
|
|
16
16
|
import type { Codec } from '../codec.js';
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// dynamic import loses AsyncLocalStorage context in React's RSC Flight renderer,
|
|
25
|
-
// breaking getSearchParams() in parallel slot pages. See TIM-523.
|
|
26
|
-
let _getSearchParamsFn: (() => URLSearchParams) | undefined;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Register the getSearchParams function. Called once at module load time
|
|
30
|
-
* from request-context.ts to avoid dynamic import at call time.
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
export function _setGetSearchParamsFn(fn: () => URLSearchParams): void {
|
|
34
|
-
_getSearchParamsFn = fn;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function getSearchParamsFromAls(): URLSearchParams {
|
|
38
|
-
if (!_getSearchParamsFn) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
'[timber] searchParams.get() is only available on the server. ' +
|
|
41
|
-
'Use searchParams.useQueryStates() on the client.'
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
return _getSearchParamsFn();
|
|
45
|
-
}
|
|
17
|
+
// Server-only reference for .get() — avoids pulling server ALS into client
|
|
18
|
+
// bundles. In client environments, .get() throws before reaching this code
|
|
19
|
+
// path. The slot lives in its own leaf module so that `request-context.ts`
|
|
20
|
+
// can register the getter without importing this file, which would drag
|
|
21
|
+
// `nuqs` into every server entry (TIM-1298). See shared/als-slots.ts.
|
|
22
|
+
import { getSearchParamsFromAls } from '../shared/als-slots.js';
|
|
23
|
+
import { parseTotal } from './parse-total.js';
|
|
46
24
|
|
|
47
25
|
// ---------------------------------------------------------------------------
|
|
48
26
|
// Types
|
|
@@ -51,13 +29,43 @@ function getSearchParamsFromAls(): URLSearchParams {
|
|
|
51
29
|
/**
|
|
52
30
|
* A codec that converts between URL string values and typed values.
|
|
53
31
|
*
|
|
54
|
-
*
|
|
32
|
+
* `parse` receives the RAW url value: `string | string[] | undefined`.
|
|
33
|
+
* A codec must be TOTAL over that domain — return a default rather than
|
|
34
|
+
* throwing on an absent or repeated param.
|
|
35
|
+
*
|
|
36
|
+
* A codec whose own `parse` covers only a PRESENT, SINGLE-VALUED param
|
|
37
|
+
* may publish `parseServerSide` instead, and timber calls that. nuqs
|
|
38
|
+
* parsers do exactly this, which is how they become total here: absent →
|
|
39
|
+
* `null` (or their `withDefault` value), repeated → the first value, and
|
|
40
|
+
* a throw from the inner parse → `null`. See
|
|
41
|
+
* design/23-search-params.md §'nuqs parsers, made total',
|
|
42
|
+
* `parse-total.ts`, and tests/nuqs-codec-boundary.test.ts (TIM-1350).
|
|
43
|
+
*
|
|
55
44
|
* Standard Schema objects (Zod, Valibot, ArkType) are auto-detected
|
|
56
|
-
* by defineSearchParams and wrapped via fromSchema
|
|
45
|
+
* by defineSearchParams and wrapped via fromSchema; those ARE total
|
|
46
|
+
* through `parse` and are called that way.
|
|
57
47
|
*/
|
|
58
48
|
export interface SearchParamCodec<T> extends Codec<T> {
|
|
59
49
|
/** Optional URL key alias, set by withUrlKey(). */
|
|
60
50
|
urlKey?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Optional TOTAL entry point over `string | string[] | undefined`,
|
|
53
|
+
* preferred over `parse` wherever timber invokes a codec. Declared here
|
|
54
|
+
* so the protocol is typed rather than duck-checked at each wrapper:
|
|
55
|
+
* anything that reconstructs a codec has to carry it, and a wrapper
|
|
56
|
+
* cannot carry a property the interface does not admit.
|
|
57
|
+
*
|
|
58
|
+
* It returns `T`, not `T | null`. This is the entry point timber calls,
|
|
59
|
+
* so whatever it returns IS the field's type — admitting a `null` the
|
|
60
|
+
* field type did not carry would let `SearchParamCodec<string>` produce
|
|
61
|
+
* `null` for an absent param under a non-nullable annotation. A codec
|
|
62
|
+
* whose absent-case answer is `null` declares that in `T`, exactly as a
|
|
63
|
+
* bare nuqs parser does: `parseAsString` is a `SearchParamCodec<string |
|
|
64
|
+
* null>` here, never a `SearchParamCodec<string>`.
|
|
65
|
+
*
|
|
66
|
+
* nuqs parser builders satisfy this. See parse-total.ts.
|
|
67
|
+
*/
|
|
68
|
+
parseServerSide?(value: string | string[] | undefined): T;
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
/** A codec with a URL key alias attached via withUrlKey(). */
|
|
@@ -116,7 +124,7 @@ export interface SearchParamsDefinition<T extends Record<string, unknown>> {
|
|
|
116
124
|
*
|
|
117
125
|
* ```tsx
|
|
118
126
|
* // app/products/page.tsx
|
|
119
|
-
* import { searchParams } from './params'
|
|
127
|
+
* import { searchParams } from './search-params'
|
|
120
128
|
* export default function Page() {
|
|
121
129
|
* const { page, category } = searchParams.get()
|
|
122
130
|
* }
|
|
@@ -135,15 +143,21 @@ export interface SearchParamsDefinition<T extends Record<string, unknown>> {
|
|
|
135
143
|
/** Pick a subset of keys. Preserves codecs and aliases. */
|
|
136
144
|
pick<K extends keyof T & string>(...keys: K[]): SearchParamsDefinition<Pick<T, K>>;
|
|
137
145
|
|
|
138
|
-
/**
|
|
139
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Serialize values to a query string (no leading '?'), omitting defaults
|
|
148
|
+
* and applying `withUrlKey` aliases. This is the value to pass to
|
|
149
|
+
* `<Link searchParams={...}>`.
|
|
150
|
+
*
|
|
151
|
+
* Returns a **string**, not a `URLSearchParams`. A `<Link>` prop crosses
|
|
152
|
+
* the RSC Flight boundary, and `URLSearchParams` is iterable — React
|
|
153
|
+
* serializes it as an entries array, which arrives as `[['pg','2'], …]`
|
|
154
|
+
* and renders as `?0=pg&0=2`. A string survives intact.
|
|
155
|
+
*/
|
|
156
|
+
buildSearchParams(values: Partial<T>): string;
|
|
140
157
|
|
|
141
158
|
/** Build a full path with query string, omitting defaults. */
|
|
142
159
|
href(pathname: string, values: Partial<T>): string;
|
|
143
160
|
|
|
144
|
-
/** Build a URLSearchParams instance, omitting defaults. */
|
|
145
|
-
toSearchParams(values: Partial<T>): URLSearchParams;
|
|
146
|
-
|
|
147
161
|
/** Read-only codec map for spreading into .extend(). */
|
|
148
162
|
codecs: { [K in keyof T]: SearchParamCodec<T[K]> };
|
|
149
163
|
|
|
@@ -182,6 +196,21 @@ type InferSchemaInput<V> = V extends { '~standard': { types?: infer TS } }
|
|
|
182
196
|
/**
|
|
183
197
|
* Infer the output type from either a SearchParamCodec or a StandardSchemaV1.
|
|
184
198
|
*
|
|
199
|
+
* A codec publishing `parseServerSide` is read through THAT signature, not
|
|
200
|
+
* through `parse` — it is the entry point timber actually calls, and it is
|
|
201
|
+
* the one that tells the truth about absent input. A bare `parseAsString`
|
|
202
|
+
* declares `parse(value: string): string` but answers `null` for a missing
|
|
203
|
+
* param, so the field is `string | null`; `parseAsInteger.withDefault(1)`
|
|
204
|
+
* narrows its own `parseServerSide` to `NonNullable<number>` and the field
|
|
205
|
+
* stays `number`. Reading `parse` instead produced a non-nullable type for
|
|
206
|
+
* a nullable field (TIM-1350).
|
|
207
|
+
*
|
|
208
|
+
* The match is structural, not nuqs-specific: any codec declaring that
|
|
209
|
+
* signature opts into being read through it, which is exactly the contract
|
|
210
|
+
* `parseTotal` applies at runtime. The two must stay in step — a type
|
|
211
|
+
* inferred from `parse` while the runtime calls `parseServerSide` is the
|
|
212
|
+
* lie this branch exists to remove.
|
|
213
|
+
*
|
|
185
214
|
* Schemas whose input type rejects `undefined` (e.g. bare `z.string()`, whose
|
|
186
215
|
* input is `string`) are implicitly optional: the URL might not contain the
|
|
187
216
|
* param, and fromSchema returns `undefined` when the schema rejects absent
|
|
@@ -194,8 +223,11 @@ type InferSchemaInput<V> = V extends { '~standard': { types?: infer TS } }
|
|
|
194
223
|
* keeps its narrow output type even though absent input yields `undefined`
|
|
195
224
|
* at runtime. Add `.default()` to coerce schemas for accurate types.
|
|
196
225
|
*/
|
|
197
|
-
export type InferField<V> =
|
|
198
|
-
|
|
226
|
+
export type InferField<V> = V extends {
|
|
227
|
+
parseServerSide(value: string | string[] | undefined): infer R;
|
|
228
|
+
}
|
|
229
|
+
? R
|
|
230
|
+
: V extends SearchParamCodec<infer T>
|
|
199
231
|
? T
|
|
200
232
|
: V extends StandardSchemaV1<infer T>
|
|
201
233
|
? undefined extends InferSchemaInput<V>
|
|
@@ -233,13 +265,36 @@ function normalizeRaw(
|
|
|
233
265
|
* default-omission: when serialize(value) === serialize(parse(undefined)),
|
|
234
266
|
* the field is omitted from the URL.
|
|
235
267
|
*
|
|
268
|
+
* Goes through `parseTotal` for the same reason request-time parsing does:
|
|
269
|
+
* a nuqs parser's own `parse` throws on absent input, and this is the
|
|
270
|
+
* absent case by construction.
|
|
271
|
+
*
|
|
272
|
+
* **A codec with no value for an absent param has no default to omit**,
|
|
273
|
+
* and `null` is returned rather than `serialize(null)`. Serializing it
|
|
274
|
+
* makes the "no value" case collide with a real one: `parseAsInteger`
|
|
275
|
+
* serializes `null` as the string `'null'`, so `buildSearchParams({ q:
|
|
276
|
+
* 'null' })` would silently drop a legitimate value (before TIM-1350 the
|
|
277
|
+
* absent parse was `undefined` and the swallowed input was the string
|
|
278
|
+
* `'undefined'` — same defect, a less likely input). Nothing is lost:
|
|
279
|
+
* `buildSearchParams` already skips a field whose `serialize` returns
|
|
280
|
+
* `null`, so a codec that encodes "no value" as an omission behaves
|
|
281
|
+
* identically, and one that encodes it as a real query value now writes
|
|
282
|
+
* it instead of dropping it.
|
|
283
|
+
*
|
|
236
284
|
* Codecs are documented to return a default rather than throw, but a
|
|
237
285
|
* hand-written codec that throws on absent input must not turn definition
|
|
238
|
-
* into a crash — treat its default as null (nothing to omit).
|
|
286
|
+
* into a crash — treat its default as null (nothing to omit). `serialize`
|
|
287
|
+
* is inside the try for the same reason.
|
|
288
|
+
*
|
|
289
|
+
* Typed `SearchParamCodec<unknown>` rather than generic on purpose: the
|
|
290
|
+
* absent-input value is whatever the codec's total entry point returns,
|
|
291
|
+
* which for a nuqs parser is `T | null` while its `serialize` declares
|
|
292
|
+
* `T`. Widening to `unknown` states that honestly instead of casting.
|
|
239
293
|
*/
|
|
240
|
-
function getDefaultSerialized
|
|
294
|
+
function getDefaultSerialized(codec: SearchParamCodec<unknown>): string | null {
|
|
241
295
|
try {
|
|
242
|
-
|
|
296
|
+
const absent = parseTotal(codec, undefined);
|
|
297
|
+
return absent === null || absent === undefined ? null : codec.serialize(absent);
|
|
243
298
|
} catch {
|
|
244
299
|
return null;
|
|
245
300
|
}
|
|
@@ -405,7 +460,7 @@ function buildDefinition<T extends Record<string, unknown>>(
|
|
|
405
460
|
for (const prop of Object.keys(codecMap)) {
|
|
406
461
|
const urlKey = getUrlKey(prop);
|
|
407
462
|
const rawValue = normalized[urlKey];
|
|
408
|
-
result[prop] = (codecMap[prop as keyof T] as SearchParamCodec<unknown
|
|
463
|
+
result[prop] = parseTotal(codecMap[prop as keyof T] as SearchParamCodec<unknown>, rawValue);
|
|
409
464
|
}
|
|
410
465
|
|
|
411
466
|
return result as T;
|
|
@@ -429,8 +484,14 @@ function buildDefinition<T extends Record<string, unknown>>(
|
|
|
429
484
|
return parseSync(raw);
|
|
430
485
|
}
|
|
431
486
|
|
|
432
|
-
// ----
|
|
433
|
-
|
|
487
|
+
// ---- buildSearchParams ----
|
|
488
|
+
//
|
|
489
|
+
// Returns a query string. It used to have a URLSearchParams-returning
|
|
490
|
+
// sibling (`toSearchParams`) that `<Link>` consumed; that shape cannot
|
|
491
|
+
// cross the RSC Flight boundary (see the interface docstring), and having
|
|
492
|
+
// two methods produce the same query two ways was a drift waiting to
|
|
493
|
+
// happen. One method now.
|
|
494
|
+
function buildSearchParams(values: Partial<T>): string {
|
|
434
495
|
const parts: string[] = [];
|
|
435
496
|
|
|
436
497
|
for (const prop of Object.keys(codecMap)) {
|
|
@@ -450,28 +511,10 @@ function buildDefinition<T extends Record<string, unknown>>(
|
|
|
450
511
|
|
|
451
512
|
// ---- href ----
|
|
452
513
|
function href(pathname: string, values: Partial<T>): string {
|
|
453
|
-
const qs =
|
|
514
|
+
const qs = buildSearchParams(values);
|
|
454
515
|
return qs ? `${pathname}?${qs}` : pathname;
|
|
455
516
|
}
|
|
456
517
|
|
|
457
|
-
// ---- toSearchParams ----
|
|
458
|
-
function toSearchParams(values: Partial<T>): URLSearchParams {
|
|
459
|
-
const usp = new URLSearchParams();
|
|
460
|
-
|
|
461
|
-
for (const prop of Object.keys(codecMap)) {
|
|
462
|
-
if (!(prop in values)) continue;
|
|
463
|
-
const codec = codecMap[prop as keyof T] as SearchParamCodec<unknown>;
|
|
464
|
-
const serialized = codec.serialize(values[prop as keyof T] as unknown);
|
|
465
|
-
|
|
466
|
-
if (serialized === defaultSerialized[prop]) continue;
|
|
467
|
-
if (serialized === null) continue;
|
|
468
|
-
|
|
469
|
-
usp.set(getUrlKey(prop), serialized);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return usp;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
518
|
// ---- extend ----
|
|
476
519
|
function extend<U extends Record<string, SearchParamCodec<unknown> | StandardSchemaV1<unknown>>>(
|
|
477
520
|
newCodecs: U
|
|
@@ -565,9 +608,8 @@ function buildDefinition<T extends Record<string, unknown>>(
|
|
|
565
608
|
useQueryStates,
|
|
566
609
|
extend,
|
|
567
610
|
pick,
|
|
568
|
-
serialize,
|
|
569
611
|
href,
|
|
570
|
-
|
|
612
|
+
buildSearchParams,
|
|
571
613
|
codecs: codecMap,
|
|
572
614
|
urlKeys: Object.freeze({ ...urlKeys }),
|
|
573
615
|
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parseTotal — invoke a codec over the FULL raw domain.
|
|
3
|
+
*
|
|
4
|
+
* `SearchParamCodec.parse` is documented to be total over
|
|
5
|
+
* `string | string[] | undefined`, because that is exactly what a URL
|
|
6
|
+
* hands it: a param can be absent (`undefined`) or repeated (`string[]`).
|
|
7
|
+
* Timber's own codecs and the Standard Schema bridges honour that.
|
|
8
|
+
*
|
|
9
|
+
* nuqs parsers do not. Their `parse` expects a **present scalar string** —
|
|
10
|
+
* nuqs checks presence itself before ever calling it — so `parseAsBoolean`
|
|
11
|
+
* and `parseAsIsoDate` threw a render-phase 500 on an absent param and
|
|
12
|
+
* `parseAsString` returned an array on a repeated one (TIM-1350).
|
|
13
|
+
*
|
|
14
|
+
* nuqs ships the missing adapter: every parser builder exposes
|
|
15
|
+
* `parseServerSide(value: string | string[] | undefined)`, which maps
|
|
16
|
+
* absent → `null` (or the parser's `withDefault` value), takes the FIRST
|
|
17
|
+
* entry of a repeated param (matching `URLSearchParams.get()`), and wraps
|
|
18
|
+
* the inner `parse` so a throw becomes `null`. That is precisely timber's
|
|
19
|
+
* domain, so we call it in preference to `parse` rather than hand-rolling
|
|
20
|
+
* a second normalization that could disagree with the client hook.
|
|
21
|
+
*
|
|
22
|
+
* Feature detection, not an instanceof check: any codec MAY publish
|
|
23
|
+
* `parseServerSide` to declare "this is my total entry point" — it is an
|
|
24
|
+
* optional member of `SearchParamCodec` — and a codec that does not is
|
|
25
|
+
* assumed already total and called through `parse`. Timber codecs and
|
|
26
|
+
* schema bridges take the second branch untouched; several of them rely on
|
|
27
|
+
* `parse(undefined)` to produce their default.
|
|
28
|
+
*
|
|
29
|
+
* **Search params only.** Segment params (`server/param-coercion.ts`) call
|
|
30
|
+
* `codec.parse` directly and must keep doing so: their domain is a value
|
|
31
|
+
* the router matched, never absent, and a codec that REJECTS one is how a
|
|
32
|
+
* route produces a 404. Routing a rejection through nuqs's `safeParse`
|
|
33
|
+
* would turn that 404 into a silent `null` param. The two domains differ
|
|
34
|
+
* in what "no value" means, not just in plumbing. Cookies are a third
|
|
35
|
+
* domain (`cookies/define-cookie.ts`) and are likewise untouched.
|
|
36
|
+
*
|
|
37
|
+
* `parseServerSide` carries a `@deprecated` tag in nuqs (it steers users to
|
|
38
|
+
* loaders, which timber does not use). It remains public, typed and
|
|
39
|
+
* exercised; `tests/nuqs-codec-boundary.test.ts` asserts totality for every
|
|
40
|
+
* parser through timber's own API, so a nuqs release that drops it fails
|
|
41
|
+
* loudly rather than silently reinstating the 500s.
|
|
42
|
+
*
|
|
43
|
+
* Design doc: design/23-search-params.md §"nuqs parsers, made total"
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import type { Codec } from '../codec.js';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A codec that publishes a total entry point over the raw URL domain.
|
|
50
|
+
*
|
|
51
|
+
* The return is `T`, not `T | null`: this is the entry point timber calls,
|
|
52
|
+
* so whatever it answers IS the field's type. A `null` for an absent param
|
|
53
|
+
* belongs in `T` — a bare nuqs parser is a codec of `string | null`, and
|
|
54
|
+
* `parseAsInteger.withDefault(1)` is a codec of `number`, because nuqs
|
|
55
|
+
* narrows its own `parseServerSide` return to `NonNullable<T>`. Declaring
|
|
56
|
+
* `T | null` here would let a codec annotated `SearchParamCodec<string>`
|
|
57
|
+
* hand back `null` under a non-nullable type (TIM-1350 review).
|
|
58
|
+
*/
|
|
59
|
+
export interface TotalCodec<T> {
|
|
60
|
+
parseServerSide(value: string | string[] | undefined): T;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function hasParseServerSide<T>(codec: Codec<T>): codec is Codec<T> & TotalCodec<T> {
|
|
64
|
+
return typeof (codec as Partial<TotalCodec<T>>).parseServerSide === 'function';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Parse a raw URL value through a codec, using the codec's total entry
|
|
69
|
+
* point when it publishes one.
|
|
70
|
+
*
|
|
71
|
+
* Returns `T`, from both branches. A `null` for an absent param is part of
|
|
72
|
+
* the codec's own `T` — see TotalCodec above — so this signature does not
|
|
73
|
+
* widen it, and a caller that must handle "no value" (`withDefault`) sees
|
|
74
|
+
* it because `T` carries it.
|
|
75
|
+
*/
|
|
76
|
+
export function parseTotal<T>(codec: Codec<T>, raw: string | string[] | undefined): T {
|
|
77
|
+
return hasParseServerSide(codec) ? codec.parseServerSide(raw) : codec.parse(raw);
|
|
78
|
+
}
|
|
@@ -15,14 +15,32 @@ import type {
|
|
|
15
15
|
SearchParamField,
|
|
16
16
|
} from './define.js';
|
|
17
17
|
import { isCodec, isStandardSchema, fromSchema } from '../schema-bridge.js';
|
|
18
|
+
import { parseTotal } from './parse-total.js';
|
|
18
19
|
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
21
|
// withDefault
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
* Wrap a nullable codec with a default value.
|
|
25
|
-
*
|
|
25
|
+
* Wrap a nullable codec with a default value. The output type becomes
|
|
26
|
+
* non-nullable, and the wrapper is TOTAL over `string | string[] |
|
|
27
|
+
* undefined` even when the inner codec is not.
|
|
28
|
+
*
|
|
29
|
+
* The default is substituted for `null` — the documented "no value"
|
|
30
|
+
* answer — and for `undefined`, which is what an implicitly-optional
|
|
31
|
+
* Standard Schema field and a bare `parseAsString` produce for an absent
|
|
32
|
+
* param. Substituting only for `null` left a field typed non-nullable
|
|
33
|
+
* `string` holding `undefined` (TIM-1350).
|
|
34
|
+
*
|
|
35
|
+
* The inner codec is invoked through `parseTotal`, so a nuqs parser gets
|
|
36
|
+
* its own normalization (absent → null, repeated → first value, inner
|
|
37
|
+
* throw → null) before either check applies. That is what makes
|
|
38
|
+
* `withDefault(parseAsBoolean, false)` total; the wrapper itself does NOT
|
|
39
|
+
* catch. A throw from a codec is a deliberate signal — `fromSchema` throws
|
|
40
|
+
* on an async schema, and an app codec may `redirect()` or `notFound()` on
|
|
41
|
+
* a value it refuses — and swallowing it would convert a loud failure into
|
|
42
|
+
* a permanently-default field. design/09 §"The SearchParamCodec Protocol":
|
|
43
|
+
* a codec that throws bubbles as a render-phase error, by design.
|
|
26
44
|
*
|
|
27
45
|
* Works with any codec — nuqs parsers, custom codecs, fromSchema results.
|
|
28
46
|
*
|
|
@@ -34,20 +52,35 @@ import { isCodec, isStandardSchema, fromSchema } from '../schema-bridge.js';
|
|
|
34
52
|
* // page.parse(undefined) → 1 (not null)
|
|
35
53
|
* // page.parse('5') → 5
|
|
36
54
|
* ```
|
|
55
|
+
*
|
|
56
|
+
* The signature strips BOTH nullish constituents from the result, not just
|
|
57
|
+
* `null`, because the runtime substitutes for both. An implicitly-optional
|
|
58
|
+
* schema field is a `SearchParamCodec<string | undefined>`, and wrapping it
|
|
59
|
+
* used to yield `SearchParamCodec<string | undefined>` — a field the
|
|
60
|
+
* wrapper guarantees is always present, still typed as maybe-absent.
|
|
37
61
|
*/
|
|
38
62
|
export function withDefault<T>(
|
|
39
|
-
codec: SearchParamCodec<T | null>,
|
|
40
|
-
defaultValue: T
|
|
41
|
-
): SearchParamCodec<T
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
63
|
+
codec: SearchParamCodec<T | null | undefined>,
|
|
64
|
+
defaultValue: NonNullable<T>
|
|
65
|
+
): SearchParamCodec<NonNullable<T>> {
|
|
66
|
+
// A wrapper that rebuilds a codec from two methods drops everything else
|
|
67
|
+
// the codec carries. `withUrlKey` lost `parseServerSide` that way; this
|
|
68
|
+
// one lost `urlKey`, so `withDefault(withUrlKey(parseAsInteger, 'p'), 1)`
|
|
69
|
+
// silently read `?page=` instead of `?p=`. Carry it explicitly rather
|
|
70
|
+
// than spreading: this wrapper's own `parse` IS the total entry point,
|
|
71
|
+
// and re-publishing the inner `parseServerSide` would let `parseTotal`
|
|
72
|
+
// reach past it and skip the default entirely.
|
|
73
|
+
const wrapped: SearchParamCodec<NonNullable<T>> = {
|
|
74
|
+
parse(value: string | string[] | undefined): NonNullable<T> {
|
|
75
|
+
const result = parseTotal(codec, value);
|
|
76
|
+
return result === null || result === undefined ? defaultValue : result;
|
|
46
77
|
},
|
|
47
|
-
serialize(value: T): string | null {
|
|
78
|
+
serialize(value: NonNullable<T>): string | null {
|
|
48
79
|
return codec.serialize(value);
|
|
49
80
|
},
|
|
50
81
|
};
|
|
82
|
+
if (codec.urlKey !== undefined) wrapped.urlKey = codec.urlKey;
|
|
83
|
+
return wrapped;
|
|
51
84
|
}
|
|
52
85
|
|
|
53
86
|
// ---------------------------------------------------------------------------
|
|
@@ -93,9 +126,25 @@ export function withUrlKey<F extends SearchParamField>(
|
|
|
93
126
|
: isStandardSchema(codecOrSchema)
|
|
94
127
|
? (fromSchema(codecOrSchema) as SearchParamCodec<T>)
|
|
95
128
|
: (codecOrSchema as SearchParamCodec<T>);
|
|
96
|
-
|
|
129
|
+
// Carry the total entry point, bound like the other two methods. A
|
|
130
|
+
// codec's totality lives in a THIRD property, `parseServerSide` (see
|
|
131
|
+
// parse-total.ts); picking only `parse`/`serialize` silently produced a
|
|
132
|
+
// non-total alias, so `withUrlKey(parseAsBoolean, 'b')` threw on an
|
|
133
|
+
// absent param while the bare parser did not (TIM-1350).
|
|
134
|
+
//
|
|
135
|
+
// Bound explicitly rather than spread: a spread copies own enumerable
|
|
136
|
+
// properties only, so a class-based codec — whose `parse` and
|
|
137
|
+
// `serialize` this wrapper already reaches through the prototype —
|
|
138
|
+
// would have kept its methods and lost exactly the one that makes it
|
|
139
|
+
// total. Three properties, one rule, no dependence on how the inner
|
|
140
|
+
// codec was constructed.
|
|
141
|
+
const wrapped: SearchParamCodecWithUrlKey<T> = {
|
|
97
142
|
parse: codec.parse.bind(codec),
|
|
98
143
|
serialize: codec.serialize.bind(codec),
|
|
99
144
|
urlKey,
|
|
100
145
|
};
|
|
146
|
+
if (typeof codec.parseServerSide === 'function') {
|
|
147
|
+
wrapped.parseServerSide = codec.parseServerSide.bind(codec);
|
|
148
|
+
}
|
|
149
|
+
return wrapped;
|
|
101
150
|
}
|
|
@@ -18,7 +18,7 @@ import type { AccessGateProps, SlotAccessGateProps } from './tree-builder.js';
|
|
|
18
18
|
import { withSpan, setSpanAttribute } from './tracing.js';
|
|
19
19
|
import { isDebug } from './debug.js';
|
|
20
20
|
import type { DenyPageEntry } from './deny-boundary.js';
|
|
21
|
-
import {
|
|
21
|
+
import { handleCaughtDeny, setFirstDeniedSegmentIndex } from './deny-boundary.js';
|
|
22
22
|
import type { ReactNode } from 'react';
|
|
23
23
|
|
|
24
24
|
// ─── AccessGate ─────────────────────────────────────────────────────────────
|
|
@@ -26,50 +26,64 @@ import type { ReactNode } from 'react';
|
|
|
26
26
|
/**
|
|
27
27
|
* Framework-injected access gate for segments.
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* When no verdict is provided (backward compat with tree-builder.ts),
|
|
35
|
-
* AccessGate calls accessFn directly with OTEL instrumentation.
|
|
29
|
+
* Calls accessFn during render — inside `renderToReadableStream`, sharing
|
|
30
|
+
* the same `React.cache` scope as layouts and pages. A `requireUser()`
|
|
31
|
+
* call in access.ts populates the cache; the same call in any layout is
|
|
32
|
+
* a free hit. Access executes exactly once per request. See TIM-1363.
|
|
36
33
|
*
|
|
37
34
|
* access.ts is a pure gate — return values are discarded. The layout below
|
|
38
35
|
* gets the same data by calling the same cached functions (React.cache dedup).
|
|
36
|
+
*
|
|
37
|
+
* On denial the gate renders the matching deny page only when this segment
|
|
38
|
+
* owns it. Because the gate is wrapped OUTSIDE its own layout, that render
|
|
39
|
+
* omits the denying segment's layout — deliberate, and the one place the
|
|
40
|
+
* in-tree path diverges from `renderDenyPage`'s inclusive slice: a layout
|
|
41
|
+
* whose access.ts denied must never run and serialize protected data into
|
|
42
|
+
* the Flight stream (TIM-1074). An ancestor-owned page is hoisted instead,
|
|
43
|
+
* because the gate also sits inside every layout above it and rendering
|
|
44
|
+
* here would wrap the deny page in all of them (TIM-1356).
|
|
45
|
+
*
|
|
46
|
+
* For skipped segments (skippedSegment=true), deny pages are NOT rendered
|
|
47
|
+
* in-tree — the client's cached layout chrome would wrap them incorrectly.
|
|
48
|
+
* Instead, the deny is recorded in ALS and rethrown so the response path
|
|
49
|
+
* can return rscErrorEnvelope for a client hard-navigate.
|
|
39
50
|
*/
|
|
40
|
-
export function AccessGate(props: AccessGateProps):
|
|
41
|
-
const {
|
|
51
|
+
export function AccessGate(props: AccessGateProps): Promise<ReactNode> {
|
|
52
|
+
const {
|
|
53
|
+
accessFn,
|
|
54
|
+
segmentName,
|
|
55
|
+
segmentKey,
|
|
56
|
+
segmentIndex,
|
|
57
|
+
denyPages,
|
|
58
|
+
skippedSegment,
|
|
59
|
+
onSettled,
|
|
60
|
+
children,
|
|
61
|
+
} = props;
|
|
42
62
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return denyElement;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
throw verdict;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Primary path: call accessFn directly during render.
|
|
60
|
-
// If denyPages is provided, catch DenySignal and render the deny page
|
|
61
|
-
// in-tree — no throw reaches React Flight, no second render pass.
|
|
62
|
-
return accessGateFallback(accessFn, segmentName, denyPages, children);
|
|
63
|
+
return accessGateFallback(
|
|
64
|
+
accessFn,
|
|
65
|
+
segmentName,
|
|
66
|
+
segmentKey,
|
|
67
|
+
segmentIndex,
|
|
68
|
+
skippedSegment ? undefined : denyPages,
|
|
69
|
+
skippedSegment,
|
|
70
|
+
onSettled,
|
|
71
|
+
children
|
|
72
|
+
);
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
76
|
+
* Calls accessFn during render with OTEL instrumentation.
|
|
77
|
+
* Records the first denied segment index in ALS for post-render consumers.
|
|
68
78
|
*/
|
|
69
79
|
async function accessGateFallback(
|
|
70
80
|
accessFn: AccessGateProps['accessFn'],
|
|
71
81
|
segmentName: AccessGateProps['segmentName'],
|
|
82
|
+
segmentKey: AccessGateProps['segmentKey'],
|
|
83
|
+
segmentIndex: AccessGateProps['segmentIndex'],
|
|
72
84
|
denyPages: DenyPageEntry[] | undefined,
|
|
85
|
+
skippedSegment: boolean | undefined,
|
|
86
|
+
onSettled: (() => void) | undefined,
|
|
73
87
|
children: ReactNode
|
|
74
88
|
): Promise<ReactNode> {
|
|
75
89
|
try {
|
|
@@ -91,17 +105,23 @@ async function accessGateFallback(
|
|
|
91
105
|
}
|
|
92
106
|
});
|
|
93
107
|
} catch (error: unknown) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
108
|
+
if (error instanceof DenySignal) {
|
|
109
|
+
if (segmentIndex !== undefined) {
|
|
110
|
+
setFirstDeniedSegmentIndex(segmentIndex);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (skippedSegment) {
|
|
114
|
+
error._hardNavigate = true;
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (denyPages) {
|
|
119
|
+
return handleCaughtDeny(denyPages, error, segmentKey);
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
throw error;
|
|
123
|
+
} finally {
|
|
124
|
+
onSettled?.();
|
|
105
125
|
}
|
|
106
126
|
|
|
107
127
|
return children;
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import type { FormFlashData } from './form-flash.js';
|
|
37
37
|
import { checkVersionSkew, applyReloadHeaders } from './version-skew.js';
|
|
38
38
|
import { logActionError } from './logger.js';
|
|
39
|
+
import { RSC_CONTENT_TYPE } from '../shared/rsc-media-type.js';
|
|
39
40
|
|
|
40
41
|
// ─── Types ────────────────────────────────────────────────────────────────
|
|
41
42
|
|
|
@@ -55,10 +56,6 @@ export interface ActionDispatchConfig {
|
|
|
55
56
|
sensitiveFields?: SensitiveFieldsOption;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
// ─── Constants ────────────────────────────────────────────────────────────
|
|
59
|
-
|
|
60
|
-
const RSC_CONTENT_TYPE = 'text/x-component';
|
|
61
|
-
|
|
62
59
|
// ─── Detection ────────────────────────────────────────────────────────────
|
|
63
60
|
|
|
64
61
|
/**
|
|
@@ -296,7 +293,9 @@ async function handleRscAction(
|
|
|
296
293
|
// serialized together so React Flight handles both in one stream.
|
|
297
294
|
payload = {
|
|
298
295
|
_action: result.actionResult,
|
|
299
|
-
|
|
296
|
+
// The payload root, not a bare tree: it carries the revalidated
|
|
297
|
+
// route's params too, and the client publishes them (TIM-1297).
|
|
298
|
+
_tree: result.revalidation.payload,
|
|
300
299
|
};
|
|
301
300
|
headers['X-Timber-Revalidation'] = '1';
|
|
302
301
|
// Metadata (<title>/<meta>/<link>) now rides the revalidation element
|
package/src/server/actions.ts
CHANGED
|
@@ -20,10 +20,13 @@ import { withSpan } from './tracing';
|
|
|
20
20
|
import { revalidationAls, type RevalidationState } from './als-registry.js';
|
|
21
21
|
// ─── Types ───────────────────────────────────────────────────────────────
|
|
22
22
|
|
|
23
|
-
/** Result of rendering a revalidation —
|
|
23
|
+
/** Result of rendering a revalidation — payload root before RSC serialization. */
|
|
24
24
|
export interface RevalidationResult {
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* The payload root — tree plus the params it rendered with, exactly as an
|
|
27
|
+
* ordinary route payload. The client splits it in `applyRevalidation`.
|
|
28
|
+
*/
|
|
29
|
+
payload: unknown;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
/** Renderer function that builds a React element tree for a given path. */
|