unwrapped 0.1.5 → 0.1.7

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # unwrapped
2
2
 
3
+ ## 0.1.7
4
+
5
+ ### Patch Changes
6
+
7
+ - 0a435ac: fixed exports
8
+ - 5911174: Replaced AsyncResultLoader by factory function makeAsyncResultLoader
9
+
10
+ ## 0.1.6
11
+
12
+ ### Patch Changes
13
+
14
+ - 58d5299: Added AsyncResultList
15
+
3
16
  ## 0.1.5
4
17
 
5
18
  ### Patch Changes
@@ -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,116 @@ 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
+ interface AsyncResultListItem<T = any, E extends ErrorBase = ErrorBase> {
488
+ key: string;
489
+ result: AsyncResult<T, E>;
490
+ unsub: () => void;
491
+ }
492
+ /**
493
+ * A list that manages multiple AsyncResult instances, tracking their states and providing utilities to monitor them.
494
+ */
495
+ declare class AsyncResultList<T = any, E extends ErrorBase = ErrorBase> {
496
+ private _list;
497
+ private _listeners;
498
+ private _state;
499
+ /**
500
+ * Gets the current tasks in the AsyncResultList.
501
+ */
502
+ get tasks(): Map<string, AsyncResultListItem<T, E>>;
503
+ /**
504
+ * Gets the number of tasks in the list.
505
+ */
506
+ get length(): number;
507
+ /**
508
+ * Gets all tasks in the list as an array.
509
+ */
510
+ get items(): AsyncResult<T, E>[];
511
+ /**
512
+ * Gets the current state of the AsyncResultList.
513
+ */
514
+ get state(): AsyncResultListState;
515
+ private set state(value);
516
+ private _onTaskFinished;
517
+ /**
518
+ * Adds a listener that gets called whenever the state of the AsyncResultList changes.
519
+ * @param listener the function to call when the state changes
520
+ * @returns a function to unsubscribe the listener
521
+ */
522
+ listen(listener: (taskQueue: AsyncResultList<T, E>) => void): () => void;
523
+ /**
524
+ * Adds an AsyncResult task to the list.
525
+ * @param key the unique key for the task
526
+ * @param task the AsyncResult task to add
527
+ * @param removeOnSettle whether to remove the task from the list once it settles (defaults to true)
528
+ * @returns the added AsyncResult task
529
+ */
530
+ add(key: string, task: AsyncResult<T, E>, removeOnSettle?: boolean): AsyncResult<T, E>;
531
+ clear(): void;
532
+ /**
533
+ * Checks if any task in the list is currently loading.
534
+ * @returns true if any task is loading, false otherwise
535
+ */
536
+ anyLoading(): boolean;
537
+ /**
538
+ * Gets all tasks that satisfy the given predicate.
539
+ * @param predicate the function to test each task
540
+ * @returns an array of tasks that satisfy the predicate
541
+ */
542
+ getAllFiltered(predicate: (task: AsyncResult<T, E>) => boolean): AsyncResult<T, E>[];
543
+ /**
544
+ * Gets all tasks that satisfy the given predicate and maps them using the provided function.
545
+ * @param filterPredicate the function to test each task
546
+ * @param mapFunc the function to map each task
547
+ * @returns an array of mapped values
548
+ */
549
+ getAllFilteredAndMap<U>(filterPredicate: (task: AsyncResult<T, E>) => boolean, mapFunc: (task: AsyncResult<T, E>) => U): U[];
550
+ /**
551
+ * Gets all tasks that have succeeded.
552
+ * @returns an array of successful AsyncResult tasks
553
+ */
554
+ getAllSuccess(): AsyncResult<T, E>[];
555
+ /**
556
+ * Gets the success values of all tasks that have succeeded.
557
+ * @returns an array of successful values
558
+ */
559
+ getAllSuccessValues(): T[];
560
+ /**
561
+ * Gets all tasks that have errored.
562
+ * @returns an array of error AsyncResult tasks
563
+ */
564
+ getAllErrors(): AsyncResult<T, E>[];
565
+ /**
566
+ * Gets the error values of all tasks that have errored.
567
+ * @returns an array of error values
568
+ */
569
+ getAllErrorValues(): E[];
570
+ /**
571
+ * Gets all tasks that are currently loading.
572
+ * @returns an array of loading AsyncResult tasks
573
+ */
574
+ getAllLoading(): AsyncResult<T, E>[];
575
+ /**
576
+ * Gets the promises of all tasks that are currently loading.
577
+ * @returns an array of promises for loading tasks
578
+ */
579
+ getAllLoadingPromises(): Promise<Result<T, E>>[];
580
+ /**
581
+ * Logs the current state and tasks of the AsyncResultList to the console.
582
+ * @param name an optional name to identify the log
583
+ */
584
+ log(name?: string): void;
585
+ /**
586
+ * Sets up a listener to log the state and tasks of the AsyncResultList whenever it changes.
587
+ * @param name an optional name to identify the log
588
+ * @returns a function to unsubscribe the debug listener
589
+ */
590
+ debug(name?: string): () => void;
591
+ }
592
+
478
593
  type KeyedAsyncCacheRefetchOptions = {
479
594
  policy: 'refetch' | 'if-error' | 'no-refetch';
480
595
  };
@@ -541,4 +656,6 @@ declare class KeyedAsyncCache<P, V, E extends ErrorBase = ErrorBase> {
541
656
  invalidateAll(): void;
542
657
  }
543
658
 
544
- export { type Action, AsyncResult, type AsyncResultGenerator, type AsyncResultListener, type AsyncResultState, type ChainStep, ErrorBase, type FlatChainStep, KeyedAsyncCache, type LazyAction, Result, type ResultState };
659
+ declare function delay(ms: number): AsyncResult<true>;
660
+
661
+ export { type Action, AsyncResult, type AsyncResultGenerator, AsyncResultList, type AsyncResultListItem, type AsyncResultListState, type AsyncResultListener, type AsyncResultState, type ChainStep, ErrorBase, type FlatChainStep, KeyedAsyncCache, type LazyAction, Result, type ResultState, delay };
@@ -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,116 @@ 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
+ interface AsyncResultListItem<T = any, E extends ErrorBase = ErrorBase> {
488
+ key: string;
489
+ result: AsyncResult<T, E>;
490
+ unsub: () => void;
491
+ }
492
+ /**
493
+ * A list that manages multiple AsyncResult instances, tracking their states and providing utilities to monitor them.
494
+ */
495
+ declare class AsyncResultList<T = any, E extends ErrorBase = ErrorBase> {
496
+ private _list;
497
+ private _listeners;
498
+ private _state;
499
+ /**
500
+ * Gets the current tasks in the AsyncResultList.
501
+ */
502
+ get tasks(): Map<string, AsyncResultListItem<T, E>>;
503
+ /**
504
+ * Gets the number of tasks in the list.
505
+ */
506
+ get length(): number;
507
+ /**
508
+ * Gets all tasks in the list as an array.
509
+ */
510
+ get items(): AsyncResult<T, E>[];
511
+ /**
512
+ * Gets the current state of the AsyncResultList.
513
+ */
514
+ get state(): AsyncResultListState;
515
+ private set state(value);
516
+ private _onTaskFinished;
517
+ /**
518
+ * Adds a listener that gets called whenever the state of the AsyncResultList changes.
519
+ * @param listener the function to call when the state changes
520
+ * @returns a function to unsubscribe the listener
521
+ */
522
+ listen(listener: (taskQueue: AsyncResultList<T, E>) => void): () => void;
523
+ /**
524
+ * Adds an AsyncResult task to the list.
525
+ * @param key the unique key for the task
526
+ * @param task the AsyncResult task to add
527
+ * @param removeOnSettle whether to remove the task from the list once it settles (defaults to true)
528
+ * @returns the added AsyncResult task
529
+ */
530
+ add(key: string, task: AsyncResult<T, E>, removeOnSettle?: boolean): AsyncResult<T, E>;
531
+ clear(): void;
532
+ /**
533
+ * Checks if any task in the list is currently loading.
534
+ * @returns true if any task is loading, false otherwise
535
+ */
536
+ anyLoading(): boolean;
537
+ /**
538
+ * Gets all tasks that satisfy the given predicate.
539
+ * @param predicate the function to test each task
540
+ * @returns an array of tasks that satisfy the predicate
541
+ */
542
+ getAllFiltered(predicate: (task: AsyncResult<T, E>) => boolean): AsyncResult<T, E>[];
543
+ /**
544
+ * Gets all tasks that satisfy the given predicate and maps them using the provided function.
545
+ * @param filterPredicate the function to test each task
546
+ * @param mapFunc the function to map each task
547
+ * @returns an array of mapped values
548
+ */
549
+ getAllFilteredAndMap<U>(filterPredicate: (task: AsyncResult<T, E>) => boolean, mapFunc: (task: AsyncResult<T, E>) => U): U[];
550
+ /**
551
+ * Gets all tasks that have succeeded.
552
+ * @returns an array of successful AsyncResult tasks
553
+ */
554
+ getAllSuccess(): AsyncResult<T, E>[];
555
+ /**
556
+ * Gets the success values of all tasks that have succeeded.
557
+ * @returns an array of successful values
558
+ */
559
+ getAllSuccessValues(): T[];
560
+ /**
561
+ * Gets all tasks that have errored.
562
+ * @returns an array of error AsyncResult tasks
563
+ */
564
+ getAllErrors(): AsyncResult<T, E>[];
565
+ /**
566
+ * Gets the error values of all tasks that have errored.
567
+ * @returns an array of error values
568
+ */
569
+ getAllErrorValues(): E[];
570
+ /**
571
+ * Gets all tasks that are currently loading.
572
+ * @returns an array of loading AsyncResult tasks
573
+ */
574
+ getAllLoading(): AsyncResult<T, E>[];
575
+ /**
576
+ * Gets the promises of all tasks that are currently loading.
577
+ * @returns an array of promises for loading tasks
578
+ */
579
+ getAllLoadingPromises(): Promise<Result<T, E>>[];
580
+ /**
581
+ * Logs the current state and tasks of the AsyncResultList to the console.
582
+ * @param name an optional name to identify the log
583
+ */
584
+ log(name?: string): void;
585
+ /**
586
+ * Sets up a listener to log the state and tasks of the AsyncResultList whenever it changes.
587
+ * @param name an optional name to identify the log
588
+ * @returns a function to unsubscribe the debug listener
589
+ */
590
+ debug(name?: string): () => void;
591
+ }
592
+
478
593
  type KeyedAsyncCacheRefetchOptions = {
479
594
  policy: 'refetch' | 'if-error' | 'no-refetch';
480
595
  };
@@ -541,4 +656,6 @@ declare class KeyedAsyncCache<P, V, E extends ErrorBase = ErrorBase> {
541
656
  invalidateAll(): void;
542
657
  }
543
658
 
544
- export { type Action, AsyncResult, type AsyncResultGenerator, type AsyncResultListener, type AsyncResultState, type ChainStep, ErrorBase, type FlatChainStep, KeyedAsyncCache, type LazyAction, Result, type ResultState };
659
+ declare function delay(ms: number): AsyncResult<true>;
660
+
661
+ export { type Action, AsyncResult, type AsyncResultGenerator, AsyncResultList, type AsyncResultListItem, type AsyncResultListState, type AsyncResultListener, type AsyncResultState, type ChainStep, ErrorBase, type FlatChainStep, KeyedAsyncCache, type LazyAction, Result, type ResultState, delay };
@@ -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, 7);
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,191 @@ 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()).map((i) => i.result);
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
+ let unsub = null;
773
+ if (removeOnSettle) {
774
+ unsub = task.listenUntilSettled((r) => {
775
+ if (r.isLoading() || r.isIdle()) return;
776
+ this._onTaskFinished();
777
+ this._list.delete(key);
778
+ }, true);
779
+ } else {
780
+ unsub = task.listen((r) => {
781
+ if (r.isLoading() || r.isIdle()) return;
782
+ this._onTaskFinished();
783
+ }, true);
784
+ }
785
+ this._list.set(key, { key, result: task, unsub });
786
+ this.state = "any-loading";
787
+ return task;
788
+ }
789
+ clear() {
790
+ this._list.forEach(({ unsub }) => unsub());
791
+ this._list.clear();
792
+ this.state = "all-settled";
793
+ }
794
+ // === Querying tasks ===
795
+ /**
796
+ * Checks if any task in the list is currently loading.
797
+ * @returns true if any task is loading, false otherwise
798
+ */
799
+ anyLoading() {
800
+ for (const item of this._list.values()) {
801
+ if (item.result.isLoading()) {
802
+ return true;
803
+ }
804
+ }
805
+ return false;
806
+ }
807
+ /**
808
+ * Gets all tasks that satisfy the given predicate.
809
+ * @param predicate the function to test each task
810
+ * @returns an array of tasks that satisfy the predicate
811
+ */
812
+ getAllFiltered(predicate) {
813
+ const filtered = [];
814
+ for (const item of this._list.values()) {
815
+ if (predicate(item.result)) {
816
+ filtered.push(item.result);
817
+ }
818
+ }
819
+ return filtered;
820
+ }
821
+ /**
822
+ * Gets all tasks that satisfy the given predicate and maps them using the provided function.
823
+ * @param filterPredicate the function to test each task
824
+ * @param mapFunc the function to map each task
825
+ * @returns an array of mapped values
826
+ */
827
+ getAllFilteredAndMap(filterPredicate, mapFunc) {
828
+ const results = [];
829
+ for (const item of this._list.values()) {
830
+ if (filterPredicate(item.result)) {
831
+ results.push(mapFunc(item.result));
832
+ }
833
+ }
834
+ return results;
835
+ }
836
+ /**
837
+ * Gets all tasks that have succeeded.
838
+ * @returns an array of successful AsyncResult tasks
839
+ */
840
+ getAllSuccess() {
841
+ return this.getAllFiltered((task) => task.isSuccess());
842
+ }
843
+ /**
844
+ * Gets the success values of all tasks that have succeeded.
845
+ * @returns an array of successful values
846
+ */
847
+ getAllSuccessValues() {
848
+ return this.getAllFilteredAndMap((task) => task.isSuccess(), (task) => task.unwrapOrThrow());
849
+ }
850
+ /**
851
+ * Gets all tasks that have errored.
852
+ * @returns an array of error AsyncResult tasks
853
+ */
854
+ getAllErrors() {
855
+ return this.getAllFiltered((task) => task.isError());
856
+ }
857
+ /**
858
+ * Gets the error values of all tasks that have errored.
859
+ * @returns an array of error values
860
+ */
861
+ getAllErrorValues() {
862
+ return this.getAllFilteredAndMap((task) => task.isError(), (task) => task.unwrapErrorOrNull());
863
+ }
864
+ /**
865
+ * Gets all tasks that are currently loading.
866
+ * @returns an array of loading AsyncResult tasks
867
+ */
868
+ getAllLoading() {
869
+ return this.getAllFiltered((task) => task.isLoading());
870
+ }
871
+ /**
872
+ * Gets the promises of all tasks that are currently loading.
873
+ * @returns an array of promises for loading tasks
874
+ */
875
+ getAllLoadingPromises() {
876
+ return this.getAllFilteredAndMap((task) => task.isLoading(), (task) => task.toResultPromise());
877
+ }
878
+ // === Debugging utilities ===
879
+ /**
880
+ * Logs the current state and tasks of the AsyncResultList to the console.
881
+ * @param name an optional name to identify the log
882
+ */
883
+ log(name) {
884
+ const time = (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8);
885
+ console.log(`${name ?? "<Anonymous TaskQueue>"} ; State at ${time} :`, this.state, this._list);
886
+ }
887
+ /**
888
+ * Sets up a listener to log the state and tasks of the AsyncResultList whenever it changes.
889
+ * @param name an optional name to identify the log
890
+ * @returns a function to unsubscribe the debug listener
891
+ */
892
+ debug(name) {
893
+ return this.listen(() => {
894
+ this.log(name);
895
+ });
896
+ }
897
+ };
898
+
702
899
  // src/core/cache.ts
703
900
  var _defaultRefetchOptions = { policy: "no-refetch" };
704
901
  function defaultParamsToKey(params) {
@@ -836,11 +1033,20 @@ var KeyedAsyncCache = class {
836
1033
  }
837
1034
  }
838
1035
  };
1036
+
1037
+ // src/core/utils.ts
1038
+ function delay(ms) {
1039
+ return AsyncResult.fromValuePromise(new Promise((resolve) => {
1040
+ setTimeout(() => resolve(true), ms);
1041
+ }));
1042
+ }
839
1043
  // Annotate the CommonJS export names for ESM import in node:
840
1044
  0 && (module.exports = {
841
1045
  AsyncResult,
1046
+ AsyncResultList,
842
1047
  ErrorBase,
843
1048
  KeyedAsyncCache,
844
- Result
1049
+ Result,
1050
+ delay
845
1051
  });
846
1052
  //# sourceMappingURL=index.js.map