@tanstack/router-core 1.168.9 → 1.168.11

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 +6 -6
  5. package/dist/cjs/load-matches.cjs.map +1 -1
  6. package/dist/cjs/router.cjs +57 -58
  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 +9 -9
  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 +57 -57
  31. package/dist/cjs/stores.cjs.map +1 -1
  32. package/dist/cjs/stores.d.cts +16 -16
  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 +6 -6
  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 +57 -58
  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 +9 -9
  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 +16 -16
  63. package/dist/esm/stores.js +58 -58
  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 +8 -11
  69. package/src/router.ts +74 -85
  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 +8 -12
  77. package/src/ssr/ssr-server.ts +39 -7
  78. package/src/ssr/transformStreamWithRouter.ts +3 -0
  79. package/src/stores.ts +86 -86
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 = () => {
@@ -1418,9 +1420,9 @@ export class RouterCore<
1418
1420
  // Snapshot of active match state keyed by routeId, used to stabilise
1419
1421
  // params/search across navigations.
1420
1422
  const previousActiveMatchesByRouteId = new Map<string, AnyRouteMatch>()
1421
- for (const store of this.stores.activeMatchStoresById.values()) {
1423
+ for (const store of this.stores.matchStores.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,9 @@ 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
- lastStateMatchId &&
1719
- this.stores.activeMatchStoresById.get(lastStateMatchId)?.state
1720
+ lastStateMatchId && this.stores.matchStores.get(lastStateMatchId)?.get()
1720
1721
  const canReuseParams =
1721
1722
  lastStateMatch &&
1722
1723
  lastStateMatch.routeId === lastRoute.id &&
@@ -1765,16 +1766,16 @@ export class RouterCore<
1765
1766
  }
1766
1767
 
1767
1768
  cancelMatches = () => {
1768
- this.stores.pendingMatchesId.state.forEach((matchId) => {
1769
+ this.stores.pendingIds.get().forEach((matchId) => {
1769
1770
  this.cancelMatch(matchId)
1770
1771
  })
1771
1772
 
1772
- this.stores.matchesId.state.forEach((matchId) => {
1773
- if (this.stores.pendingMatchStoresById.has(matchId)) {
1773
+ this.stores.matchesId.get().forEach((matchId) => {
1774
+ if (this.stores.pendingMatchStores.has(matchId)) {
1774
1775
  return
1775
1776
  }
1776
1777
 
1777
- const match = this.stores.activeMatchStoresById.get(matchId)?.state
1778
+ const match = this.stores.matchStores.get(matchId)?.get()
1778
1779
  if (!match) {
1779
1780
  return
1780
1781
  }
@@ -2354,19 +2355,19 @@ export class RouterCore<
2354
2355
  // Match the routes
2355
2356
  const pendingMatches = this.matchRoutes(this.latestLocation)
2356
2357
 
2357
- const nextCachedMatches = this.stores.cachedMatchesSnapshot.state.filter(
2358
- (d) => !pendingMatches.some((e) => e.id === d.id),
2359
- )
2358
+ const nextCachedMatches = this.stores.cachedMatches
2359
+ .get()
2360
+ .filter((d) => !pendingMatches.some((e) => e.id === d.id))
2360
2361
 
2361
2362
  // Ingest the new matches
2362
2363
  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)
2367
- this.stores.setPendingMatches(pendingMatches)
2364
+ this.stores.status.set('pending')
2365
+ this.stores.statusCode.set(200)
2366
+ this.stores.isLoading.set(true)
2367
+ this.stores.location.set(this.latestLocation)
2368
+ this.stores.setPending(pendingMatches)
2368
2369
  // If a cached match moved to pending matches, remove it from cached matches
2369
- this.stores.setCachedMatches(nextCachedMatches)
2370
+ this.stores.setCached(nextCachedMatches)
2370
2371
  })
2371
2372
  }
2372
2373
 
@@ -2375,7 +2376,7 @@ export class RouterCore<
2375
2376
  let notFound: NotFoundError | undefined
2376
2377
  let loadPromise: Promise<void>
2377
2378
  const previousLocation =
2378
- this.stores.resolvedLocation.state ?? this.stores.location.state
2379
+ this.stores.resolvedLocation.get() ?? this.stores.location.get()
2379
2380
 
2380
2381
  // eslint-disable-next-line prefer-const
2381
2382
  loadPromise = new Promise<void>((resolve) => {
@@ -2383,10 +2384,10 @@ export class RouterCore<
2383
2384
  try {
2384
2385
  this.beforeLoad()
2385
2386
  const next = this.latestLocation
2386
- const prevLocation = this.stores.resolvedLocation.state
2387
+ const prevLocation = this.stores.resolvedLocation.get()
2387
2388
  const locationChangeInfo = getLocationChangeInfo(next, prevLocation)
2388
2389
 
2389
- if (!this.stores.redirect.state) {
2390
+ if (!this.stores.redirect.get()) {
2390
2391
  this.emit({
2391
2392
  type: 'onBeforeNavigate',
2392
2393
  ...locationChangeInfo,
@@ -2402,7 +2403,7 @@ export class RouterCore<
2402
2403
  router: this,
2403
2404
  sync: opts?.sync,
2404
2405
  forceStaleReload: previousLocation.href === next.href,
2405
- matches: this.stores.pendingMatchesSnapshot.state,
2406
+ matches: this.stores.pendingMatches.get(),
2406
2407
  location: next,
2407
2408
  updateMatch: this.updateMatch,
2408
2409
  // eslint-disable-next-line @typescript-eslint/require-await
@@ -2426,27 +2427,25 @@ export class RouterCore<
2426
2427
  let hookStayingMatches: Array<AnyRouteMatch> | null = null
2427
2428
 
2428
2429
  this.batch(() => {
2429
- const pendingMatches =
2430
- this.stores.pendingMatchesSnapshot.state
2430
+ const pendingMatches = this.stores.pendingMatches.get()
2431
2431
  const mountPending = pendingMatches.length
2432
- const currentMatches =
2433
- this.stores.activeMatchesSnapshot.state
2432
+ const currentMatches = this.stores.matches.get()
2434
2433
 
2435
2434
  exitingMatches = mountPending
2436
2435
  ? currentMatches.filter(
2437
2436
  (match) =>
2438
- !this.stores.pendingMatchStoresById.has(match.id),
2437
+ !this.stores.pendingMatchStores.has(match.id),
2439
2438
  )
2440
2439
  : null
2441
2440
 
2442
2441
  // Lifecycle-hook identity: routeId only (route presence in tree)
2443
2442
  // Build routeId sets from pools to avoid derived stores.
2444
2443
  const pendingRouteIds = new Set<string>()
2445
- for (const s of this.stores.pendingMatchStoresById.values()) {
2444
+ for (const s of this.stores.pendingMatchStores.values()) {
2446
2445
  if (s.routeId) pendingRouteIds.add(s.routeId)
2447
2446
  }
2448
2447
  const activeRouteIds = new Set<string>()
2449
- for (const s of this.stores.activeMatchStoresById.values()) {
2448
+ for (const s of this.stores.matchStores.values()) {
2450
2449
  if (s.routeId) activeRouteIds.add(s.routeId)
2451
2450
  }
2452
2451
 
@@ -2466,8 +2465,8 @@ export class RouterCore<
2466
2465
  )
2467
2466
  : currentMatches
2468
2467
 
2469
- this.stores.isLoading.setState(() => false)
2470
- this.stores.loadedAt.setState(() => Date.now())
2468
+ this.stores.isLoading.set(false)
2469
+ this.stores.loadedAt.set(Date.now())
2471
2470
  /**
2472
2471
  * When committing new matches, cache any exiting matches that are still usable.
2473
2472
  * Routes that resolved with `status: 'error'` or `status: 'notFound'` are
@@ -2475,10 +2474,10 @@ export class RouterCore<
2475
2474
  * or reloads re-run their loaders instead of reusing the failed/not-found data.
2476
2475
  */
2477
2476
  if (mountPending) {
2478
- this.stores.setActiveMatches(pendingMatches)
2479
- this.stores.setPendingMatches([])
2480
- this.stores.setCachedMatches([
2481
- ...this.stores.cachedMatchesSnapshot.state,
2477
+ this.stores.setMatches(pendingMatches)
2478
+ this.stores.setPending([])
2479
+ this.stores.setCached([
2480
+ ...this.stores.cachedMatches.get(),
2482
2481
  ...exitingMatches!.filter(
2483
2482
  (d) =>
2484
2483
  d.status !== 'error' &&
@@ -2525,15 +2524,13 @@ export class RouterCore<
2525
2524
  ? redirect.status
2526
2525
  : notFound
2527
2526
  ? 404
2528
- : this.stores.activeMatchesSnapshot.state.some(
2529
- (d) => d.status === 'error',
2530
- )
2527
+ : this.stores.matches.get().some((d) => d.status === 'error')
2531
2528
  ? 500
2532
2529
  : 200
2533
2530
 
2534
2531
  this.batch(() => {
2535
- this.stores.statusCode.setState(() => nextStatusCode)
2536
- this.stores.redirect.setState(() => redirect)
2532
+ this.stores.statusCode.set(nextStatusCode)
2533
+ this.stores.redirect.set(redirect)
2537
2534
  })
2538
2535
  }
2539
2536
 
@@ -2561,13 +2558,11 @@ export class RouterCore<
2561
2558
  let newStatusCode: number | undefined = undefined
2562
2559
  if (this.hasNotFoundMatch()) {
2563
2560
  newStatusCode = 404
2564
- } else if (
2565
- this.stores.activeMatchesSnapshot.state.some((d) => d.status === 'error')
2566
- ) {
2561
+ } else if (this.stores.matches.get().some((d) => d.status === 'error')) {
2567
2562
  newStatusCode = 500
2568
2563
  }
2569
2564
  if (newStatusCode !== undefined) {
2570
- this.stores.statusCode.setState(() => newStatusCode)
2565
+ this.stores.statusCode.set(newStatusCode)
2571
2566
  }
2572
2567
  }
2573
2568
 
@@ -2596,7 +2591,7 @@ export class RouterCore<
2596
2591
  this.isViewTransitionTypesSupported
2597
2592
  ) {
2598
2593
  const next = this.latestLocation
2599
- const prevLocation = this.stores.resolvedLocation.state
2594
+ const prevLocation = this.stores.resolvedLocation.get()
2600
2595
 
2601
2596
  const resolvedViewTransitionTypes =
2602
2597
  typeof shouldViewTransition.types === 'function'
@@ -2626,30 +2621,30 @@ export class RouterCore<
2626
2621
 
2627
2622
  updateMatch: UpdateMatchFn = (id, updater) => {
2628
2623
  this.startTransition(() => {
2629
- const pendingMatch = this.stores.pendingMatchStoresById.get(id)
2624
+ const pendingMatch = this.stores.pendingMatchStores.get(id)
2630
2625
  if (pendingMatch) {
2631
- pendingMatch.setState(updater)
2626
+ pendingMatch.set(updater)
2632
2627
  return
2633
2628
  }
2634
2629
 
2635
- const activeMatch = this.stores.activeMatchStoresById.get(id)
2630
+ const activeMatch = this.stores.matchStores.get(id)
2636
2631
  if (activeMatch) {
2637
- activeMatch.setState(updater)
2632
+ activeMatch.set(updater)
2638
2633
  return
2639
2634
  }
2640
2635
 
2641
- const cachedMatch = this.stores.cachedMatchStoresById.get(id)
2636
+ const cachedMatch = this.stores.cachedMatchStores.get(id)
2642
2637
  if (cachedMatch) {
2643
- const next = updater(cachedMatch.state)
2638
+ const next = updater(cachedMatch.get())
2644
2639
  if (next.status === 'redirected') {
2645
- const deleted = this.stores.cachedMatchStoresById.delete(id)
2640
+ const deleted = this.stores.cachedMatchStores.delete(id)
2646
2641
  if (deleted) {
2647
- this.stores.cachedMatchesId.setState((prev) =>
2642
+ this.stores.cachedIds.set((prev) =>
2648
2643
  prev.filter((matchId) => matchId !== id),
2649
2644
  )
2650
2645
  }
2651
2646
  } else {
2652
- cachedMatch.setState(() => next)
2647
+ cachedMatch.set(next)
2653
2648
  }
2654
2649
  }
2655
2650
  })
@@ -2657,9 +2652,9 @@ export class RouterCore<
2657
2652
 
2658
2653
  getMatch: GetMatchFn = (matchId: string): AnyRouteMatch | undefined => {
2659
2654
  return (
2660
- this.stores.cachedMatchStoresById.get(matchId)?.state ??
2661
- this.stores.pendingMatchStoresById.get(matchId)?.state ??
2662
- this.stores.activeMatchStoresById.get(matchId)?.state
2655
+ this.stores.cachedMatchStores.get(matchId)?.get() ??
2656
+ this.stores.pendingMatchStores.get(matchId)?.get() ??
2657
+ this.stores.matchStores.get(matchId)?.get()
2663
2658
  )
2664
2659
  }
2665
2660
 
@@ -2696,15 +2691,9 @@ export class RouterCore<
2696
2691
  }
2697
2692
 
2698
2693
  this.batch(() => {
2699
- this.stores.setActiveMatches(
2700
- this.stores.activeMatchesSnapshot.state.map(invalidate),
2701
- )
2702
- this.stores.setCachedMatches(
2703
- this.stores.cachedMatchesSnapshot.state.map(invalidate),
2704
- )
2705
- this.stores.setPendingMatches(
2706
- this.stores.pendingMatchesSnapshot.state.map(invalidate),
2707
- )
2694
+ this.stores.setMatches(this.stores.matches.get().map(invalidate))
2695
+ this.stores.setCached(this.stores.cachedMatches.get().map(invalidate))
2696
+ this.stores.setPending(this.stores.pendingMatches.get().map(invalidate))
2708
2697
  })
2709
2698
 
2710
2699
  this.shouldViewTransition = false
@@ -2762,13 +2751,13 @@ export class RouterCore<
2762
2751
  clearCache: ClearCacheFn<this> = (opts) => {
2763
2752
  const filter = opts?.filter
2764
2753
  if (filter !== undefined) {
2765
- this.stores.setCachedMatches(
2766
- this.stores.cachedMatchesSnapshot.state.filter(
2767
- (m) => !filter(m as MakeRouteMatchUnion<this>),
2768
- ),
2754
+ this.stores.setCached(
2755
+ this.stores.cachedMatches
2756
+ .get()
2757
+ .filter((m) => !filter(m as MakeRouteMatchUnion<this>)),
2769
2758
  )
2770
2759
  } else {
2771
- this.stores.setCachedMatches([])
2760
+ this.stores.setCached([])
2772
2761
  }
2773
2762
  }
2774
2763
 
@@ -2816,13 +2805,13 @@ export class RouterCore<
2816
2805
  })
2817
2806
 
2818
2807
  const activeMatchIds = new Set([
2819
- ...this.stores.matchesId.state,
2820
- ...this.stores.pendingMatchesId.state,
2808
+ ...this.stores.matchesId.get(),
2809
+ ...this.stores.pendingIds.get(),
2821
2810
  ])
2822
2811
 
2823
2812
  const loadedMatchIds = new Set([
2824
2813
  ...activeMatchIds,
2825
- ...this.stores.cachedMatchesId.state,
2814
+ ...this.stores.cachedIds.get(),
2826
2815
  ])
2827
2816
 
2828
2817
  // If the matches are already loaded, we need to add them to the cached matches.
@@ -2830,8 +2819,8 @@ export class RouterCore<
2830
2819
  (match) => !loadedMatchIds.has(match.id),
2831
2820
  )
2832
2821
  if (matchesToCache.length) {
2833
- const cachedMatches = this.stores.cachedMatchesSnapshot.state
2834
- this.stores.setCachedMatches([...cachedMatches, ...matchesToCache])
2822
+ const cachedMatches = this.stores.cachedMatches.get()
2823
+ this.stores.setCached([...cachedMatches, ...matchesToCache])
2835
2824
  }
2836
2825
 
2837
2826
  try {
@@ -2886,16 +2875,16 @@ export class RouterCore<
2886
2875
  }
2887
2876
  const next = this.buildLocation(matchLocation as any)
2888
2877
 
2889
- if (opts?.pending && this.stores.status.state !== 'pending') {
2878
+ if (opts?.pending && this.stores.status.get() !== 'pending') {
2890
2879
  return false
2891
2880
  }
2892
2881
 
2893
2882
  const pending =
2894
- opts?.pending === undefined ? !this.stores.isLoading.state : opts.pending
2883
+ opts?.pending === undefined ? !this.stores.isLoading.get() : opts.pending
2895
2884
 
2896
2885
  const baseLocation = pending
2897
2886
  ? this.latestLocation
2898
- : this.stores.resolvedLocation.state || this.stores.location.state
2887
+ : this.stores.resolvedLocation.get() || this.stores.location.get()
2899
2888
 
2900
2889
  const match = findSingleMatch(
2901
2890
  next.pathname,
@@ -2931,9 +2920,9 @@ export class RouterCore<
2931
2920
  serverSsr?: ServerSsr
2932
2921
 
2933
2922
  hasNotFoundMatch = () => {
2934
- return this.stores.activeMatchesSnapshot.state.some(
2935
- (d) => d.status === 'notFound' || d.globalNotFound,
2936
- )
2923
+ return this.stores.matches
2924
+ .get()
2925
+ .some((d) => d.status === 'notFound' || d.globalNotFound)
2937
2926
  }
2938
2927
  }
2939
2928
 
@@ -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.matches
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
  }
@@ -1,5 +1,5 @@
1
1
  import { createPlugin, createStream } from 'seroval'
2
- import type { Plugin } from 'seroval'
2
+ import type { PluginData, PluginInfo, SerovalNode } from 'seroval'
3
3
 
4
4
  /**
5
5
  * Hint for RawStream encoding strategy during SSR serialization.
@@ -240,61 +240,71 @@ function toTextStream(readable: ReadableStream<Uint8Array>) {
240
240
  }
241
241
 
242
242
  // Factory plugin for binary mode
243
- const RawStreamFactoryBinaryPlugin = createPlugin<
243
+ const RawStreamFactoryBinaryPlugin = /* @__PURE__ */ createPlugin<
244
244
  Record<string, never>,
245
- undefined
245
+ PluginInfo
246
246
  >({
247
247
  tag: 'tss/RawStreamFactory',
248
248
  test(value) {
249
249
  return value === RAW_STREAM_FACTORY_BINARY
250
250
  },
251
251
  parse: {
252
- sync() {
253
- return undefined
252
+ sync(_value, _ctx, _data) {
253
+ return {}
254
254
  },
255
- async() {
256
- return Promise.resolve(undefined)
255
+ async async(_value, _ctx, _data) {
256
+ return {}
257
257
  },
258
- stream() {
259
- return undefined
258
+ stream(_value, _ctx, _data) {
259
+ return {}
260
260
  },
261
261
  },
262
- serialize() {
262
+ serialize(_node, _ctx, _data) {
263
263
  return FACTORY_BINARY
264
264
  },
265
- deserialize() {
265
+ deserialize(_node, _ctx, _data) {
266
266
  return RAW_STREAM_FACTORY_BINARY
267
267
  },
268
268
  })
269
269
 
270
270
  // Factory plugin for text mode
271
- const RawStreamFactoryTextPlugin = createPlugin<
271
+ const RawStreamFactoryTextPlugin = /* @__PURE__ */ createPlugin<
272
272
  Record<string, never>,
273
- undefined
273
+ PluginInfo
274
274
  >({
275
275
  tag: 'tss/RawStreamFactoryText',
276
276
  test(value) {
277
277
  return value === RAW_STREAM_FACTORY_TEXT
278
278
  },
279
279
  parse: {
280
- sync() {
281
- return undefined
280
+ sync(_value, _ctx, _data) {
281
+ return {}
282
282
  },
283
- async() {
284
- return Promise.resolve(undefined)
283
+ async async(_value, _ctx, _data) {
284
+ return {}
285
285
  },
286
- stream() {
287
- return undefined
286
+ stream(_value, _ctx, _data) {
287
+ return {}
288
288
  },
289
289
  },
290
- serialize() {
290
+ serialize(_node, _ctx, _data) {
291
291
  return FACTORY_TEXT
292
292
  },
293
- deserialize() {
293
+ deserialize(_node, _ctx, _data) {
294
294
  return RAW_STREAM_FACTORY_TEXT
295
295
  },
296
296
  })
297
297
 
298
+ export interface RawStreamSSRNode extends PluginInfo {
299
+ hint: SerovalNode
300
+ factory: SerovalNode
301
+ stream: SerovalNode
302
+ }
303
+
304
+ export interface RawStreamRPCNode extends PluginInfo {
305
+ streamId: SerovalNode
306
+ }
307
+
298
308
  /**
299
309
  * SSR Plugin - uses base64 or UTF-8+base64 encoding for chunks, delegates to seroval's stream mechanism.
300
310
  * Used during SSR when serializing to JavaScript code for HTML injection.
@@ -303,7 +313,10 @@ const RawStreamFactoryTextPlugin = createPlugin<
303
313
  * - 'binary': Always base64 encode (default)
304
314
  * - 'text': Try UTF-8 first, fallback to base64 for invalid UTF-8
305
315
  */
306
- export const RawStreamSSRPlugin: Plugin<any, any> = createPlugin({
316
+ export const RawStreamSSRPlugin = /* @__PURE__ */ createPlugin<
317
+ RawStream,
318
+ RawStreamSSRNode
319
+ >({
307
320
  tag: 'tss/RawStream',
308
321
  extends: [RawStreamFactoryBinaryPlugin, RawStreamFactoryTextPlugin],
309
322
 
@@ -312,19 +325,19 @@ export const RawStreamSSRPlugin: Plugin<any, any> = createPlugin({
312
325
  },
313
326
 
314
327
  parse: {
315
- sync(value: RawStream, ctx) {
328
+ sync(value: RawStream, ctx, _data) {
316
329
  // Sync parse not really supported for streams, return empty stream
317
330
  const factory =
318
331
  value.hint === 'text'
319
332
  ? RAW_STREAM_FACTORY_TEXT
320
333
  : RAW_STREAM_FACTORY_BINARY
321
334
  return {
322
- hint: value.hint,
335
+ hint: ctx.parse(value.hint),
323
336
  factory: ctx.parse(factory),
324
337
  stream: ctx.parse(createStream()),
325
338
  }
326
339
  },
327
- async async(value: RawStream, ctx) {
340
+ async async(value: RawStream, ctx, _data) {
328
341
  const factory =
329
342
  value.hint === 'text'
330
343
  ? RAW_STREAM_FACTORY_TEXT
@@ -334,12 +347,12 @@ export const RawStreamSSRPlugin: Plugin<any, any> = createPlugin({
334
347
  ? toTextStream(value.stream)
335
348
  : toBinaryStream(value.stream)
336
349
  return {
337
- hint: value.hint,
350
+ hint: await ctx.parse(value.hint),
338
351
  factory: await ctx.parse(factory),
339
352
  stream: await ctx.parse(encodedStream),
340
353
  }
341
354
  },
342
- stream(value: RawStream, ctx) {
355
+ stream(value: RawStream, ctx, _data) {
343
356
  const factory =
344
357
  value.hint === 'text'
345
358
  ? RAW_STREAM_FACTORY_TEXT
@@ -349,14 +362,14 @@ export const RawStreamSSRPlugin: Plugin<any, any> = createPlugin({
349
362
  ? toTextStream(value.stream)
350
363
  : toBinaryStream(value.stream)
351
364
  return {
352
- hint: value.hint,
365
+ hint: ctx.parse(value.hint),
353
366
  factory: ctx.parse(factory),
354
367
  stream: ctx.parse(encodedStream),
355
368
  }
356
369
  },
357
370
  },
358
371
 
359
- serialize(node: { hint: RawStreamHint; factory: any; stream: any }, ctx) {
372
+ serialize(node: RawStreamSSRNode, ctx, _data) {
360
373
  return (
361
374
  '(' +
362
375
  ctx.serialize(node.factory) +
@@ -366,23 +379,14 @@ export const RawStreamSSRPlugin: Plugin<any, any> = createPlugin({
366
379
  )
367
380
  },
368
381
 
369
- deserialize(
370
- node: { hint: RawStreamHint; factory: any; stream: any },
371
- ctx,
372
- ): any {
382
+ deserialize(node: RawStreamSSRNode, ctx, _data): any {
373
383
  const stream: ReturnType<typeof createStream> = ctx.deserialize(node.stream)
374
- return node.hint === 'text'
384
+ const hint = ctx.deserialize(node.hint)
385
+ return hint === 'text'
375
386
  ? RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT(stream)
376
387
  : RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY(stream)
377
388
  },
378
- }) as Plugin<any, any>
379
-
380
- /**
381
- * Node type for RPC plugin serialization
382
- */
383
- interface RawStreamRPCNode {
384
- streamId: number
385
- }
389
+ })
386
390
 
387
391
  /**
388
392
  * Creates an RPC plugin instance that registers raw streams with a multiplexer.
@@ -391,13 +395,12 @@ interface RawStreamRPCNode {
391
395
  *
392
396
  * @param onRawStream Callback invoked when a RawStream is encountered during serialization
393
397
  */
394
- export function createRawStreamRPCPlugin(
395
- onRawStream: OnRawStreamCallback,
396
- ): Plugin<any, any> {
398
+ /* @__NO_SIDE_EFFECTS__ */
399
+ export function createRawStreamRPCPlugin(onRawStream: OnRawStreamCallback) {
397
400
  // Own stream counter - sequential IDs starting at 1, independent of seroval internals
398
401
  let nextStreamId = 1
399
402
 
400
- return createPlugin({
403
+ return /* @__PURE__ */ createPlugin<RawStream, RawStreamRPCNode>({
401
404
  tag: 'tss/RawStream',
402
405
 
403
406
  test(value: unknown) {
@@ -405,15 +408,15 @@ export function createRawStreamRPCPlugin(
405
408
  },
406
409
 
407
410
  parse: {
408
- async(value: RawStream) {
411
+ async async(value: RawStream, ctx, _data: PluginData) {
409
412
  const streamId = nextStreamId++
410
413
  onRawStream(streamId, value.stream)
411
- return Promise.resolve({ streamId })
414
+ return { streamId: await ctx.parse(streamId) }
412
415
  },
413
- stream(value: RawStream) {
416
+ stream(value: RawStream, ctx, _data: PluginData) {
414
417
  const streamId = nextStreamId++
415
418
  onRawStream(streamId, value.stream)
416
- return { streamId }
419
+ return { streamId: ctx.parse(streamId) }
417
420
  },
418
421
  },
419
422
 
@@ -431,7 +434,7 @@ export function createRawStreamRPCPlugin(
431
434
  'RawStreamRPCPlugin.deserialize should not be called. Use createRawStreamDeserializePlugin on client.',
432
435
  )
433
436
  },
434
- }) as Plugin<any, any>
437
+ })
435
438
  }
436
439
 
437
440
  /**
@@ -442,8 +445,8 @@ export function createRawStreamRPCPlugin(
442
445
  */
443
446
  export function createRawStreamDeserializePlugin(
444
447
  getOrCreateStream: (id: number) => ReadableStream<Uint8Array>,
445
- ): Plugin<any, any> {
446
- return createPlugin({
448
+ ) {
449
+ return /* @__PURE__ */ createPlugin<any, RawStreamRPCNode>({
447
450
  tag: 'tss/RawStream',
448
451
 
449
452
  test: () => false, // Client never serializes RawStream
@@ -457,8 +460,14 @@ export function createRawStreamDeserializePlugin(
457
460
  )
458
461
  },
459
462
 
460
- deserialize(node: RawStreamRPCNode) {
461
- return getOrCreateStream(node.streamId)
463
+ deserialize(node, ctx, _data) {
464
+ // In normal seroval usage, ctx.deserialize exists.
465
+ // Some unit tests call plugin.deserialize directly with a minimal ctx.
466
+ const id =
467
+ typeof (ctx as any)?.deserialize === 'function'
468
+ ? (ctx as any).deserialize(node.streamId)
469
+ : (node as any).streamId
470
+ return getOrCreateStream(id as number)
462
471
  },
463
- }) as Plugin<any, any>
472
+ })
464
473
  }