@real-router/core 0.25.4 → 0.26.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/README.md +163 -325
- package/dist/cjs/index.d.ts +47 -178
- 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 +47 -178
- 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 +3 -3
- package/src/Router.ts +84 -574
- package/src/api/cloneRouter.ts +106 -0
- package/src/api/getDependenciesApi.ts +216 -0
- package/src/api/getLifecycleApi.ts +67 -0
- package/src/api/getPluginApi.ts +118 -0
- package/src/api/getRoutesApi.ts +566 -0
- package/src/api/index.ts +16 -0
- package/src/api/types.ts +7 -0
- package/src/getNavigator.ts +5 -2
- package/src/index.ts +17 -3
- package/src/internals.ts +115 -0
- package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +30 -0
- package/src/namespaces/DependenciesNamespace/index.ts +3 -1
- package/src/namespaces/DependenciesNamespace/validators.ts +2 -4
- package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +1 -20
- package/src/namespaces/EventBusNamespace/validators.ts +36 -0
- package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +1 -10
- package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +2 -0
- package/src/namespaces/NavigationNamespace/transition/{executeLifecycleHooks.ts → executeLifecycleGuards.ts} +9 -7
- package/src/namespaces/NavigationNamespace/transition/index.ts +3 -3
- package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +1 -16
- package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +133 -1089
- package/src/namespaces/RoutesNamespace/forwardToValidation.ts +411 -0
- package/src/namespaces/RoutesNamespace/helpers.ts +1 -407
- package/src/namespaces/RoutesNamespace/index.ts +2 -0
- package/src/namespaces/RoutesNamespace/routesStore.ts +388 -0
- package/src/namespaces/RoutesNamespace/validators.ts +209 -3
- package/src/namespaces/StateNamespace/StateNamespace.ts +1 -44
- package/src/namespaces/StateNamespace/validators.ts +46 -0
- package/src/namespaces/index.ts +3 -5
- package/src/types.ts +12 -138
- package/src/wiring/RouterWiringBuilder.ts +30 -36
- package/src/wiring/types.ts +3 -6
- package/src/wiring/wireRouter.ts +0 -1
- package/src/namespaces/CloneNamespace/CloneNamespace.ts +0 -120
- package/src/namespaces/CloneNamespace/index.ts +0 -3
- package/src/namespaces/CloneNamespace/types.ts +0 -42
- package/src/namespaces/DependenciesNamespace/DependenciesNamespace.ts +0 -248
- package/src/namespaces/RoutesNamespace/stateBuilder.ts +0 -70
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// packages/core/src/namespaces/StateNamespace/validators.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Static validation functions for StateNamespace.
|
|
5
|
+
* Called by Router facade before instance methods.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { isString, isParams, getTypeDescription } from "type-guards";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validates makeState arguments.
|
|
12
|
+
*/
|
|
13
|
+
export function validateMakeStateArgs(
|
|
14
|
+
name: unknown,
|
|
15
|
+
params: unknown,
|
|
16
|
+
path: unknown,
|
|
17
|
+
forceId: unknown,
|
|
18
|
+
): void {
|
|
19
|
+
// Validate name is a string
|
|
20
|
+
if (!isString(name)) {
|
|
21
|
+
throw new TypeError(
|
|
22
|
+
`[router.makeState] Invalid name: ${getTypeDescription(name)}. Expected string.`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Validate params if provided
|
|
27
|
+
if (params !== undefined && !isParams(params)) {
|
|
28
|
+
throw new TypeError(
|
|
29
|
+
`[router.makeState] Invalid params: ${getTypeDescription(params)}. Expected plain object.`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Validate path if provided
|
|
34
|
+
if (path !== undefined && !isString(path)) {
|
|
35
|
+
throw new TypeError(
|
|
36
|
+
`[router.makeState] Invalid path: ${getTypeDescription(path)}. Expected string.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validate forceId if provided
|
|
41
|
+
if (forceId !== undefined && typeof forceId !== "number") {
|
|
42
|
+
throw new TypeError(
|
|
43
|
+
`[router.makeState] Invalid forceId: ${getTypeDescription(forceId)}. Expected number.`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/namespaces/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// packages/core/src/namespaces/index.ts
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { createDependenciesStore } from "./DependenciesNamespace";
|
|
4
|
+
|
|
5
|
+
export type { DependenciesStore } from "./DependenciesNamespace";
|
|
4
6
|
|
|
5
7
|
export {
|
|
6
8
|
deepFreeze,
|
|
@@ -33,8 +35,4 @@ export { NavigationNamespace } from "./NavigationNamespace";
|
|
|
33
35
|
|
|
34
36
|
export { RouterLifecycleNamespace } from "./RouterLifecycleNamespace";
|
|
35
37
|
|
|
36
|
-
export { CloneNamespace } from "./CloneNamespace";
|
|
37
|
-
|
|
38
|
-
export type { ApplyConfigFn, CloneData, RouterFactory } from "./CloneNamespace";
|
|
39
|
-
|
|
40
38
|
export { EventBusNamespace } from "./EventBusNamespace";
|
package/src/types.ts
CHANGED
|
@@ -1,32 +1,30 @@
|
|
|
1
1
|
// packages/core/src/types.ts
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Core-internal types + re-exports from @real-router/types.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Factory types (PluginFactory, GuardFnFactory) and
|
|
7
|
+
* route config types (Route, RouteConfigUpdate) are canonical in @real-router/types
|
|
8
|
+
* and re-exported here for backward compatibility.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
|
-
import type { events, plugins } from "./constants";
|
|
11
|
-
import type { Router } from "./Router";
|
|
12
11
|
import type {
|
|
13
|
-
ActivationFn,
|
|
14
|
-
DefaultDependencies,
|
|
15
|
-
EventsKeys,
|
|
16
|
-
ForwardToCallback,
|
|
17
|
-
GuardFn,
|
|
18
12
|
LimitsConfig,
|
|
19
13
|
NavigationOptions,
|
|
20
14
|
Params,
|
|
21
|
-
Plugin,
|
|
22
15
|
RouterError as RouterErrorType,
|
|
23
16
|
RouteTreeState,
|
|
24
17
|
State,
|
|
25
18
|
} from "@real-router/types";
|
|
26
19
|
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
// Re-export from @real-router/types (canonical source)
|
|
21
|
+
export type {
|
|
22
|
+
GuardFnFactory,
|
|
23
|
+
PluginFactory,
|
|
24
|
+
Route,
|
|
25
|
+
RouteConfigUpdate,
|
|
26
|
+
EventMethodMap,
|
|
27
|
+
} from "@real-router/types";
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
* Event argument tuples for the router's 6 events.
|
|
@@ -68,127 +66,3 @@ export interface BuildStateResultWithSegments<P extends Params = Params> {
|
|
|
68
66
|
readonly state: RouteTreeState<P>;
|
|
69
67
|
readonly segments: readonly unknown[];
|
|
70
68
|
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Route configuration.
|
|
74
|
-
*/
|
|
75
|
-
export interface Route<
|
|
76
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
77
|
-
> {
|
|
78
|
-
[key: string]: unknown;
|
|
79
|
-
/** Route name (dot-separated for nested routes). */
|
|
80
|
-
name: string;
|
|
81
|
-
/** URL path pattern for this route. */
|
|
82
|
-
path: string;
|
|
83
|
-
/** Factory function that returns a guard for route activation. */
|
|
84
|
-
canActivate?: GuardFnFactory<Dependencies>;
|
|
85
|
-
/** Factory function that returns a guard for route deactivation. */
|
|
86
|
-
canDeactivate?: GuardFnFactory<Dependencies>;
|
|
87
|
-
/**
|
|
88
|
-
* Redirects navigation to another route.
|
|
89
|
-
*
|
|
90
|
-
* IMPORTANT: forwardTo creates a URL alias, not a transition chain.
|
|
91
|
-
* Guards (canActivate) on the source route are NOT executed.
|
|
92
|
-
* Only guards on the final destination are executed.
|
|
93
|
-
*
|
|
94
|
-
* This matches Vue Router and Angular Router behavior.
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* // Correct: guard on target
|
|
98
|
-
* { name: "old", path: "/old", forwardTo: "new" }
|
|
99
|
-
* { name: "new", path: "/new", canActivate: myGuard }
|
|
100
|
-
*
|
|
101
|
-
* // Wrong: guard on source (will be ignored with warning)
|
|
102
|
-
* { name: "old", path: "/old", forwardTo: "new", canActivate: myGuard }
|
|
103
|
-
*/
|
|
104
|
-
forwardTo?: string | ForwardToCallback<Dependencies>;
|
|
105
|
-
/** Nested child routes. */
|
|
106
|
-
children?: Route<Dependencies>[];
|
|
107
|
-
/** Encodes state params to URL params. */
|
|
108
|
-
encodeParams?: (stateParams: Params) => Params;
|
|
109
|
-
/** Decodes URL params to state params. */
|
|
110
|
-
decodeParams?: (pathParams: Params) => Params;
|
|
111
|
-
/**
|
|
112
|
-
* Default parameters for this route.
|
|
113
|
-
*
|
|
114
|
-
* @remarks
|
|
115
|
-
* **Type Contract:**
|
|
116
|
-
* The type of defaultParams MUST match the expected params type P
|
|
117
|
-
* when using `router.makeState<P>()` or `router.navigate<P>()`.
|
|
118
|
-
*
|
|
119
|
-
* These values are merged into state.params when creating route states.
|
|
120
|
-
* Missing URL params are filled from defaultParams.
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* ```typescript
|
|
124
|
-
* // Define route with pagination defaults
|
|
125
|
-
* {
|
|
126
|
-
* name: "users",
|
|
127
|
-
* path: "/users",
|
|
128
|
-
* defaultParams: { page: 1, limit: 10 }
|
|
129
|
-
* }
|
|
130
|
-
*
|
|
131
|
-
* // Navigate without specifying page/limit
|
|
132
|
-
* router.navigate("users", { filter: "active" });
|
|
133
|
-
* // Result: state.params = { page: 1, limit: 10, filter: "active" }
|
|
134
|
-
*
|
|
135
|
-
* // Correct typing — include defaultParams properties
|
|
136
|
-
* type UsersParams = { page: number; limit: number; filter?: string };
|
|
137
|
-
* ```
|
|
138
|
-
*/
|
|
139
|
-
defaultParams?: Params;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Configuration update options for updateRoute().
|
|
144
|
-
* All properties are optional. Set to null to remove the configuration.
|
|
145
|
-
*/
|
|
146
|
-
export interface RouteConfigUpdate<
|
|
147
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
148
|
-
> {
|
|
149
|
-
/** Set to null to remove forwardTo */
|
|
150
|
-
forwardTo?: string | ForwardToCallback<Dependencies> | null;
|
|
151
|
-
/** Set to null to remove defaultParams */
|
|
152
|
-
defaultParams?: Params | null;
|
|
153
|
-
/** Set to null to remove decoder */
|
|
154
|
-
decodeParams?: ((params: Params) => Params) | null;
|
|
155
|
-
/** Set to null to remove encoder */
|
|
156
|
-
encodeParams?: ((params: Params) => Params) | null;
|
|
157
|
-
/** Set to null to remove canActivate */
|
|
158
|
-
canActivate?: GuardFnFactory<Dependencies> | null;
|
|
159
|
-
/** Set to null to remove canDeactivate */
|
|
160
|
-
canDeactivate?: GuardFnFactory<Dependencies> | null;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Factory function for creating activation guards.
|
|
165
|
-
* Receives the router instance and a dependency getter.
|
|
166
|
-
*/
|
|
167
|
-
export type ActivationFnFactory<
|
|
168
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
169
|
-
> = (
|
|
170
|
-
router: Router<Dependencies>,
|
|
171
|
-
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K],
|
|
172
|
-
) => ActivationFn;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Factory function for creating guards.
|
|
176
|
-
* Receives the router instance and a dependency getter.
|
|
177
|
-
*/
|
|
178
|
-
export type GuardFnFactory<
|
|
179
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
180
|
-
> = (
|
|
181
|
-
router: Router<Dependencies>,
|
|
182
|
-
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K],
|
|
183
|
-
) => GuardFn;
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Factory function for creating plugins.
|
|
187
|
-
* Receives the router instance and a dependency getter.
|
|
188
|
-
*/
|
|
189
|
-
export type PluginFactory<
|
|
190
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
191
|
-
> = (
|
|
192
|
-
router: Router<Dependencies>,
|
|
193
|
-
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K],
|
|
194
|
-
) => Plugin;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// packages/core/src/wiring/RouterWiringBuilder.ts
|
|
2
2
|
|
|
3
|
+
import { getInternals } from "../internals";
|
|
4
|
+
import { validateStateBuilderArgs } from "../namespaces/RoutesNamespace/validators";
|
|
5
|
+
|
|
3
6
|
import type { EventBusNamespace } from "../namespaces";
|
|
4
7
|
import type { WiringOptions } from "./types";
|
|
5
8
|
import type {
|
|
@@ -18,33 +21,31 @@ export class RouterWiringBuilder<
|
|
|
18
21
|
private readonly router: WiringOptions<Dependencies>["router"];
|
|
19
22
|
private readonly options: WiringOptions<Dependencies>["options"];
|
|
20
23
|
private readonly limits: WiringOptions<Dependencies>["limits"];
|
|
21
|
-
private readonly
|
|
24
|
+
private readonly dependenciesStore: WiringOptions<Dependencies>["dependenciesStore"];
|
|
22
25
|
private readonly state: WiringOptions<Dependencies>["state"];
|
|
23
26
|
private readonly routes: WiringOptions<Dependencies>["routes"];
|
|
24
27
|
private readonly routeLifecycle: WiringOptions<Dependencies>["routeLifecycle"];
|
|
25
28
|
private readonly plugins: WiringOptions<Dependencies>["plugins"];
|
|
26
29
|
private readonly navigation: WiringOptions<Dependencies>["navigation"];
|
|
27
30
|
private readonly lifecycle: WiringOptions<Dependencies>["lifecycle"];
|
|
28
|
-
private readonly clone: WiringOptions<Dependencies>["clone"];
|
|
29
31
|
private readonly eventBus: EventBusNamespace;
|
|
30
32
|
|
|
31
33
|
constructor(wiringOptions: WiringOptions<Dependencies>) {
|
|
32
34
|
this.router = wiringOptions.router;
|
|
33
35
|
this.options = wiringOptions.options;
|
|
34
36
|
this.limits = wiringOptions.limits;
|
|
35
|
-
this.
|
|
37
|
+
this.dependenciesStore = wiringOptions.dependenciesStore;
|
|
36
38
|
this.state = wiringOptions.state;
|
|
37
39
|
this.routes = wiringOptions.routes;
|
|
38
40
|
this.routeLifecycle = wiringOptions.routeLifecycle;
|
|
39
41
|
this.plugins = wiringOptions.plugins;
|
|
40
42
|
this.navigation = wiringOptions.navigation;
|
|
41
43
|
this.lifecycle = wiringOptions.lifecycle;
|
|
42
|
-
this.clone = wiringOptions.clone;
|
|
43
44
|
this.eventBus = wiringOptions.eventBus;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
wireLimits(): void {
|
|
47
|
-
this.
|
|
48
|
+
this.dependenciesStore.limits = this.limits;
|
|
48
49
|
this.plugins.setLimits(this.limits);
|
|
49
50
|
this.eventBus.setLimits({
|
|
50
51
|
maxListeners: this.limits.maxListeners,
|
|
@@ -59,7 +60,7 @@ export class RouterWiringBuilder<
|
|
|
59
60
|
|
|
60
61
|
const routeLifecycleDeps: RouteLifecycleDependencies<Dependencies> = {
|
|
61
62
|
getDependency: <K extends keyof Dependencies>(dependencyName: K) =>
|
|
62
|
-
this.dependencies
|
|
63
|
+
this.dependenciesStore.dependencies[dependencyName] as Dependencies[K],
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
this.routeLifecycle.setDependencies(routeLifecycleDeps);
|
|
@@ -68,18 +69,27 @@ export class RouterWiringBuilder<
|
|
|
68
69
|
wireRoutesDeps(): void {
|
|
69
70
|
const routesDeps: RoutesDependencies<Dependencies> = {
|
|
70
71
|
addActivateGuard: (name, handler) => {
|
|
71
|
-
this.
|
|
72
|
+
this.routeLifecycle.addCanActivate(name, handler, true);
|
|
72
73
|
},
|
|
73
74
|
addDeactivateGuard: (name, handler) => {
|
|
74
|
-
this.
|
|
75
|
+
this.routeLifecycle.addCanDeactivate(name, handler, true);
|
|
75
76
|
},
|
|
76
77
|
makeState: (name, params, path, meta) =>
|
|
77
78
|
this.state.makeState(name, params, path, meta),
|
|
78
79
|
getState: () => this.state.get(),
|
|
79
80
|
areStatesEqual: (state1, state2, ignoreQueryParams) =>
|
|
80
81
|
this.state.areStatesEqual(state1, state2, ignoreQueryParams),
|
|
81
|
-
getDependency: (name) =>
|
|
82
|
-
|
|
82
|
+
getDependency: (name) =>
|
|
83
|
+
this.dependenciesStore.dependencies[name] as Dependencies[typeof name],
|
|
84
|
+
forwardState: (name, params) => {
|
|
85
|
+
const ctx = getInternals(this.router);
|
|
86
|
+
|
|
87
|
+
if (!ctx.noValidate) {
|
|
88
|
+
validateStateBuilderArgs(name, params, "forwardState");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return ctx.forwardState(name, params);
|
|
92
|
+
},
|
|
83
93
|
};
|
|
84
94
|
|
|
85
95
|
this.routes.setDependencies(routesDeps);
|
|
@@ -94,7 +104,7 @@ export class RouterWiringBuilder<
|
|
|
94
104
|
this.eventBus.addEventListener(eventName, cb),
|
|
95
105
|
canNavigate: () => this.eventBus.canBeginTransition(),
|
|
96
106
|
getDependency: <K extends keyof Dependencies>(dependencyName: K) =>
|
|
97
|
-
this.dependencies
|
|
107
|
+
this.dependenciesStore.dependencies[dependencyName] as Dependencies[K],
|
|
98
108
|
};
|
|
99
109
|
|
|
100
110
|
this.plugins.setDependencies(pluginsDeps);
|
|
@@ -109,10 +119,13 @@ export class RouterWiringBuilder<
|
|
|
109
119
|
this.state.set(state);
|
|
110
120
|
},
|
|
111
121
|
buildStateWithSegments: (routeName, routeParams) => {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
const ctx = getInternals(this.router);
|
|
123
|
+
|
|
124
|
+
if (!ctx.noValidate) {
|
|
125
|
+
validateStateBuilderArgs(routeName, routeParams, "navigate");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const { name, params } = ctx.forwardState(routeName, routeParams);
|
|
116
129
|
|
|
117
130
|
return this.routes.buildStateWithSegmentsResolved(name, params);
|
|
118
131
|
},
|
|
@@ -123,7 +136,7 @@ export class RouterWiringBuilder<
|
|
|
123
136
|
areStatesEqual: (state1, state2, ignoreQueryParams) =>
|
|
124
137
|
this.state.areStatesEqual(state1, state2, ignoreQueryParams),
|
|
125
138
|
getDependency: (name: string) =>
|
|
126
|
-
this.dependencies
|
|
139
|
+
this.dependenciesStore.dependencies[name as keyof Dependencies],
|
|
127
140
|
startTransition: (toState, fromState) => {
|
|
128
141
|
this.eventBus.beginTransition(toState, fromState);
|
|
129
142
|
},
|
|
@@ -183,32 +196,13 @@ export class RouterWiringBuilder<
|
|
|
183
196
|
|
|
184
197
|
wireStateDeps(): void {
|
|
185
198
|
this.state.setDependencies({
|
|
186
|
-
getDefaultParams: () => this.routes.
|
|
199
|
+
getDefaultParams: () => this.routes.getStore().config.defaultParams,
|
|
187
200
|
buildPath: (name, params) =>
|
|
188
201
|
this.routes.buildPath(name, params, this.options.get()),
|
|
189
202
|
getUrlParams: (name) => this.routes.getUrlParams(name),
|
|
190
203
|
});
|
|
191
204
|
}
|
|
192
205
|
|
|
193
|
-
wireCloneCallbacks(): void {
|
|
194
|
-
this.clone.setGetCloneData(() => {
|
|
195
|
-
const [canDeactivateFactories, canActivateFactories] =
|
|
196
|
-
this.routeLifecycle.getFactories();
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
routes: this.routes.cloneRoutes(),
|
|
200
|
-
options: { ...this.options.get() },
|
|
201
|
-
dependencies: this.dependencies.getAll(),
|
|
202
|
-
canDeactivateFactories,
|
|
203
|
-
canActivateFactories,
|
|
204
|
-
pluginFactories: this.plugins.getAll(),
|
|
205
|
-
routeConfig: this.routes.getConfig(),
|
|
206
|
-
resolvedForwardMap: this.routes.getResolvedForwardMap(),
|
|
207
|
-
routeCustomFields: this.routes.getRouteCustomFields(),
|
|
208
|
-
};
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
206
|
wireCyclicDeps(): void {
|
|
213
207
|
this.navigation.setCanNavigate(() => this.eventBus.canBeginTransition());
|
|
214
208
|
|
package/src/wiring/types.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// packages/core/src/wiring/types.ts
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
CloneNamespace,
|
|
5
|
-
DependenciesNamespace,
|
|
6
4
|
EventBusNamespace,
|
|
7
5
|
NavigationNamespace,
|
|
8
6
|
OptionsNamespace,
|
|
@@ -12,6 +10,7 @@ import type {
|
|
|
12
10
|
RoutesNamespace,
|
|
13
11
|
StateNamespace,
|
|
14
12
|
} from "../namespaces";
|
|
13
|
+
import type { DependenciesStore } from "../namespaces/DependenciesNamespace/dependenciesStore";
|
|
15
14
|
import type { Router } from "../Router";
|
|
16
15
|
import type { Limits } from "../types";
|
|
17
16
|
import type { DefaultDependencies } from "@real-router/types";
|
|
@@ -29,8 +28,8 @@ export interface WiringOptions<Dependencies extends DefaultDependencies> {
|
|
|
29
28
|
options: OptionsNamespace;
|
|
30
29
|
/** Immutable limits configuration */
|
|
31
30
|
limits: Limits;
|
|
32
|
-
/** Dependencies
|
|
33
|
-
|
|
31
|
+
/** Dependencies store */
|
|
32
|
+
dependenciesStore: DependenciesStore<Dependencies>;
|
|
34
33
|
/** State namespace */
|
|
35
34
|
state: StateNamespace;
|
|
36
35
|
/** Routes namespace */
|
|
@@ -43,8 +42,6 @@ export interface WiringOptions<Dependencies extends DefaultDependencies> {
|
|
|
43
42
|
navigation: NavigationNamespace;
|
|
44
43
|
/** Router lifecycle namespace (start/stop) */
|
|
45
44
|
lifecycle: RouterLifecycleNamespace;
|
|
46
|
-
/** Clone namespace (SSR cloning) */
|
|
47
|
-
clone: CloneNamespace<Dependencies>;
|
|
48
45
|
/** EventBus namespace — unified FSM + EventEmitter abstraction */
|
|
49
46
|
eventBus: EventBusNamespace;
|
|
50
47
|
}
|
package/src/wiring/wireRouter.ts
CHANGED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// packages/core/src/namespaces/CloneNamespace/CloneNamespace.ts
|
|
2
|
-
|
|
3
|
-
import { getTypeDescription } from "type-guards";
|
|
4
|
-
|
|
5
|
-
import type { ApplyConfigFn, CloneData, RouterFactory } from "./types";
|
|
6
|
-
import type { Router } from "../../Router";
|
|
7
|
-
import type { DefaultDependencies } from "@real-router/types";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Independent namespace for router cloning operations.
|
|
11
|
-
*
|
|
12
|
-
* This namespace handles the logic of collecting data from a source router
|
|
13
|
-
* and creating a configured clone. It requires a factory function to create
|
|
14
|
-
* the new router instance.
|
|
15
|
-
*/
|
|
16
|
-
export class CloneNamespace<
|
|
17
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
18
|
-
> {
|
|
19
|
-
// =========================================================================
|
|
20
|
-
// Instance fields
|
|
21
|
-
// =========================================================================
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Function to get cloning data from the source router.
|
|
25
|
-
*/
|
|
26
|
-
#getCloneData!: () => CloneData<Dependencies>;
|
|
27
|
-
|
|
28
|
-
// =========================================================================
|
|
29
|
-
// Static validation methods (called by facade before instance methods)
|
|
30
|
-
// =========================================================================
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Validates clone arguments.
|
|
34
|
-
* Dependencies can be undefined or a plain object without getters.
|
|
35
|
-
*/
|
|
36
|
-
static validateCloneArgs(dependencies: unknown): void {
|
|
37
|
-
// undefined is valid (no new dependencies)
|
|
38
|
-
if (dependencies === undefined) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Must be a plain object
|
|
43
|
-
if (
|
|
44
|
-
!(
|
|
45
|
-
dependencies &&
|
|
46
|
-
typeof dependencies === "object" &&
|
|
47
|
-
dependencies.constructor === Object
|
|
48
|
-
)
|
|
49
|
-
) {
|
|
50
|
-
throw new TypeError(
|
|
51
|
-
`[router.clone] Invalid dependencies: expected plain object or undefined, received ${getTypeDescription(dependencies)}`,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Getters can throw, return different values, or have side effects
|
|
56
|
-
for (const key in dependencies) {
|
|
57
|
-
if (Object.getOwnPropertyDescriptor(dependencies, key)?.get) {
|
|
58
|
-
throw new TypeError(
|
|
59
|
-
`[router.clone] Getters not allowed in dependencies: "${key}"`,
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Sets the function to collect clone data.
|
|
67
|
-
*/
|
|
68
|
-
setGetCloneData(getCloneData: () => CloneData<Dependencies>): void {
|
|
69
|
-
this.#getCloneData = getCloneData;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Creates a clone of the router with optional new dependencies.
|
|
74
|
-
*
|
|
75
|
-
* @param dependencies - Optional new dependencies for the cloned router
|
|
76
|
-
* @param factory - Factory function to create the new router instance
|
|
77
|
-
* @param applyConfig - Function to apply route config to the new router
|
|
78
|
-
*/
|
|
79
|
-
clone(
|
|
80
|
-
dependencies: Dependencies | undefined,
|
|
81
|
-
factory: RouterFactory<Dependencies>,
|
|
82
|
-
applyConfig: ApplyConfigFn<Dependencies>,
|
|
83
|
-
): Router<Dependencies> {
|
|
84
|
-
// Collect all data from source router
|
|
85
|
-
const data = this.#getCloneData();
|
|
86
|
-
|
|
87
|
-
// Merge dependencies
|
|
88
|
-
const mergedDeps = {
|
|
89
|
-
...data.dependencies,
|
|
90
|
-
...dependencies,
|
|
91
|
-
} as Dependencies;
|
|
92
|
-
|
|
93
|
-
// Create new router instance
|
|
94
|
-
const newRouter = factory(data.routes, data.options, mergedDeps);
|
|
95
|
-
|
|
96
|
-
// Copy lifecycle factories
|
|
97
|
-
for (const [name, handler] of Object.entries(data.canDeactivateFactories)) {
|
|
98
|
-
newRouter.addDeactivateGuard(name, handler);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
for (const [name, handler] of Object.entries(data.canActivateFactories)) {
|
|
102
|
-
newRouter.addActivateGuard(name, handler);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Copy plugin factories
|
|
106
|
-
if (data.pluginFactories.length > 0) {
|
|
107
|
-
newRouter.usePlugin(...data.pluginFactories);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Apply route config (decoders, encoders, defaultParams, forwardMap)
|
|
111
|
-
applyConfig(
|
|
112
|
-
newRouter,
|
|
113
|
-
data.routeConfig,
|
|
114
|
-
data.resolvedForwardMap,
|
|
115
|
-
data.routeCustomFields,
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
return newRouter;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// packages/core/src/namespaces/CloneNamespace/types.ts
|
|
2
|
-
|
|
3
|
-
import type { Router } from "../../Router";
|
|
4
|
-
import type { GuardFnFactory, PluginFactory, Route } from "../../types";
|
|
5
|
-
import type { RouteConfig } from "../RoutesNamespace";
|
|
6
|
-
import type { DefaultDependencies, Options } from "@real-router/types";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Data collected from source router for cloning.
|
|
10
|
-
*/
|
|
11
|
-
export interface CloneData<Dependencies extends DefaultDependencies> {
|
|
12
|
-
routes: Route<Dependencies>[];
|
|
13
|
-
options: Options;
|
|
14
|
-
dependencies: Partial<Dependencies>;
|
|
15
|
-
canDeactivateFactories: Record<string, GuardFnFactory<Dependencies>>;
|
|
16
|
-
canActivateFactories: Record<string, GuardFnFactory<Dependencies>>;
|
|
17
|
-
pluginFactories: PluginFactory<Dependencies>[];
|
|
18
|
-
routeConfig: RouteConfig;
|
|
19
|
-
resolvedForwardMap: Record<string, string>;
|
|
20
|
-
routeCustomFields: Record<string, Record<string, unknown>>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Factory function to create a new router instance.
|
|
25
|
-
*/
|
|
26
|
-
export type RouterFactory<Dependencies extends DefaultDependencies> = (
|
|
27
|
-
routes: Route<Dependencies>[],
|
|
28
|
-
options: Partial<Options>,
|
|
29
|
-
dependencies: Dependencies,
|
|
30
|
-
) => Router<Dependencies>;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Function to apply route config to a new router.
|
|
34
|
-
*/
|
|
35
|
-
export type ApplyConfigFn<
|
|
36
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
37
|
-
> = (
|
|
38
|
-
router: Router<Dependencies>,
|
|
39
|
-
config: RouteConfig,
|
|
40
|
-
resolvedForwardMap: Record<string, string>,
|
|
41
|
-
routeCustomFields: Record<string, Record<string, unknown>>,
|
|
42
|
-
) => void;
|