@nlozgachev/pipelined 0.42.0 → 0.43.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.
@@ -1,57 +1,5 @@
1
- import { D as Duration } from './Duration-BTeT9D-q.js';
2
- import { NonEmptyList } from './types.js';
3
-
4
- declare const _deferred: unique symbol;
5
- /**
6
- * A nominally typed, one-shot async value that supports `await` but enforces infallibility.
7
- *
8
- * Two design choices work together to make the guarantee structural rather than documentary:
9
- *
10
- * - The phantom `[_deferred]` symbol makes the type **nominal**: only values produced by
11
- * `Deferred.fromPromise` satisfy it. A plain object `{ then: ... }` does not.
12
- * - The single-parameter `.then()` **excludes rejection handlers** by construction. There is
13
- * no second argument to pass, so chaining and `.catch()` are impossible.
14
- *
15
- * This makes `Deferred<A>` the natural return type for `Task<A>`, which is guaranteed to
16
- * never reject.
17
- *
18
- * @example
19
- * ```ts
20
- * const value = await Deferred.fromPromise(Promise.resolve(42));
21
- * // value === 42
22
- * ```
23
- */
24
- type Deferred<A> = {
25
- readonly [_deferred]: A;
26
- readonly then: (onfulfilled: (value: A) => unknown) => void;
27
- };
28
- declare namespace Deferred {
29
- /**
30
- * Wraps a `Promise` into a `Deferred`, structurally excluding rejection handlers,
31
- * `.catch()`, `.finally()`, and chainable `.then()`.
32
- *
33
- * **Precondition**: `p` must never reject. If `p` rejects, the returned `Deferred` will
34
- * never resolve — `await`-ing it will hang indefinitely. Use `TaskResult.tryCatch` to
35
- * handle operations that may fail before converting to a `Deferred`.
36
- *
37
- * @example
38
- * ```ts
39
- * const d = Deferred.fromPromise(Promise.resolve("hello"));
40
- * const value = await d; // "hello"
41
- * ```
42
- */
43
- const fromPromise: <A>(p: Promise<A>) => Deferred<A>;
44
- /**
45
- * Converts a `Deferred` back into a `Promise`.
46
- *
47
- * @example
48
- * ```ts
49
- * const p = Deferred.toPromise(Deferred.fromPromise(Promise.resolve(42)));
50
- * // p is Promise<42>
51
- * ```
52
- */
53
- const toPromise: <A>(d: Deferred<A>) => Promise<A>;
54
- }
1
+ import { g as WithKind, n as WithValue, d as WithError, T as Thenable, D as Deferred, N as NonEmptyArr, e as WithErrors } from './InternalTypes-DsCqxWZm.mjs';
2
+ import { Duration } from './types.mjs';
55
3
 
56
4
  /**
57
5
  * A function that checks whether two values of type `A` are equal.
@@ -140,60 +88,6 @@ declare namespace Equality {
140
88
  const and: <A>(eq2: Equality<A>) => (eq1: Equality<A>) => Equality<A>;
141
89
  }
142
90
 
143
- type WithKind<K extends string> = {
144
- readonly kind: K;
145
- };
146
- type WithValue<T> = {
147
- readonly value: T;
148
- };
149
- type WithError<T> = {
150
- readonly error: T;
151
- };
152
- type WithErrors<T> = {
153
- readonly errors: NonEmptyList<T>;
154
- };
155
- type WithFirst<T> = {
156
- readonly first: T;
157
- };
158
- type WithSecond<T> = {
159
- readonly second: T;
160
- };
161
- type WithLog<T> = {
162
- readonly log: ReadonlyArray<T>;
163
- };
164
- /** Retry policy for `Op.interpret`. */
165
- type RetryOptions<E> = {
166
- readonly attempts: number;
167
- readonly backoff?: Duration | ((attempt: number) => Duration);
168
- readonly when?: (error: E) => boolean;
169
- };
170
- /** Timeout policy for `Op.interpret`. Wraps the entire retry sequence. */
171
- type TimeoutOptions<E> = {
172
- readonly duration: Duration;
173
- readonly onTimeout: () => E;
174
- };
175
- type WithTimeout<E> = {
176
- readonly timeout?: TimeoutOptions<E>;
177
- };
178
- type WithDuration = {
179
- readonly duration: Duration;
180
- };
181
- type WithN = {
182
- readonly n: number;
183
- };
184
- type WithConcurrency = {
185
- readonly concurrency?: number;
186
- };
187
- type WithSize = {
188
- readonly size?: number;
189
- };
190
- type WithCooldown = {
191
- readonly cooldown?: Duration;
192
- };
193
- type WithMinInterval = {
194
- readonly minInterval?: Duration;
195
- };
196
-
197
91
  type Some<A> = WithKind<"Some"> & WithValue<A>;
198
92
  type None = WithKind<"None">;
199
93
  /**
@@ -809,6 +703,545 @@ declare namespace Result {
809
703
  const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Result<E, R[K]>; }) => Result<E, R>;
810
704
  }
811
705
 
706
+ /**
707
+ * A Task that resolves to an optional value.
708
+ * Combines async operations with the Maybe type for values that may not exist.
709
+ *
710
+ * @example
711
+ * ```ts
712
+ * const findUser = (id: string): TaskMaybe<User> =>
713
+ * TaskMaybe.tryCatch(() => db.users.findById(id));
714
+ *
715
+ * pipe(
716
+ * findUser("123"),
717
+ * TaskMaybe.map(user => user.name),
718
+ * TaskMaybe.getOrElse(() => "Unknown")
719
+ * )();
720
+ * ```
721
+ */
722
+ type TaskMaybe<A> = Task<Maybe<A>>;
723
+ declare namespace TaskMaybe {
724
+ /**
725
+ * Wraps a value in a Some inside a Task.
726
+ */
727
+ const some: <A>(value: A) => TaskMaybe<A>;
728
+ /**
729
+ * Creates a TaskMaybe that resolves to None.
730
+ */
731
+ const none: <A = never>() => TaskMaybe<A>;
732
+ /**
733
+ * Lifts an Option into a TaskMaybe.
734
+ */
735
+ const fromMaybe: <A>(option: Maybe<A>) => TaskMaybe<A>;
736
+ /**
737
+ * Creates a TaskMaybe from a nullable value.
738
+ * Returns Some if the value is not null or undefined, None otherwise.
739
+ */
740
+ const fromNullable: <A>(value: A | null | undefined) => TaskMaybe<A>;
741
+ /**
742
+ * Creates a TaskMaybe from a Result.
743
+ * Ok becomes Some, Error becomes None (the error value is discarded).
744
+ */
745
+ const fromResult: <E, A>(result: Result<E, A>) => TaskMaybe<A>;
746
+ /**
747
+ * Lifts a Task into a TaskMaybe by wrapping its result in Some.
748
+ */
749
+ const fromTask: <A>(task: Task<A>) => TaskMaybe<A>;
750
+ /**
751
+ * Creates a TaskMaybe from a Promise-returning function.
752
+ * Returns Some if the promise resolves, None if it rejects.
753
+ * The factory optionally receives an `AbortSignal` forwarded from the call site.
754
+ *
755
+ * @example
756
+ * ```ts
757
+ * const fetchUser = TaskMaybe.tryCatch((signal) =>
758
+ * fetch("/user/1", { signal }).then(r => r.json())
759
+ * );
760
+ * ```
761
+ */
762
+ const tryCatch: <A>(f: (signal?: AbortSignal) => Thenable<A>) => TaskMaybe<A>;
763
+ /**
764
+ * Transforms the value inside a TaskMaybe.
765
+ */
766
+ const map: <A, B>(f: (a: A) => B) => (data: TaskMaybe<A>) => TaskMaybe<B>;
767
+ /**
768
+ * Chains TaskMaybe computations. If the first resolves to Some, passes the
769
+ * value to f. If the first resolves to None, propagates None.
770
+ *
771
+ * @example
772
+ * ```ts
773
+ * pipe(
774
+ * findUser("123"),
775
+ * TaskMaybe.chain(user => findOrg(user.orgId))
776
+ * )();
777
+ * ```
778
+ */
779
+ const chain: <A, B>(f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<B>;
780
+ /**
781
+ * Applies a function wrapped in a TaskMaybe to a value wrapped in a TaskMaybe.
782
+ * Both Tasks run in parallel.
783
+ */
784
+ const ap: <A>(arg: TaskMaybe<A>) => <B>(data: TaskMaybe<(a: A) => B>) => TaskMaybe<B>;
785
+ /**
786
+ * Extracts a value from a TaskMaybe by providing handlers for both cases.
787
+ */
788
+ const fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: TaskMaybe<A>) => Task<B>;
789
+ /**
790
+ * Pattern matches on a TaskMaybe, returning a Task of the result.
791
+ *
792
+ * @example
793
+ * ```ts
794
+ * pipe(
795
+ * findUser("123"),
796
+ * TaskMaybe.match({
797
+ * some: user => `Hello, ${user.name}`,
798
+ * none: () => "User not found"
799
+ * })
800
+ * )();
801
+ * ```
802
+ */
803
+ const match: <A, B>(cases: {
804
+ none: () => B;
805
+ some: (a: A) => B;
806
+ }) => (data: TaskMaybe<A>) => Task<B>;
807
+ /**
808
+ * Returns the value or a default if the TaskMaybe resolves to None.
809
+ * The default can be a different type, widening the result to `Task<A | B>`.
810
+ */
811
+ const getOrElse: <A, B>(defaultValue: () => B) => (data: TaskMaybe<A>) => Task<A | B>;
812
+ /**
813
+ * Executes a side effect on the value without changing the TaskMaybe.
814
+ * Useful for logging or debugging.
815
+ */
816
+ const tap: <A>(f: (a: A) => void) => (data: TaskMaybe<A>) => TaskMaybe<A>;
817
+ /**
818
+ * Filters the value inside a TaskMaybe. Returns None if the predicate fails.
819
+ */
820
+ const filter: <A>(predicate: (a: A) => boolean) => (data: TaskMaybe<A>) => TaskMaybe<A>;
821
+ /**
822
+ * Converts a TaskMaybe to a Task.Result, using onNone to produce the error value.
823
+ *
824
+ * @example
825
+ * ```ts
826
+ * pipe(
827
+ * findUser("123"),
828
+ * TaskMaybe.toResult(() => "User not found")
829
+ * );
830
+ * ```
831
+ */
832
+ const toResult: <E>(onNone: () => E) => <A>(data: TaskMaybe<A>) => Task.Result<E, A>;
833
+ /**
834
+ * Lifts a TaskMaybe value into an accumulator object.
835
+ *
836
+ * @example
837
+ * ```ts
838
+ * pipe(TaskMaybe.some(42), TaskMaybe.bindTo("value")); // TaskMaybe({ value: 42 })
839
+ * ```
840
+ */
841
+ const bindTo: <K extends string>(key: K) => <A>(data: TaskMaybe<A>) => TaskMaybe<{ [P in K]: A; }>;
842
+ /**
843
+ * Evaluates a new TaskMaybe using the current accumulator and attaches the output to a new key.
844
+ *
845
+ * @example
846
+ * ```ts
847
+ * pipe(
848
+ * TaskMaybe.some({ a: 1 }),
849
+ * TaskMaybe.bind("b", ({ a }) => TaskMaybe.some(a + 1))
850
+ * ); // TaskMaybe({ a: 1, b: 2 })
851
+ * ```
852
+ */
853
+ const bind: <K extends string, A, B>(key: K, f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<A & { [P in K]: B; }>;
854
+ /**
855
+ * Recovers from a None state by providing a fallback TaskMaybe.
856
+ *
857
+ * @example
858
+ * ```ts
859
+ * pipe(
860
+ * TaskMaybe.none(),
861
+ * TaskMaybe.recover(() => TaskMaybe.some(42))
862
+ * ); // TaskMaybe(42)
863
+ * ```
864
+ */
865
+ const recover: <A, B>(fallback: () => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<A | B>;
866
+ /**
867
+ * Combines a record of TaskMaybes into a single TaskMaybe of a record.
868
+ * Evaluates fields in parallel and returns None if any task resolves to None.
869
+ *
870
+ * @example
871
+ * ```ts
872
+ * TaskMaybe.struct({
873
+ * name: TaskMaybe.some("Alice"),
874
+ * age: TaskMaybe.some(30)
875
+ * }); // TaskMaybe({ name: "Alice", age: 30 })
876
+ * ```
877
+ */
878
+ const struct: <R extends Record<string, any>>(fields: { [K in keyof R]: TaskMaybe<R[K]>; }) => TaskMaybe<R>;
879
+ }
880
+
881
+ /**
882
+ * A Task that can fail with an error of type E or succeed with a value of type A.
883
+ * Combines async operations with typed error handling.
884
+ *
885
+ * @example
886
+ * ```ts
887
+ * const fetchUser = (id: string): TaskResult<Error, User> =>
888
+ * TaskResult.tryCatch(
889
+ * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
890
+ * (e) => new Error(`Failed to fetch user: ${e}`)
891
+ * );
892
+ * ```
893
+ */
894
+ type TaskResult<E, A> = Task<Result<E, A>>;
895
+ declare namespace TaskResult {
896
+ /**
897
+ * Wraps a value in a successful TaskResult.
898
+ */
899
+ const ok: <E, A>(value: A) => TaskResult<E, A>;
900
+ /**
901
+ * Creates a failed TaskResult with the given error.
902
+ */
903
+ const err: <E, A>(error: E) => TaskResult<E, A>;
904
+ /**
905
+ * Creates a TaskResult from a nullable value.
906
+ * Returns Ok if the value is not null or undefined, err from onNull otherwise.
907
+ */
908
+ const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
909
+ /**
910
+ * Creates a TaskResult from a Maybe.
911
+ * Some becomes Ok, None becomes err from onNone.
912
+ */
913
+ const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
914
+ /**
915
+ * Lifts a Result into a TaskResult.
916
+ */
917
+ const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
918
+ /**
919
+ * Wraps a Promise-returning function of any arguments, returning a new function
920
+ * that catches rejections and returns a TaskResult.
921
+ */
922
+ const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => Promise<A>, onError: (e: unknown) => E) => (...args: Args) => TaskResult<E, A>;
923
+ /**
924
+ * Creates a TaskResult from a function that may throw.
925
+ * Catches any errors and transforms them using the onError function.
926
+ * The factory optionally receives an `AbortSignal` forwarded from the call site.
927
+ *
928
+ * @example
929
+ * ```ts
930
+ * const fetchUser = (id: string): TaskResult<string, User> =>
931
+ * TaskResult.tryCatch(
932
+ * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
933
+ * String
934
+ * );
935
+ * ```
936
+ */
937
+ const tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
938
+ /**
939
+ * Transforms the success value inside a TaskResult.
940
+ */
941
+ const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
942
+ /**
943
+ * Transforms the error value inside a TaskResult.
944
+ */
945
+ const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
946
+ /**
947
+ * Chains TaskResult computations. If the first succeeds, passes the value to f.
948
+ * If the first fails, propagates the error.
949
+ */
950
+ const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
951
+ /**
952
+ * Extracts the value from a TaskResult by providing handlers for both cases.
953
+ */
954
+ const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
955
+ /**
956
+ * Pattern matches on a TaskResult, returning a Task of the result.
957
+ */
958
+ const match: <E, A, B>(cases: {
959
+ err: (e: E) => B;
960
+ ok: (a: A) => B;
961
+ }) => (data: TaskResult<E, A>) => Task<B>;
962
+ /**
963
+ * Recovers from an error by providing a fallback TaskResult.
964
+ * The fallback can produce a different success type, widening the result to `TaskResult<E, A | B>`.
965
+ */
966
+ const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
967
+ /**
968
+ * Returns the success value or a default value if the TaskResult is an error.
969
+ * The default can be a different type, widening the result to `Task<A | B>`.
970
+ */
971
+ const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
972
+ /**
973
+ * Executes a side effect on the success value without changing the TaskResult.
974
+ * Useful for logging or debugging.
975
+ */
976
+ const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
977
+ /**
978
+ * Executes a side effect on the error value without changing the TaskResult.
979
+ * Useful for logging or reporting async errors.
980
+ *
981
+ * @example
982
+ * ```ts
983
+ * pipe(
984
+ * fetchUser(id),
985
+ * TaskResult.tapError(e => console.error("fetch failed:", e)),
986
+ * TaskResult.chain(saveToCache),
987
+ * )
988
+ * ```
989
+ */
990
+ const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
991
+ /**
992
+ * Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
993
+ * Both Tasks run in parallel.
994
+ */
995
+ const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
996
+ /**
997
+ * Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
998
+ * Use as a terminal step in a `pipe` chain.
999
+ *
1000
+ * @example
1001
+ * ```ts
1002
+ * const controller = new AbortController();
1003
+ * const result = await pipe(
1004
+ * fetchUser("42"),
1005
+ * TaskResult.chain(user => fetchPosts(user.id)),
1006
+ * TaskResult.run(controller.signal),
1007
+ * );
1008
+ * if (Result.isOk(result)) render(result.value);
1009
+ * ```
1010
+ */
1011
+ const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Deferred<Result<E, A>>;
1012
+ /**
1013
+ * Converts a TaskResult value into an object containing a single property.
1014
+ * Initiates the pipeline accumulator record.
1015
+ *
1016
+ * @example
1017
+ * ```ts
1018
+ * pipe(TaskResult.ok(42), TaskResult.bindTo("value")); // TaskResult({ value: 42 })
1019
+ * ```
1020
+ */
1021
+ const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
1022
+ /**
1023
+ * Evaluates a new TaskResult using the current accumulator and attaches the output to a new key.
1024
+ *
1025
+ * @example
1026
+ * ```ts
1027
+ * pipe(
1028
+ * TaskResult.ok({ a: 1 }),
1029
+ * TaskResult.bind("b", ({ a }) => TaskResult.ok(a + 1))
1030
+ * ); // TaskResult({ a: 1, b: 2 })
1031
+ * ```
1032
+ */
1033
+ const bind: <K extends string, E, A, B>(key: K, f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A & { [P in K]: B; }>;
1034
+ /**
1035
+ * Combines a record of TaskResults into a single TaskResult of a record.
1036
+ * Evaluates all tasks in parallel, forwarding the AbortSignal down to each sub-task.
1037
+ * Returns the first Err encountered in key order.
1038
+ *
1039
+ * @example
1040
+ * ```ts
1041
+ * TaskResult.struct({
1042
+ * name: TaskResult.ok("Alice"),
1043
+ * age: TaskResult.ok(30)
1044
+ * }); // TaskResult({ name: "Alice", age: 30 })
1045
+ * ```
1046
+ */
1047
+ const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskResult<E, R[K]>; }) => TaskResult<E, R>;
1048
+ }
1049
+
1050
+ /**
1051
+ * A Task that resolves to a Validation — combining async operations with
1052
+ * error accumulation. Unlike TaskResult, multiple failures are collected
1053
+ * rather than short-circuiting on the first error.
1054
+ *
1055
+ * @example
1056
+ * ```ts
1057
+ * const validateName = (name: string): TaskValidation<string, string> =>
1058
+ * name.length > 0
1059
+ * ? TaskValidation.passed(name)
1060
+ * : TaskValidation.failed("Name is required");
1061
+ *
1062
+ * // Accumulate errors from multiple async validations using ap
1063
+ * pipe(
1064
+ * TaskValidation.passed((name: string) => (age: number) => ({ name, age })),
1065
+ * TaskValidation.ap(validateName("")),
1066
+ * TaskValidation.ap(validateAge(-1))
1067
+ * )();
1068
+ * // Failed(["Name is required", "Age must be positive"])
1069
+ * ```
1070
+ */
1071
+ type TaskValidation<E, A> = Task<Validation<E, A>>;
1072
+ declare namespace TaskValidation {
1073
+ /**
1074
+ * Wraps a value in a passed TaskValidation.
1075
+ */
1076
+ const passed: <E, A>(value: A) => TaskValidation<E, A>;
1077
+ /**
1078
+ * Creates a failed TaskValidation with a single error.
1079
+ */
1080
+ const failed: <E, A>(error: E) => TaskValidation<E, A>;
1081
+ /**
1082
+ * Creates a failed TaskValidation from multiple errors.
1083
+ */
1084
+ const failedAll: <E, A>(errors: NonEmptyArr<E>) => TaskValidation<E, A>;
1085
+ /**
1086
+ * Lifts a Validation into a TaskValidation.
1087
+ */
1088
+ const fromValidation: <E, A>(validation: Validation<E, A>) => TaskValidation<E, A>;
1089
+ /**
1090
+ * Creates a TaskValidation from a nullable value.
1091
+ * If the value is null or undefined, returns Failed with the error from onNull.
1092
+ * Otherwise, returns Passed.
1093
+ */
1094
+ const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskValidation<E, A>;
1095
+ /**
1096
+ * Creates a TaskValidation from a Maybe.
1097
+ * Some becomes Passed, None becomes Failed with the error from onNone.
1098
+ */
1099
+ const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskValidation<E, A>;
1100
+ /**
1101
+ * Creates a TaskValidation from a Result.
1102
+ * Ok becomes Passed, Err(e) becomes Failed([e]).
1103
+ */
1104
+ const fromResult: <E, A>(result: Result<E, A>) => TaskValidation<E, A>;
1105
+ /**
1106
+ * Creates a TaskValidation from a Promise-returning function.
1107
+ * Catches any errors and transforms them using the onError function.
1108
+ * The factory optionally receives an `AbortSignal` forwarded from the call site.
1109
+ *
1110
+ * @example
1111
+ * ```ts
1112
+ * const fetchUser = (id: string): TaskValidation<string, User> =>
1113
+ * TaskValidation.tryCatch(
1114
+ * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
1115
+ * e => `Failed to fetch user: ${e}`
1116
+ * );
1117
+ * ```
1118
+ */
1119
+ const tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, onError: (e: unknown) => E) => TaskValidation<E, A>;
1120
+ /**
1121
+ * Transforms the success value inside a TaskValidation.
1122
+ */
1123
+ const map: <E, A, B>(f: (a: A) => B) => (data: TaskValidation<E, A>) => TaskValidation<E, B>;
1124
+ /**
1125
+ * Applies a function wrapped in a TaskValidation to a value wrapped in a
1126
+ * TaskValidation. Both Tasks run in parallel and errors from both sides
1127
+ * are accumulated.
1128
+ *
1129
+ * @example
1130
+ * ```ts
1131
+ * pipe(
1132
+ * TaskValidation.passed((name: string) => (age: number) => ({ name, age })),
1133
+ * TaskValidation.ap(validateName(name)),
1134
+ * TaskValidation.ap(validateAge(age))
1135
+ * )();
1136
+ * ```
1137
+ */
1138
+ const ap: <E, A>(arg: TaskValidation<E, A>) => <B>(data: TaskValidation<E, (a: A) => B>) => TaskValidation<E, B>;
1139
+ /**
1140
+ * Extracts a value from a TaskValidation by providing handlers for both cases.
1141
+ */
1142
+ const fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: TaskValidation<E, A>) => Task<B>;
1143
+ /**
1144
+ * Pattern matches on a TaskValidation, returning a Task of the result.
1145
+ *
1146
+ * @example
1147
+ * ```ts
1148
+ * pipe(
1149
+ * validateForm(input),
1150
+ * TaskValidation.match({
1151
+ * passed: data => save(data),
1152
+ * failed: errors => showErrors(errors)
1153
+ * })
1154
+ * )();
1155
+ * ```
1156
+ */
1157
+ const match: <E, A, B>(cases: {
1158
+ passed: (a: A) => B;
1159
+ failed: (errors: NonEmptyArr<E>) => B;
1160
+ }) => (data: TaskValidation<E, A>) => Task<B>;
1161
+ /**
1162
+ * Returns the success value or a default value if the TaskValidation is failed.
1163
+ * The default can be a different type, widening the result to `Task<A | B>`.
1164
+ */
1165
+ const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskValidation<E, A>) => Task<A | B>;
1166
+ /**
1167
+ * Executes a side effect on the success value without changing the TaskValidation.
1168
+ * Useful for logging or debugging.
1169
+ */
1170
+ const tap: <E, A>(f: (a: A) => void) => (data: TaskValidation<E, A>) => TaskValidation<E, A>;
1171
+ /**
1172
+ * Recovers from a Failed state by providing a fallback TaskValidation.
1173
+ * The fallback receives the accumulated error list so callers can inspect which errors occurred.
1174
+ * The fallback can produce a different success type, widening the result to `TaskValidation<E, A | B>`.
1175
+ */
1176
+ const recover: <E, A, B>(fallback: (errors: NonEmptyArr<E>) => TaskValidation<E, B>) => (data: TaskValidation<E, A>) => TaskValidation<E, A | B>;
1177
+ /**
1178
+ * Runs two TaskValidations concurrently and combines their results into a tuple.
1179
+ * If both are Passed, returns Passed with both values. If either fails, accumulates
1180
+ * errors from both sides.
1181
+ *
1182
+ * @example
1183
+ * ```ts
1184
+ * await TaskValidation.product(
1185
+ * validateName(form.name),
1186
+ * validateAge(form.age),
1187
+ * )(); // Passed(["Alice", 30]) or Failed([...errors])
1188
+ * ```
1189
+ */
1190
+ const product: <E, A, B>(first: TaskValidation<E, A>, second: TaskValidation<E, B>) => TaskValidation<E, readonly [A, B]>;
1191
+ /**
1192
+ * Runs all TaskValidations concurrently and collects results.
1193
+ * If all are Passed, returns Passed with all values as an array.
1194
+ * If any fail, returns Failed with all accumulated errors.
1195
+ *
1196
+ * @example
1197
+ * ```ts
1198
+ * await TaskValidation.productAll([
1199
+ * validateName(form.name),
1200
+ * validateEmail(form.email),
1201
+ * validateAge(form.age),
1202
+ * ])(); // Passed([name, email, age]) or Failed([...all errors])
1203
+ * ```
1204
+ */
1205
+ const productAll: <E, A>(data: NonEmptyArr<TaskValidation<E, A>>) => TaskValidation<E, readonly A[]>;
1206
+ /**
1207
+ * Transforms all accumulated errors inside a TaskValidation.
1208
+ *
1209
+ * @example
1210
+ * ```ts
1211
+ * pipe(
1212
+ * TaskValidation.failed("oops"),
1213
+ * TaskValidation.mapError(e => e.toUpperCase())
1214
+ * ); // TaskValidation(Failed(["OOPS"]))
1215
+ * ```
1216
+ */
1217
+ const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskValidation<E, A>) => TaskValidation<F, A>;
1218
+ /**
1219
+ * Executes a side effect on the accumulated errors without changing the TaskValidation.
1220
+ *
1221
+ * @example
1222
+ * ```ts
1223
+ * pipe(
1224
+ * TaskValidation.failed("invalid name"),
1225
+ * TaskValidation.tapError(errs => logger.error(errs))
1226
+ * );
1227
+ * ```
1228
+ */
1229
+ const tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: TaskValidation<E, A>) => TaskValidation<E, A>;
1230
+ /**
1231
+ * Combines a record of TaskValidations into a single TaskValidation of a record.
1232
+ * Evaluates fields in parallel and accumulates all validation errors.
1233
+ *
1234
+ * @example
1235
+ * ```ts
1236
+ * TaskValidation.struct({
1237
+ * name: TaskValidation.passed("Alice"),
1238
+ * age: TaskValidation.passed(30)
1239
+ * }); // TaskValidation({ name: "Alice", age: 30 })
1240
+ * ```
1241
+ */
1242
+ const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskValidation<E, R[K]>; }) => TaskValidation<E, R>;
1243
+ }
1244
+
812
1245
  /**
813
1246
  * A lazy async computation that always resolves.
814
1247
  *
@@ -872,7 +1305,7 @@ declare namespace Task {
872
1305
  * const getTimestamp = Task.from(() => Promise.resolve(Date.now()));
873
1306
  * ```
874
1307
  */
875
- const from: <A>(f: (signal?: AbortSignal) => Promise<A>) => Task<A>;
1308
+ const from: <A>(f: (signal?: AbortSignal) => Thenable<A>) => Task<A>;
876
1309
  /**
877
1310
  * Creates a Task from a lazy synchronous thunk.
878
1311
  * Unlike `Task.resolve(f())`, `fromSync` does not evaluate `f` until the Task is called.
@@ -1078,7 +1511,7 @@ declare namespace Task {
1078
1511
  * await poll();
1079
1512
  * ```
1080
1513
  */
1081
- const abortable: <A>(factory: (signal: AbortSignal) => Promise<A>) => {
1514
+ const abortable: <A>(factory: (signal: AbortSignal) => Thenable<A>) => {
1082
1515
  task: Task<A>;
1083
1516
  abort: () => void;
1084
1517
  };
@@ -1117,6 +1550,337 @@ declare namespace Task {
1117
1550
  * ```
1118
1551
  */
1119
1552
  const bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
1553
+ type Maybe<A> = TaskMaybe<A>;
1554
+ const Maybe: typeof TaskMaybe;
1555
+ type Result<E, A> = TaskResult<E, A>;
1556
+ const Result: typeof TaskResult;
1557
+ type Validation<E, A> = TaskValidation<E, A>;
1558
+ const Validation: typeof TaskValidation;
1559
+ }
1560
+
1561
+ type Passed<A> = WithKind<"Passed"> & WithValue<A>;
1562
+ type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
1563
+ /**
1564
+ * Validation represents a value that is either passed with a success value,
1565
+ * or failed with accumulated errors.
1566
+ * Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
1567
+ *
1568
+ * Use Validation when you need to collect all errors (e.g., form validation).
1569
+ * Use Result when you want to fail fast on the first error.
1570
+ *
1571
+ * @example
1572
+ * ```ts
1573
+ * const validateName = (name: string): Validation<string, string> =>
1574
+ * name.length > 0 ? Validation.passed(name) : Validation.failed("Name is required");
1575
+ *
1576
+ * const validateAge = (age: number): Validation<string, number> =>
1577
+ * age >= 0 ? Validation.passed(age) : Validation.failed("Age must be positive");
1578
+ *
1579
+ * // Accumulates all errors using ap
1580
+ * pipe(
1581
+ * Validation.passed((name: string) => (age: number) => ({ name, age })),
1582
+ * Validation.ap(validateName("")),
1583
+ * Validation.ap(validateAge(-1))
1584
+ * );
1585
+ * // Failed(["Name is required", "Age must be positive"])
1586
+ * ```
1587
+ */
1588
+ type Validation<E, A> = Passed<A> | Failed<E>;
1589
+ declare namespace Validation {
1590
+ /**
1591
+ * Wraps a value in a passed Validation.
1592
+ *
1593
+ * @example
1594
+ * ```ts
1595
+ * Validation.passed(42); // Passed(42)
1596
+ * ```
1597
+ */
1598
+ const passed: <E, A>(value: A) => Validation<E, A>;
1599
+ /**
1600
+ * Creates a failed Validation from a single error.
1601
+ *
1602
+ * @example
1603
+ * ```ts
1604
+ * Validation.failed("Invalid input");
1605
+ * ```
1606
+ */
1607
+ const failed: <E>(error: E) => Failed<E>;
1608
+ /**
1609
+ * Creates a failed Validation from multiple errors.
1610
+ *
1611
+ * @example
1612
+ * ```ts
1613
+ * Validation.failedAll(["Invalid input"]);
1614
+ * ```
1615
+ */
1616
+ const failedAll: <E>(errors: NonEmptyArr<E>) => Failed<E>;
1617
+ /**
1618
+ * Type guard that checks if a Validation is passed.
1619
+ */
1620
+ const isPassed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
1621
+ /**
1622
+ * Type guard that checks if a Validation is failed.
1623
+ */
1624
+ const isFailed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
1625
+ /**
1626
+ * Creates a Validation from a predicate applied to a value.
1627
+ * Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
1628
+ *
1629
+ * @example
1630
+ * ```ts
1631
+ * const validateName = Validation.fromPredicate(
1632
+ * (s: string) => s.length > 0,
1633
+ * () => "Name is required"
1634
+ * );
1635
+ *
1636
+ * validateName("Alice"); // Passed("Alice")
1637
+ * validateName(""); // Failed(["Name is required"])
1638
+ * ```
1639
+ */
1640
+ const fromPredicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
1641
+ /**
1642
+ * Creates a Validation from a nullable value.
1643
+ * If the value is null or undefined, returns Failed with the error from onNull.
1644
+ * Otherwise, returns Passed.
1645
+ *
1646
+ * @example
1647
+ * ```ts
1648
+ * pipe(null, Validation.fromNullable(() => "is null")); // Failed(["is null"])
1649
+ * pipe(42, Validation.fromNullable(() => "is null")); // Passed(42)
1650
+ * ```
1651
+ */
1652
+ const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
1653
+ /**
1654
+ * Creates a Validation from a Maybe.
1655
+ * If the Maybe is None, returns Failed with the error from onNone.
1656
+ * Otherwise, returns Passed.
1657
+ *
1658
+ * @example
1659
+ * ```ts
1660
+ * pipe(Maybe.none(), Validation.fromMaybe(() => "is none")); // Failed(["is none"])
1661
+ * pipe(Maybe.some(42), Validation.fromMaybe(() => "is none")); // Passed(42)
1662
+ * ```
1663
+ */
1664
+ const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
1665
+ /**
1666
+ * Transforms the success value inside a Validation.
1667
+ *
1668
+ * @example
1669
+ * ```ts
1670
+ * pipe(Validation.passed(5), Validation.map(n => n * 2)); // Passed(10)
1671
+ * pipe(Validation.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
1672
+ * ```
1673
+ */
1674
+ const map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
1675
+ /**
1676
+ * Transforms the error list inside a Validation.
1677
+ *
1678
+ * @example
1679
+ * ```ts
1680
+ * pipe(Validation.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
1681
+ * ```
1682
+ */
1683
+ const mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
1684
+ /**
1685
+ * Applies a function wrapped in a Validation to a value wrapped in a Validation.
1686
+ * Accumulates errors from both sides.
1687
+ *
1688
+ * @example
1689
+ * ```ts
1690
+ * const add = (a: number) => (b: number) => a + b;
1691
+ * pipe(
1692
+ * Validation.passed(add),
1693
+ * Validation.ap(Validation.passed(5)),
1694
+ * Validation.ap(Validation.passed(3))
1695
+ * ); // Passed(8)
1696
+ *
1697
+ * pipe(
1698
+ * Validation.passed(add),
1699
+ * Validation.ap(Validation.failed<string, number>("bad a")),
1700
+ * Validation.ap(Validation.failed<string, number>("bad b"))
1701
+ * ); // Failed(["bad a", "bad b"])
1702
+ * ```
1703
+ */
1704
+ const ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
1705
+ /**
1706
+ * Extracts the value from a Validation by providing handlers for both cases.
1707
+ *
1708
+ * @example
1709
+ * ```ts
1710
+ * pipe(
1711
+ * Validation.passed(42),
1712
+ * Validation.fold(
1713
+ * errors => `Errors: ${errors.join(", ")}`,
1714
+ * value => `Value: ${value}`
1715
+ * )
1716
+ * );
1717
+ * ```
1718
+ */
1719
+ const fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
1720
+ /**
1721
+ * Pattern matches on a Validation, returning the result of the matching case.
1722
+ *
1723
+ * @example
1724
+ * ```ts
1725
+ * pipe(
1726
+ * validation,
1727
+ * Validation.match({
1728
+ * passed: value => `Got ${value}`,
1729
+ * failed: errors => `Failed: ${errors.join(", ")}`
1730
+ * })
1731
+ * );
1732
+ * ```
1733
+ */
1734
+ const match: <E, A, B>(cases: {
1735
+ passed: (a: A) => B;
1736
+ failed: (errors: NonEmptyArr<E>) => B;
1737
+ }) => (data: Validation<E, A>) => B;
1738
+ /**
1739
+ * Returns the success value or a default value if the Validation is failed.
1740
+ * The default can be a different type, widening the result to `A | B`.
1741
+ *
1742
+ * @example
1743
+ * ```ts
1744
+ * pipe(Validation.passed(5), Validation.getOrElse(() => 0)); // 5
1745
+ * pipe(Validation.failed("oops"), Validation.getOrElse(() => 0)); // 0
1746
+ * pipe(Validation.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
1747
+ * ```
1748
+ */
1749
+ const getOrElse: <E, A, B>(defaultValue: () => B) => (data: Validation<E, A>) => A | B;
1750
+ /**
1751
+ * Executes a side effect on the success value without changing the Validation.
1752
+ *
1753
+ * @example
1754
+ * ```ts
1755
+ * pipe(
1756
+ * Validation.passed(5),
1757
+ * Validation.tap(n => console.log("Value:", n)),
1758
+ * Validation.map(n => n * 2)
1759
+ * );
1760
+ * ```
1761
+ */
1762
+ const tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
1763
+ /**
1764
+ * Executes a side effect on the accumulated errors without changing the Validation.
1765
+ * Useful for logging or reporting validation failures.
1766
+ *
1767
+ * @example
1768
+ * ```ts
1769
+ * pipe(
1770
+ * Validation.failed("Name required"),
1771
+ * Validation.tapError(errors => console.error("validation failed:", errors)),
1772
+ * Validation.map(toUser)
1773
+ * );
1774
+ * ```
1775
+ */
1776
+ const tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
1777
+ /**
1778
+ * Recovers from a Failed state by providing a fallback Validation.
1779
+ * The fallback receives the accumulated error list so callers can inspect which errors occurred.
1780
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
1781
+ */
1782
+ const recover: <E, A, B>(fallback: (errors: NonEmptyArr<E>) => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
1783
+ /**
1784
+ * Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
1785
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
1786
+ *
1787
+ * @example
1788
+ * ```ts
1789
+ * pipe(
1790
+ * Validation.failed("field-error"),
1791
+ * Validation.recoverUnless(e => e === "fatal", () => Validation.passed(0))
1792
+ * ); // Passed(0)
1793
+ * ```
1794
+ */
1795
+ const recoverUnless: <E, A, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
1796
+ /**
1797
+ * Converts a Validation to a Result.
1798
+ * Passed becomes Ok, Failed becomes Err with the accumulated error list.
1799
+ *
1800
+ * @example
1801
+ * ```ts
1802
+ * Validation.toResult(Validation.passed(42)); // Ok(42)
1803
+ * Validation.toResult(Validation.failed("oops")); // Err(["oops"])
1804
+ * ```
1805
+ */
1806
+ const toResult: <E, A>(data: Validation<E, A>) => Result<NonEmptyArr<E>, A>;
1807
+ /**
1808
+ * Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
1809
+ * (errors are discarded).
1810
+ *
1811
+ * @example
1812
+ * ```ts
1813
+ * Validation.toMaybe(Validation.passed(42)); // Some(42)
1814
+ * Validation.toMaybe(Validation.failed("bad")); // None
1815
+ * ```
1816
+ */
1817
+ const toMaybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
1818
+ /**
1819
+ * Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
1820
+ *
1821
+ * Useful when bridging from error-short-circuiting `Result` pipelines into
1822
+ * error-accumulating `Validation` pipelines.
1823
+ *
1824
+ * @example
1825
+ * ```ts
1826
+ * Validation.fromResult(Result.ok(42)); // Passed(42)
1827
+ * Validation.fromResult(Result.err("bad")); // Failed(["bad"])
1828
+ * ```
1829
+ */
1830
+ const fromResult: <E, A>(data: Result<E, A>) => Validation<E, A>;
1831
+ /**
1832
+ * Combines two independent Validation instances into a tuple.
1833
+ * If both are Passed, returns Passed with both values as a tuple.
1834
+ * If either is Failed, accumulates errors from both sides.
1835
+ *
1836
+ * @example
1837
+ * ```ts
1838
+ * Validation.product(
1839
+ * Validation.passed("alice"),
1840
+ * Validation.passed(30)
1841
+ * ); // Passed(["alice", 30])
1842
+ *
1843
+ * Validation.product(
1844
+ * Validation.failed("Name required"),
1845
+ * Validation.failed("Age must be >= 0")
1846
+ * ); // Failed(["Name required", "Age must be >= 0"])
1847
+ * ```
1848
+ */
1849
+ const product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
1850
+ /**
1851
+ * Combines a non-empty list of Validation instances, accumulating all errors.
1852
+ * If all are Passed, returns Passed with all values collected into an array.
1853
+ * If any are Failed, returns Failed with all accumulated errors.
1854
+ *
1855
+ * @example
1856
+ * ```ts
1857
+ * Validation.productAll([
1858
+ * validateName(name),
1859
+ * validateEmail(email),
1860
+ * validateAge(age)
1861
+ * ]);
1862
+ * // Passed([name, email, age]) or Failed([...all errors])
1863
+ * ```
1864
+ */
1865
+ const productAll: <E, A>(data: NonEmptyArr<Validation<E, A>>) => Validation<E, readonly A[]>;
1866
+ /**
1867
+ * Combines a record of Validations into a single Validation of a record.
1868
+ * Accumulates all failed branches' errors.
1869
+ *
1870
+ * @example
1871
+ * ```ts
1872
+ * Validation.struct({
1873
+ * name: Validation.passed("Alice"),
1874
+ * age: Validation.passed(30)
1875
+ * }); // Passed({ name: "Alice", age: 30 })
1876
+ *
1877
+ * Validation.struct({
1878
+ * name: Validation.failed("Name required"),
1879
+ * age: Validation.failed("Age must be >= 0")
1880
+ * }); // Failed(["Name required", "Age must be >= 0"])
1881
+ * ```
1882
+ */
1883
+ const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Validation<E, R[K]>; }) => Validation<E, R>;
1120
1884
  }
1121
1885
 
1122
- export { Deferred as D, Equality as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithConcurrency as W, type Err as a, Ordering as b, type RetryOptions as c, type TimeoutOptions as d, type WithCooldown as e, type WithDuration as f, type WithError as g, type WithErrors as h, type WithFirst as i, type WithKind as j, type WithLog as k, type WithMinInterval as l, type WithN as m, type WithSecond as n, type WithSize as o, type WithTimeout as p, type WithValue as q };
1886
+ export { Equality as E, type Failed as F, Maybe as M, type None as N, type Ok as O, type Passed as P, Result as R, type Some as S, Task as T, Validation as V, type Err as a, Ordering as b };