@timber-js/app 0.2.0-alpha.196 → 0.2.0-alpha.198
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{actions-CWYtq6ii.js → actions-BS-m5SLv.js} +3 -3
- package/dist/_chunks/{actions-CWYtq6ii.js.map → actions-BS-m5SLv.js.map} +1 -1
- package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -1
- package/dist/_chunks/{build-manifest-DWppEdLB.js → build-manifest-DTmSGLRz.js} +51 -2
- package/dist/_chunks/build-manifest-DTmSGLRz.js.map +1 -0
- package/dist/_chunks/{cache-api-CQeYzA5g.js → cache-api-DqzgTEqk.js} +4 -49
- package/dist/_chunks/cache-api-DqzgTEqk.js.map +1 -0
- package/dist/_chunks/{chains-h7EO-u3n.js → chains-CZG7E5zg.js} +2 -2
- package/dist/_chunks/{chains-h7EO-u3n.js.map → chains-CZG7E5zg.js.map} +1 -1
- package/dist/_chunks/{cli-check-BVthpfLS.js → cli-check-dVDi1GQz.js} +3 -3
- package/dist/_chunks/{cli-check-BVthpfLS.js.map → cli-check-dVDi1GQz.js.map} +1 -1
- package/dist/_chunks/{cli-schema-sync-3Wutm8pH.js → cli-schema-sync-DTy_-Msq.js} +2 -2
- package/dist/_chunks/{cli-schema-sync-3Wutm8pH.js.map → cli-schema-sync-DTy_-Msq.js.map} +1 -1
- package/dist/_chunks/{cloudflare-BKJC3SC_.js → cloudflare-BFb__LYG.js} +2 -2
- package/dist/_chunks/{cloudflare-BKJC3SC_.js.map → cloudflare-BFb__LYG.js.map} +1 -1
- package/dist/_chunks/{convention-lint-DO10_pVl.js → convention-lint-Ph6luW4c.js} +4 -2
- package/dist/_chunks/convention-lint-Ph6luW4c.js.map +1 -0
- package/dist/_chunks/{error-boundary-D-lkwyaD.js → error-boundary-BvRCCmbN.js} +3 -3
- package/dist/_chunks/{error-boundary-D-lkwyaD.js.map → error-boundary-BvRCCmbN.js.map} +1 -1
- package/dist/_chunks/{href-validation-CMc5JRls.js → href-validation-BIrxavIy.js} +74 -2
- package/dist/_chunks/href-validation-BIrxavIy.js.map +1 -0
- package/dist/_chunks/{live-graph-Bx4HodF1.js → live-graph-BXDsdzBv.js} +3 -3
- package/dist/_chunks/{live-graph-Bx4HodF1.js.map → live-graph-BXDsdzBv.js.map} +1 -1
- package/dist/_chunks/{logger-pumCm3Il.js → logger-DDirEsn7.js} +3 -4
- package/dist/_chunks/{logger-pumCm3Il.js.map → logger-DDirEsn7.js.map} +1 -1
- package/dist/_chunks/navigation-root-B00jjGd5.js +233 -0
- package/dist/_chunks/navigation-root-B00jjGd5.js.map +1 -0
- package/dist/_chunks/{segment-context-CjOlyB8Y.js → param-value-C8TNYchQ.js} +2 -33
- package/dist/_chunks/param-value-C8TNYchQ.js.map +1 -0
- package/dist/_chunks/{poison-scan-BAxfTT5L.js → poison-scan-BoDLgbix.js} +2 -2
- package/dist/_chunks/{poison-scan-BAxfTT5L.js.map → poison-scan-BoDLgbix.js.map} +1 -1
- package/dist/_chunks/{router-ref-BzqbPwYC.js → router-ref-8gr8qsxN.js} +2 -2
- package/dist/_chunks/{router-ref-BzqbPwYC.js.map → router-ref-8gr8qsxN.js.map} +1 -1
- package/dist/_chunks/{rsc-cache-key-DD0fl_-s.js → rsc-cache-key-ClUiXQnK.js} +2 -2
- package/dist/_chunks/{rsc-cache-key-DD0fl_-s.js.map → rsc-cache-key-ClUiXQnK.js.map} +1 -1
- package/dist/_chunks/{scanner-BRIOmHE2.js → scanner-tdFPvDYi.js} +174 -7
- package/dist/_chunks/scanner-tdFPvDYi.js.map +1 -0
- package/dist/_chunks/segment-context-D9_89u34.js +34 -0
- package/dist/_chunks/segment-context-D9_89u34.js.map +1 -0
- package/dist/_chunks/singleflight-2lUWfcAk.js +54 -0
- package/dist/_chunks/singleflight-2lUWfcAk.js.map +1 -0
- package/dist/_chunks/{ssr-data-Ya2HJPFp.js → ssr-data-BQGhTPAK.js} +2 -17
- package/dist/_chunks/ssr-data-BQGhTPAK.js.map +1 -0
- package/dist/_chunks/{walkers-BU6z9xRV.js → walkers-DNX05dC0.js} +2 -2
- package/dist/_chunks/{walkers-BU6z9xRV.js.map → walkers-DNX05dC0.js.map} +1 -1
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +1 -1
- package/dist/adapters/cloudflare.js +1 -1
- package/dist/adapters/nitro.d.ts +1 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/analyze/crawl-entry.js +2 -2
- package/dist/analyze/graph-command.js +2 -2
- package/dist/cache/index.js +1 -1
- package/dist/cache/singleflight.d.ts +2 -0
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/client/browser-entry/hydrate.d.ts +21 -15
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
- package/dist/client/browser-entry/index.d.ts +4 -3
- package/dist/client/browser-entry/index.d.ts.map +1 -1
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts +17 -1
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/global-context.d.ts +15 -0
- package/dist/client/global-context.d.ts.map +1 -0
- package/dist/client/index.js +138 -35
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +0 -1
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +206 -55
- package/dist/client/internal.js.map +1 -1
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/location-search.d.ts +12 -0
- package/dist/client/location-search.d.ts.map +1 -0
- package/dist/client/navigation-api.d.ts.map +1 -1
- package/dist/client/navigation-commit.d.ts +18 -0
- package/dist/client/navigation-commit.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +13 -11
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +47 -108
- package/dist/client/navigation-root.d.ts.map +1 -1
- package/dist/client/navigation-transition.d.ts +136 -0
- package/dist/client/navigation-transition.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/params-context.d.ts +4 -5
- package/dist/client/params-context.d.ts.map +1 -1
- package/dist/client/react-root.d.ts +44 -0
- package/dist/client/react-root.d.ts.map +1 -0
- package/dist/client/router-pipeline.d.ts +2 -2
- package/dist/client/router-pipeline.d.ts.map +1 -1
- package/dist/client/router-types.d.ts +12 -2
- package/dist/client/router-types.d.ts.map +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +39 -0
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +25 -14
- package/dist/client/segment-outlet.d.ts.map +1 -1
- package/dist/client/segment-update-context.d.ts +3 -9
- package/dist/client/segment-update-context.d.ts.map +1 -1
- package/dist/client/slot-content-cache-context.d.ts +35 -0
- package/dist/client/slot-content-cache-context.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +8 -2
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/state.d.ts +0 -15
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts +13 -11
- package/dist/client/use-pathname.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +13 -13
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/client/use-segment-params.d.ts +18 -68
- package/dist/client/use-segment-params.d.ts.map +1 -1
- package/dist/config-types.d.ts +17 -0
- package/dist/config-types.d.ts.map +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/dev-tools/holding-server.d.ts +15 -10
- package/dist/dev-tools/holding-server.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -43
- package/dist/index.js.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +2 -2
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-write.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/routing/interception-overlap.d.ts +35 -0
- package/dist/routing/interception-overlap.d.ts.map +1 -0
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +3 -1
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +6 -0
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/csp-nonce.d.ts +45 -0
- package/dist/server/csp-nonce.d.ts.map +1 -0
- package/dist/server/default-status-page.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/flight-scripts.d.ts +5 -2
- package/dist/server/flight-scripts.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +17 -2
- package/dist/server/html-injector-core.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +3 -2
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/internal.js +86 -37
- package/dist/server/internal.js.map +1 -1
- package/dist/server/metadata-render.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +3 -17
- package/dist/server/node-stream-transforms.d.ts.map +1 -1
- package/dist/server/nuqs-ssr-provider.d.ts +7 -3
- package/dist/server/nuqs-ssr-provider.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/prebuilt/key-discipline.d.ts +32 -3
- package/dist/server/prebuilt/key-discipline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-utils.d.ts +4 -3
- package/dist/server/render-utils.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +22 -2
- package/dist/server/ssr-bridge-types.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +5 -1
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +59 -27
- package/dist/server/ssr-wrappers.d.ts.map +1 -1
- package/dist/server/types.d.ts +10 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/shims/navigation-rsc.d.ts +21 -0
- package/dist/shims/navigation-rsc.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +1 -0
- package/docs/api/35-api-typescript.mdx +4 -83
- package/docs/learn/03-fetching-data.mdx +1 -1
- package/docs/learn/{03b-access-control.mdx → 04-access-control.mdx} +2 -17
- package/docs/learn/05-the-flush-point.mdx +175 -0
- package/docs/learn/{05-typed-params.mdx → 06-typed-params.mdx} +1 -1
- package/docs/learn/07-typed-routes.mdx +25 -49
- package/docs/learn/{08-streaming.mdx → 09-streaming.mdx} +1 -7
- package/docs/learn/{10-middleware.mdx → 11-middleware.mdx} +1 -0
- package/package.json +3 -3
- package/src/adapters/nitro.ts +7 -7
- package/src/cache/singleflight.ts +5 -0
- package/src/client/browser-entry/hydrate.ts +54 -104
- package/src/client/browser-entry/index.ts +16 -6
- package/src/client/browser-entry/post-hydration.ts +3 -2
- package/src/client/browser-entry/router-init.ts +84 -33
- package/src/client/global-context.ts +31 -0
- package/src/client/internal.ts +1 -2
- package/src/client/link.tsx +18 -18
- package/src/client/location-search.ts +15 -0
- package/src/client/navigation-api.ts +4 -2
- package/src/client/navigation-commit.ts +48 -2
- package/src/client/navigation-context.ts +25 -37
- package/src/client/navigation-root.tsx +55 -411
- package/src/client/navigation-transition.ts +278 -0
- package/src/client/nuqs-adapter.tsx +4 -5
- package/src/client/params-context.ts +13 -18
- package/src/client/react-root.ts +72 -0
- package/src/client/router-lifecycle.ts +1 -1
- package/src/client/router-pipeline.ts +96 -22
- package/src/client/router-types.ts +12 -2
- package/src/client/router.ts +48 -36
- package/src/client/segment-cache.ts +70 -2
- package/src/client/segment-context.ts +7 -4
- package/src/client/segment-outlet.tsx +41 -86
- package/src/client/segment-update-context.ts +7 -26
- package/src/client/slot-content-cache-context.ts +43 -0
- package/src/client/ssr-data.ts +8 -2
- package/src/client/state.ts +0 -26
- package/src/client/use-pathname.ts +21 -31
- package/src/client/use-search-params.ts +31 -29
- package/src/client/use-segment-params.ts +27 -126
- package/src/config-types.ts +17 -0
- package/src/config-validation.ts +17 -0
- package/src/dev-tools/holding-server.ts +23 -12
- package/src/index.ts +26 -11
- package/src/plugins/dev-server.ts +9 -12
- package/src/plugins/entries.ts +3 -0
- package/src/plugins/shims.ts +8 -7
- package/src/plugins/static-build.ts +9 -5
- package/src/react-canary.d.ts +2 -0
- package/src/routing/codegen-write.ts +2 -0
- package/src/routing/interception-overlap.ts +141 -0
- package/src/routing/interception.ts +118 -5
- package/src/rsc-runtime/ssr.ts +3 -2
- package/src/server/als-registry.ts +6 -0
- package/src/server/csp-nonce.ts +70 -0
- package/src/server/default-status-page.ts +1 -0
- package/src/server/deny-renderer.ts +7 -3
- package/src/server/flight-scripts.ts +9 -4
- package/src/server/html-injector-core.ts +26 -9
- package/src/server/html-injectors.ts +8 -8
- package/src/server/metadata-render.ts +26 -4
- package/src/server/node-stream-transforms.ts +7 -20
- package/src/server/nuqs-ssr-provider.tsx +8 -7
- package/src/server/pipeline-phases.ts +5 -0
- package/src/server/prebuilt/key-discipline.ts +82 -13
- package/src/server/prebuilt-runtime.ts +2 -2
- package/src/server/primitives.ts +4 -4
- package/src/server/render-utils.ts +8 -4
- package/src/server/rsc-entry/action-middleware-runner.ts +7 -0
- package/src/server/rsc-entry/error-renderer.ts +5 -2
- package/src/server/rsc-entry/index.ts +8 -0
- package/src/server/rsc-entry/ssr-renderer.ts +11 -4
- package/src/server/ssr-bridge-types.ts +22 -2
- package/src/server/ssr-entry.ts +35 -28
- package/src/server/ssr-render.ts +13 -4
- package/src/server/ssr-wrappers.tsx +81 -61
- package/src/server/types.ts +10 -0
- package/src/shared/slot-params.ts +3 -4
- package/src/shims/navigation-rsc.ts +47 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +0 -1
- package/dist/_chunks/cache-api-CQeYzA5g.js.map +0 -1
- package/dist/_chunks/convention-lint-DO10_pVl.js.map +0 -1
- package/dist/_chunks/href-validation-CMc5JRls.js.map +0 -1
- package/dist/_chunks/scanner-BRIOmHE2.js.map +0 -1
- package/dist/_chunks/segment-context-CjOlyB8Y.js.map +0 -1
- package/dist/_chunks/slot-params-BCTmZkQB.js +0 -76
- package/dist/_chunks/slot-params-BCTmZkQB.js.map +0 -1
- package/dist/_chunks/ssr-data-Ya2HJPFp.js.map +0 -1
- package/dist/_chunks/use-segment-params-DzTBpkvj.js +0 -398
- package/dist/_chunks/use-segment-params-DzTBpkvj.js.map +0 -1
- package/docs/learn/04-loading-states.mdx +0 -67
- package/docs/learn/04b-the-flush-point.mdx +0 -115
- package/docs/learn/12-client-navigation.mdx +0 -176
- package/docs/learn/13-configuration.mdx +0 -166
- package/docs/more/01-advanced-routing.mdx +0 -344
- package/docs/more/02-advanced-forms.mdx +0 -137
- package/docs/more/03-coming-from-nextjs.mdx +0 -186
- package/docs/more/04-metadata-and-fonts.mdx +0 -193
- package/docs/more/04b-mdx.mdx +0 -229
- package/docs/more/05-content-collections.mdx +0 -90
- package/docs/more/06-instrumentation.mdx +0 -214
- package/docs/more/07-security.mdx +0 -129
- package/docs/more/08-developer-experience.mdx +0 -134
- package/docs/more/40-why-timber.mdx +0 -50
- package/docs/more/41-timber-vs-nextjs.mdx +0 -81
- package/docs/more/42-timber-vs-others.mdx +0 -68
- package/docs/more/50-ai-agent-instructions.mdx +0 -171
- /package/docs/learn/{06-forms-and-actions.mdx → 08-forms-and-actions.mdx} +0 -0
- /package/docs/learn/{09-caching.mdx → 10-caching.mdx} +0 -0
- /package/docs/learn/{11-error-handling.mdx → 12-error-handling.mdx} +0 -0
- /package/docs/learn/{14-deploying.mdx → 13-deploying.mdx} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { stripRscCacheKey } from '../shared/rsc-cache-key.ts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The app-visible search string from the address bar.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors what `appVisibleSearch()` does on the server: strips key-shaped
|
|
7
|
+
* `_rsc` values so the client and server agree on search state regardless
|
|
8
|
+
* of whether the document URL itself carries a payload cache key (a user
|
|
9
|
+
* pasting/sharing an RSC payload URL). Non-key-shaped `_rsc` values — an
|
|
10
|
+
* application legitimately owning that name — survive, using the same
|
|
11
|
+
* `isRscCacheKeyShape` predicate the server uses.
|
|
12
|
+
*/
|
|
13
|
+
export function locationSearch(): string {
|
|
14
|
+
return stripRscCacheKey(window.location.search);
|
|
15
|
+
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { isHardNavigating } from './navigation-root.tsx';
|
|
21
|
+
import { stripRscCacheKey } from '../shared/rsc-cache-key.ts';
|
|
21
22
|
|
|
22
23
|
// ─── Feature Detection ───────────────────────────────────────────
|
|
23
24
|
|
|
@@ -220,7 +221,7 @@ export function setupNavigationApi(callbacks: NavigationApiCallbacks): Navigatio
|
|
|
220
221
|
// Skip reload navigations — let the browser handle full page reload
|
|
221
222
|
if (event.navigationType === 'reload') return;
|
|
222
223
|
|
|
223
|
-
const url = destUrl.pathname + destUrl.search;
|
|
224
|
+
const url = destUrl.pathname + stripRscCacheKey(destUrl.search);
|
|
224
225
|
|
|
225
226
|
if (event.navigationType === 'traverse') {
|
|
226
227
|
// Back/forward button — intercept and delegate to router.
|
|
@@ -265,7 +266,8 @@ export function setupNavigationApi(callbacks: NavigationApiCallbacks): Navigatio
|
|
|
265
266
|
// destination. Once intercept() is called, currentEntry switches and
|
|
266
267
|
// getCurrentUrl() returns the destination (TIM-1232).
|
|
267
268
|
const departingUrl = nav.currentEntry?.url
|
|
268
|
-
? new URL(nav.currentEntry.url).pathname +
|
|
269
|
+
? new URL(nav.currentEntry.url).pathname +
|
|
270
|
+
stripRscCacheKey(new URL(nav.currentEntry.url).search)
|
|
269
271
|
: undefined;
|
|
270
272
|
|
|
271
273
|
event.intercept({
|
|
@@ -54,6 +54,51 @@ export interface NavigationCommitInput {
|
|
|
54
54
|
* See TIM-1356.
|
|
55
55
|
*/
|
|
56
56
|
status?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Layouts the server skipped on this response (`X-Timber-Skipped-Segments`),
|
|
59
|
+
* when it came from a fetch. Omitted by replays and revalidation.
|
|
60
|
+
*
|
|
61
|
+
* Together with `skipped` slot entries in `segmentInfo`, this decides
|
|
62
|
+
* whether the payload can be *replayed*. A partial payload only renders
|
|
63
|
+
* merged over the tree on screen, and a `skip=true` outlet resolves against
|
|
64
|
+
* the slot content cache at render time — so a stored copy of either,
|
|
65
|
+
* replayed later, shows whatever the client holds *then*, not what was on
|
|
66
|
+
* screen when the entry committed. Such entries store a null payload and
|
|
67
|
+
* traversals to them fetch instead. Decided here, not at the fetch call
|
|
68
|
+
* sites, for the same reason as `status`: `performNavigationFetch` had the
|
|
69
|
+
* check and `fetchCommitAndRender` did not, so a back/forward fetch that
|
|
70
|
+
* was answered with skips stored the holes (TIM-1432).
|
|
71
|
+
*/
|
|
72
|
+
skippedSegments?: string[] | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Whether a response skipped layouts — its payload merges over the tree on screen. */
|
|
76
|
+
export function isPartialNavigation(skippedSegments: string[] | null | undefined): boolean {
|
|
77
|
+
return skippedSegments != null && skippedSegments.length > 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Whether a payload can stand on its own when replayed from the history
|
|
82
|
+
* stack. See `NavigationCommitInput.skippedSegments`.
|
|
83
|
+
*/
|
|
84
|
+
function isReplayable(opts: NavigationCommitInput): boolean {
|
|
85
|
+
return !isPartialNavigation(opts.skippedSegments) && !hasSkippedSlot(opts.segmentInfo);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function hasSkippedSlot(segmentInfo: SegmentInfo[] | null | undefined): boolean {
|
|
89
|
+
return segmentInfo?.some((s) => s.slot && s.skipped) ?? false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The metadata a history entry keeps. `skipped` describes the *response*
|
|
94
|
+
* — "this slot's content was omitted" — and the entry stores no such
|
|
95
|
+
* payload (it stores null). Left on the entry, the flag outlives the
|
|
96
|
+
* response: `applyRevalidation()` reuses the entry's metadata beside a full
|
|
97
|
+
* re-render and would have that judged non-replayable too.
|
|
98
|
+
*/
|
|
99
|
+
function storedSegmentInfo(segmentInfo: SegmentInfo[] | null | undefined) {
|
|
100
|
+
if (!hasSkippedSlot(segmentInfo)) return segmentInfo;
|
|
101
|
+
return segmentInfo!.map(({ skipped: _skipped, ...rest }) => rest);
|
|
57
102
|
}
|
|
58
103
|
|
|
59
104
|
/**
|
|
@@ -173,6 +218,7 @@ export function createNavigationCommitter(deps: {
|
|
|
173
218
|
// traversal back to this URL would replay the metadata this drops.
|
|
174
219
|
const cacheable = opts.status === undefined || opts.status < 400;
|
|
175
220
|
const segmentInfo = cacheable ? opts.segmentInfo : [];
|
|
221
|
+
const payload = isReplayable(opts) ? opts.payload : null;
|
|
176
222
|
|
|
177
223
|
return {
|
|
178
224
|
navState,
|
|
@@ -186,9 +232,9 @@ export function createNavigationCommitter(deps: {
|
|
|
186
232
|
setNavigationState(navState);
|
|
187
233
|
|
|
188
234
|
historyStack.push(url, {
|
|
189
|
-
payload
|
|
235
|
+
payload,
|
|
190
236
|
params: opts.params,
|
|
191
|
-
segmentInfo,
|
|
237
|
+
segmentInfo: storedSegmentInfo(segmentInfo),
|
|
192
238
|
});
|
|
193
239
|
},
|
|
194
240
|
};
|
|
@@ -18,14 +18,15 @@
|
|
|
18
18
|
* All consumers (usePathname, useSearchParams) see the new values in the
|
|
19
19
|
* same render pass as the new tree.
|
|
20
20
|
*
|
|
21
|
-
* During SSR,
|
|
22
|
-
*
|
|
21
|
+
* During SSR, the wrapper chain mounts this same provider with the
|
|
22
|
+
* request's pathname and raw search string (TIM-1424), so the hooks
|
|
23
|
+
* resolve through the identical code path on both sides. Per-request
|
|
24
|
+
* isolation is by construction — the value is part of the request's
|
|
25
|
+
* element tree.
|
|
23
26
|
*
|
|
24
|
-
*
|
|
25
|
-
* environment
|
|
26
|
-
*
|
|
27
|
-
* that depend on these APIs are safe to call from any environment —
|
|
28
|
-
* they return null or no-op when the APIs aren't available.
|
|
27
|
+
* This module is `'use client'` and is never evaluated in the RSC
|
|
28
|
+
* environment. The shims plugin resolves next/navigation to
|
|
29
|
+
* navigation-rsc.ts in RSC, which has throwing stubs (TIM-1420).
|
|
29
30
|
*
|
|
30
31
|
* SINGLETON GUARANTEE: All shared mutable state uses globalThis via
|
|
31
32
|
* Symbol.for keys. The RSC client bundler can duplicate this module
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
* See design/19-client-navigation.md §"NavigationContext"
|
|
42
43
|
*/
|
|
43
44
|
|
|
44
|
-
import
|
|
45
|
+
import { createContext, useContext, createElement, type ReactNode } from 'react';
|
|
45
46
|
import type { SlotParamsRecord } from '../shared/slot-params.ts';
|
|
46
47
|
|
|
47
48
|
// ---------------------------------------------------------------------------
|
|
@@ -68,10 +69,6 @@ export interface NavigationState {
|
|
|
68
69
|
// ---------------------------------------------------------------------------
|
|
69
70
|
|
|
70
71
|
/**
|
|
71
|
-
* The context is created lazily to avoid calling createContext at module
|
|
72
|
-
* level. In the RSC environment, React.createContext doesn't exist —
|
|
73
|
-
* calling it at import time would crash the server.
|
|
74
|
-
*
|
|
75
72
|
* Context instances are stored on globalThis (NOT in module-level
|
|
76
73
|
* variables) because the ESM bundler can duplicate this module across
|
|
77
74
|
* chunks. Module-level variables would create separate instances per
|
|
@@ -79,38 +76,34 @@ export interface NavigationState {
|
|
|
79
76
|
* context A while the consumer in usePendingNavigation (shared chunk)
|
|
80
77
|
* reads from context B. globalThis guarantees a single instance.
|
|
81
78
|
*
|
|
79
|
+
* This module is `'use client'` so it is never evaluated in the RSC
|
|
80
|
+
* environment — `createContext` and `useContext` are always available.
|
|
81
|
+
* The shims plugin resolves next/navigation to navigation-rsc.ts in RSC,
|
|
82
|
+
* which has throwing stubs for the hooks (TIM-1420).
|
|
83
|
+
*
|
|
82
84
|
* See design/27-chunking-strategy.md §"Singleton Safety"
|
|
83
85
|
*/
|
|
84
86
|
|
|
85
|
-
// Symbol keys for globalThis storage — prevents collisions with user code
|
|
86
87
|
const NAV_CTX_KEY = Symbol.for('__timber_nav_ctx');
|
|
87
88
|
|
|
88
|
-
function getOrCreateContext():
|
|
89
|
+
function getOrCreateContext(): import('react').Context<NavigationState | null> {
|
|
89
90
|
const existing = (globalThis as Record<symbol, unknown>)[NAV_CTX_KEY] as
|
|
90
|
-
|
|
|
91
|
+
| import('react').Context<NavigationState | null>
|
|
91
92
|
| undefined;
|
|
92
93
|
if (existing !== undefined) return existing;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(globalThis as Record<symbol, unknown>)[NAV_CTX_KEY] = ctx;
|
|
97
|
-
return ctx;
|
|
98
|
-
}
|
|
99
|
-
return undefined;
|
|
94
|
+
const ctx = createContext<NavigationState | null>(null);
|
|
95
|
+
(globalThis as Record<symbol, unknown>)[NAV_CTX_KEY] = ctx;
|
|
96
|
+
return ctx;
|
|
100
97
|
}
|
|
101
98
|
|
|
102
99
|
/**
|
|
103
|
-
* Read the navigation context. Returns null
|
|
104
|
-
*
|
|
100
|
+
* Read the navigation context. Returns null only when no provider is above
|
|
101
|
+
* the caller — a component rendered outside the timber app.
|
|
102
|
+
*
|
|
105
103
|
* Internal — used by usePathname() and useSearchParams().
|
|
106
104
|
*/
|
|
107
105
|
export function useNavigationContext(): NavigationState | null {
|
|
108
|
-
|
|
109
|
-
if (!ctx) return null;
|
|
110
|
-
// useContext may not exist in the RSC environment — caller wraps in try/catch
|
|
111
|
-
if (typeof React.useContext !== 'function') return null;
|
|
112
|
-
// eslint-disable-next-line rules-of-hooks -- conditional on environment, not render path
|
|
113
|
-
return React.useContext(ctx);
|
|
106
|
+
return useContext(getOrCreateContext());
|
|
114
107
|
}
|
|
115
108
|
|
|
116
109
|
// ---------------------------------------------------------------------------
|
|
@@ -131,13 +124,8 @@ export interface NavigationProviderProps {
|
|
|
131
124
|
export function NavigationProvider({
|
|
132
125
|
value,
|
|
133
126
|
children,
|
|
134
|
-
}: NavigationProviderProps):
|
|
135
|
-
|
|
136
|
-
if (!ctx) {
|
|
137
|
-
// RSC environment — no context available. Return children as-is.
|
|
138
|
-
return children as React.ReactElement;
|
|
139
|
-
}
|
|
140
|
-
return createElement(ctx.Provider, { value }, children);
|
|
127
|
+
}: NavigationProviderProps): import('react').ReactElement {
|
|
128
|
+
return createElement(getOrCreateContext().Provider, { value }, children);
|
|
141
129
|
}
|
|
142
130
|
|
|
143
131
|
// ---------------------------------------------------------------------------
|