@real-router/core 0.25.4 → 0.27.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.
- package/README.md +175 -323
- package/dist/cjs/index.d.ts +47 -178
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/metafile-cjs.json +1 -1
- package/dist/esm/index.d.mts +47 -178
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/metafile-esm.json +1 -1
- package/package.json +3 -3
- package/src/Router.ts +86 -574
- package/src/api/cloneRouter.ts +106 -0
- package/src/api/getDependenciesApi.ts +216 -0
- package/src/api/getLifecycleApi.ts +67 -0
- package/src/api/getPluginApi.ts +118 -0
- package/src/api/getRoutesApi.ts +566 -0
- package/src/api/index.ts +16 -0
- package/src/api/types.ts +7 -0
- package/src/getNavigator.ts +5 -2
- package/src/index.ts +17 -3
- package/src/internals.ts +115 -0
- package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +30 -0
- package/src/namespaces/DependenciesNamespace/index.ts +3 -1
- package/src/namespaces/DependenciesNamespace/validators.ts +2 -4
- package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +1 -20
- package/src/namespaces/EventBusNamespace/validators.ts +36 -0
- package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +63 -12
- package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +2 -0
- package/src/namespaces/NavigationNamespace/transition/{executeLifecycleHooks.ts → executeLifecycleGuards.ts} +16 -7
- package/src/namespaces/NavigationNamespace/transition/index.ts +7 -4
- package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +1 -16
- package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +133 -1089
- package/src/namespaces/RoutesNamespace/forwardToValidation.ts +411 -0
- package/src/namespaces/RoutesNamespace/helpers.ts +1 -407
- package/src/namespaces/RoutesNamespace/index.ts +2 -0
- package/src/namespaces/RoutesNamespace/routesStore.ts +388 -0
- package/src/namespaces/RoutesNamespace/validators.ts +209 -3
- package/src/namespaces/StateNamespace/StateNamespace.ts +1 -44
- package/src/namespaces/StateNamespace/validators.ts +46 -0
- package/src/namespaces/index.ts +3 -5
- package/src/types.ts +12 -138
- package/src/wiring/RouterWiringBuilder.ts +30 -36
- package/src/wiring/types.ts +3 -6
- package/src/wiring/wireRouter.ts +0 -1
- package/src/namespaces/CloneNamespace/CloneNamespace.ts +0 -120
- package/src/namespaces/CloneNamespace/index.ts +0 -3
- package/src/namespaces/CloneNamespace/types.ts +0 -42
- package/src/namespaces/DependenciesNamespace/DependenciesNamespace.ts +0 -248
- 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
|
-
##
|
|
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(
|
|
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
|
-
|
|
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,400 +80,246 @@ Returns whether the router is active (started and has current state). [Wiki](htt
|
|
|
77
80
|
|
|
78
81
|
### Navigation
|
|
79
82
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Navigates to a route by name. Returns a cancel function. [Wiki](https://github.com/greydragon888/real-router/wiki/navigate)
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
router.navigate("users");
|
|
86
|
-
router.navigate("users.profile", { id: "123" });
|
|
87
|
-
router.navigate("users.profile", { id: "123" }, { replace: true });
|
|
88
|
-
|
|
89
|
-
// With callback
|
|
90
|
-
router.navigate("users", {}, {}, (err, state) => {
|
|
91
|
-
if (err) console.error(err);
|
|
92
|
-
});
|
|
83
|
+
All navigation methods return `Promise<State>`.
|
|
93
84
|
|
|
94
|
-
|
|
95
|
-
const cancel = router.navigate("users.profile", { id: "123" });
|
|
96
|
-
cancel(); // abort navigation
|
|
97
|
-
```
|
|
85
|
+
#### `router.navigate(name, params?, options?): Promise<State>`
|
|
98
86
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
Returns the current router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getState)
|
|
87
|
+
Navigates to a route by name. [Wiki](https://github.com/greydragon888/real-router/wiki/navigate)
|
|
102
88
|
|
|
103
89
|
```typescript
|
|
104
|
-
const state = router.
|
|
105
|
-
// { name: "users.profile", params: { id: "123" }, path: "/users/123" }
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
#### `router.navigateToDefault(options?, done?)`
|
|
90
|
+
const state = await router.navigate("users.profile", { id: "123" });
|
|
109
91
|
|
|
110
|
-
|
|
92
|
+
// With navigation options
|
|
93
|
+
await router.navigate("users", {}, { replace: true });
|
|
111
94
|
|
|
112
|
-
|
|
95
|
+
// Concurrent navigation cancels previous
|
|
96
|
+
router.navigate("slow-route");
|
|
97
|
+
router.navigate("fast-route"); // Previous rejects with TRANSITION_CANCELLED
|
|
113
98
|
|
|
114
|
-
|
|
99
|
+
// Cancel via AbortController
|
|
100
|
+
const controller = new AbortController();
|
|
101
|
+
router.navigate("route", {}, { signal: controller.signal });
|
|
102
|
+
controller.abort(); // rejects with TRANSITION_CANCELLED
|
|
115
103
|
|
|
116
|
-
|
|
104
|
+
// Timeout
|
|
105
|
+
router.navigate("route", {}, { signal: AbortSignal.timeout(5000) });
|
|
117
106
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
done();
|
|
107
|
+
// Error handling
|
|
108
|
+
try {
|
|
109
|
+
await router.navigate("admin");
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (err instanceof RouterError) {
|
|
112
|
+
// ROUTE_NOT_FOUND, CANNOT_ACTIVATE, CANNOT_DEACTIVATE,
|
|
113
|
+
// TRANSITION_CANCELLED, SAME_STATES, ROUTER_DISPOSED
|
|
126
114
|
}
|
|
127
|
-
}
|
|
115
|
+
}
|
|
128
116
|
```
|
|
129
117
|
|
|
130
|
-
|
|
118
|
+
**Fire-and-forget safe:** calling `router.navigate(...)` without `await` suppresses expected errors (`SAME_STATES`, `TRANSITION_CANCELLED`).
|
|
131
119
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
router.addDeactivateGuard("editor", () => (toState, fromState, done) => {
|
|
136
|
-
if (hasUnsavedChanges()) {
|
|
137
|
-
done({ error: new Error("Unsaved changes") });
|
|
138
|
-
} else {
|
|
139
|
-
done();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
```
|
|
120
|
+
#### `router.navigateToDefault(options?): Promise<State>`
|
|
143
121
|
|
|
144
|
-
|
|
122
|
+
Navigates to the default route. [Wiki](https://github.com/greydragon888/real-router/wiki/navigateToDefault)
|
|
145
123
|
|
|
146
|
-
|
|
124
|
+
#### `router.canNavigateTo(name, params?): boolean`
|
|
147
125
|
|
|
148
|
-
|
|
126
|
+
Synchronously checks if navigation to a route would be allowed by guards. [Wiki](https://github.com/greydragon888/real-router/wiki/canNavigateTo)
|
|
149
127
|
|
|
150
|
-
|
|
128
|
+
---
|
|
151
129
|
|
|
152
|
-
|
|
153
|
-
const unsubscribe = router.subscribe(({ route, previousRoute }) => {
|
|
154
|
-
console.log("Navigation:", previousRoute?.name, "→", route.name);
|
|
155
|
-
});
|
|
156
|
-
```
|
|
130
|
+
### State
|
|
157
131
|
|
|
158
|
-
#### `router.
|
|
132
|
+
#### `router.getState(): State | undefined`
|
|
159
133
|
|
|
160
|
-
|
|
134
|
+
Returns the current router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getState)
|
|
161
135
|
|
|
162
136
|
```typescript
|
|
163
|
-
|
|
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
|
|
137
|
+
const state = router.getState();
|
|
138
|
+
// { name: "users.profile", params: { id: "123" }, path: "/users/123" }
|
|
178
139
|
```
|
|
179
140
|
|
|
180
|
-
|
|
141
|
+
#### `router.getPreviousState(): State | undefined`
|
|
181
142
|
|
|
182
|
-
|
|
143
|
+
Returns the previous router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getPreviousState)
|
|
183
144
|
|
|
184
|
-
#### `router.
|
|
145
|
+
#### `router.areStatesEqual(state1, state2, ignoreQueryParams?): boolean`
|
|
185
146
|
|
|
186
|
-
|
|
147
|
+
Compare two states for equality. Query params ignored by default. [Wiki](https://github.com/greydragon888/real-router/wiki/areStatesEqual)
|
|
187
148
|
|
|
188
|
-
|
|
189
|
-
import { browserPluginFactory } from "@real-router/browser-plugin";
|
|
149
|
+
#### `router.shouldUpdateNode(nodeName): (toState, fromState?) => boolean`
|
|
190
150
|
|
|
191
|
-
|
|
192
|
-
```
|
|
151
|
+
Create a predicate to check if a route node should update during transition. [Wiki](https://github.com/greydragon888/real-router/wiki/shouldUpdateNode)
|
|
193
152
|
|
|
194
153
|
---
|
|
195
154
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
### Routes
|
|
199
|
-
|
|
200
|
-
#### `router.addRoute(route, options?): void`
|
|
201
|
-
|
|
202
|
-
Add a route definition at runtime.
|
|
203
|
-
|
|
204
|
-
**Parameters:**
|
|
155
|
+
### Path Operations
|
|
205
156
|
|
|
206
|
-
|
|
207
|
-
- `options?: { parent?: string }` — optional parent route fullName
|
|
157
|
+
#### `router.buildPath(name, params?): string`
|
|
208
158
|
|
|
209
|
-
|
|
159
|
+
Build URL path from route name. [Wiki](https://github.com/greydragon888/real-router/wiki/buildPath)
|
|
210
160
|
|
|
211
161
|
```typescript
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
);
|
|
162
|
+
const path = router.buildPath("users.profile", { id: "123" });
|
|
163
|
+
// "/users/123"
|
|
231
164
|
```
|
|
232
165
|
|
|
233
|
-
|
|
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)
|
|
166
|
+
#### `router.isActiveRoute(name, params?, strictEquality?, ignoreQueryParams?): boolean`
|
|
242
167
|
|
|
243
|
-
|
|
168
|
+
Check if route is currently active. [Wiki](https://github.com/greydragon888/real-router/wiki/isActiveRoute)
|
|
244
169
|
|
|
245
|
-
|
|
246
|
-
`name: string` — route name\
|
|
247
|
-
Returns: `Route | undefined`\
|
|
248
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/getRoute)
|
|
249
|
-
|
|
250
|
-
#### `router.hasRoute(name: string): boolean`
|
|
251
|
-
|
|
252
|
-
Check if a route exists.\
|
|
253
|
-
`name: string` — route name\
|
|
254
|
-
Returns: `boolean`\
|
|
255
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/hasRoute)
|
|
256
|
-
|
|
257
|
-
#### `router.clearRoutes(): void`
|
|
258
|
-
|
|
259
|
-
Remove all routes.
|
|
260
|
-
Returns: `void`\
|
|
261
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/clearRoutes)
|
|
170
|
+
---
|
|
262
171
|
|
|
263
|
-
|
|
172
|
+
### Events
|
|
264
173
|
|
|
265
|
-
|
|
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)
|
|
174
|
+
#### `router.subscribe(listener): Unsubscribe`
|
|
270
175
|
|
|
271
|
-
|
|
176
|
+
Subscribes to successful transitions. [Wiki](https://github.com/greydragon888/real-router/wiki/subscribe)
|
|
272
177
|
|
|
273
178
|
```typescript
|
|
274
|
-
router.
|
|
275
|
-
|
|
276
|
-
|
|
179
|
+
const unsubscribe = router.subscribe(({ route, previousRoute }) => {
|
|
180
|
+
console.log("Navigation:", previousRoute?.name, "->", route.name);
|
|
181
|
+
});
|
|
277
182
|
```
|
|
278
183
|
|
|
279
184
|
---
|
|
280
185
|
|
|
281
|
-
###
|
|
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)
|
|
186
|
+
### Plugins
|
|
316
187
|
|
|
317
|
-
#### `router.
|
|
188
|
+
#### `router.usePlugin(...plugins): Unsubscribe`
|
|
318
189
|
|
|
319
|
-
|
|
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)
|
|
190
|
+
Registers one or more plugins. Returns an unsubscribe function. [Wiki](https://github.com/greydragon888/real-router/wiki/usePlugin)
|
|
325
191
|
|
|
326
|
-
|
|
192
|
+
```typescript
|
|
193
|
+
import { browserPluginFactory } from "@real-router/browser-plugin";
|
|
327
194
|
|
|
328
|
-
|
|
329
|
-
|
|
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)
|
|
195
|
+
const unsubscribe = router.usePlugin(browserPluginFactory());
|
|
196
|
+
```
|
|
335
197
|
|
|
336
198
|
---
|
|
337
199
|
|
|
338
|
-
|
|
200
|
+
## Standalone API
|
|
339
201
|
|
|
340
|
-
|
|
202
|
+
Standalone functions provide domain-specific operations. They are tree-shakeable — only imported functions are bundled.
|
|
341
203
|
|
|
342
|
-
|
|
343
|
-
`name: string` — dependency name\
|
|
344
|
-
Returns: `unknown`\
|
|
345
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/getDependency)
|
|
204
|
+
### Routes — `getRoutesApi(router)`
|
|
346
205
|
|
|
347
|
-
|
|
206
|
+
Runtime route management. [Wiki](https://github.com/greydragon888/real-router/wiki/getRoutesApi)
|
|
348
207
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/getDependencies)
|
|
352
|
-
|
|
353
|
-
#### `router.setDependency(name: string, value: unknown): void`
|
|
208
|
+
```typescript
|
|
209
|
+
import { getRoutesApi } from "@real-router/core";
|
|
354
210
|
|
|
355
|
-
|
|
356
|
-
`name: string` — dependency name\
|
|
357
|
-
`value: unknown` — dependency value\
|
|
358
|
-
Returns: `void`\
|
|
359
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/setDependency)
|
|
211
|
+
const routes = getRoutesApi(router);
|
|
360
212
|
|
|
361
|
-
|
|
213
|
+
// Add routes
|
|
214
|
+
routes.add({ name: "settings", path: "/settings" });
|
|
215
|
+
routes.add({ name: "profile", path: "/:id" }, { parent: "users" });
|
|
362
216
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/setDependencies)
|
|
217
|
+
// Query
|
|
218
|
+
routes.has("users"); // true
|
|
219
|
+
routes.get("users"); // Route | undefined
|
|
367
220
|
|
|
368
|
-
|
|
221
|
+
// Modify
|
|
222
|
+
routes.update("users", { forwardTo: "users.list" });
|
|
223
|
+
routes.remove("settings");
|
|
224
|
+
routes.clear();
|
|
225
|
+
```
|
|
369
226
|
|
|
370
|
-
|
|
371
|
-
`name: string` — dependency name\
|
|
372
|
-
Returns: `boolean`\
|
|
373
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/hasDependency)
|
|
227
|
+
**Methods:** `add`, `remove`, `update`, `clear`, `has`, `get`, `getConfig`
|
|
374
228
|
|
|
375
|
-
|
|
229
|
+
### Dependencies — `getDependenciesApi(router)`
|
|
376
230
|
|
|
377
|
-
|
|
378
|
-
`name: string` — dependency name\
|
|
379
|
-
Returns: `void`\
|
|
380
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/removeDependency)
|
|
231
|
+
Dependency injection container. [Wiki](https://github.com/greydragon888/real-router/wiki/getDependenciesApi)
|
|
381
232
|
|
|
382
|
-
|
|
233
|
+
```typescript
|
|
234
|
+
import { getDependenciesApi } from "@real-router/core";
|
|
383
235
|
|
|
384
|
-
|
|
385
|
-
Returns: `void`\
|
|
386
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/resetDependencies)
|
|
236
|
+
const deps = getDependenciesApi(router);
|
|
387
237
|
|
|
388
|
-
|
|
238
|
+
deps.set("authService", authService);
|
|
239
|
+
deps.get("authService"); // authService
|
|
240
|
+
deps.has("authService"); // true
|
|
241
|
+
deps.getAll(); // { authService: ... }
|
|
242
|
+
deps.remove("authService");
|
|
243
|
+
deps.reset();
|
|
244
|
+
```
|
|
389
245
|
|
|
390
|
-
|
|
246
|
+
**Methods:** `get`, `getAll`, `set`, `setAll`, `remove`, `reset`, `has`
|
|
391
247
|
|
|
392
|
-
|
|
248
|
+
### Guards — `getLifecycleApi(router)`
|
|
393
249
|
|
|
394
|
-
|
|
395
|
-
Returns: `Options`\
|
|
396
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/getOptions)
|
|
250
|
+
Route activation/deactivation guards. [Wiki](https://github.com/greydragon888/real-router/wiki/getLifecycleApi)
|
|
397
251
|
|
|
398
|
-
|
|
252
|
+
```typescript
|
|
253
|
+
import { getLifecycleApi } from "@real-router/core";
|
|
399
254
|
|
|
400
|
-
|
|
255
|
+
const lifecycle = getLifecycleApi(router);
|
|
401
256
|
|
|
402
|
-
|
|
257
|
+
// Guard returns boolean or Promise<boolean> (true = allow, false = block)
|
|
258
|
+
lifecycle.addActivateGuard("admin", () => (toState, fromState) => {
|
|
259
|
+
return isAuthenticated(); // sync
|
|
260
|
+
});
|
|
403
261
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/clone)
|
|
262
|
+
lifecycle.addDeactivateGuard("editor", () => async (toState, fromState) => {
|
|
263
|
+
return !(await checkUnsavedChanges()); // async
|
|
264
|
+
});
|
|
408
265
|
|
|
409
|
-
|
|
266
|
+
// Guards receive AbortSignal for cooperative cancellation
|
|
267
|
+
lifecycle.addActivateGuard("dashboard", () => async (toState, fromState, signal) => {
|
|
268
|
+
const res = await fetch("/api/auth", { signal }); // auto-cancelled on abort
|
|
269
|
+
return res.ok;
|
|
270
|
+
});
|
|
410
271
|
|
|
411
|
-
|
|
272
|
+
// Remove guards
|
|
273
|
+
lifecycle.removeActivateGuard("admin");
|
|
274
|
+
lifecycle.removeDeactivateGuard("editor");
|
|
275
|
+
```
|
|
412
276
|
|
|
413
|
-
|
|
277
|
+
**Methods:** `addActivateGuard`, `addDeactivateGuard`, `removeActivateGuard`, `removeDeactivateGuard`
|
|
414
278
|
|
|
415
|
-
|
|
279
|
+
### Plugin Infrastructure — `getPluginApi(router)`
|
|
416
280
|
|
|
417
|
-
|
|
281
|
+
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
282
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
Returns: `State | undefined`\
|
|
422
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/matchPath)
|
|
283
|
+
```typescript
|
|
284
|
+
import { getPluginApi } from "@real-router/core";
|
|
423
285
|
|
|
424
|
-
|
|
286
|
+
const api = getPluginApi(router);
|
|
425
287
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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)
|
|
288
|
+
// State building
|
|
289
|
+
const state = api.matchPath("/users/123");
|
|
290
|
+
const builtState = api.makeState("users.profile", { id: "123" });
|
|
434
291
|
|
|
435
|
-
|
|
292
|
+
// Event system
|
|
293
|
+
const unsub = api.addEventListener(events.TRANSITION_START, (toState, fromState) => {
|
|
294
|
+
console.log("Starting:", toState.name);
|
|
295
|
+
});
|
|
436
296
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
`params?: Params` — route parameters\
|
|
440
|
-
Returns: `State | undefined`\
|
|
441
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/buildState)
|
|
297
|
+
// Navigation with pre-built state
|
|
298
|
+
await api.navigateToState(toState, fromState, opts);
|
|
442
299
|
|
|
443
|
-
|
|
300
|
+
// Root path management
|
|
301
|
+
api.setRootPath("/app");
|
|
302
|
+
api.getRootPath(); // "/app"
|
|
444
303
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
Returns: `{ name, params }` — resolved route name and merged params\
|
|
449
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/forwardState)
|
|
304
|
+
// Forward state interception (used by persistent-params-plugin)
|
|
305
|
+
api.setForwardState((name, params) => ({ name, params: withPersistent(params) }));
|
|
306
|
+
```
|
|
450
307
|
|
|
451
|
-
|
|
308
|
+
**Methods:** `makeState`, `buildState`, `buildNavigationState`, `forwardState`, `matchPath`, `setRootPath`, `getRootPath`, `navigateToState`, `addEventListener`, `getOptions`, `getTree`, `getForwardState`, `setForwardState`
|
|
452
309
|
|
|
453
|
-
|
|
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)
|
|
310
|
+
### SSR Cloning — `cloneRouter(router, deps?)`
|
|
461
311
|
|
|
462
|
-
|
|
312
|
+
Clone router for server-side rendering. [Wiki](https://github.com/greydragon888/real-router/wiki/cloneRouter)
|
|
463
313
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
Returns: `void`\
|
|
467
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/setRootPath)
|
|
314
|
+
```typescript
|
|
315
|
+
import { cloneRouter } from "@real-router/core";
|
|
468
316
|
|
|
469
|
-
|
|
317
|
+
// Server: clone router per request
|
|
318
|
+
const serverRouter = cloneRouter(router, { request: req });
|
|
319
|
+
await serverRouter.start(req.url);
|
|
320
|
+
```
|
|
470
321
|
|
|
471
|
-
|
|
472
|
-
Returns: `string`\
|
|
473
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/getRootPath)
|
|
322
|
+
Shares immutable route tree (O(1)), copies mutable state (dependencies, options, plugins, guards).
|
|
474
323
|
|
|
475
324
|
---
|
|
476
325
|
|
|
@@ -508,22 +357,25 @@ Navigation errors are instances of `RouterError`:
|
|
|
508
357
|
```typescript
|
|
509
358
|
import { RouterError, errorCodes } from "@real-router/core";
|
|
510
359
|
|
|
511
|
-
|
|
360
|
+
try {
|
|
361
|
+
await router.navigate("users");
|
|
362
|
+
} catch (err) {
|
|
512
363
|
if (err instanceof RouterError) {
|
|
513
364
|
console.log(err.code, err.message);
|
|
514
365
|
}
|
|
515
|
-
}
|
|
366
|
+
}
|
|
516
367
|
```
|
|
517
368
|
|
|
518
|
-
| Code
|
|
519
|
-
|
|
|
520
|
-
| `ROUTE_NOT_FOUND`
|
|
521
|
-
| `CANNOT_ACTIVATE`
|
|
522
|
-
| `CANNOT_DEACTIVATE`
|
|
523
|
-
| `CANCELLED`
|
|
524
|
-
| `SAME_STATES`
|
|
525
|
-
| `NOT_STARTED`
|
|
526
|
-
| `ALREADY_STARTED`
|
|
369
|
+
| Code | Description |
|
|
370
|
+
| --------------------- | ------------------------------ |
|
|
371
|
+
| `ROUTE_NOT_FOUND` | Route doesn't exist |
|
|
372
|
+
| `CANNOT_ACTIVATE` | Blocked by canActivate guard |
|
|
373
|
+
| `CANNOT_DEACTIVATE` | Blocked by canDeactivate guard |
|
|
374
|
+
| `CANCELLED` | Navigation was cancelled |
|
|
375
|
+
| `SAME_STATES` | Already at target route |
|
|
376
|
+
| `NOT_STARTED` | Router not started |
|
|
377
|
+
| `ALREADY_STARTED` | Router already started |
|
|
378
|
+
| `DISPOSED` | Router has been disposed |
|
|
527
379
|
|
|
528
380
|
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
381
|
|