resultar 3.0.0 → 3.1.0

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/index.js CHANGED
@@ -1,3 +1,14 @@
1
+ //#region src/abort-error.ts
2
+ var AbortError = class extends Error {
3
+ constructor(message = "Operation aborted", options) {
4
+ super(message, options);
5
+ this.name = "AbortError";
6
+ }
7
+ };
8
+ const hasAbortName = (value) => typeof value === "object" && value !== null && "name" in value && value.name === "AbortError";
9
+ const hasAbortCode = (value) => typeof value === "object" && value !== null && "code" in value && value.code === "ABORT_ERR";
10
+ const isAbortError = (value) => value instanceof AbortError || hasAbortName(value) || hasAbortCode(value);
11
+ //#endregion
1
12
  //#region src/pipe.ts
2
13
  const runPipe = (self, fns) => {
3
14
  const first = fns[0];
@@ -79,6 +90,14 @@ const combineResultList = (resultList) => {
79
90
  }
80
91
  return ok(values);
81
92
  };
93
+ const combineResultRecord = (resultRecord) => {
94
+ const values = {};
95
+ for (const [key, result] of Object.entries(resultRecord)) {
96
+ if (result.isErr()) return err(result.error);
97
+ values[key] = result.value;
98
+ }
99
+ return ok(values);
100
+ };
82
101
  const combineResultListWithAllErrors = (resultList) => {
83
102
  let acc = ok([]);
84
103
  for (const result of resultList) if (result.isErr() && acc.isErr()) acc.error.push(result.error);
@@ -86,6 +105,15 @@ const combineResultListWithAllErrors = (resultList) => {
86
105
  else if (result.isOk() && acc.isOk()) acc.value.push(result.value);
87
106
  return acc;
88
107
  };
108
+ const combineResultRecordWithAllErrors = (resultRecord) => {
109
+ const errors = [];
110
+ const values = {};
111
+ for (const [key, result] of Object.entries(resultRecord)) if (result.isErr()) errors.push(result.error);
112
+ else values[key] = result.value;
113
+ if (errors.length > 0) return err(errors);
114
+ return ok(values);
115
+ };
116
+ const isIterable$1 = (value) => typeof value === "object" && value !== null && Symbol.iterator in value;
89
117
  const validateAllResultItems = (items, f) => {
90
118
  return combineResultListWithAllErrors(Array.from(items, f));
91
119
  };
@@ -106,6 +134,7 @@ const firstSuccessOfResultCandidates = (candidates) => {
106
134
  if (!hasCandidates || latestError === void 0) throw createEmptyResultsCollectionError();
107
135
  return latestError;
108
136
  };
137
+ const getReason$1 = (value) => typeof value === "object" && value !== null && "reason" in value ? value.reason : void 0;
109
138
  const loopResult = (initial, options) => {
110
139
  let state = initial;
111
140
  const values = [];
@@ -223,11 +252,15 @@ var ResultNamespace = class {
223
252
  static err(error) {
224
253
  return err(error);
225
254
  }
226
- static combine(resultList) {
227
- return combineResultList(resultList);
255
+ static combine(input) {
256
+ if (Array.isArray(input)) return combineResultList(input);
257
+ if (isIterable$1(input)) return combineResultList([...input]);
258
+ return combineResultRecord(input);
228
259
  }
229
- static combineWithAllErrors(resultList) {
230
- return combineResultListWithAllErrors(resultList);
260
+ static combineWithAllErrors(input) {
261
+ if (Array.isArray(input)) return combineResultListWithAllErrors(input);
262
+ if (isIterable$1(input)) return combineResultListWithAllErrors([...input]);
263
+ return combineResultRecordWithAllErrors(input);
231
264
  }
232
265
  static validateAll(resultListOrItems, f) {
233
266
  if (f === void 0) return combineResultListWithAllErrors(resultListOrItems);
@@ -314,6 +347,15 @@ var Ok = class extends ResultVariant {
314
347
  catchTags(_handlers) {
315
348
  return ok(this.value);
316
349
  }
350
+ catchReason(_errorTag, _reasonTag, _f) {
351
+ return ok(this.value);
352
+ }
353
+ catchReasons(_errorTag, _handlers) {
354
+ return ok(this.value);
355
+ }
356
+ unwrapReason(_errorTag) {
357
+ return ok(this.value);
358
+ }
317
359
  branchResult(fCondition, fTrue, fFalse) {
318
360
  return fCondition(this.value) ? fTrue(this.value) : fFalse(this.value);
319
361
  }
@@ -415,6 +457,27 @@ var Err = class extends ResultVariant {
415
457
  if (handled.matched) return handled.value;
416
458
  return err(error);
417
459
  }
460
+ catchReason(errorTag, reasonTag, f) {
461
+ if (hasTag(this.error, errorTag)) {
462
+ const reason = getReason$1(this.error);
463
+ if (hasTag(reason, reasonTag)) return f(reason, this.error);
464
+ }
465
+ return err(this.error);
466
+ }
467
+ catchReasons(errorTag, handlers) {
468
+ if (hasTag(this.error, errorTag)) {
469
+ const reason = getReason$1(this.error);
470
+ if (typeof reason === "object" && reason !== null && "_tag" in reason) {
471
+ const handler = handlers[reason._tag];
472
+ if (handler !== void 0) return handler(reason, this.error);
473
+ }
474
+ }
475
+ return err(this.error);
476
+ }
477
+ unwrapReason(errorTag) {
478
+ if (hasTag(this.error, errorTag)) return err(getReason$1(this.error));
479
+ return err(this.error);
480
+ }
418
481
  asyncAndThen(_f) {
419
482
  return createResultAsync(Promise.resolve(err(this.error)));
420
483
  }
@@ -559,9 +622,223 @@ function isTryResultAsyncOptions(input) {
559
622
  return typeof input === "object" && input !== null && "try" in input;
560
623
  }
561
624
  const combineResultAsyncList = (asyncResultList) => ResultAsync.fromSafePromise(Promise.all(asyncResultList)).andThen((resultList) => Result.combine(resultList));
625
+ const collectResultAsyncRecord = async (asyncResultRecord) => {
626
+ const entries = Object.entries(asyncResultRecord);
627
+ const resultList = await Promise.all(entries.map((entry) => entry[1]));
628
+ const resultRecord = {};
629
+ for (const [index, [key]] of entries.entries()) {
630
+ const result = resultList[index];
631
+ if (result !== void 0) resultRecord[key] = result;
632
+ }
633
+ return resultRecord;
634
+ };
635
+ const combineResultAsyncRecord = (asyncResultRecord) => {
636
+ return new ResultAsync(collectResultAsyncRecord(asyncResultRecord).then((resultRecord) => Result.combine(resultRecord)));
637
+ };
562
638
  const combineResultAsyncListWithAllErrors = (asyncResultList) => ResultAsync.fromSafePromise(Promise.all(asyncResultList)).andThen((resultList) => Result.combineWithAllErrors(resultList));
563
- const validateAllResultAsyncItems = (items, f) => {
564
- return combineResultAsyncListWithAllErrors(Array.from(items, f));
639
+ const combineResultAsyncRecordWithAllErrors = (asyncResultRecord) => {
640
+ return new ResultAsync(collectResultAsyncRecord(asyncResultRecord).then((resultRecord) => Result.combineWithAllErrors(resultRecord)));
641
+ };
642
+ const isIterable = (value) => typeof value === "object" && value !== null && Symbol.iterator in value;
643
+ const createIllegalArgumentException = (message) => {
644
+ const error = new Error(message);
645
+ error.name = "IllegalArgumentException";
646
+ return error;
647
+ };
648
+ const createInvalidResultAsyncConcurrencyError = () => createIllegalArgumentException("ResultAsync concurrency must be a positive integer or \"unbounded\"");
649
+ const normalizeResultAsyncConcurrency = (concurrency) => {
650
+ if (concurrency === void 0) return 1;
651
+ if (concurrency === "unbounded") return Number.POSITIVE_INFINITY;
652
+ if (Number.isInteger(concurrency) && concurrency > 0) return concurrency;
653
+ throw createInvalidResultAsyncConcurrencyError();
654
+ };
655
+ const toResultAsyncRejectionError = (error) => error instanceof Error ? error : new Error(String(error));
656
+ const sortIndexedResultAsyncErrors = (errors) => [...errors].toSorted((left, right) => left.index - right.index);
657
+ const createResultAsyncTraversalState = () => ({
658
+ activeCount: 0,
659
+ errors: [],
660
+ iteratorDone: false,
661
+ nextIndex: 0,
662
+ stopScheduling: false,
663
+ values: []
664
+ });
665
+ const runConcurrentResultAsyncItems = (options) => Promise.try(async () => {
666
+ const concurrency = normalizeResultAsyncConcurrency(options.concurrency);
667
+ const iterator = options.items[Symbol.iterator]();
668
+ const state = createResultAsyncTraversalState();
669
+ return new Promise((resolve, reject) => {
670
+ let settled = false;
671
+ const rejectOnce = (error) => {
672
+ if (!settled) {
673
+ settled = true;
674
+ reject(toResultAsyncRejectionError(error));
675
+ }
676
+ };
677
+ const resolveOnce = (result) => {
678
+ if (!settled) {
679
+ settled = true;
680
+ resolve(result);
681
+ }
682
+ };
683
+ const finishIfDone = () => {
684
+ const result = options.finish(state);
685
+ if (result !== void 0) resolveOnce(result);
686
+ };
687
+ const readNext = () => {
688
+ try {
689
+ return iterator.next();
690
+ } catch (error) {
691
+ rejectOnce(error);
692
+ return;
693
+ }
694
+ };
695
+ const schedule = () => {
696
+ if (settled) return;
697
+ if (state.stopScheduling) {
698
+ finishIfDone();
699
+ return;
700
+ }
701
+ while (!state.iteratorDone && state.activeCount < concurrency) {
702
+ const next = readNext();
703
+ if (next === void 0) return;
704
+ if (next.done === true) {
705
+ state.iteratorDone = true;
706
+ break;
707
+ }
708
+ const currentIndex = state.nextIndex;
709
+ state.nextIndex += 1;
710
+ startItem(next.value, currentIndex);
711
+ }
712
+ finishIfDone();
713
+ };
714
+ const startItem = (item, currentIndex) => {
715
+ state.activeCount += 1;
716
+ try {
717
+ const resultAsync = options.run(item, currentIndex);
718
+ Promise.resolve(resultAsync).then((result) => {
719
+ options.onResult(result, currentIndex, state);
720
+ }, rejectOnce).finally(() => {
721
+ if (settled) return;
722
+ state.activeCount -= 1;
723
+ schedule();
724
+ finishIfDone();
725
+ });
726
+ } catch (error) {
727
+ rejectOnce(error);
728
+ }
729
+ };
730
+ schedule();
731
+ });
732
+ });
733
+ const createResultAsyncRetryContext = (attempt, times) => ({
734
+ attempt,
735
+ nextAttempt: attempt + 1,
736
+ retriesRemaining: Math.max(0, times - attempt)
737
+ });
738
+ const createResultAsyncRetryAbortError = (signal) => signal.reason === void 0 ? new AbortError("ResultAsync retry aborted") : new AbortError("ResultAsync retry aborted", { cause: signal.reason });
739
+ const createResultAsyncResourceAbortError = (signal) => signal.reason === void 0 ? new AbortError("ResultAsync resource scope aborted") : new AbortError("ResultAsync resource scope aborted", { cause: signal.reason });
740
+ const validateResultAsyncRetryTimes = (times) => {
741
+ if (!Number.isInteger(times) || times < 0) throw createIllegalArgumentException("ResultAsync retry times must be a non-negative integer");
742
+ };
743
+ const validateResultAsyncRetryDelayValue = (delayMs) => {
744
+ if (!Number.isFinite(delayMs) || delayMs < 0) throw createIllegalArgumentException("ResultAsync retry delayMs must be a non-negative finite number");
745
+ };
746
+ const validateResultAsyncRetryStaticDelay = (delay) => {
747
+ if (typeof delay === "number") validateResultAsyncRetryDelayValue(delay);
748
+ };
749
+ const normalizeResultAsyncRetryDelay = (delay, context) => {
750
+ const delayMs = typeof delay === "function" ? delay(context) : delay ?? 0;
751
+ validateResultAsyncRetryDelayValue(delayMs);
752
+ return delayMs;
753
+ };
754
+ const waitResultAsyncRetryDelay = async (delayMs, signal) => {
755
+ if (signal.aborted) return Result.err(createResultAsyncRetryAbortError(signal));
756
+ if (delayMs === 0) return Result.ok(void 0);
757
+ return new Promise((resolve) => {
758
+ const timeout = setTimeout(() => {
759
+ signal.removeEventListener("abort", abort);
760
+ resolve(Result.ok(void 0));
761
+ }, delayMs);
762
+ const abort = () => {
763
+ clearTimeout(timeout);
764
+ resolve(Result.err(createResultAsyncRetryAbortError(signal)));
765
+ };
766
+ signal.addEventListener("abort", abort, { once: true });
767
+ });
768
+ };
769
+ const callResultAsyncRetryOnRetry = async (options, error, context) => {
770
+ try {
771
+ await options.onRetry?.(error, context);
772
+ } catch {}
773
+ };
774
+ const shouldRetryResultAsyncError = async (options, error, context) => options.while?.(error, context) ?? true;
775
+ const resolveResultAsyncRetryRecovery = async (recovered) => recovered instanceof ResultAsync ? recovered : recovered;
776
+ const runResultAsyncRetryAttempts = async (task, options, recover) => {
777
+ validateResultAsyncRetryTimes(options.times);
778
+ validateResultAsyncRetryStaticDelay(options.delayMs);
779
+ const signal = options.signal ?? new AbortController().signal;
780
+ let attempt = 0;
781
+ while (true) {
782
+ if (signal.aborted) return Result.err(createResultAsyncRetryAbortError(signal));
783
+ const result = await task(attempt, signal);
784
+ if (result.isOk()) return Result.ok(result.value);
785
+ const context = createResultAsyncRetryContext(attempt, options.times);
786
+ if (!await shouldRetryResultAsyncError(options, result.error, context) || attempt >= options.times) return resolveResultAsyncRetryRecovery(recover(result.error, context));
787
+ await callResultAsyncRetryOnRetry(options, result.error, context);
788
+ const delayResult = await waitResultAsyncRetryDelay(normalizeResultAsyncRetryDelay(options.delayMs, context), signal);
789
+ if (delayResult.isErr()) return Result.err(delayResult.error);
790
+ attempt += 1;
791
+ }
792
+ };
793
+ const retryResultAsyncTask = (task, options) => new ResultAsync(runResultAsyncRetryAttempts(task, options, (error) => Result.err(error)));
794
+ const retryOrElseResultAsyncTask = (task, options) => new ResultAsync(runResultAsyncRetryAttempts(task, options, (error, context) => options.orElse(error, context)));
795
+ const callResultAsyncResourceRelease = async (release, resource, context) => {
796
+ try {
797
+ await release(resource, context);
798
+ } catch {}
799
+ };
800
+ const runResultAsyncWithResource = async (options) => {
801
+ const signal = options.signal ?? new AbortController().signal;
802
+ if (signal.aborted) return Result.err(createResultAsyncResourceAbortError(signal));
803
+ const acquired = await options.acquire(signal);
804
+ if (acquired.isErr()) return Result.err(acquired.error);
805
+ let result = void 0;
806
+ try {
807
+ if (signal.aborted) {
808
+ result = Result.err(createResultAsyncResourceAbortError(signal));
809
+ return result;
810
+ }
811
+ result = await toResultAsync(options.use(acquired.value, signal));
812
+ return result;
813
+ } finally {
814
+ await callResultAsyncResourceRelease(options.release, acquired.value, {
815
+ result,
816
+ signal
817
+ });
818
+ }
819
+ };
820
+ const withResultAsyncResource = (options) => new ResultAsync(runResultAsyncWithResource(options));
821
+ const validateAllResultAsyncItems = (items, f, options) => {
822
+ return new ResultAsync(runConcurrentResultAsyncItems({
823
+ concurrency: options?.concurrency,
824
+ finish: (state) => {
825
+ if (!state.iteratorDone || state.activeCount > 0) return;
826
+ if (state.errors.length > 0) return Result.err(sortIndexedResultAsyncErrors(state.errors).map((entry) => entry.error));
827
+ return Result.ok(state.values);
828
+ },
829
+ items,
830
+ onResult: (result, currentIndex, state) => {
831
+ if (result.isErr()) {
832
+ state.errors.push({
833
+ error: result.error,
834
+ index: currentIndex
835
+ });
836
+ return;
837
+ }
838
+ state.values[currentIndex] = result.value;
839
+ },
840
+ run: f
841
+ }));
565
842
  };
566
843
  const firstSuccessOfAsyncCandidates = (candidates) => {
567
844
  return new ResultAsync(Promise.try(async () => {
@@ -577,6 +854,96 @@ const firstSuccessOfAsyncCandidates = (candidates) => {
577
854
  return latestError;
578
855
  }));
579
856
  };
857
+ const getReason = (value) => typeof value === "object" && value !== null && "reason" in value ? value.reason : void 0;
858
+ const createRaceAbortReason = () => new AbortError("ResultAsync race loser interrupted");
859
+ const startRaceTask = (task, index) => {
860
+ const controller = new AbortController();
861
+ const result = task(controller.signal);
862
+ return {
863
+ controller,
864
+ result,
865
+ settled: Promise.resolve(result).then((taskResult) => ({
866
+ index,
867
+ result: taskResult
868
+ }))
869
+ };
870
+ };
871
+ const abortStartedRaceTask = (task, reason = createRaceAbortReason()) => {
872
+ if (!task.controller.signal.aborted) task.controller.abort(reason);
873
+ };
874
+ const createRaceHandle = (task) => ({
875
+ get signal() {
876
+ return task.controller.signal;
877
+ },
878
+ abort(reason) {
879
+ abortStartedRaceTask(task, reason);
880
+ },
881
+ wait() {
882
+ return task.result;
883
+ }
884
+ });
885
+ const abortRaceLosers = (startedTasks, winnerIndex) => {
886
+ const winner = startedTasks[winnerIndex];
887
+ for (const loser of startedTasks) if (loser !== winner) abortStartedRaceTask(loser);
888
+ };
889
+ const abortPendingRaceLosers = (startedTasks, winnerIndex, completedIndexes) => {
890
+ const winner = startedTasks[winnerIndex];
891
+ for (const [index, loser] of startedTasks.entries()) if (loser !== winner && !completedIndexes.has(index)) abortStartedRaceTask(loser);
892
+ };
893
+ const observeRaceFirstTask = (task, context) => {
894
+ task.settled.then(({ index, result }) => {
895
+ if (context.state.settled) return;
896
+ context.state.settled = true;
897
+ abortRaceLosers(context.startedTasks, index);
898
+ context.resolve(result);
899
+ });
900
+ };
901
+ const observeRaceSuccessTask = (task, context) => {
902
+ task.settled.then(({ index, result }) => {
903
+ if (context.state.settled) return;
904
+ context.state.completedIndexes.add(index);
905
+ if (result.isOk()) {
906
+ context.state.settled = true;
907
+ abortPendingRaceLosers(context.startedTasks, index, context.state.completedIndexes);
908
+ context.resolve(result);
909
+ return;
910
+ }
911
+ context.state.completedCount += 1;
912
+ context.state.latestError = result;
913
+ if (context.state.completedCount === context.startedTasks.length && context.state.latestError !== void 0) {
914
+ context.state.settled = true;
915
+ context.resolve(context.state.latestError);
916
+ }
917
+ });
918
+ };
919
+ const observeRaceResultAsyncTasks = (tasks, createContext, observeTask) => {
920
+ const taskList = [...tasks];
921
+ if (taskList.length === 0) return new ResultAsync(Promise.resolve(Result.err(createEmptyResultsCollectionError())));
922
+ return new ResultAsync(new Promise((resolve) => {
923
+ const startedTasks = taskList.map((task, index) => startRaceTask(task, index));
924
+ const context = createContext(resolve, startedTasks);
925
+ for (const task of startedTasks) observeTask(task, context);
926
+ }));
927
+ };
928
+ const raceFirstResultAsyncTasks = (tasks) => observeRaceResultAsyncTasks(tasks, (resolve, startedTasks) => ({
929
+ resolve,
930
+ startedTasks,
931
+ state: { settled: false }
932
+ }), (task, context) => {
933
+ observeRaceFirstTask(task, context);
934
+ });
935
+ const raceResultAsyncTasks = (tasks) => observeRaceResultAsyncTasks(tasks, (resolve, startedTasks) => ({
936
+ resolve,
937
+ startedTasks,
938
+ state: {
939
+ completedCount: 0,
940
+ completedIndexes: /* @__PURE__ */ new Set(),
941
+ latestError: void 0,
942
+ settled: false
943
+ }
944
+ }), (task, context) => {
945
+ observeRaceSuccessTask(task, context);
946
+ });
580
947
  const loopResultAsync = (initial, options) => {
581
948
  return new ResultAsync(Promise.try(async () => {
582
949
  let state = initial;
@@ -603,17 +970,28 @@ const iterateResultAsync = (initial, options) => {
603
970
  }));
604
971
  };
605
972
  const forEachResultAsync = (items, f, options) => {
606
- return new ResultAsync(Promise.try(async () => {
607
- const values = [];
608
- let index = 0;
609
- for (const item of items) {
610
- const result = await f(item, index);
611
- if (result.isErr()) return Result.err(result.error);
612
- if (options?.discard !== true) values.push(result.value);
613
- index += 1;
614
- }
615
- if (options?.discard === true) return Result.ok(void 0);
616
- return Result.ok(values);
973
+ return new ResultAsync(runConcurrentResultAsyncItems({
974
+ concurrency: options?.concurrency,
975
+ finish: (state) => {
976
+ if (state.activeCount > 0 || !state.iteratorDone && !state.stopScheduling) return;
977
+ const firstError = sortIndexedResultAsyncErrors(state.errors)[0];
978
+ if (firstError !== void 0) return Result.err(firstError.error);
979
+ if (options?.discard === true) return Result.ok(void 0);
980
+ return Result.ok(state.values);
981
+ },
982
+ items,
983
+ onResult: (result, currentIndex, state) => {
984
+ if (result.isErr()) {
985
+ state.errors.push({
986
+ error: result.error,
987
+ index: currentIndex
988
+ });
989
+ state.stopScheduling = true;
990
+ return;
991
+ }
992
+ if (options?.discard !== true) state.values[currentIndex] = result.value;
993
+ },
994
+ run: f
617
995
  }));
618
996
  };
619
997
  const resolveResultAsyncBooleanCondition = (condition) => typeof condition === "function" ? condition() : condition;
@@ -719,7 +1097,7 @@ var DisposableResultAsync = class {
719
1097
  */
720
1098
  var ResultAsync = class ResultAsync extends Pipeable {
721
1099
  static okAsync(value) {
722
- return new ResultAsync(Promise.resolve(Result.ok(value)));
1100
+ return new ResultAsync(Promise.resolve(ok(value)));
723
1101
  }
724
1102
  /**
725
1103
  * Returns a ResultAsync that is immediately resolved with a Result.ok(undefined) value.
@@ -730,33 +1108,103 @@ var ResultAsync = class ResultAsync extends Pipeable {
730
1108
  return new ResultAsync(Promise.resolve(Result.unit()));
731
1109
  }
732
1110
  static errAsync(error) {
733
- return new ResultAsync(Promise.resolve(Result.err(error)));
1111
+ return new ResultAsync(Promise.resolve(err(error)));
734
1112
  }
735
1113
  static tryCatch(fn, errorFn) {
736
- return new ResultAsync((typeof fn === "function" ? Promise.try(fn) : fn).then((value) => Result.ok(value)).catch((error) => {
737
- if (errorFn) return Result.err(errorFn(error));
738
- return Result.err(error);
1114
+ return new ResultAsync((typeof fn === "function" ? Promise.try(fn) : fn).then((value) => ok(value)).catch((error) => {
1115
+ if (errorFn) return err(errorFn(error));
1116
+ return err(error);
739
1117
  }));
740
1118
  }
741
1119
  static fromSafePromise(promise) {
742
- return new ResultAsync(promise.then((value) => Result.ok(value)));
1120
+ return new ResultAsync(promise.then((value) => ok(value)));
743
1121
  }
744
1122
  static fromPromise(promise, errorFn) {
745
- return new ResultAsync(promise.then((value) => Result.ok(value)).catch((error) => Result.err(errorFn(error))));
1123
+ return new ResultAsync(promise.then((value) => ok(value)).catch((error) => err(errorFn(error))));
746
1124
  }
747
- static combine(asyncResultList) {
748
- return combineResultAsyncList(asyncResultList);
1125
+ static combine(input) {
1126
+ if (Array.isArray(input)) return combineResultAsyncList(input);
1127
+ if (isIterable(input)) return combineResultAsyncList([...input]);
1128
+ return combineResultAsyncRecord(input);
749
1129
  }
750
- static combineWithAllErrors(asyncResultList) {
751
- return combineResultAsyncListWithAllErrors(asyncResultList);
1130
+ static combineWithAllErrors(input) {
1131
+ if (Array.isArray(input)) return combineResultAsyncListWithAllErrors(input);
1132
+ if (isIterable(input)) return combineResultAsyncListWithAllErrors([...input]);
1133
+ return combineResultAsyncRecordWithAllErrors(input);
752
1134
  }
753
- static validateAll(asyncResultListOrItems, f) {
1135
+ static validateAll(asyncResultListOrItems, f, options) {
754
1136
  if (f === void 0) return combineResultAsyncListWithAllErrors(asyncResultListOrItems);
755
- return validateAllResultAsyncItems(asyncResultListOrItems, f);
1137
+ return validateAllResultAsyncItems(asyncResultListOrItems, f, options);
756
1138
  }
757
1139
  static zip(left, right) {
758
1140
  return combineResultAsyncList([left, right]);
759
1141
  }
1142
+ static retry(task, options) {
1143
+ return retryResultAsyncTask(task, options);
1144
+ }
1145
+ static retryOrElse(task, options) {
1146
+ return retryOrElseResultAsyncTask(task, options);
1147
+ }
1148
+ static withResource(options) {
1149
+ return withResultAsyncResource(options);
1150
+ }
1151
+ static race(left, right) {
1152
+ return raceResultAsyncTasks([left, right]);
1153
+ }
1154
+ static raceAll(tasks) {
1155
+ return raceResultAsyncTasks(tasks);
1156
+ }
1157
+ static raceFirst(left, right) {
1158
+ return raceFirstResultAsyncTasks([left, right]);
1159
+ }
1160
+ static raceWith(left, right, handlers) {
1161
+ return new ResultAsync(new Promise((resolve) => {
1162
+ const leftTask = startRaceTask(left, 0);
1163
+ const rightTask = startRaceTask(right, 1);
1164
+ const leftHandle = createRaceHandle(leftTask);
1165
+ const rightHandle = createRaceHandle(rightTask);
1166
+ let settled = false;
1167
+ leftTask.settled.then(({ result }) => {
1168
+ if (settled) return;
1169
+ settled = true;
1170
+ const handled = handlers.onLeftDone(result, rightHandle);
1171
+ Promise.resolve(toResultAsync(handled)).then((handledResult) => {
1172
+ resolve(handledResult);
1173
+ });
1174
+ });
1175
+ rightTask.settled.then(({ result }) => {
1176
+ if (settled) return;
1177
+ settled = true;
1178
+ const handled = handlers.onRightDone(result, leftHandle);
1179
+ Promise.resolve(toResultAsync(handled)).then((handledResult) => {
1180
+ resolve(handledResult);
1181
+ });
1182
+ });
1183
+ }));
1184
+ }
1185
+ static timeout(task, options) {
1186
+ const timeoutTask = (signal) => {
1187
+ return new ResultAsync(new Promise((resolve) => {
1188
+ const timeout = setTimeout(() => {
1189
+ resolve(Result.err(options.onTimeout()));
1190
+ }, options.timeoutMs);
1191
+ signal.addEventListener("abort", () => {
1192
+ clearTimeout(timeout);
1193
+ }, { once: true });
1194
+ }));
1195
+ };
1196
+ return ResultAsync.raceWith(task, timeoutTask, {
1197
+ onLeftDone: (result, timeoutHandle) => {
1198
+ timeoutHandle.abort(createRaceAbortReason());
1199
+ return result;
1200
+ },
1201
+ onRightDone: (result, taskHandle) => {
1202
+ if (result.isErr()) taskHandle.abort(result.error);
1203
+ else taskHandle.abort(createRaceAbortReason());
1204
+ return result;
1205
+ }
1206
+ });
1207
+ }
760
1208
  static firstSuccessOf(candidates) {
761
1209
  return firstSuccessOfAsyncCandidates(candidates);
762
1210
  }
@@ -796,11 +1244,9 @@ var ResultAsync = class ResultAsync extends Pipeable {
796
1244
  static fromThrowable(fn, errorFn) {
797
1245
  return (...args) => new ResultAsync((async () => {
798
1246
  try {
799
- const v = await fn(...args);
800
- return Result.ok(v);
1247
+ return ok(await fn(...args));
801
1248
  } catch (error) {
802
- const e = errorFn ? errorFn(error) : error;
803
- return Result.err(e);
1249
+ return err(errorFn ? errorFn(error) : error);
804
1250
  }
805
1251
  })());
806
1252
  }
@@ -814,32 +1260,32 @@ var ResultAsync = class ResultAsync extends Pipeable {
814
1260
  }
815
1261
  mapErr(f) {
816
1262
  return new ResultAsync(this.innerPromise.then(async (res) => {
817
- if (res.isOk()) return Result.ok(res.value);
818
- return Result.err(await f(res.error));
1263
+ if (res.isOk()) return ok(res.value);
1264
+ return err(await f(res.error));
819
1265
  }));
820
1266
  }
821
1267
  map(f) {
822
1268
  return new ResultAsync(this.innerPromise.then(async (res) => {
823
- if (res.isErr()) return Result.err(res.error);
824
- return Result.ok(await f(res.value));
1269
+ if (res.isErr()) return err(res.error);
1270
+ return ok(await f(res.value));
825
1271
  }));
826
1272
  }
827
1273
  as(value) {
828
1274
  return new ResultAsync(this.innerPromise.then((res) => {
829
- if (res.isErr()) return Result.err(res.error);
830
- return Result.ok(value);
1275
+ if (res.isErr()) return err(res.error);
1276
+ return ok(value);
831
1277
  }));
832
1278
  }
833
1279
  filterOrElse(predicate, onFalse) {
834
1280
  return new ResultAsync(this.innerPromise.then(async (res) => {
835
- if (res.isErr()) return Result.err(res.error);
836
- if (await predicate(res.value)) return Result.ok(res.value);
837
- return Result.err(await onFalse(res.value));
1281
+ if (res.isErr()) return err(res.error);
1282
+ if (await predicate(res.value)) return ok(res.value);
1283
+ return err(await onFalse(res.value));
838
1284
  }));
839
1285
  }
840
1286
  andThen(f) {
841
1287
  return new ResultAsync(this.innerPromise.then((res) => {
842
- if (res.isErr()) return Result.err(res.error);
1288
+ if (res.isErr()) return err(res.error);
843
1289
  const next = f(res.value);
844
1290
  return next instanceof ResultAsync ? next.innerPromise : next;
845
1291
  }));
@@ -856,7 +1302,7 @@ var ResultAsync = class ResultAsync extends Pipeable {
856
1302
  const next = f(res.error);
857
1303
  return next instanceof ResultAsync ? next.innerPromise : next;
858
1304
  }
859
- return Result.ok(res.value);
1305
+ return ok(res.value);
860
1306
  }));
861
1307
  }
862
1308
  catchTag(tag, f) {
@@ -881,6 +1327,42 @@ var ResultAsync = class ResultAsync extends Pipeable {
881
1327
  return Result.err(error);
882
1328
  }));
883
1329
  }
1330
+ catchReason(errorTag, reasonTag, f) {
1331
+ return new ResultAsync(this.innerPromise.then((res) => {
1332
+ if (res.isOk()) return Result.ok(res.value);
1333
+ if (hasTag(res.error, errorTag)) {
1334
+ const reason = getReason(res.error);
1335
+ if (hasTag(reason, reasonTag)) {
1336
+ const next = f(reason, res.error);
1337
+ return next instanceof ResultAsync ? next.innerPromise : next;
1338
+ }
1339
+ }
1340
+ return Result.err(res.error);
1341
+ }));
1342
+ }
1343
+ catchReasons(errorTag, handlers) {
1344
+ return new ResultAsync(this.innerPromise.then((res) => {
1345
+ if (res.isOk()) return Result.ok(res.value);
1346
+ if (hasTag(res.error, errorTag)) {
1347
+ const reason = getReason(res.error);
1348
+ if (typeof reason === "object" && reason !== null && "_tag" in reason) {
1349
+ const handler = handlers[reason._tag];
1350
+ if (handler !== void 0) {
1351
+ const next = handler(reason, res.error);
1352
+ return next instanceof ResultAsync ? next.innerPromise : next;
1353
+ }
1354
+ }
1355
+ }
1356
+ return Result.err(res.error);
1357
+ }));
1358
+ }
1359
+ unwrapReason(errorTag) {
1360
+ return new ResultAsync(this.innerPromise.then((res) => {
1361
+ if (res.isOk()) return Result.ok(res.value);
1362
+ if (hasTag(res.error, errorTag)) return Result.err(getReason(res.error));
1363
+ return Result.err(res.error);
1364
+ }));
1365
+ }
884
1366
  async match(input, fnErr) {
885
1367
  return this.innerPromise.then((res) => typeof input === "function" ? res.match(input, getMatchErrorHandler(input, fnErr)) : res.match(input));
886
1368
  }
@@ -984,6 +1466,28 @@ function tryResultAsync(input, errorFn) {
984
1466
  /** Compatibility alias. Prefer `tryResultAsync` in new code. */
985
1467
  const tryCatchAsync = tryResultAsync;
986
1468
  //#endregion
1469
+ //#region src/redacted.ts
1470
+ const redactedValues = /* @__PURE__ */ new WeakMap();
1471
+ const formatRedacted = (label) => label === void 0 ? "<redacted>" : `<redacted:${label}>`;
1472
+ var RedactedValue = class {
1473
+ __resultarRedacted = true;
1474
+ label;
1475
+ constructor(value, label) {
1476
+ this.label = label;
1477
+ redactedValues.set(this, value);
1478
+ }
1479
+ toJSON() {
1480
+ return this.toString();
1481
+ }
1482
+ toString() {
1483
+ return formatRedacted(this.label);
1484
+ }
1485
+ };
1486
+ const redact = (value, label) => new RedactedValue(value, label);
1487
+ const isRedacted = (value) => typeof value === "object" && value !== null && redactedValues.has(value);
1488
+ const revealRedacted = (value) => redactedValues.get(value);
1489
+ const stringifyRedacted = (value) => value.toString();
1490
+ //#endregion
987
1491
  //#region src/tagged-error.ts
988
1492
  const defaultBaseError = Error;
989
1493
  const defaultMessageTemplate = "$message";
@@ -1020,7 +1524,7 @@ const templateValueStringifiers = {
1020
1524
  string: stringifyDirectTemplateValue,
1021
1525
  symbol: stringifySymbolTemplateValue
1022
1526
  };
1023
- const stringifyTemplateValue = (value) => templateValueStringifiers[typeof value]?.(value) ?? "";
1527
+ const stringifyTemplateValue = (value) => isRedacted(value) ? stringifyRedacted(value) : templateValueStringifiers[typeof value]?.(value) ?? "";
1024
1528
  const compileMessageInterpolator = (template) => (values) => template.replaceAll(templateVariableMatcher, (variable, key) => {
1025
1529
  const value = values?.[key];
1026
1530
  return value === void 0 ? variable : stringifyTemplateValue(value);
@@ -1043,13 +1547,23 @@ const assignReadonly = (target, key, value) => {
1043
1547
  writable: false
1044
1548
  });
1045
1549
  };
1046
- const serializeCause = (cause) => {
1047
- if (!isError(cause)) return cause;
1048
- return {
1550
+ const serializeTaggedValue = (value) => isRedacted(value) ? stringifyRedacted(value) : value;
1551
+ const serializeCause = (cause, seen = /* @__PURE__ */ new Set()) => {
1552
+ if (!isError(cause)) return serializeTaggedValue(cause);
1553
+ if (seen.has(cause)) return {
1554
+ cause: "[Circular]",
1049
1555
  message: cause.message,
1050
1556
  name: cause.name,
1051
1557
  stack: cause.stack
1052
1558
  };
1559
+ seen.add(cause);
1560
+ const json = {
1561
+ message: cause.message,
1562
+ name: cause.name,
1563
+ stack: cause.stack
1564
+ };
1565
+ if (cause.cause !== void 0) json["cause"] = serializeCause(cause.cause, seen);
1566
+ return json;
1053
1567
  };
1054
1568
  const findCause = (error, ErrorClass) => {
1055
1569
  const seen = /* @__PURE__ */ new Set();
@@ -1097,12 +1611,34 @@ function createTaggedError(options) {
1097
1611
  name: this.name
1098
1612
  };
1099
1613
  if (this.cause !== void 0) json["cause"] = serializeCause(this.cause);
1100
- for (const [key, value] of Object.entries(this)) if (!(key in json) && key !== "cause" && key !== "stack") json[key] = value;
1614
+ for (const [key, value] of Object.entries(this)) if (!(key in json) && key !== "cause" && key !== "stack") json[key] = serializeTaggedValue(value);
1101
1615
  return json;
1102
1616
  }
1103
1617
  }
1104
1618
  return GeneratedTaggedError;
1105
1619
  }
1620
+ const taggedEnum = () => {
1621
+ return new Proxy({
1622
+ $is(tag, value) {
1623
+ return typeof value === "object" && value !== null && "_tag" in value && value._tag === tag;
1624
+ },
1625
+ $match(value, handlers) {
1626
+ const handler = handlers[value._tag];
1627
+ if (handler === void 0) throw new Error(`No tagged enum handler for ${String(value._tag)}`);
1628
+ return handler(value);
1629
+ }
1630
+ }, { get(base, property, receiver) {
1631
+ if (property in base) return Reflect.get(base, property, receiver);
1632
+ if (typeof property !== "string") return;
1633
+ return (props) => {
1634
+ const value = { _tag: property };
1635
+ if (props !== void 0) {
1636
+ for (const [key, propValue] of Object.entries(props)) if (key !== "_tag") value[key] = propValue;
1637
+ }
1638
+ return Object.freeze(value);
1639
+ };
1640
+ } });
1641
+ };
1106
1642
  const matchError = (error, handlers) => {
1107
1643
  if ("_tag" in error && typeof error._tag === "string" && error._tag in handlers) {
1108
1644
  const handler = handlers[error._tag];
@@ -1120,6 +1656,6 @@ const matchErrorPartial = (error, handlers, fallback) => {
1120
1656
  return fallback(error);
1121
1657
  };
1122
1658
  //#endregion
1123
- export { DisposableResult, DisposableResultAsync, Result, ResultAsync, createTaggedError, tryResult as default, tryResult as try, tryResult, err, errAsync, findCause, fromPromise, fromSafePromise, fromThrowable, fromThrowableAsync, isError, matchError, matchErrorPartial, ok, okAsync, safeTry, tryResultAsync as tryAsync, tryResultAsync, tryCatch, tryCatchAsync, unit, unitAsync };
1659
+ export { AbortError, DisposableResult, DisposableResultAsync, Result, ResultAsync, createTaggedError, tryResult as default, tryResult as try, tryResult, err, errAsync, findCause, fromPromise, fromSafePromise, fromThrowable, fromThrowableAsync, isAbortError, isError, isRedacted, matchError, matchErrorPartial, ok, okAsync, redact, revealRedacted, safeTry, taggedEnum, tryResultAsync as tryAsync, tryResultAsync, tryCatch, tryCatchAsync, unit, unitAsync };
1124
1660
 
1125
1661
  //# sourceMappingURL=index.js.map