@timber-js/app 0.2.0-alpha.122 → 0.2.0-alpha.123
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/{actions-Dy8vOjFt.js → actions-ZlcKx0H9.js} +5 -5
- package/dist/_chunks/{actions-Dy8vOjFt.js.map → actions-ZlcKx0H9.js.map} +1 -1
- package/dist/_chunks/{define-CPVQaWbx.js → define-C0V_eKiW.js} +6 -18
- package/dist/_chunks/define-C0V_eKiW.js.map +1 -0
- package/dist/_chunks/{handler-store-CcwNX-gk.js → handler-store-bIAstrxQ.js} +1 -1
- package/dist/_chunks/{handler-store-CcwNX-gk.js.map → handler-store-bIAstrxQ.js.map} +1 -1
- package/dist/_chunks/{merge-search-params-az6ZiBeU.js → merge-search-params-Cm1j99HC.js} +1 -1
- package/dist/_chunks/{merge-search-params-az6ZiBeU.js.map → merge-search-params-Cm1j99HC.js.map} +1 -1
- package/dist/_chunks/{navigation-root-DoRTeBm5.js → navigation-root-Ds_hDtRW.js} +2 -2
- package/dist/_chunks/{navigation-root-DoRTeBm5.js.map → navigation-root-Ds_hDtRW.js.map} +1 -1
- package/dist/_chunks/{resolve-schema-cURaYvaD.js → resolve-schema-DU2nbVOi.js} +1 -1
- package/dist/_chunks/{resolve-schema-cURaYvaD.js.map → resolve-schema-DU2nbVOi.js.map} +1 -1
- package/dist/_chunks/{router-ref-CpvjBqdu.js → router-ref-B2-2kIIC.js} +2 -2
- package/dist/_chunks/{router-ref-CpvjBqdu.js.map → router-ref-B2-2kIIC.js.map} +1 -1
- package/dist/_chunks/{segment-context-EsfQpS--.js → segment-context-Bg0pFbLT.js} +1 -1
- package/dist/_chunks/{segment-context-EsfQpS--.js.map → segment-context-Bg0pFbLT.js.map} +1 -1
- package/dist/_chunks/{ssr-data-m9-cNEIw.js → ssr-data-DVX8S7vj.js} +1 -1
- package/dist/_chunks/{ssr-data-m9-cNEIw.js.map → ssr-data-DVX8S7vj.js.map} +1 -1
- package/dist/_chunks/{use-segment-params-CtIAjqK0.js → use-segment-params-Du7u25cK.js} +3 -8
- package/dist/_chunks/{use-segment-params-CtIAjqK0.js.map → use-segment-params-Du7u25cK.js.map} +1 -1
- package/dist/_chunks/{validation-BMU5MPzP.js → validation-AfEFM5ze.js} +1 -1
- package/dist/_chunks/{validation-BMU5MPzP.js.map → validation-AfEFM5ze.js.map} +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/error-boundary.js +2 -2
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +47 -14
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.js +67 -32
- package/dist/client/internal.js.map +1 -1
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +8 -0
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/shallow-url.d.ts +10 -0
- package/dist/client/shallow-url.d.ts.map +1 -0
- package/dist/cookies/index.js +2 -2
- package/dist/index.js +1 -1
- package/dist/params/index.js +1 -1
- package/dist/segment-params/define.d.ts +0 -6
- package/dist/segment-params/define.d.ts.map +1 -1
- package/dist/segment-params/index.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/internal.js +3 -3
- package/package.json +6 -7
- package/src/cli.ts +0 -0
- package/src/client/browser-entry/action-dispatch.ts +9 -10
- package/src/client/browser-entry/post-hydration.ts +12 -6
- package/src/client/index.ts +1 -5
- package/src/client/link.tsx +25 -12
- package/src/client/router.ts +74 -25
- package/src/client/rsc-fetch.ts +20 -5
- package/src/client/shallow-url.ts +22 -0
- package/src/segment-params/define.ts +2 -29
- package/dist/_chunks/define-CPVQaWbx.js.map +0 -1
package/dist/client/internal.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t as bindUseQueryStates } from "../_chunks/use-query-states-C9G6LP0F.js";
|
|
2
|
-
import { c as cachedSearchParams, i as _setCachedSearch, n as getSsrData, r as setSsrData, s as cachedSearch, t as clearSsrData } from "../_chunks/ssr-data-
|
|
3
|
-
import {
|
|
2
|
+
import { c as cachedSearchParams, i as _setCachedSearch, n as getSsrData, r as setSsrData, s as cachedSearch, t as clearSsrData } from "../_chunks/ssr-data-DVX8S7vj.js";
|
|
3
|
+
import { a as setNavigationState, i as getNavigationState, r as NavigationProvider, t as setCurrentParams } from "../_chunks/use-segment-params-Du7u25cK.js";
|
|
4
|
+
import { n as getRouterOrNull, r as setGlobalRouter, t as getRouter } from "../_chunks/router-ref-B2-2kIIC.js";
|
|
4
5
|
import { TimberErrorBoundary } from "./error-boundary.js";
|
|
5
|
-
import { n as useSegmentContext, t as SegmentProvider } from "../_chunks/segment-context-
|
|
6
|
-
import { t as setHardNavigating } from "../_chunks/navigation-root-
|
|
7
|
-
import { a as getNavigationState, i as NavigationProvider, o as setNavigationState, t as setCurrentParams } from "../_chunks/use-segment-params-CtIAjqK0.js";
|
|
6
|
+
import { n as useSegmentContext, t as SegmentProvider } from "../_chunks/segment-context-Bg0pFbLT.js";
|
|
7
|
+
import { t as setHardNavigating } from "../_chunks/navigation-root-Ds_hDtRW.js";
|
|
8
8
|
import { cloneElement, isValidElement, useSyncExternalStore } from "react";
|
|
9
9
|
//#region src/client/segment-cache.ts
|
|
10
10
|
/**
|
|
@@ -558,8 +558,12 @@ async function fetchRscPayload(url, deps, stateTree, currentUrl, signal) {
|
|
|
558
558
|
return response;
|
|
559
559
|
});
|
|
560
560
|
await wrappedPromise;
|
|
561
|
+
const payload = deps.decodeRsc(wrappedPromise);
|
|
562
|
+
const decodePromise = Promise.resolve(payload).then(() => void 0);
|
|
563
|
+
decodePromise.catch(() => {});
|
|
561
564
|
return {
|
|
562
|
-
payload
|
|
565
|
+
payload,
|
|
566
|
+
decodePromise,
|
|
563
567
|
headElements,
|
|
564
568
|
segmentInfo,
|
|
565
569
|
params,
|
|
@@ -577,6 +581,7 @@ async function fetchRscPayload(url, deps, stateTree, currentUrl, signal) {
|
|
|
577
581
|
}
|
|
578
582
|
return {
|
|
579
583
|
payload: await response.text(),
|
|
584
|
+
decodePromise: null,
|
|
580
585
|
headElements: extractHeadElements(response),
|
|
581
586
|
segmentInfo: extractSegmentInfo(response),
|
|
582
587
|
params: extractParams(response),
|
|
@@ -600,6 +605,7 @@ function createRouter(deps) {
|
|
|
600
605
|
const historyStack = new HistoryStack();
|
|
601
606
|
const segmentElementCache = new SegmentElementCache();
|
|
602
607
|
let routerPhase = { phase: "idle" };
|
|
608
|
+
let navigationId = 0;
|
|
603
609
|
const pendingListeners = /* @__PURE__ */ new Set();
|
|
604
610
|
let currentNavAbort = null;
|
|
605
611
|
/**
|
|
@@ -636,14 +642,29 @@ function createRouter(deps) {
|
|
|
636
642
|
}
|
|
637
643
|
/**
|
|
638
644
|
* Merge a partial RSC payload with cached segment elements if segments
|
|
639
|
-
* were skipped
|
|
640
|
-
*
|
|
645
|
+
* were skipped. Returns the merged payload ready for rendering.
|
|
646
|
+
*
|
|
647
|
+
* Segment element caching is deferred to after paint by the caller
|
|
648
|
+
* so it doesn't block the render path.
|
|
649
|
+
*/
|
|
650
|
+
async function mergePayload(payload, skippedSegments) {
|
|
651
|
+
if (skippedSegments && skippedSegments.length > 0) return mergeSegmentTree(payload != null && typeof payload === "object" && "then" in payload ? await payload : payload, skippedSegments, segmentElementCache);
|
|
652
|
+
return payload;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Schedule segment element caching after paint. Resolves thenable
|
|
656
|
+
* payloads first since tree walking requires resolved React elements.
|
|
657
|
+
* Guards against stale writes: if a newer navigation started before
|
|
658
|
+
* this callback fires, the cache write is skipped.
|
|
641
659
|
*/
|
|
642
|
-
function
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
660
|
+
function deferSegmentCaching(payload) {
|
|
661
|
+
const capturedNavId = navigationId;
|
|
662
|
+
afterPaint(async () => {
|
|
663
|
+
if (capturedNavId !== navigationId) return;
|
|
664
|
+
const resolved = payload != null && typeof payload === "object" && "then" in payload ? await payload : payload;
|
|
665
|
+
if (capturedNavId !== navigationId) return;
|
|
666
|
+
cacheSegmentElements(resolved, segmentElementCache);
|
|
667
|
+
});
|
|
647
668
|
}
|
|
648
669
|
/**
|
|
649
670
|
* Update navigation state (params + pathname) for the next render.
|
|
@@ -663,37 +684,41 @@ function createRouter(deps) {
|
|
|
663
684
|
setNavigationState(navState);
|
|
664
685
|
return navState;
|
|
665
686
|
}
|
|
666
|
-
/**
|
|
667
|
-
* Render a payload via navigateTransition (production) or renderRoot (tests).
|
|
668
|
-
* The perform callback should fetch data, update state, and return the
|
|
669
|
-
* FetchResult plus the NavigationState (so it can be passed explicitly
|
|
670
|
-
* to wrapPayload/renderRoot without temporal coupling).
|
|
671
|
-
*/
|
|
672
687
|
async function renderViaTransition(url, perform) {
|
|
673
688
|
if (deps.navigateTransition) {
|
|
674
689
|
let headElements = null;
|
|
690
|
+
let decodePromise = null;
|
|
675
691
|
await deps.navigateTransition(url, async (wrapPayload) => {
|
|
676
692
|
const result = await perform();
|
|
677
693
|
headElements = result.headElements;
|
|
678
|
-
|
|
694
|
+
decodePromise = result.decodePromise;
|
|
695
|
+
const merged = await mergePayload(result.payload, result.skippedSegments);
|
|
679
696
|
historyStack.push(url, {
|
|
680
697
|
payload: merged,
|
|
681
698
|
headElements: result.headElements,
|
|
682
699
|
params: result.params
|
|
683
700
|
});
|
|
701
|
+
deferSegmentCaching(merged);
|
|
684
702
|
return wrapPayload(merged, result.navState);
|
|
685
703
|
});
|
|
686
|
-
return
|
|
704
|
+
return {
|
|
705
|
+
headElements,
|
|
706
|
+
decodePromise
|
|
707
|
+
};
|
|
687
708
|
}
|
|
688
709
|
const result = await perform();
|
|
689
|
-
const merged =
|
|
710
|
+
const merged = await mergePayload(result.payload, result.skippedSegments);
|
|
690
711
|
historyStack.push(url, {
|
|
691
712
|
payload: merged,
|
|
692
713
|
headElements: result.headElements,
|
|
693
714
|
params: result.params
|
|
694
715
|
});
|
|
716
|
+
deferSegmentCaching(merged);
|
|
695
717
|
renderPayload(merged, result.navState);
|
|
696
|
-
return
|
|
718
|
+
return {
|
|
719
|
+
headElements: result.headElements,
|
|
720
|
+
decodePromise: result.decodePromise
|
|
721
|
+
};
|
|
697
722
|
}
|
|
698
723
|
/** Apply head elements (title, meta tags) to the DOM if available. */
|
|
699
724
|
function applyHead(elements) {
|
|
@@ -722,6 +747,7 @@ function createRouter(deps) {
|
|
|
722
747
|
const prefetched = prefetchCache.consume(url);
|
|
723
748
|
let result = prefetched ? {
|
|
724
749
|
payload: prefetched.payload,
|
|
750
|
+
decodePromise: null,
|
|
725
751
|
headElements: prefetched.headElements,
|
|
726
752
|
segmentInfo: prefetched.segmentInfo ?? null,
|
|
727
753
|
params: prefetched.params ?? null,
|
|
@@ -756,6 +782,7 @@ function createRouter(deps) {
|
|
|
756
782
|
const replace = options.replace === true;
|
|
757
783
|
const externalSignal = options._signal;
|
|
758
784
|
const skipHistory = options._skipHistory === true;
|
|
785
|
+
navigationId++;
|
|
759
786
|
const navAbort = createNavAbort(externalSignal);
|
|
760
787
|
const currentScrollY = deps.getScrollY();
|
|
761
788
|
if (deps.saveNavigationEntryScroll) deps.saveNavigationEntryScroll(currentScrollY);
|
|
@@ -772,11 +799,13 @@ function createRouter(deps) {
|
|
|
772
799
|
}
|
|
773
800
|
setPending(true, url);
|
|
774
801
|
try {
|
|
775
|
-
|
|
802
|
+
const { headElements, decodePromise } = await renderViaTransition(url, () => performNavigationFetch(url, {
|
|
776
803
|
replace,
|
|
777
804
|
signal: navAbort.signal,
|
|
778
805
|
skipHistory: effectiveSkipHistory
|
|
779
|
-
}))
|
|
806
|
+
}));
|
|
807
|
+
if (decodePromise) await decodePromise;
|
|
808
|
+
applyHead(headElements);
|
|
780
809
|
window.dispatchEvent(new Event("timber:navigation-end"));
|
|
781
810
|
restoreScrollAfterPaint(scroll ? 0 : currentScrollY);
|
|
782
811
|
} catch (error) {
|
|
@@ -807,10 +836,11 @@ function createRouter(deps) {
|
|
|
807
836
|
}
|
|
808
837
|
async function refresh() {
|
|
809
838
|
const currentUrl = deps.getCurrentUrl();
|
|
839
|
+
navigationId++;
|
|
810
840
|
const navAbort = createNavAbort();
|
|
811
841
|
setPending(true, currentUrl);
|
|
812
842
|
try {
|
|
813
|
-
|
|
843
|
+
const { headElements, decodePromise } = await renderViaTransition(currentUrl, async () => {
|
|
814
844
|
const result = await fetchRscPayload(currentUrl, deps, void 0, void 0, navAbort.signal);
|
|
815
845
|
updateSegmentCache(result.segmentInfo);
|
|
816
846
|
const navState = updateNavigationState(result.params, currentUrl);
|
|
@@ -818,7 +848,9 @@ function createRouter(deps) {
|
|
|
818
848
|
...result,
|
|
819
849
|
navState
|
|
820
850
|
};
|
|
821
|
-
})
|
|
851
|
+
});
|
|
852
|
+
if (decodePromise) await decodePromise;
|
|
853
|
+
applyHead(headElements);
|
|
822
854
|
} catch (error) {
|
|
823
855
|
if (isAbortError(error)) return;
|
|
824
856
|
throw error;
|
|
@@ -829,6 +861,7 @@ function createRouter(deps) {
|
|
|
829
861
|
}
|
|
830
862
|
}
|
|
831
863
|
async function handlePopState(url, scrollY = 0, externalSignal) {
|
|
864
|
+
navigationId++;
|
|
832
865
|
const entry = historyStack.get(url);
|
|
833
866
|
if (entry && entry.payload !== null) {
|
|
834
867
|
const navState = updateNavigationState(entry.params, url);
|
|
@@ -839,7 +872,7 @@ function createRouter(deps) {
|
|
|
839
872
|
const navAbort = createNavAbort(externalSignal);
|
|
840
873
|
setPending(true, url);
|
|
841
874
|
try {
|
|
842
|
-
|
|
875
|
+
const { headElements, decodePromise } = await renderViaTransition(url, async () => {
|
|
843
876
|
const result = await fetchRscPayload(url, deps, segmentCache.serializeStateTree(segmentElementCache.getMergeablePaths()), void 0, navAbort.signal);
|
|
844
877
|
updateSegmentCache(result.segmentInfo);
|
|
845
878
|
const navState = updateNavigationState(result.params, url);
|
|
@@ -847,7 +880,9 @@ function createRouter(deps) {
|
|
|
847
880
|
...result,
|
|
848
881
|
navState
|
|
849
882
|
};
|
|
850
|
-
})
|
|
883
|
+
});
|
|
884
|
+
if (decodePromise) await decodePromise;
|
|
885
|
+
applyHead(headElements);
|
|
851
886
|
restoreScrollAfterPaint(scrollY);
|
|
852
887
|
} catch (error) {
|
|
853
888
|
if (isAbortError(error)) return;
|
|
@@ -882,12 +917,12 @@ function createRouter(deps) {
|
|
|
882
917
|
prefetch,
|
|
883
918
|
applyRevalidation(element, headElements) {
|
|
884
919
|
const currentUrl = deps.getCurrentUrl();
|
|
885
|
-
const merged = mergeAndCachePayload(element, null);
|
|
886
920
|
historyStack.push(currentUrl, {
|
|
887
|
-
payload:
|
|
921
|
+
payload: element,
|
|
888
922
|
headElements
|
|
889
923
|
});
|
|
890
|
-
|
|
924
|
+
deferSegmentCaching(element);
|
|
925
|
+
renderPayload(element, getNavigationState());
|
|
891
926
|
applyHead(headElements);
|
|
892
927
|
},
|
|
893
928
|
initSegmentCache: (segments) => updateSegmentCache(segments),
|