@tanstack/router-core 0.0.1-beta.159 → 0.0.1-beta.160

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.159",
4
+ "version": "0.0.1-beta.160",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://tanstack.com/router",
@@ -43,7 +43,7 @@
43
43
  "tiny-invariant": "^1.3.1",
44
44
  "tiny-warning": "^1.0.3",
45
45
  "@gisatcz/cross-package-react-context": "^0.2.0",
46
- "@tanstack/react-store": "0.0.1-beta.159"
46
+ "@tanstack/react-store": "0.0.1-beta.160"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "rollup --config rollup.config.js",
package/src/route.ts CHANGED
@@ -90,7 +90,7 @@ export type RouteLoaderFromRoute<TRoute extends AnyRoute> = LoaderFn<
90
90
  >
91
91
 
92
92
  export type RouteProps<
93
- TLoader = unknown,
93
+ TLoader extends any = unknown,
94
94
  TFullSearchSchema extends AnySearchSchema = AnySearchSchema,
95
95
  TAllParams extends AnyPathParams = AnyPathParams,
96
96
  TRouteContext extends AnyContext = AnyContext,
@@ -173,10 +173,6 @@ type Prefix<T extends string, U extends string> = U extends `${T}${infer _}`
173
173
  ? U
174
174
  : never
175
175
 
176
- type PrefixOrExact<T extends string, U extends string> = U extends T
177
- ? U
178
- : Prefix<T, U>
179
-
180
176
  export type BaseRouteOptions<
181
177
  TParentRoute extends AnyRoute = AnyRoute,
182
178
  TCustomId extends string = string,
@@ -185,7 +181,7 @@ export type BaseRouteOptions<
185
181
  TParentSearchSchema extends AnySearchSchema = {},
186
182
  TSearchSchema extends AnySearchSchema = {},
187
183
  TFullSearchSchema extends AnySearchSchema = TSearchSchema,
188
- TParams = unknown,
184
+ TParams extends AnyPathParams = {},
189
185
  TAllParams = ParamsFallback<TPath, TParams>,
190
186
  TParentContext extends AnyContext = AnyContext,
191
187
  TAllParentContext extends AnyContext = AnyContext,
@@ -194,7 +190,7 @@ export type BaseRouteOptions<
194
190
  > = RoutePathOptions<TCustomId, TPath> & {
195
191
  layoutLimit?: string
196
192
  getParentRoute: () => TParentRoute
197
- validateSearch?: SearchSchemaValidator<TSearchSchema, TParentSearchSchema>
193
+ validateSearch?: SearchSchemaValidator<TSearchSchema>
198
194
  loader?: LoaderFn<
199
195
  TLoader,
200
196
  TSearchSchema,
@@ -203,7 +199,12 @@ export type BaseRouteOptions<
203
199
  NoInfer<TRouteContext>,
204
200
  TAllContext
205
201
  >
206
- } & (
202
+ } & ([TLoader] extends [never]
203
+ ? {
204
+ loader: 'Loaders must return a type other than never. If you are throwing a redirect() and not returning anything, return a redirect() instead.'
205
+ }
206
+ : {}) &
207
+ (
207
208
  | {
208
209
  // Both or none
209
210
  parseParams?: (
@@ -211,17 +212,6 @@ export type BaseRouteOptions<
211
212
  ) => TParams extends Record<ParsePathParams<TPath>, any>
212
213
  ? TParams
213
214
  : 'parseParams must return an object'
214
- // | {
215
- // parse: (
216
- // rawParams: IsAny<
217
- // TPath,
218
- // any,
219
- // Record<ParsePathParams<TPath>, string>
220
- // >,
221
- // ) => TParams extends Record<ParsePathParams<TPath>, any>
222
- // ? TParams
223
- // : 'parseParams must return an object'
224
- // }
225
215
  stringifyParams?: (
226
216
  params: NoInfer<ParamsFallback<TPath, TParams>>,
227
217
  ) => Record<ParsePathParams<TPath>, string>
@@ -364,7 +354,6 @@ export type ParseParamsOption<TPath extends string, TParams> = ParseParamsFn<
364
354
  TPath,
365
355
  TParams
366
356
  >
367
- // | ParseParamsObj<TPath, TParams>
368
357
 
369
358
  export type ParseParamsFn<TPath extends string, TParams> = (
370
359
  rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
@@ -377,24 +366,17 @@ export type ParseParamsObj<TPath extends string, TParams> = {
377
366
  }
378
367
 
379
368
  // The parse type here allows a zod schema to be passed directly to the validator
380
- export type SearchSchemaValidator<TReturn, TParentSchema> =
381
- | SearchSchemaValidatorObj<TReturn, TParentSchema>
382
- | SearchSchemaValidatorFn<TReturn, TParentSchema>
369
+ export type SearchSchemaValidator<TReturn> =
370
+ | SearchSchemaValidatorObj<TReturn>
371
+ | SearchSchemaValidatorFn<TReturn>
383
372
 
384
- export type SearchSchemaValidatorObj<TReturn, TParentSchema> = {
385
- parse?: SearchSchemaValidatorFn<TReturn, TParentSchema>
373
+ export type SearchSchemaValidatorObj<TReturn> = {
374
+ parse?: SearchSchemaValidatorFn<TReturn>
386
375
  }
387
376
 
388
- export type SearchSchemaValidatorFn<TReturn, TParentSchema> = (
377
+ export type SearchSchemaValidatorFn<TReturn> = (
389
378
  searchObj: Record<string, unknown>,
390
- ) => {} extends TParentSchema
391
- ? TReturn
392
- : keyof TReturn extends keyof TParentSchema
393
- ? {
394
- error: 'Top level search params cannot be redefined by child routes!'
395
- keys: keyof TReturn & keyof TParentSchema
396
- }
397
- : TReturn
379
+ ) => TReturn
398
380
 
399
381
  export type DefinedPathParamWarning =
400
382
  'Path params cannot be redefined by child routes!'
@@ -805,10 +787,8 @@ export class RouterContext<TRouterContext extends {}> {
805
787
  | 'parseParams'
806
788
  | 'stringifyParams'
807
789
  >,
808
- ) => {
809
- return new RootRoute<TLoader, TSearchSchema, TRouteContext, TRouterContext>(
810
- options as any,
811
- )
790
+ ): RootRoute<TLoader, TSearchSchema, TRouteContext, TRouterContext> => {
791
+ return new RootRoute(options) as any
812
792
  }
813
793
  }
814
794
 
package/src/router.ts CHANGED
@@ -107,8 +107,8 @@ export type HydrationCtx = {
107
107
  }
108
108
 
109
109
  export interface RouteMatch<
110
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
111
- TRoute extends AnyRoute = Route,
110
+ TRouteTree extends AnyRoute = AnyRoute,
111
+ TRoute extends AnyRoute = AnyRoute,
112
112
  > {
113
113
  id: string
114
114
  key?: string
@@ -182,7 +182,7 @@ export interface RouterOptions<
182
182
  }
183
183
 
184
184
  export interface RouterState<
185
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
185
+ TRouteTree extends AnyRoute = AnyRoute,
186
186
  // TState extends LocationState = LocationState,
187
187
  > {
188
188
  status: 'idle' | 'pending'
@@ -250,7 +250,7 @@ export const componentTypes = [
250
250
  ] as const
251
251
 
252
252
  export class Router<
253
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
253
+ TRouteTree extends AnyRoute = AnyRoute,
254
254
  TDehydrated extends Record<string, any> = Record<string, any>,
255
255
  > {
256
256
  types!: {
@@ -290,40 +290,43 @@ export class Router<
290
290
  onUpdate: () => {
291
291
  const prev = this.state
292
292
 
293
- this.state = this.__store.state
293
+ const next = this.__store.state
294
+
295
+ console.log(
296
+ Object.values(next.matchesById).find((d) => d.status === 'error'),
297
+ )
294
298
 
295
- const matchesByIdChanged = prev.matchesById !== this.state.matchesById
299
+ const matchesByIdChanged = prev.matchesById !== next.matchesById
296
300
  let matchesChanged
297
301
  let pendingMatchesChanged
298
302
 
299
303
  if (!matchesByIdChanged) {
300
304
  matchesChanged =
301
- prev.matchIds.length !== this.state.matchIds.length ||
302
- prev.matchIds.some((d, i) => d !== this.state.matchIds[i])
305
+ prev.matchIds.length !== next.matchIds.length ||
306
+ prev.matchIds.some((d, i) => d !== next.matchIds[i])
303
307
 
304
308
  pendingMatchesChanged =
305
- prev.pendingMatchIds.length !== this.state.pendingMatchIds.length ||
306
- prev.pendingMatchIds.some(
307
- (d, i) => d !== this.state.pendingMatchIds[i],
308
- )
309
+ prev.pendingMatchIds.length !== next.pendingMatchIds.length ||
310
+ prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i])
309
311
  }
310
312
 
311
313
  if (matchesByIdChanged || matchesChanged) {
312
- this.state.matches = this.state.matchIds.map((id) => {
313
- return this.state.matchesById[id] as any
314
+ next.matches = next.matchIds.map((id) => {
315
+ return next.matchesById[id] as any
314
316
  })
315
317
  }
316
318
 
317
319
  if (matchesByIdChanged || pendingMatchesChanged) {
318
- this.state.pendingMatches = this.state.pendingMatchIds.map((id) => {
319
- return this.state.matchesById[id] as any
320
+ next.pendingMatches = next.pendingMatchIds.map((id) => {
321
+ return next.matchesById[id] as any
320
322
  })
321
323
  }
322
324
 
323
- this.state.isFetching = [
324
- ...this.state.matches,
325
- ...this.state.pendingMatches,
326
- ].some((d) => d.isFetching)
325
+ next.isFetching = [...next.matches, ...next.pendingMatches].some(
326
+ (d) => d.isFetching,
327
+ )
328
+
329
+ this.state = next
327
330
  },
328
331
  defaultPriority: 'low',
329
332
  })
@@ -424,11 +427,12 @@ export class Router<
424
427
  this.getRouteMatch(id)?.abortController?.abort()
425
428
  }
426
429
 
427
- safeLoad = (opts?: { next?: ParsedLocation }) => {
428
- return this.load(opts).catch((err) => {
429
- // console.warn(err)
430
- // invariant(false, 'Encountered an error during router.load()! ☝️.')
431
- })
430
+ safeLoad = async (opts?: { next?: ParsedLocation }) => {
431
+ try {
432
+ return this.load(opts)
433
+ } catch (err) {
434
+ // Don't do anything
435
+ }
432
436
  }
433
437
 
434
438
  latestLoadPromise: Promise<void> = Promise.resolve()
@@ -477,11 +481,16 @@ export class Router<
477
481
 
478
482
  try {
479
483
  // Load the matches
480
- await this.loadMatches(pendingMatches)
484
+ try {
485
+ await this.loadMatches(pendingMatches)
486
+ } catch (err) {
487
+ // swallow this error, since we'll display the
488
+ // errors on the route components
489
+ }
481
490
 
482
491
  // Only apply the latest transition
483
492
  if ((latestPromise = checkLatest())) {
484
- return await latestPromise
493
+ return latestPromise
485
494
  }
486
495
 
487
496
  const prevLocation = this.state.resolvedLocation
@@ -502,7 +511,7 @@ export class Router<
502
511
  } catch (err) {
503
512
  // Only apply the latest transition
504
513
  if ((latestPromise = checkLatest())) {
505
- return await latestPromise
514
+ return latestPromise
506
515
  }
507
516
 
508
517
  reject(err)
@@ -519,7 +528,7 @@ export class Router<
519
528
  string,
520
529
  RouteMatch<TRouteTree, ParseRoute<TRouteTree>>
521
530
  >,
522
- nextMatches: RouteMatch[],
531
+ nextMatches: AnyRouteMatch[],
523
532
  ): Record<string, RouteMatch<TRouteTree, ParseRoute<TRouteTree>>> => {
524
533
  const nextMatchesById: any = {
525
534
  ...prevMatchesById,
@@ -697,7 +706,7 @@ export class Router<
697
706
  componentTypes.some((d) => (route.options[d] as any)?.preload)
698
707
  )
699
708
 
700
- const routeMatch: RouteMatch = {
709
+ const routeMatch: AnyRouteMatch = {
701
710
  id: matchId,
702
711
  key: stringifiedKey,
703
712
  routeId: route.id,
@@ -860,6 +869,7 @@ export class Router<
860
869
  }
861
870
  }
862
871
 
872
+ console.log('set error')
863
873
  this.setRouteMatch(match.id, (s) => ({
864
874
  ...s,
865
875
  error: err,
@@ -926,25 +936,9 @@ export class Router<
926
936
  : undefined
927
937
  }
928
938
 
929
- const loadPromise = (async () => {
939
+ const load = async () => {
930
940
  let latestPromise
931
941
 
932
- const componentsPromise = Promise.all(
933
- componentTypes.map(async (type) => {
934
- const component = route.options[type]
935
-
936
- if ((component as any)?.preload) {
937
- await (component as any).preload()
938
- }
939
- }),
940
- )
941
-
942
- const loaderPromise = route.options.loader?.({
943
- ...match,
944
- preload: !!opts?.preload,
945
- parentMatchPromise,
946
- })
947
-
948
942
  const handleError = (err: any) => {
949
943
  if (isRedirect(err)) {
950
944
  if (!opts?.preload) {
@@ -957,6 +951,22 @@ export class Router<
957
951
  }
958
952
 
959
953
  try {
954
+ const componentsPromise = Promise.all(
955
+ componentTypes.map(async (type) => {
956
+ const component = route.options[type]
957
+
958
+ if ((component as any)?.preload) {
959
+ await (component as any).preload()
960
+ }
961
+ }),
962
+ )
963
+
964
+ const loaderPromise = route.options.loader?.({
965
+ ...match,
966
+ preload: !!opts?.preload,
967
+ parentMatchPromise,
968
+ })
969
+
960
970
  const [_, loader] = await Promise.all([
961
971
  componentsPromise,
962
972
  loaderPromise,
@@ -964,37 +974,36 @@ export class Router<
964
974
  if ((latestPromise = checkLatest())) return await latestPromise
965
975
 
966
976
  this.setRouteMatchData(match.id, () => loader, opts)
967
- } catch (err) {
977
+ } catch (loaderError) {
968
978
  if ((latestPromise = checkLatest())) return await latestPromise
979
+ handleError(loaderError)
969
980
 
970
- if (handleError(err)) {
971
- return
972
- }
973
-
974
- const errorHandler =
975
- route.options.onLoadError ?? route.options.onError
976
-
977
- let caughtError = err
981
+ let error = loaderError
978
982
 
979
983
  try {
980
- errorHandler?.(err)
981
- } catch (errorHandlerErr) {
982
- caughtError = errorHandlerErr
983
-
984
- if (handleError(errorHandlerErr)) {
985
- return
984
+ if (route.options.onLoadError) {
985
+ route.options.onLoadError?.(loaderError)
986
+ } else {
987
+ route.options.onError?.(loaderError)
986
988
  }
989
+ } catch (errorHandlerErr) {
990
+ error = errorHandlerErr
991
+ handleError(error)
987
992
  }
988
993
 
994
+ console.log('set error')
989
995
  this.setRouteMatch(match.id, (s) => ({
990
996
  ...s,
991
- error: caughtError,
997
+ error: error,
992
998
  status: 'error',
993
999
  isFetching: false,
994
1000
  updatedAt: Date.now(),
995
1001
  }))
1002
+ console.log(this.getRouteMatch(match.id)?.status)
996
1003
  }
997
- })()
1004
+ }
1005
+
1006
+ const loadPromise = load()
998
1007
 
999
1008
  this.setRouteMatch(match.id, (s) => ({
1000
1009
  ...s,
@@ -1602,13 +1611,19 @@ export class Router<
1602
1611
  prev: RouteMatch<TRouteTree, AnyRoute>,
1603
1612
  ) => RouteMatch<TRouteTree, AnyRoute>,
1604
1613
  ) => {
1605
- this.__store.setState((prev) => ({
1606
- ...prev,
1607
- matchesById: {
1608
- ...prev.matchesById,
1609
- [id]: updater(prev.matchesById[id] as any),
1610
- },
1611
- }))
1614
+ this.__store.setState((prev) => {
1615
+ if (!prev.matchesById[id]) {
1616
+ console.warn(`No match found with id: ${id}`)
1617
+ }
1618
+
1619
+ return {
1620
+ ...prev,
1621
+ matchesById: {
1622
+ ...prev.matchesById,
1623
+ [id]: updater(prev.matchesById[id] as any),
1624
+ },
1625
+ }
1626
+ })
1612
1627
  }
1613
1628
 
1614
1629
  setRouteMatchData = (
@@ -1640,6 +1655,7 @@ export class Router<
1640
1655
  this.options.defaultMaxAge ??
1641
1656
  Infinity)
1642
1657
 
1658
+ console.log('set success')
1643
1659
  this.setRouteMatch(id, (s) => ({
1644
1660
  ...s,
1645
1661
  error: undefined,