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