@tanstack/router-core 1.132.0-alpha.2 → 1.132.0-alpha.20

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 (142) hide show
  1. package/dist/cjs/Matches.cjs.map +1 -1
  2. package/dist/cjs/Matches.d.cts +2 -2
  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 +15 -3
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/index.d.cts +11 -4
  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/location.d.cts +38 -0
  14. package/dist/cjs/path.cjs +7 -49
  15. package/dist/cjs/path.cjs.map +1 -1
  16. package/dist/cjs/path.d.cts +3 -6
  17. package/dist/cjs/qss.cjs +19 -19
  18. package/dist/cjs/qss.cjs.map +1 -1
  19. package/dist/cjs/qss.d.cts +6 -4
  20. package/dist/cjs/redirect.cjs +3 -3
  21. package/dist/cjs/redirect.cjs.map +1 -1
  22. package/dist/cjs/rewrite.cjs +63 -0
  23. package/dist/cjs/rewrite.cjs.map +1 -0
  24. package/dist/cjs/rewrite.d.cts +22 -0
  25. package/dist/cjs/route.cjs.map +1 -1
  26. package/dist/cjs/route.d.cts +42 -37
  27. package/dist/cjs/router.cjs +134 -780
  28. package/dist/cjs/router.cjs.map +1 -1
  29. package/dist/cjs/router.d.cts +68 -36
  30. package/dist/cjs/scroll-restoration.cjs +32 -29
  31. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  32. package/dist/cjs/scroll-restoration.d.cts +1 -1
  33. package/dist/cjs/searchParams.cjs +7 -15
  34. package/dist/cjs/searchParams.cjs.map +1 -1
  35. package/dist/cjs/ssr/constants.cjs +5 -0
  36. package/dist/cjs/ssr/constants.cjs.map +1 -0
  37. package/dist/cjs/ssr/constants.d.cts +1 -0
  38. package/dist/cjs/ssr/{seroval-plugins.cjs → serializer/ShallowErrorPlugin.cjs} +2 -2
  39. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -0
  40. package/dist/cjs/ssr/{seroval-plugins.d.cts → serializer/ShallowErrorPlugin.d.cts} +1 -2
  41. package/dist/cjs/ssr/serializer/seroval-plugins.cjs +11 -0
  42. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -0
  43. package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -0
  44. package/dist/cjs/ssr/serializer/transformer.cjs +52 -0
  45. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -0
  46. package/dist/cjs/ssr/serializer/transformer.d.cts +56 -0
  47. package/dist/cjs/ssr/server.d.cts +5 -0
  48. package/dist/cjs/ssr/ssr-client.cjs +15 -1
  49. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  50. package/dist/cjs/ssr/ssr-client.d.cts +5 -1
  51. package/dist/cjs/ssr/ssr-server.cjs +12 -10
  52. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  53. package/dist/cjs/ssr/ssr-server.d.cts +0 -1
  54. package/dist/cjs/ssr/tsrScript.cjs +1 -1
  55. package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
  56. package/dist/cjs/utils.cjs +8 -7
  57. package/dist/cjs/utils.cjs.map +1 -1
  58. package/dist/cjs/utils.d.cts +1 -1
  59. package/dist/esm/Matches.d.ts +2 -2
  60. package/dist/esm/Matches.js.map +1 -1
  61. package/dist/esm/config.d.ts +17 -0
  62. package/dist/esm/config.js +10 -0
  63. package/dist/esm/config.js.map +1 -0
  64. package/dist/esm/fileRoute.d.ts +3 -2
  65. package/dist/esm/index.d.ts +11 -4
  66. package/dist/esm/index.js +17 -5
  67. package/dist/esm/index.js.map +1 -1
  68. package/dist/esm/load-matches.d.ts +16 -0
  69. package/dist/esm/load-matches.js +636 -0
  70. package/dist/esm/load-matches.js.map +1 -0
  71. package/dist/esm/location.d.ts +38 -0
  72. package/dist/esm/path.d.ts +3 -6
  73. package/dist/esm/path.js +7 -49
  74. package/dist/esm/path.js.map +1 -1
  75. package/dist/esm/qss.d.ts +6 -4
  76. package/dist/esm/qss.js +19 -19
  77. package/dist/esm/qss.js.map +1 -1
  78. package/dist/esm/redirect.js +3 -3
  79. package/dist/esm/redirect.js.map +1 -1
  80. package/dist/esm/rewrite.d.ts +22 -0
  81. package/dist/esm/rewrite.js +63 -0
  82. package/dist/esm/rewrite.js.map +1 -0
  83. package/dist/esm/route.d.ts +42 -37
  84. package/dist/esm/route.js.map +1 -1
  85. package/dist/esm/router.d.ts +68 -36
  86. package/dist/esm/router.js +136 -782
  87. package/dist/esm/router.js.map +1 -1
  88. package/dist/esm/scroll-restoration.d.ts +1 -1
  89. package/dist/esm/scroll-restoration.js +32 -29
  90. package/dist/esm/scroll-restoration.js.map +1 -1
  91. package/dist/esm/searchParams.js +7 -15
  92. package/dist/esm/searchParams.js.map +1 -1
  93. package/dist/esm/ssr/constants.d.ts +1 -0
  94. package/dist/esm/ssr/constants.js +5 -0
  95. package/dist/esm/ssr/constants.js.map +1 -0
  96. package/dist/esm/ssr/{seroval-plugins.d.ts → serializer/ShallowErrorPlugin.d.ts} +1 -2
  97. package/dist/esm/ssr/{seroval-plugins.js → serializer/ShallowErrorPlugin.js} +2 -2
  98. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -0
  99. package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -0
  100. package/dist/esm/ssr/serializer/seroval-plugins.js +11 -0
  101. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -0
  102. package/dist/esm/ssr/serializer/transformer.d.ts +56 -0
  103. package/dist/esm/ssr/serializer/transformer.js +52 -0
  104. package/dist/esm/ssr/serializer/transformer.js.map +1 -0
  105. package/dist/esm/ssr/server.d.ts +5 -0
  106. package/dist/esm/ssr/ssr-client.d.ts +5 -1
  107. package/dist/esm/ssr/ssr-client.js +15 -1
  108. package/dist/esm/ssr/ssr-client.js.map +1 -1
  109. package/dist/esm/ssr/ssr-server.d.ts +0 -1
  110. package/dist/esm/ssr/ssr-server.js +12 -10
  111. package/dist/esm/ssr/ssr-server.js.map +1 -1
  112. package/dist/esm/ssr/tsrScript.js +1 -1
  113. package/dist/esm/ssr/tsrScript.js.map +1 -1
  114. package/dist/esm/utils.d.ts +1 -1
  115. package/dist/esm/utils.js +8 -7
  116. package/dist/esm/utils.js.map +1 -1
  117. package/package.json +1 -1
  118. package/src/Matches.ts +2 -2
  119. package/src/config.ts +42 -0
  120. package/src/fileRoute.ts +15 -3
  121. package/src/index.ts +32 -3
  122. package/src/load-matches.ts +955 -0
  123. package/src/location.ts +38 -0
  124. package/src/path.ts +9 -66
  125. package/src/qss.ts +27 -24
  126. package/src/redirect.ts +3 -3
  127. package/src/rewrite.ts +70 -0
  128. package/src/route.ts +136 -33
  129. package/src/router.ts +271 -1170
  130. package/src/scroll-restoration.ts +42 -37
  131. package/src/searchParams.ts +8 -19
  132. package/src/ssr/constants.ts +1 -0
  133. package/src/ssr/{seroval-plugins.ts → serializer/ShallowErrorPlugin.ts} +2 -2
  134. package/src/ssr/serializer/seroval-plugins.ts +9 -0
  135. package/src/ssr/serializer/transformer.ts +215 -0
  136. package/src/ssr/server.ts +6 -0
  137. package/src/ssr/ssr-client.ts +30 -3
  138. package/src/ssr/ssr-server.ts +18 -10
  139. package/src/ssr/tsrScript.ts +5 -1
  140. package/src/utils.ts +11 -10
  141. package/dist/cjs/ssr/seroval-plugins.cjs.map +0 -1
  142. package/dist/esm/ssr/seroval-plugins.js.map +0 -1
@@ -11,6 +11,8 @@ const searchParams = require("./searchParams.cjs");
11
11
  const root = require("./root.cjs");
12
12
  const redirect = require("./redirect.cjs");
13
13
  const lruCache = require("./lru-cache.cjs");
14
+ const loadMatches = require("./load-matches.cjs");
15
+ const rewrite = require("./rewrite.cjs");
14
16
  function defaultSerializeError(err) {
15
17
  if (err instanceof Error) {
16
18
  const obj = {
@@ -55,7 +57,6 @@ class RouterCore {
55
57
  "The notFoundRoute API is deprecated and will be removed in the next major version. See https://tanstack.com/router/v1/docs/framework/react/guide/not-found-errors#migrating-from-notfoundroute for more info."
56
58
  );
57
59
  }
58
- const previousOptions = this.options;
59
60
  this.options = {
60
61
  ...this.options,
61
62
  ...newOptions
@@ -67,24 +68,43 @@ class RouterCore {
67
68
  char
68
69
  ])
69
70
  ) : void 0;
70
- if (!this.basepath || newOptions.basepath && newOptions.basepath !== previousOptions.basepath) {
71
- if (newOptions.basepath === void 0 || newOptions.basepath === "" || newOptions.basepath === "/") {
72
- this.basepath = "/";
71
+ if (!this.history || this.options.history && this.options.history !== this.history) {
72
+ if (!this.options.history) {
73
+ if (!this.isServer) {
74
+ this.history = history.createBrowserHistory();
75
+ }
73
76
  } else {
74
- this.basepath = `/${path.trimPath(newOptions.basepath)}`;
77
+ this.history = this.options.history;
75
78
  }
76
79
  }
77
- if (!this.history || this.options.history && this.options.history !== this.history) {
78
- this.history = this.options.history ?? (this.isServer ? history.createMemoryHistory({
79
- initialEntries: [this.basepath || "/"]
80
- }) : history.createBrowserHistory());
81
- this.latestLocation = this.parseLocation();
80
+ if (this.options.basepath) {
81
+ const basepathRewrite = rewrite.rewriteBasepath({
82
+ basepath: this.options.basepath
83
+ });
84
+ if (this.options.rewrite) {
85
+ this.rewrite = rewrite.composeRewrites([basepathRewrite, this.options.rewrite]);
86
+ } else {
87
+ this.rewrite = basepathRewrite;
88
+ }
89
+ } else {
90
+ this.rewrite = this.options.rewrite;
91
+ }
92
+ this.origin = this.options.origin;
93
+ if (!this.origin) {
94
+ if (!this.isServer) {
95
+ this.origin = window.origin;
96
+ } else {
97
+ this.origin = "http://localhost";
98
+ }
99
+ }
100
+ if (this.history) {
101
+ this.updateLatestLocation();
82
102
  }
83
103
  if (this.options.routeTree !== this.routeTree) {
84
104
  this.routeTree = this.options.routeTree;
85
105
  this.buildRouteTree();
86
106
  }
87
- if (!this.__store) {
107
+ if (!this.__store && this.latestLocation) {
88
108
  this.__store = new store.Store(getInitialRouterState(this.latestLocation), {
89
109
  onUpdate: () => {
90
110
  this.__store.state = {
@@ -103,6 +123,12 @@ class RouterCore {
103
123
  );
104
124
  }
105
125
  };
126
+ this.updateLatestLocation = () => {
127
+ this.latestLocation = this.parseLocation(
128
+ this.history.location,
129
+ this.latestLocation
130
+ );
131
+ };
106
132
  this.buildRouteTree = () => {
107
133
  const { routesById, routesByPath, flatRoutes } = processRouteTree({
108
134
  routeTree: this.routeTree,
@@ -140,25 +166,30 @@ class RouterCore {
140
166
  }
141
167
  });
142
168
  };
143
- this.parseLocation = (previousLocation, locationToParse) => {
169
+ this.parseLocation = (locationToParse, previousLocation) => {
144
170
  const parse = ({
145
- pathname,
146
- search,
147
- hash,
171
+ href,
148
172
  state
149
173
  }) => {
150
- const parsedSearch = this.options.parseSearch(search);
174
+ const fullUrl = new URL(href, this.origin);
175
+ const url = rewrite.executeRewriteInput(this.rewrite, fullUrl);
176
+ const parsedSearch = this.options.parseSearch(url.search);
151
177
  const searchStr = this.options.stringifySearch(parsedSearch);
178
+ url.search = searchStr;
179
+ const fullPath = url.href.replace(url.origin, "");
180
+ const { pathname, hash } = url;
152
181
  return {
182
+ href: fullPath,
183
+ publicHref: href,
184
+ url: url.href,
153
185
  pathname,
154
186
  searchStr,
155
187
  search: utils.replaceEqualDeep(previousLocation?.search, parsedSearch),
156
188
  hash: hash.split("#").reverse()[0] ?? "",
157
- href: `${pathname}${searchStr}${hash}`,
158
189
  state: utils.replaceEqualDeep(previousLocation?.state, state)
159
190
  };
160
191
  };
161
- const location = parse(locationToParse ?? this.history.location);
192
+ const location = parse(locationToParse);
162
193
  const { __tempLocation, __tempKey } = location.state;
163
194
  if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
164
195
  const parsedTempLocation = parse(__tempLocation);
@@ -174,11 +205,9 @@ class RouterCore {
174
205
  };
175
206
  this.resolvePathWithBase = (from, path$1) => {
176
207
  const resolvedPath = path.resolvePath({
177
- basepath: this.basepath,
178
208
  base: from,
179
209
  to: path.cleanPath(path$1),
180
210
  trailingSlash: this.options.trailingSlash,
181
- caseSensitive: this.options.caseSensitive,
182
211
  parseCache: this.parsePathnameCache
183
212
  });
184
213
  return resolvedPath;
@@ -200,7 +229,6 @@ class RouterCore {
200
229
  return getMatchedRoutes({
201
230
  pathname,
202
231
  routePathname,
203
- basepath: this.basepath,
204
232
  caseSensitive: this.options.caseSensitive,
205
233
  routesByPath: this.routesByPath,
206
234
  routesById: this.routesById,
@@ -227,57 +255,51 @@ class RouterCore {
227
255
  _buildLocation: true
228
256
  });
229
257
  const lastMatch = utils.last(allCurrentLocationMatches);
230
- let fromPath = this.resolvePathWithBase(lastMatch.fullPath, ".");
231
- const toPath = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
232
- const routeIsChanging = !!dest.to && !comparePaths(dest.to.toString(), fromPath) && !comparePaths(toPath, fromPath);
233
- if (dest.unsafeRelative === "path") {
234
- fromPath = currentLocation.pathname;
235
- } else if (routeIsChanging && dest.from) {
236
- fromPath = dest.from;
237
- if (process.env.NODE_ENV !== "production" && dest._isNavigate) {
238
- const allFromMatches = this.getMatchedRoutes(
239
- dest.from,
240
- void 0
241
- ).matchedRoutes;
242
- const matchedFrom = [...allCurrentLocationMatches].reverse().find((d) => {
243
- return comparePaths(d.fullPath, fromPath);
244
- });
245
- const matchedCurrent = [...allFromMatches].reverse().find((d) => {
246
- return comparePaths(d.fullPath, currentLocation.pathname);
247
- });
248
- if (!matchedFrom && !matchedCurrent) {
249
- console.warn(`Could not find match for from: ${fromPath}`);
250
- }
258
+ if (dest.from && process.env.NODE_ENV !== "production" && dest._isNavigate) {
259
+ const allFromMatches = this.getMatchedRoutes(
260
+ dest.from,
261
+ void 0
262
+ ).matchedRoutes;
263
+ const matchedFrom = utils.findLast(allCurrentLocationMatches, (d) => {
264
+ return comparePaths(d.fullPath, dest.from);
265
+ });
266
+ const matchedCurrent = utils.findLast(allFromMatches, (d) => {
267
+ return comparePaths(d.fullPath, lastMatch.fullPath);
268
+ });
269
+ if (!matchedFrom && !matchedCurrent) {
270
+ console.warn(`Could not find match for from: ${dest.from}`);
251
271
  }
252
272
  }
253
- fromPath = this.resolvePathWithBase(fromPath, ".");
273
+ const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lastMatch.fullPath;
274
+ const fromPath = this.resolvePathWithBase(defaultedFromPath, ".");
254
275
  const fromSearch = lastMatch.search;
255
276
  const fromParams = { ...lastMatch.params };
256
277
  const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
257
- let nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : {
258
- ...fromParams,
259
- ...utils.functionalUpdate(dest.params, fromParams)
260
- };
278
+ const nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : Object.assign(
279
+ fromParams,
280
+ utils.functionalUpdate(dest.params, fromParams)
281
+ );
261
282
  const interpolatedNextTo = path.interpolatePath({
262
283
  path: nextTo,
263
- params: nextParams ?? {},
284
+ params: nextParams,
264
285
  parseCache: this.parsePathnameCache
265
286
  }).interpolatedPath;
266
287
  const destRoutes = this.matchRoutes(interpolatedNextTo, void 0, {
267
288
  _buildLocation: true
268
289
  }).map((d) => this.looseRoutesById[d.routeId]);
269
290
  if (Object.keys(nextParams).length > 0) {
270
- destRoutes.map((route) => {
271
- return route.options.params?.stringify ?? route.options.stringifyParams;
272
- }).filter(Boolean).forEach((fn) => {
273
- nextParams = { ...nextParams, ...fn(nextParams) };
274
- });
291
+ for (const route of destRoutes) {
292
+ const fn = route.options.params?.stringify ?? route.options.stringifyParams;
293
+ if (fn) {
294
+ Object.assign(nextParams, fn(nextParams));
295
+ }
296
+ }
275
297
  }
276
298
  const nextPathname = path.interpolatePath({
277
299
  // Use the original template path for interpolation
278
300
  // This preserves the original parameter syntax including optional parameters
279
301
  path: nextTo,
280
- params: nextParams ?? {},
302
+ params: nextParams,
281
303
  leaveWildcards: false,
282
304
  leaveParams: opts.leaveParams,
283
305
  decodeCharMap: this.pathParamsDecodeCharMap,
@@ -285,19 +307,19 @@ class RouterCore {
285
307
  }).interpolatedPath;
286
308
  let nextSearch = fromSearch;
287
309
  if (opts._includeValidateSearch && this.options.search?.strict) {
288
- let validatedSearch = {};
310
+ const validatedSearch = {};
289
311
  destRoutes.forEach((route) => {
290
- try {
291
- if (route.options.validateSearch) {
292
- validatedSearch = {
293
- ...validatedSearch,
294
- ...validateSearch(route.options.validateSearch, {
312
+ if (route.options.validateSearch) {
313
+ try {
314
+ Object.assign(
315
+ validatedSearch,
316
+ validateSearch(route.options.validateSearch, {
295
317
  ...validatedSearch,
296
318
  ...nextSearch
297
- }) ?? {}
298
- };
319
+ })
320
+ );
321
+ } catch {
299
322
  }
300
- } catch {
301
323
  }
302
324
  });
303
325
  nextSearch = validatedSearch;
@@ -314,13 +336,18 @@ class RouterCore {
314
336
  const hashStr = hash ? `#${hash}` : "";
315
337
  let nextState = dest.state === true ? currentLocation.state : dest.state ? utils.functionalUpdate(dest.state, currentLocation.state) : {};
316
338
  nextState = utils.replaceEqualDeep(currentLocation.state, nextState);
339
+ const fullPath = `${nextPathname}${searchStr}${hashStr}`;
340
+ const url = new URL(fullPath, this.origin);
341
+ const rewrittenUrl = rewrite.executeRewriteOutput(this.rewrite, url);
317
342
  return {
343
+ publicHref: rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
344
+ href: fullPath,
345
+ url: rewrittenUrl.href,
318
346
  pathname: nextPathname,
319
347
  search: nextSearch,
320
348
  searchStr,
321
349
  state: nextState,
322
350
  hash: hash ?? "",
323
- href: `${nextPathname}${searchStr}${hashStr}`,
324
351
  unmaskOnReload: dest.unmaskOnReload
325
352
  };
326
353
  };
@@ -331,7 +358,6 @@ class RouterCore {
331
358
  let params = {};
332
359
  const foundMask = this.options.routeMasks?.find((d) => {
333
360
  const match = path.matchPathname(
334
- this.basepath,
335
361
  next.pathname,
336
362
  {
337
363
  to: d.from,
@@ -349,7 +375,7 @@ class RouterCore {
349
375
  if (foundMask) {
350
376
  const { from: _from, ...maskProps } = foundMask;
351
377
  maskedDest = {
352
- ...utils.pick(opts, ["from"]),
378
+ from: opts.from,
353
379
  ...maskProps,
354
380
  params
355
381
  };
@@ -357,14 +383,13 @@ class RouterCore {
357
383
  }
358
384
  }
359
385
  if (maskedNext) {
360
- const maskedFinal = build(maskedDest);
361
- next.maskedLocation = maskedFinal;
386
+ next.maskedLocation = maskedNext;
362
387
  }
363
388
  return next;
364
389
  };
365
390
  if (opts.mask) {
366
391
  return buildWithMatches(opts, {
367
- ...utils.pick(opts, ["from"]),
392
+ from: opts.from,
368
393
  ...opts.mask
369
394
  });
370
395
  }
@@ -392,7 +417,7 @@ class RouterCore {
392
417
  });
393
418
  return isEqual;
394
419
  };
395
- const isSameUrl = this.latestLocation.href === next.href;
420
+ const isSameUrl = path.trimPathRight(this.latestLocation.href) === path.trimPathRight(next.href);
396
421
  const previousCommitPromise = this.commitLocationPromise;
397
422
  this.commitLocationPromise = utils.createControlledPromise(() => {
398
423
  previousCommitPromise?.resolve();
@@ -428,7 +453,7 @@ class RouterCore {
428
453
  nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true;
429
454
  this.shouldViewTransition = viewTransition;
430
455
  this.history[next.replace ? "replace" : "push"](
431
- nextHistory.href,
456
+ nextHistory.publicHref,
432
457
  nextHistory.state,
433
458
  { ignoreBlocker }
434
459
  );
@@ -481,7 +506,7 @@ class RouterCore {
481
506
  if (reloadDocument) {
482
507
  if (!href) {
483
508
  const location = this.buildLocation({ to, ...rest });
484
- href = this.history.createHref(location.href);
509
+ href = location.href;
485
510
  }
486
511
  if (rest.replace) {
487
512
  window.location.replace(href);
@@ -499,7 +524,7 @@ class RouterCore {
499
524
  };
500
525
  this.beforeLoad = () => {
501
526
  this.cancelMatches();
502
- this.latestLocation = this.parseLocation(this.latestLocation);
527
+ this.updateLatestLocation();
503
528
  if (this.isServer) {
504
529
  const nextLocation = this.buildLocation({
505
530
  to: this.latestLocation.pathname,
@@ -560,10 +585,12 @@ class RouterCore {
560
585
  location: next
561
586
  })
562
587
  });
563
- await this.loadMatches({
588
+ await loadMatches.loadMatches({
589
+ router: this,
564
590
  sync: opts?.sync,
565
591
  matches: this.state.pendingMatches,
566
592
  location: next,
593
+ updateMatch: this.updateMatch,
567
594
  // eslint-disable-next-line @typescript-eslint/require-await
568
595
  onReady: async () => {
569
596
  this.startViewTransition(async () => {
@@ -687,598 +714,6 @@ class RouterCore {
687
714
  const findFn = (d) => d.id === matchId;
688
715
  return this.state.cachedMatches.find(findFn) ?? this.state.pendingMatches?.find(findFn) ?? this.state.matches.find(findFn);
689
716
  };
690
- this.triggerOnReady = (innerLoadContext) => {
691
- if (!innerLoadContext.rendered) {
692
- innerLoadContext.rendered = true;
693
- return innerLoadContext.onReady?.();
694
- }
695
- };
696
- this.resolvePreload = (innerLoadContext, matchId) => {
697
- return !!(innerLoadContext.preload && !this.state.matches.some((d) => d.id === matchId));
698
- };
699
- this.handleRedirectAndNotFound = (innerLoadContext, match, err) => {
700
- if (!redirect.isRedirect(err) && !notFound.isNotFound(err)) return;
701
- if (redirect.isRedirect(err) && err.redirectHandled && !err.options.reloadDocument) {
702
- throw err;
703
- }
704
- if (match) {
705
- match._nonReactive.beforeLoadPromise?.resolve();
706
- match._nonReactive.loaderPromise?.resolve();
707
- match._nonReactive.beforeLoadPromise = void 0;
708
- match._nonReactive.loaderPromise = void 0;
709
- const status = redirect.isRedirect(err) ? "redirected" : "notFound";
710
- innerLoadContext.updateMatch(match.id, (prev) => ({
711
- ...prev,
712
- status,
713
- isFetching: false,
714
- error: err
715
- }));
716
- if (notFound.isNotFound(err) && !err.routeId) {
717
- err.routeId = match.routeId;
718
- }
719
- match._nonReactive.loadPromise?.resolve();
720
- }
721
- if (redirect.isRedirect(err)) {
722
- innerLoadContext.rendered = true;
723
- err.options._fromLocation = innerLoadContext.location;
724
- err.redirectHandled = true;
725
- err = this.resolveRedirect(err);
726
- throw err;
727
- } else {
728
- this._handleNotFound(innerLoadContext, err);
729
- throw err;
730
- }
731
- };
732
- this.shouldSkipLoader = (matchId) => {
733
- const match = this.getMatch(matchId);
734
- if (!this.isServer && match._nonReactive.dehydrated) {
735
- return true;
736
- }
737
- if (this.isServer) {
738
- if (match.ssr === false) {
739
- return true;
740
- }
741
- }
742
- return false;
743
- };
744
- this.handleSerialError = (innerLoadContext, index, err, routerCode) => {
745
- const { id: matchId, routeId } = innerLoadContext.matches[index];
746
- const route = this.looseRoutesById[routeId];
747
- if (err instanceof Promise) {
748
- throw err;
749
- }
750
- err.routerCode = routerCode;
751
- innerLoadContext.firstBadMatchIndex ??= index;
752
- this.handleRedirectAndNotFound(
753
- innerLoadContext,
754
- this.getMatch(matchId),
755
- err
756
- );
757
- try {
758
- route.options.onError?.(err);
759
- } catch (errorHandlerErr) {
760
- err = errorHandlerErr;
761
- this.handleRedirectAndNotFound(
762
- innerLoadContext,
763
- this.getMatch(matchId),
764
- err
765
- );
766
- }
767
- innerLoadContext.updateMatch(matchId, (prev) => {
768
- prev._nonReactive.beforeLoadPromise?.resolve();
769
- prev._nonReactive.beforeLoadPromise = void 0;
770
- prev._nonReactive.loadPromise?.resolve();
771
- return {
772
- ...prev,
773
- error: err,
774
- status: "error",
775
- isFetching: false,
776
- updatedAt: Date.now(),
777
- abortController: new AbortController()
778
- };
779
- });
780
- };
781
- this.isBeforeLoadSsr = (innerLoadContext, matchId, index, route) => {
782
- const existingMatch = this.getMatch(matchId);
783
- const parentMatchId = innerLoadContext.matches[index - 1]?.id;
784
- const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
785
- if (this.isShell()) {
786
- existingMatch.ssr = matchId === root.rootRouteId;
787
- return;
788
- }
789
- if (parentMatch?.ssr === false) {
790
- existingMatch.ssr = false;
791
- return;
792
- }
793
- const parentOverride = (tempSsr2) => {
794
- if (tempSsr2 === true && parentMatch?.ssr === "data-only") {
795
- return "data-only";
796
- }
797
- return tempSsr2;
798
- };
799
- const defaultSsr = this.options.defaultSsr ?? true;
800
- if (route.options.ssr === void 0) {
801
- existingMatch.ssr = parentOverride(defaultSsr);
802
- return;
803
- }
804
- if (typeof route.options.ssr !== "function") {
805
- existingMatch.ssr = parentOverride(route.options.ssr);
806
- return;
807
- }
808
- const { search, params } = this.getMatch(matchId);
809
- const ssrFnContext = {
810
- search: makeMaybe(search, existingMatch.searchError),
811
- params: makeMaybe(params, existingMatch.paramsError),
812
- location: innerLoadContext.location,
813
- matches: innerLoadContext.matches.map((match) => ({
814
- index: match.index,
815
- pathname: match.pathname,
816
- fullPath: match.fullPath,
817
- staticData: match.staticData,
818
- id: match.id,
819
- routeId: match.routeId,
820
- search: makeMaybe(match.search, match.searchError),
821
- params: makeMaybe(match.params, match.paramsError),
822
- ssr: match.ssr
823
- }))
824
- };
825
- const tempSsr = route.options.ssr(ssrFnContext);
826
- if (utils.isPromise(tempSsr)) {
827
- return tempSsr.then((ssr) => {
828
- existingMatch.ssr = parentOverride(ssr ?? defaultSsr);
829
- });
830
- }
831
- existingMatch.ssr = parentOverride(tempSsr ?? defaultSsr);
832
- return;
833
- };
834
- this.setupPendingTimeout = (innerLoadContext, matchId, route) => {
835
- const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
836
- const shouldPending = !!(innerLoadContext.onReady && !this.isServer && !this.resolvePreload(innerLoadContext, matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? this.options?.defaultPendingComponent));
837
- const match = this.getMatch(matchId);
838
- if (shouldPending && match._nonReactive.pendingTimeout === void 0) {
839
- const pendingTimeout = setTimeout(() => {
840
- this.triggerOnReady(innerLoadContext);
841
- }, pendingMs);
842
- match._nonReactive.pendingTimeout = pendingTimeout;
843
- }
844
- };
845
- this.shouldExecuteBeforeLoad = (innerLoadContext, matchId, route) => {
846
- const existingMatch = this.getMatch(matchId);
847
- if (!existingMatch._nonReactive.beforeLoadPromise && !existingMatch._nonReactive.loaderPromise)
848
- return true;
849
- this.setupPendingTimeout(innerLoadContext, matchId, route);
850
- const then = () => {
851
- let shouldExecuteBeforeLoad = true;
852
- const match = this.getMatch(matchId);
853
- if (match.status === "error") {
854
- shouldExecuteBeforeLoad = true;
855
- } else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
856
- this.handleRedirectAndNotFound(innerLoadContext, match, match.error);
857
- }
858
- return shouldExecuteBeforeLoad;
859
- };
860
- return existingMatch._nonReactive.beforeLoadPromise ? existingMatch._nonReactive.beforeLoadPromise.then(then) : then();
861
- };
862
- this.executeBeforeLoad = (innerLoadContext, matchId, index, route) => {
863
- const match = this.getMatch(matchId);
864
- match._nonReactive.beforeLoadPromise = utils.createControlledPromise();
865
- const prevLoadPromise = match._nonReactive.loadPromise;
866
- match._nonReactive.loadPromise = utils.createControlledPromise(() => {
867
- prevLoadPromise?.resolve();
868
- });
869
- const { paramsError, searchError } = match;
870
- if (paramsError) {
871
- this.handleSerialError(
872
- innerLoadContext,
873
- index,
874
- paramsError,
875
- "PARSE_PARAMS"
876
- );
877
- }
878
- if (searchError) {
879
- this.handleSerialError(
880
- innerLoadContext,
881
- index,
882
- searchError,
883
- "VALIDATE_SEARCH"
884
- );
885
- }
886
- this.setupPendingTimeout(innerLoadContext, matchId, route);
887
- const abortController = new AbortController();
888
- const parentMatchId = innerLoadContext.matches[index - 1]?.id;
889
- const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
890
- const parentMatchContext = parentMatch?.context ?? this.options.context ?? void 0;
891
- const context = { ...parentMatchContext, ...match.__routeContext };
892
- let isPending = false;
893
- const pending = () => {
894
- if (isPending) return;
895
- isPending = true;
896
- innerLoadContext.updateMatch(matchId, (prev) => ({
897
- ...prev,
898
- isFetching: "beforeLoad",
899
- fetchCount: prev.fetchCount + 1,
900
- abortController,
901
- context
902
- }));
903
- };
904
- const resolve = () => {
905
- match._nonReactive.beforeLoadPromise?.resolve();
906
- match._nonReactive.beforeLoadPromise = void 0;
907
- innerLoadContext.updateMatch(matchId, (prev) => ({
908
- ...prev,
909
- isFetching: false
910
- }));
911
- };
912
- if (!route.options.beforeLoad) {
913
- store.batch(() => {
914
- pending();
915
- resolve();
916
- });
917
- return;
918
- }
919
- const { search, params, cause } = match;
920
- const preload = this.resolvePreload(innerLoadContext, matchId);
921
- const beforeLoadFnContext = {
922
- search,
923
- abortController,
924
- params,
925
- preload,
926
- context,
927
- location: innerLoadContext.location,
928
- navigate: (opts) => this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
929
- buildLocation: this.buildLocation,
930
- cause: preload ? "preload" : cause,
931
- matches: innerLoadContext.matches
932
- };
933
- const updateContext = (beforeLoadContext2) => {
934
- if (beforeLoadContext2 === void 0) {
935
- store.batch(() => {
936
- pending();
937
- resolve();
938
- });
939
- return;
940
- }
941
- if (redirect.isRedirect(beforeLoadContext2) || notFound.isNotFound(beforeLoadContext2)) {
942
- pending();
943
- this.handleSerialError(
944
- innerLoadContext,
945
- index,
946
- beforeLoadContext2,
947
- "BEFORE_LOAD"
948
- );
949
- }
950
- store.batch(() => {
951
- pending();
952
- innerLoadContext.updateMatch(matchId, (prev) => ({
953
- ...prev,
954
- __beforeLoadContext: beforeLoadContext2,
955
- context: {
956
- ...prev.context,
957
- ...beforeLoadContext2
958
- }
959
- }));
960
- resolve();
961
- });
962
- };
963
- let beforeLoadContext;
964
- try {
965
- beforeLoadContext = route.options.beforeLoad(beforeLoadFnContext);
966
- if (utils.isPromise(beforeLoadContext)) {
967
- pending();
968
- return beforeLoadContext.catch((err) => {
969
- this.handleSerialError(innerLoadContext, index, err, "BEFORE_LOAD");
970
- }).then(updateContext);
971
- }
972
- } catch (err) {
973
- pending();
974
- this.handleSerialError(innerLoadContext, index, err, "BEFORE_LOAD");
975
- }
976
- updateContext(beforeLoadContext);
977
- return;
978
- };
979
- this.handleBeforeLoad = (innerLoadContext, index) => {
980
- const { id: matchId, routeId } = innerLoadContext.matches[index];
981
- const route = this.looseRoutesById[routeId];
982
- const serverSsr = () => {
983
- if (this.isServer) {
984
- const maybePromise = this.isBeforeLoadSsr(
985
- innerLoadContext,
986
- matchId,
987
- index,
988
- route
989
- );
990
- if (utils.isPromise(maybePromise)) return maybePromise.then(queueExecution);
991
- }
992
- return queueExecution();
993
- };
994
- const queueExecution = () => {
995
- if (this.shouldSkipLoader(matchId)) return;
996
- const shouldExecuteBeforeLoadResult = this.shouldExecuteBeforeLoad(
997
- innerLoadContext,
998
- matchId,
999
- route
1000
- );
1001
- return utils.isPromise(shouldExecuteBeforeLoadResult) ? shouldExecuteBeforeLoadResult.then(execute) : execute(shouldExecuteBeforeLoadResult);
1002
- };
1003
- const execute = (shouldExecuteBeforeLoad) => {
1004
- if (shouldExecuteBeforeLoad) {
1005
- return this.executeBeforeLoad(innerLoadContext, matchId, index, route);
1006
- }
1007
- return;
1008
- };
1009
- return serverSsr();
1010
- };
1011
- this.executeHead = (innerLoadContext, matchId, route) => {
1012
- const match = this.getMatch(matchId);
1013
- if (!match) {
1014
- return;
1015
- }
1016
- if (!route.options.head && !route.options.scripts && !route.options.headers) {
1017
- return;
1018
- }
1019
- const assetContext = {
1020
- matches: innerLoadContext.matches,
1021
- match,
1022
- params: match.params,
1023
- loaderData: match.loaderData
1024
- };
1025
- return Promise.all([
1026
- route.options.head?.(assetContext),
1027
- route.options.scripts?.(assetContext),
1028
- route.options.headers?.(assetContext)
1029
- ]).then(([headFnContent, scripts, headers]) => {
1030
- const meta = headFnContent?.meta;
1031
- const links = headFnContent?.links;
1032
- const headScripts = headFnContent?.scripts;
1033
- const styles = headFnContent?.styles;
1034
- return {
1035
- meta,
1036
- links,
1037
- headScripts,
1038
- headers,
1039
- scripts,
1040
- styles
1041
- };
1042
- });
1043
- };
1044
- this.potentialPendingMinPromise = (matchId) => {
1045
- const latestMatch = this.getMatch(matchId);
1046
- return latestMatch._nonReactive.minPendingPromise;
1047
- };
1048
- this.getLoaderContext = (innerLoadContext, matchId, index, route) => {
1049
- const parentMatchPromise = innerLoadContext.matchPromises[index - 1];
1050
- const { params, loaderDeps, abortController, context, cause } = this.getMatch(matchId);
1051
- const preload = this.resolvePreload(innerLoadContext, matchId);
1052
- return {
1053
- params,
1054
- deps: loaderDeps,
1055
- preload: !!preload,
1056
- parentMatchPromise,
1057
- abortController,
1058
- context,
1059
- location: innerLoadContext.location,
1060
- navigate: (opts) => this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
1061
- cause: preload ? "preload" : cause,
1062
- route
1063
- };
1064
- };
1065
- this.runLoader = async (innerLoadContext, matchId, index, route) => {
1066
- try {
1067
- try {
1068
- if (!this.isServer || this.getMatch(matchId).ssr === true) {
1069
- this.loadRouteChunk(route);
1070
- }
1071
- const loaderResult = route.options.loader?.(
1072
- this.getLoaderContext(innerLoadContext, matchId, index, route)
1073
- );
1074
- const loaderResultIsPromise = route.options.loader && utils.isPromise(loaderResult);
1075
- const willLoadSomething = !!(loaderResultIsPromise || route._lazyPromise || route._componentsPromise || route.options.head || route.options.scripts || route.options.headers || this.getMatch(matchId)._nonReactive.minPendingPromise);
1076
- if (willLoadSomething) {
1077
- innerLoadContext.updateMatch(matchId, (prev) => ({
1078
- ...prev,
1079
- isFetching: "loader"
1080
- }));
1081
- }
1082
- if (route.options.loader) {
1083
- const loaderData = loaderResultIsPromise ? await loaderResult : loaderResult;
1084
- this.handleRedirectAndNotFound(
1085
- innerLoadContext,
1086
- this.getMatch(matchId),
1087
- loaderData
1088
- );
1089
- if (loaderData !== void 0) {
1090
- innerLoadContext.updateMatch(matchId, (prev) => ({
1091
- ...prev,
1092
- loaderData
1093
- }));
1094
- }
1095
- }
1096
- if (route._lazyPromise) await route._lazyPromise;
1097
- const headResult = this.executeHead(innerLoadContext, matchId, route);
1098
- const head = headResult ? await headResult : void 0;
1099
- const pendingPromise = this.potentialPendingMinPromise(matchId);
1100
- if (pendingPromise) await pendingPromise;
1101
- if (route._componentsPromise) await route._componentsPromise;
1102
- innerLoadContext.updateMatch(matchId, (prev) => ({
1103
- ...prev,
1104
- error: void 0,
1105
- status: "success",
1106
- isFetching: false,
1107
- updatedAt: Date.now(),
1108
- ...head
1109
- }));
1110
- } catch (e) {
1111
- let error = e;
1112
- const pendingPromise = this.potentialPendingMinPromise(matchId);
1113
- if (pendingPromise) await pendingPromise;
1114
- this.handleRedirectAndNotFound(
1115
- innerLoadContext,
1116
- this.getMatch(matchId),
1117
- e
1118
- );
1119
- try {
1120
- route.options.onError?.(e);
1121
- } catch (onErrorError) {
1122
- error = onErrorError;
1123
- this.handleRedirectAndNotFound(
1124
- innerLoadContext,
1125
- this.getMatch(matchId),
1126
- onErrorError
1127
- );
1128
- }
1129
- const headResult = this.executeHead(innerLoadContext, matchId, route);
1130
- const head = headResult ? await headResult : void 0;
1131
- innerLoadContext.updateMatch(matchId, (prev) => ({
1132
- ...prev,
1133
- error,
1134
- status: "error",
1135
- isFetching: false,
1136
- ...head
1137
- }));
1138
- }
1139
- } catch (err) {
1140
- const match = this.getMatch(matchId);
1141
- if (match) {
1142
- const headResult = this.executeHead(innerLoadContext, matchId, route);
1143
- if (headResult) {
1144
- const head = await headResult;
1145
- innerLoadContext.updateMatch(matchId, (prev) => ({
1146
- ...prev,
1147
- ...head
1148
- }));
1149
- }
1150
- match._nonReactive.loaderPromise = void 0;
1151
- }
1152
- this.handleRedirectAndNotFound(innerLoadContext, match, err);
1153
- }
1154
- };
1155
- this.loadRouteMatch = async (innerLoadContext, index) => {
1156
- const { id: matchId, routeId } = innerLoadContext.matches[index];
1157
- let loaderShouldRunAsync = false;
1158
- let loaderIsRunningAsync = false;
1159
- const route = this.looseRoutesById[routeId];
1160
- const prevMatch = this.getMatch(matchId);
1161
- if (this.shouldSkipLoader(matchId)) {
1162
- if (this.isServer) {
1163
- const headResult = this.executeHead(innerLoadContext, matchId, route);
1164
- if (headResult) {
1165
- const head = await headResult;
1166
- innerLoadContext.updateMatch(matchId, (prev) => ({
1167
- ...prev,
1168
- ...head
1169
- }));
1170
- }
1171
- return this.getMatch(matchId);
1172
- }
1173
- } else if (prevMatch._nonReactive.loaderPromise) {
1174
- if (prevMatch.status === "success" && !innerLoadContext.sync && !prevMatch.preload) {
1175
- return this.getMatch(matchId);
1176
- }
1177
- await prevMatch._nonReactive.loaderPromise;
1178
- const match2 = this.getMatch(matchId);
1179
- if (match2.error) {
1180
- this.handleRedirectAndNotFound(innerLoadContext, match2, match2.error);
1181
- }
1182
- } else {
1183
- const age = Date.now() - this.getMatch(matchId).updatedAt;
1184
- const preload = this.resolvePreload(innerLoadContext, matchId);
1185
- const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
1186
- const shouldReloadOption = route.options.shouldReload;
1187
- const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(
1188
- this.getLoaderContext(innerLoadContext, matchId, index, route)
1189
- ) : shouldReloadOption;
1190
- const nextPreload = !!preload && !this.state.matches.some((d) => d.id === matchId);
1191
- const match2 = this.getMatch(matchId);
1192
- match2._nonReactive.loaderPromise = utils.createControlledPromise();
1193
- if (nextPreload !== match2.preload) {
1194
- innerLoadContext.updateMatch(matchId, (prev) => ({
1195
- ...prev,
1196
- preload: nextPreload
1197
- }));
1198
- }
1199
- const { status, invalid } = this.getMatch(matchId);
1200
- loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
1201
- if (preload && route.options.preload === false) ;
1202
- else if (loaderShouldRunAsync && !innerLoadContext.sync) {
1203
- loaderIsRunningAsync = true;
1204
- (async () => {
1205
- try {
1206
- await this.runLoader(innerLoadContext, matchId, index, route);
1207
- const match3 = this.getMatch(matchId);
1208
- match3._nonReactive.loaderPromise?.resolve();
1209
- match3._nonReactive.loadPromise?.resolve();
1210
- match3._nonReactive.loaderPromise = void 0;
1211
- } catch (err) {
1212
- if (redirect.isRedirect(err)) {
1213
- await this.navigate(err.options);
1214
- }
1215
- }
1216
- })();
1217
- } else if (status !== "success" || loaderShouldRunAsync && innerLoadContext.sync) {
1218
- await this.runLoader(innerLoadContext, matchId, index, route);
1219
- } else {
1220
- const headResult = this.executeHead(innerLoadContext, matchId, route);
1221
- if (headResult) {
1222
- const head = await headResult;
1223
- innerLoadContext.updateMatch(matchId, (prev) => ({
1224
- ...prev,
1225
- ...head
1226
- }));
1227
- }
1228
- }
1229
- }
1230
- const match = this.getMatch(matchId);
1231
- if (!loaderIsRunningAsync) {
1232
- match._nonReactive.loaderPromise?.resolve();
1233
- match._nonReactive.loadPromise?.resolve();
1234
- }
1235
- clearTimeout(match._nonReactive.pendingTimeout);
1236
- match._nonReactive.pendingTimeout = void 0;
1237
- if (!loaderIsRunningAsync) match._nonReactive.loaderPromise = void 0;
1238
- match._nonReactive.dehydrated = void 0;
1239
- const nextIsFetching = loaderIsRunningAsync ? match.isFetching : false;
1240
- if (nextIsFetching !== match.isFetching || match.invalid !== false) {
1241
- innerLoadContext.updateMatch(matchId, (prev) => ({
1242
- ...prev,
1243
- isFetching: nextIsFetching,
1244
- invalid: false
1245
- }));
1246
- }
1247
- return this.getMatch(matchId);
1248
- };
1249
- this.loadMatches = async (baseContext) => {
1250
- const innerLoadContext = baseContext;
1251
- innerLoadContext.updateMatch ??= this.updateMatch;
1252
- innerLoadContext.matchPromises = [];
1253
- if (!this.isServer && this.state.matches.some((d) => d._forcePending)) {
1254
- this.triggerOnReady(innerLoadContext);
1255
- }
1256
- try {
1257
- for (let i = 0; i < innerLoadContext.matches.length; i++) {
1258
- const beforeLoad = this.handleBeforeLoad(innerLoadContext, i);
1259
- if (utils.isPromise(beforeLoad)) await beforeLoad;
1260
- }
1261
- const max = innerLoadContext.firstBadMatchIndex ?? innerLoadContext.matches.length;
1262
- for (let i = 0; i < max; i++) {
1263
- innerLoadContext.matchPromises.push(
1264
- this.loadRouteMatch(innerLoadContext, i)
1265
- );
1266
- }
1267
- await Promise.all(innerLoadContext.matchPromises);
1268
- const readyPromise = this.triggerOnReady(innerLoadContext);
1269
- if (utils.isPromise(readyPromise)) await readyPromise;
1270
- } catch (err) {
1271
- if (notFound.isNotFound(err) && !innerLoadContext.preload) {
1272
- const readyPromise = this.triggerOnReady(innerLoadContext);
1273
- if (utils.isPromise(readyPromise)) await readyPromise;
1274
- throw err;
1275
- }
1276
- if (redirect.isRedirect(err)) {
1277
- throw err;
1278
- }
1279
- }
1280
- return innerLoadContext.matches;
1281
- };
1282
717
  this.invalidate = (opts) => {
1283
718
  const invalidate = (d) => {
1284
719
  if (opts?.filter?.(d) ?? true) {
@@ -1343,39 +778,7 @@ class RouterCore {
1343
778
  };
1344
779
  this.clearCache({ filter });
1345
780
  };
1346
- this.loadRouteChunk = (route) => {
1347
- if (!route._lazyLoaded && route._lazyPromise === void 0) {
1348
- if (route.lazyFn) {
1349
- route._lazyPromise = route.lazyFn().then((lazyRoute) => {
1350
- const { id: _id, ...options2 } = lazyRoute.options;
1351
- Object.assign(route.options, options2);
1352
- route._lazyLoaded = true;
1353
- route._lazyPromise = void 0;
1354
- });
1355
- } else {
1356
- route._lazyLoaded = true;
1357
- }
1358
- }
1359
- if (!route._componentsLoaded && route._componentsPromise === void 0) {
1360
- const loadComponents = () => {
1361
- const preloads = [];
1362
- for (const type of componentTypes) {
1363
- const preload = route.options[type]?.preload;
1364
- if (preload) preloads.push(preload());
1365
- }
1366
- if (preloads.length)
1367
- return Promise.all(preloads).then(() => {
1368
- route._componentsLoaded = true;
1369
- route._componentsPromise = void 0;
1370
- });
1371
- route._componentsLoaded = true;
1372
- route._componentsPromise = void 0;
1373
- return;
1374
- };
1375
- route._componentsPromise = route._lazyPromise ? route._lazyPromise.then(loadComponents) : loadComponents();
1376
- }
1377
- return route._componentsPromise;
1378
- };
781
+ this.loadRouteChunk = loadMatches.loadRouteChunk;
1379
782
  this.preloadRoute = async (opts) => {
1380
783
  const next = this.buildLocation(opts);
1381
784
  let matches = this.matchRoutes(next, {
@@ -1403,7 +806,8 @@ class RouterCore {
1403
806
  });
1404
807
  });
1405
808
  try {
1406
- matches = await this.loadMatches({
809
+ matches = await loadMatches.loadMatches({
810
+ router: this,
1407
811
  matches,
1408
812
  location: next,
1409
813
  preload: true,
@@ -1449,7 +853,6 @@ class RouterCore {
1449
853
  const pending = opts?.pending === void 0 ? !this.state.isLoading : opts.pending;
1450
854
  const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location;
1451
855
  const match = path.matchPathname(
1452
- this.basepath,
1453
856
  baseLocation.pathname,
1454
857
  {
1455
858
  ...opts,
@@ -1470,35 +873,6 @@ class RouterCore {
1470
873
  }
1471
874
  return match;
1472
875
  };
1473
- this._handleNotFound = (innerLoadContext, err) => {
1474
- const routeCursor = this.routesById[err.routeId ?? ""] ?? this.routeTree;
1475
- const matchesByRouteId = {};
1476
- for (const match of innerLoadContext.matches) {
1477
- matchesByRouteId[match.routeId] = match;
1478
- }
1479
- if (!routeCursor.options.notFoundComponent && this.options?.defaultNotFoundComponent) {
1480
- routeCursor.options.notFoundComponent = this.options.defaultNotFoundComponent;
1481
- }
1482
- invariant(
1483
- routeCursor.options.notFoundComponent,
1484
- "No notFoundComponent found. Please set a notFoundComponent on your route or provide a defaultNotFoundComponent to the router."
1485
- );
1486
- const matchForRoute = matchesByRouteId[routeCursor.id];
1487
- invariant(
1488
- matchForRoute,
1489
- "Could not find match for route: " + routeCursor.id
1490
- );
1491
- innerLoadContext.updateMatch(matchForRoute.id, (prev) => ({
1492
- ...prev,
1493
- status: "notFound",
1494
- error: err,
1495
- isFetching: false
1496
- }));
1497
- if (err.routerCode === "BEFORE_LOAD" && routeCursor.parentRoute) {
1498
- err.routeId = routeCursor.parentRoute.id;
1499
- this._handleNotFound(innerLoadContext, err);
1500
- }
1501
- };
1502
876
  this.hasNotFoundMatch = () => {
1503
877
  return this.__store.state.matches.some(
1504
878
  (d) => d.status === "notFound" || d.globalNotFound
@@ -1564,25 +938,6 @@ class RouterCore {
1564
938
  }
1565
939
  return root.rootRouteId;
1566
940
  })();
1567
- const parseErrors = matchedRoutes.map((route) => {
1568
- let parsedParamsError;
1569
- const parseParams = route.options.params?.parse ?? route.options.parseParams;
1570
- if (parseParams) {
1571
- try {
1572
- const parsedParams = parseParams(routeParams);
1573
- Object.assign(routeParams, parsedParams);
1574
- } catch (err) {
1575
- parsedParamsError = new PathParamError(err.message, {
1576
- cause: err
1577
- });
1578
- if (opts?.throwOnError) {
1579
- throw parsedParamsError;
1580
- }
1581
- return parsedParamsError;
1582
- }
1583
- }
1584
- return;
1585
- });
1586
941
  const matches = [];
1587
942
  const getParentContext = (parentMatch) => {
1588
943
  const parentMatchId = parentMatch?.id;
@@ -1621,22 +976,44 @@ class RouterCore {
1621
976
  search: preMatchSearch
1622
977
  }) ?? "";
1623
978
  const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
1624
- const { usedParams, interpolatedPath } = path.interpolatePath({
979
+ const { interpolatedPath } = path.interpolatePath({
1625
980
  path: route.fullPath,
1626
981
  params: routeParams,
1627
982
  decodeCharMap: this.pathParamsDecodeCharMap
1628
983
  });
1629
- const matchId = path.interpolatePath({
984
+ const interpolatePathResult = path.interpolatePath({
1630
985
  path: route.id,
1631
986
  params: routeParams,
1632
987
  leaveWildcards: true,
1633
988
  decodeCharMap: this.pathParamsDecodeCharMap,
1634
989
  parseCache: this.parsePathnameCache
1635
- }).interpolatedPath + loaderDepsHash;
990
+ });
991
+ const matchId = interpolatePathResult.interpolatedPath + loaderDepsHash;
1636
992
  const existingMatch = this.getMatch(matchId);
1637
993
  const previousMatch = this.state.matches.find(
1638
994
  (d) => d.routeId === route.id
1639
995
  );
996
+ const strictParams = existingMatch?._strictParams ?? interpolatePathResult.usedParams;
997
+ let paramsError = void 0;
998
+ if (!existingMatch) {
999
+ const strictParseParams = route.options.params?.parse ?? route.options.parseParams;
1000
+ if (strictParseParams) {
1001
+ try {
1002
+ Object.assign(
1003
+ strictParams,
1004
+ strictParseParams(strictParams)
1005
+ );
1006
+ } catch (err) {
1007
+ paramsError = new PathParamError(err.message, {
1008
+ cause: err
1009
+ });
1010
+ if (opts?.throwOnError) {
1011
+ throw paramsError;
1012
+ }
1013
+ }
1014
+ }
1015
+ }
1016
+ Object.assign(routeParams, strictParams);
1640
1017
  const cause = previousMatch ? "stay" : "enter";
1641
1018
  let match;
1642
1019
  if (existingMatch) {
@@ -1644,19 +1021,19 @@ class RouterCore {
1644
1021
  ...existingMatch,
1645
1022
  cause,
1646
1023
  params: previousMatch ? utils.replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
1647
- _strictParams: usedParams,
1024
+ _strictParams: strictParams,
1648
1025
  search: previousMatch ? utils.replaceEqualDeep(previousMatch.search, preMatchSearch) : utils.replaceEqualDeep(existingMatch.search, preMatchSearch),
1649
1026
  _strictSearch: strictMatchSearch
1650
1027
  };
1651
1028
  } else {
1652
- const status = route.options.loader || route.options.beforeLoad || route.lazyFn || routeNeedsPreload(route) ? "pending" : "success";
1029
+ const status = route.options.loader || route.options.beforeLoad || route.lazyFn || loadMatches.routeNeedsPreload(route) ? "pending" : "success";
1653
1030
  match = {
1654
1031
  id: matchId,
1655
1032
  index,
1656
1033
  routeId: route.id,
1657
1034
  params: previousMatch ? utils.replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
1658
- _strictParams: usedParams,
1659
- pathname: path.joinPaths([this.basepath, interpolatedPath]),
1035
+ _strictParams: strictParams,
1036
+ pathname: interpolatedPath,
1660
1037
  updatedAt: Date.now(),
1661
1038
  search: previousMatch ? utils.replaceEqualDeep(previousMatch.search, preMatchSearch) : preMatchSearch,
1662
1039
  _strictSearch: strictMatchSearch,
@@ -1664,7 +1041,7 @@ class RouterCore {
1664
1041
  status,
1665
1042
  isFetching: false,
1666
1043
  error: void 0,
1667
- paramsError: parseErrors[index],
1044
+ paramsError,
1668
1045
  __routeContext: void 0,
1669
1046
  _nonReactive: {
1670
1047
  loadPromise: utils.createControlledPromise()
@@ -1732,12 +1109,6 @@ class SearchParamError extends Error {
1732
1109
  }
1733
1110
  class PathParamError extends Error {
1734
1111
  }
1735
- function makeMaybe(value, error) {
1736
- if (error) {
1737
- return { status: "error", error };
1738
- }
1739
- return { status: "success", value };
1740
- }
1741
1112
  const normalize = (str) => str.endsWith("/") && str.length > 1 ? str.slice(0, -1) : str;
1742
1113
  function comparePaths(a, b) {
1743
1114
  return normalize(a) === normalize(b);
@@ -1782,20 +1153,6 @@ function validateSearch(validateSearch2, input) {
1782
1153
  }
1783
1154
  return {};
1784
1155
  }
1785
- const componentTypes = [
1786
- "component",
1787
- "errorComponent",
1788
- "pendingComponent",
1789
- "notFoundComponent"
1790
- ];
1791
- function routeNeedsPreload(route) {
1792
- for (const componentType of componentTypes) {
1793
- if (route.options[componentType]?.preload) {
1794
- return true;
1795
- }
1796
- }
1797
- return false;
1798
- }
1799
1156
  const REQUIRED_PARAM_BASE_SCORE = 0.5;
1800
1157
  const OPTIONAL_PARAM_BASE_SCORE = 0.4;
1801
1158
  const WILDCARD_PARAM_BASE_SCORE = 0.25;
@@ -1928,7 +1285,6 @@ function processRouteTree({
1928
1285
  function getMatchedRoutes({
1929
1286
  pathname,
1930
1287
  routePathname,
1931
- basepath,
1932
1288
  caseSensitive,
1933
1289
  routesByPath,
1934
1290
  routesById,
@@ -1939,7 +1295,6 @@ function getMatchedRoutes({
1939
1295
  const trimmedPath = path.trimPathRight(pathname);
1940
1296
  const getMatchedParams = (route) => {
1941
1297
  const result = path.matchPathname(
1942
- basepath,
1943
1298
  trimmedPath,
1944
1299
  {
1945
1300
  to: route.fullPath,
@@ -2064,7 +1419,6 @@ function applySearchMiddleware({
2064
1419
  exports.PathParamError = PathParamError;
2065
1420
  exports.RouterCore = RouterCore;
2066
1421
  exports.SearchParamError = SearchParamError;
2067
- exports.componentTypes = componentTypes;
2068
1422
  exports.defaultSerializeError = defaultSerializeError;
2069
1423
  exports.getInitialRouterState = getInitialRouterState;
2070
1424
  exports.getLocationChangeInfo = getLocationChangeInfo;