@tanstack/router-core 0.0.1-alpha.3 → 0.0.1-alpha.4

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/src/index.ts CHANGED
@@ -7,9 +7,10 @@ import {
7
7
  History,
8
8
  HashHistory,
9
9
  } from 'history'
10
- import React from 'react'
10
+ import invariant from 'tiny-invariant'
11
11
 
12
12
  export { createHashHistory, createBrowserHistory, createMemoryHistory }
13
+ export { invariant }
13
14
 
14
15
  import { decode, encode } from './qss'
15
16
 
@@ -62,6 +63,7 @@ export interface FrameworkGenerics {
62
63
 
63
64
  export interface RouteConfig<
64
65
  TId extends string = string,
66
+ TRouteId extends string = string,
65
67
  TPath extends string = string,
66
68
  TFullPath extends string = string,
67
69
  TRouteLoaderData extends AnyLoaderData = AnyLoaderData,
@@ -80,9 +82,11 @@ export interface RouteConfig<
80
82
  TKnownChildren = unknown,
81
83
  > {
82
84
  id: TId
85
+ routeId: TRouteId
83
86
  path: NoInfer<TPath>
84
87
  fullPath: TFullPath
85
88
  options: RouteOptions<
89
+ TRouteId,
86
90
  TPath,
87
91
  TRouteLoaderData,
88
92
  TLoaderData,
@@ -104,6 +108,7 @@ export interface RouteConfig<
104
108
  createChildRoute: CreateRouteConfigFn<
105
109
  false,
106
110
  TId,
111
+ TFullPath,
107
112
  TLoaderData,
108
113
  TFullSearchSchema,
109
114
  TAllParams
@@ -113,6 +118,7 @@ export interface RouteConfig<
113
118
  : { error: 'Invalid route detected'; route: TNewChildren },
114
119
  ) => RouteConfig<
115
120
  TId,
121
+ TRouteId,
116
122
  TPath,
117
123
  TFullPath,
118
124
  TRouteLoaderData,
@@ -133,10 +139,12 @@ export interface RouteConfig<
133
139
  type CreateRouteConfigFn<
134
140
  TIsRoot extends boolean = false,
135
141
  TParentId extends string = string,
142
+ TParentPath extends string = string,
136
143
  TParentAllLoaderData extends AnyLoaderData = {},
137
144
  TParentSearchSchema extends AnySearchSchema = {},
138
145
  TParentParams extends AnyPathParams = {},
139
146
  > = <
147
+ TRouteId extends string,
140
148
  TPath extends string,
141
149
  TRouteLoaderData extends AnyLoaderData,
142
150
  TActionPayload,
@@ -152,10 +160,16 @@ type CreateRouteConfigFn<
152
160
  ? Record<ParsePathParams<TPath>, string>
153
161
  : NoInfer<TParams>,
154
162
  TKnownChildren extends RouteConfig[] = RouteConfig[],
163
+ TResolvedId extends string = string extends TRouteId
164
+ ? string extends TPath
165
+ ? string
166
+ : TPath
167
+ : TRouteId,
155
168
  >(
156
169
  options?: TIsRoot extends true
157
170
  ? Omit<
158
171
  RouteOptions<
172
+ TRouteId,
159
173
  TPath,
160
174
  TRouteLoaderData,
161
175
  Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
@@ -171,6 +185,7 @@ type CreateRouteConfigFn<
171
185
  'path'
172
186
  > & { path?: never }
173
187
  : RouteOptions<
188
+ TRouteId,
174
189
  TPath,
175
190
  TRouteLoaderData,
176
191
  Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
@@ -186,10 +201,12 @@ type CreateRouteConfigFn<
186
201
  children?: TKnownChildren,
187
202
  isRoot?: boolean,
188
203
  parentId?: string,
204
+ parentPath?: string,
189
205
  ) => RouteConfig<
190
- RouteId<TParentId, TPath>,
206
+ RoutePrefix<TParentId, TResolvedId>,
207
+ TResolvedId,
191
208
  TPath,
192
- RouteIdToPath<RouteId<TParentId, TPath>>,
209
+ string extends TPath ? '' : RoutePath<RoutePrefix<TParentPath, TPath>>,
193
210
  TRouteLoaderData,
194
211
  Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
195
212
  TActionPayload,
@@ -208,11 +225,10 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
208
225
  children,
209
226
  isRoot = true,
210
227
  parentId,
228
+ parentPath,
211
229
  ) => {
212
230
  if (isRoot) {
213
231
  ;(options as any).path = rootRouteId
214
- } else {
215
- warning(!options.path, 'Routes must have a path property.')
216
232
  }
217
233
 
218
234
  // Strip the root from parentIds
@@ -220,14 +236,16 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
220
236
  parentId = ''
221
237
  }
222
238
 
223
- let path = String(isRoot ? rootRouteId : options.path)
239
+ let path: undefined | string = isRoot ? rootRouteId : options.path
224
240
 
225
241
  // If the path is anything other than an index path, trim it up
226
- if (path !== '/') {
242
+ if (path && path !== '/') {
227
243
  path = trimPath(path)
228
244
  }
229
245
 
230
- let id = joinPaths([parentId, path])
246
+ const routeId = path || (options as { id?: string }).id
247
+
248
+ let id = joinPaths([parentId, routeId])
231
249
 
232
250
  if (path === rootRouteId) {
233
251
  path = '/'
@@ -237,10 +255,12 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
237
255
  id = joinPaths(['/', id])
238
256
  }
239
257
 
240
- const fullPath = id === rootRouteId ? '/' : trimPathRight(id)
258
+ const fullPath =
259
+ id === rootRouteId ? '/' : trimPathRight(joinPaths([parentPath, path]))
241
260
 
242
261
  return {
243
262
  id: id as any,
263
+ routeId: routeId as any,
244
264
  path: path as any,
245
265
  fullPath: fullPath as any,
246
266
  options: options as any,
@@ -249,10 +269,11 @@ export const createRouteConfig: CreateRouteConfigFn<true> = (
249
269
  createRouteConfig(
250
270
  options,
251
271
  cb((childOptions: any) =>
252
- createRouteConfig(childOptions, undefined, false, id),
272
+ createRouteConfig(childOptions, undefined, false, id, fullPath),
253
273
  ),
254
274
  false,
255
275
  parentId,
276
+ parentPath,
256
277
  ),
257
278
  }
258
279
  }
@@ -271,6 +292,8 @@ export interface AnyRouteConfig
271
292
  any,
272
293
  any,
273
294
  any,
295
+ any,
296
+ any,
274
297
  any
275
298
  > {}
276
299
 
@@ -289,6 +312,7 @@ export interface AnyRouteConfigWithChildren<TChildren>
289
312
  any,
290
313
  any,
291
314
  any,
315
+ any,
292
316
  TChildren
293
317
  > {}
294
318
 
@@ -297,7 +321,8 @@ export interface AnyAllRouteInfo {
297
321
  routeInfo: AnyRouteInfo
298
322
  routeInfoById: Record<string, AnyRouteInfo>
299
323
  routeInfoByFullPath: Record<string, AnyRouteInfo>
300
- fullPath: string
324
+ routeIds: any
325
+ routePaths: any
301
326
  }
302
327
 
303
328
  export interface DefaultAllRouteInfo {
@@ -305,7 +330,8 @@ export interface DefaultAllRouteInfo {
305
330
  routeInfo: RouteInfo
306
331
  routeInfoById: Record<string, RouteInfo>
307
332
  routeInfoByFullPath: Record<string, RouteInfo>
308
- fullPath: string
333
+ routeIds: string
334
+ routePaths: string
309
335
  }
310
336
 
311
337
  export interface AllRouteInfo<TRouteConfig extends AnyRouteConfig = RouteConfig>
@@ -325,20 +351,27 @@ export interface RoutesInfoInner<
325
351
  any,
326
352
  any,
327
353
  any,
354
+ any,
355
+ any,
328
356
  any
329
357
  > = RouteInfo,
358
+ TRouteInfoById = {
359
+ [TInfo in TRouteInfo as TInfo['id']]: TInfo
360
+ },
361
+ TRouteInfoByFullPath = {
362
+ [TInfo in TRouteInfo as TInfo['fullPath'] extends RootRouteId
363
+ ? never
364
+ : string extends TInfo['fullPath']
365
+ ? never
366
+ : TInfo['fullPath']]: TInfo
367
+ },
330
368
  > {
331
369
  routeConfig: TRouteConfig
332
370
  routeInfo: TRouteInfo
333
- routeInfoById: {
334
- [TInfo in TRouteInfo as TInfo['id']]: TInfo
335
- }
336
- routeInfoByFullPath: {
337
- [TInfo in TRouteInfo as TInfo['id'] extends RootRouteId
338
- ? never
339
- : RouteIdToPath<TInfo['id']>]: TInfo
340
- }
341
- fullPath: RouteIdToPath<TRouteInfo['id']>
371
+ routeInfoById: TRouteInfoById
372
+ routeInfoByFullPath: TRouteInfoByFullPath
373
+ routeIds: keyof TRouteInfoById
374
+ routePaths: keyof TRouteInfoByFullPath
342
375
  }
343
376
 
344
377
  export interface AnyRoute extends Route<any, any> {}
@@ -356,6 +389,7 @@ export interface AnyRouteInfo
356
389
  any,
357
390
  any,
358
391
  any,
392
+ any,
359
393
  any
360
394
  > {}
361
395
 
@@ -363,7 +397,7 @@ export interface AnyRouteInfo
363
397
  // [E in T as E[TKey]]: E
364
398
  // }
365
399
 
366
- type RouteIdToPath<T extends string> = T extends RootRouteId
400
+ type RoutePath<T extends string> = T extends RootRouteId
367
401
  ? '/'
368
402
  : TrimPathRight<`${T}`>
369
403
 
@@ -397,6 +431,7 @@ export type ValueKeys<O> = Extract<keyof O, PropertyKey>
397
431
 
398
432
  export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
399
433
  infer TId,
434
+ infer TRouteId,
400
435
  infer TPath,
401
436
  infer TFullPath,
402
437
  infer TRouteLoaderData,
@@ -411,10 +446,11 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
411
446
  infer TAllParams,
412
447
  any
413
448
  >
414
- ? string extends TId
449
+ ? string extends TRouteId
415
450
  ? never
416
451
  : RouteInfo<
417
452
  TId,
453
+ TRouteId,
418
454
  TPath,
419
455
  TFullPath,
420
456
  TRouteLoaderData,
@@ -432,8 +468,9 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
432
468
 
433
469
  export interface RouteInfo<
434
470
  TId extends string = string,
471
+ TRouteId extends string = string,
435
472
  TPath extends string = string,
436
- TFullPath extends {} = string,
473
+ TFullPath extends string = string,
437
474
  TRouteLoaderData extends AnyLoaderData = {},
438
475
  TLoaderData extends AnyLoaderData = {},
439
476
  TActionPayload = unknown,
@@ -449,6 +486,7 @@ export interface RouteInfo<
449
486
  TAllParams extends AnyPathParams = {},
450
487
  > {
451
488
  id: TId
489
+ routeId: TRouteId
452
490
  path: TPath
453
491
  fullPath: TFullPath
454
492
  routeLoaderData: TRouteLoaderData
@@ -461,6 +499,7 @@ export interface RouteInfo<
461
499
  params: TParams
462
500
  allParams: TAllParams
463
501
  options: RouteOptions<
502
+ TRouteId,
464
503
  TPath,
465
504
  TRouteLoaderData,
466
505
  TLoaderData,
@@ -484,14 +523,16 @@ type DeepAwaited<T> = T extends Promise<infer A>
484
523
  export const rootRouteId = '__root__' as const
485
524
  export type RootRouteId = typeof rootRouteId
486
525
 
487
- type RouteId<
526
+ type RoutePrefix<
488
527
  TPrefix extends string,
489
- TPath extends string,
490
- > = string extends TPath
528
+ TId extends string,
529
+ > = string extends TId
491
530
  ? RootRouteId
492
- : `${TPrefix}/${TPath}` extends '/'
493
- ? '/'
494
- : `/${TrimPathLeft<`${TrimPathRight<TPrefix>}/${TrimPath<TPath>}`>}`
531
+ : TId extends string
532
+ ? `${TPrefix}/${TId}` extends '/'
533
+ ? '/'
534
+ : `/${TrimPathLeft<`${TrimPathRight<TPrefix>}/${TrimPath<TId>}`>}`
535
+ : never
495
536
 
496
537
  type CleanPath<T extends string> = T extends `${infer L}//${infer R}`
497
538
  ? CleanPath<`${CleanPath<L>}/${CleanPath<R>}`>
@@ -621,6 +662,7 @@ export type ParentParams<TParentParams> = AnyPathParams extends TParentParams
621
662
  }
622
663
 
623
664
  export type RouteOptions<
665
+ TRouteId extends string = string,
624
666
  TPath extends string = string,
625
667
  TRouteLoaderData extends AnyLoaderData = {},
626
668
  TLoaderData extends AnyLoaderData = {},
@@ -635,9 +677,15 @@ export type RouteOptions<
635
677
  string
636
678
  >,
637
679
  TAllParams extends AnyPathParams = {},
638
- > = {
639
- // The path to match (relative to the nearest parent `Route` component or root basepath)
640
- path: TPath
680
+ > = (
681
+ | {
682
+ // The path to match (relative to the nearest parent `Route` component or root basepath)
683
+ path: TPath
684
+ }
685
+ | {
686
+ id: TRouteId
687
+ }
688
+ ) & {
641
689
  // If true, this route will be matched as case-sensitive
642
690
  caseSensitive?: boolean
643
691
  validateSearch?: SearchSchemaValidator<TSearchSchema, TParentSearchSchema>
@@ -654,20 +702,20 @@ export type RouteOptions<
654
702
  // // An array of child routes
655
703
  // children?: Route<any, any, any, any>[]
656
704
  } & (
657
- | {
658
- parseParams?: never
659
- stringifyParams?: never
660
- }
661
- | {
662
- // Parse params optionally receives path params as strings and returns them in a parsed format (like a number or boolean)
663
- parseParams: (
664
- rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
665
- ) => TParams
666
- stringifyParams: (
667
- params: TParams,
668
- ) => Record<ParsePathParams<TPath>, string>
669
- }
670
- ) &
705
+ | {
706
+ parseParams?: never
707
+ stringifyParams?: never
708
+ }
709
+ | {
710
+ // Parse params optionally receives path params as strings and returns them in a parsed format (like a number or boolean)
711
+ parseParams: (
712
+ rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
713
+ ) => TParams
714
+ stringifyParams: (
715
+ params: TParams,
716
+ ) => Record<ParsePathParams<TPath>, string>
717
+ }
718
+ ) &
671
719
  RouteLoaders<
672
720
  // Route Loaders (see below) can be inline on the route, or resolved async
673
721
  TRouteLoaderData,
@@ -924,7 +972,7 @@ type RoutesById<TAllRouteInfo extends AnyAllRouteInfo> = {
924
972
  }
925
973
 
926
974
  // type RoutesByPath<TAllRouteInfo extends AnyAllRouteInfo> = {
927
- // [K in TAllRouteInfo['fullPath']]: Route<
975
+ // [K in TAllRouteInfo['routePaths']]: Route<
928
976
  // TAllRouteInfo,
929
977
  // TAllRouteInfo['routeInfoByFullPath'][K]
930
978
  // >
@@ -934,16 +982,16 @@ export type ValidFromPath<
934
982
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
935
983
  > =
936
984
  | undefined
937
- | (string extends TAllRouteInfo['fullPath']
985
+ | (string extends TAllRouteInfo['routePaths']
938
986
  ? string
939
- : TAllRouteInfo['fullPath'])
987
+ : TAllRouteInfo['routePaths'])
940
988
 
941
989
  // type ValidToPath<
942
990
  // TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
943
991
  // TFrom = undefined,
944
992
  // > = TFrom extends undefined
945
- // ? TAllRouteInfo['fullPath'] | `...unsafe-relative-path (cast "as any")`
946
- // : LooseAutocomplete<'.' | TAllRouteInfo['fullPath']>
993
+ // ? TAllRouteInfo['routePaths'] | `...unsafe-relative-path (cast "as any")`
994
+ // : LooseAutocomplete<'.' | TAllRouteInfo['routePaths']>
947
995
 
948
996
  export interface Router<
949
997
  TRouteConfig extends AnyRouteConfig = RouteConfig,
@@ -1506,64 +1554,88 @@ export function createRouter<
1506
1554
  ...(router.state.pending?.matches ?? []),
1507
1555
  ]
1508
1556
 
1509
- const recurse = async (
1510
- routes: Route<any, any>[],
1511
- parentMatch?: RouteMatch,
1512
- ): Promise<void> => {
1557
+ const recurse = async (routes: Route<any, any>[]): Promise<void> => {
1558
+ const parentMatch = last(matches)
1513
1559
  let params = parentMatch?.params ?? {}
1514
1560
 
1515
1561
  const filteredRoutes = router.options.filterRoutes?.(routes) ?? routes
1516
1562
 
1517
- const route = filteredRoutes?.find((route) => {
1518
- const fuzzy = !!(route.routePath !== '/' || route.childRoutes?.length)
1519
- const matchParams = matchPathname(pathname, {
1520
- to: route.fullPath,
1521
- fuzzy,
1522
- caseSensitive:
1523
- route.options.caseSensitive ?? router.options.caseSensitive,
1524
- })
1563
+ let foundRoutes: Route[] = []
1564
+
1565
+ const findMatchInRoutes = (parentRoutes: Route[], routes: Route[]) => {
1566
+ routes.some((route) => {
1567
+ if (!route.routePath && route.childRoutes?.length) {
1568
+ return findMatchInRoutes(
1569
+ [...foundRoutes, route],
1570
+ route.childRoutes,
1571
+ )
1572
+ }
1525
1573
 
1526
- if (matchParams) {
1527
- let parsedParams
1574
+ const fuzzy = !!(
1575
+ route.routePath !== '/' || route.childRoutes?.length
1576
+ )
1528
1577
 
1529
- try {
1530
- parsedParams =
1531
- route.options.parseParams?.(matchParams!) ?? matchParams
1532
- } catch (err) {
1533
- if (opts?.strictParseParams) {
1534
- throw err
1578
+ const matchParams = matchPathname(pathname, {
1579
+ to: route.fullPath,
1580
+ fuzzy,
1581
+ caseSensitive:
1582
+ route.options.caseSensitive ?? router.options.caseSensitive,
1583
+ })
1584
+
1585
+ if (matchParams) {
1586
+ let parsedParams
1587
+
1588
+ try {
1589
+ parsedParams =
1590
+ route.options.parseParams?.(matchParams!) ?? matchParams
1591
+ } catch (err) {
1592
+ if (opts?.strictParseParams) {
1593
+ throw err
1594
+ }
1595
+ }
1596
+
1597
+ params = {
1598
+ ...params,
1599
+ ...parsedParams,
1535
1600
  }
1536
1601
  }
1537
1602
 
1538
- params = {
1539
- ...params,
1540
- ...parsedParams,
1603
+ if (!!matchParams) {
1604
+ foundRoutes = [...parentRoutes, route]
1541
1605
  }
1542
- }
1543
1606
 
1544
- return !!matchParams
1545
- })
1607
+ return !!foundRoutes.length
1608
+ })
1609
+
1610
+ return !!foundRoutes.length
1611
+ }
1546
1612
 
1547
- if (!route) {
1613
+ findMatchInRoutes([], filteredRoutes)
1614
+
1615
+ if (!foundRoutes.length) {
1548
1616
  return
1549
1617
  }
1550
1618
 
1551
- const interpolatedPath = interpolatePath(route.routePath, params)
1552
- const matchId = interpolatePath(route.routeId, params, true)
1619
+ foundRoutes.forEach((foundRoute) => {
1620
+ const interpolatedPath = interpolatePath(foundRoute.routePath, params)
1621
+ const matchId = interpolatePath(foundRoute.routeId, params, true)
1553
1622
 
1554
- const match =
1555
- existingMatches.find((d) => d.matchId === matchId) ||
1556
- router.preloadCache[matchId]?.match ||
1557
- createRouteMatch(router, route, {
1558
- matchId,
1559
- params,
1560
- pathname: joinPaths([pathname, interpolatedPath]),
1561
- })
1623
+ const match =
1624
+ existingMatches.find((d) => d.matchId === matchId) ||
1625
+ router.preloadCache[matchId]?.match ||
1626
+ createRouteMatch(router, foundRoute, {
1627
+ matchId,
1628
+ params,
1629
+ pathname: joinPaths([pathname, interpolatedPath]),
1630
+ })
1631
+
1632
+ matches.push(match)
1633
+ })
1562
1634
 
1563
- matches.push(match)
1635
+ const foundRoute = last(foundRoutes)!
1564
1636
 
1565
- if (route.childRoutes?.length) {
1566
- recurse(route.childRoutes, match)
1637
+ if (foundRoute.childRoutes?.length) {
1638
+ recurse(foundRoute.childRoutes)
1567
1639
  }
1568
1640
  }
1569
1641
 
@@ -1690,14 +1762,10 @@ export function createRouter<
1690
1762
  isExternal = true
1691
1763
  } catch (e) {}
1692
1764
 
1693
- if (isExternal) {
1694
- if (process.env.NODE_ENV !== 'production') {
1695
- throw new Error(
1696
- 'Attempting to navigate to external url with router.navigate!',
1697
- )
1698
- }
1699
- return
1700
- }
1765
+ invariant(
1766
+ !isExternal,
1767
+ 'Attempting to navigate to external url with router.navigate!',
1768
+ )
1701
1769
 
1702
1770
  return router._navigate({
1703
1771
  from: fromString,
@@ -1867,6 +1935,7 @@ export interface Route<
1867
1935
  TRouteInfo extends AnyRouteInfo = RouteInfo,
1868
1936
  > {
1869
1937
  routeId: TRouteInfo['id']
1938
+ routeRouteId: TRouteInfo['routeId']
1870
1939
  routePath: TRouteInfo['path']
1871
1940
  fullPath: TRouteInfo['fullPath']
1872
1941
  parentRoute?: AnyRoute
@@ -1874,23 +1943,21 @@ export interface Route<
1874
1943
  options: RouteOptions
1875
1944
  router: Router<TAllRouteInfo['routeConfig'], TAllRouteInfo>
1876
1945
  buildLink: <TTo extends string = '.'>(
1877
- options: // CheckRelativePath<
1878
- // TAllRouteInfo,
1879
- // TRouteInfo['fullPath'],
1880
- // NoInfer<TTo>
1881
- // > &
1882
- Omit<LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
1946
+ options: Omit<
1947
+ LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
1948
+ 'from'
1949
+ >,
1883
1950
  ) => LinkInfo
1884
1951
  matchRoute: <
1885
1952
  TTo extends string = '.',
1886
1953
  TResolved extends string = ResolveRelativePath<TRouteInfo['id'], TTo>,
1887
1954
  >(
1888
- matchLocation: // CheckRelativePath<
1889
- // TAllRouteInfo,
1890
- // TRouteInfo['fullPath'],
1891
- // NoInfer<TTo>
1892
- // > &
1893
- Omit<ToOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
1955
+ matchLocation: CheckRelativePath<
1956
+ TAllRouteInfo,
1957
+ TRouteInfo['fullPath'],
1958
+ NoInfer<TTo>
1959
+ > &
1960
+ Omit<ToOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
1894
1961
  opts?: MatchRouteOptions,
1895
1962
  ) => RouteInfoByPath<TAllRouteInfo, TResolved>['allParams']
1896
1963
  navigate: <TTo extends string = '.'>(
@@ -1921,12 +1988,12 @@ export function createRoute<
1921
1988
  // ]).replace(new RegExp(`^${rootRouteId}`), '')
1922
1989
  // ) as TRouteInfo['id']
1923
1990
 
1924
- const { id: routeId, path: routePath, fullPath } = routeConfig
1991
+ const { id, routeId, path: routePath, fullPath } = routeConfig
1925
1992
 
1926
1993
  const action =
1927
- router.state.actions[routeId] ||
1994
+ router.state.actions[id] ||
1928
1995
  (() => {
1929
- router.state.actions[routeId] = {
1996
+ router.state.actions[id] = {
1930
1997
  pending: [],
1931
1998
  submit: async <T, U>(
1932
1999
  submission: T,
@@ -1976,11 +2043,12 @@ export function createRoute<
1976
2043
  }
1977
2044
  },
1978
2045
  }
1979
- return router.state.actions[routeId]!
2046
+ return router.state.actions[id]!
1980
2047
  })()
1981
2048
 
1982
2049
  let route: Route<TAllRouteInfo, TRouteInfo> = {
1983
- routeId,
2050
+ routeId: id,
2051
+ routeRouteId: routeId,
1984
2052
  routePath,
1985
2053
  fullPath,
1986
2054
  options,
@@ -2099,7 +2167,8 @@ export type ToOptions<
2099
2167
  from?: TFrom
2100
2168
  // // When using relative route paths, this option forces resolution from the current path, instead of the route API's path or `from` path
2101
2169
  // fromCurrent?: boolean
2102
- } & SearchParamOptions<TAllRouteInfo, TFrom, TResolvedTo> &
2170
+ } & CheckPath<TAllRouteInfo, NoInfer<TResolvedTo>> &
2171
+ SearchParamOptions<TAllRouteInfo, TFrom, TResolvedTo> &
2103
2172
  PathParamOptions<TAllRouteInfo, TFrom, TResolvedTo>
2104
2173
 
2105
2174
  export type ToPathOption<
@@ -2109,7 +2178,7 @@ export type ToPathOption<
2109
2178
  > =
2110
2179
  | TTo
2111
2180
  | RelativeToPathAutoComplete<
2112
- TAllRouteInfo['fullPath'],
2181
+ TAllRouteInfo['routePaths'],
2113
2182
  NoInfer<TFrom> extends string ? NoInfer<TFrom> : '',
2114
2183
  NoInfer<TTo> & string
2115
2184
  >
@@ -2121,7 +2190,7 @@ export type ToIdOption<
2121
2190
  > =
2122
2191
  | TTo
2123
2192
  | RelativeToPathAutoComplete<
2124
- TAllRouteInfo['routeInfo']['id'],
2193
+ TAllRouteInfo['routeIds'],
2125
2194
  NoInfer<TFrom> extends string ? NoInfer<TFrom> : '',
2126
2195
  NoInfer<TTo> & string
2127
2196
  >
@@ -2151,23 +2220,33 @@ export type CheckRelativePath<
2151
2220
  TTo,
2152
2221
  > = TTo extends string
2153
2222
  ? TFrom extends string
2154
- ? ResolveRelativePath<TFrom, TTo> extends TAllRouteInfo['fullPath']
2223
+ ? ResolveRelativePath<TFrom, TTo> extends TAllRouteInfo['routePaths']
2155
2224
  ? {}
2156
2225
  : {
2157
2226
  Error: `${TFrom} + ${TTo} resolves to ${ResolveRelativePath<
2158
2227
  TFrom,
2159
2228
  TTo
2160
2229
  >}, which is not a valid route path.`
2161
- 'Valid Route Paths': TAllRouteInfo['fullPath']
2230
+ 'Valid Route Paths': TAllRouteInfo['routePaths']
2162
2231
  }
2163
2232
  : {}
2164
2233
  : {}
2165
2234
 
2166
- export type ResolveRelativePath<
2167
- TFrom,
2168
- TTo = '.',
2169
- TRooted = false,
2170
- > = TFrom extends string
2235
+ export type CheckPath<TAllRouteInfo extends AnyAllRouteInfo, TPath> = Exclude<
2236
+ TPath,
2237
+ TAllRouteInfo['routePaths']
2238
+ > extends never
2239
+ ? {}
2240
+ : CheckPathError<TAllRouteInfo, Exclude<TPath, TAllRouteInfo['routePaths']>>
2241
+
2242
+ export type CheckPathError<TAllRouteInfo extends AnyAllRouteInfo, TInvalids> = {
2243
+ Error: `${TInvalids extends string
2244
+ ? TInvalids
2245
+ : never} is not a valid route path.`
2246
+ 'Valid Route Paths': TAllRouteInfo['routePaths']
2247
+ }
2248
+
2249
+ export type ResolveRelativePath<TFrom, TTo = '.'> = TFrom extends string
2171
2250
  ? TTo extends string
2172
2251
  ? TTo extends '.'
2173
2252
  ? TFrom
@@ -2215,21 +2294,19 @@ type SearchParamOptions<
2215
2294
  TTo,
2216
2295
  TFromSchema = RouteInfoByPath<TAllRouteInfo, TFrom>['fullSearchSchema'],
2217
2296
  TToSchema = RouteInfoByPath<TAllRouteInfo, TTo>['fullSearchSchema'],
2218
- > =
2219
- // If the next route search extend or cover the from route, params will be optional
2220
- StartsWith<TFrom, TTo> extends true
2221
- ? {
2222
- search?: SearchReducer<TFromSchema, TToSchema>
2223
- }
2224
- : // Optional search params? Allow it
2225
- keyof PickRequired<TToSchema> extends never
2226
- ? {
2227
- search?: SearchReducer<TFromSchema, TToSchema>
2228
- }
2229
- : {
2230
- // Must have required search params, enforce it
2231
- search: SearchReducer<TFromSchema, TToSchema>
2232
- }
2297
+ > = StartsWith<TFrom, TTo> extends true // If the next route search extend or cover the from route, params will be optional
2298
+ ? {
2299
+ search?: SearchReducer<TFromSchema, TToSchema>
2300
+ }
2301
+ : // Optional search params? Allow it
2302
+ keyof PickRequired<TToSchema> extends never
2303
+ ? {
2304
+ search?: SearchReducer<TFromSchema, TToSchema>
2305
+ }
2306
+ : {
2307
+ // Must have required search params, enforce it
2308
+ search: SearchReducer<TFromSchema, TToSchema>
2309
+ }
2233
2310
 
2234
2311
  type SearchReducer<TFrom, TTo> = TTo | ((current: TFrom) => TTo)
2235
2312