@tanstack/router-core 1.156.0 → 1.157.1
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/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/isServer/client.cjs +5 -0
- package/dist/cjs/isServer/client.cjs.map +1 -0
- package/dist/cjs/isServer/client.d.cts +1 -0
- package/dist/cjs/isServer/development.cjs +5 -0
- package/dist/cjs/isServer/development.cjs.map +1 -0
- package/dist/cjs/isServer/development.d.cts +1 -0
- package/dist/cjs/isServer/server.cjs +5 -0
- package/dist/cjs/isServer/server.cjs.map +1 -0
- package/dist/cjs/isServer/server.d.cts +1 -0
- package/dist/cjs/isServer.d.cts +24 -0
- package/dist/cjs/load-matches.cjs +2 -1
- package/dist/cjs/load-matches.cjs.map +1 -1
- package/dist/cjs/location.d.cts +2 -3
- package/dist/cjs/router.cjs +27 -18
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/utils.cjs +5 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +9 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/isServer/client.d.ts +1 -0
- package/dist/esm/isServer/client.js +5 -0
- package/dist/esm/isServer/client.js.map +1 -0
- package/dist/esm/isServer/development.d.ts +1 -0
- package/dist/esm/isServer/development.js +5 -0
- package/dist/esm/isServer/development.js.map +1 -0
- package/dist/esm/isServer/server.d.ts +1 -0
- package/dist/esm/isServer/server.js +5 -0
- package/dist/esm/isServer/server.js.map +1 -0
- package/dist/esm/isServer.d.ts +24 -0
- package/dist/esm/load-matches.js +2 -1
- package/dist/esm/load-matches.js.map +1 -1
- package/dist/esm/location.d.ts +2 -3
- package/dist/esm/router.js +28 -19
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/utils.d.ts +9 -0
- package/dist/esm/utils.js +5 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +81 -1
- package/src/index.ts +1 -0
- package/src/isServer/client.ts +1 -0
- package/src/isServer/development.ts +2 -0
- package/src/isServer/server.ts +1 -0
- package/src/isServer.ts +24 -0
- package/src/load-matches.ts +8 -7
- package/src/location.ts +2 -3
- package/src/router.ts +58 -32
- package/src/scroll-restoration.ts +3 -2
- package/src/utils.ts +15 -0
package/src/router.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
createControlledPromise,
|
|
5
5
|
decodePath,
|
|
6
6
|
deepEqual,
|
|
7
|
+
encodeNonAscii,
|
|
7
8
|
findLast,
|
|
8
9
|
functionalUpdate,
|
|
9
10
|
isDangerousProtocol,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
trimPath,
|
|
26
27
|
trimPathRight,
|
|
27
28
|
} from './path'
|
|
29
|
+
import { isServer } from './isServer'
|
|
28
30
|
import { createLRUCache } from './lru-cache'
|
|
29
31
|
import { isNotFound } from './not-found'
|
|
30
32
|
import { setupScrollRestoration } from './scroll-restoration'
|
|
@@ -1018,7 +1020,7 @@ export class RouterCore<
|
|
|
1018
1020
|
(this.options.history && this.options.history !== this.history)
|
|
1019
1021
|
) {
|
|
1020
1022
|
if (!this.options.history) {
|
|
1021
|
-
if (!this.isServer) {
|
|
1023
|
+
if (!(isServer ?? this.isServer)) {
|
|
1022
1024
|
this.history = createBrowserHistory() as TRouterHistory
|
|
1023
1025
|
}
|
|
1024
1026
|
} else {
|
|
@@ -1028,7 +1030,11 @@ export class RouterCore<
|
|
|
1028
1030
|
|
|
1029
1031
|
this.origin = this.options.origin
|
|
1030
1032
|
if (!this.origin) {
|
|
1031
|
-
if (
|
|
1033
|
+
if (
|
|
1034
|
+
!(isServer ?? this.isServer) &&
|
|
1035
|
+
window?.origin &&
|
|
1036
|
+
window.origin !== 'null'
|
|
1037
|
+
) {
|
|
1032
1038
|
this.origin = window.origin
|
|
1033
1039
|
} else {
|
|
1034
1040
|
// fallback for the server, can be overridden by calling router.update({origin}) on the server
|
|
@@ -1044,7 +1050,7 @@ export class RouterCore<
|
|
|
1044
1050
|
this.routeTree = this.options.routeTree as TRouteTree
|
|
1045
1051
|
let processRouteTreeResult: ProcessRouteTreeResult<TRouteTree>
|
|
1046
1052
|
if (
|
|
1047
|
-
this.isServer &&
|
|
1053
|
+
(isServer ?? this.isServer) &&
|
|
1048
1054
|
globalThis.__TSR_CACHE__ &&
|
|
1049
1055
|
globalThis.__TSR_CACHE__.routeTree === this.routeTree
|
|
1050
1056
|
) {
|
|
@@ -1055,7 +1061,10 @@ export class RouterCore<
|
|
|
1055
1061
|
this.resolvePathCache = createLRUCache(1000)
|
|
1056
1062
|
processRouteTreeResult = this.buildRouteTree()
|
|
1057
1063
|
// only cache if nothing else is cached yet
|
|
1058
|
-
if (
|
|
1064
|
+
if (
|
|
1065
|
+
(isServer ?? this.isServer) &&
|
|
1066
|
+
globalThis.__TSR_CACHE__ === undefined
|
|
1067
|
+
) {
|
|
1059
1068
|
globalThis.__TSR_CACHE__ = {
|
|
1060
1069
|
routeTree: this.routeTree,
|
|
1061
1070
|
processRouteTreeResult: processRouteTreeResult as any,
|
|
@@ -1091,7 +1100,8 @@ export class RouterCore<
|
|
|
1091
1100
|
this.basepath = nextBasepath
|
|
1092
1101
|
|
|
1093
1102
|
const rewrites: Array<LocationRewrite> = []
|
|
1094
|
-
|
|
1103
|
+
const trimmed = trimPath(nextBasepath)
|
|
1104
|
+
if (trimmed && trimmed !== '/') {
|
|
1095
1105
|
rewrites.push(
|
|
1096
1106
|
rewriteBasepath({
|
|
1097
1107
|
basepath: nextBasepath,
|
|
@@ -1237,8 +1247,8 @@ export class RouterCore<
|
|
|
1237
1247
|
return {
|
|
1238
1248
|
href: fullPath,
|
|
1239
1249
|
publicHref: href,
|
|
1240
|
-
url: url,
|
|
1241
1250
|
pathname: decodePath(url.pathname),
|
|
1251
|
+
external: !!this.rewrite && url.origin !== this.origin,
|
|
1242
1252
|
searchStr,
|
|
1243
1253
|
search: replaceEqualDeep(previousLocation?.search, parsedSearch) as any,
|
|
1244
1254
|
hash: decodePath(url.hash.split('#').reverse()[0] ?? ''),
|
|
@@ -1479,7 +1489,7 @@ export class RouterCore<
|
|
|
1479
1489
|
|
|
1480
1490
|
match = {
|
|
1481
1491
|
id: matchId,
|
|
1482
|
-
ssr: this.isServer ? undefined : route.options.ssr,
|
|
1492
|
+
ssr: (isServer ?? this.isServer) ? undefined : route.options.ssr,
|
|
1483
1493
|
index,
|
|
1484
1494
|
routeId: route.id,
|
|
1485
1495
|
params: previousMatch
|
|
@@ -1878,22 +1888,43 @@ export class RouterCore<
|
|
|
1878
1888
|
// Create the full path of the location
|
|
1879
1889
|
const fullPath = `${nextPathname}${searchStr}${hashStr}`
|
|
1880
1890
|
|
|
1881
|
-
//
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1891
|
+
// Compute href and publicHref without URL construction when no rewrite
|
|
1892
|
+
let href: string
|
|
1893
|
+
let publicHref: string
|
|
1894
|
+
let external = false
|
|
1895
|
+
|
|
1896
|
+
if (this.rewrite) {
|
|
1897
|
+
// With rewrite, we need to construct URL to apply the rewrite
|
|
1898
|
+
const url = new URL(fullPath, this.origin)
|
|
1899
|
+
const rewrittenUrl = executeRewriteOutput(this.rewrite, url)
|
|
1900
|
+
href = url.href.replace(url.origin, '')
|
|
1901
|
+
// If rewrite changed the origin, publicHref needs full URL
|
|
1902
|
+
// Otherwise just use the path components
|
|
1903
|
+
if (rewrittenUrl.origin !== this.origin) {
|
|
1904
|
+
publicHref = rewrittenUrl.href
|
|
1905
|
+
external = true
|
|
1906
|
+
} else {
|
|
1907
|
+
publicHref =
|
|
1908
|
+
rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash
|
|
1909
|
+
}
|
|
1910
|
+
} else {
|
|
1911
|
+
// Fast path: no rewrite, skip URL construction entirely
|
|
1912
|
+
// fullPath is already the correct href (origin-stripped)
|
|
1913
|
+
// We need to encode non-ASCII (unicode) characters for the href
|
|
1914
|
+
// since decodePath decoded them from the interpolated path
|
|
1915
|
+
href = encodeNonAscii(fullPath)
|
|
1916
|
+
publicHref = href
|
|
1917
|
+
}
|
|
1886
1918
|
|
|
1887
1919
|
return {
|
|
1888
|
-
publicHref
|
|
1889
|
-
|
|
1890
|
-
href: fullPath,
|
|
1891
|
-
url: rewrittenUrl,
|
|
1920
|
+
publicHref,
|
|
1921
|
+
href,
|
|
1892
1922
|
pathname: nextPathname,
|
|
1893
1923
|
search: nextSearch,
|
|
1894
1924
|
searchStr,
|
|
1895
1925
|
state: nextState as any,
|
|
1896
1926
|
hash: hash ?? '',
|
|
1927
|
+
external,
|
|
1897
1928
|
unmaskOnReload: dest.unmaskOnReload,
|
|
1898
1929
|
}
|
|
1899
1930
|
}
|
|
@@ -2006,9 +2037,6 @@ export class RouterCore<
|
|
|
2006
2037
|
maskedLocation,
|
|
2007
2038
|
// eslint-disable-next-line prefer-const
|
|
2008
2039
|
hashScrollIntoView,
|
|
2009
|
-
// don't pass url into history since it is a URL instance that cannot be serialized
|
|
2010
|
-
// eslint-disable-next-line prefer-const
|
|
2011
|
-
url: _url,
|
|
2012
2040
|
...nextHistory
|
|
2013
2041
|
} = next
|
|
2014
2042
|
|
|
@@ -2154,8 +2182,9 @@ export class RouterCore<
|
|
|
2154
2182
|
// be a complete path (possibly with basepath)
|
|
2155
2183
|
if (to !== undefined || !href) {
|
|
2156
2184
|
const location = this.buildLocation({ to, ...rest } as any)
|
|
2157
|
-
|
|
2158
|
-
|
|
2185
|
+
// Use publicHref which contains the path (origin-stripped is fine for reload)
|
|
2186
|
+
href = href ?? location.publicHref
|
|
2187
|
+
publicHref = publicHref ?? location.publicHref
|
|
2159
2188
|
}
|
|
2160
2189
|
|
|
2161
2190
|
// Use publicHref when available and href is not a full URL,
|
|
@@ -2215,7 +2244,7 @@ export class RouterCore<
|
|
|
2215
2244
|
this.cancelMatches()
|
|
2216
2245
|
this.updateLatestLocation()
|
|
2217
2246
|
|
|
2218
|
-
if (this.isServer) {
|
|
2247
|
+
if (isServer ?? this.isServer) {
|
|
2219
2248
|
// for SPAs on the initial load, this is handled by the Transitioner
|
|
2220
2249
|
const nextLocation = this.buildLocation({
|
|
2221
2250
|
to: this.latestLocation.pathname,
|
|
@@ -2226,10 +2255,9 @@ export class RouterCore<
|
|
|
2226
2255
|
_includeValidateSearch: true,
|
|
2227
2256
|
})
|
|
2228
2257
|
|
|
2229
|
-
if
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
) {
|
|
2258
|
+
// Check if location changed - origin check is unnecessary since buildLocation
|
|
2259
|
+
// always uses this.origin when constructing URLs
|
|
2260
|
+
if (this.latestLocation.publicHref !== nextLocation.publicHref) {
|
|
2233
2261
|
const href = this.getParsedLocationHref(nextLocation)
|
|
2234
2262
|
|
|
2235
2263
|
throw redirect({ href })
|
|
@@ -2365,7 +2393,7 @@ export class RouterCore<
|
|
|
2365
2393
|
} catch (err) {
|
|
2366
2394
|
if (isRedirect(err)) {
|
|
2367
2395
|
redirect = err
|
|
2368
|
-
if (!this.isServer) {
|
|
2396
|
+
if (!(isServer ?? this.isServer)) {
|
|
2369
2397
|
this.navigate({
|
|
2370
2398
|
...redirect.options,
|
|
2371
2399
|
replace: true,
|
|
@@ -2553,11 +2581,9 @@ export class RouterCore<
|
|
|
2553
2581
|
}
|
|
2554
2582
|
|
|
2555
2583
|
getParsedLocationHref = (location: ParsedLocation) => {
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
}
|
|
2560
|
-
return href
|
|
2584
|
+
// For redirects and external use, we need publicHref (with rewrite output applied)
|
|
2585
|
+
// href is the internal path after rewrite input, publicHref is user-facing
|
|
2586
|
+
return location.publicHref || '/'
|
|
2561
2587
|
}
|
|
2562
2588
|
|
|
2563
2589
|
resolveRedirect = (redirect: AnyRedirect): AnyRedirect => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { functionalUpdate } from './utils'
|
|
2
|
+
import { isServer } from './isServer'
|
|
2
3
|
import type { AnyRouter } from './router'
|
|
3
4
|
import type { ParsedLocation } from './location'
|
|
4
5
|
import type { NonNullableUpdater } from './utils'
|
|
@@ -217,7 +218,7 @@ export function restoreScroll({
|
|
|
217
218
|
/** Setup global listeners and hooks to support scroll restoration. */
|
|
218
219
|
/** Setup global listeners and hooks to support scroll restoration. */
|
|
219
220
|
export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
220
|
-
if (!scrollRestorationCache && !router.isServer) {
|
|
221
|
+
if (!scrollRestorationCache && !(isServer ?? router.isServer)) {
|
|
221
222
|
return
|
|
222
223
|
}
|
|
223
224
|
const shouldScrollRestoration =
|
|
@@ -228,7 +229,7 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
if (
|
|
231
|
-
router.isServer ||
|
|
232
|
+
(isServer ?? router.isServer) ||
|
|
232
233
|
router.isScrollRestorationSetup ||
|
|
233
234
|
!scrollRestorationCache
|
|
234
235
|
) {
|
package/src/utils.ts
CHANGED
|
@@ -613,6 +613,21 @@ export function decodePath(path: string, decodeIgnore?: Array<string>): string {
|
|
|
613
613
|
return result
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
+
/**
|
|
617
|
+
* Encodes non-ASCII (unicode) characters in a path while preserving
|
|
618
|
+
* already percent-encoded sequences. This is used to generate proper
|
|
619
|
+
* href values without constructing URL objects.
|
|
620
|
+
*
|
|
621
|
+
* Unlike encodeURI, this won't double-encode percent-encoded sequences
|
|
622
|
+
* like %2F or %25 because it only targets non-ASCII characters.
|
|
623
|
+
*/
|
|
624
|
+
export function encodeNonAscii(path: string): string {
|
|
625
|
+
// eslint-disable-next-line no-control-regex
|
|
626
|
+
if (!/[^\u0000-\u007F]/.test(path)) return path
|
|
627
|
+
// eslint-disable-next-line no-control-regex
|
|
628
|
+
return path.replace(/[^\u0000-\u007F]/gu, encodeURIComponent)
|
|
629
|
+
}
|
|
630
|
+
|
|
616
631
|
/**
|
|
617
632
|
* Builds the dev-mode CSS styles URL for route-scoped CSS collection.
|
|
618
633
|
* Used by HeadContent components in all framework implementations to construct
|