@tanstack/react-router 1.16.2 → 1.16.5
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/dist/cjs/fileRoute.cjs.map +1 -1
- package/dist/cjs/fileRoute.d.cts +4 -2
- package/dist/cjs/link.cjs +16 -16
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/not-found.d.cts +1 -1
- package/dist/cjs/redirects.cjs.map +1 -1
- package/dist/cjs/redirects.d.cts +1 -0
- package/dist/cjs/route.cjs +1 -1
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +4 -3
- package/dist/cjs/router.cjs +142 -149
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +4 -2
- package/dist/esm/fileRoute.d.ts +4 -2
- package/dist/esm/fileRoute.js.map +1 -1
- package/dist/esm/link.js +16 -16
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/not-found.d.ts +1 -1
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/redirects.d.ts +1 -0
- package/dist/esm/redirects.js.map +1 -1
- package/dist/esm/route.d.ts +4 -3
- package/dist/esm/route.js +1 -1
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +4 -2
- package/dist/esm/router.js +143 -150
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/fileRoute.ts +2 -2
- package/src/link.tsx +18 -18
- package/src/not-found.tsx +1 -1
- package/src/redirects.ts +1 -0
- package/src/route.ts +11 -3
- package/src/router.ts +168 -179
package/src/router.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
last,
|
|
39
39
|
pick,
|
|
40
40
|
Timeout,
|
|
41
|
+
isServer,
|
|
41
42
|
} from './utils'
|
|
42
43
|
import { RouteComponent } from './route'
|
|
43
44
|
import { AnyRouteMatch, MatchRouteOptions, RouteMatch } from './Matches'
|
|
@@ -63,19 +64,12 @@ import {
|
|
|
63
64
|
trimPathRight,
|
|
64
65
|
} from './path'
|
|
65
66
|
import invariant from 'tiny-invariant'
|
|
66
|
-
import { isRedirect } from './redirects'
|
|
67
|
+
import { AnyRedirect, isRedirect } from './redirects'
|
|
67
68
|
import { NotFoundError, isNotFound } from './not-found'
|
|
68
69
|
import { ResolveRelativePath, ToOptions } from './link'
|
|
69
70
|
import { NoInfer } from '@tanstack/react-store'
|
|
70
71
|
import warning from 'tiny-warning'
|
|
71
|
-
import {
|
|
72
|
-
DeferredPromise,
|
|
73
|
-
DeferredPromiseState,
|
|
74
|
-
defaultDeserializeError,
|
|
75
|
-
isDehydratedDeferred,
|
|
76
|
-
isServerSideError,
|
|
77
|
-
} from '.'
|
|
78
|
-
// import warning from 'tiny-warning'
|
|
72
|
+
import { DeferredPromiseState } from '.'
|
|
79
73
|
|
|
80
74
|
//
|
|
81
75
|
|
|
@@ -1135,108 +1129,96 @@ export class Router<
|
|
|
1135
1129
|
}
|
|
1136
1130
|
|
|
1137
1131
|
// Check each match middleware to see if the route can be accessed
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
const abortController = new AbortController()
|
|
1143
|
-
|
|
1144
|
-
const handleErrorAndRedirect = (err: any, code: string) => {
|
|
1145
|
-
err.routerCode = code
|
|
1146
|
-
firstBadMatchIndex = firstBadMatchIndex ?? index
|
|
1132
|
+
for (let [index, match] of matches.entries()) {
|
|
1133
|
+
const parentMatch = matches[index - 1]
|
|
1134
|
+
const route = this.looseRoutesById[match.routeId]!
|
|
1135
|
+
const abortController = new AbortController()
|
|
1147
1136
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1137
|
+
const handleError = (err: any, code: string) => {
|
|
1138
|
+
err.routerCode = code
|
|
1139
|
+
firstBadMatchIndex = firstBadMatchIndex ?? index
|
|
1151
1140
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1141
|
+
if (isRedirect(err)) {
|
|
1142
|
+
throw err
|
|
1143
|
+
}
|
|
1155
1144
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1145
|
+
if (isNotFound(err)) {
|
|
1146
|
+
err.routeId = match.routeId
|
|
1147
|
+
throw err
|
|
1148
|
+
}
|
|
1160
1149
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1150
|
+
try {
|
|
1151
|
+
route.options.onError?.(err)
|
|
1152
|
+
} catch (errorHandlerErr) {
|
|
1153
|
+
err = errorHandlerErr
|
|
1165
1154
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
error: err,
|
|
1169
|
-
status: 'error',
|
|
1170
|
-
updatedAt: Date.now(),
|
|
1171
|
-
abortController: new AbortController(),
|
|
1155
|
+
if (isRedirect(errorHandlerErr)) {
|
|
1156
|
+
throw errorHandlerErr
|
|
1172
1157
|
}
|
|
1173
1158
|
}
|
|
1174
1159
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1160
|
+
matches[index] = match = {
|
|
1161
|
+
...match,
|
|
1162
|
+
error: err,
|
|
1163
|
+
status: 'error',
|
|
1164
|
+
updatedAt: Date.now(),
|
|
1165
|
+
abortController: new AbortController(),
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1179
1168
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1169
|
+
try {
|
|
1170
|
+
if (match.paramsError) {
|
|
1171
|
+
handleError(match.paramsError, 'PARSE_PARAMS')
|
|
1172
|
+
}
|
|
1183
1173
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1174
|
+
if (match.searchError) {
|
|
1175
|
+
handleError(match.searchError, 'VALIDATE_SEARCH')
|
|
1176
|
+
}
|
|
1186
1177
|
|
|
1187
|
-
|
|
1188
|
-
route.options.pendingMs ?? this.options.defaultPendingMs
|
|
1189
|
-
const pendingPromise =
|
|
1190
|
-
typeof pendingMs === 'number' && pendingMs <= 0
|
|
1191
|
-
? Promise.resolve()
|
|
1192
|
-
: new Promise<void>((r) => setTimeout(r, pendingMs))
|
|
1193
|
-
|
|
1194
|
-
const beforeLoadContext =
|
|
1195
|
-
(await route.options.beforeLoad?.({
|
|
1196
|
-
search: match.search,
|
|
1197
|
-
abortController,
|
|
1198
|
-
params: match.params,
|
|
1199
|
-
preload: !!preload,
|
|
1200
|
-
context: parentContext,
|
|
1201
|
-
location: this.state.location,
|
|
1202
|
-
// TOOD: just expose state and router, etc
|
|
1203
|
-
navigate: (opts) =>
|
|
1204
|
-
this.navigate({ ...opts, from: match.pathname } as any),
|
|
1205
|
-
buildLocation: this.buildLocation,
|
|
1206
|
-
cause: preload ? 'preload' : match.cause,
|
|
1207
|
-
})) ?? ({} as any)
|
|
1208
|
-
|
|
1209
|
-
if (isRedirect(beforeLoadContext)) {
|
|
1210
|
-
throw beforeLoadContext
|
|
1211
|
-
}
|
|
1178
|
+
const parentContext = parentMatch?.context ?? this.options.context ?? {}
|
|
1212
1179
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1180
|
+
const pendingMs =
|
|
1181
|
+
route.options.pendingMs ?? this.options.defaultPendingMs
|
|
1182
|
+
const pendingPromise =
|
|
1183
|
+
typeof pendingMs === 'number' && pendingMs <= 0
|
|
1184
|
+
? Promise.resolve()
|
|
1185
|
+
: new Promise<void>((r) => setTimeout(r, pendingMs))
|
|
1217
1186
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
match.routeContext,
|
|
1222
|
-
beforeLoadContext,
|
|
1223
|
-
),
|
|
1224
|
-
context: replaceEqualDeep(match.context, context),
|
|
1187
|
+
const beforeLoadContext =
|
|
1188
|
+
(await route.options.beforeLoad?.({
|
|
1189
|
+
search: match.search,
|
|
1225
1190
|
abortController,
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1191
|
+
params: match.params,
|
|
1192
|
+
preload: !!preload,
|
|
1193
|
+
context: parentContext,
|
|
1194
|
+
location: this.state.location,
|
|
1195
|
+
// TOOD: just expose state and router, etc
|
|
1196
|
+
navigate: (opts) =>
|
|
1197
|
+
this.navigate({ ...opts, from: match.pathname } as any),
|
|
1198
|
+
buildLocation: this.buildLocation,
|
|
1199
|
+
cause: preload ? 'preload' : match.cause,
|
|
1200
|
+
})) ?? ({} as any)
|
|
1201
|
+
|
|
1202
|
+
if (isRedirect(beforeLoadContext)) {
|
|
1203
|
+
throw beforeLoadContext
|
|
1231
1204
|
}
|
|
1232
|
-
}
|
|
1233
|
-
} catch (err) {
|
|
1234
|
-
if (isRedirect(err)) {
|
|
1235
|
-
if (!preload) this.navigate(err as any)
|
|
1236
|
-
return matches
|
|
1237
|
-
}
|
|
1238
1205
|
|
|
1239
|
-
|
|
1206
|
+
const context = {
|
|
1207
|
+
...parentContext,
|
|
1208
|
+
...beforeLoadContext,
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
matches[index] = match = {
|
|
1212
|
+
...match,
|
|
1213
|
+
routeContext: replaceEqualDeep(match.routeContext, beforeLoadContext),
|
|
1214
|
+
context: replaceEqualDeep(match.context, context),
|
|
1215
|
+
abortController,
|
|
1216
|
+
pendingPromise,
|
|
1217
|
+
}
|
|
1218
|
+
} catch (err) {
|
|
1219
|
+
handleError(err, 'BEFORE_LOAD')
|
|
1220
|
+
break
|
|
1221
|
+
}
|
|
1240
1222
|
}
|
|
1241
1223
|
|
|
1242
1224
|
const validResolvedMatches = matches.slice(0, firstBadMatchIndex)
|
|
@@ -1244,26 +1226,19 @@ export class Router<
|
|
|
1244
1226
|
|
|
1245
1227
|
validResolvedMatches.forEach((match, index) => {
|
|
1246
1228
|
matchPromises.push(
|
|
1247
|
-
new Promise<void>(async (resolve) => {
|
|
1229
|
+
new Promise<void>(async (resolve, reject) => {
|
|
1248
1230
|
const parentMatchPromise = matchPromises[index - 1]
|
|
1249
1231
|
const route = this.looseRoutesById[match.routeId]!
|
|
1250
1232
|
|
|
1251
|
-
const
|
|
1233
|
+
const handleError = (err: any) => {
|
|
1252
1234
|
if (isRedirect(err)) {
|
|
1253
|
-
|
|
1254
|
-
this.navigate(err as any)
|
|
1255
|
-
}
|
|
1256
|
-
return true
|
|
1235
|
+
throw err
|
|
1257
1236
|
}
|
|
1258
1237
|
|
|
1259
1238
|
if (isNotFound(err)) {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
return true
|
|
1239
|
+
err.routeId = match.routeId
|
|
1240
|
+
throw err
|
|
1264
1241
|
}
|
|
1265
|
-
|
|
1266
|
-
return false
|
|
1267
1242
|
}
|
|
1268
1243
|
|
|
1269
1244
|
let loadPromise: Promise<void> | undefined
|
|
@@ -1360,9 +1335,7 @@ export class Router<
|
|
|
1360
1335
|
const loaderData = await loadPromise
|
|
1361
1336
|
if ((latestPromise = checkLatest())) return await latestPromise
|
|
1362
1337
|
|
|
1363
|
-
|
|
1364
|
-
if (handleErrorAndRedirect(loaderData)) return
|
|
1365
|
-
}
|
|
1338
|
+
handleError(loaderData)
|
|
1366
1339
|
|
|
1367
1340
|
if (didShowPending && pendingMinMs) {
|
|
1368
1341
|
await new Promise((r) => setTimeout(r, pendingMinMs))
|
|
@@ -1372,6 +1345,7 @@ export class Router<
|
|
|
1372
1345
|
|
|
1373
1346
|
const [meta, headers] = await Promise.all([
|
|
1374
1347
|
route.options.meta?.({
|
|
1348
|
+
params: match.params,
|
|
1375
1349
|
loaderData,
|
|
1376
1350
|
}),
|
|
1377
1351
|
route.options.headers?.({
|
|
@@ -1392,13 +1366,13 @@ export class Router<
|
|
|
1392
1366
|
}
|
|
1393
1367
|
} catch (error) {
|
|
1394
1368
|
if ((latestPromise = checkLatest())) return await latestPromise
|
|
1395
|
-
|
|
1369
|
+
handleError(error)
|
|
1396
1370
|
|
|
1397
1371
|
try {
|
|
1398
1372
|
route.options.onError?.(error)
|
|
1399
1373
|
} catch (onErrorError) {
|
|
1400
1374
|
error = onErrorError
|
|
1401
|
-
|
|
1375
|
+
handleError(onErrorError)
|
|
1402
1376
|
}
|
|
1403
1377
|
|
|
1404
1378
|
matches[index] = match = {
|
|
@@ -1439,29 +1413,33 @@ export class Router<
|
|
|
1439
1413
|
!!preload && !this.state.matches.find((d) => d.id === match.id),
|
|
1440
1414
|
}
|
|
1441
1415
|
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1416
|
+
try {
|
|
1417
|
+
if (match.status !== 'success') {
|
|
1418
|
+
// If we need to potentially show the pending component,
|
|
1419
|
+
// start a timer to show it after the pendingMs
|
|
1420
|
+
if (shouldPending) {
|
|
1421
|
+
match.pendingPromise?.then(async () => {
|
|
1422
|
+
if ((latestPromise = checkLatest())) return latestPromise
|
|
1423
|
+
|
|
1424
|
+
didShowPending = true
|
|
1425
|
+
matches[index] = match = {
|
|
1426
|
+
...match,
|
|
1427
|
+
showPending: true,
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
updateMatch(match)
|
|
1431
|
+
resolve()
|
|
1432
|
+
})
|
|
1433
|
+
}
|
|
1454
1434
|
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1435
|
+
// Critical Fetching, we need to await
|
|
1436
|
+
await fetch()
|
|
1437
|
+
} else if (match.invalid || (shouldReload ?? age > staleAge)) {
|
|
1438
|
+
// Background Fetching, no need to wait
|
|
1439
|
+
fetch()
|
|
1458
1440
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
await fetch()
|
|
1462
|
-
} else if (match.invalid || (shouldReload ?? age > staleAge)) {
|
|
1463
|
-
// Background Fetching, no need to wait
|
|
1464
|
-
fetch()
|
|
1441
|
+
} catch (err) {
|
|
1442
|
+
reject(err)
|
|
1465
1443
|
}
|
|
1466
1444
|
|
|
1467
1445
|
resolve()
|
|
@@ -1470,24 +1448,11 @@ export class Router<
|
|
|
1470
1448
|
})
|
|
1471
1449
|
|
|
1472
1450
|
await Promise.all(matchPromises)
|
|
1451
|
+
|
|
1473
1452
|
return matches
|
|
1474
1453
|
}
|
|
1475
1454
|
|
|
1476
|
-
invalidate = () => {
|
|
1477
|
-
const invalidate = (d: any) => ({
|
|
1478
|
-
...d,
|
|
1479
|
-
invalid: true,
|
|
1480
|
-
})
|
|
1481
|
-
|
|
1482
|
-
this.__store.setState((s) => ({
|
|
1483
|
-
...s,
|
|
1484
|
-
matches: s.matches.map(invalidate),
|
|
1485
|
-
cachedMatches: s.cachedMatches.map(invalidate),
|
|
1486
|
-
pendingMatches: s.pendingMatches?.map(invalidate),
|
|
1487
|
-
}))
|
|
1488
|
-
|
|
1489
|
-
this.load()
|
|
1490
|
-
}
|
|
1455
|
+
invalidate = () => {}
|
|
1491
1456
|
|
|
1492
1457
|
load = async (): Promise<void> => {
|
|
1493
1458
|
const promise = new Promise<void>(async (resolve, reject) => {
|
|
@@ -1538,8 +1503,11 @@ export class Router<
|
|
|
1538
1503
|
checkLatest: () => this.checkLatest(promise),
|
|
1539
1504
|
})
|
|
1540
1505
|
} catch (err) {
|
|
1541
|
-
|
|
1542
|
-
|
|
1506
|
+
if (isRedirect(err)) {
|
|
1507
|
+
this.handleRedirect(err)
|
|
1508
|
+
} else if (isNotFound(err)) {
|
|
1509
|
+
this.handleNotFound(pendingMatches, err)
|
|
1510
|
+
}
|
|
1543
1511
|
}
|
|
1544
1512
|
|
|
1545
1513
|
// Only apply the latest transition
|
|
@@ -1609,6 +1577,18 @@ export class Router<
|
|
|
1609
1577
|
return this.latestLoadPromise
|
|
1610
1578
|
}
|
|
1611
1579
|
|
|
1580
|
+
handleRedirect = (err: AnyRedirect) => {
|
|
1581
|
+
if (!err.href) {
|
|
1582
|
+
err.href = this.buildLocation(err as any).href
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
if (isServer) {
|
|
1586
|
+
throw err
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
this.navigate(err as any)
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1612
1592
|
cleanCache = () => {
|
|
1613
1593
|
// This is where all of the garbage collection magic happens
|
|
1614
1594
|
this.__store.setState((s) => {
|
|
@@ -1663,13 +1643,22 @@ export class Router<
|
|
|
1663
1643
|
})
|
|
1664
1644
|
})
|
|
1665
1645
|
|
|
1666
|
-
|
|
1667
|
-
matches
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1646
|
+
try {
|
|
1647
|
+
matches = await this.loadMatches({
|
|
1648
|
+
matches,
|
|
1649
|
+
preload: true,
|
|
1650
|
+
checkLatest: () => undefined,
|
|
1651
|
+
})
|
|
1671
1652
|
|
|
1672
|
-
|
|
1653
|
+
return matches
|
|
1654
|
+
} catch (err) {
|
|
1655
|
+
// Preload errors are not fatal, but we should still log them
|
|
1656
|
+
if (!isRedirect(err) && !isNotFound(err)) {
|
|
1657
|
+
console.error(err)
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
return undefined
|
|
1661
|
+
}
|
|
1673
1662
|
}
|
|
1674
1663
|
|
|
1675
1664
|
matchRoute = <
|
|
@@ -1856,6 +1845,7 @@ export class Router<
|
|
|
1856
1845
|
...match,
|
|
1857
1846
|
...dehydratedMatch,
|
|
1858
1847
|
meta: route.options.meta?.({
|
|
1848
|
+
params: match.params,
|
|
1859
1849
|
loaderData: dehydratedMatch.loaderData,
|
|
1860
1850
|
}),
|
|
1861
1851
|
links: route.options.links?.(),
|
|
@@ -1875,39 +1865,38 @@ export class Router<
|
|
|
1875
1865
|
}
|
|
1876
1866
|
|
|
1877
1867
|
// Finds a match that has a notFoundComponent
|
|
1878
|
-
|
|
1879
|
-
matches: AnyRouteMatch[],
|
|
1880
|
-
currentMatch: AnyRouteMatch,
|
|
1881
|
-
err: NotFoundError,
|
|
1882
|
-
) => {
|
|
1868
|
+
handleNotFound = (matches: AnyRouteMatch[], err: NotFoundError) => {
|
|
1883
1869
|
const matchesByRouteId = Object.fromEntries(
|
|
1884
1870
|
matches.map((match) => [match.routeId, match]),
|
|
1885
1871
|
) as Record<string, AnyRouteMatch>
|
|
1886
1872
|
|
|
1887
|
-
if (err.global) {
|
|
1888
|
-
matchesByRouteId[rootRouteId]!.notFoundError = err
|
|
1889
|
-
} else {
|
|
1873
|
+
if (!err.global && err.routeId) {
|
|
1890
1874
|
// If the err contains a routeId, start searching up from that route
|
|
1891
|
-
let currentRoute =
|
|
1892
|
-
err.route ?? currentMatch.routeId
|
|
1893
|
-
] as AnyRoute
|
|
1875
|
+
let currentRoute = this.looseRoutesById[err.routeId]
|
|
1894
1876
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
currentRoute
|
|
1877
|
+
if (currentRoute) {
|
|
1878
|
+
// Go up the tree until we find a route with a notFoundComponent
|
|
1879
|
+
while (!currentRoute.options.notFoundComponent) {
|
|
1880
|
+
currentRoute = currentRoute?.parentRoute
|
|
1898
1881
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1882
|
+
invariant(
|
|
1883
|
+
currentRoute,
|
|
1884
|
+
'Found invalid route tree while trying to find not-found handler.',
|
|
1885
|
+
)
|
|
1903
1886
|
|
|
1904
|
-
|
|
1905
|
-
|
|
1887
|
+
if (currentRoute.id === rootRouteId) break
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
const match = matchesByRouteId[currentRoute.id]
|
|
1891
|
+
invariant(match, 'Could not find match for route: ' + currentRoute.id)
|
|
1892
|
+
match.notFoundError = err
|
|
1906
1893
|
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
match.notFoundError = err
|
|
1894
|
+
return
|
|
1895
|
+
}
|
|
1910
1896
|
}
|
|
1897
|
+
|
|
1898
|
+
// Otherwise, just set the notFoundError on the root route
|
|
1899
|
+
matchesByRouteId[rootRouteId]!.notFoundError = err
|
|
1911
1900
|
}
|
|
1912
1901
|
|
|
1913
1902
|
hasNotFoundMatch = () => {
|