@real-router/core 0.25.4 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +163 -325
  2. package/dist/cjs/index.d.ts +47 -178
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/metafile-cjs.json +1 -1
  6. package/dist/esm/index.d.mts +47 -178
  7. package/dist/esm/index.mjs +1 -1
  8. package/dist/esm/index.mjs.map +1 -1
  9. package/dist/esm/metafile-esm.json +1 -1
  10. package/package.json +3 -3
  11. package/src/Router.ts +84 -574
  12. package/src/api/cloneRouter.ts +106 -0
  13. package/src/api/getDependenciesApi.ts +216 -0
  14. package/src/api/getLifecycleApi.ts +67 -0
  15. package/src/api/getPluginApi.ts +118 -0
  16. package/src/api/getRoutesApi.ts +566 -0
  17. package/src/api/index.ts +16 -0
  18. package/src/api/types.ts +7 -0
  19. package/src/getNavigator.ts +5 -2
  20. package/src/index.ts +17 -3
  21. package/src/internals.ts +115 -0
  22. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +30 -0
  23. package/src/namespaces/DependenciesNamespace/index.ts +3 -1
  24. package/src/namespaces/DependenciesNamespace/validators.ts +2 -4
  25. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +1 -20
  26. package/src/namespaces/EventBusNamespace/validators.ts +36 -0
  27. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +1 -10
  28. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +2 -0
  29. package/src/namespaces/NavigationNamespace/transition/{executeLifecycleHooks.ts → executeLifecycleGuards.ts} +9 -7
  30. package/src/namespaces/NavigationNamespace/transition/index.ts +3 -3
  31. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +1 -16
  32. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +133 -1089
  33. package/src/namespaces/RoutesNamespace/forwardToValidation.ts +411 -0
  34. package/src/namespaces/RoutesNamespace/helpers.ts +1 -407
  35. package/src/namespaces/RoutesNamespace/index.ts +2 -0
  36. package/src/namespaces/RoutesNamespace/routesStore.ts +388 -0
  37. package/src/namespaces/RoutesNamespace/validators.ts +209 -3
  38. package/src/namespaces/StateNamespace/StateNamespace.ts +1 -44
  39. package/src/namespaces/StateNamespace/validators.ts +46 -0
  40. package/src/namespaces/index.ts +3 -5
  41. package/src/types.ts +12 -138
  42. package/src/wiring/RouterWiringBuilder.ts +30 -36
  43. package/src/wiring/types.ts +3 -6
  44. package/src/wiring/wireRouter.ts +0 -1
  45. package/src/namespaces/CloneNamespace/CloneNamespace.ts +0 -120
  46. package/src/namespaces/CloneNamespace/index.ts +0 -3
  47. package/src/namespaces/CloneNamespace/types.ts +0 -42
  48. package/src/namespaces/DependenciesNamespace/DependenciesNamespace.ts +0 -248
  49. package/src/namespaces/RoutesNamespace/stateBuilder.ts +0 -70
package/README.md CHANGED
@@ -29,13 +29,16 @@ const routes = [
29
29
 
30
30
  const router = createRouter(routes);
31
31
 
32
- router.start();
33
- router.navigate("users.profile", { id: "123" });
32
+ await router.start("/");
33
+ await router.navigate("users.profile", { id: "123" });
34
34
  ```
35
35
 
36
36
  ---
37
37
 
38
- ## Essential API
38
+ ## Router API
39
+
40
+ The Router class provides core lifecycle, navigation, state, and subscription methods.
41
+ Domain-specific operations (routes, dependencies, guards, plugin infrastructure, cloning) are available through standalone API functions for tree-shaking.
39
42
 
40
43
  ### `createRouter(routes?, options?, dependencies?)`
41
44
 
@@ -53,23 +56,23 @@ const router = createRouter(
53
56
 
54
57
  ### Lifecycle
55
58
 
56
- #### `router.start(startPath?, done?)`
59
+ #### `router.start(path): Promise<State>`
57
60
 
58
- Starts the router. [Wiki](https://github.com/greydragon888/real-router/wiki/start)
61
+ Starts the router with an initial path. Returns a Promise that resolves with the matched state. [Wiki](https://github.com/greydragon888/real-router/wiki/start)
59
62
 
60
63
  ```typescript
61
- router.start();
62
- router.start("/users/123");
63
- router.start("/users/123", (err, state) => {
64
- if (err) console.error(err);
65
- });
64
+ const state = await router.start("/users/123");
66
65
  ```
67
66
 
68
- #### `router.stop()`
67
+ #### `router.stop(): this`
68
+
69
+ Stops the router. Cancels any in-progress transition. [Wiki](https://github.com/greydragon888/real-router/wiki/stop)
70
+
71
+ #### `router.dispose(): void`
69
72
 
70
- Stops the router. [Wiki](https://github.com/greydragon888/real-router/wiki/stop)
73
+ Permanently terminates the router. Unlike `stop()`, it cannot be restarted. All mutating methods throw `RouterError(DISPOSED)` after disposal. Idempotent. [Wiki](https://github.com/greydragon888/real-router/wiki/dispose)
71
74
 
72
- #### `router.isActive()`
75
+ #### `router.isActive(): boolean`
73
76
 
74
77
  Returns whether the router is active (started and has current state). [Wiki](https://github.com/greydragon888/real-router/wiki/isActive)
75
78
 
@@ -77,26 +80,48 @@ Returns whether the router is active (started and has current state). [Wiki](htt
77
80
 
78
81
  ### Navigation
79
82
 
80
- #### `router.navigate(name, params?, options?, done?)`
83
+ All navigation methods return `Promise<State>`.
81
84
 
82
- Navigates to a route by name. Returns a cancel function. [Wiki](https://github.com/greydragon888/real-router/wiki/navigate)
85
+ #### `router.navigate(name, params?, options?): Promise<State>`
86
+
87
+ Navigates to a route by name. [Wiki](https://github.com/greydragon888/real-router/wiki/navigate)
83
88
 
84
89
  ```typescript
85
- router.navigate("users");
86
- router.navigate("users.profile", { id: "123" });
87
- router.navigate("users.profile", { id: "123" }, { replace: true });
90
+ const state = await router.navigate("users.profile", { id: "123" });
88
91
 
89
- // With callback
90
- router.navigate("users", {}, {}, (err, state) => {
91
- if (err) console.error(err);
92
- });
92
+ // With navigation options
93
+ await router.navigate("users", {}, { replace: true });
94
+
95
+ // Concurrent navigation cancels previous
96
+ router.navigate("slow-route");
97
+ router.navigate("fast-route"); // Previous rejects with TRANSITION_CANCELLED
93
98
 
94
- // Cancellation
95
- const cancel = router.navigate("users.profile", { id: "123" });
96
- cancel(); // abort navigation
99
+ // Error handling
100
+ try {
101
+ await router.navigate("admin");
102
+ } catch (err) {
103
+ if (err instanceof RouterError) {
104
+ // ROUTE_NOT_FOUND, CANNOT_ACTIVATE, CANNOT_DEACTIVATE,
105
+ // TRANSITION_CANCELLED, SAME_STATES, ROUTER_DISPOSED
106
+ }
107
+ }
97
108
  ```
98
109
 
99
- #### `router.getState()`
110
+ **Fire-and-forget safe:** calling `router.navigate(...)` without `await` suppresses expected errors (`SAME_STATES`, `TRANSITION_CANCELLED`).
111
+
112
+ #### `router.navigateToDefault(options?): Promise<State>`
113
+
114
+ Navigates to the default route. [Wiki](https://github.com/greydragon888/real-router/wiki/navigateToDefault)
115
+
116
+ #### `router.canNavigateTo(name, params?): boolean`
117
+
118
+ Synchronously checks if navigation to a route would be allowed by guards. [Wiki](https://github.com/greydragon888/real-router/wiki/canNavigateTo)
119
+
120
+ ---
121
+
122
+ ### State
123
+
124
+ #### `router.getState(): State | undefined`
100
125
 
101
126
  Returns the current router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getState)
102
127
 
@@ -105,85 +130,56 @@ const state = router.getState();
105
130
  // { name: "users.profile", params: { id: "123" }, path: "/users/123" }
106
131
  ```
107
132
 
108
- #### `router.navigateToDefault(options?, done?)`
133
+ #### `router.getPreviousState(): State | undefined`
109
134
 
110
- Navigates to the default route. [Wiki](https://github.com/greydragon888/real-router/wiki/navigateToDefault)
135
+ Returns the previous router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getPreviousState)
111
136
 
112
- ---
137
+ #### `router.areStatesEqual(state1, state2, ignoreQueryParams?): boolean`
113
138
 
114
- ### Guards
139
+ Compare two states for equality. Query params ignored by default. [Wiki](https://github.com/greydragon888/real-router/wiki/areStatesEqual)
115
140
 
116
- #### `router.addActivateGuard(name, guardFactory)`
141
+ #### `router.shouldUpdateNode(nodeName): (toState, fromState?) => boolean`
117
142
 
118
- Registers a guard for route activation. [Wiki](https://github.com/greydragon888/real-router/wiki/canActivate)
143
+ Create a predicate to check if a route node should update during transition. [Wiki](https://github.com/greydragon888/real-router/wiki/shouldUpdateNode)
119
144
 
120
- ```typescript
121
- router.addActivateGuard("admin", () => (toState, fromState, done) => {
122
- if (!isAuthenticated()) {
123
- done({ redirect: { name: "login" } });
124
- } else {
125
- done();
126
- }
127
- });
128
- ```
145
+ ---
129
146
 
130
- #### `router.addDeactivateGuard(name, guardFactory)`
147
+ ### Path Operations
131
148
 
132
- Registers a guard for route deactivation. [Wiki](https://github.com/greydragon888/real-router/wiki/canDeactivate)
149
+ #### `router.buildPath(name, params?): string`
150
+
151
+ Build URL path from route name. [Wiki](https://github.com/greydragon888/real-router/wiki/buildPath)
133
152
 
134
153
  ```typescript
135
- router.addDeactivateGuard("editor", () => (toState, fromState, done) => {
136
- if (hasUnsavedChanges()) {
137
- done({ error: new Error("Unsaved changes") });
138
- } else {
139
- done();
140
- }
141
- });
154
+ const path = router.buildPath("users.profile", { id: "123" });
155
+ // "/users/123"
142
156
  ```
143
157
 
158
+ #### `router.isActiveRoute(name, params?, strictEquality?, ignoreQueryParams?): boolean`
159
+
160
+ Check if route is currently active. [Wiki](https://github.com/greydragon888/real-router/wiki/isActiveRoute)
161
+
144
162
  ---
145
163
 
146
164
  ### Events
147
165
 
148
- #### `router.subscribe(listener)`
166
+ #### `router.subscribe(listener): Unsubscribe`
149
167
 
150
168
  Subscribes to successful transitions. [Wiki](https://github.com/greydragon888/real-router/wiki/subscribe)
151
169
 
152
170
  ```typescript
153
171
  const unsubscribe = router.subscribe(({ route, previousRoute }) => {
154
- console.log("Navigation:", previousRoute?.name, "", route.name);
172
+ console.log("Navigation:", previousRoute?.name, "->", route.name);
155
173
  });
156
174
  ```
157
175
 
158
- #### `router.addEventListener(event, listener)`
159
-
160
- Adds an event listener. Returns an unsubscribe function. [Wiki](https://github.com/greydragon888/real-router/wiki/addEventListener)
161
-
162
- ```typescript
163
- import { events } from "@real-router/core";
164
-
165
- const unsubscribe = router.addEventListener(
166
- events.TRANSITION_START,
167
- (toState, fromState) => {
168
- console.log("Starting:", toState.name);
169
- },
170
- );
171
-
172
- // To remove listener, call the returned unsubscribe function
173
- unsubscribe();
174
-
175
- // Available events:
176
- // ROUTER_START, ROUTER_STOP
177
- // TRANSITION_START, TRANSITION_SUCCESS, TRANSITION_ERROR, TRANSITION_CANCEL
178
- ```
179
-
180
176
  ---
181
177
 
182
178
  ### Plugins
183
179
 
184
- #### `router.usePlugin(pluginFactory)`
180
+ #### `router.usePlugin(...plugins): Unsubscribe`
185
181
 
186
- Registers a plugin. Returns an unsubscribe function. [Wiki](https://github.com/greydragon888/real-router/wiki/usePlugin)
182
+ Registers one or more plugins. Returns an unsubscribe function. [Wiki](https://github.com/greydragon888/real-router/wiki/usePlugin)
187
183
 
188
184
  ```typescript
189
185
  import { browserPluginFactory } from "@real-router/browser-plugin";
@@ -193,284 +189,123 @@ const unsubscribe = router.usePlugin(browserPluginFactory());
193
189
 
194
190
  ---
195
191
 
196
- ## Advanced API
197
-
198
- ### Routes
199
-
200
- #### `router.addRoute(route, options?): void`
201
-
202
- Add a route definition at runtime.
192
+ ## Standalone API
203
193
 
204
- **Parameters:**
194
+ Standalone functions provide domain-specific operations. They are tree-shakeable — only imported functions are bundled.
205
195
 
206
- - `route: Route | Route[]` — route configuration object(s)
207
- - `options?: { parent?: string }` — optional parent route fullName
196
+ ### Routes `getRoutesApi(router)`
208
197
 
209
- **Examples:**
198
+ Runtime route management. [Wiki](https://github.com/greydragon888/real-router/wiki/getRoutesApi)
210
199
 
211
200
  ```typescript
212
- // Add route with children syntax
213
- router.addRoute({
214
- name: "users",
215
- path: "/users",
216
- children: [{ name: "profile", path: "/:id" }],
217
- });
218
-
219
- // Add route under existing parent using { parent } option
220
- router.addRoute({ name: "profile", path: "/:id" }, { parent: "users" });
221
- // Creates "users.profile" fullName
222
-
223
- // Batch add under same parent
224
- router.addRoute(
225
- [
226
- { name: "profile", path: "/:id" },
227
- { name: "settings", path: "/settings" },
228
- ],
229
- { parent: "users" },
230
- );
231
- ```
232
-
233
- Returns: `void`\
234
- [Wiki](https://github.com/greydragon888/real-router/wiki/addRoute)
235
-
236
- #### `router.removeRoute(name: string): void`
237
-
238
- Remove a route by name.\
239
- `name: string` — route name to remove\
240
- Returns: `void`\
241
- [Wiki](https://github.com/greydragon888/real-router/wiki/removeRoute)
242
-
243
- #### `router.getRoute(name: string): Route | undefined`
244
-
245
- Get route definition by name.\
246
- `name: string` — route name\
247
- Returns: `Route | undefined`\
248
- [Wiki](https://github.com/greydragon888/real-router/wiki/getRoute)
201
+ import { getRoutesApi } from "@real-router/core";
249
202
 
250
- #### `router.hasRoute(name: string): boolean`
203
+ const routes = getRoutesApi(router);
251
204
 
252
- Check if a route exists.\
253
- `name: string` route name\
254
- Returns: `boolean`\
255
- [Wiki](https://github.com/greydragon888/real-router/wiki/hasRoute)
205
+ // Add routes
206
+ routes.add({ name: "settings", path: "/settings" });
207
+ routes.add({ name: "profile", path: "/:id" }, { parent: "users" });
256
208
 
257
- #### `router.clearRoutes(): void`
209
+ // Query
210
+ routes.has("users"); // true
211
+ routes.get("users"); // Route | undefined
258
212
 
259
- Remove all routes.
260
- Returns: `void`\
261
- [Wiki](https://github.com/greydragon888/real-router/wiki/clearRoutes)
262
-
263
- #### `router.updateRoute(name: string, updates: Partial<Route>): void`
264
-
265
- Update route configuration.\
266
- `name: string` — route name\
267
- `updates: Partial<Route>` — properties to update\
268
- Returns: `void`\
269
- [Wiki](https://github.com/greydragon888/real-router/wiki/updateRoute)
270
-
271
- **Note:** To set up route forwarding (redirect), use the `forwardTo` option in route configuration:
272
-
273
- ```typescript
274
- router.addRoute({ name: "old-url", path: "/old", forwardTo: "new-url" });
275
- // Or update existing route
276
- router.updateRoute("old-url", { forwardTo: "new-url" });
213
+ // Modify
214
+ routes.update("users", { forwardTo: "users.list" });
215
+ routes.remove("settings");
216
+ routes.clear();
277
217
  ```
278
218
 
279
- ---
280
-
281
- ### State Utilities
282
-
283
- #### `router.getPreviousState(): State | undefined`
284
-
285
- Get previous router state.\
286
- Returns: `State | undefined`\
287
- [Wiki](https://github.com/greydragon888/real-router/wiki/getPreviousState)
288
-
289
- #### `router.shouldUpdateNode(nodeName: string): (toState, fromState?) => boolean`
290
-
291
- Create a predicate to check if a route node should update during transition.\
292
- `nodeName: string` — route node name\
293
- Returns: predicate function\
294
- [Wiki](https://github.com/greydragon888/real-router/wiki/shouldUpdateNode)
295
-
296
- #### `router.areStatesEqual(state1: State, state2: State, ignoreQueryParams?: boolean): boolean`
297
-
298
- Compare two states for equality.\
299
- `state1: State` — first state\
300
- `state2: State` — second state\
301
- `ignoreQueryParams?: boolean` — ignore query params (default: true)\
302
- Returns: `boolean`\
303
- [Wiki](https://github.com/greydragon888/real-router/wiki/areStatesEqual)
304
-
305
- ---
306
-
307
- ### Path Operations
308
-
309
- #### `router.buildPath(name: string, params?: Params): string`
310
-
311
- Build URL path from route name.\
312
- `name: string` — route name\
313
- `params?: Params` — route parameters\
314
- Returns: `string`\
315
- [Wiki](https://github.com/greydragon888/real-router/wiki/buildPath)
316
-
317
- #### `router.buildUrl(name: string, params?: Params, options?: object): string`
318
-
319
- Build full URL from route name (includes base path and query string).\
320
- `name: string` — route name\
321
- `params?: Params` — route parameters\
322
- `options?: object` — URL building options\
323
- Returns: `string`\
324
- [Wiki](https://github.com/greydragon888/real-router/wiki/buildUrl)
325
-
326
- #### `router.isActiveRoute(name: string, params?: Params, strictEquality?: boolean, ignoreQueryParams?: boolean): boolean`
327
-
328
- Check if route is currently active.\
329
- `name: string` — route name\
330
- `params?: Params` — route parameters\
331
- `strictEquality?: boolean` — exact match (default: false)\
332
- `ignoreQueryParams?: boolean` — ignore query params (default: true)\
333
- Returns: `boolean`\
334
- [Wiki](https://github.com/greydragon888/real-router/wiki/isActiveRoute)
335
-
336
- ---
337
-
338
- ### Dependencies
219
+ **Methods:** `add`, `remove`, `update`, `clear`, `has`, `get`, `getConfig`
339
220
 
340
- #### `router.getDependency(name: string): unknown`
221
+ ### Dependencies — `getDependenciesApi(router)`
341
222
 
342
- Get a dependency by name.\
343
- `name: string` — dependency name\
344
- Returns: `unknown`\
345
- [Wiki](https://github.com/greydragon888/real-router/wiki/getDependency)
223
+ Dependency injection container. [Wiki](https://github.com/greydragon888/real-router/wiki/getDependenciesApi)
346
224
 
347
- #### `router.getDependencies(): Dependencies`
348
-
349
- Get all dependencies.\
350
- Returns: `Dependencies`\
351
- [Wiki](https://github.com/greydragon888/real-router/wiki/getDependencies)
352
-
353
- #### `router.setDependency(name: string, value: unknown): void`
354
-
355
- Set a dependency.\
356
- `name: string` — dependency name\
357
- `value: unknown` — dependency value\
358
- Returns: `void`\
359
- [Wiki](https://github.com/greydragon888/real-router/wiki/setDependency)
360
-
361
- #### `router.setDependencies(deps: Dependencies): void`
362
-
363
- Set multiple dependencies.\
364
- `deps: Dependencies` — dependencies object\
365
- Returns: `void`\
366
- [Wiki](https://github.com/greydragon888/real-router/wiki/setDependencies)
367
-
368
- #### `router.hasDependency(name: string): boolean`
369
-
370
- Check if dependency exists.\
371
- `name: string` — dependency name\
372
- Returns: `boolean`\
373
- [Wiki](https://github.com/greydragon888/real-router/wiki/hasDependency)
374
-
375
- #### `router.removeDependency(name: string): void`
376
-
377
- Remove a dependency.\
378
- `name: string` — dependency name\
379
- Returns: `void`\
380
- [Wiki](https://github.com/greydragon888/real-router/wiki/removeDependency)
381
-
382
- #### `router.resetDependencies(): void`
225
+ ```typescript
226
+ import { getDependenciesApi } from "@real-router/core";
383
227
 
384
- Remove all dependencies.\
385
- Returns: `void`\
386
- [Wiki](https://github.com/greydragon888/real-router/wiki/resetDependencies)
228
+ const deps = getDependenciesApi(router);
387
229
 
388
- ---
230
+ deps.set("authService", authService);
231
+ deps.get("authService"); // authService
232
+ deps.has("authService"); // true
233
+ deps.getAll(); // { authService: ... }
234
+ deps.remove("authService");
235
+ deps.reset();
236
+ ```
389
237
 
390
- ### Options
238
+ **Methods:** `get`, `getAll`, `set`, `setAll`, `remove`, `reset`, `has`
391
239
 
392
- #### `router.getOptions(): Options`
240
+ ### Guards — `getLifecycleApi(router)`
393
241
 
394
- Get all router options.\
395
- Returns: `Options`\
396
- [Wiki](https://github.com/greydragon888/real-router/wiki/getOptions)
242
+ Route activation/deactivation guards. [Wiki](https://github.com/greydragon888/real-router/wiki/getLifecycleApi)
397
243
 
398
- ---
399
-
400
- ### Other
244
+ ```typescript
245
+ import { getLifecycleApi } from "@real-router/core";
401
246
 
402
- #### `router.clone(dependencies?: Dependencies): Router`
247
+ const lifecycle = getLifecycleApi(router);
403
248
 
404
- Clone router for SSR.\
405
- `dependencies?: Dependencies` override dependencies\
406
- Returns: `Router`\
407
- [Wiki](https://github.com/greydragon888/real-router/wiki/clone)
249
+ // Guard returns boolean or Promise<boolean> (true = allow, false = block)
250
+ lifecycle.addActivateGuard("admin", () => (toState, fromState) => {
251
+ return isAuthenticated(); // sync
252
+ });
408
253
 
409
- ---
254
+ lifecycle.addDeactivateGuard("editor", () => async (toState, fromState) => {
255
+ return !(await checkUnsavedChanges()); // async
256
+ });
410
257
 
411
- ## Plugin Development API
258
+ // Remove guards
259
+ lifecycle.removeActivateGuard("admin");
260
+ lifecycle.removeDeactivateGuard("editor");
261
+ ```
412
262
 
413
- The following methods are designed for **plugin authors**. They provide low-level access for advanced use cases like browser history integration, persistent parameters, and custom navigation sources.
263
+ **Methods:** `addActivateGuard`, `addDeactivateGuard`, `removeActivateGuard`, `removeDeactivateGuard`
414
264
 
415
- These methods are stable but intended for plugin development, not application code.
265
+ ### Plugin Infrastructure `getPluginApi(router)`
416
266
 
417
- #### `router.matchPath(path: string): State | undefined`
267
+ Low-level API for plugin authors. Provides access to state building, path matching, event system, and navigation. [Wiki](https://github.com/greydragon888/real-router/wiki/getPluginApi)
418
268
 
419
- Match URL path to route state.\
420
- `path: string` URL path to match\
421
- Returns: `State | undefined`\
422
- [Wiki](https://github.com/greydragon888/real-router/wiki/matchPath)
269
+ ```typescript
270
+ import { getPluginApi } from "@real-router/core";
423
271
 
424
- #### `router.makeState(name, params?, path?, meta?, forceId?): State`
272
+ const api = getPluginApi(router);
425
273
 
426
- Create State with custom `meta.id` for history restoration.\
427
- `name: string` route name\
428
- `params?: Params` route parameters\
429
- `path?: string` — URL path\
430
- `meta?: object` — metadata\
431
- `forceId?: number` — force specific `meta.id` value\
432
- Returns: `State`\
433
- [Wiki](https://github.com/greydragon888/real-router/wiki/makeState)
274
+ // State building
275
+ const state = api.matchPath("/users/123");
276
+ const builtState = api.makeState("users.profile", { id: "123" });
434
277
 
435
- #### `router.buildState(name: string, params?: Params): State | undefined`
278
+ // Event system
279
+ const unsub = api.addEventListener(events.TRANSITION_START, (toState, fromState) => {
280
+ console.log("Starting:", toState.name);
281
+ });
436
282
 
437
- Validate route and build state with segment metadata.\
438
- `name: string` route name\
439
- `params?: Params` — route parameters\
440
- Returns: `State | undefined`\
441
- [Wiki](https://github.com/greydragon888/real-router/wiki/buildState)
283
+ // Navigation with pre-built state
284
+ await api.navigateToState(toState, fromState, opts);
442
285
 
443
- #### `router.forwardState(name: string, params: Params): { name: string; params: Params }`
286
+ // Root path management
287
+ api.setRootPath("/app");
288
+ api.getRootPath(); // "/app"
444
289
 
445
- Resolve route forwarding and merge default params.\
446
- `name: string` route name\
447
- `params: Params` — route parameters\
448
- Returns: `{ name, params }` — resolved route name and merged params\
449
- [Wiki](https://github.com/greydragon888/real-router/wiki/forwardState)
290
+ // Forward state interception (used by persistent-params-plugin)
291
+ api.setForwardState((name, params) => ({ name, params: withPersistent(params) }));
292
+ ```
450
293
 
451
- #### `router.navigateToState(toState, fromState, opts, done, emitSuccess): CancelFn`
294
+ **Methods:** `makeState`, `buildState`, `buildNavigationState`, `forwardState`, `matchPath`, `setRootPath`, `getRootPath`, `navigateToState`, `addEventListener`, `getOptions`, `getTree`, `getForwardState`, `setForwardState`
452
295
 
453
- Navigate with pre-built State object.\
454
- `toState: State` — target state\
455
- `fromState: State | undefined` — current state\
456
- `opts: NavigationOptions` — navigation options\
457
- `done: DoneFn` — callback\
458
- `emitSuccess: boolean` — whether to emit TRANSITION_SUCCESS\
459
- Returns: `CancelFn`\
460
- [Wiki](https://github.com/greydragon888/real-router/wiki/navigateToState)
296
+ ### SSR Cloning `cloneRouter(router, deps?)`
461
297
 
462
- #### `router.setRootPath(rootPath: string): void`
298
+ Clone router for server-side rendering. [Wiki](https://github.com/greydragon888/real-router/wiki/cloneRouter)
463
299
 
464
- Dynamically modify router base path.\
465
- `rootPath: string` new root path prefix\
466
- Returns: `void`\
467
- [Wiki](https://github.com/greydragon888/real-router/wiki/setRootPath)
300
+ ```typescript
301
+ import { cloneRouter } from "@real-router/core";
468
302
 
469
- #### `router.getRootPath(): string`
303
+ // Server: clone router per request
304
+ const serverRouter = cloneRouter(router, { request: req });
305
+ await serverRouter.start(req.url);
306
+ ```
470
307
 
471
- Read current base path.\
472
- Returns: `string`\
473
- [Wiki](https://github.com/greydragon888/real-router/wiki/getRootPath)
308
+ Shares immutable route tree (O(1)), copies mutable state (dependencies, options, plugins, guards).
474
309
 
475
310
  ---
476
311
 
@@ -508,22 +343,25 @@ Navigation errors are instances of `RouterError`:
508
343
  ```typescript
509
344
  import { RouterError, errorCodes } from "@real-router/core";
510
345
 
511
- router.navigate("users", {}, {}, (err, state) => {
346
+ try {
347
+ await router.navigate("users");
348
+ } catch (err) {
512
349
  if (err instanceof RouterError) {
513
350
  console.log(err.code, err.message);
514
351
  }
515
- });
352
+ }
516
353
  ```
517
354
 
518
- | Code | Description |
519
- | ------------------- | ------------------------------ |
520
- | `ROUTE_NOT_FOUND` | Route doesn't exist |
521
- | `CANNOT_ACTIVATE` | Blocked by canActivate guard |
522
- | `CANNOT_DEACTIVATE` | Blocked by canDeactivate guard |
523
- | `CANCELLED` | Navigation was cancelled |
524
- | `SAME_STATES` | Already at target route |
525
- | `NOT_STARTED` | Router not started |
526
- | `ALREADY_STARTED` | Router already started |
355
+ | Code | Description |
356
+ | --------------------- | ------------------------------ |
357
+ | `ROUTE_NOT_FOUND` | Route doesn't exist |
358
+ | `CANNOT_ACTIVATE` | Blocked by canActivate guard |
359
+ | `CANNOT_DEACTIVATE` | Blocked by canDeactivate guard |
360
+ | `CANCELLED` | Navigation was cancelled |
361
+ | `SAME_STATES` | Already at target route |
362
+ | `NOT_STARTED` | Router not started |
363
+ | `ALREADY_STARTED` | Router already started |
364
+ | `DISPOSED` | Router has been disposed |
527
365
 
528
366
  See [RouterError](https://github.com/greydragon888/real-router/wiki/RouterError) and [Error Codes](https://github.com/greydragon888/real-router/wiki/error-codes) for details.
529
367