@tanstack/router-core 1.171.14 → 1.171.16-pre.0
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/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +3 -12
- package/dist/cjs/await-signal.cjs +21 -0
- package/dist/cjs/await-signal.cjs.map +1 -0
- package/dist/cjs/await-signal.d.cts +1 -0
- package/dist/cjs/index.cjs +3 -1
- package/dist/cjs/index.d.cts +3 -2
- package/dist/cjs/isServer/client.cjs +2 -0
- package/dist/cjs/isServer/client.cjs.map +1 -1
- package/dist/cjs/isServer/client.d.cts +1 -0
- package/dist/cjs/isServer/development.cjs +2 -0
- package/dist/cjs/isServer/development.cjs.map +1 -1
- package/dist/cjs/isServer/development.d.cts +1 -0
- package/dist/cjs/isServer/server.cjs +2 -0
- package/dist/cjs/isServer/server.cjs.map +1 -1
- package/dist/cjs/isServer/server.d.cts +1 -0
- package/dist/cjs/load-client.cjs +1470 -0
- package/dist/cjs/load-client.cjs.map +1 -0
- package/dist/cjs/load-client.d.cts +147 -0
- package/dist/cjs/load-server.cjs +565 -0
- package/dist/cjs/load-server.cjs.map +1 -0
- package/dist/cjs/load-server.d.cts +16 -0
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/redirect.d.cts +0 -1
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/router.cjs +187 -445
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +62 -52
- package/dist/cjs/scroll-restoration.cjs +27 -34
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/ssr/client.cjs +2 -2
- package/dist/cjs/ssr/createRequestHandler.cjs +60 -9
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.d.cts +1 -0
- package/dist/cjs/ssr/handlerCallback.cjs +49 -4
- package/dist/cjs/ssr/handlerCallback.cjs.map +1 -1
- package/dist/cjs/ssr/handlerCallback.d.cts +3 -0
- package/dist/cjs/ssr/server.cjs +4 -0
- package/dist/cjs/ssr/server.d.cts +2 -2
- package/dist/cjs/ssr/ssr-client.d.cts +1 -10
- package/dist/cjs/ssr/ssr-match-id.cjs +2 -2
- package/dist/cjs/ssr/ssr-match-id.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.cjs +6 -6
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +27 -1
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
- package/dist/cjs/ssr/transformStreamWithRouter.d.cts +2 -0
- package/dist/cjs/ssr/types.d.cts +0 -1
- package/dist/cjs/stores.cjs +30 -104
- package/dist/cjs/stores.cjs.map +1 -1
- package/dist/cjs/stores.d.cts +7 -32
- package/dist/cjs/utils.cjs +0 -4
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/esm/Matches.d.ts +3 -12
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/await-signal.d.ts +1 -0
- package/dist/esm/await-signal.js +21 -0
- package/dist/esm/await-signal.js.map +1 -0
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +3 -2
- package/dist/esm/isServer/client.d.ts +1 -0
- package/dist/esm/isServer/client.js +2 -1
- package/dist/esm/isServer/client.js.map +1 -1
- package/dist/esm/isServer/development.d.ts +1 -0
- package/dist/esm/isServer/development.js +2 -1
- package/dist/esm/isServer/development.js.map +1 -1
- package/dist/esm/isServer/server.d.ts +1 -0
- package/dist/esm/isServer/server.js +2 -1
- package/dist/esm/isServer/server.js.map +1 -1
- package/dist/esm/load-client.d.ts +147 -0
- package/dist/esm/load-client.js +1462 -0
- package/dist/esm/load-client.js.map +1 -0
- package/dist/esm/load-server.d.ts +16 -0
- package/dist/esm/load-server.js +565 -0
- package/dist/esm/load-server.js.map +1 -0
- package/dist/esm/redirect.d.ts +0 -1
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +62 -52
- package/dist/esm/router.js +188 -446
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js +27 -34
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/client.js +1 -1
- package/dist/esm/ssr/createRequestHandler.d.ts +1 -0
- package/dist/esm/ssr/createRequestHandler.js +61 -11
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/handlerCallback.d.ts +3 -0
- package/dist/esm/ssr/handlerCallback.js +47 -5
- package/dist/esm/ssr/handlerCallback.js.map +1 -1
- package/dist/esm/ssr/server.d.ts +2 -2
- package/dist/esm/ssr/server.js +3 -3
- package/dist/esm/ssr/ssr-client.d.ts +1 -10
- package/dist/esm/ssr/ssr-match-id.js +2 -2
- package/dist/esm/ssr/ssr-match-id.js.map +1 -1
- package/dist/esm/ssr/ssr-server.js +6 -6
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/transformStreamWithRouter.d.ts +2 -0
- package/dist/esm/ssr/transformStreamWithRouter.js +27 -1
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
- package/dist/esm/ssr/types.d.ts +0 -1
- package/dist/esm/stores.d.ts +7 -32
- package/dist/esm/stores.js +30 -104
- package/dist/esm/stores.js.map +1 -1
- package/dist/esm/utils.js +1 -4
- package/dist/esm/utils.js.map +1 -1
- package/package.json +3 -3
- package/src/Matches.ts +6 -21
- package/src/await-signal.ts +27 -0
- package/src/index.ts +1 -3
- package/src/isServer/client.ts +1 -0
- package/src/isServer/development.ts +1 -0
- package/src/isServer/server.ts +1 -0
- package/src/load-client.ts +2701 -0
- package/src/load-server.ts +849 -0
- package/src/redirect.ts +0 -1
- package/src/route.ts +2 -11
- package/src/router.ts +380 -774
- package/src/scroll-restoration.ts +40 -56
- package/src/ssr/createRequestHandler.ts +109 -16
- package/src/ssr/handlerCallback.ts +76 -10
- package/src/ssr/server.ts +4 -1
- package/src/ssr/ssr-client.ts +1 -310
- package/src/ssr/ssr-match-id.ts +11 -2
- package/src/ssr/ssr-server.ts +9 -8
- package/src/ssr/transformStreamWithRouter.ts +37 -1
- package/src/ssr/types.ts +0 -1
- package/src/stores.ts +46 -208
- package/dist/cjs/load-matches.cjs +0 -658
- package/dist/cjs/load-matches.cjs.map +0 -1
- package/dist/cjs/load-matches.d.cts +0 -18
- package/dist/cjs/ssr/ssr-client.cjs +0 -183
- package/dist/cjs/ssr/ssr-client.cjs.map +0 -1
- package/dist/esm/load-matches.d.ts +0 -18
- package/dist/esm/load-matches.js +0 -656
- package/dist/esm/load-matches.js.map +0 -1
- package/dist/esm/ssr/ssr-client.js +0 -183
- package/dist/esm/ssr/ssr-client.js.map +0 -1
- package/src/load-matches.ts +0 -1278
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
// Keep this filename free of a secondary extension so declaration generation
|
|
2
|
+
// can rewrite relative imports for both ESM and CJS.
|
|
3
|
+
import { isNotFound } from './not-found'
|
|
4
|
+
import { isRedirect, redirect } from './redirect'
|
|
5
|
+
import { rootRouteId } from './root'
|
|
6
|
+
import { loadRouteChunk } from './load-client'
|
|
7
|
+
import { waitForReason } from './await-signal'
|
|
8
|
+
import { getLocationChangeInfo, runRouteLifecycle } from './router'
|
|
9
|
+
import type { ParsedLocation } from './location'
|
|
10
|
+
import type { AnyRouteMatch } from './Matches'
|
|
11
|
+
import type { NotFoundError } from './not-found'
|
|
12
|
+
import type {
|
|
13
|
+
AnyRoute,
|
|
14
|
+
BeforeLoadContextOptions,
|
|
15
|
+
LoaderFnContext,
|
|
16
|
+
RouteContextOptions,
|
|
17
|
+
SsrContextOptions,
|
|
18
|
+
} from './route'
|
|
19
|
+
import type { AnyRedirect } from './redirect'
|
|
20
|
+
import type { AnyRouter, SSROption } from './router'
|
|
21
|
+
|
|
22
|
+
declare const serverLanePhase: unique symbol
|
|
23
|
+
|
|
24
|
+
type ServerLane<TPhase extends 'matched' | 'contextualized' | 'reduced'> = {
|
|
25
|
+
readonly [serverLanePhase]: TPhase
|
|
26
|
+
location: ParsedLocation
|
|
27
|
+
matches: Array<AnyRouteMatch>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type MatchedLane = ServerLane<'matched'>
|
|
31
|
+
|
|
32
|
+
type IndexedOutcome = [index: number, outcome: LoaderOutcome, boundary?: number]
|
|
33
|
+
|
|
34
|
+
type ContextualizedLane = ServerLane<'contextualized'> & {
|
|
35
|
+
end: number
|
|
36
|
+
failure?: IndexedOutcome
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type ReducedLane = ServerLane<'reduced'>
|
|
40
|
+
|
|
41
|
+
const SUCCESS = 0
|
|
42
|
+
const ERROR = 1
|
|
43
|
+
const NOT_FOUND = 2
|
|
44
|
+
const REDIRECTED = 3
|
|
45
|
+
const SKIPPED = 4
|
|
46
|
+
|
|
47
|
+
type LoaderOutcome =
|
|
48
|
+
| [typeof SUCCESS, data: unknown]
|
|
49
|
+
| [typeof ERROR, error: unknown]
|
|
50
|
+
| [typeof NOT_FOUND, error: NotFoundError]
|
|
51
|
+
| [typeof REDIRECTED, redirect: AnyRedirect]
|
|
52
|
+
| [typeof SKIPPED]
|
|
53
|
+
|
|
54
|
+
type LoaderTask = {
|
|
55
|
+
index: number
|
|
56
|
+
outcome: Promise<LoaderOutcome>
|
|
57
|
+
match: Promise<AnyRouteMatch>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type ServerLoadResult =
|
|
61
|
+
| {
|
|
62
|
+
type: 'render'
|
|
63
|
+
status: 200 | 404 | 500
|
|
64
|
+
matches: Array<AnyRouteMatch>
|
|
65
|
+
}
|
|
66
|
+
| { type: 'redirect'; redirect: AnyRedirect }
|
|
67
|
+
|
|
68
|
+
function getRoute(router: AnyRouter, match: AnyRouteMatch): AnyRoute {
|
|
69
|
+
return router.routesById[match.routeId]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalize(value: unknown, rejected: boolean): LoaderOutcome {
|
|
73
|
+
if (isRedirect(value)) {
|
|
74
|
+
return [REDIRECTED, value]
|
|
75
|
+
}
|
|
76
|
+
if (isNotFound(value)) {
|
|
77
|
+
return [NOT_FOUND, value]
|
|
78
|
+
}
|
|
79
|
+
if (rejected && typeof (value as any)?.then === 'function') {
|
|
80
|
+
value = new Error('A Promise was thrown', { cause: value })
|
|
81
|
+
}
|
|
82
|
+
return rejected ? [ERROR, value] : [SUCCESS, value]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function normalizeError(route: AnyRoute, cause: unknown): LoaderOutcome {
|
|
86
|
+
let outcome = normalize(cause, true)
|
|
87
|
+
if (outcome[0] !== ERROR) {
|
|
88
|
+
return outcome
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
route.options.onError?.(outcome[1])
|
|
92
|
+
} catch (onErrorCause) {
|
|
93
|
+
outcome = normalize(onErrorCause, true)
|
|
94
|
+
}
|
|
95
|
+
return outcome
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function maybe<TValue>(
|
|
99
|
+
value: TValue,
|
|
100
|
+
cause: unknown,
|
|
101
|
+
): { status: 'success'; value: TValue } | { status: 'error'; error: unknown } {
|
|
102
|
+
if (cause !== undefined) {
|
|
103
|
+
return { status: 'error', error: cause }
|
|
104
|
+
}
|
|
105
|
+
return { status: 'success', value }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function navigateFrom(router: AnyRouter, location: ParsedLocation) {
|
|
109
|
+
return (options: any) =>
|
|
110
|
+
router.navigate({
|
|
111
|
+
...options,
|
|
112
|
+
_fromLocation: location,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function waitFor<T>(value: Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
117
|
+
return signal ? waitForReason(value, signal) : value
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function resolveSsr(
|
|
121
|
+
router: AnyRouter,
|
|
122
|
+
lane: MatchedLane,
|
|
123
|
+
index: number,
|
|
124
|
+
): Promise<SSROption> {
|
|
125
|
+
const match = lane.matches[index]!
|
|
126
|
+
const route = getRoute(router, match)
|
|
127
|
+
const parentSsr = lane.matches[index - 1]?.ssr
|
|
128
|
+
|
|
129
|
+
if (router.isShell()) {
|
|
130
|
+
return route.id === rootRouteId
|
|
131
|
+
}
|
|
132
|
+
if (parentSsr === false) {
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const inherit = (value: SSROption): SSROption => {
|
|
137
|
+
return value === true && parentSsr === 'data-only' ? 'data-only' : value
|
|
138
|
+
}
|
|
139
|
+
const defaultSsr = router.options.defaultSsr ?? true
|
|
140
|
+
const inheritedDefault = inherit(defaultSsr)
|
|
141
|
+
// A functional override can fail. Establish the inherited policy first so
|
|
142
|
+
// the selected error boundary retains the route's actual renderability.
|
|
143
|
+
match.ssr = inheritedDefault
|
|
144
|
+
const option = route.options.ssr
|
|
145
|
+
if (option === undefined) {
|
|
146
|
+
return inheritedDefault
|
|
147
|
+
}
|
|
148
|
+
if (typeof option !== 'function') {
|
|
149
|
+
return inherit(option)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const context: SsrContextOptions<any, any, any> = {
|
|
153
|
+
search: maybe(match.search, match.searchError),
|
|
154
|
+
params: maybe(match.params, match.paramsError),
|
|
155
|
+
location: lane.location,
|
|
156
|
+
matches: lane.matches.map((candidate) => ({
|
|
157
|
+
index: candidate.index,
|
|
158
|
+
pathname: candidate.pathname,
|
|
159
|
+
fullPath: candidate.fullPath,
|
|
160
|
+
staticData: candidate.staticData,
|
|
161
|
+
id: candidate.id,
|
|
162
|
+
routeId: candidate.routeId,
|
|
163
|
+
search: maybe(candidate.search, candidate.searchError),
|
|
164
|
+
params: maybe(candidate.params, candidate.paramsError),
|
|
165
|
+
ssr: candidate.ssr,
|
|
166
|
+
})),
|
|
167
|
+
}
|
|
168
|
+
return inherit((await option(context)) ?? defaultSsr)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function stampNotFound(
|
|
172
|
+
match: AnyRouteMatch,
|
|
173
|
+
outcome: LoaderOutcome,
|
|
174
|
+
): LoaderOutcome {
|
|
175
|
+
if (outcome[0] === NOT_FOUND && !outcome[1].routeId) {
|
|
176
|
+
outcome[1].routeId = match.routeId
|
|
177
|
+
}
|
|
178
|
+
return outcome
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function contextualize(
|
|
182
|
+
router: AnyRouter,
|
|
183
|
+
lane: MatchedLane,
|
|
184
|
+
signal?: AbortSignal,
|
|
185
|
+
): Promise<ContextualizedLane> {
|
|
186
|
+
const globalBoundary = lane.matches.findIndex((match) => match._notFound)
|
|
187
|
+
let end = globalBoundary < 0 ? lane.matches.length : globalBoundary + 1
|
|
188
|
+
let failure: IndexedOutcome | undefined
|
|
189
|
+
let parentContext: Record<string, unknown> = {
|
|
190
|
+
...(router.options.context ?? {}),
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (let index = 0; index < end; index++) {
|
|
194
|
+
const match = lane.matches[index]!
|
|
195
|
+
const route = getRoute(router, match)
|
|
196
|
+
try {
|
|
197
|
+
match.ssr = await resolveSsr(router, lane, index)
|
|
198
|
+
} catch (cause) {
|
|
199
|
+
signal?.throwIfAborted()
|
|
200
|
+
failure = [index, stampNotFound(match, normalizeError(route, cause))]
|
|
201
|
+
end = index
|
|
202
|
+
}
|
|
203
|
+
signal?.throwIfAborted()
|
|
204
|
+
if (failure?.[1][0] === REDIRECTED) {
|
|
205
|
+
break
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
match.__beforeLoadContext = undefined
|
|
209
|
+
let context = parentContext
|
|
210
|
+
try {
|
|
211
|
+
let routeContext
|
|
212
|
+
if (route.options.context) {
|
|
213
|
+
const routeContextOptions: RouteContextOptions<
|
|
214
|
+
any,
|
|
215
|
+
any,
|
|
216
|
+
any,
|
|
217
|
+
any,
|
|
218
|
+
any
|
|
219
|
+
> = {
|
|
220
|
+
deps: match.loaderDeps,
|
|
221
|
+
params: match.params,
|
|
222
|
+
context: parentContext,
|
|
223
|
+
location: lane.location,
|
|
224
|
+
navigate: navigateFrom(router, lane.location),
|
|
225
|
+
buildLocation: router.buildLocation,
|
|
226
|
+
cause: match.cause,
|
|
227
|
+
abortController: match.abortController,
|
|
228
|
+
preload: false,
|
|
229
|
+
matches: lane.matches,
|
|
230
|
+
routeId: route.id,
|
|
231
|
+
}
|
|
232
|
+
routeContext = route.options.context(routeContextOptions) ?? undefined
|
|
233
|
+
}
|
|
234
|
+
context = {
|
|
235
|
+
...parentContext,
|
|
236
|
+
...routeContext,
|
|
237
|
+
}
|
|
238
|
+
match.context = context
|
|
239
|
+
} catch (cause) {
|
|
240
|
+
signal?.throwIfAborted()
|
|
241
|
+
if (!failure) {
|
|
242
|
+
failure = [index, stampNotFound(match, normalizeError(route, cause))]
|
|
243
|
+
}
|
|
244
|
+
end = index
|
|
245
|
+
break
|
|
246
|
+
}
|
|
247
|
+
signal?.throwIfAborted()
|
|
248
|
+
if (failure) {
|
|
249
|
+
break
|
|
250
|
+
}
|
|
251
|
+
const validationError = match.paramsError ?? match.searchError
|
|
252
|
+
if (validationError !== undefined) {
|
|
253
|
+
failure = [
|
|
254
|
+
index,
|
|
255
|
+
stampNotFound(match, normalizeError(route, validationError)),
|
|
256
|
+
]
|
|
257
|
+
end = index
|
|
258
|
+
break
|
|
259
|
+
}
|
|
260
|
+
signal?.throwIfAborted()
|
|
261
|
+
|
|
262
|
+
if (match.ssr === false || !route.options.beforeLoad) {
|
|
263
|
+
parentContext = context
|
|
264
|
+
continue
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const abortController = match.abortController
|
|
268
|
+
const options: BeforeLoadContextOptions<
|
|
269
|
+
any,
|
|
270
|
+
any,
|
|
271
|
+
any,
|
|
272
|
+
any,
|
|
273
|
+
any,
|
|
274
|
+
any,
|
|
275
|
+
any,
|
|
276
|
+
any,
|
|
277
|
+
any
|
|
278
|
+
> = {
|
|
279
|
+
search: match.search,
|
|
280
|
+
abortController,
|
|
281
|
+
params: match.params,
|
|
282
|
+
preload: false,
|
|
283
|
+
context,
|
|
284
|
+
location: lane.location,
|
|
285
|
+
navigate: navigateFrom(router, lane.location),
|
|
286
|
+
buildLocation: router.buildLocation,
|
|
287
|
+
cause: match.cause,
|
|
288
|
+
matches: lane.matches,
|
|
289
|
+
routeId: route.id,
|
|
290
|
+
...router.options.additionalContext,
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
const beforeLoadContext = await route.options.beforeLoad(options)
|
|
295
|
+
signal?.throwIfAborted()
|
|
296
|
+
const outcome = stampNotFound(match, normalize(beforeLoadContext, false))
|
|
297
|
+
if (outcome[0] !== SUCCESS) {
|
|
298
|
+
failure = [index, outcome]
|
|
299
|
+
end = index
|
|
300
|
+
break
|
|
301
|
+
}
|
|
302
|
+
match.__beforeLoadContext = beforeLoadContext
|
|
303
|
+
match.context = {
|
|
304
|
+
...context,
|
|
305
|
+
...beforeLoadContext,
|
|
306
|
+
}
|
|
307
|
+
parentContext = match.context
|
|
308
|
+
} catch (cause) {
|
|
309
|
+
signal?.throwIfAborted()
|
|
310
|
+
failure = [index, stampNotFound(match, normalizeError(route, cause))]
|
|
311
|
+
end = index
|
|
312
|
+
break
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
location: lane.location,
|
|
318
|
+
matches: lane.matches,
|
|
319
|
+
end,
|
|
320
|
+
failure,
|
|
321
|
+
} as ContextualizedLane
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function getLoaderContext(
|
|
325
|
+
router: AnyRouter,
|
|
326
|
+
lane: ContextualizedLane,
|
|
327
|
+
match: AnyRouteMatch,
|
|
328
|
+
route: AnyRoute,
|
|
329
|
+
index: number,
|
|
330
|
+
tasks: Array<LoaderTask>,
|
|
331
|
+
): LoaderFnContext {
|
|
332
|
+
return {
|
|
333
|
+
params: match.params,
|
|
334
|
+
deps: match.loaderDeps,
|
|
335
|
+
preload: false,
|
|
336
|
+
parentMatchPromise: tasks[index - 1]?.match,
|
|
337
|
+
abortController: match.abortController,
|
|
338
|
+
context: match.context,
|
|
339
|
+
location: lane.location,
|
|
340
|
+
navigate: navigateFrom(router, lane.location),
|
|
341
|
+
cause: match.cause,
|
|
342
|
+
route,
|
|
343
|
+
...router.options.additionalContext,
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function createLoaderTask(
|
|
348
|
+
router: AnyRouter,
|
|
349
|
+
lane: ContextualizedLane,
|
|
350
|
+
index: number,
|
|
351
|
+
tasks: Array<LoaderTask>,
|
|
352
|
+
signal?: AbortSignal,
|
|
353
|
+
): LoaderTask {
|
|
354
|
+
const match = lane.matches[index]!
|
|
355
|
+
const route = getRoute(router, match)
|
|
356
|
+
let outcome: Promise<LoaderOutcome>
|
|
357
|
+
|
|
358
|
+
if (match.ssr === false) {
|
|
359
|
+
outcome = Promise.resolve<LoaderOutcome>([SKIPPED])
|
|
360
|
+
} else {
|
|
361
|
+
const routeLoader = route.options.loader
|
|
362
|
+
const loader =
|
|
363
|
+
typeof routeLoader === 'function' ? routeLoader : routeLoader?.handler
|
|
364
|
+
if (!loader) {
|
|
365
|
+
outcome = Promise.resolve<LoaderOutcome>([SUCCESS, undefined])
|
|
366
|
+
} else {
|
|
367
|
+
outcome = Promise.resolve()
|
|
368
|
+
.then(() =>
|
|
369
|
+
loader(getLoaderContext(router, lane, match, route, index, tasks)),
|
|
370
|
+
)
|
|
371
|
+
.then(
|
|
372
|
+
(result) => normalize(result, false),
|
|
373
|
+
(cause) => normalize(cause, true),
|
|
374
|
+
)
|
|
375
|
+
.then((result): LoaderOutcome => {
|
|
376
|
+
if (
|
|
377
|
+
result[0] !== REDIRECTED &&
|
|
378
|
+
(signal?.aborted || match.abortController.signal.reason === lane)
|
|
379
|
+
) {
|
|
380
|
+
return [SKIPPED]
|
|
381
|
+
}
|
|
382
|
+
if (result[0] === ERROR) {
|
|
383
|
+
result = normalizeError(route, result[1])
|
|
384
|
+
}
|
|
385
|
+
return stampNotFound(match, result)
|
|
386
|
+
})
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const parentMatch = outcome.then((result) => {
|
|
391
|
+
const snapshot = { ...match }
|
|
392
|
+
if (result[0] === SUCCESS) {
|
|
393
|
+
snapshot.loaderData = result[1]
|
|
394
|
+
snapshot.status = 'success'
|
|
395
|
+
snapshot.error = undefined
|
|
396
|
+
snapshot.invalid = false
|
|
397
|
+
snapshot.isFetching = false
|
|
398
|
+
} else if (result[0] === ERROR) {
|
|
399
|
+
snapshot.status = 'error'
|
|
400
|
+
snapshot.error = result[1]
|
|
401
|
+
} else if (result[0] === NOT_FOUND) {
|
|
402
|
+
snapshot.status = 'notFound'
|
|
403
|
+
snapshot.error = result[1]
|
|
404
|
+
}
|
|
405
|
+
return snapshot
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
return { index, outcome, match: parentMatch }
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async function getNotFoundBoundary(
|
|
412
|
+
router: AnyRouter,
|
|
413
|
+
matches: Array<AnyRouteMatch>,
|
|
414
|
+
indexed: IndexedOutcome | undefined,
|
|
415
|
+
signal?: AbortSignal,
|
|
416
|
+
fallback = 0,
|
|
417
|
+
): Promise<number> {
|
|
418
|
+
const cause = indexed?.[1][1] as NotFoundError | undefined
|
|
419
|
+
let index = cause?.routeId
|
|
420
|
+
? matches.findIndex((match) => match.routeId === cause.routeId)
|
|
421
|
+
: (indexed?.[0] ?? matches.length - 1)
|
|
422
|
+
if (index < 0) {
|
|
423
|
+
index = 0
|
|
424
|
+
}
|
|
425
|
+
for (let candidate = index; candidate >= 0; candidate--) {
|
|
426
|
+
const route = getRoute(router, matches[candidate]!)
|
|
427
|
+
const loading = loadRouteChunk(route, false)
|
|
428
|
+
if (loading) {
|
|
429
|
+
try {
|
|
430
|
+
await loading
|
|
431
|
+
} catch {
|
|
432
|
+
signal?.throwIfAborted()
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
signal?.throwIfAborted()
|
|
436
|
+
if (route.options.notFoundComponent) {
|
|
437
|
+
return candidate
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return cause?.routeId ? index : fallback
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function abortMatches(
|
|
444
|
+
matches: Array<AnyRouteMatch>,
|
|
445
|
+
start = 0,
|
|
446
|
+
reason?: unknown,
|
|
447
|
+
): void {
|
|
448
|
+
for (let index = start; index < matches.length; index++) {
|
|
449
|
+
matches[index]!.abortController.abort(reason)
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
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
|
+
async function applyFailure(
|
|
463
|
+
router: AnyRouter,
|
|
464
|
+
lane: ContextualizedLane,
|
|
465
|
+
indexed: IndexedOutcome | undefined,
|
|
466
|
+
signal?: AbortSignal,
|
|
467
|
+
): Promise<{ status: 200 | 404 | 500; boundary?: number; kind?: number }> {
|
|
468
|
+
if (!indexed) {
|
|
469
|
+
const boundary = lane.matches.findIndex((match) => match._notFound)
|
|
470
|
+
if (boundary >= 0) {
|
|
471
|
+
abortMatches(lane.matches, boundary + 1)
|
|
472
|
+
return { status: 404, boundary, kind: NOT_FOUND }
|
|
473
|
+
}
|
|
474
|
+
return { status: 200 }
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const [index, outcome] = indexed
|
|
478
|
+
if (outcome[0] === ERROR) {
|
|
479
|
+
const match = lane.matches[index]!
|
|
480
|
+
match._notFound = undefined
|
|
481
|
+
match.status = 'error'
|
|
482
|
+
match.error = outcome[1]
|
|
483
|
+
match.isFetching = false
|
|
484
|
+
abortMatches(lane.matches, index + 1)
|
|
485
|
+
return { status: 500, boundary: index, kind: ERROR }
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const boundary =
|
|
489
|
+
indexed[2] ??
|
|
490
|
+
(await getNotFoundBoundary(router, lane.matches, indexed, signal))
|
|
491
|
+
const match = lane.matches[boundary]!
|
|
492
|
+
const cause = outcome[1] as NotFoundError
|
|
493
|
+
cause.routeId = match.routeId
|
|
494
|
+
match._notFound = undefined
|
|
495
|
+
if (match.routeId === router.routeTree.id) {
|
|
496
|
+
match.status = 'success'
|
|
497
|
+
match._notFound = true
|
|
498
|
+
match.error = cause
|
|
499
|
+
} else {
|
|
500
|
+
match.status = 'notFound'
|
|
501
|
+
match.error = cause
|
|
502
|
+
}
|
|
503
|
+
match.isFetching = false
|
|
504
|
+
abortMatches(lane.matches, boundary + 1)
|
|
505
|
+
return { status: 404, boundary, kind: NOT_FOUND }
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async function loadNormalChunks(
|
|
509
|
+
router: AnyRouter,
|
|
510
|
+
lane: ContextualizedLane,
|
|
511
|
+
end: number,
|
|
512
|
+
signal?: AbortSignal,
|
|
513
|
+
): Promise<IndexedOutcome | undefined> {
|
|
514
|
+
const chunks: Array<IndexedOutcome | Promise<IndexedOutcome | undefined>> = []
|
|
515
|
+
for (let index = 0; index < lane.matches.length; index++) {
|
|
516
|
+
const match = lane.matches[index]!
|
|
517
|
+
if (index >= end || match.ssr !== true || match.status !== 'success') {
|
|
518
|
+
continue
|
|
519
|
+
}
|
|
520
|
+
const route = getRoute(router, match)
|
|
521
|
+
try {
|
|
522
|
+
const loading = loadRouteChunk(route)
|
|
523
|
+
if (loading) {
|
|
524
|
+
const chunk = loading.then(
|
|
525
|
+
() => {
|
|
526
|
+
signal?.throwIfAborted()
|
|
527
|
+
return undefined
|
|
528
|
+
},
|
|
529
|
+
(cause) => {
|
|
530
|
+
signal?.throwIfAborted()
|
|
531
|
+
return [
|
|
532
|
+
index,
|
|
533
|
+
stampNotFound(match, normalizeError(route, cause)),
|
|
534
|
+
] as IndexedOutcome
|
|
535
|
+
},
|
|
536
|
+
)
|
|
537
|
+
// Route-order reduction can return before later chunks settle.
|
|
538
|
+
void chunk.catch(() => {})
|
|
539
|
+
chunks.push(chunk)
|
|
540
|
+
}
|
|
541
|
+
} catch (cause) {
|
|
542
|
+
signal?.throwIfAborted()
|
|
543
|
+
chunks.push([index, stampNotFound(match, normalizeError(route, cause))])
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
for (const chunk of chunks) {
|
|
547
|
+
const indexed = Array.isArray(chunk) ? chunk : await chunk
|
|
548
|
+
if (indexed) {
|
|
549
|
+
return indexed
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return undefined
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async function projectLane(
|
|
556
|
+
router: AnyRouter,
|
|
557
|
+
lane: ReducedLane,
|
|
558
|
+
signal?: AbortSignal,
|
|
559
|
+
): Promise<void> {
|
|
560
|
+
for (const match of lane.matches) {
|
|
561
|
+
const routeOptions = getRoute(router, match).options
|
|
562
|
+
if (routeOptions.head || routeOptions.scripts || routeOptions.headers) {
|
|
563
|
+
const context = {
|
|
564
|
+
ssr: router.options.ssr,
|
|
565
|
+
matches: lane.matches,
|
|
566
|
+
match,
|
|
567
|
+
params: match.params,
|
|
568
|
+
loaderData: match.loaderData,
|
|
569
|
+
}
|
|
570
|
+
try {
|
|
571
|
+
const [head, scripts, headers] = await Promise.all([
|
|
572
|
+
routeOptions.head?.(context),
|
|
573
|
+
routeOptions.scripts?.(context),
|
|
574
|
+
routeOptions.headers?.(context),
|
|
575
|
+
])
|
|
576
|
+
signal?.throwIfAborted()
|
|
577
|
+
match.meta = head?.meta
|
|
578
|
+
match.links = head?.links
|
|
579
|
+
match.headScripts = head?.scripts
|
|
580
|
+
match.styles = head?.styles
|
|
581
|
+
match.scripts = scripts
|
|
582
|
+
match.headers = headers
|
|
583
|
+
} catch (cause) {
|
|
584
|
+
signal?.throwIfAborted()
|
|
585
|
+
console.error(cause)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (match.ssr === false || match.status !== 'success' || match._notFound) {
|
|
589
|
+
break
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
async function executeServerLane(
|
|
595
|
+
router: AnyRouter,
|
|
596
|
+
location: ParsedLocation,
|
|
597
|
+
matchedMatches: Array<AnyRouteMatch>,
|
|
598
|
+
signal?: AbortSignal,
|
|
599
|
+
): Promise<ServerLoadResult> {
|
|
600
|
+
const matched = {
|
|
601
|
+
location,
|
|
602
|
+
matches: matchedMatches.map((match) => ({
|
|
603
|
+
...match,
|
|
604
|
+
__beforeLoadContext: undefined,
|
|
605
|
+
context: {},
|
|
606
|
+
isFetching: false,
|
|
607
|
+
abortController: new AbortController(),
|
|
608
|
+
})),
|
|
609
|
+
} as MatchedLane
|
|
610
|
+
const abortLane = () => abortMatches(matched.matches, 0, signal?.reason)
|
|
611
|
+
if (signal?.aborted) {
|
|
612
|
+
abortLane()
|
|
613
|
+
signal.throwIfAborted()
|
|
614
|
+
}
|
|
615
|
+
signal?.addEventListener('abort', abortLane, { once: true })
|
|
616
|
+
|
|
617
|
+
try {
|
|
618
|
+
const plannedGlobalBoundary = matched.matches.findIndex(
|
|
619
|
+
(match) => match._notFound,
|
|
620
|
+
)
|
|
621
|
+
if (router.options.notFoundMode !== 'root' && plannedGlobalBoundary >= 0) {
|
|
622
|
+
const boundary = await getNotFoundBoundary(
|
|
623
|
+
router,
|
|
624
|
+
matched.matches,
|
|
625
|
+
undefined,
|
|
626
|
+
signal,
|
|
627
|
+
plannedGlobalBoundary,
|
|
628
|
+
)
|
|
629
|
+
if (boundary !== plannedGlobalBoundary) {
|
|
630
|
+
matched.matches[plannedGlobalBoundary]!._notFound = undefined
|
|
631
|
+
matched.matches[boundary]!._notFound = true
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const lane = await contextualize(router, matched, signal)
|
|
635
|
+
signal?.throwIfAborted()
|
|
636
|
+
|
|
637
|
+
let loaderEnd = lane.end
|
|
638
|
+
if (lane.failure?.[1][0] === REDIRECTED) {
|
|
639
|
+
loaderEnd = 0
|
|
640
|
+
} else if (lane.failure?.[1][0] === NOT_FOUND) {
|
|
641
|
+
lane.failure[2] = await getNotFoundBoundary(
|
|
642
|
+
router,
|
|
643
|
+
lane.matches,
|
|
644
|
+
lane.failure,
|
|
645
|
+
signal,
|
|
646
|
+
)
|
|
647
|
+
loaderEnd = Math.min(loaderEnd, lane.failure[2] + 1)
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const tasks: Array<LoaderTask> = []
|
|
651
|
+
for (let index = 0; index < loaderEnd; index++) {
|
|
652
|
+
const task = createLoaderTask(router, lane, index, tasks, signal)
|
|
653
|
+
tasks.push(task)
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
let loaderFailure: IndexedOutcome | undefined
|
|
657
|
+
let control = lane.failure?.[1][0] === REDIRECTED ? lane.failure : undefined
|
|
658
|
+
try {
|
|
659
|
+
await Promise.all(
|
|
660
|
+
tasks.map((task) =>
|
|
661
|
+
task.outcome.then((loadedOutcome) => {
|
|
662
|
+
const match = lane.matches[task.index]!
|
|
663
|
+
const outcome = loadedOutcome
|
|
664
|
+
if (outcome[0] === SUCCESS) {
|
|
665
|
+
match.loaderData = outcome[1]
|
|
666
|
+
match.status = 'success'
|
|
667
|
+
match.error = undefined
|
|
668
|
+
match.invalid = false
|
|
669
|
+
match.isFetching = false
|
|
670
|
+
match.updatedAt = Date.now()
|
|
671
|
+
} else if (outcome[0] === REDIRECTED) {
|
|
672
|
+
control = [task.index, outcome]
|
|
673
|
+
throw control
|
|
674
|
+
} else {
|
|
675
|
+
// A selective-SSR skip must stay pending for hydration. Every
|
|
676
|
+
// settled server attempt is otherwise renderable unless
|
|
677
|
+
// reduction selects it as the lane's terminal failure.
|
|
678
|
+
if (match.ssr !== false) {
|
|
679
|
+
match.status = 'success'
|
|
680
|
+
match.error = undefined
|
|
681
|
+
match.invalid = true
|
|
682
|
+
match.isFetching = false
|
|
683
|
+
}
|
|
684
|
+
if (!loaderFailure && outcome[0] !== SKIPPED) {
|
|
685
|
+
loaderFailure = [task.index, outcome]
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}),
|
|
689
|
+
),
|
|
690
|
+
)
|
|
691
|
+
} catch (cause) {
|
|
692
|
+
if (!Array.isArray(cause)) {
|
|
693
|
+
throw cause
|
|
694
|
+
}
|
|
695
|
+
control = cause as IndexedOutcome
|
|
696
|
+
}
|
|
697
|
+
signal?.throwIfAborted()
|
|
698
|
+
|
|
699
|
+
if (control?.[1][0] === REDIRECTED) {
|
|
700
|
+
abortMatches(lane.matches, 0, lane)
|
|
701
|
+
return resolveServerRedirect(router, location, control[1][1])
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
let failure = lane.failure ?? loaderFailure
|
|
705
|
+
const plannedBoundary = lane.matches.findIndex((match) => match._notFound)
|
|
706
|
+
let readinessEnd: number
|
|
707
|
+
if (failure) {
|
|
708
|
+
const outcomeEnd = (failure[2] ??=
|
|
709
|
+
failure[1][0] === NOT_FOUND
|
|
710
|
+
? await getNotFoundBoundary(router, lane.matches, failure, signal)
|
|
711
|
+
: failure[0])
|
|
712
|
+
for (const task of tasks) {
|
|
713
|
+
if (task.index >= outcomeEnd) {
|
|
714
|
+
break
|
|
715
|
+
}
|
|
716
|
+
const outcome = await task.outcome
|
|
717
|
+
// Presence means a loader previously succeeded, even with `undefined`.
|
|
718
|
+
if (
|
|
719
|
+
outcome[0] !== SUCCESS &&
|
|
720
|
+
outcome[0] < REDIRECTED &&
|
|
721
|
+
!('loaderData' in lane.matches[task.index]!)
|
|
722
|
+
) {
|
|
723
|
+
failure = [task.index, outcome]
|
|
724
|
+
failure[2] =
|
|
725
|
+
outcome[0] === NOT_FOUND
|
|
726
|
+
? await getNotFoundBoundary(router, lane.matches, failure, signal)
|
|
727
|
+
: task.index
|
|
728
|
+
break
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
readinessEnd = failure[2]
|
|
732
|
+
} else {
|
|
733
|
+
readinessEnd = plannedBoundary < 0 ? lane.matches.length : plannedBoundary
|
|
734
|
+
}
|
|
735
|
+
const requiredFailure = await loadNormalChunks(
|
|
736
|
+
router,
|
|
737
|
+
lane,
|
|
738
|
+
readinessEnd,
|
|
739
|
+
signal,
|
|
740
|
+
)
|
|
741
|
+
signal?.throwIfAborted()
|
|
742
|
+
if (requiredFailure) {
|
|
743
|
+
if (requiredFailure[1][0] === REDIRECTED) {
|
|
744
|
+
abortMatches(lane.matches)
|
|
745
|
+
return resolveServerRedirect(router, location, requiredFailure[1][1])
|
|
746
|
+
}
|
|
747
|
+
failure = requiredFailure
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const terminal = await applyFailure(router, lane, failure, signal)
|
|
751
|
+
if (terminal.boundary !== undefined) {
|
|
752
|
+
const match = lane.matches[terminal.boundary]!
|
|
753
|
+
if (match.ssr === true) {
|
|
754
|
+
const route = getRoute(router, match)
|
|
755
|
+
try {
|
|
756
|
+
if (terminal.kind === ERROR) {
|
|
757
|
+
await loadRouteChunk(route, 'errorComponent')
|
|
758
|
+
} else if (match._notFound) {
|
|
759
|
+
await Promise.all([
|
|
760
|
+
loadRouteChunk(route),
|
|
761
|
+
loadRouteChunk(route, 'notFoundComponent'),
|
|
762
|
+
])
|
|
763
|
+
} else {
|
|
764
|
+
await loadRouteChunk(route, 'notFoundComponent')
|
|
765
|
+
}
|
|
766
|
+
} catch {}
|
|
767
|
+
signal?.throwIfAborted()
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
signal?.throwIfAborted()
|
|
772
|
+
await projectLane(
|
|
773
|
+
router,
|
|
774
|
+
{
|
|
775
|
+
location: lane.location,
|
|
776
|
+
matches: lane.matches,
|
|
777
|
+
} as ReducedLane,
|
|
778
|
+
signal,
|
|
779
|
+
)
|
|
780
|
+
signal?.throwIfAborted()
|
|
781
|
+
router.serverSsr?.onCleanup(abortLane)
|
|
782
|
+
return { type: 'render', status: terminal.status, matches: lane.matches }
|
|
783
|
+
} finally {
|
|
784
|
+
signal?.removeEventListener('abort', abortLane)
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
type ServerLoadOptions = NonNullable<Parameters<AnyRouter['load']>[0]> & {
|
|
789
|
+
_signal?: AbortSignal
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
export async function loadServerRoute(
|
|
793
|
+
router: AnyRouter,
|
|
794
|
+
opts?: ServerLoadOptions,
|
|
795
|
+
): Promise<void> {
|
|
796
|
+
router.updateLatestLocation()
|
|
797
|
+
const next = router.latestLocation
|
|
798
|
+
const previous = router._committed
|
|
799
|
+
let result: ServerLoadResult
|
|
800
|
+
try {
|
|
801
|
+
const canonical = router.buildLocation({
|
|
802
|
+
to: next.pathname,
|
|
803
|
+
search: true,
|
|
804
|
+
params: true,
|
|
805
|
+
hash: true,
|
|
806
|
+
state: true,
|
|
807
|
+
_includeValidateSearch: true,
|
|
808
|
+
})
|
|
809
|
+
if (next.publicHref !== canonical.publicHref) {
|
|
810
|
+
const href = canonical.publicHref || '/'
|
|
811
|
+
throw canonical.external
|
|
812
|
+
? redirect({ href })
|
|
813
|
+
: redirect({ href, _builtLocation: canonical })
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const fromLocation = router.stores.resolvedLocation.get()
|
|
817
|
+
const changeInfo = getLocationChangeInfo(next, fromLocation)
|
|
818
|
+
router.emit({ type: 'onBeforeNavigate', ...changeInfo })
|
|
819
|
+
router.emit({ type: 'onBeforeLoad', ...changeInfo })
|
|
820
|
+
opts?._signal?.throwIfAborted()
|
|
821
|
+
result = await waitFor(
|
|
822
|
+
executeServerLane(router, next, router.matchRoutes(next), opts?._signal),
|
|
823
|
+
opts?._signal,
|
|
824
|
+
)
|
|
825
|
+
opts?._signal?.throwIfAborted()
|
|
826
|
+
} catch (cause) {
|
|
827
|
+
opts?._signal?.throwIfAborted()
|
|
828
|
+
if (!isRedirect(cause)) {
|
|
829
|
+
throw cause
|
|
830
|
+
}
|
|
831
|
+
result = resolveServerRedirect(router, next, cause)
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
router._serverResult = result
|
|
835
|
+
router.batch(() => {
|
|
836
|
+
router.stores.location.set(next)
|
|
837
|
+
router.stores.status.set('idle')
|
|
838
|
+
if (result.type === 'render') {
|
|
839
|
+
router.stores.setMatches(result.matches)
|
|
840
|
+
router.stores.resolvedLocation.set(next)
|
|
841
|
+
}
|
|
842
|
+
})
|
|
843
|
+
if (result.type === 'render') {
|
|
844
|
+
router._committed = result.matches
|
|
845
|
+
runRouteLifecycle(router, previous, result.matches)
|
|
846
|
+
}
|
|
847
|
+
router._commitPromise?.resolve()
|
|
848
|
+
router._commitPromise = undefined
|
|
849
|
+
}
|