@tanstack/router-core 1.171.24 → 1.171.25
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/load-client.cjs +299 -389
- package/dist/cjs/load-client.cjs.map +1 -1
- package/dist/cjs/load-client.d.cts +18 -18
- package/dist/cjs/load-server.cjs +45 -32
- package/dist/cjs/load-server.cjs.map +1 -1
- package/dist/cjs/redirect.cjs +1 -1
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/redirect.d.cts +1 -1
- package/dist/cjs/router.cjs +17 -17
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +3 -5
- package/dist/esm/load-client.d.ts +18 -18
- package/dist/esm/load-client.js +299 -389
- package/dist/esm/load-client.js.map +1 -1
- package/dist/esm/load-server.js +45 -32
- package/dist/esm/load-server.js.map +1 -1
- package/dist/esm/redirect.d.ts +1 -1
- package/dist/esm/redirect.js +1 -1
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/router.d.ts +3 -5
- package/dist/esm/router.js +17 -17
- package/dist/esm/router.js.map +1 -1
- package/package.json +8 -2
- package/src/load-client.ts +535 -659
- package/src/load-server.ts +97 -35
- package/src/redirect.ts +2 -18
- package/src/router.ts +22 -42
package/src/load-server.ts
CHANGED
|
@@ -82,17 +82,51 @@ function normalize(value: unknown, rejected: boolean): LoaderOutcome {
|
|
|
82
82
|
return rejected ? [ERROR, value] : [SUCCESS, value]
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function normalizeError(
|
|
85
|
+
function normalizeError(
|
|
86
|
+
router: AnyRouter,
|
|
87
|
+
lane: { location: ParsedLocation },
|
|
88
|
+
route: AnyRoute,
|
|
89
|
+
cause: unknown,
|
|
90
|
+
signal?: AbortSignal,
|
|
91
|
+
notify = true,
|
|
92
|
+
): LoaderOutcome {
|
|
93
|
+
signal?.throwIfAborted()
|
|
86
94
|
let outcome = normalize(cause, true)
|
|
87
95
|
if (outcome[0] !== ERROR) {
|
|
88
|
-
return outcome
|
|
96
|
+
return materializeRedirect(router, lane, route, outcome, signal, notify)
|
|
89
97
|
}
|
|
90
98
|
try {
|
|
91
99
|
route.options.onError?.(outcome[1])
|
|
92
100
|
} catch (onErrorCause) {
|
|
93
101
|
outcome = normalize(onErrorCause, true)
|
|
94
102
|
}
|
|
95
|
-
|
|
103
|
+
signal?.throwIfAborted()
|
|
104
|
+
return materializeRedirect(router, lane, route, outcome, signal, notify)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function materializeRedirect(
|
|
108
|
+
router: AnyRouter,
|
|
109
|
+
lane: { location: ParsedLocation },
|
|
110
|
+
route: AnyRoute,
|
|
111
|
+
outcome: LoaderOutcome,
|
|
112
|
+
signal?: AbortSignal,
|
|
113
|
+
notify = true,
|
|
114
|
+
): LoaderOutcome {
|
|
115
|
+
if (outcome[0] !== REDIRECTED) {
|
|
116
|
+
return outcome
|
|
117
|
+
}
|
|
118
|
+
signal?.throwIfAborted()
|
|
119
|
+
try {
|
|
120
|
+
outcome[1].options._fromLocation = lane.location
|
|
121
|
+
router.resolveRedirect(outcome[1])
|
|
122
|
+
signal?.throwIfAborted()
|
|
123
|
+
return outcome
|
|
124
|
+
} catch (cause) {
|
|
125
|
+
signal?.throwIfAborted()
|
|
126
|
+
return notify
|
|
127
|
+
? normalizeError(router, lane, route, cause, signal, false)
|
|
128
|
+
: [ERROR, cause]
|
|
129
|
+
}
|
|
96
130
|
}
|
|
97
131
|
|
|
98
132
|
function maybe<TValue>(
|
|
@@ -197,7 +231,13 @@ async function contextualize(
|
|
|
197
231
|
match.ssr = await resolveSsr(router, lane, index)
|
|
198
232
|
} catch (cause) {
|
|
199
233
|
signal?.throwIfAborted()
|
|
200
|
-
failure = [
|
|
234
|
+
failure = [
|
|
235
|
+
index,
|
|
236
|
+
stampNotFound(
|
|
237
|
+
match,
|
|
238
|
+
normalizeError(router, lane, route, cause, signal),
|
|
239
|
+
),
|
|
240
|
+
]
|
|
201
241
|
end = index
|
|
202
242
|
}
|
|
203
243
|
signal?.throwIfAborted()
|
|
@@ -239,7 +279,13 @@ async function contextualize(
|
|
|
239
279
|
} catch (cause) {
|
|
240
280
|
signal?.throwIfAborted()
|
|
241
281
|
if (!failure) {
|
|
242
|
-
failure = [
|
|
282
|
+
failure = [
|
|
283
|
+
index,
|
|
284
|
+
stampNotFound(
|
|
285
|
+
match,
|
|
286
|
+
normalizeError(router, lane, route, cause, signal),
|
|
287
|
+
),
|
|
288
|
+
]
|
|
243
289
|
}
|
|
244
290
|
end = index
|
|
245
291
|
break
|
|
@@ -252,7 +298,10 @@ async function contextualize(
|
|
|
252
298
|
if (validationError !== undefined) {
|
|
253
299
|
failure = [
|
|
254
300
|
index,
|
|
255
|
-
stampNotFound(
|
|
301
|
+
stampNotFound(
|
|
302
|
+
match,
|
|
303
|
+
normalizeError(router, lane, route, validationError, signal),
|
|
304
|
+
),
|
|
256
305
|
]
|
|
257
306
|
end = index
|
|
258
307
|
break
|
|
@@ -293,7 +342,16 @@ async function contextualize(
|
|
|
293
342
|
try {
|
|
294
343
|
const beforeLoadContext = await route.options.beforeLoad(options)
|
|
295
344
|
signal?.throwIfAborted()
|
|
296
|
-
const outcome = stampNotFound(
|
|
345
|
+
const outcome = stampNotFound(
|
|
346
|
+
match,
|
|
347
|
+
materializeRedirect(
|
|
348
|
+
router,
|
|
349
|
+
lane,
|
|
350
|
+
route,
|
|
351
|
+
normalize(beforeLoadContext, false),
|
|
352
|
+
signal,
|
|
353
|
+
),
|
|
354
|
+
)
|
|
297
355
|
if (outcome[0] !== SUCCESS) {
|
|
298
356
|
failure = [index, outcome]
|
|
299
357
|
end = index
|
|
@@ -307,7 +365,13 @@ async function contextualize(
|
|
|
307
365
|
parentContext = match.context
|
|
308
366
|
} catch (cause) {
|
|
309
367
|
signal?.throwIfAborted()
|
|
310
|
-
failure = [
|
|
368
|
+
failure = [
|
|
369
|
+
index,
|
|
370
|
+
stampNotFound(
|
|
371
|
+
match,
|
|
372
|
+
normalizeError(router, lane, route, cause, signal),
|
|
373
|
+
),
|
|
374
|
+
]
|
|
311
375
|
end = index
|
|
312
376
|
break
|
|
313
377
|
}
|
|
@@ -373,14 +437,13 @@ function createLoaderTask(
|
|
|
373
437
|
(cause) => normalize(cause, true),
|
|
374
438
|
)
|
|
375
439
|
.then((result): LoaderOutcome => {
|
|
376
|
-
if (
|
|
377
|
-
result[0] !== REDIRECTED &&
|
|
378
|
-
(signal?.aborted || match.abortController.signal.reason === lane)
|
|
379
|
-
) {
|
|
440
|
+
if (signal?.aborted || match.abortController.signal.reason === lane) {
|
|
380
441
|
return [SKIPPED]
|
|
381
442
|
}
|
|
382
443
|
if (result[0] === ERROR) {
|
|
383
|
-
result = normalizeError(route, result[1])
|
|
444
|
+
result = normalizeError(router, lane, route, result[1], signal)
|
|
445
|
+
} else {
|
|
446
|
+
result = materializeRedirect(router, lane, route, result, signal)
|
|
384
447
|
}
|
|
385
448
|
return stampNotFound(match, result)
|
|
386
449
|
})
|
|
@@ -424,13 +487,13 @@ async function getNotFoundBoundary(
|
|
|
424
487
|
}
|
|
425
488
|
for (let candidate = index; candidate >= 0; candidate--) {
|
|
426
489
|
const route = getRoute(router, matches[candidate]!)
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
490
|
+
try {
|
|
491
|
+
const loading = loadRouteChunk(route, false)
|
|
492
|
+
if (loading) {
|
|
430
493
|
await loading
|
|
431
|
-
} catch {
|
|
432
|
-
signal?.throwIfAborted()
|
|
433
494
|
}
|
|
495
|
+
} catch {
|
|
496
|
+
signal?.throwIfAborted()
|
|
434
497
|
}
|
|
435
498
|
signal?.throwIfAborted()
|
|
436
499
|
if (route.options.notFoundComponent) {
|
|
@@ -450,15 +513,6 @@ function abortMatches(
|
|
|
450
513
|
}
|
|
451
514
|
}
|
|
452
515
|
|
|
453
|
-
function resolveServerRedirect(
|
|
454
|
-
router: AnyRouter,
|
|
455
|
-
location: ParsedLocation,
|
|
456
|
-
value: AnyRedirect,
|
|
457
|
-
): ServerLoadResult {
|
|
458
|
-
value.options._fromLocation = location
|
|
459
|
-
return { type: 'redirect', redirect: router.resolveRedirect(value) }
|
|
460
|
-
}
|
|
461
|
-
|
|
462
516
|
async function applyFailure(
|
|
463
517
|
router: AnyRouter,
|
|
464
518
|
lane: ContextualizedLane,
|
|
@@ -530,7 +584,10 @@ async function loadNormalChunks(
|
|
|
530
584
|
signal?.throwIfAborted()
|
|
531
585
|
return [
|
|
532
586
|
index,
|
|
533
|
-
stampNotFound(
|
|
587
|
+
stampNotFound(
|
|
588
|
+
match,
|
|
589
|
+
normalizeError(router, lane, route, cause, signal),
|
|
590
|
+
),
|
|
534
591
|
] as IndexedOutcome
|
|
535
592
|
},
|
|
536
593
|
)
|
|
@@ -540,7 +597,13 @@ async function loadNormalChunks(
|
|
|
540
597
|
}
|
|
541
598
|
} catch (cause) {
|
|
542
599
|
signal?.throwIfAborted()
|
|
543
|
-
chunks.push([
|
|
600
|
+
chunks.push([
|
|
601
|
+
index,
|
|
602
|
+
stampNotFound(
|
|
603
|
+
match,
|
|
604
|
+
normalizeError(router, lane, route, cause, signal),
|
|
605
|
+
),
|
|
606
|
+
])
|
|
544
607
|
}
|
|
545
608
|
}
|
|
546
609
|
for (const chunk of chunks) {
|
|
@@ -698,7 +761,7 @@ async function executeServerLane(
|
|
|
698
761
|
|
|
699
762
|
if (control?.[1][0] === REDIRECTED) {
|
|
700
763
|
abortMatches(lane.matches, 0, lane)
|
|
701
|
-
return
|
|
764
|
+
return { type: 'redirect', redirect: control[1][1] }
|
|
702
765
|
}
|
|
703
766
|
|
|
704
767
|
let failure = lane.failure ?? loaderFailure
|
|
@@ -742,7 +805,7 @@ async function executeServerLane(
|
|
|
742
805
|
if (requiredFailure) {
|
|
743
806
|
if (requiredFailure[1][0] === REDIRECTED) {
|
|
744
807
|
abortMatches(lane.matches)
|
|
745
|
-
return
|
|
808
|
+
return { type: 'redirect', redirect: requiredFailure[1][1] }
|
|
746
809
|
}
|
|
747
810
|
failure = requiredFailure
|
|
748
811
|
}
|
|
@@ -808,9 +871,7 @@ export async function loadServerRoute(
|
|
|
808
871
|
})
|
|
809
872
|
if (next.publicHref !== canonical.publicHref) {
|
|
810
873
|
const href = canonical.publicHref || '/'
|
|
811
|
-
throw
|
|
812
|
-
? redirect({ href })
|
|
813
|
-
: redirect({ href, _builtLocation: canonical })
|
|
874
|
+
throw redirect({ href })
|
|
814
875
|
}
|
|
815
876
|
|
|
816
877
|
const fromLocation = router.stores.resolvedLocation.get()
|
|
@@ -828,7 +889,8 @@ export async function loadServerRoute(
|
|
|
828
889
|
if (!isRedirect(cause)) {
|
|
829
890
|
throw cause
|
|
830
891
|
}
|
|
831
|
-
|
|
892
|
+
cause.options._fromLocation = next
|
|
893
|
+
result = { type: 'redirect', redirect: router.resolveRedirect(cause) }
|
|
832
894
|
}
|
|
833
895
|
|
|
834
896
|
router._serverResult = result
|
package/src/redirect.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { NavigateOptions } from './link'
|
|
2
2
|
import type { AnyRouter, RegisteredRouter } from './router'
|
|
3
|
-
import type { ParsedLocation } from './location'
|
|
4
3
|
|
|
5
4
|
export type AnyRedirect = Redirect<any, any, any, any, any>
|
|
6
5
|
|
|
@@ -14,13 +13,7 @@ export type Redirect<
|
|
|
14
13
|
TMaskFrom extends string = TFrom,
|
|
15
14
|
TMaskTo extends string = '.',
|
|
16
15
|
> = Response & {
|
|
17
|
-
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
18
|
-
/**
|
|
19
|
-
* @internal
|
|
20
|
-
* A **trusted** built location that can be used to redirect to.
|
|
21
|
-
*/
|
|
22
|
-
_builtLocation?: ParsedLocation
|
|
23
|
-
}
|
|
16
|
+
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
24
17
|
}
|
|
25
18
|
|
|
26
19
|
export type RedirectOptions<
|
|
@@ -50,11 +43,6 @@ export type RedirectOptions<
|
|
|
50
43
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RedirectType#headers-property)
|
|
51
44
|
*/
|
|
52
45
|
headers?: HeadersInit
|
|
53
|
-
/**
|
|
54
|
-
* @internal
|
|
55
|
-
* A **trusted** built location that can be used to redirect to.
|
|
56
|
-
*/
|
|
57
|
-
_builtLocation?: ParsedLocation
|
|
58
46
|
} & NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
59
47
|
|
|
60
48
|
export type ResolvedRedirect<
|
|
@@ -122,11 +110,7 @@ export function redirect<
|
|
|
122
110
|
): Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> {
|
|
123
111
|
opts.statusCode = opts.statusCode || opts.code || 307
|
|
124
112
|
|
|
125
|
-
if (
|
|
126
|
-
!opts._builtLocation &&
|
|
127
|
-
!opts.reloadDocument &&
|
|
128
|
-
typeof opts.href === 'string'
|
|
129
|
-
) {
|
|
113
|
+
if (!opts.reloadDocument && typeof opts.href === 'string') {
|
|
130
114
|
try {
|
|
131
115
|
new URL(opts.href)
|
|
132
116
|
opts.reloadDocument = true
|
package/src/router.ts
CHANGED
|
@@ -692,13 +692,7 @@ export type PreloadRouteFn<
|
|
|
692
692
|
TTo,
|
|
693
693
|
TMaskFrom,
|
|
694
694
|
TMaskTo
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* @internal
|
|
698
|
-
* A **trusted** built location that can be used to redirect to.
|
|
699
|
-
*/
|
|
700
|
-
_builtLocation?: ParsedLocation
|
|
701
|
-
},
|
|
695
|
+
>,
|
|
702
696
|
) => Promise<Array<AnyRouteMatch> | undefined>
|
|
703
697
|
|
|
704
698
|
export type MatchRouteFn<
|
|
@@ -937,10 +931,10 @@ export function runRouteLifecycle(
|
|
|
937
931
|
router: AnyRouter,
|
|
938
932
|
previous: Array<AnyRouteMatch>,
|
|
939
933
|
matches: Array<AnyRouteMatch>,
|
|
940
|
-
|
|
934
|
+
owner?: LoadTransaction,
|
|
941
935
|
): void {
|
|
942
936
|
for (const match of previous) {
|
|
943
|
-
if (
|
|
937
|
+
if (owner && router._tx !== owner) {
|
|
944
938
|
return
|
|
945
939
|
}
|
|
946
940
|
if (!matches.some((candidate) => candidate.routeId === match.routeId)) {
|
|
@@ -950,7 +944,7 @@ export function runRouteLifecycle(
|
|
|
950
944
|
}
|
|
951
945
|
}
|
|
952
946
|
for (const match of matches) {
|
|
953
|
-
if (
|
|
947
|
+
if (owner && router._tx !== owner) {
|
|
954
948
|
return
|
|
955
949
|
}
|
|
956
950
|
const route = (router.routesById as Record<string, AnyRoute>)[
|
|
@@ -1846,6 +1840,19 @@ export class RouterCore<
|
|
|
1846
1840
|
unmaskOnReload?: boolean
|
|
1847
1841
|
} = {},
|
|
1848
1842
|
): ParsedLocation => {
|
|
1843
|
+
if (dest.href) {
|
|
1844
|
+
const parsed = parseHref(dest.href, {} as ParsedHistoryState)
|
|
1845
|
+
dest = {
|
|
1846
|
+
...dest,
|
|
1847
|
+
to: executeRewriteInput(
|
|
1848
|
+
this.rewrite,
|
|
1849
|
+
new URL(parsed.pathname, this.origin),
|
|
1850
|
+
).pathname,
|
|
1851
|
+
search: this.options.parseSearch(parsed.search),
|
|
1852
|
+
hash: parsed.hash.slice(1),
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1849
1856
|
// We allow the caller to override the current location
|
|
1850
1857
|
const currentLocation =
|
|
1851
1858
|
dest._fromLocation || this._pendingLocation || this.latestLocation
|
|
@@ -2216,38 +2223,12 @@ export class RouterCore<
|
|
|
2216
2223
|
hashScrollIntoView,
|
|
2217
2224
|
viewTransition,
|
|
2218
2225
|
ignoreBlocker,
|
|
2219
|
-
_redirects,
|
|
2220
|
-
href,
|
|
2221
2226
|
...rest
|
|
2222
|
-
}: BuildNextOptions &
|
|
2223
|
-
CommitLocationOptions & { _redirects?: number } = {}) => {
|
|
2224
|
-
if (href) {
|
|
2225
|
-
const currentIndex = this.history.location.state.__TSR_index
|
|
2226
|
-
|
|
2227
|
-
const parsed = parseHref(href, {
|
|
2228
|
-
__TSR_index: replace ? currentIndex : currentIndex + 1,
|
|
2229
|
-
})
|
|
2230
|
-
|
|
2231
|
-
// If the href contains the basepath, we need to strip it before setting `to`
|
|
2232
|
-
// because `buildLocation` will add the basepath back when creating the final URL.
|
|
2233
|
-
// Without this, hrefs like '/app/about' would become '/app/app/about'.
|
|
2234
|
-
const hrefUrl = new URL(parsed.pathname, this.origin)
|
|
2235
|
-
const rewrittenUrl = executeRewriteInput(this.rewrite, hrefUrl)
|
|
2236
|
-
|
|
2237
|
-
rest.to = rewrittenUrl.pathname
|
|
2238
|
-
rest.search = this.options.parseSearch(parsed.search)
|
|
2239
|
-
// remove the leading `#` from the hash
|
|
2240
|
-
rest.hash = parsed.hash.slice(1)
|
|
2241
|
-
}
|
|
2242
|
-
|
|
2227
|
+
}: BuildNextOptions & CommitLocationOptions = {}) => {
|
|
2243
2228
|
const location = this.buildLocation({
|
|
2244
2229
|
...(rest as any),
|
|
2245
2230
|
_includeValidateSearch: true,
|
|
2246
2231
|
})
|
|
2247
|
-
if (_redirects) {
|
|
2248
|
-
;(location as typeof location & { _redirects?: number })._redirects =
|
|
2249
|
-
_redirects
|
|
2250
|
-
}
|
|
2251
2232
|
|
|
2252
2233
|
this._pendingLocation = location as ParsedLocation<
|
|
2253
2234
|
FullSearchSchema<TRouteTree>
|
|
@@ -2514,9 +2495,8 @@ export class RouterCore<
|
|
|
2514
2495
|
resolveRedirect = (redirect: AnyRedirect): AnyRedirect => {
|
|
2515
2496
|
const locationHeader = redirect.headers.get('Location')
|
|
2516
2497
|
|
|
2517
|
-
if (!redirect.options.href
|
|
2518
|
-
const location =
|
|
2519
|
-
redirect.options._builtLocation ?? this.buildLocation(redirect.options)
|
|
2498
|
+
if (!redirect.options.href) {
|
|
2499
|
+
const location = this.buildLocation(redirect.options)
|
|
2520
2500
|
const href = location.publicHref || '/'
|
|
2521
2501
|
redirect.options.href = href
|
|
2522
2502
|
redirect.headers.set('Location', href)
|
|
@@ -2535,7 +2515,6 @@ export class RouterCore<
|
|
|
2535
2515
|
|
|
2536
2516
|
if (
|
|
2537
2517
|
redirect.options.href &&
|
|
2538
|
-
!redirect.options._builtLocation &&
|
|
2539
2518
|
// Check for dangerous protocols before processing the redirect
|
|
2540
2519
|
isDangerousProtocol(redirect.options.href, this.protocolAllowlist)
|
|
2541
2520
|
) {
|
|
@@ -2611,7 +2590,8 @@ export class RouterCore<
|
|
|
2611
2590
|
TTrailingSlashOption,
|
|
2612
2591
|
TDefaultStructuralSharingOption,
|
|
2613
2592
|
TRouterHistory
|
|
2614
|
-
> = (opts
|
|
2593
|
+
> = (opts: any, builtLocation?: ParsedLocation) =>
|
|
2594
|
+
preloadClientRoute(this, opts, 0, builtLocation)
|
|
2615
2595
|
|
|
2616
2596
|
matchRoute: MatchRouteFn<
|
|
2617
2597
|
TRouteTree,
|