@tanstack/router-core 1.125.4 → 1.127.0

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 (77) hide show
  1. package/dist/cjs/Matches.cjs.map +1 -1
  2. package/dist/cjs/Matches.d.cts +1 -1
  3. package/dist/cjs/RouterProvider.d.cts +1 -0
  4. package/dist/cjs/index.d.cts +1 -2
  5. package/dist/cjs/router.cjs +26 -33
  6. package/dist/cjs/router.cjs.map +1 -1
  7. package/dist/cjs/router.d.cts +10 -57
  8. package/dist/cjs/ssr/client.cjs +0 -2
  9. package/dist/cjs/ssr/client.cjs.map +1 -1
  10. package/dist/cjs/ssr/client.d.cts +1 -2
  11. package/dist/cjs/ssr/createRequestHandler.cjs +2 -1
  12. package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
  13. package/dist/cjs/ssr/seroval-plugins.cjs +34 -0
  14. package/dist/cjs/ssr/seroval-plugins.cjs.map +1 -0
  15. package/dist/cjs/ssr/seroval-plugins.d.cts +10 -0
  16. package/dist/cjs/ssr/server.cjs +0 -4
  17. package/dist/cjs/ssr/server.cjs.map +1 -1
  18. package/dist/cjs/ssr/server.d.cts +1 -3
  19. package/dist/cjs/ssr/ssr-client.cjs +18 -56
  20. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  21. package/dist/cjs/ssr/ssr-client.d.cts +17 -57
  22. package/dist/cjs/ssr/ssr-server.cjs +75 -220
  23. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  24. package/dist/cjs/ssr/ssr-server.d.cts +14 -28
  25. package/dist/cjs/ssr/transformStreamWithRouter.cjs +1 -0
  26. package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
  27. package/dist/cjs/ssr/tsrScript.cjs +1 -1
  28. package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
  29. package/dist/cjs/ssr/tsrScript.d.cts +0 -1
  30. package/dist/esm/Matches.d.ts +1 -1
  31. package/dist/esm/Matches.js.map +1 -1
  32. package/dist/esm/RouterProvider.d.ts +1 -0
  33. package/dist/esm/index.d.ts +1 -2
  34. package/dist/esm/router.d.ts +10 -57
  35. package/dist/esm/router.js +26 -33
  36. package/dist/esm/router.js.map +1 -1
  37. package/dist/esm/ssr/client.d.ts +1 -2
  38. package/dist/esm/ssr/client.js +1 -3
  39. package/dist/esm/ssr/client.js.map +1 -1
  40. package/dist/esm/ssr/createRequestHandler.js +3 -2
  41. package/dist/esm/ssr/createRequestHandler.js.map +1 -1
  42. package/dist/esm/ssr/seroval-plugins.d.ts +10 -0
  43. package/dist/esm/ssr/seroval-plugins.js +34 -0
  44. package/dist/esm/ssr/seroval-plugins.js.map +1 -0
  45. package/dist/esm/ssr/server.d.ts +1 -3
  46. package/dist/esm/ssr/server.js +1 -5
  47. package/dist/esm/ssr/ssr-client.d.ts +17 -57
  48. package/dist/esm/ssr/ssr-client.js +18 -56
  49. package/dist/esm/ssr/ssr-client.js.map +1 -1
  50. package/dist/esm/ssr/ssr-server.d.ts +14 -28
  51. package/dist/esm/ssr/ssr-server.js +76 -221
  52. package/dist/esm/ssr/ssr-server.js.map +1 -1
  53. package/dist/esm/ssr/transformStreamWithRouter.js +1 -0
  54. package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
  55. package/dist/esm/ssr/tsrScript.d.ts +0 -1
  56. package/dist/esm/ssr/tsrScript.js +1 -1
  57. package/dist/esm/ssr/tsrScript.js.map +1 -1
  58. package/package.json +3 -1
  59. package/src/Matches.ts +1 -1
  60. package/src/RouterProvider.ts +1 -0
  61. package/src/index.ts +0 -18
  62. package/src/router.ts +41 -89
  63. package/src/ssr/client.ts +1 -11
  64. package/src/ssr/createRequestHandler.ts +2 -2
  65. package/src/ssr/seroval-plugins.ts +43 -0
  66. package/src/ssr/server.ts +1 -14
  67. package/src/ssr/ssr-client.ts +35 -128
  68. package/src/ssr/ssr-server.ts +89 -307
  69. package/src/ssr/transformStreamWithRouter.ts +1 -0
  70. package/src/ssr/tsrScript.ts +4 -88
  71. package/dist/cjs/serializer.cjs +0 -146
  72. package/dist/cjs/serializer.cjs.map +0 -1
  73. package/dist/cjs/serializer.d.cts +0 -28
  74. package/dist/esm/serializer.d.ts +0 -28
  75. package/dist/esm/serializer.js +0 -146
  76. package/dist/esm/serializer.js.map +0 -1
  77. package/src/serializer.ts +0 -205
package/src/router.ts CHANGED
@@ -46,7 +46,6 @@ import type {
46
46
  Updater,
47
47
  } from './utils'
48
48
  import type { ParsedLocation } from './location'
49
- import type { DeferredPromiseState } from './defer'
50
49
  import type {
51
50
  AnyContext,
52
51
  AnyRoute,
@@ -78,7 +77,6 @@ import type {
78
77
  NavigateFn,
79
78
  } from './RouterProvider'
80
79
  import type { Manifest } from './manifest'
81
- import type { TsrSerializer } from './serializer'
82
80
  import type { AnySchema, AnyValidator } from './validators'
83
81
  import type { NavigateOptions, ResolveRelativePath, ToOptions } from './link'
84
82
  import type { NotFoundError } from './not-found'
@@ -288,7 +286,7 @@ export interface RouterOptions<
288
286
  * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)
289
287
  * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)
290
288
  */
291
- dehydrate?: () => TDehydrated
289
+ dehydrate?: () => Awaitable<TDehydrated>
292
290
  /**
293
291
  * A function that will be called when the router is hydrated.
294
292
  *
@@ -441,6 +439,7 @@ export interface BuildNextOptions {
441
439
  href?: string
442
440
  _fromLocation?: ParsedLocation
443
441
  unsafeRelative?: 'path'
442
+ _isNavigate?: boolean
444
443
  }
445
444
 
446
445
  type NavigationEventInfo = {
@@ -451,7 +450,7 @@ type NavigationEventInfo = {
451
450
  hashChanged: boolean
452
451
  }
453
452
 
454
- export type RouterEvents = {
453
+ export interface RouterEvents {
455
454
  onBeforeNavigate: {
456
455
  type: 'onBeforeNavigate'
457
456
  } & NavigationEventInfo
@@ -467,10 +466,6 @@ export type RouterEvents = {
467
466
  onBeforeRouteMount: {
468
467
  type: 'onBeforeRouteMount'
469
468
  } & NavigationEventInfo
470
- onInjectedHtml: {
471
- type: 'onInjectedHtml'
472
- promise: Promise<string>
473
- }
474
469
  onRendered: {
475
470
  type: 'onRendered'
476
471
  } & NavigationEventInfo
@@ -485,6 +480,11 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
485
480
  fn: ListenerFn<TRouterEvent>
486
481
  }
487
482
 
483
+ export type SubscribeFn = <TType extends keyof RouterEvents>(
484
+ eventType: TType,
485
+ fn: ListenerFn<RouterEvents[TType]>,
486
+ ) => () => void
487
+
488
488
  export interface MatchRoutesOpts {
489
489
  preload?: boolean
490
490
  throwOnError?: boolean
@@ -522,11 +522,6 @@ export type RouterConstructorOptions<
522
522
  > &
523
523
  RouterContextOptions<TRouteTree>
524
524
 
525
- export interface RouterErrorSerializer<TSerializedError> {
526
- serialize: (err: unknown) => TSerializedError
527
- deserialize: (err: TSerializedError) => unknown
528
- }
529
-
530
525
  export type PreloadRouteFn<
531
526
  TRouteTree extends AnyRoute,
532
527
  TTrailingSlashOption extends TrailingSlashOption,
@@ -623,11 +618,6 @@ export type CommitLocationFn = ({
623
618
 
624
619
  export type StartTransitionFn = (fn: () => void) => void
625
620
 
626
- export type SubscribeFn = <TType extends keyof RouterEvents>(
627
- eventType: TType,
628
- fn: ListenerFn<RouterEvents[TType]>,
629
- ) => () => void
630
-
631
621
  export interface MatchRoutesFn {
632
622
  (
633
623
  pathname: string,
@@ -657,16 +647,16 @@ export type ClearCacheFn<TRouter extends AnyRouter> = (opts?: {
657
647
  filter?: (d: MakeRouteMatchUnion<TRouter>) => boolean
658
648
  }) => void
659
649
 
660
- export interface ServerSrr {
650
+ export interface ServerSsr {
661
651
  injectedHtml: Array<InjectedHtmlEntry>
662
652
  injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>
663
653
  injectScript: (
664
654
  getScript: () => string | Promise<string>,
665
655
  opts?: { logScript?: boolean },
666
656
  ) => Promise<void>
667
- streamValue: (key: string, value: any) => void
668
- streamedKeys: Set<string>
669
- onMatchSettled: (opts: { router: AnyRouter; match: AnyRouteMatch }) => any
657
+ isDehydrated: () => boolean
658
+ onRenderFinished: (listener: () => void) => void
659
+ dehydrate: () => Promise<void>
670
660
  }
671
661
 
672
662
  export type AnyRouterWithContext<TContext> = RouterCore<
@@ -709,29 +699,6 @@ export function defaultSerializeError(err: unknown) {
709
699
  data: err,
710
700
  }
711
701
  }
712
- export interface ExtractedBaseEntry {
713
- dataType: '__beforeLoadContext' | 'loaderData'
714
- type: string
715
- path: Array<string>
716
- id: number
717
- matchIndex: number
718
- }
719
-
720
- export interface ExtractedStream extends ExtractedBaseEntry {
721
- type: 'stream'
722
- streamState: StreamState
723
- }
724
-
725
- export interface ExtractedPromise extends ExtractedBaseEntry {
726
- type: 'promise'
727
- promiseState: DeferredPromiseState<any>
728
- }
729
-
730
- export type ExtractedEntry = ExtractedStream | ExtractedPromise
731
-
732
- export type StreamState = {
733
- promises: Array<ControlledPromise<string | null>>
734
- }
735
702
 
736
703
  export type TrailingSlashOption = 'always' | 'never' | 'preserve'
737
704
 
@@ -837,7 +804,7 @@ export class RouterCore<
837
804
  })
838
805
 
839
806
  if (typeof document !== 'undefined') {
840
- ;(window as any).__TSR_ROUTER__ = this
807
+ self.__TSR_ROUTER__ = this
841
808
  }
842
809
  }
843
810
 
@@ -1292,7 +1259,7 @@ export class RouterCore<
1292
1259
  error: undefined,
1293
1260
  paramsError: parseErrors[index],
1294
1261
  __routeContext: {},
1295
- __beforeLoadContext: {},
1262
+ __beforeLoadContext: undefined,
1296
1263
  context: {},
1297
1264
  abortController: new AbortController(),
1298
1265
  fetchCount: 0,
@@ -1419,11 +1386,11 @@ export class RouterCore<
1419
1386
  // We allow the caller to override the current location
1420
1387
  const currentLocation = dest._fromLocation || this.latestLocation
1421
1388
 
1422
- const allFromMatches = this.matchRoutes(currentLocation, {
1389
+ const allCurrentLocationMatches = this.matchRoutes(currentLocation, {
1423
1390
  _buildLocation: true,
1424
1391
  })
1425
1392
 
1426
- const lastMatch = last(allFromMatches)!
1393
+ const lastMatch = last(allCurrentLocationMatches)!
1427
1394
 
1428
1395
  // First let's find the starting pathname
1429
1396
  // By default, start with the current location
@@ -1442,12 +1409,29 @@ export class RouterCore<
1442
1409
  fromPath = currentLocation.pathname
1443
1410
  } else if (routeIsChanging && dest.from) {
1444
1411
  fromPath = dest.from
1445
- const existingFrom = [...allFromMatches].reverse().find((d) => {
1446
- return this.comparePaths(d.fullPath, fromPath)
1447
- })
1448
1412
 
1449
- if (!existingFrom) {
1450
- console.warn(`Could not find match for from: ${fromPath}`)
1413
+ // do this check only on navigations during test or development
1414
+ if (process.env.NODE_ENV !== 'production' && dest._isNavigate) {
1415
+ const allFromMatches = this.getMatchedRoutes(
1416
+ dest.from,
1417
+ undefined,
1418
+ ).matchedRoutes
1419
+
1420
+ const matchedFrom = [...allCurrentLocationMatches]
1421
+ .reverse()
1422
+ .find((d) => {
1423
+ return this.comparePaths(d.fullPath, fromPath)
1424
+ })
1425
+
1426
+ const matchedCurrent = [...allFromMatches].reverse().find((d) => {
1427
+ return this.comparePaths(d.fullPath, currentLocation.pathname)
1428
+ })
1429
+
1430
+ // for from to be invalid it shouldn't just be unmatched to currentLocation
1431
+ // but the currentLocation should also be unmatched to from
1432
+ if (!matchedFrom && !matchedCurrent) {
1433
+ console.warn(`Could not find match for from: ${fromPath}`)
1434
+ }
1451
1435
  }
1452
1436
  }
1453
1437
 
@@ -1777,6 +1761,7 @@ export class RouterCore<
1777
1761
  ...rest,
1778
1762
  href,
1779
1763
  to: to as string,
1764
+ _isNavigate: true,
1780
1765
  })
1781
1766
  }
1782
1767
 
@@ -2169,10 +2154,6 @@ export class RouterCore<
2169
2154
  this._handleNotFound(matches, err, {
2170
2155
  updateMatch,
2171
2156
  })
2172
- this.serverSsr?.onMatchSettled({
2173
- router: this,
2174
- match: this.getMatch(match.id)!,
2175
- })
2176
2157
  throw err
2177
2158
  }
2178
2159
  }
@@ -2430,8 +2411,7 @@ export class RouterCore<
2430
2411
  }
2431
2412
 
2432
2413
  const beforeLoadContext =
2433
- (await route.options.beforeLoad?.(beforeLoadFnContext)) ??
2434
- {}
2414
+ await route.options.beforeLoad?.(beforeLoadFnContext)
2435
2415
 
2436
2416
  if (
2437
2417
  isRedirect(beforeLoadContext) ||
@@ -2524,10 +2504,6 @@ export class RouterCore<
2524
2504
  ...prev,
2525
2505
  ...head,
2526
2506
  }))
2527
- this.serverSsr?.onMatchSettled({
2528
- router: this,
2529
- match: this.getMatch(matchId)!,
2530
- })
2531
2507
  return this.getMatch(matchId)!
2532
2508
  } else {
2533
2509
  await potentialPendingMinPromise()
@@ -2689,11 +2665,6 @@ export class RouterCore<
2689
2665
  ...head,
2690
2666
  }))
2691
2667
  }
2692
-
2693
- this.serverSsr?.onMatchSettled({
2694
- router: this,
2695
- match: this.getMatch(matchId)!,
2696
- })
2697
2668
  } catch (err) {
2698
2669
  const head = await executeHead()
2699
2670
 
@@ -2754,10 +2725,6 @@ export class RouterCore<
2754
2725
  ...prev,
2755
2726
  ...head,
2756
2727
  }))
2757
- this.serverSsr?.onMatchSettled({
2758
- router: this,
2759
- match: this.getMatch(matchId)!,
2760
- })
2761
2728
  }
2762
2729
  }
2763
2730
  if (!loaderIsRunningAsync) {
@@ -3057,24 +3024,9 @@ export class RouterCore<
3057
3024
 
3058
3025
  ssr?: {
3059
3026
  manifest: Manifest | undefined
3060
- serializer: TsrSerializer
3061
- }
3062
-
3063
- serverSsr?: {
3064
- injectedHtml: Array<InjectedHtmlEntry>
3065
- injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>
3066
- injectScript: (
3067
- getScript: () => string | Promise<string>,
3068
- opts?: { logScript?: boolean },
3069
- ) => Promise<void>
3070
- streamValue: (key: string, value: any) => void
3071
- streamedKeys: Set<string>
3072
- onMatchSettled: (opts: { router: AnyRouter; match: AnyRouteMatch }) => any
3073
3027
  }
3074
3028
 
3075
- clientSsr?: {
3076
- getStreamedValue: <T>(key: string) => T | undefined
3077
- }
3029
+ serverSsr?: ServerSsr
3078
3030
 
3079
3031
  _handleNotFound = (
3080
3032
  matches: Array<AnyRouteMatch>,
package/src/ssr/client.ts CHANGED
@@ -2,14 +2,4 @@ export { mergeHeaders, headersInitToObject } from './headers'
2
2
  export { json } from './json'
3
3
  export type { JsonResponse } from './json'
4
4
  export { hydrate } from './ssr-client'
5
- export type {
6
- DehydratedRouter,
7
- ClientExtractedBaseEntry,
8
- TsrSsrGlobal,
9
- ClientExtractedEntry,
10
- SsrMatch,
11
- ClientExtractedPromise,
12
- ClientExtractedStream,
13
- ResolvePromiseState,
14
- } from './ssr-client'
15
- export { tsrSerializer } from '../serializer'
5
+ export * from './ssr-client'
@@ -1,6 +1,6 @@
1
1
  import { createMemoryHistory } from '@tanstack/history'
2
2
  import { mergeHeaders } from './headers'
3
- import { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server'
3
+ import { attachRouterServerSsrUtils } from './ssr-server'
4
4
  import type { HandlerCallback } from './handlerCallback'
5
5
  import type { AnyRouter } from '../router'
6
6
  import type { Manifest } from '../manifest'
@@ -39,7 +39,7 @@ export function createRequestHandler<TRouter extends AnyRouter>({
39
39
 
40
40
  await router.load()
41
41
 
42
- dehydrateRouter(router)
42
+ await router.serverSsr?.dehydrate()
43
43
 
44
44
  const responseHeaders = getRequestHeaders({
45
45
  router,
@@ -0,0 +1,43 @@
1
+ import { createPlugin } from 'seroval'
2
+ import type { SerovalNode } from 'seroval'
3
+
4
+ interface ErrorNode {
5
+ message: SerovalNode
6
+ }
7
+
8
+ /**
9
+ * this plugin serializes only the `message` part of an Error
10
+ * this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized
11
+ */
12
+ export const ShallowErrorPlugin = /* @__PURE__ */ createPlugin<
13
+ Error,
14
+ ErrorNode
15
+ >({
16
+ tag: 'tanstack-start:seroval-plugins/Error',
17
+ test(value) {
18
+ return value instanceof Error
19
+ },
20
+ parse: {
21
+ sync(value, ctx) {
22
+ return {
23
+ message: ctx.parse(value.message),
24
+ }
25
+ },
26
+ async async(value, ctx) {
27
+ return {
28
+ message: await ctx.parse(value.message),
29
+ }
30
+ },
31
+ stream(value, ctx) {
32
+ return {
33
+ message: ctx.parse(value.message),
34
+ }
35
+ },
36
+ },
37
+ serialize(node, ctx) {
38
+ return 'new Error(' + ctx.serialize(node.message) + ')'
39
+ },
40
+ deserialize(node, ctx) {
41
+ return new Error(ctx.deserialize(node.message) as string)
42
+ },
43
+ })
package/src/ssr/server.ts CHANGED
@@ -7,17 +7,4 @@ export {
7
7
  transformStreamWithRouter,
8
8
  transformReadableStreamWithRouter,
9
9
  } from './transformStreamWithRouter'
10
- export {
11
- attachRouterServerSsrUtils,
12
- dehydrateRouter,
13
- extractAsyncLoaderData,
14
- onMatchSettled,
15
- replaceBy,
16
- } from './ssr-server'
17
- export type {
18
- ServerExtractedBaseEntry,
19
- ServerExtractedEntry,
20
- ServerExtractedPromise,
21
- ServerExtractedStream,
22
- } from './ssr-server'
23
- export * from './tsrScript'
10
+ export { attachRouterServerSsrUtils } from './ssr-server'
@@ -1,114 +1,62 @@
1
1
  import invariant from 'tiny-invariant'
2
- import { isPlainObject } from '../utils'
3
- import { tsrSerializer } from '../serializer'
4
- import type { DeferredPromiseState } from '../defer'
5
2
  import type { MakeRouteMatch } from '../Matches'
6
- import type { AnyRouter, ControllablePromise } from '../router'
3
+ import type { AnyRouter } from '../router'
7
4
  import type { Manifest } from '../manifest'
8
5
  import type { RouteContextOptions } from '../route'
6
+ import type { GLOBAL_TSR } from './ssr-server'
9
7
 
10
8
  declare global {
11
9
  interface Window {
12
- __TSR_SSR__?: TsrSsrGlobal
10
+ [GLOBAL_TSR]?: TsrSsrGlobal
13
11
  }
14
12
  }
15
13
 
16
14
  export interface TsrSsrGlobal {
17
- matches: Array<SsrMatch>
18
- streamedValues: Record<
19
- string,
20
- {
21
- value: any
22
- parsed: any
23
- }
24
- >
25
- cleanScripts: () => void
26
- dehydrated?: any
27
- initMatch: (match: SsrMatch) => void
28
- resolvePromise: (opts: {
29
- matchId: string
30
- id: number
31
- promiseState: DeferredPromiseState<any>
32
- }) => void
33
- injectChunk: (opts: { matchId: string; id: number; chunk: string }) => void
34
- closeStream: (opts: { matchId: string; id: number }) => void
35
- }
36
-
37
- export interface SsrMatch {
38
- id: string
39
- __beforeLoadContext: string
40
- loaderData?: string
41
- error?: string
42
- extracted?: Array<ClientExtractedEntry>
43
- updatedAt: MakeRouteMatch['updatedAt']
44
- status: MakeRouteMatch['status']
45
- ssr?: boolean | 'data-only'
15
+ router?: DehydratedRouter
16
+ // clean scripts, shortened since this is sent for each streamed script
17
+ c: () => void
46
18
  }
47
19
 
48
- export type ClientExtractedEntry =
49
- | ClientExtractedStream
50
- | ClientExtractedPromise
51
-
52
- export interface ClientExtractedPromise extends ClientExtractedBaseEntry {
53
- type: 'promise'
54
- value?: ControllablePromise<any>
55
- }
56
-
57
- export interface ClientExtractedStream extends ClientExtractedBaseEntry {
58
- type: 'stream'
59
- value?: ReadableStream & { controller?: ReadableStreamDefaultController }
60
- }
61
-
62
- export interface ClientExtractedBaseEntry {
63
- type: string
64
- path: Array<string>
20
+ function hydrateMatch(
21
+ deyhydratedMatch: DehydratedMatch,
22
+ ): Partial<MakeRouteMatch> {
23
+ return {
24
+ id: deyhydratedMatch.i,
25
+ __beforeLoadContext: deyhydratedMatch.b,
26
+ loaderData: deyhydratedMatch.l,
27
+ status: deyhydratedMatch.s,
28
+ ssr: deyhydratedMatch.ssr,
29
+ updatedAt: deyhydratedMatch.u,
30
+ error: deyhydratedMatch.e,
31
+ }
65
32
  }
66
-
67
- export interface ResolvePromiseState {
68
- matchId: string
69
- id: number
70
- promiseState: DeferredPromiseState<any>
33
+ export interface DehydratedMatch {
34
+ i: MakeRouteMatch['id']
35
+ b?: MakeRouteMatch['__beforeLoadContext']
36
+ l?: MakeRouteMatch['loaderData']
37
+ e?: MakeRouteMatch['error']
38
+ u: MakeRouteMatch['updatedAt']
39
+ s: MakeRouteMatch['status']
40
+ ssr?: MakeRouteMatch['ssr']
71
41
  }
72
42
 
73
43
  export interface DehydratedRouter {
74
44
  manifest: Manifest | undefined
75
- dehydratedData: any
76
- lastMatchId: string
45
+ dehydratedData?: any
46
+ lastMatchId?: string
47
+ matches: Array<DehydratedMatch>
77
48
  }
78
49
 
79
50
  export async function hydrate(router: AnyRouter): Promise<any> {
80
51
  invariant(
81
- window.__TSR_SSR__?.dehydrated,
82
- 'Expected to find a dehydrated data on window.__TSR_SSR__.dehydrated... but we did not. Please file an issue!',
52
+ window.$_TSR?.router,
53
+ 'Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!',
83
54
  )
84
55
 
85
- const { manifest, dehydratedData, lastMatchId } = tsrSerializer.parse(
86
- window.__TSR_SSR__.dehydrated,
87
- ) as DehydratedRouter
56
+ const { manifest, dehydratedData, lastMatchId } = window.$_TSR.router
88
57
 
89
58
  router.ssr = {
90
59
  manifest,
91
- serializer: tsrSerializer,
92
- }
93
-
94
- router.clientSsr = {
95
- getStreamedValue: <T>(key: string): T | undefined => {
96
- if (router.isServer) {
97
- return undefined
98
- }
99
-
100
- const streamedValue = window.__TSR_SSR__?.streamedValues[key]
101
-
102
- if (!streamedValue) {
103
- return
104
- }
105
-
106
- if (!streamedValue.parsed) {
107
- streamedValue.parsed = router.ssr!.serializer.parse(streamedValue.value)
108
- }
109
-
110
- return streamedValue.parsed
111
- },
112
60
  }
113
61
 
114
62
  // Hydrate the router state
@@ -126,16 +74,15 @@ export async function hydrate(router: AnyRouter): Promise<any> {
126
74
  // First step is to reyhdrate loaderData and __beforeLoadContext
127
75
  let firstNonSsrMatchIndex: number | undefined = undefined
128
76
  matches.forEach((match) => {
129
- const dehydratedMatch = window.__TSR_SSR__!.matches.find(
130
- (d) => d.id === match.id,
77
+ const dehydratedMatch = window.$_TSR!.router!.matches.find(
78
+ (d) => d.i === match.id,
131
79
  )
132
-
133
80
  if (!dehydratedMatch) {
134
81
  Object.assign(match, { dehydrated: false, ssr: false })
135
82
  return
136
83
  }
137
84
 
138
- Object.assign(match, dehydratedMatch)
85
+ Object.assign(match, hydrateMatch(dehydratedMatch))
139
86
 
140
87
  if (match.ssr === false) {
141
88
  match._dehydrated = false
@@ -153,30 +100,6 @@ export async function hydrate(router: AnyRouter): Promise<any> {
153
100
  if (match.ssr === false) {
154
101
  return
155
102
  }
156
-
157
- // Handle beforeLoadContext
158
- if (dehydratedMatch.__beforeLoadContext) {
159
- match.__beforeLoadContext = router.ssr!.serializer.parse(
160
- dehydratedMatch.__beforeLoadContext,
161
- ) as any
162
- }
163
-
164
- // Handle loaderData
165
- if (dehydratedMatch.loaderData) {
166
- match.loaderData = router.ssr!.serializer.parse(
167
- dehydratedMatch.loaderData,
168
- )
169
- }
170
-
171
- // Handle error
172
- if (dehydratedMatch.error) {
173
- match.error = router.ssr!.serializer.parse(dehydratedMatch.error)
174
- }
175
-
176
- // Handle extracted
177
- ;(match as unknown as SsrMatch).extracted?.forEach((ex) => {
178
- deepMutableSetByPath(match, ['loaderData', ...ex.path], ex.value)
179
- })
180
103
  })
181
104
 
182
105
  router.__store.setState((s) => {
@@ -271,21 +194,5 @@ export async function hydrate(router: AnyRouter): Promise<any> {
271
194
  })
272
195
  })
273
196
  }
274
-
275
197
  return routeChunkPromise
276
198
  }
277
-
278
- function deepMutableSetByPath<T>(obj: T, path: Array<string>, value: any) {
279
- // mutable set by path retaining array and object references
280
- if (path.length === 1) {
281
- ;(obj as any)[path[0]!] = value
282
- }
283
-
284
- const [key, ...rest] = path
285
-
286
- if (Array.isArray(obj)) {
287
- deepMutableSetByPath(obj[Number(key)], rest, value)
288
- } else if (isPlainObject(obj)) {
289
- deepMutableSetByPath((obj as any)[key!], rest, value)
290
- }
291
- }