@hkdigital/lib-core 0.4.24 → 0.4.26
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/dist/logging/internal/adapters/pino.d.ts +7 -3
- package/dist/logging/internal/adapters/pino.js +200 -67
- package/dist/logging/internal/transports/pretty-transport.d.ts +17 -0
- package/dist/logging/internal/transports/pretty-transport.js +104 -0
- package/dist/logging/internal/transports/test-transport.d.ts +19 -0
- package/dist/logging/internal/transports/test-transport.js +79 -0
- package/dist/network/loaders/audio/AudioScene.svelte.d.ts +19 -10
- package/dist/network/loaders/audio/AudioScene.svelte.js +50 -75
- package/dist/network/loaders/image/ImageScene.svelte.d.ts +13 -13
- package/dist/network/loaders/image/ImageScene.svelte.js +56 -83
- package/dist/network/states/NetworkLoader.svelte.d.ts +6 -0
- package/dist/network/states/NetworkLoader.svelte.js +15 -6
- package/dist/services/service-base/ServiceBase.d.ts +12 -8
- package/dist/services/service-base/ServiceBase.js +8 -6
- package/dist/state/machines/finite-state-machine/FiniteStateMachine.svelte.d.ts +5 -9
- package/dist/state/machines/finite-state-machine/FiniteStateMachine.svelte.js +62 -32
- package/dist/state/machines/finite-state-machine/README.md +48 -46
- package/dist/state/machines/finite-state-machine/constants.d.ts +13 -0
- package/dist/state/machines/finite-state-machine/constants.js +15 -0
- package/dist/state/machines/finite-state-machine/index.d.ts +1 -0
- package/dist/state/machines/finite-state-machine/index.js +1 -0
- package/dist/state/machines/finite-state-machine/typedef.d.ts +3 -3
- package/dist/state/machines/finite-state-machine/typedef.js +21 -15
- package/dist/state/machines/loading-state-machine/LoadingStateMachine.svelte.d.ts +12 -0
- package/dist/state/machines/loading-state-machine/LoadingStateMachine.svelte.js +27 -2
- package/dist/state/machines/loading-state-machine/README.md +89 -41
- package/dist/state/machines/loading-state-machine/constants.d.ts +2 -0
- package/dist/state/machines/loading-state-machine/constants.js +2 -0
- package/package.json +1 -1
- package/dist/logging/internal/adapters/pino.js__ +0 -260
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* @see {@link https://runed.dev/docs/utilities/finite-state-machine}
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import { isTestEnv } from '../../../util/env.js';
|
|
8
|
+
import EventEmitter from '../../../generic/events/classes/EventEmitter.js';
|
|
9
|
+
import { ENTER, EXIT } from './constants.js';
|
|
10
|
+
|
|
11
|
+
/** @typedef {import('./typedef.js').TransitionData} TransitionData */
|
|
8
12
|
/** @typedef {import('./typedef.js').OnEnterCallback} OnEnterCallback */
|
|
9
13
|
/** @typedef {import('./typedef.js').OnExitCallback} OnExitCallback */
|
|
10
14
|
|
|
@@ -25,9 +29,9 @@ export function isLifecycleFnMeta(meta) {
|
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
/**
|
|
28
|
-
* Defines a Finite State Machine
|
|
32
|
+
* Defines a Finite State Machine that extends EventEmitter
|
|
29
33
|
*/
|
|
30
|
-
export default class FiniteStateMachine {
|
|
34
|
+
export default class FiniteStateMachine extends EventEmitter {
|
|
31
35
|
#current = $state();
|
|
32
36
|
states;
|
|
33
37
|
#timeout = {};
|
|
@@ -38,6 +42,9 @@ export default class FiniteStateMachine {
|
|
|
38
42
|
/** @type {OnExitCallback | null} */
|
|
39
43
|
onexit = null;
|
|
40
44
|
|
|
45
|
+
/** @type {boolean} */
|
|
46
|
+
#enableConsoleWarnings = !isTestEnv;
|
|
47
|
+
|
|
41
48
|
/**
|
|
42
49
|
* Constructor
|
|
43
50
|
*
|
|
@@ -45,16 +52,22 @@ export default class FiniteStateMachine {
|
|
|
45
52
|
* @param {{ [key: string]: { [key: string]: (string|((...args: any[])=>void)) } }} states
|
|
46
53
|
*/
|
|
47
54
|
constructor(initial, states) {
|
|
55
|
+
super();
|
|
48
56
|
this.#current = initial;
|
|
49
57
|
this.states = states;
|
|
50
58
|
|
|
51
59
|
// synthetically trigger _enter for the initial state.
|
|
52
|
-
|
|
60
|
+
const initialTransitionData = {
|
|
53
61
|
from: null,
|
|
54
62
|
to: initial,
|
|
55
63
|
event: null,
|
|
56
64
|
args: []
|
|
57
|
-
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
this.#executeAction('_enter', initialTransitionData);
|
|
68
|
+
|
|
69
|
+
// Emit ENTER event for external listeners for initial state
|
|
70
|
+
this.emit(ENTER, { state: initial, transition: initialTransitionData });
|
|
58
71
|
}
|
|
59
72
|
|
|
60
73
|
/**
|
|
@@ -65,50 +78,66 @@ export default class FiniteStateMachine {
|
|
|
65
78
|
* @param {any[]} [args]
|
|
66
79
|
*/
|
|
67
80
|
#transition(newState, event, args) {
|
|
68
|
-
/** @type {
|
|
69
|
-
const
|
|
81
|
+
/** @type {TransitionData} */
|
|
82
|
+
const transition = { from: this.#current, to: newState, event, args };
|
|
70
83
|
|
|
71
84
|
// Call onexit callback before leaving current state
|
|
72
|
-
this.onexit?.(this.#current,
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
this.onexit?.(this.#current, transition);
|
|
86
|
+
|
|
87
|
+
// Emit EXIT event for external listeners
|
|
88
|
+
this.emit(EXIT, { state: this.#current, transition });
|
|
89
|
+
|
|
90
|
+
this.#executeAction('_exit', transition);
|
|
75
91
|
this.#current = newState;
|
|
76
|
-
this.#
|
|
77
|
-
|
|
92
|
+
this.#executeAction('_enter', transition);
|
|
93
|
+
|
|
94
|
+
// Emit ENTER event for external listeners
|
|
95
|
+
this.emit(ENTER, { state: newState, transition });
|
|
96
|
+
|
|
78
97
|
// Call onenter callback after state change
|
|
79
|
-
this.onenter?.(newState,
|
|
98
|
+
this.onenter?.(newState, transition);
|
|
80
99
|
}
|
|
81
100
|
|
|
82
101
|
/**
|
|
83
|
-
*
|
|
102
|
+
* Execute an action for the given event
|
|
84
103
|
*
|
|
85
104
|
* @param {string} event
|
|
86
105
|
* @param {any} args
|
|
87
106
|
*/
|
|
88
|
-
#
|
|
107
|
+
#executeAction(event, ...args) {
|
|
89
108
|
const action =
|
|
90
109
|
this.states[this.#current]?.[event] ?? this.states['*']?.[event];
|
|
110
|
+
|
|
91
111
|
if (action instanceof Function) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
switch (event) {
|
|
113
|
+
// Internal lifecycle events
|
|
114
|
+
case ENTER:
|
|
115
|
+
case EXIT:
|
|
116
|
+
if (isLifecycleFnMeta(args[0])) {
|
|
117
|
+
return action(args[0]);
|
|
118
|
+
} else {
|
|
119
|
+
throw new Error(`Invalid transition data passed to lifecycle function`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Normal state events
|
|
123
|
+
default:
|
|
124
|
+
return action(...args);
|
|
125
|
+
}
|
|
126
|
+
} else if (typeof action === 'string') {
|
|
127
|
+
// No function execution => just return target state
|
|
128
|
+
return action;
|
|
129
|
+
} else {
|
|
130
|
+
// No action found - only warn for non-lifecycle events
|
|
131
|
+
if (event !== ENTER && event !== EXIT) {
|
|
132
|
+
if (this.#enableConsoleWarnings) {
|
|
96
133
|
console.warn(
|
|
97
|
-
'
|
|
134
|
+
'No action defined for event',
|
|
135
|
+
event,
|
|
136
|
+
'in state',
|
|
137
|
+
this.#current
|
|
98
138
|
);
|
|
99
139
|
}
|
|
100
|
-
} else {
|
|
101
|
-
return action(...args);
|
|
102
140
|
}
|
|
103
|
-
} else if (typeof action === 'string') {
|
|
104
|
-
return action;
|
|
105
|
-
} else if (event !== '_enter' && event !== '_exit') {
|
|
106
|
-
console.warn(
|
|
107
|
-
'No action defined for event',
|
|
108
|
-
event,
|
|
109
|
-
'in state',
|
|
110
|
-
this.#current
|
|
111
|
-
);
|
|
112
141
|
}
|
|
113
142
|
}
|
|
114
143
|
/**
|
|
@@ -118,7 +147,8 @@ export default class FiniteStateMachine {
|
|
|
118
147
|
* @param {any[]} args
|
|
119
148
|
*/
|
|
120
149
|
send(event, ...args) {
|
|
121
|
-
const newState = this.#
|
|
150
|
+
const newState = this.#executeAction(event, ...args);
|
|
151
|
+
|
|
122
152
|
if (newState && newState !== this.#current) {
|
|
123
153
|
this.#transition(newState, event, args);
|
|
124
154
|
}
|
|
@@ -39,7 +39,7 @@ console.log(machine.current); // 'paused'
|
|
|
39
39
|
## Constructor
|
|
40
40
|
|
|
41
41
|
```javascript
|
|
42
|
-
new FiniteStateMachine(initialState, states)
|
|
42
|
+
new FiniteStateMachine(initialState, states);
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
- `initialState`: The starting state (string)
|
|
@@ -56,16 +56,16 @@ Each state can define:
|
|
|
56
56
|
```javascript
|
|
57
57
|
const machine = new FiniteStateMachine('idle', {
|
|
58
58
|
idle: {
|
|
59
|
-
_enter: (
|
|
59
|
+
_enter: (transition) => {
|
|
60
60
|
console.log('Entered idle state');
|
|
61
61
|
},
|
|
62
|
-
_exit: (
|
|
62
|
+
_exit: (transition) => {
|
|
63
63
|
console.log('Leaving idle state');
|
|
64
64
|
},
|
|
65
65
|
start: 'running'
|
|
66
66
|
},
|
|
67
67
|
running: {
|
|
68
|
-
_enter: (
|
|
68
|
+
_enter: (transition) => {
|
|
69
69
|
console.log('Started running');
|
|
70
70
|
},
|
|
71
71
|
stop: 'idle'
|
|
@@ -73,14 +73,14 @@ const machine = new FiniteStateMachine('idle', {
|
|
|
73
73
|
});
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
## Callback
|
|
76
|
+
## Callback TransitionData
|
|
77
77
|
|
|
78
|
-
Enter and exit callbacks receive
|
|
78
|
+
Enter and exit callbacks receive transition data about the state change:
|
|
79
79
|
|
|
80
80
|
```javascript
|
|
81
|
-
/** @typedef {import('./typedef.js').
|
|
81
|
+
/** @typedef {import('./typedef.js').TransitionData} TransitionData */
|
|
82
82
|
|
|
83
|
-
//
|
|
83
|
+
// TransitionData structure:
|
|
84
84
|
{
|
|
85
85
|
from: 'previousState', // State being exited
|
|
86
86
|
to: 'newState', // State being entered
|
|
@@ -94,18 +94,18 @@ Enter and exit callbacks receive metadata about the transition:
|
|
|
94
94
|
For better type safety, import the type definitions:
|
|
95
95
|
|
|
96
96
|
```javascript
|
|
97
|
-
/** @typedef {import('./typedef.js').
|
|
97
|
+
/** @typedef {import('./typedef.js').TransitionData} TransitionData */
|
|
98
98
|
/** @typedef {import('./typedef.js').OnEnterCallback} OnEnterCallback */
|
|
99
99
|
/** @typedef {import('./typedef.js').OnExitCallback} OnExitCallback */
|
|
100
100
|
|
|
101
101
|
/** @type {OnEnterCallback} */
|
|
102
|
-
const handleEnter = (
|
|
103
|
-
console.log(`Entering ${
|
|
102
|
+
const handleEnter = (currentState, transition) => {
|
|
103
|
+
console.log(`Entering ${currentState} from ${transition.from}`);
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
/** @type {OnExitCallback} */
|
|
107
|
-
const handleExit = (
|
|
108
|
-
console.log(`Leaving ${
|
|
107
|
+
const handleExit = (currentState, transition) => {
|
|
108
|
+
console.log(`Leaving ${currentState} to ${transition.to}`);
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
machine.onenter = handleEnter;
|
|
@@ -160,7 +160,7 @@ const machine = new FiniteStateMachine('idle', {
|
|
|
160
160
|
resume: 'running'
|
|
161
161
|
},
|
|
162
162
|
'*': {
|
|
163
|
-
reset: 'idle',
|
|
163
|
+
reset: 'idle', // Available from any state
|
|
164
164
|
error: 'error'
|
|
165
165
|
},
|
|
166
166
|
error: {
|
|
@@ -171,7 +171,7 @@ const machine = new FiniteStateMachine('idle', {
|
|
|
171
171
|
|
|
172
172
|
### Same-State Transitions
|
|
173
173
|
|
|
174
|
-
Same-state transitions (e.g., `idle → idle`) do NOT trigger enter/exit
|
|
174
|
+
Same-state transitions (e.g., `idle → idle`) do NOT trigger enter/exit
|
|
175
175
|
callbacks. The state remains unchanged.
|
|
176
176
|
|
|
177
177
|
```javascript
|
|
@@ -209,8 +209,8 @@ const machine = new FiniteStateMachine('idle', {
|
|
|
209
209
|
error: { retry: 'loading', reset: 'idle' }
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
-
machine.onexit = (
|
|
213
|
-
switch (
|
|
212
|
+
machine.onexit = (currentState, transition) => {
|
|
213
|
+
switch (currentState) {
|
|
214
214
|
case 'loading':
|
|
215
215
|
console.log('Leaving loading state...');
|
|
216
216
|
// Cancel ongoing requests
|
|
@@ -224,8 +224,8 @@ machine.onexit = (state, metadata) => {
|
|
|
224
224
|
}
|
|
225
225
|
};
|
|
226
226
|
|
|
227
|
-
machine.onenter = (
|
|
228
|
-
switch (
|
|
227
|
+
machine.onenter = (currentState, transition) => {
|
|
228
|
+
switch (currentState) {
|
|
229
229
|
case 'loading':
|
|
230
230
|
console.log('Started loading...');
|
|
231
231
|
showSpinner();
|
|
@@ -236,7 +236,7 @@ machine.onenter = (state, metadata) => {
|
|
|
236
236
|
break;
|
|
237
237
|
case 'error':
|
|
238
238
|
console.log('Loading failed');
|
|
239
|
-
showError(
|
|
239
|
+
showError(transition.args[0]);
|
|
240
240
|
break;
|
|
241
241
|
}
|
|
242
242
|
};
|
|
@@ -247,7 +247,7 @@ machine.onenter = (state, metadata) => {
|
|
|
247
247
|
The callbacks are executed in this specific order during state transitions:
|
|
248
248
|
|
|
249
249
|
1. **`onexit`** - Called before leaving current state
|
|
250
|
-
2. **`_exit`** - Individual state exit callback
|
|
250
|
+
2. **`_exit`** - Individual state exit callback
|
|
251
251
|
3. **`_enter`** - Individual state enter callback
|
|
252
252
|
4. **`onenter`** - Called after entering new state
|
|
253
253
|
|
|
@@ -264,11 +264,11 @@ const machine = new FiniteStateMachine('idle', {
|
|
|
264
264
|
}
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
-
machine.onexit = (
|
|
268
|
-
machine.onenter = (
|
|
267
|
+
machine.onexit = (currentState) => console.log(`3. onexit ${currentState}`);
|
|
268
|
+
machine.onenter = (currentState) => console.log(`6. onenter ${currentState}`);
|
|
269
269
|
|
|
270
270
|
// Initial state triggers _enter and onenter
|
|
271
|
-
// Output:
|
|
271
|
+
// Output:
|
|
272
272
|
// 2. idle _enter
|
|
273
273
|
// 6. onenter idle
|
|
274
274
|
|
|
@@ -276,7 +276,7 @@ machine.send('start');
|
|
|
276
276
|
// Output:
|
|
277
277
|
// 3. onexit idle
|
|
278
278
|
// 4. idle _exit
|
|
279
|
-
// 5. loading _enter
|
|
279
|
+
// 5. loading _enter
|
|
280
280
|
// 6. onenter loading
|
|
281
281
|
```
|
|
282
282
|
|
|
@@ -294,6 +294,7 @@ When using FiniteStateMachine with Svelte's reactive derived state, use this pat
|
|
|
294
294
|
### Pattern: Separate onenter from Reactive Monitoring
|
|
295
295
|
|
|
296
296
|
**✅ Use `onexit` and `onenter` for immediate state actions:**
|
|
297
|
+
|
|
297
298
|
```javascript
|
|
298
299
|
const machine = new FiniteStateMachine('idle', {
|
|
299
300
|
idle: { start: 'loading' },
|
|
@@ -312,8 +313,8 @@ machine.onexit = (state) => {
|
|
|
312
313
|
}
|
|
313
314
|
};
|
|
314
315
|
|
|
315
|
-
machine.onenter = (
|
|
316
|
-
switch (
|
|
316
|
+
machine.onenter = (label) => {
|
|
317
|
+
switch (label) {
|
|
317
318
|
case 'loading':
|
|
318
319
|
this.#startProcess(); // Start async process immediately
|
|
319
320
|
break;
|
|
@@ -326,6 +327,7 @@ machine.onenter = (state) => {
|
|
|
326
327
|
```
|
|
327
328
|
|
|
328
329
|
**✅ Use `$effect` for reactive state monitoring:**
|
|
330
|
+
|
|
329
331
|
```javascript
|
|
330
332
|
// Monitor derived/computed values and trigger transitions when conditions are met
|
|
331
333
|
$effect(() => {
|
|
@@ -341,8 +343,8 @@ $effect(() => {
|
|
|
341
343
|
### Why This Pattern?
|
|
342
344
|
|
|
343
345
|
- **`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
|
+
- **`onenter`**: Handles setup and initialization when entering states
|
|
347
|
+
- **`$effect`**: Handles reactive monitoring of derived/computed values over time
|
|
346
348
|
- **Avoids timing issues**: Doesn't check completion status immediately on state entry
|
|
347
349
|
- **Leverages Svelte reactivity**: Automatically responds to changes in reactive variables
|
|
348
350
|
- **Clean separation**: State machine handles discrete transitions, effects handle continuous monitoring
|
|
@@ -365,9 +367,9 @@ export default class TaskProcessor {
|
|
|
365
367
|
finished: { reset: 'idle' },
|
|
366
368
|
failed: { retry: 'processing', reset: 'idle' }
|
|
367
369
|
});
|
|
368
|
-
|
|
370
|
+
|
|
369
371
|
#tasks = $state([]);
|
|
370
|
-
|
|
372
|
+
|
|
371
373
|
// Derived progress calculation
|
|
372
374
|
#progress = $derived.by(() => {
|
|
373
375
|
let completed = 0;
|
|
@@ -379,8 +381,8 @@ export default class TaskProcessor {
|
|
|
379
381
|
|
|
380
382
|
constructor() {
|
|
381
383
|
// onexit: Handle cleanup when leaving states
|
|
382
|
-
this.#machine.onexit = (
|
|
383
|
-
switch (
|
|
384
|
+
this.#machine.onexit = (currentState) => {
|
|
385
|
+
switch (currentState) {
|
|
384
386
|
case 'processing':
|
|
385
387
|
this.#cancelTasks(); // Cancel ongoing tasks if interrupted
|
|
386
388
|
break;
|
|
@@ -388,8 +390,8 @@ export default class TaskProcessor {
|
|
|
388
390
|
};
|
|
389
391
|
|
|
390
392
|
// onenter: Handle immediate state actions
|
|
391
|
-
this.#machine.onenter = (
|
|
392
|
-
switch (
|
|
393
|
+
this.#machine.onenter = (currentState) => {
|
|
394
|
+
switch (currentState) {
|
|
393
395
|
case 'processing':
|
|
394
396
|
this.#startAllTasks(); // Start processing immediately
|
|
395
397
|
break;
|
|
@@ -397,7 +399,7 @@ export default class TaskProcessor {
|
|
|
397
399
|
this.#notifyComplete(); // Cleanup/notify when done
|
|
398
400
|
break;
|
|
399
401
|
}
|
|
400
|
-
this.state =
|
|
402
|
+
this.state = currentState;
|
|
401
403
|
};
|
|
402
404
|
|
|
403
405
|
// $effect: Monitor reactive completion
|
|
@@ -419,22 +421,22 @@ export default class TaskProcessor {
|
|
|
419
421
|
// Component.svelte
|
|
420
422
|
<script>
|
|
421
423
|
import { FiniteStateMachine } from '$lib/state/classes.js';
|
|
422
|
-
|
|
424
|
+
|
|
423
425
|
const machine = new FiniteStateMachine('idle', {
|
|
424
426
|
idle: { start: 'loading' },
|
|
425
427
|
loading: { complete: 'loaded', error: 'error' },
|
|
426
428
|
loaded: { reset: 'idle' },
|
|
427
429
|
error: { retry: 'loading', reset: 'idle' }
|
|
428
430
|
});
|
|
429
|
-
|
|
431
|
+
|
|
430
432
|
// Reactive state updates
|
|
431
433
|
$effect(() => {
|
|
432
434
|
console.log('State changed to:', machine.current);
|
|
433
435
|
});
|
|
434
|
-
|
|
436
|
+
|
|
435
437
|
// Handle state-specific actions
|
|
436
|
-
machine.onexit = (
|
|
437
|
-
switch (
|
|
438
|
+
machine.onexit = (currentState) => {
|
|
439
|
+
switch (currentState) {
|
|
438
440
|
case 'loading':
|
|
439
441
|
// Cancel any ongoing requests
|
|
440
442
|
cancelRequests();
|
|
@@ -442,8 +444,8 @@ export default class TaskProcessor {
|
|
|
442
444
|
}
|
|
443
445
|
};
|
|
444
446
|
|
|
445
|
-
machine.onenter = (
|
|
446
|
-
switch (
|
|
447
|
+
machine.onenter = (currentState) => {
|
|
448
|
+
switch (currentState) {
|
|
447
449
|
case 'loading':
|
|
448
450
|
loadData();
|
|
449
451
|
break;
|
|
@@ -475,7 +477,7 @@ console.log(machine.current); // Still 'idle'
|
|
|
475
477
|
|
|
476
478
|
## Best Practices
|
|
477
479
|
|
|
478
|
-
1. **Clear state names**: Use descriptive state names like `loading`, `error`,
|
|
480
|
+
1. **Clear state names**: Use descriptive state names like `loading`, `error`,
|
|
479
481
|
`authenticated` rather than generic ones
|
|
480
482
|
2. **Minimal state count**: Keep the number of states manageable
|
|
481
483
|
3. **Explicit transitions**: Define all valid transitions explicitly
|
|
@@ -524,7 +526,7 @@ const auth = new FiniteStateMachine('anonymous', {
|
|
|
524
526
|
failure: 'anonymous'
|
|
525
527
|
},
|
|
526
528
|
authenticated: {
|
|
527
|
-
_enter: (
|
|
529
|
+
_enter: (transition) => console.log('Welcome!'),
|
|
528
530
|
logout: 'anonymous',
|
|
529
531
|
expire: 'anonymous'
|
|
530
532
|
}
|
|
@@ -542,4 +544,4 @@ The state machine includes comprehensive tests covering:
|
|
|
542
544
|
- Immediate state access
|
|
543
545
|
- Callback execution order
|
|
544
546
|
|
|
545
|
-
See `FiniteStateMachine.test.js` for detailed examples.
|
|
547
|
+
See `FiniteStateMachine.test.js` for detailed examples.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Constants for FiniteStateMachine events
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Event emitted when entering a state
|
|
6
|
+
* @type {string}
|
|
7
|
+
*/
|
|
8
|
+
export const ENTER: string;
|
|
9
|
+
/**
|
|
10
|
+
* Event emitted when exiting a state
|
|
11
|
+
* @type {string}
|
|
12
|
+
*/
|
|
13
|
+
export const EXIT: string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Constants for FiniteStateMachine events
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Event emitted when entering a state
|
|
7
|
+
* @type {string}
|
|
8
|
+
*/
|
|
9
|
+
export const ENTER = 'enter';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Event emitted when exiting a state
|
|
13
|
+
* @type {string}
|
|
14
|
+
*/
|
|
15
|
+
export const EXIT = 'exit';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Metadata object passed to state transition callbacks
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
4
|
+
export type TransitionData = {
|
|
5
5
|
/**
|
|
6
6
|
* - The state being exited
|
|
7
7
|
*/
|
|
@@ -22,8 +22,8 @@ export type StateTransitionMetadata = {
|
|
|
22
22
|
/**
|
|
23
23
|
* Callback function called when entering a state
|
|
24
24
|
*/
|
|
25
|
-
export type OnEnterCallback = (
|
|
25
|
+
export type OnEnterCallback = (currentState: string, transition: TransitionData) => void;
|
|
26
26
|
/**
|
|
27
27
|
* Callback function called when exiting a state
|
|
28
28
|
*/
|
|
29
|
-
export type OnExitCallback = (
|
|
29
|
+
export type OnExitCallback = (currentState: string, transition: TransitionData) => void;
|
|
@@ -4,25 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Metadata object passed to state transition callbacks
|
|
7
|
-
*
|
|
8
|
-
* @typedef {object}
|
|
7
|
+
*
|
|
8
|
+
* @typedef {object} TransitionData
|
|
9
9
|
* @property {string} from - The state being exited
|
|
10
|
-
* @property {string} to - The state being entered
|
|
10
|
+
* @property {string} to - The state being entered
|
|
11
11
|
* @property {string} event - The event that triggered the transition
|
|
12
12
|
* @property {any[]} args - Arguments passed to the send() method
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Callback function called when entering a state
|
|
17
|
+
*
|
|
18
|
+
* @callback OnEnterCallback
|
|
19
|
+
* @param {string} currentState - The state being entered
|
|
20
|
+
* @param {TransitionData} transition - Details about the transition
|
|
21
|
+
* @returns {void}
|
|
22
|
+
*/
|
|
20
23
|
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Callback function called when exiting a state
|
|
26
|
+
*
|
|
27
|
+
* @callback OnExitCallback
|
|
28
|
+
* @param {string} currentState - The state being exited
|
|
29
|
+
* @param {TransitionData} transition - Details about the transition
|
|
30
|
+
* @returns {void}
|
|
31
|
+
*/
|
|
26
32
|
|
|
27
|
-
// Export types for
|
|
28
|
-
export {};
|
|
33
|
+
// Export types for JSdoc
|
|
34
|
+
export {};
|
|
@@ -5,6 +5,18 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
5
5
|
constructor();
|
|
6
6
|
/** The last error */
|
|
7
7
|
get error(): Error;
|
|
8
|
+
/**
|
|
9
|
+
* Transition to timeout state
|
|
10
|
+
* - Only valid when currently loading
|
|
11
|
+
* - Useful for external timeout management
|
|
12
|
+
*/
|
|
13
|
+
doTimeout(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Transition to cancelled state
|
|
16
|
+
* - Only valid when currently loading
|
|
17
|
+
* - Useful for external cancellation management
|
|
18
|
+
*/
|
|
19
|
+
doCancel(): void;
|
|
8
20
|
#private;
|
|
9
21
|
}
|
|
10
22
|
import FiniteStateMachine from '../finite-state-machine/FiniteStateMachine.svelte.js';
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
STATE_LOADED,
|
|
11
11
|
STATE_CANCELLED,
|
|
12
12
|
STATE_ERROR,
|
|
13
|
+
STATE_TIMEOUT,
|
|
13
14
|
|
|
14
15
|
// > Signals
|
|
15
16
|
INITIAL,
|
|
@@ -17,7 +18,8 @@ import {
|
|
|
17
18
|
CANCEL,
|
|
18
19
|
ERROR,
|
|
19
20
|
LOADED,
|
|
20
|
-
UNLOAD
|
|
21
|
+
UNLOAD,
|
|
22
|
+
TIMEOUT
|
|
21
23
|
} from './constants.js';
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -41,7 +43,8 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
41
43
|
// },
|
|
42
44
|
[CANCEL]: STATE_CANCELLED,
|
|
43
45
|
[ERROR]: STATE_ERROR,
|
|
44
|
-
[LOADED]: STATE_LOADED
|
|
46
|
+
[LOADED]: STATE_LOADED,
|
|
47
|
+
[TIMEOUT]: STATE_TIMEOUT
|
|
45
48
|
},
|
|
46
49
|
[STATE_LOADED]: {
|
|
47
50
|
// _enter: () => {
|
|
@@ -58,6 +61,10 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
58
61
|
[LOAD]: STATE_LOADING,
|
|
59
62
|
[UNLOAD]: STATE_UNLOADING
|
|
60
63
|
},
|
|
64
|
+
[STATE_TIMEOUT]: {
|
|
65
|
+
[LOAD]: STATE_LOADING,
|
|
66
|
+
[UNLOAD]: STATE_UNLOADING
|
|
67
|
+
},
|
|
61
68
|
[STATE_ERROR]: {
|
|
62
69
|
_enter: ({ /*from, to, event,*/ args }) => {
|
|
63
70
|
if (args[0] instanceof Error) {
|
|
@@ -86,4 +93,22 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
86
93
|
get error() {
|
|
87
94
|
return this.#error;
|
|
88
95
|
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Transition to timeout state
|
|
99
|
+
* - Only valid when currently loading
|
|
100
|
+
* - Useful for external timeout management
|
|
101
|
+
*/
|
|
102
|
+
doTimeout() {
|
|
103
|
+
this.send(TIMEOUT);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Transition to cancelled state
|
|
108
|
+
* - Only valid when currently loading
|
|
109
|
+
* - Useful for external cancellation management
|
|
110
|
+
*/
|
|
111
|
+
doCancel() {
|
|
112
|
+
this.send(CANCEL);
|
|
113
|
+
}
|
|
89
114
|
}
|