@real-router/core 0.34.1 → 0.35.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/README.md +50 -250
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/metafile-cjs.json +1 -1
- package/dist/esm/index.d.mts +3 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/metafile-esm.json +1 -1
- package/package.json +5 -5
- package/src/Router.ts +21 -27
- package/src/api/getDependenciesApi.ts +2 -9
- package/src/api/getLifecycleApi.ts +1 -8
- package/src/api/getPluginApi.ts +1 -6
- package/src/api/getRoutesApi.ts +3 -11
- package/src/api/helpers.ts +10 -0
- package/src/constants.ts +3 -1
- package/src/index.ts +2 -1
- package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +14 -20
- package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +129 -144
- package/src/namespaces/NavigationNamespace/index.ts +1 -1
- package/src/namespaces/NavigationNamespace/transition/index.ts +5 -2
- package/src/namespaces/NavigationNamespace/types.ts +26 -28
- package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +1 -9
- package/src/namespaces/PluginsNamespace/types.ts +2 -12
- package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +32 -58
- package/src/namespaces/RouteLifecycleNamespace/types.ts +3 -10
- package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +8 -51
- package/src/namespaces/RouterLifecycleNamespace/types.ts +12 -2
- package/src/namespaces/StateNamespace/StateNamespace.ts +0 -15
- package/src/transitionPath.ts +1 -1
- package/src/wiring/RouterWiringBuilder.ts +54 -39
- package/src/wiring/wireRouter.ts +2 -3
|
@@ -10,13 +10,9 @@ import {
|
|
|
10
10
|
} from "./validators";
|
|
11
11
|
import { errorCodes, constants } from "../../constants";
|
|
12
12
|
import { RouterError } from "../../RouterError";
|
|
13
|
-
import {
|
|
13
|
+
import { nameToIDs } from "../../transitionPath";
|
|
14
14
|
|
|
15
|
-
import type {
|
|
16
|
-
NavigationDependencies,
|
|
17
|
-
TransitionDependencies,
|
|
18
|
-
TransitionOutput,
|
|
19
|
-
} from "./types";
|
|
15
|
+
import type { NavigationDependencies, TransitionOutput } from "./types";
|
|
20
16
|
import type {
|
|
21
17
|
NavigationOptions,
|
|
22
18
|
Params,
|
|
@@ -24,20 +20,80 @@ import type {
|
|
|
24
20
|
TransitionMeta,
|
|
25
21
|
} from "@real-router/types";
|
|
26
22
|
|
|
23
|
+
const FROZEN_ACTIVATED: string[] = [constants.UNKNOWN_ROUTE];
|
|
24
|
+
|
|
25
|
+
Object.freeze(FROZEN_ACTIVATED);
|
|
26
|
+
const FROZEN_REPLACE_OPTS: NavigationOptions = { replace: true };
|
|
27
|
+
|
|
28
|
+
Object.freeze(FROZEN_REPLACE_OPTS);
|
|
29
|
+
|
|
30
|
+
function forceReplaceFromUnknown(
|
|
31
|
+
opts: NavigationOptions,
|
|
32
|
+
fromState: State | undefined,
|
|
33
|
+
): NavigationOptions {
|
|
34
|
+
return fromState?.name === constants.UNKNOWN_ROUTE && !opts.replace
|
|
35
|
+
? { ...opts, replace: true }
|
|
36
|
+
: opts;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function stripSignal({
|
|
40
|
+
signal: _,
|
|
41
|
+
...rest
|
|
42
|
+
}: NavigationOptions): NavigationOptions {
|
|
43
|
+
return rest;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function routeTransitionError(
|
|
47
|
+
deps: NavigationDependencies,
|
|
48
|
+
error: unknown,
|
|
49
|
+
toState: State,
|
|
50
|
+
fromState: State | undefined,
|
|
51
|
+
): void {
|
|
52
|
+
const routerError = error as RouterError;
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
routerError.code === errorCodes.TRANSITION_CANCELLED ||
|
|
56
|
+
routerError.code === errorCodes.ROUTE_NOT_FOUND
|
|
57
|
+
) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
deps.sendTransitionFail(toState, fromState, routerError);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function buildSuccessState(
|
|
65
|
+
finalState: State,
|
|
66
|
+
transitionOutput: TransitionOutput["meta"],
|
|
67
|
+
fromState: State | undefined,
|
|
68
|
+
opts: NavigationOptions,
|
|
69
|
+
): State {
|
|
70
|
+
const transitionMeta: TransitionMeta = {
|
|
71
|
+
phase: transitionOutput.phase,
|
|
72
|
+
...(fromState?.name !== undefined && { from: fromState.name }),
|
|
73
|
+
reason: "success",
|
|
74
|
+
segments: transitionOutput.segments,
|
|
75
|
+
...(opts.reload !== undefined && { reload: opts.reload }),
|
|
76
|
+
...(opts.redirected !== undefined && { redirected: opts.redirected }),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
Object.freeze(transitionMeta.segments.deactivated);
|
|
80
|
+
Object.freeze(transitionMeta.segments.activated);
|
|
81
|
+
Object.freeze(transitionMeta.segments);
|
|
82
|
+
Object.freeze(transitionMeta);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
...finalState,
|
|
86
|
+
transition: transitionMeta,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
27
90
|
/**
|
|
28
91
|
* Independent namespace for managing navigation.
|
|
29
92
|
*
|
|
30
|
-
* Handles navigate(), navigateToDefault(),
|
|
93
|
+
* Handles navigate(), navigateToDefault(), navigateToNotFound(), and transition state.
|
|
31
94
|
*/
|
|
32
95
|
export class NavigationNamespace {
|
|
33
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
34
|
-
// Functional reference for cyclic dependency
|
|
35
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
36
|
-
|
|
37
|
-
// Dependencies injected via setDependencies (replaces full router reference)
|
|
38
|
-
#canNavigate!: () => boolean;
|
|
39
96
|
#deps!: NavigationDependencies;
|
|
40
|
-
#transitionDeps!: TransitionDependencies;
|
|
41
97
|
#currentController: AbortController | null = null;
|
|
42
98
|
|
|
43
99
|
// =========================================================================
|
|
@@ -64,30 +120,10 @@ export class NavigationNamespace {
|
|
|
64
120
|
// Dependency injection
|
|
65
121
|
// =========================================================================
|
|
66
122
|
|
|
67
|
-
/**
|
|
68
|
-
* Sets the canNavigate check (cyclic dependency on EventBusNamespace).
|
|
69
|
-
* Must be called before using navigate().
|
|
70
|
-
*/
|
|
71
|
-
setCanNavigate(fn: () => boolean): void {
|
|
72
|
-
this.#canNavigate = fn;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Sets dependencies for navigation operations.
|
|
77
|
-
* Must be called before using navigation methods.
|
|
78
|
-
*/
|
|
79
123
|
setDependencies(deps: NavigationDependencies): void {
|
|
80
124
|
this.#deps = deps;
|
|
81
125
|
}
|
|
82
126
|
|
|
83
|
-
/**
|
|
84
|
-
* Sets dependencies for transition operations.
|
|
85
|
-
* Must be called before using navigation methods.
|
|
86
|
-
*/
|
|
87
|
-
setTransitionDependencies(deps: TransitionDependencies): void {
|
|
88
|
-
this.#transitionDeps = deps;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
127
|
// =========================================================================
|
|
92
128
|
// Instance methods
|
|
93
129
|
// =========================================================================
|
|
@@ -101,7 +137,7 @@ export class NavigationNamespace {
|
|
|
101
137
|
params: Params,
|
|
102
138
|
opts: NavigationOptions,
|
|
103
139
|
): Promise<State> {
|
|
104
|
-
if (!this.#canNavigate()) {
|
|
140
|
+
if (!this.#deps.canNavigate()) {
|
|
105
141
|
throw new RouterError(errorCodes.ROUTER_NOT_STARTED);
|
|
106
142
|
}
|
|
107
143
|
|
|
@@ -130,7 +166,10 @@ export class NavigationNamespace {
|
|
|
130
166
|
|
|
131
167
|
const fromState = deps.getState();
|
|
132
168
|
|
|
169
|
+
opts = forceReplaceFromUnknown(opts, fromState);
|
|
170
|
+
|
|
133
171
|
if (
|
|
172
|
+
fromState &&
|
|
134
173
|
!opts.reload &&
|
|
135
174
|
!opts.force &&
|
|
136
175
|
deps.areStatesEqual(fromState, toState, false)
|
|
@@ -142,32 +181,7 @@ export class NavigationNamespace {
|
|
|
142
181
|
throw err;
|
|
143
182
|
}
|
|
144
183
|
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Internal navigation function that accepts pre-built state.
|
|
150
|
-
* Used by RouterLifecycleNamespace for start() transitions.
|
|
151
|
-
*/
|
|
152
|
-
async navigateToState(
|
|
153
|
-
toState: State,
|
|
154
|
-
fromState: State | undefined,
|
|
155
|
-
opts: NavigationOptions,
|
|
156
|
-
): Promise<State> {
|
|
157
|
-
const deps = this.#deps;
|
|
158
|
-
const transitionDeps = this.#transitionDeps;
|
|
159
|
-
|
|
160
|
-
if (transitionDeps.isTransitioning()) {
|
|
161
|
-
logger.warn(
|
|
162
|
-
"router.navigate",
|
|
163
|
-
"Concurrent navigation detected on shared router instance. " +
|
|
164
|
-
"For SSR, use cloneRouter() to create isolated instance per request.",
|
|
165
|
-
);
|
|
166
|
-
this.#currentController?.abort(
|
|
167
|
-
new RouterError(errorCodes.TRANSITION_CANCELLED),
|
|
168
|
-
);
|
|
169
|
-
deps.cancelNavigation();
|
|
170
|
-
}
|
|
184
|
+
this.#abortPreviousNavigation();
|
|
171
185
|
|
|
172
186
|
const controller = new AbortController();
|
|
173
187
|
|
|
@@ -195,7 +209,7 @@ export class NavigationNamespace {
|
|
|
195
209
|
|
|
196
210
|
try {
|
|
197
211
|
const { state: finalState, meta: transitionOutput } = await transition(
|
|
198
|
-
|
|
212
|
+
deps,
|
|
199
213
|
toState,
|
|
200
214
|
fromState,
|
|
201
215
|
opts,
|
|
@@ -206,7 +220,7 @@ export class NavigationNamespace {
|
|
|
206
220
|
finalState.name === constants.UNKNOWN_ROUTE ||
|
|
207
221
|
deps.hasRoute(finalState.name)
|
|
208
222
|
) {
|
|
209
|
-
const stateWithTransition =
|
|
223
|
+
const stateWithTransition = buildSuccessState(
|
|
210
224
|
finalState,
|
|
211
225
|
transitionOutput,
|
|
212
226
|
fromState,
|
|
@@ -216,9 +230,7 @@ export class NavigationNamespace {
|
|
|
216
230
|
deps.setState(stateWithTransition);
|
|
217
231
|
|
|
218
232
|
const transitionOpts =
|
|
219
|
-
opts.signal === undefined
|
|
220
|
-
? opts
|
|
221
|
-
: NavigationNamespace.#stripSignal(opts);
|
|
233
|
+
opts.signal === undefined ? opts : stripSignal(opts);
|
|
222
234
|
|
|
223
235
|
deps.sendTransitionDone(stateWithTransition, fromState, transitionOpts);
|
|
224
236
|
|
|
@@ -228,16 +240,16 @@ export class NavigationNamespace {
|
|
|
228
240
|
routeName: finalState.name,
|
|
229
241
|
});
|
|
230
242
|
|
|
231
|
-
deps.
|
|
243
|
+
deps.sendTransitionFail(finalState, fromState, err);
|
|
232
244
|
|
|
233
245
|
throw err;
|
|
234
246
|
}
|
|
235
247
|
} catch (error) {
|
|
236
|
-
|
|
248
|
+
routeTransitionError(deps, error, toState, fromState);
|
|
237
249
|
|
|
238
250
|
throw error;
|
|
239
251
|
} finally {
|
|
240
|
-
controller.abort();
|
|
252
|
+
controller.abort();
|
|
241
253
|
if (this.#currentController === controller) {
|
|
242
254
|
this.#currentController = null;
|
|
243
255
|
}
|
|
@@ -258,104 +270,77 @@ export class NavigationNamespace {
|
|
|
258
270
|
});
|
|
259
271
|
}
|
|
260
272
|
|
|
261
|
-
const
|
|
262
|
-
options.defaultRoute,
|
|
263
|
-
deps.getDependency,
|
|
264
|
-
);
|
|
273
|
+
const { route, params } = deps.resolveDefault();
|
|
265
274
|
|
|
266
|
-
if (!
|
|
275
|
+
if (!route) {
|
|
267
276
|
throw new RouterError(errorCodes.ROUTE_NOT_FOUND, {
|
|
268
277
|
routeName: "defaultRoute resolved to empty",
|
|
269
278
|
});
|
|
270
279
|
}
|
|
271
280
|
|
|
272
|
-
|
|
273
|
-
options.defaultParams,
|
|
274
|
-
deps.getDependency,
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
return this.navigate(resolvedRoute, resolvedParams, opts);
|
|
281
|
+
return this.navigate(route, params, opts);
|
|
278
282
|
}
|
|
279
283
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
*/
|
|
283
|
-
abortCurrentNavigation(): void {
|
|
284
|
-
this.#currentController?.abort(
|
|
285
|
-
new RouterError(errorCodes.TRANSITION_CANCELLED),
|
|
286
|
-
);
|
|
287
|
-
this.#currentController = null;
|
|
288
|
-
}
|
|
284
|
+
navigateToNotFound(path: string): State {
|
|
285
|
+
this.#abortPreviousNavigation();
|
|
289
286
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
287
|
+
const fromState = this.#deps.getState();
|
|
288
|
+
const deactivated: string[] = fromState
|
|
289
|
+
? nameToIDs(fromState.name).toReversed()
|
|
290
|
+
: [];
|
|
293
291
|
|
|
294
|
-
|
|
295
|
-
* Strips the non-serializable `signal` field from NavigationOptions.
|
|
296
|
-
*/
|
|
297
|
-
static #stripSignal(opts: NavigationOptions): NavigationOptions {
|
|
298
|
-
// eslint-disable-next-line sonarjs/no-unused-vars
|
|
299
|
-
const { signal: _, ...rest } = opts;
|
|
292
|
+
Object.freeze(deactivated);
|
|
300
293
|
|
|
301
|
-
|
|
302
|
-
|
|
294
|
+
const segments: TransitionMeta["segments"] = {
|
|
295
|
+
deactivated,
|
|
296
|
+
activated: FROZEN_ACTIVATED,
|
|
297
|
+
intersection: "",
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
Object.freeze(segments);
|
|
303
301
|
|
|
304
|
-
/**
|
|
305
|
-
* Builds the final state with frozen TransitionMeta attached.
|
|
306
|
-
*/
|
|
307
|
-
static #buildSuccessState(
|
|
308
|
-
finalState: State,
|
|
309
|
-
transitionOutput: TransitionOutput["meta"],
|
|
310
|
-
fromState: State | undefined,
|
|
311
|
-
opts: NavigationOptions,
|
|
312
|
-
): State {
|
|
313
302
|
const transitionMeta: TransitionMeta = {
|
|
314
|
-
phase:
|
|
315
|
-
...(fromState
|
|
303
|
+
phase: "activating",
|
|
304
|
+
...(fromState && { from: fromState.name }),
|
|
316
305
|
reason: "success",
|
|
317
|
-
segments
|
|
318
|
-
...(opts.reload !== undefined && { reload: opts.reload }),
|
|
319
|
-
...(opts.redirected !== undefined && { redirected: opts.redirected }),
|
|
306
|
+
segments,
|
|
320
307
|
};
|
|
321
308
|
|
|
322
|
-
Object.freeze(transitionMeta.segments.deactivated);
|
|
323
|
-
Object.freeze(transitionMeta.segments.activated);
|
|
324
|
-
Object.freeze(transitionMeta.segments);
|
|
325
309
|
Object.freeze(transitionMeta);
|
|
326
310
|
|
|
327
|
-
|
|
328
|
-
|
|
311
|
+
const state: State = {
|
|
312
|
+
name: constants.UNKNOWN_ROUTE,
|
|
313
|
+
params: {} as Params,
|
|
314
|
+
path,
|
|
329
315
|
transition: transitionMeta,
|
|
330
316
|
};
|
|
317
|
+
|
|
318
|
+
Object.freeze(state);
|
|
319
|
+
|
|
320
|
+
this.#deps.setState(state);
|
|
321
|
+
this.#deps.emitTransitionSuccess(state, fromState, FROZEN_REPLACE_OPTS);
|
|
322
|
+
|
|
323
|
+
return state;
|
|
331
324
|
}
|
|
332
325
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
fromState: State | undefined,
|
|
340
|
-
): void {
|
|
341
|
-
const routerError = error as RouterError;
|
|
342
|
-
|
|
343
|
-
// Already routed: cancel/stop sent CANCEL, sendTransitionError called in try block
|
|
344
|
-
if (
|
|
345
|
-
routerError.code === errorCodes.TRANSITION_CANCELLED ||
|
|
346
|
-
routerError.code === errorCodes.ROUTE_NOT_FOUND
|
|
347
|
-
) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
326
|
+
abortCurrentNavigation(): void {
|
|
327
|
+
this.#currentController?.abort(
|
|
328
|
+
new RouterError(errorCodes.TRANSITION_CANCELLED),
|
|
329
|
+
);
|
|
330
|
+
this.#currentController = null;
|
|
331
|
+
}
|
|
350
332
|
|
|
351
|
-
|
|
352
|
-
if (
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
this.#
|
|
333
|
+
#abortPreviousNavigation(): void {
|
|
334
|
+
if (this.#deps.isTransitioning()) {
|
|
335
|
+
logger.warn(
|
|
336
|
+
"router.navigate",
|
|
337
|
+
"Concurrent navigation detected on shared router instance. " +
|
|
338
|
+
"For SSR, use cloneRouter() to create isolated instance per request.",
|
|
339
|
+
);
|
|
340
|
+
this.#currentController?.abort(
|
|
341
|
+
new RouterError(errorCodes.TRANSITION_CANCELLED),
|
|
342
|
+
);
|
|
343
|
+
this.#deps.cancelNavigation();
|
|
359
344
|
}
|
|
360
345
|
}
|
|
361
346
|
}
|
|
@@ -5,11 +5,14 @@ import { constants, errorCodes } from "../../../constants";
|
|
|
5
5
|
import { RouterError } from "../../../RouterError";
|
|
6
6
|
import { getTransitionPath } from "../../../transitionPath";
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { NavigationDependencies, TransitionOutput } from "../types";
|
|
9
9
|
import type { NavigationOptions, State } from "@real-router/types";
|
|
10
10
|
|
|
11
11
|
export async function transition(
|
|
12
|
-
deps:
|
|
12
|
+
deps: Pick<
|
|
13
|
+
NavigationDependencies,
|
|
14
|
+
"getLifecycleFunctions" | "isActive" | "clearCanDeactivate"
|
|
15
|
+
>,
|
|
13
16
|
toState: State,
|
|
14
17
|
fromState: State | undefined,
|
|
15
18
|
opts: NavigationOptions,
|
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
*
|
|
17
17
|
* These are function references from other namespaces/facade,
|
|
18
18
|
* avoiding the need to pass the entire Router object.
|
|
19
|
-
|
|
19
|
+
**/
|
|
20
20
|
export interface NavigationDependencies {
|
|
21
21
|
/** Get router options */
|
|
22
22
|
getOptions: () => Options;
|
|
@@ -54,8 +54,8 @@ export interface NavigationDependencies {
|
|
|
54
54
|
ignoreQueryParams?: boolean,
|
|
55
55
|
) => boolean;
|
|
56
56
|
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/** Resolve defaultRoute and defaultParams options (static value or callback) */
|
|
58
|
+
resolveDefault: () => { route: string; params: Params };
|
|
59
59
|
|
|
60
60
|
/** Start transition and send NAVIGATE event to routerFSM */
|
|
61
61
|
startTransition: (toState: State, fromState: State | undefined) => void;
|
|
@@ -70,15 +70,8 @@ export interface NavigationDependencies {
|
|
|
70
70
|
opts: NavigationOptions,
|
|
71
71
|
) => void;
|
|
72
72
|
|
|
73
|
-
/** Send FAIL event to routerFSM
|
|
74
|
-
|
|
75
|
-
toState: State,
|
|
76
|
-
fromState: State | undefined,
|
|
77
|
-
error: unknown,
|
|
78
|
-
) => void;
|
|
79
|
-
|
|
80
|
-
/** Send FAIL event to routerFSM (transition error) */
|
|
81
|
-
sendTransitionError: (
|
|
73
|
+
/** Send FAIL event to routerFSM */
|
|
74
|
+
sendTransitionFail: (
|
|
82
75
|
toState: State,
|
|
83
76
|
fromState: State | undefined,
|
|
84
77
|
error: unknown,
|
|
@@ -90,24 +83,17 @@ export interface NavigationDependencies {
|
|
|
90
83
|
fromState: State | undefined,
|
|
91
84
|
error: unknown,
|
|
92
85
|
) => void;
|
|
93
|
-
}
|
|
94
86
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
};
|
|
105
|
-
}
|
|
87
|
+
/** Emit TRANSITION_SUCCESS event to listeners (without FSM transition) */
|
|
88
|
+
emitTransitionSuccess: (
|
|
89
|
+
toState: State,
|
|
90
|
+
fromState?: State,
|
|
91
|
+
opts?: NavigationOptions,
|
|
92
|
+
) => void;
|
|
93
|
+
|
|
94
|
+
/** Check if navigation can begin (router is started) */
|
|
95
|
+
canNavigate: () => boolean;
|
|
106
96
|
|
|
107
|
-
/**
|
|
108
|
-
* Dependencies required for the transition function.
|
|
109
|
-
*/
|
|
110
|
-
export interface TransitionDependencies {
|
|
111
97
|
/** Get lifecycle functions (canDeactivate, canActivate maps) */
|
|
112
98
|
getLifecycleFunctions: () => [Map<string, GuardFn>, Map<string, GuardFn>];
|
|
113
99
|
|
|
@@ -120,3 +106,15 @@ export interface TransitionDependencies {
|
|
|
120
106
|
/** Clear canDeactivate guard for a route */
|
|
121
107
|
clearCanDeactivate: (name: string) => void;
|
|
122
108
|
}
|
|
109
|
+
|
|
110
|
+
export interface TransitionOutput {
|
|
111
|
+
state: State;
|
|
112
|
+
meta: {
|
|
113
|
+
phase: TransitionPhase;
|
|
114
|
+
segments: {
|
|
115
|
+
deactivated: string[];
|
|
116
|
+
activated: string[];
|
|
117
|
+
intersection: string;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -12,7 +12,6 @@ import { DEFAULT_LIMITS } from "../../constants";
|
|
|
12
12
|
import { computeThresholds } from "../../helpers";
|
|
13
13
|
|
|
14
14
|
import type { PluginsDependencies } from "./types";
|
|
15
|
-
import type { Router } from "../../Router";
|
|
16
15
|
import type { Limits, PluginFactory } from "../../types";
|
|
17
16
|
import type {
|
|
18
17
|
DefaultDependencies,
|
|
@@ -32,7 +31,6 @@ export class PluginsNamespace<
|
|
|
32
31
|
readonly #plugins = new Set<PluginFactory<Dependencies>>();
|
|
33
32
|
readonly #unsubscribes = new Set<Unsubscribe>();
|
|
34
33
|
|
|
35
|
-
#router!: Router<Dependencies>;
|
|
36
34
|
#deps!: PluginsDependencies<Dependencies>;
|
|
37
35
|
#limits: Limits = DEFAULT_LIMITS;
|
|
38
36
|
|
|
@@ -77,10 +75,6 @@ export class PluginsNamespace<
|
|
|
77
75
|
// Dependency injection
|
|
78
76
|
// =========================================================================
|
|
79
77
|
|
|
80
|
-
setRouter(router: Router<Dependencies>): void {
|
|
81
|
-
this.#router = router;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
78
|
setDependencies(deps: PluginsDependencies<Dependencies>): void {
|
|
85
79
|
this.#deps = deps;
|
|
86
80
|
}
|
|
@@ -289,9 +283,7 @@ export class PluginsNamespace<
|
|
|
289
283
|
}
|
|
290
284
|
|
|
291
285
|
#startPlugin(pluginFactory: PluginFactory<Dependencies>): Unsubscribe {
|
|
292
|
-
|
|
293
|
-
// Plugin factories receive full router as part of their public API
|
|
294
|
-
const appliedPlugin = pluginFactory(this.#router, this.#deps.getDependency);
|
|
286
|
+
const appliedPlugin = this.#deps.compileFactory(pluginFactory);
|
|
295
287
|
|
|
296
288
|
PluginsNamespace.validatePlugin(appliedPlugin);
|
|
297
289
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// packages/core/src/namespaces/PluginsNamespace/types.ts
|
|
2
2
|
|
|
3
|
-
import type { EventMethodMap } from "../../types";
|
|
3
|
+
import type { EventMethodMap, PluginFactory } from "../../types";
|
|
4
4
|
import type {
|
|
5
5
|
DefaultDependencies,
|
|
6
6
|
EventName,
|
|
@@ -8,25 +8,15 @@ import type {
|
|
|
8
8
|
Unsubscribe,
|
|
9
9
|
} from "@real-router/types";
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Dependencies injected into PluginsNamespace.
|
|
13
|
-
*
|
|
14
|
-
* Note: Plugin factories still receive the router object directly
|
|
15
|
-
* as they need access to various router methods. This interface
|
|
16
|
-
* only covers the internal namespace operations.
|
|
17
|
-
*/
|
|
18
11
|
export interface PluginsDependencies<
|
|
19
12
|
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
20
13
|
> {
|
|
21
|
-
/** Add event listener for plugin subscription */
|
|
22
14
|
addEventListener: <E extends EventName>(
|
|
23
15
|
eventName: E,
|
|
24
16
|
cb: Plugin[EventMethodMap[E]],
|
|
25
17
|
) => Unsubscribe;
|
|
26
18
|
|
|
27
|
-
/** Check if navigation is possible (for warning about late onStart) */
|
|
28
19
|
canNavigate: () => boolean;
|
|
29
20
|
|
|
30
|
-
|
|
31
|
-
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K];
|
|
21
|
+
compileFactory: (factory: PluginFactory<Dependencies>) => Plugin;
|
|
32
22
|
}
|