@timber-js/app 0.2.0-alpha.4 → 0.2.0-alpha.40
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-ECi_61pb.js +108 -0
- package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
- package/dist/_chunks/define-cookie-BmKbSyp0.js +93 -0
- package/dist/_chunks/define-cookie-BmKbSyp0.js.map +1 -0
- package/dist/_chunks/error-boundary-BAN3751q.js +211 -0
- package/dist/_chunks/error-boundary-BAN3751q.js.map +1 -0
- package/dist/_chunks/{format-CwdaB0_2.js → format-cX7wzEp2.js} +2 -2
- package/dist/_chunks/{format-CwdaB0_2.js.map → format-cX7wzEp2.js.map} +1 -1
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-D2djYaIm.js} +112 -77
- package/dist/_chunks/interception-D2djYaIm.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-CZJi4CuK.js → request-context-BxYIJM24.js} +93 -69
- package/dist/_chunks/request-context-BxYIJM24.js.map +1 -0
- package/dist/_chunks/segment-context-C6byCyZU.js +69 -0
- package/dist/_chunks/segment-context-C6byCyZU.js.map +1 -0
- package/dist/_chunks/stale-reload-C0ValzG7.js +47 -0
- package/dist/_chunks/stale-reload-C0ValzG7.js.map +1 -0
- package/dist/_chunks/{tracing-Cwn7697K.js → tracing-CuXiCP5p.js} +17 -3
- package/dist/_chunks/{tracing-Cwn7697K.js.map → tracing-CuXiCP5p.js.map} +1 -1
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-BvW0TKDn.js} +1 -1
- package/dist/_chunks/{use-query-states-D5KaffOK.js.map → use-query-states-BvW0TKDn.js.map} +1 -1
- package/dist/_chunks/wrappers-C6J0nNji.js +331 -0
- package/dist/_chunks/wrappers-C6J0nNji.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 +88 -18
- 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.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/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +213 -93
- package/dist/client/index.js.map +1 -1
- package/dist/client/link.d.ts +22 -8
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +2 -2
- package/dist/client/router.d.ts +25 -3
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +23 -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/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 +2 -2
- package/dist/client/use-params.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/codec.d.ts +21 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/cookies/define-cookie.d.ts +33 -12
- 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/fonts/local.d.ts +4 -2
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/index.d.ts +112 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +635 -233
- package/dist/index.js.map +1 -1
- package/dist/params/define.d.ts +76 -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 +104 -0
- package/dist/params/index.js.map +1 -0
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.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/dev-error-overlay.d.ts +26 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +7 -0
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +9 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +6 -0
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +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 +6 -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 +153 -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 +3 -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/als-registry.d.ts +18 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/debug.d.ts +46 -15
- package/dist/server/debug.d.ts.map +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/flight-injection-state.d.ts +78 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +39 -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 +5 -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 +1975 -1649
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.d.ts +24 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +77 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +7 -4
- 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 +2 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +46 -3
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +6 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +9 -0
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/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/tracing.d.ts +10 -0
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +19 -12
- 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/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 -14
- 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 +34 -26
- package/src/cli.ts +0 -0
- package/src/client/browser-entry.ts +94 -90
- package/src/client/error-boundary.tsx +18 -1
- package/src/client/index.ts +10 -1
- package/src/client/link.tsx +78 -19
- package/src/client/navigation-context.ts +2 -2
- package/src/client/router.ts +105 -60
- package/src/client/rsc-fetch.ts +63 -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/stale-reload.ts +32 -6
- package/src/client/top-loader.tsx +10 -9
- package/src/client/transition-root.tsx +7 -1
- package/src/client/use-params.ts +3 -3
- package/src/client/use-query-states.ts +1 -1
- package/src/codec.ts +21 -0
- package/src/cookies/define-cookie.ts +69 -18
- package/src/fonts/css.ts +2 -1
- package/src/fonts/local.ts +7 -3
- package/src/index.ts +280 -85
- package/src/params/define.ts +260 -0
- package/src/params/index.ts +28 -0
- package/src/plugins/adapter-build.ts +6 -0
- package/src/plugins/build-manifest.ts +11 -0
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/dev-error-overlay.ts +70 -1
- package/src/plugins/dev-server.ts +38 -4
- package/src/plugins/entries.ts +12 -11
- package/src/plugins/fonts.ts +171 -19
- package/src/plugins/mdx.ts +9 -5
- package/src/plugins/routing.ts +40 -14
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +1 -1
- package/src/plugins/static-build.ts +8 -4
- package/src/routing/codegen.ts +109 -88
- package/src/routing/scanner.ts +55 -6
- package/src/routing/status-file-lint.ts +2 -1
- package/src/routing/types.ts +7 -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 +504 -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 +14 -5
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +19 -2
- package/src/server/als-registry.ts +18 -4
- package/src/server/build-manifest.ts +4 -4
- package/src/server/compress.ts +25 -7
- package/src/server/debug.ts +55 -17
- package/src/server/default-logger.ts +98 -0
- package/src/server/deny-renderer.ts +2 -1
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +57 -14
- package/src/server/flight-injection-state.ts +152 -0
- package/src/server/flight-scripts.ts +59 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injectors.ts +103 -66
- package/src/server/index.ts +9 -4
- package/src/server/logger.ts +38 -35
- package/src/server/node-stream-transforms.ts +381 -0
- package/src/server/pipeline.ts +131 -39
- package/src/server/primitives.ts +47 -5
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +112 -119
- package/src/server/route-element-builder.ts +106 -114
- package/src/server/route-handler.ts +2 -1
- package/src/server/route-matcher.ts +2 -2
- package/src/server/rsc-entry/error-renderer.ts +5 -3
- package/src/server/rsc-entry/helpers.ts +122 -3
- package/src/server/rsc-entry/index.ts +125 -49
- package/src/server/rsc-entry/rsc-payload.ts +52 -12
- package/src/server/rsc-entry/rsc-stream.ts +33 -8
- package/src/server/rsc-entry/ssr-renderer.ts +40 -13
- package/src/server/slot-resolver.ts +199 -210
- package/src/server/ssr-entry.ts +169 -17
- package/src/server/ssr-render.ts +266 -67
- package/src/server/tracing.ts +23 -0
- package/src/server/tree-builder.ts +91 -57
- 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 +48 -0
- package/src/shims/navigation-client.ts +1 -1
- package/src/shims/navigation.ts +1 -1
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-B4WUeqJ-.js +0 -75
- package/dist/_chunks/debug-B4WUeqJ-.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-CZJi4CuK.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/client/error-boundary.js.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/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
|
@@ -1,128 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
|
-
import {
|
|
4
|
-
import { Component, createElement } from "react";
|
|
5
|
-
//#region src/client/error-boundary.tsx
|
|
6
|
-
/**
|
|
7
|
-
* Framework-injected React error boundary.
|
|
8
|
-
*
|
|
9
|
-
* Catches errors thrown by children and renders a fallback component
|
|
10
|
-
* with the appropriate props based on error type:
|
|
11
|
-
* - DenySignal (4xx) → { status, dangerouslyPassData }
|
|
12
|
-
* - RenderError (5xx) → { error, digest, reset }
|
|
13
|
-
* - Unhandled error → { error, digest: null, reset }
|
|
14
|
-
*
|
|
15
|
-
* The `status` prop controls which errors this boundary catches:
|
|
16
|
-
* - Specific code (e.g. 403) → only that status
|
|
17
|
-
* - Category (400) → any 4xx
|
|
18
|
-
* - Category (500) → any 5xx
|
|
19
|
-
* - Omitted → catches everything (error.tsx behavior)
|
|
20
|
-
*
|
|
21
|
-
* See design/10-error-handling.md §"Status-Code Files"
|
|
22
|
-
*/
|
|
23
|
-
var _isUnloading = false;
|
|
24
|
-
if (typeof window !== "undefined") {
|
|
25
|
-
window.addEventListener("beforeunload", () => {
|
|
26
|
-
_isUnloading = true;
|
|
27
|
-
});
|
|
28
|
-
window.addEventListener("pagehide", () => {
|
|
29
|
-
_isUnloading = true;
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
var TimberErrorBoundary = class extends Component {
|
|
33
|
-
constructor(props) {
|
|
34
|
-
super(props);
|
|
35
|
-
this.state = {
|
|
36
|
-
hasError: false,
|
|
37
|
-
error: null
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
static getDerivedStateFromError(error) {
|
|
41
|
-
if (_isUnloading) return {
|
|
42
|
-
hasError: false,
|
|
43
|
-
error: null
|
|
44
|
-
};
|
|
45
|
-
return {
|
|
46
|
-
hasError: true,
|
|
47
|
-
error
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
componentDidUpdate(prevProps) {
|
|
51
|
-
if (this.state.hasError && prevProps.children !== this.props.children) this.setState({
|
|
52
|
-
hasError: false,
|
|
53
|
-
error: null
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
/** Reset the error state so children re-render. */
|
|
57
|
-
reset = () => {
|
|
58
|
-
this.setState({
|
|
59
|
-
hasError: false,
|
|
60
|
-
error: null
|
|
61
|
-
});
|
|
62
|
-
};
|
|
63
|
-
render() {
|
|
64
|
-
if (!this.state.hasError || !this.state.error) return this.props.children;
|
|
65
|
-
const error = this.state.error;
|
|
66
|
-
const parsed = parseDigest(error);
|
|
67
|
-
if (parsed?.type === "redirect") throw error;
|
|
68
|
-
if (this.props.status != null) {
|
|
69
|
-
const errorStatus = getErrorStatus(parsed, error);
|
|
70
|
-
if (errorStatus == null || !statusMatches(this.props.status, errorStatus)) throw error;
|
|
71
|
-
}
|
|
72
|
-
if (parsed?.type === "deny" && this.props.isSlotBoundary) {
|
|
73
|
-
const ssrData = getSsrData();
|
|
74
|
-
if (ssrData?._navContext) ssrData._navContext._denyHandledByBoundary = true;
|
|
75
|
-
}
|
|
76
|
-
if (parsed?.type === "deny") return createElement(this.props.fallbackComponent, {
|
|
77
|
-
status: parsed.status,
|
|
78
|
-
dangerouslyPassData: parsed.data
|
|
79
|
-
});
|
|
80
|
-
const digest = parsed?.type === "render-error" ? {
|
|
81
|
-
code: parsed.code,
|
|
82
|
-
data: parsed.data
|
|
83
|
-
} : null;
|
|
84
|
-
return createElement(this.props.fallbackComponent, {
|
|
85
|
-
error,
|
|
86
|
-
digest,
|
|
87
|
-
reset: this.reset
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
/**
|
|
92
|
-
* Parse the structured digest from the error.
|
|
93
|
-
* React sets `error.digest` from the string returned by RSC's onError.
|
|
94
|
-
*/
|
|
95
|
-
function parseDigest(error) {
|
|
96
|
-
const raw = error.digest;
|
|
97
|
-
if (typeof raw !== "string") return null;
|
|
98
|
-
try {
|
|
99
|
-
const parsed = JSON.parse(raw);
|
|
100
|
-
if (parsed && typeof parsed === "object" && typeof parsed.type === "string") return parsed;
|
|
101
|
-
} catch {}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Extract the HTTP status code from a parsed digest or error message.
|
|
106
|
-
* Falls back to message pattern matching for errors without a digest.
|
|
107
|
-
*/
|
|
108
|
-
function getErrorStatus(parsed, error) {
|
|
109
|
-
if (parsed?.type === "deny") return parsed.status;
|
|
110
|
-
if (parsed?.type === "render-error") return parsed.status;
|
|
111
|
-
if (parsed?.type === "redirect") return parsed.status;
|
|
112
|
-
const match = error.message.match(/^Access denied with status (\d+)$/);
|
|
113
|
-
if (match) return parseInt(match[1], 10);
|
|
114
|
-
return 500;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Check whether an error's status matches the boundary's status filter.
|
|
118
|
-
* Category markers (400, 500) match any status in that range.
|
|
119
|
-
*/
|
|
120
|
-
function statusMatches(boundaryStatus, errorStatus) {
|
|
121
|
-
if (boundaryStatus === 400) return errorStatus >= 400 && errorStatus <= 499;
|
|
122
|
-
if (boundaryStatus === 500) return errorStatus >= 500 && errorStatus <= 599;
|
|
123
|
-
return boundaryStatus === errorStatus;
|
|
124
|
-
}
|
|
125
|
-
//#endregion
|
|
3
|
+
import { t as TimberErrorBoundary } from "../_chunks/error-boundary-BAN3751q.js";
|
|
126
4
|
export { TimberErrorBoundary };
|
|
127
|
-
|
|
128
|
-
//# sourceMappingURL=error-boundary.js.map
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export type { JsonSerializable, RenderErrorDigest } from './types';
|
|
2
2
|
export { Link, interpolateParams, resolveHref, validateLinkHref, buildLinkProps } from './link';
|
|
3
|
+
export { mergePreservedSearchParams } from '#/shared/merge-search-params.js';
|
|
3
4
|
export type { LinkProps, LinkPropsWithHref, LinkPropsWithParams } from './link';
|
|
4
5
|
export type { OnNavigateHandler, OnNavigateEvent } from './link';
|
|
5
6
|
export { createRouter } from './router';
|
|
6
|
-
export type { RouterInstance, NavigationOptions, RouterDeps, RscDecoder, RootRenderer, } from './router';
|
|
7
|
+
export type { RouterInstance, NavigationOptions, RouterDeps, RouterPhase, RscDecoder, RootRenderer, } from './router';
|
|
7
8
|
export { useNavigationPending } from './use-navigation-pending';
|
|
8
9
|
export { useLinkStatus, LinkStatusContext } from './use-link-status';
|
|
9
10
|
export type { LinkStatus } from './use-link-status';
|
|
@@ -21,7 +22,7 @@ export { HistoryStack } from './history';
|
|
|
21
22
|
export type { HistoryEntry } from './history';
|
|
22
23
|
export { useActionState, useFormAction, useFormErrors } from './form';
|
|
23
24
|
export type { UseActionStateFn, UseActionStateReturn, FormErrorsResult } from './form';
|
|
24
|
-
export {
|
|
25
|
+
export { useSegmentParams, setCurrentParams } from './use-params';
|
|
25
26
|
export { NavigationProvider, getNavigationState, setNavigationState } from './navigation-context';
|
|
26
27
|
export type { NavigationState } from './navigation-context';
|
|
27
28
|
export { useQueryStates, bindUseQueryStates } from './use-query-states';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGnE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAChG,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAChF,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,UAAU,EACV,YAAY,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAGpG,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAGvF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGnE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAChG,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAChF,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,UAAU,EACV,YAAY,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAGpG,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAGvF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGlE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClG,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAUtE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAClE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,YAAY,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/client/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import { t as
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
2
|
+
import { n as __exportAll } from "../_chunks/chunk-DYhsFzuS.js";
|
|
3
|
+
import { n as useSegmentContext, r as mergePreservedSearchParams, t as SegmentProvider } from "../_chunks/segment-context-C6byCyZU.js";
|
|
4
|
+
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-BAN3751q.js";
|
|
5
|
+
import { n as useQueryStates, t as bindUseQueryStates } from "../_chunks/use-query-states-BvW0TKDn.js";
|
|
6
|
+
import { t as _registerUseCookieModule } from "../_chunks/define-cookie-BmKbSyp0.js";
|
|
7
|
+
import React, { cloneElement, createContext, createElement, isValidElement, useActionState as useActionState$1, useContext, useSyncExternalStore, useTransition } from "react";
|
|
7
8
|
import { jsx } from "react/jsx-runtime";
|
|
8
9
|
//#region src/client/use-link-status.ts
|
|
9
10
|
/**
|
|
@@ -46,7 +47,7 @@ function useLinkStatus() {
|
|
|
46
47
|
*
|
|
47
48
|
* Holds the current route params and pathname, updated atomically
|
|
48
49
|
* with the RSC tree on each navigation. This replaces the previous
|
|
49
|
-
* useSyncExternalStore approach for
|
|
50
|
+
* useSyncExternalStore approach for useSegmentParams() and usePathname(),
|
|
50
51
|
* which suffered from a timing gap: the new tree could commit before
|
|
51
52
|
* the external store re-renders fired, causing a frame where both
|
|
52
53
|
* old and new active states were visible simultaneously.
|
|
@@ -107,7 +108,7 @@ function getOrCreateContext() {
|
|
|
107
108
|
/**
|
|
108
109
|
* Read the navigation context. Returns null during SSR (no provider)
|
|
109
110
|
* or in the RSC environment (no context available).
|
|
110
|
-
* Internal — used by
|
|
111
|
+
* Internal — used by useSegmentParams() and usePathname().
|
|
111
112
|
*/
|
|
112
113
|
function useNavigationContext() {
|
|
113
114
|
const ctx = getOrCreateContext();
|
|
@@ -225,6 +226,18 @@ function getRouterOrNull() {
|
|
|
225
226
|
//#endregion
|
|
226
227
|
//#region src/client/link.tsx
|
|
227
228
|
/**
|
|
229
|
+
* Read the current URL's search string without requiring a React hook.
|
|
230
|
+
* On the client, reads window.location.search. During SSR, reads from
|
|
231
|
+
* the request context (getSsrData). Returns empty string if unavailable.
|
|
232
|
+
*/
|
|
233
|
+
function getCurrentSearch() {
|
|
234
|
+
if (typeof window !== "undefined") return window.location.search;
|
|
235
|
+
const data = getSsrData();
|
|
236
|
+
if (!data) return "";
|
|
237
|
+
const str = new URLSearchParams(data.searchParams).toString();
|
|
238
|
+
return str ? `?${str}` : "";
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
228
241
|
* Reject dangerous URL schemes that could execute script.
|
|
229
242
|
* Security: design/13-security.md § Link scheme injection (test #9)
|
|
230
243
|
*/
|
|
@@ -324,15 +337,16 @@ function shouldInterceptClick(event, resolvedHref) {
|
|
|
324
337
|
* its own click handling.
|
|
325
338
|
*
|
|
326
339
|
* Supports typed routes via codegen overloads. At runtime:
|
|
327
|
-
* - `
|
|
340
|
+
* - `segmentParams` prop interpolates dynamic segments in the href pattern
|
|
328
341
|
* - `searchParams` prop serializes query parameters via a SearchParamsDefinition
|
|
329
342
|
*/
|
|
330
|
-
function Link({ href, prefetch, scroll,
|
|
331
|
-
const { href:
|
|
343
|
+
function Link({ href, prefetch, scroll, segmentParams, searchParams, preserveSearchParams, onNavigate, onClick: userOnClick, onMouseEnter: userOnMouseEnter, children, ...rest }) {
|
|
344
|
+
const { href: baseHref } = buildLinkProps({
|
|
332
345
|
href,
|
|
333
|
-
params,
|
|
346
|
+
params: segmentParams,
|
|
334
347
|
searchParams
|
|
335
348
|
});
|
|
349
|
+
const resolvedHref = preserveSearchParams ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams) : baseHref;
|
|
336
350
|
const internal = isInternalHref(resolvedHref);
|
|
337
351
|
const handleClick = internal ? (event) => {
|
|
338
352
|
userOnClick?.(event);
|
|
@@ -351,12 +365,16 @@ function Link({ href, prefetch, scroll, params, searchParams, onNavigate, onClic
|
|
|
351
365
|
if (!router) return;
|
|
352
366
|
event.preventDefault();
|
|
353
367
|
const shouldScroll = scroll !== false;
|
|
354
|
-
|
|
368
|
+
const navHref = preserveSearchParams ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams) : resolvedHref;
|
|
369
|
+
router.navigate(navHref, { scroll: shouldScroll });
|
|
355
370
|
} : userOnClick;
|
|
356
371
|
const handleMouseEnter = internal && prefetch ? (event) => {
|
|
357
372
|
userOnMouseEnter?.(event);
|
|
358
373
|
const router = getRouterOrNull();
|
|
359
|
-
if (router)
|
|
374
|
+
if (router) {
|
|
375
|
+
const prefetchHref = preserveSearchParams ? mergePreservedSearchParams(baseHref, getCurrentSearch(), preserveSearchParams) : resolvedHref;
|
|
376
|
+
router.prefetch(prefetchHref);
|
|
377
|
+
}
|
|
360
378
|
} : userOnMouseEnter;
|
|
361
379
|
return /* @__PURE__ */ jsx("a", {
|
|
362
380
|
...rest,
|
|
@@ -520,7 +538,7 @@ var HistoryStack = class {
|
|
|
520
538
|
function setCurrentParams(params) {
|
|
521
539
|
_setCurrentParams(params);
|
|
522
540
|
}
|
|
523
|
-
function
|
|
541
|
+
function useSegmentParams(_route) {
|
|
524
542
|
try {
|
|
525
543
|
const navContext = useNavigationContext();
|
|
526
544
|
if (navContext !== null) return navContext.params;
|
|
@@ -759,10 +777,28 @@ function generateCacheBustId() {
|
|
|
759
777
|
function appendRscParam(url) {
|
|
760
778
|
return `${url}${url.includes("?") ? "&" : "?"}_rsc=${generateCacheBustId()}`;
|
|
761
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* The client's deployment ID, set at bootstrap from the runtime config.
|
|
782
|
+
* Sent with every RSC/action request for version skew detection.
|
|
783
|
+
* Null in dev mode. See TIM-446.
|
|
784
|
+
*/
|
|
785
|
+
var clientDeploymentId = null;
|
|
786
|
+
/** Header name used by the server to signal a version skew reload. */
|
|
787
|
+
var RELOAD_HEADER = "X-Timber-Reload";
|
|
788
|
+
/** Header name for the client's deployment ID. */
|
|
789
|
+
var DEPLOYMENT_ID_HEADER = "X-Timber-Deployment-Id";
|
|
790
|
+
/**
|
|
791
|
+
* Check if a response signals a version skew reload.
|
|
792
|
+
* Triggers a full page reload if the server indicates the client is stale.
|
|
793
|
+
*/
|
|
794
|
+
function checkReloadSignal(response) {
|
|
795
|
+
return response.headers.get(RELOAD_HEADER) === "1";
|
|
796
|
+
}
|
|
762
797
|
function buildRscHeaders(stateTree, currentUrl) {
|
|
763
798
|
const headers = { Accept: RSC_CONTENT_TYPE };
|
|
764
799
|
if (stateTree) headers["X-Timber-State-Tree"] = JSON.stringify(stateTree);
|
|
765
800
|
if (currentUrl) headers["X-Timber-URL"] = currentUrl;
|
|
801
|
+
if (clientDeploymentId) headers[DEPLOYMENT_ID_HEADER] = clientDeploymentId;
|
|
766
802
|
return headers;
|
|
767
803
|
}
|
|
768
804
|
/**
|
|
@@ -817,7 +853,7 @@ function extractSkippedSegments(response) {
|
|
|
817
853
|
* Extract route params from the X-Timber-Params response header.
|
|
818
854
|
* Returns null if the header is missing or malformed.
|
|
819
855
|
*
|
|
820
|
-
* Used to populate
|
|
856
|
+
* Used to populate useSegmentParams() after client-side navigation.
|
|
821
857
|
*/
|
|
822
858
|
function extractParams(response) {
|
|
823
859
|
const header = response.headers.get("X-Timber-Params");
|
|
@@ -840,6 +876,16 @@ var RedirectError = class extends Error {
|
|
|
840
876
|
}
|
|
841
877
|
};
|
|
842
878
|
/**
|
|
879
|
+
* Thrown when the server signals a version skew (X-Timber-Reload header).
|
|
880
|
+
* Caught in navigate() to trigger a full page reload via triggerStaleReload().
|
|
881
|
+
* See TIM-446.
|
|
882
|
+
*/
|
|
883
|
+
var VersionSkewError = class extends Error {
|
|
884
|
+
constructor() {
|
|
885
|
+
super("Version skew detected — server has been redeployed");
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
/**
|
|
843
889
|
* Fetch an RSC payload from the server. If a decodeRsc function is provided,
|
|
844
890
|
* the response is decoded into a React element tree via createFromFetch.
|
|
845
891
|
* Otherwise, the raw response text is returned (test mode).
|
|
@@ -860,6 +906,7 @@ async function fetchRscPayload(url, deps, stateTree, currentUrl) {
|
|
|
860
906
|
let params = null;
|
|
861
907
|
let skippedSegments = null;
|
|
862
908
|
const wrappedPromise = fetchPromise.then((response) => {
|
|
909
|
+
if (checkReloadSignal(response)) throw new VersionSkewError();
|
|
863
910
|
const redirectLocation = response.headers.get("X-Timber-Redirect") || (response.status >= 300 && response.status < 400 ? response.headers.get("Location") : null);
|
|
864
911
|
if (redirectLocation) throw new RedirectError(redirectLocation);
|
|
865
912
|
headElements = extractHeadElements(response);
|
|
@@ -904,23 +951,20 @@ function isAbortError(error) {
|
|
|
904
951
|
if (error instanceof Error && error.name === "AbortError") return true;
|
|
905
952
|
return false;
|
|
906
953
|
}
|
|
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
954
|
function createRouter(deps) {
|
|
912
955
|
const segmentCache = new SegmentCache();
|
|
913
956
|
const prefetchCache = new PrefetchCache();
|
|
914
957
|
const historyStack = new HistoryStack();
|
|
915
958
|
const segmentElementCache = new SegmentElementCache();
|
|
916
|
-
let
|
|
917
|
-
let pendingUrl = null;
|
|
959
|
+
let routerPhase = { phase: "idle" };
|
|
918
960
|
const pendingListeners = /* @__PURE__ */ new Set();
|
|
919
961
|
function setPending(value, url) {
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
962
|
+
const next = value && url ? {
|
|
963
|
+
phase: "navigating",
|
|
964
|
+
targetUrl: url
|
|
965
|
+
} : { phase: "idle" };
|
|
966
|
+
if (routerPhase.phase === next.phase && (routerPhase.phase === "idle" || routerPhase.phase === "navigating" && next.phase === "navigating" && routerPhase.targetUrl === next.targetUrl)) return;
|
|
967
|
+
routerPhase = next;
|
|
924
968
|
for (const listener of pendingListeners) listener(value);
|
|
925
969
|
}
|
|
926
970
|
/** Update the segment cache from server-provided segment metadata. */
|
|
@@ -930,8 +974,8 @@ function createRouter(deps) {
|
|
|
930
974
|
if (tree) segmentCache.set("/", tree);
|
|
931
975
|
}
|
|
932
976
|
/** Render a decoded RSC payload into the DOM if a renderer is available. */
|
|
933
|
-
function renderPayload(payload) {
|
|
934
|
-
if (deps.renderRoot) deps.renderRoot(payload);
|
|
977
|
+
function renderPayload(payload, navState) {
|
|
978
|
+
if (deps.renderRoot) deps.renderRoot(payload, navState);
|
|
935
979
|
}
|
|
936
980
|
/**
|
|
937
981
|
* Merge a partial RSC payload with cached segment elements if segments
|
|
@@ -947,24 +991,26 @@ function createRouter(deps) {
|
|
|
947
991
|
/**
|
|
948
992
|
* Update navigation state (params + pathname) for the next render.
|
|
949
993
|
*
|
|
950
|
-
* Sets
|
|
951
|
-
*
|
|
952
|
-
*
|
|
953
|
-
*
|
|
994
|
+
* Sets the module-level fallback (for tests and SSR) and the
|
|
995
|
+
* globalThis bridge, then returns the NavigationState so callers
|
|
996
|
+
* can pass it explicitly to renderRoot/wrapPayload — eliminating
|
|
997
|
+
* temporal coupling with getNavigationState().
|
|
954
998
|
*/
|
|
955
999
|
function updateNavigationState(params, url) {
|
|
956
1000
|
const resolvedParams = params ?? {};
|
|
957
1001
|
setCurrentParams(resolvedParams);
|
|
958
|
-
|
|
1002
|
+
const navState = {
|
|
959
1003
|
params: resolvedParams,
|
|
960
1004
|
pathname: url.startsWith("http") ? new URL(url).pathname : url.split("?")[0] || "/"
|
|
961
|
-
}
|
|
1005
|
+
};
|
|
1006
|
+
setNavigationState(navState);
|
|
1007
|
+
return navState;
|
|
962
1008
|
}
|
|
963
1009
|
/**
|
|
964
1010
|
* Render a payload via navigateTransition (production) or renderRoot (tests).
|
|
965
|
-
* The perform callback should fetch data, update state, and return the
|
|
966
|
-
*
|
|
967
|
-
*
|
|
1011
|
+
* The perform callback should fetch data, update state, and return the
|
|
1012
|
+
* FetchResult plus the NavigationState (so it can be passed explicitly
|
|
1013
|
+
* to wrapPayload/renderRoot without temporal coupling).
|
|
968
1014
|
*/
|
|
969
1015
|
async function renderViaTransition(url, perform) {
|
|
970
1016
|
if (deps.navigateTransition) {
|
|
@@ -978,7 +1024,7 @@ function createRouter(deps) {
|
|
|
978
1024
|
headElements: result.headElements,
|
|
979
1025
|
params: result.params
|
|
980
1026
|
});
|
|
981
|
-
return wrapPayload(merged);
|
|
1027
|
+
return wrapPayload(merged, result.navState);
|
|
982
1028
|
});
|
|
983
1029
|
return headElements;
|
|
984
1030
|
}
|
|
@@ -989,7 +1035,7 @@ function createRouter(deps) {
|
|
|
989
1035
|
headElements: result.headElements,
|
|
990
1036
|
params: result.params
|
|
991
1037
|
});
|
|
992
|
-
renderPayload(merged);
|
|
1038
|
+
renderPayload(merged, result.navState);
|
|
993
1039
|
return result.headElements;
|
|
994
1040
|
}
|
|
995
1041
|
/** Apply head elements (title, meta tags) to the DOM if available. */
|
|
@@ -1002,6 +1048,16 @@ function createRouter(deps) {
|
|
|
1002
1048
|
else callback();
|
|
1003
1049
|
}
|
|
1004
1050
|
/**
|
|
1051
|
+
* Schedule scroll restoration after the next paint and fire the
|
|
1052
|
+
* scroll-restored event. Used by navigate, popstate, and refresh.
|
|
1053
|
+
*/
|
|
1054
|
+
function restoreScrollAfterPaint(scrollY) {
|
|
1055
|
+
afterPaint(() => {
|
|
1056
|
+
deps.scrollTo(0, scrollY);
|
|
1057
|
+
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1005
1061
|
* Core navigation logic shared between the transition and fallback paths.
|
|
1006
1062
|
* Fetches the RSC payload, updates all state, and returns the result.
|
|
1007
1063
|
*/
|
|
@@ -1028,8 +1084,11 @@ function createRouter(deps) {
|
|
|
1028
1084
|
scrollY: 0
|
|
1029
1085
|
}, "", url);
|
|
1030
1086
|
updateSegmentCache(result.segmentInfo);
|
|
1031
|
-
updateNavigationState(result.params, url);
|
|
1032
|
-
return
|
|
1087
|
+
const navState = updateNavigationState(result.params, url);
|
|
1088
|
+
return {
|
|
1089
|
+
...result,
|
|
1090
|
+
navState
|
|
1091
|
+
};
|
|
1033
1092
|
}
|
|
1034
1093
|
async function navigate(url, options = {}) {
|
|
1035
1094
|
const scroll = options.scroll !== false;
|
|
@@ -1043,12 +1102,13 @@ function createRouter(deps) {
|
|
|
1043
1102
|
try {
|
|
1044
1103
|
applyHead(await renderViaTransition(url, () => performNavigationFetch(url, { replace })));
|
|
1045
1104
|
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
|
-
});
|
|
1105
|
+
restoreScrollAfterPaint(scroll ? 0 : currentScrollY);
|
|
1051
1106
|
} catch (error) {
|
|
1107
|
+
if (error instanceof VersionSkewError) {
|
|
1108
|
+
const { triggerStaleReload } = await import("../_chunks/stale-reload-C0ValzG7.js");
|
|
1109
|
+
triggerStaleReload();
|
|
1110
|
+
return new Promise(() => {});
|
|
1111
|
+
}
|
|
1052
1112
|
if (error instanceof RedirectError) {
|
|
1053
1113
|
setPending(false);
|
|
1054
1114
|
await navigate(error.redirectUrl, { replace: true });
|
|
@@ -1067,8 +1127,11 @@ function createRouter(deps) {
|
|
|
1067
1127
|
applyHead(await renderViaTransition(currentUrl, async () => {
|
|
1068
1128
|
const result = await fetchRscPayload(currentUrl, deps);
|
|
1069
1129
|
updateSegmentCache(result.segmentInfo);
|
|
1070
|
-
updateNavigationState(result.params, currentUrl);
|
|
1071
|
-
return
|
|
1130
|
+
const navState = updateNavigationState(result.params, currentUrl);
|
|
1131
|
+
return {
|
|
1132
|
+
...result,
|
|
1133
|
+
navState
|
|
1134
|
+
};
|
|
1072
1135
|
}));
|
|
1073
1136
|
} finally {
|
|
1074
1137
|
setPending(false);
|
|
@@ -1077,26 +1140,23 @@ function createRouter(deps) {
|
|
|
1077
1140
|
async function handlePopState(url, scrollY = 0) {
|
|
1078
1141
|
const entry = historyStack.get(url);
|
|
1079
1142
|
if (entry && entry.payload !== null) {
|
|
1080
|
-
updateNavigationState(entry.params, url);
|
|
1081
|
-
renderPayload(entry.payload);
|
|
1143
|
+
const navState = updateNavigationState(entry.params, url);
|
|
1144
|
+
renderPayload(entry.payload, navState);
|
|
1082
1145
|
applyHead(entry.headElements);
|
|
1083
|
-
|
|
1084
|
-
deps.scrollTo(0, scrollY);
|
|
1085
|
-
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1086
|
-
});
|
|
1146
|
+
restoreScrollAfterPaint(scrollY);
|
|
1087
1147
|
} else {
|
|
1088
1148
|
setPending(true, url);
|
|
1089
1149
|
try {
|
|
1090
1150
|
applyHead(await renderViaTransition(url, async () => {
|
|
1091
1151
|
const result = await fetchRscPayload(url, deps, segmentCache.serializeStateTree(segmentElementCache.getMergeablePaths()));
|
|
1092
1152
|
updateSegmentCache(result.segmentInfo);
|
|
1093
|
-
updateNavigationState(result.params, url);
|
|
1094
|
-
return
|
|
1153
|
+
const navState = updateNavigationState(result.params, url);
|
|
1154
|
+
return {
|
|
1155
|
+
...result,
|
|
1156
|
+
navState
|
|
1157
|
+
};
|
|
1095
1158
|
}));
|
|
1096
|
-
|
|
1097
|
-
deps.scrollTo(0, scrollY);
|
|
1098
|
-
window.dispatchEvent(new Event("timber:scroll-restored"));
|
|
1099
|
-
});
|
|
1159
|
+
restoreScrollAfterPaint(scrollY);
|
|
1100
1160
|
} finally {
|
|
1101
1161
|
setPending(false);
|
|
1102
1162
|
}
|
|
@@ -1117,8 +1177,8 @@ function createRouter(deps) {
|
|
|
1117
1177
|
navigate,
|
|
1118
1178
|
refresh,
|
|
1119
1179
|
handlePopState,
|
|
1120
|
-
isPending: () =>
|
|
1121
|
-
getPendingUrl: () =>
|
|
1180
|
+
isPending: () => routerPhase.phase === "navigating",
|
|
1181
|
+
getPendingUrl: () => routerPhase.phase === "navigating" ? routerPhase.targetUrl : null,
|
|
1122
1182
|
onPendingChange(listener) {
|
|
1123
1183
|
pendingListeners.add(listener);
|
|
1124
1184
|
return () => pendingListeners.delete(listener);
|
|
@@ -1131,7 +1191,7 @@ function createRouter(deps) {
|
|
|
1131
1191
|
payload: merged,
|
|
1132
1192
|
headElements
|
|
1133
1193
|
});
|
|
1134
|
-
renderPayload(merged);
|
|
1194
|
+
renderPayload(merged, getNavigationState());
|
|
1135
1195
|
applyHead(headElements);
|
|
1136
1196
|
},
|
|
1137
1197
|
initSegmentCache: (segments) => updateSegmentCache(segments),
|
|
@@ -1354,36 +1414,6 @@ function useSearchParams() {
|
|
|
1354
1414
|
return typeof window !== "undefined" ? getSearchParams() : getServerSearchParams();
|
|
1355
1415
|
}
|
|
1356
1416
|
//#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
1417
|
//#region src/client/use-selected-layout-segment.ts
|
|
1388
1418
|
/**
|
|
1389
1419
|
* useSelectedLayoutSegment / useSelectedLayoutSegments — client-side hooks
|
|
@@ -1589,6 +1619,96 @@ function useFormErrors(result) {
|
|
|
1589
1619
|
};
|
|
1590
1620
|
}
|
|
1591
1621
|
//#endregion
|
|
1592
|
-
|
|
1622
|
+
//#region src/client/use-cookie.ts
|
|
1623
|
+
/**
|
|
1624
|
+
* useCookie — reactive client-side cookie hook.
|
|
1625
|
+
*
|
|
1626
|
+
* Uses useSyncExternalStore for SSR-safe, reactive cookie access.
|
|
1627
|
+
* All components reading the same cookie name re-render on change.
|
|
1628
|
+
* No cross-tab sync (intentional — see design/29-cookies.md).
|
|
1629
|
+
*
|
|
1630
|
+
* See design/29-cookies.md §"useCookie(name) Hook"
|
|
1631
|
+
*/
|
|
1632
|
+
var use_cookie_exports = /* @__PURE__ */ __exportAll({ useCookie: () => useCookie });
|
|
1633
|
+
/** Per-name subscriber sets. */
|
|
1634
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
1635
|
+
/** Parse a cookie name from document.cookie. */
|
|
1636
|
+
function getCookieValue(name) {
|
|
1637
|
+
if (typeof document === "undefined") return void 0;
|
|
1638
|
+
const match = document.cookie.match(new RegExp("(?:^|;\\s*)" + name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\s*=\\s*([^;]*)"));
|
|
1639
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
1640
|
+
}
|
|
1641
|
+
/** Serialize options into a cookie string suffix. */
|
|
1642
|
+
function serializeOptions(options) {
|
|
1643
|
+
if (!options) return "; Path=/; SameSite=Lax";
|
|
1644
|
+
const parts = [];
|
|
1645
|
+
parts.push(`Path=${options.path ?? "/"}`);
|
|
1646
|
+
if (options.domain) parts.push(`Domain=${options.domain}`);
|
|
1647
|
+
if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
1648
|
+
if (options.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
1649
|
+
const sameSite = options.sameSite ?? "lax";
|
|
1650
|
+
parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
|
|
1651
|
+
if (options.secure) parts.push("Secure");
|
|
1652
|
+
return "; " + parts.join("; ");
|
|
1653
|
+
}
|
|
1654
|
+
/** Notify all subscribers for a given cookie name. */
|
|
1655
|
+
function notify(name) {
|
|
1656
|
+
const subs = listeners.get(name);
|
|
1657
|
+
if (subs) for (const fn of subs) fn();
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* Reactive hook for reading/writing a client-side cookie.
|
|
1661
|
+
*
|
|
1662
|
+
* Returns `[value, setCookie, deleteCookie]`:
|
|
1663
|
+
* - `value`: current cookie value (string | undefined)
|
|
1664
|
+
* - `setCookie`: sets the cookie and triggers re-renders
|
|
1665
|
+
* - `deleteCookie`: deletes the cookie and triggers re-renders
|
|
1666
|
+
*
|
|
1667
|
+
* @param name - Cookie name.
|
|
1668
|
+
* @param defaultOptions - Default options for setCookie calls.
|
|
1669
|
+
*/
|
|
1670
|
+
function useCookie(name, defaultOptions) {
|
|
1671
|
+
const subscribe = (callback) => {
|
|
1672
|
+
let subs = listeners.get(name);
|
|
1673
|
+
if (!subs) {
|
|
1674
|
+
subs = /* @__PURE__ */ new Set();
|
|
1675
|
+
listeners.set(name, subs);
|
|
1676
|
+
}
|
|
1677
|
+
subs.add(callback);
|
|
1678
|
+
return () => {
|
|
1679
|
+
subs.delete(callback);
|
|
1680
|
+
if (subs.size === 0) listeners.delete(name);
|
|
1681
|
+
};
|
|
1682
|
+
};
|
|
1683
|
+
const getSnapshot = () => getCookieValue(name);
|
|
1684
|
+
const getServerSnapshot = () => getSsrData()?.cookies.get(name);
|
|
1685
|
+
const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
1686
|
+
const setCookie = (newValue, options) => {
|
|
1687
|
+
const merged = {
|
|
1688
|
+
...defaultOptions,
|
|
1689
|
+
...options
|
|
1690
|
+
};
|
|
1691
|
+
document.cookie = `${name}=${encodeURIComponent(newValue)}${serializeOptions(merged)}`;
|
|
1692
|
+
notify(name);
|
|
1693
|
+
};
|
|
1694
|
+
const deleteCookie = () => {
|
|
1695
|
+
const path = defaultOptions?.path ?? "/";
|
|
1696
|
+
const domain = defaultOptions?.domain;
|
|
1697
|
+
let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;
|
|
1698
|
+
if (domain) cookieStr += `; Domain=${domain}`;
|
|
1699
|
+
document.cookie = cookieStr;
|
|
1700
|
+
notify(name);
|
|
1701
|
+
};
|
|
1702
|
+
return [
|
|
1703
|
+
value,
|
|
1704
|
+
setCookie,
|
|
1705
|
+
deleteCookie
|
|
1706
|
+
];
|
|
1707
|
+
}
|
|
1708
|
+
//#endregion
|
|
1709
|
+
//#region src/client/index.ts
|
|
1710
|
+
_registerUseCookieModule(use_cookie_exports);
|
|
1711
|
+
//#endregion
|
|
1712
|
+
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
1713
|
|
|
1594
1714
|
//# sourceMappingURL=index.js.map
|