@timber-js/app 0.2.0-alpha.185 → 0.2.0-alpha.186
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-C-Rw9vPc.js} +3 -3
- package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-C-Rw9vPc.js.map} +1 -1
- package/dist/_chunks/als-slots-mFweg276.js +27 -0
- package/dist/_chunks/als-slots-mFweg276.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-Cd0VZ_Pd.js} +3 -3
- package/dist/_chunks/{cache-api-B-lhk9p4.js.map → cache-api-Cd0VZ_Pd.js.map} +1 -1
- package/dist/_chunks/cli-schema-sync-CKgHC2MB.js +1857 -0
- package/dist/_chunks/cli-schema-sync-CKgHC2MB.js.map +1 -0
- package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-Cs0uZXea.js} +89 -12
- package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-Cs0uZXea.js.map} +1 -1
- package/dist/_chunks/error-boundary-DpYRI_I1.js +330 -0
- package/dist/_chunks/error-boundary-DpYRI_I1.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/fs-identity-D7vb6GdI.js +208 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
- package/dist/_chunks/{logger-AWfuX-KJ.js → logger-N7e5auP0.js} +9 -13
- package/dist/_chunks/logger-N7e5auP0.js.map +1 -0
- package/dist/_chunks/navigation-root-B29qg0_T.js +274 -0
- package/dist/_chunks/navigation-root-B29qg0_T.js.map +1 -0
- package/dist/_chunks/param-value-C8TNYchQ.js +66 -0
- package/dist/_chunks/param-value-C8TNYchQ.js.map +1 -0
- package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-DEGLSJs3.js} +2 -1
- package/dist/_chunks/plugin-context-DEGLSJs3.js.map +1 -0
- 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-payload-path-B_LBodc2.js +48 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
- package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
- package/dist/_chunks/{segment-classify-Byy425ng.js.map → segment-classify-C539Pa2O.js.map} +1 -1
- 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-segment-params-ClyUNq4d.js +128 -0
- package/dist/_chunks/use-segment-params-ClyUNq4d.js.map +1 -0
- package/dist/_chunks/{walkers-_6zKFlch.js → walkers-BhhwI9TD.js} +21 -87
- package/dist/_chunks/walkers-BhhwI9TD.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/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 +2 -3
- 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/cli.js +2 -2
- 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/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 +1 -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.js +18 -11
- 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 +865 -306
- package/dist/client/internal.js.map +1 -1
- 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 +71 -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 +38 -25
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +79 -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-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/cookies/index.js +3 -3
- package/dist/cookies/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +906 -321
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +31 -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 +9 -0
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +136 -8
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-types.d.ts +18 -0
- package/dist/routing/codegen-types.d.ts.map +1 -1
- 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/index.js +3 -3
- package/dist/routing/interception.d.ts +235 -6
- package/dist/routing/interception.d.ts.map +1 -1
- 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/walkers.d.ts +6 -0
- package/dist/routing/walkers.d.ts.map +1 -1
- package/dist/search-params/define.d.ts +0 -6
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.js +176 -2
- package/dist/search-params/index.js.map +1 -1
- package/dist/segment-params/define.d.ts +0 -6
- package/dist/segment-params/define.d.ts.map +1 -1
- package/dist/segment-params/index.js +69 -1
- package/dist/segment-params/index.js.map +1 -0
- package/dist/server/actions.d.ts +6 -3
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +2 -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/default-status-page.d.ts +45 -0
- package/dist/server/default-status-page.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +14 -3
- package/dist/server/deny-renderer.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.js +2 -2
- package/dist/server/internal.js +393 -212
- package/dist/server/internal.js.map +1 -1
- package/dist/server/param-coercion.d.ts +10 -1
- 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/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 +32 -2
- 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/error-renderer.d.ts +14 -2
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +2 -10
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -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/rsc-payload.d.ts +3 -2
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +3 -2
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +2 -0
- 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 +6 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -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/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-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/31-api-client.mdx +4 -2
- package/docs/learn/02-pages-and-layouts.mdx +1 -1
- package/docs/learn/11-error-handling.mdx +2 -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 +172 -2
- package/docs/more/04-metadata-and-fonts.mdx +1 -1
- package/package.json +2 -2
- package/src/adapters/build-output-helper.ts +116 -3
- package/src/adapters/cloudflare.ts +86 -11
- 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/client/browser-entry/action-dispatch.ts +9 -4
- package/src/client/browser-entry/hydrate.ts +40 -29
- package/src/client/browser-entry/index.ts +15 -1
- 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 +20 -15
- package/src/client/history.ts +13 -6
- package/src/client/internal.ts +4 -3
- package/src/client/link.tsx +55 -8
- package/src/client/navigation-api.ts +3 -3
- package/src/client/navigation-commit.ts +174 -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 +389 -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 +242 -707
- package/src/client/rsc-fetch.ts +169 -102
- package/src/client/segment-cache.ts +121 -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-router.ts +1 -1
- package/src/client/use-segment-params.ts +41 -18
- package/src/index.ts +5 -1
- package/src/plugin-context.ts +32 -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 +59 -2
- package/src/plugins/static-build.ts +315 -73
- package/src/routing/codegen-types.ts +18 -0
- package/src/routing/codegen.ts +50 -10
- package/src/routing/collision-probe.ts +438 -0
- package/src/routing/collision-spaces.ts +281 -0
- package/src/routing/interception.ts +896 -50
- package/src/routing/manifest-codegen.ts +5 -3
- package/src/routing/scanner.ts +114 -89
- 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/walkers.ts +8 -0
- package/src/search-params/define.ts +6 -29
- package/src/segment-params/define.ts +4 -27
- package/src/server/action-handler.ts +3 -1
- package/src/server/actions.ts +6 -3
- package/src/server/als-registry.ts +2 -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/default-status-page.ts +127 -0
- package/src/server/deny-renderer.ts +81 -20
- package/src/server/head-response.ts +54 -0
- package/src/server/param-coercion.ts +48 -18
- package/src/server/pipeline-helpers.ts +0 -45
- package/src/server/pipeline-interception.ts +81 -32
- package/src/server/pipeline-outcome.ts +2 -4
- package/src/server/pipeline-phases.ts +68 -16
- package/src/server/pipeline.ts +57 -10
- package/src/server/prebuilt-runtime.ts +4 -4
- package/src/server/publish-params.ts +42 -0
- package/src/server/request-context.ts +97 -18
- package/src/server/route-element-builder.ts +89 -98
- package/src/server/route-handler.ts +8 -8
- package/src/server/route-matcher.ts +21 -9
- package/src/server/rsc-cache-key-guard.ts +170 -0
- package/src/server/rsc-entry/api-handler.ts +6 -8
- package/src/server/rsc-entry/error-renderer.ts +64 -25
- package/src/server/rsc-entry/helpers.ts +31 -16
- package/src/server/rsc-entry/index.ts +36 -28
- package/src/server/rsc-entry/render-route.ts +9 -4
- package/src/server/rsc-entry/revalidate-renderer.ts +1 -1
- package/src/server/rsc-entry/rsc-payload.ts +14 -25
- package/src/server/rsc-entry/rsc-stream.ts +4 -3
- package/src/server/rsc-entry/ssr-renderer.ts +13 -9
- package/src/server/skippable-prefix.ts +92 -0
- package/src/server/slot-interception.ts +168 -0
- package/src/server/slot-resolver.ts +253 -156
- package/src/server/ssr-bridge-types.ts +6 -0
- package/src/server/ssr-entry.ts +12 -4
- package/src/server/ssr-wrappers.tsx +33 -32
- package/src/server/state-tree-diff.ts +14 -55
- package/src/server/static-generator.ts +65 -27
- package/src/server/static-not-found.ts +134 -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-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/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/router-ref-CtmF-aPv.js.map +0 -1
- package/dist/_chunks/ssr-data-BOWsq18U.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.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/src/plugins/request-dep.ts +0 -499
|
@@ -30,6 +30,8 @@ import { checkVersionSkew, applyReloadHeaders } from './version-skew.js';
|
|
|
30
30
|
import { serveStaticMetadataFile, serializeSitemap } from './pipeline-metadata.js';
|
|
31
31
|
import { loadModule } from './safe-load.js';
|
|
32
32
|
import { findInterceptionMatch } from './pipeline-interception.js';
|
|
33
|
+
import { computeSegmentTreePaths } from '../routing/segment-keys.js';
|
|
34
|
+
import { parseClientStateTree } from './state-tree-diff.js';
|
|
33
35
|
import { applyCookieJar, cloneWithMutableHeaders, type ProxyResolver } from './pipeline-helpers.js';
|
|
34
36
|
import { coerceSegmentParams } from './param-coercion.js';
|
|
35
37
|
import { outcomeToResponse, type PhaseOutcome } from './pipeline-outcome.js';
|
|
@@ -293,17 +295,6 @@ export async function handleRequest(
|
|
|
293
295
|
// outer Server-Timing writer can append without hitting an
|
|
294
296
|
// immutable header bag (e.g. user returns Response.redirect()).
|
|
295
297
|
if (handlerResult instanceof Response) {
|
|
296
|
-
if (method === 'HEAD') {
|
|
297
|
-
const headHeaders = new Headers(handlerResult.headers);
|
|
298
|
-
if (handlerResult.ok && !headHeaders.has('Cache-Control')) {
|
|
299
|
-
headHeaders.set('Cache-Control', 'public, max-age=14400, must-revalidate');
|
|
300
|
-
}
|
|
301
|
-
return new Response(null, {
|
|
302
|
-
status: handlerResult.status,
|
|
303
|
-
statusText: handlerResult.statusText,
|
|
304
|
-
headers: headHeaders,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
298
|
const res = cloneWithMutableHeaders(handlerResult);
|
|
308
299
|
if (res.ok && !res.headers.has('Cache-Control')) {
|
|
309
300
|
res.headers.set('Cache-Control', 'public, max-age=14400, must-revalidate');
|
|
@@ -401,14 +392,75 @@ export async function handleRequest(
|
|
|
401
392
|
? validateInterceptionHeader(rawSourceUrl, stripTrailingSlash)
|
|
402
393
|
: null;
|
|
403
394
|
if (validatedSourceUrl) {
|
|
404
|
-
|
|
395
|
+
// The scope of an interception is the segment that owns the intercepting
|
|
396
|
+
// slot, so the guard asks whether the route the user is LEAVING renders
|
|
397
|
+
// that segment. Two independent answers to "what is on screen?", tried in
|
|
398
|
+
// order — deferred behind a thunk so neither runs unless a rewrite's
|
|
399
|
+
// target pattern matches.
|
|
400
|
+
//
|
|
401
|
+
// 1. What the client says it has mounted (X-Timber-State-Tree
|
|
402
|
+
// `treePaths`). Authoritative about tree shape and nothing else.
|
|
403
|
+
// 2. What re-matching X-Timber-URL implies. Correct while the address bar
|
|
404
|
+
// still holds the source page, which stops being true the moment a
|
|
405
|
+
// modal is open — the address is then the *intercepted* URL and
|
|
406
|
+
// re-matching it resolves through whichever group owns the canonical
|
|
407
|
+
// page (TIM-1282).
|
|
408
|
+
//
|
|
409
|
+
// Neither is trusted: both are client-supplied, and satisfying the scope
|
|
410
|
+
// only selects which build-time rewrite applies. The rendered pathname is
|
|
411
|
+
// always the rewrite's own `interceptingPrefix`, the server re-derives the
|
|
412
|
+
// rendered chain from it below, and every access.ts runs regardless.
|
|
413
|
+
//
|
|
414
|
+
// They are handed over as two sets in that order rather than one union:
|
|
415
|
+
// each describes a single rendered chain, and only within one chain does
|
|
416
|
+
// "the deepest scope" name the innermost owner (TIM-1318). Unioned, a
|
|
417
|
+
// deeper scope from the address-implied canonical branch — which after
|
|
418
|
+
// (2) may be a route group the client never mounted — would outrank the
|
|
419
|
+
// owner actually on screen.
|
|
420
|
+
const resolveSourceScopes = () => {
|
|
421
|
+
const mounted = new Set(parseClientStateTree(req)?.treePaths ?? []);
|
|
422
|
+
const sourceRoute = config.matchRoute(validatedSourceUrl);
|
|
423
|
+
const addressed = new Set(sourceRoute ? computeSegmentTreePaths(sourceRoute.segments) : []);
|
|
424
|
+
const scopes = [mounted, addressed].filter((scope) => scope.size > 0);
|
|
425
|
+
// Neither channel produced a tree — no scope can contain anything, and
|
|
426
|
+
// an origin that matches no route is not a legitimate soft navigation.
|
|
427
|
+
return scopes.length > 0 ? scopes : null;
|
|
428
|
+
};
|
|
429
|
+
const rewrite = findInterceptionMatch(
|
|
405
430
|
canonicalPathname,
|
|
406
|
-
|
|
431
|
+
resolveSourceScopes,
|
|
407
432
|
config.interceptionRewrites
|
|
408
433
|
);
|
|
409
|
-
if (
|
|
410
|
-
|
|
411
|
-
|
|
434
|
+
if (rewrite?.mode === 'children') {
|
|
435
|
+
// Sibling layout swap (TIM-1280). Nothing is re-matched: the resolver
|
|
436
|
+
// addresses the owner directory by tree path and returns the chain
|
|
437
|
+
// `[…owner ancestors, interceptingNode, …descendants]`, which renders
|
|
438
|
+
// as an ordinary route. `interception` stays unset — there is no slot
|
|
439
|
+
// to intercept into, and setting it would additionally arm the modal
|
|
440
|
+
// path for every slot in the tree we are about to render.
|
|
441
|
+
//
|
|
442
|
+
// A null here means the scope named nothing in this manifest, or no
|
|
443
|
+
// intercepting child matched the target. Both fall through to the
|
|
444
|
+
// canonical route, which is what a hard navigation renders.
|
|
445
|
+
const interceptedMatch = config.matchInterceptedRoute?.(
|
|
446
|
+
canonicalPathname,
|
|
447
|
+
rewrite.interceptingScope
|
|
448
|
+
);
|
|
449
|
+
if (interceptedMatch) match = interceptedMatch;
|
|
450
|
+
} else if (rewrite) {
|
|
451
|
+
const sourceMatch = config.matchRoute(rewrite.interceptingPrefix);
|
|
452
|
+
// The scope test above was about the route the user is LEAVING. The
|
|
453
|
+
// route we are about to render is a different one —
|
|
454
|
+
// `interceptingPrefix` is URL-derived, and route groups are
|
|
455
|
+
// URL-invisible, so `/` can resolve into a sibling group that does not
|
|
456
|
+
// own the slot. Rendering that would reproduce the TIM-1278 failure on
|
|
457
|
+
// a valid tree: the rewrite hijacks the navigation and no slot exists
|
|
458
|
+
// to render the intercepting page. Fall through to the canonical
|
|
459
|
+
// target route instead.
|
|
460
|
+
const rendersTheSlot =
|
|
461
|
+
sourceMatch !== null &&
|
|
462
|
+
computeSegmentTreePaths(sourceMatch.segments).includes(rewrite.interceptingScope);
|
|
463
|
+
if (rendersTheSlot) {
|
|
412
464
|
match = sourceMatch;
|
|
413
465
|
interception = { targetPathname: canonicalPathname };
|
|
414
466
|
}
|
package/src/server/pipeline.ts
CHANGED
|
@@ -35,6 +35,9 @@ import { makeProxyResolver } from './pipeline-helpers.js';
|
|
|
35
35
|
import { handleRequest, runProxyPhase } from './pipeline-phases.js';
|
|
36
36
|
import { outcomeToResponse } from './pipeline-outcome.js';
|
|
37
37
|
import { canonicalize } from './canonicalize.js';
|
|
38
|
+
import { enforceRscCacheKey, hardenRscPayloadResponse } from './rsc-cache-key-guard.js';
|
|
39
|
+
import { stripHeadBody } from './head-response.js';
|
|
40
|
+
import { RSC_KEY_HEADERS } from '../shared/rsc-cache-key.js';
|
|
38
41
|
import { isDebug } from './debug.js';
|
|
39
42
|
|
|
40
43
|
// ─── Route Match Result ────────────────────────────────────────────────────
|
|
@@ -142,6 +145,17 @@ export interface PipelineConfig {
|
|
|
142
145
|
* See design/07-routing.md §"Intercepting Routes"
|
|
143
146
|
*/
|
|
144
147
|
interceptionRewrites?: import('../routing/interception.js').InterceptionRewrite[];
|
|
148
|
+
/**
|
|
149
|
+
* Resolver for children-path interceptions — the sibling layout swap.
|
|
150
|
+
*
|
|
151
|
+
* Separate from `matchRoute` because it addresses the owner directory by
|
|
152
|
+
* tree path rather than by pathname, which needs the manifest tree itself.
|
|
153
|
+
* Omitting it disables the `'children'` interception shape and leaves the
|
|
154
|
+
* canonical route rendering, which is the fail-safe outcome.
|
|
155
|
+
*
|
|
156
|
+
* See design/07-routing.md §"Intercepting Routes"
|
|
157
|
+
*/
|
|
158
|
+
matchInterceptedRoute?: import('./children-interception.js').InterceptedRouteMatcher;
|
|
145
159
|
/**
|
|
146
160
|
* Control Server-Timing header output.
|
|
147
161
|
*
|
|
@@ -393,17 +407,30 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
393
407
|
// DevSpanProcessor reads this for tree/summary output.
|
|
394
408
|
await setSpanAttribute('http.response.status_code', result.status);
|
|
395
409
|
|
|
396
|
-
// Vary
|
|
397
|
-
// separately for the same URL. Without this, a shared cache may
|
|
398
|
-
// serve an RSC Flight payload to a browser expecting HTML (or
|
|
399
|
-
// vice versa). See GHSA-wfc6-r584-vfw7, design/13-security.md.
|
|
410
|
+
// Vary on exactly the headers the `_rsc` cache key hashes.
|
|
400
411
|
//
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
412
|
+
// Those two mechanisms answer the same question — which request
|
|
413
|
+
// headers change this response — so they are the same list, not
|
|
414
|
+
// two lists that happen to agree. A separate hand-written list
|
|
415
|
+
// here drifted from `RSC_KEY_HEADERS` the moment the key set
|
|
416
|
+
// grew, and the drift is invisible: `Vary` is the *fallback*
|
|
417
|
+
// layer, used only when a cache omits the query from its key,
|
|
418
|
+
// which is precisely when nobody is watching (TIM-1268).
|
|
419
|
+
//
|
|
420
|
+
// Why any of it: without `Vary: Accept` a shared cache may serve
|
|
421
|
+
// an RSC Flight payload to a browser expecting HTML, or the
|
|
422
|
+
// reverse (GHSA-wfc6-r584-vfw7, design/13-security.md). The
|
|
423
|
+
// `_rsc` param puts that distinction in the URL, so correctness
|
|
424
|
+
// no longer *depends* on `Vary` — which is opt-in configuration
|
|
425
|
+
// on Cloudflare and CloudFront. `Vary` covers the requests that
|
|
426
|
+
// arrive without the param: a stripped query, a hand-rolled
|
|
427
|
+
// client.
|
|
428
|
+
//
|
|
429
|
+
// It costs no hit rate. Document requests send no `X-Timber-*`
|
|
430
|
+
// header at all, so they collapse to a single cache key; payload
|
|
431
|
+
// requests are already fragmented by these same values via the
|
|
432
|
+
// URL.
|
|
433
|
+
const varyTokens = [...RSC_KEY_HEADERS];
|
|
407
434
|
const existingVary = result.headers.get('Vary');
|
|
408
435
|
const existingTokens = existingVary
|
|
409
436
|
? existingVary
|
|
@@ -419,6 +446,26 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
419
446
|
);
|
|
420
447
|
}
|
|
421
448
|
|
|
449
|
+
// A request may only claim an `_rsc` cache key that matches its
|
|
450
|
+
// own headers. The key is predictable by design, so without this
|
|
451
|
+
// a caller could render its own variant under another client's
|
|
452
|
+
// key and have a shared cache store it there (TIM-1268).
|
|
453
|
+
await enforceRscCacheKey(canonicalReq, result);
|
|
454
|
+
|
|
455
|
+
// Flight payloads must never be sniffable into a renderable
|
|
456
|
+
// type — applied at this single exit so every producer is
|
|
457
|
+
// covered, not just the success path (TIM-1268).
|
|
458
|
+
hardenRscPayloadResponse(result);
|
|
459
|
+
|
|
460
|
+
// A HEAD response carries the headers its GET would produce and
|
|
461
|
+
// no content (RFC 9110 §9.3.2). Applied at this single exit so
|
|
462
|
+
// every response shape is covered — page render, API route,
|
|
463
|
+
// metadata route, deny page, error page, proxy short-circuit —
|
|
464
|
+
// rather than per-renderer, where it was missing for page
|
|
465
|
+
// renders entirely (TIM-1324). The render still runs: the
|
|
466
|
+
// headers have to be the ones a GET would have sent.
|
|
467
|
+
result = stripHeadBody(result, method);
|
|
468
|
+
|
|
422
469
|
// Append Server-Timing header based on configured mode.
|
|
423
470
|
// Header mutability is guaranteed by the producer-side clone
|
|
424
471
|
// in `outcomeToResponse` and the metadata-route / auto-sitemap
|
|
@@ -173,17 +173,17 @@ const registry = new Map<string, PrebuiltRegistration>();
|
|
|
173
173
|
*/
|
|
174
174
|
function resolveKeyParams(store: {
|
|
175
175
|
segmentParams?: Record<string, string | string[]>;
|
|
176
|
-
|
|
176
|
+
slotParams?: Record<string, Record<string, string | string[]>>;
|
|
177
177
|
}): Record<string, string | string[]> | null {
|
|
178
178
|
const main = store.segmentParams ?? {};
|
|
179
|
-
const
|
|
180
|
-
if (!
|
|
179
|
+
const slots = store.slotParams;
|
|
180
|
+
if (!slots || Object.keys(slots).length === 0) return main;
|
|
181
181
|
// Spread before canonicalizing: param records are framework-produced
|
|
182
182
|
// Object.create(null) objects (prototype-pollution defense) — normalize
|
|
183
183
|
// the records themselves, let nested values face the full allowlist.
|
|
184
184
|
const mainCanonical = tryCanonicalize({ ...main });
|
|
185
185
|
if (mainCanonical === null) return null;
|
|
186
|
-
for (const slotParams of
|
|
186
|
+
for (const slotParams of Object.values(slots)) {
|
|
187
187
|
const merged = tryCanonicalize({ ...main, ...slotParams });
|
|
188
188
|
if (merged === null || merged !== mainCanonical) return null;
|
|
189
189
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publishing the request's params onto the RSC payload.
|
|
3
|
+
*
|
|
4
|
+
* Every tree the server sends the browser goes through here: the ordinary
|
|
5
|
+
* route payload (`route-element-builder.ts`), both deny renderers
|
|
6
|
+
* (`deny-renderer.ts`) and the error renderer. One helper rather than a wrap
|
|
7
|
+
* at each site, because these previously *were* separate sites — a response
|
|
8
|
+
* header, an inline script, and a second copy of each on the deny path — and
|
|
9
|
+
* the deny path shipping empty params was the bug that came of it (TIM-1285).
|
|
10
|
+
*
|
|
11
|
+
* Reads the request store rather than taking params as an argument, so a
|
|
12
|
+
* caller cannot pass a different record than the one the request rendered
|
|
13
|
+
* with. See design/41-global-params.md §"Transport".
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { toPlainRecord } from '../shared/param-value.js';
|
|
17
|
+
import type { RscPayloadRoot } from '../shared/payload-root.js';
|
|
18
|
+
import { getSegmentParamsForClient, getSlotParamsForClient } from './request-context.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build the payload root: the tree, and the params it rendered with beside it.
|
|
22
|
+
*
|
|
23
|
+
* The params are a *sibling* of the tree, not a provider around it. A provider
|
|
24
|
+
* inside the payload is shadowed by the retained tree's own provider on a
|
|
25
|
+
* partial navigation, and its props are not readable at the instant the root
|
|
26
|
+
* row resolves — see `shared/payload-root.ts` for both, and TIM-1297. The
|
|
27
|
+
* client renders the one provider readers see, above the merge point.
|
|
28
|
+
*
|
|
29
|
+
* The records are flattened to plain objects on the way out. Every param
|
|
30
|
+
* record the framework builds is `Object.create(null)` (design/13-security.md
|
|
31
|
+
* #36b/#36c), and React Flight rejects a null prototype — "Classes or null
|
|
32
|
+
* prototypes are not supported". `ParamsProvider` restores the prototype on
|
|
33
|
+
* the other side, so what the app reads is unchanged; only the wire
|
|
34
|
+
* representation differs.
|
|
35
|
+
*/
|
|
36
|
+
export function withPublishedParams(element: React.ReactElement): RscPayloadRoot {
|
|
37
|
+
return {
|
|
38
|
+
tree: element,
|
|
39
|
+
params: toPlainRecord(getSegmentParamsForClient()),
|
|
40
|
+
slotParams: toPlainRecord(getSlotParamsForClient() ?? null),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -15,9 +15,14 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { requestContextAls, type RequestContextStore } from './als-registry.js';
|
|
18
|
-
import { _setGetSearchParamsFn } from '../
|
|
19
|
-
import { _setGetSegmentParamsFn } from '../segment-params/define.js';
|
|
18
|
+
import { _setGetSearchParamsFn, _setGetSegmentParamsFn } from '../shared/als-slots.js';
|
|
20
19
|
import { consumeSeededCookies } from './cookie-context.js';
|
|
20
|
+
import { appVisibleSearch } from '../shared/rsc-cache-key.js';
|
|
21
|
+
import {
|
|
22
|
+
mergeSlotParams,
|
|
23
|
+
resolveSegmentParams,
|
|
24
|
+
type SlotParamsRecord,
|
|
25
|
+
} from '../shared/slot-params.js';
|
|
21
26
|
import { isDebug } from './debug.js';
|
|
22
27
|
|
|
23
28
|
// Re-export the ALS for framework-internal consumers that need direct access.
|
|
@@ -111,17 +116,13 @@ export function getSegmentParams(segmentPath?: string): Record<string, string |
|
|
|
111
116
|
);
|
|
112
117
|
}
|
|
113
118
|
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// This ensures params from segments above the slot (that the slot
|
|
122
|
-
// doesn't re-derive) are still available.
|
|
123
|
-
return { ...store.segmentParams, ...slotParams };
|
|
124
|
-
}
|
|
119
|
+
// Parallel slots may derive a param the main route never had, or the same
|
|
120
|
+
// name with a different type (catch-all [...year] → string[] vs dynamic
|
|
121
|
+
// [year] → string). `resolveSegmentParams` is the shared definition the
|
|
122
|
+
// client's useSegmentParams() also reads, so the two halves of one
|
|
123
|
+
// documented API cannot drift (TIM-1285).
|
|
124
|
+
const slotResolved = resolveSegmentParams(store.segmentParams, store.slotParams, segmentPath);
|
|
125
|
+
if (slotResolved !== store.segmentParams) return slotResolved;
|
|
125
126
|
|
|
126
127
|
// Dev-mode validation: warn when the segment path expects dynamic
|
|
127
128
|
// segments that don't exist on the actual matched segment. This catches
|
|
@@ -173,8 +174,82 @@ export function setSlotParams(
|
|
|
173
174
|
): void {
|
|
174
175
|
const store = requestContextAls.getStore();
|
|
175
176
|
if (!store) return; // non-throwing — optional diagnostic
|
|
176
|
-
if (!store.
|
|
177
|
-
store.
|
|
177
|
+
if (!store.slotParams) store.slotParams = Object.create(null) as SlotParamsRecord;
|
|
178
|
+
store.slotParams[segmentPath] = params;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Run `fn` with the segment params a parallel slot's own chain produced, so
|
|
183
|
+
* a no-arg `getSegmentParams()` inside that slot returns the slot's params
|
|
184
|
+
* rather than the main route's.
|
|
185
|
+
*
|
|
186
|
+
* ALS is the only channel available: the slot's page and layouts are plain
|
|
187
|
+
* components that receive no params prop and cannot know their own tree
|
|
188
|
+
* path, so they have no way to ask for the keyed overload. The slot resolver
|
|
189
|
+
* invokes each of them itself (page through `SafeSlotPage`, layouts and
|
|
190
|
+
* access functions through their wrappers), and this scopes those calls.
|
|
191
|
+
*
|
|
192
|
+
* The store is wrapped in a Proxy rather than cloned. Everything a slot
|
|
193
|
+
* renders can write to the *live* request store — `setDenyStatus` from an
|
|
194
|
+
* access gate, cookie writes, the flush flag — and a clone would silently
|
|
195
|
+
* strand those writes in a copy the pipeline never reads. Only the two
|
|
196
|
+
* params fields are shadowed; every other read and every write passes
|
|
197
|
+
* straight through to the real store.
|
|
198
|
+
*
|
|
199
|
+
* Returns `fn()`'s result unchanged, and no-ops outside a request context or
|
|
200
|
+
* before route matching has set the main params. See TIM-1283.
|
|
201
|
+
*
|
|
202
|
+
* @internal — framework use only
|
|
203
|
+
*/
|
|
204
|
+
export function runWithSlotSegmentParams<T>(
|
|
205
|
+
slotSegmentPath: string | undefined,
|
|
206
|
+
slotParams: Record<string, string | string[]>,
|
|
207
|
+
fn: () => T
|
|
208
|
+
): T {
|
|
209
|
+
const store = requestContextAls.getStore();
|
|
210
|
+
if (!store?.segmentParams) return fn();
|
|
211
|
+
|
|
212
|
+
const merged = mergeSlotParams(store.segmentParams, slotParams);
|
|
213
|
+
const matchedSegmentPath = slotSegmentPath ?? store.matchedSegmentPath;
|
|
214
|
+
const scoped = new Proxy(store, {
|
|
215
|
+
get(target, prop, receiver) {
|
|
216
|
+
if (prop === 'segmentParams') return merged;
|
|
217
|
+
if (prop === 'matchedSegmentPath') return matchedSegmentPath;
|
|
218
|
+
return Reflect.get(target, prop, receiver);
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
return requestContextAls.run(scoped, fn);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* The main route's coerced params, or an empty record before route matching.
|
|
226
|
+
*
|
|
227
|
+
* Non-throwing, unlike `getSegmentParams()`: the deny payload path publishes
|
|
228
|
+
* params from wherever the pipeline happened to fail, which may be before
|
|
229
|
+
* matching completed.
|
|
230
|
+
*
|
|
231
|
+
* @internal — framework use only. See TIM-1285.
|
|
232
|
+
*/
|
|
233
|
+
export function getSegmentParamsForClient(): Record<string, string | string[]> {
|
|
234
|
+
return requestContextAls.getStore()?.segmentParams ?? {};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The per-slot params to publish to the client, or `undefined` when the
|
|
239
|
+
* request rendered no slot with params of its own.
|
|
240
|
+
*
|
|
241
|
+
* The client cannot derive these: a slot matches the URL through its own
|
|
242
|
+
* sub-tree, and the browser only ever sees the main route's record. Reading
|
|
243
|
+
* the map here — rather than threading it back out of the element builder —
|
|
244
|
+
* keeps one producer, since `setSlotParams` already writes it during slot
|
|
245
|
+
* resolution and every serialization site runs after that completes.
|
|
246
|
+
*
|
|
247
|
+
* @internal — framework use only. See TIM-1285.
|
|
248
|
+
*/
|
|
249
|
+
export function getSlotParamsForClient(): SlotParamsRecord | undefined {
|
|
250
|
+
const store = requestContextAls.getStore();
|
|
251
|
+
if (!store?.slotParams) return undefined;
|
|
252
|
+
return Object.keys(store.slotParams).length > 0 ? store.slotParams : undefined;
|
|
178
253
|
}
|
|
179
254
|
|
|
180
255
|
/**
|
|
@@ -247,7 +322,7 @@ export type ReadonlyHeaders = Pick<
|
|
|
247
322
|
*/
|
|
248
323
|
export function runWithRequestContext<T>(req: Request, fn: () => T): T {
|
|
249
324
|
const originalCopy = new Headers(req.headers);
|
|
250
|
-
const
|
|
325
|
+
const appVisible = appVisibleSearch(new URL(req.url));
|
|
251
326
|
const seed = consumeSeededCookies(req);
|
|
252
327
|
const store: RequestContextStore = {
|
|
253
328
|
headers: freezeHeaders(req.headers),
|
|
@@ -257,8 +332,12 @@ export function runWithRequestContext<T>(req: Request, fn: () => T): T {
|
|
|
257
332
|
// gated on `parsedCookies` being undefined.
|
|
258
333
|
cookieHeader: seed ? '' : (req.headers.get('cookie') ?? ''),
|
|
259
334
|
parsedCookies: seed,
|
|
260
|
-
searchParams
|
|
261
|
-
|
|
335
|
+
// Not `parsedUrl.searchParams` / `parsedUrl.search`: this store is what
|
|
336
|
+
// `getSearchParams()` and `redirect({ preserveSearchParams })` read, and
|
|
337
|
+
// the RSC payload URL carries the framework's `_rsc` cache key that no
|
|
338
|
+
// other request has (TIM-1272).
|
|
339
|
+
searchParams: appVisible.params,
|
|
340
|
+
searchString: appVisible.search,
|
|
262
341
|
cookieJar: new Map(),
|
|
263
342
|
flushed: false,
|
|
264
343
|
mutableContext: false,
|