@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.
Files changed (79) hide show
  1. package/dist/cjs/hash-scroll.cjs +1 -1
  2. package/dist/cjs/hash-scroll.cjs.map +1 -1
  3. package/dist/cjs/index.d.cts +1 -1
  4. package/dist/cjs/load-matches.cjs +4 -4
  5. package/dist/cjs/load-matches.cjs.map +1 -1
  6. package/dist/cjs/router.cjs +44 -45
  7. package/dist/cjs/router.cjs.map +1 -1
  8. package/dist/cjs/router.d.cts +3 -1
  9. package/dist/cjs/scroll-restoration.cjs +1 -1
  10. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  11. package/dist/cjs/ssr/createRequestHandler.cjs +2 -2
  12. package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
  13. package/dist/cjs/ssr/serializer/RawStream.cjs +41 -32
  14. package/dist/cjs/ssr/serializer/RawStream.cjs.map +1 -1
  15. package/dist/cjs/ssr/serializer/RawStream.d.cts +12 -4
  16. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -1
  17. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.d.cts +2 -2
  18. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -1
  19. package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -1
  20. package/dist/cjs/ssr/serializer/transformer.cjs +16 -14
  21. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
  22. package/dist/cjs/ssr/serializer/transformer.d.cts +24 -23
  23. package/dist/cjs/ssr/ssr-client.cjs +8 -8
  24. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  25. package/dist/cjs/ssr/ssr-server.cjs +31 -9
  26. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  27. package/dist/cjs/ssr/ssr-server.d.cts +3 -2
  28. package/dist/cjs/ssr/transformStreamWithRouter.cjs +4 -1
  29. package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
  30. package/dist/cjs/stores.cjs +27 -27
  31. package/dist/cjs/stores.cjs.map +1 -1
  32. package/dist/cjs/stores.d.cts +2 -2
  33. package/dist/esm/hash-scroll.js +1 -1
  34. package/dist/esm/hash-scroll.js.map +1 -1
  35. package/dist/esm/index.d.ts +1 -1
  36. package/dist/esm/load-matches.js +4 -4
  37. package/dist/esm/load-matches.js.map +1 -1
  38. package/dist/esm/router.d.ts +3 -1
  39. package/dist/esm/router.js +44 -45
  40. package/dist/esm/router.js.map +1 -1
  41. package/dist/esm/scroll-restoration.js +1 -1
  42. package/dist/esm/scroll-restoration.js.map +1 -1
  43. package/dist/esm/ssr/createRequestHandler.js +2 -2
  44. package/dist/esm/ssr/createRequestHandler.js.map +1 -1
  45. package/dist/esm/ssr/serializer/RawStream.d.ts +12 -4
  46. package/dist/esm/ssr/serializer/RawStream.js +41 -32
  47. package/dist/esm/ssr/serializer/RawStream.js.map +1 -1
  48. package/dist/esm/ssr/serializer/ShallowErrorPlugin.d.ts +2 -2
  49. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -1
  50. package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -1
  51. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -1
  52. package/dist/esm/ssr/serializer/transformer.d.ts +24 -23
  53. package/dist/esm/ssr/serializer/transformer.js +16 -14
  54. package/dist/esm/ssr/serializer/transformer.js.map +1 -1
  55. package/dist/esm/ssr/ssr-client.js +8 -8
  56. package/dist/esm/ssr/ssr-client.js.map +1 -1
  57. package/dist/esm/ssr/ssr-server.d.ts +3 -2
  58. package/dist/esm/ssr/ssr-server.js +31 -9
  59. package/dist/esm/ssr/ssr-server.js.map +1 -1
  60. package/dist/esm/ssr/transformStreamWithRouter.js +4 -1
  61. package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
  62. package/dist/esm/stores.d.ts +2 -2
  63. package/dist/esm/stores.js +28 -28
  64. package/dist/esm/stores.js.map +1 -1
  65. package/package.json +3 -3
  66. package/src/hash-scroll.ts +1 -1
  67. package/src/index.ts +1 -1
  68. package/src/load-matches.ts +6 -6
  69. package/src/router.ts +59 -57
  70. package/src/scroll-restoration.ts +1 -1
  71. package/src/ssr/createRequestHandler.ts +4 -5
  72. package/src/ssr/serializer/RawStream.ts +65 -56
  73. package/src/ssr/serializer/ShallowErrorPlugin.ts +2 -2
  74. package/src/ssr/serializer/seroval-plugins.ts +2 -1
  75. package/src/ssr/serializer/transformer.ts +71 -76
  76. package/src/ssr/ssr-client.ts +7 -11
  77. package/src/ssr/ssr-server.ts +39 -7
  78. package/src/ssr/transformStreamWithRouter.ts +3 -0
  79. package/src/stores.ts +34 -34
@@ -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 state() {
8
+ get() {
9
9
  return value;
10
10
  },
11
- setState(updater) {
12
- value = updater(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 state() {
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.state));
39
- const pendingMatchesSnapshot = createReadonlyStore(() => readPoolMatches(pendingMatchStoresById, pendingMatchesId.state));
40
- const cachedMatchesSnapshot = createReadonlyStore(() => readPoolMatches(cachedMatchStoresById, cachedMatchesId.state));
41
- const firstMatchId = createReadonlyStore(() => matchesId.state[0]);
42
- const hasPendingMatches = createReadonlyStore(() => matchesId.state.some((matchId) => {
43
- return activeMatchStoresById.get(matchId)?.state.status === "pending";
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.state.href,
47
- resolvedLocationHref: resolvedLocation.state?.href,
48
- status: status.state
46
+ locationHref: location.get().href,
47
+ resolvedLocationHref: resolvedLocation.get()?.href,
48
+ status: status.get()
49
49
  }));
50
50
  const __store = createReadonlyStore(() => ({
51
- status: status.state,
52
- loadedAt: loadedAt.state,
53
- isLoading: isLoading.state,
54
- isTransitioning: isTransitioning.state,
55
- matches: activeMatchesSnapshot.state,
56
- location: location.state,
57
- resolvedLocation: resolvedLocation.state,
58
- statusCode: statusCode.state,
59
- redirect: redirect.state
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.state;
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.state;
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.state);
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.state !== nextMatch) existing.setState(() => nextMatch);
138
+ if (existing.get() !== nextMatch) existing.set(nextMatch);
139
139
  }
140
- if (!arraysEqual(idStore.state, nextIds)) idStore.setState(() => nextIds);
140
+ if (!arraysEqual(idStore.get(), nextIds)) idStore.set(nextIds);
141
141
  });
142
142
  }
143
143
  //#endregion
@@ -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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
- "version": "1.168.8",
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.4.2",
172
- "seroval-plugins": "^1.4.2",
171
+ "seroval": "^1.5.0",
172
+ "seroval-plugins": "^1.5.0",
173
173
  "@tanstack/history": "1.161.6"
174
174
  },
175
175
  "devDependencies": {
@@ -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.state
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 {
@@ -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.state.some((matchId) => {
49
- return router.stores.activeMatchStoresById.get(matchId)?.state._forcePending
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.state[index]
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.state.find(
891
- (d) => d.routeId === routeId,
892
- )?.id
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: () => Promise<void>
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.setState(() => this.latestLocation)
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.state
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.state)
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.state)
1718
+ const lastStateMatchId = last(this.stores.matchesId.get())
1717
1719
  const lastStateMatch =
1718
1720
  lastStateMatchId &&
1719
- this.stores.activeMatchStoresById.get(lastStateMatchId)?.state
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.state.forEach((matchId) => {
1770
+ this.stores.pendingMatchesId.get().forEach((matchId) => {
1769
1771
  this.cancelMatch(matchId)
1770
1772
  })
1771
1773
 
1772
- this.stores.matchesId.state.forEach((matchId) => {
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)?.state
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.state.filter(
2358
- (d) => !pendingMatches.some((e) => e.id === d.id),
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.setState(() => 'pending')
2364
- this.stores.statusCode.setState(() => 200)
2365
- this.stores.isLoading.setState(() => true)
2366
- this.stores.location.setState(() => this.latestLocation)
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.state ?? this.stores.location.state
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.state
2388
+ const prevLocation = this.stores.resolvedLocation.get()
2387
2389
  const locationChangeInfo = getLocationChangeInfo(next, prevLocation)
2388
2390
 
2389
- if (!this.stores.redirect.state) {
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.state,
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.state
2432
+ this.stores.pendingMatchesSnapshot.get()
2431
2433
  const mountPending = pendingMatches.length
2432
2434
  const currentMatches =
2433
- this.stores.activeMatchesSnapshot.state
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.setState(() => false)
2470
- this.stores.loadedAt.setState(() => Date.now())
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.state,
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.state.some(
2529
- (d) => d.status === 'error',
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.setState(() => nextStatusCode)
2536
- this.stores.redirect.setState(() => 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.state.some((d) => d.status === 'error')
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.setState(() => newStatusCode)
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.state
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.setState(updater)
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.setState(updater)
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.state)
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.setState((prev) =>
2649
+ this.stores.cachedMatchesId.set((prev) =>
2648
2650
  prev.filter((matchId) => matchId !== id),
2649
2651
  )
2650
2652
  }
2651
2653
  } else {
2652
- cachedMatch.setState(() => next)
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)?.state ??
2661
- this.stores.pendingMatchStoresById.get(matchId)?.state ??
2662
- this.stores.activeMatchStoresById.get(matchId)?.state
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.state.map(invalidate),
2702
+ this.stores.activeMatchesSnapshot.get().map(invalidate),
2701
2703
  )
2702
2704
  this.stores.setCachedMatches(
2703
- this.stores.cachedMatchesSnapshot.state.map(invalidate),
2705
+ this.stores.cachedMatchesSnapshot.get().map(invalidate),
2704
2706
  )
2705
2707
  this.stores.setPendingMatches(
2706
- this.stores.pendingMatchesSnapshot.state.map(invalidate),
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.state.filter(
2767
- (m) => !filter(m as MakeRouteMatchUnion<this>),
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.state,
2820
- ...this.stores.pendingMatchesId.state,
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.state,
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.state
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.state !== 'pending') {
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.state : opts.pending
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.state || this.stores.location.state
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.state.some(
2935
- (d) => d.status === 'notFound' || d.globalNotFound,
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.state ?? router.stores.location.state,
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
- opts.router.stores.activeMatchesSnapshot.state.map<AnyHeaders>(
83
- (match) => match.headers,
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.state
86
+ const redirect = opts.router.stores.redirect.get()
88
87
  if (redirect) {
89
88
  matchHeaders.push(redirect.headers)
90
89
  }