@tanstack/react-router 1.97.14 → 1.97.17

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/Match.cjs +8 -24
  2. package/dist/cjs/Match.cjs.map +1 -1
  3. package/dist/cjs/Matches.cjs +1 -1
  4. package/dist/cjs/Matches.cjs.map +1 -1
  5. package/dist/cjs/RouterProvider.cjs.map +1 -1
  6. package/dist/cjs/RouterProvider.d.cts +0 -1
  7. package/dist/cjs/ScriptOnce.cjs +1 -8
  8. package/dist/cjs/ScriptOnce.cjs.map +1 -1
  9. package/dist/cjs/ScriptOnce.d.cts +1 -1
  10. package/dist/cjs/Transitioner.cjs +1 -2
  11. package/dist/cjs/Transitioner.cjs.map +1 -1
  12. package/dist/cjs/awaited.cjs +1 -22
  13. package/dist/cjs/awaited.cjs.map +1 -1
  14. package/dist/cjs/index.cjs +2 -7
  15. package/dist/cjs/index.cjs.map +1 -1
  16. package/dist/cjs/index.d.cts +4 -6
  17. package/dist/cjs/router.cjs +11 -129
  18. package/dist/cjs/router.cjs.map +1 -1
  19. package/dist/cjs/router.d.cts +33 -93
  20. package/dist/cjs/routerContext.cjs.map +1 -1
  21. package/dist/cjs/routerContext.d.cts +7 -2
  22. package/dist/cjs/serializer.d.cts +15 -0
  23. package/dist/cjs/useRouterState.cjs +1 -1
  24. package/dist/cjs/useRouterState.cjs.map +1 -1
  25. package/dist/cjs/utils.cjs.map +1 -1
  26. package/dist/cjs/utils.d.cts +2 -2
  27. package/dist/esm/Match.js +9 -25
  28. package/dist/esm/Match.js.map +1 -1
  29. package/dist/esm/Matches.js +1 -1
  30. package/dist/esm/Matches.js.map +1 -1
  31. package/dist/esm/RouterProvider.d.ts +0 -1
  32. package/dist/esm/RouterProvider.js.map +1 -1
  33. package/dist/esm/ScriptOnce.d.ts +1 -1
  34. package/dist/esm/ScriptOnce.js +1 -8
  35. package/dist/esm/ScriptOnce.js.map +1 -1
  36. package/dist/esm/Transitioner.js +1 -2
  37. package/dist/esm/Transitioner.js.map +1 -1
  38. package/dist/esm/awaited.js +1 -22
  39. package/dist/esm/awaited.js.map +1 -1
  40. package/dist/esm/index.d.ts +4 -6
  41. package/dist/esm/index.js +1 -6
  42. package/dist/esm/index.js.map +1 -1
  43. package/dist/esm/router.d.ts +33 -93
  44. package/dist/esm/router.js +11 -129
  45. package/dist/esm/router.js.map +1 -1
  46. package/dist/esm/routerContext.d.ts +7 -2
  47. package/dist/esm/routerContext.js.map +1 -1
  48. package/dist/esm/serializer.d.ts +15 -0
  49. package/dist/esm/useRouterState.js +1 -1
  50. package/dist/esm/useRouterState.js.map +1 -1
  51. package/dist/esm/utils.d.ts +2 -2
  52. package/dist/esm/utils.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/Match.tsx +4 -29
  55. package/src/Matches.tsx +1 -1
  56. package/src/RouterProvider.tsx +3 -3
  57. package/src/ScriptOnce.tsx +0 -8
  58. package/src/Transitioner.tsx +1 -1
  59. package/src/awaited.tsx +3 -25
  60. package/src/index.tsx +12 -34
  61. package/src/router.ts +44 -271
  62. package/src/routerContext.tsx +7 -1
  63. package/src/serializer.ts +24 -0
  64. package/src/useRouterState.tsx +1 -1
  65. package/src/utils.ts +1 -1
  66. package/dist/cjs/isServerSideError.cjs +0 -22
  67. package/dist/cjs/isServerSideError.cjs.map +0 -1
  68. package/dist/cjs/isServerSideError.d.cts +0 -5
  69. package/dist/cjs/transformer.cjs +0 -137
  70. package/dist/cjs/transformer.cjs.map +0 -1
  71. package/dist/cjs/transformer.d.cts +0 -16
  72. package/dist/esm/isServerSideError.d.ts +0 -5
  73. package/dist/esm/isServerSideError.js +0 -22
  74. package/dist/esm/isServerSideError.js.map +0 -1
  75. package/dist/esm/transformer.d.ts +0 -16
  76. package/dist/esm/transformer.js +0 -137
  77. package/dist/esm/transformer.js.map +0 -1
  78. package/src/isServerSideError.tsx +0 -23
  79. package/src/transformer.ts +0 -192
package/src/router.ts CHANGED
@@ -5,8 +5,6 @@ import {
5
5
  } from '@tanstack/history'
6
6
  import { Store, batch } from '@tanstack/react-store'
7
7
  import invariant from 'tiny-invariant'
8
- import warning from 'tiny-warning'
9
- import jsesc from 'jsesc'
10
8
  import { rootRouteId } from './root'
11
9
  import { defaultParseSearch, defaultStringifySearch } from './searchParams'
12
10
  import {
@@ -30,7 +28,7 @@ import {
30
28
  } from './path'
31
29
  import { isRedirect, isResolvedRedirect } from './redirects'
32
30
  import { isNotFound } from './not-found'
33
- import { defaultTransformer } from './transformer'
31
+ import type { StartSerializer } from './serializer'
34
32
  import type * as React from 'react'
35
33
  import type {
36
34
  HistoryLocation,
@@ -83,42 +81,15 @@ import type {
83
81
  import type { AnyRedirect, ResolvedRedirect } from './redirects'
84
82
  import type { NotFoundError } from './not-found'
85
83
  import type { NavigateOptions, ResolveRelativePath, ToOptions } from './link'
86
- import type { RouterTransformer } from './transformer'
87
84
  import type { AnySchema, AnyValidator } from './validators'
88
85
 
89
- export interface TSRGlobalMatch {
90
- index: number
91
- __beforeLoadContext?: string
92
- loaderData?: string
93
- extracted: Record<string, ClientExtractedEntry>
94
- }
95
- export interface TSRGlobal {
96
- matches: Array<TSRGlobalMatch>
97
- streamedValues: Record<
98
- string,
99
- {
100
- value: any
101
- parsed: any
102
- }
103
- >
104
- cleanScripts: () => void
105
- dehydrated?: any
106
- }
107
86
  declare global {
108
87
  interface Window {
109
- __TSR__?: RegisteredTSRGlobal
110
- __TSR_ROUTER_CONTEXT__?: React.Context<Router<any, any, any>>
88
+ __TSR_ROUTER__?: AnyRouter
111
89
  }
112
90
  }
113
91
 
114
- type RegisteredTSRGlobal = Register extends {
115
- __TSR__: infer TTSR extends TSRGlobal
116
- }
117
- ? TTSR
118
- : TSRGlobal
119
-
120
92
  export interface Register {
121
- // __TSR__: TSRGlobal
122
93
  // router: Router
123
94
  }
124
95
 
@@ -138,11 +109,6 @@ export type RegisteredRouter = Register extends {
138
109
  ? TRouter
139
110
  : AnyRouter
140
111
 
141
- export type HydrationCtx = {
142
- router: DehydratedRouter
143
- payload: Record<string, any>
144
- }
145
-
146
112
  export type InferRouterContext<TRouteTree extends AnyRoute> =
147
113
  TRouteTree extends RootRoute<
148
114
  any,
@@ -157,32 +123,10 @@ export type InferRouterContext<TRouteTree extends AnyRoute> =
157
123
  ? TRouterContext
158
124
  : AnyContext
159
125
 
160
- export interface ClientExtractedBaseEntry {
161
- type: string
162
- path: Array<string>
163
- }
164
-
165
126
  export type ControllablePromise<T = any> = Promise<T> & {
166
127
  resolve: (value: T) => void
167
128
  reject: (value?: any) => void
168
129
  }
169
- export interface ClientExtractedPromise extends ClientExtractedBaseEntry {
170
- type: 'promise'
171
- value?: ControllablePromise<any>
172
- }
173
-
174
- export interface ClientExtractedStream extends ClientExtractedBaseEntry {
175
- type: 'stream'
176
- value?: ReadableStream & { controller?: ReadableStreamDefaultController }
177
- }
178
-
179
- export type ClientExtractedEntry =
180
- | ClientExtractedStream
181
- | ClientExtractedPromise
182
-
183
- export type StreamState = {
184
- promises: Array<ControlledPromise<string | null>>
185
- }
186
130
 
187
131
  export type RouterContextOptions<TRouteTree extends AnyRoute> =
188
132
  AnyContext extends InferRouterContext<TRouteTree>
@@ -195,13 +139,14 @@ export type RouterContextOptions<TRouteTree extends AnyRoute> =
195
139
 
196
140
  export type TrailingSlashOption = 'always' | 'never' | 'preserve'
197
141
 
142
+ export type InjectedHtmlEntry = Promise<string>
143
+
198
144
  export interface RouterOptions<
199
145
  TRouteTree extends AnyRoute,
200
146
  TTrailingSlashOption extends TrailingSlashOption,
201
147
  TDefaultStructuralSharingOption extends boolean = false,
202
148
  TRouterHistory extends RouterHistory = RouterHistory,
203
149
  TDehydrated extends Record<string, any> = Record<string, any>,
204
- TSerializedError extends Record<string, any> = Record<string, any>,
205
150
  > {
206
151
  /**
207
152
  * The history object that will be used to manage the browser history.
@@ -456,19 +401,6 @@ export interface RouterOptions<
456
401
  * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/not-found-errors#default-router-wide-not-found-handling)
457
402
  */
458
403
  defaultNotFoundComponent?: NotFoundRouteComponent
459
- /**
460
- * The transformer that will be used when sending data between the server and the client during SSR.
461
- *
462
- * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#transformer-property)
463
- * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/ssr#data-transformers)
464
- */
465
- transformer?: RouterTransformer
466
- /**
467
- * The serializer object that will be used to determine how errors are serialized and deserialized between the server and the client.
468
- *
469
- * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#errorserializer-property)
470
- */
471
- errorSerializer?: RouterErrorSerializer<TSerializedError>
472
404
  /**
473
405
  * Configures how trailing slashes are treated.
474
406
  *
@@ -566,20 +498,6 @@ export interface MatchedRoutesResult {
566
498
  routeParams: Record<string, string>
567
499
  }
568
500
 
569
- export interface DehydratedRouterState {
570
- dehydratedMatches: Array<DehydratedRouteMatch>
571
- }
572
-
573
- export type DehydratedRouteMatch = Pick<
574
- MakeRouteMatch,
575
- 'id' | 'status' | 'updatedAt' | 'loaderData'
576
- >
577
-
578
- export interface DehydratedRouter {
579
- state: DehydratedRouterState
580
- manifest?: Manifest
581
- }
582
-
583
501
  export interface ViewTransitionOptions {
584
502
  types: Array<string>
585
503
  }
@@ -590,15 +508,13 @@ export type RouterConstructorOptions<
590
508
  TDefaultStructuralSharingOption extends boolean,
591
509
  TRouterHistory extends RouterHistory,
592
510
  TDehydrated extends Record<string, any>,
593
- TSerializedError extends Record<string, any>,
594
511
  > = Omit<
595
512
  RouterOptions<
596
513
  TRouteTree,
597
514
  TTrailingSlashOption,
598
515
  TDefaultStructuralSharingOption,
599
516
  TRouterHistory,
600
- TDehydrated,
601
- TSerializedError
517
+ TDehydrated
602
518
  >,
603
519
  'context'
604
520
  > &
@@ -682,6 +598,10 @@ export type RouterEvents = {
682
598
  pathChanged: boolean
683
599
  hrefChanged: boolean
684
600
  }
601
+ onInjectedHtml: {
602
+ type: 'onInjectedHtml'
603
+ promise: Promise<string>
604
+ }
685
605
  }
686
606
 
687
607
  export type RouterEvent = RouterEvents[keyof RouterEvents]
@@ -706,8 +626,7 @@ export function createRouter<
706
626
  TTrailingSlashOption,
707
627
  TDefaultStructuralSharingOption,
708
628
  TRouterHistory,
709
- TDehydrated,
710
- TSerializedError
629
+ TDehydrated
711
630
  >,
712
631
  ) {
713
632
  return new Router<
@@ -743,42 +662,18 @@ export class Router<
743
662
  shouldViewTransition?: boolean | ViewTransitionOptions = undefined
744
663
  isViewTransitionTypesSupported?: boolean = undefined
745
664
  subscribers = new Set<RouterListener<RouterEvent>>()
746
- dehydratedData?: TDehydrated
747
665
  viewTransitionPromise?: ControlledPromise<true>
748
- manifest?: Manifest
749
- AfterEachMatch?: (props: {
750
- match: Pick<
751
- AnyRouteMatch,
752
- 'id' | 'status' | 'error' | 'loadPromise' | 'minPendingPromise'
753
- >
754
- matchIndex: number
755
- }) => any
756
- serializeLoaderData?: (
757
- type: '__beforeLoadContext' | 'loaderData',
758
- loaderData: any,
759
- ctx: {
760
- router: AnyRouter
761
- match: AnyRouteMatch
762
- },
763
- ) => any
764
- serializer?: (data: any) => string
765
666
 
766
667
  // Must build in constructor
767
668
  __store!: Store<RouterState<TRouteTree>>
768
669
  options!: PickAsRequired<
769
- Omit<
770
- RouterOptions<
771
- TRouteTree,
772
- TTrailingSlashOption,
773
- TDefaultStructuralSharingOption,
774
- TRouterHistory,
775
- TDehydrated,
776
- TSerializedError
777
- >,
778
- 'transformer'
779
- > & {
780
- transformer: RouterTransformer
781
- },
670
+ RouterOptions<
671
+ TRouteTree,
672
+ TTrailingSlashOption,
673
+ TDefaultStructuralSharingOption,
674
+ TRouterHistory,
675
+ TDehydrated
676
+ >,
782
677
  'stringifySearch' | 'parseSearch' | 'context'
783
678
  >
784
679
  history!: TRouterHistory
@@ -800,8 +695,7 @@ export class Router<
800
695
  TTrailingSlashOption,
801
696
  TDefaultStructuralSharingOption,
802
697
  TRouterHistory,
803
- TDehydrated,
804
- TSerializedError
698
+ TDehydrated
805
699
  >,
806
700
  ) {
807
701
  this.update({
@@ -814,11 +708,10 @@ export class Router<
814
708
  notFoundMode: options.notFoundMode ?? 'fuzzy',
815
709
  stringifySearch: options.stringifySearch ?? defaultStringifySearch,
816
710
  parseSearch: options.parseSearch ?? defaultParseSearch,
817
- transformer: options.transformer ?? defaultTransformer,
818
711
  })
819
712
 
820
713
  if (typeof document !== 'undefined') {
821
- ;(window as any).__TSR__ROUTER__ = this
714
+ ;(window as any).__TSR_ROUTER__ = this
822
715
  }
823
716
  }
824
717
 
@@ -833,8 +726,7 @@ export class Router<
833
726
  TTrailingSlashOption,
834
727
  TDefaultStructuralSharingOption,
835
728
  TRouterHistory,
836
- TDehydrated,
837
- TSerializedError
729
+ TDehydrated
838
730
  >,
839
731
  ) => {
840
732
  if (newOptions.notFoundRoute) {
@@ -1623,7 +1515,7 @@ export class Router<
1623
1515
  }) ?? {}),
1624
1516
  }
1625
1517
  }
1626
- } catch (e) {
1518
+ } catch {
1627
1519
  // ignore errors here because they are already handled in matchRoutes
1628
1520
  }
1629
1521
  })
@@ -1685,7 +1577,7 @@ export class Router<
1685
1577
  ) ?? {}),
1686
1578
  }
1687
1579
  return validatedSearch
1688
- } catch (e) {
1580
+ } catch {
1689
1581
  // ignore errors here because they are already handled in matchRoutes
1690
1582
  }
1691
1583
  }
@@ -2448,21 +2340,10 @@ export class Router<
2448
2340
  matches,
2449
2341
  }
2450
2342
 
2451
- let beforeLoadContext =
2343
+ const beforeLoadContext =
2452
2344
  (await route.options.beforeLoad?.(beforeLoadFnContext)) ??
2453
2345
  {}
2454
2346
 
2455
- if (this.serializeLoaderData) {
2456
- beforeLoadContext = this.serializeLoaderData(
2457
- '__beforeLoadContext',
2458
- beforeLoadContext,
2459
- {
2460
- router: this,
2461
- match: this.getMatch(matchId)!,
2462
- },
2463
- )
2464
- }
2465
-
2466
2347
  if (
2467
2348
  isRedirect(beforeLoadContext) ||
2468
2349
  isNotFound(beforeLoadContext)
@@ -2602,20 +2483,9 @@ export class Router<
2602
2483
  }))
2603
2484
 
2604
2485
  // Kick off the loader!
2605
- let loaderData =
2486
+ const loaderData =
2606
2487
  await route.options.loader?.(getLoaderContext())
2607
2488
 
2608
- if (this.serializeLoaderData) {
2609
- loaderData = this.serializeLoaderData(
2610
- 'loaderData',
2611
- loaderData,
2612
- {
2613
- router: this,
2614
- match: this.getMatch(matchId)!,
2615
- },
2616
- )
2617
- }
2618
-
2619
2489
  handleRedirectAndNotFound(
2620
2490
  this.getMatch(matchId)!,
2621
2491
  loaderData,
@@ -2679,6 +2549,11 @@ export class Router<
2679
2549
  }))
2680
2550
  }
2681
2551
 
2552
+ this.serverSsr?.onMatchSettled({
2553
+ router: this,
2554
+ match: this.getMatch(matchId)!,
2555
+ })
2556
+
2682
2557
  // Last but not least, wait for the the components
2683
2558
  // to be preloaded before we resolve the match
2684
2559
  await route._componentsPromise
@@ -3028,127 +2903,25 @@ export class Router<
3028
2903
  return match
3029
2904
  }
3030
2905
 
3031
- dehydrate = (): DehydratedRouter => {
3032
- const pickError =
3033
- this.options.errorSerializer?.serialize ?? defaultSerializeError
3034
-
3035
- return {
3036
- state: {
3037
- dehydratedMatches: this.state.matches.map((d) => {
3038
- return {
3039
- ...pick(d, ['id', 'status', 'updatedAt']),
3040
- // If an error occurs server-side during SSRing,
3041
- // send a small subset of the error to the client
3042
- error: d.error
3043
- ? {
3044
- data: pickError(d.error),
3045
- __isServerError: true,
3046
- }
3047
- : undefined,
3048
- // NOTE: We don't send the loader data here, because
3049
- // there is a potential that it needs to be streamed.
3050
- // Instead, we render it next to the route match in the HTML
3051
- // which gives us the potential to stream it via suspense.
3052
- }
3053
- }),
3054
- },
3055
- manifest: this.manifest,
3056
- }
2906
+ ssr?: {
2907
+ manifest: Manifest | undefined
2908
+ serializer: StartSerializer
3057
2909
  }
3058
2910
 
3059
- hydrate = () => {
3060
- // Client hydrates from window
3061
- let ctx: HydrationCtx | undefined
3062
-
3063
- if (typeof document !== 'undefined') {
3064
- ctx = this.options.transformer.parse(window.__TSR__?.dehydrated) as any
3065
- }
3066
-
3067
- invariant(
3068
- ctx,
3069
- 'Expected to find a dehydrated data on window.__TSR__.dehydrated... but we did not. Please file an issue!',
3070
- )
3071
-
3072
- this.dehydratedData = ctx.payload as any
3073
- this.options.hydrate?.(ctx.payload as any)
3074
- const dehydratedState = ctx.router.state
3075
-
3076
- const matches = this.matchRoutes(this.state.location).map((match) => {
3077
- const dehydratedMatch = dehydratedState.dehydratedMatches.find(
3078
- (d) => d.id === match.id,
3079
- )
3080
-
3081
- invariant(
3082
- dehydratedMatch,
3083
- `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
3084
- )
3085
-
3086
- return {
3087
- ...match,
3088
- ...dehydratedMatch,
3089
- }
3090
- })
3091
-
3092
- this.__store.setState((s) => {
3093
- return {
3094
- ...s,
3095
- matches: matches as any,
3096
- }
3097
- })
3098
-
3099
- this.manifest = ctx.router.manifest
2911
+ serverSsr?: {
2912
+ injectedHtml: Array<InjectedHtmlEntry>
2913
+ injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>
2914
+ injectScript: (
2915
+ getScript: () => string | Promise<string>,
2916
+ opts?: { logScript?: boolean },
2917
+ ) => Promise<void>
2918
+ streamValue: (key: string, value: any) => void
2919
+ streamedKeys: Set<string>
2920
+ onMatchSettled: (opts: { router: AnyRouter; match: AnyRouteMatch }) => any
3100
2921
  }
3101
2922
 
3102
- injectedHtml: Array<() => string> = []
3103
- injectHtml = (html: string) => {
3104
- const cb = () => {
3105
- this.injectedHtml = this.injectedHtml.filter((d) => d !== cb)
3106
- return html
3107
- }
3108
-
3109
- this.injectedHtml.push(cb)
3110
- }
3111
- injectScript = (script: string, opts?: { logScript?: boolean }) => {
3112
- this.injectHtml(
3113
- `<script class='tsr-once'>${script}${
3114
- process.env.NODE_ENV === 'development' && (opts?.logScript ?? true)
3115
- ? `; console.info(\`Injected From Server:
3116
- ${jsesc(script, { quotes: 'backtick' })}\`)`
3117
- : ''
3118
- }; if (typeof __TSR__ !== 'undefined') __TSR__.cleanScripts()</script>`,
3119
- )
3120
- }
3121
-
3122
- streamedKeys: Set<string> = new Set()
3123
-
3124
- getStreamedValue = <T>(key: string): T | undefined => {
3125
- if (this.isServer) {
3126
- return undefined
3127
- }
3128
-
3129
- const streamedValue = window.__TSR__?.streamedValues[key]
3130
-
3131
- if (!streamedValue) {
3132
- return
3133
- }
3134
-
3135
- if (!streamedValue.parsed) {
3136
- streamedValue.parsed = this.options.transformer.parse(streamedValue.value)
3137
- }
3138
-
3139
- return streamedValue.parsed
3140
- }
3141
-
3142
- streamValue = (key: string, value: any) => {
3143
- warning(
3144
- !this.streamedKeys.has(key),
3145
- 'Key has already been streamed: ' + key,
3146
- )
3147
-
3148
- this.streamedKeys.add(key)
3149
- this.injectScript(
3150
- `__TSR__.streamedValues['${key}'] = { value: ${this.serializer?.(this.options.transformer.stringify(value))}}`,
3151
- )
2923
+ clientSsr?: {
2924
+ getStreamedValue: <T>(key: string) => T | undefined
3152
2925
  }
3153
2926
 
3154
2927
  _handleNotFound = (
@@ -1,5 +1,11 @@
1
1
  import * as React from 'react'
2
- import type { Router } from './router'
2
+ import type { AnyRouter, Router } from './router'
3
+
4
+ declare global {
5
+ interface Window {
6
+ __TSR_ROUTER_CONTEXT__?: React.Context<AnyRouter>
7
+ }
8
+ }
3
9
 
4
10
  const routerContext = React.createContext<Router<any, any, any>>(null!)
5
11
 
@@ -0,0 +1,24 @@
1
+ export interface StartSerializer {
2
+ stringify: (obj: unknown) => string
3
+ parse: (str: string) => unknown
4
+ encode: <T>(value: T) => T
5
+ decode: <T>(value: T) => T
6
+ }
7
+
8
+ export type SerializerStringifyBy<T, TSerializable> = T extends TSerializable
9
+ ? T
10
+ : T extends (...args: Array<any>) => any
11
+ ? 'Function is not serializable'
12
+ : { [K in keyof T]: SerializerStringifyBy<T[K], TSerializable> }
13
+
14
+ export type SerializerParseBy<T, TSerializable> = T extends TSerializable
15
+ ? T
16
+ : T extends React.JSX.Element
17
+ ? ReadableStream
18
+ : { [K in keyof T]: SerializerParseBy<T[K], TSerializable> }
19
+
20
+ export type Serializable = Date | undefined | Error | FormData
21
+
22
+ export type SerializerStringify<T> = SerializerStringifyBy<T, Serializable>
23
+
24
+ export type SerializerParse<T> = SerializerParseBy<T, Serializable>
@@ -36,7 +36,7 @@ export function useRouterState<
36
36
  })
37
37
  const router = opts?.router || contextRouter
38
38
  const previousResult =
39
- useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>()
39
+ useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)
40
40
 
41
41
  return useStore(router.__store, (state) => {
42
42
  if (opts?.select) {
package/src/utils.ts CHANGED
@@ -470,7 +470,7 @@ export function usePrevious<T>(value: T): T | null {
470
470
  * ```
471
471
  */
472
472
  export function useIntersectionObserver<T extends Element>(
473
- ref: React.RefObject<T>,
473
+ ref: React.RefObject<T | null>,
474
474
  callback: (entry: IntersectionObserverEntry | undefined) => void,
475
475
  intersectionObserverOptions: IntersectionObserverInit = {},
476
476
  options: { disabled?: boolean } = {},
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- function isServerSideError(error) {
4
- if (!(typeof error === "object" && error && "data" in error)) return false;
5
- if (!("__isServerError" in error && error.__isServerError)) return false;
6
- if (!(typeof error.data === "object" && error.data)) return false;
7
- return error.__isServerError === true;
8
- }
9
- function defaultDeserializeError(serializedData) {
10
- if ("name" in serializedData && "message" in serializedData) {
11
- const error = new Error(serializedData.message);
12
- error.name = serializedData.name;
13
- if (process.env.NODE_ENV === "development") {
14
- error.stack = serializedData.stack;
15
- }
16
- return error;
17
- }
18
- return serializedData.data;
19
- }
20
- exports.defaultDeserializeError = defaultDeserializeError;
21
- exports.isServerSideError = isServerSideError;
22
- //# sourceMappingURL=isServerSideError.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isServerSideError.cjs","sources":["../../src/isServerSideError.tsx"],"sourcesContent":["export function isServerSideError(error: unknown): error is {\n __isServerError: true\n data: Record<string, any>\n} {\n if (!(typeof error === 'object' && error && 'data' in error)) return false\n if (!('__isServerError' in error && error.__isServerError)) return false\n if (!(typeof error.data === 'object' && error.data)) return false\n\n return error.__isServerError === true\n}\n\nexport function defaultDeserializeError(serializedData: Record<string, any>) {\n if ('name' in serializedData && 'message' in serializedData) {\n const error = new Error(serializedData.message)\n error.name = serializedData.name\n if (process.env.NODE_ENV === 'development') {\n error.stack = serializedData.stack\n }\n return error\n }\n\n return serializedData.data\n}\n"],"names":[],"mappings":";;AAAO,SAAS,kBAAkB,OAGhC;AACA,MAAI,EAAE,OAAO,UAAU,YAAY,SAAS,UAAU,OAAe,QAAA;AACrE,MAAI,EAAE,qBAAqB,SAAS,MAAM,iBAAyB,QAAA;AACnE,MAAI,EAAE,OAAO,MAAM,SAAS,YAAY,MAAM,MAAc,QAAA;AAE5D,SAAO,MAAM,oBAAoB;AACnC;AAEO,SAAS,wBAAwB,gBAAqC;AACvE,MAAA,UAAU,kBAAkB,aAAa,gBAAgB;AAC3D,UAAM,QAAQ,IAAI,MAAM,eAAe,OAAO;AAC9C,UAAM,OAAO,eAAe;AACxB,QAAA,QAAQ,IAAI,aAAa,eAAe;AAC1C,YAAM,QAAQ,eAAe;AAAA,IAAA;AAExB,WAAA;AAAA,EAAA;AAGT,SAAO,eAAe;AACxB;;;"}
@@ -1,5 +0,0 @@
1
- export declare function isServerSideError(error: unknown): error is {
2
- __isServerError: true;
3
- data: Record<string, any>;
4
- };
5
- export declare function defaultDeserializeError(serializedData: Record<string, any>): any;