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