@real-router/core 0.2.4 → 0.4.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.
@@ -1,5 +1,5 @@
1
- import { ErrorCodeKeys, ErrorCodeValues, ErrorCodeToValueMap, EventToNameMap, State, DefaultDependencies, Route, Options, Router } from '@real-router/types';
2
- export { ActivationFn, ActivationFnFactory, CancelFn, Config, DefaultDependencies, DoneFn, Listener, Middleware, MiddlewareFactory, NavigationOptions, Options, Params, Plugin, PluginFactory, Route, Router, SimpleState, State, StateMeta, SubscribeFn, SubscribeState, Subscription, Unsubscribe } from '@real-router/types';
1
+ import { EventToPluginMap, EventToNameMap, ErrorCodeKeys, ErrorCodeValues, ErrorCodeToValueMap, EventsKeys, State, DefaultDependencies, Options, Params, StateMetaInput, SimpleState, RouteTreeState, DoneFn, Unsubscribe, EventName, Plugin, NavigationOptions, CancelFn, SubscribeFn, Middleware, ActivationFn } from '@real-router/types';
2
+ export { ActivationFn, CancelFn, Config, DefaultDependencies, DoneFn, Listener, Middleware, NavigationOptions, Options, Params, Plugin, SimpleState, State, StateMeta, SubscribeFn, SubscribeState, Subscription, Unsubscribe } from '@real-router/types';
3
3
 
4
4
  type ConstantsKeys = "UNKNOWN_ROUTE";
5
5
  type Constants = Record<ConstantsKeys, string>;
@@ -15,12 +15,263 @@ declare const errorCodes: ErrorCodeToValueMap;
15
15
  * Special route names and identifiers.
16
16
  */
17
17
  declare const constants: Constants;
18
+ /**
19
+ * Plugin method names.
20
+ * Maps to methods that plugins can implement to hook into router lifecycle.
21
+ */
22
+ declare const plugins: EventToPluginMap;
18
23
  /**
19
24
  * Event names for router event system.
20
25
  * Used with addEventListener/removeEventListener for reactive subscriptions.
21
26
  */
22
27
  declare const events: EventToNameMap;
23
28
 
29
+ type EventMethodMap = {
30
+ [K in EventsKeys as (typeof events)[K]]: (typeof plugins)[K];
31
+ };
32
+ /**
33
+ * Observable state passed to subscribers
34
+ */
35
+ interface SubscribeState {
36
+ route: State;
37
+ previousRoute: State | undefined;
38
+ }
39
+ /**
40
+ * Observer interface per Observable spec
41
+ */
42
+ interface Observer {
43
+ next?: (value: SubscribeState) => void;
44
+ error?: (err: unknown) => void;
45
+ complete?: () => void;
46
+ }
47
+ /**
48
+ * Subscription interface per Observable spec
49
+ */
50
+ interface Subscription {
51
+ unsubscribe: () => void;
52
+ readonly closed: boolean;
53
+ }
54
+ /**
55
+ * Observable options for enhanced control
56
+ */
57
+ interface ObservableOptions {
58
+ /** AbortSignal for automatic unsubscription */
59
+ signal?: AbortSignal;
60
+ /** Replay current state to new subscribers (default: true) */
61
+ replay?: boolean;
62
+ }
63
+ /**
64
+ * Observable interface for TC39 compliance
65
+ */
66
+ interface RouterObservable {
67
+ [key: symbol]: () => RouterObservable;
68
+ subscribe: (observer: Observer | ((value: SubscribeState) => void), options?: ObservableOptions) => Subscription;
69
+ }
70
+
71
+ /**
72
+ * Symbol.observable polyfill declaration for TC39 proposal
73
+ *
74
+ * @see https://github.com/tc39/proposal-observable
75
+ */
76
+ declare global {
77
+ interface SymbolConstructor {
78
+ readonly observable: unique symbol;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Router class with integrated namespace architecture.
84
+ *
85
+ * All functionality is provided by namespace classes:
86
+ * - OptionsNamespace: getOptions, setOption
87
+ * - DependenciesNamespace: get/set/remove dependencies
88
+ * - ObservableNamespace: event listeners, subscribe
89
+ * - StateNamespace: state storage (getState, setState, getPreviousState)
90
+ * - RoutesNamespace: route tree operations
91
+ * - RouteLifecycleNamespace: canActivate/canDeactivate guards
92
+ * - MiddlewareNamespace: middleware chain
93
+ * - PluginsNamespace: plugin lifecycle
94
+ * - NavigationNamespace: navigate, navigateToState
95
+ * - RouterLifecycleNamespace: start, stop, isStarted
96
+ *
97
+ * @internal This class implementation is internal. Use createRouter() instead.
98
+ */
99
+ declare class Router<Dependencies extends DefaultDependencies = DefaultDependencies> {
100
+ #private;
101
+ [key: string]: unknown;
102
+ /**
103
+ * @param routes - Route definitions
104
+ * @param options - Router options
105
+ * @param dependencies - DI dependencies
106
+ */
107
+ constructor(routes?: Route<Dependencies>[], options?: Partial<Options>, dependencies?: Dependencies);
108
+ addRoute(routes: Route<Dependencies>[] | Route<Dependencies>): this;
109
+ removeRoute(name: string): this;
110
+ clearRoutes(): this;
111
+ getRoute(name: string): Route<Dependencies> | undefined;
112
+ hasRoute(name: string): boolean;
113
+ updateRoute(name: string, updates: RouteConfigUpdate<Dependencies>): this;
114
+ isActiveRoute(name: string, params?: Params, strictEquality?: boolean, ignoreQueryParams?: boolean): boolean;
115
+ buildPath(route: string, params?: Params): string;
116
+ matchPath<P extends Params = Params, MP extends Params = Params>(path: string, source?: string): State<P, MP> | undefined;
117
+ setRootPath(rootPath: string): void;
118
+ getRootPath(): string;
119
+ makeState<P extends Params = Params, MP extends Params = Params>(name: string, params?: P, path?: string, meta?: StateMetaInput<MP>, forceId?: number): State<P, MP>;
120
+ getState<P extends Params = Params, MP extends Params = Params>(): State<P, MP> | undefined;
121
+ getPreviousState(): State | undefined;
122
+ areStatesEqual(state1: State | undefined, state2: State | undefined, ignoreQueryParams?: boolean): boolean;
123
+ forwardState<P extends Params = Params>(routeName: string, routeParams: P): SimpleState<P>;
124
+ buildState(routeName: string, routeParams: Params): RouteTreeState | undefined;
125
+ shouldUpdateNode(nodeName: string): (toState: State, fromState?: State) => boolean;
126
+ getOptions(): Options;
127
+ getOption<K extends keyof Options>(option: K): Options[K];
128
+ setOption(option: keyof Options, value: Options[keyof Options]): this;
129
+ isActive(): boolean;
130
+ start(...args: [] | [done: DoneFn] | [startPathOrState: string | State] | [startPathOrState: string | State, done: DoneFn]): this;
131
+ stop(): this;
132
+ canDeactivate(name: string, canDeactivateHandler: ActivationFnFactory<Dependencies> | boolean): this;
133
+ canActivate(name: string, canActivateHandler: ActivationFnFactory<Dependencies> | boolean): this;
134
+ usePlugin(...plugins: PluginFactory<Dependencies>[]): Unsubscribe;
135
+ useMiddleware(...middlewares: MiddlewareFactory<Dependencies>[]): Unsubscribe;
136
+ clearMiddleware(): this;
137
+ setDependency<K extends keyof Dependencies & string>(dependencyName: K, dependency: Dependencies[K]): this;
138
+ setDependencies(deps: Dependencies): this;
139
+ getDependency<K extends keyof Dependencies>(key: K): Dependencies[K];
140
+ getDependencies(): Partial<Dependencies>;
141
+ removeDependency(dependencyName: keyof Dependencies): this;
142
+ hasDependency(dependencyName: keyof Dependencies): boolean;
143
+ resetDependencies(): this;
144
+ addEventListener<E extends EventName>(eventName: E, cb: Plugin[EventMethodMap[E]]): Unsubscribe;
145
+ navigate(routeName: string, routeParamsOrDone?: Params | DoneFn, optionsOrDone?: NavigationOptions | DoneFn, done?: DoneFn): CancelFn;
146
+ navigateToDefault(optsOrDone?: NavigationOptions | DoneFn, done?: DoneFn): CancelFn;
147
+ navigateToState(toState: State, fromState: State | undefined, opts: NavigationOptions, callback: DoneFn, emitSuccess: boolean): CancelFn;
148
+ subscribe(listener: SubscribeFn): Unsubscribe;
149
+ /**
150
+ * TC39 Observable spec: router[Symbol.observable]() returns observable
151
+ */
152
+ [Symbol.observable](): RouterObservable;
153
+ /**
154
+ * RxJS compatibility: router["@@observable"]() returns observable
155
+ */
156
+ ["@@observable"](): RouterObservable;
157
+ clone(dependencies?: Dependencies): Router<Dependencies>;
158
+ }
159
+
160
+ /**
161
+ * Router-dependent types.
162
+ *
163
+ * These types reference the Router class and are therefore defined in core
164
+ * rather than core-types to avoid circular dependencies.
165
+ */
166
+
167
+ /**
168
+ * Extended build result that includes segments for path building.
169
+ * Used internally to avoid duplicate getSegmentsByName calls.
170
+ *
171
+ * @param segments - Route segments from getSegmentsByName (typed as unknown[] for cross-package compatibility)
172
+ * @internal
173
+ */
174
+ interface BuildStateResultWithSegments<P extends Params = Params> {
175
+ readonly state: RouteTreeState<P>;
176
+ readonly segments: readonly unknown[];
177
+ }
178
+ /**
179
+ * Route configuration.
180
+ */
181
+ interface Route<Dependencies extends DefaultDependencies = DefaultDependencies> {
182
+ [key: string]: unknown;
183
+ /** Route name (dot-separated for nested routes). */
184
+ name: string;
185
+ /** URL path pattern for this route. */
186
+ path: string;
187
+ /** Factory function that returns a guard for route activation. */
188
+ canActivate?: ActivationFnFactory<Dependencies>;
189
+ /**
190
+ * Redirects navigation to another route.
191
+ *
192
+ * IMPORTANT: forwardTo creates a URL alias, not a transition chain.
193
+ * Guards (canActivate) on the source route are NOT executed.
194
+ * Only guards on the final destination are executed.
195
+ *
196
+ * This matches Vue Router and Angular Router behavior.
197
+ *
198
+ * @example
199
+ * // Correct: guard on target
200
+ * { name: "old", path: "/old", forwardTo: "new" }
201
+ * { name: "new", path: "/new", canActivate: myGuard }
202
+ *
203
+ * // Wrong: guard on source (will be ignored with warning)
204
+ * { name: "old", path: "/old", forwardTo: "new", canActivate: myGuard }
205
+ */
206
+ forwardTo?: string;
207
+ /** Nested child routes. */
208
+ children?: Route<Dependencies>[];
209
+ /** Encodes state params to URL params. */
210
+ encodeParams?: (stateParams: Params) => Params;
211
+ /** Decodes URL params to state params. */
212
+ decodeParams?: (pathParams: Params) => Params;
213
+ /**
214
+ * Default parameters for this route.
215
+ *
216
+ * @remarks
217
+ * **Type Contract:**
218
+ * The type of defaultParams MUST match the expected params type P
219
+ * when using `router.makeState<P>()` or `router.navigate<P>()`.
220
+ *
221
+ * These values are merged into state.params when creating route states.
222
+ * Missing URL params are filled from defaultParams.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * // Define route with pagination defaults
227
+ * {
228
+ * name: "users",
229
+ * path: "/users",
230
+ * defaultParams: { page: 1, limit: 10 }
231
+ * }
232
+ *
233
+ * // Navigate without specifying page/limit
234
+ * router.navigate("users", { filter: "active" });
235
+ * // Result: state.params = { page: 1, limit: 10, filter: "active" }
236
+ *
237
+ * // Correct typing — include defaultParams properties
238
+ * type UsersParams = { page: number; limit: number; filter?: string };
239
+ * ```
240
+ */
241
+ defaultParams?: Params;
242
+ }
243
+ /**
244
+ * Configuration update options for updateRoute().
245
+ * All properties are optional. Set to null to remove the configuration.
246
+ */
247
+ interface RouteConfigUpdate<Dependencies extends DefaultDependencies = DefaultDependencies> {
248
+ /** Set to null to remove forwardTo */
249
+ forwardTo?: string | null;
250
+ /** Set to null to remove defaultParams */
251
+ defaultParams?: Params | null;
252
+ /** Set to null to remove decoder */
253
+ decodeParams?: ((params: Params) => Params) | null;
254
+ /** Set to null to remove encoder */
255
+ encodeParams?: ((params: Params) => Params) | null;
256
+ /** Set to null to remove canActivate */
257
+ canActivate?: ActivationFnFactory<Dependencies> | null;
258
+ }
259
+ /**
260
+ * Factory function for creating activation guards.
261
+ * Receives the router instance and a dependency getter.
262
+ */
263
+ type ActivationFnFactory<Dependencies extends DefaultDependencies = DefaultDependencies> = (router: Router<Dependencies>, getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K]) => ActivationFn;
264
+ /**
265
+ * Factory function for creating middleware.
266
+ * Receives the router instance and a dependency getter.
267
+ */
268
+ type MiddlewareFactory<Dependencies extends DefaultDependencies = DefaultDependencies> = (router: Router<Dependencies>, getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K]) => Middleware;
269
+ /**
270
+ * Factory function for creating plugins.
271
+ * Receives the router instance and a dependency getter.
272
+ */
273
+ type PluginFactory<Dependencies extends DefaultDependencies = DefaultDependencies> = (router: Router<Dependencies>, getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K]) => Plugin;
274
+
24
275
  declare class RouterError extends Error {
25
276
  [key: string]: unknown;
26
277
  readonly segment: string | undefined;
@@ -210,7 +461,20 @@ declare class RouterError extends Error {
210
461
 
211
462
  /**
212
463
  * Creates a new router instance.
464
+ *
465
+ * @param routes - Array of route definitions
466
+ * @param options - Router configuration options
467
+ * @param dependencies - Dependencies to inject into the router
468
+ * @returns A new Router instance
469
+ *
470
+ * @example
471
+ * const router = createRouter([
472
+ * { name: 'home', path: '/' },
473
+ * { name: 'users', path: '/users' },
474
+ * ]);
475
+ *
476
+ * router.start('/');
213
477
  */
214
478
  declare const createRouter: <Dependencies extends DefaultDependencies = DefaultDependencies>(routes?: Route<Dependencies>[], options?: Partial<Options>, dependencies?: Dependencies) => Router<Dependencies>;
215
479
 
216
- export { type Constants, type ErrorCodes, RouterError, constants, createRouter, errorCodes, events };
480
+ export { type ActivationFnFactory, type BuildStateResultWithSegments, type Constants, type ErrorCodes, type MiddlewareFactory, type PluginFactory, type Route, type RouteConfigUpdate, Router, RouterError, constants, createRouter, errorCodes, events };