@tanstack/router-core 1.168.8 → 1.168.10
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/cjs/hash-scroll.cjs +1 -1
- package/dist/cjs/hash-scroll.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/load-matches.cjs +4 -4
- package/dist/cjs/load-matches.cjs.map +1 -1
- package/dist/cjs/router.cjs +44 -45
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +3 -1
- package/dist/cjs/scroll-restoration.cjs +1 -1
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.cjs +2 -2
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/RawStream.cjs +41 -32
- package/dist/cjs/ssr/serializer/RawStream.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/RawStream.d.cts +12 -4
- package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/ShallowErrorPlugin.d.cts +2 -2
- package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -1
- package/dist/cjs/ssr/serializer/transformer.cjs +16 -14
- package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/transformer.d.cts +24 -23
- package/dist/cjs/ssr/ssr-client.cjs +8 -8
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.cjs +31 -9
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.d.cts +3 -2
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +4 -1
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
- package/dist/cjs/stores.cjs +27 -27
- package/dist/cjs/stores.cjs.map +1 -1
- package/dist/cjs/stores.d.cts +2 -2
- package/dist/esm/hash-scroll.js +1 -1
- package/dist/esm/hash-scroll.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/load-matches.js +4 -4
- package/dist/esm/load-matches.js.map +1 -1
- package/dist/esm/router.d.ts +3 -1
- package/dist/esm/router.js +44 -45
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js +1 -1
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/createRequestHandler.js +2 -2
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/serializer/RawStream.d.ts +12 -4
- package/dist/esm/ssr/serializer/RawStream.js +41 -32
- package/dist/esm/ssr/serializer/RawStream.js.map +1 -1
- package/dist/esm/ssr/serializer/ShallowErrorPlugin.d.ts +2 -2
- package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -1
- package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -1
- package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -1
- package/dist/esm/ssr/serializer/transformer.d.ts +24 -23
- package/dist/esm/ssr/serializer/transformer.js +16 -14
- package/dist/esm/ssr/serializer/transformer.js.map +1 -1
- package/dist/esm/ssr/ssr-client.js +8 -8
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.d.ts +3 -2
- package/dist/esm/ssr/ssr-server.js +31 -9
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/transformStreamWithRouter.js +4 -1
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
- package/dist/esm/stores.d.ts +2 -2
- package/dist/esm/stores.js +28 -28
- package/dist/esm/stores.js.map +1 -1
- package/package.json +3 -3
- package/src/hash-scroll.ts +1 -1
- package/src/index.ts +1 -1
- package/src/load-matches.ts +6 -6
- package/src/router.ts +59 -57
- package/src/scroll-restoration.ts +1 -1
- package/src/ssr/createRequestHandler.ts +4 -5
- package/src/ssr/serializer/RawStream.ts +65 -56
- package/src/ssr/serializer/ShallowErrorPlugin.ts +2 -2
- package/src/ssr/serializer/seroval-plugins.ts +2 -1
- package/src/ssr/serializer/transformer.ts +71 -76
- package/src/ssr/ssr-client.ts +7 -11
- package/src/ssr/ssr-server.ts +39 -7
- package/src/ssr/transformStreamWithRouter.ts +3 -0
- package/src/stores.ts +34 -34
package/dist/esm/stores.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { arraysEqual } from "./utils.js";
|
|
1
|
+
import { arraysEqual, functionalUpdate } from "./utils.js";
|
|
2
2
|
import { createLRUCache } from "./lru-cache.js";
|
|
3
3
|
//#region src/stores.ts
|
|
4
4
|
/** SSR non-reactive createMutableStore */
|
|
5
5
|
function createNonReactiveMutableStore(initialValue) {
|
|
6
6
|
let value = initialValue;
|
|
7
7
|
return {
|
|
8
|
-
get
|
|
8
|
+
get() {
|
|
9
9
|
return value;
|
|
10
10
|
},
|
|
11
|
-
|
|
12
|
-
value =
|
|
11
|
+
set(nextOrUpdater) {
|
|
12
|
+
value = functionalUpdate(nextOrUpdater, value);
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
/** SSR non-reactive createReadonlyStore */
|
|
17
17
|
function createNonReactiveReadonlyStore(read) {
|
|
18
|
-
return { get
|
|
18
|
+
return { get() {
|
|
19
19
|
return read();
|
|
20
20
|
} };
|
|
21
21
|
}
|
|
@@ -35,38 +35,38 @@ function createRouterStores(initialState, config) {
|
|
|
35
35
|
const matchesId = createMutableStore([]);
|
|
36
36
|
const pendingMatchesId = createMutableStore([]);
|
|
37
37
|
const cachedMatchesId = createMutableStore([]);
|
|
38
|
-
const activeMatchesSnapshot = createReadonlyStore(() => readPoolMatches(activeMatchStoresById, matchesId.
|
|
39
|
-
const pendingMatchesSnapshot = createReadonlyStore(() => readPoolMatches(pendingMatchStoresById, pendingMatchesId.
|
|
40
|
-
const cachedMatchesSnapshot = createReadonlyStore(() => readPoolMatches(cachedMatchStoresById, cachedMatchesId.
|
|
41
|
-
const firstMatchId = createReadonlyStore(() => matchesId.
|
|
42
|
-
const hasPendingMatches = createReadonlyStore(() => matchesId.
|
|
43
|
-
return activeMatchStoresById.get(matchId)?.
|
|
38
|
+
const activeMatchesSnapshot = createReadonlyStore(() => readPoolMatches(activeMatchStoresById, matchesId.get()));
|
|
39
|
+
const pendingMatchesSnapshot = createReadonlyStore(() => readPoolMatches(pendingMatchStoresById, pendingMatchesId.get()));
|
|
40
|
+
const cachedMatchesSnapshot = createReadonlyStore(() => readPoolMatches(cachedMatchStoresById, cachedMatchesId.get()));
|
|
41
|
+
const firstMatchId = createReadonlyStore(() => matchesId.get()[0]);
|
|
42
|
+
const hasPendingMatches = createReadonlyStore(() => matchesId.get().some((matchId) => {
|
|
43
|
+
return activeMatchStoresById.get(matchId)?.get().status === "pending";
|
|
44
44
|
}));
|
|
45
45
|
const matchRouteReactivity = createReadonlyStore(() => ({
|
|
46
|
-
locationHref: location.
|
|
47
|
-
resolvedLocationHref: resolvedLocation.
|
|
48
|
-
status: status.
|
|
46
|
+
locationHref: location.get().href,
|
|
47
|
+
resolvedLocationHref: resolvedLocation.get()?.href,
|
|
48
|
+
status: status.get()
|
|
49
49
|
}));
|
|
50
50
|
const __store = createReadonlyStore(() => ({
|
|
51
|
-
status: status.
|
|
52
|
-
loadedAt: loadedAt.
|
|
53
|
-
isLoading: isLoading.
|
|
54
|
-
isTransitioning: isTransitioning.
|
|
55
|
-
matches: activeMatchesSnapshot.
|
|
56
|
-
location: location.
|
|
57
|
-
resolvedLocation: resolvedLocation.
|
|
58
|
-
statusCode: statusCode.
|
|
59
|
-
redirect: redirect.
|
|
51
|
+
status: status.get(),
|
|
52
|
+
loadedAt: loadedAt.get(),
|
|
53
|
+
isLoading: isLoading.get(),
|
|
54
|
+
isTransitioning: isTransitioning.get(),
|
|
55
|
+
matches: activeMatchesSnapshot.get(),
|
|
56
|
+
location: location.get(),
|
|
57
|
+
resolvedLocation: resolvedLocation.get(),
|
|
58
|
+
statusCode: statusCode.get(),
|
|
59
|
+
redirect: redirect.get()
|
|
60
60
|
}));
|
|
61
61
|
const matchStoreByRouteIdCache = createLRUCache(64);
|
|
62
62
|
function getMatchStoreByRouteId(routeId) {
|
|
63
63
|
let cached = matchStoreByRouteIdCache.get(routeId);
|
|
64
64
|
if (!cached) {
|
|
65
65
|
cached = createReadonlyStore(() => {
|
|
66
|
-
const ids = matchesId.
|
|
66
|
+
const ids = matchesId.get();
|
|
67
67
|
for (const id of ids) {
|
|
68
68
|
const matchStore = activeMatchStoresById.get(id);
|
|
69
|
-
if (matchStore && matchStore.routeId === routeId) return matchStore.
|
|
69
|
+
if (matchStore && matchStore.routeId === routeId) return matchStore.get();
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
matchStoreByRouteIdCache.set(routeId, cached);
|
|
@@ -117,7 +117,7 @@ function readPoolMatches(pool, ids) {
|
|
|
117
117
|
const matches = [];
|
|
118
118
|
for (const id of ids) {
|
|
119
119
|
const matchStore = pool.get(id);
|
|
120
|
-
if (matchStore) matches.push(matchStore.
|
|
120
|
+
if (matchStore) matches.push(matchStore.get());
|
|
121
121
|
}
|
|
122
122
|
return matches;
|
|
123
123
|
}
|
|
@@ -135,9 +135,9 @@ function reconcileMatchPool(nextMatches, pool, idStore, createMutableStore, batc
|
|
|
135
135
|
continue;
|
|
136
136
|
}
|
|
137
137
|
existing.routeId = nextMatch.routeId;
|
|
138
|
-
if (existing.
|
|
138
|
+
if (existing.get() !== nextMatch) existing.set(nextMatch);
|
|
139
139
|
}
|
|
140
|
-
if (!arraysEqual(idStore.
|
|
140
|
+
if (!arraysEqual(idStore.get(), nextIds)) idStore.set(nextIds);
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
//#endregion
|
package/dist/esm/stores.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stores.js","names":[],"sources":["../../src/stores.ts"],"sourcesContent":["import { createLRUCache } from './lru-cache'\nimport { arraysEqual } from './utils'\n\nimport type { AnyRoute } from './route'\nimport type { RouterState } from './router'\nimport type { FullSearchSchema } from './routeInfo'\nimport type { ParsedLocation } from './location'\nimport type { AnyRedirect } from './redirect'\nimport type { AnyRouteMatch } from './Matches'\n\nexport interface RouterReadableStore<TValue> {\n readonly state: TValue\n}\n\nexport interface RouterWritableStore<\n TValue,\n> extends RouterReadableStore<TValue> {\n setState: (updater: (prev: TValue) => TValue) => void\n}\n\nexport type RouterBatchFn = (fn: () => void) => void\n\nexport type MutableStoreFactory = <TValue>(\n initialValue: TValue,\n) => RouterWritableStore<TValue>\n\nexport type ReadonlyStoreFactory = <TValue>(\n read: () => TValue,\n) => RouterReadableStore<TValue>\n\nexport type GetStoreConfig = (opts: { isServer?: boolean }) => StoreConfig\n\nexport type StoreConfig = {\n createMutableStore: MutableStoreFactory\n createReadonlyStore: ReadonlyStoreFactory\n batch: RouterBatchFn\n init?: (stores: RouterStores<AnyRoute>) => void\n}\n\ntype MatchStore = RouterWritableStore<AnyRouteMatch> & {\n routeId?: string\n}\ntype ReadableStore<TValue> = RouterReadableStore<TValue>\n\n/** SSR non-reactive createMutableStore */\nexport function createNonReactiveMutableStore<TValue>(\n initialValue: TValue,\n): RouterWritableStore<TValue> {\n let value = initialValue\n\n return {\n get state() {\n return value\n },\n setState(updater: (prev: TValue) => TValue) {\n value = updater(value)\n },\n }\n}\n\n/** SSR non-reactive createReadonlyStore */\nexport function createNonReactiveReadonlyStore<TValue>(\n read: () => TValue,\n): RouterReadableStore<TValue> {\n return {\n get state() {\n return read()\n },\n }\n}\n\nexport interface RouterStores<in out TRouteTree extends AnyRoute> {\n status: RouterWritableStore<RouterState<TRouteTree>['status']>\n loadedAt: RouterWritableStore<number>\n isLoading: RouterWritableStore<boolean>\n isTransitioning: RouterWritableStore<boolean>\n location: RouterWritableStore<ParsedLocation<FullSearchSchema<TRouteTree>>>\n resolvedLocation: RouterWritableStore<\n ParsedLocation<FullSearchSchema<TRouteTree>> | undefined\n >\n statusCode: RouterWritableStore<number>\n redirect: RouterWritableStore<AnyRedirect | undefined>\n matchesId: RouterWritableStore<Array<string>>\n pendingMatchesId: RouterWritableStore<Array<string>>\n /** @internal */\n cachedMatchesId: RouterWritableStore<Array<string>>\n activeMatchesSnapshot: ReadableStore<Array<AnyRouteMatch>>\n pendingMatchesSnapshot: ReadableStore<Array<AnyRouteMatch>>\n cachedMatchesSnapshot: ReadableStore<Array<AnyRouteMatch>>\n firstMatchId: ReadableStore<string | undefined>\n hasPendingMatches: ReadableStore<boolean>\n matchRouteReactivity: ReadableStore<{\n locationHref: string\n resolvedLocationHref: string | undefined\n status: RouterState<TRouteTree>['status']\n }>\n __store: RouterReadableStore<RouterState<TRouteTree>>\n\n activeMatchStoresById: Map<string, MatchStore>\n pendingMatchStoresById: Map<string, MatchStore>\n cachedMatchStoresById: Map<string, MatchStore>\n\n /**\n * Get a computed store that resolves a routeId to its current match state.\n * Returns the same cached store instance for repeated calls with the same key.\n * The computed depends on matchesId + the individual match store, so\n * subscribers are only notified when the resolved match state changes.\n */\n getMatchStoreByRouteId: (\n routeId: string,\n ) => RouterReadableStore<AnyRouteMatch | undefined>\n\n setActiveMatches: (nextMatches: Array<AnyRouteMatch>) => void\n setPendingMatches: (nextMatches: Array<AnyRouteMatch>) => void\n setCachedMatches: (nextMatches: Array<AnyRouteMatch>) => void\n}\n\nexport function createRouterStores<TRouteTree extends AnyRoute>(\n initialState: RouterState<TRouteTree>,\n config: StoreConfig,\n): RouterStores<TRouteTree> {\n const { createMutableStore, createReadonlyStore, batch, init } = config\n\n // non reactive utilities\n const activeMatchStoresById = new Map<string, MatchStore>()\n const pendingMatchStoresById = new Map<string, MatchStore>()\n const cachedMatchStoresById = new Map<string, MatchStore>()\n\n // atoms\n const status = createMutableStore(initialState.status)\n const loadedAt = createMutableStore(initialState.loadedAt)\n const isLoading = createMutableStore(initialState.isLoading)\n const isTransitioning = createMutableStore(initialState.isTransitioning)\n const location = createMutableStore(initialState.location)\n const resolvedLocation = createMutableStore(initialState.resolvedLocation)\n const statusCode = createMutableStore(initialState.statusCode)\n const redirect = createMutableStore(initialState.redirect)\n const matchesId = createMutableStore<Array<string>>([])\n const pendingMatchesId = createMutableStore<Array<string>>([])\n const cachedMatchesId = createMutableStore<Array<string>>([])\n\n // 1st order derived stores\n const activeMatchesSnapshot = createReadonlyStore(() =>\n readPoolMatches(activeMatchStoresById, matchesId.state),\n )\n const pendingMatchesSnapshot = createReadonlyStore(() =>\n readPoolMatches(pendingMatchStoresById, pendingMatchesId.state),\n )\n const cachedMatchesSnapshot = createReadonlyStore(() =>\n readPoolMatches(cachedMatchStoresById, cachedMatchesId.state),\n )\n const firstMatchId = createReadonlyStore(() => matchesId.state[0])\n const hasPendingMatches = createReadonlyStore(() =>\n matchesId.state.some((matchId) => {\n const store = activeMatchStoresById.get(matchId)\n return store?.state.status === 'pending'\n }),\n )\n const matchRouteReactivity = createReadonlyStore(() => ({\n locationHref: location.state.href,\n resolvedLocationHref: resolvedLocation.state?.href,\n status: status.state,\n }))\n\n // compatibility \"big\" state store\n const __store = createReadonlyStore(() => ({\n status: status.state,\n loadedAt: loadedAt.state,\n isLoading: isLoading.state,\n isTransitioning: isTransitioning.state,\n matches: activeMatchesSnapshot.state,\n location: location.state,\n resolvedLocation: resolvedLocation.state,\n statusCode: statusCode.state,\n redirect: redirect.state,\n }))\n\n // Per-routeId computed store cache.\n // Each entry resolves routeId → match state through the signal graph,\n // giving consumers a single store to subscribe to instead of the\n // two-level byRouteId → matchStore pattern.\n //\n // 64 max size is arbitrary, this is only for active matches anyway so\n // it should be plenty. And we already have a 32 limit due to route\n // matching bitmask anyway.\n const matchStoreByRouteIdCache = createLRUCache<\n string,\n RouterReadableStore<AnyRouteMatch | undefined>\n >(64)\n\n function getMatchStoreByRouteId(\n routeId: string,\n ): RouterReadableStore<AnyRouteMatch | undefined> {\n let cached = matchStoreByRouteIdCache.get(routeId)\n if (!cached) {\n cached = createReadonlyStore(() => {\n // Reading matchesId.state tracks it as a dependency.\n // When matchesId changes (navigation), this computed re-evaluates.\n const ids = matchesId.state\n for (const id of ids) {\n const matchStore = activeMatchStoresById.get(id)\n if (matchStore && matchStore.routeId === routeId) {\n // Reading matchStore.state tracks it as a dependency.\n // When the match store's state changes, this re-evaluates.\n return matchStore.state\n }\n }\n return undefined\n })\n matchStoreByRouteIdCache.set(routeId, cached)\n }\n return cached\n }\n\n const store = {\n // atoms\n status,\n loadedAt,\n isLoading,\n isTransitioning,\n location,\n resolvedLocation,\n statusCode,\n redirect,\n matchesId,\n pendingMatchesId,\n cachedMatchesId,\n\n // derived\n activeMatchesSnapshot,\n pendingMatchesSnapshot,\n cachedMatchesSnapshot,\n firstMatchId,\n hasPendingMatches,\n matchRouteReactivity,\n\n // non-reactive state\n activeMatchStoresById,\n pendingMatchStoresById,\n cachedMatchStoresById,\n\n // compatibility \"big\" state\n __store,\n\n // per-key computed stores\n getMatchStoreByRouteId,\n\n // methods\n setActiveMatches,\n setPendingMatches,\n setCachedMatches,\n }\n\n // initialize the active matches\n setActiveMatches(initialState.matches as Array<AnyRouteMatch>)\n init?.(store)\n\n // setters to update non-reactive utilities in sync with the reactive stores\n function setActiveMatches(nextMatches: Array<AnyRouteMatch>) {\n reconcileMatchPool(\n nextMatches,\n activeMatchStoresById,\n matchesId,\n createMutableStore,\n batch,\n )\n }\n\n function setPendingMatches(nextMatches: Array<AnyRouteMatch>) {\n reconcileMatchPool(\n nextMatches,\n pendingMatchStoresById,\n pendingMatchesId,\n createMutableStore,\n batch,\n )\n }\n\n function setCachedMatches(nextMatches: Array<AnyRouteMatch>) {\n reconcileMatchPool(\n nextMatches,\n cachedMatchStoresById,\n cachedMatchesId,\n createMutableStore,\n batch,\n )\n }\n\n return store\n}\n\nfunction readPoolMatches(\n pool: Map<string, MatchStore>,\n ids: Array<string>,\n): Array<AnyRouteMatch> {\n const matches: Array<AnyRouteMatch> = []\n for (const id of ids) {\n const matchStore = pool.get(id)\n if (matchStore) {\n matches.push(matchStore.state)\n }\n }\n return matches\n}\n\nfunction reconcileMatchPool(\n nextMatches: Array<AnyRouteMatch>,\n pool: Map<string, MatchStore>,\n idStore: RouterWritableStore<Array<string>>,\n createMutableStore: MutableStoreFactory,\n batch: RouterBatchFn,\n): void {\n const nextIds = nextMatches.map((d) => d.id)\n const nextIdSet = new Set(nextIds)\n\n batch(() => {\n for (const id of pool.keys()) {\n if (!nextIdSet.has(id)) {\n pool.delete(id)\n }\n }\n\n for (const nextMatch of nextMatches) {\n const existing = pool.get(nextMatch.id)\n if (!existing) {\n const matchStore = createMutableStore(nextMatch) as MatchStore\n matchStore.routeId = nextMatch.routeId\n pool.set(nextMatch.id, matchStore)\n continue\n }\n\n existing.routeId = nextMatch.routeId\n if (existing.state !== nextMatch) {\n existing.setState(() => nextMatch)\n }\n }\n\n if (!arraysEqual(idStore.state, nextIds)) {\n idStore.setState(() => nextIds)\n }\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stores.js","names":[],"sources":["../../src/stores.ts"],"sourcesContent":["import { createLRUCache } from './lru-cache'\nimport { arraysEqual, functionalUpdate } from './utils'\n\nimport type { AnyRoute } from './route'\nimport type { RouterState } from './router'\nimport type { FullSearchSchema } from './routeInfo'\nimport type { ParsedLocation } from './location'\nimport type { AnyRedirect } from './redirect'\nimport type { AnyRouteMatch } from './Matches'\n\nexport interface RouterReadableStore<TValue> {\n get: () => TValue\n}\n\nexport interface RouterWritableStore<\n TValue,\n> extends RouterReadableStore<TValue> {\n set: ((updater: (prev: TValue) => TValue) => void) & ((value: TValue) => void)\n}\n\nexport type RouterBatchFn = (fn: () => void) => void\n\nexport type MutableStoreFactory = <TValue>(\n initialValue: TValue,\n) => RouterWritableStore<TValue>\n\nexport type ReadonlyStoreFactory = <TValue>(\n read: () => TValue,\n) => RouterReadableStore<TValue>\n\nexport type GetStoreConfig = (opts: { isServer?: boolean }) => StoreConfig\n\nexport type StoreConfig = {\n createMutableStore: MutableStoreFactory\n createReadonlyStore: ReadonlyStoreFactory\n batch: RouterBatchFn\n init?: (stores: RouterStores<AnyRoute>) => void\n}\n\ntype MatchStore = RouterWritableStore<AnyRouteMatch> & {\n routeId?: string\n}\ntype ReadableStore<TValue> = RouterReadableStore<TValue>\n\n/** SSR non-reactive createMutableStore */\nexport function createNonReactiveMutableStore<TValue>(\n initialValue: TValue,\n): RouterWritableStore<TValue> {\n let value = initialValue\n\n return {\n get() {\n return value\n },\n set(nextOrUpdater: TValue | ((prev: TValue) => TValue)) {\n value = functionalUpdate(nextOrUpdater, value)\n },\n }\n}\n\n/** SSR non-reactive createReadonlyStore */\nexport function createNonReactiveReadonlyStore<TValue>(\n read: () => TValue,\n): RouterReadableStore<TValue> {\n return {\n get() {\n return read()\n },\n }\n}\n\nexport interface RouterStores<in out TRouteTree extends AnyRoute> {\n status: RouterWritableStore<RouterState<TRouteTree>['status']>\n loadedAt: RouterWritableStore<number>\n isLoading: RouterWritableStore<boolean>\n isTransitioning: RouterWritableStore<boolean>\n location: RouterWritableStore<ParsedLocation<FullSearchSchema<TRouteTree>>>\n resolvedLocation: RouterWritableStore<\n ParsedLocation<FullSearchSchema<TRouteTree>> | undefined\n >\n statusCode: RouterWritableStore<number>\n redirect: RouterWritableStore<AnyRedirect | undefined>\n matchesId: RouterWritableStore<Array<string>>\n pendingMatchesId: RouterWritableStore<Array<string>>\n /** @internal */\n cachedMatchesId: RouterWritableStore<Array<string>>\n activeMatchesSnapshot: ReadableStore<Array<AnyRouteMatch>>\n pendingMatchesSnapshot: ReadableStore<Array<AnyRouteMatch>>\n cachedMatchesSnapshot: ReadableStore<Array<AnyRouteMatch>>\n firstMatchId: ReadableStore<string | undefined>\n hasPendingMatches: ReadableStore<boolean>\n matchRouteReactivity: ReadableStore<{\n locationHref: string\n resolvedLocationHref: string | undefined\n status: RouterState<TRouteTree>['status']\n }>\n __store: RouterReadableStore<RouterState<TRouteTree>>\n\n activeMatchStoresById: Map<string, MatchStore>\n pendingMatchStoresById: Map<string, MatchStore>\n cachedMatchStoresById: Map<string, MatchStore>\n\n /**\n * Get a computed store that resolves a routeId to its current match state.\n * Returns the same cached store instance for repeated calls with the same key.\n * The computed depends on matchesId + the individual match store, so\n * subscribers are only notified when the resolved match state changes.\n */\n getMatchStoreByRouteId: (\n routeId: string,\n ) => RouterReadableStore<AnyRouteMatch | undefined>\n\n setActiveMatches: (nextMatches: Array<AnyRouteMatch>) => void\n setPendingMatches: (nextMatches: Array<AnyRouteMatch>) => void\n setCachedMatches: (nextMatches: Array<AnyRouteMatch>) => void\n}\n\nexport function createRouterStores<TRouteTree extends AnyRoute>(\n initialState: RouterState<TRouteTree>,\n config: StoreConfig,\n): RouterStores<TRouteTree> {\n const { createMutableStore, createReadonlyStore, batch, init } = config\n\n // non reactive utilities\n const activeMatchStoresById = new Map<string, MatchStore>()\n const pendingMatchStoresById = new Map<string, MatchStore>()\n const cachedMatchStoresById = new Map<string, MatchStore>()\n\n // atoms\n const status = createMutableStore(initialState.status)\n const loadedAt = createMutableStore(initialState.loadedAt)\n const isLoading = createMutableStore(initialState.isLoading)\n const isTransitioning = createMutableStore(initialState.isTransitioning)\n const location = createMutableStore(initialState.location)\n const resolvedLocation = createMutableStore(initialState.resolvedLocation)\n const statusCode = createMutableStore(initialState.statusCode)\n const redirect = createMutableStore(initialState.redirect)\n const matchesId = createMutableStore<Array<string>>([])\n const pendingMatchesId = createMutableStore<Array<string>>([])\n const cachedMatchesId = createMutableStore<Array<string>>([])\n\n // 1st order derived stores\n const activeMatchesSnapshot = createReadonlyStore(() =>\n readPoolMatches(activeMatchStoresById, matchesId.get()),\n )\n const pendingMatchesSnapshot = createReadonlyStore(() =>\n readPoolMatches(pendingMatchStoresById, pendingMatchesId.get()),\n )\n const cachedMatchesSnapshot = createReadonlyStore(() =>\n readPoolMatches(cachedMatchStoresById, cachedMatchesId.get()),\n )\n const firstMatchId = createReadonlyStore(() => matchesId.get()[0])\n const hasPendingMatches = createReadonlyStore(() =>\n matchesId.get().some((matchId) => {\n const store = activeMatchStoresById.get(matchId)\n return store?.get().status === 'pending'\n }),\n )\n const matchRouteReactivity = createReadonlyStore(() => ({\n locationHref: location.get().href,\n resolvedLocationHref: resolvedLocation.get()?.href,\n status: status.get(),\n }))\n\n // compatibility \"big\" state store\n const __store = createReadonlyStore(() => ({\n status: status.get(),\n loadedAt: loadedAt.get(),\n isLoading: isLoading.get(),\n isTransitioning: isTransitioning.get(),\n matches: activeMatchesSnapshot.get(),\n location: location.get(),\n resolvedLocation: resolvedLocation.get(),\n statusCode: statusCode.get(),\n redirect: redirect.get(),\n }))\n\n // Per-routeId computed store cache.\n // Each entry resolves routeId → match state through the signal graph,\n // giving consumers a single store to subscribe to instead of the\n // two-level byRouteId → matchStore pattern.\n //\n // 64 max size is arbitrary, this is only for active matches anyway so\n // it should be plenty. And we already have a 32 limit due to route\n // matching bitmask anyway.\n const matchStoreByRouteIdCache = createLRUCache<\n string,\n RouterReadableStore<AnyRouteMatch | undefined>\n >(64)\n\n function getMatchStoreByRouteId(\n routeId: string,\n ): RouterReadableStore<AnyRouteMatch | undefined> {\n let cached = matchStoreByRouteIdCache.get(routeId)\n if (!cached) {\n cached = createReadonlyStore(() => {\n // Reading matchesId.get() tracks it as a dependency.\n // When matchesId changes (navigation), this computed re-evaluates.\n const ids = matchesId.get()\n for (const id of ids) {\n const matchStore = activeMatchStoresById.get(id)\n if (matchStore && matchStore.routeId === routeId) {\n // Reading matchStore.get() tracks it as a dependency.\n // When the match store's state changes, this re-evaluates.\n return matchStore.get()\n }\n }\n return undefined\n })\n matchStoreByRouteIdCache.set(routeId, cached)\n }\n return cached\n }\n\n const store = {\n // atoms\n status,\n loadedAt,\n isLoading,\n isTransitioning,\n location,\n resolvedLocation,\n statusCode,\n redirect,\n matchesId,\n pendingMatchesId,\n cachedMatchesId,\n\n // derived\n activeMatchesSnapshot,\n pendingMatchesSnapshot,\n cachedMatchesSnapshot,\n firstMatchId,\n hasPendingMatches,\n matchRouteReactivity,\n\n // non-reactive state\n activeMatchStoresById,\n pendingMatchStoresById,\n cachedMatchStoresById,\n\n // compatibility \"big\" state\n __store,\n\n // per-key computed stores\n getMatchStoreByRouteId,\n\n // methods\n setActiveMatches,\n setPendingMatches,\n setCachedMatches,\n }\n\n // initialize the active matches\n setActiveMatches(initialState.matches as Array<AnyRouteMatch>)\n init?.(store)\n\n // setters to update non-reactive utilities in sync with the reactive stores\n function setActiveMatches(nextMatches: Array<AnyRouteMatch>) {\n reconcileMatchPool(\n nextMatches,\n activeMatchStoresById,\n matchesId,\n createMutableStore,\n batch,\n )\n }\n\n function setPendingMatches(nextMatches: Array<AnyRouteMatch>) {\n reconcileMatchPool(\n nextMatches,\n pendingMatchStoresById,\n pendingMatchesId,\n createMutableStore,\n batch,\n )\n }\n\n function setCachedMatches(nextMatches: Array<AnyRouteMatch>) {\n reconcileMatchPool(\n nextMatches,\n cachedMatchStoresById,\n cachedMatchesId,\n createMutableStore,\n batch,\n )\n }\n\n return store\n}\n\nfunction readPoolMatches(\n pool: Map<string, MatchStore>,\n ids: Array<string>,\n): Array<AnyRouteMatch> {\n const matches: Array<AnyRouteMatch> = []\n for (const id of ids) {\n const matchStore = pool.get(id)\n if (matchStore) {\n matches.push(matchStore.get())\n }\n }\n return matches\n}\n\nfunction reconcileMatchPool(\n nextMatches: Array<AnyRouteMatch>,\n pool: Map<string, MatchStore>,\n idStore: RouterWritableStore<Array<string>>,\n createMutableStore: MutableStoreFactory,\n batch: RouterBatchFn,\n): void {\n const nextIds = nextMatches.map((d) => d.id)\n const nextIdSet = new Set(nextIds)\n\n batch(() => {\n for (const id of pool.keys()) {\n if (!nextIdSet.has(id)) {\n pool.delete(id)\n }\n }\n\n for (const nextMatch of nextMatches) {\n const existing = pool.get(nextMatch.id)\n if (!existing) {\n const matchStore = createMutableStore(nextMatch) as MatchStore\n matchStore.routeId = nextMatch.routeId\n pool.set(nextMatch.id, matchStore)\n continue\n }\n\n existing.routeId = nextMatch.routeId\n if (existing.get() !== nextMatch) {\n existing.set(nextMatch)\n }\n }\n\n if (!arraysEqual(idStore.get(), nextIds)) {\n idStore.set(nextIds)\n }\n })\n}\n"],"mappings":";;;;AA6CA,SAAgB,8BACd,cAC6B;CAC7B,IAAI,QAAQ;AAEZ,QAAO;EACL,MAAM;AACJ,UAAO;;EAET,IAAI,eAAoD;AACtD,WAAQ,iBAAiB,eAAe,MAAM;;EAEjD;;;AAIH,SAAgB,+BACd,MAC6B;AAC7B,QAAO,EACL,MAAM;AACJ,SAAO,MAAM;IAEhB;;AAiDH,SAAgB,mBACd,cACA,QAC0B;CAC1B,MAAM,EAAE,oBAAoB,qBAAqB,OAAO,SAAS;CAGjE,MAAM,wCAAwB,IAAI,KAAyB;CAC3D,MAAM,yCAAyB,IAAI,KAAyB;CAC5D,MAAM,wCAAwB,IAAI,KAAyB;CAG3D,MAAM,SAAS,mBAAmB,aAAa,OAAO;CACtD,MAAM,WAAW,mBAAmB,aAAa,SAAS;CAC1D,MAAM,YAAY,mBAAmB,aAAa,UAAU;CAC5D,MAAM,kBAAkB,mBAAmB,aAAa,gBAAgB;CACxE,MAAM,WAAW,mBAAmB,aAAa,SAAS;CAC1D,MAAM,mBAAmB,mBAAmB,aAAa,iBAAiB;CAC1E,MAAM,aAAa,mBAAmB,aAAa,WAAW;CAC9D,MAAM,WAAW,mBAAmB,aAAa,SAAS;CAC1D,MAAM,YAAY,mBAAkC,EAAE,CAAC;CACvD,MAAM,mBAAmB,mBAAkC,EAAE,CAAC;CAC9D,MAAM,kBAAkB,mBAAkC,EAAE,CAAC;CAG7D,MAAM,wBAAwB,0BAC5B,gBAAgB,uBAAuB,UAAU,KAAK,CAAC,CACxD;CACD,MAAM,yBAAyB,0BAC7B,gBAAgB,wBAAwB,iBAAiB,KAAK,CAAC,CAChE;CACD,MAAM,wBAAwB,0BAC5B,gBAAgB,uBAAuB,gBAAgB,KAAK,CAAC,CAC9D;CACD,MAAM,eAAe,0BAA0B,UAAU,KAAK,CAAC,GAAG;CAClE,MAAM,oBAAoB,0BACxB,UAAU,KAAK,CAAC,MAAM,YAAY;AAEhC,SADc,sBAAsB,IAAI,QAAQ,EAClC,KAAK,CAAC,WAAW;GAC/B,CACH;CACD,MAAM,uBAAuB,2BAA2B;EACtD,cAAc,SAAS,KAAK,CAAC;EAC7B,sBAAsB,iBAAiB,KAAK,EAAE;EAC9C,QAAQ,OAAO,KAAK;EACrB,EAAE;CAGH,MAAM,UAAU,2BAA2B;EACzC,QAAQ,OAAO,KAAK;EACpB,UAAU,SAAS,KAAK;EACxB,WAAW,UAAU,KAAK;EAC1B,iBAAiB,gBAAgB,KAAK;EACtC,SAAS,sBAAsB,KAAK;EACpC,UAAU,SAAS,KAAK;EACxB,kBAAkB,iBAAiB,KAAK;EACxC,YAAY,WAAW,KAAK;EAC5B,UAAU,SAAS,KAAK;EACzB,EAAE;CAUH,MAAM,2BAA2B,eAG/B,GAAG;CAEL,SAAS,uBACP,SACgD;EAChD,IAAI,SAAS,yBAAyB,IAAI,QAAQ;AAClD,MAAI,CAAC,QAAQ;AACX,YAAS,0BAA0B;IAGjC,MAAM,MAAM,UAAU,KAAK;AAC3B,SAAK,MAAM,MAAM,KAAK;KACpB,MAAM,aAAa,sBAAsB,IAAI,GAAG;AAChD,SAAI,cAAc,WAAW,YAAY,QAGvC,QAAO,WAAW,KAAK;;KAI3B;AACF,4BAAyB,IAAI,SAAS,OAAO;;AAE/C,SAAO;;CAGT,MAAM,QAAQ;EAEZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EAGA;EAGA;EACA;EACA;EACD;AAGD,kBAAiB,aAAa,QAAgC;AAC9D,QAAO,MAAM;CAGb,SAAS,iBAAiB,aAAmC;AAC3D,qBACE,aACA,uBACA,WACA,oBACA,MACD;;CAGH,SAAS,kBAAkB,aAAmC;AAC5D,qBACE,aACA,wBACA,kBACA,oBACA,MACD;;CAGH,SAAS,iBAAiB,aAAmC;AAC3D,qBACE,aACA,uBACA,iBACA,oBACA,MACD;;AAGH,QAAO;;AAGT,SAAS,gBACP,MACA,KACsB;CACtB,MAAM,UAAgC,EAAE;AACxC,MAAK,MAAM,MAAM,KAAK;EACpB,MAAM,aAAa,KAAK,IAAI,GAAG;AAC/B,MAAI,WACF,SAAQ,KAAK,WAAW,KAAK,CAAC;;AAGlC,QAAO;;AAGT,SAAS,mBACP,aACA,MACA,SACA,oBACA,OACM;CACN,MAAM,UAAU,YAAY,KAAK,MAAM,EAAE,GAAG;CAC5C,MAAM,YAAY,IAAI,IAAI,QAAQ;AAElC,aAAY;AACV,OAAK,MAAM,MAAM,KAAK,MAAM,CAC1B,KAAI,CAAC,UAAU,IAAI,GAAG,CACpB,MAAK,OAAO,GAAG;AAInB,OAAK,MAAM,aAAa,aAAa;GACnC,MAAM,WAAW,KAAK,IAAI,UAAU,GAAG;AACvC,OAAI,CAAC,UAAU;IACb,MAAM,aAAa,mBAAmB,UAAU;AAChD,eAAW,UAAU,UAAU;AAC/B,SAAK,IAAI,UAAU,IAAI,WAAW;AAClC;;AAGF,YAAS,UAAU,UAAU;AAC7B,OAAI,SAAS,KAAK,KAAK,UACrB,UAAS,IAAI,UAAU;;AAI3B,MAAI,CAAC,YAAY,QAAQ,KAAK,EAAE,QAAQ,CACtC,SAAQ,IAAI,QAAQ;GAEtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-core",
|
|
3
|
-
"version": "1.168.
|
|
3
|
+
"version": "1.168.10",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -168,8 +168,8 @@
|
|
|
168
168
|
},
|
|
169
169
|
"dependencies": {
|
|
170
170
|
"cookie-es": "^2.0.0",
|
|
171
|
-
"seroval": "^1.
|
|
172
|
-
"seroval-plugins": "^1.
|
|
171
|
+
"seroval": "^1.5.0",
|
|
172
|
+
"seroval-plugins": "^1.5.0",
|
|
173
173
|
"@tanstack/history": "1.161.6"
|
|
174
174
|
},
|
|
175
175
|
"devDependencies": {
|
package/src/hash-scroll.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { AnyRouter } from './router'
|
|
|
7
7
|
*/
|
|
8
8
|
export function handleHashScroll(router: AnyRouter) {
|
|
9
9
|
if (typeof document !== 'undefined' && (document as any).querySelector) {
|
|
10
|
-
const location = router.stores.location.
|
|
10
|
+
const location = router.stores.location.get()
|
|
11
11
|
const hashScrollIntoViewOptions =
|
|
12
12
|
location.state.__hashScrollIntoViewOptions ?? true
|
|
13
13
|
|
package/src/index.ts
CHANGED
|
@@ -435,7 +435,6 @@ export type {
|
|
|
435
435
|
AnySerializationAdapter,
|
|
436
436
|
SerializationAdapter,
|
|
437
437
|
ValidateSerializableInput,
|
|
438
|
-
ValidateSerializableInputResult,
|
|
439
438
|
SerializerExtensions,
|
|
440
439
|
ValidateSerializable,
|
|
441
440
|
RegisteredSerializableInput,
|
|
@@ -444,6 +443,7 @@ export type {
|
|
|
444
443
|
Serializable,
|
|
445
444
|
TSR_SERIALIZABLE,
|
|
446
445
|
TsrSerializable,
|
|
446
|
+
SerializationError,
|
|
447
447
|
} from './ssr/serializer/transformer'
|
|
448
448
|
|
|
449
449
|
export {
|
package/src/load-matches.ts
CHANGED
|
@@ -45,8 +45,8 @@ const triggerOnReady = (inner: InnerLoadContext): void | Promise<void> => {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const hasForcePendingActiveMatch = (router: AnyRouter): boolean => {
|
|
48
|
-
return router.stores.matchesId.
|
|
49
|
-
return router.stores.activeMatchStoresById.get(matchId)?.
|
|
48
|
+
return router.stores.matchesId.get().some((matchId) => {
|
|
49
|
+
return router.stores.activeMatchStoresById.get(matchId)?.get()._forcePending
|
|
50
50
|
})
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -879,7 +879,7 @@ const loadRouteMatch = async (
|
|
|
879
879
|
}
|
|
880
880
|
} else {
|
|
881
881
|
const prevMatch = inner.router.getMatch(matchId)! // This is where all of the stale-while-revalidate magic happens
|
|
882
|
-
const activeIdAtIndex = inner.router.stores.matchesId.
|
|
882
|
+
const activeIdAtIndex = inner.router.stores.matchesId.get()[index]
|
|
883
883
|
const activeAtIndex =
|
|
884
884
|
(activeIdAtIndex &&
|
|
885
885
|
inner.router.stores.activeMatchStoresById.get(activeIdAtIndex)) ||
|
|
@@ -887,9 +887,9 @@ const loadRouteMatch = async (
|
|
|
887
887
|
const previousRouteMatchId =
|
|
888
888
|
activeAtIndex?.routeId === routeId
|
|
889
889
|
? activeIdAtIndex
|
|
890
|
-
: inner.router.stores.activeMatchesSnapshot
|
|
891
|
-
(
|
|
892
|
-
|
|
890
|
+
: inner.router.stores.activeMatchesSnapshot
|
|
891
|
+
.get()
|
|
892
|
+
.find((d) => d.routeId === routeId)?.id
|
|
893
893
|
const preload = resolvePreload(inner, matchId)
|
|
894
894
|
|
|
895
895
|
// there is a loaderPromise, so we are in the middle of a load
|
package/src/router.ts
CHANGED
|
@@ -799,7 +799,9 @@ export interface ServerSsr {
|
|
|
799
799
|
setRenderFinished: () => void
|
|
800
800
|
cleanup: () => void
|
|
801
801
|
onSerializationFinished: (listener: () => void) => void
|
|
802
|
-
dehydrate: (
|
|
802
|
+
dehydrate: (opts?: {
|
|
803
|
+
requestAssets?: Array<RouterManagedTag>
|
|
804
|
+
}) => Promise<void>
|
|
803
805
|
takeBufferedScripts: () => RouterManagedTag | undefined
|
|
804
806
|
/**
|
|
805
807
|
* Takes any buffered HTML that was injected.
|
|
@@ -1167,7 +1169,7 @@ export class RouterCore<
|
|
|
1167
1169
|
}
|
|
1168
1170
|
|
|
1169
1171
|
if (needsLocationUpdate && this.stores) {
|
|
1170
|
-
this.stores.location.
|
|
1172
|
+
this.stores.location.set(this.latestLocation)
|
|
1171
1173
|
}
|
|
1172
1174
|
|
|
1173
1175
|
if (
|
|
@@ -1182,7 +1184,7 @@ export class RouterCore<
|
|
|
1182
1184
|
}
|
|
1183
1185
|
|
|
1184
1186
|
get state(): RouterState<TRouteTree> {
|
|
1185
|
-
return this.stores.__store.
|
|
1187
|
+
return this.stores.__store.get()
|
|
1186
1188
|
}
|
|
1187
1189
|
|
|
1188
1190
|
updateLatestLocation = () => {
|
|
@@ -1420,7 +1422,7 @@ export class RouterCore<
|
|
|
1420
1422
|
const previousActiveMatchesByRouteId = new Map<string, AnyRouteMatch>()
|
|
1421
1423
|
for (const store of this.stores.activeMatchStoresById.values()) {
|
|
1422
1424
|
if (store.routeId) {
|
|
1423
|
-
previousActiveMatchesByRouteId.set(store.routeId, store.
|
|
1425
|
+
previousActiveMatchesByRouteId.set(store.routeId, store.get())
|
|
1424
1426
|
}
|
|
1425
1427
|
}
|
|
1426
1428
|
|
|
@@ -1713,10 +1715,10 @@ export class RouterCore<
|
|
|
1713
1715
|
}
|
|
1714
1716
|
|
|
1715
1717
|
// Determine params: reuse from state if possible, otherwise parse
|
|
1716
|
-
const lastStateMatchId = last(this.stores.matchesId.
|
|
1718
|
+
const lastStateMatchId = last(this.stores.matchesId.get())
|
|
1717
1719
|
const lastStateMatch =
|
|
1718
1720
|
lastStateMatchId &&
|
|
1719
|
-
this.stores.activeMatchStoresById.get(lastStateMatchId)?.
|
|
1721
|
+
this.stores.activeMatchStoresById.get(lastStateMatchId)?.get()
|
|
1720
1722
|
const canReuseParams =
|
|
1721
1723
|
lastStateMatch &&
|
|
1722
1724
|
lastStateMatch.routeId === lastRoute.id &&
|
|
@@ -1765,16 +1767,16 @@ export class RouterCore<
|
|
|
1765
1767
|
}
|
|
1766
1768
|
|
|
1767
1769
|
cancelMatches = () => {
|
|
1768
|
-
this.stores.pendingMatchesId.
|
|
1770
|
+
this.stores.pendingMatchesId.get().forEach((matchId) => {
|
|
1769
1771
|
this.cancelMatch(matchId)
|
|
1770
1772
|
})
|
|
1771
1773
|
|
|
1772
|
-
this.stores.matchesId.
|
|
1774
|
+
this.stores.matchesId.get().forEach((matchId) => {
|
|
1773
1775
|
if (this.stores.pendingMatchStoresById.has(matchId)) {
|
|
1774
1776
|
return
|
|
1775
1777
|
}
|
|
1776
1778
|
|
|
1777
|
-
const match = this.stores.activeMatchStoresById.get(matchId)?.
|
|
1779
|
+
const match = this.stores.activeMatchStoresById.get(matchId)?.get()
|
|
1778
1780
|
if (!match) {
|
|
1779
1781
|
return
|
|
1780
1782
|
}
|
|
@@ -2354,16 +2356,16 @@ export class RouterCore<
|
|
|
2354
2356
|
// Match the routes
|
|
2355
2357
|
const pendingMatches = this.matchRoutes(this.latestLocation)
|
|
2356
2358
|
|
|
2357
|
-
const nextCachedMatches = this.stores.cachedMatchesSnapshot
|
|
2358
|
-
|
|
2359
|
-
|
|
2359
|
+
const nextCachedMatches = this.stores.cachedMatchesSnapshot
|
|
2360
|
+
.get()
|
|
2361
|
+
.filter((d) => !pendingMatches.some((e) => e.id === d.id))
|
|
2360
2362
|
|
|
2361
2363
|
// Ingest the new matches
|
|
2362
2364
|
this.batch(() => {
|
|
2363
|
-
this.stores.status.
|
|
2364
|
-
this.stores.statusCode.
|
|
2365
|
-
this.stores.isLoading.
|
|
2366
|
-
this.stores.location.
|
|
2365
|
+
this.stores.status.set('pending')
|
|
2366
|
+
this.stores.statusCode.set(200)
|
|
2367
|
+
this.stores.isLoading.set(true)
|
|
2368
|
+
this.stores.location.set(this.latestLocation)
|
|
2367
2369
|
this.stores.setPendingMatches(pendingMatches)
|
|
2368
2370
|
// If a cached match moved to pending matches, remove it from cached matches
|
|
2369
2371
|
this.stores.setCachedMatches(nextCachedMatches)
|
|
@@ -2375,7 +2377,7 @@ export class RouterCore<
|
|
|
2375
2377
|
let notFound: NotFoundError | undefined
|
|
2376
2378
|
let loadPromise: Promise<void>
|
|
2377
2379
|
const previousLocation =
|
|
2378
|
-
this.stores.resolvedLocation.
|
|
2380
|
+
this.stores.resolvedLocation.get() ?? this.stores.location.get()
|
|
2379
2381
|
|
|
2380
2382
|
// eslint-disable-next-line prefer-const
|
|
2381
2383
|
loadPromise = new Promise<void>((resolve) => {
|
|
@@ -2383,10 +2385,10 @@ export class RouterCore<
|
|
|
2383
2385
|
try {
|
|
2384
2386
|
this.beforeLoad()
|
|
2385
2387
|
const next = this.latestLocation
|
|
2386
|
-
const prevLocation = this.stores.resolvedLocation.
|
|
2388
|
+
const prevLocation = this.stores.resolvedLocation.get()
|
|
2387
2389
|
const locationChangeInfo = getLocationChangeInfo(next, prevLocation)
|
|
2388
2390
|
|
|
2389
|
-
if (!this.stores.redirect.
|
|
2391
|
+
if (!this.stores.redirect.get()) {
|
|
2390
2392
|
this.emit({
|
|
2391
2393
|
type: 'onBeforeNavigate',
|
|
2392
2394
|
...locationChangeInfo,
|
|
@@ -2402,7 +2404,7 @@ export class RouterCore<
|
|
|
2402
2404
|
router: this,
|
|
2403
2405
|
sync: opts?.sync,
|
|
2404
2406
|
forceStaleReload: previousLocation.href === next.href,
|
|
2405
|
-
matches: this.stores.pendingMatchesSnapshot.
|
|
2407
|
+
matches: this.stores.pendingMatchesSnapshot.get(),
|
|
2406
2408
|
location: next,
|
|
2407
2409
|
updateMatch: this.updateMatch,
|
|
2408
2410
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
@@ -2427,10 +2429,10 @@ export class RouterCore<
|
|
|
2427
2429
|
|
|
2428
2430
|
this.batch(() => {
|
|
2429
2431
|
const pendingMatches =
|
|
2430
|
-
this.stores.pendingMatchesSnapshot.
|
|
2432
|
+
this.stores.pendingMatchesSnapshot.get()
|
|
2431
2433
|
const mountPending = pendingMatches.length
|
|
2432
2434
|
const currentMatches =
|
|
2433
|
-
this.stores.activeMatchesSnapshot.
|
|
2435
|
+
this.stores.activeMatchesSnapshot.get()
|
|
2434
2436
|
|
|
2435
2437
|
exitingMatches = mountPending
|
|
2436
2438
|
? currentMatches.filter(
|
|
@@ -2466,8 +2468,8 @@ export class RouterCore<
|
|
|
2466
2468
|
)
|
|
2467
2469
|
: currentMatches
|
|
2468
2470
|
|
|
2469
|
-
this.stores.isLoading.
|
|
2470
|
-
this.stores.loadedAt.
|
|
2471
|
+
this.stores.isLoading.set(false)
|
|
2472
|
+
this.stores.loadedAt.set(Date.now())
|
|
2471
2473
|
/**
|
|
2472
2474
|
* When committing new matches, cache any exiting matches that are still usable.
|
|
2473
2475
|
* Routes that resolved with `status: 'error'` or `status: 'notFound'` are
|
|
@@ -2478,7 +2480,7 @@ export class RouterCore<
|
|
|
2478
2480
|
this.stores.setActiveMatches(pendingMatches)
|
|
2479
2481
|
this.stores.setPendingMatches([])
|
|
2480
2482
|
this.stores.setCachedMatches([
|
|
2481
|
-
...this.stores.cachedMatchesSnapshot.
|
|
2483
|
+
...this.stores.cachedMatchesSnapshot.get(),
|
|
2482
2484
|
...exitingMatches!.filter(
|
|
2483
2485
|
(d) =>
|
|
2484
2486
|
d.status !== 'error' &&
|
|
@@ -2525,15 +2527,15 @@ export class RouterCore<
|
|
|
2525
2527
|
? redirect.status
|
|
2526
2528
|
: notFound
|
|
2527
2529
|
? 404
|
|
2528
|
-
: this.stores.activeMatchesSnapshot
|
|
2529
|
-
(
|
|
2530
|
-
|
|
2530
|
+
: this.stores.activeMatchesSnapshot
|
|
2531
|
+
.get()
|
|
2532
|
+
.some((d) => d.status === 'error')
|
|
2531
2533
|
? 500
|
|
2532
2534
|
: 200
|
|
2533
2535
|
|
|
2534
2536
|
this.batch(() => {
|
|
2535
|
-
this.stores.statusCode.
|
|
2536
|
-
this.stores.redirect.
|
|
2537
|
+
this.stores.statusCode.set(nextStatusCode)
|
|
2538
|
+
this.stores.redirect.set(redirect)
|
|
2537
2539
|
})
|
|
2538
2540
|
}
|
|
2539
2541
|
|
|
@@ -2562,12 +2564,12 @@ export class RouterCore<
|
|
|
2562
2564
|
if (this.hasNotFoundMatch()) {
|
|
2563
2565
|
newStatusCode = 404
|
|
2564
2566
|
} else if (
|
|
2565
|
-
this.stores.activeMatchesSnapshot.
|
|
2567
|
+
this.stores.activeMatchesSnapshot.get().some((d) => d.status === 'error')
|
|
2566
2568
|
) {
|
|
2567
2569
|
newStatusCode = 500
|
|
2568
2570
|
}
|
|
2569
2571
|
if (newStatusCode !== undefined) {
|
|
2570
|
-
this.stores.statusCode.
|
|
2572
|
+
this.stores.statusCode.set(newStatusCode)
|
|
2571
2573
|
}
|
|
2572
2574
|
}
|
|
2573
2575
|
|
|
@@ -2596,7 +2598,7 @@ export class RouterCore<
|
|
|
2596
2598
|
this.isViewTransitionTypesSupported
|
|
2597
2599
|
) {
|
|
2598
2600
|
const next = this.latestLocation
|
|
2599
|
-
const prevLocation = this.stores.resolvedLocation.
|
|
2601
|
+
const prevLocation = this.stores.resolvedLocation.get()
|
|
2600
2602
|
|
|
2601
2603
|
const resolvedViewTransitionTypes =
|
|
2602
2604
|
typeof shouldViewTransition.types === 'function'
|
|
@@ -2628,28 +2630,28 @@ export class RouterCore<
|
|
|
2628
2630
|
this.startTransition(() => {
|
|
2629
2631
|
const pendingMatch = this.stores.pendingMatchStoresById.get(id)
|
|
2630
2632
|
if (pendingMatch) {
|
|
2631
|
-
pendingMatch.
|
|
2633
|
+
pendingMatch.set(updater)
|
|
2632
2634
|
return
|
|
2633
2635
|
}
|
|
2634
2636
|
|
|
2635
2637
|
const activeMatch = this.stores.activeMatchStoresById.get(id)
|
|
2636
2638
|
if (activeMatch) {
|
|
2637
|
-
activeMatch.
|
|
2639
|
+
activeMatch.set(updater)
|
|
2638
2640
|
return
|
|
2639
2641
|
}
|
|
2640
2642
|
|
|
2641
2643
|
const cachedMatch = this.stores.cachedMatchStoresById.get(id)
|
|
2642
2644
|
if (cachedMatch) {
|
|
2643
|
-
const next = updater(cachedMatch.
|
|
2645
|
+
const next = updater(cachedMatch.get())
|
|
2644
2646
|
if (next.status === 'redirected') {
|
|
2645
2647
|
const deleted = this.stores.cachedMatchStoresById.delete(id)
|
|
2646
2648
|
if (deleted) {
|
|
2647
|
-
this.stores.cachedMatchesId.
|
|
2649
|
+
this.stores.cachedMatchesId.set((prev) =>
|
|
2648
2650
|
prev.filter((matchId) => matchId !== id),
|
|
2649
2651
|
)
|
|
2650
2652
|
}
|
|
2651
2653
|
} else {
|
|
2652
|
-
cachedMatch.
|
|
2654
|
+
cachedMatch.set(next)
|
|
2653
2655
|
}
|
|
2654
2656
|
}
|
|
2655
2657
|
})
|
|
@@ -2657,9 +2659,9 @@ export class RouterCore<
|
|
|
2657
2659
|
|
|
2658
2660
|
getMatch: GetMatchFn = (matchId: string): AnyRouteMatch | undefined => {
|
|
2659
2661
|
return (
|
|
2660
|
-
this.stores.cachedMatchStoresById.get(matchId)?.
|
|
2661
|
-
this.stores.pendingMatchStoresById.get(matchId)?.
|
|
2662
|
-
this.stores.activeMatchStoresById.get(matchId)?.
|
|
2662
|
+
this.stores.cachedMatchStoresById.get(matchId)?.get() ??
|
|
2663
|
+
this.stores.pendingMatchStoresById.get(matchId)?.get() ??
|
|
2664
|
+
this.stores.activeMatchStoresById.get(matchId)?.get()
|
|
2663
2665
|
)
|
|
2664
2666
|
}
|
|
2665
2667
|
|
|
@@ -2697,13 +2699,13 @@ export class RouterCore<
|
|
|
2697
2699
|
|
|
2698
2700
|
this.batch(() => {
|
|
2699
2701
|
this.stores.setActiveMatches(
|
|
2700
|
-
this.stores.activeMatchesSnapshot.
|
|
2702
|
+
this.stores.activeMatchesSnapshot.get().map(invalidate),
|
|
2701
2703
|
)
|
|
2702
2704
|
this.stores.setCachedMatches(
|
|
2703
|
-
this.stores.cachedMatchesSnapshot.
|
|
2705
|
+
this.stores.cachedMatchesSnapshot.get().map(invalidate),
|
|
2704
2706
|
)
|
|
2705
2707
|
this.stores.setPendingMatches(
|
|
2706
|
-
this.stores.pendingMatchesSnapshot.
|
|
2708
|
+
this.stores.pendingMatchesSnapshot.get().map(invalidate),
|
|
2707
2709
|
)
|
|
2708
2710
|
})
|
|
2709
2711
|
|
|
@@ -2763,9 +2765,9 @@ export class RouterCore<
|
|
|
2763
2765
|
const filter = opts?.filter
|
|
2764
2766
|
if (filter !== undefined) {
|
|
2765
2767
|
this.stores.setCachedMatches(
|
|
2766
|
-
this.stores.cachedMatchesSnapshot
|
|
2767
|
-
(
|
|
2768
|
-
|
|
2768
|
+
this.stores.cachedMatchesSnapshot
|
|
2769
|
+
.get()
|
|
2770
|
+
.filter((m) => !filter(m as MakeRouteMatchUnion<this>)),
|
|
2769
2771
|
)
|
|
2770
2772
|
} else {
|
|
2771
2773
|
this.stores.setCachedMatches([])
|
|
@@ -2816,13 +2818,13 @@ export class RouterCore<
|
|
|
2816
2818
|
})
|
|
2817
2819
|
|
|
2818
2820
|
const activeMatchIds = new Set([
|
|
2819
|
-
...this.stores.matchesId.
|
|
2820
|
-
...this.stores.pendingMatchesId.
|
|
2821
|
+
...this.stores.matchesId.get(),
|
|
2822
|
+
...this.stores.pendingMatchesId.get(),
|
|
2821
2823
|
])
|
|
2822
2824
|
|
|
2823
2825
|
const loadedMatchIds = new Set([
|
|
2824
2826
|
...activeMatchIds,
|
|
2825
|
-
...this.stores.cachedMatchesId.
|
|
2827
|
+
...this.stores.cachedMatchesId.get(),
|
|
2826
2828
|
])
|
|
2827
2829
|
|
|
2828
2830
|
// If the matches are already loaded, we need to add them to the cached matches.
|
|
@@ -2830,7 +2832,7 @@ export class RouterCore<
|
|
|
2830
2832
|
(match) => !loadedMatchIds.has(match.id),
|
|
2831
2833
|
)
|
|
2832
2834
|
if (matchesToCache.length) {
|
|
2833
|
-
const cachedMatches = this.stores.cachedMatchesSnapshot.
|
|
2835
|
+
const cachedMatches = this.stores.cachedMatchesSnapshot.get()
|
|
2834
2836
|
this.stores.setCachedMatches([...cachedMatches, ...matchesToCache])
|
|
2835
2837
|
}
|
|
2836
2838
|
|
|
@@ -2886,16 +2888,16 @@ export class RouterCore<
|
|
|
2886
2888
|
}
|
|
2887
2889
|
const next = this.buildLocation(matchLocation as any)
|
|
2888
2890
|
|
|
2889
|
-
if (opts?.pending && this.stores.status.
|
|
2891
|
+
if (opts?.pending && this.stores.status.get() !== 'pending') {
|
|
2890
2892
|
return false
|
|
2891
2893
|
}
|
|
2892
2894
|
|
|
2893
2895
|
const pending =
|
|
2894
|
-
opts?.pending === undefined ? !this.stores.isLoading.
|
|
2896
|
+
opts?.pending === undefined ? !this.stores.isLoading.get() : opts.pending
|
|
2895
2897
|
|
|
2896
2898
|
const baseLocation = pending
|
|
2897
2899
|
? this.latestLocation
|
|
2898
|
-
: this.stores.resolvedLocation.
|
|
2900
|
+
: this.stores.resolvedLocation.get() || this.stores.location.get()
|
|
2899
2901
|
|
|
2900
2902
|
const match = findSingleMatch(
|
|
2901
2903
|
next.pathname,
|
|
@@ -2931,9 +2933,9 @@ export class RouterCore<
|
|
|
2931
2933
|
serverSsr?: ServerSsr
|
|
2932
2934
|
|
|
2933
2935
|
hasNotFoundMatch = () => {
|
|
2934
|
-
return this.stores.activeMatchesSnapshot
|
|
2935
|
-
(
|
|
2936
|
-
|
|
2936
|
+
return this.stores.activeMatchesSnapshot
|
|
2937
|
+
.get()
|
|
2938
|
+
.some((d) => d.status === 'notFound' || d.globalNotFound)
|
|
2937
2939
|
}
|
|
2938
2940
|
}
|
|
2939
2941
|
|
|
@@ -233,7 +233,7 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
233
233
|
window.addEventListener('pagehide', () => {
|
|
234
234
|
snapshotCurrentScrollTargets(
|
|
235
235
|
getKey(
|
|
236
|
-
router.stores.resolvedLocation.
|
|
236
|
+
router.stores.resolvedLocation.get() ?? router.stores.location.get(),
|
|
237
237
|
),
|
|
238
238
|
)
|
|
239
239
|
cache.persist()
|
|
@@ -78,13 +78,12 @@ export function createRequestHandler<TRouter extends AnyRouter>({
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function getRequestHeaders(opts: { router: AnyRouter }): Headers {
|
|
81
|
-
const matchHeaders =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
81
|
+
const matchHeaders = opts.router.stores.activeMatchesSnapshot
|
|
82
|
+
.get()
|
|
83
|
+
.map<AnyHeaders>((match) => match.headers)
|
|
85
84
|
|
|
86
85
|
// Handle Redirects
|
|
87
|
-
const redirect = opts.router.stores.redirect.
|
|
86
|
+
const redirect = opts.router.stores.redirect.get()
|
|
88
87
|
if (redirect) {
|
|
89
88
|
matchHeaders.push(redirect.headers)
|
|
90
89
|
}
|