@real-router/core 0.36.2 → 0.38.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 CHANGED
@@ -1,26 +1,25 @@
1
1
  # @real-router/core
2
2
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
3
+ [![npm](https://img.shields.io/npm/v/@real-router/core.svg?style=flat-square)](https://www.npmjs.com/package/@real-router/core)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@real-router/core.svg?style=flat-square)](https://www.npmjs.com/package/@real-router/core)
5
+ [![bundle size](https://deno.bundlejs.com/?q=@real-router/core&treeshake=[{createRouter}]&badge=detailed)](https://bundlejs.com/?q=@real-router/core&treeshake=[{createRouter}])
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](../../LICENSE)
5
7
 
6
- Core router implementation for Real-Router.
8
+ > Simple, powerful, view-agnostic, modular and extensible router for JavaScript applications.
9
+
10
+ This is the core package of the [Real-Router](https://github.com/greydragon888/real-router) monorepo. It provides the router implementation, lifecycle management, navigation pipeline, and tree-shakeable standalone API modules.
7
11
 
8
12
  ## Installation
9
13
 
10
14
  ```bash
11
15
  npm install @real-router/core
12
- # or
13
- pnpm add @real-router/core
14
- # or
15
- yarn add @real-router/core
16
- # or
17
- bun add @real-router/core
18
16
  ```
19
17
 
20
18
  ## Quick Start
21
19
 
22
20
  ```typescript
23
21
  import { createRouter } from "@real-router/core";
22
+ import { browserPluginFactory } from "@real-router/browser-plugin";
24
23
 
25
24
  const routes = [
26
25
  { name: "home", path: "/" },
@@ -32,213 +31,211 @@ const routes = [
32
31
  ];
33
32
 
34
33
  const router = createRouter(routes);
34
+ router.usePlugin(browserPluginFactory());
35
35
 
36
36
  await router.start("/");
37
37
  await router.navigate("users.profile", { id: "123" });
38
38
  ```
39
39
 
40
- ---
41
-
42
40
  ## Router API
43
41
 
44
- The Router class provides core lifecycle, navigation, state, and subscription methods.
45
- Domain-specific operations (routes, dependencies, guards, plugin infrastructure, cloning) are available through [standalone API functions](#standalone-api) for tree-shaking.
46
-
47
- ### `createRouter(routes?, options?, dependencies?)`
48
-
49
- Creates a new router instance. [Wiki](https://github.com/greydragon888/real-router/wiki/createRouter)
50
-
51
- ```typescript
52
- const router = createRouter(routes, options, dependencies);
53
- ```
54
-
55
- ---
56
-
57
42
  ### Lifecycle
58
43
 
59
- #### `router.start(path): Promise<State>`
60
-
61
- Starts the router with an initial path. [Wiki](https://github.com/greydragon888/real-router/wiki/start)
62
-
63
- #### `router.stop(): this`
64
-
65
- Stops the router. Cancels any in-progress transition. [Wiki](https://github.com/greydragon888/real-router/wiki/stop)
66
-
67
- #### `router.dispose(): void`
68
-
69
- Permanently terminates the router. Cannot be restarted. [Wiki](https://github.com/greydragon888/real-router/wiki/dispose)
70
-
71
- #### `router.isActive(): boolean`
72
-
73
- Returns whether the router is active. [Wiki](https://github.com/greydragon888/real-router/wiki/isActive)
74
-
75
- ---
44
+ | Method | Returns | Description |
45
+ | ------------- | ---------------- | ---------------------------------------------- |
46
+ | `start(path)` | `Promise<State>` | Start the router with an initial path |
47
+ | `stop()` | `this` | Stop the router, cancel in-progress transition |
48
+ | `dispose()` | `void` | Permanently terminate (cannot restart) |
49
+ | `isActive()` | `boolean` | Whether the router is started |
76
50
 
77
51
  ### Navigation
78
52
 
79
- #### `router.navigate(name, params?, options?): Promise<State>`
80
-
81
- Navigates to a route by name. Supports AbortController cancellation. Fire-and-forget safe. [Wiki](https://github.com/greydragon888/real-router/wiki/navigate)
53
+ | Method | Returns | Description |
54
+ | ----------------------------------- | ---------------- | ----------------------------------------- |
55
+ | `navigate(name, params?, options?)` | `Promise<State>` | Navigate to a route. Fire-and-forget safe |
56
+ | `navigateToDefault(options?)` | `Promise<State>` | Navigate to the default route |
57
+ | `navigateToNotFound(path?)` | `State` | Synchronously set UNKNOWN_ROUTE state |
58
+ | `canNavigateTo(name, params?)` | `boolean` | Check if guards allow navigation |
82
59
 
83
60
  ```typescript
84
61
  await router.navigate("users.profile", { id: "123" });
85
- await router.navigate("users", {}, { replace: true });
86
- ```
62
+ await router.navigate("dashboard", {}, { replace: true });
87
63
 
88
- #### `router.navigateToDefault(options?): Promise<State>`
89
-
90
- Navigates to the default route. [Wiki](https://github.com/greydragon888/real-router/wiki/navigateToDefault)
91
-
92
- #### `router.navigateToNotFound(path?): State`
93
-
94
- Synchronously sets the router to UNKNOWN_ROUTE state. Bypasses the transition pipeline. [Wiki](https://github.com/greydragon888/real-router/wiki/navigateToNotFound)
95
-
96
- #### `router.canNavigateTo(name, params?): boolean`
97
-
98
- Checks if navigation would be allowed by guards. [Wiki](https://github.com/greydragon888/real-router/wiki/canNavigateTo)
99
-
100
- ---
64
+ // Cancellable navigation
65
+ const controller = new AbortController();
66
+ router.navigate("users", {}, { signal: controller.signal });
67
+ controller.abort();
68
+ ```
101
69
 
102
70
  ### State
103
71
 
104
- #### `router.getState(): State | undefined`
105
-
106
- Returns the current router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getState)
107
-
108
- #### `router.getPreviousState(): State | undefined`
109
-
110
- Returns the previous router state. [Wiki](https://github.com/greydragon888/real-router/wiki/getPreviousState)
111
-
112
- #### `router.areStatesEqual(state1, state2, ignoreQueryParams?): boolean`
113
-
114
- Compare two states for equality. [Wiki](https://github.com/greydragon888/real-router/wiki/areStatesEqual)
115
-
116
- #### `router.shouldUpdateNode(nodeName): (toState, fromState?) => boolean`
117
-
118
- Create a predicate to check if a route node should update. [Wiki](https://github.com/greydragon888/real-router/wiki/shouldUpdateNode)
119
-
120
- ---
121
-
122
- ### Path Operations
123
-
124
- #### `router.buildPath(name, params?): string`
125
-
126
- Build URL path from route name. [Wiki](https://github.com/greydragon888/real-router/wiki/buildPath)
127
-
128
- #### `router.isActiveRoute(name, params?, strictEquality?, ignoreQueryParams?): boolean`
129
-
130
- Check if route is currently active. [Wiki](https://github.com/greydragon888/real-router/wiki/isActiveRoute)
72
+ | Method | Returns | Description |
73
+ | -------------------------------------------------- | -------------------- | ------------------------------------ |
74
+ | `getState()` | `State \| undefined` | Current router state (deeply frozen) |
75
+ | `getPreviousState()` | `State \| undefined` | Previous router state |
76
+ | `areStatesEqual(s1, s2, ignoreQP?)` | `boolean` | Compare two states |
77
+ | `isActiveRoute(name, params?, strict?, ignoreQP?)` | `boolean` | Check if route is active |
78
+ | `buildPath(name, params?)` | `string` | Build URL path from route name |
131
79
 
132
- ---
80
+ ### Events & Plugins
133
81
 
134
- ### Events
135
-
136
- #### `router.subscribe(listener): Unsubscribe`
137
-
138
- Subscribes to successful transitions. [Wiki](https://github.com/greydragon888/real-router/wiki/subscribe)
82
+ | Method | Returns | Description |
83
+ | ----------------------- | ------------- | -------------------------------- |
84
+ | `subscribe(listener)` | `Unsubscribe` | Listen to successful transitions |
85
+ | `usePlugin(...plugins)` | `Unsubscribe` | Register plugin factories |
139
86
 
140
87
  ```typescript
141
88
  const unsub = router.subscribe(({ route, previousRoute }) => {
142
- console.log(previousRoute?.name, "", route.name);
89
+ console.log(previousRoute?.name, "->", route.name);
143
90
  });
144
91
  ```
145
92
 
146
- ---
147
-
148
- ### Plugins
149
-
150
- #### `router.usePlugin(...plugins): Unsubscribe`
93
+ ## Standalone API
151
94
 
152
- Registers one or more plugins. [Wiki](https://github.com/greydragon888/real-router/wiki/usePlugin)
95
+ Tree-shakeable functions imported from `@real-router/core/api`. Only imported functions are bundled.
153
96
 
154
97
  ```typescript
155
- import { browserPluginFactory } from "@real-router/browser-plugin";
156
-
157
- router.usePlugin(browserPluginFactory());
98
+ import {
99
+ getRoutesApi,
100
+ getDependenciesApi,
101
+ getLifecycleApi,
102
+ getPluginApi,
103
+ cloneRouter,
104
+ } from "@real-router/core/api";
158
105
  ```
159
106
 
160
- ---
161
-
162
- ## Standalone API
163
-
164
- Tree-shakeable functions for domain-specific operations.
107
+ | Function | Purpose | Key methods |
108
+ | ---------------------------- | --------------------- | ---------------------------------------------------------------------------- |
109
+ | `getRoutesApi(router)` | Dynamic route CRUD | `add`, `remove`, `update`, `replace`, `has`, `get` |
110
+ | `getDependenciesApi(router)` | Dependency injection | `get`, `set`, `setAll`, `remove`, `has` |
111
+ | `getLifecycleApi(router)` | Guard registration | `addActivateGuard`, `addDeactivateGuard`, `remove*` |
112
+ | `getPluginApi(router)` | Plugin infrastructure | `makeState`, `matchPath`, `addInterceptor`, `extendRouter`, `getRouteConfig` |
113
+ | `cloneRouter(router, deps?)` | SSR cloning | Shares route definitions, independent state |
165
114
 
166
- ### `getRoutesApi(router)` — Route Management
115
+ ## Utilities
167
116
 
168
- Add, remove, replace, and query routes at runtime. [Wiki](https://github.com/greydragon888/real-router/wiki/getRoutesApi)
117
+ SSR helpers imported from `@real-router/core/utils`.
169
118
 
170
- **Methods:** `add`, `remove`, `replace`, `update`, `clear`, `has`, `get`, `getConfig`
171
-
172
- ### `getDependenciesApi(router)` — Dependencies
173
-
174
- Dependency injection container. [Wiki](https://github.com/greydragon888/real-router/wiki/getDependenciesApi)
175
-
176
- **Methods:** `get`, `getAll`, `set`, `setAll`, `remove`, `reset`, `has`
177
-
178
- ### `getLifecycleApi(router)` — Guards
179
-
180
- Route activation/deactivation guards. [Wiki](https://github.com/greydragon888/real-router/wiki/getLifecycleApi)
181
-
182
- **Methods:** `addActivateGuard`, `addDeactivateGuard`, `removeActivateGuard`, `removeDeactivateGuard`
183
-
184
- ### `getPluginApi(router)` — Plugin Infrastructure
119
+ ```typescript
120
+ import { serializeState } from "@real-router/core/utils";
185
121
 
186
- Low-level API for plugin authors. State building, path matching, event system, method interception, router extension. [Wiki](https://github.com/greydragon888/real-router/wiki/getPluginApi)
122
+ const json = serializeState({ name: "home", path: "/" });
123
+ const html = `<script>window.__STATE__=${json}</script>`;
124
+ ```
187
125
 
188
- **Methods:** `makeState`, `buildState`, `buildNavigationState`, `forwardState`, `matchPath`, `setRootPath`, `getRootPath`, `addEventListener`, `getOptions`, `getTree`, `addInterceptor`, `extendRouter`
126
+ | Function | Purpose |
127
+ | ---------------------- | ----------------------------------------------------------------- |
128
+ | `serializeState(data)` | XSS-safe JSON serialization for embedding in HTML `<script>` tags |
189
129
 
190
- ### `getNavigator(router)` Navigator
130
+ ### `getNavigator(router)` (main entry)
191
131
 
192
- Frozen subset of router methods for view layers. Pre-bound, safe to destructure. [Wiki](https://github.com/greydragon888/real-router/wiki/getNavigator)
132
+ Frozen read-only subset of router methods for view layers. Pre-bound, safe to destructure. Imported from `@real-router/core`, not `/api`.
193
133
 
194
- ### `cloneRouter(router, deps?)` — SSR Cloning
134
+ ```typescript
135
+ import { getNavigator } from "@real-router/core";
136
+ ```
195
137
 
196
- Clone router for server-side rendering. [Wiki](https://github.com/greydragon888/real-router/wiki/cloneRouter)
138
+ ```typescript
139
+ // Dynamic route management
140
+ const routes = getRoutesApi(router);
141
+ routes.add({ name: "settings", path: "/settings" });
142
+ routes.replace(newRoutes); // atomic HMR-safe replacement
143
+
144
+ // Dependency injection for guards and plugins
145
+ const deps = getDependenciesApi(router);
146
+ deps.set("authService", authService);
147
+
148
+ // Global lifecycle guards
149
+ const lifecycle = getLifecycleApi(router);
150
+ lifecycle.addActivateGuard("admin", (router, getDep) => (toState) => {
151
+ return getDep("authService").isAuthenticated();
152
+ });
197
153
 
198
- ---
154
+ // SSR — clone with request-scoped deps
155
+ const requestRouter = cloneRouter(router, { store: requestStore });
156
+ await requestRouter.start(req.url);
157
+ ```
199
158
 
200
- ## Configuration
159
+ ## Route Configuration
201
160
 
202
- See [RouterOptions](https://github.com/greydragon888/real-router/wiki/RouterOptions) for all available options.
161
+ ```typescript
162
+ import type { Route } from "@real-router/core";
203
163
 
204
- ---
164
+ const routes: Route[] = [
165
+ {
166
+ name: "admin",
167
+ path: "/admin",
168
+ canActivate: (router, getDep) => (toState, fromState, signal) => {
169
+ return getDep("authService").isAdmin();
170
+ },
171
+ children: [
172
+ {
173
+ name: "dashboard",
174
+ path: "/dashboard",
175
+ defaultParams: { tab: "overview" },
176
+ },
177
+ ],
178
+ },
179
+ {
180
+ name: "legacy",
181
+ path: "/old-path",
182
+ forwardTo: "home", // URL alias — guards on source are NOT executed
183
+ },
184
+ {
185
+ name: "product",
186
+ path: "/product/:id",
187
+ encodeParams: ({ id }) => ({ id: String(id) }),
188
+ decodeParams: ({ id }) => ({ id: Number(id) }),
189
+ },
190
+ ];
191
+ ```
205
192
 
206
193
  ## Error Handling
207
194
 
208
- Navigation errors are instances of `RouterError`. See [RouterError](https://github.com/greydragon888/real-router/wiki/RouterError) and [Error Codes](https://github.com/greydragon888/real-router/wiki/error-codes) for details.
209
-
210
- ---
211
-
212
- ## Observable Support
195
+ Navigation errors are instances of `RouterError` with typed error codes:
213
196
 
214
- > Observable API has been moved to `@real-router/rx` package for zero bundle cost.
215
- > See [@real-router/rx](../rx/README.md) for reactive stream APIs.
197
+ ```typescript
198
+ import { RouterError, errorCodes } from "@real-router/core";
199
+
200
+ try {
201
+ await router.navigate("admin");
202
+ } catch (err) {
203
+ if (err instanceof RouterError) {
204
+ // err.code: ROUTE_NOT_FOUND | CANNOT_ACTIVATE | CANNOT_DEACTIVATE
205
+ // | TRANSITION_CANCELLED | SAME_STATES | DISPOSED | ...
206
+ }
207
+ }
208
+ ```
216
209
 
217
- ---
210
+ See [RouterError](https://github.com/greydragon888/real-router/wiki/RouterError) and [Error Codes](https://github.com/greydragon888/real-router/wiki/error-codes) for the full reference.
218
211
 
219
212
  ## Documentation
220
213
 
221
- Full documentation available on the [Wiki](https://github.com/greydragon888/real-router/wiki):
214
+ Full documentation: [Wiki](https://github.com/greydragon888/real-router/wiki)
222
215
 
223
- - [Creating a Router](https://github.com/greydragon888/real-router/wiki/createRouter)
224
- - [Navigation](https://github.com/greydragon888/real-router/wiki/navigate)
225
- - [State](https://github.com/greydragon888/real-router/wiki/getState)
226
- - [Guards](https://github.com/greydragon888/real-router/wiki/getLifecycleApi)
227
- - [Plugins](https://github.com/greydragon888/real-router/wiki/usePlugin)
228
- - [Error Codes](https://github.com/greydragon888/real-router/wiki/error-codes)
216
+ - [Core Concepts](https://github.com/greydragon888/real-router/wiki/core-concepts) — overview and mental model
217
+ - [Defining Routes](https://github.com/greydragon888/real-router/wiki/Route) — nesting, path syntax, guards
218
+ - [Navigation Lifecycle](https://github.com/greydragon888/real-router/wiki/navigation-lifecycle) — transitions, guards, hooks
219
+ - [RouterOptions](https://github.com/greydragon888/real-router/wiki/RouterOptions) — `defaultRoute`, `trailingSlash`, `allowNotFound`, and more
220
+ - [Plugin Architecture](https://github.com/greydragon888/real-router/wiki/plugin-architecture) — interception, extension, events
229
221
  - [Migration from router5](https://github.com/greydragon888/real-router/wiki/migration-guide)
230
222
 
231
- ---
232
-
233
223
  ## Related Packages
234
224
 
235
- - [@real-router/react](https://www.npmjs.com/package/@real-router/react) — React integration
236
- - [@real-router/browser-plugin](https://www.npmjs.com/package/@real-router/browser-plugin) Browser history
237
- - [@real-router/hash-plugin](https://www.npmjs.com/package/@real-router/hash-plugin) Hash-based routing
238
- - [@real-router/logger-plugin](https://www.npmjs.com/package/@real-router/logger-plugin) Debug logging
239
- - [@real-router/persistent-params-plugin](https://www.npmjs.com/package/@real-router/persistent-params-plugin) Persistent params
240
- - [@real-router/route-utils](https://www.npmjs.com/package/@real-router/route-utils) Route tree queries and segment testing utilities
225
+ | Package | Description |
226
+ | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |
227
+ | [@real-router/react](https://www.npmjs.com/package/@real-router/react) | React integration (`RouterProvider`, hooks, `Link`, `RouteView`) |
228
+ | [@real-router/browser-plugin](https://www.npmjs.com/package/@real-router/browser-plugin) | Browser History API and URL synchronization |
229
+ | [@real-router/hash-plugin](https://www.npmjs.com/package/@real-router/hash-plugin) | Hash-based routing |
230
+ | [@real-router/rx](https://www.npmjs.com/package/@real-router/rx) | Observable API (`state$`, `events$`, TC39 Observable) |
231
+ | [@real-router/logger-plugin](https://www.npmjs.com/package/@real-router/logger-plugin) | Development logging |
232
+ | [@real-router/persistent-params-plugin](https://www.npmjs.com/package/@real-router/persistent-params-plugin) | Parameter persistence |
233
+ | [@real-router/route-utils](https://www.npmjs.com/package/@real-router/route-utils) | Route tree queries and segment testing |
234
+
235
+ ## Contributing
236
+
237
+ See [contributing guidelines](../../CONTRIBUTING.md) for development setup and PR process.
241
238
 
242
239
  ## License
243
240
 
244
- MIT © [Oleg Ivanov](https://github.com/greydragon888)
241
+ [MIT](../../LICENSE) © [Oleg Ivanov](https://github.com/greydragon888)