@real-router/core 0.56.0 → 0.57.1

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 (112) hide show
  1. package/dist/cjs/Router-Brp6_4FE.js +6 -0
  2. package/dist/cjs/Router-Brp6_4FE.js.map +1 -0
  3. package/dist/cjs/api.d.ts +1 -1
  4. package/dist/cjs/api.js +1 -1
  5. package/dist/cjs/{cloneRouter-DRieJvam.js → cloneRouter-CZx0T0RQ.js} +2 -2
  6. package/dist/cjs/{cloneRouter-DRieJvam.js.map → cloneRouter-CZx0T0RQ.js.map} +1 -1
  7. package/dist/cjs/{index-C-i6vx5Y.d.ts → index-BWUmnecT.d.ts} +1 -2
  8. package/dist/cjs/index-BWUmnecT.d.ts.map +1 -0
  9. package/dist/cjs/index-CYpAZCoc.d.ts.map +1 -1
  10. package/dist/cjs/index.d.ts +1 -1
  11. package/dist/cjs/index.js +1 -1
  12. package/dist/cjs/utils.js +1 -1
  13. package/dist/cjs/utils.js.map +1 -1
  14. package/dist/cjs/validation.d.ts +1 -1
  15. package/dist/esm/Router-LT61erYH.mjs +6 -0
  16. package/dist/esm/Router-LT61erYH.mjs.map +1 -0
  17. package/dist/esm/api.d.mts +1 -1
  18. package/dist/esm/api.mjs +1 -1
  19. package/dist/esm/{cloneRouter-DHrH6D_z.mjs → cloneRouter-DAscsmmF.mjs} +2 -2
  20. package/dist/esm/{cloneRouter-DHrH6D_z.mjs.map → cloneRouter-DAscsmmF.mjs.map} +1 -1
  21. package/dist/esm/{index-C-i6vx5Y.d.mts → index-BWUmnecT.d.mts} +1 -2
  22. package/dist/esm/index-BWUmnecT.d.mts.map +1 -0
  23. package/dist/esm/index-CYpAZCoc.d.mts.map +1 -1
  24. package/dist/esm/index.d.mts +1 -1
  25. package/dist/esm/index.mjs +1 -1
  26. package/dist/esm/utils.mjs +1 -1
  27. package/dist/esm/utils.mjs.map +1 -1
  28. package/dist/esm/validation.d.mts +1 -1
  29. package/package.json +4 -5
  30. package/dist/cjs/Router-IEGavTKk.js +0 -6
  31. package/dist/cjs/Router-IEGavTKk.js.map +0 -1
  32. package/dist/cjs/index-C-i6vx5Y.d.ts.map +0 -1
  33. package/dist/esm/Router-B3aeavRb.mjs +0 -6
  34. package/dist/esm/Router-B3aeavRb.mjs.map +0 -1
  35. package/dist/esm/index-C-i6vx5Y.d.mts.map +0 -1
  36. package/src/Router.ts +0 -737
  37. package/src/RouterError.ts +0 -324
  38. package/src/api/cloneRouter.ts +0 -159
  39. package/src/api/getDependenciesApi.ts +0 -160
  40. package/src/api/getLifecycleApi.ts +0 -65
  41. package/src/api/getPluginApi.ts +0 -228
  42. package/src/api/getRoutesApi.ts +0 -831
  43. package/src/api/helpers.ts +0 -10
  44. package/src/api/index.ts +0 -16
  45. package/src/api/types.ts +0 -12
  46. package/src/constants.ts +0 -101
  47. package/src/createRouter.ts +0 -32
  48. package/src/fsm/index.ts +0 -5
  49. package/src/fsm/routerFSM.ts +0 -130
  50. package/src/getNavigator.ts +0 -30
  51. package/src/guards.ts +0 -46
  52. package/src/helpers.ts +0 -197
  53. package/src/index.ts +0 -66
  54. package/src/internals.ts +0 -228
  55. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +0 -30
  56. package/src/namespaces/DependenciesNamespace/index.ts +0 -5
  57. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +0 -522
  58. package/src/namespaces/EventBusNamespace/index.ts +0 -5
  59. package/src/namespaces/EventBusNamespace/types.ts +0 -11
  60. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -552
  61. package/src/namespaces/NavigationNamespace/constants.ts +0 -55
  62. package/src/namespaces/NavigationNamespace/index.ts +0 -5
  63. package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +0 -108
  64. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +0 -124
  65. package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +0 -283
  66. package/src/namespaces/NavigationNamespace/types.ts +0 -110
  67. package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +0 -28
  68. package/src/namespaces/OptionsNamespace/constants.ts +0 -19
  69. package/src/namespaces/OptionsNamespace/helpers.ts +0 -50
  70. package/src/namespaces/OptionsNamespace/index.ts +0 -7
  71. package/src/namespaces/OptionsNamespace/validators.ts +0 -13
  72. package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +0 -291
  73. package/src/namespaces/PluginsNamespace/constants.ts +0 -34
  74. package/src/namespaces/PluginsNamespace/index.ts +0 -7
  75. package/src/namespaces/PluginsNamespace/types.ts +0 -22
  76. package/src/namespaces/PluginsNamespace/validators.ts +0 -28
  77. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +0 -558
  78. package/src/namespaces/RouteLifecycleNamespace/index.ts +0 -5
  79. package/src/namespaces/RouteLifecycleNamespace/types.ts +0 -10
  80. package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -81
  81. package/src/namespaces/RouterLifecycleNamespace/constants.ts +0 -25
  82. package/src/namespaces/RouterLifecycleNamespace/index.ts +0 -5
  83. package/src/namespaces/RouterLifecycleNamespace/types.ts +0 -30
  84. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +0 -582
  85. package/src/namespaces/RoutesNamespace/constants.ts +0 -6
  86. package/src/namespaces/RoutesNamespace/forwardChain.ts +0 -34
  87. package/src/namespaces/RoutesNamespace/helpers.ts +0 -204
  88. package/src/namespaces/RoutesNamespace/index.ts +0 -11
  89. package/src/namespaces/RoutesNamespace/routeGuards.ts +0 -62
  90. package/src/namespaces/RoutesNamespace/routesStore.ts +0 -566
  91. package/src/namespaces/RoutesNamespace/types.ts +0 -81
  92. package/src/namespaces/StateNamespace/StateNamespace.ts +0 -224
  93. package/src/namespaces/StateNamespace/helpers.ts +0 -24
  94. package/src/namespaces/StateNamespace/index.ts +0 -5
  95. package/src/namespaces/StateNamespace/types.ts +0 -15
  96. package/src/namespaces/index.ts +0 -35
  97. package/src/stateMetaStore.ts +0 -15
  98. package/src/transitionPath.ts +0 -440
  99. package/src/typeGuards.ts +0 -59
  100. package/src/types/RouterValidator.ts +0 -156
  101. package/src/types.ts +0 -77
  102. package/src/utils/createRequestScope.ts +0 -174
  103. package/src/utils/getStaticPaths.ts +0 -50
  104. package/src/utils/hydrateRouter.ts +0 -89
  105. package/src/utils/index.ts +0 -27
  106. package/src/utils/serializeRouterState.ts +0 -120
  107. package/src/utils/serializeState.ts +0 -63
  108. package/src/validation.ts +0 -12
  109. package/src/wiring/RouterWiringBuilder.ts +0 -275
  110. package/src/wiring/index.ts +0 -7
  111. package/src/wiring/types.ts +0 -47
  112. package/src/wiring/wireRouter.ts +0 -26
@@ -1,522 +0,0 @@
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
- LeaveState,
15
- NavigationOptions,
16
- Plugin,
17
- State,
18
- SubscribeFn,
19
- TreeChangedEvent,
20
- Unsubscribe,
21
- } from "@real-router/types";
22
- import type { EventEmitter } from "event-emitter";
23
-
24
- /**
25
- * Internal-only event key for route-tree mutations. Lives on the same
26
- * `EventEmitter` as the 7 transition events but never enters the public
27
- * `EventName` union — reachable only through
28
- * `getRoutesApi(router).subscribeChanges()`.
29
- */
30
- const TREE_CHANGED = "TREE_CHANGED";
31
-
32
- function ensureError(value: unknown): Error {
33
- /* v8 ignore next -- @preserve: defensive guard — listeners should always throw Error objects */
34
- return value instanceof Error ? value : new Error(String(value));
35
- }
36
-
37
- function settleLeavePromises(
38
- promises: Promise<void>[],
39
- firstSyncError: unknown,
40
- signal: AbortSignal,
41
- ): Promise<void> {
42
- return new Promise<void>((resolve, reject) => {
43
- const onAbort = (): void => {
44
- reject(ensureError(signal.reason));
45
- };
46
-
47
- if (signal.aborted) {
48
- onAbort();
49
-
50
- return;
51
- }
52
-
53
- signal.addEventListener("abort", onAbort, { once: true });
54
-
55
- void Promise.allSettled(promises).then((results) => {
56
- signal.removeEventListener("abort", onAbort);
57
-
58
- if (signal.aborted) {
59
- // Race lost to abort — the abort handler already rejected; do nothing
60
- return;
61
- }
62
-
63
- if (firstSyncError !== undefined) {
64
- reject(ensureError(firstSyncError));
65
-
66
- return;
67
- }
68
-
69
- const rejected = results.find(
70
- (result): result is PromiseRejectedResult =>
71
- result.status === "rejected",
72
- );
73
-
74
- if (rejected !== undefined) {
75
- reject(ensureError(rejected.reason));
76
-
77
- return;
78
- }
79
-
80
- resolve();
81
- });
82
- });
83
- }
84
-
85
- export class EventBusNamespace {
86
- readonly #fsm: FSM<RouterState, RouterEvent, null, RouterPayloads>;
87
- readonly #emitter: EventEmitter<RouterEventMap>;
88
- readonly #leaveListeners: LeaveFn[] = [];
89
-
90
- #currentToState: State | undefined;
91
- #pendingToState: State | undefined;
92
- #pendingFromState: State | undefined;
93
- #pendingError: unknown;
94
-
95
- constructor(options: EventBusOptions) {
96
- this.#fsm = options.routerFSM;
97
- this.#emitter = options.emitter;
98
- this.#currentToState = undefined;
99
- this.#setupFSMActions();
100
- }
101
-
102
- static validateSubscribeListener(listener: unknown): void {
103
- if (typeof listener !== "function") {
104
- throw new TypeError(
105
- "[router.subscribe] Expected a function. " +
106
- "For Observable pattern use @real-router/rx package",
107
- );
108
- }
109
- }
110
-
111
- static validateSubscribeLeaveListener(listener: unknown): void {
112
- if (typeof listener !== "function") {
113
- throw new TypeError("[router.subscribeLeave] Expected a function");
114
- }
115
- }
116
-
117
- emitRouterStart(): void {
118
- this.#emitter.emit(events.ROUTER_START);
119
- }
120
-
121
- emitRouterStop(): void {
122
- this.#emitter.emit(events.ROUTER_STOP);
123
- }
124
-
125
- emitTransitionStart(toState: State, fromState?: State): void {
126
- this.#emitter.emit(events.TRANSITION_START, toState, fromState);
127
- }
128
-
129
- emitTransitionSuccess(
130
- toState: State,
131
- fromState?: State,
132
- opts?: NavigationOptions,
133
- ): void {
134
- this.#emitter.emit(events.TRANSITION_SUCCESS, toState, fromState, opts);
135
- }
136
-
137
- emitTransitionError(
138
- toState?: State,
139
- fromState?: State,
140
- error?: RouterError,
141
- ): void {
142
- this.#emitter.emit(events.TRANSITION_ERROR, toState, fromState, error);
143
- }
144
-
145
- emitTransitionCancel(toState: State, fromState?: State): void {
146
- this.#emitter.emit(events.TRANSITION_CANCEL, toState, fromState);
147
- }
148
-
149
- emitTransitionLeaveApprove(toState: State, fromState?: State): void {
150
- this.#emitter.emit(events.TRANSITION_LEAVE_APPROVE, toState, fromState);
151
- }
152
-
153
- /**
154
- * Emits the internal `TREE_CHANGED` event after a structural route-tree
155
- * mutation. Reuses the shared `EventEmitter` — so depth tracking
156
- * (`maxEventDepth`) and per-listener error isolation (`onListenerError`)
157
- * apply automatically.
158
- */
159
- emitTreeChanged(event: TreeChangedEvent): void {
160
- this.#emitter.emit(TREE_CHANGED, event);
161
- }
162
-
163
- /**
164
- * Subscribes to `TREE_CHANGED`. **Lenient** duplicate semantics (mirrors
165
- * {@link subscribe}): each call wraps the handler in a fresh closure, so N
166
- * registrations of the same reference produce N independent subscriptions.
167
- */
168
- subscribeTreeChanged(
169
- handler: (event: TreeChangedEvent) => void,
170
- ): Unsubscribe {
171
- return this.#emitter.on(TREE_CHANGED, (event: TreeChangedEvent) => {
172
- handler(event);
173
- });
174
- }
175
-
176
- /** Number of active `TREE_CHANGED` listeners (drives conditional emit). */
177
- treeChangedListenerCount(): number {
178
- return this.#emitter.listenerCount(TREE_CHANGED);
179
- }
180
-
181
- sendStart(): void {
182
- this.#fsm.send(routerEvents.START);
183
- }
184
-
185
- sendStop(): void {
186
- this.#fsm.send(routerEvents.STOP);
187
- }
188
-
189
- sendDispose(): void {
190
- this.#fsm.send(routerEvents.DISPOSE);
191
- }
192
-
193
- sendStarted(): void {
194
- this.#fsm.send(routerEvents.STARTED);
195
- }
196
-
197
- sendNavigate(toState: State, fromState?: State): void {
198
- this.#currentToState = toState;
199
- // Bypass FSM dispatch — forceState + direct emit (no action lookup, no rest params)
200
- this.#fsm.forceState(routerStates.TRANSITION_STARTED);
201
- this.emitTransitionStart(toState, fromState);
202
- }
203
-
204
- sendComplete(
205
- state: State,
206
- fromState?: State,
207
- opts: NavigationOptions = {},
208
- ): void {
209
- // Bypass FSM dispatch — forceState + direct emit
210
- this.#fsm.forceState(routerStates.READY);
211
- this.emitTransitionSuccess(state, fromState, opts);
212
-
213
- if (this.#currentToState === state) {
214
- this.#currentToState = undefined;
215
- }
216
- }
217
-
218
- sendLeaveApprove(toState: State, fromState?: State): void {
219
- // Bypass FSM dispatch — forceState + direct emit (no action lookup, no rest params)
220
- this.#fsm.forceState(routerStates.LEAVE_APPROVED);
221
- this.emitTransitionLeaveApprove(toState, fromState);
222
- }
223
-
224
- sendFail(toState?: State, fromState?: State, error?: unknown): void {
225
- const prev = this.#currentToState;
226
-
227
- this.#pendingToState = toState;
228
- this.#pendingFromState = fromState;
229
- this.#pendingError = error;
230
- this.#fsm.send(routerEvents.FAIL);
231
-
232
- if (this.#currentToState === prev) {
233
- this.#currentToState = undefined;
234
- }
235
- }
236
-
237
- sendFailSafe(toState?: State, fromState?: State, error?: unknown): void {
238
- if (this.isReady()) {
239
- this.sendFail(toState, fromState, error);
240
- } else {
241
- this.emitTransitionError(toState, fromState, error as RouterError);
242
- }
243
- }
244
-
245
- sendCancel(toState: State, fromState?: State): void {
246
- const prev = this.#currentToState;
247
-
248
- this.#pendingToState = toState;
249
- this.#pendingFromState = fromState;
250
- this.#fsm.send(routerEvents.CANCEL);
251
-
252
- if (this.#currentToState === prev) {
253
- this.#currentToState = undefined;
254
- }
255
- }
256
-
257
- canBeginTransition(): boolean {
258
- return this.#fsm.canSend(routerEvents.NAVIGATE);
259
- }
260
-
261
- canStart(): boolean {
262
- return this.#fsm.canSend(routerEvents.START);
263
- }
264
-
265
- canCancel(): boolean {
266
- return this.#fsm.canSend(routerEvents.CANCEL);
267
- }
268
-
269
- isActive(): boolean {
270
- const fsmState = this.#fsm.getState();
271
-
272
- return fsmState !== routerStates.IDLE && fsmState !== routerStates.DISPOSED;
273
- }
274
-
275
- isDisposed(): boolean {
276
- return this.#fsm.getState() === routerStates.DISPOSED;
277
- }
278
-
279
- isTransitioning(): boolean {
280
- const state = this.#fsm.getState();
281
-
282
- return (
283
- state === routerStates.TRANSITION_STARTED ||
284
- state === routerStates.LEAVE_APPROVED
285
- );
286
- }
287
-
288
- isLeaveApproved(): boolean {
289
- return this.#fsm.getState() === routerStates.LEAVE_APPROVED;
290
- }
291
-
292
- isReady(): boolean {
293
- return this.#fsm.getState() === routerStates.READY;
294
- }
295
-
296
- isStarting(): boolean {
297
- return this.#fsm.getState() === routerStates.STARTING;
298
- }
299
-
300
- getCurrentToState(): State | undefined {
301
- return this.#currentToState;
302
- }
303
-
304
- /**
305
- * Plugin-author API for subscribing to internal router events.
306
- *
307
- * @remarks
308
- *
309
- * **Duplicate-registration semantics — strict (throws).** Passing the same
310
- * callback reference twice for the same event throws
311
- * `Error("Duplicate listener for ...")` from the underlying `EventEmitter`.
312
- * This is loud-on-misuse by design: plugin code is expected to register
313
- * each callback once. The contract differs from {@link subscribe} /
314
- * {@link subscribeLeave}, which are end-user surfaces and silently accept
315
- * duplicates.
316
- */
317
- addEventListener<E extends EventName>(
318
- eventName: E,
319
- cb: Plugin[EventMethodMap[E]],
320
- ): Unsubscribe {
321
- return this.#emitter.on(
322
- eventName,
323
- cb as (...args: RouterEventMap[typeof eventName]) => void,
324
- );
325
- }
326
-
327
- /**
328
- * End-user / UI-binding API for subscribing to successful transitions.
329
- *
330
- * @remarks
331
- *
332
- * **Duplicate-registration semantics — independent.** Each call wraps
333
- * `listener` in a fresh closure and registers it as a distinct internal
334
- * slot. `router.subscribe(fn)` twice produces **two** active subscriptions;
335
- * `fn` fires twice per `TRANSITION_SUCCESS`. The returned `Unsubscribe` is
336
- * paired with its specific call — invoking it removes exactly that
337
- * registration.
338
- *
339
- * This contract differs from {@link addEventListener} (plugin API, throws
340
- * on duplicate). End-user code that wants idempotent registration must
341
- * gate itself, e.g. `if (!unsub) unsub = router.subscribe(fn);`.
342
- */
343
- subscribe(listener: SubscribeFn): Unsubscribe {
344
- return this.#emitter.on(
345
- events.TRANSITION_SUCCESS,
346
- (toState: State, fromState?: State) => {
347
- listener({ route: toState, previousRoute: fromState });
348
- },
349
- );
350
- }
351
-
352
- /**
353
- * End-user / UI-binding API for subscribing to confirmed route departures
354
- * (`LEAVE_APPROVED` phase). Async listeners block the activation phase.
355
- *
356
- * @remarks
357
- *
358
- * **Duplicate-registration semantics — independent (with internal quirk).**
359
- * Each call pushes `listener` onto the internal array; `router.subscribeLeave(fn)`
360
- * twice produces two array entries. `fn` fires **once** per leave when
361
- * iteration snapshots the array (a snapshot is taken on entry to
362
- * `awaitLeaveListeners`), but the function reference is invoked once per
363
- * array slot — so in practice the wrapper fires twice through the same
364
- * closure (no observable difference for stateless `fn`).
365
- *
366
- * The returned `Unsubscribe` removes the **first** array entry matching the
367
- * function reference (`indexOf` semantic), not the most recently added one.
368
- * Net effect of N subscribes + M unsubscribes is correct (N - M entries
369
- * remain), but the specific physical entry that survives is reverse of the
370
- * unsubscribe-call order. Irrelevant in practice — the function reference
371
- * is the same; observable behaviour is identical regardless of which
372
- * physical entry is removed.
373
- *
374
- * Contract differs from {@link addEventListener} (throws on duplicate).
375
- * For idempotent registration, gate at the call site.
376
- */
377
- subscribeLeave(listener: LeaveFn): Unsubscribe {
378
- this.#leaveListeners.push(listener);
379
-
380
- return () => {
381
- const idx = this.#leaveListeners.indexOf(listener);
382
-
383
- if (idx !== -1) {
384
- this.#leaveListeners.splice(idx, 1);
385
- }
386
- };
387
- }
388
-
389
- hasLeaveListeners(): boolean {
390
- return this.#leaveListeners.length > 0;
391
- }
392
-
393
- awaitLeaveListeners(
394
- toState: State,
395
- fromState: State | undefined,
396
- signal: AbortSignal,
397
- ): Promise<void> | undefined {
398
- if (fromState === undefined) {
399
- return undefined;
400
- }
401
-
402
- // Freeze the payload wrapper so listeners cannot mutate it (`payload.route`
403
- // is already deep-frozen via the State immutability invariant; this closes
404
- // the wrapper-mutation gap surfaced by audit `probe-05-payload-frozen`).
405
- const leaveState: LeaveState = Object.freeze({
406
- route: fromState,
407
- nextRoute: toState,
408
- signal,
409
- });
410
-
411
- let promises: Promise<void>[] | undefined;
412
- let firstSyncError: unknown;
413
-
414
- // Snapshot before iteration — a listener that reentrantly calls
415
- // `subscribeLeave(newFn)` or its own `unsubscribe()` must not affect the
416
- // current emit cycle. Symmetric with the EventEmitter snapshot invariant
417
- // (PR #666 / #659). Use `Array.from` rather than `[...array]` to keep the
418
- // intent explicit (some lint rules treat spread-of-own-array as
419
- // redundant and silently revert it).
420
- const snapshot = [...this.#leaveListeners];
421
-
422
- for (const listener of snapshot) {
423
- try {
424
- const result = listener(leaveState);
425
-
426
- if (result !== undefined && typeof result.then === "function") {
427
- promises ??= [];
428
- promises.push(result);
429
- }
430
- } catch (error: unknown) {
431
- if (firstSyncError === undefined) {
432
- firstSyncError = error;
433
- }
434
- }
435
- }
436
-
437
- if (promises === undefined) {
438
- if (firstSyncError !== undefined) {
439
- throw ensureError(firstSyncError);
440
- }
441
-
442
- return undefined;
443
- }
444
-
445
- return settleLeavePromises(promises, firstSyncError, signal);
446
- }
447
-
448
- clearAll(): void {
449
- this.#emitter.clearAll();
450
- this.#leaveListeners.length = 0;
451
- }
452
-
453
- setLimits(limits: {
454
- maxListeners: number;
455
- warnListeners: number;
456
- maxEventDepth: number;
457
- }): void {
458
- this.#emitter.setLimits(limits);
459
- }
460
-
461
- sendCancelIfPossible(fromState: State | undefined): void {
462
- const toState = this.#currentToState;
463
-
464
- if (!this.canCancel() || toState === undefined) {
465
- return;
466
- }
467
-
468
- this.sendCancel(toState, fromState);
469
- }
470
-
471
- #emitPendingError(): void {
472
- this.emitTransitionError(
473
- this.#pendingToState,
474
- this.#pendingFromState,
475
- this.#pendingError as RouterError | undefined,
476
- );
477
- }
478
-
479
- #setupFSMActions(): void {
480
- const fsm = this.#fsm;
481
-
482
- fsm.on(routerStates.STARTING, routerEvents.STARTED, () => {
483
- this.emitRouterStart();
484
- });
485
-
486
- fsm.on(routerStates.READY, routerEvents.STOP, () => {
487
- this.emitRouterStop();
488
- });
489
-
490
- // NAVIGATE and COMPLETE actions bypassed — sendNavigate/sendComplete
491
- // use fsm.forceState() + direct emit for zero-allocation hot path.
492
- const handleCancel = () => {
493
- const toState = this.#pendingToState;
494
-
495
- /* v8 ignore next -- @preserve: #pendingToState guaranteed set by sendCancel before send() */
496
- if (toState === undefined) {
497
- return;
498
- }
499
-
500
- this.emitTransitionCancel(toState, this.#pendingFromState);
501
- };
502
-
503
- fsm.on(routerStates.TRANSITION_STARTED, routerEvents.CANCEL, handleCancel);
504
- fsm.on(routerStates.LEAVE_APPROVED, routerEvents.CANCEL, handleCancel);
505
-
506
- fsm.on(routerStates.LEAVE_APPROVED, routerEvents.FAIL, () => {
507
- this.#emitPendingError();
508
- });
509
-
510
- fsm.on(routerStates.STARTING, routerEvents.FAIL, () => {
511
- this.#emitPendingError();
512
- });
513
-
514
- fsm.on(routerStates.READY, routerEvents.FAIL, () => {
515
- this.#emitPendingError();
516
- });
517
-
518
- fsm.on(routerStates.TRANSITION_STARTED, routerEvents.FAIL, () => {
519
- this.#emitPendingError();
520
- });
521
- }
522
- }
@@ -1,5 +0,0 @@
1
- // packages/core/src/namespaces/EventBusNamespace/index.ts
2
-
3
- export { EventBusNamespace } from "./EventBusNamespace";
4
-
5
- export type { EventBusOptions } from "./types";
@@ -1,11 +0,0 @@
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
- }