@nlozgachev/pipelined 0.62.0 → 0.64.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,5 +1,5 @@
1
- import { h as WithKind, o as WithValue, e as WithError, a as NonEmptyArr, T as Thenable, D as Deferred, f as WithErrors } from './InternalTypes-LdhLQx3N.js';
2
- import { D as Duration } from './Duration-B8joKzro.js';
1
+ import { h as WithKind, o as WithValue, e as WithError, a as NonEmptyArr, f as WithErrors, D as Deferred, T as Thenable } from './InternalTypes-CCXa8Kvr.js';
2
+ import { D as Duration } from './Duration-DeyxG6VQ.js';
3
3
  import { RetryPolicy } from './types.js';
4
4
 
5
5
  /**
@@ -16,7 +16,7 @@ import { RetryPolicy } from './types.js';
16
16
  * ```
17
17
  */
18
18
  type Equality<A> = (a: A, b: A) => boolean;
19
- declare namespace Equality {
19
+ declare const Equality: {
20
20
  /**
21
21
  * Equality for strings. Case-sensitive.
22
22
  *
@@ -26,7 +26,7 @@ declare namespace Equality {
26
26
  * Equality.string("hello", "Hello"); // false
27
27
  * ```
28
28
  */
29
- const string: Equality<string>;
29
+ string: Equality<string>;
30
30
  /**
31
31
  * Equality for numbers. Uses strict equality.
32
32
  *
@@ -35,7 +35,7 @@ declare namespace Equality {
35
35
  * Equality.number(42, 42); // true
36
36
  * ```
37
37
  */
38
- const number: Equality<number>;
38
+ number: Equality<number>;
39
39
  /**
40
40
  * Equality for booleans.
41
41
  *
@@ -44,7 +44,7 @@ declare namespace Equality {
44
44
  * Equality.boolean(true, true); // true
45
45
  * ```
46
46
  */
47
- const boolean: Equality<boolean>;
47
+ boolean: Equality<boolean>;
48
48
  /**
49
49
  * Equality for `Date` values. Compares by numeric time value.
50
50
  *
@@ -53,7 +53,7 @@ declare namespace Equality {
53
53
  * Equality.date(new Date("2024-01-01"), new Date("2024-01-01")); // true
54
54
  * ```
55
55
  */
56
- const date: Equality<Date>;
56
+ date: Equality<Date>;
57
57
  /**
58
58
  * Lifts an element equality into an array equality. Two arrays are equal if they have the
59
59
  * same length and every element pair is equal under `eq`.
@@ -63,7 +63,7 @@ declare namespace Equality {
63
63
  * Equality.array(Equality.number)([1, 2, 3], [1, 2, 3]); // true
64
64
  * ```
65
65
  */
66
- const array: <A>(eq: Equality<A>) => Equality<readonly A[]>;
66
+ array: <A>(eq: Equality<A>) => Equality<readonly A[]>;
67
67
  /**
68
68
  * Adapts an equality for type `A` into an equality for type `B` by extracting a field.
69
69
  * Read as "equality by this field": `pipe(Equality.string, Equality.by(u => u.name))`.
@@ -75,7 +75,7 @@ declare namespace Equality {
75
75
  * byId({ id: "p1", price: 9 }, { id: "p1", price: 12 }); // true
76
76
  * ```
77
77
  */
78
- const by: <A, B>(f: (b: B) => A) => (eq: Equality<A>) => Equality<B>;
78
+ by: <A, B>(f: (b: B) => A) => (eq: Equality<A>) => Equality<B>;
79
79
  /**
80
80
  * Combines two equalities with logical AND. Both must pass for two values to be considered equal.
81
81
  * Data-last: the first equality is the data being piped.
@@ -86,7 +86,7 @@ declare namespace Equality {
86
86
  * exact(userA, userB); // true only if name AND role match
87
87
  * ```
88
88
  */
89
- const and: <A>(eq2: Equality<A>) => (eq1: Equality<A>) => Equality<A>;
89
+ and: <A>(eq2: Equality<A>) => (eq1: Equality<A>) => Equality<A>;
90
90
  /**
91
91
  * Derives deep equality for a record from field-level `Equality` checkers.
92
92
  *
@@ -98,7 +98,7 @@ declare namespace Equality {
98
98
  * });
99
99
  * ```
100
100
  */
101
- const struct: <R extends Record<string, unknown>>(fields: { [K in keyof R]: Equality<R[K]>; }) => Equality<R>;
101
+ struct: <R extends Record<string, unknown>>(fields: { [K in keyof R]: Equality<R[K]>; }) => Equality<R>;
102
102
  /**
103
103
  * Derives element-wise equality for a tuple from positional `Equality` checkers.
104
104
  *
@@ -108,8 +108,8 @@ declare namespace Equality {
108
108
  * pairEq(["a", 1], ["a", 1]); // true
109
109
  * ```
110
110
  */
111
- const tuple: <T extends readonly unknown[]>(...equalities: { [K in keyof T]: Equality<T[K]>; }) => Equality<T>;
112
- }
111
+ tuple: <T extends readonly unknown[]>(...equalities: { [K in keyof T]: Equality<T[K]>; }) => Equality<T>;
112
+ };
113
113
 
114
114
  type Some<A> = WithKind<"Some"> & WithValue<A>;
115
115
  type None = WithKind<"None">;
@@ -129,8 +129,8 @@ type None = WithKind<"None">;
129
129
  * ```
130
130
  */
131
131
  type Maybe<T> = Some<T> | None;
132
- declare namespace Maybe {
133
- namespace make {
132
+ declare const Maybe: {
133
+ make: {
134
134
  /**
135
135
  * Creates a Some containing the given value.
136
136
  *
@@ -139,7 +139,7 @@ declare namespace Maybe {
139
139
  * Maybe.make.some(42); // Some(42)
140
140
  * ```
141
141
  */
142
- const some: <A>(value: A) => Some<A>;
142
+ some: <A>(value: A) => Some<A>;
143
143
  /**
144
144
  * Creates a None (empty Maybe).
145
145
  *
@@ -148,9 +148,9 @@ declare namespace Maybe {
148
148
  * Maybe.make.none(); // None
149
149
  * ```
150
150
  */
151
- const none: () => None;
152
- }
153
- namespace is {
151
+ none: () => None;
152
+ };
153
+ is: {
154
154
  /**
155
155
  * Type guard that checks if a Maybe is Some.
156
156
  *
@@ -162,7 +162,7 @@ declare namespace Maybe {
162
162
  * }
163
163
  * ```
164
164
  */
165
- const some: <A>(data: Maybe<A>) => data is Some<A>;
165
+ some: <A>(data: Maybe<A>) => data is Some<A>;
166
166
  /**
167
167
  * Type guard that checks if a Maybe is None.
168
168
  *
@@ -174,9 +174,9 @@ declare namespace Maybe {
174
174
  * }
175
175
  * ```
176
176
  */
177
- const none: <A>(data: Maybe<A>) => data is None;
178
- }
179
- namespace to {
177
+ none: <A>(data: Maybe<A>) => data is None;
178
+ };
179
+ to: {
180
180
  /**
181
181
  * Extracts the value from a Maybe, returning null if None.
182
182
  *
@@ -186,7 +186,7 @@ declare namespace Maybe {
186
186
  * Maybe.to.nullable(Maybe.make.none()); // null
187
187
  * ```
188
188
  */
189
- const nullable: <A>(data: Maybe<A>) => A | null;
189
+ nullable: <A>(data: Maybe<A>) => A | null;
190
190
  /**
191
191
  * Extracts the value from a Maybe, returning undefined if None.
192
192
  *
@@ -196,7 +196,7 @@ declare namespace Maybe {
196
196
  * Maybe.to.undefined(Maybe.make.none()); // undefined
197
197
  * ```
198
198
  */
199
- const undefined: <A>(data: Maybe<A>) => A | undefined;
199
+ undefined: <A>(data: Maybe<A>) => A | undefined;
200
200
  /**
201
201
  * Converts a Maybe to a Result.
202
202
  * Some becomes Ok, None becomes Err with the provided error.
@@ -214,9 +214,9 @@ declare namespace Maybe {
214
214
  * ); // Err("Value was missing")
215
215
  * ```
216
216
  */
217
- const Result: <E>(onNone: () => E) => <A>(data: Maybe<A>) => Result<E, A>;
218
- }
219
- namespace from {
217
+ Result: <E>(onNone: () => E) => <A>(data: Maybe<A>) => Result<E, A>;
218
+ };
219
+ from: {
220
220
  /**
221
221
  * Creates a Maybe from a nullable value.
222
222
  * Returns None if the value is null or undefined, Some otherwise.
@@ -227,7 +227,7 @@ declare namespace Maybe {
227
227
  * Maybe.from.nullable(42); // Some(42)
228
228
  * ```
229
229
  */
230
- const nullable: <A>(value: A | null | undefined) => Maybe<A>;
230
+ nullable: <A>(value: A | null | undefined) => Maybe<A>;
231
231
  /**
232
232
  * Creates a Maybe from a predicate applied to a value.
233
233
  * Returns Some if the predicate passes, None otherwise.
@@ -241,7 +241,7 @@ declare namespace Maybe {
241
241
  * pipe("", Maybe.from.Predicate((s: string) => s.length > 0)); // None
242
242
  * ```
243
243
  */
244
- const Predicate: <A>(pred: (a: A) => boolean) => (a: A) => Maybe<A>;
244
+ Predicate: <A>(pred: (a: A) => boolean) => (a: A) => Maybe<A>;
245
245
  /**
246
246
  * Creates a Maybe from a Result.
247
247
  * Ok becomes Some, Err becomes None (the error is discarded).
@@ -252,8 +252,8 @@ declare namespace Maybe {
252
252
  * Maybe.from.Result(Result.make.err("oops")); // None
253
253
  * ```
254
254
  */
255
- const Result: <E, A>(data: Result<E, A>) => Maybe<A>;
256
- }
255
+ Result: <E, A>(data: Result<E, A>) => Maybe<A>;
256
+ };
257
257
  /**
258
258
  * Transforms the value inside a Maybe if it exists.
259
259
  *
@@ -263,7 +263,7 @@ declare namespace Maybe {
263
263
  * pipe(Maybe.make.none(), Maybe.map(n => n * 2)); // None
264
264
  * ```
265
265
  */
266
- const map: <A, B>(f: (a: A) => B) => (data: Maybe<A>) => Maybe<B>;
266
+ map: <A, B>(f: (a: A) => B) => (data: Maybe<A>) => Maybe<B>;
267
267
  /**
268
268
  * Chains Maybe computations. If the first is Some, passes the value to f.
269
269
  * If the first is None, propagates None.
@@ -279,7 +279,7 @@ declare namespace Maybe {
279
279
  * pipe(Maybe.make.some("abc"), Maybe.chain(parseNumber)); // None
280
280
  * ```
281
281
  */
282
- const chain: <A, B>(f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<B>;
282
+ chain: <A, B>(f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<B>;
283
283
  /**
284
284
  * Extracts the value from a Maybe by providing handlers for both cases.
285
285
  *
@@ -294,7 +294,7 @@ declare namespace Maybe {
294
294
  * ); // "Value: 5"
295
295
  * ```
296
296
  */
297
- const fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: Maybe<A>) => B;
297
+ fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: Maybe<A>) => B;
298
298
  /**
299
299
  * Pattern matches on a Maybe, returning the result of the matching case.
300
300
  *
@@ -309,7 +309,7 @@ declare namespace Maybe {
309
309
  * );
310
310
  * ```
311
311
  */
312
- const match: <A, B>(cases: {
312
+ match: <A, B>(cases: {
313
313
  none: () => B;
314
314
  some: (a: A) => B;
315
315
  }) => (data: Maybe<A>) => B;
@@ -325,7 +325,7 @@ declare namespace Maybe {
325
325
  * pipe(Maybe.make.none<string>(), Maybe.getOrElse(() => null)); // null — typed as string | null
326
326
  * ```
327
327
  */
328
- const getOrElse: <B>(defaultValue: () => B) => <A>(data: Maybe<A>) => A | B;
328
+ getOrElse: <B>(defaultValue: () => B) => <A>(data: Maybe<A>) => A | B;
329
329
  /**
330
330
  * Executes a side effect on the value without changing the Maybe.
331
331
  * Useful for logging or debugging.
@@ -339,7 +339,7 @@ declare namespace Maybe {
339
339
  * );
340
340
  * ```
341
341
  */
342
- const tap: <A>(f: (a: A) => void) => (data: Maybe<A>) => Maybe<A>;
342
+ tap: <A>(f: (a: A) => void) => (data: Maybe<A>) => Maybe<A>;
343
343
  /**
344
344
  * Filters a Maybe based on a predicate.
345
345
  * Returns None if the predicate returns false or if the Maybe is already None.
@@ -350,7 +350,7 @@ declare namespace Maybe {
350
350
  * pipe(Maybe.make.some(2), Maybe.filter(n => n > 3)); // None
351
351
  * ```
352
352
  */
353
- const filter: <A>(predicate: (a: A) => boolean) => (data: Maybe<A>) => Maybe<A>;
353
+ filter: <A>(predicate: (a: A) => boolean) => (data: Maybe<A>) => Maybe<A>;
354
354
  /**
355
355
  * Recovers from a None by providing a fallback Maybe.
356
356
  * The fallback can produce a different type, widening the result to `Maybe<A | B>`.
@@ -361,7 +361,7 @@ declare namespace Maybe {
361
361
  * pipe(Maybe.make.some(10), Maybe.recover(() => Maybe.make.some(42))); // Some(10)
362
362
  * ```
363
363
  */
364
- const recover: <B>(fallback: () => Maybe<B>) => <A>(data: Maybe<A>) => Maybe<A | B>;
364
+ recover: <B>(fallback: () => Maybe<B>) => <A>(data: Maybe<A>) => Maybe<A | B>;
365
365
  /**
366
366
  * Applies a function wrapped in a Maybe to a value wrapped in a Maybe.
367
367
  *
@@ -375,7 +375,7 @@ declare namespace Maybe {
375
375
  * ); // Some(8)
376
376
  * ```
377
377
  */
378
- const ap: <A>(arg: Maybe<A>) => <B>(data: Maybe<(a: A) => B>) => Maybe<B>;
378
+ ap: <A>(arg: Maybe<A>) => <B>(data: Maybe<(a: A) => B>) => Maybe<B>;
379
379
  /**
380
380
  * Converts a Maybe value into an object containing a single property.
381
381
  * Initiates the pipeline accumulator record.
@@ -385,7 +385,7 @@ declare namespace Maybe {
385
385
  * pipe(Maybe.make.some(42), Maybe.bindTo("value")); // Some({ value: 42 })
386
386
  * ```
387
387
  */
388
- const bindTo: <K extends string>(key: K) => <A>(data: Maybe<A>) => Maybe<{ [P in K]: A; }>;
388
+ bindTo: <K extends string>(key: K) => <A>(data: Maybe<A>) => Maybe<{ [P in K]: A; }>;
389
389
  /**
390
390
  * Evaluates a new Maybe using the current accumulator and attaches the output to a new key.
391
391
  *
@@ -397,7 +397,7 @@ declare namespace Maybe {
397
397
  * ); // Some({ a: 1, b: 2 })
398
398
  * ```
399
399
  */
400
- const bind: <K extends string, A, B>(key: K, f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<A & { [P in K]: B; }>;
400
+ bind: <K extends string, A, B>(key: K, f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<A & { [P in K]: B; }>;
401
401
  /**
402
402
  * Combines a record of Maybes into a single Maybe of a record.
403
403
  * Evaluates fields in key order and short-circuits on the first None.
@@ -410,7 +410,7 @@ declare namespace Maybe {
410
410
  * }); // Some({ name: "Alice", age: 30 })
411
411
  * ```
412
412
  */
413
- const struct: <R extends Record<string, any>>(fields: { [K in keyof R]: Maybe<R[K]>; }) => Maybe<R>;
413
+ struct: <R extends Record<string, any>>(fields: { [K in keyof R]: Maybe<R[K]>; }) => Maybe<R>;
414
414
  /**
415
415
  * Swaps the outer `Maybe` and inner `Result` context.
416
416
  * `Some(Ok(a))` becomes `Ok(Some(a))`, `Some(Err(e))` becomes `Err(e)`, and `None` becomes `Ok(None)`.
@@ -422,8 +422,8 @@ declare namespace Maybe {
422
422
  * Maybe.transposeResult(Maybe.make.none()); // Ok(None)
423
423
  * ```
424
424
  */
425
- const transposeResult: <E, A>(data: Maybe<Result<E, A>>) => Result<E, Maybe<A>>;
426
- }
425
+ transposeResult: <E, A>(data: Maybe<Result<E, A>>) => Result<E, Maybe<A>>;
426
+ };
427
427
 
428
428
  /**
429
429
  * A function that orders two values of type `A`. Returns a negative number when `a` comes before
@@ -442,7 +442,7 @@ declare namespace Maybe {
442
442
  * ```
443
443
  */
444
444
  type Ordering<A> = (a: A, b: A) => number;
445
- declare namespace Ordering {
445
+ declare const Ordering: {
446
446
  /**
447
447
  * Alphabetical ordering for strings.
448
448
  *
@@ -451,7 +451,7 @@ declare namespace Ordering {
451
451
  * Ordering.string("apple", "banana"); // negative
452
452
  * ```
453
453
  */
454
- const string: Ordering<string>;
454
+ string: Ordering<string>;
455
455
  /**
456
456
  * Numeric ordering. Equivalent to `(a, b) => a - b`.
457
457
  *
@@ -460,7 +460,7 @@ declare namespace Ordering {
460
460
  * pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
461
461
  * ```
462
462
  */
463
- const number: Ordering<number>;
463
+ number: Ordering<number>;
464
464
  /**
465
465
  * Ordering for `Date` values by numeric time value.
466
466
  *
@@ -469,7 +469,7 @@ declare namespace Ordering {
469
469
  * pipe(dates, Arr.sortWith(Ordering.date)); // earliest first
470
470
  * ```
471
471
  */
472
- const date: Ordering<Date>;
472
+ date: Ordering<Date>;
473
473
  /**
474
474
  * Flips the direction of an ordering.
475
475
  *
@@ -478,7 +478,7 @@ declare namespace Ordering {
478
478
  * pipe([3, 1, 2], Arr.sortWith(Ordering.reverse(Ordering.number))); // [3, 2, 1]
479
479
  * ```
480
480
  */
481
- const reverse: <A>(ord: Ordering<A>) => Ordering<A>;
481
+ reverse: <A>(ord: Ordering<A>) => Ordering<A>;
482
482
  /**
483
483
  * Chains two orderings: the second is used only when the first returns `0`.
484
484
  * Data-last: the first ordering is the data being piped.
@@ -488,7 +488,7 @@ declare namespace Ordering {
488
488
  * const byDeptThenSalary = pipe(byDept, Ordering.thenBy(bySalary));
489
489
  * ```
490
490
  */
491
- const thenBy: <A>(ord2: Ordering<A>) => (ord1: Ordering<A>) => Ordering<A>;
491
+ thenBy: <A>(ord2: Ordering<A>) => (ord1: Ordering<A>) => Ordering<A>;
492
492
  /**
493
493
  * Adapts an ordering for type `A` into an ordering for type `B` by extracting a field.
494
494
  * Read as "ordering by this field": `pipe(Ordering.number, Ordering.by(p => p.price))`.
@@ -500,7 +500,7 @@ declare namespace Ordering {
500
500
  * pipe(products, Arr.sortWith(byPrice));
501
501
  * ```
502
502
  */
503
- const by: <A, B>(f: (b: B) => A) => (ord: Ordering<A>) => Ordering<B>;
503
+ by: <A, B>(f: (b: B) => A) => (ord: Ordering<A>) => Ordering<B>;
504
504
  /**
505
505
  * Combines a list of orderings into a single composite comparator.
506
506
  * Evaluates each ordering in sequence until a non-zero comparison result is found.
@@ -512,7 +512,7 @@ declare namespace Ordering {
512
512
  * const sortUsers = Ordering.byFields([byName, byAge]);
513
513
  * ```
514
514
  */
515
- const byFields: <A>(orderings: ReadonlyArray<Ordering<A>>) => Ordering<A>;
515
+ byFields: <A>(orderings: ReadonlyArray<Ordering<A>>) => Ordering<A>;
516
516
  /**
517
517
  * Derives a lexicographical tuple ordering from positional `Ordering` comparators.
518
518
  *
@@ -522,8 +522,8 @@ declare namespace Ordering {
522
522
  * pairOrd(["a", 1], ["a", 2]); // negative
523
523
  * ```
524
524
  */
525
- const tuple: <T extends readonly unknown[]>(...orderings: { [K in keyof T]: Ordering<T[K]>; }) => Ordering<T>;
526
- }
525
+ tuple: <T extends readonly unknown[]>(...orderings: { [K in keyof T]: Ordering<T[K]>; }) => Ordering<T>;
526
+ };
527
527
 
528
528
  type Ok<A> = WithKind<"Ok"> & WithValue<A>;
529
529
  type Err<E> = WithKind<"Err"> & WithError<E>;
@@ -544,8 +544,8 @@ type Err<E> = WithKind<"Err"> & WithError<E>;
544
544
  * ```
545
545
  */
546
546
  type Result<E, A> = Ok<A> | Err<E>;
547
- declare namespace Result {
548
- namespace make {
547
+ declare const Result: {
548
+ make: {
549
549
  /**
550
550
  * Creates a successful Result with the given value.
551
551
  *
@@ -554,7 +554,7 @@ declare namespace Result {
554
554
  * Result.make.ok(42); // Ok(42)
555
555
  * ```
556
556
  */
557
- const ok: <A>(value: A) => Ok<A>;
557
+ ok: <A>(value: A) => Ok<A>;
558
558
  /**
559
559
  * Creates a failed Result with the given error.
560
560
  *
@@ -563,9 +563,9 @@ declare namespace Result {
563
563
  * Result.make.err("Error message"); // Err("Error message")
564
564
  * ```
565
565
  */
566
- const err: <E>(e: E) => Err<E>;
567
- }
568
- namespace is {
566
+ err: <E>(e: E) => Err<E>;
567
+ };
568
+ is: {
569
569
  /**
570
570
  * Type guard that checks if a Result is Ok.
571
571
  *
@@ -577,7 +577,7 @@ declare namespace Result {
577
577
  * }
578
578
  * ```
579
579
  */
580
- const ok: <E, A>(data: Result<E, A>) => data is Ok<A>;
580
+ ok: <E, A>(data: Result<E, A>) => data is Ok<A>;
581
581
  /**
582
582
  * Type guard that checks if a Result is Err.
583
583
  *
@@ -589,12 +589,8 @@ declare namespace Result {
589
589
  * }
590
590
  * ```
591
591
  */
592
- const err: <E, A>(data: Result<E, A>) => data is Err<E>;
593
- }
594
- /**
595
- * Creates a Result from a function that may throw.
596
- * Catches any errors and transforms them using the onError function.
597
- *
592
+ err: <E, A>(data: Result<E, A>) => data is Err<E>;
593
+ };
598
594
  /**
599
595
  * Creates a Result from a synchronous thunk that may throw.
600
596
  * Catches any errors and transforms them using the `onError` function.
@@ -607,7 +603,7 @@ declare namespace Result {
607
603
  * );
608
604
  * ```
609
605
  */
610
- const tryCatch: <E, A>(f: () => A, options: {
606
+ tryCatch: <E, A>(f: () => A, options: {
611
607
  onError: (e: unknown) => E;
612
608
  }) => Result<E, A>;
613
609
  /**
@@ -619,7 +615,7 @@ declare namespace Result {
619
615
  * pipe(Result.make.err("error"), Result.map(n => n * 2)); // Err("error")
620
616
  * ```
621
617
  */
622
- const map: <E, A, B>(f: (a: A) => B) => (data: Result<E, A>) => Result<E, B>;
618
+ map: <E, A, B>(f: (a: A) => B) => (data: Result<E, A>) => Result<E, B>;
623
619
  /**
624
620
  * Transforms the error value inside a Result.
625
621
  *
@@ -628,7 +624,7 @@ declare namespace Result {
628
624
  * pipe(Result.make.err("oops"), Result.mapError(e => e.toUpperCase())); // Err("OOPS")
629
625
  * ```
630
626
  */
631
- const mapError: <E, F, A>(f: (e: E) => F) => (data: Result<E, A>) => Result<F, A>;
627
+ mapError: <E, F, A>(f: (e: E) => F) => (data: Result<E, A>) => Result<F, A>;
632
628
  /**
633
629
  * Chains Result computations. If the first is Ok, passes the value to f.
634
630
  * If the first is Err, propagates the error.
@@ -642,7 +638,7 @@ declare namespace Result {
642
638
  * pipe(Result.make.ok(-1), Result.chain(validatePositive)); // Err("Must be positive")
643
639
  * ```
644
640
  */
645
- const chain: <E2, A, B>(f: (a: A) => Result<E2, B>) => <E1 = never>(data: Result<E1, A>) => Result<E1 | E2, B>;
641
+ chain: <E2, A, B>(f: (a: A) => Result<E2, B>) => <E1 = never>(data: Result<E1, A>) => Result<E1 | E2, B>;
646
642
  /**
647
643
  * Extracts the value from a Result by providing handlers for both cases.
648
644
  *
@@ -657,7 +653,7 @@ declare namespace Result {
657
653
  * ); // "Value: 5"
658
654
  * ```
659
655
  */
660
- const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: Result<E, A>) => B;
656
+ fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: Result<E, A>) => B;
661
657
  /**
662
658
  * Pattern matches on a Result, returning the result of the matching case.
663
659
  *
@@ -672,7 +668,7 @@ declare namespace Result {
672
668
  * );
673
669
  * ```
674
670
  */
675
- const match: <E, A, B>(cases: {
671
+ match: <E, A, B>(cases: {
676
672
  ok: (a: A) => B;
677
673
  err: (e: E) => B;
678
674
  }) => (data: Result<E, A>) => B;
@@ -688,7 +684,7 @@ declare namespace Result {
688
684
  * pipe(Result.make.err("error"), Result.getOrElse(() => null)); // null — typed as number | null
689
685
  * ```
690
686
  */
691
- const getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Result<E, A>) => A | B;
687
+ getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Result<E, A>) => A | B;
692
688
  /**
693
689
  * Executes a side effect on the success value without changing the Result.
694
690
  * Useful for logging or debugging.
@@ -702,7 +698,7 @@ declare namespace Result {
702
698
  * );
703
699
  * ```
704
700
  */
705
- const tap: <E, A>(f: (a: A) => void) => (data: Result<E, A>) => Result<E, A>;
701
+ tap: <E, A>(f: (a: A) => void) => (data: Result<E, A>) => Result<E, A>;
706
702
  /**
707
703
  * Executes a side effect on the error value without changing the Result.
708
704
  * Useful for logging or reporting errors.
@@ -716,8 +712,8 @@ declare namespace Result {
716
712
  * )
717
713
  * ```
718
714
  */
719
- const tapError: <E, A>(f: (e: E) => void) => (data: Result<E, A>) => Result<E, A>;
720
- namespace from {
715
+ tapError: <E, A>(f: (e: E) => void) => (data: Result<E, A>) => Result<E, A>;
716
+ from: {
721
717
  /**
722
718
  * Creates a Result from a predicate applied to a value.
723
719
  * Returns Ok if the predicate passes, Err from onFalse otherwise.
@@ -729,7 +725,7 @@ declare namespace Result {
729
725
  * pipe("", Result.from.Predicate(s => s.length > 0, () => "empty string")); // Err("empty string")
730
726
  * ```
731
727
  */
732
- const Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Result<E, A>;
728
+ Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Result<E, A>;
733
729
  /**
734
730
  * Creates a Result from a nullable value.
735
731
  * Returns Ok if the value is not null or undefined, error from onNull otherwise.
@@ -740,7 +736,7 @@ declare namespace Result {
740
736
  * pipe(42, Result.from.nullable(() => "is null")); // Ok(42)
741
737
  * ```
742
738
  */
743
- const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Result<E, A>;
739
+ nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Result<E, A>;
744
740
  /**
745
741
  * Creates a Result from a Maybe.
746
742
  * Some becomes Ok, None becomes error from onNone.
@@ -751,7 +747,7 @@ declare namespace Result {
751
747
  * pipe(Maybe.make.some(42), Result.from.Maybe(() => "is none")); // Ok(42)
752
748
  * ```
753
749
  */
754
- const Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Result<E, A>;
750
+ Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Result<E, A>;
755
751
  /**
756
752
  * Converts a `Validation` to a `Result`, combining accumulated errors using `combineErrors`.
757
753
  * `Passed(a)` becomes `Ok(a)`; `Failed(errors)` becomes `Err(combineErrors(errors))`.
@@ -761,13 +757,13 @@ declare namespace Result {
761
757
  * Result.from.Validation((errors) => errors.join(", "))(Validation.make.failed("error1")); // Err("error1")
762
758
  * ```
763
759
  */
764
- const Validation: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (val: Validation<E1, A>) => Result<E2, A>;
765
- }
760
+ Validation: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (val: Validation<E1, A>) => Result<E2, A>;
761
+ };
766
762
  /**
767
763
  * Recovers from an error by providing a fallback Result.
768
764
  * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
769
765
  */
770
- const recover: <E, B>(fallback: (e: E) => Result<E, B>) => <A>(data: Result<E, A>) => Result<E, A | B>;
766
+ recover: <E, B>(fallback: (e: E) => Result<E, B>) => <A>(data: Result<E, A>) => Result<E, A | B>;
771
767
  /**
772
768
  * Recovers from an error unless the predicate `isBlocked` returns true for that error.
773
769
  * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
@@ -780,8 +776,8 @@ declare namespace Result {
780
776
  * ); // Ok(0)
781
777
  * ```
782
778
  */
783
- const recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: () => Result<E, B>) => <A>(data: Result<E, A>) => Result<E, A | B>;
784
- namespace to {
779
+ recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: () => Result<E, B>) => <A>(data: Result<E, A>) => Result<E, A | B>;
780
+ to: {
785
781
  /**
786
782
  * Converts a Result to a Maybe.
787
783
  * Ok becomes Some, Err becomes None (the error is discarded).
@@ -792,7 +788,7 @@ declare namespace Result {
792
788
  * Result.to.Maybe(Result.make.err("oops")); // None
793
789
  * ```
794
790
  */
795
- const Maybe: <E, A>(data: Result<E, A>) => Maybe<A>;
791
+ Maybe: <E, A>(data: Result<E, A>) => Maybe<A>;
796
792
  /**
797
793
  * Converts a `Result` to a `Validation`. `Ok(a)` becomes `Passed(a)`; `Err(e)` becomes `Failed([e])`.
798
794
  *
@@ -802,8 +798,8 @@ declare namespace Result {
802
798
  * Result.to.Validation(Result.make.err("bad")); // Failed(["bad"])
803
799
  * ```
804
800
  */
805
- const Validation: <E, A>(data: Result<E, A>) => Validation<E, A>;
806
- }
801
+ Validation: <E, A>(data: Result<E, A>) => Validation<E, A>;
802
+ };
807
803
  /**
808
804
  * Swaps the outer `Result` and inner `Maybe` context.
809
805
  * `Ok(Some(a))` becomes `Some(Ok(a))`, `Ok(None)` becomes `None`, and `Err(e)` becomes `Some(Err(e))`.
@@ -815,7 +811,7 @@ declare namespace Result {
815
811
  * Result.transposeMaybe(Result.make.err("error")); // Some(Err("error"))
816
812
  * ```
817
813
  */
818
- const transposeMaybe: <E, A>(data: Result<E, Maybe<A>>) => Maybe<Result<E, A>>;
814
+ transposeMaybe: <E, A>(data: Result<E, Maybe<A>>) => Maybe<Result<E, A>>;
819
815
  /**
820
816
  * Applies a function wrapped in a Result to a value wrapped in a Result.
821
817
  *
@@ -829,7 +825,7 @@ declare namespace Result {
829
825
  * ); // Ok(8)
830
826
  * ```
831
827
  */
832
- const ap: <E, A>(arg: Result<E, A>) => <B>(data: Result<E, (a: A) => B>) => Result<E, B>;
828
+ ap: <E, A>(arg: Result<E, A>) => <B>(data: Result<E, (a: A) => B>) => Result<E, B>;
833
829
  /**
834
830
  * Converts a Result value into an object containing a single property.
835
831
  * Initiates the pipeline accumulator record.
@@ -839,7 +835,7 @@ declare namespace Result {
839
835
  * pipe(Result.make.ok(42), Result.bindTo("value")); // Ok({ value: 42 })
840
836
  * ```
841
837
  */
842
- const bindTo: <K extends string>(key: K) => <E, A>(data: Result<E, A>) => Result<E, { [P in K]: A; }>;
838
+ bindTo: <K extends string>(key: K) => <E, A>(data: Result<E, A>) => Result<E, { [P in K]: A; }>;
843
839
  /**
844
840
  * Evaluates a new Result using the current accumulator and attaches the output to a new key.
845
841
  *
@@ -851,7 +847,7 @@ declare namespace Result {
851
847
  * ); // Ok({ a: 1, b: 2 })
852
848
  * ```
853
849
  */
854
- const bind: <K extends string, E, A, B>(key: K, f: (a: A) => Result<E, B>) => (data: Result<E, A>) => Result<E, A & { [P in K]: B; }>;
850
+ bind: <K extends string, E, A, B>(key: K, f: (a: A) => Result<E, B>) => (data: Result<E, A>) => Result<E, A & { [P in K]: B; }>;
855
851
  /**
856
852
  * Combines a record of Results into a single Result of a record.
857
853
  * Evaluates fields in key order and short-circuits on the first failure.
@@ -864,7 +860,7 @@ declare namespace Result {
864
860
  * }); // Ok({ name: "Alice", age: 30 })
865
861
  * ```
866
862
  */
867
- const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Result<E, R[K]>; }) => Result<E, R>;
863
+ struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Result<E, R[K]>; }) => Result<E, R>;
868
864
  /**
869
865
  * Narrows an `Ok` value with a predicate, converting to `Err(onFail(a))` if the predicate returns false.
870
866
  *
@@ -876,7 +872,7 @@ declare namespace Result {
876
872
  * ); // Err("Age 15 is below 18")
877
873
  * ```
878
874
  */
879
- const ensure: <A, E2>(predicate: (a: A) => boolean, onFail: (a: A) => E2) => <E1 = never>(data: Result<E1, A>) => Result<E1 | E2, A>;
875
+ ensure: <A, E2>(predicate: (a: A) => boolean, onFail: (a: A) => E2) => <E1 = never>(data: Result<E1, A>) => Result<E1 | E2, A>;
880
876
  /**
881
877
  * Transforms both branches of a Result simultaneously.
882
878
  * Applies `onErr` to `Err` values and `onOk` to `Ok` values.
@@ -892,1562 +888,861 @@ declare namespace Result {
892
888
  * ); // Ok(10)
893
889
  * ```
894
890
  */
895
- const bimap: <E1, E2, A, B>(onErr: (e: E1) => E2, onOk: (a: A) => B) => (data: Result<E1, A>) => Result<E2, B>;
896
- }
891
+ bimap: <E1, E2, A, B>(onErr: (e: E1) => E2, onOk: (a: A) => B) => (data: Result<E1, A>) => Result<E2, B>;
892
+ };
897
893
 
894
+ type Passed<A> = WithKind<"Passed"> & WithValue<A>;
895
+ type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
896
+ declare function toResult<E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2): (val: Validation<E1, A>) => Result<E2, A>;
897
+ declare function toResult<E, A>(data: Validation<E, A>): Result<NonEmptyArr<E>, A>;
898
898
  /**
899
- * TaskMaybe represents a lazy, infallible async operation that resolves to a `Maybe<A>`.
900
- * It is a type alias for `Task<Maybe<A>>`.
899
+ * Validation represents a value that is either passed with a success value,
900
+ * or failed with accumulated errors.
901
+ * Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
901
902
  *
902
- * Use Task.Maybe for async operations that can result in a missing value (e.g. database lookups).
903
+ * Use Validation when you need to collect all errors (e.g., form validation).
904
+ * Use Result when you want to fail fast on the first error.
903
905
  *
904
906
  * @example
905
907
  * ```ts
906
- * const findUser = (id: string): Task.Maybe<User> =>
907
- * Task.Maybe.tryCatch((signal) =>
908
- * fetch(`/users/${id}`, { signal }).then(r => r.ok ? r.json() : null)
909
- * );
908
+ * const validateName = (name: string): Validation<string, string> =>
909
+ * name.length > 0 ? Validation.make.passed(name) : Validation.make.failed("Name is required");
910
+ *
911
+ * const validateAge = (age: number): Validation<string, number> =>
912
+ * age >= 0 ? Validation.make.passed(age) : Validation.make.failed("Age must be positive");
913
+ *
914
+ * // Accumulates all errors using ap
915
+ * pipe(
916
+ * Validation.make.passed((name: string) => (age: number) => ({ name, age })),
917
+ * Validation.ap(validateName("")),
918
+ * Validation.ap(validateAge(-1))
919
+ * );
920
+ * // Failed(["Name is required", "Age must be positive"])
910
921
  * ```
911
922
  */
912
- type TaskMaybe<A> = Task<Maybe<A>>;
913
- declare namespace TaskMaybe {
914
- /**
915
- * Wraps a value in a Some inside a Task.
916
- *
917
- * @example
918
- * ```ts
919
- * const task = Task.Maybe.some(42);
920
- * const res = await task(); // Some(42)
921
- * ```
922
- */
923
- namespace make {
923
+ type Validation<E, A> = Passed<A> | Failed<E>;
924
+ declare const Validation: {
925
+ make: {
926
+ /**
927
+ * Wraps a value in a passed Validation.
928
+ *
929
+ * @example
930
+ * ```ts
931
+ * Validation.make.passed(42); // Passed(42)
932
+ * ```
933
+ */
934
+ passed: <E, A>(value: A) => Validation<E, A>;
935
+ /**
936
+ * Creates a failed Validation from a single error.
937
+ *
938
+ * @example
939
+ * ```ts
940
+ * Validation.make.failed("Invalid input");
941
+ * ```
942
+ */
943
+ failed: <E>(error: E) => Failed<E>;
944
+ /**
945
+ * Creates a failed Validation from multiple errors.
946
+ *
947
+ * @example
948
+ * ```ts
949
+ * Validation.make.failedAll(["Invalid input"]);
950
+ * ```
951
+ */
952
+ failedAll: <E>(errors: NonEmptyArr<E>) => Failed<E>;
953
+ };
954
+ is: {
924
955
  /**
925
- * Creates a Task.Maybe that resolves to Some(value).
956
+ * Type guard that checks if a Validation is passed.
926
957
  *
927
958
  * @example
928
959
  * ```ts
929
- * const task = Task.Maybe.make.some(42);
930
- * const res = await task(); // Some(42)
960
+ * const v = Validation.make.passed(42);
961
+ * if (Validation.is.passed(v)) {
962
+ * console.log(v.value); // 42
963
+ * }
931
964
  * ```
932
965
  */
933
- const some: <A>(value: A) => TaskMaybe<A>;
966
+ passed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
934
967
  /**
935
- * Creates a Task.Maybe that resolves to None.
968
+ * Type guard that checks if a Validation is failed.
936
969
  *
937
970
  * @example
938
971
  * ```ts
939
- * const task = Task.Maybe.make.none();
940
- * const res = await task(); // None
972
+ * const v = Validation.make.failed("invalid");
973
+ * if (Validation.is.failed(v)) {
974
+ * console.log(v.errors); // ["invalid"]
975
+ * }
941
976
  * ```
942
977
  */
943
- const none: <A = never>() => TaskMaybe<A>;
944
- }
945
- const some: <A>(value: A) => TaskMaybe<A>;
946
- const none: <A = never>() => TaskMaybe<A>;
947
- namespace from {
978
+ failed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
979
+ };
980
+ /**
981
+ * Creates a Validation from a synchronous thunk that may throw.
982
+ * Catches any errors and transforms them using the `onError` function into a Failed validation.
983
+ *
984
+ * @example
985
+ * ```ts
986
+ * const result = Validation.tryCatch(
987
+ * () => JSON.parse(rawString),
988
+ * { onError: (e) => `Parse error: ${e}` }
989
+ * );
990
+ * ```
991
+ */
992
+ tryCatch: <E, A>(f: () => A, options: {
993
+ onError: (e: unknown) => E;
994
+ }) => Validation<E, A>;
995
+ from: {
948
996
  /**
949
- * Lifts a Maybe into a Task.Maybe.
997
+ * Creates a Validation from a predicate applied to a value.
998
+ * Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
950
999
  *
951
1000
  * @example
952
1001
  * ```ts
953
- * Task.Maybe.from.Maybe(Maybe.make.some(42));
1002
+ * const validateName = Validation.from.Predicate(
1003
+ * (s: string) => s.length > 0,
1004
+ * () => "Name is required"
1005
+ * );
1006
+ *
1007
+ * validateName("Alice"); // Passed("Alice")
1008
+ * validateName(""); // Failed(["Name is required"])
954
1009
  * ```
955
1010
  */
956
- const Maybe: <A>(option: Maybe<A>) => TaskMaybe<A>;
1011
+ Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
957
1012
  /**
958
- * Creates a Task.Maybe from a nullable value.
959
- * Returns Some if the value is not null or undefined, None otherwise.
1013
+ * Creates a Validation from a nullable value.
1014
+ * If the value is null or undefined, returns Failed with the error from onNull.
1015
+ * Otherwise, returns Passed.
960
1016
  *
961
1017
  * @example
962
1018
  * ```ts
963
- * Task.Maybe.from.nullable(42); // resolves to Some(42)
964
- * Task.Maybe.from.nullable(null); // resolves to None
1019
+ * pipe(null, Validation.from.nullable(() => "is null")); // Failed(["is null"])
1020
+ * pipe(42, Validation.from.nullable(() => "is null")); // Passed(42)
965
1021
  * ```
966
1022
  */
967
- const nullable: <A>(value: A | null | undefined) => TaskMaybe<A>;
1023
+ nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
968
1024
  /**
969
- * Creates a Task.Maybe from a Result.
970
- * Ok becomes Some, Error becomes None (the error value is discarded).
1025
+ * Creates a Validation from a Maybe.
1026
+ * If the Maybe is None, returns Failed with the error from onNone.
1027
+ * Otherwise, returns Passed.
971
1028
  *
972
1029
  * @example
973
1030
  * ```ts
974
- * Task.Maybe.from.Result(Result.make.ok(42)); // resolves to Some(42)
975
- * Task.Maybe.from.Result(Result.make.err("e")); // resolves to None
1031
+ * pipe(Maybe.make.none(), Validation.from.Maybe(() => "is none")); // Failed(["is none"])
1032
+ * pipe(Maybe.make.some(42), Validation.from.Maybe(() => "is none")); // Passed(42)
976
1033
  * ```
977
1034
  */
978
- const Result: <E, A>(result: Result<E, A>) => TaskMaybe<A>;
1035
+ Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
979
1036
  /**
980
- * Lifts a Task into a Task.Maybe by wrapping its result in Some.
1037
+ * Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
1038
+ *
1039
+ * Useful when bridging from error-short-circuiting `Result` pipelines into
1040
+ * error-accumulating `Validation` pipelines.
981
1041
  *
982
1042
  * @example
983
1043
  * ```ts
984
- * Task.Maybe.from.Task(Task.resolve(42)); // resolves to Some(42)
1044
+ * Validation.from.Result(Result.make.ok(42)); // Passed(42)
1045
+ * Validation.from.Result(Result.make.err("bad")); // Failed(["bad"])
985
1046
  * ```
986
1047
  */
987
- const Task: <A>(task: Task<A>) => TaskMaybe<A>;
988
- }
1048
+ Result: <E, A>(data: Result<E, A>) => Validation<E, A>;
1049
+ };
989
1050
  /**
990
- * Creates a Task.Maybe from a Promise-returning function.
991
- * Returns Some if the promise resolves, None if it rejects.
992
- * The factory optionally receives an `AbortSignal` forwarded from the call site.
1051
+ * Transforms the success value inside a Validation.
993
1052
  *
994
1053
  * @example
995
1054
  * ```ts
996
- * const fetchUser = Task.Maybe.tryCatch((signal) =>
997
- * fetch("/user/1", { signal }).then(r => r.json())
998
- * );
1055
+ * pipe(Validation.make.passed(5), Validation.map(n => n * 2)); // Passed(10)
1056
+ * pipe(Validation.make.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
999
1057
  * ```
1000
1058
  */
1001
- const tryCatch: <A>(f: (signal?: AbortSignal) => Thenable<A>) => TaskMaybe<A>;
1059
+ map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
1002
1060
  /**
1003
- * Transforms the value inside a Task.Maybe.
1061
+ * Transforms the error list inside a Validation.
1062
+ *
1063
+ * @example
1064
+ * ```ts
1065
+ * pipe(Validation.make.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
1066
+ * ```
1004
1067
  */
1005
- const map: <A, B>(f: (a: A) => B) => (data: TaskMaybe<A>) => TaskMaybe<B>;
1068
+ mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
1006
1069
  /**
1007
- * Chains Task.Maybe computations. If the first resolves to Some, passes the
1008
- * value to f. If the first resolves to None, propagates None.
1070
+ * Applies a function wrapped in a Validation to a value wrapped in a Validation.
1071
+ * Accumulates errors from both sides.
1009
1072
  *
1010
1073
  * @example
1011
1074
  * ```ts
1075
+ * const add = (a: number) => (b: number) => a + b;
1076
+ * pipe(
1077
+ * Validation.make.passed(add),
1078
+ * Validation.ap(Validation.make.passed(5)),
1079
+ * Validation.ap(Validation.make.passed(3))
1080
+ * ); // Passed(8)
1081
+ *
1012
1082
  * pipe(
1013
- * findUser("123"),
1014
- * Task.Maybe.chain(user => findOrg(user.orgId))
1015
- * )();
1083
+ * Validation.make.passed(add),
1084
+ * Validation.ap(Validation.make.failed<string>("bad a")),
1085
+ * Validation.ap(Validation.make.failed<string>("bad b"))
1086
+ * ); // Failed(["bad a", "bad b"])
1016
1087
  * ```
1017
1088
  */
1018
- const chain: <A, B>(f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<B>;
1089
+ ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
1019
1090
  /**
1020
- * Applies a function wrapped in a Task.Maybe to a value wrapped in a Task.Maybe.
1021
- * Both Tasks run in parallel.
1022
- */
1023
- const ap: <A>(arg: TaskMaybe<A>) => <B>(data: TaskMaybe<(a: A) => B>) => TaskMaybe<B>;
1024
- /**
1025
- * Extracts a value from a Task.Maybe by providing handlers for both cases.
1091
+ * Applies a function wrapped in a Validation to a value wrapped in a Validation,
1092
+ * using a custom error concatenator function when both sides fail.
1093
+ *
1094
+ * @example
1095
+ * ```ts
1096
+ * const concat = (e1: NonEmptyArr<string>, e2: NonEmptyArr<string>): NonEmptyArr<string> =>
1097
+ * [...e1, ...e2];
1098
+ * pipe(fnVal, Validation.apCustom(concat)(argVal));
1099
+ * ```
1026
1100
  */
1027
- const fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: TaskMaybe<A>) => Task<B>;
1101
+ apCustom: <E1, E2, E3>(concat: (e1: NonEmptyArr<E1>, e2: NonEmptyArr<E2>) => NonEmptyArr<E3>) => <A>(arg: Validation<E2, A>) => <B>(data: Validation<E1, (a: A) => B>) => Validation<E3, B>;
1028
1102
  /**
1029
- * Pattern matches on a Task.Maybe, returning a Task of the result.
1103
+ * Extracts the value from a Validation by providing handlers for both cases.
1030
1104
  *
1031
1105
  * @example
1032
1106
  * ```ts
1033
1107
  * pipe(
1034
- * findUser("123"),
1035
- * Task.Maybe.match({
1036
- * some: user => `Hello, ${user.name}`,
1037
- * none: () => "User not found"
1038
- * })
1039
- * )();
1108
+ * Validation.make.passed(42),
1109
+ * Validation.fold(
1110
+ * errors => `Errors: ${errors.join(", ")}`,
1111
+ * value => `Value: ${value}`
1112
+ * )
1113
+ * );
1040
1114
  * ```
1041
1115
  */
1042
- const match: <A, B>(cases: {
1043
- none: () => B;
1044
- some: (a: A) => B;
1045
- }) => (data: TaskMaybe<A>) => Task<B>;
1046
- /**
1047
- * Returns the value or a default if the Task.Maybe resolves to None.
1048
- * The default can be a different type, widening the result to `Task<A | B>`.
1049
- */
1050
- const getOrElse: <B>(defaultValue: () => B) => <A>(data: TaskMaybe<A>) => Task<A | B>;
1051
- /**
1052
- * Executes a side effect on the value without changing the Task.Maybe.
1053
- * Useful for logging or debugging.
1054
- */
1055
- const tap: <A>(f: (a: A) => void) => (data: TaskMaybe<A>) => TaskMaybe<A>;
1056
- /**
1057
- * Filters the value inside a Task.Maybe. Returns None if the predicate fails.
1058
- */
1059
- const filter: <A>(predicate: (a: A) => boolean) => (data: TaskMaybe<A>) => TaskMaybe<A>;
1060
- namespace to {
1061
- /**
1062
- * Converts a Task.Maybe to a Task.Result, using onNone to produce the error value.
1063
- *
1064
- * @example
1065
- * ```ts
1066
- * pipe(
1067
- * findUser("123"),
1068
- * Task.Maybe.to.Result(() => "User not found")
1069
- * );
1070
- * ```
1071
- */
1072
- const Result: <E>(onNone: () => E) => <A>(data: TaskMaybe<A>) => Task.Result<E, A>;
1073
- }
1116
+ fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
1074
1117
  /**
1075
- * Lifts a Task.Maybe value into an accumulator object.
1118
+ * Pattern matches on a Validation, returning the result of the matching case.
1076
1119
  *
1077
1120
  * @example
1078
1121
  * ```ts
1079
- * pipe(Task.Maybe.some(42), Task.Maybe.bindTo("value")); // Task.Maybe({ value: 42 })
1122
+ * pipe(
1123
+ * validation,
1124
+ * Validation.match({
1125
+ * passed: value => `Got ${value}`,
1126
+ * failed: errors => `Failed: ${errors.join(", ")}`
1127
+ * })
1128
+ * );
1080
1129
  * ```
1081
1130
  */
1082
- const bindTo: <K extends string>(key: K) => <A>(data: TaskMaybe<A>) => TaskMaybe<{ [P in K]: A; }>;
1131
+ match: <E, A, B>(cases: {
1132
+ passed: (a: A) => B;
1133
+ failed: (errors: NonEmptyArr<E>) => B;
1134
+ }) => (data: Validation<E, A>) => B;
1083
1135
  /**
1084
- * Evaluates a new Task.Maybe using the current accumulator and attaches the output to a new key.
1136
+ * Returns the success value or a default value if the Validation is failed.
1137
+ * The default can be a different type, widening the result to `A | B`.
1085
1138
  *
1086
1139
  * @example
1087
1140
  * ```ts
1088
- * pipe(
1089
- * Task.Maybe.some({ a: 1 }),
1090
- * Task.Maybe.bind("b", ({ a }) => Task.Maybe.some(a + 1))
1091
- * ); // Task.Maybe({ a: 1, b: 2 })
1141
+ * pipe(Validation.make.passed(5), Validation.getOrElse(() => 0)); // 5
1142
+ * pipe(Validation.make.failed("oops"), Validation.getOrElse(() => 0)); // 0
1143
+ * pipe(Validation.make.failed("oops"), Validation.getOrElse(() => null)); // null typed as number | null
1092
1144
  * ```
1093
1145
  */
1094
- const bind: <K extends string, A, B>(key: K, f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<A & { [P in K]: B; }>;
1146
+ getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Validation<E, A>) => A | B;
1095
1147
  /**
1096
- * Recovers from a None state by providing a fallback Task.Maybe.
1148
+ * Executes a side effect on the success value without changing the Validation.
1097
1149
  *
1098
1150
  * @example
1099
1151
  * ```ts
1100
1152
  * pipe(
1101
- * Task.Maybe.none(),
1102
- * Task.Maybe.recover(() => Task.Maybe.some(42))
1103
- * ); // Task.Maybe(42)
1153
+ * Validation.make.passed(5),
1154
+ * Validation.tap(n => console.log("Value:", n)),
1155
+ * Validation.map(n => n * 2)
1156
+ * );
1104
1157
  * ```
1105
1158
  */
1106
- const recover: <B>(fallback: () => TaskMaybe<B>) => <A>(data: TaskMaybe<A>) => TaskMaybe<A | B>;
1159
+ tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
1107
1160
  /**
1108
- * Combines a record of Task.Maybes into a single Task.Maybe of a record.
1109
- * Evaluates fields in parallel and returns None if any task resolves to None.
1161
+ * Executes a side effect on the accumulated errors without changing the Validation.
1162
+ * Useful for logging or reporting validation failures.
1110
1163
  *
1111
1164
  * @example
1112
1165
  * ```ts
1113
- * Task.Maybe.struct({
1114
- * name: Task.Maybe.some("Alice"),
1115
- * age: Task.Maybe.some(30)
1116
- * }); // Task.Maybe({ name: "Alice", age: 30 })
1166
+ * pipe(
1167
+ * Validation.make.failed("Name required"),
1168
+ * Validation.tapError(errors => console.error("validation failed:", errors)),
1169
+ * Validation.map(toUser)
1170
+ * );
1117
1171
  * ```
1118
1172
  */
1119
- const struct: <R extends Record<string, any>>(fields: { [K in keyof R]: TaskMaybe<R[K]>; }) => TaskMaybe<R>;
1173
+ tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
1174
+ /**
1175
+ * Recovers from a Failed state by providing a fallback Validation.
1176
+ * The fallback receives the accumulated error list so callers can inspect which errors occurred.
1177
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
1178
+ */
1179
+ recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => Validation<E, B>) => <A>(data: Validation<E, A>) => Validation<E, A | B>;
1120
1180
  /**
1121
- * Creates a memoized version of a Task.Maybe. The task is executed at most once on first call,
1122
- * and its resolved Maybe is cached for all subsequent calls.
1181
+ * Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
1182
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
1123
1183
  *
1124
1184
  * @example
1125
1185
  * ```ts
1126
- * const loadUser = Task.Maybe.memoize(fetchUserMaybeTask);
1186
+ * pipe(
1187
+ * Validation.make.failed("field-error"),
1188
+ * Validation.recoverUnless(e => e === "fatal", () => Validation.make.passed(0))
1189
+ * ); // Passed(0)
1127
1190
  * ```
1128
1191
  */
1129
- const memoize: <A>(task: TaskMaybe<A>) => TaskMaybe<A>;
1130
- }
1131
-
1132
- /**
1133
- * A Task that can fail with an error of type E or succeed with a value of type A.
1134
- * Combines async operations with typed error handling.
1135
- *
1136
- * @example
1137
- * ```ts
1138
- * const fetchUser = (id: string): Task.Result<Error, User> =>
1139
- * Task.Result.tryCatch(
1140
- * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
1141
- * { onError: (e) => new Error(`Failed to fetch user: ${e}`) }
1142
- * );
1143
- * ```
1144
- */
1145
- type TaskResult<E, A> = Task<Result<E, A>>;
1146
- declare namespace TaskResult {
1147
- namespace make {
1148
- /**
1149
- * Wraps a value in a successful Task.Result.
1150
- *
1151
- * @example
1152
- * ```ts
1153
- * const task = Task.Result.make.ok(42);
1154
- * const res = await task(); // Ok(42)
1155
- * ```
1156
- */
1157
- const ok: <E = never, A = unknown>(value: A) => TaskResult<E, A>;
1158
- /**
1159
- * Creates a failed Task.Result with the given error.
1160
- *
1161
- * @example
1162
- * ```ts
1163
- * const task = Task.Result.make.err("failed");
1164
- * const res = await task(); // Err("failed")
1165
- * ```
1166
- */
1167
- const err: <E, A = never>(error: E) => TaskResult<E, A>;
1168
- }
1169
- const ok: <E = never, A = unknown>(value: A) => TaskResult<E, A>;
1170
- const err: <E, A = never>(error: E) => TaskResult<E, A>;
1171
- namespace from {
1172
- /**
1173
- * Creates a Task.Result from a nullable value.
1174
- * Returns Ok if the value is not null or undefined, err from onNull otherwise.
1175
- *
1176
- * @example
1177
- * ```ts
1178
- * Task.Result.from.nullable(() => "missing")(42); // resolves to Ok(42)
1179
- * Task.Result.from.nullable(() => "missing")(null); // resolves to Err("missing")
1180
- * ```
1181
- */
1182
- const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
1192
+ recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => <A>(data: Validation<E, A>) => Validation<E, A | B>;
1193
+ to: {
1183
1194
  /**
1184
- * Creates a Task.Result from a Maybe.
1185
- * Some becomes Ok, None becomes err from onNone.
1195
+ * Converts a Validation to a Result.
1196
+ * Passed becomes Ok.
1197
+ * Direct call converts Failed to Err with accumulated error list `NonEmptyArr<E>`.
1198
+ * Curried call converts Failed to Err with combined error `E2` via `combineErrors`.
1186
1199
  *
1187
1200
  * @example
1188
1201
  * ```ts
1189
- * Task.Result.from.Maybe(() => "empty")(Maybe.make.some(42)); // resolves to Ok(42)
1190
- * Task.Result.from.Maybe(() => "empty")(Maybe.make.none()); // resolves to Err("empty")
1202
+ * Validation.to.Result(Validation.make.passed(42)); // Ok(42)
1203
+ * Validation.to.Result(Validation.make.failed("oops")); // Err(["oops"])
1204
+ * pipe(Validation.make.failed("oops"), Validation.to.Result(errors => errors.join(", "))); // Err("oops")
1191
1205
  * ```
1192
1206
  */
1193
- const Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
1207
+ Result: typeof toResult;
1194
1208
  /**
1195
- * Lifts a Result into a Task.Result.
1209
+ * Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
1210
+ * (errors are discarded).
1196
1211
  *
1197
1212
  * @example
1198
1213
  * ```ts
1199
- * Task.Result.from.Result(Result.make.ok(42)); // resolves to Ok(42)
1214
+ * Validation.to.Maybe(Validation.make.passed(42)); // Some(42)
1215
+ * Validation.to.Maybe(Validation.make.failed("bad")); // None
1200
1216
  * ```
1201
1217
  */
1202
- /**
1203
- * Lifts a Result into a Task.Result.
1204
- *
1205
- * @example
1206
- * ```ts
1207
- * Task.Result.from.Result(Result.make.ok(42)); // resolves to Ok(42)
1208
- * ```
1209
- */
1210
- const Result: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
1211
- }
1212
- namespace to {
1213
- /**
1214
- * Converts a Task.Result to a Task.Maybe, dropping the error value on Err.
1215
- *
1216
- * @example
1217
- * ```ts
1218
- * const taskResult = Task.Result.ok(42);
1219
- * const taskMaybe = pipe(taskResult, Task.Result.to.Maybe);
1220
- * ```
1221
- */
1222
- const Maybe: <E, A>(data: TaskResult<E, A>) => TaskMaybe<A>;
1223
- }
1224
- /**
1225
- * Creates a Task.Result from a Promise-returning thunk that may throw or reject.
1226
- * Catches any errors and transforms them using the `onError` function into an `Err`.
1227
- * The thunk optionally receives an `AbortSignal` forwarded from the call site.
1228
- *
1229
- * @example
1230
- * ```ts
1231
- * const loadUser = Task.Result.tryCatch(
1232
- * (signal) => userStore.get("u_123", { signal }),
1233
- * { onError: (e) => new DbError(e) }
1234
- * );
1235
- * ```
1236
- */
1237
- const tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
1238
- onError: (error: unknown) => E;
1239
- }) => TaskResult<E, A>;
1240
- /**
1241
- * Transforms the success value inside a Task.Result.
1242
- */
1243
- const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
1244
- /**
1245
- * Transforms the error value inside a Task.Result.
1246
- */
1247
- const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
1248
- /**
1249
- * Chains Task.Result computations. If the first succeeds, passes the value to f.
1250
- * If the first fails, propagates the error.
1251
- */
1252
- const chain: <E2, A, B>(f: (a: A) => TaskResult<E2, B>) => <E1 = never>(data: TaskResult<E1, A>) => TaskResult<E1 | E2, B>;
1253
- /**
1254
- * Extracts the value from a Task.Result by providing handlers for both cases.
1255
- */
1256
- const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
1257
- /**
1258
- * Pattern matches on a Task.Result, returning a Task of the result.
1259
- */
1260
- const match: <E, A, B>(cases: {
1261
- err: (e: E) => B;
1262
- ok: (a: A) => B;
1263
- }) => (data: TaskResult<E, A>) => Task<B>;
1264
- /**
1265
- * Recovers from an error by providing a fallback Task.Result.
1266
- * The fallback can produce a different success type, widening the result to `Task.Result<E, A | B>`.
1267
- */
1268
- const recover: <E, B>(fallback: (e: E) => TaskResult<E, B>) => <A>(data: TaskResult<E, A>) => TaskResult<E, A | B>;
1269
- /**
1270
- * Recovers from an error unless the predicate `isBlocked` returns true for that error.
1271
- * The fallback can produce a different success type, widening the result to `Task.Result<E, A | B>`.
1272
- *
1273
- * @example
1274
- * ```ts
1275
- * pipe(
1276
- * fetchTask,
1277
- * Task.Result.recoverUnless(
1278
- * (e) => e === "fatal",
1279
- * () => Task.Result.ok("fallback")
1280
- * )
1281
- * );
1282
- * ```
1283
- */
1284
- const recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: (e: E) => TaskResult<E, B>) => <A>(data: TaskResult<E, A>) => TaskResult<E, A | B>;
1285
- /**
1286
- * Returns the success value or a default value if the Task.Result is an error.
1287
- * The default can be a different type, widening the result to `Task<A | B>`.
1288
- */
1289
- const getOrElse: <B>(defaultValue: () => B) => <E, A>(data: TaskResult<E, A>) => Task<A | B>;
1290
- /**
1291
- * Executes a side effect on the success value without changing the Task.Result.
1292
- * Useful for logging or debugging.
1293
- */
1294
- const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
1295
- /**
1296
- * Executes a side effect on the error value without changing the Task.Result.
1297
- * Useful for logging or reporting async errors.
1298
- *
1299
- * @example
1300
- * ```ts
1301
- * pipe(
1302
- * fetchUser(id),
1303
- * Task.Result.tapError(e => console.error("fetch failed:", e)),
1304
- * Task.Result.chain(saveToCache),
1305
- * )
1306
- * ```
1307
- */
1308
- const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
1309
- /**
1310
- * Applies a function wrapped in a Task.Result to a value wrapped in a Task.Result.
1311
- * Both Tasks run in parallel.
1312
- */
1313
- const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
1314
- /**
1315
- * Executes a `Task.Result` with an optional signal, returning `Promise<Result<E, A>>`.
1316
- * Use as a terminal step in a `pipe` chain.
1317
- *
1318
- * @example
1319
- * ```ts
1320
- * const controller = new AbortController();
1321
- * const result = await pipe(
1322
- * fetchUser("42"),
1323
- * Task.Result.chain(user => fetchPosts(user.id)),
1324
- * Task.Result.run(controller.signal),
1325
- * );
1326
- * if (Result.is.ok(result)) render(result.value);
1327
- * ```
1328
- */
1329
- const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Deferred<Result<E, A>>;
1330
- /**
1331
- * Converts a Task.Result value into an object containing a single property.
1332
- * Initiates the pipeline accumulator record.
1333
- *
1334
- * @example
1335
- * ```ts
1336
- * pipe(Task.Result.ok(42), Task.Result.bindTo("value")); // Task.Result({ value: 42 })
1337
- * ```
1338
- */
1339
- const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
1340
- /**
1341
- * Evaluates a new Task.Result using the current accumulator and attaches the output to a new key.
1342
- *
1343
- * @example
1344
- * ```ts
1345
- * pipe(
1346
- * Task.Result.ok({ a: 1 }),
1347
- * Task.Result.bind("b", ({ a }) => Task.Result.ok(a + 1))
1348
- * ); // Task.Result({ a: 1, b: 2 })
1349
- * ```
1350
- */
1351
- 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; }>;
1218
+ Maybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
1219
+ };
1352
1220
  /**
1353
- * Combines a record of Task.Results into a single Task.Result of a record.
1354
- * Evaluates all tasks in parallel, forwarding the AbortSignal down to each sub-task.
1355
- * Returns the first Err encountered in key order.
1221
+ * Combines two independent Validation instances into a tuple.
1222
+ * If both are Passed, returns Passed with both values as a tuple.
1223
+ * If either is Failed, accumulates errors from both sides.
1356
1224
  *
1357
1225
  * @example
1358
1226
  * ```ts
1359
- * Task.Result.struct({
1360
- * name: Task.Result.ok("Alice"),
1361
- * age: Task.Result.ok(30)
1362
- * }); // Task.Result({ name: "Alice", age: 30 })
1363
- * ```
1364
- */
1365
- const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskResult<E, R[K]>; }) => TaskResult<E, R>;
1366
- /**
1367
- * Retries a fallible Task.Result according to a RetryPolicy.
1368
- * If the task succeeds, returns Ok immediately.
1369
- * If the task fails, retries up to policy.attempts times with delays generated by policy.
1227
+ * Validation.product(
1228
+ * Validation.make.passed("alice"),
1229
+ * Validation.make.passed(30)
1230
+ * ); // Passed(["alice", 30])
1370
1231
  *
1371
- * @example
1372
- * ```ts
1373
- * const policy = RetryPolicy.exponential({ attempts: 3, initial: Duration.milliseconds(100) });
1374
- * const retryableFetch = pipe(fetchData, Task.Result.retry(policy));
1232
+ * Validation.product(
1233
+ * Validation.make.failed("Name required"),
1234
+ * Validation.make.failed("Age must be >= 0")
1235
+ * ); // Failed(["Name required", "Age must be >= 0"])
1375
1236
  * ```
1376
1237
  */
1377
- const retry: (policy: RetryPolicy) => <E, A>(task: TaskResult<E, A>) => TaskResult<E, A>;
1238
+ product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
1378
1239
  /**
1379
- * Creates a memoized version of a Task.Result. The task is executed at most once on first call,
1380
- * and its resolved Result is cached for all subsequent calls.
1240
+ * Combines a non-empty list of Validation instances, accumulating all errors.
1241
+ * If all are Passed, returns Passed with all values collected into an array.
1242
+ * If any are Failed, returns Failed with all accumulated errors.
1381
1243
  *
1382
1244
  * @example
1383
1245
  * ```ts
1384
- * const loadConfig = Task.Result.memoize(fetchConfigTask);
1246
+ * Validation.productAll([
1247
+ * validateName(name),
1248
+ * validateEmail(email),
1249
+ * validateAge(age)
1250
+ * ]);
1251
+ * // Passed([name, email, age]) or Failed([...all errors])
1385
1252
  * ```
1386
1253
  */
1387
- const memoize: <E, A>(task: TaskResult<E, A>) => TaskResult<E, A>;
1254
+ productAll: <E, A>(data: NonEmptyArr<Validation<E, A>>) => Validation<E, readonly A[]>;
1388
1255
  /**
1389
- * Times out a fallible task, resolving to `Err(onTimeout())` if the duration elapses
1390
- * before the task completes.
1256
+ * Combines a record of Validations into a single Validation of a record.
1257
+ * Accumulates all failed branches' errors.
1391
1258
  *
1392
1259
  * @example
1393
1260
  * ```ts
1394
- * const fetchWithTimeout = pipe(
1395
- * fetchTask,
1396
- * Task.Result.timeout({ duration: Duration.seconds(5), onTimeout: () => "Request timed out" })
1397
- * );
1398
- * ```
1399
- */
1400
- const timeout: <E2>(options: {
1401
- duration: Duration;
1402
- onTimeout: () => E2;
1403
- }) => <E1 = never, A = unknown>(task: TaskResult<E1, A>) => TaskResult<E1 | E2, A>;
1404
- /**
1405
- * Runs a list of fallible tasks in parallel and collects all outcomes (`Ok` and `Err`)
1406
- * without short-circuiting on failure.
1261
+ * Validation.struct({
1262
+ * name: Validation.make.passed("Alice"),
1263
+ * age: Validation.make.passed(30)
1264
+ * }); // Passed({ name: "Alice", age: 30 })
1407
1265
  *
1408
- * @example
1409
- * ```ts
1410
- * const results = await Task.Result.allSettled([task1, task2, task3])();
1411
- * // [Ok(val1), Err(err2), Ok(val3)]
1266
+ * Validation.struct({
1267
+ * name: Validation.make.failed("Name required"),
1268
+ * age: Validation.make.failed("Age must be >= 0")
1269
+ * }); // Failed(["Name required", "Age must be >= 0"])
1412
1270
  * ```
1413
1271
  */
1414
- const allSettled: <E, A>(tasks: ReadonlyArray<TaskResult<E, A>>) => Task<ReadonlyArray<Result<E, A>>>;
1415
- }
1272
+ struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Validation<E, R[K]>; }) => Validation<E, R>;
1273
+ };
1416
1274
 
1275
+ type _CoreMaybe<A> = Maybe<A>;
1276
+ type _CoreResult<E, A> = Result<E, A>;
1277
+ type _CoreValidation<E, A> = Validation<E, A>;
1417
1278
  /**
1418
- * A Task that resolves to a Validation — combining async operations with
1419
- * error accumulation. Unlike Task.Result, multiple failures are collected
1420
- * rather than short-circuiting on the first error.
1279
+ * A lazy async computation that always resolves.
1280
+ *
1281
+ * Two guarantees:
1282
+ * - **Lazy** — nothing starts until you call it.
1283
+ * - **Infallible** — it never rejects. If failure is possible, encode it in the
1284
+ * return type using `Task.Result<E, A>` instead.
1285
+ *
1286
+ * An optional `AbortSignal` can be passed at the call site. Combinators like
1287
+ * `retry`, `pollUntil`, and `timeout` thread it automatically to every inner
1288
+ * operation. Existing tasks that ignore the signal continue to work unchanged.
1289
+ *
1290
+ * Calling a Task returns a `Deferred<A>` — a one-shot async value that supports
1291
+ * `await` but has no `.catch()`, `.finally()`, or chainable `.then()`.
1292
+ *
1293
+ * **Consuming a Task:**
1294
+ *
1295
+ * Use `await task()` to run it and get the value directly:
1296
+ * ```ts
1297
+ * const value: number = await task();
1298
+ * ```
1299
+ *
1300
+ * When you need an explicit `Promise<A>` (e.g. for a third-party API), convert
1301
+ * the `Deferred` with `Deferred.to.Promise`:
1302
+ * ```ts
1303
+ * const p: Promise<number> = Deferred.to.Promise(task());
1304
+ * ```
1421
1305
  *
1422
1306
  * @example
1423
1307
  * ```ts
1424
- * const validateName = (name: string): Task.Validation<string, string> =>
1425
- * name.length > 0
1426
- * ? Task.Validation.passed(name)
1427
- * : Task.Validation.failed("Name is required");
1308
+ * const getTimestamp: Task<number> = Task.resolve(Date.now());
1428
1309
  *
1429
- * // Accumulate errors from multiple async validations using ap
1430
- * pipe(
1431
- * Task.Validation.passed((name: string) => (age: number) => ({ name, age })),
1432
- * Task.Validation.ap(validateName("")),
1433
- * Task.Validation.ap(validateAge(-1))
1434
- * )();
1435
- * // Failed(["Name is required", "Age must be positive"])
1310
+ * // Nothing runs yet getTimestamp is just a description
1311
+ * const formatted = pipe(
1312
+ * getTimestamp,
1313
+ * Task.map(ts => new Date(ts).toISOString())
1314
+ * );
1315
+ *
1316
+ * // Execute when ready
1317
+ * const result = await formatted();
1436
1318
  * ```
1437
1319
  */
1438
- type TaskValidation<E, A> = Task<Validation<E, A>>;
1439
- declare namespace TaskValidation {
1440
- namespace make {
1441
- /**
1442
- * Wraps a value in a passed Task.Validation.
1443
- *
1444
- * @example
1445
- * ```ts
1446
- * const task = Task.Validation.make.passed(42);
1447
- * const res = await task(); // Passed(42)
1448
- * ```
1449
- */
1450
- const passed: <E = never, A = unknown>(value: A) => TaskValidation<E, A>;
1451
- /**
1452
- * Creates a failed Task.Validation with a single error.
1453
- *
1454
- * @example
1455
- * ```ts
1456
- * const task = Task.Validation.make.failed("invalid");
1457
- * const res = await task(); // Failed(["invalid"])
1458
- * ```
1459
- */
1460
- const failed: <E, A = never>(error: E) => TaskValidation<E, A>;
1461
- /**
1462
- * Creates a failed Task.Validation from multiple errors.
1463
- *
1464
- * @example
1465
- * ```ts
1466
- * const task = Task.Validation.make.failedAll(["err1", "err2"]);
1467
- * const res = await task(); // Failed(["err1", "err2"])
1468
- * ```
1469
- */
1470
- const failedAll: <E, A = never>(errors: NonEmptyArr<E>) => TaskValidation<E, A>;
1471
- }
1472
- const passed: <E = never, A = unknown>(value: A) => TaskValidation<E, A>;
1473
- const failed: <E, A = never>(error: E) => TaskValidation<E, A>;
1474
- const failedAll: <E, A = never>(errors: NonEmptyArr<E>) => TaskValidation<E, A>;
1475
- namespace from {
1476
- /**
1477
- * Lifts a Validation into a Task.Validation.
1478
- *
1479
- * @example
1480
- * ```ts
1481
- * Task.Validation.from.Validation(Validation.make.passed(42));
1482
- * ```
1483
- */
1484
- const Validation: <E, A>(validation: Validation<E, A>) => TaskValidation<E, A>;
1485
- /**
1486
- * Creates a Task.Validation from a nullable value.
1487
- * If the value is null or undefined, returns Failed with the error from onNull.
1488
- * Otherwise, returns Passed.
1489
- *
1490
- * @example
1491
- * ```ts
1492
- * Task.Validation.from.nullable(() => "missing")(42); // resolves to Passed(42)
1493
- * Task.Validation.from.nullable(() => "missing")(null); // resolves to Failed(["missing"])
1494
- * ```
1495
- */
1496
- const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskValidation<E, A>;
1497
- /**
1498
- * Creates a Task.Validation from a Maybe.
1499
- * Some becomes Passed, None becomes Failed with the error from onNone.
1500
- *
1501
- * @example
1502
- * ```ts
1503
- * Task.Validation.from.Maybe(() => "empty")(Maybe.make.some(42)); // resolves to Passed(42)
1504
- * Task.Validation.from.Maybe(() => "empty")(Maybe.make.none()); // resolves to Failed(["empty"])
1505
- * ```
1506
- */
1507
- const Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskValidation<E, A>;
1508
- /**
1509
- * Creates a Task.Validation from a Result.
1510
- * Ok becomes Passed, Err(e) becomes Failed([e]).
1511
- *
1512
- * @example
1513
- * ```ts
1514
- * Task.Validation.from.Result(Result.make.ok(42)); // resolves to Passed(42)
1515
- * Task.Validation.from.Result(Result.make.err("bad")); // resolves to Failed(["bad"])
1516
- * ```
1517
- */
1518
- const Result: <E, A>(result: Result<E, A>) => TaskValidation<E, A>;
1519
- }
1520
- namespace to {
1521
- /**
1522
- * Converts a `Task.Validation` to a `Task.Result`, combining accumulated errors using `combineErrors`.
1523
- * `Passed(a)` becomes `Ok(a)`; `Failed(errors)` becomes `Err(combineErrors(errors))`.
1524
- *
1525
- * @example
1526
- * ```ts
1527
- * Task.Validation.to.Result((errors) => errors.join(", "))(validationTask);
1528
- * ```
1529
- */
1530
- const Result: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (data: TaskValidation<E1, A>) => TaskResult<E2, A>;
1320
+ type Task<A> = (signal?: AbortSignal) => Deferred<A>;
1321
+ declare const Task: {
1322
+ /**
1323
+ * Creates a Task that immediately resolves to the given value.
1324
+ *
1325
+ * @example
1326
+ * ```ts
1327
+ * const task = Task.resolve(42);
1328
+ * const value = await task(); // 42
1329
+ * ```
1330
+ */
1331
+ resolve: <A>(value: A) => Task<A>;
1332
+ from: {
1531
1333
  /**
1532
- * Converts a `Task.Validation` to a `Task.Maybe`.
1533
- * `Passed(a)` becomes `Some(a)`; `Failed(errors)` becomes `None` (errors are discarded).
1334
+ * Creates a Task from a lazy synchronous thunk.
1335
+ * Unlike `Task.resolve(f())`, `from.sync` does not evaluate `f` until the Task is called.
1534
1336
  *
1535
1337
  * @example
1536
1338
  * ```ts
1537
- * Task.Validation.to.Maybe(validationTask);
1339
+ * const t = Task.from.sync(() => Date.now()); // Date.now() not called yet
1340
+ * const ts = await t(); // called here, every time
1538
1341
  * ```
1539
1342
  */
1540
- const Maybe: <E, A>(data: TaskValidation<E, A>) => TaskMaybe<A>;
1541
- }
1542
- /**
1543
- * Creates a Task.Validation from a Promise-returning function.
1544
- * Catches any errors and transforms them using the onError function.
1545
- * The factory optionally receives an `AbortSignal` forwarded from the call site.
1343
+ sync: <A>(f: () => A) => Task<A>;
1344
+ };
1546
1345
  /**
1547
- * Creates a Task.Validation from a Promise-returning thunk that may throw or reject.
1548
- * Catches any errors and transforms them using the `onError` function into a Failed validation.
1549
- * The thunk optionally receives an `AbortSignal` forwarded from the call site.
1346
+ * Wraps a Promise-returning thunk that may throw or reject,
1347
+ * trapping errors with a fallback function and returning a guaranteed `Task<A>`.
1550
1348
  *
1551
1349
  * @example
1552
1350
  * ```ts
1553
- * const loadConfig = Task.Validation.tryCatch(
1554
- * (signal) => configStore.get("default", { signal }),
1555
- * { onError: (e) => `Failed to load config: ${e}` }
1351
+ * const loadConfig = Task.tryCatch(
1352
+ * () => configStore.get("default"),
1353
+ * { onError: () => DEFAULT_CONFIG }
1556
1354
  * );
1557
1355
  * ```
1558
1356
  */
1559
- const tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
1560
- onError: (error: unknown) => E;
1561
- }) => TaskValidation<E, A>;
1562
- /**
1563
- * Transforms the success value inside a Task.Validation.
1564
- */
1565
- const map: <E, A, B>(f: (a: A) => B) => (data: TaskValidation<E, A>) => TaskValidation<E, B>;
1357
+ tryCatch: <A>(f: (signal?: AbortSignal) => globalThis.Promise<A>, options: {
1358
+ onError: (error: unknown) => A;
1359
+ }) => Task<A>;
1566
1360
  /**
1567
- * Applies a function wrapped in a Task.Validation to a value wrapped in a
1568
- * Task.Validation. Both Tasks run in parallel and errors from both sides
1569
- * are accumulated.
1361
+ * Transforms the value inside a Task.
1570
1362
  *
1571
1363
  * @example
1572
1364
  * ```ts
1573
1365
  * pipe(
1574
- * Task.Validation.passed((name: string) => (age: number) => ({ name, age })),
1575
- * Task.Validation.ap(validateName(name)),
1576
- * Task.Validation.ap(validateAge(age))
1577
- * )();
1366
+ * Task.resolve(5),
1367
+ * Task.map(n => n * 2)
1368
+ * )(); // Deferred<10>
1578
1369
  * ```
1579
1370
  */
1580
- const ap: <E, A>(arg: TaskValidation<E, A>) => <B>(data: TaskValidation<E, (a: A) => B>) => TaskValidation<E, B>;
1581
- /**
1582
- * Extracts a value from a Task.Validation by providing handlers for both cases.
1583
- */
1584
- const fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: TaskValidation<E, A>) => Task<B>;
1371
+ map: <A, B>(f: (a: A) => B) => (data: Task<A>) => Task<B>;
1585
1372
  /**
1586
- * Pattern matches on a Task.Validation, returning a Task of the result.
1373
+ * Chains Task computations. Passes the resolved value of the first Task to f.
1587
1374
  *
1588
1375
  * @example
1589
1376
  * ```ts
1377
+ * const readUserId: Task<string> = Task.resolve(session.userId);
1378
+ * const loadPrefs = (id: string): Task<Preferences> =>
1379
+ * Task.resolve(prefsCache.get(id));
1380
+ *
1590
1381
  * pipe(
1591
- * validateForm(input),
1592
- * Task.Validation.match({
1593
- * passed: data => save(data),
1594
- * failed: errors => showErrors(errors)
1595
- * })
1596
- * )();
1382
+ * readUserId,
1383
+ * Task.chain(loadPrefs)
1384
+ * )(); // Deferred<Preferences>
1597
1385
  * ```
1598
1386
  */
1599
- const match: <E, A, B>(cases: {
1600
- passed: (a: A) => B;
1601
- failed: (errors: NonEmptyArr<E>) => B;
1602
- }) => (data: TaskValidation<E, A>) => Task<B>;
1603
- /**
1604
- * Returns the success value or a default value if the Task.Validation is failed.
1605
- * The default can be a different type, widening the result to `Task<A | B>`.
1606
- */
1607
- const getOrElse: <B>(defaultValue: () => B) => <E, A>(data: TaskValidation<E, A>) => Task<A | B>;
1608
- /**
1609
- * Executes a side effect on the success value without changing the Task.Validation.
1610
- * Useful for logging or debugging.
1611
- */
1612
- const tap: <E, A>(f: (a: A) => void) => (data: TaskValidation<E, A>) => TaskValidation<E, A>;
1613
- /**
1614
- * Recovers from a Failed state by providing a fallback Task.Validation.
1615
- * The fallback receives the accumulated error list so callers can inspect which errors occurred.
1616
- * The fallback can produce a different success type, widening the result to `Task.Validation<E, A | B>`.
1617
- */
1618
- const recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => TaskValidation<E, B>) => <A>(data: TaskValidation<E, A>) => TaskValidation<E, A | B>;
1619
- /**
1620
- * Recovers from a Failed state unless the predicate `isBlocked` returns true for the accumulated errors.
1621
- * The fallback receives the accumulated errors and can produce a different success type, widening the result to `Task.Validation<E, A | B>`.
1622
- *
1623
- * @example
1624
- * ```ts
1625
- * pipe(
1626
- * validationTask,
1627
- * Task.Validation.recoverUnless(
1628
- * (errors) => errors.includes("fatal"),
1629
- * (errors) => Task.Validation.passed("fallback")
1630
- * )
1631
- * );
1632
- * ```
1633
- */
1634
- const recoverUnless: <E, B>(isBlocked: (errors: NonEmptyArr<E>) => boolean, fallback: (errors: NonEmptyArr<E>) => TaskValidation<E, B>) => <A>(data: TaskValidation<E, A>) => TaskValidation<E, A | B>;
1635
- /**
1636
- * Runs two Task.Validations concurrently and combines their results into a tuple.
1637
- * If both are Passed, returns Passed with both values. If either fails, accumulates
1638
- * errors from both sides.
1639
- *
1640
- * @example
1641
- * ```ts
1642
- * await Task.Validation.product(
1643
- * validateName(form.name),
1644
- * validateAge(form.age),
1645
- * )(); // Passed(["Alice", 30]) or Failed([...errors])
1646
- * ```
1647
- */
1648
- const product: <E, A, B>(first: TaskValidation<E, A>, second: TaskValidation<E, B>) => TaskValidation<E, readonly [A, B]>;
1649
- /**
1650
- * Runs all Task.Validations concurrently and collects results.
1651
- * If all are Passed, returns Passed with all values as an array.
1652
- * If any fail, returns Failed with all accumulated errors.
1653
- *
1654
- * @example
1655
- * ```ts
1656
- * await Task.Validation.productAll([
1657
- * validateName(form.name),
1658
- * validateEmail(form.email),
1659
- * validateAge(form.age),
1660
- * ])(); // Passed([name, email, age]) or Failed([...all errors])
1661
- * ```
1662
- */
1663
- const productAll: <E, A>(data: NonEmptyArr<TaskValidation<E, A>>) => TaskValidation<E, readonly A[]>;
1664
- /**
1665
- * Transforms all accumulated errors inside a Task.Validation.
1666
- *
1667
- * @example
1668
- * ```ts
1669
- * pipe(
1670
- * Task.Validation.failed("oops"),
1671
- * Task.Validation.mapError(e => e.toUpperCase())
1672
- * ); // Task.Validation(Failed(["OOPS"]))
1673
- * ```
1674
- */
1675
- const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskValidation<E, A>) => TaskValidation<F, A>;
1676
- /**
1677
- * Executes a side effect on the accumulated errors without changing the Task.Validation.
1678
- *
1679
- * @example
1680
- * ```ts
1681
- * pipe(
1682
- * Task.Validation.failed("invalid name"),
1683
- * Task.Validation.tapError(errs => logger.error(errs))
1684
- * );
1685
- * ```
1686
- */
1687
- const tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: TaskValidation<E, A>) => TaskValidation<E, A>;
1688
- /**
1689
- * Combines a record of Task.Validations into a single Task.Validation of a record.
1690
- * Evaluates fields in parallel and accumulates all validation errors.
1691
- *
1692
- * @example
1693
- * ```ts
1694
- * Task.Validation.struct({
1695
- * name: Task.Validation.passed("Alice"),
1696
- * age: Task.Validation.passed(30)
1697
- * }); // Task.Validation({ name: "Alice", age: 30 })
1698
- * ```
1699
- */
1700
- const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskValidation<E, R[K]>; }) => TaskValidation<E, R>;
1701
- /**
1702
- * Creates a memoized version of a Task.Validation. The task is executed at most once on first call,
1703
- * and its resolved Validation is cached for all subsequent calls.
1704
- *
1705
- * @example
1706
- * ```ts
1707
- * const validate = Task.Validation.memoize(validateFormTask);
1708
- * ```
1709
- */
1710
- const memoize: <E, A>(task: TaskValidation<E, A>) => TaskValidation<E, A>;
1711
- }
1712
-
1713
- /**
1714
- * A lazy async computation that always resolves.
1715
- *
1716
- * Two guarantees:
1717
- * - **Lazy** — nothing starts until you call it.
1718
- * - **Infallible** — it never rejects. If failure is possible, encode it in the
1719
- * return type using `Task.Result<E, A>` instead.
1720
- *
1721
- * An optional `AbortSignal` can be passed at the call site. Combinators like
1722
- * `retry`, `pollUntil`, and `timeout` thread it automatically to every inner
1723
- * operation. Existing tasks that ignore the signal continue to work unchanged.
1724
- *
1725
- * Calling a Task returns a `Deferred<A>` — a one-shot async value that supports
1726
- * `await` but has no `.catch()`, `.finally()`, or chainable `.then()`.
1727
- *
1728
- * **Consuming a Task:**
1729
- *
1730
- * Use `await task()` to run it and get the value directly:
1731
- * ```ts
1732
- * const value: number = await task();
1733
- * ```
1734
- *
1735
- * When you need an explicit `Promise<A>` (e.g. for a third-party API), convert
1736
- * the `Deferred` with `Deferred.to.Promise`:
1737
- * ```ts
1738
- * const p: Promise<number> = Deferred.to.Promise(task());
1739
- * ```
1740
- *
1741
- * @example
1742
- * ```ts
1743
- * const getTimestamp: Task<number> = Task.resolve(Date.now());
1744
- *
1745
- * // Nothing runs yet — getTimestamp is just a description
1746
- * const formatted = pipe(
1747
- * getTimestamp,
1748
- * Task.map(ts => new Date(ts).toISOString())
1749
- * );
1750
- *
1751
- * // Execute when ready
1752
- * const result = await formatted();
1753
- * ```
1754
- */
1755
- type Task<A> = (signal?: AbortSignal) => Deferred<A>;
1756
- declare namespace Task {
1757
- /**
1758
- * Creates a Task that immediately resolves to the given value.
1759
- *
1760
- * @example
1761
- * ```ts
1762
- * const task = Task.resolve(42);
1763
- * const value = await task(); // 42
1764
- * ```
1765
- */
1766
- const resolve: <A>(value: A) => Task<A>;
1767
- namespace from {
1768
- /**
1769
- * Creates a Task from a lazy synchronous thunk.
1770
- * Unlike `Task.resolve(f())`, `from.sync` does not evaluate `f` until the Task is called.
1771
- *
1772
- * @example
1773
- * ```ts
1774
- * const t = Task.from.sync(() => Date.now()); // Date.now() not called yet
1775
- * const ts = await t(); // called here, every time
1776
- * ```
1777
- */
1778
- const sync: <A>(f: () => A) => Task<A>;
1779
- }
1780
- /**
1781
- * Wraps a Promise-returning thunk that may throw or reject,
1782
- * trapping errors with a fallback function and returning a guaranteed `Task<A>`.
1783
- *
1784
- * @example
1785
- * ```ts
1786
- * const loadConfig = Task.tryCatch(
1787
- * () => configStore.get("default"),
1788
- * { onError: () => DEFAULT_CONFIG }
1789
- * );
1790
- * ```
1791
- */
1792
- const tryCatch: <A>(f: (signal?: AbortSignal) => globalThis.Promise<A>, options: {
1793
- onError: (error: unknown) => A;
1794
- }) => Task<A>;
1795
- /**
1796
- * Transforms the value inside a Task.
1797
- *
1798
- * @example
1799
- * ```ts
1800
- * pipe(
1801
- * Task.resolve(5),
1802
- * Task.map(n => n * 2)
1803
- * )(); // Deferred<10>
1804
- * ```
1805
- */
1806
- const map: <A, B>(f: (a: A) => B) => (data: Task<A>) => Task<B>;
1807
- /**
1808
- * Chains Task computations. Passes the resolved value of the first Task to f.
1809
- *
1810
- * @example
1811
- * ```ts
1812
- * const readUserId: Task<string> = Task.resolve(session.userId);
1813
- * const loadPrefs = (id: string): Task<Preferences> =>
1814
- * Task.resolve(prefsCache.get(id));
1815
- *
1816
- * pipe(
1817
- * readUserId,
1818
- * Task.chain(loadPrefs)
1819
- * )(); // Deferred<Preferences>
1820
- * ```
1821
- */
1822
- const chain: <A, B>(f: (a: A) => Task<B>) => (data: Task<A>) => Task<B>;
1387
+ chain: <A, B>(f: (a: A) => Task<B>) => (data: Task<A>) => Task<B>;
1823
1388
  /**
1824
1389
  * Applies a function wrapped in a Task to a value wrapped in a Task.
1825
1390
  * Both Tasks run in parallel.
1826
1391
  *
1827
- * @example
1828
- * ```ts
1829
- * const add = (a: number) => (b: number) => a + b;
1830
- * pipe(
1831
- * Task.resolve(add),
1832
- * Task.ap(Task.resolve(5)),
1833
- * Task.ap(Task.resolve(3))
1834
- * )(); // Deferred<8>
1835
- * ```
1836
- */
1837
- const ap: <A>(arg: Task<A>) => <B>(data: Task<(a: A) => B>) => Task<B>;
1838
- /**
1839
- * Executes a side effect on the value without changing the Task.
1840
- * Useful for logging or debugging.
1841
- *
1842
- * @example
1843
- * ```ts
1844
- * pipe(
1845
- * loadConfig,
1846
- * Task.tap(cfg => console.log("Config:", cfg)),
1847
- * Task.map(buildReport)
1848
- * );
1849
- * ```
1850
- */
1851
- const tap: <A>(f: (a: A) => void) => (data: Task<A>) => Task<A>;
1852
- /**
1853
- * Runs multiple Tasks in parallel and collects their results.
1854
- *
1855
- * @example
1856
- * ```ts
1857
- * Task.all([loadConfig, detectLocale, loadTheme])();
1858
- * // Deferred<[Config, string, Theme]>
1859
- * ```
1860
- */
1861
- const all: <T extends readonly Task<unknown>[]>(tasks: T) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
1862
- /**
1863
- * Delays the execution of a Task by the specified duration.
1864
- * Useful for debouncing or rate limiting.
1865
- *
1866
- * @example
1867
- * ```ts
1868
- * pipe(
1869
- * Task.resolve(42),
1870
- * Task.delay(Duration.seconds(1))
1871
- * )(); // Resolves after 1 second
1872
- * ```
1873
- */
1874
- const delay: (duration: Duration) => <A>(data: Task<A>) => Task<A>;
1875
- /**
1876
- * Runs a Task a fixed number of times sequentially, collecting all results into an array.
1877
- * An optional delay duration can be inserted between runs.
1878
- *
1879
- * @example
1880
- * ```ts
1881
- * pipe(
1882
- * pollSensor,
1883
- * Task.repeat({ times: 5, delay: Duration.seconds(1) })
1884
- * )(); // Task<Reading[]> — 5 readings, one per second
1885
- * ```
1886
- */
1887
- const repeat: (options: {
1888
- times: number;
1889
- delay?: Duration;
1890
- }) => <A>(task: Task<A>) => Task<readonly A[]>;
1891
- /**
1892
- * Runs a Task repeatedly until the result satisfies a predicate, returning that result.
1893
- * An optional delay duration can be inserted between runs.
1894
- * An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
1895
- * regardless of whether the predicate was satisfied.
1896
- *
1897
- * @example
1898
- * ```ts
1899
- * pipe(
1900
- * checkStatus,
1901
- * Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
1902
- * )(); // polls every 500ms until status is "ready"
1903
- * ```
1904
- */
1905
- const repeatUntil: <A>(options: {
1906
- when: (a: A) => boolean;
1907
- delay?: Duration;
1908
- maxAttempts?: number;
1909
- }) => (task: Task<A>) => Task<A>;
1910
- /**
1911
- * Resolves with the value of the first Task to complete. All Tasks start
1912
- * immediately. When one resolves, the other tasks are cancelled (aborted)
1913
- * downstream.
1914
- *
1915
- * @example
1916
- * ```ts
1917
- * const fast = Task.resolve("fast");
1918
- * const slow = Task.delay(Duration.milliseconds(200))(Task.resolve("slow"));
1919
- *
1920
- * await Task.race([fast, slow])(); // "fast"
1921
- * ```
1922
- */
1923
- const race: <A>(tasks: ReadonlyArray<Task<A>>) => Task<A>;
1924
- /**
1925
- * Runs an array of Tasks concurrently and collects their results in an array.
1926
- * Forward-propagates the call site's AbortSignal to all subtasks concurrently.
1927
- *
1928
- * @example
1929
- * ```ts
1930
- * Task.sequence([loadConfig, detectLocale, loadTheme])();
1931
- * // Deferred<[Config, string, Theme]>
1932
- * ```
1933
- */
1934
- const sequence: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
1935
- /**
1936
- * Runs an array of Tasks one at a time in order, collecting all results.
1937
- * Each Task starts only after the previous one resolves.
1938
- *
1939
- * @example
1940
- * ```ts
1941
- * let log: number[] = [];
1942
- * const makeTask = (n: number) => Task.resolve(n);
1943
- *
1944
- * await Task.sequential([makeTask(1), makeTask(2), makeTask(3)])();
1945
- * // log = [1, 2, 3] — tasks ran in order
1946
- * ```
1947
- */
1948
- const sequential: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
1949
- /**
1950
- * Converts a `Task<A>` into a `Task<Result<E, A>>`, resolving to `Err` if the
1951
- * Task does not complete within the given duration. The inner Task receives an
1952
- * `AbortSignal` that fires when the deadline passes, so asynchronous operations
1953
- * that accept a signal are cancelled rather than left dangling.
1954
- *
1955
- * @example
1956
- * ```ts
1957
- * pipe(
1958
- * heavyComputation,
1959
- * Task.timeout({ duration: Duration.seconds(5), onTimeout: () => "timed out" }),
1960
- * Task.Result.chain(processResult)
1961
- * );
1962
- * ```
1963
- */
1964
- const timeout: <E>(options: {
1965
- duration: Duration;
1966
- onTimeout: () => E;
1967
- }) => <A>(task: Task<A>) => Task<Result<E, A>>;
1968
- /**
1969
- * Creates a Task paired with an `abort` handle. Calling `abort()` cancels the
1970
- * current in-flight call immediately. Unlike a one-shot abort, calling `task()`
1971
- * again after `abort()` starts a fresh call with a new signal.
1972
- *
1973
- * Each invocation of `task()` automatically cancels the previous in-flight call,
1974
- * making it safe to call repeatedly (e.g. on user input) without leaking promises.
1975
- *
1976
- * If an outer signal is also present (passed at the call site), aborting it
1977
- * propagates into the internal controller.
1978
- *
1979
- * @example
1980
- * ```ts
1981
- * const { task: poll, abort } = Task.abortable(
1982
- * (signal) => waitForEvent(bus, "ready", { signal }),
1983
- * );
1984
- *
1985
- * onUnmount(abort);
1986
- * await poll();
1987
- * ```
1988
- */
1989
- const abortable: <A>(factory: (signal: AbortSignal) => Thenable<A>) => {
1990
- task: Task<A>;
1991
- abort: () => void;
1992
- };
1993
- /**
1994
- * Executes a task with an optional signal. Use as a terminal step in a `pipe` chain.
1995
- *
1996
- * @example
1997
- * ```ts
1998
- * const name = await pipe(
1999
- * loadConfig,
2000
- * Task.map(config => config.name),
2001
- * Task.run(),
2002
- * );
2003
- * ```
2004
- */
2005
- const run: (signal?: AbortSignal) => <A>(task: Task<A>) => Deferred<A>;
2006
- /**
2007
- * Converts a Task value into an object containing a single property.
2008
- * Initiates the pipeline accumulator record.
2009
- *
2010
- * @example
2011
- * ```ts
2012
- * pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
2013
- * ```
2014
- */
2015
- const bindTo: <K extends string>(key: K) => <A>(data: Task<A>) => Task<{ [P in K]: A; }>;
2016
- /**
2017
- * Evaluates a new Task using the current accumulator and attaches the output to a new key.
2018
- *
2019
- * @example
2020
- * ```ts
2021
- * pipe(
2022
- * Task.resolve({ a: 1 }),
2023
- * Task.bind("b", ({ a }) => Task.resolve(a + 1))
2024
- * ); // Task({ a: 1, b: 2 })
2025
- * ```
2026
- */
2027
- const bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
2028
- /**
2029
- * Creates a memoized version of a Task. The task is executed at most once on first call,
2030
- * and its resolved value is cached for all subsequent calls.
2031
- *
2032
- * @example
2033
- * ```ts
2034
- * const loadToken = Task.memoize(loadAuthToken);
2035
- * const token1 = await loadToken(); // loads token
2036
- * const token2 = await loadToken(); // returns cached token immediately
2037
- * ```
2038
- */
2039
- const memoize: <A>(task: Task<A>) => Task<A>;
2040
- /**
2041
- * Monitors progress of a Task by calling `onProgress(0)` before execution and `onProgress(1)` upon completion.
2042
- *
2043
- * @example
2044
- * ```ts
2045
- * const taskWithProgress = pipe(
2046
- * readTask,
2047
- * Task.withProgress((ratio) => console.log(`Progress: ${ratio * 100}%`))
2048
- * );
2049
- * ```
2050
- */
2051
- const withProgress: <A>(onProgress: (ratio: number) => void) => (task: Task<A>) => Task<A>;
2052
- type LabeledTask<L extends string, A> = Task<A> & {
2053
- readonly label: L;
2054
- };
2055
- /**
2056
- * Attaches a read-only `.label` property to a Task, preserving the literal string generic type for IDE tooltips.
2057
- *
2058
- * @example
2059
- * ```ts
2060
- * const labeledTask = pipe(readTask, Task.withLabel("readUser"));
2061
- * console.log(labeledTask.label); // "readUser"
2062
- * ```
2063
- */
2064
- const withLabel: <L extends string>(label: L) => <A>(task: Task<A>) => LabeledTask<L, A>;
2065
- type Maybe<A> = TaskMaybe<A>;
2066
- const Maybe: typeof TaskMaybe;
2067
- type Result<E, A> = TaskResult<E, A>;
2068
- const Result: typeof TaskResult;
2069
- type Validation<E, A> = TaskValidation<E, A>;
2070
- const Validation: typeof TaskValidation;
2071
- }
2072
-
2073
- type Passed<A> = WithKind<"Passed"> & WithValue<A>;
2074
- type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
2075
- /**
2076
- * Validation represents a value that is either passed with a success value,
2077
- * or failed with accumulated errors.
2078
- * Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
2079
- *
2080
- * Use Validation when you need to collect all errors (e.g., form validation).
2081
- * Use Result when you want to fail fast on the first error.
2082
- *
2083
- * @example
2084
- * ```ts
2085
- * const validateName = (name: string): Validation<string, string> =>
2086
- * name.length > 0 ? Validation.make.passed(name) : Validation.make.failed("Name is required");
2087
- *
2088
- * const validateAge = (age: number): Validation<string, number> =>
2089
- * age >= 0 ? Validation.make.passed(age) : Validation.make.failed("Age must be positive");
2090
- *
2091
- * // Accumulates all errors using ap
2092
- * pipe(
2093
- * Validation.make.passed((name: string) => (age: number) => ({ name, age })),
2094
- * Validation.ap(validateName("")),
2095
- * Validation.ap(validateAge(-1))
2096
- * );
2097
- * // Failed(["Name is required", "Age must be positive"])
2098
- * ```
2099
- */
2100
- type Validation<E, A> = Passed<A> | Failed<E>;
2101
- declare namespace Validation {
2102
- namespace make {
2103
- /**
2104
- * Wraps a value in a passed Validation.
2105
- *
2106
- * @example
2107
- * ```ts
2108
- * Validation.make.passed(42); // Passed(42)
2109
- * ```
2110
- */
2111
- const passed: <E, A>(value: A) => Validation<E, A>;
2112
- /**
2113
- * Creates a failed Validation from a single error.
2114
- *
2115
- * @example
2116
- * ```ts
2117
- * Validation.make.failed("Invalid input");
2118
- * ```
2119
- */
2120
- const failed: <E>(error: E) => Failed<E>;
2121
- /**
2122
- * Creates a failed Validation from multiple errors.
2123
- *
2124
- * @example
2125
- * ```ts
2126
- * Validation.make.failedAll(["Invalid input"]);
2127
- * ```
2128
- */
2129
- const failedAll: <E>(errors: NonEmptyArr<E>) => Failed<E>;
2130
- }
2131
- namespace is {
2132
- /**
2133
- * Type guard that checks if a Validation is passed.
2134
- *
2135
- * @example
2136
- * ```ts
2137
- * const v = Validation.make.passed(42);
2138
- * if (Validation.is.passed(v)) {
2139
- * console.log(v.value); // 42
2140
- * }
2141
- * ```
2142
- */
2143
- const passed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
2144
- /**
2145
- * Type guard that checks if a Validation is failed.
2146
- *
2147
- * @example
2148
- * ```ts
2149
- * const v = Validation.make.failed("invalid");
2150
- * if (Validation.is.failed(v)) {
2151
- * console.log(v.errors); // ["invalid"]
2152
- * }
2153
- * ```
2154
- */
2155
- const failed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
2156
- }
2157
- /**
2158
- * Creates a Validation from a synchronous thunk that may throw.
2159
- * Catches any errors and transforms them using the `onError` function into a Failed validation.
2160
- *
2161
- * @example
2162
- * ```ts
2163
- * const result = Validation.tryCatch(
2164
- * () => JSON.parse(rawString),
2165
- * { onError: (e) => `Parse error: ${e}` }
2166
- * );
2167
- * ```
2168
- */
2169
- const tryCatch: <E, A>(f: () => A, options: {
2170
- onError: (e: unknown) => E;
2171
- }) => Validation<E, A>;
2172
- namespace from {
2173
- /**
2174
- * Creates a Validation from a predicate applied to a value.
2175
- * Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
2176
- *
2177
- * @example
2178
- * ```ts
2179
- * const validateName = Validation.from.Predicate(
2180
- * (s: string) => s.length > 0,
2181
- * () => "Name is required"
2182
- * );
2183
- *
2184
- * validateName("Alice"); // Passed("Alice")
2185
- * validateName(""); // Failed(["Name is required"])
2186
- * ```
2187
- */
2188
- const Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
2189
- /**
2190
- * Creates a Validation from a nullable value.
2191
- * If the value is null or undefined, returns Failed with the error from onNull.
2192
- * Otherwise, returns Passed.
2193
- *
2194
- * @example
2195
- * ```ts
2196
- * pipe(null, Validation.from.nullable(() => "is null")); // Failed(["is null"])
2197
- * pipe(42, Validation.from.nullable(() => "is null")); // Passed(42)
2198
- * ```
2199
- */
2200
- const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
2201
- /**
2202
- * Creates a Validation from a Maybe.
2203
- * If the Maybe is None, returns Failed with the error from onNone.
2204
- * Otherwise, returns Passed.
2205
- *
2206
- * @example
2207
- * ```ts
2208
- * pipe(Maybe.make.none(), Validation.from.Maybe(() => "is none")); // Failed(["is none"])
2209
- * pipe(Maybe.make.some(42), Validation.from.Maybe(() => "is none")); // Passed(42)
2210
- * ```
2211
- */
2212
- const Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
2213
- /**
2214
- * Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
2215
- *
2216
- * Useful when bridging from error-short-circuiting `Result` pipelines into
2217
- * error-accumulating `Validation` pipelines.
2218
- *
2219
- * @example
2220
- * ```ts
2221
- * Validation.from.Result(Result.make.ok(42)); // Passed(42)
2222
- * Validation.from.Result(Result.make.err("bad")); // Failed(["bad"])
2223
- * ```
2224
- */
2225
- const Result: <E, A>(data: Result<E, A>) => Validation<E, A>;
2226
- }
1392
+ * @example
1393
+ * ```ts
1394
+ * const add = (a: number) => (b: number) => a + b;
1395
+ * pipe(
1396
+ * Task.resolve(add),
1397
+ * Task.ap(Task.resolve(5)),
1398
+ * Task.ap(Task.resolve(3))
1399
+ * )(); // Deferred<8>
1400
+ * ```
1401
+ */
1402
+ ap: <A>(arg: Task<A>) => <B>(data: Task<(a: A) => B>) => Task<B>;
2227
1403
  /**
2228
- * Transforms the success value inside a Validation.
1404
+ * Executes a side effect on the value without changing the Task.
1405
+ * Useful for logging or debugging.
2229
1406
  *
2230
1407
  * @example
2231
1408
  * ```ts
2232
- * pipe(Validation.make.passed(5), Validation.map(n => n * 2)); // Passed(10)
2233
- * pipe(Validation.make.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
1409
+ * pipe(
1410
+ * loadConfig,
1411
+ * Task.tap(cfg => console.log("Config:", cfg)),
1412
+ * Task.map(buildReport)
1413
+ * );
2234
1414
  * ```
2235
1415
  */
2236
- const map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
1416
+ tap: <A>(f: (a: A) => void) => (data: Task<A>) => Task<A>;
2237
1417
  /**
2238
- * Transforms the error list inside a Validation.
1418
+ * Runs multiple Tasks in parallel and collects their results.
2239
1419
  *
2240
1420
  * @example
2241
1421
  * ```ts
2242
- * pipe(Validation.make.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
1422
+ * Task.all([loadConfig, detectLocale, loadTheme])();
1423
+ * // Deferred<[Config, string, Theme]>
2243
1424
  * ```
2244
1425
  */
2245
- const mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
1426
+ all: <T extends readonly Task<unknown>[]>(tasks: T) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
2246
1427
  /**
2247
- * Applies a function wrapped in a Validation to a value wrapped in a Validation.
2248
- * Accumulates errors from both sides.
1428
+ * Delays the execution of a Task by the specified duration.
1429
+ * Useful for debouncing or rate limiting.
2249
1430
  *
2250
1431
  * @example
2251
1432
  * ```ts
2252
- * const add = (a: number) => (b: number) => a + b;
2253
1433
  * pipe(
2254
- * Validation.make.passed(add),
2255
- * Validation.ap(Validation.make.passed(5)),
2256
- * Validation.ap(Validation.make.passed(3))
2257
- * ); // Passed(8)
1434
+ * Task.resolve(42),
1435
+ * Task.delay(Duration.seconds(1))
1436
+ * )(); // Resolves after 1 second
1437
+ * ```
1438
+ */
1439
+ delay: (duration: Duration) => <A>(data: Task<A>) => Task<A>;
1440
+ /**
1441
+ * Runs a Task a fixed number of times sequentially, collecting all results into an array.
1442
+ * An optional delay duration can be inserted between runs.
2258
1443
  *
1444
+ * @example
1445
+ * ```ts
2259
1446
  * pipe(
2260
- * Validation.make.passed(add),
2261
- * Validation.ap(Validation.make.failed<string>("bad a")),
2262
- * Validation.ap(Validation.make.failed<string>("bad b"))
2263
- * ); // Failed(["bad a", "bad b"])
1447
+ * pollSensor,
1448
+ * Task.repeat({ times: 5, delay: Duration.seconds(1) })
1449
+ * )(); // Task<Reading[]> — 5 readings, one per second
2264
1450
  * ```
2265
1451
  */
2266
- const ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
1452
+ repeat: (options: {
1453
+ times: number;
1454
+ delay?: Duration;
1455
+ }) => <A>(task: Task<A>) => Task<readonly A[]>;
2267
1456
  /**
2268
- * Applies a function wrapped in a Validation to a value wrapped in a Validation,
2269
- * using a custom error concatenator function when both sides fail.
1457
+ * Runs a Task repeatedly until the result satisfies a predicate, returning that result.
1458
+ * An optional delay duration can be inserted between runs.
1459
+ * An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
1460
+ * regardless of whether the predicate was satisfied.
2270
1461
  *
2271
1462
  * @example
2272
1463
  * ```ts
2273
- * const concat = (e1: NonEmptyArr<string>, e2: NonEmptyArr<string>): NonEmptyArr<string> =>
2274
- * [...e1, ...e2];
2275
- * pipe(fnVal, Validation.apCustom(concat)(argVal));
1464
+ * pipe(
1465
+ * checkStatus,
1466
+ * Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
1467
+ * )(); // polls every 500ms until status is "ready"
2276
1468
  * ```
2277
1469
  */
2278
- const apCustom: <E1, E2, E3>(concat: (e1: NonEmptyArr<E1>, e2: NonEmptyArr<E2>) => NonEmptyArr<E3>) => <A>(arg: Validation<E2, A>) => <B>(data: Validation<E1, (a: A) => B>) => Validation<E3, B>;
1470
+ repeatUntil: <A>(options: {
1471
+ when: (a: A) => boolean;
1472
+ delay?: Duration;
1473
+ maxAttempts?: number;
1474
+ }) => (task: Task<A>) => Task<A>;
2279
1475
  /**
2280
- * Extracts the value from a Validation by providing handlers for both cases.
1476
+ * Resolves with the value of the first Task to complete. All Tasks start
1477
+ * immediately. When one resolves, the other tasks are cancelled (aborted)
1478
+ * downstream.
2281
1479
  *
2282
1480
  * @example
2283
1481
  * ```ts
2284
- * pipe(
2285
- * Validation.make.passed(42),
2286
- * Validation.fold(
2287
- * errors => `Errors: ${errors.join(", ")}`,
2288
- * value => `Value: ${value}`
2289
- * )
2290
- * );
1482
+ * const fast = Task.resolve("fast");
1483
+ * const slow = Task.delay(Duration.milliseconds(200))(Task.resolve("slow"));
1484
+ *
1485
+ * await Task.race([fast, slow])(); // "fast"
2291
1486
  * ```
2292
1487
  */
2293
- const fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
1488
+ race: <A>(tasks: ReadonlyArray<Task<A>>) => Task<A>;
2294
1489
  /**
2295
- * Pattern matches on a Validation, returning the result of the matching case.
1490
+ * Runs an array of Tasks concurrently and collects their results in an array.
1491
+ * Forward-propagates the call site's AbortSignal to all subtasks concurrently.
2296
1492
  *
2297
1493
  * @example
2298
1494
  * ```ts
2299
- * pipe(
2300
- * validation,
2301
- * Validation.match({
2302
- * passed: value => `Got ${value}`,
2303
- * failed: errors => `Failed: ${errors.join(", ")}`
2304
- * })
2305
- * );
1495
+ * Task.sequence([loadConfig, detectLocale, loadTheme])();
1496
+ * // Deferred<[Config, string, Theme]>
2306
1497
  * ```
2307
1498
  */
2308
- const match: <E, A, B>(cases: {
2309
- passed: (a: A) => B;
2310
- failed: (errors: NonEmptyArr<E>) => B;
2311
- }) => (data: Validation<E, A>) => B;
1499
+ sequence: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
2312
1500
  /**
2313
- * Returns the success value or a default value if the Validation is failed.
2314
- * The default can be a different type, widening the result to `A | B`.
1501
+ * Runs an array of Tasks one at a time in order, collecting all results.
1502
+ * Each Task starts only after the previous one resolves.
2315
1503
  *
2316
1504
  * @example
2317
1505
  * ```ts
2318
- * pipe(Validation.make.passed(5), Validation.getOrElse(() => 0)); // 5
2319
- * pipe(Validation.make.failed("oops"), Validation.getOrElse(() => 0)); // 0
2320
- * pipe(Validation.make.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
1506
+ * let log: number[] = [];
1507
+ * const makeTask = (n: number) => Task.resolve(n);
1508
+ *
1509
+ * await Task.sequential([makeTask(1), makeTask(2), makeTask(3)])();
1510
+ * // log = [1, 2, 3] — tasks ran in order
2321
1511
  * ```
2322
1512
  */
2323
- const getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Validation<E, A>) => A | B;
1513
+ sequential: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
2324
1514
  /**
2325
- * Executes a side effect on the success value without changing the Validation.
1515
+ * Converts a `Task<A>` into a `Task<Result<E, A>>`, resolving to `Err` if the
1516
+ * Task does not complete within the given duration. The inner Task receives an
1517
+ * `AbortSignal` that fires when the deadline passes, so asynchronous operations
1518
+ * that accept a signal are cancelled rather than left dangling.
2326
1519
  *
2327
1520
  * @example
2328
1521
  * ```ts
2329
1522
  * pipe(
2330
- * Validation.make.passed(5),
2331
- * Validation.tap(n => console.log("Value:", n)),
2332
- * Validation.map(n => n * 2)
1523
+ * heavyComputation,
1524
+ * Task.timeout({ duration: Duration.seconds(5), onTimeout: () => "timed out" }),
1525
+ * Task.Result.chain(processResult)
2333
1526
  * );
2334
1527
  * ```
2335
1528
  */
2336
- const tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
1529
+ timeout: <E>(options: {
1530
+ duration: Duration;
1531
+ onTimeout: () => E;
1532
+ }) => <A>(task: Task<A>) => Task<Result<E, A>>;
2337
1533
  /**
2338
- * Executes a side effect on the accumulated errors without changing the Validation.
2339
- * Useful for logging or reporting validation failures.
1534
+ * Creates a Task paired with an `abort` handle. Calling `abort()` cancels the
1535
+ * current in-flight call immediately. Unlike a one-shot abort, calling `task()`
1536
+ * again after `abort()` starts a fresh call with a new signal.
1537
+ *
1538
+ * Each invocation of `task()` automatically cancels the previous in-flight call,
1539
+ * making it safe to call repeatedly (e.g. on user input) without leaking promises.
1540
+ *
1541
+ * If an outer signal is also present (passed at the call site), aborting it
1542
+ * propagates into the internal controller.
2340
1543
  *
2341
1544
  * @example
2342
1545
  * ```ts
2343
- * pipe(
2344
- * Validation.make.failed("Name required"),
2345
- * Validation.tapError(errors => console.error("validation failed:", errors)),
2346
- * Validation.map(toUser)
1546
+ * const { task: poll, abort } = Task.abortable(
1547
+ * (signal) => waitForEvent(bus, "ready", { signal }),
2347
1548
  * );
1549
+ *
1550
+ * onUnmount(abort);
1551
+ * await poll();
2348
1552
  * ```
2349
1553
  */
2350
- const tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
1554
+ abortable: <A>(factory: (signal: AbortSignal) => Thenable<A>) => {
1555
+ task: Task<A>;
1556
+ abort: () => void;
1557
+ };
2351
1558
  /**
2352
- * Recovers from a Failed state by providing a fallback Validation.
2353
- * The fallback receives the accumulated error list so callers can inspect which errors occurred.
2354
- * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
1559
+ * Executes a task with an optional signal. Use as a terminal step in a `pipe` chain.
1560
+ *
1561
+ * @example
1562
+ * ```ts
1563
+ * const name = await pipe(
1564
+ * loadConfig,
1565
+ * Task.map(config => config.name),
1566
+ * Task.run(),
1567
+ * );
1568
+ * ```
2355
1569
  */
2356
- const recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => Validation<E, B>) => <A>(data: Validation<E, A>) => Validation<E, A | B>;
1570
+ run: (signal?: AbortSignal) => <A>(task: Task<A>) => Deferred<A>;
2357
1571
  /**
2358
- * Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
2359
- * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
1572
+ * Converts a Task value into an object containing a single property.
1573
+ * Initiates the pipeline accumulator record.
2360
1574
  *
2361
1575
  * @example
2362
1576
  * ```ts
2363
- * pipe(
2364
- * Validation.make.failed("field-error"),
2365
- * Validation.recoverUnless(e => e === "fatal", () => Validation.make.passed(0))
2366
- * ); // Passed(0)
1577
+ * pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
2367
1578
  * ```
2368
1579
  */
2369
- const recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => <A>(data: Validation<E, A>) => Validation<E, A | B>;
2370
- namespace to {
2371
- /**
2372
- * Converts a Validation to a Result.
2373
- * Passed becomes Ok.
2374
- * Direct call converts Failed to Err with accumulated error list `NonEmptyArr<E>`.
2375
- * Curried call converts Failed to Err with combined error `E2` via `combineErrors`.
2376
- *
2377
- * @example
2378
- * ```ts
2379
- * Validation.to.Result(Validation.make.passed(42)); // Ok(42)
2380
- * Validation.to.Result(Validation.make.failed("oops")); // Err(["oops"])
2381
- * pipe(Validation.make.failed("oops"), Validation.to.Result(errors => errors.join(", "))); // Err("oops")
2382
- * ```
2383
- */
2384
- function Result<E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2): (val: Validation<E1, A>) => Result<E2, A>;
2385
- function Result<E, A>(data: Validation<E, A>): Result<NonEmptyArr<E>, A>;
2386
- /**
2387
- * Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
2388
- * (errors are discarded).
2389
- *
2390
- * @example
2391
- * ```ts
2392
- * Validation.to.Maybe(Validation.make.passed(42)); // Some(42)
2393
- * Validation.to.Maybe(Validation.make.failed("bad")); // None
2394
- * ```
2395
- */
2396
- const Maybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
2397
- }
1580
+ bindTo: <K extends string>(key: K) => <A>(data: Task<A>) => Task<{ [P in K]: A; }>;
2398
1581
  /**
2399
- * Combines two independent Validation instances into a tuple.
2400
- * If both are Passed, returns Passed with both values as a tuple.
2401
- * If either is Failed, accumulates errors from both sides.
1582
+ * Evaluates a new Task using the current accumulator and attaches the output to a new key.
2402
1583
  *
2403
1584
  * @example
2404
1585
  * ```ts
2405
- * Validation.product(
2406
- * Validation.make.passed("alice"),
2407
- * Validation.make.passed(30)
2408
- * ); // Passed(["alice", 30])
2409
- *
2410
- * Validation.product(
2411
- * Validation.make.failed("Name required"),
2412
- * Validation.make.failed("Age must be >= 0")
2413
- * ); // Failed(["Name required", "Age must be >= 0"])
1586
+ * pipe(
1587
+ * Task.resolve({ a: 1 }),
1588
+ * Task.bind("b", ({ a }) => Task.resolve(a + 1))
1589
+ * ); // Task({ a: 1, b: 2 })
2414
1590
  * ```
2415
1591
  */
2416
- const product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
1592
+ bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
2417
1593
  /**
2418
- * Combines a non-empty list of Validation instances, accumulating all errors.
2419
- * If all are Passed, returns Passed with all values collected into an array.
2420
- * If any are Failed, returns Failed with all accumulated errors.
1594
+ * Creates a memoized version of a Task. The task is executed at most once on first call,
1595
+ * and its resolved value is cached for all subsequent calls.
2421
1596
  *
2422
1597
  * @example
2423
1598
  * ```ts
2424
- * Validation.productAll([
2425
- * validateName(name),
2426
- * validateEmail(email),
2427
- * validateAge(age)
2428
- * ]);
2429
- * // Passed([name, email, age]) or Failed([...all errors])
1599
+ * const loadToken = Task.memoize(loadAuthToken);
1600
+ * const token1 = await loadToken(); // loads token
1601
+ * const token2 = await loadToken(); // returns cached token immediately
2430
1602
  * ```
2431
1603
  */
2432
- const productAll: <E, A>(data: NonEmptyArr<Validation<E, A>>) => Validation<E, readonly A[]>;
1604
+ memoize: <A>(task: Task<A>) => Task<A>;
2433
1605
  /**
2434
- * Combines a record of Validations into a single Validation of a record.
2435
- * Accumulates all failed branches' errors.
1606
+ * Monitors progress of a Task by calling `onProgress(0)` before execution and `onProgress(1)` upon completion.
2436
1607
  *
2437
1608
  * @example
2438
1609
  * ```ts
2439
- * Validation.struct({
2440
- * name: Validation.make.passed("Alice"),
2441
- * age: Validation.make.passed(30)
2442
- * }); // Passed({ name: "Alice", age: 30 })
1610
+ * const taskWithProgress = pipe(
1611
+ * readTask,
1612
+ * Task.withProgress((ratio) => console.log(`Progress: ${ratio * 100}%`))
1613
+ * );
1614
+ * ```
1615
+ */
1616
+ withProgress: <A>(onProgress: (ratio: number) => void) => (task: Task<A>) => Task<A>;
1617
+ /**
1618
+ * Attaches a read-only `.label` property to a Task, preserving the literal string generic type for IDE tooltips.
2443
1619
  *
2444
- * Validation.struct({
2445
- * name: Validation.make.failed("Name required"),
2446
- * age: Validation.make.failed("Age must be >= 0")
2447
- * }); // Failed(["Name required", "Age must be >= 0"])
1620
+ * @example
1621
+ * ```ts
1622
+ * const labeledTask = pipe(readTask, Task.withLabel("readUser"));
1623
+ * console.log(labeledTask.label); // "readUser"
2448
1624
  * ```
2449
1625
  */
2450
- const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Validation<E, R[K]>; }) => Validation<E, R>;
1626
+ withLabel: <L extends string>(label: L) => <A>(task: Task<A>) => Task.LabeledTask<L, A>;
1627
+ Maybe: {
1628
+ make: {
1629
+ some: <A>(value: A) => Task.Maybe<A>;
1630
+ none: <A = never>() => Task.Maybe<A>;
1631
+ };
1632
+ from: {
1633
+ Maybe: <A>(option: Maybe<A>) => Task.Maybe<A>;
1634
+ nullable: <A>(value: A | null | undefined) => Task.Maybe<A>;
1635
+ Result: <E, A>(result: Result<E, A>) => Task.Maybe<A>;
1636
+ Task: <A>(task: Task<A>) => Task.Maybe<A>;
1637
+ };
1638
+ tryCatch: <A>(f: (signal?: AbortSignal) => Thenable<A>) => Task.Maybe<A>;
1639
+ map: <A, B>(f: (a: A) => B) => (data: Task.Maybe<A>) => Task.Maybe<B>;
1640
+ chain: <A, B>(f: (a: A) => Task.Maybe<B>) => (data: Task.Maybe<A>) => Task.Maybe<B>;
1641
+ ap: <A>(arg: Task.Maybe<A>) => <B>(data: Task.Maybe<(a: A) => B>) => Task.Maybe<B>;
1642
+ fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: Task.Maybe<A>) => Task<B>;
1643
+ match: <A, B>(cases: {
1644
+ none: () => B;
1645
+ some: (a: A) => B;
1646
+ }) => (data: Task.Maybe<A>) => Task<B>;
1647
+ getOrElse: <B>(defaultValue: () => B) => <A>(data: Task.Maybe<A>) => Task<A | B>;
1648
+ tap: <A>(f: (a: A) => void) => (data: Task.Maybe<A>) => Task.Maybe<A>;
1649
+ filter: <A>(predicate: (a: A) => boolean) => (data: Task.Maybe<A>) => Task.Maybe<A>;
1650
+ to: {
1651
+ Result: <E>(onNone: () => E) => <A>(data: Task.Maybe<A>) => Task.Result<E, A>;
1652
+ };
1653
+ bindTo: <K extends string>(key: K) => <A>(data: Task.Maybe<A>) => Task.Maybe<{ [P in K]: A; }>;
1654
+ bind: <K extends string, A, B>(key: K, f: (a: A) => Task.Maybe<B>) => (data: Task.Maybe<A>) => Task.Maybe<A & { [P in K]: B; }>;
1655
+ recover: <B>(fallback: () => Task.Maybe<B>) => <A>(data: Task.Maybe<A>) => Task.Maybe<A | B>;
1656
+ struct: <R extends Record<string, any>>(fields: { [K in keyof R]: Task.Maybe<R[K]>; }) => Task.Maybe<R>;
1657
+ memoize: <A>(task: Task.Maybe<A>) => Task.Maybe<A>;
1658
+ };
1659
+ Result: {
1660
+ make: {
1661
+ ok: <E = never, A = unknown>(value: A) => Task.Result<E, A>;
1662
+ err: <E, A = never>(error: E) => Task.Result<E, A>;
1663
+ };
1664
+ from: {
1665
+ nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Task.Result<E, A>;
1666
+ Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Task.Result<E, A>;
1667
+ Result: <E, A>(result: Result<E, A>) => Task.Result<E, A>;
1668
+ };
1669
+ to: {
1670
+ Maybe: <E, A>(data: Task.Result<E, A>) => Task.Maybe<A>;
1671
+ };
1672
+ tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
1673
+ onError: (error: unknown) => E;
1674
+ }) => Task.Result<E, A>;
1675
+ map: <E, A, B>(f: (a: A) => B) => (data: Task.Result<E, A>) => Task.Result<E, B>;
1676
+ mapError: <E, F, A>(f: (e: E) => F) => (data: Task.Result<E, A>) => Task.Result<F, A>;
1677
+ chain: <E2, A, B>(f: (a: A) => Task.Result<E2, B>) => <E1 = never>(data: Task.Result<E1, A>) => Task.Result<E1 | E2, B>;
1678
+ fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: Task.Result<E, A>) => Task<B>;
1679
+ match: <E, A, B>(cases: {
1680
+ err: (e: E) => B;
1681
+ ok: (a: A) => B;
1682
+ }) => (data: Task.Result<E, A>) => Task<B>;
1683
+ recover: <E, B>(fallback: (e: E) => Task.Result<E, B>) => <A>(data: Task.Result<E, A>) => Task.Result<E, A | B>;
1684
+ recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: (e: E) => Task.Result<E, B>) => <A>(data: Task.Result<E, A>) => Task.Result<E, A | B>;
1685
+ getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Task.Result<E, A>) => Task<A | B>;
1686
+ tap: <E, A>(f: (a: A) => void) => (data: Task.Result<E, A>) => Task.Result<E, A>;
1687
+ tapError: <E, A>(f: (e: E) => void) => (data: Task.Result<E, A>) => Task.Result<E, A>;
1688
+ ap: <E, A>(arg: Task.Result<E, A>) => <B>(data: Task.Result<E, (a: A) => B>) => Task.Result<E, B>;
1689
+ run: (signal?: AbortSignal) => <E, A>(task: Task.Result<E, A>) => Deferred<Result<E, A>>;
1690
+ bindTo: <K extends string>(key: K) => <E, A>(data: Task.Result<E, A>) => Task.Result<E, { [P in K]: A; }>;
1691
+ bind: <K extends string, E, A, B>(key: K, f: (a: A) => Task.Result<E, B>) => (data: Task.Result<E, A>) => Task.Result<E, A & { [P in K]: B; }>;
1692
+ struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Task.Result<E, R[K]>; }) => Task.Result<E, R>;
1693
+ retry: (policy: RetryPolicy) => <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
1694
+ memoize: <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
1695
+ timeout: <E2>(options: {
1696
+ duration: Duration;
1697
+ onTimeout: () => E2;
1698
+ }) => <E1 = never, A = unknown>(task: Task.Result<E1, A>) => Task.Result<E1 | E2, A>;
1699
+ allSettled: <E, A>(tasks: ReadonlyArray<Task.Result<E, A>>) => Task<ReadonlyArray<Result<E, A>>>;
1700
+ };
1701
+ Validation: {
1702
+ make: {
1703
+ passed: <E = never, A = unknown>(value: A) => Task.Validation<E, A>;
1704
+ failed: <E, A = never>(error: E) => Task.Validation<E, A>;
1705
+ failedAll: <E, A = never>(errors: NonEmptyArr<E>) => Task.Validation<E, A>;
1706
+ };
1707
+ from: {
1708
+ Validation: <E, A>(validation: Validation<E, A>) => Task.Validation<E, A>;
1709
+ nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Task.Validation<E, A>;
1710
+ Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Task.Validation<E, A>;
1711
+ Result: <E, A>(result: Result<E, A>) => Task.Validation<E, A>;
1712
+ };
1713
+ to: {
1714
+ Result: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (data: Task.Validation<E1, A>) => Task.Result<E2, A>;
1715
+ Maybe: <E, A>(data: Task.Validation<E, A>) => Task.Maybe<A>;
1716
+ };
1717
+ tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
1718
+ onError: (error: unknown) => E;
1719
+ }) => Task.Validation<E, A>;
1720
+ map: <E, A, B>(f: (a: A) => B) => (data: Task.Validation<E, A>) => Task.Validation<E, B>;
1721
+ ap: <E, A>(arg: Task.Validation<E, A>) => <B>(data: Task.Validation<E, (a: A) => B>) => Task.Validation<E, B>;
1722
+ fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: Task.Validation<E, A>) => Task<B>;
1723
+ match: <E, A, B>(cases: {
1724
+ passed: (a: A) => B;
1725
+ failed: (errors: NonEmptyArr<E>) => B;
1726
+ }) => (data: Task.Validation<E, A>) => Task<B>;
1727
+ getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Task.Validation<E, A>) => Task<A | B>;
1728
+ tap: <E, A>(f: (a: A) => void) => (data: Task.Validation<E, A>) => Task.Validation<E, A>;
1729
+ recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => Task.Validation<E, B>) => <A>(data: Task.Validation<E, A>) => Task.Validation<E, A | B>;
1730
+ recoverUnless: <E, B>(isBlocked: (errors: NonEmptyArr<E>) => boolean, fallback: (errors: NonEmptyArr<E>) => Task.Validation<E, B>) => <A>(data: Task.Validation<E, A>) => Task.Validation<E, A | B>;
1731
+ product: <E, A, B>(first: Task.Validation<E, A>, second: Task.Validation<E, B>) => Task.Validation<E, readonly [A, B]>;
1732
+ productAll: <E, A>(data: NonEmptyArr<Task.Validation<E, A>>) => Task.Validation<E, readonly A[]>;
1733
+ mapError: <E, F, A>(f: (e: E) => F) => (data: Task.Validation<E, A>) => Task.Validation<F, A>;
1734
+ tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: Task.Validation<E, A>) => Task.Validation<E, A>;
1735
+ struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Task.Validation<E, R[K]>; }) => Task.Validation<E, R>;
1736
+ memoize: <E, A>(task: Task.Validation<E, A>) => Task.Validation<E, A>;
1737
+ };
1738
+ };
1739
+ declare namespace Task {
1740
+ type LabeledTask<L extends string, A> = Task<A> & {
1741
+ readonly label: L;
1742
+ };
1743
+ type Maybe<A> = Task<_CoreMaybe<A>>;
1744
+ type Result<E, A> = Task<_CoreResult<E, A>>;
1745
+ type Validation<E, A> = Task<_CoreValidation<E, A>>;
2451
1746
  }
2452
1747
 
2453
1748
  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 };