@hkdigital/lib-core 0.4.22 → 0.4.24

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 (30) hide show
  1. package/dist/auth/jwt/util.js +35 -41
  2. package/dist/network/loaders/audio/AudioScene.svelte.js +2 -2
  3. package/dist/network/loaders/image/ImageScene.svelte.js +18 -28
  4. package/dist/network/states/NetworkLoader.svelte.d.ts +1 -1
  5. package/dist/network/states/NetworkLoader.svelte.js +2 -2
  6. package/dist/services/README.md +23 -0
  7. package/dist/state/classes.d.ts +0 -2
  8. package/dist/state/classes.js +0 -2
  9. package/dist/state/{classes → machines}/finite-state-machine/FiniteStateMachine.svelte.d.ts +10 -0
  10. package/dist/state/{classes → machines}/finite-state-machine/FiniteStateMachine.svelte.js +19 -1
  11. package/dist/state/machines/finite-state-machine/README.md +545 -0
  12. package/dist/state/{classes → machines}/finite-state-machine/index.d.ts +1 -1
  13. package/dist/state/{classes → machines}/finite-state-machine/index.js +1 -1
  14. package/dist/state/machines/finite-state-machine/typedef.d.ts +29 -0
  15. package/dist/state/machines/finite-state-machine/typedef.js +28 -0
  16. package/dist/state/{classes → machines}/loading-state-machine/LoadingStateMachine.svelte.d.ts +0 -2
  17. package/dist/state/{classes → machines}/loading-state-machine/LoadingStateMachine.svelte.js +7 -27
  18. package/dist/state/machines/loading-state-machine/README.md +544 -0
  19. package/dist/state/machines/typedef.d.ts +1 -0
  20. package/dist/state/machines/typedef.js +1 -0
  21. package/dist/state/machines.d.ts +2 -0
  22. package/dist/state/machines.js +2 -0
  23. package/dist/state/typedef.d.ts +1 -0
  24. package/dist/state/typedef.js +1 -0
  25. package/dist/ui/components/game-box/README.md +245 -0
  26. package/package.json +1 -1
  27. /package/dist/state/{classes → machines}/loading-state-machine/constants.d.ts +0 -0
  28. /package/dist/state/{classes → machines}/loading-state-machine/constants.js +0 -0
  29. /package/dist/state/{classes → machines}/loading-state-machine/index.d.ts +0 -0
  30. /package/dist/state/{classes → machines}/loading-state-machine/index.js +0 -0
@@ -0,0 +1,545 @@
1
+ # FiniteStateMachine
2
+
3
+ A lightweight finite state machine implementation for JavaScript applications, designed to work seamlessly with Svelte 5 runes.
4
+
5
+ ## Overview
6
+
7
+ The `FiniteStateMachine` class provides a simple yet powerful way to manage application state through well-defined states and transitions. It supports enter/exit callbacks, event-driven transitions, and debounced events.
8
+
9
+ ## Basic Usage
10
+
11
+ ```javascript
12
+ import { FiniteStateMachine } from '$lib/state/classes.js';
13
+
14
+ const machine = new FiniteStateMachine('idle', {
15
+ idle: {
16
+ start: 'running'
17
+ },
18
+ running: {
19
+ pause: 'paused',
20
+ stop: 'idle'
21
+ },
22
+ paused: {
23
+ resume: 'running',
24
+ stop: 'idle'
25
+ }
26
+ });
27
+
28
+ // Check current state
29
+ console.log(machine.current); // 'idle'
30
+
31
+ // Send events to trigger transitions
32
+ machine.send('start');
33
+ console.log(machine.current); // 'running'
34
+
35
+ machine.send('pause');
36
+ console.log(machine.current); // 'paused'
37
+ ```
38
+
39
+ ## Constructor
40
+
41
+ ```javascript
42
+ new FiniteStateMachine(initialState, states)
43
+ ```
44
+
45
+ - `initialState`: The starting state (string)
46
+ - `states`: Object defining available states and their transitions
47
+
48
+ ## State Definition
49
+
50
+ Each state can define:
51
+
52
+ - **Transitions**: Event name → target state
53
+ - **Enter callback**: `_enter` function called when entering the state
54
+ - **Exit callback**: `_exit` function called when leaving the state
55
+
56
+ ```javascript
57
+ const machine = new FiniteStateMachine('idle', {
58
+ idle: {
59
+ _enter: (metadata) => {
60
+ console.log('Entered idle state');
61
+ },
62
+ _exit: (metadata) => {
63
+ console.log('Leaving idle state');
64
+ },
65
+ start: 'running'
66
+ },
67
+ running: {
68
+ _enter: (metadata) => {
69
+ console.log('Started running');
70
+ },
71
+ stop: 'idle'
72
+ }
73
+ });
74
+ ```
75
+
76
+ ## Callback Metadata
77
+
78
+ Enter and exit callbacks receive metadata about the transition:
79
+
80
+ ```javascript
81
+ /** @typedef {import('./typedef.js').StateTransitionMetadata} StateTransitionMetadata */
82
+
83
+ // Metadata structure:
84
+ {
85
+ from: 'previousState', // State being exited
86
+ to: 'newState', // State being entered
87
+ event: 'eventName', // Event that triggered transition
88
+ args: [] // Arguments passed to send()
89
+ }
90
+ ```
91
+
92
+ ### TypeScript/JSDoc Integration
93
+
94
+ For better type safety, import the type definitions:
95
+
96
+ ```javascript
97
+ /** @typedef {import('./typedef.js').StateTransitionMetadata} StateTransitionMetadata */
98
+ /** @typedef {import('./typedef.js').OnEnterCallback} OnEnterCallback */
99
+ /** @typedef {import('./typedef.js').OnExitCallback} OnExitCallback */
100
+
101
+ /** @type {OnEnterCallback} */
102
+ const handleEnter = (state, metadata) => {
103
+ console.log(`Entering ${state} from ${metadata.from}`);
104
+ };
105
+
106
+ /** @type {OnExitCallback} */
107
+ const handleExit = (state, metadata) => {
108
+ console.log(`Leaving ${state} to ${metadata.to}`);
109
+ };
110
+
111
+ machine.onenter = handleEnter;
112
+ machine.onexit = handleExit;
113
+ ```
114
+
115
+ ## Methods
116
+
117
+ ### `send(event, ...args)`
118
+
119
+ Triggers a state transition based on the event.
120
+
121
+ ```javascript
122
+ machine.send('start');
123
+ machine.send('error', new Error('Something went wrong'));
124
+ ```
125
+
126
+ Returns the current state after processing the event.
127
+
128
+ ### `debounce(wait, event, ...args)`
129
+
130
+ Debounces event sending to prevent rapid-fire transitions.
131
+
132
+ ```javascript
133
+ // Will only execute after 500ms of inactivity
134
+ await machine.debounce(500, 'search', query);
135
+ ```
136
+
137
+ ### `current` (getter)
138
+
139
+ Returns the current state as a string.
140
+
141
+ ```javascript
142
+ console.log(machine.current); // 'idle'
143
+ ```
144
+
145
+ ## Advanced Features
146
+
147
+ ### Wildcard States
148
+
149
+ Use `*` to define transitions available from any state:
150
+
151
+ ```javascript
152
+ const machine = new FiniteStateMachine('idle', {
153
+ idle: {
154
+ start: 'running'
155
+ },
156
+ running: {
157
+ pause: 'paused'
158
+ },
159
+ paused: {
160
+ resume: 'running'
161
+ },
162
+ '*': {
163
+ reset: 'idle', // Available from any state
164
+ error: 'error'
165
+ },
166
+ error: {
167
+ reset: 'idle'
168
+ }
169
+ });
170
+ ```
171
+
172
+ ### Same-State Transitions
173
+
174
+ Same-state transitions (e.g., `idle → idle`) do NOT trigger enter/exit
175
+ callbacks. The state remains unchanged.
176
+
177
+ ```javascript
178
+ machine.send('reset'); // If already in 'idle', no callbacks are called
179
+ ```
180
+
181
+ ### Function Actions
182
+
183
+ Instead of target states, you can define function actions:
184
+
185
+ ```javascript
186
+ const machine = new FiniteStateMachine('idle', {
187
+ idle: {
188
+ log: () => {
189
+ console.log('Logging from idle state');
190
+ return 'idle'; // Stay in same state
191
+ },
192
+ start: 'running'
193
+ },
194
+ running: {
195
+ stop: 'idle'
196
+ }
197
+ });
198
+ ```
199
+
200
+ ## onenter and onexit Callbacks
201
+
202
+ The `onenter` and `onexit` callbacks provide a unified way to react to all state changes, designed to work reliably with Svelte's reactivity system:
203
+
204
+ ```javascript
205
+ const machine = new FiniteStateMachine('idle', {
206
+ idle: { start: 'loading' },
207
+ loading: { complete: 'loaded', error: 'error' },
208
+ loaded: { reset: 'idle' },
209
+ error: { retry: 'loading', reset: 'idle' }
210
+ });
211
+
212
+ machine.onexit = (state, metadata) => {
213
+ switch (state) {
214
+ case 'loading':
215
+ console.log('Leaving loading state...');
216
+ // Cancel ongoing requests
217
+ abortController?.abort();
218
+ break;
219
+ case 'loaded':
220
+ console.log('Leaving loaded state...');
221
+ // Cleanup resources
222
+ releaseResources();
223
+ break;
224
+ }
225
+ };
226
+
227
+ machine.onenter = (state, metadata) => {
228
+ switch (state) {
229
+ case 'loading':
230
+ console.log('Started loading...');
231
+ showSpinner();
232
+ break;
233
+ case 'loaded':
234
+ console.log('Loading complete!');
235
+ hideSpinner();
236
+ break;
237
+ case 'error':
238
+ console.log('Loading failed');
239
+ showError(metadata.args[0]);
240
+ break;
241
+ }
242
+ };
243
+ ```
244
+
245
+ ### Callback Execution Order
246
+
247
+ The callbacks are executed in this specific order during state transitions:
248
+
249
+ 1. **`onexit`** - Called before leaving current state
250
+ 2. **`_exit`** - Individual state exit callback
251
+ 3. **`_enter`** - Individual state enter callback
252
+ 4. **`onenter`** - Called after entering new state
253
+
254
+ ```javascript
255
+ const machine = new FiniteStateMachine('idle', {
256
+ idle: {
257
+ _enter: () => console.log('2. idle _enter'),
258
+ _exit: () => console.log('4. idle _exit'),
259
+ start: 'loading'
260
+ },
261
+ loading: {
262
+ _enter: () => console.log('5. loading _enter'),
263
+ complete: 'loaded'
264
+ }
265
+ });
266
+
267
+ machine.onexit = (state) => console.log(`3. onexit ${state}`);
268
+ machine.onenter = (state) => console.log(`6. onenter ${state}`);
269
+
270
+ // Initial state triggers _enter and onenter
271
+ // Output:
272
+ // 2. idle _enter
273
+ // 6. onenter idle
274
+
275
+ machine.send('start');
276
+ // Output:
277
+ // 3. onexit idle
278
+ // 4. idle _exit
279
+ // 5. loading _enter
280
+ // 6. onenter loading
281
+ ```
282
+
283
+ ### onexit vs onenter
284
+
285
+ - **`onexit`**: Called when leaving a state - perfect for cleanup, cancellation, resource release
286
+ - **`onenter`**: Called when entering a state - perfect for initialization, setup, starting processes
287
+ - **`_exit`/`_enter`**: Individual per-state callbacks, called during transition
288
+ - **All callbacks are optional**: Set to null if not needed
289
+
290
+ ## Integration with Svelte Reactivity
291
+
292
+ When using FiniteStateMachine with Svelte's reactive derived state, use this pattern to avoid timing issues and ensure reliable state monitoring:
293
+
294
+ ### Pattern: Separate onenter from Reactive Monitoring
295
+
296
+ **✅ Use `onexit` and `onenter` for immediate state actions:**
297
+ ```javascript
298
+ const machine = new FiniteStateMachine('idle', {
299
+ idle: { start: 'loading' },
300
+ loading: { complete: 'loaded' },
301
+ loaded: { reset: 'idle' }
302
+ });
303
+
304
+ machine.onexit = (state) => {
305
+ switch (state) {
306
+ case 'loading':
307
+ this.#cancelProcess(); // Cancel ongoing operations
308
+ break;
309
+ case 'loaded':
310
+ this.#releaseResources(); // Cleanup when leaving
311
+ break;
312
+ }
313
+ };
314
+
315
+ machine.onenter = (state) => {
316
+ switch (state) {
317
+ case 'loading':
318
+ this.#startProcess(); // Start async process immediately
319
+ break;
320
+ case 'loaded':
321
+ this.#notifyComplete(); // Notify when complete
322
+ break;
323
+ }
324
+ this.state = state; // Update public state
325
+ };
326
+ ```
327
+
328
+ **✅ Use `$effect` for reactive state monitoring:**
329
+ ```javascript
330
+ // Monitor derived/computed values and trigger transitions when conditions are met
331
+ $effect(() => {
332
+ if (machine.current === 'loading') {
333
+ // Check completion based on reactive derived values
334
+ if (this.#itemsCompleted === this.#totalItems && this.#totalItems > 0) {
335
+ machine.send('complete'); // Trigger transition when condition met
336
+ }
337
+ }
338
+ });
339
+ ```
340
+
341
+ ### Why This Pattern?
342
+
343
+ - **`onexit`**: Handles cleanup and teardown when leaving states
344
+ - **`onenter`**: Handles setup and initialization when entering states
345
+ - **`$effect`**: Handles reactive monitoring of derived/computed values over time
346
+ - **Avoids timing issues**: Doesn't check completion status immediately on state entry
347
+ - **Leverages Svelte reactivity**: Automatically responds to changes in reactive variables
348
+ - **Clean separation**: State machine handles discrete transitions, effects handle continuous monitoring
349
+ - **Complete lifecycle**: Full control over state entry and exit
350
+
351
+ ### Use Cases for This Pattern:
352
+
353
+ - **Progress monitoring**: File uploads, multi-step processes
354
+ - **Derived state transitions**: Validation completion, multi-source loading
355
+ - **Real-time condition checking**: Monitoring reactive computed properties
356
+ - **Complex completion logic**: When completion depends on multiple reactive values
357
+
358
+ ### Example: Multi-Task Processor
359
+
360
+ ```javascript
361
+ export default class TaskProcessor {
362
+ #machine = new FiniteStateMachine('idle', {
363
+ idle: { start: 'processing' },
364
+ processing: { complete: 'finished', error: 'failed' },
365
+ finished: { reset: 'idle' },
366
+ failed: { retry: 'processing', reset: 'idle' }
367
+ });
368
+
369
+ #tasks = $state([]);
370
+
371
+ // Derived progress calculation
372
+ #progress = $derived.by(() => {
373
+ let completed = 0;
374
+ for (const task of this.#tasks) {
375
+ if (task.completed) completed++;
376
+ }
377
+ return { completed, total: this.#tasks.length };
378
+ });
379
+
380
+ constructor() {
381
+ // onexit: Handle cleanup when leaving states
382
+ this.#machine.onexit = (state) => {
383
+ switch (state) {
384
+ case 'processing':
385
+ this.#cancelTasks(); // Cancel ongoing tasks if interrupted
386
+ break;
387
+ }
388
+ };
389
+
390
+ // onenter: Handle immediate state actions
391
+ this.#machine.onenter = (state) => {
392
+ switch (state) {
393
+ case 'processing':
394
+ this.#startAllTasks(); // Start processing immediately
395
+ break;
396
+ case 'finished':
397
+ this.#notifyComplete(); // Cleanup/notify when done
398
+ break;
399
+ }
400
+ this.state = state;
401
+ };
402
+
403
+ // $effect: Monitor reactive completion
404
+ $effect(() => {
405
+ if (this.#machine.current === 'processing') {
406
+ const { completed, total } = this.#progress;
407
+ if (completed === total && total > 0) {
408
+ this.#machine.send('complete');
409
+ }
410
+ }
411
+ });
412
+ }
413
+ }
414
+ ```
415
+
416
+ ### Basic Component Integration
417
+
418
+ ```javascript
419
+ // Component.svelte
420
+ <script>
421
+ import { FiniteStateMachine } from '$lib/state/classes.js';
422
+
423
+ const machine = new FiniteStateMachine('idle', {
424
+ idle: { start: 'loading' },
425
+ loading: { complete: 'loaded', error: 'error' },
426
+ loaded: { reset: 'idle' },
427
+ error: { retry: 'loading', reset: 'idle' }
428
+ });
429
+
430
+ // Reactive state updates
431
+ $effect(() => {
432
+ console.log('State changed to:', machine.current);
433
+ });
434
+
435
+ // Handle state-specific actions
436
+ machine.onexit = (state) => {
437
+ switch (state) {
438
+ case 'loading':
439
+ // Cancel any ongoing requests
440
+ cancelRequests();
441
+ break;
442
+ }
443
+ };
444
+
445
+ machine.onenter = (state) => {
446
+ switch (state) {
447
+ case 'loading':
448
+ loadData();
449
+ break;
450
+ case 'error':
451
+ showErrorMessage();
452
+ break;
453
+ }
454
+ };
455
+ </script>
456
+
457
+ <button onclick={() => machine.send('start')}>
458
+ {machine.current === 'loading' ? 'Loading...' : 'Start'}
459
+ </button>
460
+ ```
461
+
462
+ ## Error Handling
463
+
464
+ Invalid transitions are handled gracefully with console warnings:
465
+
466
+ ```javascript
467
+ const machine = new FiniteStateMachine('idle', {
468
+ idle: { start: 'running' },
469
+ running: { stop: 'idle' }
470
+ });
471
+
472
+ machine.send('invalidEvent'); // Logs warning, stays in current state
473
+ console.log(machine.current); // Still 'idle'
474
+ ```
475
+
476
+ ## Best Practices
477
+
478
+ 1. **Clear state names**: Use descriptive state names like `loading`, `error`,
479
+ `authenticated` rather than generic ones
480
+ 2. **Minimal state count**: Keep the number of states manageable
481
+ 3. **Explicit transitions**: Define all valid transitions explicitly
482
+ 4. **Error states**: Include error states and recovery paths
483
+ 5. **Callback cleanup**: Use exit callbacks to clean up resources
484
+
485
+ ## Examples
486
+
487
+ ### Loading State Machine
488
+
489
+ ```javascript
490
+ const loader = new FiniteStateMachine('idle', {
491
+ idle: {
492
+ _enter: () => console.log('Ready to load'),
493
+ load: 'loading'
494
+ },
495
+ loading: {
496
+ _enter: () => console.log('Loading started'),
497
+ _exit: () => console.log('Loading finished'),
498
+ success: 'loaded',
499
+ error: 'error'
500
+ },
501
+ loaded: {
502
+ _enter: () => console.log('Data loaded successfully'),
503
+ reload: 'loading',
504
+ reset: 'idle'
505
+ },
506
+ error: {
507
+ _enter: ({ args }) => console.error('Load failed:', args[0]),
508
+ retry: 'loading',
509
+ reset: 'idle'
510
+ }
511
+ });
512
+ ```
513
+
514
+ ### Authentication State Machine
515
+
516
+ ```javascript
517
+ const auth = new FiniteStateMachine('anonymous', {
518
+ anonymous: {
519
+ login: 'authenticating'
520
+ },
521
+ authenticating: {
522
+ _enter: () => console.log('Checking credentials...'),
523
+ success: 'authenticated',
524
+ failure: 'anonymous'
525
+ },
526
+ authenticated: {
527
+ _enter: (meta) => console.log('Welcome!'),
528
+ logout: 'anonymous',
529
+ expire: 'anonymous'
530
+ }
531
+ });
532
+ ```
533
+
534
+ ## Testing
535
+
536
+ The state machine includes comprehensive tests covering:
537
+
538
+ - Basic state transitions
539
+ - Enter/exit callbacks
540
+ - Invalid transitions
541
+ - Same-state transitions
542
+ - Immediate state access
543
+ - Callback execution order
544
+
545
+ See `FiniteStateMachine.test.js` for detailed examples.
@@ -1 +1 @@
1
- export { default as FiniteStateMachine } from "./FiniteStateMachine.svelte";
1
+ export { default as FiniteStateMachine } from "./FiniteStateMachine.svelte.js";
@@ -1 +1 @@
1
- export { default as FiniteStateMachine } from './FiniteStateMachine.svelte';
1
+ export { default as FiniteStateMachine } from './FiniteStateMachine.svelte.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Metadata object passed to state transition callbacks
3
+ */
4
+ export type StateTransitionMetadata = {
5
+ /**
6
+ * - The state being exited
7
+ */
8
+ from: string;
9
+ /**
10
+ * - The state being entered
11
+ */
12
+ to: string;
13
+ /**
14
+ * - The event that triggered the transition
15
+ */
16
+ event: string;
17
+ /**
18
+ * - Arguments passed to the send() method
19
+ */
20
+ args: any[];
21
+ };
22
+ /**
23
+ * Callback function called when entering a state
24
+ */
25
+ export type OnEnterCallback = (arg0: string, arg1: StateTransitionMetadata) => void;
26
+ /**
27
+ * Callback function called when exiting a state
28
+ */
29
+ export type OnExitCallback = (arg0: string, arg1: StateTransitionMetadata) => void;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @fileoverview Type definitions for FiniteStateMachine
3
+ */
4
+
5
+ /**
6
+ * Metadata object passed to state transition callbacks
7
+ *
8
+ * @typedef {object} StateTransitionMetadata
9
+ * @property {string} from - The state being exited
10
+ * @property {string} to - The state being entered
11
+ * @property {string} event - The event that triggered the transition
12
+ * @property {any[]} args - Arguments passed to the send() method
13
+ */
14
+
15
+ /**
16
+ * Callback function called when entering a state
17
+ *
18
+ * @typedef {function(string, StateTransitionMetadata): void} OnEnterCallback
19
+ */
20
+
21
+ /**
22
+ * Callback function called when exiting a state
23
+ *
24
+ * @typedef {function(string, StateTransitionMetadata): void} OnExitCallback
25
+ */
26
+
27
+ // Export types for external use (this is just for JSDoc, no actual exports needed)
28
+ export {};
@@ -3,8 +3,6 @@
3
3
  */
4
4
  export default class LoadingStateMachine extends FiniteStateMachine {
5
5
  constructor();
6
- /** @type {(( state: string )=>void)|null} */
7
- onenter: ((state: string) => void) | null;
8
6
  /** The last error */
9
7
  get error(): Error;
10
8
  #private;
@@ -30,49 +30,31 @@ export default class LoadingStateMachine extends FiniteStateMachine {
30
30
  /** @type {Error|null} */
31
31
  #error = null;
32
32
 
33
- /** @type {(( state: string )=>void)|null} */
34
- onenter = null;
35
-
36
33
  constructor() {
37
- let superCalled = false;
38
34
  super(STATE_INITIAL, {
39
35
  [STATE_INITIAL]: {
40
- _enter: () => {
41
- if (superCalled) {
42
- this.onenter?.(STATE_INITIAL);
43
- }
44
- superCalled = true;
45
- },
46
36
  [LOAD]: STATE_LOADING
47
37
  },
48
38
  [STATE_LOADING]: {
49
- _enter: () => {
50
- // console.log('LoadingStateMachine: enter LOADING');
51
- this.onenter?.(STATE_LOADING);
52
- },
39
+ // _enter: () => {
40
+ // console.log('LoadingStateMachine: enter LOADING');
41
+ // },
53
42
  [CANCEL]: STATE_CANCELLED,
54
43
  [ERROR]: STATE_ERROR,
55
44
  [LOADED]: STATE_LOADED
56
45
  },
57
46
  [STATE_LOADED]: {
58
- _enter: () => {
59
- // console.log('LoadingStateMachine: enter LOADED');
60
- this.onenter?.(STATE_LOADED);
61
- },
47
+ // _enter: () => {
48
+ // console.log('LoadingStateMachine: enter LOADED');
49
+ // },
62
50
  [LOAD]: STATE_LOADING,
63
51
  [UNLOAD]: STATE_UNLOADING
64
52
  },
65
53
  [STATE_UNLOADING]: {
66
- _enter: () => {
67
- this.onenter?.(STATE_UNLOADING);
68
- },
69
54
  [ERROR]: STATE_ERROR,
70
55
  [INITIAL]: STATE_INITIAL
71
56
  },
72
57
  [STATE_CANCELLED]: {
73
- _enter: () => {
74
- this.onenter?.(STATE_CANCELLED);
75
- },
76
58
  [LOAD]: STATE_LOADING,
77
59
  [UNLOAD]: STATE_UNLOADING
78
60
  },
@@ -90,10 +72,8 @@ export default class LoadingStateMachine extends FiniteStateMachine {
90
72
  this.#error = new Error('The state machine entered STATE_ERROR');
91
73
  }
92
74
  }
93
-
94
- this.onenter?.(STATE_CANCELLED);
95
75
  },
96
- _leave: () => {
76
+ _exit: () => {
97
77
  this.#error = null;
98
78
  },
99
79
  [LOAD]: STATE_LOADING,