@real-router/core 0.23.0 → 0.24.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/index.d.ts +14 -9
- 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 +14 -9
- 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 +4 -4
- package/src/Router.ts +4 -4
- package/src/index.ts +2 -0
- package/src/namespaces/CloneNamespace/types.ts +3 -3
- package/src/namespaces/MiddlewareNamespace/MiddlewareNamespace.ts +19 -4
- package/src/namespaces/MiddlewareNamespace/constants.ts +3 -0
- package/src/namespaces/MiddlewareNamespace/validators.ts +7 -8
- package/src/namespaces/NavigationNamespace/transition/executeLifecycleHooks.ts +11 -52
- package/src/namespaces/NavigationNamespace/transition/index.ts +3 -3
- package/src/namespaces/NavigationNamespace/transition/processLifecycleResult.ts +19 -31
- package/src/namespaces/NavigationNamespace/types.ts +2 -5
- package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +17 -2
- package/src/namespaces/PluginsNamespace/validators.ts +7 -3
- package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +28 -43
- package/src/namespaces/RouteLifecycleNamespace/validators.ts +2 -2
- package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +3 -3
- package/src/namespaces/RoutesNamespace/types.ts +3 -3
- package/src/typeGuards.ts +0 -1
- package/src/types.ts +16 -4
|
@@ -219,6 +219,13 @@ export class PluginsNamespace<
|
|
|
219
219
|
return this.#plugins.has(factory);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Disposes all registered plugins by running their teardown callbacks
|
|
224
|
+
* and removing event listener subscriptions.
|
|
225
|
+
* Unlike {@link MiddlewareNamespace.clearAll}, active disposal is required —
|
|
226
|
+
* plugins have an active lifecycle (event subscriptions, teardown hooks).
|
|
227
|
+
* Named "dispose" (not "clear") because there is active cleanup to perform.
|
|
228
|
+
*/
|
|
222
229
|
disposeAll(): void {
|
|
223
230
|
for (const unsubscribe of this.#unsubscribes) {
|
|
224
231
|
unsubscribe();
|
|
@@ -244,9 +251,17 @@ export class PluginsNamespace<
|
|
|
244
251
|
const { warn, error } = computeThresholds(maxPlugins);
|
|
245
252
|
|
|
246
253
|
if (totalCount >= error) {
|
|
247
|
-
logger.error(
|
|
254
|
+
logger.error(
|
|
255
|
+
LOGGER_CONTEXT,
|
|
256
|
+
`${totalCount} plugins registered! ` +
|
|
257
|
+
`This is excessive and will impact performance. ` +
|
|
258
|
+
`Hard limit at ${maxPlugins}.`,
|
|
259
|
+
);
|
|
248
260
|
} else if (totalCount >= warn) {
|
|
249
|
-
logger.warn(
|
|
261
|
+
logger.warn(
|
|
262
|
+
LOGGER_CONTEXT,
|
|
263
|
+
`${totalCount} plugins registered. ` + `Consider if all are necessary.`,
|
|
264
|
+
);
|
|
250
265
|
}
|
|
251
266
|
}
|
|
252
267
|
|
|
@@ -19,10 +19,10 @@ import type { DefaultDependencies, Plugin } from "@real-router/types";
|
|
|
19
19
|
export function validateUsePluginArgs<D extends DefaultDependencies>(
|
|
20
20
|
plugins: unknown[],
|
|
21
21
|
): asserts plugins is PluginFactory<D>[] {
|
|
22
|
-
for (const plugin of plugins) {
|
|
22
|
+
for (const [i, plugin] of plugins.entries()) {
|
|
23
23
|
if (typeof plugin !== "function") {
|
|
24
24
|
throw new TypeError(
|
|
25
|
-
`[router.usePlugin] Expected plugin factory function, got ${
|
|
25
|
+
`[router.usePlugin] Expected plugin factory function at index ${i}, got ${getTypeDescription(plugin)}`,
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -74,6 +74,10 @@ export function validatePluginLimit(
|
|
|
74
74
|
const totalCount = currentCount + newCount;
|
|
75
75
|
|
|
76
76
|
if (totalCount > maxPlugins) {
|
|
77
|
-
throw new Error(
|
|
77
|
+
throw new Error(
|
|
78
|
+
`[router.usePlugin] Plugin limit exceeded (${maxPlugins}). ` +
|
|
79
|
+
`Current: ${currentCount}, Attempting to add: ${newCount}. ` +
|
|
80
|
+
`This indicates an architectural problem. Consider consolidating plugins.`,
|
|
81
|
+
);
|
|
78
82
|
}
|
|
79
83
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/core/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts
|
|
2
2
|
|
|
3
3
|
import { logger } from "@real-router/logger";
|
|
4
|
-
import { isBoolean,
|
|
4
|
+
import { isBoolean, getTypeDescription } from "type-guards";
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
validateHandler,
|
|
@@ -13,23 +13,19 @@ import { computeThresholds } from "../../helpers";
|
|
|
13
13
|
|
|
14
14
|
import type { RouteLifecycleDependencies } from "./types";
|
|
15
15
|
import type { Router } from "../../Router";
|
|
16
|
-
import type {
|
|
17
|
-
import type {
|
|
18
|
-
ActivationFn,
|
|
19
|
-
DefaultDependencies,
|
|
20
|
-
State,
|
|
21
|
-
} from "@real-router/types";
|
|
16
|
+
import type { GuardFnFactory, Limits } from "../../types";
|
|
17
|
+
import type { DefaultDependencies, GuardFn, State } from "@real-router/types";
|
|
22
18
|
|
|
23
19
|
/**
|
|
24
|
-
* Converts a boolean value to
|
|
20
|
+
* Converts a boolean value to a guard function factory.
|
|
25
21
|
* Used for the shorthand syntax where true/false is passed instead of a function.
|
|
26
22
|
*/
|
|
27
23
|
function booleanToFactory<Dependencies extends DefaultDependencies>(
|
|
28
24
|
value: boolean,
|
|
29
|
-
):
|
|
30
|
-
const
|
|
25
|
+
): GuardFnFactory<Dependencies> {
|
|
26
|
+
const guardFn: GuardFn = () => value;
|
|
31
27
|
|
|
32
|
-
return () =>
|
|
28
|
+
return () => guardFn;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
/**
|
|
@@ -43,14 +39,14 @@ export class RouteLifecycleNamespace<
|
|
|
43
39
|
> {
|
|
44
40
|
readonly #canDeactivateFactories = new Map<
|
|
45
41
|
string,
|
|
46
|
-
|
|
42
|
+
GuardFnFactory<Dependencies>
|
|
47
43
|
>();
|
|
48
44
|
readonly #canActivateFactories = new Map<
|
|
49
45
|
string,
|
|
50
|
-
|
|
46
|
+
GuardFnFactory<Dependencies>
|
|
51
47
|
>();
|
|
52
|
-
readonly #canDeactivateFunctions = new Map<string,
|
|
53
|
-
readonly #canActivateFunctions = new Map<string,
|
|
48
|
+
readonly #canDeactivateFunctions = new Map<string, GuardFn>();
|
|
49
|
+
readonly #canActivateFunctions = new Map<string, GuardFn>();
|
|
54
50
|
|
|
55
51
|
readonly #registering = new Set<string>();
|
|
56
52
|
|
|
@@ -65,7 +61,7 @@ export class RouteLifecycleNamespace<
|
|
|
65
61
|
static validateHandler<D extends DefaultDependencies>(
|
|
66
62
|
handler: unknown,
|
|
67
63
|
methodName: string,
|
|
68
|
-
): asserts handler is
|
|
64
|
+
): asserts handler is GuardFnFactory<D> | boolean {
|
|
69
65
|
validateHandler<D>(handler, methodName);
|
|
70
66
|
}
|
|
71
67
|
|
|
@@ -95,7 +91,7 @@ export class RouteLifecycleNamespace<
|
|
|
95
91
|
*/
|
|
96
92
|
addCanActivate(
|
|
97
93
|
name: string,
|
|
98
|
-
handler:
|
|
94
|
+
handler: GuardFnFactory<Dependencies> | boolean,
|
|
99
95
|
skipValidation: boolean,
|
|
100
96
|
): void {
|
|
101
97
|
if (!skipValidation) {
|
|
@@ -137,7 +133,7 @@ export class RouteLifecycleNamespace<
|
|
|
137
133
|
*/
|
|
138
134
|
addCanDeactivate(
|
|
139
135
|
name: string,
|
|
140
|
-
handler:
|
|
136
|
+
handler: GuardFnFactory<Dependencies> | boolean,
|
|
141
137
|
skipValidation: boolean,
|
|
142
138
|
): void {
|
|
143
139
|
if (!skipValidation) {
|
|
@@ -208,17 +204,11 @@ export class RouteLifecycleNamespace<
|
|
|
208
204
|
* @returns Tuple of [canDeactivateFactories, canActivateFactories]
|
|
209
205
|
*/
|
|
210
206
|
getFactories(): [
|
|
211
|
-
Record<string,
|
|
212
|
-
Record<string,
|
|
207
|
+
Record<string, GuardFnFactory<Dependencies>>,
|
|
208
|
+
Record<string, GuardFnFactory<Dependencies>>,
|
|
213
209
|
] {
|
|
214
|
-
const deactivateRecord: Record<
|
|
215
|
-
|
|
216
|
-
ActivationFnFactory<Dependencies>
|
|
217
|
-
> = {};
|
|
218
|
-
const activateRecord: Record<
|
|
219
|
-
string,
|
|
220
|
-
ActivationFnFactory<Dependencies>
|
|
221
|
-
> = {};
|
|
210
|
+
const deactivateRecord: Record<string, GuardFnFactory<Dependencies>> = {};
|
|
211
|
+
const activateRecord: Record<string, GuardFnFactory<Dependencies>> = {};
|
|
222
212
|
|
|
223
213
|
for (const [name, factory] of this.#canDeactivateFactories) {
|
|
224
214
|
deactivateRecord[name] = factory;
|
|
@@ -236,7 +226,7 @@ export class RouteLifecycleNamespace<
|
|
|
236
226
|
*
|
|
237
227
|
* @returns Tuple of [canDeactivateFunctions, canActivateFunctions] as Maps
|
|
238
228
|
*/
|
|
239
|
-
getFunctions(): [Map<string,
|
|
229
|
+
getFunctions(): [Map<string, GuardFn>, Map<string, GuardFn>] {
|
|
240
230
|
return [this.#canDeactivateFunctions, this.#canActivateFunctions];
|
|
241
231
|
}
|
|
242
232
|
|
|
@@ -279,9 +269,9 @@ export class RouteLifecycleNamespace<
|
|
|
279
269
|
#registerHandler(
|
|
280
270
|
type: "activate" | "deactivate",
|
|
281
271
|
name: string,
|
|
282
|
-
handler:
|
|
283
|
-
factories: Map<string,
|
|
284
|
-
functions: Map<string,
|
|
272
|
+
handler: GuardFnFactory<Dependencies> | boolean,
|
|
273
|
+
factories: Map<string, GuardFnFactory<Dependencies>>,
|
|
274
|
+
functions: Map<string, GuardFn>,
|
|
285
275
|
methodName: string,
|
|
286
276
|
isOverwrite: boolean,
|
|
287
277
|
): void {
|
|
@@ -328,7 +318,7 @@ export class RouteLifecycleNamespace<
|
|
|
328
318
|
}
|
|
329
319
|
|
|
330
320
|
#checkGuardSync(
|
|
331
|
-
functions: Map<string,
|
|
321
|
+
functions: Map<string, GuardFn>,
|
|
332
322
|
name: string,
|
|
333
323
|
toState: State,
|
|
334
324
|
fromState: State | undefined,
|
|
@@ -347,17 +337,12 @@ export class RouteLifecycleNamespace<
|
|
|
347
337
|
return result;
|
|
348
338
|
}
|
|
349
339
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
340
|
+
logger.warn(
|
|
341
|
+
`router.${methodName}`,
|
|
342
|
+
`Guard for "${name}" returned a Promise. Sync check cannot resolve async guards — returning false.`,
|
|
343
|
+
);
|
|
358
344
|
|
|
359
|
-
|
|
360
|
-
return true;
|
|
345
|
+
return false;
|
|
361
346
|
} catch {
|
|
362
347
|
return false;
|
|
363
348
|
}
|
|
@@ -9,7 +9,7 @@ import { isBoolean, getTypeDescription } from "type-guards";
|
|
|
9
9
|
|
|
10
10
|
import { DEFAULT_LIMITS } from "../../constants";
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type { GuardFnFactory } from "../../types";
|
|
13
13
|
import type { DefaultDependencies } from "@real-router/types";
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -18,7 +18,7 @@ import type { DefaultDependencies } from "@real-router/types";
|
|
|
18
18
|
export function validateHandler<D extends DefaultDependencies>(
|
|
19
19
|
handler: unknown,
|
|
20
20
|
methodName: string,
|
|
21
|
-
): asserts handler is
|
|
21
|
+
): asserts handler is GuardFnFactory<D> | boolean {
|
|
22
22
|
if (!isBoolean(handler) && typeof handler !== "function") {
|
|
23
23
|
throw new TypeError(
|
|
24
24
|
`[router.${methodName}] Handler must be a boolean or factory function, ` +
|
|
@@ -39,8 +39,8 @@ import { getTransitionPath } from "../../transitionPath";
|
|
|
39
39
|
|
|
40
40
|
import type { RouteConfig, RoutesDependencies } from "./types";
|
|
41
41
|
import type {
|
|
42
|
-
ActivationFnFactory,
|
|
43
42
|
BuildStateResultWithSegments,
|
|
43
|
+
GuardFnFactory,
|
|
44
44
|
Route,
|
|
45
45
|
RouteConfigUpdate,
|
|
46
46
|
} from "../../types";
|
|
@@ -85,14 +85,14 @@ export class RoutesNamespace<
|
|
|
85
85
|
// Key: route name, Value: canActivate factory
|
|
86
86
|
readonly #pendingCanActivate = new Map<
|
|
87
87
|
string,
|
|
88
|
-
|
|
88
|
+
GuardFnFactory<Dependencies>
|
|
89
89
|
>();
|
|
90
90
|
|
|
91
91
|
// Pending canDeactivate handlers that need to be registered after router is set
|
|
92
92
|
// Key: route name, Value: canDeactivate factory
|
|
93
93
|
readonly #pendingCanDeactivate = new Map<
|
|
94
94
|
string,
|
|
95
|
-
|
|
95
|
+
GuardFnFactory<Dependencies>
|
|
96
96
|
>();
|
|
97
97
|
|
|
98
98
|
#rootPath = "";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// packages/core/src/namespaces/RoutesNamespace/types.ts
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { GuardFnFactory } from "../../types";
|
|
4
4
|
import type {
|
|
5
5
|
DefaultDependencies,
|
|
6
6
|
ForwardToCallback,
|
|
@@ -22,13 +22,13 @@ export interface RoutesDependencies<
|
|
|
22
22
|
/** Register canActivate handler for a route */
|
|
23
23
|
addActivateGuard: (
|
|
24
24
|
name: string,
|
|
25
|
-
handler:
|
|
25
|
+
handler: GuardFnFactory<Dependencies>,
|
|
26
26
|
) => void;
|
|
27
27
|
|
|
28
28
|
/** Register canDeactivate handler for a route */
|
|
29
29
|
addDeactivateGuard: (
|
|
30
30
|
name: string,
|
|
31
|
-
handler:
|
|
31
|
+
handler: GuardFnFactory<Dependencies>,
|
|
32
32
|
) => void;
|
|
33
33
|
|
|
34
34
|
/** Create state object */
|
package/src/typeGuards.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
DefaultDependencies,
|
|
15
15
|
EventsKeys,
|
|
16
16
|
ForwardToCallback,
|
|
17
|
+
GuardFn,
|
|
17
18
|
LimitsConfig,
|
|
18
19
|
Middleware,
|
|
19
20
|
NavigationOptions,
|
|
@@ -81,9 +82,9 @@ export interface Route<
|
|
|
81
82
|
/** URL path pattern for this route. */
|
|
82
83
|
path: string;
|
|
83
84
|
/** Factory function that returns a guard for route activation. */
|
|
84
|
-
canActivate?:
|
|
85
|
+
canActivate?: GuardFnFactory<Dependencies>;
|
|
85
86
|
/** Factory function that returns a guard for route deactivation. */
|
|
86
|
-
canDeactivate?:
|
|
87
|
+
canDeactivate?: GuardFnFactory<Dependencies>;
|
|
87
88
|
/**
|
|
88
89
|
* Redirects navigation to another route.
|
|
89
90
|
*
|
|
@@ -155,9 +156,9 @@ export interface RouteConfigUpdate<
|
|
|
155
156
|
/** Set to null to remove encoder */
|
|
156
157
|
encodeParams?: ((params: Params) => Params) | null;
|
|
157
158
|
/** Set to null to remove canActivate */
|
|
158
|
-
canActivate?:
|
|
159
|
+
canActivate?: GuardFnFactory<Dependencies> | null;
|
|
159
160
|
/** Set to null to remove canDeactivate */
|
|
160
|
-
canDeactivate?:
|
|
161
|
+
canDeactivate?: GuardFnFactory<Dependencies> | null;
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
/**
|
|
@@ -171,6 +172,17 @@ export type ActivationFnFactory<
|
|
|
171
172
|
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K],
|
|
172
173
|
) => ActivationFn;
|
|
173
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Factory function for creating guards.
|
|
177
|
+
* Receives the router instance and a dependency getter.
|
|
178
|
+
*/
|
|
179
|
+
export type GuardFnFactory<
|
|
180
|
+
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
181
|
+
> = (
|
|
182
|
+
router: Router<Dependencies>,
|
|
183
|
+
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K],
|
|
184
|
+
) => GuardFn;
|
|
185
|
+
|
|
174
186
|
/**
|
|
175
187
|
* Factory function for creating middleware.
|
|
176
188
|
* Receives the router instance and a dependency getter.
|