@timber-js/app 0.2.0-alpha.6 → 0.2.0-alpha.61
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/LICENSE +8 -0
- package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-Ba7URUIn.js} +1 -1
- package/dist/_chunks/als-registry-Ba7URUIn.js.map +1 -0
- package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
- package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
- package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
- package/dist/_chunks/define-CT98cU9c.js +121 -0
- package/dist/_chunks/define-CT98cU9c.js.map +1 -0
- package/dist/_chunks/define-TK8C1M3x.js +279 -0
- package/dist/_chunks/define-TK8C1M3x.js.map +1 -0
- package/dist/_chunks/define-cookie-BWr_52kY.js +93 -0
- package/dist/_chunks/define-cookie-BWr_52kY.js.map +1 -0
- package/dist/_chunks/error-boundary-DpZJBCqh.js +211 -0
- package/dist/_chunks/error-boundary-DpZJBCqh.js.map +1 -0
- package/dist/_chunks/{format-DviM89f0.js → format-cX7wzEp2.js} +2 -2
- package/dist/_chunks/{format-DviM89f0.js.map → format-cX7wzEp2.js.map} +1 -1
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-Cey5DCGr.js} +129 -77
- package/dist/_chunks/interception-Cey5DCGr.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-BU684ls2.js} +1 -1
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-BU684ls2.js.map} +1 -1
- package/dist/_chunks/{request-context-DIkVh_jG.js → request-context-rju2rbga.js} +97 -69
- package/dist/_chunks/request-context-rju2rbga.js.map +1 -0
- package/dist/_chunks/segment-context-CyaM1mrD.js +72 -0
- package/dist/_chunks/segment-context-CyaM1mrD.js.map +1 -0
- package/dist/_chunks/stale-reload-BSSym1MJ.js +64 -0
- package/dist/_chunks/stale-reload-BSSym1MJ.js.map +1 -0
- package/dist/_chunks/{tracing-Cwn7697K.js → tracing-VYETCQsg.js} +17 -3
- package/dist/_chunks/{tracing-Cwn7697K.js.map → tracing-VYETCQsg.js.map} +1 -1
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-wEXY2JQB.js} +1 -1
- package/dist/_chunks/use-query-states-wEXY2JQB.js.map +1 -0
- package/dist/_chunks/wrappers-BaG1bnM3.js +63 -0
- package/dist/_chunks/wrappers-BaG1bnM3.js.map +1 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +17 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +56 -13
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/fast-hash.d.ts +22 -0
- package/dist/cache/fast-hash.d.ts.map +1 -0
- package/dist/cache/index.d.ts +5 -2
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +90 -20
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/register-cached-function.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +18 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/timber-cache.d.ts +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +10 -1
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -125
- package/dist/client/error-reconstituter.d.ts +54 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +2 -2
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +433 -252
- package/dist/client/index.js.map +1 -1
- package/dist/client/link-pending-store.d.ts +78 -0
- package/dist/client/link-pending-store.d.ts.map +1 -0
- package/dist/client/link.d.ts +23 -9
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +2 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/router.d.ts +25 -3
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +36 -2
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-merger.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +63 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +1 -1
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/transition-root.d.ts +1 -1
- package/dist/client/transition-root.d.ts.map +1 -1
- package/dist/client/use-params.d.ts +3 -3
- package/dist/client/use-params.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/codec.d.ts +21 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/cookies/define-cookie.d.ts +34 -13
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -83
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/index.d.ts +127 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +665 -242
- package/dist/index.js.map +1 -1
- package/dist/params/define.d.ts +100 -0
- package/dist/params/define.d.ts.map +1 -0
- package/dist/params/index.d.ts +8 -0
- package/dist/params/index.d.ts.map +1 -0
- package/dist/params/index.js +4 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +2 -2
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +3 -3
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +32 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-browser-logs.d.ts +84 -0
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
- package/dist/plugins/dev-error-overlay.d.ts +26 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/dev-logs.d.ts +1 -1
- package/dist/plugins/dev-logs.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +9 -2
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +1 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts +6 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +1 -1
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/status-file-lint.d.ts +2 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +16 -4
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/search-params/codecs.d.ts +1 -1
- package/dist/search-params/define.d.ts +159 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -5
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +4 -474
- package/dist/search-params/registry.d.ts +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/server/access-gate.d.ts +4 -0
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +1 -1
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +25 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/debug.d.ts +1 -1
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +4 -0
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +4 -3
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/flush.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +51 -11
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +4 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1977 -1648
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.d.ts +25 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +113 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +20 -6
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +30 -3
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +65 -38
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +7 -0
- 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 +9 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +2 -2
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +48 -5
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +8 -3
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +10 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +22 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +39 -21
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +50 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +1 -1
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +36 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +10 -0
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +20 -13
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -3
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/waituntil-bridge.d.ts.map +1 -1
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +1 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +1 -1
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/package.json +17 -17
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +58 -9
- package/src/cache/fast-hash.ts +34 -0
- package/src/cache/index.ts +5 -2
- package/src/cache/register-cached-function.ts +7 -3
- package/src/cache/singleflight.ts +62 -4
- package/src/cache/timber-cache.ts +40 -29
- package/src/cli.ts +0 -0
- package/src/client/browser-entry.ts +151 -99
- package/src/client/error-boundary.tsx +18 -1
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +2 -2
- package/src/client/index.ts +10 -1
- package/src/client/link-pending-store.ts +136 -0
- package/src/client/link.tsx +137 -22
- package/src/client/navigation-context.ts +6 -5
- package/src/client/router.ts +117 -60
- package/src/client/rsc-fetch.ts +90 -2
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-context.ts +6 -1
- package/src/client/segment-merger.ts +2 -8
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/stale-reload.ts +73 -6
- package/src/client/top-loader.tsx +10 -9
- package/src/client/transition-root.tsx +20 -2
- package/src/client/use-params.ts +4 -4
- package/src/client/use-query-states.ts +2 -2
- package/src/codec.ts +21 -0
- package/src/cookies/define-cookie.ts +71 -20
- package/src/fonts/css.ts +2 -1
- package/src/index.ts +297 -85
- package/src/params/define.ts +327 -0
- package/src/params/index.ts +28 -0
- package/src/plugins/adapter-build.ts +8 -2
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +3 -3
- package/src/plugins/cache-transform.ts +1 -1
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-browser-logs.ts +284 -0
- package/src/plugins/dev-error-overlay.ts +70 -1
- package/src/plugins/dev-logs.ts +1 -1
- package/src/plugins/dev-server.ts +41 -7
- package/src/plugins/entries.ts +6 -8
- package/src/plugins/fonts.ts +102 -55
- package/src/plugins/mdx.ts +1 -1
- package/src/plugins/routing.ts +57 -17
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +69 -31
- package/src/plugins/static-build.ts +10 -6
- package/src/routing/codegen.ts +109 -88
- package/src/routing/scanner.ts +86 -7
- package/src/routing/status-file-lint.ts +3 -2
- package/src/routing/types.ts +17 -4
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/search-params/codecs.ts +1 -1
- package/src/search-params/define.ts +518 -0
- package/src/search-params/index.ts +12 -18
- package/src/search-params/registry.ts +1 -1
- package/src/search-params/wrappers.ts +85 -0
- package/src/server/access-gate.tsx +40 -9
- package/src/server/action-client.ts +8 -2
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +20 -3
- package/src/server/actions.ts +1 -1
- package/src/server/als-registry.ts +25 -4
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/debug.ts +1 -1
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-renderer.ts +5 -3
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +58 -15
- package/src/server/fallback-error.ts +29 -14
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injectors.ts +277 -117
- package/src/server/index.ts +9 -4
- package/src/server/logger.ts +44 -36
- package/src/server/node-stream-transforms.ts +509 -0
- package/src/server/pipeline-interception.ts +1 -1
- package/src/server/pipeline.ts +148 -41
- package/src/server/primitives.ts +47 -5
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +125 -119
- package/src/server/route-element-builder.ts +107 -115
- package/src/server/route-handler.ts +2 -1
- package/src/server/route-matcher.ts +9 -2
- package/src/server/rsc-entry/api-handler.ts +8 -8
- package/src/server/rsc-entry/error-renderer.ts +286 -81
- package/src/server/rsc-entry/helpers.ts +134 -5
- package/src/server/rsc-entry/index.ts +177 -76
- package/src/server/rsc-entry/rsc-payload.ts +91 -18
- package/src/server/rsc-entry/rsc-stream.ts +74 -18
- package/src/server/rsc-entry/ssr-bridge.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +152 -34
- package/src/server/slot-resolver.ts +231 -220
- package/src/server/ssr-entry.ts +211 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/status-code-resolver.ts +1 -1
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +23 -0
- package/src/server/tree-builder.ts +92 -58
- package/src/server/types.ts +1 -3
- package/src/server/version-skew.ts +104 -0
- package/src/server/waituntil-bridge.ts +4 -1
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/navigation-client.ts +1 -1
- package/src/shims/navigation.ts +2 -1
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
- package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
- package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
- package/dist/client/error-boundary.js.map +0 -1
- package/dist/client/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/cookies/index.js.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/search-params/index.js.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/response-cache.d.ts +0 -53
- package/dist/server/response-cache.d.ts.map +0 -1
- package/src/client/link-status-provider.tsx +0 -30
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/prerender.ts +0 -139
- package/src/server/response-cache.ts +0 -277
package/dist/client/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { n as useQueryStates, t as bindUseQueryStates } from "../_chunks/use-query-states-
|
|
4
|
-
import { t as
|
|
5
|
-
import { TimberErrorBoundary } from "
|
|
6
|
-
import
|
|
2
|
+
import { n as __exportAll } from "../_chunks/chunk-DYhsFzuS.js";
|
|
3
|
+
import { n as useQueryStates, t as bindUseQueryStates } from "../_chunks/use-query-states-wEXY2JQB.js";
|
|
4
|
+
import { n as useSegmentContext, r as mergePreservedSearchParams, t as SegmentProvider } from "../_chunks/segment-context-CyaM1mrD.js";
|
|
5
|
+
import { a as _setCachedSearch, c as cachedSearch, d as globalRouter, i as setSsrData, l as cachedSearchParams, n as clearSsrData, o as _setCurrentParams, r as getSsrData, s as _setGlobalRouter, t as TimberErrorBoundary, u as currentParams } from "../_chunks/error-boundary-DpZJBCqh.js";
|
|
6
|
+
import { t as _registerUseCookieModule } from "../_chunks/define-cookie-BWr_52kY.js";
|
|
7
|
+
import React, { cloneElement, createContext, createElement, isValidElement, useActionState as useActionState$1, useContext, useEffect, useRef, useState, useSyncExternalStore, useTransition } from "react";
|
|
7
8
|
import { jsx } from "react/jsx-runtime";
|
|
8
9
|
//#region src/client/use-link-status.ts
|
|
9
10
|
/**
|
|
@@ -40,165 +41,6 @@ function useLinkStatus() {
|
|
|
40
41
|
return useContext(LinkStatusContext);
|
|
41
42
|
}
|
|
42
43
|
//#endregion
|
|
43
|
-
//#region src/client/navigation-context.ts
|
|
44
|
-
/**
|
|
45
|
-
* NavigationContext — React context for navigation state.
|
|
46
|
-
*
|
|
47
|
-
* Holds the current route params and pathname, updated atomically
|
|
48
|
-
* with the RSC tree on each navigation. This replaces the previous
|
|
49
|
-
* useSyncExternalStore approach for useParams() and usePathname(),
|
|
50
|
-
* which suffered from a timing gap: the new tree could commit before
|
|
51
|
-
* the external store re-renders fired, causing a frame where both
|
|
52
|
-
* old and new active states were visible simultaneously.
|
|
53
|
-
*
|
|
54
|
-
* By wrapping the RSC payload element in NavigationProvider inside
|
|
55
|
-
* renderRoot(), the context value and the element tree are passed to
|
|
56
|
-
* reactRoot.render() in the same call — atomic by construction.
|
|
57
|
-
* All consumers (useParams, usePathname) see the new values in the
|
|
58
|
-
* same render pass as the new tree.
|
|
59
|
-
*
|
|
60
|
-
* During SSR, no NavigationProvider is mounted. Hooks fall back to
|
|
61
|
-
* the ALS-backed getSsrData() for per-request isolation.
|
|
62
|
-
*
|
|
63
|
-
* IMPORTANT: createContext and useContext are NOT available in the RSC
|
|
64
|
-
* environment (React Server Components use a stripped-down React).
|
|
65
|
-
* The context is lazily initialized on first access, and all functions
|
|
66
|
-
* that depend on these APIs are safe to call from any environment —
|
|
67
|
-
* they return null or no-op when the APIs aren't available.
|
|
68
|
-
*
|
|
69
|
-
* SINGLETON GUARANTEE: All shared mutable state uses globalThis via
|
|
70
|
-
* Symbol.for keys. The RSC client bundler can duplicate this module
|
|
71
|
-
* across chunks (browser-entry graph + client-reference graph). With
|
|
72
|
-
* ESM output, each chunk gets its own module scope — module-level
|
|
73
|
-
* variables would create separate singleton instances per chunk.
|
|
74
|
-
* globalThis guarantees a single instance regardless of duplication.
|
|
75
|
-
*
|
|
76
|
-
* This workaround will be removed when Rolldown ships `format: 'app'`
|
|
77
|
-
* (module registry format that deduplicates like webpack/Turbopack).
|
|
78
|
-
* See design/27-chunking-strategy.md.
|
|
79
|
-
*
|
|
80
|
-
* See design/19-client-navigation.md §"NavigationContext"
|
|
81
|
-
*/
|
|
82
|
-
/**
|
|
83
|
-
* The context is created lazily to avoid calling createContext at module
|
|
84
|
-
* level. In the RSC environment, React.createContext doesn't exist —
|
|
85
|
-
* calling it at import time would crash the server.
|
|
86
|
-
*
|
|
87
|
-
* Context instances are stored on globalThis (NOT in module-level
|
|
88
|
-
* variables) because the ESM bundler can duplicate this module across
|
|
89
|
-
* chunks. Module-level variables would create separate instances per
|
|
90
|
-
* chunk — the provider in TransitionRoot (index chunk) would use
|
|
91
|
-
* context A while the consumer in LinkStatusProvider (shared chunk)
|
|
92
|
-
* reads from context B. globalThis guarantees a single instance.
|
|
93
|
-
*
|
|
94
|
-
* See design/27-chunking-strategy.md §"Singleton Safety"
|
|
95
|
-
*/
|
|
96
|
-
var NAV_CTX_KEY = Symbol.for("__timber_nav_ctx");
|
|
97
|
-
var PENDING_CTX_KEY = Symbol.for("__timber_pending_nav_ctx");
|
|
98
|
-
function getOrCreateContext() {
|
|
99
|
-
const existing = globalThis[NAV_CTX_KEY];
|
|
100
|
-
if (existing !== void 0) return existing;
|
|
101
|
-
if (typeof React.createContext === "function") {
|
|
102
|
-
const ctx = React.createContext(null);
|
|
103
|
-
globalThis[NAV_CTX_KEY] = ctx;
|
|
104
|
-
return ctx;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Read the navigation context. Returns null during SSR (no provider)
|
|
109
|
-
* or in the RSC environment (no context available).
|
|
110
|
-
* Internal — used by useParams() and usePathname().
|
|
111
|
-
*/
|
|
112
|
-
function useNavigationContext() {
|
|
113
|
-
const ctx = getOrCreateContext();
|
|
114
|
-
if (!ctx) return null;
|
|
115
|
-
if (typeof React.useContext !== "function") return null;
|
|
116
|
-
return React.useContext(ctx);
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Wraps children with NavigationContext.Provider.
|
|
120
|
-
*
|
|
121
|
-
* Used in browser-entry.ts renderRoot to wrap the RSC payload element
|
|
122
|
-
* so that navigation state updates atomically with the tree render.
|
|
123
|
-
*/
|
|
124
|
-
function NavigationProvider({ value, children }) {
|
|
125
|
-
const ctx = getOrCreateContext();
|
|
126
|
-
if (!ctx) return children;
|
|
127
|
-
return createElement(ctx.Provider, { value }, children);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Navigation state communicated between the router and renderRoot.
|
|
131
|
-
*
|
|
132
|
-
* The router calls setNavigationState() before renderRoot(). The
|
|
133
|
-
* renderRoot callback reads via getNavigationState() to create the
|
|
134
|
-
* NavigationProvider with the correct params/pathname.
|
|
135
|
-
*
|
|
136
|
-
* This is NOT used by hooks directly — hooks read from React context.
|
|
137
|
-
*
|
|
138
|
-
* Stored on globalThis (like the context instances above) because the
|
|
139
|
-
* router lives in one chunk while renderRoot lives in another. Module-
|
|
140
|
-
* level variables would be separate per chunk.
|
|
141
|
-
*/
|
|
142
|
-
var NAV_STATE_KEY = Symbol.for("__timber_nav_state");
|
|
143
|
-
function _getNavStateStore() {
|
|
144
|
-
const g = globalThis;
|
|
145
|
-
if (!g[NAV_STATE_KEY]) g[NAV_STATE_KEY] = { current: {
|
|
146
|
-
params: {},
|
|
147
|
-
pathname: "/"
|
|
148
|
-
} };
|
|
149
|
-
return g[NAV_STATE_KEY];
|
|
150
|
-
}
|
|
151
|
-
function setNavigationState(state) {
|
|
152
|
-
_getNavStateStore().current = state;
|
|
153
|
-
}
|
|
154
|
-
function getNavigationState() {
|
|
155
|
-
return _getNavStateStore().current;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Separate context for the in-flight navigation URL. Provided by
|
|
159
|
-
* TransitionRoot (urgent useState), consumed by LinkStatusProvider
|
|
160
|
-
* and useNavigationPending.
|
|
161
|
-
*
|
|
162
|
-
* Uses globalThis via Symbol.for for the same reason as NavigationContext
|
|
163
|
-
* above — the bundler may duplicate this module across chunks, and module-
|
|
164
|
-
* level variables would create separate context instances.
|
|
165
|
-
*/
|
|
166
|
-
function getOrCreatePendingContext() {
|
|
167
|
-
const existing = globalThis[PENDING_CTX_KEY];
|
|
168
|
-
if (existing !== void 0) return existing;
|
|
169
|
-
if (typeof React.createContext === "function") {
|
|
170
|
-
const ctx = React.createContext(null);
|
|
171
|
-
globalThis[PENDING_CTX_KEY] = ctx;
|
|
172
|
-
return ctx;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Read the pending navigation URL from context.
|
|
177
|
-
* Returns null during SSR (no provider) or in the RSC environment.
|
|
178
|
-
*/
|
|
179
|
-
function usePendingNavigationUrl() {
|
|
180
|
-
const ctx = getOrCreatePendingContext();
|
|
181
|
-
if (!ctx) return null;
|
|
182
|
-
if (typeof React.useContext !== "function") return null;
|
|
183
|
-
return React.useContext(ctx);
|
|
184
|
-
}
|
|
185
|
-
//#endregion
|
|
186
|
-
//#region src/client/link-status-provider.tsx
|
|
187
|
-
var NOT_PENDING = { pending: false };
|
|
188
|
-
var IS_PENDING = { pending: true };
|
|
189
|
-
/**
|
|
190
|
-
* Client component that reads the pending URL from PendingNavigationContext
|
|
191
|
-
* and provides a scoped LinkStatusContext to children. Renders no extra DOM —
|
|
192
|
-
* just a context provider around children.
|
|
193
|
-
*/
|
|
194
|
-
function LinkStatusProvider({ href, children }) {
|
|
195
|
-
const status = usePendingNavigationUrl() === href ? IS_PENDING : NOT_PENDING;
|
|
196
|
-
return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
|
|
197
|
-
value: status,
|
|
198
|
-
children
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
//#endregion
|
|
202
44
|
//#region src/client/router-ref.ts
|
|
203
45
|
/**
|
|
204
46
|
* Set the global router instance. Called once during bootstrap.
|
|
@@ -223,8 +65,62 @@ function getRouterOrNull() {
|
|
|
223
65
|
return globalRouter;
|
|
224
66
|
}
|
|
225
67
|
//#endregion
|
|
68
|
+
//#region src/client/link-pending-store.ts
|
|
69
|
+
var LINK_PENDING_KEY = Symbol.for("__timber_link_pending");
|
|
70
|
+
/** Status object indicating link is pending — shared reference */
|
|
71
|
+
var PENDING_LINK_STATUS = { pending: true };
|
|
72
|
+
/** Status object indicating link is idle — shared reference */
|
|
73
|
+
var IDLE_LINK_STATUS = { pending: false };
|
|
74
|
+
function getStore() {
|
|
75
|
+
const g = globalThis;
|
|
76
|
+
if (!g[LINK_PENDING_KEY]) g[LINK_PENDING_KEY] = {
|
|
77
|
+
current: null,
|
|
78
|
+
navId: 0
|
|
79
|
+
};
|
|
80
|
+
return g[LINK_PENDING_KEY];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Register the link instance that initiated the current navigation.
|
|
84
|
+
*
|
|
85
|
+
* Called from <Link>'s click handler before router.navigate().
|
|
86
|
+
* - Resets the previous pending link to IDLE (urgent update, immediate)
|
|
87
|
+
* - Does NOT set the new link to PENDING here — the Link's click handler
|
|
88
|
+
* calls setLinkStatus(PENDING) directly for the eager show
|
|
89
|
+
* - Increments the navId counter for stale-clear protection
|
|
90
|
+
*
|
|
91
|
+
* Pass `null` to clear (e.g., for programmatic navigations).
|
|
92
|
+
*/
|
|
93
|
+
function setLinkForCurrentNavigation(link) {
|
|
94
|
+
const store = getStore();
|
|
95
|
+
const prev = store.current;
|
|
96
|
+
if (prev && prev !== link) prev.setLinkStatus(IDLE_LINK_STATUS);
|
|
97
|
+
store.current = link;
|
|
98
|
+
store.navId++;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Unmount a link instance from navigation tracking. Called when a Link
|
|
102
|
+
* component unmounts while it is the current navigation link. Prevents
|
|
103
|
+
* calling setState on an unmounted component.
|
|
104
|
+
*/
|
|
105
|
+
function unmountLinkForCurrentNavigation(link) {
|
|
106
|
+
const store = getStore();
|
|
107
|
+
if (store.current === link) store.current = null;
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
226
110
|
//#region src/client/link.tsx
|
|
227
111
|
/**
|
|
112
|
+
* Read the current URL's search string without requiring a React hook.
|
|
113
|
+
* On the client, reads window.location.search. During SSR, reads from
|
|
114
|
+
* the request context (getSsrData). Returns empty string if unavailable.
|
|
115
|
+
*/
|
|
116
|
+
function getCurrentSearch() {
|
|
117
|
+
if (typeof window !== "undefined") return window.location.search;
|
|
118
|
+
const data = getSsrData();
|
|
119
|
+
if (!data) return "";
|
|
120
|
+
const str = new URLSearchParams(data.searchParams).toString();
|
|
121
|
+
return str ? `?${str}` : "";
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
228
124
|
* Reject dangerous URL schemes that could execute script.
|
|
229
125
|
* Security: design/13-security.md § Link scheme injection (test #9)
|
|
230
126
|
*/
|
|
@@ -324,15 +220,26 @@ function shouldInterceptClick(event, resolvedHref) {
|
|
|
324
220
|
* its own click handling.
|
|
325
221
|
*
|
|
326
222
|
* Supports typed routes via codegen overloads. At runtime:
|
|
327
|
-
* - `
|
|
223
|
+
* - `segmentParams` prop interpolates dynamic segments in the href pattern
|
|
328
224
|
* - `searchParams` prop serializes query parameters via a SearchParamsDefinition
|
|
329
225
|
*/
|
|
330
|
-
function Link({ href, prefetch, scroll,
|
|
331
|
-
const { href:
|
|
226
|
+
function Link({ href, prefetch, scroll, segmentParams, searchParams, preserveSearchParams, onNavigate, onClick: userOnClick, onMouseEnter: userOnMouseEnter, children, ...rest }) {
|
|
227
|
+
const { href: baseHref } = buildLinkProps({
|
|
332
228
|
href,
|
|
333
|
-
params,
|
|
229
|
+
params: segmentParams,
|
|
334
230
|
searchParams
|
|
335
231
|
});
|
|
232
|
+
const [linkStatus, setLinkStatus] = useState(IDLE_LINK_STATUS);
|
|
233
|
+
const linkInstanceRef = useRef(null);
|
|
234
|
+
if (!linkInstanceRef.current) linkInstanceRef.current = { setLinkStatus };
|
|
235
|
+
else linkInstanceRef.current.setLinkStatus = setLinkStatus;
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
const instance = linkInstanceRef.current;
|
|
238
|
+
return () => {
|
|
239
|
+
if (instance) unmountLinkForCurrentNavigation(instance);
|
|
240
|
+
};
|
|
241
|
+
}, []);
|
|
242
|
+
const resolvedHref = preserveSearchParams ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams) : baseHref;
|
|
336
243
|
const internal = isInternalHref(resolvedHref);
|
|
337
244
|
const handleClick = internal ? (event) => {
|
|
338
245
|
userOnClick?.(event);
|
|
@@ -351,20 +258,26 @@ function Link({ href, prefetch, scroll, params, searchParams, onNavigate, onClic
|
|
|
351
258
|
if (!router) return;
|
|
352
259
|
event.preventDefault();
|
|
353
260
|
const shouldScroll = scroll !== false;
|
|
354
|
-
|
|
261
|
+
const navHref = preserveSearchParams ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams) : resolvedHref;
|
|
262
|
+
setLinkStatus(PENDING_LINK_STATUS);
|
|
263
|
+
setLinkForCurrentNavigation(linkInstanceRef.current);
|
|
264
|
+
router.navigate(navHref, { scroll: shouldScroll });
|
|
355
265
|
} : userOnClick;
|
|
356
266
|
const handleMouseEnter = internal && prefetch ? (event) => {
|
|
357
267
|
userOnMouseEnter?.(event);
|
|
358
268
|
const router = getRouterOrNull();
|
|
359
|
-
if (router)
|
|
269
|
+
if (router) {
|
|
270
|
+
const prefetchHref = preserveSearchParams ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams) : resolvedHref;
|
|
271
|
+
router.prefetch(prefetchHref);
|
|
272
|
+
}
|
|
360
273
|
} : userOnMouseEnter;
|
|
361
274
|
return /* @__PURE__ */ jsx("a", {
|
|
362
275
|
...rest,
|
|
363
276
|
href: resolvedHref,
|
|
364
277
|
onClick: handleClick,
|
|
365
278
|
onMouseEnter: handleMouseEnter,
|
|
366
|
-
children: /* @__PURE__ */ jsx(
|
|
367
|
-
|
|
279
|
+
children: /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
|
|
280
|
+
value: linkStatus,
|
|
368
281
|
children
|
|
369
282
|
})
|
|
370
283
|
});
|
|
@@ -501,6 +414,150 @@ var HistoryStack = class {
|
|
|
501
414
|
}
|
|
502
415
|
};
|
|
503
416
|
//#endregion
|
|
417
|
+
//#region src/client/navigation-context.ts
|
|
418
|
+
/**
|
|
419
|
+
* NavigationContext — React context for navigation state.
|
|
420
|
+
*
|
|
421
|
+
* Holds the current route params and pathname, updated atomically
|
|
422
|
+
* with the RSC tree on each navigation. This replaces the previous
|
|
423
|
+
* useSyncExternalStore approach for useSegmentParams() and usePathname(),
|
|
424
|
+
* which suffered from a timing gap: the new tree could commit before
|
|
425
|
+
* the external store re-renders fired, causing a frame where both
|
|
426
|
+
* old and new active states were visible simultaneously.
|
|
427
|
+
*
|
|
428
|
+
* By wrapping the RSC payload element in NavigationProvider inside
|
|
429
|
+
* renderRoot(), the context value and the element tree are passed to
|
|
430
|
+
* reactRoot.render() in the same call — atomic by construction.
|
|
431
|
+
* All consumers (useParams, usePathname) see the new values in the
|
|
432
|
+
* same render pass as the new tree.
|
|
433
|
+
*
|
|
434
|
+
* During SSR, no NavigationProvider is mounted. Hooks fall back to
|
|
435
|
+
* the ALS-backed getSsrData() for per-request isolation.
|
|
436
|
+
*
|
|
437
|
+
* IMPORTANT: createContext and useContext are NOT available in the RSC
|
|
438
|
+
* environment (React Server Components use a stripped-down React).
|
|
439
|
+
* The context is lazily initialized on first access, and all functions
|
|
440
|
+
* that depend on these APIs are safe to call from any environment —
|
|
441
|
+
* they return null or no-op when the APIs aren't available.
|
|
442
|
+
*
|
|
443
|
+
* SINGLETON GUARANTEE: All shared mutable state uses globalThis via
|
|
444
|
+
* Symbol.for keys. The RSC client bundler can duplicate this module
|
|
445
|
+
* across chunks (browser-entry graph + client-reference graph). With
|
|
446
|
+
* ESM output, each chunk gets its own module scope — module-level
|
|
447
|
+
* variables would create separate singleton instances per chunk.
|
|
448
|
+
* globalThis guarantees a single instance regardless of duplication.
|
|
449
|
+
*
|
|
450
|
+
* This workaround will be removed when Rolldown ships `format: 'app'`
|
|
451
|
+
* (module registry format that deduplicates like webpack/Turbopack).
|
|
452
|
+
* See design/27-chunking-strategy.md.
|
|
453
|
+
*
|
|
454
|
+
* See design/19-client-navigation.md §"NavigationContext"
|
|
455
|
+
*/
|
|
456
|
+
/**
|
|
457
|
+
* The context is created lazily to avoid calling createContext at module
|
|
458
|
+
* level. In the RSC environment, React.createContext doesn't exist —
|
|
459
|
+
* calling it at import time would crash the server.
|
|
460
|
+
*
|
|
461
|
+
* Context instances are stored on globalThis (NOT in module-level
|
|
462
|
+
* variables) because the ESM bundler can duplicate this module across
|
|
463
|
+
* chunks. Module-level variables would create separate instances per
|
|
464
|
+
* chunk — the provider in TransitionRoot (index chunk) would use
|
|
465
|
+
* context A while the consumer in useNavigationPending (shared chunk)
|
|
466
|
+
* reads from context B. globalThis guarantees a single instance.
|
|
467
|
+
*
|
|
468
|
+
* See design/27-chunking-strategy.md §"Singleton Safety"
|
|
469
|
+
*/
|
|
470
|
+
var NAV_CTX_KEY = Symbol.for("__timber_nav_ctx");
|
|
471
|
+
var PENDING_CTX_KEY = Symbol.for("__timber_pending_nav_ctx");
|
|
472
|
+
function getOrCreateContext() {
|
|
473
|
+
const existing = globalThis[NAV_CTX_KEY];
|
|
474
|
+
if (existing !== void 0) return existing;
|
|
475
|
+
if (typeof React.createContext === "function") {
|
|
476
|
+
const ctx = React.createContext(null);
|
|
477
|
+
globalThis[NAV_CTX_KEY] = ctx;
|
|
478
|
+
return ctx;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Read the navigation context. Returns null during SSR (no provider)
|
|
483
|
+
* or in the RSC environment (no context available).
|
|
484
|
+
* Internal — used by useSegmentParams() and usePathname().
|
|
485
|
+
*/
|
|
486
|
+
function useNavigationContext() {
|
|
487
|
+
const ctx = getOrCreateContext();
|
|
488
|
+
if (!ctx) return null;
|
|
489
|
+
if (typeof React.useContext !== "function") return null;
|
|
490
|
+
return React.useContext(ctx);
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Wraps children with NavigationContext.Provider.
|
|
494
|
+
*
|
|
495
|
+
* Used in browser-entry.ts renderRoot to wrap the RSC payload element
|
|
496
|
+
* so that navigation state updates atomically with the tree render.
|
|
497
|
+
*/
|
|
498
|
+
function NavigationProvider({ value, children }) {
|
|
499
|
+
const ctx = getOrCreateContext();
|
|
500
|
+
if (!ctx) return children;
|
|
501
|
+
return createElement(ctx.Provider, { value }, children);
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Navigation state communicated between the router and renderRoot.
|
|
505
|
+
*
|
|
506
|
+
* The router calls setNavigationState() before renderRoot(). The
|
|
507
|
+
* renderRoot callback reads via getNavigationState() to create the
|
|
508
|
+
* NavigationProvider with the correct params/pathname.
|
|
509
|
+
*
|
|
510
|
+
* This is NOT used by hooks directly — hooks read from React context.
|
|
511
|
+
*
|
|
512
|
+
* Stored on globalThis (like the context instances above) because the
|
|
513
|
+
* router lives in one chunk while renderRoot lives in another. Module-
|
|
514
|
+
* level variables would be separate per chunk.
|
|
515
|
+
*/
|
|
516
|
+
var NAV_STATE_KEY = Symbol.for("__timber_nav_state");
|
|
517
|
+
function _getNavStateStore() {
|
|
518
|
+
const g = globalThis;
|
|
519
|
+
if (!g[NAV_STATE_KEY]) g[NAV_STATE_KEY] = { current: {
|
|
520
|
+
params: {},
|
|
521
|
+
pathname: "/"
|
|
522
|
+
} };
|
|
523
|
+
return g[NAV_STATE_KEY];
|
|
524
|
+
}
|
|
525
|
+
function setNavigationState(state) {
|
|
526
|
+
_getNavStateStore().current = state;
|
|
527
|
+
}
|
|
528
|
+
function getNavigationState() {
|
|
529
|
+
return _getNavStateStore().current;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Separate context for the in-flight navigation URL. Provided by
|
|
533
|
+
* TransitionRoot (urgent useState), consumed by useNavigationPending
|
|
534
|
+
* and TopLoader. Per-link pending state uses useOptimistic instead
|
|
535
|
+
* (see link-pending-store.ts).
|
|
536
|
+
*
|
|
537
|
+
* Uses globalThis via Symbol.for for the same reason as NavigationContext
|
|
538
|
+
* above — the bundler may duplicate this module across chunks, and module-
|
|
539
|
+
* level variables would create separate context instances.
|
|
540
|
+
*/
|
|
541
|
+
function getOrCreatePendingContext() {
|
|
542
|
+
const existing = globalThis[PENDING_CTX_KEY];
|
|
543
|
+
if (existing !== void 0) return existing;
|
|
544
|
+
if (typeof React.createContext === "function") {
|
|
545
|
+
const ctx = React.createContext(null);
|
|
546
|
+
globalThis[PENDING_CTX_KEY] = ctx;
|
|
547
|
+
return ctx;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Read the pending navigation URL from context.
|
|
552
|
+
* Returns null during SSR (no provider) or in the RSC environment.
|
|
553
|
+
*/
|
|
554
|
+
function usePendingNavigationUrl() {
|
|
555
|
+
const ctx = getOrCreatePendingContext();
|
|
556
|
+
if (!ctx) return null;
|
|
557
|
+
if (typeof React.useContext !== "function") return null;
|
|
558
|
+
return React.useContext(ctx);
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
504
561
|
//#region src/client/use-params.ts
|
|
505
562
|
/**
|
|
506
563
|
* Set the current route params in the module-level store.
|
|
@@ -520,7 +577,7 @@ var HistoryStack = class {
|
|
|
520
577
|
function setCurrentParams(params) {
|
|
521
578
|
_setCurrentParams(params);
|
|
522
579
|
}
|
|
523
|
-
function
|
|
580
|
+
function useSegmentParams(_route) {
|
|
524
581
|
try {
|
|
525
582
|
const navContext = useNavigationContext();
|
|
526
583
|
if (navContext !== null) return navContext.params;
|
|
@@ -759,10 +816,28 @@ function generateCacheBustId() {
|
|
|
759
816
|
function appendRscParam(url) {
|
|
760
817
|
return `${url}${url.includes("?") ? "&" : "?"}_rsc=${generateCacheBustId()}`;
|
|
761
818
|
}
|
|
819
|
+
/**
|
|
820
|
+
* The client's deployment ID, set at bootstrap from the runtime config.
|
|
821
|
+
* Sent with every RSC/action request for version skew detection.
|
|
822
|
+
* Null in dev mode. See TIM-446.
|
|
823
|
+
*/
|
|
824
|
+
var clientDeploymentId = null;
|
|
825
|
+
/** Header name used by the server to signal a version skew reload. */
|
|
826
|
+
var RELOAD_HEADER = "X-Timber-Reload";
|
|
827
|
+
/** Header name for the client's deployment ID. */
|
|
828
|
+
var DEPLOYMENT_ID_HEADER = "X-Timber-Deployment-Id";
|
|
829
|
+
/**
|
|
830
|
+
* Check if a response signals a version skew reload.
|
|
831
|
+
* Triggers a full page reload if the server indicates the client is stale.
|
|
832
|
+
*/
|
|
833
|
+
function checkReloadSignal(response) {
|
|
834
|
+
return response.headers.get(RELOAD_HEADER) === "1";
|
|
835
|
+
}
|
|
762
836
|
function buildRscHeaders(stateTree, currentUrl) {
|
|
763
837
|
const headers = { Accept: RSC_CONTENT_TYPE };
|
|
764
838
|
if (stateTree) headers["X-Timber-State-Tree"] = JSON.stringify(stateTree);
|
|
765
839
|
if (currentUrl) headers["X-Timber-URL"] = currentUrl;
|
|
840
|
+
if (clientDeploymentId) headers[DEPLOYMENT_ID_HEADER] = clientDeploymentId;
|
|
766
841
|
return headers;
|
|
767
842
|
}
|
|
768
843
|
/**
|
|
@@ -817,7 +892,7 @@ function extractSkippedSegments(response) {
|
|
|
817
892
|
* Extract route params from the X-Timber-Params response header.
|
|
818
893
|
* Returns null if the header is missing or malformed.
|
|
819
894
|
*
|
|
820
|
-
* Used to populate
|
|
895
|
+
* Used to populate useSegmentParams() after client-side navigation.
|
|
821
896
|
*/
|
|
822
897
|
function extractParams(response) {
|
|
823
898
|
const header = response.headers.get("X-Timber-Params");
|
|
@@ -840,6 +915,33 @@ var RedirectError = class extends Error {
|
|
|
840
915
|
}
|
|
841
916
|
};
|
|
842
917
|
/**
|
|
918
|
+
* Thrown when the server signals a version skew (X-Timber-Reload header).
|
|
919
|
+
* Caught in navigate() to trigger a full page reload via triggerStaleReload().
|
|
920
|
+
* See TIM-446.
|
|
921
|
+
*/
|
|
922
|
+
var VersionSkewError = class extends Error {
|
|
923
|
+
constructor() {
|
|
924
|
+
super("Version skew detected — server has been redeployed");
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
/**
|
|
928
|
+
* Thrown when the server returns a 5xx error for an RSC payload request.
|
|
929
|
+
* The server sends X-Timber-Error header and a JSON body instead of a
|
|
930
|
+
* broken RSC stream. Caught in navigate() to trigger a hard navigation
|
|
931
|
+
* so the server can render the error page as HTML.
|
|
932
|
+
*
|
|
933
|
+
* See design/10-error-handling.md §"Error Page Rendering for Client Navigation"
|
|
934
|
+
*/
|
|
935
|
+
var ServerErrorResponse = class extends Error {
|
|
936
|
+
status;
|
|
937
|
+
url;
|
|
938
|
+
constructor(status, url) {
|
|
939
|
+
super(`Server error ${status} during navigation to ${url}`);
|
|
940
|
+
this.status = status;
|
|
941
|
+
this.url = url;
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
/**
|
|
843
945
|
* Fetch an RSC payload from the server. If a decodeRsc function is provided,
|
|
844
946
|
* the response is decoded into a React element tree via createFromFetch.
|
|
845
947
|
* Otherwise, the raw response text is returned (test mode).
|
|
@@ -860,8 +962,10 @@ async function fetchRscPayload(url, deps, stateTree, currentUrl) {
|
|
|
860
962
|
let params = null;
|
|
861
963
|
let skippedSegments = null;
|
|
862
964
|
const wrappedPromise = fetchPromise.then((response) => {
|
|
965
|
+
if (checkReloadSignal(response)) throw new VersionSkewError();
|
|
863
966
|
const redirectLocation = response.headers.get("X-Timber-Redirect") || (response.status >= 300 && response.status < 400 ? response.headers.get("Location") : null);
|
|
864
967
|
if (redirectLocation) throw new RedirectError(redirectLocation);
|
|
968
|
+
if (response.headers.get("X-Timber-Error") === "1" && response.status >= 500) throw new ServerErrorResponse(response.status, url);
|
|
865
969
|
headElements = extractHeadElements(response);
|
|
866
970
|
segmentInfo = extractSegmentInfo(response);
|
|
867
971
|
params = extractParams(response);
|
|
@@ -904,23 +1008,20 @@ function isAbortError(error) {
|
|
|
904
1008
|
if (error instanceof Error && error.name === "AbortError") return true;
|
|
905
1009
|
return false;
|
|
906
1010
|
}
|
|
907
|
-
/**
|
|
908
|
-
* Create a router instance. In production, called once at app hydration
|
|
909
|
-
* with real browser APIs. In tests, called with mock dependencies.
|
|
910
|
-
*/
|
|
911
1011
|
function createRouter(deps) {
|
|
912
1012
|
const segmentCache = new SegmentCache();
|
|
913
1013
|
const prefetchCache = new PrefetchCache();
|
|
914
1014
|
const historyStack = new HistoryStack();
|
|
915
1015
|
const segmentElementCache = new SegmentElementCache();
|
|
916
|
-
let
|
|
917
|
-
let pendingUrl = null;
|
|
1016
|
+
let routerPhase = { phase: "idle" };
|
|
918
1017
|
const pendingListeners = /* @__PURE__ */ new Set();
|
|
919
1018
|
function setPending(value, url) {
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1019
|
+
const next = value && url ? {
|
|
1020
|
+
phase: "navigating",
|
|
1021
|
+
targetUrl: url
|
|
1022
|
+
} : { phase: "idle" };
|
|
1023
|
+
if (routerPhase.phase === next.phase && (routerPhase.phase === "idle" || routerPhase.phase === "navigating" && next.phase === "navigating" && routerPhase.targetUrl === next.targetUrl)) return;
|
|
1024
|
+
routerPhase = next;
|
|
924
1025
|
for (const listener of pendingListeners) listener(value);
|
|
925
1026
|
}
|
|
926
1027
|
/** Update the segment cache from server-provided segment metadata. */
|
|
@@ -930,8 +1031,8 @@ function createRouter(deps) {
|
|
|
930
1031
|
if (tree) segmentCache.set("/", tree);
|
|
931
1032
|
}
|
|
932
1033
|
/** Render a decoded RSC payload into the DOM if a renderer is available. */
|
|
933
|
-
function renderPayload(payload) {
|
|
934
|
-
if (deps.renderRoot) deps.renderRoot(payload);
|
|
1034
|
+
function renderPayload(payload, navState) {
|
|
1035
|
+
if (deps.renderRoot) deps.renderRoot(payload, navState);
|
|
935
1036
|
}
|
|
936
1037
|
/**
|
|
937
1038
|
* Merge a partial RSC payload with cached segment elements if segments
|
|
@@ -947,24 +1048,26 @@ function createRouter(deps) {
|
|
|
947
1048
|
/**
|
|
948
1049
|
* Update navigation state (params + pathname) for the next render.
|
|
949
1050
|
*
|
|
950
|
-
* Sets
|
|
951
|
-
*
|
|
952
|
-
*
|
|
953
|
-
*
|
|
1051
|
+
* Sets the module-level fallback (for tests and SSR) and the
|
|
1052
|
+
* globalThis bridge, then returns the NavigationState so callers
|
|
1053
|
+
* can pass it explicitly to renderRoot/wrapPayload — eliminating
|
|
1054
|
+
* temporal coupling with getNavigationState().
|
|
954
1055
|
*/
|
|
955
1056
|
function updateNavigationState(params, url) {
|
|
956
1057
|
const resolvedParams = params ?? {};
|
|
957
1058
|
setCurrentParams(resolvedParams);
|
|
958
|
-
|
|
1059
|
+
const navState = {
|
|
959
1060
|
params: resolvedParams,
|
|
960
1061
|
pathname: url.startsWith("http") ? new URL(url).pathname : url.split("?")[0] || "/"
|
|
961
|
-
}
|
|
1062
|
+
};
|
|
1063
|
+
setNavigationState(navState);
|
|
1064
|
+
return navState;
|
|
962
1065
|
}
|
|
963
1066
|
/**
|
|
964
1067
|
* Render a payload via navigateTransition (production) or renderRoot (tests).
|
|
965
|
-
* The perform callback should fetch data, update state, and return the
|
|
966
|
-
*
|
|
967
|
-
*
|
|
1068
|
+
* The perform callback should fetch data, update state, and return the
|
|
1069
|
+
* FetchResult plus the NavigationState (so it can be passed explicitly
|
|
1070
|
+
* to wrapPayload/renderRoot without temporal coupling).
|
|
968
1071
|
*/
|
|
969
1072
|
async function renderViaTransition(url, perform) {
|
|
970
1073
|
if (deps.navigateTransition) {
|
|
@@ -978,7 +1081,7 @@ function createRouter(deps) {
|
|
|
978
1081
|
headElements: result.headElements,
|
|
979
1082
|
params: result.params
|
|
980
1083
|
});
|
|
981
|
-
return wrapPayload(merged);
|
|
1084
|
+
return wrapPayload(merged, result.navState);
|
|
982
1085
|
});
|
|
983
1086
|
return headElements;
|
|
984
1087
|
}
|
|
@@ -989,7 +1092,7 @@ function createRouter(deps) {
|
|
|
989
1092
|
headElements: result.headElements,
|
|
990
1093
|
params: result.params
|
|
991
1094
|
});
|
|
992
|
-
renderPayload(merged);
|
|
1095
|
+
renderPayload(merged, result.navState);
|
|
993
1096
|
return result.headElements;
|
|
994
1097
|
}
|
|
995
1098
|
/** Apply head elements (title, meta tags) to the DOM if available. */
|
|
@@ -1002,6 +1105,16 @@ function createRouter(deps) {
|
|
|
1002
1105
|
else callback();
|
|
1003
1106
|
}
|
|
1004
1107
|
/**
|
|
1108
|
+
* Schedule scroll restoration after the next paint and fire the
|
|
1109
|
+
* scroll-restored event. Used by navigate, popstate, and refresh.
|
|
1110
|
+
*/
|
|
1111
|
+
function restoreScrollAfterPaint(scrollY) {
|
|
1112
|
+
afterPaint(() => {
|
|
1113
|
+
deps.scrollTo(0, scrollY);
|
|
1114
|
+
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1005
1118
|
* Core navigation logic shared between the transition and fallback paths.
|
|
1006
1119
|
* Fetches the RSC payload, updates all state, and returns the result.
|
|
1007
1120
|
*/
|
|
@@ -1028,8 +1141,11 @@ function createRouter(deps) {
|
|
|
1028
1141
|
scrollY: 0
|
|
1029
1142
|
}, "", url);
|
|
1030
1143
|
updateSegmentCache(result.segmentInfo);
|
|
1031
|
-
updateNavigationState(result.params, url);
|
|
1032
|
-
return
|
|
1144
|
+
const navState = updateNavigationState(result.params, url);
|
|
1145
|
+
return {
|
|
1146
|
+
...result,
|
|
1147
|
+
navState
|
|
1148
|
+
};
|
|
1033
1149
|
}
|
|
1034
1150
|
async function navigate(url, options = {}) {
|
|
1035
1151
|
const scroll = options.scroll !== false;
|
|
@@ -1043,17 +1159,22 @@ function createRouter(deps) {
|
|
|
1043
1159
|
try {
|
|
1044
1160
|
applyHead(await renderViaTransition(url, () => performNavigationFetch(url, { replace })));
|
|
1045
1161
|
window.dispatchEvent(new Event("timber:navigation-end"));
|
|
1046
|
-
|
|
1047
|
-
if (scroll) deps.scrollTo(0, 0);
|
|
1048
|
-
else deps.scrollTo(0, currentScrollY);
|
|
1049
|
-
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1050
|
-
});
|
|
1162
|
+
restoreScrollAfterPaint(scroll ? 0 : currentScrollY);
|
|
1051
1163
|
} catch (error) {
|
|
1164
|
+
if (error instanceof VersionSkewError) {
|
|
1165
|
+
const { triggerStaleReload } = await import("../_chunks/stale-reload-BSSym1MJ.js");
|
|
1166
|
+
triggerStaleReload();
|
|
1167
|
+
return new Promise(() => {});
|
|
1168
|
+
}
|
|
1052
1169
|
if (error instanceof RedirectError) {
|
|
1053
1170
|
setPending(false);
|
|
1054
1171
|
await navigate(error.redirectUrl, { replace: true });
|
|
1055
1172
|
return;
|
|
1056
1173
|
}
|
|
1174
|
+
if (error instanceof ServerErrorResponse) {
|
|
1175
|
+
window.location.href = error.url;
|
|
1176
|
+
return new Promise(() => {});
|
|
1177
|
+
}
|
|
1057
1178
|
if (isAbortError(error)) return;
|
|
1058
1179
|
throw error;
|
|
1059
1180
|
} finally {
|
|
@@ -1067,8 +1188,11 @@ function createRouter(deps) {
|
|
|
1067
1188
|
applyHead(await renderViaTransition(currentUrl, async () => {
|
|
1068
1189
|
const result = await fetchRscPayload(currentUrl, deps);
|
|
1069
1190
|
updateSegmentCache(result.segmentInfo);
|
|
1070
|
-
updateNavigationState(result.params, currentUrl);
|
|
1071
|
-
return
|
|
1191
|
+
const navState = updateNavigationState(result.params, currentUrl);
|
|
1192
|
+
return {
|
|
1193
|
+
...result,
|
|
1194
|
+
navState
|
|
1195
|
+
};
|
|
1072
1196
|
}));
|
|
1073
1197
|
} finally {
|
|
1074
1198
|
setPending(false);
|
|
@@ -1077,26 +1201,23 @@ function createRouter(deps) {
|
|
|
1077
1201
|
async function handlePopState(url, scrollY = 0) {
|
|
1078
1202
|
const entry = historyStack.get(url);
|
|
1079
1203
|
if (entry && entry.payload !== null) {
|
|
1080
|
-
updateNavigationState(entry.params, url);
|
|
1081
|
-
renderPayload(entry.payload);
|
|
1204
|
+
const navState = updateNavigationState(entry.params, url);
|
|
1205
|
+
renderPayload(entry.payload, navState);
|
|
1082
1206
|
applyHead(entry.headElements);
|
|
1083
|
-
|
|
1084
|
-
deps.scrollTo(0, scrollY);
|
|
1085
|
-
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1086
|
-
});
|
|
1207
|
+
restoreScrollAfterPaint(scrollY);
|
|
1087
1208
|
} else {
|
|
1088
1209
|
setPending(true, url);
|
|
1089
1210
|
try {
|
|
1090
1211
|
applyHead(await renderViaTransition(url, async () => {
|
|
1091
1212
|
const result = await fetchRscPayload(url, deps, segmentCache.serializeStateTree(segmentElementCache.getMergeablePaths()));
|
|
1092
1213
|
updateSegmentCache(result.segmentInfo);
|
|
1093
|
-
updateNavigationState(result.params, url);
|
|
1094
|
-
return
|
|
1214
|
+
const navState = updateNavigationState(result.params, url);
|
|
1215
|
+
return {
|
|
1216
|
+
...result,
|
|
1217
|
+
navState
|
|
1218
|
+
};
|
|
1095
1219
|
}));
|
|
1096
|
-
|
|
1097
|
-
deps.scrollTo(0, scrollY);
|
|
1098
|
-
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1099
|
-
});
|
|
1220
|
+
restoreScrollAfterPaint(scrollY);
|
|
1100
1221
|
} finally {
|
|
1101
1222
|
setPending(false);
|
|
1102
1223
|
}
|
|
@@ -1117,8 +1238,8 @@ function createRouter(deps) {
|
|
|
1117
1238
|
navigate,
|
|
1118
1239
|
refresh,
|
|
1119
1240
|
handlePopState,
|
|
1120
|
-
isPending: () =>
|
|
1121
|
-
getPendingUrl: () =>
|
|
1241
|
+
isPending: () => routerPhase.phase === "navigating",
|
|
1242
|
+
getPendingUrl: () => routerPhase.phase === "navigating" ? routerPhase.targetUrl : null,
|
|
1122
1243
|
onPendingChange(listener) {
|
|
1123
1244
|
pendingListeners.add(listener);
|
|
1124
1245
|
return () => pendingListeners.delete(listener);
|
|
@@ -1131,7 +1252,7 @@ function createRouter(deps) {
|
|
|
1131
1252
|
payload: merged,
|
|
1132
1253
|
headElements
|
|
1133
1254
|
});
|
|
1134
|
-
renderPayload(merged);
|
|
1255
|
+
renderPayload(merged, getNavigationState());
|
|
1135
1256
|
applyHead(headElements);
|
|
1136
1257
|
},
|
|
1137
1258
|
initSegmentCache: (segments) => updateSegmentCache(segments),
|
|
@@ -1354,36 +1475,6 @@ function useSearchParams() {
|
|
|
1354
1475
|
return typeof window !== "undefined" ? getSearchParams() : getServerSearchParams();
|
|
1355
1476
|
}
|
|
1356
1477
|
//#endregion
|
|
1357
|
-
//#region src/client/segment-context.ts
|
|
1358
|
-
/**
|
|
1359
|
-
* Segment Context — provides layout segment position for useSelectedLayoutSegment hooks.
|
|
1360
|
-
*
|
|
1361
|
-
* Each layout in the segment tree is wrapped with a SegmentProvider that stores
|
|
1362
|
-
* the URL segments from root to the current layout level. The hooks read this
|
|
1363
|
-
* context to determine which child segments are active below the calling layout.
|
|
1364
|
-
*
|
|
1365
|
-
* The context value is intentionally minimal: just the segment path array and
|
|
1366
|
-
* parallel route keys. No internal cache details are exposed.
|
|
1367
|
-
*
|
|
1368
|
-
* Design docs: design/19-client-navigation.md, design/14-ecosystem.md
|
|
1369
|
-
*/
|
|
1370
|
-
var SegmentContext = createContext(null);
|
|
1371
|
-
/** Read the segment context. Returns null if no provider is above this component. */
|
|
1372
|
-
function useSegmentContext() {
|
|
1373
|
-
return useContext(SegmentContext);
|
|
1374
|
-
}
|
|
1375
|
-
/**
|
|
1376
|
-
* Wraps each layout to provide segment position context.
|
|
1377
|
-
* Injected by rsc-entry.ts during element tree construction.
|
|
1378
|
-
*/
|
|
1379
|
-
function SegmentProvider({ segments, segmentId: _segmentId, parallelRouteKeys, children }) {
|
|
1380
|
-
const value = useMemo(() => ({
|
|
1381
|
-
segments,
|
|
1382
|
-
parallelRouteKeys
|
|
1383
|
-
}), [segments.join("/"), parallelRouteKeys.join(",")]);
|
|
1384
|
-
return createElement(SegmentContext.Provider, { value }, children);
|
|
1385
|
-
}
|
|
1386
|
-
//#endregion
|
|
1387
1478
|
//#region src/client/use-selected-layout-segment.ts
|
|
1388
1479
|
/**
|
|
1389
1480
|
* useSelectedLayoutSegment / useSelectedLayoutSegments — client-side hooks
|
|
@@ -1589,6 +1680,96 @@ function useFormErrors(result) {
|
|
|
1589
1680
|
};
|
|
1590
1681
|
}
|
|
1591
1682
|
//#endregion
|
|
1592
|
-
|
|
1683
|
+
//#region src/client/use-cookie.ts
|
|
1684
|
+
/**
|
|
1685
|
+
* useCookie — reactive client-side cookie hook.
|
|
1686
|
+
*
|
|
1687
|
+
* Uses useSyncExternalStore for SSR-safe, reactive cookie access.
|
|
1688
|
+
* All components reading the same cookie name re-render on change.
|
|
1689
|
+
* No cross-tab sync (intentional — see design/29-cookies.md).
|
|
1690
|
+
*
|
|
1691
|
+
* See design/29-cookies.md §"useCookie(name) Hook"
|
|
1692
|
+
*/
|
|
1693
|
+
var use_cookie_exports = /* @__PURE__ */ __exportAll({ useCookie: () => useCookie });
|
|
1694
|
+
/** Per-name subscriber sets. */
|
|
1695
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
1696
|
+
/** Parse a cookie name from document.cookie. */
|
|
1697
|
+
function getCookieValue(name) {
|
|
1698
|
+
if (typeof document === "undefined") return void 0;
|
|
1699
|
+
const match = document.cookie.match(new RegExp("(?:^|;\\s*)" + name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\s*=\\s*([^;]*)"));
|
|
1700
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
1701
|
+
}
|
|
1702
|
+
/** Serialize options into a cookie string suffix. */
|
|
1703
|
+
function serializeOptions(options) {
|
|
1704
|
+
if (!options) return "; Path=/; SameSite=Lax";
|
|
1705
|
+
const parts = [];
|
|
1706
|
+
parts.push(`Path=${options.path ?? "/"}`);
|
|
1707
|
+
if (options.domain) parts.push(`Domain=${options.domain}`);
|
|
1708
|
+
if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
1709
|
+
if (options.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
1710
|
+
const sameSite = options.sameSite ?? "lax";
|
|
1711
|
+
parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
|
|
1712
|
+
if (options.secure) parts.push("Secure");
|
|
1713
|
+
return "; " + parts.join("; ");
|
|
1714
|
+
}
|
|
1715
|
+
/** Notify all subscribers for a given cookie name. */
|
|
1716
|
+
function notify(name) {
|
|
1717
|
+
const subs = listeners.get(name);
|
|
1718
|
+
if (subs) for (const fn of subs) fn();
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Reactive hook for reading/writing a client-side cookie.
|
|
1722
|
+
*
|
|
1723
|
+
* Returns `[value, setCookie, deleteCookie]`:
|
|
1724
|
+
* - `value`: current cookie value (string | undefined)
|
|
1725
|
+
* - `setCookie`: sets the cookie and triggers re-renders
|
|
1726
|
+
* - `deleteCookie`: deletes the cookie and triggers re-renders
|
|
1727
|
+
*
|
|
1728
|
+
* @param name - Cookie name.
|
|
1729
|
+
* @param defaultOptions - Default options for setCookie calls.
|
|
1730
|
+
*/
|
|
1731
|
+
function useCookie(name, defaultOptions) {
|
|
1732
|
+
const subscribe = (callback) => {
|
|
1733
|
+
let subs = listeners.get(name);
|
|
1734
|
+
if (!subs) {
|
|
1735
|
+
subs = /* @__PURE__ */ new Set();
|
|
1736
|
+
listeners.set(name, subs);
|
|
1737
|
+
}
|
|
1738
|
+
subs.add(callback);
|
|
1739
|
+
return () => {
|
|
1740
|
+
subs.delete(callback);
|
|
1741
|
+
if (subs.size === 0) listeners.delete(name);
|
|
1742
|
+
};
|
|
1743
|
+
};
|
|
1744
|
+
const getSnapshot = () => getCookieValue(name);
|
|
1745
|
+
const getServerSnapshot = () => getSsrData()?.cookies.get(name);
|
|
1746
|
+
const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
1747
|
+
const setCookie = (newValue, options) => {
|
|
1748
|
+
const merged = {
|
|
1749
|
+
...defaultOptions,
|
|
1750
|
+
...options
|
|
1751
|
+
};
|
|
1752
|
+
document.cookie = `${name}=${encodeURIComponent(newValue)}${serializeOptions(merged)}`;
|
|
1753
|
+
notify(name);
|
|
1754
|
+
};
|
|
1755
|
+
const deleteCookie = () => {
|
|
1756
|
+
const path = defaultOptions?.path ?? "/";
|
|
1757
|
+
const domain = defaultOptions?.domain;
|
|
1758
|
+
let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;
|
|
1759
|
+
if (domain) cookieStr += `; Domain=${domain}`;
|
|
1760
|
+
document.cookie = cookieStr;
|
|
1761
|
+
notify(name);
|
|
1762
|
+
};
|
|
1763
|
+
return [
|
|
1764
|
+
value,
|
|
1765
|
+
setCookie,
|
|
1766
|
+
deleteCookie
|
|
1767
|
+
];
|
|
1768
|
+
}
|
|
1769
|
+
//#endregion
|
|
1770
|
+
//#region src/client/index.ts
|
|
1771
|
+
_registerUseCookieModule(use_cookie_exports);
|
|
1772
|
+
//#endregion
|
|
1773
|
+
export { HistoryStack, Link, LinkStatusContext, NavigationProvider, PrefetchCache, SegmentCache, SegmentProvider, TimberErrorBoundary, bindUseQueryStates, buildLinkProps, clearSsrData, createRouter, getNavigationState, getRouter, getSsrData, interpolateParams, mergePreservedSearchParams, resolveHref, setCurrentParams, setGlobalRouter, setNavigationState, setSsrData, useActionState, useCookie, useFormAction, useFormErrors, useLinkStatus, useNavigationPending, usePathname, useQueryStates, useRouter, useSearchParams, useSegmentContext, useSegmentParams, useSelectedLayoutSegment, useSelectedLayoutSegments, validateLinkHref };
|
|
1593
1774
|
|
|
1594
1775
|
//# sourceMappingURL=index.js.map
|