@tanstack/router-core 1.142.13 → 1.143.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
- "version": "1.142.13",
3
+ "version": "1.143.4",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
package/src/link.ts CHANGED
@@ -353,6 +353,8 @@ export interface NavigateOptionProps {
353
353
  * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/NavigateOptionsType#href)
354
354
  */
355
355
  href?: string
356
+ /** @internal */
357
+ publicHref?: string
356
358
  }
357
359
 
358
360
  export type ToOptions<
package/src/router.ts CHANGED
@@ -1177,6 +1177,7 @@ export class RouterCore<
1177
1177
  // Before we do any processing, we need to allow rewrites to modify the URL
1178
1178
  // build up the full URL by combining the href from history with the router's origin
1179
1179
  const fullUrl = new URL(href, this.origin)
1180
+
1180
1181
  const url = executeRewriteInput(this.rewrite, fullUrl)
1181
1182
 
1182
1183
  const parsedSearch = this.options.parseSearch(url.search)
@@ -1187,11 +1188,33 @@ export class RouterCore<
1187
1188
 
1188
1189
  const fullPath = url.href.replace(url.origin, '')
1189
1190
 
1191
+ // Save the internal pathname for route matching (before output rewrite)
1192
+ const internalPathname = url.pathname
1193
+
1194
+ // Compute publicHref by applying the output rewrite.
1195
+ //
1196
+ // The publicHref represents the URL as it should appear in the browser.
1197
+ // This must match what buildLocation computes for the same logical route,
1198
+ // otherwise the server-side redirect check will see a mismatch and trigger
1199
+ // an infinite redirect loop.
1200
+ //
1201
+ // We always apply the output rewrite (not conditionally) because the
1202
+ // incoming URL may have already been transformed by external middleware
1203
+ // before reaching the router. In that case, the input rewrite has nothing
1204
+ // to do, but we still need the output rewrite to reconstruct the correct
1205
+ // public-facing URL.
1206
+ //
1207
+ // Clone the URL to avoid mutating the one used for route matching.
1208
+ const urlForOutput = new URL(url.href)
1209
+ const rewrittenUrl = executeRewriteOutput(this.rewrite, urlForOutput)
1210
+ const publicHref =
1211
+ rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash
1212
+
1190
1213
  return {
1191
1214
  href: fullPath,
1192
- publicHref: href,
1215
+ publicHref,
1193
1216
  url: url,
1194
- pathname: decodePath(url.pathname),
1217
+ pathname: decodePath(internalPathname),
1195
1218
  searchStr,
1196
1219
  search: replaceEqualDeep(previousLocation?.search, parsedSearch) as any,
1197
1220
  hash: url.hash.split('#').reverse()[0] ?? '',
@@ -2006,20 +2029,35 @@ export class RouterCore<
2006
2029
  *
2007
2030
  * @link https://tanstack.com/router/latest/docs/framework/react/api/router/NavigateOptionsType
2008
2031
  */
2009
- navigate: NavigateFn = async ({ to, reloadDocument, href, ...rest }) => {
2010
- if (!reloadDocument && href) {
2032
+ navigate: NavigateFn = async ({
2033
+ to,
2034
+ reloadDocument,
2035
+ href,
2036
+ publicHref,
2037
+ ...rest
2038
+ }) => {
2039
+ let hrefIsUrl = false
2040
+
2041
+ if (href) {
2011
2042
  try {
2012
2043
  new URL(`${href}`)
2013
- reloadDocument = true
2044
+ hrefIsUrl = true
2014
2045
  } catch {}
2015
2046
  }
2016
2047
 
2048
+ if (hrefIsUrl && !reloadDocument) {
2049
+ reloadDocument = true
2050
+ }
2051
+
2017
2052
  if (reloadDocument) {
2018
- if (!href) {
2053
+ if (!href || (!publicHref && !hrefIsUrl)) {
2019
2054
  const location = this.buildLocation({ to, ...rest } as any)
2020
- href = location.url.href
2055
+ href = href ?? location.url.href
2056
+ publicHref = publicHref ?? location.url.href
2021
2057
  }
2022
2058
 
2059
+ const reloadHref = !hrefIsUrl && publicHref ? publicHref : href
2060
+
2023
2061
  // Check blockers for external URLs unless ignoreBlocker is true
2024
2062
  if (!rest.ignoreBlocker) {
2025
2063
  // Cast to access internal getBlockers method
@@ -2040,9 +2078,9 @@ export class RouterCore<
2040
2078
  }
2041
2079
 
2042
2080
  if (rest.replace) {
2043
- window.location.replace(href)
2081
+ window.location.replace(reloadHref)
2044
2082
  } else {
2045
- window.location.href = href
2083
+ window.location.href = reloadHref
2046
2084
  }
2047
2085
  return Promise.resolve()
2048
2086
  }