@timber-js/app 0.2.0-alpha.184 → 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-C539Pa2O.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-segment-params-ClyUNq4d.js +128 -0
- package/dist/_chunks/use-segment-params-ClyUNq4d.js.map +1 -0
- package/dist/_chunks/{walkers-BtTlKviE.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 +872 -305
- 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 +39 -16
- 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 +915 -320
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +33 -1
- 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 +149 -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/types.d.ts +1 -3
- 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/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-boundary.d.ts +4 -7
- package/dist/server/deny-boundary.d.ts.map +1 -1
- 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 +528 -373
- 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/prebuilt-builder.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +0 -12
- 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 +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/sitemap-generator.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/server/status-code-resolver.d.ts +3 -10
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- 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/dist/shims/navigation-client.d.ts +8 -19
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +0 -1
- package/dist/shims/navigation.d.ts.map +1 -1
- 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 +4 -3
- 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 -690
- package/src/client/rsc-fetch.ts +180 -122
- 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 +34 -1
- 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 +60 -3
- package/src/plugins/static-build.ts +333 -63
- 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 +6 -9
- package/src/routing/scanner.ts +114 -113
- 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 +1 -3
- 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-boundary.ts +5 -31
- package/src/server/deny-renderer.ts +83 -22
- 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 +3 -5
- package/src/server/pipeline-phases.ts +68 -16
- package/src/server/pipeline.ts +57 -10
- package/src/server/prebuilt-builder.ts +1 -7
- package/src/server/prebuilt-runtime.ts +4 -4
- package/src/server/primitives.ts +0 -18
- 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 +12 -7
- 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/sitemap-generator.ts +1 -7
- 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 +67 -45
- package/src/server/static-not-found.ts +134 -0
- package/src/server/status-code-resolver.ts +4 -47
- 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/src/shims/navigation-client.ts +8 -26
- package/src/shims/navigation.ts +0 -4
- 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-D3naS3eH.js +0 -688
- package/dist/_chunks/cli-schema-sync-D3naS3eH.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/segment-classify-Byy425ng.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-BtTlKviE.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
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment base path — Vite's resolved `base`, as it applies to the URLs
|
|
3
|
+
* timber addresses at runtime.
|
|
4
|
+
*
|
|
5
|
+
* A static build deployed under a sub-path (`base: '/repo/'`, the GitHub
|
|
6
|
+
* Pages project-site layout) serves every generated file below that prefix:
|
|
7
|
+
* the document for `/about` lives at `/repo/about/index.html`, its flight
|
|
8
|
+
* payload at `/repo/_rsc/about/index.rsc`. The client works in *route space* — the
|
|
9
|
+
* paths the app declares — so both a strip (browser URL → route path) and a
|
|
10
|
+
* prefix (route-space path → URL) are needed, and this module owns both.
|
|
11
|
+
*
|
|
12
|
+
* Pure functions, no state: the caller supplies the base. `client/rsc-fetch.ts`
|
|
13
|
+
* holds the client's copy, set at bootstrap from `virtual:timber-config`.
|
|
14
|
+
*
|
|
15
|
+
* See design/11-platform.md §"Deploying under a non-root base" (TIM-1261).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** `https://cdn.example.com/`, `//cdn.example.com/` — a base pointing off-origin. */
|
|
19
|
+
function isAbsoluteUrlBase(base: string): boolean {
|
|
20
|
+
return base.startsWith('//') || /^[a-z][a-z0-9+.-]*:\/\//i.test(base);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* True when `base` is document-relative (`'./'`, `'foo/'`) — it makes asset
|
|
25
|
+
* URLs resolve against whatever document loaded them, which says nothing
|
|
26
|
+
* about where the deployment sits, so no prefix can be computed from it.
|
|
27
|
+
*/
|
|
28
|
+
export function isRelativeBase(base: string | undefined): boolean {
|
|
29
|
+
if (!base) return false;
|
|
30
|
+
return !base.startsWith('/') && !isAbsoluteUrlBase(base);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Normalize Vite's `base` into a path prefix. Always returns a value with a
|
|
35
|
+
* leading and trailing slash.
|
|
36
|
+
*
|
|
37
|
+
* Two forms carry no usable deployment prefix and normalize to `/`:
|
|
38
|
+
*
|
|
39
|
+
* - **An absolute-URL base** points *assets* at a CDN. The HTML documents and
|
|
40
|
+
* `.rsc` payloads are still served from the deployment origin, so their
|
|
41
|
+
* URLs stay root-relative. This is correct, not a degradation.
|
|
42
|
+
* - **A relative base** — see `isRelativeBase`. The static build warns,
|
|
43
|
+
* because SPA navigation then only works at the domain root.
|
|
44
|
+
*/
|
|
45
|
+
export function normalizeBasePath(base: string | undefined): string {
|
|
46
|
+
if (!base) return '/';
|
|
47
|
+
if (isAbsoluteUrlBase(base) || isRelativeBase(base)) return '/';
|
|
48
|
+
return base.endsWith('/') ? base : `${base}/`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Strip the base prefix from a browser pathname, returning the route-space
|
|
53
|
+
* path. With base `/repo/`: `/repo/about` → `/about`, `/repo/` and `/repo`
|
|
54
|
+
* → `/`.
|
|
55
|
+
*
|
|
56
|
+
* A pathname outside the base is returned unchanged. It cannot be served by
|
|
57
|
+
* this deployment at all, so there is no better answer than letting the
|
|
58
|
+
* resulting fetch 404 and the router hard-navigate — visibly wrong beats
|
|
59
|
+
* silently rewritten.
|
|
60
|
+
*
|
|
61
|
+
* @param base A normalized base (see `normalizeBasePath`).
|
|
62
|
+
*/
|
|
63
|
+
export function stripBasePath(base: string, pathname: string): string {
|
|
64
|
+
if (base === '/') return pathname;
|
|
65
|
+
const withoutTrailingSlash = base.slice(0, -1);
|
|
66
|
+
if (pathname === withoutTrailingSlash) return '/';
|
|
67
|
+
if (!pathname.startsWith(base)) return pathname;
|
|
68
|
+
return pathname.slice(withoutTrailingSlash.length);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Prefix a route-space, root-relative path with the base.
|
|
73
|
+
* `/_rsc/about/index.rsc` → `/repo/_rsc/about/index.rsc`.
|
|
74
|
+
*
|
|
75
|
+
* @param base A normalized base (see `normalizeBasePath`).
|
|
76
|
+
*/
|
|
77
|
+
export function withBasePath(base: string, path: string): string {
|
|
78
|
+
if (base === '/') return path;
|
|
79
|
+
return path.startsWith('/') ? base.slice(0, -1) + path : `${base}${path}`;
|
|
80
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical form of a segment param value.
|
|
3
|
+
*
|
|
4
|
+
* `getSegmentParams()` on the server and `useSegmentParams()` on the client
|
|
5
|
+
* must return the same value — same prototype, same own properties. This
|
|
6
|
+
* module is how that is guaranteed, and the mechanism matters:
|
|
7
|
+
*
|
|
8
|
+
* **Both sides are images of one normalizer.** A codec's output is deep-cloned
|
|
9
|
+
* into a closed canonical domain at coercion time, and *that clone* is what the
|
|
10
|
+
* server returns and what goes on the wire. Server and client agree by
|
|
11
|
+
* construction, because neither holds the codec's original.
|
|
12
|
+
*
|
|
13
|
+
* That replaces predicting what React Flight would do to an arbitrary value.
|
|
14
|
+
* Prediction is what the previous design attempted and it cannot be finished:
|
|
15
|
+
* the question "will Flight's decode output be observably identical to this
|
|
16
|
+
* input?" ranges over every way a JS object can carry state that is not in its
|
|
17
|
+
* serialization — own keys, enumerability, symbols, holes, accessors,
|
|
18
|
+
* subclassing, exotic objects — and a `Proxy` defeats it outright, since a
|
|
19
|
+
* lying `getPrototypeOf` trap makes any static check unsound. Twelve review
|
|
20
|
+
* findings on PR #992 were each one more case of that set, and the set does
|
|
21
|
+
* not close.
|
|
22
|
+
*
|
|
23
|
+
* Normalizing closes it. The only remaining question is whether Flight
|
|
24
|
+
* round-trips the normalizer's *output range* — a finite domain we defined,
|
|
25
|
+
* covered by `tests/e2e/segment-params.test.ts` against the real serializer.
|
|
26
|
+
*
|
|
27
|
+
* ## The domain
|
|
28
|
+
*
|
|
29
|
+
* - `undefined`, `null`, `string`, `number`, `boolean`, `bigint`
|
|
30
|
+
* - null-prototype objects, own enumerable string keys only
|
|
31
|
+
* - dense arrays
|
|
32
|
+
* - `Date`, `Map`, `Set` — rebuilt, never the codec's instance
|
|
33
|
+
*
|
|
34
|
+
* ...and it is a **tree**: no value appears twice, and nothing is cyclic.
|
|
35
|
+
* That is not a simplification, it is the last prediction being removed.
|
|
36
|
+
* Flight encodes a `Date` by value at each occurrence but tracks plain objects
|
|
37
|
+
* for reference dedup, so preserving aliasing would carry it across for some
|
|
38
|
+
* types and drop it for others — and knowing which is exactly the kind of
|
|
39
|
+
* guess this design exists to stop making (codex, PR #992). A tree has no
|
|
40
|
+
* sharing to preserve or lose, so what Flight does about it is unobservable.
|
|
41
|
+
*
|
|
42
|
+
* Anything else throws, naming the param and what it was. Note what is *not*
|
|
43
|
+
* a rejection: a `Date` subclass normalizes to a `Date`, a decorated array to
|
|
44
|
+
* a plain one, a sparse array to a dense one, a getter to the value it
|
|
45
|
+
* returned. Those used to be twelve separate checks. They are not divergences
|
|
46
|
+
* any more, because the normalization happens once and both sides see its
|
|
47
|
+
* result — so they need no checks at all.
|
|
48
|
+
*
|
|
49
|
+
* Own properties that Flight would drop (non-enumerable, symbol-keyed) are
|
|
50
|
+
* dropped here instead, symmetrically. Prototype pollution is handled by the
|
|
51
|
+
* same pass: `__proto__` is never copied, and every object is
|
|
52
|
+
* `Object.create(null)` (design/13-security.md #36b/#36c, TIM-873).
|
|
53
|
+
*
|
|
54
|
+
* ## The prototype flip
|
|
55
|
+
*
|
|
56
|
+
* Flight refuses to serialize a null-prototype object, so the canonical form
|
|
57
|
+
* cannot go on the wire as-is. `toPlainRecord` and `toNullProtoRecord` flip
|
|
58
|
+
* the prototype on the way out and back. They are exact inverses and both
|
|
59
|
+
* total, because they only ever see canonical values — there is nothing to
|
|
60
|
+
* validate and no shape to special-case.
|
|
61
|
+
*
|
|
62
|
+
* See design/41-global-params.md §"Transport".
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/** Types the canonical form rebuilds rather than rejects. */
|
|
66
|
+
const REBUILT = ['Date', 'Map', 'Set'] as const;
|
|
67
|
+
|
|
68
|
+
/** The domain, for error messages. Derived, never a second hand-written list. */
|
|
69
|
+
const DOMAIN = `a string, number, boolean, bigint, null, undefined, a plain object, an array, or ${REBUILT.join('/')}`;
|
|
70
|
+
|
|
71
|
+
function reject(path: string, was: string, hint: string): never {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`[timber] Segment param "${path || '(root)'}" was coerced to ${was}, which cannot ` +
|
|
74
|
+
`cross to the client. A param value may be ${DOMAIN}.\n` +
|
|
75
|
+
` ${hint}\n` +
|
|
76
|
+
` See design/41-global-params.md §"Transport".`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function describe(value: object): string {
|
|
81
|
+
return (value as { constructor?: { name?: string } }).constructor?.name ?? 'an object';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Deep-clone a codec's output into the canonical form, or throw.
|
|
86
|
+
*
|
|
87
|
+
* `seen` accumulates every object the walk has entered, and a second encounter
|
|
88
|
+
* is rejected. That is one rule for two things — a shared reference and a cycle
|
|
89
|
+
* are both "this object again" — and it is what keeps the result a tree.
|
|
90
|
+
*/
|
|
91
|
+
export function normalizeParamValue(value: unknown, path = ''): unknown {
|
|
92
|
+
return normalize(value, path, new Set());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function normalize(value: unknown, path: string, seen: Set<object>): unknown {
|
|
96
|
+
if (value === null) return null;
|
|
97
|
+
|
|
98
|
+
const kind = typeof value;
|
|
99
|
+
if (kind === 'string' || kind === 'number' || kind === 'boolean' || kind === 'bigint') {
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
if (kind === 'undefined') return undefined;
|
|
103
|
+
if (kind === 'function') {
|
|
104
|
+
reject(path, 'a function', 'Return the data it would produce, not the function.');
|
|
105
|
+
}
|
|
106
|
+
if (kind === 'symbol') {
|
|
107
|
+
reject(path, 'a symbol', 'Return a string instead — a symbol has no wire representation.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const object = value as object;
|
|
111
|
+
if (seen.has(object)) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`[timber] Segment param "${path || '(root)'}" is a value that already appears ` +
|
|
114
|
+
`elsewhere in the same param — a shared reference or a cycle. A param value is a ` +
|
|
115
|
+
`tree: React Flight carries a repeated \`Date\` by value and a repeated object by ` +
|
|
116
|
+
`reference, so sharing would survive for some types and not others.\n` +
|
|
117
|
+
` Return separate values, or move the shared part outside the params.\n` +
|
|
118
|
+
` See design/41-global-params.md §"Transport".`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
seen.add(object);
|
|
122
|
+
|
|
123
|
+
if (Array.isArray(object)) {
|
|
124
|
+
// Read by index, so holes become `undefined` — on both sides, which is
|
|
125
|
+
// the point. A subclass and any own properties are left behind for the
|
|
126
|
+
// same reason: the clone is a plain, dense array either way.
|
|
127
|
+
const out: unknown[] = [];
|
|
128
|
+
for (let index = 0; index < object.length; index++) {
|
|
129
|
+
out.push(normalize((object as unknown[])[index], `${path}[${index}]`, seen));
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (object instanceof Date) {
|
|
135
|
+
// A fresh Date, so a subclass or an attached property cannot travel half
|
|
136
|
+
// way and be dropped by the wire.
|
|
137
|
+
return new Date(object.getTime());
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (object instanceof Map) {
|
|
141
|
+
const out = new Map<unknown, unknown>();
|
|
142
|
+
for (const [key, entry] of object) {
|
|
143
|
+
out.set(
|
|
144
|
+
normalize(key, `${path}<key>`, seen),
|
|
145
|
+
normalize(entry, `${path}.get(${keyLabel(key)})`, seen)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (object instanceof Set) {
|
|
152
|
+
const out = new Set<unknown>();
|
|
153
|
+
let index = 0;
|
|
154
|
+
for (const entry of object) out.add(normalize(entry, `${path}[${index++}]`, seen));
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Everything else is judged by its prototype. A `Proxy` can lie here, and
|
|
159
|
+
// that is fine: whatever it answers, the clone below reads through it once
|
|
160
|
+
// and both sides see the same snapshot.
|
|
161
|
+
const prototype = Object.getPrototypeOf(object);
|
|
162
|
+
if (prototype !== null && prototype !== Object.prototype) {
|
|
163
|
+
reject(
|
|
164
|
+
path,
|
|
165
|
+
`a ${describe(object)} instance`,
|
|
166
|
+
'Return a plain object with the fields you need.'
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Own *enumerable string* keys only — the rest is what Flight would drop,
|
|
171
|
+
// so dropping it here keeps the two sides identical. `__proto__` is skipped
|
|
172
|
+
// rather than copied: it has a language-level setter that would change the
|
|
173
|
+
// prototype chain of the copy (TIM-655, TIM-855, TIM-873).
|
|
174
|
+
const out: Record<string, unknown> = Object.create(null);
|
|
175
|
+
for (const key of Object.keys(object)) {
|
|
176
|
+
if (key === '__proto__') continue;
|
|
177
|
+
out[key] = normalize(
|
|
178
|
+
(object as Record<string, unknown>)[key],
|
|
179
|
+
path ? `${path}.${key}` : key,
|
|
180
|
+
seen
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function keyLabel(key: unknown): string {
|
|
187
|
+
return typeof key === 'string' ? JSON.stringify(key) : String(key);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ─── Prototype flip ──────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Canonical form → wire form. React Flight rejects a null prototype
|
|
194
|
+
* ("Classes or null prototypes are not supported"), so objects cross as plain
|
|
195
|
+
* ones and are restored on arrival.
|
|
196
|
+
*/
|
|
197
|
+
export function toPlainRecord<T>(value: T): T {
|
|
198
|
+
return reproto(value, {}) as T;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Wire form → canonical form. The exact inverse of `toPlainRecord`. */
|
|
202
|
+
export function toNullProtoRecord<T>(value: T): T {
|
|
203
|
+
return reproto(value, null) as T;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Rebuild a canonical value with objects on `proto`.
|
|
208
|
+
*
|
|
209
|
+
* Total by construction: its input is always canonical, so the cases are the
|
|
210
|
+
* domain and nothing else. No validation, no shape it might not have seen, and
|
|
211
|
+
* no cycle to guard — a canonical value is a tree. That is what moving the
|
|
212
|
+
* checking to `normalizeParamValue` bought.
|
|
213
|
+
*/
|
|
214
|
+
function reproto(value: unknown, proto: object | null): unknown {
|
|
215
|
+
if (value === null || typeof value !== 'object') return value;
|
|
216
|
+
|
|
217
|
+
const object = value as object;
|
|
218
|
+
|
|
219
|
+
// A Date carries no nested values, so it crosses as itself.
|
|
220
|
+
if (object instanceof Date) return object;
|
|
221
|
+
|
|
222
|
+
if (Array.isArray(object)) {
|
|
223
|
+
return (object as unknown[]).map((item) => reproto(item, proto));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (object instanceof Map) {
|
|
227
|
+
const out = new Map<unknown, unknown>();
|
|
228
|
+
for (const [key, entry] of object) out.set(reproto(key, proto), reproto(entry, proto));
|
|
229
|
+
return out;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (object instanceof Set) {
|
|
233
|
+
const out = new Set<unknown>();
|
|
234
|
+
for (const entry of object) out.add(reproto(entry, proto));
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const out: Record<string, unknown> = proto === null ? Object.create(null) : {};
|
|
239
|
+
for (const key of Object.keys(object)) {
|
|
240
|
+
if (key === '__proto__') continue;
|
|
241
|
+
out[key] = reproto((object as Record<string, unknown>)[key], proto);
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shape of an RSC payload's root row.
|
|
3
|
+
*
|
|
4
|
+
* Every tree the server sends the browser is serialized as
|
|
5
|
+
* `{ tree, params, slotParams }` — the route's element tree, plus the coerced
|
|
6
|
+
* params it rendered with, as *siblings* rather than as a wrapper around the
|
|
7
|
+
* tree. See design/41-global-params.md §"Transport".
|
|
8
|
+
*
|
|
9
|
+
* Two reasons it is a sibling field rather than a provider inside the payload
|
|
10
|
+
* (TIM-1297, which is TIM-1294's mechanism corrected):
|
|
11
|
+
*
|
|
12
|
+
* 1. **A provider inside the payload cannot serve a partial navigation.** The
|
|
13
|
+
* client keeps the previous tree and splices the new payload in at the
|
|
14
|
+
* first updated `SegmentOutlet`, so the payload's own provider lands
|
|
15
|
+
* *below* the retained region — and the retained region's root is the
|
|
16
|
+
* *departing* route's provider, which therefore wins for every reader in a
|
|
17
|
+
* skipped layout. Wrapping something above it does not help: context
|
|
18
|
+
* resolves to the nearest provider, and the departing one is nearer.
|
|
19
|
+
* Params belong to the *navigation*, so the provider has to be owned by the
|
|
20
|
+
* client, above the merge point, and there must be exactly one.
|
|
21
|
+
*
|
|
22
|
+
* 2. **Element props are not readable at the instant the root resolves.**
|
|
23
|
+
* Flight outlines a React element's props and fills the record in after the
|
|
24
|
+
* root row resolves, so a reader that unblocks on the root sees `{}` — and
|
|
25
|
+
* since the object is filled *in place*, its identity never changes and any
|
|
26
|
+
* memo keyed on it caches the empty snapshot permanently. A plain model
|
|
27
|
+
* field has no such window: the root chunk stays blocked until everything
|
|
28
|
+
* it references has resolved.
|
|
29
|
+
*
|
|
30
|
+
* This module is the single declaration of that shape. The server builds roots
|
|
31
|
+
* through `server/publish-params.ts` and the client reads them through the
|
|
32
|
+
* helpers here — producer and consumer do not each describe the payload.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import type { SlotParamsRecord } from './slot-params.js';
|
|
36
|
+
|
|
37
|
+
/** The params published beside a tree. */
|
|
38
|
+
export interface PublishedParams {
|
|
39
|
+
/** The main route's coerced params. */
|
|
40
|
+
params: Record<string, string | string[]>;
|
|
41
|
+
/** Per-slot params, or null when the route rendered no slots with params. */
|
|
42
|
+
slotParams: SlotParamsRecord | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Params ready to publish: settled, or a promise the root provider suspends on.
|
|
47
|
+
*
|
|
48
|
+
* Both forms exist on purpose. The hydration path cannot await — `hydrateRoot`
|
|
49
|
+
* has to be called before the inline Flight stream has necessarily produced
|
|
50
|
+
* the root row — so it hands over the promise and suspends exactly where React
|
|
51
|
+
* was already going to suspend on the tree. Every other path settles it inside
|
|
52
|
+
* the navigation transition first, which is what keeps a decode failure inside
|
|
53
|
+
* the app's own error boundaries instead of above them (TIM-1297).
|
|
54
|
+
*/
|
|
55
|
+
export type ParamsSource = PublishedParams | Promise<PublishedParams>;
|
|
56
|
+
|
|
57
|
+
/** The root row of an RSC payload. */
|
|
58
|
+
export interface RscPayloadRoot extends PublishedParams {
|
|
59
|
+
/** The route's element tree. */
|
|
60
|
+
tree: unknown;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* What a reader gets when the value it was handed is not a payload root.
|
|
65
|
+
*
|
|
66
|
+
* In the browser this is unreachable for a real response: all four producers
|
|
67
|
+
* of a route payload go through `withPublishedParams`, and a client talking to
|
|
68
|
+
* a different build is answered with 204 at Stage 1c
|
|
69
|
+
* (`server/pipeline-phases.ts`) before any payload exists. It is reachable in
|
|
70
|
+
* the router's test/fallback path, where `decodeRsc` is absent and the
|
|
71
|
+
* "payload" is the raw response text.
|
|
72
|
+
*/
|
|
73
|
+
export const NO_PUBLISHED_PARAMS: PublishedParams = { params: {}, slotParams: null };
|
|
74
|
+
|
|
75
|
+
/** True when `value` carries published params — a root, or a read of one. */
|
|
76
|
+
function hasPublishedParams(value: unknown): value is PublishedParams {
|
|
77
|
+
return (
|
|
78
|
+
typeof value === 'object' &&
|
|
79
|
+
value !== null &&
|
|
80
|
+
'params' in value &&
|
|
81
|
+
typeof (value as PublishedParams).params === 'object' &&
|
|
82
|
+
(value as PublishedParams).params !== null
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Read the params published beside a tree.
|
|
88
|
+
*
|
|
89
|
+
* Accepts a payload root *or* a `PublishedParams` already split off one, so
|
|
90
|
+
* the client can pre-resolve on the navigation path and still hand the same
|
|
91
|
+
* value to the same provider. Never throws.
|
|
92
|
+
*/
|
|
93
|
+
export function readPublishedParams(source: unknown): PublishedParams {
|
|
94
|
+
if (!hasPublishedParams(source)) return NO_PUBLISHED_PARAMS;
|
|
95
|
+
return { params: source.params, slotParams: source.slotParams ?? null };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Read the renderable tree out of a payload root.
|
|
100
|
+
*
|
|
101
|
+
* Returns the value unchanged when it is not a root — the router's fallback
|
|
102
|
+
* path stores raw response text under the same name, and a test asserting on
|
|
103
|
+
* that text should see the text.
|
|
104
|
+
*/
|
|
105
|
+
export function readPayloadTree(root: unknown): unknown {
|
|
106
|
+
if (typeof root === 'object' && root !== null && 'tree' in root && hasPublishedParams(root)) {
|
|
107
|
+
return (root as RscPayloadRoot).tree;
|
|
108
|
+
}
|
|
109
|
+
return root;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** A decoded payload, split into the two things the client does with it. */
|
|
113
|
+
export interface SplitPayload {
|
|
114
|
+
/** The renderable tree — an element, or a thenable React suspends on. */
|
|
115
|
+
tree: unknown;
|
|
116
|
+
/**
|
|
117
|
+
* The params published beside it. Settled when the root already is, so the
|
|
118
|
+
* hydration path can render without an extra await.
|
|
119
|
+
*
|
|
120
|
+
* **Never rejects.** A decode failure has to surface where React renders
|
|
121
|
+
* `tree`, so the error boundary *around the tree* catches it. Rejecting here
|
|
122
|
+
* too would take down the provider above every boundary in the app, turning
|
|
123
|
+
* a contained failure into a blank page (TIM-1297).
|
|
124
|
+
*/
|
|
125
|
+
params: ParamsSource;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Split a decoded payload root into its tree and its params.
|
|
130
|
+
*
|
|
131
|
+
* Accepts a settled root or a thenable of one, and preserves which it was: a
|
|
132
|
+
* settled root splits synchronously, so no code path gains a suspend point it
|
|
133
|
+
* did not already have.
|
|
134
|
+
*/
|
|
135
|
+
export function splitPayloadRoot(root: unknown): SplitPayload {
|
|
136
|
+
if (
|
|
137
|
+
typeof root !== 'object' ||
|
|
138
|
+
root === null ||
|
|
139
|
+
typeof (root as PromiseLike<unknown>).then !== 'function'
|
|
140
|
+
) {
|
|
141
|
+
return { tree: readPayloadTree(root), params: readPublishedParams(root) };
|
|
142
|
+
}
|
|
143
|
+
const settled = root as PromiseLike<unknown>;
|
|
144
|
+
const tree = Promise.resolve(settled).then(readPayloadTree);
|
|
145
|
+
// The rejection still reaches React through its own read of `tree`; this
|
|
146
|
+
// only marks it handled for the case where nothing renders it (a partial
|
|
147
|
+
// navigation whose segment update finds no matching outlet).
|
|
148
|
+
tree.catch(() => {});
|
|
149
|
+
const params = Promise.resolve(settled).then(readPublishedParams, () => NO_PUBLISHED_PARAMS);
|
|
150
|
+
return { tree, params };
|
|
151
|
+
}
|