@tanstack/router-core 1.120.7 → 1.121.0-alpha.11

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 (51) hide show
  1. package/dist/cjs/fileRoute.d.cts +6 -2
  2. package/dist/cjs/index.cjs +3 -0
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/index.d.cts +7 -7
  5. package/dist/cjs/link.cjs.map +1 -1
  6. package/dist/cjs/link.d.cts +18 -1
  7. package/dist/cjs/path.cjs +130 -16
  8. package/dist/cjs/path.cjs.map +1 -1
  9. package/dist/cjs/path.d.cts +17 -0
  10. package/dist/cjs/redirect.cjs +17 -7
  11. package/dist/cjs/redirect.cjs.map +1 -1
  12. package/dist/cjs/redirect.d.cts +13 -7
  13. package/dist/cjs/route.cjs +12 -1
  14. package/dist/cjs/route.cjs.map +1 -1
  15. package/dist/cjs/route.d.cts +18 -27
  16. package/dist/cjs/router.cjs +395 -335
  17. package/dist/cjs/router.cjs.map +1 -1
  18. package/dist/cjs/router.d.cts +48 -8
  19. package/dist/cjs/typePrimitives.d.cts +2 -2
  20. package/dist/cjs/utils.cjs.map +1 -1
  21. package/dist/cjs/utils.d.cts +3 -0
  22. package/dist/esm/fileRoute.d.ts +6 -2
  23. package/dist/esm/index.d.ts +7 -7
  24. package/dist/esm/index.js +5 -2
  25. package/dist/esm/link.d.ts +18 -1
  26. package/dist/esm/link.js.map +1 -1
  27. package/dist/esm/path.d.ts +17 -0
  28. package/dist/esm/path.js +130 -16
  29. package/dist/esm/path.js.map +1 -1
  30. package/dist/esm/redirect.d.ts +13 -7
  31. package/dist/esm/redirect.js +17 -7
  32. package/dist/esm/redirect.js.map +1 -1
  33. package/dist/esm/route.d.ts +18 -27
  34. package/dist/esm/route.js +12 -1
  35. package/dist/esm/route.js.map +1 -1
  36. package/dist/esm/router.d.ts +48 -8
  37. package/dist/esm/router.js +398 -338
  38. package/dist/esm/router.js.map +1 -1
  39. package/dist/esm/typePrimitives.d.ts +2 -2
  40. package/dist/esm/utils.d.ts +3 -0
  41. package/dist/esm/utils.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/fileRoute.ts +90 -1
  44. package/src/index.ts +14 -8
  45. package/src/link.ts +97 -11
  46. package/src/path.ts +181 -16
  47. package/src/redirect.ts +39 -16
  48. package/src/route.ts +91 -64
  49. package/src/router.ts +569 -434
  50. package/src/typePrimitives.ts +2 -2
  51. package/src/utils.ts +15 -0
@@ -48,6 +48,7 @@ class RouterCore {
48
48
  this.isScrollRestoring = false;
49
49
  this.isScrollRestorationSetup = false;
50
50
  this.startTransition = (fn) => fn();
51
+ this.isShell = false;
51
52
  this.update = (newOptions) => {
52
53
  var _a;
53
54
  if (newOptions.notFoundRoute) {
@@ -74,10 +75,7 @@ class RouterCore {
74
75
  this.basepath = `/${path.trimPath(newOptions.basepath)}`;
75
76
  }
76
77
  }
77
- if (
78
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
79
- !this.history || this.options.history && this.options.history !== this.history
80
- ) {
78
+ if (!this.history || this.options.history && this.options.history !== this.history) {
81
79
  this.history = this.options.history ?? (this.isServer ? history.createMemoryHistory({
82
80
  initialEntries: [this.basepath || "/"]
83
81
  }) : history.createBrowserHistory());
@@ -100,16 +98,28 @@ class RouterCore {
100
98
  });
101
99
  scrollRestoration.setupScrollRestoration(this);
102
100
  }
103
- if (typeof window !== "undefined" && "CSS" in window && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
104
- typeof ((_a = window.CSS) == null ? void 0 : _a.supports) === "function") {
101
+ if (typeof window !== "undefined" && "CSS" in window && typeof ((_a = window.CSS) == null ? void 0 : _a.supports) === "function") {
105
102
  this.isViewTransitionTypesSupported = window.CSS.supports(
106
103
  "selector(:active-view-transition-type(a)"
107
104
  );
108
105
  }
106
+ if (this.latestLocation.search.__TSS_SHELL) {
107
+ this.isShell = true;
108
+ }
109
109
  };
110
110
  this.buildRouteTree = () => {
111
- this.routesById = {};
112
- this.routesByPath = {};
111
+ const { routesById, routesByPath, flatRoutes } = processRouteTree({
112
+ routeTree: this.routeTree,
113
+ initRoute: (route, i) => {
114
+ route.init({
115
+ originalIndex: i,
116
+ defaultSsr: this.options.defaultSsr
117
+ });
118
+ }
119
+ });
120
+ this.routesById = routesById;
121
+ this.routesByPath = routesByPath;
122
+ this.flatRoutes = flatRoutes;
113
123
  const notFoundRoute = this.options.notFoundRoute;
114
124
  if (notFoundRoute) {
115
125
  notFoundRoute.init({
@@ -118,77 +128,6 @@ class RouterCore {
118
128
  });
119
129
  this.routesById[notFoundRoute.id] = notFoundRoute;
120
130
  }
121
- const recurseRoutes = (childRoutes) => {
122
- childRoutes.forEach((childRoute, i) => {
123
- childRoute.init({
124
- originalIndex: i,
125
- defaultSsr: this.options.defaultSsr
126
- });
127
- const existingRoute = this.routesById[childRoute.id];
128
- invariant(
129
- !existingRoute,
130
- `Duplicate routes found with id: ${String(childRoute.id)}`
131
- );
132
- this.routesById[childRoute.id] = childRoute;
133
- if (!childRoute.isRoot && childRoute.path) {
134
- const trimmedFullPath = path.trimPathRight(childRoute.fullPath);
135
- if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith("/")) {
136
- this.routesByPath[trimmedFullPath] = childRoute;
137
- }
138
- }
139
- const children = childRoute.children;
140
- if (children == null ? void 0 : children.length) {
141
- recurseRoutes(children);
142
- }
143
- });
144
- };
145
- recurseRoutes([this.routeTree]);
146
- const scoredRoutes = [];
147
- const routes = Object.values(this.routesById);
148
- routes.forEach((d, i) => {
149
- var _a;
150
- if (d.isRoot || !d.path) {
151
- return;
152
- }
153
- const trimmed = path.trimPathLeft(d.fullPath);
154
- const parsed = path.parsePathname(trimmed);
155
- while (parsed.length > 1 && ((_a = parsed[0]) == null ? void 0 : _a.value) === "/") {
156
- parsed.shift();
157
- }
158
- const scores = parsed.map((segment) => {
159
- if (segment.value === "/") {
160
- return 0.75;
161
- }
162
- if (segment.type === "param") {
163
- return 0.5;
164
- }
165
- if (segment.type === "wildcard") {
166
- return 0.25;
167
- }
168
- return 1;
169
- });
170
- scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores });
171
- });
172
- this.flatRoutes = scoredRoutes.sort((a, b) => {
173
- const minLength = Math.min(a.scores.length, b.scores.length);
174
- for (let i = 0; i < minLength; i++) {
175
- if (a.scores[i] !== b.scores[i]) {
176
- return b.scores[i] - a.scores[i];
177
- }
178
- }
179
- if (a.scores.length !== b.scores.length) {
180
- return b.scores.length - a.scores.length;
181
- }
182
- for (let i = 0; i < minLength; i++) {
183
- if (a.parsed[i].value !== b.parsed[i].value) {
184
- return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
185
- }
186
- }
187
- return a.index - b.index;
188
- }).map((d, i) => {
189
- d.child.rank = i;
190
- return d.child;
191
- });
192
131
  };
193
132
  this.subscribe = (eventType, fn) => {
194
133
  const listener = {
@@ -257,41 +196,19 @@ class RouterCore {
257
196
  },
258
197
  opts
259
198
  );
260
- } else {
261
- return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
262
199
  }
200
+ return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
263
201
  };
264
- this.getMatchedRoutes = (next, dest) => {
265
- let routeParams = {};
266
- const trimmedPath = path.trimPathRight(next.pathname);
267
- const getMatchedParams = (route) => {
268
- const result = path.matchPathname(this.basepath, trimmedPath, {
269
- to: route.fullPath,
270
- caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
271
- fuzzy: true
272
- });
273
- return result;
274
- };
275
- let foundRoute = (dest == null ? void 0 : dest.to) !== void 0 ? this.routesByPath[dest.to] : void 0;
276
- if (foundRoute) {
277
- routeParams = getMatchedParams(foundRoute);
278
- } else {
279
- foundRoute = this.flatRoutes.find((route) => {
280
- const matchedParams = getMatchedParams(route);
281
- if (matchedParams) {
282
- routeParams = matchedParams;
283
- return true;
284
- }
285
- return false;
286
- });
287
- }
288
- let routeCursor = foundRoute || this.routesById[root.rootRouteId];
289
- const matchedRoutes = [routeCursor];
290
- while (routeCursor.parentRoute) {
291
- routeCursor = routeCursor.parentRoute;
292
- matchedRoutes.unshift(routeCursor);
293
- }
294
- return { matchedRoutes, routeParams, foundRoute };
202
+ this.getMatchedRoutes = (pathname, routePathname) => {
203
+ return getMatchedRoutes({
204
+ pathname,
205
+ routePathname,
206
+ basepath: this.basepath,
207
+ caseSensitive: this.options.caseSensitive,
208
+ routesByPath: this.routesByPath,
209
+ routesById: this.routesById,
210
+ flatRoutes: this.flatRoutes
211
+ });
295
212
  };
296
213
  this.cancelMatch = (id) => {
297
214
  const match = this.getMatch(id);
@@ -306,173 +223,92 @@ class RouterCore {
306
223
  });
307
224
  };
308
225
  this.buildLocation = (opts) => {
309
- const build = (dest = {}, matchedRoutesResult) => {
310
- var _a, _b, _c, _d, _e, _f, _g;
311
- const fromMatches = dest._fromLocation ? this.matchRoutes(dest._fromLocation, { _buildLocation: true }) : this.state.matches;
312
- const fromMatch = dest.from != null ? fromMatches.find(
313
- (d) => path.matchPathname(this.basepath, path.trimPathRight(d.pathname), {
314
- to: dest.from,
315
- caseSensitive: false,
316
- fuzzy: false
317
- })
318
- ) : void 0;
319
- const fromPath = (fromMatch == null ? void 0 : fromMatch.pathname) || this.latestLocation.pathname;
320
- invariant(
321
- dest.from == null || fromMatch != null,
322
- "Could not find match for from: " + dest.from
323
- );
324
- const fromSearch = ((_a = this.state.pendingMatches) == null ? void 0 : _a.length) ? (_b = utils.last(this.state.pendingMatches)) == null ? void 0 : _b.search : ((_c = utils.last(fromMatches)) == null ? void 0 : _c.search) || this.latestLocation.search;
325
- const stayingMatches = matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.filter(
326
- (d) => fromMatches.find((e) => e.routeId === d.id)
327
- );
328
- let pathname;
329
- if (dest.to) {
330
- const resolvePathTo = (fromMatch == null ? void 0 : fromMatch.fullPath) || ((_d = utils.last(fromMatches)) == null ? void 0 : _d.fullPath) || this.latestLocation.pathname;
331
- pathname = this.resolvePathWithBase(resolvePathTo, `${dest.to}`);
332
- } else {
333
- const fromRouteByFromPathRouteId = this.routesById[(_e = stayingMatches == null ? void 0 : stayingMatches.find((route) => {
334
- const interpolatedPath = path.interpolatePath({
335
- path: route.fullPath,
336
- params: (matchedRoutesResult == null ? void 0 : matchedRoutesResult.routeParams) ?? {},
337
- decodeCharMap: this.pathParamsDecodeCharMap
338
- }).interpolatedPath;
339
- const pathname2 = path.joinPaths([this.basepath, interpolatedPath]);
340
- return pathname2 === fromPath;
341
- })) == null ? void 0 : _e.id];
342
- pathname = this.resolvePathWithBase(
343
- fromPath,
344
- (fromRouteByFromPathRouteId == null ? void 0 : fromRouteByFromPathRouteId.to) ?? fromPath
345
- );
226
+ const build = (dest = {}) => {
227
+ var _a;
228
+ const currentLocation = dest._fromLocation || this.latestLocation;
229
+ const allFromMatches = this.matchRoutes(currentLocation, {
230
+ _buildLocation: true
231
+ });
232
+ const lastMatch = utils.last(allFromMatches);
233
+ let fromPath = lastMatch.fullPath;
234
+ if (dest.unsafeRelative === "path") {
235
+ fromPath = currentLocation.pathname;
236
+ } else if (dest.to && dest.from) {
237
+ fromPath = dest.from;
238
+ const existingFrom = [...allFromMatches].reverse().find((d) => {
239
+ return d.fullPath === fromPath || d.fullPath === path.joinPaths([fromPath, "/"]);
240
+ });
241
+ if (!existingFrom) {
242
+ console.warn(`Could not find match for from: ${dest.from}`);
243
+ }
346
244
  }
347
- const prevParams = { ...(_f = utils.last(fromMatches)) == null ? void 0 : _f.params };
348
- let nextParams = (dest.params ?? true) === true ? prevParams : {
349
- ...prevParams,
350
- ...utils.functionalUpdate(dest.params, prevParams)
245
+ const fromSearch = lastMatch.search;
246
+ const fromParams = { ...lastMatch.params };
247
+ const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : fromPath;
248
+ let nextParams = (dest.params ?? true) === true ? fromParams : {
249
+ ...fromParams,
250
+ ...utils.functionalUpdate(dest.params, fromParams)
351
251
  };
252
+ const destRoutes = this.matchRoutes(
253
+ nextTo,
254
+ {},
255
+ {
256
+ _buildLocation: true
257
+ }
258
+ ).map((d) => this.looseRoutesById[d.routeId]);
352
259
  if (Object.keys(nextParams).length > 0) {
353
- matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.map((route) => {
260
+ destRoutes.map((route) => {
354
261
  var _a2;
355
262
  return ((_a2 = route.options.params) == null ? void 0 : _a2.stringify) ?? route.options.stringifyParams;
356
263
  }).filter(Boolean).forEach((fn) => {
357
264
  nextParams = { ...nextParams, ...fn(nextParams) };
358
265
  });
359
266
  }
360
- pathname = path.interpolatePath({
361
- path: pathname,
267
+ const nextPathname = path.interpolatePath({
268
+ path: nextTo,
362
269
  params: nextParams ?? {},
363
270
  leaveWildcards: false,
364
271
  leaveParams: opts.leaveParams,
365
272
  decodeCharMap: this.pathParamsDecodeCharMap
366
273
  }).interpolatedPath;
367
- let search = fromSearch;
368
- if (opts._includeValidateSearch && ((_g = this.options.search) == null ? void 0 : _g.strict)) {
274
+ let nextSearch = fromSearch;
275
+ if (opts._includeValidateSearch && ((_a = this.options.search) == null ? void 0 : _a.strict)) {
369
276
  let validatedSearch = {};
370
- matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.forEach((route) => {
277
+ destRoutes.forEach((route) => {
371
278
  try {
372
279
  if (route.options.validateSearch) {
373
280
  validatedSearch = {
374
281
  ...validatedSearch,
375
282
  ...validateSearch(route.options.validateSearch, {
376
283
  ...validatedSearch,
377
- ...search
284
+ ...nextSearch
378
285
  }) ?? {}
379
286
  };
380
287
  }
381
288
  } catch {
382
289
  }
383
290
  });
384
- search = validatedSearch;
291
+ nextSearch = validatedSearch;
385
292
  }
386
- const applyMiddlewares = (search2) => {
387
- const allMiddlewares = (matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.reduce(
388
- (acc, route) => {
389
- var _a2;
390
- const middlewares = [];
391
- if ("search" in route.options) {
392
- if ((_a2 = route.options.search) == null ? void 0 : _a2.middlewares) {
393
- middlewares.push(...route.options.search.middlewares);
394
- }
395
- } else if (route.options.preSearchFilters || route.options.postSearchFilters) {
396
- const legacyMiddleware = ({
397
- search: search3,
398
- next
399
- }) => {
400
- let nextSearch = search3;
401
- if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
402
- nextSearch = route.options.preSearchFilters.reduce(
403
- (prev, next2) => next2(prev),
404
- search3
405
- );
406
- }
407
- const result = next(nextSearch);
408
- if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
409
- return route.options.postSearchFilters.reduce(
410
- (prev, next2) => next2(prev),
411
- result
412
- );
413
- }
414
- return result;
415
- };
416
- middlewares.push(legacyMiddleware);
417
- }
418
- if (opts._includeValidateSearch && route.options.validateSearch) {
419
- const validate = ({ search: search3, next }) => {
420
- const result = next(search3);
421
- try {
422
- const validatedSearch = {
423
- ...result,
424
- ...validateSearch(
425
- route.options.validateSearch,
426
- result
427
- ) ?? {}
428
- };
429
- return validatedSearch;
430
- } catch {
431
- return result;
432
- }
433
- };
434
- middlewares.push(validate);
435
- }
436
- return acc.concat(middlewares);
437
- },
438
- []
439
- )) ?? [];
440
- const final = ({ search: search3 }) => {
441
- if (!dest.search) {
442
- return {};
443
- }
444
- if (dest.search === true) {
445
- return search3;
446
- }
447
- return utils.functionalUpdate(dest.search, search3);
448
- };
449
- allMiddlewares.push(final);
450
- const applyNext = (index, currentSearch) => {
451
- if (index >= allMiddlewares.length) {
452
- return currentSearch;
453
- }
454
- const middleware = allMiddlewares[index];
455
- const next = (newSearch) => {
456
- return applyNext(index + 1, newSearch);
457
- };
458
- return middleware({ search: currentSearch, next });
459
- };
460
- return applyNext(0, search2);
461
- };
462
- search = applyMiddlewares(search);
463
- search = utils.replaceEqualDeep(fromSearch, search);
464
- const searchStr = this.options.stringifySearch(search);
465
- const hash = dest.hash === true ? this.latestLocation.hash : dest.hash ? utils.functionalUpdate(dest.hash, this.latestLocation.hash) : void 0;
293
+ nextSearch = applySearchMiddleware({
294
+ search: nextSearch,
295
+ dest,
296
+ destRoutes,
297
+ _includeValidateSearch: opts._includeValidateSearch
298
+ });
299
+ nextSearch = utils.replaceEqualDeep(fromSearch, nextSearch);
300
+ const searchStr = this.options.stringifySearch(nextSearch);
301
+ const hash = dest.hash === true ? currentLocation.hash : dest.hash ? utils.functionalUpdate(dest.hash, currentLocation.hash) : void 0;
466
302
  const hashStr = hash ? `#${hash}` : "";
467
- let nextState = dest.state === true ? this.latestLocation.state : dest.state ? utils.functionalUpdate(dest.state, this.latestLocation.state) : {};
468
- nextState = utils.replaceEqualDeep(this.latestLocation.state, nextState);
303
+ let nextState = dest.state === true ? currentLocation.state : dest.state ? utils.functionalUpdate(dest.state, currentLocation.state) : {};
304
+ nextState = utils.replaceEqualDeep(currentLocation.state, nextState);
469
305
  return {
470
- pathname,
471
- search,
306
+ pathname: nextPathname,
307
+ search: nextSearch,
472
308
  searchStr,
473
309
  state: nextState,
474
310
  hash: hash ?? "",
475
- href: `${pathname}${searchStr}${hashStr}`,
311
+ href: `${nextPathname}${searchStr}${hashStr}`,
476
312
  unmaskOnReload: dest.unmaskOnReload
477
313
  };
478
314
  };
@@ -504,14 +340,11 @@ class RouterCore {
504
340
  maskedNext = build(maskedDest);
505
341
  }
506
342
  }
507
- const nextMatches = this.getMatchedRoutes(next, dest);
508
- const final = build(dest, nextMatches);
509
343
  if (maskedNext) {
510
- const maskedMatches = this.getMatchedRoutes(maskedNext, maskedDest);
511
- const maskedFinal = build(maskedDest, maskedMatches);
512
- final.maskedLocation = maskedFinal;
344
+ const maskedFinal = build(maskedDest);
345
+ next.maskedLocation = maskedFinal;
513
346
  }
514
- return final;
347
+ return next;
515
348
  };
516
349
  if (opts.mask) {
517
350
  return buildWithMatches(opts, {
@@ -618,6 +451,13 @@ class RouterCore {
618
451
  });
619
452
  };
620
453
  this.navigate = ({ to, reloadDocument, href, ...rest }) => {
454
+ if (!reloadDocument && href) {
455
+ try {
456
+ new URL(`${href}`);
457
+ reloadDocument = true;
458
+ } catch {
459
+ }
460
+ }
621
461
  if (reloadDocument) {
622
462
  if (!href) {
623
463
  const location = this.buildLocation({ to, ...rest });
@@ -636,8 +476,23 @@ class RouterCore {
636
476
  to
637
477
  });
638
478
  };
639
- this.load = async (opts) => {
479
+ this.beforeLoad = () => {
480
+ this.cancelMatches();
640
481
  this.latestLocation = this.parseLocation(this.latestLocation);
482
+ const pendingMatches = this.matchRoutes(this.latestLocation);
483
+ this.__store.setState((s) => ({
484
+ ...s,
485
+ status: "pending",
486
+ isLoading: true,
487
+ location: this.latestLocation,
488
+ pendingMatches,
489
+ // If a cached moved to pendingMatches, remove it from cachedMatches
490
+ cachedMatches: s.cachedMatches.filter((d) => {
491
+ return !pendingMatches.find((e) => e.id === d.id);
492
+ })
493
+ }));
494
+ };
495
+ this.load = async (opts) => {
641
496
  let redirect$1;
642
497
  let notFound$1;
643
498
  let loadPromise;
@@ -645,24 +500,9 @@ class RouterCore {
645
500
  this.startTransition(async () => {
646
501
  var _a;
647
502
  try {
503
+ this.beforeLoad();
648
504
  const next = this.latestLocation;
649
505
  const prevLocation = this.state.resolvedLocation;
650
- this.cancelMatches();
651
- let pendingMatches;
652
- store.batch(() => {
653
- pendingMatches = this.matchRoutes(next);
654
- this.__store.setState((s) => ({
655
- ...s,
656
- status: "pending",
657
- isLoading: true,
658
- location: next,
659
- pendingMatches,
660
- // If a cached moved to pendingMatches, remove it from cachedMatches
661
- cachedMatches: s.cachedMatches.filter((d) => {
662
- return !pendingMatches.find((e) => e.id === d.id);
663
- })
664
- }));
665
- });
666
506
  if (!this.state.redirect) {
667
507
  this.emit({
668
508
  type: "onBeforeNavigate",
@@ -681,7 +521,7 @@ class RouterCore {
681
521
  });
682
522
  await this.loadMatches({
683
523
  sync: opts == null ? void 0 : opts.sync,
684
- matches: pendingMatches,
524
+ matches: this.state.pendingMatches,
685
525
  location: next,
686
526
  // eslint-disable-next-line @typescript-eslint/require-await
687
527
  onReady: async () => {
@@ -730,11 +570,11 @@ class RouterCore {
730
570
  }
731
571
  });
732
572
  } catch (err) {
733
- if (redirect.isResolvedRedirect(err)) {
573
+ if (redirect.isRedirect(err)) {
734
574
  redirect$1 = err;
735
575
  if (!this.isServer) {
736
576
  this.navigate({
737
- ...redirect$1,
577
+ ...redirect$1.options,
738
578
  replace: true,
739
579
  ignoreBlocker: true
740
580
  });
@@ -744,7 +584,7 @@ class RouterCore {
744
584
  }
745
585
  this.__store.setState((s) => ({
746
586
  ...s,
747
- statusCode: redirect$1 ? redirect$1.statusCode : notFound$1 ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200,
587
+ statusCode: redirect$1 ? redirect$1.status : notFound$1 ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200,
748
588
  redirect: redirect$1
749
589
  }));
750
590
  }
@@ -842,12 +682,14 @@ class RouterCore {
842
682
  };
843
683
  const handleRedirectAndNotFound = (match, err) => {
844
684
  var _a, _b, _c, _d;
845
- if (redirect.isResolvedRedirect(err)) {
846
- if (!err.reloadDocument) {
847
- throw err;
848
- }
849
- }
850
685
  if (redirect.isRedirect(err) || notFound.isNotFound(err)) {
686
+ if (redirect.isRedirect(err)) {
687
+ if (err.redirectHandled) {
688
+ if (!err.options.reloadDocument) {
689
+ throw err;
690
+ }
691
+ }
692
+ }
851
693
  updateMatch(match.id, (prev) => ({
852
694
  ...prev,
853
695
  status: redirect.isRedirect(err) ? "redirected" : notFound.isNotFound(err) ? "notFound" : "error",
@@ -864,7 +706,9 @@ class RouterCore {
864
706
  (_c = match.loadPromise) == null ? void 0 : _c.resolve();
865
707
  if (redirect.isRedirect(err)) {
866
708
  rendered = true;
867
- err = this.resolveRedirect({ ...err, _fromLocation: location });
709
+ err.options._fromLocation = location;
710
+ err.redirectHandled = true;
711
+ err = this.resolveRedirect(err);
868
712
  throw err;
869
713
  } else if (notFound.isNotFound(err)) {
870
714
  this._handleNotFound(matches, err, {
@@ -1072,7 +916,7 @@ class RouterCore {
1072
916
  loaderPromise: utils.createControlledPromise(),
1073
917
  preload: !!preload && !this.state.matches.find((d) => d.id === matchId)
1074
918
  }));
1075
- const executeHead = () => {
919
+ const executeHead = async () => {
1076
920
  var _a2, _b2, _c2, _d2, _e, _f;
1077
921
  const match = this.getMatch(matchId);
1078
922
  if (!match) {
@@ -1084,20 +928,13 @@ class RouterCore {
1084
928
  params: match.params,
1085
929
  loaderData: match.loaderData
1086
930
  };
1087
- const headFnContent = (_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext);
931
+ const headFnContent = await ((_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext));
1088
932
  const meta = headFnContent == null ? void 0 : headFnContent.meta;
1089
933
  const links = headFnContent == null ? void 0 : headFnContent.links;
1090
934
  const headScripts = headFnContent == null ? void 0 : headFnContent.scripts;
1091
- const scripts = (_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext);
1092
- const headers = (_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext);
1093
- updateMatch(matchId, (prev) => ({
1094
- ...prev,
1095
- meta,
1096
- links,
1097
- headScripts,
1098
- headers,
1099
- scripts
1100
- }));
935
+ const scripts = await ((_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext));
936
+ const headers = await ((_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext));
937
+ return { meta, links, headScripts, headers, scripts };
1101
938
  };
1102
939
  const runLoader = async () => {
1103
940
  var _a2, _b2, _c2, _d2, _e;
@@ -1122,17 +959,19 @@ class RouterCore {
1122
959
  await route._lazyPromise;
1123
960
  await potentialPendingMinPromise();
1124
961
  await route._componentsPromise;
1125
- store.batch(() => {
1126
- updateMatch(matchId, (prev) => ({
1127
- ...prev,
1128
- error: void 0,
1129
- status: "success",
1130
- isFetching: false,
1131
- updatedAt: Date.now(),
1132
- loaderData
1133
- }));
1134
- executeHead();
1135
- });
962
+ updateMatch(matchId, (prev) => ({
963
+ ...prev,
964
+ error: void 0,
965
+ status: "success",
966
+ isFetching: false,
967
+ updatedAt: Date.now(),
968
+ loaderData
969
+ }));
970
+ const head = await executeHead();
971
+ updateMatch(matchId, (prev) => ({
972
+ ...prev,
973
+ ...head
974
+ }));
1136
975
  } catch (e) {
1137
976
  let error = e;
1138
977
  await potentialPendingMinPromise();
@@ -1146,28 +985,26 @@ class RouterCore {
1146
985
  onErrorError
1147
986
  );
1148
987
  }
1149
- store.batch(() => {
1150
- updateMatch(matchId, (prev) => ({
1151
- ...prev,
1152
- error,
1153
- status: "error",
1154
- isFetching: false
1155
- }));
1156
- executeHead();
1157
- });
988
+ const head = await executeHead();
989
+ updateMatch(matchId, (prev) => ({
990
+ ...prev,
991
+ error,
992
+ status: "error",
993
+ isFetching: false,
994
+ ...head
995
+ }));
1158
996
  }
1159
997
  (_e = this.serverSsr) == null ? void 0 : _e.onMatchSettled({
1160
998
  router: this,
1161
999
  match: this.getMatch(matchId)
1162
1000
  });
1163
1001
  } catch (err) {
1164
- store.batch(() => {
1165
- updateMatch(matchId, (prev) => ({
1166
- ...prev,
1167
- loaderPromise: void 0
1168
- }));
1169
- executeHead();
1170
- });
1002
+ const head = await executeHead();
1003
+ updateMatch(matchId, (prev) => ({
1004
+ ...prev,
1005
+ loaderPromise: void 0,
1006
+ ...head
1007
+ }));
1171
1008
  handleRedirectAndNotFound(this.getMatch(matchId), err);
1172
1009
  }
1173
1010
  };
@@ -1187,15 +1024,19 @@ class RouterCore {
1187
1024
  loaderPromise: void 0
1188
1025
  }));
1189
1026
  } catch (err) {
1190
- if (redirect.isResolvedRedirect(err)) {
1191
- await this.navigate(err);
1027
+ if (redirect.isRedirect(err)) {
1028
+ await this.navigate(err.options);
1192
1029
  }
1193
1030
  }
1194
1031
  })();
1195
1032
  } else if (status !== "success" || loaderShouldRunAsync && sync) {
1196
1033
  await runLoader();
1197
1034
  } else {
1198
- executeHead();
1035
+ const head = await executeHead();
1036
+ updateMatch(matchId, (prev) => ({
1037
+ ...prev,
1038
+ ...head
1039
+ }));
1199
1040
  }
1200
1041
  }
1201
1042
  if (!loaderIsRunningAsync) {
@@ -1254,10 +1095,13 @@ class RouterCore {
1254
1095
  });
1255
1096
  return this.load({ sync: opts == null ? void 0 : opts.sync });
1256
1097
  };
1257
- this.resolveRedirect = (err) => {
1258
- const redirect2 = err;
1259
- if (!redirect2.href) {
1260
- redirect2.href = this.buildLocation(redirect2).href;
1098
+ this.resolveRedirect = (redirect2) => {
1099
+ if (!redirect2.options.href) {
1100
+ redirect2.options.href = this.buildLocation(redirect2.options).href;
1101
+ redirect2.headers.set("Location", redirect2.options.href);
1102
+ }
1103
+ if (!redirect2.headers.get("Location")) {
1104
+ redirect2.headers.set("Location", redirect2.options.href);
1261
1105
  }
1262
1106
  return redirect2;
1263
1107
  };
@@ -1359,11 +1203,11 @@ class RouterCore {
1359
1203
  return matches;
1360
1204
  } catch (err) {
1361
1205
  if (redirect.isRedirect(err)) {
1362
- if (err.reloadDocument) {
1206
+ if (err.options.reloadDocument) {
1363
1207
  return void 0;
1364
1208
  }
1365
1209
  return await this.preloadRoute({
1366
- ...err,
1210
+ ...err.options,
1367
1211
  _fromLocation: next
1368
1212
  });
1369
1213
  }
@@ -1467,9 +1311,10 @@ class RouterCore {
1467
1311
  return this.routesById;
1468
1312
  }
1469
1313
  matchRoutesInternal(next, opts) {
1314
+ var _a;
1470
1315
  const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes(
1471
- next,
1472
- opts == null ? void 0 : opts.dest
1316
+ next.pathname,
1317
+ (_a = opts == null ? void 0 : opts.dest) == null ? void 0 : _a.to
1473
1318
  );
1474
1319
  let isGlobalNotFound = false;
1475
1320
  if (
@@ -1500,9 +1345,9 @@ class RouterCore {
1500
1345
  return root.rootRouteId;
1501
1346
  })();
1502
1347
  const parseErrors = matchedRoutes.map((route) => {
1503
- var _a;
1348
+ var _a2;
1504
1349
  let parsedParamsError;
1505
- const parseParams = ((_a = route.options.params) == null ? void 0 : _a.parse) ?? route.options.parseParams;
1350
+ const parseParams = ((_a2 = route.options.params) == null ? void 0 : _a2.parse) ?? route.options.parseParams;
1506
1351
  if (parseParams) {
1507
1352
  try {
1508
1353
  const parsedParams = parseParams(routeParams);
@@ -1526,7 +1371,7 @@ class RouterCore {
1526
1371
  return parentContext;
1527
1372
  };
1528
1373
  matchedRoutes.forEach((route, index) => {
1529
- var _a, _b;
1374
+ var _a2, _b;
1530
1375
  const parentMatch = matches[index - 1];
1531
1376
  const [preMatchSearch, strictMatchSearch, searchError] = (() => {
1532
1377
  const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? next.search;
@@ -1554,7 +1399,7 @@ class RouterCore {
1554
1399
  return [parentSearch, {}, searchParamError];
1555
1400
  }
1556
1401
  })();
1557
- const loaderDeps = ((_b = (_a = route.options).loaderDeps) == null ? void 0 : _b.call(_a, {
1402
+ const loaderDeps = ((_b = (_a2 = route.options).loaderDeps) == null ? void 0 : _b.call(_a2, {
1558
1403
  search: preMatchSearch
1559
1404
  })) ?? "";
1560
1405
  const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
@@ -1632,7 +1477,7 @@ class RouterCore {
1632
1477
  matches.push(match);
1633
1478
  });
1634
1479
  matches.forEach((match, index) => {
1635
- var _a, _b;
1480
+ var _a2, _b;
1636
1481
  const route = this.looseRoutesById[match.routeId];
1637
1482
  const existingMatch = this.getMatch(match.id);
1638
1483
  if (!existingMatch && (opts == null ? void 0 : opts._buildLocation) !== true) {
@@ -1650,7 +1495,7 @@ class RouterCore {
1650
1495
  preload: !!match.preload,
1651
1496
  matches
1652
1497
  };
1653
- match.__routeContext = ((_b = (_a = route.options).context) == null ? void 0 : _b.call(_a, contextFnContext)) ?? {};
1498
+ match.__routeContext = ((_b = (_a2 = route.options).context) == null ? void 0 : _b.call(_a2, contextFnContext)) ?? {};
1654
1499
  match.context = {
1655
1500
  ...parentContext,
1656
1501
  ...match.__routeContext,
@@ -1720,6 +1565,219 @@ function routeNeedsPreload(route) {
1720
1565
  }
1721
1566
  return false;
1722
1567
  }
1568
+ function processRouteTree({
1569
+ routeTree,
1570
+ initRoute
1571
+ }) {
1572
+ const routesById = {};
1573
+ const routesByPath = {};
1574
+ const recurseRoutes = (childRoutes) => {
1575
+ childRoutes.forEach((childRoute, i) => {
1576
+ initRoute == null ? void 0 : initRoute(childRoute, i);
1577
+ const existingRoute = routesById[childRoute.id];
1578
+ invariant(
1579
+ !existingRoute,
1580
+ `Duplicate routes found with id: ${String(childRoute.id)}`
1581
+ );
1582
+ routesById[childRoute.id] = childRoute;
1583
+ if (!childRoute.isRoot && childRoute.path) {
1584
+ const trimmedFullPath = path.trimPathRight(childRoute.fullPath);
1585
+ if (!routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith("/")) {
1586
+ routesByPath[trimmedFullPath] = childRoute;
1587
+ }
1588
+ }
1589
+ const children = childRoute.children;
1590
+ if (children == null ? void 0 : children.length) {
1591
+ recurseRoutes(children);
1592
+ }
1593
+ });
1594
+ };
1595
+ recurseRoutes([routeTree]);
1596
+ const scoredRoutes = [];
1597
+ const routes = Object.values(routesById);
1598
+ routes.forEach((d, i) => {
1599
+ var _a;
1600
+ if (d.isRoot || !d.path) {
1601
+ return;
1602
+ }
1603
+ const trimmed = path.trimPathLeft(d.fullPath);
1604
+ const parsed = path.parsePathname(trimmed);
1605
+ while (parsed.length > 1 && ((_a = parsed[0]) == null ? void 0 : _a.value) === "/") {
1606
+ parsed.shift();
1607
+ }
1608
+ const scores = parsed.map((segment) => {
1609
+ if (segment.value === "/") {
1610
+ return 0.75;
1611
+ }
1612
+ if (segment.type === "param" && segment.prefixSegment && segment.suffixSegment) {
1613
+ return 0.55;
1614
+ }
1615
+ if (segment.type === "param" && segment.prefixSegment) {
1616
+ return 0.52;
1617
+ }
1618
+ if (segment.type === "param" && segment.suffixSegment) {
1619
+ return 0.51;
1620
+ }
1621
+ if (segment.type === "param") {
1622
+ return 0.5;
1623
+ }
1624
+ if (segment.type === "wildcard" && segment.prefixSegment && segment.suffixSegment) {
1625
+ return 0.3;
1626
+ }
1627
+ if (segment.type === "wildcard" && segment.prefixSegment) {
1628
+ return 0.27;
1629
+ }
1630
+ if (segment.type === "wildcard" && segment.suffixSegment) {
1631
+ return 0.26;
1632
+ }
1633
+ if (segment.type === "wildcard") {
1634
+ return 0.25;
1635
+ }
1636
+ return 1;
1637
+ });
1638
+ scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores });
1639
+ });
1640
+ const flatRoutes = scoredRoutes.sort((a, b) => {
1641
+ const minLength = Math.min(a.scores.length, b.scores.length);
1642
+ for (let i = 0; i < minLength; i++) {
1643
+ if (a.scores[i] !== b.scores[i]) {
1644
+ return b.scores[i] - a.scores[i];
1645
+ }
1646
+ }
1647
+ if (a.scores.length !== b.scores.length) {
1648
+ return b.scores.length - a.scores.length;
1649
+ }
1650
+ for (let i = 0; i < minLength; i++) {
1651
+ if (a.parsed[i].value !== b.parsed[i].value) {
1652
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1653
+ }
1654
+ }
1655
+ return a.index - b.index;
1656
+ }).map((d, i) => {
1657
+ d.child.rank = i;
1658
+ return d.child;
1659
+ });
1660
+ return { routesById, routesByPath, flatRoutes };
1661
+ }
1662
+ function getMatchedRoutes({
1663
+ pathname,
1664
+ routePathname,
1665
+ basepath,
1666
+ caseSensitive,
1667
+ routesByPath,
1668
+ routesById,
1669
+ flatRoutes
1670
+ }) {
1671
+ let routeParams = {};
1672
+ const trimmedPath = path.trimPathRight(pathname);
1673
+ const getMatchedParams = (route) => {
1674
+ var _a;
1675
+ const result = path.matchPathname(basepath, trimmedPath, {
1676
+ to: route.fullPath,
1677
+ caseSensitive: ((_a = route.options) == null ? void 0 : _a.caseSensitive) ?? caseSensitive,
1678
+ fuzzy: true
1679
+ });
1680
+ return result;
1681
+ };
1682
+ let foundRoute = routePathname !== void 0 ? routesByPath[routePathname] : void 0;
1683
+ if (foundRoute) {
1684
+ routeParams = getMatchedParams(foundRoute);
1685
+ } else {
1686
+ foundRoute = flatRoutes.find((route) => {
1687
+ const matchedParams = getMatchedParams(route);
1688
+ if (matchedParams) {
1689
+ routeParams = matchedParams;
1690
+ return true;
1691
+ }
1692
+ return false;
1693
+ });
1694
+ }
1695
+ let routeCursor = foundRoute || routesById[root.rootRouteId];
1696
+ const matchedRoutes = [routeCursor];
1697
+ while (routeCursor.parentRoute) {
1698
+ routeCursor = routeCursor.parentRoute;
1699
+ matchedRoutes.unshift(routeCursor);
1700
+ }
1701
+ return { matchedRoutes, routeParams, foundRoute };
1702
+ }
1703
+ function applySearchMiddleware({
1704
+ search,
1705
+ dest,
1706
+ destRoutes,
1707
+ _includeValidateSearch
1708
+ }) {
1709
+ const allMiddlewares = destRoutes.reduce(
1710
+ (acc, route) => {
1711
+ var _a;
1712
+ const middlewares = [];
1713
+ if ("search" in route.options) {
1714
+ if ((_a = route.options.search) == null ? void 0 : _a.middlewares) {
1715
+ middlewares.push(...route.options.search.middlewares);
1716
+ }
1717
+ } else if (route.options.preSearchFilters || route.options.postSearchFilters) {
1718
+ const legacyMiddleware = ({
1719
+ search: search2,
1720
+ next
1721
+ }) => {
1722
+ let nextSearch = search2;
1723
+ if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
1724
+ nextSearch = route.options.preSearchFilters.reduce(
1725
+ (prev, next2) => next2(prev),
1726
+ search2
1727
+ );
1728
+ }
1729
+ const result = next(nextSearch);
1730
+ if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
1731
+ return route.options.postSearchFilters.reduce(
1732
+ (prev, next2) => next2(prev),
1733
+ result
1734
+ );
1735
+ }
1736
+ return result;
1737
+ };
1738
+ middlewares.push(legacyMiddleware);
1739
+ }
1740
+ if (_includeValidateSearch && route.options.validateSearch) {
1741
+ const validate = ({ search: search2, next }) => {
1742
+ const result = next(search2);
1743
+ try {
1744
+ const validatedSearch = {
1745
+ ...result,
1746
+ ...validateSearch(route.options.validateSearch, result) ?? {}
1747
+ };
1748
+ return validatedSearch;
1749
+ } catch {
1750
+ return result;
1751
+ }
1752
+ };
1753
+ middlewares.push(validate);
1754
+ }
1755
+ return acc.concat(middlewares);
1756
+ },
1757
+ []
1758
+ ) ?? [];
1759
+ const final = ({ search: search2 }) => {
1760
+ if (!dest.search) {
1761
+ return {};
1762
+ }
1763
+ if (dest.search === true) {
1764
+ return search2;
1765
+ }
1766
+ return utils.functionalUpdate(dest.search, search2);
1767
+ };
1768
+ allMiddlewares.push(final);
1769
+ const applyNext = (index, currentSearch) => {
1770
+ if (index >= allMiddlewares.length) {
1771
+ return currentSearch;
1772
+ }
1773
+ const middleware = allMiddlewares[index];
1774
+ const next = (newSearch) => {
1775
+ return applyNext(index + 1, newSearch);
1776
+ };
1777
+ return middleware({ search: currentSearch, next });
1778
+ };
1779
+ return applyNext(0, search);
1780
+ }
1723
1781
  exports.PathParamError = PathParamError;
1724
1782
  exports.RouterCore = RouterCore;
1725
1783
  exports.SearchParamError = SearchParamError;
@@ -1727,5 +1785,7 @@ exports.componentTypes = componentTypes;
1727
1785
  exports.defaultSerializeError = defaultSerializeError;
1728
1786
  exports.getInitialRouterState = getInitialRouterState;
1729
1787
  exports.getLocationChangeInfo = getLocationChangeInfo;
1788
+ exports.getMatchedRoutes = getMatchedRoutes;
1730
1789
  exports.lazyFn = lazyFn;
1790
+ exports.processRouteTree = processRouteTree;
1731
1791
  //# sourceMappingURL=router.cjs.map