@real-router/react 0.1.1 → 0.1.3
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 +66 -295
- package/dist/cjs/index.d.ts +1798 -65
- package/dist/esm/index.d.mts +1798 -65
- package/package.json +3 -2
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,80 +1,1813 @@
|
|
|
1
|
-
|
|
2
|
-
import * as react from 'react';
|
|
3
|
-
import { MouseEvent, ReactNode, FC, HTMLAttributes, MouseEventHandler } from 'react';
|
|
1
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { FC, HTMLAttributes, MouseEvent as MouseEvent$1, MouseEventHandler, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Route Node Type Definitions — Minimal Public API.
|
|
7
|
+
*
|
|
8
|
+
* This module exports ONLY the essential types used by real-router:
|
|
9
|
+
* - QueryParamsMode, QueryParamsOptions
|
|
10
|
+
* - RouteTreeState
|
|
11
|
+
*
|
|
12
|
+
* These types are copied from route-node to avoid circular dependencies.
|
|
13
|
+
*
|
|
14
|
+
* @module route-node-types
|
|
15
|
+
*/
|
|
16
|
+
export type ArrayFormat = "none" | "brackets" | "index" | "comma";
|
|
17
|
+
export type BooleanFormat = "none" | "string" | "empty-true";
|
|
18
|
+
export type NullFormat = "default" | "hidden";
|
|
19
|
+
/**
|
|
20
|
+
* Options for query parameter parsing and building.
|
|
21
|
+
*/
|
|
22
|
+
export interface QueryParamsOptions {
|
|
23
|
+
arrayFormat?: ArrayFormat;
|
|
24
|
+
booleanFormat?: BooleanFormat;
|
|
25
|
+
nullFormat?: NullFormat;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Controls how query parameters are handled during matching.
|
|
29
|
+
*/
|
|
30
|
+
export type QueryParamsMode = "default" | "strict" | "loose";
|
|
31
|
+
export type ParamSource = "url" | "query";
|
|
32
|
+
export type ParamTypeMap = Record<string, ParamSource>;
|
|
33
|
+
export type RouteTreeStateMeta = Record<string, ParamTypeMap>;
|
|
34
|
+
export interface RouteParams {
|
|
35
|
+
[key: string]: string | string[] | number | number[] | boolean | boolean[] | RouteParams | RouteParams[] | Record<string, string | number | boolean> | null | undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Complete state representation of a matched route.
|
|
39
|
+
*/
|
|
40
|
+
export interface RouteTreeState<P extends Record<string, unknown> = RouteParams> {
|
|
41
|
+
name: string;
|
|
42
|
+
params: P;
|
|
43
|
+
meta: RouteTreeStateMeta;
|
|
44
|
+
}
|
|
45
|
+
export type Unsubscribe = () => void;
|
|
46
|
+
export type CancelFn = () => void;
|
|
47
|
+
export interface SimpleState<P extends Params = Params> {
|
|
48
|
+
name: string;
|
|
49
|
+
params: P;
|
|
50
|
+
}
|
|
51
|
+
export interface State<P extends Params = Params, MP extends Params = Params> {
|
|
52
|
+
name: string;
|
|
53
|
+
params: P;
|
|
54
|
+
path: string;
|
|
55
|
+
meta?: StateMeta<MP> | undefined;
|
|
56
|
+
}
|
|
57
|
+
export interface StateMeta<P extends Params = Params> {
|
|
58
|
+
id: number;
|
|
59
|
+
params: P;
|
|
60
|
+
options: NavigationOptions;
|
|
61
|
+
redirected: boolean;
|
|
62
|
+
source?: string | undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Input type for makeState meta parameter.
|
|
66
|
+
* Omits `id` since it's auto-generated by makeState.
|
|
67
|
+
*/
|
|
68
|
+
export type StateMetaInput<P extends Params = Params> = Omit<StateMeta<P>, "id">;
|
|
69
|
+
/**
|
|
70
|
+
* RouterError interface describing the public API of the RouterError class.
|
|
71
|
+
* The actual class implementation is in the real-router package.
|
|
72
|
+
* This interface enables structural typing compatibility between
|
|
73
|
+
* core-types and real-router packages.
|
|
74
|
+
*/
|
|
75
|
+
export interface RouterError extends Error {
|
|
76
|
+
[key: string]: unknown;
|
|
77
|
+
readonly code: string;
|
|
78
|
+
readonly segment: string | undefined;
|
|
79
|
+
readonly path: string | undefined;
|
|
80
|
+
readonly redirect: State | undefined;
|
|
81
|
+
setCode: (code: string) => void;
|
|
82
|
+
setErrorInstance: (err: Error) => void;
|
|
83
|
+
setAdditionalFields: (fields: Record<string, unknown>) => void;
|
|
84
|
+
hasField: (key: string) => boolean;
|
|
85
|
+
getField: (key: string) => unknown;
|
|
86
|
+
toJSON: () => Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
export type DoneFn = (error?: RouterError, state?: State) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Configuration options that control navigation transition behavior.
|
|
91
|
+
*
|
|
92
|
+
* @description
|
|
93
|
+
* NavigationOptions provides fine-grained control over how the router performs navigation
|
|
94
|
+
* transitions. These options affect history management, transition lifecycle execution,
|
|
95
|
+
* guard enforcement, and state comparison logic.
|
|
96
|
+
*
|
|
97
|
+
* All options are optional and have sensible defaults. Options can be combined to achieve
|
|
98
|
+
* complex navigation behaviors. The options object is stored in state.meta.options and is
|
|
99
|
+
* available to middleware, guards, and event listeners.
|
|
100
|
+
*
|
|
101
|
+
* @see {@link Router.navigate} for navigation method that accepts these options
|
|
102
|
+
* @see {@link State.meta} for where options are stored after navigation
|
|
103
|
+
*/
|
|
104
|
+
export interface NavigationOptions {
|
|
105
|
+
[key: string]: string | number | boolean | Record<string, unknown> | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Replace the current history entry instead of pushing a new one.
|
|
108
|
+
*
|
|
109
|
+
* @description
|
|
110
|
+
* When `true`, the navigation will replace the current entry in browser history instead
|
|
111
|
+
* of adding a new entry. This is typically used by history plugins (browser plugin) to
|
|
112
|
+
* control how navigation affects the browser's back/forward buttons.
|
|
113
|
+
*
|
|
114
|
+
* @default false
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* // Redirect after login - prevent back button to login page
|
|
118
|
+
* router.navigate('dashboard', {}, { replace: true });
|
|
119
|
+
*
|
|
120
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState}
|
|
121
|
+
*/
|
|
122
|
+
replace?: boolean | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Force reload of the current route even if states are equal.
|
|
125
|
+
*
|
|
126
|
+
* @description
|
|
127
|
+
* When `true`, bypasses the "same state" check that normally prevents navigation when
|
|
128
|
+
* the target state equals the current state. This forces a full transition lifecycle
|
|
129
|
+
* execution, allowing route components to reload with the same parameters.
|
|
130
|
+
*
|
|
131
|
+
* Without `reload`:
|
|
132
|
+
* - Navigation to current route throws SAME_STATES error
|
|
133
|
+
* - No lifecycle hooks or middleware execute
|
|
134
|
+
* - No events are fired
|
|
135
|
+
*
|
|
136
|
+
* With `reload`:
|
|
137
|
+
* - Full transition executes (deactivate → activate → middleware)
|
|
138
|
+
* - All lifecycle hooks run again
|
|
139
|
+
* - TRANSITION_SUCCESS event fires with same state
|
|
140
|
+
* - State object is recreated (new reference)
|
|
141
|
+
*
|
|
142
|
+
* @default false
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* // Refresh current page data
|
|
146
|
+
* router.navigate(currentRoute.name, currentRoute.params, { reload: true });
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* // Force re-fetch on same route with different query params
|
|
150
|
+
* // Note: query params are in path, not checked for equality
|
|
151
|
+
* router.navigate('search', { term: 'react' }, { reload: true });
|
|
152
|
+
*
|
|
153
|
+
* @see {@link force} for alternative that forces transition
|
|
154
|
+
* @see {@link Router.areStatesEqual} for state comparison logic
|
|
155
|
+
*/
|
|
156
|
+
reload?: boolean | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Preview navigation without any side effects (dry-run mode).
|
|
159
|
+
*
|
|
160
|
+
* @description
|
|
161
|
+
* When `true`, returns the would-be target state via callback WITHOUT:
|
|
162
|
+
* - Executing canDeactivate/canActivate guards
|
|
163
|
+
* - Executing middleware
|
|
164
|
+
* - Updating router state (`router.getState()` remains unchanged)
|
|
165
|
+
* - Emitting any transition events (TRANSITION_START, TRANSITION_SUCCESS, etc.)
|
|
166
|
+
*
|
|
167
|
+
* The callback receives `(undefined, toState)` where `toState` is the computed
|
|
168
|
+
* target state that WOULD result from this navigation.
|
|
169
|
+
*
|
|
170
|
+
* @default false
|
|
171
|
+
*
|
|
172
|
+
* @remarks
|
|
173
|
+
* This option is useful for:
|
|
174
|
+
* - Validating that a route exists and params are correct
|
|
175
|
+
* - SSR: previewing state for pre-rendering without side effects
|
|
176
|
+
* - Dry-run before actual navigation
|
|
177
|
+
*
|
|
178
|
+
* @deprecated Consider using `router.buildState()` + `router.makeState()` instead
|
|
179
|
+
* for clearer intent. This option may be removed in a future major version.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* // Preview navigation - router.getState() is NOT changed
|
|
183
|
+
* router.navigate('users.view', { id: 123 }, { skipTransition: true }, (err, previewState) => {
|
|
184
|
+
* console.log(previewState); // { name: 'users.view', params: { id: 123 }, path: '/users/view/123', ... }
|
|
185
|
+
* console.log(router.getState()); // Still the previous state!
|
|
186
|
+
* });
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* // Recommended alternative (clearer intent)
|
|
190
|
+
* const route = router.buildState('users.view', { id: 123 });
|
|
191
|
+
* if (route) {
|
|
192
|
+
* const path = router.buildPath(route.name, route.params);
|
|
193
|
+
* const previewState = router.makeState(route.name, route.params, path, { params: route.meta });
|
|
194
|
+
* }
|
|
195
|
+
*
|
|
196
|
+
* @see {@link forceDeactivate} for skipping only canDeactivate guards
|
|
197
|
+
* @see {@link force} for forcing navigation while preserving lifecycle
|
|
198
|
+
*/
|
|
199
|
+
skipTransition?: boolean | undefined;
|
|
200
|
+
/**
|
|
201
|
+
* Force navigation even if target state equals current state.
|
|
202
|
+
*
|
|
203
|
+
* @description
|
|
204
|
+
* When `true`, bypasses the "same state" equality check but still executes the full
|
|
205
|
+
* transition lifecycle (unlike `skipTransition`). Similar to `reload` but can be used
|
|
206
|
+
* for any forced navigation scenario.
|
|
207
|
+
*
|
|
208
|
+
* Difference from `reload`:
|
|
209
|
+
* - `reload`: semantic meaning is "refresh current route"
|
|
210
|
+
* - `force`: general-purpose bypass of equality check
|
|
211
|
+
* - Both have identical implementation effect
|
|
212
|
+
*
|
|
213
|
+
* The equality check compares:
|
|
214
|
+
* - state.name (route name)
|
|
215
|
+
* - state.params (route parameters, shallow comparison)
|
|
216
|
+
*
|
|
217
|
+
* @default false
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* // Force transition for tracking even if params didn't change
|
|
221
|
+
* router.navigate('analytics', { event: 'pageview' }, { force: true });
|
|
222
|
+
*
|
|
223
|
+
* @see {@link reload} for semantic equivalent (preferred for refresh scenarios)
|
|
224
|
+
* @see {@link skipTransition} for bypassing entire lifecycle
|
|
225
|
+
*/
|
|
226
|
+
force?: boolean | undefined;
|
|
227
|
+
/**
|
|
228
|
+
* Skip canDeactivate guards during transition.
|
|
229
|
+
*
|
|
230
|
+
* @description
|
|
231
|
+
* When `true`, bypasses only the canDeactivate lifecycle hooks for segments being
|
|
232
|
+
* deactivated. canActivate guards and middleware still execute normally. This allows
|
|
233
|
+
* forcing navigation away from routes with confirmation dialogs or unsaved changes.
|
|
234
|
+
*
|
|
235
|
+
* Skipped vs executed:
|
|
236
|
+
* ```
|
|
237
|
+
* // Normal transition
|
|
238
|
+
* deactivate(fromSegments) → activate(toSegments) → middleware → success
|
|
239
|
+
*
|
|
240
|
+
* // With forceDeactivate: true
|
|
241
|
+
* [skip deactivate] → activate(toSegments) → middleware → success
|
|
242
|
+
* ```
|
|
243
|
+
*
|
|
244
|
+
* ⚠️ Data loss risk: Bypassing canDeactivate means unsaved changes will be lost
|
|
245
|
+
*
|
|
246
|
+
* @default false
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* // Force logout even with unsaved changes
|
|
250
|
+
* function forceLogout() {
|
|
251
|
+
* router.navigate('login', {}, {
|
|
252
|
+
* forceDeactivate: true,
|
|
253
|
+
* replace: true
|
|
254
|
+
* });
|
|
255
|
+
* }
|
|
256
|
+
*
|
|
257
|
+
* @see {@link skipTransition} for bypassing all guards and middleware
|
|
258
|
+
* @see {@link Router.clearCanDeactivate} for programmatically clearing guards
|
|
259
|
+
*/
|
|
260
|
+
forceDeactivate?: boolean | undefined;
|
|
261
|
+
/**
|
|
262
|
+
* Internal flag indicating navigation is result of a redirect.
|
|
263
|
+
*
|
|
264
|
+
* @internal
|
|
265
|
+
*
|
|
266
|
+
* @description
|
|
267
|
+
* Automatically set by the router when a navigation is triggered by a redirect from
|
|
268
|
+
* middleware or lifecycle hooks. This flag is used internally to track redirect chains
|
|
269
|
+
* and is stored in state.meta.redirected.
|
|
270
|
+
*
|
|
271
|
+
* @default false (auto-set by router during redirects)
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* // Middleware triggers automatic redirect
|
|
275
|
+
* router.useMiddleware((toState, fromState, opts) => {
|
|
276
|
+
* if (!isAuthenticated && toState.name !== 'login') {
|
|
277
|
+
* // Router will automatically set redirected: true
|
|
278
|
+
* return { name: 'login', params: { next: toState.path } };
|
|
279
|
+
* }
|
|
280
|
+
* });
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* // Accessing redirect flag in lifecycle
|
|
284
|
+
* router.canActivate('dashboard', (toState, fromState) => {
|
|
285
|
+
* if (toState.meta?.redirected) {
|
|
286
|
+
* console.log('This navigation is from a redirect');
|
|
287
|
+
* }
|
|
288
|
+
* return true;
|
|
289
|
+
* });
|
|
290
|
+
*
|
|
291
|
+
* @see {@link Router.navigate} for redirect handling implementation
|
|
292
|
+
* @see {@link State.meta.redirected} for redirect flag in state
|
|
293
|
+
*/
|
|
294
|
+
redirected?: boolean | undefined;
|
|
295
|
+
}
|
|
296
|
+
export interface Params {
|
|
297
|
+
[key: string]: string | string[] | number | number[] | boolean | boolean[] | Params | Params[] | Record<string, string | number | boolean> | null | undefined;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Event type keys
|
|
301
|
+
*/
|
|
302
|
+
export type EventsKeys = "ROUTER_START" | "ROUTER_STOP" | "TRANSITION_START" | "TRANSITION_CANCEL" | "TRANSITION_SUCCESS" | "TRANSITION_ERROR";
|
|
303
|
+
/**
|
|
304
|
+
* Mapping of event keys to event names
|
|
305
|
+
*/
|
|
306
|
+
export interface EventToNameMap {
|
|
307
|
+
ROUTER_START: "$start";
|
|
308
|
+
ROUTER_STOP: "$stop";
|
|
309
|
+
TRANSITION_START: "$$start";
|
|
310
|
+
TRANSITION_CANCEL: "$$cancel";
|
|
311
|
+
TRANSITION_SUCCESS: "$$success";
|
|
312
|
+
TRANSITION_ERROR: "$$error";
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Log message severity level.
|
|
316
|
+
*
|
|
317
|
+
* Ordered by severity (lowest to highest):
|
|
318
|
+
* - `log`: Informational messages, debugging, trace
|
|
319
|
+
* - `warn`: Warnings, deprecations, non-critical issues
|
|
320
|
+
* - `error`: Critical errors, exceptions, failures
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```ts
|
|
324
|
+
* const level: LogLevel = 'warn';
|
|
325
|
+
* logger[level]('Router', 'Message'); // Calls logger.warn()
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export type LogLevel = "log" | "warn" | "error";
|
|
329
|
+
/**
|
|
330
|
+
* Logger threshold configuration level.
|
|
331
|
+
*
|
|
332
|
+
* Determines which messages are displayed based on severity:
|
|
333
|
+
* - `all`: Show all messages (log, warn, error)
|
|
334
|
+
* - `warn-error`: Show only warnings and errors (filter out log)
|
|
335
|
+
* - `error-only`: Show only errors (filter out log and warn)
|
|
336
|
+
* - `none`: Show no messages (completely silent, unless callback ignores level)
|
|
337
|
+
*
|
|
338
|
+
* Note: Higher threshold = fewer messages shown.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* // Production: only show errors
|
|
343
|
+
* logger.configure({ level: 'error-only' });
|
|
344
|
+
*
|
|
345
|
+
* // Development: show everything
|
|
346
|
+
* logger.configure({ level: 'all' });
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export type LogLevelConfig = "all" | "warn-error" | "error-only" | "none";
|
|
350
|
+
/**
|
|
351
|
+
* Callback function type for custom log processing.
|
|
352
|
+
*
|
|
353
|
+
* Receives all log messages that pass the configured level threshold
|
|
354
|
+
* (unless `callbackIgnoresLevel` is true, then receives all messages).
|
|
355
|
+
*
|
|
356
|
+
* Common use cases:
|
|
357
|
+
* - Send logs to external analytics service
|
|
358
|
+
* - Store logs in memory for debugging
|
|
359
|
+
* - Filter and forward to remote logging system
|
|
360
|
+
* - Display logs in custom UI component
|
|
361
|
+
*
|
|
362
|
+
* @param level - Severity level of this message
|
|
363
|
+
* @param context - Context/module identifier (e.g., 'Router', 'Plugin')
|
|
364
|
+
* @param message - Main log message text
|
|
365
|
+
* @param args - Additional arguments (objects, errors, etc.)
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* const analyticsCallback: LogCallback = (level, context, message, ...args) => {
|
|
370
|
+
* sendToAnalytics({
|
|
371
|
+
* severity: level,
|
|
372
|
+
* module: context,
|
|
373
|
+
* text: message,
|
|
374
|
+
* metadata: args
|
|
375
|
+
* });
|
|
376
|
+
* };
|
|
377
|
+
*
|
|
378
|
+
* logger.configure({ callback: analyticsCallback });
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
export type LogCallback = (level: LogLevel, context: string, message: string, ...args: unknown[]) => void;
|
|
382
|
+
/**
|
|
383
|
+
* Logger configuration interface.
|
|
384
|
+
*
|
|
385
|
+
* Controls both console output and callback behavior.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```ts
|
|
389
|
+
* // Minimal configuration
|
|
390
|
+
* const config: LoggerConfig = {
|
|
391
|
+
* level: 'warn-error'
|
|
392
|
+
* };
|
|
393
|
+
*
|
|
394
|
+
* // Full configuration with callback
|
|
395
|
+
* const config: LoggerConfig = {
|
|
396
|
+
* level: 'error-only',
|
|
397
|
+
* callback: (level, context, message) => {
|
|
398
|
+
* // Send all errors to monitoring service
|
|
399
|
+
* },
|
|
400
|
+
* callbackIgnoresLevel: false // Callback respects 'error-only' level
|
|
401
|
+
* };
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
export interface LoggerConfig {
|
|
405
|
+
/**
|
|
406
|
+
* Minimum severity level to display in console.
|
|
407
|
+
*
|
|
408
|
+
* Messages below this threshold are filtered out from console output.
|
|
409
|
+
* Does not affect callback unless `callbackIgnoresLevel` is false.
|
|
410
|
+
*
|
|
411
|
+
* @default 'all'
|
|
412
|
+
*/
|
|
413
|
+
level: LogLevelConfig;
|
|
414
|
+
/**
|
|
415
|
+
* Optional callback function for custom log processing.
|
|
416
|
+
*
|
|
417
|
+
* Called for each log message (subject to `callbackIgnoresLevel` setting).
|
|
418
|
+
* Can be undefined to disable callback processing.
|
|
419
|
+
*
|
|
420
|
+
* @default undefined
|
|
421
|
+
*/
|
|
422
|
+
callback?: LogCallback | undefined;
|
|
423
|
+
/**
|
|
424
|
+
* Whether callback should receive ALL messages regardless of level threshold.
|
|
425
|
+
*
|
|
426
|
+
* - `false` (default): Callback only receives messages that pass level threshold
|
|
427
|
+
* (same filtering as console output)
|
|
428
|
+
* - `true`: Callback receives ALL messages, even those filtered from console
|
|
429
|
+
* (useful for analytics where you want to track everything)
|
|
430
|
+
*
|
|
431
|
+
* @default false
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```ts
|
|
435
|
+
* // Scenario: Show only errors in console, but track ALL logs in analytics
|
|
436
|
+
* logger.configure({
|
|
437
|
+
* level: 'error-only', // Console: only errors
|
|
438
|
+
* callback: sendToAnalytics,
|
|
439
|
+
* callbackIgnoresLevel: true // Callback: receives log/warn/error
|
|
440
|
+
* });
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
callbackIgnoresLevel?: boolean;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Extended build result that includes segments for path building.
|
|
447
|
+
* Used internally to avoid duplicate getSegmentsByName calls.
|
|
448
|
+
*
|
|
449
|
+
* @param segments - Route segments from getSegmentsByName (typed as unknown[] for cross-package compatibility)
|
|
450
|
+
* @internal
|
|
451
|
+
*/
|
|
452
|
+
export interface BuildStateResultWithSegments<P extends Params = Params> {
|
|
453
|
+
readonly state: RouteTreeState<P>;
|
|
454
|
+
readonly segments: readonly unknown[];
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Route configuration.
|
|
458
|
+
*/
|
|
459
|
+
export interface Route<Dependencies extends DefaultDependencies = DefaultDependencies> {
|
|
460
|
+
[key: string]: unknown;
|
|
461
|
+
/** Route name (dot-separated for nested routes). */
|
|
462
|
+
name: string;
|
|
463
|
+
/** URL path pattern for this route. */
|
|
464
|
+
path: string;
|
|
465
|
+
/** Factory function that returns a guard for route activation. */
|
|
466
|
+
canActivate?: ActivationFnFactory<Dependencies>;
|
|
467
|
+
/**
|
|
468
|
+
* Redirects navigation to another route.
|
|
469
|
+
*
|
|
470
|
+
* IMPORTANT: forwardTo creates a URL alias, not a transition chain.
|
|
471
|
+
* Guards (canActivate) on the source route are NOT executed.
|
|
472
|
+
* Only guards on the final destination are executed.
|
|
473
|
+
*
|
|
474
|
+
* This matches Vue Router and Angular Router behavior.
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* // Correct: guard on target
|
|
478
|
+
* { name: "old", path: "/old", forwardTo: "new" }
|
|
479
|
+
* { name: "new", path: "/new", canActivate: myGuard }
|
|
480
|
+
*
|
|
481
|
+
* // Wrong: guard on source (will be ignored with warning)
|
|
482
|
+
* { name: "old", path: "/old", forwardTo: "new", canActivate: myGuard }
|
|
483
|
+
*/
|
|
484
|
+
forwardTo?: string;
|
|
485
|
+
/** Nested child routes. */
|
|
486
|
+
children?: Route<Dependencies>[];
|
|
487
|
+
/** Encodes state params to URL params. */
|
|
488
|
+
encodeParams?: (stateParams: Params) => Params;
|
|
489
|
+
/** Decodes URL params to state params. */
|
|
490
|
+
decodeParams?: (pathParams: Params) => Params;
|
|
491
|
+
/**
|
|
492
|
+
* Default parameters for this route.
|
|
493
|
+
*
|
|
494
|
+
* @remarks
|
|
495
|
+
* **Type Contract:**
|
|
496
|
+
* The type of defaultParams MUST match the expected params type P
|
|
497
|
+
* when using `router.makeState<P>()` or `router.navigate<P>()`.
|
|
498
|
+
*
|
|
499
|
+
* These values are merged into state.params when creating route states.
|
|
500
|
+
* Missing URL params are filled from defaultParams.
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* ```typescript
|
|
504
|
+
* // Define route with pagination defaults
|
|
505
|
+
* {
|
|
506
|
+
* name: "users",
|
|
507
|
+
* path: "/users",
|
|
508
|
+
* defaultParams: { page: 1, limit: 10 }
|
|
509
|
+
* }
|
|
510
|
+
*
|
|
511
|
+
* // Navigate without specifying page/limit
|
|
512
|
+
* router.navigate("users", { filter: "active" });
|
|
513
|
+
* // Result: state.params = { page: 1, limit: 10, filter: "active" }
|
|
514
|
+
*
|
|
515
|
+
* // Correct typing — include defaultParams properties
|
|
516
|
+
* type UsersParams = { page: number; limit: number; filter?: string };
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
defaultParams?: Params;
|
|
8
520
|
}
|
|
9
|
-
|
|
10
|
-
|
|
521
|
+
/**
|
|
522
|
+
* Router configuration options.
|
|
523
|
+
*
|
|
524
|
+
* Note: For input, use `Partial<Options>` as all fields have defaults.
|
|
525
|
+
* After initialization, `getOptions()` returns resolved `Options` with all fields populated.
|
|
526
|
+
*/
|
|
527
|
+
export interface Options {
|
|
528
|
+
/**
|
|
529
|
+
* Default route to navigate to on start.
|
|
530
|
+
* Empty string means no default route.
|
|
531
|
+
*
|
|
532
|
+
* @default ""
|
|
533
|
+
*/
|
|
534
|
+
defaultRoute: string;
|
|
535
|
+
/**
|
|
536
|
+
* Default parameters for the default route.
|
|
537
|
+
*
|
|
538
|
+
* @default {}
|
|
539
|
+
*/
|
|
540
|
+
defaultParams: Params;
|
|
541
|
+
/**
|
|
542
|
+
* How to handle trailing slashes in URLs.
|
|
543
|
+
* - "strict": Route must match exactly
|
|
544
|
+
* - "never": Always remove trailing slash
|
|
545
|
+
* - "always": Always add trailing slash
|
|
546
|
+
* - "preserve": Keep as provided
|
|
547
|
+
*
|
|
548
|
+
* @default "preserve"
|
|
549
|
+
*/
|
|
550
|
+
trailingSlash: "strict" | "never" | "always" | "preserve";
|
|
551
|
+
/**
|
|
552
|
+
* Whether route names are case-sensitive.
|
|
553
|
+
*
|
|
554
|
+
* @default false
|
|
555
|
+
*/
|
|
556
|
+
caseSensitive: boolean;
|
|
557
|
+
/**
|
|
558
|
+
* How to encode URL parameters.
|
|
559
|
+
* - "default": Standard encoding
|
|
560
|
+
* - "uri": URI encoding (encodeURI)
|
|
561
|
+
* - "uriComponent": Component encoding (encodeURIComponent)
|
|
562
|
+
* - "none": No encoding
|
|
563
|
+
*
|
|
564
|
+
* @default "default"
|
|
565
|
+
*/
|
|
566
|
+
urlParamsEncoding: "default" | "uri" | "uriComponent" | "none";
|
|
567
|
+
/**
|
|
568
|
+
* How to handle query parameters.
|
|
569
|
+
*
|
|
570
|
+
* @default "loose"
|
|
571
|
+
*/
|
|
572
|
+
queryParamsMode: QueryParamsMode;
|
|
573
|
+
/**
|
|
574
|
+
* Query parameter parsing options.
|
|
575
|
+
*
|
|
576
|
+
* @default undefined
|
|
577
|
+
*/
|
|
578
|
+
queryParams?: QueryParamsOptions;
|
|
579
|
+
/**
|
|
580
|
+
* Allow matching routes that don't exist.
|
|
581
|
+
* When true, unknown routes navigate without error.
|
|
582
|
+
*
|
|
583
|
+
* @default true
|
|
584
|
+
*/
|
|
585
|
+
allowNotFound: boolean;
|
|
586
|
+
/**
|
|
587
|
+
* Rewrite path on successful match.
|
|
588
|
+
*
|
|
589
|
+
* @default false
|
|
590
|
+
*/
|
|
591
|
+
rewritePathOnMatch: boolean;
|
|
592
|
+
/**
|
|
593
|
+
* Logger configuration.
|
|
594
|
+
*
|
|
595
|
+
* @default undefined
|
|
596
|
+
*/
|
|
597
|
+
logger?: Partial<LoggerConfig>;
|
|
598
|
+
}
|
|
599
|
+
export type ActivationFn = (toState: State, fromState: State | undefined, done: DoneFn) => boolean | Promise<boolean | object | void> | State | void;
|
|
600
|
+
export type ActivationFnFactory<Dependencies extends DefaultDependencies = DefaultDependencies> = (router: Router<Dependencies>, getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K]) => ActivationFn;
|
|
601
|
+
export type DefaultDependencies = object;
|
|
602
|
+
/**
|
|
603
|
+
* Configuration update options for updateRoute().
|
|
604
|
+
* All properties are optional. Set to null to remove the configuration.
|
|
605
|
+
*/
|
|
606
|
+
export interface RouteConfigUpdate<Dependencies extends DefaultDependencies = DefaultDependencies> {
|
|
607
|
+
/** Set to null to remove forwardTo */
|
|
608
|
+
forwardTo?: string | null;
|
|
609
|
+
/** Set to null to remove defaultParams */
|
|
610
|
+
defaultParams?: Params | null;
|
|
611
|
+
/** Set to null to remove decoder */
|
|
612
|
+
decodeParams?: ((params: Params) => Params) | null;
|
|
613
|
+
/** Set to null to remove encoder */
|
|
614
|
+
encodeParams?: ((params: Params) => Params) | null;
|
|
615
|
+
/** Set to null to remove canActivate */
|
|
616
|
+
canActivate?: ActivationFnFactory<Dependencies> | null;
|
|
617
|
+
}
|
|
618
|
+
export interface Router<Dependencies extends DefaultDependencies = DefaultDependencies> {
|
|
619
|
+
[key: symbol]: unknown;
|
|
620
|
+
[key: string]: unknown;
|
|
621
|
+
addRoute: (routes: Route<Dependencies>[] | Route<Dependencies>) => Router<Dependencies>;
|
|
622
|
+
isActiveRoute: (name: string, params?: Params, strictEquality?: boolean, ignoreQueryParams?: boolean) => boolean;
|
|
623
|
+
buildPath: (route: string, params?: Params) => string;
|
|
624
|
+
/**
|
|
625
|
+
* Internal path builder that accepts pre-computed segments.
|
|
626
|
+
* Avoids duplicate getSegmentsByName call when segments are already available.
|
|
627
|
+
*
|
|
628
|
+
* @param segments - Route segments from getSegmentsByName (typed as unknown[] for cross-package compatibility)
|
|
629
|
+
* @internal
|
|
630
|
+
*/
|
|
631
|
+
buildPathWithSegments: (route: string, params: Params, segments: readonly unknown[]) => string;
|
|
632
|
+
matchPath: <P extends Params = Params, MP extends Params = Params>(path: string, source?: string) => State<P, MP> | undefined;
|
|
633
|
+
/**
|
|
634
|
+
* Sets the root path for the router.
|
|
635
|
+
*
|
|
636
|
+
* @param rootPath - New root path
|
|
637
|
+
* @returns void
|
|
638
|
+
*/
|
|
639
|
+
setRootPath: (rootPath: string) => void;
|
|
640
|
+
/**
|
|
641
|
+
* Gets the current root path for the router.
|
|
642
|
+
*
|
|
643
|
+
* @returns Current root path
|
|
644
|
+
*/
|
|
645
|
+
getRootPath: () => string;
|
|
646
|
+
/**
|
|
647
|
+
* Removes route configurations (metadata only).
|
|
648
|
+
*
|
|
649
|
+
* @description
|
|
650
|
+
* Clears associated configurations for a route (decoders, encoders, defaultParams,
|
|
651
|
+
* forwardMap). Note: RouteNode doesn't provide API for actual route removal from tree.
|
|
652
|
+
* Consider recreating the router with filtered routes for full removal.
|
|
653
|
+
*
|
|
654
|
+
* @param name - Route name to remove configurations for
|
|
655
|
+
* @returns Router instance for chaining
|
|
656
|
+
* @throws {TypeError} If name is not a valid route name
|
|
657
|
+
*/
|
|
658
|
+
removeRoute: (name: string) => Router<Dependencies>;
|
|
659
|
+
/**
|
|
660
|
+
* Clears all routes from the router.
|
|
661
|
+
*
|
|
662
|
+
* @description
|
|
663
|
+
* Removes all route definitions, configurations, and lifecycle handlers.
|
|
664
|
+
* Preserves: listeners, plugins, dependencies, options, state.
|
|
665
|
+
* After clearing, you can add new routes with addRoute().
|
|
666
|
+
*
|
|
667
|
+
* @returns Router instance for chaining
|
|
668
|
+
*
|
|
669
|
+
* @example
|
|
670
|
+
* // Clear all routes and add new ones
|
|
671
|
+
* router.clearRoutes().addRoute([
|
|
672
|
+
* { name: 'home', path: '/' },
|
|
673
|
+
* { name: 'about', path: '/about' }
|
|
674
|
+
* ]);
|
|
675
|
+
*/
|
|
676
|
+
clearRoutes: () => Router<Dependencies>;
|
|
677
|
+
/**
|
|
678
|
+
* Retrieves the full configuration of a route by name.
|
|
679
|
+
*
|
|
680
|
+
* @description
|
|
681
|
+
* Reconstructs the Route object from internal storage, including:
|
|
682
|
+
* - name, path, children from route definitions
|
|
683
|
+
* - forwardTo from forwardMap
|
|
684
|
+
* - defaultParams, decodeParams, encodeParams from config
|
|
685
|
+
* - canActivate from lifecycle factories
|
|
686
|
+
*
|
|
687
|
+
* Note: Custom properties (meta, etc.) are NOT preserved and won't be returned.
|
|
688
|
+
*
|
|
689
|
+
* @param name - Route name (dot-notation for nested routes, e.g., 'users.profile')
|
|
690
|
+
* @returns Route configuration or undefined if not found
|
|
691
|
+
*
|
|
692
|
+
* @throws {TypeError} If name is not a valid route name
|
|
693
|
+
*
|
|
694
|
+
* @example
|
|
695
|
+
* const route = router.getRoute('users.profile');
|
|
696
|
+
* if (route) {
|
|
697
|
+
* console.log(route.path, route.defaultParams);
|
|
698
|
+
* }
|
|
699
|
+
*/
|
|
700
|
+
getRoute: (name: string) => Route<Dependencies> | undefined;
|
|
701
|
+
/**
|
|
702
|
+
* Checks if a route exists in the router.
|
|
703
|
+
*
|
|
704
|
+
* @description
|
|
705
|
+
* Lightweight check for route existence without constructing the full Route object.
|
|
706
|
+
* More efficient than `!!router.getRoute(name)` when you only need to check existence.
|
|
707
|
+
*
|
|
708
|
+
* @param name - Route name to check (supports dot notation for nested routes)
|
|
709
|
+
* @returns true if route exists, false otherwise
|
|
710
|
+
*
|
|
711
|
+
* @throws {TypeError} If name is not a valid route name
|
|
712
|
+
*
|
|
713
|
+
* @example
|
|
714
|
+
* if (router.hasRoute('users.profile')) {
|
|
715
|
+
* router.navigate('users.profile', { id: 123 });
|
|
716
|
+
* }
|
|
717
|
+
*/
|
|
718
|
+
hasRoute: (name: string) => boolean;
|
|
719
|
+
/**
|
|
720
|
+
* Updates configuration properties of an existing route.
|
|
721
|
+
*
|
|
722
|
+
* @description
|
|
723
|
+
* Only updates configuration (forwardTo, defaultParams, encoders, decoders, canActivate).
|
|
724
|
+
* Does NOT update path or children (requires tree rebuild - use removeRoute + addRoute).
|
|
725
|
+
*
|
|
726
|
+
* Set a property to null to remove it. For example:
|
|
727
|
+
* - `{ forwardTo: null }` removes the forwardTo redirect
|
|
728
|
+
* - `{ canActivate: null }` removes the canActivate guard
|
|
729
|
+
*
|
|
730
|
+
* @param name - Route name to update
|
|
731
|
+
* @param updates - Partial route configuration to apply
|
|
732
|
+
* @returns Router instance for chaining
|
|
733
|
+
*
|
|
734
|
+
* @throws {TypeError} If name is not a valid route name
|
|
735
|
+
* @throws {ReferenceError} If route does not exist
|
|
736
|
+
* @throws {Error} If updating forwardTo with invalid target or cycle
|
|
737
|
+
*
|
|
738
|
+
* @example
|
|
739
|
+
* // Add/update configuration
|
|
740
|
+
* router.updateRoute('users', {
|
|
741
|
+
* defaultParams: { page: 1 },
|
|
742
|
+
* canActivate: authGuard
|
|
743
|
+
* });
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* // Remove configuration
|
|
747
|
+
* router.updateRoute('oldRoute', { forwardTo: null });
|
|
748
|
+
*/
|
|
749
|
+
updateRoute: (name: string, updates: RouteConfigUpdate<Dependencies>) => Router<Dependencies>;
|
|
750
|
+
/**
|
|
751
|
+
* Returns a copy of the previous state before the last navigation.
|
|
752
|
+
*
|
|
753
|
+
* @returns Copy of the previous state or undefined if no previous state exists
|
|
754
|
+
*/
|
|
755
|
+
getPreviousState: () => State | undefined;
|
|
756
|
+
shouldUpdateNode: (nodeName: string) => (toState: State, fromState?: State) => boolean;
|
|
757
|
+
/**
|
|
758
|
+
* Returns a copy of the router's current configuration options.
|
|
759
|
+
*
|
|
760
|
+
* @description
|
|
761
|
+
* Provides read-only access to the router's configuration by returning a shallow
|
|
762
|
+
* copy of all current options. This method is useful for inspecting settings,
|
|
763
|
+
* debugging, passing configuration to other components, or conditional logic
|
|
764
|
+
* based on router configuration.
|
|
765
|
+
*
|
|
766
|
+
* @returns A shallow copy of the current router options. Each call returns
|
|
767
|
+
* a new object with all configuration properties.
|
|
768
|
+
*
|
|
769
|
+
* @example
|
|
770
|
+
* // Basic usage - inspect configuration
|
|
771
|
+
* const options = router.getOptions();
|
|
772
|
+
* console.log('Case sensitive:', options.caseSensitive);
|
|
773
|
+
* console.log('Trailing slash mode:', options.trailingSlash);
|
|
774
|
+
*
|
|
775
|
+
* @see {@link setOption} for modifying individual options
|
|
776
|
+
*/
|
|
777
|
+
getOptions: () => Options;
|
|
778
|
+
/**
|
|
779
|
+
* Sets a single configuration option value.
|
|
780
|
+
*
|
|
781
|
+
* @description
|
|
782
|
+
* Modifies an individual router configuration option with type-safe validation.
|
|
783
|
+
* This method can ONLY be used before calling router.start() - after the router
|
|
784
|
+
* starts, all options become immutable and any attempt to modify them will throw
|
|
785
|
+
* an error.
|
|
786
|
+
*
|
|
787
|
+
* @param option - The name of the option to set. Must be a valid option key.
|
|
788
|
+
* @param value - The new value for the option. Type must match the option's expected type.
|
|
789
|
+
*
|
|
790
|
+
* @returns The router instance for method chaining.
|
|
791
|
+
*
|
|
792
|
+
* @throws {Error} If router is already started (router.isStarted() === true)
|
|
793
|
+
* @throws {ReferenceError} If option name doesn't exist in Options interface
|
|
794
|
+
* @throws {TypeError} If value type doesn't match expected type for the option
|
|
795
|
+
* @throws {TypeError} If object option receives non-plain object (array, date, class, null)
|
|
796
|
+
*
|
|
797
|
+
* @see {@link getOptions} for retrieving current options
|
|
798
|
+
*/
|
|
799
|
+
setOption: (option: keyof Options, value: Options[keyof Options]) => Router<Dependencies>;
|
|
800
|
+
makeState: <P extends Params = Params, MP extends Params = Params>(name: string, params?: P, path?: string, meta?: StateMetaInput<MP>, forceId?: number) => State<P, MP>;
|
|
801
|
+
makeNotFoundState: (path: string, options?: NavigationOptions) => State;
|
|
802
|
+
getState: <P extends Params = Params, MP extends Params = Params>() => State<P, MP> | undefined;
|
|
803
|
+
setState: <P extends Params = Params, MP extends Params = Params>(state?: State<P, MP>) => void;
|
|
804
|
+
areStatesEqual: (state1: State | undefined, state2: State | undefined, ignoreQueryParams?: boolean) => boolean;
|
|
805
|
+
areStatesDescendants: (parentState: State, childState: State) => boolean;
|
|
806
|
+
forwardState: <P extends Params = Params>(routeName: string, routeParams: P) => SimpleState<P>;
|
|
807
|
+
buildState: (routeName: string, routeParams: Params) => RouteTreeState | undefined;
|
|
808
|
+
/**
|
|
809
|
+
* Builds state with segments for internal use.
|
|
810
|
+
* Avoids duplicate getSegmentsByName call when path building is needed.
|
|
811
|
+
*
|
|
812
|
+
* @internal
|
|
813
|
+
*/
|
|
814
|
+
buildStateWithSegments: <P extends Params = Params>(routeName: string, routeParams: P) => BuildStateResultWithSegments<P> | undefined;
|
|
815
|
+
/**
|
|
816
|
+
* Checks whether the router has been successfully started.
|
|
817
|
+
*
|
|
818
|
+
* @description
|
|
819
|
+
* Returns true if the router has been started via the `start()` method and has not
|
|
820
|
+
* been stopped. When the router is started, it means:
|
|
821
|
+
* - Initial navigation has been attempted
|
|
822
|
+
* - Event listeners can receive navigation events
|
|
823
|
+
* - The router is ready to handle navigation requests
|
|
824
|
+
*
|
|
825
|
+
* Note: A router being "started" doesn't guarantee that the initial navigation
|
|
826
|
+
* succeeded. Use `getState()` to verify if a valid state exists.
|
|
827
|
+
*
|
|
828
|
+
* @returns true if the router is started, false otherwise
|
|
829
|
+
*
|
|
830
|
+
* @example
|
|
831
|
+
* // Check if router is started before navigation
|
|
832
|
+
* if (!router.isStarted()) {
|
|
833
|
+
* router.start('/home');
|
|
834
|
+
* }
|
|
835
|
+
*
|
|
836
|
+
* @example
|
|
837
|
+
* // Conditional logic based on router state
|
|
838
|
+
* const isReady = router.isStarted() && router.getState() !== undefined;
|
|
839
|
+
*/
|
|
840
|
+
isStarted: () => boolean;
|
|
841
|
+
/**
|
|
842
|
+
* Checks if the router is active (starting or started).
|
|
843
|
+
*
|
|
844
|
+
* @description
|
|
845
|
+
* Returns true if the router is in the process of starting or has already started.
|
|
846
|
+
* This is different from `isStarted()` which only returns true after successful
|
|
847
|
+
* initial transition.
|
|
848
|
+
*
|
|
849
|
+
* This method is primarily used internally by the transition module to determine
|
|
850
|
+
* if transitions should be cancelled. During the initial start transition,
|
|
851
|
+
* `isStarted()` is false but `isActive()` is true, allowing the transition to proceed.
|
|
852
|
+
*
|
|
853
|
+
* @returns true if router is active (starting or started), false if stopped
|
|
854
|
+
*
|
|
855
|
+
* @example
|
|
856
|
+
* // Check if router is active (even during initial start)
|
|
857
|
+
* if (router.isActive()) {
|
|
858
|
+
* console.log('Router is active');
|
|
859
|
+
* }
|
|
860
|
+
*
|
|
861
|
+
* @see {@link isStarted} to check if initial transition completed
|
|
862
|
+
* @see https://github.com/greydragon888/real-router/issues/50
|
|
863
|
+
*/
|
|
864
|
+
isActive: () => boolean;
|
|
865
|
+
/**
|
|
866
|
+
* Checks if a navigation transition is currently in progress.
|
|
867
|
+
*
|
|
868
|
+
* @description
|
|
869
|
+
* Returns true when the router is actively processing a navigation request.
|
|
870
|
+
* This includes the time spent executing guards (canDeactivate, canActivate)
|
|
871
|
+
* and middleware functions.
|
|
872
|
+
*
|
|
873
|
+
* Useful for:
|
|
874
|
+
* - Preventing route modifications during navigation
|
|
875
|
+
* - Showing loading indicators
|
|
876
|
+
* - Debouncing navigation requests
|
|
877
|
+
*
|
|
878
|
+
* @returns true if navigation is in progress, false otherwise
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
881
|
+
* // Prevent route removal during navigation
|
|
882
|
+
* if (router.isNavigating()) {
|
|
883
|
+
* console.warn('Cannot modify routes during navigation');
|
|
884
|
+
* return;
|
|
885
|
+
* }
|
|
886
|
+
*
|
|
887
|
+
* @example
|
|
888
|
+
* // Show loading state
|
|
889
|
+
* const isLoading = router.isNavigating();
|
|
890
|
+
*
|
|
891
|
+
* @remarks
|
|
892
|
+
* After FSM migration (RFC-2), this will use RouterState.TRANSITIONING
|
|
893
|
+
* for more granular state tracking.
|
|
894
|
+
*/
|
|
895
|
+
isNavigating: () => boolean;
|
|
896
|
+
/**
|
|
897
|
+
* Initializes the router and performs the initial navigation.
|
|
898
|
+
*
|
|
899
|
+
* @description
|
|
900
|
+
* Starts the router and navigates to the initial route. This method must be called
|
|
901
|
+
* before any navigation operations. The initial route can be specified as a path
|
|
902
|
+
* string, a state object, or determined by the default route option.
|
|
903
|
+
*
|
|
904
|
+
* @param startPathOrState - Optional. The initial route as a path string or state object.
|
|
905
|
+
* If omitted, uses the default route if configured.
|
|
906
|
+
* @param done - Optional. Callback function called when start completes or fails.
|
|
907
|
+
*
|
|
908
|
+
* @returns The router instance for method chaining
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* router.start()
|
|
912
|
+
*
|
|
913
|
+
* @example
|
|
914
|
+
* router.start('/users/123', (err, state) => {
|
|
915
|
+
* if (!err) console.log('Started at:', state.name)
|
|
916
|
+
* })
|
|
917
|
+
*/
|
|
918
|
+
start: (() => Router<Dependencies>) & ((done: DoneFn) => Router<Dependencies>) & ((startPathOrState: string | State) => Router<Dependencies>) & ((startPathOrState: string | State, done: DoneFn) => Router<Dependencies>);
|
|
919
|
+
/**
|
|
920
|
+
* Stops the router and cleans up its state.
|
|
921
|
+
*
|
|
922
|
+
* @description
|
|
923
|
+
* Stops the router, clearing the current state and preventing further navigation.
|
|
924
|
+
* This method should be called when the router is no longer needed, typically
|
|
925
|
+
* during application cleanup or before unmounting.
|
|
926
|
+
*
|
|
927
|
+
* If the router is not started, this method does nothing and returns silently.
|
|
928
|
+
*
|
|
929
|
+
* @returns The router instance for method chaining
|
|
930
|
+
*
|
|
931
|
+
* @example
|
|
932
|
+
* // Stop the router
|
|
933
|
+
* router.stop();
|
|
934
|
+
*
|
|
935
|
+
* @fires ROUTER_STOP - When the router is successfully stopped
|
|
936
|
+
*
|
|
937
|
+
* @see {@link start} to restart the router
|
|
938
|
+
* @see {@link isStarted} to check router status
|
|
939
|
+
*/
|
|
940
|
+
stop: () => Router<Dependencies>;
|
|
941
|
+
canDeactivate: (name: string, canDeactivateHandler: ActivationFnFactory<Dependencies> | boolean) => Router<Dependencies>;
|
|
942
|
+
clearCanDeactivate: (name: string, silent?: boolean) => Router<Dependencies>;
|
|
943
|
+
canActivate: (name: string, canActivateHandler: ActivationFnFactory<Dependencies> | boolean) => Router<Dependencies>;
|
|
944
|
+
clearCanActivate: (name: string, silent?: boolean) => Router<Dependencies>;
|
|
945
|
+
getLifecycleFactories: () => [
|
|
946
|
+
Record<string, ActivationFnFactory<Dependencies>>,
|
|
947
|
+
Record<string, ActivationFnFactory<Dependencies>>
|
|
948
|
+
];
|
|
949
|
+
getLifecycleFunctions: () => [
|
|
950
|
+
Map<string, ActivationFn>,
|
|
951
|
+
Map<string, ActivationFn>
|
|
952
|
+
];
|
|
953
|
+
/**
|
|
954
|
+
* Registers plugin(s) to extend router functionality through lifecycle event subscriptions.
|
|
955
|
+
*
|
|
956
|
+
* @description
|
|
957
|
+
* Provides the primary mechanism for adding cross-cutting functionality to the router
|
|
958
|
+
* through a plugin-based architecture. Plugins can react to router lifecycle events
|
|
959
|
+
* (start/stop, navigation transitions) without modifying the core router code.
|
|
960
|
+
*
|
|
961
|
+
* @param plugins - Variable number of plugin factory functions.
|
|
962
|
+
* Each factory receives (router, getDependency) and must return
|
|
963
|
+
* a Plugin object with optional event handler methods.
|
|
964
|
+
*
|
|
965
|
+
* @returns Unsubscribe function that removes only the plugins registered in this call.
|
|
966
|
+
* Calls teardown() for each plugin and removes all event subscriptions.
|
|
967
|
+
* Safe to call multiple times (subsequent calls are no-op with error logging).
|
|
968
|
+
*
|
|
969
|
+
* @throws {TypeError} If any plugin parameter is not a function
|
|
970
|
+
* @throws {TypeError} If any factory returns a non-object value
|
|
971
|
+
* @throws {TypeError} If returned plugin object contains unknown properties
|
|
972
|
+
* @throws {Error} If any plugin factory is already registered (duplicate by reference)
|
|
973
|
+
* @throws {Error} If total plugin count would exceed 50 after registration
|
|
974
|
+
* @throws {*} Rethrows any exception thrown by factory functions (after rollback)
|
|
975
|
+
*
|
|
976
|
+
* @example
|
|
977
|
+
* // Basic logging plugin
|
|
978
|
+
* const loggingPlugin = (router) => ({
|
|
979
|
+
* onTransitionStart: (toState, fromState) => {
|
|
980
|
+
* console.log(`Navigating: ${fromState?.name} → ${toState.name}`);
|
|
981
|
+
* },
|
|
982
|
+
* onTransitionSuccess: (toState) => {
|
|
983
|
+
* console.log(`Arrived at: ${toState.name}`);
|
|
984
|
+
* },
|
|
985
|
+
* });
|
|
986
|
+
*
|
|
987
|
+
* @example
|
|
988
|
+
* // Remove plugin
|
|
989
|
+
* const remove = router.usePlugin(loggerPlugin)
|
|
990
|
+
* remove() // Stop logging
|
|
991
|
+
*
|
|
992
|
+
* const unsubscribe = router.usePlugin(loggingPlugin);
|
|
993
|
+
*
|
|
994
|
+
* @see {@link getPlugins} for retrieving registered plugin factories (internal use)
|
|
995
|
+
* @see {@link useMiddleware} for navigation-specific middleware (different from plugins)
|
|
996
|
+
* @see {@link addEventListener} for low-level event subscription
|
|
997
|
+
*/
|
|
998
|
+
usePlugin: (...plugins: PluginFactory<Dependencies>[]) => Unsubscribe;
|
|
999
|
+
getPlugins: () => PluginFactory<Dependencies>[];
|
|
1000
|
+
/**
|
|
1001
|
+
* Registers middleware functions to execute during navigation transitions.
|
|
1002
|
+
*
|
|
1003
|
+
* @description
|
|
1004
|
+
* Provides the primary mechanism for adding custom logic to the navigation pipeline
|
|
1005
|
+
* through middleware functions. Middleware execute after lifecycle hooks (canActivate/
|
|
1006
|
+
* canDeactivate) and can modify or validate state during route transitions.
|
|
1007
|
+
*
|
|
1008
|
+
* @param middlewares - Variable number of middleware factory functions.
|
|
1009
|
+
* Each factory receives (router, getDependency) and must return
|
|
1010
|
+
* a middleware function with signature:
|
|
1011
|
+
* (toState, fromState, done) => void | Promise<State | boolean | void>
|
|
1012
|
+
*
|
|
1013
|
+
* @returns Unsubscribe function that removes only the middleware registered in this call.
|
|
1014
|
+
* Safe to call multiple times (subsequent calls are no-op with warnings).
|
|
1015
|
+
*
|
|
1016
|
+
* @throws {TypeError} If any middleware parameter is not a function
|
|
1017
|
+
* @throws {TypeError} If any factory returns a non-function value
|
|
1018
|
+
* @throws {Error} If any middleware factory is already registered (duplicate)
|
|
1019
|
+
* @throws {Error} If total middleware count would exceed 50 after registration
|
|
1020
|
+
* @throws {*} Rethrows any exception thrown by factory functions during initialization
|
|
1021
|
+
*
|
|
1022
|
+
* @example
|
|
1023
|
+
*
|
|
1024
|
+
* router.useMiddleware((router) => (toState, fromState, done) => {
|
|
1025
|
+
* console.log('Navigating to:', toState.name)
|
|
1026
|
+
* done()
|
|
1027
|
+
* })
|
|
1028
|
+
*
|
|
1029
|
+
* @example
|
|
1030
|
+
* // Auth middleware
|
|
1031
|
+
* router.useMiddleware(() => (toState, fromState, done) => {
|
|
1032
|
+
* if (toState.meta.requiresAuth && !isAuthenticated()) {
|
|
1033
|
+
* done({ redirect: { name: 'login' } })
|
|
1034
|
+
* } else {
|
|
1035
|
+
* done()
|
|
1036
|
+
* }
|
|
1037
|
+
* })
|
|
1038
|
+
*/
|
|
1039
|
+
useMiddleware: (...middlewares: MiddlewareFactory<Dependencies>[]) => Unsubscribe;
|
|
1040
|
+
clearMiddleware: () => Router<Dependencies>;
|
|
1041
|
+
getMiddlewareFactories: () => MiddlewareFactory<Dependencies>[];
|
|
1042
|
+
getMiddlewareFunctions: () => Middleware[];
|
|
1043
|
+
setDependency: <K extends keyof Dependencies & string>(dependencyName: K, dependency: Dependencies[K]) => Router<Dependencies>;
|
|
1044
|
+
/**
|
|
1045
|
+
* Sets multiple dependencies at once using a batch operation.
|
|
1046
|
+
*
|
|
1047
|
+
* @description
|
|
1048
|
+
* Provides an optimized way to register multiple dependencies in a single operation.
|
|
1049
|
+
* This method is the primary approach for initializing dependencies during router
|
|
1050
|
+
* setup and for bulk updates of the dependency container.
|
|
1051
|
+
*
|
|
1052
|
+
* @param deps - Object containing dependencies to set. Must be a plain object.
|
|
1053
|
+
* Properties with undefined values are ignored (not set).
|
|
1054
|
+
* All other values (including null, false, 0) are set.
|
|
1055
|
+
*
|
|
1056
|
+
* @returns The router instance for method chaining.
|
|
1057
|
+
*
|
|
1058
|
+
* @throws {TypeError} If deps is not a plain object (e.g., class instance, array, null)
|
|
1059
|
+
* @throws {TypeError} If any property in deps has a getter (accessor property)
|
|
1060
|
+
* @throws {Error} If total dependencies would exceed 100 after the operation
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* // Basic batch setup
|
|
1064
|
+
* router.setDependencies({
|
|
1065
|
+
* api: new ApiService(),
|
|
1066
|
+
* logger: console,
|
|
1067
|
+
* cache: cacheService,
|
|
1068
|
+
* });
|
|
1069
|
+
*
|
|
1070
|
+
* @see {@link setDependency} for setting individual dependencies
|
|
1071
|
+
* @see {@link getDependencies} for retrieving all dependencies
|
|
1072
|
+
* @see {@link resetDependencies} for clearing all dependencies
|
|
1073
|
+
* @see {@link removeDependency} for removing specific dependencies
|
|
1074
|
+
*/
|
|
1075
|
+
setDependencies: (deps: Dependencies) => Router<Dependencies>;
|
|
1076
|
+
/**
|
|
1077
|
+
* Retrieves a dependency from the router's dependency container by name.
|
|
1078
|
+
*
|
|
1079
|
+
* @description
|
|
1080
|
+
* Provides type-safe access to dependencies registered in the router's dependency
|
|
1081
|
+
* injection container. This method is the primary way to access services and utilities
|
|
1082
|
+
* within middleware, plugins, and lifecycle hooks.
|
|
1083
|
+
*
|
|
1084
|
+
* @template K - The dependency name, must be a key of the Dependencies type
|
|
1085
|
+
*
|
|
1086
|
+
* @param key - The name of the dependency to retrieve. Must be a string and
|
|
1087
|
+
* must exist in the Dependencies type definition.
|
|
1088
|
+
*
|
|
1089
|
+
* @returns The dependency value with proper type inference based on Dependencies type.
|
|
1090
|
+
* Returns the same reference on repeated calls (not a copy).
|
|
1091
|
+
*
|
|
1092
|
+
* @throws {TypeError} If the key parameter is not a string type
|
|
1093
|
+
* (e.g., number, object, null, undefined)
|
|
1094
|
+
* @throws {ReferenceError} If no dependency exists with the given name.
|
|
1095
|
+
* Error message includes the dependency name for debugging.
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* // Basic usage - direct access
|
|
1099
|
+
* interface MyDependencies {
|
|
1100
|
+
* api: ApiService;
|
|
1101
|
+
* logger: Logger;
|
|
1102
|
+
* }
|
|
1103
|
+
*
|
|
1104
|
+
* router.setDependency('api', new ApiService());
|
|
1105
|
+
* const api = router.getDependency('api'); // Type: ApiService
|
|
1106
|
+
*
|
|
1107
|
+
* @see {@link getDependencies} for retrieving all dependencies at once
|
|
1108
|
+
* @see {@link setDependency} for registering dependencies
|
|
1109
|
+
* @see {@link hasDependency} for checking dependency existence
|
|
1110
|
+
* @see {@link removeDependency} for removing dependencies
|
|
1111
|
+
*/
|
|
1112
|
+
getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K];
|
|
1113
|
+
/**
|
|
1114
|
+
* Returns a shallow copy of all registered dependencies.
|
|
1115
|
+
*
|
|
1116
|
+
* @description
|
|
1117
|
+
* Retrieves a snapshot of all dependencies currently stored in the router's
|
|
1118
|
+
* dependency container. The method creates a new object on each call, protecting
|
|
1119
|
+
* the internal container structure from external modifications.
|
|
1120
|
+
*
|
|
1121
|
+
* @returns A new object containing all dependencies as key-value pairs.
|
|
1122
|
+
* Returns {} if no dependencies are registered.
|
|
1123
|
+
*
|
|
1124
|
+
* @example
|
|
1125
|
+
* // Basic usage - get all dependencies
|
|
1126
|
+
* const deps = router.getDependencies();
|
|
1127
|
+
* console.log(deps); // { api: ApiService, logger: Logger }
|
|
1128
|
+
*
|
|
1129
|
+
* @see {@link getDependency} for accessing individual dependencies
|
|
1130
|
+
* @see {@link setDependency} for adding dependencies
|
|
1131
|
+
* @see {@link setDependencies} for batch setting
|
|
1132
|
+
* @see {@link removeDependency} for removing dependencies
|
|
1133
|
+
* @see {@link resetDependencies} for clearing all dependencies
|
|
1134
|
+
* @see {@link hasDependency} for checking dependency existence
|
|
1135
|
+
*/
|
|
1136
|
+
getDependencies: () => Partial<Dependencies>;
|
|
1137
|
+
/**
|
|
1138
|
+
* Removes a dependency from the router's dependency container.
|
|
1139
|
+
*
|
|
1140
|
+
* @description
|
|
1141
|
+
* Safely removes a registered dependency by name. This method is idempotent,
|
|
1142
|
+
* meaning it can be called multiple times with the same dependency name without
|
|
1143
|
+
* causing errors. If the dependency doesn't exist, a warning is logged but
|
|
1144
|
+
* execution continues normally.
|
|
1145
|
+
*
|
|
1146
|
+
* @param dependencyName - The name of the dependency to remove.
|
|
1147
|
+
* Type-safe in TypeScript (must be a key of Dependencies).
|
|
1148
|
+
* Safe to call with non-existent dependencies (logs warning).
|
|
1149
|
+
*
|
|
1150
|
+
* @returns The router instance for method chaining.
|
|
1151
|
+
*
|
|
1152
|
+
* @example
|
|
1153
|
+
* // Basic removal
|
|
1154
|
+
* router.setDependency('tempLogger', logger);
|
|
1155
|
+
* router.removeDependency('tempLogger');
|
|
1156
|
+
*
|
|
1157
|
+
* console.log(router.hasDependency('tempLogger')); // false
|
|
1158
|
+
*
|
|
1159
|
+
* @see {@link setDependency} for adding dependencies
|
|
1160
|
+
* @see {@link getDependency} for retrieving dependencies (throws after removal)
|
|
1161
|
+
* @see {@link hasDependency} for checking dependency existence (returns false after removal)
|
|
1162
|
+
* @see {@link resetDependencies} for removing all dependencies at once
|
|
1163
|
+
*/
|
|
1164
|
+
removeDependency: (dependencyName: keyof Dependencies) => Router<Dependencies>;
|
|
1165
|
+
/**
|
|
1166
|
+
* Checks whether a dependency with the specified name exists in the router.
|
|
1167
|
+
*
|
|
1168
|
+
* @description
|
|
1169
|
+
* Provides a safe way to check for dependency existence without throwing errors.
|
|
1170
|
+
* This method is essential for implementing conditional logic based on optional
|
|
1171
|
+
* dependencies and for validating dependency setup before accessing them.
|
|
1172
|
+
*
|
|
1173
|
+
* @param dependencyName - The name of the dependency to check.
|
|
1174
|
+
* Type-safe in TypeScript (must be a key of Dependencies).
|
|
1175
|
+
* In runtime, non-string primitives are coerced to strings.
|
|
1176
|
+
*
|
|
1177
|
+
* @returns true if the dependency exists (even with falsy values like null/false/0),
|
|
1178
|
+
* false if the dependency has never been set or was removed.
|
|
1179
|
+
*
|
|
1180
|
+
* @example
|
|
1181
|
+
* // Basic existence check
|
|
1182
|
+
* router.setDependency('api', apiService);
|
|
1183
|
+
* console.log(router.hasDependency('api')); // true
|
|
1184
|
+
* console.log(router.hasDependency('nonexistent')); // false
|
|
1185
|
+
*
|
|
1186
|
+
* const ready = hasAllDependencies(router, ['api', 'auth', 'logger']);
|
|
1187
|
+
*
|
|
1188
|
+
* @see {@link getDependency} for retrieving dependencies (throws if not found)
|
|
1189
|
+
* @see {@link getDependencies} for getting all dependencies at once
|
|
1190
|
+
* @see {@link setDependency} for registering dependencies
|
|
1191
|
+
* @see {@link removeDependency} for removing dependencies
|
|
1192
|
+
*/
|
|
1193
|
+
hasDependency: (dependencyName: keyof Dependencies) => boolean;
|
|
1194
|
+
/**
|
|
1195
|
+
* Removes all dependencies from the router's dependency container.
|
|
1196
|
+
*
|
|
1197
|
+
* @description
|
|
1198
|
+
* Performs a complete reset of the dependency container by removing all registered
|
|
1199
|
+
* dependencies at once. This is a destructive operation that clears the entire
|
|
1200
|
+
* dependency state, effectively returning the container to its initial empty state.
|
|
1201
|
+
*
|
|
1202
|
+
* @returns The router instance for method chaining.
|
|
1203
|
+
*
|
|
1204
|
+
* @example
|
|
1205
|
+
* // Basic reset
|
|
1206
|
+
* router.setDependency('logger', logger);
|
|
1207
|
+
* router.setDependency('api', apiService);
|
|
1208
|
+
* router.setDependency('cache', cacheService);
|
|
1209
|
+
*
|
|
1210
|
+
* router.resetDependencies();
|
|
1211
|
+
*
|
|
1212
|
+
* console.log(router.getDependencies()); // {}
|
|
1213
|
+
* console.log(router.hasDependency('logger')); // false
|
|
1214
|
+
*
|
|
1215
|
+
* @see {@link setDependency} for adding individual dependencies
|
|
1216
|
+
* @see {@link setDependencies} for setting multiple dependencies at once
|
|
1217
|
+
* @see {@link removeDependency} for removing individual dependencies
|
|
1218
|
+
* @see {@link getDependencies} for getting all current dependencies
|
|
1219
|
+
* @see {@link hasDependency} for checking if specific dependency exists
|
|
1220
|
+
*/
|
|
1221
|
+
resetDependencies: () => Router<Dependencies>;
|
|
1222
|
+
/**
|
|
1223
|
+
* Invokes all registered event listeners for a specific router lifecycle event.
|
|
1224
|
+
*
|
|
1225
|
+
* @internal
|
|
1226
|
+
* This is an internal method used by the router core. It should NOT be called
|
|
1227
|
+
* directly by application code. Events are automatically dispatched by router
|
|
1228
|
+
* methods like start(), stop(), navigate(), etc.
|
|
1229
|
+
*
|
|
1230
|
+
* @description
|
|
1231
|
+
* Synchronously invokes all registered event listeners for a given router lifecycle
|
|
1232
|
+
* event in their registration order (FIFO). The method provides critical guarantees:
|
|
1233
|
+
* fail-safe execution, state immutability, recursion protection, and iteration safety.
|
|
1234
|
+
*
|
|
1235
|
+
* @param eventName - The event type to invoke listeners for.
|
|
1236
|
+
* Must be one of: ROUTER_START, ROUTER_STOP, TRANSITION_START,
|
|
1237
|
+
* TRANSITION_SUCCESS, TRANSITION_ERROR, TRANSITION_CANCEL.
|
|
1238
|
+
*
|
|
1239
|
+
* @param toState - Target state for navigation events. Deep frozen before passing.
|
|
1240
|
+
* Optional for ROUTER_START/STOP, required for TRANSITION_*.
|
|
1241
|
+
*
|
|
1242
|
+
* @param fromState - Source state for navigation events. Deep frozen before passing.
|
|
1243
|
+
* Optional for all events (undefined for first navigation).
|
|
1244
|
+
*
|
|
1245
|
+
* @param arg - Additional event data:
|
|
1246
|
+
* - NavigationOptions for TRANSITION_SUCCESS
|
|
1247
|
+
* - RouterError for TRANSITION_ERROR
|
|
1248
|
+
* - undefined for other events
|
|
1249
|
+
*
|
|
1250
|
+
* @returns void - Method performs side effects (invokes listeners)
|
|
1251
|
+
*
|
|
1252
|
+
* @throws {Error} If recursion depth exceeds MAX_DEPTH (5) for the event type
|
|
1253
|
+
* @throws {TypeError} If state validation fails (invalid State object structure)
|
|
1254
|
+
*
|
|
1255
|
+
* @see {@link addEventListener} for subscribing to router events (public API)
|
|
1256
|
+
* @see {@link removeEventListener} for unsubscribing from events (public API)
|
|
1257
|
+
* @see {@link usePlugin} for plugin-based event handling (recommended)
|
|
1258
|
+
*/
|
|
1259
|
+
invokeEventListeners: (eventName: EventToNameMap[EventsKeys], toState?: State, fromState?: State, arg?: RouterError | NavigationOptions) => void;
|
|
1260
|
+
/**
|
|
1261
|
+
* Checks if there are any listeners registered for a given event.
|
|
1262
|
+
*
|
|
1263
|
+
* @internal
|
|
1264
|
+
* Used for performance optimization to skip event emission when no listeners exist.
|
|
1265
|
+
* This avoids the overhead of argument validation and event dispatch when
|
|
1266
|
+
* there are no subscribers.
|
|
1267
|
+
*
|
|
1268
|
+
* @param eventName - The event type to check for listeners. Must be one of the
|
|
1269
|
+
* predefined event constants.
|
|
1270
|
+
*
|
|
1271
|
+
* @returns true if at least one listener is registered for the event, false otherwise.
|
|
1272
|
+
* Returns false for invalid event names instead of throwing.
|
|
1273
|
+
*
|
|
1274
|
+
* @example
|
|
1275
|
+
* ```typescript
|
|
1276
|
+
* // Skip expensive event emission if no listeners
|
|
1277
|
+
* if (router.hasListeners(events.TRANSITION_ERROR)) {
|
|
1278
|
+
* router.invokeEventListeners(events.TRANSITION_ERROR, toState, fromState, error);
|
|
1279
|
+
* }
|
|
1280
|
+
* ```
|
|
1281
|
+
*
|
|
1282
|
+
* @see {@link invokeEventListeners} for the internal event dispatch mechanism
|
|
1283
|
+
* @see {@link addEventListener} for registering event listeners
|
|
1284
|
+
*/
|
|
1285
|
+
hasListeners: (eventName: EventToNameMap[EventsKeys]) => boolean;
|
|
1286
|
+
/**
|
|
1287
|
+
* Removes a previously registered event listener from the router's event system.
|
|
1288
|
+
*
|
|
1289
|
+
* @internal
|
|
1290
|
+
* This is a low-level internal API used primarily by the router core and plugin system.
|
|
1291
|
+
* For application code, use the unsubscribe function returned by addEventListener instead.
|
|
1292
|
+
*
|
|
1293
|
+
* @description
|
|
1294
|
+
* Removes a specific event listener callback from the router's event system, preventing it
|
|
1295
|
+
* from being invoked on future events. This method is a fundamental part of the subscription
|
|
1296
|
+
* lifecycle, ensuring proper cleanup and preventing memory leaks.
|
|
1297
|
+
*
|
|
1298
|
+
* @param eventName - The event type to remove the listener from. Must be one of the
|
|
1299
|
+
* predefined event constants (events.ROUTER_START, events.TRANSITION_SUCCESS, etc.).
|
|
1300
|
+
* TypeScript enforces valid event names at compile time.
|
|
1301
|
+
*
|
|
1302
|
+
* @param cb - The callback function to remove. Must be the **exact same reference** that was
|
|
1303
|
+
* passed to addEventListener. Using a different function (even with identical code)
|
|
1304
|
+
* will not match and will log a warning.
|
|
1305
|
+
*
|
|
1306
|
+
* @returns void - No return value (follows DOM API convention). Use the unsubscribe function
|
|
1307
|
+
* from addEventListener if you need guaranteed cleanup confirmation.
|
|
1308
|
+
*
|
|
1309
|
+
* @throws {Error} If eventName is not a valid event constant
|
|
1310
|
+
* @throws {TypeError} If cb is not a function (null, undefined, string, etc.)
|
|
1311
|
+
*
|
|
1312
|
+
* @see {@link addEventListener} for registering event listeners (returns unsubscribe function)
|
|
1313
|
+
* @see {@link usePlugin} for plugin-based event handling (handles cleanup automatically)
|
|
1314
|
+
* @see {@link invokeEventListeners} for the internal event dispatch mechanism
|
|
1315
|
+
*/
|
|
1316
|
+
removeEventListener: (eventName: EventToNameMap[EventsKeys], cb: Plugin$1[keyof Plugin$1]) => void;
|
|
1317
|
+
/**
|
|
1318
|
+
* Registers an event listener for a specific router lifecycle event.
|
|
1319
|
+
*
|
|
1320
|
+
* @description
|
|
1321
|
+
* Provides type-safe subscription to router events with automatic memory leak protection
|
|
1322
|
+
* and state immutability guarantees. This is the low-level API for event handling - for
|
|
1323
|
+
* most use cases, consider using plugins (usePlugin) or the subscribe method instead.
|
|
1324
|
+
*
|
|
1325
|
+
* @param eventName - The event type to listen for. Must be one of the predefined
|
|
1326
|
+
* event constants (events.ROUTER_START, events.TRANSITION_SUCCESS, etc.).
|
|
1327
|
+
* TypeScript enforces valid event names at compile time.
|
|
1328
|
+
*
|
|
1329
|
+
* @param cb - The callback function to invoke when the event occurs. Signature must
|
|
1330
|
+
* match the event type. TypeScript enforces correct callback signature.
|
|
1331
|
+
* All State parameters will be deeply frozen before passing.
|
|
1332
|
+
*
|
|
1333
|
+
* @returns Unsubscribe function that removes the listener. Safe to call multiple times
|
|
1334
|
+
* (subsequent calls log warning but don't throw). Closure captures event and
|
|
1335
|
+
* callback for automatic cleanup.
|
|
1336
|
+
*
|
|
1337
|
+
* @throws {Error} If the same callback is already registered for this event
|
|
1338
|
+
* @throws {Error} If listener count reaches 10000 (hard limit, indicates memory leak)
|
|
1339
|
+
* @throws {Error} If eventName is not a valid event constant
|
|
1340
|
+
* @throws {TypeError} If callback is not a function
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* const unsub = router.addEventListener('TRANSITION_START', (toState, fromState) => {
|
|
1344
|
+
* console.log('Starting navigation:', toState.name)
|
|
1345
|
+
* })
|
|
1346
|
+
*
|
|
1347
|
+
* @example
|
|
1348
|
+
* router.addEventListener('TRANSITION_ERROR', (toState, fromState, err) => {
|
|
1349
|
+
* console.error('Navigation failed:', err)
|
|
1350
|
+
* })
|
|
1351
|
+
*
|
|
1352
|
+
* @see {@link usePlugin} for plugin-based event handling (recommended)
|
|
1353
|
+
* @see {@link subscribe} for simplified navigation event subscription
|
|
1354
|
+
* @see {@link removeEventListener} for manual listener removal (use unsubscribe instead)
|
|
1355
|
+
*/
|
|
1356
|
+
addEventListener: (eventName: EventToNameMap[EventsKeys], cb: Plugin$1[keyof Plugin$1]) => Unsubscribe;
|
|
1357
|
+
forward: (fromRoute: string, toRoute: string) => Router<Dependencies>;
|
|
1358
|
+
/**
|
|
1359
|
+
* Navigates to the specified route.
|
|
1360
|
+
*
|
|
1361
|
+
* @description
|
|
1362
|
+
* Performs a navigation transition from the current route to the target route.
|
|
1363
|
+
* The method handles route activation/deactivation lifecycle, middleware execution,
|
|
1364
|
+
* and state management. Navigation can be customized with options and supports
|
|
1365
|
+
* both synchronous and asynchronous operations.
|
|
1366
|
+
*
|
|
1367
|
+
* @param routeName - The name of the route to navigate to. Must be a registered route.
|
|
1368
|
+
* @param routeParams - Optional parameters to pass to the route. These will be used
|
|
1369
|
+
* to build the route path and will be available in the route state.
|
|
1370
|
+
* @param options - Optional navigation options to control the transition behavior
|
|
1371
|
+
* @param done - Optional callback function called when navigation completes or fails.
|
|
1372
|
+
* Receives error as first argument and state as second.
|
|
1373
|
+
*
|
|
1374
|
+
* @returns A cancel function that can be called to abort the navigation.
|
|
1375
|
+
* Calling cancel will trigger the TRANSITION_CANCELLED event.
|
|
1376
|
+
*
|
|
1377
|
+
* @example
|
|
1378
|
+
* // Simple navigation
|
|
1379
|
+
* router.navigate('home');
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* // Navigation with parameters
|
|
1383
|
+
* router.navigate('user', { id: '123' });
|
|
1384
|
+
*
|
|
1385
|
+
* @example
|
|
1386
|
+
* // Cancellable navigation
|
|
1387
|
+
* const cancel = router.navigate('slow-route', {}, {}, (err) => {
|
|
1388
|
+
* if (err?.code === 'CANCELLED') console.log('Navigation was cancelled');
|
|
1389
|
+
* });
|
|
1390
|
+
* // Later...
|
|
1391
|
+
* cancel(); // Abort the navigation
|
|
1392
|
+
*
|
|
1393
|
+
* @throws {RouterError} With code 'NOT_STARTED' if router is not started
|
|
1394
|
+
* @throws {RouterError} With code 'ROUTE_NOT_FOUND' if route doesn't exist
|
|
1395
|
+
* @throws {RouterError} With code 'SAME_STATES' if navigating to current route without reload
|
|
1396
|
+
* @throws {RouterError} With code 'CANNOT_DEACTIVATE' if canDeactivate guard prevents navigation
|
|
1397
|
+
* @throws {RouterError} With code 'CANNOT_ACTIVATE' if canActivate guard prevents navigation
|
|
1398
|
+
* @throws {RouterError} With code 'TRANSITION_ERR' if middleware throws an error
|
|
1399
|
+
*/
|
|
1400
|
+
navigate: ((routeName: string) => CancelFn) & ((routeName: string, routeParams: Params) => CancelFn) & ((routeName: string, done: DoneFn) => CancelFn) & ((routeName: string, routeParams: Params, options: NavigationOptions) => CancelFn) & ((routeName: string, routeParams: Params, done: DoneFn) => CancelFn) & ((routeName: string, routeParams: Params, options: NavigationOptions, done: DoneFn) => CancelFn);
|
|
1401
|
+
/**
|
|
1402
|
+
* Navigates to the default route if one is configured.
|
|
1403
|
+
*
|
|
1404
|
+
* Uses `defaultRoute` and `defaultParams` from router options.
|
|
1405
|
+
* Returns no-op if no default route configured.
|
|
1406
|
+
*
|
|
1407
|
+
* @description
|
|
1408
|
+
* Convenience method that navigates to the route specified in router options
|
|
1409
|
+
* as `defaultRoute` with `defaultParams`. If no default route is configured,
|
|
1410
|
+
* this method does nothing and returns a no-op cancel function.
|
|
1411
|
+
*
|
|
1412
|
+
* @param opts - Optional navigation options (same as navigate method)
|
|
1413
|
+
* @param done - Optional callback function called when navigation completes
|
|
1414
|
+
*
|
|
1415
|
+
* @returns A cancel function that can be called to abort the navigation.
|
|
1416
|
+
* Returns no-op function if no default route is configured.
|
|
1417
|
+
*
|
|
1418
|
+
* @see {@link navigate} for detailed behavior and error handling
|
|
1419
|
+
*/
|
|
1420
|
+
navigateToDefault: (() => CancelFn) & ((done: DoneFn) => CancelFn) & ((opts: NavigationOptions) => CancelFn) & ((opts: NavigationOptions, done: DoneFn) => CancelFn);
|
|
1421
|
+
/**
|
|
1422
|
+
* Internal navigation method that accepts pre-built state.
|
|
1423
|
+
*
|
|
1424
|
+
* @internal
|
|
1425
|
+
* @description
|
|
1426
|
+
* This is an internal method used by the router and plugins to perform navigation
|
|
1427
|
+
* with a pre-built state object. It should not be used directly by application code.
|
|
1428
|
+
* Use `navigate()` instead for normal navigation operations.
|
|
1429
|
+
*
|
|
1430
|
+
* The method provides control over TRANSITION_SUCCESS event emission through the
|
|
1431
|
+
* `emitSuccess` parameter, allowing internal callers to manage event emission
|
|
1432
|
+
* themselves to avoid duplicate events.
|
|
1433
|
+
*
|
|
1434
|
+
* @param toState - The target state to navigate to (pre-built)
|
|
1435
|
+
* @param fromState - The current state to navigate from
|
|
1436
|
+
* @param opts - Navigation options
|
|
1437
|
+
* @param callback - Callback function called when navigation completes
|
|
1438
|
+
* @param emitSuccess - Whether to emit TRANSITION_SUCCESS event (false for internal use)
|
|
1439
|
+
*
|
|
1440
|
+
* @returns A cancel function that can be called to abort the navigation
|
|
1441
|
+
*
|
|
1442
|
+
* @private
|
|
1443
|
+
*/
|
|
1444
|
+
navigateToState: (toState: State, fromState: State | undefined, opts: NavigationOptions, callback: DoneFn, emitSuccess: boolean) => CancelFn;
|
|
1445
|
+
/**
|
|
1446
|
+
* Subscribes to successful navigation transitions.
|
|
1447
|
+
*
|
|
1448
|
+
* @description
|
|
1449
|
+
* Registers a listener function that will be called whenever a navigation transition
|
|
1450
|
+
* completes successfully. This is the primary method for integrating UI frameworks
|
|
1451
|
+
* with the router to react to route changes.
|
|
1452
|
+
*
|
|
1453
|
+
* @param listener - Function called on each successful navigation transition.
|
|
1454
|
+
* Receives { route, previousRoute } where:
|
|
1455
|
+
* - route: The new state (frozen/immutable)
|
|
1456
|
+
* - previousRoute: The previous state (frozen/immutable, undefined on first navigation)
|
|
1457
|
+
*
|
|
1458
|
+
* @returns Unsubscribe function to remove the listener. Safe to call multiple times.
|
|
1459
|
+
*
|
|
1460
|
+
* @example
|
|
1461
|
+
* // Basic subscription
|
|
1462
|
+
* const unsubscribe = router.subscribe(({ route, previousRoute }) => {
|
|
1463
|
+
* console.log(`Navigation: ${previousRoute?.name || 'init'} → ${route.name}`);
|
|
1464
|
+
* });
|
|
1465
|
+
*
|
|
1466
|
+
* // Later, cleanup
|
|
1467
|
+
* unsubscribe();
|
|
1468
|
+
*
|
|
1469
|
+
* @example
|
|
1470
|
+
*
|
|
1471
|
+
* // Analytics
|
|
1472
|
+
* router.subscribe(({ route }) => {
|
|
1473
|
+
* analytics.track('page_view', { path: route.path })
|
|
1474
|
+
* })
|
|
1475
|
+
*
|
|
1476
|
+
* @throws {TypeError} If listener is not a function. Error message includes
|
|
1477
|
+
* hint about using Symbol.observable for Observable pattern.
|
|
1478
|
+
*
|
|
1479
|
+
* @see {@link addEventListener} for low-level event subscription
|
|
1480
|
+
* @see {@link usePlugin} for subscribing to all router events
|
|
1481
|
+
* @see {@link navigate} for triggering navigation
|
|
1482
|
+
*/
|
|
1483
|
+
subscribe: (listener: SubscribeFn) => Unsubscribe;
|
|
1484
|
+
/**
|
|
1485
|
+
* Creates a clone of this router with the same configuration.
|
|
1486
|
+
*
|
|
1487
|
+
* @description
|
|
1488
|
+
* Creates a new router instance with the same routes, options, middleware,
|
|
1489
|
+
* plugins, and lifecycle handlers as the original. The cloned router is
|
|
1490
|
+
* independent of the original - changes to one do not affect the other.
|
|
1491
|
+
*
|
|
1492
|
+
* Use cases:
|
|
1493
|
+
* - Server-side rendering (SSR): Create a fresh router for each request
|
|
1494
|
+
* - Testing: Clone router to test different scenarios without side effects
|
|
1495
|
+
* - Feature flags: Create alternative router configurations
|
|
1496
|
+
*
|
|
1497
|
+
* What is cloned:
|
|
1498
|
+
* - Route tree structure (via rootNode)
|
|
1499
|
+
* - Router options (defaultRoute, trailingSlash, etc.)
|
|
1500
|
+
* - Middleware factories
|
|
1501
|
+
* - Plugin factories
|
|
1502
|
+
* - Lifecycle factories (canActivate, canDeactivate)
|
|
1503
|
+
* - Config (encoders, decoders, defaultParams, forwardMap)
|
|
1504
|
+
*
|
|
1505
|
+
* What is NOT cloned:
|
|
1506
|
+
* - Current state (cloned router starts fresh)
|
|
1507
|
+
* - Event listeners (subscribers must re-register)
|
|
1508
|
+
* - Started status (cloned router is not started)
|
|
1509
|
+
*
|
|
1510
|
+
* @param dependencies - Optional new dependencies for the cloned router.
|
|
1511
|
+
* If not provided, uses empty dependencies.
|
|
1512
|
+
*
|
|
1513
|
+
* @returns A new router instance with the same configuration.
|
|
1514
|
+
*
|
|
1515
|
+
* @example
|
|
1516
|
+
* // Basic cloning
|
|
1517
|
+
* const router = createRouter(routes, options);
|
|
1518
|
+
* const clonedRouter = router.clone();
|
|
1519
|
+
*
|
|
1520
|
+
* @example
|
|
1521
|
+
* // SSR: Clone with request-specific dependencies
|
|
1522
|
+
* app.get('*', (req, res) => {
|
|
1523
|
+
* const ssrRouter = router.clone({ request: req });
|
|
1524
|
+
* ssrRouter.start(req.url, (err, state) => {
|
|
1525
|
+
* // Render with state...
|
|
1526
|
+
* });
|
|
1527
|
+
* });
|
|
1528
|
+
*
|
|
1529
|
+
* @example
|
|
1530
|
+
* // Testing: Clone for isolated test
|
|
1531
|
+
* it('should navigate to user', () => {
|
|
1532
|
+
* const testRouter = router.clone();
|
|
1533
|
+
* testRouter.start();
|
|
1534
|
+
* testRouter.navigate('user', { id: '123' });
|
|
1535
|
+
* expect(testRouter.getState().name).toBe('user');
|
|
1536
|
+
* });
|
|
1537
|
+
*/
|
|
1538
|
+
clone: (dependencies?: Dependencies) => Router<Dependencies>;
|
|
1539
|
+
}
|
|
1540
|
+
interface Plugin$1 {
|
|
1541
|
+
onStart?: () => void;
|
|
1542
|
+
onStop?: () => void;
|
|
1543
|
+
onTransitionStart?: (toState: State, fromState?: State) => void;
|
|
1544
|
+
onTransitionCancel?: (toState: State, fromState?: State) => void;
|
|
1545
|
+
onTransitionError?: (toState: State | undefined, fromState: State | undefined, err: RouterError) => void;
|
|
1546
|
+
onTransitionSuccess?: (toState: State, fromState: State | undefined, opts: NavigationOptions) => void;
|
|
1547
|
+
teardown?: () => void;
|
|
1548
|
+
}
|
|
1549
|
+
export type Middleware = ActivationFn;
|
|
1550
|
+
export type MiddlewareFactory<Dependencies extends DefaultDependencies = DefaultDependencies> = (router: Router<Dependencies>, getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K]) => Middleware;
|
|
1551
|
+
export type PluginFactory<Dependencies extends DefaultDependencies = DefaultDependencies> = (router: Router<Dependencies>, getDependency: <K extends keyof Dependencies>(key: K) => Dependencies[K]) => Plugin$1;
|
|
1552
|
+
export interface SubscribeState {
|
|
1553
|
+
route: State;
|
|
1554
|
+
previousRoute?: State | undefined;
|
|
1555
|
+
}
|
|
1556
|
+
export type SubscribeFn = (state: SubscribeState) => void;
|
|
1557
|
+
declare class RouterError$1 extends Error {
|
|
1558
|
+
[key: string]: unknown;
|
|
1559
|
+
readonly segment: string | undefined;
|
|
1560
|
+
readonly path: string | undefined;
|
|
1561
|
+
readonly redirect: State | undefined;
|
|
1562
|
+
code: string;
|
|
1563
|
+
/**
|
|
1564
|
+
* Creates a new RouterError instance.
|
|
1565
|
+
*
|
|
1566
|
+
* The options object accepts built-in fields (message, segment, path, redirect)
|
|
1567
|
+
* and any additional custom fields, which will all be attached to the error instance.
|
|
1568
|
+
*
|
|
1569
|
+
* @param code - The error code (e.g., "ROUTE_NOT_FOUND", "CANNOT_ACTIVATE")
|
|
1570
|
+
* @param options - Optional configuration object
|
|
1571
|
+
* @param options.message - Custom error message (defaults to code if not provided)
|
|
1572
|
+
* @param options.segment - The route segment where the error occurred
|
|
1573
|
+
* @param options.path - The full path where the error occurred
|
|
1574
|
+
* @param options.redirect - Optional redirect state for navigation errors
|
|
1575
|
+
*
|
|
1576
|
+
* @example
|
|
1577
|
+
* ```typescript
|
|
1578
|
+
* // Basic error
|
|
1579
|
+
* const err1 = new RouterError("ROUTE_NOT_FOUND");
|
|
1580
|
+
*
|
|
1581
|
+
* // Error with custom message
|
|
1582
|
+
* const err2 = new RouterError("ERR", { message: "Something went wrong" });
|
|
1583
|
+
*
|
|
1584
|
+
* // Error with context and custom fields
|
|
1585
|
+
* const err3 = new RouterError("CANNOT_ACTIVATE", {
|
|
1586
|
+
* message: "Insufficient permissions",
|
|
1587
|
+
* segment: "admin",
|
|
1588
|
+
* path: "/admin/users",
|
|
1589
|
+
* userId: "123" // custom field
|
|
1590
|
+
* });
|
|
1591
|
+
*
|
|
1592
|
+
* // Error with redirect
|
|
1593
|
+
* const err4 = new RouterError("TRANSITION_ERR", {
|
|
1594
|
+
* redirect: { name: "home", path: "/", params: {} }
|
|
1595
|
+
* });
|
|
1596
|
+
* ```
|
|
1597
|
+
*/
|
|
1598
|
+
constructor(code: string, { message, segment, path, redirect, ...rest }?: {
|
|
1599
|
+
[key: string]: unknown;
|
|
1600
|
+
message?: string | undefined;
|
|
1601
|
+
segment?: string | undefined;
|
|
1602
|
+
path?: string | undefined;
|
|
1603
|
+
redirect?: State | undefined;
|
|
1604
|
+
});
|
|
1605
|
+
/**
|
|
1606
|
+
* Updates the error code and conditionally updates the message.
|
|
1607
|
+
*
|
|
1608
|
+
* If the current message is one of the standard error code values
|
|
1609
|
+
* (e.g., "ROUTE_NOT_FOUND", "SAME_STATES"), it will be replaced with the new code.
|
|
1610
|
+
* This allows keeping error messages in sync with codes when using standard error codes.
|
|
1611
|
+
*
|
|
1612
|
+
* If the message is custom (not a standard error code), it will be preserved.
|
|
1613
|
+
*
|
|
1614
|
+
* @param newCode - The new error code to set
|
|
1615
|
+
*
|
|
1616
|
+
* @example
|
|
1617
|
+
* // Message follows code (standard error code as message)
|
|
1618
|
+
* const err = new RouterError("ROUTE_NOT_FOUND", { message: "ROUTE_NOT_FOUND" });
|
|
1619
|
+
* err.setCode("CUSTOM_ERROR"); // message becomes "CUSTOM_ERROR"
|
|
1620
|
+
*
|
|
1621
|
+
* @example
|
|
1622
|
+
* // Custom message is preserved
|
|
1623
|
+
* const err = new RouterError("ERR", { message: "Custom error message" });
|
|
1624
|
+
* err.setCode("NEW_CODE"); // message stays "Custom error message"
|
|
1625
|
+
*/
|
|
1626
|
+
setCode(newCode: string): void;
|
|
1627
|
+
/**
|
|
1628
|
+
* Copies properties from another Error instance to this RouterError.
|
|
1629
|
+
*
|
|
1630
|
+
* This method updates the message, cause, and stack trace from the provided error.
|
|
1631
|
+
* Useful for wrapping native errors while preserving error context.
|
|
1632
|
+
*
|
|
1633
|
+
* @param err - The Error instance to copy properties from
|
|
1634
|
+
* @throws {TypeError} If err is null or undefined
|
|
1635
|
+
*
|
|
1636
|
+
* @example
|
|
1637
|
+
* ```typescript
|
|
1638
|
+
* const routerErr = new RouterError("TRANSITION_ERR");
|
|
1639
|
+
* try {
|
|
1640
|
+
* // some operation that might fail
|
|
1641
|
+
* } catch (nativeErr) {
|
|
1642
|
+
* routerErr.setErrorInstance(nativeErr);
|
|
1643
|
+
* throw routerErr;
|
|
1644
|
+
* }
|
|
1645
|
+
* ```
|
|
1646
|
+
*/
|
|
1647
|
+
setErrorInstance(err: Error): void;
|
|
1648
|
+
/**
|
|
1649
|
+
* Adds custom fields to the error object.
|
|
1650
|
+
*
|
|
1651
|
+
* This method allows attaching arbitrary data to the error for debugging or logging purposes.
|
|
1652
|
+
* All fields become accessible as properties on the error instance and are included in JSON serialization.
|
|
1653
|
+
*
|
|
1654
|
+
* Reserved method names (setCode, setErrorInstance, setAdditionalFields, hasField, getField, toJSON)
|
|
1655
|
+
* are automatically filtered out to prevent accidental overwriting of class methods.
|
|
1656
|
+
*
|
|
1657
|
+
* @param fields - Object containing custom fields to add to the error
|
|
1658
|
+
*
|
|
1659
|
+
* @example
|
|
1660
|
+
* ```typescript
|
|
1661
|
+
* const err = new RouterError("CANNOT_ACTIVATE");
|
|
1662
|
+
* err.setAdditionalFields({
|
|
1663
|
+
* userId: "123",
|
|
1664
|
+
* attemptedRoute: "/admin",
|
|
1665
|
+
* reason: "insufficient permissions"
|
|
1666
|
+
* });
|
|
1667
|
+
*
|
|
1668
|
+
* console.log(err.userId); // "123"
|
|
1669
|
+
* console.log(JSON.stringify(err)); // includes all custom fields
|
|
1670
|
+
* ```
|
|
1671
|
+
*/
|
|
1672
|
+
setAdditionalFields(fields: Record<string, unknown>): void;
|
|
1673
|
+
/**
|
|
1674
|
+
* Checks if a custom field exists on the error object.
|
|
1675
|
+
*
|
|
1676
|
+
* This method checks for both custom fields added via setAdditionalFields()
|
|
1677
|
+
* and built-in fields (code, message, segment, etc.).
|
|
1678
|
+
*
|
|
1679
|
+
* @param key - The field name to check
|
|
1680
|
+
* @returns `true` if the field exists, `false` otherwise
|
|
1681
|
+
*
|
|
1682
|
+
* @example
|
|
1683
|
+
* ```typescript
|
|
1684
|
+
* const err = new RouterError("ERR", { segment: "users" });
|
|
1685
|
+
* err.setAdditionalFields({ userId: "123" });
|
|
1686
|
+
*
|
|
1687
|
+
* err.hasField("userId"); // true
|
|
1688
|
+
* err.hasField("segment"); // true
|
|
1689
|
+
* err.hasField("unknown"); // false
|
|
1690
|
+
* ```
|
|
1691
|
+
*/
|
|
1692
|
+
hasField(key: string): boolean;
|
|
1693
|
+
/**
|
|
1694
|
+
* Retrieves a custom field value from the error object.
|
|
1695
|
+
*
|
|
1696
|
+
* This method can access both custom fields and built-in fields.
|
|
1697
|
+
* Returns `undefined` if the field doesn't exist.
|
|
1698
|
+
*
|
|
1699
|
+
* @param key - The field name to retrieve
|
|
1700
|
+
* @returns The field value, or `undefined` if it doesn't exist
|
|
1701
|
+
*
|
|
1702
|
+
* @example
|
|
1703
|
+
* ```typescript
|
|
1704
|
+
* const err = new RouterError("ERR");
|
|
1705
|
+
* err.setAdditionalFields({ userId: "123", role: "admin" });
|
|
1706
|
+
*
|
|
1707
|
+
* err.getField("userId"); // "123"
|
|
1708
|
+
* err.getField("role"); // "admin"
|
|
1709
|
+
* err.getField("code"); // "ERR" (built-in field)
|
|
1710
|
+
* err.getField("unknown"); // undefined
|
|
1711
|
+
* ```
|
|
1712
|
+
*/
|
|
1713
|
+
getField(key: string): unknown;
|
|
1714
|
+
/**
|
|
1715
|
+
* Serializes the error to a JSON-compatible object.
|
|
1716
|
+
*
|
|
1717
|
+
* This method is automatically called by JSON.stringify() and includes:
|
|
1718
|
+
* - Built-in fields: code, message, segment (if set), path (if set), redirect (if set)
|
|
1719
|
+
* - All custom fields added via setAdditionalFields() or constructor
|
|
1720
|
+
* - Excludes: stack trace (for security/cleanliness)
|
|
1721
|
+
*
|
|
1722
|
+
* @returns A plain object representation of the error, suitable for JSON serialization
|
|
1723
|
+
*
|
|
1724
|
+
* @example
|
|
1725
|
+
* ```typescript
|
|
1726
|
+
* const err = new RouterError("ROUTE_NOT_FOUND", {
|
|
1727
|
+
* message: "Route not found",
|
|
1728
|
+
* path: "/admin/users/123"
|
|
1729
|
+
* });
|
|
1730
|
+
* err.setAdditionalFields({ userId: "123" });
|
|
1731
|
+
*
|
|
1732
|
+
* JSON.stringify(err);
|
|
1733
|
+
* // {
|
|
1734
|
+
* // "code": "ROUTE_NOT_FOUND",
|
|
1735
|
+
* // "message": "Route not found",
|
|
1736
|
+
* // "path": "/admin/users/123",
|
|
1737
|
+
* // "userId": "123"
|
|
1738
|
+
* // }
|
|
1739
|
+
* ```
|
|
1740
|
+
*/
|
|
1741
|
+
toJSON(): Record<string, unknown>;
|
|
1742
|
+
}
|
|
1743
|
+
export interface RouteState<P extends Params = Params, MP extends Params = Params> {
|
|
1744
|
+
route: State<P, MP> | undefined;
|
|
1745
|
+
previousRoute?: State | undefined;
|
|
1746
|
+
}
|
|
1747
|
+
export type RouteContext = {
|
|
1748
|
+
router: Router;
|
|
11
1749
|
} & RouteState;
|
|
12
|
-
interface BaseLinkProps
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1750
|
+
export interface BaseLinkProps {
|
|
1751
|
+
[key: string]: unknown;
|
|
1752
|
+
router: Router;
|
|
1753
|
+
routeName: string;
|
|
1754
|
+
routeParams?: Params;
|
|
1755
|
+
routeOptions?: {
|
|
1756
|
+
[key: string]: unknown;
|
|
1757
|
+
reload?: boolean;
|
|
1758
|
+
replace?: boolean;
|
|
1759
|
+
};
|
|
1760
|
+
className?: string;
|
|
1761
|
+
activeClassName?: string;
|
|
1762
|
+
activeStrict?: boolean;
|
|
1763
|
+
ignoreQueryParams?: boolean;
|
|
1764
|
+
onClick?: (evt: MouseEvent<HTMLAnchorElement>) => void;
|
|
1765
|
+
successCallback?: (state?: State) => void;
|
|
1766
|
+
errorCallback?: (err: RouterError$1) => void;
|
|
1767
|
+
target?: string;
|
|
1768
|
+
children?: ReactNode;
|
|
1769
|
+
previousRoute?: State;
|
|
32
1770
|
}
|
|
33
|
-
|
|
34
1771
|
/**
|
|
35
1772
|
* Optimized BaseLink component with memoization and performance improvements
|
|
36
1773
|
*/
|
|
37
|
-
declare const BaseLink: FC<BaseLinkProps
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
errorCallback?: (error?: RouterError) => void;
|
|
1774
|
+
export declare const BaseLink: FC<BaseLinkProps>;
|
|
1775
|
+
interface BaseLinkProps$1<P extends Params = Params, MP extends Params = Params> extends HTMLAttributes<HTMLAnchorElement> {
|
|
1776
|
+
router: Router;
|
|
1777
|
+
routeName: string;
|
|
1778
|
+
route?: State<P, MP> | undefined;
|
|
1779
|
+
previousRoute?: State | undefined;
|
|
1780
|
+
routeParams?: P;
|
|
1781
|
+
routeOptions?: NavigationOptions;
|
|
1782
|
+
className?: string;
|
|
1783
|
+
activeClassName?: string;
|
|
1784
|
+
activeStrict?: boolean;
|
|
1785
|
+
ignoreQueryParams?: boolean;
|
|
1786
|
+
target?: string;
|
|
1787
|
+
onClick?: MouseEventHandler<HTMLAnchorElement>;
|
|
1788
|
+
onMouseOver?: MouseEventHandler<HTMLAnchorElement>;
|
|
1789
|
+
successCallback?: (state?: State<P, MP>) => void;
|
|
1790
|
+
errorCallback?: (error?: RouterError$1) => void;
|
|
55
1791
|
}
|
|
56
|
-
|
|
57
|
-
declare const
|
|
58
|
-
|
|
59
|
-
declare const ConnectedLink: FC<Omit<BaseLinkProps, "router" | "route" | "previousRoute">>;
|
|
60
|
-
|
|
1792
|
+
export declare const Link: FC<Omit<BaseLinkProps$1, "router">>;
|
|
1793
|
+
export declare const ConnectedLink: FC<Omit<BaseLinkProps$1, "router" | "route" | "previousRoute">>;
|
|
61
1794
|
/**
|
|
62
1795
|
* Hook that subscribes to a specific route node with optimizations.
|
|
63
1796
|
* Provides the current and previous route when the node is affected.
|
|
64
1797
|
*/
|
|
65
|
-
declare function useRouteNode(nodeName: string): RouteContext
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
router: Router;
|
|
71
|
-
children: ReactNode;
|
|
1798
|
+
export declare function useRouteNode(nodeName: string): RouteContext;
|
|
1799
|
+
export declare const useRoute: () => RouteContext;
|
|
1800
|
+
export interface RouteProviderProps {
|
|
1801
|
+
router: Router;
|
|
1802
|
+
children: ReactNode;
|
|
72
1803
|
}
|
|
73
|
-
declare const RouterProvider: FC<RouteProviderProps>;
|
|
74
|
-
|
|
75
|
-
declare const
|
|
76
|
-
declare const
|
|
1804
|
+
export declare const RouterProvider: FC<RouteProviderProps>;
|
|
1805
|
+
declare const RouteContext$1: import("react").Context<RouteContext | null>;
|
|
1806
|
+
export declare const RouterContext: import("react").Context<Router<object> | null>;
|
|
1807
|
+
export declare const useRouter: () => Router;
|
|
77
1808
|
|
|
78
|
-
|
|
1809
|
+
export {
|
|
1810
|
+
RouteContext$1 as RouteContext,
|
|
1811
|
+
};
|
|
79
1812
|
|
|
80
|
-
export {
|
|
1813
|
+
export {};
|