@tanstack/react-start-client 1.111.11 → 1.112.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.
@@ -4,6 +4,7 @@ import { isNotFound, isRedirect } from '@tanstack/react-router'
4
4
  import { mergeHeaders } from './headers'
5
5
  import { globalMiddleware } from './registerGlobalMiddleware'
6
6
  import { startSerializer } from './serializer'
7
+ import type { Readable } from 'node:stream'
7
8
  import type {
8
9
  AnyValidator,
9
10
  Constrain,
@@ -31,20 +32,37 @@ export interface JsonResponse<TData> extends Response {
31
32
  export type CompiledFetcherFnOptions = {
32
33
  method: Method
33
34
  data: unknown
35
+ response?: ServerFnResponseType
34
36
  headers?: HeadersInit
35
37
  signal?: AbortSignal
36
38
  context?: any
37
39
  }
38
40
 
39
- export type Fetcher<TMiddlewares, TValidator, TResponse> =
41
+ export type Fetcher<
42
+ TMiddlewares,
43
+ TValidator,
44
+ TResponse,
45
+ TServerFnResponseType extends ServerFnResponseType,
46
+ > =
40
47
  undefined extends IntersectAllValidatorInputs<TMiddlewares, TValidator>
41
- ? OptionalFetcher<TMiddlewares, TValidator, TResponse>
42
- : RequiredFetcher<TMiddlewares, TValidator, TResponse>
48
+ ? OptionalFetcher<
49
+ TMiddlewares,
50
+ TValidator,
51
+ TResponse,
52
+ TServerFnResponseType
53
+ >
54
+ : RequiredFetcher<
55
+ TMiddlewares,
56
+ TValidator,
57
+ TResponse,
58
+ TServerFnResponseType
59
+ >
43
60
 
44
61
  export interface FetcherBase {
45
62
  url: string
46
63
  __executeServer: (opts: {
47
64
  method: Method
65
+ response?: ServerFnResponseType
48
66
  data: unknown
49
67
  headers?: HeadersInit
50
68
  context?: any
@@ -55,51 +73,50 @@ export interface FetcherBase {
55
73
  export type FetchResult<
56
74
  TMiddlewares,
57
75
  TResponse,
58
- TFullResponse extends boolean,
59
- > = false extends TFullResponse
60
- ? Promise<FetcherData<TResponse>>
61
- : Promise<FullFetcherData<TMiddlewares, TResponse>>
62
-
63
- export interface OptionalFetcher<TMiddlewares, TValidator, TResponse>
64
- extends FetcherBase {
65
- <TFullResponse extends boolean>(
66
- options?: OptionalFetcherDataOptions<
67
- TMiddlewares,
68
- TValidator,
69
- TFullResponse
70
- >,
71
- ): FetchResult<TMiddlewares, TResponse, TFullResponse>
76
+ TServerFnResponseType extends ServerFnResponseType,
77
+ > = TServerFnResponseType extends 'raw'
78
+ ? Promise<Response>
79
+ : TServerFnResponseType extends 'full'
80
+ ? Promise<FullFetcherData<TMiddlewares, TResponse>>
81
+ : Promise<FetcherData<TResponse>>
82
+
83
+ export interface OptionalFetcher<
84
+ TMiddlewares,
85
+ TValidator,
86
+ TResponse,
87
+ TServerFnResponseType extends ServerFnResponseType,
88
+ > extends FetcherBase {
89
+ (
90
+ options?: OptionalFetcherDataOptions<TMiddlewares, TValidator>,
91
+ ): FetchResult<TMiddlewares, TResponse, TServerFnResponseType>
72
92
  }
73
93
 
74
- export interface RequiredFetcher<TMiddlewares, TValidator, TResponse>
75
- extends FetcherBase {
76
- <TFullResponse extends boolean>(
77
- opts: RequiredFetcherDataOptions<TMiddlewares, TValidator, TFullResponse>,
78
- ): FetchResult<TMiddlewares, TResponse, TFullResponse>
94
+ export interface RequiredFetcher<
95
+ TMiddlewares,
96
+ TValidator,
97
+ TResponse,
98
+ TServerFnResponseType extends ServerFnResponseType,
99
+ > extends FetcherBase {
100
+ (
101
+ opts: RequiredFetcherDataOptions<TMiddlewares, TValidator>,
102
+ ): FetchResult<TMiddlewares, TResponse, TServerFnResponseType>
79
103
  }
80
104
 
81
- export type FetcherBaseOptions<TFullResponse extends boolean = false> = {
105
+ export type FetcherBaseOptions = {
82
106
  headers?: HeadersInit
83
107
  type?: ServerFnType
84
108
  signal?: AbortSignal
85
- fullResponse?: TFullResponse
86
109
  }
87
110
 
88
111
  export type ServerFnType = 'static' | 'dynamic'
89
112
 
90
- export interface OptionalFetcherDataOptions<
91
- TMiddlewares,
92
- TValidator,
93
- TFullResponse extends boolean,
94
- > extends FetcherBaseOptions<TFullResponse> {
113
+ export interface OptionalFetcherDataOptions<TMiddlewares, TValidator>
114
+ extends FetcherBaseOptions {
95
115
  data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>
96
116
  }
97
117
 
98
- export interface RequiredFetcherDataOptions<
99
- TMiddlewares,
100
- TValidator,
101
- TFullResponse extends boolean,
102
- > extends FetcherBaseOptions<TFullResponse> {
118
+ export interface RequiredFetcherDataOptions<TMiddlewares, TValidator>
119
+ extends FetcherBaseOptions {
103
120
  data: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>
104
121
  }
105
122
 
@@ -119,39 +136,78 @@ export type RscStream<T> = {
119
136
  }
120
137
 
121
138
  export type Method = 'GET' | 'POST'
139
+ export type ServerFnResponseType = 'data' | 'full' | 'raw'
122
140
 
123
- export type ServerFn<TMethod, TMiddlewares, TValidator, TResponse> = (
124
- ctx: ServerFnCtx<TMethod, TMiddlewares, TValidator>,
125
- ) => Promise<SerializerStringify<TResponse>> | SerializerStringify<TResponse>
141
+ // see https://h3.unjs.io/guide/event-handler#responses-types
142
+ export type RawResponse = Response | ReadableStream | Readable | null | string
126
143
 
127
- export interface ServerFnCtx<TMethod, TMiddlewares, TValidator> {
144
+ export type ServerFnReturnType<
145
+ TServerFnResponseType extends ServerFnResponseType,
146
+ TResponse,
147
+ > = TServerFnResponseType extends 'raw'
148
+ ? RawResponse | Promise<RawResponse>
149
+ : Promise<SerializerStringify<TResponse>> | SerializerStringify<TResponse>
150
+ export type ServerFn<
151
+ TMethod,
152
+ TServerFnResponseType extends ServerFnResponseType,
153
+ TMiddlewares,
154
+ TValidator,
155
+ TResponse,
156
+ > = (
157
+ ctx: ServerFnCtx<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,
158
+ ) => ServerFnReturnType<TServerFnResponseType, TResponse>
159
+
160
+ export interface ServerFnCtx<
161
+ TMethod,
162
+ TServerFnResponseType extends ServerFnResponseType,
163
+ TMiddlewares,
164
+ TValidator,
165
+ > {
128
166
  method: TMethod
167
+ response: TServerFnResponseType
129
168
  data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TValidator>>
130
169
  context: Expand<AssignAllServerContext<TMiddlewares>>
131
170
  signal: AbortSignal
132
171
  }
133
172
 
134
- export type CompiledFetcherFn<TResponse> = {
173
+ export type CompiledFetcherFn<
174
+ TResponse,
175
+ TServerFnResponseType extends ServerFnResponseType,
176
+ > = {
135
177
  (
136
- opts: CompiledFetcherFnOptions & ServerFnBaseOptions<Method>,
178
+ opts: CompiledFetcherFnOptions &
179
+ ServerFnBaseOptions<Method, TServerFnResponseType>,
137
180
  ): Promise<TResponse>
138
181
  url: string
139
182
  }
140
183
 
141
184
  type ServerFnBaseOptions<
142
185
  TMethod extends Method = 'GET',
186
+ TServerFnResponseType extends ServerFnResponseType = 'data',
143
187
  TResponse = unknown,
144
188
  TMiddlewares = unknown,
145
189
  TInput = unknown,
146
190
  > = {
147
191
  method: TMethod
192
+ response?: TServerFnResponseType
148
193
  validateClient?: boolean
149
194
  middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyMiddleware>>
150
195
  validator?: ConstrainValidator<TInput>
151
- extractedFn?: CompiledFetcherFn<TResponse>
152
- serverFn?: ServerFn<TMethod, TMiddlewares, TInput, TResponse>
196
+ extractedFn?: CompiledFetcherFn<TResponse, TServerFnResponseType>
197
+ serverFn?: ServerFn<
198
+ TMethod,
199
+ TServerFnResponseType,
200
+ TMiddlewares,
201
+ TInput,
202
+ TResponse
203
+ >
153
204
  functionId: string
154
- type: ServerFnTypeOrTypeFn<TMethod, TMiddlewares, AnyValidator>
205
+ type: ServerFnTypeOrTypeFn<
206
+ TMethod,
207
+ TServerFnResponseType,
208
+ TMiddlewares,
209
+ AnyValidator
210
+ >
155
211
  }
156
212
 
157
213
  export type ValidatorSerializerStringify<TValidator> = Validator<
@@ -166,78 +222,142 @@ export type ConstrainValidator<TValidator> = unknown extends TValidator
166
222
  ? TValidator
167
223
  : Constrain<TValidator, ValidatorSerializerStringify<TValidator>>
168
224
 
169
- export interface ServerFnMiddleware<TMethod extends Method, TValidator> {
225
+ export interface ServerFnMiddleware<
226
+ TMethod extends Method,
227
+ TServerFnResponseType extends ServerFnResponseType,
228
+ TValidator,
229
+ > {
170
230
  middleware: <const TNewMiddlewares = undefined>(
171
231
  middlewares: Constrain<TNewMiddlewares, ReadonlyArray<AnyMiddleware>>,
172
- ) => ServerFnAfterMiddleware<TMethod, TNewMiddlewares, TValidator>
232
+ ) => ServerFnAfterMiddleware<
233
+ TMethod,
234
+ TServerFnResponseType,
235
+ TNewMiddlewares,
236
+ TValidator
237
+ >
173
238
  }
174
239
 
175
240
  export interface ServerFnAfterMiddleware<
176
241
  TMethod extends Method,
242
+ TServerFnResponseType extends ServerFnResponseType,
177
243
  TMiddlewares,
178
244
  TValidator,
179
- > extends ServerFnValidator<TMethod, TMiddlewares>,
180
- ServerFnTyper<TMethod, TMiddlewares, TValidator>,
181
- ServerFnHandler<TMethod, TMiddlewares, TValidator> {}
245
+ > extends ServerFnValidator<TMethod, TServerFnResponseType, TMiddlewares>,
246
+ ServerFnTyper<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,
247
+ ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}
182
248
 
183
- export type ValidatorFn<TMethod extends Method, TMiddlewares> = <TValidator>(
249
+ export type ValidatorFn<
250
+ TMethod extends Method,
251
+ TServerFnResponseType extends ServerFnResponseType,
252
+ TMiddlewares,
253
+ > = <TValidator>(
184
254
  validator: ConstrainValidator<TValidator>,
185
- ) => ServerFnAfterValidator<TMethod, TMiddlewares, TValidator>
255
+ ) => ServerFnAfterValidator<
256
+ TMethod,
257
+ TServerFnResponseType,
258
+ TMiddlewares,
259
+ TValidator
260
+ >
186
261
 
187
- export interface ServerFnValidator<TMethod extends Method, TMiddlewares> {
188
- validator: ValidatorFn<TMethod, TMiddlewares>
262
+ export interface ServerFnValidator<
263
+ TMethod extends Method,
264
+ TServerFnResponseType extends ServerFnResponseType,
265
+ TMiddlewares,
266
+ > {
267
+ validator: ValidatorFn<TMethod, TServerFnResponseType, TMiddlewares>
189
268
  }
190
269
 
191
270
  export interface ServerFnAfterValidator<
192
271
  TMethod extends Method,
272
+ TServerFnResponseType extends ServerFnResponseType,
193
273
  TMiddlewares,
194
274
  TValidator,
195
- > extends ServerFnMiddleware<TMethod, TValidator>,
196
- ServerFnTyper<TMethod, TMiddlewares, TValidator>,
197
- ServerFnHandler<TMethod, TMiddlewares, TValidator> {}
275
+ > extends ServerFnMiddleware<TMethod, TServerFnResponseType, TValidator>,
276
+ ServerFnTyper<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,
277
+ ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}
198
278
 
199
279
  // Typer
200
280
  export interface ServerFnTyper<
201
281
  TMethod extends Method,
282
+ TServerFnResponseType extends ServerFnResponseType,
202
283
  TMiddlewares,
203
284
  TValidator,
204
285
  > {
205
286
  type: (
206
- typer: ServerFnTypeOrTypeFn<TMethod, TMiddlewares, TValidator>,
207
- ) => ServerFnAfterTyper<TMethod, TMiddlewares, TValidator>
287
+ typer: ServerFnTypeOrTypeFn<
288
+ TMethod,
289
+ TServerFnResponseType,
290
+ TMiddlewares,
291
+ TValidator
292
+ >,
293
+ ) => ServerFnAfterTyper<
294
+ TMethod,
295
+ TServerFnResponseType,
296
+ TMiddlewares,
297
+ TValidator
298
+ >
208
299
  }
209
300
 
210
301
  export type ServerFnTypeOrTypeFn<
211
302
  TMethod extends Method,
303
+ TServerFnResponseType extends ServerFnResponseType,
212
304
  TMiddlewares,
213
305
  TValidator,
214
306
  > =
215
307
  | ServerFnType
216
- | ((ctx: ServerFnCtx<TMethod, TMiddlewares, TValidator>) => ServerFnType)
308
+ | ((
309
+ ctx: ServerFnCtx<
310
+ TMethod,
311
+ TServerFnResponseType,
312
+ TMiddlewares,
313
+ TValidator
314
+ >,
315
+ ) => ServerFnType)
217
316
 
218
317
  export interface ServerFnAfterTyper<
219
318
  TMethod extends Method,
319
+ TServerFnResponseType extends ServerFnResponseType,
220
320
  TMiddlewares,
221
321
  TValidator,
222
- > extends ServerFnHandler<TMethod, TMiddlewares, TValidator> {}
322
+ > extends ServerFnHandler<
323
+ TMethod,
324
+ TServerFnResponseType,
325
+ TMiddlewares,
326
+ TValidator
327
+ > {}
223
328
 
224
329
  // Handler
225
330
  export interface ServerFnHandler<
226
331
  TMethod extends Method,
332
+ TServerFnResponseType extends ServerFnResponseType,
227
333
  TMiddlewares,
228
334
  TValidator,
229
335
  > {
230
336
  handler: <TNewResponse>(
231
- fn?: ServerFn<TMethod, TMiddlewares, TValidator, TNewResponse>,
232
- ) => Fetcher<TMiddlewares, TValidator, TNewResponse>
337
+ fn?: ServerFn<
338
+ TMethod,
339
+ TServerFnResponseType,
340
+ TMiddlewares,
341
+ TValidator,
342
+ TNewResponse
343
+ >,
344
+ ) => Fetcher<TMiddlewares, TValidator, TNewResponse, TServerFnResponseType>
233
345
  }
234
346
 
235
- export interface ServerFnBuilder<TMethod extends Method = 'GET'>
236
- extends ServerFnMiddleware<TMethod, undefined>,
237
- ServerFnValidator<TMethod, undefined>,
238
- ServerFnTyper<TMethod, undefined, undefined>,
239
- ServerFnHandler<TMethod, undefined, undefined> {
240
- options: ServerFnBaseOptions<TMethod, unknown, undefined, undefined>
347
+ export interface ServerFnBuilder<
348
+ TMethod extends Method = 'GET',
349
+ TServerFnResponseType extends ServerFnResponseType = 'data',
350
+ > extends ServerFnMiddleware<TMethod, TServerFnResponseType, undefined>,
351
+ ServerFnValidator<TMethod, TServerFnResponseType, undefined>,
352
+ ServerFnTyper<TMethod, TServerFnResponseType, undefined, undefined>,
353
+ ServerFnHandler<TMethod, TServerFnResponseType, undefined, undefined> {
354
+ options: ServerFnBaseOptions<
355
+ TMethod,
356
+ TServerFnResponseType,
357
+ unknown,
358
+ undefined,
359
+ undefined
360
+ >
241
361
  }
242
362
 
243
363
  type StaticCachedResult = {
@@ -379,18 +499,27 @@ setServerFnStaticCache(() => {
379
499
 
380
500
  export function createServerFn<
381
501
  TMethod extends Method,
502
+ TServerFnResponseType extends ServerFnResponseType = 'data',
382
503
  TResponse = unknown,
383
504
  TMiddlewares = undefined,
384
505
  TValidator = undefined,
385
506
  >(
386
507
  options?: {
387
508
  method?: TMethod
509
+ response?: TServerFnResponseType
388
510
  type?: ServerFnType
389
511
  },
390
- __opts?: ServerFnBaseOptions<TMethod, TResponse, TMiddlewares, TValidator>,
391
- ): ServerFnBuilder<TMethod> {
512
+ __opts?: ServerFnBaseOptions<
513
+ TMethod,
514
+ TServerFnResponseType,
515
+ TResponse,
516
+ TMiddlewares,
517
+ TValidator
518
+ >,
519
+ ): ServerFnBuilder<TMethod, TServerFnResponseType> {
392
520
  const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<
393
521
  TMethod,
522
+ ServerFnResponseType,
394
523
  TResponse,
395
524
  TMiddlewares,
396
525
  TValidator
@@ -403,30 +532,45 @@ export function createServerFn<
403
532
  return {
404
533
  options: resolvedOptions as any,
405
534
  middleware: (middleware) => {
406
- return createServerFn<TMethod, TResponse, TMiddlewares, TValidator>(
407
- undefined,
408
- Object.assign(resolvedOptions, { middleware }),
409
- ) as any
535
+ return createServerFn<
536
+ TMethod,
537
+ ServerFnResponseType,
538
+ TResponse,
539
+ TMiddlewares,
540
+ TValidator
541
+ >(undefined, Object.assign(resolvedOptions, { middleware })) as any
410
542
  },
411
543
  validator: (validator) => {
412
- return createServerFn<TMethod, TResponse, TMiddlewares, TValidator>(
413
- undefined,
414
- Object.assign(resolvedOptions, { validator }),
415
- ) as any
544
+ return createServerFn<
545
+ TMethod,
546
+ ServerFnResponseType,
547
+ TResponse,
548
+ TMiddlewares,
549
+ TValidator
550
+ >(undefined, Object.assign(resolvedOptions, { validator })) as any
416
551
  },
417
552
  type: (type) => {
418
- return createServerFn<TMethod, TResponse, TMiddlewares, TValidator>(
419
- undefined,
420
- Object.assign(resolvedOptions, { type }),
421
- ) as any
553
+ return createServerFn<
554
+ TMethod,
555
+ ServerFnResponseType,
556
+ TResponse,
557
+ TMiddlewares,
558
+ TValidator
559
+ >(undefined, Object.assign(resolvedOptions, { type })) as any
422
560
  },
423
561
  handler: (...args) => {
424
562
  // This function signature changes due to AST transformations
425
563
  // in the babel plugin. We need to cast it to the correct
426
564
  // function signature post-transformation
427
565
  const [extractedFn, serverFn] = args as unknown as [
428
- CompiledFetcherFn<TResponse>,
429
- ServerFn<TMethod, TMiddlewares, TValidator, TResponse>,
566
+ CompiledFetcherFn<TResponse, TServerFnResponseType>,
567
+ ServerFn<
568
+ TMethod,
569
+ TServerFnResponseType,
570
+ TMiddlewares,
571
+ TValidator,
572
+ TResponse
573
+ >,
430
574
  ]
431
575
 
432
576
  // Keep the original function around so we can use it
@@ -455,6 +599,9 @@ export function createServerFn<
455
599
  signal: opts?.signal,
456
600
  context: {},
457
601
  }).then((d) => {
602
+ if (resolvedOptions.response === 'full') {
603
+ return d
604
+ }
458
605
  if (d.error) throw d.error
459
606
  return d.result
460
607
  })
@@ -589,19 +736,20 @@ function flattenMiddlewares(
589
736
 
590
737
  export type MiddlewareOptions = {
591
738
  method: Method
739
+ response?: ServerFnResponseType
592
740
  data: any
593
741
  headers?: HeadersInit
594
742
  signal?: AbortSignal
595
743
  sendContext?: any
596
744
  context?: any
597
- type: ServerFnTypeOrTypeFn<any, any, any>
745
+ type: ServerFnTypeOrTypeFn<any, any, any, any>
598
746
  functionId: string
599
747
  }
600
748
 
601
749
  export type MiddlewareResult = MiddlewareOptions & {
602
750
  result?: unknown
603
751
  error?: unknown
604
- type: ServerFnTypeOrTypeFn<any, any, any>
752
+ type: ServerFnTypeOrTypeFn<any, any, any, any>
605
753
  }
606
754
 
607
755
  export type NextFn = (ctx: MiddlewareResult) => Promise<MiddlewareResult>
@@ -634,7 +782,11 @@ const applyMiddleware = async (
634
782
  },
635
783
  headers: mergeHeaders(ctx.headers, userCtx.headers),
636
784
  result:
637
- userCtx.result !== undefined ? userCtx.result : (ctx as any).result,
785
+ userCtx.result !== undefined
786
+ ? userCtx.result
787
+ : ctx.response === 'raw'
788
+ ? userCtx
789
+ : (ctx as any).result,
638
790
  error: userCtx.error ?? (ctx as any).error,
639
791
  })
640
792
  }) as any,
@@ -729,7 +881,7 @@ async function executeMiddleware(
729
881
  }
730
882
 
731
883
  function serverFnBaseToMiddleware(
732
- options: ServerFnBaseOptions<any, any, any, any>,
884
+ options: ServerFnBaseOptions<any, any, any, any, any>,
733
885
  ): AnyMiddleware {
734
886
  return {
735
887
  _types: undefined!,
@@ -9,7 +9,11 @@ import type {
9
9
  MakeRouteMatch,
10
10
  } from '@tanstack/react-router'
11
11
 
12
- import type { DeferredPromiseState, Manifest } from '@tanstack/router-core'
12
+ import type {
13
+ DeferredPromiseState,
14
+ Manifest,
15
+ RouteContextOptions,
16
+ } from '@tanstack/router-core'
13
17
 
14
18
  declare global {
15
19
  interface Window {
@@ -122,13 +126,9 @@ export function hydrate(router: AnyRouter) {
122
126
  return router.loadRouteChunk(route)
123
127
  }),
124
128
  )
129
+ // Right after hydration and before the first render, we need to rehydrate each match
130
+ // First step is to reyhdrate loaderData and __beforeLoadContext
125
131
  matches.forEach((match) => {
126
- const route = router.looseRoutesById[match.routeId]!
127
-
128
- // Right after hydration and before the first render, we need to rehydrate each match
129
- // This includes rehydrating the loaderData and also using the beforeLoadContext
130
- // to reconstruct any context that was serialized on the server
131
-
132
132
  const dehydratedMatch = window.__TSR_SSR__!.matches.find(
133
133
  (d) => d.id === match.id,
134
134
  )
@@ -136,20 +136,11 @@ export function hydrate(router: AnyRouter) {
136
136
  if (dehydratedMatch) {
137
137
  Object.assign(match, dehydratedMatch)
138
138
 
139
- const parentMatch = matches[match.index - 1]
140
- const parentContext = parentMatch?.context ?? router.options.context ?? {}
141
-
142
139
  // Handle beforeLoadContext
143
140
  if (dehydratedMatch.__beforeLoadContext) {
144
141
  match.__beforeLoadContext = router.ssr!.serializer.parse(
145
142
  dehydratedMatch.__beforeLoadContext,
146
143
  ) as any
147
-
148
- match.context = {
149
- ...parentContext,
150
- ...match.__routeContext,
151
- ...match.__beforeLoadContext,
152
- }
153
144
  }
154
145
 
155
146
  // Handle loaderData
@@ -175,6 +166,51 @@ export function hydrate(router: AnyRouter) {
175
166
  })
176
167
  }
177
168
 
169
+ return match
170
+ })
171
+
172
+ router.__store.setState((s) => {
173
+ return {
174
+ ...s,
175
+ matches,
176
+ }
177
+ })
178
+
179
+ // Allow the user to handle custom hydration data
180
+ router.options.hydrate?.(dehydratedData)
181
+
182
+ // now that all necessary data is hydrated:
183
+ // 1) fully reconstruct the route context
184
+ // 2) execute `head()` and `scripts()` for each match
185
+ router.state.matches.forEach((match) => {
186
+ const route = router.looseRoutesById[match.routeId]!
187
+
188
+ const parentMatch = router.state.matches[match.index - 1]
189
+ const parentContext = parentMatch?.context ?? router.options.context ?? {}
190
+
191
+ // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed
192
+ // so run it again and merge route context
193
+ const contextFnContext: RouteContextOptions<any, any, any, any> = {
194
+ deps: match.loaderDeps,
195
+ params: match.params,
196
+ context: parentContext,
197
+ location: router.state.location,
198
+ navigate: (opts: any) =>
199
+ router.navigate({ ...opts, _fromLocation: router.state.location }),
200
+ buildLocation: router.buildLocation,
201
+ cause: match.cause,
202
+ abortController: match.abortController,
203
+ preload: false,
204
+ matches,
205
+ }
206
+ match.__routeContext = route.options.context?.(contextFnContext) ?? {}
207
+
208
+ match.context = {
209
+ ...parentContext,
210
+ ...match.__routeContext,
211
+ ...match.__beforeLoadContext,
212
+ }
213
+
178
214
  const assetContext = {
179
215
  matches: router.state.matches,
180
216
  match,
@@ -189,19 +225,8 @@ export function hydrate(router: AnyRouter) {
189
225
  match.links = headFnContent?.links
190
226
  match.headScripts = headFnContent?.scripts
191
227
  match.scripts = scripts
192
-
193
- return match
194
228
  })
195
229
 
196
- router.__store.setState((s) => {
197
- return {
198
- ...s,
199
- matches,
200
- }
201
- })
202
-
203
- // Allow the user to handle custom hydration data
204
- router.options.hydrate?.(dehydratedData)
205
230
  return routeChunkPromise
206
231
  }
207
232