@real-router/types 0.12.0 → 0.14.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.
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * This module exports ONLY the essential types used by real-router:
5
5
  * - QueryParamsMode, QueryParamsOptions
6
- * - RouteTreeState
6
+ * - RouteParams, RouteTreeState
7
7
  *
8
8
  * These types are copied from route-node to avoid circular dependencies.
9
9
  *
@@ -68,8 +68,6 @@ interface StateMeta<P extends Params = Params> {
68
68
  id: number;
69
69
  params: P;
70
70
  options: NavigationOptions;
71
- redirected: boolean;
72
- source?: string | undefined;
73
71
  }
74
72
  /**
75
73
  * Input type for makeState meta parameter.
@@ -230,7 +228,7 @@ interface NavigationOptions {
230
228
  * @description
231
229
  * Automatically set by the router when a navigation is triggered by a redirect from
232
230
  * middleware or lifecycle hooks. This flag is used internally to track redirect chains
233
- * and is stored in state.meta.redirected.
231
+ * and is stored in state.meta.options.redirected.
234
232
  *
235
233
  * @default false (auto-set by router during redirects)
236
234
  *
@@ -246,14 +244,14 @@ interface NavigationOptions {
246
244
  * @example
247
245
  * // Accessing redirect flag in lifecycle
248
246
  * router.addActivateGuard('dashboard', (toState, fromState) => {
249
- * if (toState.meta?.redirected) {
247
+ * if (toState.meta?.options?.redirected) {
250
248
  * console.log('This navigation is from a redirect');
251
249
  * }
252
250
  * return true;
253
251
  * });
254
252
  *
255
253
  * @see {@link Router.navigate} for redirect handling implementation
256
- * @see {@link State.meta.redirected} for redirect flag in state
254
+ * @see {@link NavigationOptions.redirected} for the input mechanism
257
255
  */
258
256
  redirected?: boolean | undefined;
259
257
  }
@@ -435,6 +433,7 @@ interface Options {
435
433
  noValidate?: boolean;
436
434
  }
437
435
  type ActivationFn = (toState: State, fromState: State | undefined) => boolean | Promise<boolean | State | void> | State | void;
436
+ type GuardFn = (toState: State, fromState: State | undefined) => boolean | Promise<boolean>;
438
437
  type DefaultDependencies = object;
439
438
  interface Config {
440
439
  decoders: Record<string, (params: Params) => Params>;
@@ -488,9 +487,9 @@ interface Navigator {
488
487
  * Defines the contract for router implementations. The actual Router class in
489
488
  * @real-router/core implements this interface with full functionality.
490
489
  *
491
- * This interface uses `ActivationFn | boolean` for guard types to avoid circular
490
+ * This interface uses `GuardFn | boolean` for guard types to avoid circular
492
491
  * dependencies. The concrete Router class in @real-router/core narrows this to
493
- * `ActivationFnFactory | boolean` for more precise type checking.
492
+ * `GuardFnFactory | boolean` for more precise type checking.
494
493
  */
495
494
  interface Router {
496
495
  /**
@@ -500,7 +499,7 @@ interface Router {
500
499
  * @param guard - Guard function or boolean
501
500
  * @returns this for method chaining
502
501
  */
503
- addActivateGuard: (name: string, guard: ActivationFn | boolean) => this;
502
+ addActivateGuard: (name: string, guard: GuardFn | boolean) => this;
504
503
  /**
505
504
  * Register a deactivation guard for a route.
506
505
  *
@@ -508,7 +507,7 @@ interface Router {
508
507
  * @param guard - Guard function or boolean
509
508
  * @returns this for method chaining
510
509
  */
511
- addDeactivateGuard: (name: string, guard: ActivationFn | boolean) => this;
510
+ addDeactivateGuard: (name: string, guard: GuardFn | boolean) => this;
512
511
  /**
513
512
  * Remove an activation guard from a route.
514
513
  *
@@ -601,4 +600,4 @@ interface ErrorCodeToValueMap {
601
600
  ROUTER_DISPOSED: "DISPOSED";
602
601
  }
603
602
 
604
- export type { ActivationFn, Config, DefaultDependencies, DefaultParamsCallback, DefaultRouteCallback, ErrorCodeKeys, ErrorCodeToValueMap, ErrorCodeValues, EventName, EventToNameMap, EventToPluginMap, EventsKeys, ForwardToCallback, LimitsConfig, Listener, Middleware, NavigationOptions, Navigator, Options, Params, Plugin, PluginMethod, QueryParamsMode, QueryParamsOptions, RouteTreeState, Router, RouterError, SimpleState, State, StateMeta, StateMetaInput, SubscribeFn, SubscribeState, Subscription, TransitionMeta, TransitionPhase, TransitionReason, Unsubscribe };
603
+ export type { ActivationFn, Config, DefaultDependencies, DefaultParamsCallback, DefaultRouteCallback, ErrorCodeKeys, ErrorCodeToValueMap, ErrorCodeValues, EventName, EventToNameMap, EventToPluginMap, EventsKeys, ForwardToCallback, GuardFn, LimitsConfig, Listener, Middleware, NavigationOptions, Navigator, Options, Params, Plugin, PluginMethod, QueryParamsMode, QueryParamsOptions, RouteParams, RouteTreeState, Router, RouterError, SimpleState, State, StateMeta, StateMetaInput, SubscribeFn, SubscribeState, Subscription, TransitionMeta, TransitionPhase, TransitionReason, Unsubscribe };
@@ -1 +1 @@
1
- {"inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js":{"bytes":569,"imports":[],"format":"esm"},"src/index.ts":{"bytes":1283,"imports":[{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/cjs/index.js":{"imports":[],"exports":[],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0}},"bytes":0}}}
1
+ {"inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js":{"bytes":569,"imports":[],"format":"esm"},"src/index.ts":{"bytes":1309,"imports":[{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/cjs/index.js":{"imports":[],"exports":[],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0}},"bytes":0}}}
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * This module exports ONLY the essential types used by real-router:
5
5
  * - QueryParamsMode, QueryParamsOptions
6
- * - RouteTreeState
6
+ * - RouteParams, RouteTreeState
7
7
  *
8
8
  * These types are copied from route-node to avoid circular dependencies.
9
9
  *
@@ -68,8 +68,6 @@ interface StateMeta<P extends Params = Params> {
68
68
  id: number;
69
69
  params: P;
70
70
  options: NavigationOptions;
71
- redirected: boolean;
72
- source?: string | undefined;
73
71
  }
74
72
  /**
75
73
  * Input type for makeState meta parameter.
@@ -230,7 +228,7 @@ interface NavigationOptions {
230
228
  * @description
231
229
  * Automatically set by the router when a navigation is triggered by a redirect from
232
230
  * middleware or lifecycle hooks. This flag is used internally to track redirect chains
233
- * and is stored in state.meta.redirected.
231
+ * and is stored in state.meta.options.redirected.
234
232
  *
235
233
  * @default false (auto-set by router during redirects)
236
234
  *
@@ -246,14 +244,14 @@ interface NavigationOptions {
246
244
  * @example
247
245
  * // Accessing redirect flag in lifecycle
248
246
  * router.addActivateGuard('dashboard', (toState, fromState) => {
249
- * if (toState.meta?.redirected) {
247
+ * if (toState.meta?.options?.redirected) {
250
248
  * console.log('This navigation is from a redirect');
251
249
  * }
252
250
  * return true;
253
251
  * });
254
252
  *
255
253
  * @see {@link Router.navigate} for redirect handling implementation
256
- * @see {@link State.meta.redirected} for redirect flag in state
254
+ * @see {@link NavigationOptions.redirected} for the input mechanism
257
255
  */
258
256
  redirected?: boolean | undefined;
259
257
  }
@@ -435,6 +433,7 @@ interface Options {
435
433
  noValidate?: boolean;
436
434
  }
437
435
  type ActivationFn = (toState: State, fromState: State | undefined) => boolean | Promise<boolean | State | void> | State | void;
436
+ type GuardFn = (toState: State, fromState: State | undefined) => boolean | Promise<boolean>;
438
437
  type DefaultDependencies = object;
439
438
  interface Config {
440
439
  decoders: Record<string, (params: Params) => Params>;
@@ -488,9 +487,9 @@ interface Navigator {
488
487
  * Defines the contract for router implementations. The actual Router class in
489
488
  * @real-router/core implements this interface with full functionality.
490
489
  *
491
- * This interface uses `ActivationFn | boolean` for guard types to avoid circular
490
+ * This interface uses `GuardFn | boolean` for guard types to avoid circular
492
491
  * dependencies. The concrete Router class in @real-router/core narrows this to
493
- * `ActivationFnFactory | boolean` for more precise type checking.
492
+ * `GuardFnFactory | boolean` for more precise type checking.
494
493
  */
495
494
  interface Router {
496
495
  /**
@@ -500,7 +499,7 @@ interface Router {
500
499
  * @param guard - Guard function or boolean
501
500
  * @returns this for method chaining
502
501
  */
503
- addActivateGuard: (name: string, guard: ActivationFn | boolean) => this;
502
+ addActivateGuard: (name: string, guard: GuardFn | boolean) => this;
504
503
  /**
505
504
  * Register a deactivation guard for a route.
506
505
  *
@@ -508,7 +507,7 @@ interface Router {
508
507
  * @param guard - Guard function or boolean
509
508
  * @returns this for method chaining
510
509
  */
511
- addDeactivateGuard: (name: string, guard: ActivationFn | boolean) => this;
510
+ addDeactivateGuard: (name: string, guard: GuardFn | boolean) => this;
512
511
  /**
513
512
  * Remove an activation guard from a route.
514
513
  *
@@ -601,4 +600,4 @@ interface ErrorCodeToValueMap {
601
600
  ROUTER_DISPOSED: "DISPOSED";
602
601
  }
603
602
 
604
- export type { ActivationFn, Config, DefaultDependencies, DefaultParamsCallback, DefaultRouteCallback, ErrorCodeKeys, ErrorCodeToValueMap, ErrorCodeValues, EventName, EventToNameMap, EventToPluginMap, EventsKeys, ForwardToCallback, LimitsConfig, Listener, Middleware, NavigationOptions, Navigator, Options, Params, Plugin, PluginMethod, QueryParamsMode, QueryParamsOptions, RouteTreeState, Router, RouterError, SimpleState, State, StateMeta, StateMetaInput, SubscribeFn, SubscribeState, Subscription, TransitionMeta, TransitionPhase, TransitionReason, Unsubscribe };
603
+ export type { ActivationFn, Config, DefaultDependencies, DefaultParamsCallback, DefaultRouteCallback, ErrorCodeKeys, ErrorCodeToValueMap, ErrorCodeValues, EventName, EventToNameMap, EventToPluginMap, EventsKeys, ForwardToCallback, GuardFn, LimitsConfig, Listener, Middleware, NavigationOptions, Navigator, Options, Params, Plugin, PluginMethod, QueryParamsMode, QueryParamsOptions, RouteParams, RouteTreeState, Router, RouterError, SimpleState, State, StateMeta, StateMetaInput, SubscribeFn, SubscribeState, Subscription, TransitionMeta, TransitionPhase, TransitionReason, Unsubscribe };
@@ -1 +1 @@
1
- {"inputs":{"src/index.ts":{"bytes":1283,"imports":[],"format":"esm"}},"outputs":{"dist/esm/index.mjs":{"imports":[],"exports":[],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0}},"bytes":0}}}
1
+ {"inputs":{"src/index.ts":{"bytes":1309,"imports":[],"format":"esm"}},"outputs":{"dist/esm/index.mjs":{"imports":[],"exports":[],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0}},"bytes":0}}}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@real-router/types",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "type": "commonjs",
5
5
  "description": "Shared TypeScript types for Real Router ecosystem",
6
6
  "types": "./dist/esm/index.d.mts",
7
7
  "exports": {
8
8
  ".": {
9
+ "development": "./src/index.ts",
9
10
  "types": {
10
11
  "import": "./dist/esm/index.d.mts",
11
12
  "require": "./dist/cjs/index.d.ts"
@@ -13,7 +14,8 @@
13
14
  }
14
15
  },
15
16
  "files": [
16
- "dist"
17
+ "dist",
18
+ "src"
17
19
  ],
18
20
  "repository": {
19
21
  "type": "git",
package/src/base.ts ADDED
@@ -0,0 +1,259 @@
1
+ // packages/core-types/modules/base.ts
2
+
3
+ // Note: RouteTreeState is exported from route-node-types.ts
4
+ // It uses RouteParams as default type parameter.
5
+ // Real Router code should use RouteTreeState<Params> when needed.
6
+
7
+ export type Unsubscribe = () => void;
8
+
9
+ export interface SimpleState<P extends Params = Params> {
10
+ name: string;
11
+ params: P;
12
+ }
13
+
14
+ export type TransitionPhase = "deactivating" | "activating" | "middleware";
15
+
16
+ export type TransitionReason = "success" | "blocked" | "cancelled" | "error";
17
+
18
+ export interface TransitionMeta {
19
+ phase: TransitionPhase;
20
+ from?: string;
21
+ reason: TransitionReason;
22
+ blocker?: string;
23
+ segments: {
24
+ deactivated: string[];
25
+ activated: string[];
26
+ intersection: string;
27
+ };
28
+ }
29
+
30
+ export interface State<P extends Params = Params, MP extends Params = Params> {
31
+ name: string;
32
+ params: P;
33
+ path: string;
34
+ meta?: StateMeta<MP> | undefined;
35
+ transition?: TransitionMeta | undefined;
36
+ }
37
+
38
+ export interface StateMeta<P extends Params = Params> {
39
+ id: number;
40
+ params: P;
41
+ options: NavigationOptions;
42
+ }
43
+
44
+ /**
45
+ * Input type for makeState meta parameter.
46
+ * Omits `id` since it's auto-generated by makeState.
47
+ */
48
+ export type StateMetaInput<P extends Params = Params> = Omit<
49
+ StateMeta<P>,
50
+ "id"
51
+ >;
52
+
53
+ /**
54
+ * RouterError interface describing the public API of the RouterError class.
55
+ * The actual class implementation is in the real-router package.
56
+ * This interface enables structural typing compatibility between
57
+ * core-types and real-router packages.
58
+ */
59
+ export interface RouterError extends Error {
60
+ [key: string]: unknown;
61
+ readonly code: string;
62
+ readonly segment: string | undefined;
63
+ readonly path: string | undefined;
64
+ readonly redirect: State | undefined;
65
+ setCode: (code: string) => void;
66
+ setErrorInstance: (err: Error) => void;
67
+ setAdditionalFields: (fields: Record<string, unknown>) => void;
68
+ hasField: (key: string) => boolean;
69
+ getField: (key: string) => unknown;
70
+ toJSON: () => Record<string, unknown>;
71
+ }
72
+
73
+ /**
74
+ * Configuration options that control navigation transition behavior.
75
+ *
76
+ * @description
77
+ * NavigationOptions provides fine-grained control over how the router performs navigation
78
+ * transitions. These options affect history management, transition lifecycle execution,
79
+ * guard enforcement, and state comparison logic.
80
+ *
81
+ * All options are optional and have sensible defaults. Options can be combined to achieve
82
+ * complex navigation behaviors. The options object is stored in state.meta.options and is
83
+ * available to middleware, guards, and event listeners.
84
+ *
85
+ * @see {@link Router.navigate} for navigation method that accepts these options
86
+ * @see {@link State.meta} for where options are stored after navigation
87
+ */
88
+ export interface NavigationOptions {
89
+ [key: string]:
90
+ | string
91
+ | number
92
+ | boolean
93
+ | Record<string, unknown>
94
+ | undefined;
95
+
96
+ /**
97
+ * Replace the current history entry instead of pushing a new one.
98
+ *
99
+ * @description
100
+ * When `true`, the navigation will replace the current entry in browser history instead
101
+ * of adding a new entry. This is typically used by history plugins (browser plugin) to
102
+ * control how navigation affects the browser's back/forward buttons.
103
+ *
104
+ * @default false
105
+ *
106
+ * @example
107
+ * // Redirect after login - prevent back button to login page
108
+ * router.navigate('dashboard', {}, { replace: true });
109
+ *
110
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState}
111
+ */
112
+ replace?: boolean | undefined;
113
+
114
+ /**
115
+ * Force reload of the current route even if states are equal.
116
+ *
117
+ * @description
118
+ * When `true`, bypasses the "same state" check that normally prevents navigation when
119
+ * the target state equals the current state. This forces a full transition lifecycle
120
+ * execution, allowing route components to reload with the same parameters.
121
+ *
122
+ * Without `reload`:
123
+ * - Navigation to current route throws SAME_STATES error
124
+ * - No lifecycle hooks or middleware execute
125
+ * - No events are fired
126
+ *
127
+ * With `reload`:
128
+ * - Full transition executes (deactivate → activate → middleware)
129
+ * - All lifecycle hooks run again
130
+ * - TRANSITION_SUCCESS event fires with same state
131
+ * - State object is recreated (new reference)
132
+ *
133
+ * @default false
134
+ *
135
+ * @example
136
+ * // Refresh current page data
137
+ * router.navigate(currentRoute.name, currentRoute.params, { reload: true });
138
+ *
139
+ * @example
140
+ * // Force re-fetch on same route with different query params
141
+ * // Note: query params are in path, not checked for equality
142
+ * router.navigate('search', { term: 'react' }, { reload: true });
143
+ *
144
+ * @see {@link force} for alternative that forces transition
145
+ * @see {@link Router.areStatesEqual} for state comparison logic
146
+ */
147
+ reload?: boolean | undefined;
148
+
149
+ /**
150
+ * Force navigation even if target state equals current state.
151
+ *
152
+ * @description
153
+ * When `true`, bypasses the "same state" equality check but still executes the full
154
+ * transition lifecycle. Similar to `reload` but can be used
155
+ * for any forced navigation scenario.
156
+ *
157
+ * Difference from `reload`:
158
+ * - `reload`: semantic meaning is "refresh current route"
159
+ * - `force`: general-purpose bypass of equality check
160
+ * - Both have identical implementation effect
161
+ *
162
+ * The equality check compares:
163
+ * - state.name (route name)
164
+ * - state.params (route parameters, shallow comparison)
165
+ *
166
+ * @default false
167
+ *
168
+ * @example
169
+ * // Force transition for tracking even if params didn't change
170
+ * router.navigate('analytics', { event: 'pageview' }, { force: true });
171
+ *
172
+ * @see {@link reload} for semantic equivalent (preferred for refresh scenarios)
173
+ */
174
+ force?: boolean | undefined;
175
+
176
+ /**
177
+ * Skip canDeactivate guards during transition.
178
+ *
179
+ * @description
180
+ * When `true`, bypasses only the canDeactivate lifecycle hooks for segments being
181
+ * deactivated. canActivate guards and middleware still execute normally. This allows
182
+ * forcing navigation away from routes with confirmation dialogs or unsaved changes.
183
+ *
184
+ * Skipped vs executed:
185
+ * ```
186
+ * // Normal transition
187
+ * deactivate(fromSegments) → activate(toSegments) → middleware → success
188
+ *
189
+ * // With forceDeactivate: true
190
+ * [skip deactivate] → activate(toSegments) → middleware → success
191
+ * ```
192
+ *
193
+ * ⚠️ Data loss risk: Bypassing canDeactivate means unsaved changes will be lost
194
+ *
195
+ * @default false
196
+ *
197
+ * @example
198
+ * // Force logout even with unsaved changes
199
+ * function forceLogout() {
200
+ * router.navigate('login', {}, {
201
+ * forceDeactivate: true,
202
+ * replace: true
203
+ * });
204
+ * }
205
+ *
206
+ * @see {@link Router.clearCanDeactivate} for programmatically clearing guards
207
+ */
208
+ forceDeactivate?: boolean | undefined;
209
+
210
+ /**
211
+ * Internal flag indicating navigation is result of a redirect.
212
+ *
213
+ * @internal
214
+ *
215
+ * @description
216
+ * Automatically set by the router when a navigation is triggered by a redirect from
217
+ * middleware or lifecycle hooks. This flag is used internally to track redirect chains
218
+ * and is stored in state.meta.options.redirected.
219
+ *
220
+ * @default false (auto-set by router during redirects)
221
+ *
222
+ * @example
223
+ * // Middleware triggers automatic redirect
224
+ * router.useMiddleware((toState, fromState, opts) => {
225
+ * if (!isAuthenticated && toState.name !== 'login') {
226
+ * // Router will automatically set redirected: true
227
+ * return { name: 'login', params: { next: toState.path } };
228
+ * }
229
+ * });
230
+ *
231
+ * @example
232
+ * // Accessing redirect flag in lifecycle
233
+ * router.addActivateGuard('dashboard', (toState, fromState) => {
234
+ * if (toState.meta?.options?.redirected) {
235
+ * console.log('This navigation is from a redirect');
236
+ * }
237
+ * return true;
238
+ * });
239
+ *
240
+ * @see {@link Router.navigate} for redirect handling implementation
241
+ * @see {@link NavigationOptions.redirected} for the input mechanism
242
+ */
243
+ redirected?: boolean | undefined;
244
+ }
245
+
246
+ export interface Params {
247
+ [key: string]:
248
+ | string
249
+ | string[]
250
+ | number
251
+ | number[]
252
+ | boolean
253
+ | boolean[]
254
+ | Params
255
+ | Params[]
256
+ | Record<string, string | number | boolean>
257
+ | null
258
+ | undefined;
259
+ }
@@ -0,0 +1,104 @@
1
+ // packages/core-types/modules/constants.ts
2
+
3
+ /**
4
+ * Plugin lifecycle method names
5
+ */
6
+ export type PluginMethod =
7
+ | "onStart"
8
+ | "onStop"
9
+ | "onTransitionStart"
10
+ | "onTransitionCancel"
11
+ | "onTransitionSuccess"
12
+ | "onTransitionError";
13
+
14
+ /**
15
+ * Router event names
16
+ */
17
+ export type EventName =
18
+ | "$start"
19
+ | "$stop"
20
+ | "$$start"
21
+ | "$$cancel"
22
+ | "$$success"
23
+ | "$$error";
24
+
25
+ /**
26
+ * Event type keys
27
+ */
28
+ export type EventsKeys =
29
+ | "ROUTER_START"
30
+ | "ROUTER_STOP"
31
+ | "TRANSITION_START"
32
+ | "TRANSITION_CANCEL"
33
+ | "TRANSITION_SUCCESS"
34
+ | "TRANSITION_ERROR";
35
+
36
+ /**
37
+ * Error code values
38
+ */
39
+ export type ErrorCodeValues =
40
+ | "NOT_STARTED"
41
+ | "NO_START_PATH_OR_STATE"
42
+ | "ALREADY_STARTED"
43
+ | "ROUTE_NOT_FOUND"
44
+ | "SAME_STATES"
45
+ | "CANNOT_DEACTIVATE"
46
+ | "CANNOT_ACTIVATE"
47
+ | "TRANSITION_ERR"
48
+ | "CANCELLED"
49
+ | "DISPOSED";
50
+
51
+ /**
52
+ * Error code keys
53
+ */
54
+ export type ErrorCodeKeys =
55
+ | "ROUTER_NOT_STARTED"
56
+ | "NO_START_PATH_OR_STATE"
57
+ | "ROUTER_ALREADY_STARTED"
58
+ | "ROUTE_NOT_FOUND"
59
+ | "SAME_STATES"
60
+ | "CANNOT_DEACTIVATE"
61
+ | "CANNOT_ACTIVATE"
62
+ | "TRANSITION_ERR"
63
+ | "TRANSITION_CANCELLED"
64
+ | "ROUTER_DISPOSED";
65
+
66
+ /**
67
+ * Mapping of event keys to plugin methods
68
+ */
69
+ export interface EventToPluginMap {
70
+ readonly ROUTER_START: "onStart";
71
+ readonly ROUTER_STOP: "onStop";
72
+ readonly TRANSITION_START: "onTransitionStart";
73
+ readonly TRANSITION_CANCEL: "onTransitionCancel";
74
+ readonly TRANSITION_SUCCESS: "onTransitionSuccess";
75
+ readonly TRANSITION_ERROR: "onTransitionError";
76
+ }
77
+
78
+ /**
79
+ * Mapping of event keys to event names
80
+ */
81
+ export interface EventToNameMap {
82
+ ROUTER_START: "$start";
83
+ ROUTER_STOP: "$stop";
84
+ TRANSITION_START: "$$start";
85
+ TRANSITION_CANCEL: "$$cancel";
86
+ TRANSITION_SUCCESS: "$$success";
87
+ TRANSITION_ERROR: "$$error";
88
+ }
89
+
90
+ /**
91
+ * Mapping of error code keys to their values
92
+ */
93
+ export interface ErrorCodeToValueMap {
94
+ ROUTER_NOT_STARTED: "NOT_STARTED";
95
+ NO_START_PATH_OR_STATE: "NO_START_PATH_OR_STATE";
96
+ ROUTER_ALREADY_STARTED: "ALREADY_STARTED";
97
+ ROUTE_NOT_FOUND: "ROUTE_NOT_FOUND";
98
+ SAME_STATES: "SAME_STATES";
99
+ CANNOT_DEACTIVATE: "CANNOT_DEACTIVATE";
100
+ CANNOT_ACTIVATE: "CANNOT_ACTIVATE";
101
+ TRANSITION_ERR: "TRANSITION_ERR";
102
+ TRANSITION_CANCELLED: "CANCELLED";
103
+ ROUTER_DISPOSED: "DISPOSED";
104
+ }
package/src/index.ts ADDED
@@ -0,0 +1,63 @@
1
+ // packages/core-types/modules/index.ts
2
+
3
+ // Route node types
4
+ export type {
5
+ QueryParamsMode,
6
+ QueryParamsOptions,
7
+ RouteParams,
8
+ RouteTreeState,
9
+ } from "./route-node-types";
10
+
11
+ // Base types
12
+ export type {
13
+ Params,
14
+ State,
15
+ StateMeta,
16
+ StateMetaInput,
17
+ SimpleState,
18
+ NavigationOptions,
19
+ Unsubscribe,
20
+ RouterError,
21
+ TransitionPhase,
22
+ TransitionReason,
23
+ TransitionMeta,
24
+ } from "./base";
25
+
26
+ // Router types (base types without Router dependency)
27
+ // Note: Route, RouteConfigUpdate, ActivationFnFactory, MiddlewareFactory,
28
+ // PluginFactory, BuildStateResultWithSegments are in @real-router/core
29
+ export type {
30
+ Options,
31
+ DefaultRouteCallback,
32
+ ForwardToCallback,
33
+ DefaultParamsCallback,
34
+ ActivationFn,
35
+ GuardFn,
36
+ DefaultDependencies,
37
+ Config,
38
+ Plugin,
39
+ Middleware,
40
+ SubscribeState,
41
+ SubscribeFn,
42
+ Listener,
43
+ Subscription,
44
+ Navigator,
45
+ Router,
46
+ } from "./router";
47
+
48
+ // Limits configuration
49
+ export type { LimitsConfig } from "./limits";
50
+
51
+ export type {
52
+ PluginMethod,
53
+ EventName,
54
+ EventsKeys,
55
+ ErrorCodeValues,
56
+ ErrorCodeKeys,
57
+ EventToPluginMap,
58
+ EventToNameMap,
59
+ ErrorCodeToValueMap,
60
+ } from "./constants";
61
+
62
+ // Note: RouterError type is a forward declaration matching the class in real-router package
63
+ // Use import { RouterError } from "real-router" for the actual class implementation
package/src/limits.ts ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Configuration for router resource limits.
3
+ * Controls maximum allowed values for various router operations to prevent resource exhaustion.
4
+ */
5
+ export interface LimitsConfig {
6
+ /**
7
+ * Maximum number of route dependencies allowed.
8
+ * Prevents circular dependency chains and excessive dependency graphs.
9
+ *
10
+ * @default 100
11
+ */
12
+ maxDependencies: number;
13
+
14
+ /**
15
+ * Maximum number of plugins that can be registered.
16
+ * Limits plugin stack depth to prevent performance degradation.
17
+ *
18
+ * @default 50
19
+ */
20
+ maxPlugins: number;
21
+
22
+ /**
23
+ * Maximum number of middleware functions in the navigation pipeline.
24
+ * Controls middleware chain length to prevent stack overflow and performance issues.
25
+ *
26
+ * @default 50
27
+ */
28
+ maxMiddleware: number;
29
+
30
+ /**
31
+ * Maximum number of event listeners per event type.
32
+ * Prevents memory leaks from excessive listener registration.
33
+ *
34
+ * @default 10000
35
+ */
36
+ maxListeners: number;
37
+
38
+ /**
39
+ * Listener count at which a memory leak warning is logged per event type.
40
+ * Set to 0 to disable the warning.
41
+ *
42
+ * @default 1000
43
+ */
44
+ warnListeners: number;
45
+
46
+ /**
47
+ * Maximum depth of nested event propagation.
48
+ * Prevents infinite recursion in event handling chains.
49
+ *
50
+ * @default 5
51
+ */
52
+ maxEventDepth: number;
53
+
54
+ /**
55
+ * Maximum number of lifecycle handlers (canActivate/canDeactivate) per route.
56
+ * Controls guard function stack to prevent excessive validation overhead.
57
+ *
58
+ * @default 200
59
+ */
60
+ maxLifecycleHandlers: number;
61
+ }
@@ -0,0 +1,73 @@
1
+ // packages/core-types/modules/route-node-types.ts
2
+
3
+ /**
4
+ * Route Node Type Definitions — Minimal Public API.
5
+ *
6
+ * This module exports ONLY the essential types used by real-router:
7
+ * - QueryParamsMode, QueryParamsOptions
8
+ * - RouteParams, RouteTreeState
9
+ *
10
+ * These types are copied from route-node to avoid circular dependencies.
11
+ *
12
+ * @module route-node-types
13
+ */
14
+
15
+ // =============================================================================
16
+ // Search Params Types
17
+ // =============================================================================
18
+
19
+ type ArrayFormat = "none" | "brackets" | "index" | "comma";
20
+ type BooleanFormat = "none" | "string" | "empty-true";
21
+ type NullFormat = "default" | "hidden";
22
+
23
+ /**
24
+ * Options for query parameter parsing and building.
25
+ */
26
+ export interface QueryParamsOptions {
27
+ arrayFormat?: ArrayFormat;
28
+ booleanFormat?: BooleanFormat;
29
+ nullFormat?: NullFormat;
30
+ }
31
+
32
+ // =============================================================================
33
+ // Mode Types
34
+ // =============================================================================
35
+
36
+ /**
37
+ * Controls how query parameters are handled during matching.
38
+ */
39
+ export type QueryParamsMode = "default" | "strict" | "loose";
40
+
41
+ // =============================================================================
42
+ // Route State Types
43
+ // =============================================================================
44
+
45
+ type ParamSource = "url" | "query";
46
+ type ParamTypeMap = Record<string, ParamSource>;
47
+ type RouteTreeStateMeta = Record<string, ParamTypeMap>;
48
+
49
+ export interface RouteParams {
50
+ [key: string]:
51
+ | string
52
+ | string[]
53
+ | number
54
+ | number[]
55
+ | boolean
56
+ | boolean[]
57
+ | RouteParams
58
+ | RouteParams[]
59
+ | Record<string, string | number | boolean>
60
+ | null
61
+ | undefined;
62
+ }
63
+
64
+ /**
65
+ * Complete state representation of a matched route.
66
+ */
67
+ export interface RouteTreeState<
68
+ P extends Record<string, unknown> = RouteParams,
69
+ > {
70
+ name: string;
71
+ params: P;
72
+ meta: RouteTreeStateMeta;
73
+ }
package/src/router.ts ADDED
@@ -0,0 +1,307 @@
1
+ // packages/core-types/modules/router.ts
2
+
3
+ /**
4
+ * Base router types without Router class dependency.
5
+ *
6
+ * Router-dependent types (Route, RouteConfigUpdate, ActivationFnFactory,
7
+ * MiddlewareFactory, PluginFactory) are defined in @real-router/core
8
+ * to avoid circular dependencies.
9
+ */
10
+
11
+ import type {
12
+ State,
13
+ Params,
14
+ NavigationOptions,
15
+ RouterError,
16
+ Unsubscribe,
17
+ } from "./base";
18
+ import type { LimitsConfig } from "./limits";
19
+ import type { QueryParamsMode, QueryParamsOptions } from "./route-node-types";
20
+
21
+ // Logger types (duplicated from @real-router/logger to avoid dependency)
22
+ type LogLevel = "log" | "warn" | "error";
23
+ type LogLevelConfig = "all" | "warn-error" | "error-only" | "none";
24
+ type LogCallback = (
25
+ level: LogLevel,
26
+ context: string,
27
+ message: string,
28
+ ...args: unknown[]
29
+ ) => void;
30
+ interface LoggerConfig {
31
+ level: LogLevelConfig;
32
+ callback?: LogCallback | undefined;
33
+ callbackIgnoresLevel?: boolean;
34
+ }
35
+
36
+ /**
37
+ * Callback function for dynamically resolving the default route.
38
+ * Receives a dependency getter function to access router dependencies.
39
+ */
40
+ export type DefaultRouteCallback<Dependencies = object> = (
41
+ getDependency: <K extends keyof Dependencies>(name: K) => Dependencies[K],
42
+ ) => string;
43
+
44
+ /**
45
+ * Callback function for dynamically resolving the forward target route.
46
+ * Receives a dependency getter function and current route parameters.
47
+ */
48
+ export type ForwardToCallback<Dependencies = object> = (
49
+ getDependency: <K extends keyof Dependencies>(name: K) => Dependencies[K],
50
+ params: Params,
51
+ ) => string;
52
+
53
+ /**
54
+ * Callback function for dynamically resolving the default parameters.
55
+ * Receives a dependency getter function to access router dependencies.
56
+ */
57
+ export type DefaultParamsCallback<Dependencies = object> = (
58
+ getDependency: <K extends keyof Dependencies>(name: K) => Dependencies[K],
59
+ ) => Params;
60
+
61
+ /**
62
+ * Router configuration options.
63
+ *
64
+ * Note: For input, use `Partial<Options>` as all fields have defaults.
65
+ * After initialization, `getOptions()` returns resolved `Options` with all fields populated.
66
+ */
67
+ export interface Options {
68
+ /**
69
+ * Default route to navigate to on start.
70
+ * Empty string means no default route.
71
+ *
72
+ * @default ""
73
+ */
74
+ defaultRoute: string | DefaultRouteCallback;
75
+
76
+ /**
77
+ * Default parameters for the default route.
78
+ *
79
+ * @default {}
80
+ */
81
+ defaultParams: Params | DefaultParamsCallback;
82
+
83
+ /**
84
+ * How to handle trailing slashes in URLs.
85
+ * - "strict": Route must match exactly
86
+ * - "never": Always remove trailing slash
87
+ * - "always": Always add trailing slash
88
+ * - "preserve": Keep as provided
89
+ *
90
+ * @default "preserve"
91
+ */
92
+ trailingSlash: "strict" | "never" | "always" | "preserve";
93
+
94
+ /**
95
+ * How to encode URL parameters.
96
+ * - "default": Standard encoding
97
+ * - "uri": URI encoding (encodeURI)
98
+ * - "uriComponent": Component encoding (encodeURIComponent)
99
+ * - "none": No encoding
100
+ *
101
+ * @default "default"
102
+ */
103
+ urlParamsEncoding: "default" | "uri" | "uriComponent" | "none";
104
+
105
+ /**
106
+ * How to handle query parameters.
107
+ *
108
+ * @default "loose"
109
+ */
110
+ queryParamsMode: QueryParamsMode;
111
+
112
+ /**
113
+ * Query parameter parsing options.
114
+ *
115
+ * @default undefined
116
+ */
117
+ queryParams?: QueryParamsOptions;
118
+
119
+ /**
120
+ * Allow matching routes that don't exist.
121
+ * When true, unknown routes navigate without error.
122
+ *
123
+ * @default true
124
+ */
125
+ allowNotFound: boolean;
126
+
127
+ /**
128
+ * Rewrite path on successful match.
129
+ *
130
+ * @default false
131
+ */
132
+ rewritePathOnMatch: boolean;
133
+
134
+ /**
135
+ * Logger configuration.
136
+ *
137
+ * @default undefined
138
+ */
139
+ logger?: Partial<LoggerConfig>;
140
+
141
+ /**
142
+ * Router resource limits configuration.
143
+ * Controls maximum allowed values for various router operations.
144
+ *
145
+ * @default DEFAULT_LIMITS (from LimitsNamespace)
146
+ */
147
+ limits?: Partial<LimitsConfig>;
148
+
149
+ /**
150
+ * Disables argument validation in public router methods.
151
+ * Use in production for performance. Keep false in development for early error detection.
152
+ *
153
+ * @default false
154
+ */
155
+ noValidate?: boolean;
156
+ }
157
+
158
+ export type ActivationFn = (
159
+ toState: State,
160
+ fromState: State | undefined,
161
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
162
+ ) => boolean | Promise<boolean | State | void> | State | void;
163
+
164
+ export type GuardFn = (
165
+ toState: State,
166
+ fromState: State | undefined,
167
+ ) => boolean | Promise<boolean>;
168
+
169
+ export type DefaultDependencies = object;
170
+
171
+ export interface Config {
172
+ decoders: Record<string, (params: Params) => Params>;
173
+ encoders: Record<string, (params: Params) => Params>;
174
+ defaultParams: Record<string, Params>;
175
+ forwardMap: Record<string, string>;
176
+ }
177
+
178
+ export interface Plugin {
179
+ onStart?: () => void;
180
+ onStop?: () => void;
181
+ onTransitionStart?: (toState: State, fromState?: State) => void;
182
+ onTransitionCancel?: (toState: State, fromState?: State) => void;
183
+ onTransitionError?: (
184
+ toState: State | undefined,
185
+ fromState: State | undefined,
186
+ err: RouterError,
187
+ ) => void;
188
+ onTransitionSuccess?: (
189
+ toState: State,
190
+ fromState: State | undefined,
191
+ opts: NavigationOptions,
192
+ ) => void;
193
+ teardown?: () => void;
194
+ }
195
+
196
+ // eslint-disable-next-line sonarjs/redundant-type-aliases
197
+ export type Middleware = ActivationFn;
198
+
199
+ export interface SubscribeState {
200
+ route: State;
201
+ previousRoute?: State | undefined;
202
+ }
203
+
204
+ export type SubscribeFn = (state: SubscribeState) => void;
205
+
206
+ export interface Listener {
207
+ [key: string]: unknown;
208
+ next: (val: unknown) => void;
209
+ error?: (err: unknown) => void;
210
+ complete?: () => void;
211
+ }
212
+
213
+ export interface Subscription {
214
+ unsubscribe: Unsubscribe;
215
+ }
216
+
217
+ /**
218
+ * Navigator interface - a minimal, safe subset of Router methods.
219
+ *
220
+ * Provides only the essential navigation and state inspection methods.
221
+ * Excludes lifecycle methods (start, stop), plugin management, and internal APIs.
222
+ * Use this when you need to pass a limited router interface to components.
223
+ *
224
+ * For full router access, use the Router interface directly or the useRouter() hook.
225
+ */
226
+ export interface Navigator {
227
+ navigate: (
228
+ routeName: string,
229
+ routeParams?: Params,
230
+ options?: NavigationOptions,
231
+ ) => Promise<State>;
232
+ getState: () => State | undefined;
233
+ isActiveRoute: (
234
+ name: string,
235
+ params?: Params,
236
+ strictEquality?: boolean,
237
+ ignoreQueryParams?: boolean,
238
+ ) => boolean;
239
+ canNavigateTo: (name: string, params?: Params) => boolean;
240
+ subscribe: (listener: SubscribeFn) => Unsubscribe;
241
+ }
242
+
243
+ /**
244
+ * Router interface - public API for route navigation and lifecycle management.
245
+ *
246
+ * Defines the contract for router implementations. The actual Router class in
247
+ * @real-router/core implements this interface with full functionality.
248
+ *
249
+ * This interface uses `GuardFn | boolean` for guard types to avoid circular
250
+ * dependencies. The concrete Router class in @real-router/core narrows this to
251
+ * `GuardFnFactory | boolean` for more precise type checking.
252
+ */
253
+ export interface Router {
254
+ /**
255
+ * Register an activation guard for a route.
256
+ *
257
+ * @param name - Route name
258
+ * @param guard - Guard function or boolean
259
+ * @returns this for method chaining
260
+ */
261
+ addActivateGuard: (name: string, guard: GuardFn | boolean) => this;
262
+
263
+ /**
264
+ * Register a deactivation guard for a route.
265
+ *
266
+ * @param name - Route name
267
+ * @param guard - Guard function or boolean
268
+ * @returns this for method chaining
269
+ */
270
+ addDeactivateGuard: (name: string, guard: GuardFn | boolean) => this;
271
+
272
+ /**
273
+ * Remove an activation guard from a route.
274
+ *
275
+ * @param name - Route name
276
+ */
277
+ removeActivateGuard: (name: string) => void;
278
+
279
+ /**
280
+ * Remove a deactivation guard from a route.
281
+ *
282
+ * @param name - Route name
283
+ */
284
+ removeDeactivateGuard: (name: string) => void;
285
+
286
+ /**
287
+ * Check if navigation to a route is allowed without performing actual navigation.
288
+ *
289
+ * Synchronously checks all activation and deactivation guards in the transition path.
290
+ * Async guards return false with a console warning.
291
+ *
292
+ * @param name - Route name to check
293
+ * @param params - Route parameters (optional)
294
+ * @returns true if navigation is allowed, false otherwise
295
+ */
296
+ canNavigateTo: (name: string, params?: Params) => boolean;
297
+
298
+ /**
299
+ * Dispose the router and release all resources.
300
+ *
301
+ * Stops the router if active, calls plugin teardown, clears all event
302
+ * listeners, middleware, routes, and dependencies. After disposal, all
303
+ * mutating methods throw a ROUTER_DISPOSED error. Idempotent — safe to
304
+ * call multiple times.
305
+ */
306
+ dispose: () => void;
307
+ }