@tanstack/router-core 1.132.0-alpha.0 → 1.132.0-alpha.12

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 (128) hide show
  1. package/dist/cjs/Matches.cjs.map +1 -1
  2. package/dist/cjs/Matches.d.cts +9 -11
  3. package/dist/cjs/config.cjs +10 -0
  4. package/dist/cjs/config.cjs.map +1 -0
  5. package/dist/cjs/config.d.cts +17 -0
  6. package/dist/cjs/fileRoute.d.cts +3 -2
  7. package/dist/cjs/index.cjs +10 -2
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/index.d.cts +8 -3
  10. package/dist/cjs/load-matches.cjs +636 -0
  11. package/dist/cjs/load-matches.cjs.map +1 -0
  12. package/dist/cjs/load-matches.d.cts +16 -0
  13. package/dist/cjs/qss.cjs +19 -19
  14. package/dist/cjs/qss.cjs.map +1 -1
  15. package/dist/cjs/qss.d.cts +6 -4
  16. package/dist/cjs/redirect.cjs +3 -3
  17. package/dist/cjs/redirect.cjs.map +1 -1
  18. package/dist/cjs/route.cjs.map +1 -1
  19. package/dist/cjs/route.d.cts +42 -41
  20. package/dist/cjs/router.cjs +85 -654
  21. package/dist/cjs/router.cjs.map +1 -1
  22. package/dist/cjs/router.d.cts +19 -23
  23. package/dist/cjs/scroll-restoration.cjs +32 -29
  24. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  25. package/dist/cjs/scroll-restoration.d.cts +1 -10
  26. package/dist/cjs/searchParams.cjs +7 -15
  27. package/dist/cjs/searchParams.cjs.map +1 -1
  28. package/dist/cjs/ssr/constants.cjs +5 -0
  29. package/dist/cjs/ssr/constants.cjs.map +1 -0
  30. package/dist/cjs/ssr/constants.d.cts +1 -0
  31. package/dist/cjs/ssr/{seroval-plugins.cjs → serializer/ShallowErrorPlugin.cjs} +2 -2
  32. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -0
  33. package/dist/cjs/ssr/{seroval-plugins.d.cts → serializer/ShallowErrorPlugin.d.cts} +1 -2
  34. package/dist/cjs/ssr/serializer/seroval-plugins.cjs +11 -0
  35. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -0
  36. package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -0
  37. package/dist/cjs/ssr/serializer/transformer.cjs +52 -0
  38. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -0
  39. package/dist/cjs/ssr/serializer/transformer.d.cts +56 -0
  40. package/dist/cjs/ssr/server.d.cts +5 -0
  41. package/dist/cjs/ssr/ssr-client.cjs +53 -40
  42. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  43. package/dist/cjs/ssr/ssr-client.d.cts +5 -1
  44. package/dist/cjs/ssr/ssr-server.cjs +12 -10
  45. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  46. package/dist/cjs/ssr/ssr-server.d.cts +0 -1
  47. package/dist/cjs/ssr/tsrScript.cjs +1 -1
  48. package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
  49. package/dist/cjs/typePrimitives.d.cts +6 -6
  50. package/dist/cjs/utils.cjs +14 -7
  51. package/dist/cjs/utils.cjs.map +1 -1
  52. package/dist/cjs/utils.d.cts +2 -1
  53. package/dist/esm/Matches.d.ts +9 -11
  54. package/dist/esm/Matches.js.map +1 -1
  55. package/dist/esm/config.d.ts +17 -0
  56. package/dist/esm/config.js +10 -0
  57. package/dist/esm/config.js.map +1 -0
  58. package/dist/esm/fileRoute.d.ts +3 -2
  59. package/dist/esm/index.d.ts +8 -3
  60. package/dist/esm/index.js +11 -3
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/load-matches.d.ts +16 -0
  63. package/dist/esm/load-matches.js +636 -0
  64. package/dist/esm/load-matches.js.map +1 -0
  65. package/dist/esm/qss.d.ts +6 -4
  66. package/dist/esm/qss.js +19 -19
  67. package/dist/esm/qss.js.map +1 -1
  68. package/dist/esm/redirect.js +3 -3
  69. package/dist/esm/redirect.js.map +1 -1
  70. package/dist/esm/route.d.ts +42 -41
  71. package/dist/esm/route.js.map +1 -1
  72. package/dist/esm/router.d.ts +19 -23
  73. package/dist/esm/router.js +85 -654
  74. package/dist/esm/router.js.map +1 -1
  75. package/dist/esm/scroll-restoration.d.ts +1 -10
  76. package/dist/esm/scroll-restoration.js +32 -29
  77. package/dist/esm/scroll-restoration.js.map +1 -1
  78. package/dist/esm/searchParams.js +7 -15
  79. package/dist/esm/searchParams.js.map +1 -1
  80. package/dist/esm/ssr/constants.d.ts +1 -0
  81. package/dist/esm/ssr/constants.js +5 -0
  82. package/dist/esm/ssr/constants.js.map +1 -0
  83. package/dist/esm/ssr/{seroval-plugins.d.ts → serializer/ShallowErrorPlugin.d.ts} +1 -2
  84. package/dist/esm/ssr/{seroval-plugins.js → serializer/ShallowErrorPlugin.js} +2 -2
  85. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -0
  86. package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -0
  87. package/dist/esm/ssr/serializer/seroval-plugins.js +11 -0
  88. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -0
  89. package/dist/esm/ssr/serializer/transformer.d.ts +56 -0
  90. package/dist/esm/ssr/serializer/transformer.js +52 -0
  91. package/dist/esm/ssr/serializer/transformer.js.map +1 -0
  92. package/dist/esm/ssr/server.d.ts +5 -0
  93. package/dist/esm/ssr/ssr-client.d.ts +5 -1
  94. package/dist/esm/ssr/ssr-client.js +53 -40
  95. package/dist/esm/ssr/ssr-client.js.map +1 -1
  96. package/dist/esm/ssr/ssr-server.d.ts +0 -1
  97. package/dist/esm/ssr/ssr-server.js +12 -10
  98. package/dist/esm/ssr/ssr-server.js.map +1 -1
  99. package/dist/esm/ssr/tsrScript.js +1 -1
  100. package/dist/esm/ssr/tsrScript.js.map +1 -1
  101. package/dist/esm/typePrimitives.d.ts +6 -6
  102. package/dist/esm/utils.d.ts +2 -1
  103. package/dist/esm/utils.js +14 -7
  104. package/dist/esm/utils.js.map +1 -1
  105. package/package.json +2 -2
  106. package/src/Matches.ts +18 -10
  107. package/src/config.ts +42 -0
  108. package/src/fileRoute.ts +15 -3
  109. package/src/index.ts +24 -2
  110. package/src/load-matches.ts +955 -0
  111. package/src/qss.ts +27 -24
  112. package/src/redirect.ts +3 -3
  113. package/src/route.ts +146 -35
  114. package/src/router.ts +135 -925
  115. package/src/scroll-restoration.ts +42 -37
  116. package/src/searchParams.ts +8 -19
  117. package/src/ssr/constants.ts +1 -0
  118. package/src/ssr/{seroval-plugins.ts → serializer/ShallowErrorPlugin.ts} +2 -2
  119. package/src/ssr/serializer/seroval-plugins.ts +9 -0
  120. package/src/ssr/serializer/transformer.ts +215 -0
  121. package/src/ssr/server.ts +6 -0
  122. package/src/ssr/ssr-client.ts +72 -44
  123. package/src/ssr/ssr-server.ts +18 -10
  124. package/src/ssr/tsrScript.ts +5 -1
  125. package/src/typePrimitives.ts +6 -6
  126. package/src/utils.ts +21 -10
  127. package/dist/cjs/ssr/seroval-plugins.cjs.map +0 -1
  128. package/dist/esm/ssr/seroval-plugins.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { Store, batch } from "@tanstack/store";
2
2
  import { createMemoryHistory, createBrowserHistory, parseHref } from "@tanstack/history";
3
3
  import invariant from "tiny-invariant";
4
- import { pick, createControlledPromise, deepEqual, replaceEqualDeep, last, functionalUpdate } from "./utils.js";
4
+ import { createControlledPromise, deepEqual, replaceEqualDeep, last, findLast, functionalUpdate } from "./utils.js";
5
5
  import { trimPath, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths, trimPathLeft, parsePathname, SEGMENT_TYPE_PARAM, SEGMENT_TYPE_OPTIONAL_PARAM, SEGMENT_TYPE_WILDCARD, SEGMENT_TYPE_PATHNAME } from "./path.js";
6
6
  import { isNotFound } from "./not-found.js";
7
7
  import { setupScrollRestoration } from "./scroll-restoration.js";
@@ -9,6 +9,7 @@ import { defaultParseSearch, defaultStringifySearch } from "./searchParams.js";
9
9
  import { rootRouteId } from "./root.js";
10
10
  import { redirect, isRedirect } from "./redirect.js";
11
11
  import { createLRUCache } from "./lru-cache.js";
12
+ import { loadMatches, loadRouteChunk, routeNeedsPreload } from "./load-matches.js";
12
13
  function defaultSerializeError(err) {
13
14
  if (err instanceof Error) {
14
15
  const obj = {
@@ -76,7 +77,7 @@ class RouterCore {
76
77
  this.history = this.options.history ?? (this.isServer ? createMemoryHistory({
77
78
  initialEntries: [this.basepath || "/"]
78
79
  }) : createBrowserHistory());
79
- this.latestLocation = this.parseLocation();
80
+ this.updateLatestLocation();
80
81
  }
81
82
  if (this.options.routeTree !== this.routeTree) {
82
83
  this.routeTree = this.options.routeTree;
@@ -101,6 +102,12 @@ class RouterCore {
101
102
  );
102
103
  }
103
104
  };
105
+ this.updateLatestLocation = () => {
106
+ this.latestLocation = this.parseLocation(
107
+ this.history.location,
108
+ this.latestLocation
109
+ );
110
+ };
104
111
  this.buildRouteTree = () => {
105
112
  const { routesById, routesByPath, flatRoutes } = processRouteTree({
106
113
  routeTree: this.routeTree,
@@ -138,7 +145,7 @@ class RouterCore {
138
145
  }
139
146
  });
140
147
  };
141
- this.parseLocation = (previousLocation, locationToParse) => {
148
+ this.parseLocation = (locationToParse, previousLocation) => {
142
149
  const parse = ({
143
150
  pathname,
144
151
  search,
@@ -156,7 +163,7 @@ class RouterCore {
156
163
  state: replaceEqualDeep(previousLocation?.state, state)
157
164
  };
158
165
  };
159
- const location = parse(locationToParse ?? this.history.location);
166
+ const location = parse(locationToParse);
160
167
  const { __tempLocation, __tempKey } = location.state;
161
168
  if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
162
169
  const parsedTempLocation = parse(__tempLocation);
@@ -210,13 +217,8 @@ class RouterCore {
210
217
  const match = this.getMatch(id);
211
218
  if (!match) return;
212
219
  match.abortController.abort();
213
- this.updateMatch(id, (prev) => {
214
- clearTimeout(prev.pendingTimeout);
215
- return {
216
- ...prev,
217
- pendingTimeout: void 0
218
- };
219
- });
220
+ clearTimeout(match._nonReactive.pendingTimeout);
221
+ match._nonReactive.pendingTimeout = void 0;
220
222
  };
221
223
  this.cancelMatches = () => {
222
224
  this.state.pendingMatches?.forEach((match) => {
@@ -230,60 +232,51 @@ class RouterCore {
230
232
  _buildLocation: true
231
233
  });
232
234
  const lastMatch = last(allCurrentLocationMatches);
233
- let fromPath = lastMatch.fullPath;
234
- const toPath = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
235
- const routeIsChanging = !!dest.to && !comparePaths(dest.to.toString(), fromPath) && !comparePaths(toPath, fromPath);
236
- if (dest.unsafeRelative === "path") {
237
- fromPath = currentLocation.pathname;
238
- } else if (routeIsChanging && dest.from) {
239
- fromPath = dest.from;
240
- if (process.env.NODE_ENV !== "production" && dest._isNavigate) {
241
- const allFromMatches = this.getMatchedRoutes(
242
- dest.from,
243
- void 0
244
- ).matchedRoutes;
245
- const matchedFrom = [...allCurrentLocationMatches].reverse().find((d) => {
246
- return comparePaths(d.fullPath, fromPath);
247
- });
248
- const matchedCurrent = [...allFromMatches].reverse().find((d) => {
249
- return comparePaths(d.fullPath, currentLocation.pathname);
250
- });
251
- if (!matchedFrom && !matchedCurrent) {
252
- console.warn(`Could not find match for from: ${fromPath}`);
253
- }
235
+ if (dest.from && process.env.NODE_ENV !== "production" && dest._isNavigate) {
236
+ const allFromMatches = this.getMatchedRoutes(
237
+ dest.from,
238
+ void 0
239
+ ).matchedRoutes;
240
+ const matchedFrom = findLast(allCurrentLocationMatches, (d) => {
241
+ return comparePaths(d.fullPath, dest.from);
242
+ });
243
+ const matchedCurrent = findLast(allFromMatches, (d) => {
244
+ return comparePaths(d.fullPath, lastMatch.fullPath);
245
+ });
246
+ if (!matchedFrom && !matchedCurrent) {
247
+ console.warn(`Could not find match for from: ${dest.from}`);
254
248
  }
255
249
  }
250
+ const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lastMatch.fullPath;
251
+ const fromPath = this.resolvePathWithBase(defaultedFromPath, ".");
256
252
  const fromSearch = lastMatch.search;
257
253
  const fromParams = { ...lastMatch.params };
258
254
  const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
259
- let nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : {
260
- ...fromParams,
261
- ...functionalUpdate(dest.params, fromParams)
262
- };
255
+ const nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : Object.assign(
256
+ fromParams,
257
+ functionalUpdate(dest.params, fromParams)
258
+ );
263
259
  const interpolatedNextTo = interpolatePath({
264
260
  path: nextTo,
265
- params: nextParams ?? {},
261
+ params: nextParams,
266
262
  parseCache: this.parsePathnameCache
267
263
  }).interpolatedPath;
268
- const destRoutes = this.matchRoutes(
269
- interpolatedNextTo,
270
- {},
271
- {
272
- _buildLocation: true
273
- }
274
- ).map((d) => this.looseRoutesById[d.routeId]);
264
+ const destRoutes = this.matchRoutes(interpolatedNextTo, void 0, {
265
+ _buildLocation: true
266
+ }).map((d) => this.looseRoutesById[d.routeId]);
275
267
  if (Object.keys(nextParams).length > 0) {
276
- destRoutes.map((route) => {
277
- return route.options.params?.stringify ?? route.options.stringifyParams;
278
- }).filter(Boolean).forEach((fn) => {
279
- nextParams = { ...nextParams, ...fn(nextParams) };
280
- });
268
+ for (const route of destRoutes) {
269
+ const fn = route.options.params?.stringify ?? route.options.stringifyParams;
270
+ if (fn) {
271
+ Object.assign(nextParams, fn(nextParams));
272
+ }
273
+ }
281
274
  }
282
275
  const nextPathname = interpolatePath({
283
276
  // Use the original template path for interpolation
284
277
  // This preserves the original parameter syntax including optional parameters
285
278
  path: nextTo,
286
- params: nextParams ?? {},
279
+ params: nextParams,
287
280
  leaveWildcards: false,
288
281
  leaveParams: opts.leaveParams,
289
282
  decodeCharMap: this.pathParamsDecodeCharMap,
@@ -291,19 +284,19 @@ class RouterCore {
291
284
  }).interpolatedPath;
292
285
  let nextSearch = fromSearch;
293
286
  if (opts._includeValidateSearch && this.options.search?.strict) {
294
- let validatedSearch = {};
287
+ const validatedSearch = {};
295
288
  destRoutes.forEach((route) => {
296
- try {
297
- if (route.options.validateSearch) {
298
- validatedSearch = {
299
- ...validatedSearch,
300
- ...validateSearch(route.options.validateSearch, {
289
+ if (route.options.validateSearch) {
290
+ try {
291
+ Object.assign(
292
+ validatedSearch,
293
+ validateSearch(route.options.validateSearch, {
301
294
  ...validatedSearch,
302
295
  ...nextSearch
303
- }) ?? {}
304
- };
296
+ })
297
+ );
298
+ } catch {
305
299
  }
306
- } catch {
307
300
  }
308
301
  });
309
302
  nextSearch = validatedSearch;
@@ -355,7 +348,7 @@ class RouterCore {
355
348
  if (foundMask) {
356
349
  const { from: _from, ...maskProps } = foundMask;
357
350
  maskedDest = {
358
- ...pick(opts, ["from"]),
351
+ from: opts.from,
359
352
  ...maskProps,
360
353
  params
361
354
  };
@@ -370,7 +363,7 @@ class RouterCore {
370
363
  };
371
364
  if (opts.mask) {
372
365
  return buildWithMatches(opts, {
373
- ...pick(opts, ["from"]),
366
+ from: opts.from,
374
367
  ...opts.mask
375
368
  });
376
369
  }
@@ -505,7 +498,7 @@ class RouterCore {
505
498
  };
506
499
  this.beforeLoad = () => {
507
500
  this.cancelMatches();
508
- this.latestLocation = this.parseLocation(this.latestLocation);
501
+ this.updateLatestLocation();
509
502
  if (this.isServer) {
510
503
  const nextLocation = this.buildLocation({
511
504
  to: this.latestLocation.pathname,
@@ -566,10 +559,12 @@ class RouterCore {
566
559
  location: next
567
560
  })
568
561
  });
569
- await this.loadMatches({
562
+ await loadMatches({
563
+ router: this,
570
564
  sync: opts?.sync,
571
565
  matches: this.state.pendingMatches,
572
566
  location: next,
567
+ updateMatch: this.updateMatch,
573
568
  // eslint-disable-next-line @typescript-eslint/require-await
574
569
  onReady: async () => {
575
570
  this.startViewTransition(async () => {
@@ -693,510 +688,13 @@ class RouterCore {
693
688
  const findFn = (d) => d.id === matchId;
694
689
  return this.state.cachedMatches.find(findFn) ?? this.state.pendingMatches?.find(findFn) ?? this.state.matches.find(findFn);
695
690
  };
696
- this.loadMatches = async ({
697
- location,
698
- matches,
699
- preload: allPreload,
700
- onReady,
701
- updateMatch = this.updateMatch,
702
- sync
703
- }) => {
704
- let firstBadMatchIndex;
705
- let rendered = false;
706
- const triggerOnReady = async () => {
707
- if (!rendered) {
708
- rendered = true;
709
- await onReady?.();
710
- }
711
- };
712
- const resolvePreload = (matchId) => {
713
- return !!(allPreload && !this.state.matches.some((d) => d.id === matchId));
714
- };
715
- if (!this.isServer && this.state.matches.some((d) => d._forcePending)) {
716
- triggerOnReady();
717
- }
718
- const handleRedirectAndNotFound = (match, err) => {
719
- if (isRedirect(err) || isNotFound(err)) {
720
- if (isRedirect(err)) {
721
- if (err.redirectHandled) {
722
- if (!err.options.reloadDocument) {
723
- throw err;
724
- }
725
- }
726
- }
727
- match.beforeLoadPromise?.resolve();
728
- match.loaderPromise?.resolve();
729
- updateMatch(match.id, (prev) => ({
730
- ...prev,
731
- status: isRedirect(err) ? "redirected" : isNotFound(err) ? "notFound" : "error",
732
- isFetching: false,
733
- error: err,
734
- beforeLoadPromise: void 0,
735
- loaderPromise: void 0
736
- }));
737
- if (!err.routeId) {
738
- err.routeId = match.routeId;
739
- }
740
- match.loadPromise?.resolve();
741
- if (isRedirect(err)) {
742
- rendered = true;
743
- err.options._fromLocation = location;
744
- err.redirectHandled = true;
745
- err = this.resolveRedirect(err);
746
- throw err;
747
- } else if (isNotFound(err)) {
748
- this._handleNotFound(matches, err, {
749
- updateMatch
750
- });
751
- throw err;
752
- }
753
- }
754
- };
755
- const shouldSkipLoader = (matchId) => {
756
- const match = this.getMatch(matchId);
757
- if (!this.isServer && match._dehydrated) {
758
- return true;
759
- }
760
- if (this.isServer) {
761
- if (match.ssr === false) {
762
- return true;
763
- }
764
- }
765
- return false;
766
- };
767
- try {
768
- await new Promise((resolveAll, rejectAll) => {
769
- ;
770
- (async () => {
771
- try {
772
- const handleSerialError = (index, err, routerCode) => {
773
- const { id: matchId, routeId } = matches[index];
774
- const route = this.looseRoutesById[routeId];
775
- if (err instanceof Promise) {
776
- throw err;
777
- }
778
- err.routerCode = routerCode;
779
- firstBadMatchIndex = firstBadMatchIndex ?? index;
780
- handleRedirectAndNotFound(this.getMatch(matchId), err);
781
- try {
782
- route.options.onError?.(err);
783
- } catch (errorHandlerErr) {
784
- err = errorHandlerErr;
785
- handleRedirectAndNotFound(this.getMatch(matchId), err);
786
- }
787
- updateMatch(matchId, (prev) => {
788
- prev.beforeLoadPromise?.resolve();
789
- prev.loadPromise?.resolve();
790
- return {
791
- ...prev,
792
- error: err,
793
- status: "error",
794
- isFetching: false,
795
- updatedAt: Date.now(),
796
- abortController: new AbortController(),
797
- beforeLoadPromise: void 0
798
- };
799
- });
800
- };
801
- for (const [index, { id: matchId, routeId }] of matches.entries()) {
802
- const existingMatch = this.getMatch(matchId);
803
- const parentMatchId = matches[index - 1]?.id;
804
- const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
805
- const route = this.looseRoutesById[routeId];
806
- const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
807
- if (this.isServer) {
808
- let ssr;
809
- if (this.isShell()) {
810
- ssr = matchId === rootRouteId;
811
- } else {
812
- const defaultSsr = this.options.defaultSsr ?? true;
813
- if (parentMatch?.ssr === false) {
814
- ssr = false;
815
- } else {
816
- let tempSsr;
817
- if (route.options.ssr === void 0) {
818
- tempSsr = defaultSsr;
819
- } else if (typeof route.options.ssr === "function") {
820
- let makeMaybe = function(value, error) {
821
- if (error) {
822
- return { status: "error", error };
823
- }
824
- return { status: "success", value };
825
- };
826
- const { search, params } = this.getMatch(matchId);
827
- const ssrFnContext = {
828
- search: makeMaybe(search, existingMatch.searchError),
829
- params: makeMaybe(params, existingMatch.paramsError),
830
- location,
831
- matches: matches.map((match) => ({
832
- index: match.index,
833
- pathname: match.pathname,
834
- fullPath: match.fullPath,
835
- staticData: match.staticData,
836
- id: match.id,
837
- routeId: match.routeId,
838
- search: makeMaybe(match.search, match.searchError),
839
- params: makeMaybe(match.params, match.paramsError),
840
- ssr: match.ssr
841
- }))
842
- };
843
- tempSsr = await route.options.ssr(ssrFnContext) ?? defaultSsr;
844
- } else {
845
- tempSsr = route.options.ssr;
846
- }
847
- if (tempSsr === true && parentMatch?.ssr === "data-only") {
848
- ssr = "data-only";
849
- } else {
850
- ssr = tempSsr;
851
- }
852
- }
853
- }
854
- updateMatch(matchId, (prev) => ({
855
- ...prev,
856
- ssr
857
- }));
858
- }
859
- if (shouldSkipLoader(matchId)) {
860
- continue;
861
- }
862
- const shouldPending = !!(onReady && !this.isServer && !resolvePreload(matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? this.options?.defaultPendingComponent));
863
- let executeBeforeLoad = true;
864
- const setupPendingTimeout = () => {
865
- if (shouldPending && this.getMatch(matchId).pendingTimeout === void 0) {
866
- const pendingTimeout = setTimeout(() => {
867
- try {
868
- triggerOnReady();
869
- } catch {
870
- }
871
- }, pendingMs);
872
- updateMatch(matchId, (prev) => ({
873
- ...prev,
874
- pendingTimeout
875
- }));
876
- }
877
- };
878
- if (
879
- // If we are in the middle of a load, either of these will be present
880
- // (not to be confused with `loadPromise`, which is always defined)
881
- existingMatch.beforeLoadPromise || existingMatch.loaderPromise
882
- ) {
883
- setupPendingTimeout();
884
- await existingMatch.beforeLoadPromise;
885
- const match = this.getMatch(matchId);
886
- if (match.status === "error") {
887
- executeBeforeLoad = true;
888
- } else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
889
- handleRedirectAndNotFound(match, match.error);
890
- }
891
- }
892
- if (executeBeforeLoad) {
893
- try {
894
- updateMatch(matchId, (prev) => {
895
- const prevLoadPromise = prev.loadPromise;
896
- return {
897
- ...prev,
898
- loadPromise: createControlledPromise(() => {
899
- prevLoadPromise?.resolve();
900
- }),
901
- beforeLoadPromise: createControlledPromise()
902
- };
903
- });
904
- const { paramsError, searchError } = this.getMatch(matchId);
905
- if (paramsError) {
906
- handleSerialError(index, paramsError, "PARSE_PARAMS");
907
- }
908
- if (searchError) {
909
- handleSerialError(index, searchError, "VALIDATE_SEARCH");
910
- }
911
- setupPendingTimeout();
912
- const abortController = new AbortController();
913
- const parentMatchContext = parentMatch?.context ?? this.options.context ?? {};
914
- updateMatch(matchId, (prev) => ({
915
- ...prev,
916
- isFetching: "beforeLoad",
917
- fetchCount: prev.fetchCount + 1,
918
- abortController,
919
- context: {
920
- ...parentMatchContext,
921
- ...prev.__routeContext
922
- }
923
- }));
924
- const { search, params, context, cause } = this.getMatch(matchId);
925
- const preload = resolvePreload(matchId);
926
- const beforeLoadFnContext = {
927
- search,
928
- abortController,
929
- params,
930
- preload,
931
- context,
932
- location,
933
- navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
934
- buildLocation: this.buildLocation,
935
- cause: preload ? "preload" : cause,
936
- matches
937
- };
938
- const beforeLoadContext = await route.options.beforeLoad?.(beforeLoadFnContext);
939
- if (isRedirect(beforeLoadContext) || isNotFound(beforeLoadContext)) {
940
- handleSerialError(index, beforeLoadContext, "BEFORE_LOAD");
941
- }
942
- updateMatch(matchId, (prev) => {
943
- return {
944
- ...prev,
945
- __beforeLoadContext: beforeLoadContext,
946
- context: {
947
- ...parentMatchContext,
948
- ...prev.__routeContext,
949
- ...beforeLoadContext
950
- },
951
- abortController
952
- };
953
- });
954
- } catch (err) {
955
- handleSerialError(index, err, "BEFORE_LOAD");
956
- }
957
- updateMatch(matchId, (prev) => {
958
- prev.beforeLoadPromise?.resolve();
959
- return {
960
- ...prev,
961
- beforeLoadPromise: void 0,
962
- isFetching: false
963
- };
964
- });
965
- }
966
- }
967
- const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
968
- const matchPromises = [];
969
- validResolvedMatches.forEach(({ id: matchId, routeId }, index) => {
970
- matchPromises.push(
971
- (async () => {
972
- let loaderShouldRunAsync = false;
973
- let loaderIsRunningAsync = false;
974
- const route = this.looseRoutesById[routeId];
975
- const executeHead = async () => {
976
- const match = this.getMatch(matchId);
977
- if (!match) {
978
- return;
979
- }
980
- const assetContext = {
981
- matches,
982
- match,
983
- params: match.params,
984
- loaderData: match.loaderData
985
- };
986
- const headFnContent = await route.options.head?.(assetContext);
987
- const meta = headFnContent?.meta;
988
- const links = headFnContent?.links;
989
- const headScripts = headFnContent?.scripts;
990
- const styles = headFnContent?.styles;
991
- const scripts = await route.options.scripts?.(assetContext);
992
- const headers = await route.options.headers?.(assetContext);
993
- return {
994
- meta,
995
- links,
996
- headScripts,
997
- headers,
998
- scripts,
999
- styles
1000
- };
1001
- };
1002
- const potentialPendingMinPromise = async () => {
1003
- const latestMatch = this.getMatch(matchId);
1004
- if (latestMatch.minPendingPromise) {
1005
- await latestMatch.minPendingPromise;
1006
- }
1007
- };
1008
- const prevMatch = this.getMatch(matchId);
1009
- if (shouldSkipLoader(matchId)) {
1010
- if (this.isServer) {
1011
- const head = await executeHead();
1012
- updateMatch(matchId, (prev) => ({
1013
- ...prev,
1014
- ...head
1015
- }));
1016
- return this.getMatch(matchId);
1017
- }
1018
- } else if (prevMatch.loaderPromise) {
1019
- if (prevMatch.status === "success" && !sync && !prevMatch.preload) {
1020
- return this.getMatch(matchId);
1021
- }
1022
- await prevMatch.loaderPromise;
1023
- const match = this.getMatch(matchId);
1024
- if (match.error) {
1025
- handleRedirectAndNotFound(match, match.error);
1026
- }
1027
- } else {
1028
- const parentMatchPromise = matchPromises[index - 1];
1029
- const getLoaderContext = () => {
1030
- const {
1031
- params,
1032
- loaderDeps,
1033
- abortController,
1034
- context,
1035
- cause
1036
- } = this.getMatch(matchId);
1037
- const preload2 = resolvePreload(matchId);
1038
- return {
1039
- params,
1040
- deps: loaderDeps,
1041
- preload: !!preload2,
1042
- parentMatchPromise,
1043
- abortController,
1044
- context,
1045
- location,
1046
- navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
1047
- cause: preload2 ? "preload" : cause,
1048
- route
1049
- };
1050
- };
1051
- const age = Date.now() - this.getMatch(matchId).updatedAt;
1052
- const preload = resolvePreload(matchId);
1053
- const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
1054
- const shouldReloadOption = route.options.shouldReload;
1055
- const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(getLoaderContext()) : shouldReloadOption;
1056
- updateMatch(matchId, (prev) => ({
1057
- ...prev,
1058
- loaderPromise: createControlledPromise(),
1059
- preload: !!preload && !this.state.matches.some((d) => d.id === matchId)
1060
- }));
1061
- const runLoader = async () => {
1062
- try {
1063
- try {
1064
- if (!this.isServer || this.isServer && this.getMatch(matchId).ssr === true) {
1065
- this.loadRouteChunk(route);
1066
- }
1067
- updateMatch(matchId, (prev) => ({
1068
- ...prev,
1069
- isFetching: "loader"
1070
- }));
1071
- const loaderData = await route.options.loader?.(getLoaderContext());
1072
- handleRedirectAndNotFound(
1073
- this.getMatch(matchId),
1074
- loaderData
1075
- );
1076
- updateMatch(matchId, (prev) => ({
1077
- ...prev,
1078
- loaderData
1079
- }));
1080
- await route._lazyPromise;
1081
- const head = await executeHead();
1082
- await potentialPendingMinPromise();
1083
- await route._componentsPromise;
1084
- updateMatch(matchId, (prev) => ({
1085
- ...prev,
1086
- error: void 0,
1087
- status: "success",
1088
- isFetching: false,
1089
- updatedAt: Date.now(),
1090
- ...head
1091
- }));
1092
- } catch (e) {
1093
- let error = e;
1094
- await potentialPendingMinPromise();
1095
- handleRedirectAndNotFound(this.getMatch(matchId), e);
1096
- try {
1097
- route.options.onError?.(e);
1098
- } catch (onErrorError) {
1099
- error = onErrorError;
1100
- handleRedirectAndNotFound(
1101
- this.getMatch(matchId),
1102
- onErrorError
1103
- );
1104
- }
1105
- const head = await executeHead();
1106
- updateMatch(matchId, (prev) => ({
1107
- ...prev,
1108
- error,
1109
- status: "error",
1110
- isFetching: false,
1111
- ...head
1112
- }));
1113
- }
1114
- } catch (err) {
1115
- const head = await executeHead();
1116
- updateMatch(matchId, (prev) => ({
1117
- ...prev,
1118
- loaderPromise: void 0,
1119
- ...head
1120
- }));
1121
- handleRedirectAndNotFound(this.getMatch(matchId), err);
1122
- }
1123
- };
1124
- const { status, invalid } = this.getMatch(matchId);
1125
- loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
1126
- if (preload && route.options.preload === false) {
1127
- } else if (loaderShouldRunAsync && !sync) {
1128
- loaderIsRunningAsync = true;
1129
- (async () => {
1130
- try {
1131
- await runLoader();
1132
- const { loaderPromise, loadPromise } = this.getMatch(matchId);
1133
- loaderPromise?.resolve();
1134
- loadPromise?.resolve();
1135
- updateMatch(matchId, (prev) => ({
1136
- ...prev,
1137
- loaderPromise: void 0
1138
- }));
1139
- } catch (err) {
1140
- if (isRedirect(err)) {
1141
- await this.navigate(err.options);
1142
- }
1143
- }
1144
- })();
1145
- } else if (status !== "success" || loaderShouldRunAsync && sync) {
1146
- await runLoader();
1147
- } else {
1148
- const head = await executeHead();
1149
- updateMatch(matchId, (prev) => ({
1150
- ...prev,
1151
- ...head
1152
- }));
1153
- }
1154
- }
1155
- if (!loaderIsRunningAsync) {
1156
- const { loaderPromise, loadPromise } = this.getMatch(matchId);
1157
- loaderPromise?.resolve();
1158
- loadPromise?.resolve();
1159
- }
1160
- updateMatch(matchId, (prev) => {
1161
- clearTimeout(prev.pendingTimeout);
1162
- return {
1163
- ...prev,
1164
- isFetching: loaderIsRunningAsync ? prev.isFetching : false,
1165
- loaderPromise: loaderIsRunningAsync ? prev.loaderPromise : void 0,
1166
- invalid: false,
1167
- pendingTimeout: void 0,
1168
- _dehydrated: void 0
1169
- };
1170
- });
1171
- return this.getMatch(matchId);
1172
- })()
1173
- );
1174
- });
1175
- await Promise.all(matchPromises);
1176
- resolveAll();
1177
- } catch (err) {
1178
- rejectAll(err);
1179
- }
1180
- })();
1181
- });
1182
- await triggerOnReady();
1183
- } catch (err) {
1184
- if (isRedirect(err) || isNotFound(err)) {
1185
- if (isNotFound(err) && !allPreload) {
1186
- await triggerOnReady();
1187
- }
1188
- throw err;
1189
- }
1190
- }
1191
- return matches;
1192
- };
1193
691
  this.invalidate = (opts) => {
1194
692
  const invalidate = (d) => {
1195
693
  if (opts?.filter?.(d) ?? true) {
1196
694
  return {
1197
695
  ...d,
1198
696
  invalid: true,
1199
- ...opts?.forcePending || d.status === "error" ? { status: "pending", error: void 0 } : {}
697
+ ...opts?.forcePending || d.status === "error" ? { status: "pending", error: void 0 } : void 0
1200
698
  };
1201
699
  }
1202
700
  return d;
@@ -1254,31 +752,7 @@ class RouterCore {
1254
752
  };
1255
753
  this.clearCache({ filter });
1256
754
  };
1257
- this.loadRouteChunk = (route) => {
1258
- if (route._lazyPromise === void 0) {
1259
- if (route.lazyFn) {
1260
- route._lazyPromise = route.lazyFn().then((lazyRoute) => {
1261
- const { id: _id, ...options2 } = lazyRoute.options;
1262
- Object.assign(route.options, options2);
1263
- });
1264
- } else {
1265
- route._lazyPromise = Promise.resolve();
1266
- }
1267
- }
1268
- if (route._componentsPromise === void 0) {
1269
- route._componentsPromise = route._lazyPromise.then(
1270
- () => Promise.all(
1271
- componentTypes.map(async (type) => {
1272
- const component = route.options[type];
1273
- if (component?.preload) {
1274
- await component.preload();
1275
- }
1276
- })
1277
- )
1278
- );
1279
- }
1280
- return route._componentsPromise;
1281
- };
755
+ this.loadRouteChunk = loadRouteChunk;
1282
756
  this.preloadRoute = async (opts) => {
1283
757
  const next = this.buildLocation(opts);
1284
758
  let matches = this.matchRoutes(next, {
@@ -1306,7 +780,8 @@ class RouterCore {
1306
780
  });
1307
781
  });
1308
782
  try {
1309
- matches = await this.loadMatches({
783
+ matches = await loadMatches({
784
+ router: this,
1310
785
  matches,
1311
786
  location: next,
1312
787
  preload: true,
@@ -1373,39 +848,6 @@ class RouterCore {
1373
848
  }
1374
849
  return match;
1375
850
  };
1376
- this._handleNotFound = (matches, err, {
1377
- updateMatch = this.updateMatch
1378
- } = {}) => {
1379
- const routeCursor = this.routesById[err.routeId ?? ""] ?? this.routeTree;
1380
- const matchesByRouteId = {};
1381
- for (const match of matches) {
1382
- matchesByRouteId[match.routeId] = match;
1383
- }
1384
- if (!routeCursor.options.notFoundComponent && this.options?.defaultNotFoundComponent) {
1385
- routeCursor.options.notFoundComponent = this.options.defaultNotFoundComponent;
1386
- }
1387
- invariant(
1388
- routeCursor.options.notFoundComponent,
1389
- "No notFoundComponent found. Please set a notFoundComponent on your route or provide a defaultNotFoundComponent to the router."
1390
- );
1391
- const matchForRoute = matchesByRouteId[routeCursor.id];
1392
- invariant(
1393
- matchForRoute,
1394
- "Could not find match for route: " + routeCursor.id
1395
- );
1396
- updateMatch(matchForRoute.id, (prev) => ({
1397
- ...prev,
1398
- status: "notFound",
1399
- error: err,
1400
- isFetching: false
1401
- }));
1402
- if (err.routerCode === "BEFORE_LOAD" && routeCursor.parentRoute) {
1403
- err.routeId = routeCursor.parentRoute.id;
1404
- this._handleNotFound(matches, err, {
1405
- updateMatch
1406
- });
1407
- }
1408
- };
1409
851
  this.hasNotFoundMatch = () => {
1410
852
  return this.__store.state.matches.some(
1411
853
  (d) => d.status === "notFound" || d.globalNotFound
@@ -1493,16 +935,16 @@ class RouterCore {
1493
935
  const matches = [];
1494
936
  const getParentContext = (parentMatch) => {
1495
937
  const parentMatchId = parentMatch?.id;
1496
- const parentContext = !parentMatchId ? this.options.context ?? {} : parentMatch.context ?? this.options.context ?? {};
938
+ const parentContext = !parentMatchId ? this.options.context ?? void 0 : parentMatch.context ?? this.options.context ?? void 0;
1497
939
  return parentContext;
1498
940
  };
1499
941
  matchedRoutes.forEach((route, index) => {
1500
942
  const parentMatch = matches[index - 1];
1501
943
  const [preMatchSearch, strictMatchSearch, searchError] = (() => {
1502
944
  const parentSearch = parentMatch?.search ?? next.search;
1503
- const parentStrictSearch = parentMatch?._strictSearch ?? {};
945
+ const parentStrictSearch = parentMatch?._strictSearch ?? void 0;
1504
946
  try {
1505
- const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ?? {};
947
+ const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ?? void 0;
1506
948
  return [
1507
949
  {
1508
950
  ...parentSearch,
@@ -1572,7 +1014,10 @@ class RouterCore {
1572
1014
  isFetching: false,
1573
1015
  error: void 0,
1574
1016
  paramsError: parseErrors[index],
1575
- __routeContext: {},
1017
+ __routeContext: void 0,
1018
+ _nonReactive: {
1019
+ loadPromise: createControlledPromise()
1020
+ },
1576
1021
  __beforeLoadContext: void 0,
1577
1022
  context: {},
1578
1023
  abortController: new AbortController(),
@@ -1586,7 +1031,6 @@ class RouterCore {
1586
1031
  headScripts: void 0,
1587
1032
  meta: void 0,
1588
1033
  staticData: route.options.staticData || {},
1589
- loadPromise: createControlledPromise(),
1590
1034
  fullPath: route.fullPath
1591
1035
  };
1592
1036
  }
@@ -1608,19 +1052,21 @@ class RouterCore {
1608
1052
  if (!existingMatch && opts?._buildLocation !== true) {
1609
1053
  const parentMatch = matches[index - 1];
1610
1054
  const parentContext = getParentContext(parentMatch);
1611
- const contextFnContext = {
1612
- deps: match.loaderDeps,
1613
- params: match.params,
1614
- context: parentContext,
1615
- location: next,
1616
- navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
1617
- buildLocation: this.buildLocation,
1618
- cause: match.cause,
1619
- abortController: match.abortController,
1620
- preload: !!match.preload,
1621
- matches
1622
- };
1623
- match.__routeContext = route.options.context?.(contextFnContext) ?? {};
1055
+ if (route.options.context) {
1056
+ const contextFnContext = {
1057
+ deps: match.loaderDeps,
1058
+ params: match.params,
1059
+ context: parentContext ?? {},
1060
+ location: next,
1061
+ navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
1062
+ buildLocation: this.buildLocation,
1063
+ cause: match.cause,
1064
+ abortController: match.abortController,
1065
+ preload: !!match.preload,
1066
+ matches
1067
+ };
1068
+ match.__routeContext = route.options.context(contextFnContext) ?? void 0;
1069
+ }
1624
1070
  match.context = {
1625
1071
  ...parentContext,
1626
1072
  ...match.__routeContext,
@@ -1679,20 +1125,6 @@ function validateSearch(validateSearch2, input) {
1679
1125
  }
1680
1126
  return {};
1681
1127
  }
1682
- const componentTypes = [
1683
- "component",
1684
- "errorComponent",
1685
- "pendingComponent",
1686
- "notFoundComponent"
1687
- ];
1688
- function routeNeedsPreload(route) {
1689
- for (const componentType of componentTypes) {
1690
- if (route.options[componentType]?.preload) {
1691
- return true;
1692
- }
1693
- }
1694
- return false;
1695
- }
1696
1128
  const REQUIRED_PARAM_BASE_SCORE = 0.5;
1697
1129
  const OPTIONAL_PARAM_BASE_SCORE = 0.4;
1698
1130
  const WILDCARD_PARAM_BASE_SCORE = 0.25;
@@ -1923,7 +1355,7 @@ function applySearchMiddleware({
1923
1355
  try {
1924
1356
  const validatedSearch = {
1925
1357
  ...result,
1926
- ...validateSearch(route.options.validateSearch, result) ?? {}
1358
+ ...validateSearch(route.options.validateSearch, result) ?? void 0
1927
1359
  };
1928
1360
  return validatedSearch;
1929
1361
  } catch {
@@ -1962,7 +1394,6 @@ export {
1962
1394
  PathParamError,
1963
1395
  RouterCore,
1964
1396
  SearchParamError,
1965
- componentTypes,
1966
1397
  defaultSerializeError,
1967
1398
  getInitialRouterState,
1968
1399
  getLocationChangeInfo,