@hkdigital/lib-core 0.4.25 → 0.4.27
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/network/loaders/audio/AudioScene.svelte.d.ts +30 -10
- package/dist/network/loaders/audio/AudioScene.svelte.js +113 -74
- package/dist/network/loaders/image/ImageScene.svelte.d.ts +24 -13
- package/dist/network/loaders/image/ImageScene.svelte.js +118 -83
- package/dist/network/states/NetworkLoader.svelte.d.ts +2 -2
- package/dist/network/states/NetworkLoader.svelte.js +15 -17
- package/dist/state/machines/finite-state-machine/FiniteStateMachine.svelte.d.ts +2 -2
- package/dist/state/machines/finite-state-machine/FiniteStateMachine.svelte.js +13 -13
- package/dist/state/machines/finite-state-machine/README.md +31 -31
- package/dist/state/machines/finite-state-machine/typedef.d.ts +3 -3
- package/dist/state/machines/finite-state-machine/typedef.js +18 -12
- package/dist/state/machines/loading-state-machine/LoadingStateMachine.svelte.d.ts +4 -4
- package/dist/state/machines/loading-state-machine/LoadingStateMachine.svelte.js +15 -9
- package/dist/state/machines/loading-state-machine/README.md +95 -70
- package/dist/state/machines/loading-state-machine/constants.d.ts +4 -2
- package/dist/state/machines/loading-state-machine/constants.js +4 -2
- package/package.json +1 -1
|
@@ -4,17 +4,18 @@ A specialized finite state machine designed for managing loading operations with
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
`LoadingStateMachine` extends `FiniteStateMachine` to provide a standardized way to handle loading workflows. It includes predefined states for initial, loading, loaded, unloading,
|
|
7
|
+
`LoadingStateMachine` extends `FiniteStateMachine` to provide a standardized way to handle loading workflows. It includes predefined states for initial, loading, loaded, unloading, aborted, and error conditions.
|
|
8
8
|
|
|
9
9
|
## States
|
|
10
10
|
|
|
11
|
-
The machine defines
|
|
11
|
+
The machine defines eight primary states:
|
|
12
12
|
|
|
13
13
|
- **`INITIAL`** - Starting state, ready to begin loading
|
|
14
14
|
- **`LOADING`** - Currently loading data or resources
|
|
15
15
|
- **`LOADED`** - Successfully loaded, data available
|
|
16
16
|
- **`UNLOADING`** - Cleaning up or releasing resources
|
|
17
|
-
- **`
|
|
17
|
+
- **`ABORTING`** - Currently aborting loading operation
|
|
18
|
+
- **`ABORTED`** - Loading operation was aborted
|
|
18
19
|
- **`ERROR`** - An error occurred during loading
|
|
19
20
|
- **`TIMEOUT`** - Loading operation exceeded time limit
|
|
20
21
|
|
|
@@ -25,7 +26,8 @@ Available events to trigger state transitions:
|
|
|
25
26
|
- **`LOAD`** - Start loading operation
|
|
26
27
|
- **`LOADED`** - Mark loading as complete
|
|
27
28
|
- **`UNLOAD`** - Begin cleanup/unloading
|
|
28
|
-
- **`
|
|
29
|
+
- **`ABORT`** - Start aborting the loading operation
|
|
30
|
+
- **`ABORTED`** - Mark abort operation as complete
|
|
29
31
|
- **`ERROR`** - Signal an error occurred
|
|
30
32
|
- **`TIMEOUT`** - Signal operation has timed out
|
|
31
33
|
- **`INITIAL`** - Return to initial state
|
|
@@ -44,7 +46,7 @@ import {
|
|
|
44
46
|
LOAD,
|
|
45
47
|
LOADED,
|
|
46
48
|
ERROR,
|
|
47
|
-
|
|
49
|
+
ABORT
|
|
48
50
|
} from '$lib/state/machines.js';
|
|
49
51
|
|
|
50
52
|
const loader = new LoadingStateMachine();
|
|
@@ -67,10 +69,11 @@ console.log(loader.current); // STATE_LOADED
|
|
|
67
69
|
|
|
68
70
|
```
|
|
69
71
|
INITIAL → LOADING
|
|
70
|
-
LOADING → LOADED |
|
|
72
|
+
LOADING → LOADED | ABORTING | ERROR | TIMEOUT
|
|
71
73
|
LOADED → LOADING | UNLOADING
|
|
72
74
|
UNLOADING → INITIAL | ERROR
|
|
73
|
-
|
|
75
|
+
ABORTING → ABORTED | ERROR
|
|
76
|
+
ABORTED → LOADING | UNLOADING
|
|
74
77
|
ERROR → LOADING | UNLOADING
|
|
75
78
|
TIMEOUT → LOADING | UNLOADING
|
|
76
79
|
```
|
|
@@ -78,26 +81,26 @@ TIMEOUT → LOADING | UNLOADING
|
|
|
78
81
|
### Transition Diagram
|
|
79
82
|
|
|
80
83
|
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
┌─────────┐
|
|
87
|
-
│ LOADING
|
|
88
|
-
└────┬────┘
|
|
89
|
-
│
|
|
90
|
-
|
|
91
|
-
│
|
|
92
|
-
▼
|
|
93
|
-
┌────────┐ ┌───────┐
|
|
94
|
-
│ LOADED │ │ ERROR │
|
|
95
|
-
└────┬───┘ └───┬───┘
|
|
96
|
-
│ │
|
|
97
|
-
UNLOAD│
|
|
98
|
-
▼ ▼
|
|
99
|
-
|
|
100
|
-
│UNLOADING
|
|
84
|
+
┌─────────┐
|
|
85
|
+
│ INITIAL │
|
|
86
|
+
└────┬────┘
|
|
87
|
+
LOAD│
|
|
88
|
+
▼
|
|
89
|
+
┌─────────┐ ABORT ┌──────────┐
|
|
90
|
+
│ LOADING │──────────────────────────────→│ ABORTING │
|
|
91
|
+
└────┬────┘ └─────┬────┘
|
|
92
|
+
│ │
|
|
93
|
+
LOADED│ ERROR TIMEOUT ABORTED │ERROR
|
|
94
|
+
│ │ │ │ │
|
|
95
|
+
▼ ▼ ▼ ▼ ▼
|
|
96
|
+
┌────────┐ ┌───────┐ ┌─────────┐ ┌─────────┐
|
|
97
|
+
│ LOADED │ │ ERROR │ │ TIMEOUT │ │ ABORTED │
|
|
98
|
+
└────┬───┘ └───┬───┘ └────┬────┘ └────┬────┘
|
|
99
|
+
│ │ │ │
|
|
100
|
+
UNLOAD│ LOAD│UNLOAD LOAD│UNLOAD LOAD│UNLOAD
|
|
101
|
+
▼ ▼ ▼ ▼
|
|
102
|
+
┌──────────┐ │
|
|
103
|
+
│UNLOADING │◄────────────────────────────────┘
|
|
101
104
|
└──────────┘
|
|
102
105
|
```
|
|
103
106
|
|
|
@@ -108,8 +111,8 @@ The `onenter` callback provides a reliable way to react to state changes, design
|
|
|
108
111
|
```javascript
|
|
109
112
|
const loader = new LoadingStateMachine();
|
|
110
113
|
|
|
111
|
-
loader.onenter = (
|
|
112
|
-
switch (
|
|
114
|
+
loader.onenter = (currentState) => {
|
|
115
|
+
switch (currentState) {
|
|
113
116
|
case STATE_LOADING:
|
|
114
117
|
console.log('Started loading...');
|
|
115
118
|
showSpinner();
|
|
@@ -141,8 +144,8 @@ $effect(() => {
|
|
|
141
144
|
});
|
|
142
145
|
|
|
143
146
|
// onenter catches every transition
|
|
144
|
-
loader.onenter = (
|
|
145
|
-
console.log(
|
|
147
|
+
loader.onenter = (currentState) => {
|
|
148
|
+
console.log(currentState); // Sees every state change
|
|
146
149
|
};
|
|
147
150
|
```
|
|
148
151
|
|
|
@@ -184,12 +187,12 @@ const loader = new LoadingStateMachine();
|
|
|
184
187
|
// External timeout management
|
|
185
188
|
const timeoutId = setTimeout(() => {
|
|
186
189
|
if (loader.current === STATE_LOADING) {
|
|
187
|
-
loader.
|
|
190
|
+
loader.timeout(); // Transitions to STATE_TIMEOUT
|
|
188
191
|
}
|
|
189
192
|
}, 10000); // 10 second timeout
|
|
190
193
|
|
|
191
|
-
loader.onenter = (
|
|
192
|
-
switch (
|
|
194
|
+
loader.onenter = (currentState) => {
|
|
195
|
+
switch (currentState) {
|
|
193
196
|
case STATE_TIMEOUT:
|
|
194
197
|
console.log('Loading timed out');
|
|
195
198
|
showRetryButton();
|
|
@@ -201,13 +204,22 @@ loader.onenter = (state) => {
|
|
|
201
204
|
};
|
|
202
205
|
```
|
|
203
206
|
|
|
204
|
-
###
|
|
207
|
+
### timeout Method
|
|
205
208
|
|
|
206
|
-
Use `
|
|
209
|
+
Use `timeout()` to manually trigger a timeout transition:
|
|
207
210
|
|
|
208
211
|
```javascript
|
|
209
212
|
// Only works when in STATE_LOADING
|
|
210
|
-
loader.
|
|
213
|
+
loader.timeout(); // Sends TIMEOUT signal
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### abort Method
|
|
217
|
+
|
|
218
|
+
Use `abort()` to manually trigger an abort transition:
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// Only works when in STATE_LOADING
|
|
222
|
+
loader.abort(); // Sends ABORT signal, transitions to STATE_ABORTING
|
|
211
223
|
```
|
|
212
224
|
|
|
213
225
|
## Integration with Svelte Reactivity
|
|
@@ -220,8 +232,8 @@ LoadingStateMachine inherits the `onenter` callback and Svelte reactivity integr
|
|
|
220
232
|
```javascript
|
|
221
233
|
const loader = new LoadingStateMachine();
|
|
222
234
|
|
|
223
|
-
loader.onenter = (
|
|
224
|
-
switch (
|
|
235
|
+
loader.onenter = (currentState) => {
|
|
236
|
+
switch (currentState) {
|
|
225
237
|
case STATE_LOADING:
|
|
226
238
|
this.#startLoading(); // Start async process immediately
|
|
227
239
|
break;
|
|
@@ -267,8 +279,8 @@ export default class MultiSourceLoader {
|
|
|
267
279
|
|
|
268
280
|
constructor() {
|
|
269
281
|
// Handle immediate loading state actions
|
|
270
|
-
this.#loader.onenter = (
|
|
271
|
-
switch (
|
|
282
|
+
this.#loader.onenter = (currentState) => {
|
|
283
|
+
switch (currentState) {
|
|
272
284
|
case STATE_LOADING:
|
|
273
285
|
this.#startAllSources();
|
|
274
286
|
break;
|
|
@@ -282,7 +294,7 @@ export default class MultiSourceLoader {
|
|
|
282
294
|
this.#handleTimeout();
|
|
283
295
|
break;
|
|
284
296
|
}
|
|
285
|
-
this.state =
|
|
297
|
+
this.state = currentState;
|
|
286
298
|
};
|
|
287
299
|
|
|
288
300
|
// Monitor reactive completion
|
|
@@ -313,14 +325,14 @@ export default class MultiSourceLoader {
|
|
|
313
325
|
LOAD,
|
|
314
326
|
LOADED,
|
|
315
327
|
ERROR,
|
|
316
|
-
|
|
328
|
+
ABORT
|
|
317
329
|
} from '$lib/state/machines.js';
|
|
318
330
|
|
|
319
331
|
const loader = new LoadingStateMachine();
|
|
320
332
|
let data = $state(null);
|
|
321
333
|
|
|
322
|
-
loader.onenter = (
|
|
323
|
-
if (
|
|
334
|
+
loader.onenter = (currentState) => {
|
|
335
|
+
if (currentState === STATE_LOADING) {
|
|
324
336
|
loadData();
|
|
325
337
|
}
|
|
326
338
|
};
|
|
@@ -351,7 +363,7 @@ export default class MultiSourceLoader {
|
|
|
351
363
|
{/if}
|
|
352
364
|
```
|
|
353
365
|
|
|
354
|
-
### Advanced Component with
|
|
366
|
+
### Advanced Component with Abort Handling
|
|
355
367
|
|
|
356
368
|
```javascript
|
|
357
369
|
<script>
|
|
@@ -360,24 +372,29 @@ export default class MultiSourceLoader {
|
|
|
360
372
|
STATE_INITIAL,
|
|
361
373
|
STATE_LOADING,
|
|
362
374
|
STATE_LOADED,
|
|
363
|
-
|
|
375
|
+
STATE_ABORTING,
|
|
376
|
+
STATE_ABORTED,
|
|
364
377
|
STATE_ERROR,
|
|
365
378
|
LOAD,
|
|
366
379
|
LOADED,
|
|
367
380
|
ERROR,
|
|
368
|
-
|
|
381
|
+
ABORT,
|
|
382
|
+
ABORTED
|
|
369
383
|
} from '$lib/state/machines.js';
|
|
370
384
|
|
|
371
385
|
const loader = new LoadingStateMachine();
|
|
372
386
|
let abortController = null;
|
|
373
387
|
|
|
374
|
-
loader.onenter = (
|
|
375
|
-
switch (
|
|
388
|
+
loader.onenter = (currentState) => {
|
|
389
|
+
switch (currentState) {
|
|
376
390
|
case STATE_LOADING:
|
|
377
391
|
startLoad();
|
|
378
392
|
break;
|
|
379
|
-
case
|
|
393
|
+
case STATE_ABORTING:
|
|
394
|
+
// Start abort process
|
|
380
395
|
abortController?.abort();
|
|
396
|
+
// Simulate abort completion
|
|
397
|
+
setTimeout(() => loader.send(ABORTED), 100);
|
|
381
398
|
break;
|
|
382
399
|
}
|
|
383
400
|
};
|
|
@@ -393,7 +410,7 @@ export default class MultiSourceLoader {
|
|
|
393
410
|
loader.send(LOADED);
|
|
394
411
|
} catch (error) {
|
|
395
412
|
if (error.name === 'AbortError') {
|
|
396
|
-
// Request was
|
|
413
|
+
// Request was aborted, machine will transition to STATE_ABORTED
|
|
397
414
|
} else {
|
|
398
415
|
loader.send(ERROR, error);
|
|
399
416
|
}
|
|
@@ -405,13 +422,15 @@ export default class MultiSourceLoader {
|
|
|
405
422
|
{#if loader.current === STATE_INITIAL}
|
|
406
423
|
<button onclick={() => loader.send(LOAD)}>Start Loading</button>
|
|
407
424
|
{:else if loader.current === STATE_LOADING}
|
|
408
|
-
<button onclick={() => loader.send(
|
|
425
|
+
<button onclick={() => loader.send(ABORT)}>Abort Loading</button>
|
|
409
426
|
<div>Loading data...</div>
|
|
427
|
+
{:else if loader.current === STATE_ABORTING}
|
|
428
|
+
<div>Aborting...</div>
|
|
410
429
|
{:else if loader.current === STATE_LOADED}
|
|
411
430
|
<div>Data loaded successfully!</div>
|
|
412
431
|
<button onclick={() => loader.send(LOAD)}>Reload</button>
|
|
413
|
-
{:else if loader.current ===
|
|
414
|
-
<div>Loading
|
|
432
|
+
{:else if loader.current === STATE_ABORTED}
|
|
433
|
+
<div>Loading aborted</div>
|
|
415
434
|
<button onclick={() => loader.send(LOAD)}>Try Again</button>
|
|
416
435
|
{:else if loader.current === STATE_ERROR}
|
|
417
436
|
<div>Error: {loader.error.message}</div>
|
|
@@ -426,8 +445,8 @@ export default class MultiSourceLoader {
|
|
|
426
445
|
|
|
427
446
|
```javascript
|
|
428
447
|
// ✅ Good - use onenter for reliable side effects
|
|
429
|
-
loader.onenter = (
|
|
430
|
-
if (
|
|
448
|
+
loader.onenter = (currentState) => {
|
|
449
|
+
if (currentState === STATE_LOADING) {
|
|
431
450
|
analytics.track('loading_started');
|
|
432
451
|
}
|
|
433
452
|
};
|
|
@@ -443,14 +462,17 @@ $effect(() => {
|
|
|
443
462
|
### 2. Handle All Error States
|
|
444
463
|
|
|
445
464
|
```javascript
|
|
446
|
-
loader.onenter = (
|
|
447
|
-
switch (
|
|
465
|
+
loader.onenter = (currentState) => {
|
|
466
|
+
switch (currentState) {
|
|
448
467
|
case STATE_ERROR:
|
|
449
468
|
showErrorToast(loader.error.message);
|
|
450
469
|
logError(loader.error);
|
|
451
470
|
break;
|
|
452
|
-
case
|
|
453
|
-
showMessage('
|
|
471
|
+
case STATE_ABORTING:
|
|
472
|
+
showMessage('Aborting operation...');
|
|
473
|
+
break;
|
|
474
|
+
case STATE_ABORTED:
|
|
475
|
+
showMessage('Operation aborted');
|
|
454
476
|
break;
|
|
455
477
|
}
|
|
456
478
|
};
|
|
@@ -459,14 +481,15 @@ loader.onenter = (state) => {
|
|
|
459
481
|
### 3. Implement Proper Cleanup
|
|
460
482
|
|
|
461
483
|
```javascript
|
|
462
|
-
loader.onenter = (
|
|
463
|
-
switch (
|
|
484
|
+
loader.onenter = (currentState) => {
|
|
485
|
+
switch (currentState) {
|
|
464
486
|
case STATE_LOADING:
|
|
465
487
|
showProgressBar();
|
|
466
488
|
break;
|
|
467
489
|
case STATE_LOADED:
|
|
468
490
|
case STATE_ERROR:
|
|
469
|
-
case
|
|
491
|
+
case STATE_ABORTING:
|
|
492
|
+
case STATE_ABORTED:
|
|
470
493
|
hideProgressBar();
|
|
471
494
|
break;
|
|
472
495
|
case STATE_UNLOADING:
|
|
@@ -500,8 +523,8 @@ loader.send('load');
|
|
|
500
523
|
const resourceLoader = new LoadingStateMachine();
|
|
501
524
|
let resource = null;
|
|
502
525
|
|
|
503
|
-
resourceLoader.onenter = async (
|
|
504
|
-
switch (
|
|
526
|
+
resourceLoader.onenter = async (currentState) => {
|
|
527
|
+
switch (currentState) {
|
|
505
528
|
case STATE_LOADING:
|
|
506
529
|
try {
|
|
507
530
|
resource = await loadResource();
|
|
@@ -529,8 +552,8 @@ const retryLoader = new LoadingStateMachine();
|
|
|
529
552
|
let retryCount = 0;
|
|
530
553
|
const maxRetries = 3;
|
|
531
554
|
|
|
532
|
-
retryLoader.onenter = async (
|
|
533
|
-
switch (
|
|
555
|
+
retryLoader.onenter = async (currentState) => {
|
|
556
|
+
switch (currentState) {
|
|
534
557
|
case STATE_LOADING:
|
|
535
558
|
try {
|
|
536
559
|
await performLoad();
|
|
@@ -576,7 +599,8 @@ import {
|
|
|
576
599
|
STATE_LOADING,
|
|
577
600
|
STATE_LOADED,
|
|
578
601
|
STATE_UNLOADING,
|
|
579
|
-
|
|
602
|
+
STATE_ABORTING,
|
|
603
|
+
STATE_ABORTED,
|
|
580
604
|
STATE_ERROR,
|
|
581
605
|
STATE_TIMEOUT,
|
|
582
606
|
|
|
@@ -584,7 +608,8 @@ import {
|
|
|
584
608
|
LOAD,
|
|
585
609
|
LOADED,
|
|
586
610
|
UNLOAD,
|
|
587
|
-
|
|
611
|
+
ABORT,
|
|
612
|
+
ABORTED,
|
|
588
613
|
ERROR,
|
|
589
614
|
INITIAL,
|
|
590
615
|
TIMEOUT
|
|
@@ -2,12 +2,14 @@ export const STATE_INITIAL: "initial";
|
|
|
2
2
|
export const STATE_LOADING: "loading";
|
|
3
3
|
export const STATE_UNLOADING: "unloading";
|
|
4
4
|
export const STATE_LOADED: "loaded";
|
|
5
|
-
export const
|
|
5
|
+
export const STATE_ABORTING: "aborting";
|
|
6
|
+
export const STATE_ABORTED: "aborted";
|
|
6
7
|
export const STATE_ERROR: "error";
|
|
7
8
|
export const STATE_TIMEOUT: "timeout";
|
|
8
9
|
export const INITIAL: "initial";
|
|
9
10
|
export const LOAD: "load";
|
|
10
|
-
export const
|
|
11
|
+
export const ABORT: "abort";
|
|
12
|
+
export const ABORTED: "aborted";
|
|
11
13
|
export const ERROR: "error";
|
|
12
14
|
export const LOADED: "loaded";
|
|
13
15
|
export const UNLOAD: "unload";
|
|
@@ -3,7 +3,8 @@ export const STATE_LOADING = 'loading';
|
|
|
3
3
|
export const STATE_UNLOADING = 'unloading';
|
|
4
4
|
export const STATE_LOADED = 'loaded';
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const STATE_ABORTING = 'aborting';
|
|
7
|
+
export const STATE_ABORTED = 'aborted';
|
|
7
8
|
export const STATE_ERROR = 'error';
|
|
8
9
|
export const STATE_TIMEOUT = 'timeout';
|
|
9
10
|
|
|
@@ -11,7 +12,8 @@ export const STATE_TIMEOUT = 'timeout';
|
|
|
11
12
|
|
|
12
13
|
export const INITIAL = 'initial';
|
|
13
14
|
export const LOAD = 'load';
|
|
14
|
-
export const
|
|
15
|
+
export const ABORT = 'abort';
|
|
16
|
+
export const ABORTED = 'aborted';
|
|
15
17
|
export const ERROR = 'error';
|
|
16
18
|
export const LOADED = 'loaded';
|
|
17
19
|
export const UNLOAD = 'unload';
|