@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.
Files changed (49) hide show
  1. package/README.md +163 -325
  2. package/dist/cjs/index.d.ts +47 -178
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/metafile-cjs.json +1 -1
  6. package/dist/esm/index.d.mts +47 -178
  7. package/dist/esm/index.mjs +1 -1
  8. package/dist/esm/index.mjs.map +1 -1
  9. package/dist/esm/metafile-esm.json +1 -1
  10. package/package.json +3 -3
  11. package/src/Router.ts +84 -574
  12. package/src/api/cloneRouter.ts +106 -0
  13. package/src/api/getDependenciesApi.ts +216 -0
  14. package/src/api/getLifecycleApi.ts +67 -0
  15. package/src/api/getPluginApi.ts +118 -0
  16. package/src/api/getRoutesApi.ts +566 -0
  17. package/src/api/index.ts +16 -0
  18. package/src/api/types.ts +7 -0
  19. package/src/getNavigator.ts +5 -2
  20. package/src/index.ts +17 -3
  21. package/src/internals.ts +115 -0
  22. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +30 -0
  23. package/src/namespaces/DependenciesNamespace/index.ts +3 -1
  24. package/src/namespaces/DependenciesNamespace/validators.ts +2 -4
  25. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +1 -20
  26. package/src/namespaces/EventBusNamespace/validators.ts +36 -0
  27. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +1 -10
  28. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +2 -0
  29. package/src/namespaces/NavigationNamespace/transition/{executeLifecycleHooks.ts → executeLifecycleGuards.ts} +9 -7
  30. package/src/namespaces/NavigationNamespace/transition/index.ts +3 -3
  31. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +1 -16
  32. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +133 -1089
  33. package/src/namespaces/RoutesNamespace/forwardToValidation.ts +411 -0
  34. package/src/namespaces/RoutesNamespace/helpers.ts +1 -407
  35. package/src/namespaces/RoutesNamespace/index.ts +2 -0
  36. package/src/namespaces/RoutesNamespace/routesStore.ts +388 -0
  37. package/src/namespaces/RoutesNamespace/validators.ts +209 -3
  38. package/src/namespaces/StateNamespace/StateNamespace.ts +1 -44
  39. package/src/namespaces/StateNamespace/validators.ts +46 -0
  40. package/src/namespaces/index.ts +3 -5
  41. package/src/types.ts +12 -138
  42. package/src/wiring/RouterWiringBuilder.ts +30 -36
  43. package/src/wiring/types.ts +3 -6
  44. package/src/wiring/wireRouter.ts +0 -1
  45. package/src/namespaces/CloneNamespace/CloneNamespace.ts +0 -120
  46. package/src/namespaces/CloneNamespace/index.ts +0 -3
  47. package/src/namespaces/CloneNamespace/types.ts +0 -42
  48. package/src/namespaces/DependenciesNamespace/DependenciesNamespace.ts +0 -248
  49. 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
+ }
@@ -1,6 +1,8 @@
1
1
  // packages/core/src/namespaces/index.ts
2
2
 
3
- export { DependenciesNamespace } from "./DependenciesNamespace";
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
- * Router-dependent types.
4
+ * Core-internal types + re-exports from @real-router/types.
5
5
  *
6
- * These types reference the Router class and are therefore defined in core
7
- * rather than core-types to avoid circular dependencies.
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 type EventMethodMap = {
28
- [K in EventsKeys as (typeof events)[K]]: (typeof plugins)[K];
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 dependencies: WiringOptions<Dependencies>["dependencies"];
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.dependencies = wiringOptions.dependencies;
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.dependencies.setLimits(this.limits);
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.get(dependencyName),
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.router.addActivateGuard(name, handler);
72
+ this.routeLifecycle.addCanActivate(name, handler, true);
72
73
  },
73
74
  addDeactivateGuard: (name, handler) => {
74
- this.router.addDeactivateGuard(name, handler);
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) => this.dependencies.get(name),
82
- forwardState: (name, params) => this.router.forwardState(name, params),
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.get(dependencyName),
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 { name, params } = this.router.forwardState(
113
- routeName,
114
- routeParams,
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.get(name as keyof 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.getConfig().defaultParams,
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
 
@@ -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 namespace */
33
- dependencies: DependenciesNamespace<Dependencies>;
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
  }
@@ -23,6 +23,5 @@ export function wireRouter<Dependencies extends DefaultDependencies>(
23
23
  builder.wireNavigationDeps();
24
24
  builder.wireLifecycleDeps();
25
25
  builder.wireStateDeps();
26
- builder.wireCloneCallbacks();
27
26
  builder.wireCyclicDeps();
28
27
  }
@@ -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,3 +0,0 @@
1
- export { CloneNamespace } from "./CloneNamespace";
2
-
3
- export type { ApplyConfigFn, CloneData, RouterFactory } from "./types";
@@ -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;