@real-router/core 0.45.1 → 0.45.2

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 (75) hide show
  1. package/package.json +7 -10
  2. package/src/Router.ts +684 -0
  3. package/src/RouterError.ts +324 -0
  4. package/src/api/cloneRouter.ts +77 -0
  5. package/src/api/getDependenciesApi.ts +168 -0
  6. package/src/api/getLifecycleApi.ts +65 -0
  7. package/src/api/getPluginApi.ts +167 -0
  8. package/src/api/getRoutesApi.ts +573 -0
  9. package/src/api/helpers.ts +10 -0
  10. package/src/api/index.ts +16 -0
  11. package/src/api/types.ts +12 -0
  12. package/src/constants.ts +87 -0
  13. package/src/createRouter.ts +32 -0
  14. package/src/fsm/index.ts +5 -0
  15. package/src/fsm/routerFSM.ts +120 -0
  16. package/src/getNavigator.ts +30 -0
  17. package/src/guards.ts +46 -0
  18. package/src/helpers.ts +179 -0
  19. package/src/index.ts +50 -0
  20. package/src/internals.ts +173 -0
  21. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +30 -0
  22. package/src/namespaces/DependenciesNamespace/index.ts +5 -0
  23. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +311 -0
  24. package/src/namespaces/EventBusNamespace/index.ts +5 -0
  25. package/src/namespaces/EventBusNamespace/types.ts +11 -0
  26. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +405 -0
  27. package/src/namespaces/NavigationNamespace/constants.ts +55 -0
  28. package/src/namespaces/NavigationNamespace/index.ts +5 -0
  29. package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +100 -0
  30. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +124 -0
  31. package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +221 -0
  32. package/src/namespaces/NavigationNamespace/types.ts +100 -0
  33. package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +28 -0
  34. package/src/namespaces/OptionsNamespace/constants.ts +19 -0
  35. package/src/namespaces/OptionsNamespace/helpers.ts +50 -0
  36. package/src/namespaces/OptionsNamespace/index.ts +7 -0
  37. package/src/namespaces/OptionsNamespace/validators.ts +13 -0
  38. package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +291 -0
  39. package/src/namespaces/PluginsNamespace/constants.ts +34 -0
  40. package/src/namespaces/PluginsNamespace/index.ts +7 -0
  41. package/src/namespaces/PluginsNamespace/types.ts +22 -0
  42. package/src/namespaces/PluginsNamespace/validators.ts +28 -0
  43. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +377 -0
  44. package/src/namespaces/RouteLifecycleNamespace/index.ts +5 -0
  45. package/src/namespaces/RouteLifecycleNamespace/types.ts +10 -0
  46. package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +81 -0
  47. package/src/namespaces/RouterLifecycleNamespace/constants.ts +25 -0
  48. package/src/namespaces/RouterLifecycleNamespace/index.ts +5 -0
  49. package/src/namespaces/RouterLifecycleNamespace/types.ts +26 -0
  50. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +535 -0
  51. package/src/namespaces/RoutesNamespace/constants.ts +6 -0
  52. package/src/namespaces/RoutesNamespace/forwardChain.ts +34 -0
  53. package/src/namespaces/RoutesNamespace/helpers.ts +126 -0
  54. package/src/namespaces/RoutesNamespace/index.ts +11 -0
  55. package/src/namespaces/RoutesNamespace/routeGuards.ts +62 -0
  56. package/src/namespaces/RoutesNamespace/routesStore.ts +346 -0
  57. package/src/namespaces/RoutesNamespace/types.ts +81 -0
  58. package/src/namespaces/StateNamespace/StateNamespace.ts +211 -0
  59. package/src/namespaces/StateNamespace/helpers.ts +24 -0
  60. package/src/namespaces/StateNamespace/index.ts +5 -0
  61. package/src/namespaces/StateNamespace/types.ts +15 -0
  62. package/src/namespaces/index.ts +35 -0
  63. package/src/stateMetaStore.ts +15 -0
  64. package/src/transitionPath.ts +436 -0
  65. package/src/typeGuards.ts +59 -0
  66. package/src/types/RouterValidator.ts +154 -0
  67. package/src/types.ts +69 -0
  68. package/src/utils/getStaticPaths.ts +50 -0
  69. package/src/utils/index.ts +5 -0
  70. package/src/utils/serializeState.ts +22 -0
  71. package/src/validation.ts +12 -0
  72. package/src/wiring/RouterWiringBuilder.ts +261 -0
  73. package/src/wiring/index.ts +7 -0
  74. package/src/wiring/types.ts +47 -0
  75. package/src/wiring/wireRouter.ts +26 -0
@@ -0,0 +1,311 @@
1
+ // packages/core/src/namespaces/EventBusNamespace/EventBusNamespace.ts
2
+
3
+ import { events } from "../../constants";
4
+ import { routerEvents, routerStates } from "../../fsm";
5
+
6
+ import type { EventBusOptions } from "./types";
7
+ import type { RouterEvent, RouterPayloads, RouterState } from "../../fsm";
8
+ import type { RouterError } from "../../RouterError";
9
+ import type { EventMethodMap, RouterEventMap } from "../../types";
10
+ import type { FSM } from "@real-router/fsm";
11
+ import type {
12
+ EventName,
13
+ LeaveFn,
14
+ NavigationOptions,
15
+ Plugin,
16
+ State,
17
+ SubscribeFn,
18
+ Unsubscribe,
19
+ } from "@real-router/types";
20
+ import type { EventEmitter } from "event-emitter";
21
+
22
+ export class EventBusNamespace {
23
+ readonly #fsm: FSM<RouterState, RouterEvent, null, RouterPayloads>;
24
+ readonly #emitter: EventEmitter<RouterEventMap>;
25
+
26
+ #currentToState: State | undefined;
27
+ #pendingToState: State | undefined;
28
+ #pendingFromState: State | undefined;
29
+ #pendingError: unknown;
30
+
31
+ constructor(options: EventBusOptions) {
32
+ this.#fsm = options.routerFSM;
33
+ this.#emitter = options.emitter;
34
+ this.#currentToState = undefined;
35
+ this.#setupFSMActions();
36
+ }
37
+
38
+ static validateSubscribeListener(listener: unknown): void {
39
+ if (typeof listener !== "function") {
40
+ throw new TypeError(
41
+ "[router.subscribe] Expected a function. " +
42
+ "For Observable pattern use @real-router/rx package",
43
+ );
44
+ }
45
+ }
46
+
47
+ static validateSubscribeLeaveListener(listener: unknown): void {
48
+ if (typeof listener !== "function") {
49
+ throw new TypeError("[router.subscribeLeave] Expected a function");
50
+ }
51
+ }
52
+
53
+ emitRouterStart(): void {
54
+ this.#emitter.emit(events.ROUTER_START);
55
+ }
56
+
57
+ emitRouterStop(): void {
58
+ this.#emitter.emit(events.ROUTER_STOP);
59
+ }
60
+
61
+ emitTransitionStart(toState: State, fromState?: State): void {
62
+ this.#emitter.emit(events.TRANSITION_START, toState, fromState);
63
+ }
64
+
65
+ emitTransitionSuccess(
66
+ toState: State,
67
+ fromState?: State,
68
+ opts?: NavigationOptions,
69
+ ): void {
70
+ this.#emitter.emit(events.TRANSITION_SUCCESS, toState, fromState, opts);
71
+ }
72
+
73
+ emitTransitionError(
74
+ toState?: State,
75
+ fromState?: State,
76
+ error?: RouterError,
77
+ ): void {
78
+ this.#emitter.emit(events.TRANSITION_ERROR, toState, fromState, error);
79
+ }
80
+
81
+ emitTransitionCancel(toState: State, fromState?: State): void {
82
+ this.#emitter.emit(events.TRANSITION_CANCEL, toState, fromState);
83
+ }
84
+
85
+ emitTransitionLeaveApprove(toState: State, fromState?: State): void {
86
+ this.#emitter.emit(events.TRANSITION_LEAVE_APPROVE, toState, fromState);
87
+ }
88
+
89
+ sendStart(): void {
90
+ this.#fsm.send(routerEvents.START);
91
+ }
92
+
93
+ sendStop(): void {
94
+ this.#fsm.send(routerEvents.STOP);
95
+ }
96
+
97
+ sendDispose(): void {
98
+ this.#fsm.send(routerEvents.DISPOSE);
99
+ }
100
+
101
+ sendStarted(): void {
102
+ this.#fsm.send(routerEvents.STARTED);
103
+ }
104
+
105
+ sendNavigate(toState: State, fromState?: State): void {
106
+ this.#currentToState = toState;
107
+ // Bypass FSM dispatch — forceState + direct emit (no action lookup, no rest params)
108
+ this.#fsm.forceState(routerStates.TRANSITION_STARTED);
109
+ this.emitTransitionStart(toState, fromState);
110
+ }
111
+
112
+ sendComplete(
113
+ state: State,
114
+ fromState?: State,
115
+ opts: NavigationOptions = {},
116
+ ): void {
117
+ // Bypass FSM dispatch — forceState + direct emit
118
+ this.#fsm.forceState(routerStates.READY);
119
+ this.emitTransitionSuccess(state, fromState, opts);
120
+
121
+ if (this.#currentToState === state) {
122
+ this.#currentToState = undefined;
123
+ }
124
+ }
125
+
126
+ sendLeaveApprove(toState: State, fromState?: State): void {
127
+ // Bypass FSM dispatch — forceState + direct emit (no action lookup, no rest params)
128
+ this.#fsm.forceState(routerStates.LEAVE_APPROVED);
129
+ this.emitTransitionLeaveApprove(toState, fromState);
130
+ }
131
+
132
+ sendFail(toState?: State, fromState?: State, error?: unknown): void {
133
+ const prev = this.#currentToState;
134
+
135
+ this.#pendingToState = toState;
136
+ this.#pendingFromState = fromState;
137
+ this.#pendingError = error;
138
+ this.#fsm.send(routerEvents.FAIL);
139
+
140
+ if (this.#currentToState === prev) {
141
+ this.#currentToState = undefined;
142
+ }
143
+ }
144
+
145
+ sendFailSafe(toState?: State, fromState?: State, error?: unknown): void {
146
+ if (this.isReady()) {
147
+ this.sendFail(toState, fromState, error);
148
+ } else {
149
+ this.emitTransitionError(toState, fromState, error as RouterError);
150
+ }
151
+ }
152
+
153
+ sendCancel(toState: State, fromState?: State): void {
154
+ const prev = this.#currentToState;
155
+
156
+ this.#pendingToState = toState;
157
+ this.#pendingFromState = fromState;
158
+ this.#fsm.send(routerEvents.CANCEL);
159
+
160
+ if (this.#currentToState === prev) {
161
+ this.#currentToState = undefined;
162
+ }
163
+ }
164
+
165
+ canBeginTransition(): boolean {
166
+ return this.#fsm.canSend(routerEvents.NAVIGATE);
167
+ }
168
+
169
+ canStart(): boolean {
170
+ return this.#fsm.canSend(routerEvents.START);
171
+ }
172
+
173
+ canCancel(): boolean {
174
+ return this.#fsm.canSend(routerEvents.CANCEL);
175
+ }
176
+
177
+ isActive(): boolean {
178
+ const fsmState = this.#fsm.getState();
179
+
180
+ return fsmState !== routerStates.IDLE && fsmState !== routerStates.DISPOSED;
181
+ }
182
+
183
+ isDisposed(): boolean {
184
+ return this.#fsm.getState() === routerStates.DISPOSED;
185
+ }
186
+
187
+ isTransitioning(): boolean {
188
+ const state = this.#fsm.getState();
189
+
190
+ return (
191
+ state === routerStates.TRANSITION_STARTED ||
192
+ state === routerStates.LEAVE_APPROVED
193
+ );
194
+ }
195
+
196
+ isLeaveApproved(): boolean {
197
+ return this.#fsm.getState() === routerStates.LEAVE_APPROVED;
198
+ }
199
+
200
+ isReady(): boolean {
201
+ return this.#fsm.getState() === routerStates.READY;
202
+ }
203
+
204
+ getCurrentToState(): State | undefined {
205
+ return this.#currentToState;
206
+ }
207
+
208
+ addEventListener<E extends EventName>(
209
+ eventName: E,
210
+ cb: Plugin[EventMethodMap[E]],
211
+ ): Unsubscribe {
212
+ return this.#emitter.on(
213
+ eventName,
214
+ cb as (...args: RouterEventMap[typeof eventName]) => void,
215
+ );
216
+ }
217
+
218
+ subscribe(listener: SubscribeFn): Unsubscribe {
219
+ return this.#emitter.on(
220
+ events.TRANSITION_SUCCESS,
221
+ (toState: State, fromState?: State) => {
222
+ listener({ route: toState, previousRoute: fromState });
223
+ },
224
+ );
225
+ }
226
+
227
+ subscribeLeave(listener: LeaveFn): Unsubscribe {
228
+ return this.#emitter.on(
229
+ events.TRANSITION_LEAVE_APPROVE,
230
+ (toState: State, fromState?: State) => {
231
+ if (fromState !== undefined) {
232
+ listener({ route: fromState, nextRoute: toState });
233
+ }
234
+ },
235
+ );
236
+ }
237
+
238
+ clearAll(): void {
239
+ this.#emitter.clearAll();
240
+ }
241
+
242
+ setLimits(limits: {
243
+ maxListeners: number;
244
+ warnListeners: number;
245
+ maxEventDepth: number;
246
+ }): void {
247
+ this.#emitter.setLimits(limits);
248
+ }
249
+
250
+ sendCancelIfPossible(fromState: State | undefined): void {
251
+ const toState = this.#currentToState;
252
+
253
+ if (!this.canCancel() || toState === undefined) {
254
+ return;
255
+ }
256
+
257
+ this.sendCancel(toState, fromState);
258
+ }
259
+
260
+ #emitPendingError(): void {
261
+ this.emitTransitionError(
262
+ this.#pendingToState,
263
+ this.#pendingFromState,
264
+ this.#pendingError as RouterError | undefined,
265
+ );
266
+ }
267
+
268
+ #setupFSMActions(): void {
269
+ const fsm = this.#fsm;
270
+
271
+ fsm.on(routerStates.STARTING, routerEvents.STARTED, () => {
272
+ this.emitRouterStart();
273
+ });
274
+
275
+ fsm.on(routerStates.READY, routerEvents.STOP, () => {
276
+ this.emitRouterStop();
277
+ });
278
+
279
+ // NAVIGATE and COMPLETE actions bypassed — sendNavigate/sendComplete
280
+ // use fsm.forceState() + direct emit for zero-allocation hot path.
281
+ const handleCancel = () => {
282
+ const toState = this.#pendingToState;
283
+
284
+ /* v8 ignore next -- @preserve: #pendingToState guaranteed set by sendCancel before send() */
285
+ if (toState === undefined) {
286
+ return;
287
+ }
288
+
289
+ this.emitTransitionCancel(toState, this.#pendingFromState);
290
+ };
291
+
292
+ fsm.on(routerStates.TRANSITION_STARTED, routerEvents.CANCEL, handleCancel);
293
+ fsm.on(routerStates.LEAVE_APPROVED, routerEvents.CANCEL, handleCancel);
294
+
295
+ fsm.on(routerStates.LEAVE_APPROVED, routerEvents.FAIL, () => {
296
+ this.#emitPendingError();
297
+ });
298
+
299
+ fsm.on(routerStates.STARTING, routerEvents.FAIL, () => {
300
+ this.#emitPendingError();
301
+ });
302
+
303
+ fsm.on(routerStates.READY, routerEvents.FAIL, () => {
304
+ this.#emitPendingError();
305
+ });
306
+
307
+ fsm.on(routerStates.TRANSITION_STARTED, routerEvents.FAIL, () => {
308
+ this.#emitPendingError();
309
+ });
310
+ }
311
+ }
@@ -0,0 +1,5 @@
1
+ // packages/core/src/namespaces/EventBusNamespace/index.ts
2
+
3
+ export { EventBusNamespace } from "./EventBusNamespace";
4
+
5
+ export type { EventBusOptions } from "./types";
@@ -0,0 +1,11 @@
1
+ // packages/core/src/namespaces/EventBusNamespace/types.ts
2
+
3
+ import type { RouterEvent, RouterPayloads, RouterState } from "../../fsm";
4
+ import type { RouterEventMap } from "../../types";
5
+ import type { FSM } from "@real-router/fsm";
6
+ import type { EventEmitter } from "event-emitter";
7
+
8
+ export interface EventBusOptions {
9
+ routerFSM: FSM<RouterState, RouterEvent, null, RouterPayloads>;
10
+ emitter: EventEmitter<RouterEventMap>;
11
+ }