unwrapped 0.1.4 → 0.1.6
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/CHANGELOG.md +12 -0
- package/README.md +25 -16
- package/dist/core/index.d.mts +112 -1
- package/dist/core/index.d.ts +112 -1
- package/dist/core/index.js +203 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +200 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/vue/index.d.mts +221 -3
- package/dist/vue/index.d.ts +221 -3
- package/dist/vue/index.js +12 -0
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/index.mjs +13 -1
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
# Unwrapped
|
|
2
2
|
|
|
3
|
-
A TypeScript library for
|
|
3
|
+
A TypeScript library for handling more gracefully synchronous and asynchronous operations that can fail via Result types. Provides also utilities for caching and binding for popular web frameworks.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Error handling in TypeScript is fundamentally built around throwing exceptions and catching them with try/catch blocks. This works fine for simple scripts where an unexpected error should crash the program, but modern applications—especially frontends—need to handle errors gracefully without crashing the entire app.
|
|
8
|
+
|
|
9
|
+
**Unwrapped** provides a different approach by providing Result types, with variants for both synchronous and asynchronous operations.
|
|
10
|
+
While their primary and most basic use are for describing the result of operations that may fail, they can be chained to describe chains of operations, with build-in short-circuiting when encoutering an error. These chains can be described either by successively calling methods like `.chain()`, or by using a generator syntax inspired by Effect (although much simplified).
|
|
11
|
+
|
|
12
|
+
Without **Unwrapped**, the traditional approach leads to scattered state management: separate variables for loading, error, and data, manual state transitions, and the ever-present risk of forgetting to set loading = false in a finally block. Error types are unknown, forcing type assertions everywhere. Chaining multiple async operations that can each fail becomes a mess of nested try/catch blocks or promise chains with multiple .catch() handlers.
|
|
13
|
+
|
|
14
|
+
On the contrary, **Unwrapped**'s AsyncResult type wraps loading, error, and success states in one type allowing for a much leaner and less error prone way of writing. Unsettled asynchronous operations will always give you an AsyncResult in a loading state, and when this work finishes, the AsyncResult will always be in a settled state, being either error or success.
|
|
15
|
+
|
|
16
|
+
**Unwrapped** is composed of multiple sub-modules :
|
|
8
17
|
|
|
9
18
|
- **Core**: Framework-agnostic utilities for managing results and async operations
|
|
10
19
|
- **Vue**: Vue 3 composables and components for reactive async state management
|
|
@@ -19,6 +28,20 @@ A brief comparison with other libraries can be found at the "Why Unwrapped ?" se
|
|
|
19
28
|
npm install unwrapped
|
|
20
29
|
```
|
|
21
30
|
|
|
31
|
+
## API Reference
|
|
32
|
+
|
|
33
|
+
### Core Module (`unwrapped/core`)
|
|
34
|
+
|
|
35
|
+
- **`Result<T, E>`**: Synchronous result type
|
|
36
|
+
- **`AsyncResult<T, E>`**: Asynchronous result with state tracking
|
|
37
|
+
- **`ErrorBase`**: Base error class with structured logging
|
|
38
|
+
- **`KeyedAsyncCache<P, V, E>`**: Cache for async operations
|
|
39
|
+
|
|
40
|
+
### Vue Module (`unwrapped/vue`)
|
|
41
|
+
|
|
42
|
+
- **Composables**: `useAsyncResultRef`, `useAction`, `useLazyAction`, `useReactiveChain`, `useGenerator`, `useLazyGenerator`, `useReactiveGenerator`
|
|
43
|
+
- **Components**: `AsyncResultLoader`, `buildCustomAsyncResultLoader`
|
|
44
|
+
|
|
22
45
|
|
|
23
46
|
## Core Concepts
|
|
24
47
|
|
|
@@ -825,20 +848,6 @@ Unwrapped is in very active development and a lot of features are still planned,
|
|
|
825
848
|
- Debounce on relevant utilities
|
|
826
849
|
|
|
827
850
|
|
|
828
|
-
## API Reference
|
|
829
|
-
|
|
830
|
-
### Core Module (`unwrapped/core`)
|
|
831
|
-
|
|
832
|
-
- **`Result<T, E>`**: Synchronous result type
|
|
833
|
-
- **`AsyncResult<T, E>`**: Asynchronous result with state tracking
|
|
834
|
-
- **`ErrorBase`**: Base error class with structured logging
|
|
835
|
-
- **`KeyedAsyncCache<P, V, E>`**: Cache for async operations
|
|
836
|
-
|
|
837
|
-
### Vue Module (`unwrapped/vue`)
|
|
838
|
-
|
|
839
|
-
- **Composables**: `useAsyncResultRef`, `useAction`, `useLazyAction`, `useReactiveChain`, `useGenerator`, `useLazyGenerator`, `useReactiveGenerator`
|
|
840
|
-
- **Components**: `AsyncResultLoader`, `buildCustomAsyncResultLoader`
|
|
841
|
-
|
|
842
851
|
## License
|
|
843
852
|
|
|
844
853
|
LGPL-3.0-or-later
|
package/dist/core/index.d.mts
CHANGED
|
@@ -261,6 +261,11 @@ declare class AsyncResult<T, E extends ErrorBase = ErrorBase> {
|
|
|
261
261
|
* @throws an normal JS Error if the result is not successful
|
|
262
262
|
*/
|
|
263
263
|
unwrapOrThrow(): T;
|
|
264
|
+
/**
|
|
265
|
+
* Returns the error value if the AsyncResult is in an error state, otherwise returns null.
|
|
266
|
+
* @returns the error value or null
|
|
267
|
+
*/
|
|
268
|
+
unwrapErrorOrNull(): E | null;
|
|
264
269
|
private set state(value);
|
|
265
270
|
private setState;
|
|
266
271
|
/**
|
|
@@ -475,6 +480,110 @@ declare class AsyncResult<T, E extends ErrorBase = ErrorBase> {
|
|
|
475
480
|
debug(name?: string): () => void;
|
|
476
481
|
}
|
|
477
482
|
|
|
483
|
+
/**
|
|
484
|
+
* The possible states of an AsyncResultList.
|
|
485
|
+
*/
|
|
486
|
+
type AsyncResultListState = "any-loading" | "all-settled";
|
|
487
|
+
/**
|
|
488
|
+
* A list that manages multiple AsyncResult instances, tracking their states and providing utilities to monitor them.
|
|
489
|
+
*/
|
|
490
|
+
declare class AsyncResultList<T = any, E extends ErrorBase = ErrorBase> {
|
|
491
|
+
private _list;
|
|
492
|
+
private _listeners;
|
|
493
|
+
private _state;
|
|
494
|
+
/**
|
|
495
|
+
* Gets the current tasks in the AsyncResultList.
|
|
496
|
+
*/
|
|
497
|
+
get tasks(): Map<string, AsyncResult<T, E>>;
|
|
498
|
+
/**
|
|
499
|
+
* Gets the number of tasks in the list.
|
|
500
|
+
*/
|
|
501
|
+
get length(): number;
|
|
502
|
+
/**
|
|
503
|
+
* Gets all tasks in the list as an array.
|
|
504
|
+
*/
|
|
505
|
+
get items(): AsyncResult<T, E>[];
|
|
506
|
+
/**
|
|
507
|
+
* Gets the current state of the AsyncResultList.
|
|
508
|
+
*/
|
|
509
|
+
get state(): AsyncResultListState;
|
|
510
|
+
private set state(value);
|
|
511
|
+
private _onTaskFinished;
|
|
512
|
+
/**
|
|
513
|
+
* Adds a listener that gets called whenever the state of the AsyncResultList changes.
|
|
514
|
+
* @param listener the function to call when the state changes
|
|
515
|
+
* @returns a function to unsubscribe the listener
|
|
516
|
+
*/
|
|
517
|
+
listen(listener: (taskQueue: AsyncResultList<T, E>) => void): () => void;
|
|
518
|
+
/**
|
|
519
|
+
* Adds an AsyncResult task to the list.
|
|
520
|
+
* @param key the unique key for the task
|
|
521
|
+
* @param task the AsyncResult task to add
|
|
522
|
+
* @param removeOnSettle whether to remove the task from the list once it settles (defaults to true)
|
|
523
|
+
* @returns the added AsyncResult task
|
|
524
|
+
*/
|
|
525
|
+
add(key: string, task: AsyncResult<T, E>, removeOnSettle?: boolean): AsyncResult<T, E>;
|
|
526
|
+
/**
|
|
527
|
+
* Checks if any task in the list is currently loading.
|
|
528
|
+
* @returns true if any task is loading, false otherwise
|
|
529
|
+
*/
|
|
530
|
+
anyLoading(): boolean;
|
|
531
|
+
/**
|
|
532
|
+
* Gets all tasks that satisfy the given predicate.
|
|
533
|
+
* @param predicate the function to test each task
|
|
534
|
+
* @returns an array of tasks that satisfy the predicate
|
|
535
|
+
*/
|
|
536
|
+
getAllFiltered(predicate: (task: AsyncResult<T, E>) => boolean): AsyncResult<T, E>[];
|
|
537
|
+
/**
|
|
538
|
+
* Gets all tasks that satisfy the given predicate and maps them using the provided function.
|
|
539
|
+
* @param filterPredicate the function to test each task
|
|
540
|
+
* @param mapFunc the function to map each task
|
|
541
|
+
* @returns an array of mapped values
|
|
542
|
+
*/
|
|
543
|
+
getAllFilteredAndMap<U>(filterPredicate: (task: AsyncResult<T, E>) => boolean, mapFunc: (task: AsyncResult<T, E>) => U): U[];
|
|
544
|
+
/**
|
|
545
|
+
* Gets all tasks that have succeeded.
|
|
546
|
+
* @returns an array of successful AsyncResult tasks
|
|
547
|
+
*/
|
|
548
|
+
getAllSuccess(): AsyncResult<T, E>[];
|
|
549
|
+
/**
|
|
550
|
+
* Gets the success values of all tasks that have succeeded.
|
|
551
|
+
* @returns an array of successful values
|
|
552
|
+
*/
|
|
553
|
+
getAllSuccessValues(): T[];
|
|
554
|
+
/**
|
|
555
|
+
* Gets all tasks that have errored.
|
|
556
|
+
* @returns an array of error AsyncResult tasks
|
|
557
|
+
*/
|
|
558
|
+
getAllErrors(): AsyncResult<T, E>[];
|
|
559
|
+
/**
|
|
560
|
+
* Gets the error values of all tasks that have errored.
|
|
561
|
+
* @returns an array of error values
|
|
562
|
+
*/
|
|
563
|
+
getAllErrorValues(): E[];
|
|
564
|
+
/**
|
|
565
|
+
* Gets all tasks that are currently loading.
|
|
566
|
+
* @returns an array of loading AsyncResult tasks
|
|
567
|
+
*/
|
|
568
|
+
getAllLoading(): AsyncResult<T, E>[];
|
|
569
|
+
/**
|
|
570
|
+
* Gets the promises of all tasks that are currently loading.
|
|
571
|
+
* @returns an array of promises for loading tasks
|
|
572
|
+
*/
|
|
573
|
+
getAllLoadingPromises(): Promise<Result<T, E>>[];
|
|
574
|
+
/**
|
|
575
|
+
* Logs the current state and tasks of the AsyncResultList to the console.
|
|
576
|
+
* @param name an optional name to identify the log
|
|
577
|
+
*/
|
|
578
|
+
log(name?: string): void;
|
|
579
|
+
/**
|
|
580
|
+
* Sets up a listener to log the state and tasks of the AsyncResultList whenever it changes.
|
|
581
|
+
* @param name an optional name to identify the log
|
|
582
|
+
* @returns a function to unsubscribe the debug listener
|
|
583
|
+
*/
|
|
584
|
+
debug(name?: string): () => void;
|
|
585
|
+
}
|
|
586
|
+
|
|
478
587
|
type KeyedAsyncCacheRefetchOptions = {
|
|
479
588
|
policy: 'refetch' | 'if-error' | 'no-refetch';
|
|
480
589
|
};
|
|
@@ -541,4 +650,6 @@ declare class KeyedAsyncCache<P, V, E extends ErrorBase = ErrorBase> {
|
|
|
541
650
|
invalidateAll(): void;
|
|
542
651
|
}
|
|
543
652
|
|
|
544
|
-
|
|
653
|
+
declare function delay(ms: number): AsyncResult<true>;
|
|
654
|
+
|
|
655
|
+
export { type Action, AsyncResult, type AsyncResultGenerator, AsyncResultList, type AsyncResultListState, type AsyncResultListener, type AsyncResultState, type ChainStep, ErrorBase, type FlatChainStep, KeyedAsyncCache, type LazyAction, Result, type ResultState, delay };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -261,6 +261,11 @@ declare class AsyncResult<T, E extends ErrorBase = ErrorBase> {
|
|
|
261
261
|
* @throws an normal JS Error if the result is not successful
|
|
262
262
|
*/
|
|
263
263
|
unwrapOrThrow(): T;
|
|
264
|
+
/**
|
|
265
|
+
* Returns the error value if the AsyncResult is in an error state, otherwise returns null.
|
|
266
|
+
* @returns the error value or null
|
|
267
|
+
*/
|
|
268
|
+
unwrapErrorOrNull(): E | null;
|
|
264
269
|
private set state(value);
|
|
265
270
|
private setState;
|
|
266
271
|
/**
|
|
@@ -475,6 +480,110 @@ declare class AsyncResult<T, E extends ErrorBase = ErrorBase> {
|
|
|
475
480
|
debug(name?: string): () => void;
|
|
476
481
|
}
|
|
477
482
|
|
|
483
|
+
/**
|
|
484
|
+
* The possible states of an AsyncResultList.
|
|
485
|
+
*/
|
|
486
|
+
type AsyncResultListState = "any-loading" | "all-settled";
|
|
487
|
+
/**
|
|
488
|
+
* A list that manages multiple AsyncResult instances, tracking their states and providing utilities to monitor them.
|
|
489
|
+
*/
|
|
490
|
+
declare class AsyncResultList<T = any, E extends ErrorBase = ErrorBase> {
|
|
491
|
+
private _list;
|
|
492
|
+
private _listeners;
|
|
493
|
+
private _state;
|
|
494
|
+
/**
|
|
495
|
+
* Gets the current tasks in the AsyncResultList.
|
|
496
|
+
*/
|
|
497
|
+
get tasks(): Map<string, AsyncResult<T, E>>;
|
|
498
|
+
/**
|
|
499
|
+
* Gets the number of tasks in the list.
|
|
500
|
+
*/
|
|
501
|
+
get length(): number;
|
|
502
|
+
/**
|
|
503
|
+
* Gets all tasks in the list as an array.
|
|
504
|
+
*/
|
|
505
|
+
get items(): AsyncResult<T, E>[];
|
|
506
|
+
/**
|
|
507
|
+
* Gets the current state of the AsyncResultList.
|
|
508
|
+
*/
|
|
509
|
+
get state(): AsyncResultListState;
|
|
510
|
+
private set state(value);
|
|
511
|
+
private _onTaskFinished;
|
|
512
|
+
/**
|
|
513
|
+
* Adds a listener that gets called whenever the state of the AsyncResultList changes.
|
|
514
|
+
* @param listener the function to call when the state changes
|
|
515
|
+
* @returns a function to unsubscribe the listener
|
|
516
|
+
*/
|
|
517
|
+
listen(listener: (taskQueue: AsyncResultList<T, E>) => void): () => void;
|
|
518
|
+
/**
|
|
519
|
+
* Adds an AsyncResult task to the list.
|
|
520
|
+
* @param key the unique key for the task
|
|
521
|
+
* @param task the AsyncResult task to add
|
|
522
|
+
* @param removeOnSettle whether to remove the task from the list once it settles (defaults to true)
|
|
523
|
+
* @returns the added AsyncResult task
|
|
524
|
+
*/
|
|
525
|
+
add(key: string, task: AsyncResult<T, E>, removeOnSettle?: boolean): AsyncResult<T, E>;
|
|
526
|
+
/**
|
|
527
|
+
* Checks if any task in the list is currently loading.
|
|
528
|
+
* @returns true if any task is loading, false otherwise
|
|
529
|
+
*/
|
|
530
|
+
anyLoading(): boolean;
|
|
531
|
+
/**
|
|
532
|
+
* Gets all tasks that satisfy the given predicate.
|
|
533
|
+
* @param predicate the function to test each task
|
|
534
|
+
* @returns an array of tasks that satisfy the predicate
|
|
535
|
+
*/
|
|
536
|
+
getAllFiltered(predicate: (task: AsyncResult<T, E>) => boolean): AsyncResult<T, E>[];
|
|
537
|
+
/**
|
|
538
|
+
* Gets all tasks that satisfy the given predicate and maps them using the provided function.
|
|
539
|
+
* @param filterPredicate the function to test each task
|
|
540
|
+
* @param mapFunc the function to map each task
|
|
541
|
+
* @returns an array of mapped values
|
|
542
|
+
*/
|
|
543
|
+
getAllFilteredAndMap<U>(filterPredicate: (task: AsyncResult<T, E>) => boolean, mapFunc: (task: AsyncResult<T, E>) => U): U[];
|
|
544
|
+
/**
|
|
545
|
+
* Gets all tasks that have succeeded.
|
|
546
|
+
* @returns an array of successful AsyncResult tasks
|
|
547
|
+
*/
|
|
548
|
+
getAllSuccess(): AsyncResult<T, E>[];
|
|
549
|
+
/**
|
|
550
|
+
* Gets the success values of all tasks that have succeeded.
|
|
551
|
+
* @returns an array of successful values
|
|
552
|
+
*/
|
|
553
|
+
getAllSuccessValues(): T[];
|
|
554
|
+
/**
|
|
555
|
+
* Gets all tasks that have errored.
|
|
556
|
+
* @returns an array of error AsyncResult tasks
|
|
557
|
+
*/
|
|
558
|
+
getAllErrors(): AsyncResult<T, E>[];
|
|
559
|
+
/**
|
|
560
|
+
* Gets the error values of all tasks that have errored.
|
|
561
|
+
* @returns an array of error values
|
|
562
|
+
*/
|
|
563
|
+
getAllErrorValues(): E[];
|
|
564
|
+
/**
|
|
565
|
+
* Gets all tasks that are currently loading.
|
|
566
|
+
* @returns an array of loading AsyncResult tasks
|
|
567
|
+
*/
|
|
568
|
+
getAllLoading(): AsyncResult<T, E>[];
|
|
569
|
+
/**
|
|
570
|
+
* Gets the promises of all tasks that are currently loading.
|
|
571
|
+
* @returns an array of promises for loading tasks
|
|
572
|
+
*/
|
|
573
|
+
getAllLoadingPromises(): Promise<Result<T, E>>[];
|
|
574
|
+
/**
|
|
575
|
+
* Logs the current state and tasks of the AsyncResultList to the console.
|
|
576
|
+
* @param name an optional name to identify the log
|
|
577
|
+
*/
|
|
578
|
+
log(name?: string): void;
|
|
579
|
+
/**
|
|
580
|
+
* Sets up a listener to log the state and tasks of the AsyncResultList whenever it changes.
|
|
581
|
+
* @param name an optional name to identify the log
|
|
582
|
+
* @returns a function to unsubscribe the debug listener
|
|
583
|
+
*/
|
|
584
|
+
debug(name?: string): () => void;
|
|
585
|
+
}
|
|
586
|
+
|
|
478
587
|
type KeyedAsyncCacheRefetchOptions = {
|
|
479
588
|
policy: 'refetch' | 'if-error' | 'no-refetch';
|
|
480
589
|
};
|
|
@@ -541,4 +650,6 @@ declare class KeyedAsyncCache<P, V, E extends ErrorBase = ErrorBase> {
|
|
|
541
650
|
invalidateAll(): void;
|
|
542
651
|
}
|
|
543
652
|
|
|
544
|
-
|
|
653
|
+
declare function delay(ms: number): AsyncResult<true>;
|
|
654
|
+
|
|
655
|
+
export { type Action, AsyncResult, type AsyncResultGenerator, AsyncResultList, type AsyncResultListState, type AsyncResultListener, type AsyncResultState, type ChainStep, ErrorBase, type FlatChainStep, KeyedAsyncCache, type LazyAction, Result, type ResultState, delay };
|
package/dist/core/index.js
CHANGED
|
@@ -21,9 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AsyncResult: () => AsyncResult,
|
|
24
|
+
AsyncResultList: () => AsyncResultList,
|
|
24
25
|
ErrorBase: () => ErrorBase,
|
|
25
26
|
KeyedAsyncCache: () => KeyedAsyncCache,
|
|
26
|
-
Result: () => Result
|
|
27
|
+
Result: () => Result,
|
|
28
|
+
delay: () => delay
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(index_exports);
|
|
29
31
|
|
|
@@ -308,6 +310,16 @@ var AsyncResult = class _AsyncResult {
|
|
|
308
310
|
}
|
|
309
311
|
throw new Error("Tried to unwrap an AsyncResult that is not successful");
|
|
310
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Returns the error value if the AsyncResult is in an error state, otherwise returns null.
|
|
315
|
+
* @returns the error value or null
|
|
316
|
+
*/
|
|
317
|
+
unwrapErrorOrNull() {
|
|
318
|
+
if (this._state.status === "error") {
|
|
319
|
+
return this._state.error;
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
311
323
|
// === Creating/updating from settled values ===
|
|
312
324
|
set state(newState) {
|
|
313
325
|
this._state = newState;
|
|
@@ -691,7 +703,7 @@ var AsyncResult = class _AsyncResult {
|
|
|
691
703
|
}
|
|
692
704
|
// === Debuging ===
|
|
693
705
|
log(name) {
|
|
694
|
-
const time = (/* @__PURE__ */ new Date()).toTimeString().slice(0,
|
|
706
|
+
const time = (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8);
|
|
695
707
|
console.log(`${name ?? "<Anonymous AsyncResult>"} ; State at ${time} :`, this.state);
|
|
696
708
|
}
|
|
697
709
|
debug(name) {
|
|
@@ -699,6 +711,185 @@ var AsyncResult = class _AsyncResult {
|
|
|
699
711
|
}
|
|
700
712
|
};
|
|
701
713
|
|
|
714
|
+
// src/core/asyncResultList.ts
|
|
715
|
+
var AsyncResultList = class {
|
|
716
|
+
_list = /* @__PURE__ */ new Map();
|
|
717
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
718
|
+
_state = "all-settled";
|
|
719
|
+
// === Getters ===
|
|
720
|
+
/**
|
|
721
|
+
* Gets the current tasks in the AsyncResultList.
|
|
722
|
+
*/
|
|
723
|
+
get tasks() {
|
|
724
|
+
return this._list;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Gets the number of tasks in the list.
|
|
728
|
+
*/
|
|
729
|
+
get length() {
|
|
730
|
+
return this._list.size;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Gets all tasks in the list as an array.
|
|
734
|
+
*/
|
|
735
|
+
get items() {
|
|
736
|
+
return Array.from(this._list.values());
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Gets the current state of the AsyncResultList.
|
|
740
|
+
*/
|
|
741
|
+
get state() {
|
|
742
|
+
return this._state;
|
|
743
|
+
}
|
|
744
|
+
set state(s) {
|
|
745
|
+
this._state = s;
|
|
746
|
+
this._listeners.forEach((f) => f(this));
|
|
747
|
+
}
|
|
748
|
+
_onTaskFinished() {
|
|
749
|
+
this.state = this.anyLoading() ? "any-loading" : "all-settled";
|
|
750
|
+
}
|
|
751
|
+
// === Listeners ===
|
|
752
|
+
/**
|
|
753
|
+
* Adds a listener that gets called whenever the state of the AsyncResultList changes.
|
|
754
|
+
* @param listener the function to call when the state changes
|
|
755
|
+
* @returns a function to unsubscribe the listener
|
|
756
|
+
*/
|
|
757
|
+
listen(listener) {
|
|
758
|
+
this._listeners.add(listener);
|
|
759
|
+
return () => {
|
|
760
|
+
this._listeners.delete(listener);
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
// === Managing tasks ===
|
|
764
|
+
/**
|
|
765
|
+
* Adds an AsyncResult task to the list.
|
|
766
|
+
* @param key the unique key for the task
|
|
767
|
+
* @param task the AsyncResult task to add
|
|
768
|
+
* @param removeOnSettle whether to remove the task from the list once it settles (defaults to true)
|
|
769
|
+
* @returns the added AsyncResult task
|
|
770
|
+
*/
|
|
771
|
+
add(key, task, removeOnSettle = true) {
|
|
772
|
+
this._list.set(key, task);
|
|
773
|
+
this.state = "any-loading";
|
|
774
|
+
if (removeOnSettle) {
|
|
775
|
+
task.listenUntilSettled((r) => {
|
|
776
|
+
if (r.isLoading() || r.isIdle()) return;
|
|
777
|
+
this._onTaskFinished();
|
|
778
|
+
this._list.delete(key);
|
|
779
|
+
}, true);
|
|
780
|
+
} else {
|
|
781
|
+
task.listen((r) => {
|
|
782
|
+
if (r.isLoading() || r.isIdle()) return;
|
|
783
|
+
this._onTaskFinished();
|
|
784
|
+
}, true);
|
|
785
|
+
}
|
|
786
|
+
return task;
|
|
787
|
+
}
|
|
788
|
+
// === Querying tasks ===
|
|
789
|
+
/**
|
|
790
|
+
* Checks if any task in the list is currently loading.
|
|
791
|
+
* @returns true if any task is loading, false otherwise
|
|
792
|
+
*/
|
|
793
|
+
anyLoading() {
|
|
794
|
+
for (const task of this._list.values()) {
|
|
795
|
+
if (task.isLoading()) {
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Gets all tasks that satisfy the given predicate.
|
|
803
|
+
* @param predicate the function to test each task
|
|
804
|
+
* @returns an array of tasks that satisfy the predicate
|
|
805
|
+
*/
|
|
806
|
+
getAllFiltered(predicate) {
|
|
807
|
+
const filtered = [];
|
|
808
|
+
for (const task of this._list.values()) {
|
|
809
|
+
if (predicate(task)) {
|
|
810
|
+
filtered.push(task);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
return filtered;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Gets all tasks that satisfy the given predicate and maps them using the provided function.
|
|
817
|
+
* @param filterPredicate the function to test each task
|
|
818
|
+
* @param mapFunc the function to map each task
|
|
819
|
+
* @returns an array of mapped values
|
|
820
|
+
*/
|
|
821
|
+
getAllFilteredAndMap(filterPredicate, mapFunc) {
|
|
822
|
+
const results = [];
|
|
823
|
+
for (const task of this._list.values()) {
|
|
824
|
+
if (filterPredicate(task)) {
|
|
825
|
+
results.push(mapFunc(task));
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return results;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Gets all tasks that have succeeded.
|
|
832
|
+
* @returns an array of successful AsyncResult tasks
|
|
833
|
+
*/
|
|
834
|
+
getAllSuccess() {
|
|
835
|
+
return this.getAllFiltered((task) => task.isSuccess());
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Gets the success values of all tasks that have succeeded.
|
|
839
|
+
* @returns an array of successful values
|
|
840
|
+
*/
|
|
841
|
+
getAllSuccessValues() {
|
|
842
|
+
return this.getAllFilteredAndMap((task) => task.isSuccess(), (task) => task.unwrapOrThrow());
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Gets all tasks that have errored.
|
|
846
|
+
* @returns an array of error AsyncResult tasks
|
|
847
|
+
*/
|
|
848
|
+
getAllErrors() {
|
|
849
|
+
return this.getAllFiltered((task) => task.isError());
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Gets the error values of all tasks that have errored.
|
|
853
|
+
* @returns an array of error values
|
|
854
|
+
*/
|
|
855
|
+
getAllErrorValues() {
|
|
856
|
+
return this.getAllFilteredAndMap((task) => task.isError(), (task) => task.unwrapErrorOrNull());
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Gets all tasks that are currently loading.
|
|
860
|
+
* @returns an array of loading AsyncResult tasks
|
|
861
|
+
*/
|
|
862
|
+
getAllLoading() {
|
|
863
|
+
return this.getAllFiltered((task) => task.isLoading());
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Gets the promises of all tasks that are currently loading.
|
|
867
|
+
* @returns an array of promises for loading tasks
|
|
868
|
+
*/
|
|
869
|
+
getAllLoadingPromises() {
|
|
870
|
+
return this.getAllFilteredAndMap((task) => task.isLoading(), (task) => task.toResultPromise());
|
|
871
|
+
}
|
|
872
|
+
// === Debugging utilities ===
|
|
873
|
+
/**
|
|
874
|
+
* Logs the current state and tasks of the AsyncResultList to the console.
|
|
875
|
+
* @param name an optional name to identify the log
|
|
876
|
+
*/
|
|
877
|
+
log(name) {
|
|
878
|
+
const time = (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8);
|
|
879
|
+
console.log(`${name ?? "<Anonymous TaskQueue>"} ; State at ${time} :`, this.state, this._list);
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Sets up a listener to log the state and tasks of the AsyncResultList whenever it changes.
|
|
883
|
+
* @param name an optional name to identify the log
|
|
884
|
+
* @returns a function to unsubscribe the debug listener
|
|
885
|
+
*/
|
|
886
|
+
debug(name) {
|
|
887
|
+
return this.listen(() => {
|
|
888
|
+
this.log(name);
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
|
|
702
893
|
// src/core/cache.ts
|
|
703
894
|
var _defaultRefetchOptions = { policy: "no-refetch" };
|
|
704
895
|
function defaultParamsToKey(params) {
|
|
@@ -836,11 +1027,20 @@ var KeyedAsyncCache = class {
|
|
|
836
1027
|
}
|
|
837
1028
|
}
|
|
838
1029
|
};
|
|
1030
|
+
|
|
1031
|
+
// src/core/utils.ts
|
|
1032
|
+
function delay(ms) {
|
|
1033
|
+
return AsyncResult.fromValuePromise(new Promise((resolve) => {
|
|
1034
|
+
setTimeout(() => resolve(true), ms);
|
|
1035
|
+
}));
|
|
1036
|
+
}
|
|
839
1037
|
// Annotate the CommonJS export names for ESM import in node:
|
|
840
1038
|
0 && (module.exports = {
|
|
841
1039
|
AsyncResult,
|
|
1040
|
+
AsyncResultList,
|
|
842
1041
|
ErrorBase,
|
|
843
1042
|
KeyedAsyncCache,
|
|
844
|
-
Result
|
|
1043
|
+
Result,
|
|
1044
|
+
delay
|
|
845
1045
|
});
|
|
846
1046
|
//# sourceMappingURL=index.js.map
|