@nlozgachev/pipelined 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,11 +14,11 @@ npm add @nlozgachev/pipelined
14
14
 
15
15
  ## Possibly maybe
16
16
 
17
- **pipelined** names every possible state and gives you operations that compose. `Maybe<A>` for
18
- values that may or may not be there. `Result<E, A>` for operations that succeed or fail with a typed
19
- error. `TaskResult<E, A>` for async operations that keep failures as typed values and propagate
20
- cancellation automatically. `Op<I, E, A>` for managing repeated async interactions — retry, timeout,
21
- and concurrency strategy in one place. And, of course, there is more than that.
17
+ In mainstream TypeScript, code is often burdened by implicit control flow: unchecked exceptions,
18
+ manual null propagation, and unhandled asynchronous failures. `pipelined` turns these complex
19
+ runtime states into simple, transparent data structures that compose. By representing optionality as
20
+ `Maybe`, failures as `Result`, lazy asynchronous pipelines as `TaskResult`, and repeated stateful
21
+ interactions as `Op`, the library helps disentangle business logic from control mechanics.
22
22
 
23
23
  ## Documentation
24
24
 
@@ -54,8 +54,10 @@ Every step that sees `None` is skipped. The fallback runs once, at the end.
54
54
 
55
55
  ## Example: typed async errors
56
56
 
57
- Unhandled rejections are invisible until they crash. `TaskResult<E, A>` keeps failures as typed
58
- values the error type is part of the signature, not a runtime surprise.
57
+ In JavaScript, asynchronous exceptions bypass the static type system, leaving unhandled rejections
58
+ as invisible runtime risks. `TaskResult<E, A>` represents fallible asynchronous computations as
59
+ lazy, infallible tasks that resolve to a typed `Result`. The error type is explicitly tracked in the
60
+ function signature, ensuring that failures are handled before compile time:
59
61
 
60
62
  ```ts
61
63
  import { pipe } from "@nlozgachev/pipelined/composition";
@@ -110,8 +112,10 @@ if (Result.isOk(result)) {
110
112
 
111
113
  ## Example: transforming data
112
114
 
113
- The utils modules wrap JavaScript's built-in types with data-last, curried operations that return
114
- `Maybe` wherever a value might be absent. They compose naturally with the core types:
115
+ Standard JavaScript arrays and records routinely return `undefined` on out-of-bounds access or
116
+ missing keys. The utility modules in `pipelined` wrap these operations with data-last, curried
117
+ helper functions that return `Maybe` when a value might be missing, allowing data transformation
118
+ steps to compose naturally with the core types:
115
119
 
116
120
  ```ts
117
121
  import { pipe } from "@nlozgachev/pipelined/composition";
@@ -148,7 +152,9 @@ the same way.
148
152
 
149
153
  ## Example: retry, timeout, and cancellation
150
154
 
151
- A careful, production-minded attempt at "fetch with retry, timeout, and cancellation":
155
+ Handling robust network interactions including retry attempts, backoff timing, timeouts, and
156
+ signal-driven cancellation — typically requires complex, stateful code that is highly prone to
157
+ subtle race conditions:
152
158
 
153
159
  ```ts
154
160
  type UserResult =
@@ -184,10 +190,6 @@ async function fetchUser(
184
190
  }
185
191
  ```
186
192
 
187
- The signal is forwarded by hand. The timeout needs its own controller. Timed-out aborts are
188
- distinguished from external cancellation by checking `signal?.aborted`. The retry is recursive to
189
- thread the attempt count.
190
-
191
193
  With **pipelined**:
192
194
 
193
195
  ```ts
@@ -228,13 +230,13 @@ if (Op.isOk(outcome)) {
228
230
  fetchUser.abort();
229
231
  ```
230
232
 
231
- ## Example: repeated interactions
232
-
233
- Real UIs make the same call many times — a search input fires on every keystroke, a submit button
234
- gets clicked twice, a polling loop needs to stop when something newer starts. Each scenario has a
235
- different answer to the same question: *what happens to the previous call when a new one arrives?*
233
+ ## Example: repeated UI interactions
236
234
 
237
- `Op` makes that question a one-word configuration choice.
235
+ User interfaces frequently trigger repeated asynchronous events: a search input firing on every
236
+ keystroke, a submit button clicked multiple times, or a polling loop that must terminate when a
237
+ newer request starts. Managing these concurrency scenarios traditionally requires complex, ad-hoc
238
+ state machines. `Op` simplifies this by allowing developers to declare the concurrency strategy as a
239
+ simple configuration choice:
238
240
 
239
241
  **Search — cancel the previous call when the user types:**
240
242
 
@@ -292,78 +294,53 @@ form.addEventListener("submit", (e) => {
292
294
  });
293
295
  ```
294
296
 
295
- `restartable`, `exclusive`, `debounced`, `throttled`, `queue`, `buffered`, `concurrent`, `keyed`,
296
- `once` each strategy is a complete, tested answer to one concurrency scenario. Swap the word, keep
297
- the rest of the code.
298
-
299
- ## What's included?
300
-
301
- The library covers the states you encounter in real applications: values that may be absent,
302
- operations that accumulate multiple errors, data that moves through
303
- `NotAsked >> Loading >> ( Success | Failure )`, async interactions with concurrency policies, nested
304
- immutable updates, and computations that share a common environment. Every type follows the same
305
- conventions — `map`, `chain`, `match`, `getOrElse` — so moving between them feels familiar.
306
-
307
- ### pipelined/core
308
-
309
- - **`Maybe<A>`** a value that may not exist; propagates absence without null checks.
310
- - **`Result<E, A>`** — an operation that succeeds or fails with a typed error.
311
- - **`Validation<E, A>`** — like `Result`, but accumulates every failure instead of stopping at the
312
- first.
313
- - **`Task<A>`** a lazy, infallible async operation; nothing runs until called.
314
- - **`TaskResult<E, A>`** a lazy async operation that can fail with a typed error.
315
- - **`TaskMaybe<A>`** a lazy async operation that may produce nothing.
316
- - **`TaskValidation<E, A>`** a lazy async operation that accumulates validation errors.
317
- - **`Op<I, E, A>`** — a managed async operation with a named concurrency strategy: `restartable`,
318
- `exclusive`, `debounced`, `throttled`, `queue`, `buffered`, `concurrent`, `keyed`, or `once`.
319
- Handles retry, timeout, cancellation, and state in one place.
320
- - **`RemoteData<E, A>`** — the four states of a data fetch: `NotAsked`, `Loading`, `Failure`,
321
- `Success`.
322
- - **`These<A, B>`** an inclusive OR: holds a first value, a second, or both at once.
323
- - **`Lens<S, A>`** focus on a required field in a nested structure. Read, set, and modify
324
- immutably.
325
- - **`Optional<S, A>`** — like `Lens`, but the target may be absent (nullable fields, array indices).
326
- - **`Reader<R, A>`** — a computation that depends on an environment `R`, supplied once at the
327
- boundary.
328
- - **`State<S, A>`** a computation that reads and updates a state value, threaded explicitly
329
- through the chain.
330
- - **`Logged<W, A>`** a computation that accumulates a log alongside its value; no console output,
331
- just data.
332
- - **`Predicate<A>`** — a typed boolean function, composable with `and`, `or`, `not`, and `using`.
333
- - **`Refinement<A, B>`** a type predicate that narrows `A` to `B` at runtime; composes with
334
- `Predicate`.
335
- - **`Resource<E, A>`** an acquire/release pair for safe resource management in `TaskResult`
336
- pipelines.
337
- - **`Deferred<A>`** — an infallible async value: a thenable that always resolves, never rejects.
338
- - **`Tuple<A, B>`** a typed pair with `first`, `second`, `map`, `swap`, and `fold`.
339
-
340
- ### pipelined/utils
341
-
342
- Everyday utilities for built-in JS types.
343
-
344
- - **`Arr`** — array utilities, data-last, returning `Maybe` instead of `undefined`.
345
- - **`Rec`** — record/object utilities, data-last, with `Maybe`-returning key lookup.
346
- - **`Dict`** — `ReadonlyMap<K, V>` utilities: `lookup`, `groupBy`, `upsert`, set operations.
347
- - **`Uniq`** — `ReadonlySet<A>` utilities: `insert`, `remove`, `union`, `intersection`,
348
- `difference`.
349
- - **`Num`** — number utilities: `range`, `clamp`, `between`, safe `parse`, and curried arithmetic.
350
- - **`Str`** — string utilities: `split`, `trim`, `words`, `lines`, and safe `parse.int` /
351
- `parse.float`.
352
-
353
- Every utility is benchmarked against its native equivalent. The data-last currying adds a function
354
- call; that is the expected cost of composability. Operations that exceeded a reasonable overhead
355
- have custom implementations that in several cases run faster than the native method they replace.
356
- See the [benchmarks page](https://pipelined.lozgachev.dev/appendix/benchmarks) for the methodology.
357
-
358
- ### pipelined/types
359
-
360
- - **`Brand<K, T>`** — nominal typing at compile time, zero runtime cost.
361
- - **`NonEmptyList<A>`** — an array guaranteed to have at least one element.
362
-
363
- ### pipelined/composition
364
-
365
- - **`pipe`**, **`flow`**, **`compose`** — function composition.
366
- - **`curry`** / **`uncurry`**, **`tap`**, **`memoize`**, and other function utilities.
297
+ The system supports a variety of built-in strategies — `restartable`, `exclusive`, `debounced`,
298
+ `throttled`, `queue`, `buffered`, `concurrent`, `keyed`, and `once` making the integration of
299
+ complex async scenarios highly predictable.
300
+
301
+ ## What is included
302
+
303
+ The library covers the full spectrum of state and control flow scenarios encountered in production
304
+ applications.
305
+
306
+ ### Core context containers
307
+
308
+ `Maybe` represents explicit optionality without null checks. `Result` handles synchronous, typed
309
+ success and failure, while `Validation` accumulates multiple errors. `RemoteData` tracks the four
310
+ states of an asynchronous data fetch (`NotAsked`, `Loading`, `Failure`, `Success`), and `These`
311
+ handles inclusive-OR scenarios containing a first value, a second, or both simultaneously.
312
+
313
+ ### Asynchronous operations
314
+
315
+ `Task` represents a lazy, infallible asynchronous computation. Fallible asynchronous workflows are
316
+ handled by `TaskResult`, `TaskMaybe`, and `TaskValidation`. For managing stateful, recurring
317
+ asynchronous operations with complex scheduling, `Op` implements named concurrency strategies such
318
+ as `restartable`, `exclusive`, `debounced`, `throttled`, and `queue`, handling retries, timeouts,
319
+ and signal propagation automatically.
320
+
321
+ ### Optics and environment state
322
+
323
+ `Lens` and `Optional` provide a simple concrete interface for safe, nested immutable data updates.
324
+ Environment-dependent calculations and explicit state threading are supported by the `Reader` and
325
+ `State` abstractions, while `Logged` enables side-effect-free data logging.
326
+
327
+ ### Optimized utilities
328
+
329
+ Custom, performance-optimized utility modules (`Arr`, `Rec`, `Dict`, `Uniq`, `Num`, `Str`) wrap
330
+ standard JavaScript types to return explicit types like `Maybe` and support data-last currying.
331
+ Functions are composed using `pipe` and `flow`, which are enriched with high-level composition
332
+ helpers like `when`, `unless`, `either`, `safe`, and `async` to support robust, expressive
333
+ pipelines.
334
+
335
+ ### Nominal branding and non-empty lists
336
+
337
+ Compile-time nominal typing with zero runtime overhead is provided by `Brand`, and `NonEmptyList`
338
+ guarantees that a list is never empty, eliminating defensive array length checks.
339
+
340
+ Every utility in the library is benchmarked against its native equivalent. The data-last currying
341
+ adds a small function call overhead, which is the expected cost of composability. For operations
342
+ where native overhead is significant, custom implementations are used that often run faster than
343
+ their native counterparts.
367
344
 
368
345
  ## License
369
346
 
@@ -304,6 +304,28 @@ declare namespace Result {
304
304
  * ```
305
305
  */
306
306
  const ap: <E, A>(arg: Result<E, A>) => <B>(data: Result<E, (a: A) => B>) => Result<E, B>;
307
+ /**
308
+ * Converts a Result value into an object containing a single property.
309
+ * Initiates the pipeline accumulator record.
310
+ *
311
+ * @example
312
+ * ```ts
313
+ * pipe(Result.ok(42), Result.bindTo("value")); // Ok({ value: 42 })
314
+ * ```
315
+ */
316
+ const bindTo: <K extends string>(key: K) => <E, A>(data: Result<E, A>) => Result<E, { [P in K]: A; }>;
317
+ /**
318
+ * Evaluates a new Result using the current accumulator and attaches the output to a new key.
319
+ *
320
+ * @example
321
+ * ```ts
322
+ * pipe(
323
+ * Result.ok({ a: 1 }),
324
+ * Result.bind("b", ({ a }) => Result.ok(a + 1))
325
+ * ); // Ok({ a: 1, b: 2 })
326
+ * ```
327
+ */
328
+ 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; }>;
307
329
  }
308
330
 
309
331
  type Some<A> = WithKind<"Some"> & WithValue<A>;
@@ -519,6 +541,28 @@ declare namespace Maybe {
519
541
  * ```
520
542
  */
521
543
  const ap: <A>(arg: Maybe<A>) => <B>(data: Maybe<(a: A) => B>) => Maybe<B>;
544
+ /**
545
+ * Converts a Maybe value into an object containing a single property.
546
+ * Initiates the pipeline accumulator record.
547
+ *
548
+ * @example
549
+ * ```ts
550
+ * pipe(Maybe.some(42), Maybe.bindTo("value")); // Some({ value: 42 })
551
+ * ```
552
+ */
553
+ const bindTo: <K extends string>(key: K) => <A>(data: Maybe<A>) => Maybe<{ [P in K]: A; }>;
554
+ /**
555
+ * Evaluates a new Maybe using the current accumulator and attaches the output to a new key.
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * pipe(
560
+ * Maybe.some({ a: 1 }),
561
+ * Maybe.bind("b", ({ a }) => Maybe.some(a + 1))
562
+ * ); // Some({ a: 1, b: 2 })
563
+ * ```
564
+ */
565
+ const bind: <K extends string, A, B>(key: K, f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<A & { [P in K]: B; }>;
522
566
  }
523
567
 
524
568
  declare const _deferred: unique symbol;
@@ -1024,6 +1068,28 @@ declare namespace Task {
1024
1068
  * ```
1025
1069
  */
1026
1070
  const run: (signal?: AbortSignal) => <A>(task: Task<A>) => Promise<A>;
1071
+ /**
1072
+ * Converts a Task value into an object containing a single property.
1073
+ * Initiates the pipeline accumulator record.
1074
+ *
1075
+ * @example
1076
+ * ```ts
1077
+ * pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
1078
+ * ```
1079
+ */
1080
+ const bindTo: <K extends string>(key: K) => <A>(data: Task<A>) => Task<{ [P in K]: A; }>;
1081
+ /**
1082
+ * Evaluates a new Task using the current accumulator and attaches the output to a new key.
1083
+ *
1084
+ * @example
1085
+ * ```ts
1086
+ * pipe(
1087
+ * Task.resolve({ a: 1 }),
1088
+ * Task.bind("b", ({ a }) => Task.resolve(a + 1))
1089
+ * ); // Task({ a: 1, b: 2 })
1090
+ * ```
1091
+ */
1092
+ const bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
1027
1093
  }
1028
1094
 
1029
- export { Deferred as D, Equality as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithValue as W, type Err as a, Ordering as b, type WithLog as c, type WithKind as d, type WithError as e, type RetryOptions as f, type TimeoutOptions as g, type WithTimeout as h, type WithMinInterval as i, type WithCooldown as j, type WithConcurrency as k, type WithSize as l, type WithDuration as m, type WithN as n, type WithErrors as o, type WithFirst as p, type WithSecond as q };
1095
+ export { Deferred as D, Equality as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithConcurrency as W, type Err as a, Ordering as b, type RetryOptions as c, type TimeoutOptions as d, type WithCooldown as e, type WithDuration as f, type WithError as g, type WithErrors as h, type WithFirst as i, type WithKind as j, type WithLog as k, type WithMinInterval as l, type WithN as m, type WithSecond as n, type WithSize as o, type WithTimeout as p, type WithValue as q };
@@ -304,6 +304,28 @@ declare namespace Result {
304
304
  * ```
305
305
  */
306
306
  const ap: <E, A>(arg: Result<E, A>) => <B>(data: Result<E, (a: A) => B>) => Result<E, B>;
307
+ /**
308
+ * Converts a Result value into an object containing a single property.
309
+ * Initiates the pipeline accumulator record.
310
+ *
311
+ * @example
312
+ * ```ts
313
+ * pipe(Result.ok(42), Result.bindTo("value")); // Ok({ value: 42 })
314
+ * ```
315
+ */
316
+ const bindTo: <K extends string>(key: K) => <E, A>(data: Result<E, A>) => Result<E, { [P in K]: A; }>;
317
+ /**
318
+ * Evaluates a new Result using the current accumulator and attaches the output to a new key.
319
+ *
320
+ * @example
321
+ * ```ts
322
+ * pipe(
323
+ * Result.ok({ a: 1 }),
324
+ * Result.bind("b", ({ a }) => Result.ok(a + 1))
325
+ * ); // Ok({ a: 1, b: 2 })
326
+ * ```
327
+ */
328
+ 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; }>;
307
329
  }
308
330
 
309
331
  type Some<A> = WithKind<"Some"> & WithValue<A>;
@@ -519,6 +541,28 @@ declare namespace Maybe {
519
541
  * ```
520
542
  */
521
543
  const ap: <A>(arg: Maybe<A>) => <B>(data: Maybe<(a: A) => B>) => Maybe<B>;
544
+ /**
545
+ * Converts a Maybe value into an object containing a single property.
546
+ * Initiates the pipeline accumulator record.
547
+ *
548
+ * @example
549
+ * ```ts
550
+ * pipe(Maybe.some(42), Maybe.bindTo("value")); // Some({ value: 42 })
551
+ * ```
552
+ */
553
+ const bindTo: <K extends string>(key: K) => <A>(data: Maybe<A>) => Maybe<{ [P in K]: A; }>;
554
+ /**
555
+ * Evaluates a new Maybe using the current accumulator and attaches the output to a new key.
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * pipe(
560
+ * Maybe.some({ a: 1 }),
561
+ * Maybe.bind("b", ({ a }) => Maybe.some(a + 1))
562
+ * ); // Some({ a: 1, b: 2 })
563
+ * ```
564
+ */
565
+ const bind: <K extends string, A, B>(key: K, f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<A & { [P in K]: B; }>;
522
566
  }
523
567
 
524
568
  declare const _deferred: unique symbol;
@@ -1024,6 +1068,28 @@ declare namespace Task {
1024
1068
  * ```
1025
1069
  */
1026
1070
  const run: (signal?: AbortSignal) => <A>(task: Task<A>) => Promise<A>;
1071
+ /**
1072
+ * Converts a Task value into an object containing a single property.
1073
+ * Initiates the pipeline accumulator record.
1074
+ *
1075
+ * @example
1076
+ * ```ts
1077
+ * pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
1078
+ * ```
1079
+ */
1080
+ const bindTo: <K extends string>(key: K) => <A>(data: Task<A>) => Task<{ [P in K]: A; }>;
1081
+ /**
1082
+ * Evaluates a new Task using the current accumulator and attaches the output to a new key.
1083
+ *
1084
+ * @example
1085
+ * ```ts
1086
+ * pipe(
1087
+ * Task.resolve({ a: 1 }),
1088
+ * Task.bind("b", ({ a }) => Task.resolve(a + 1))
1089
+ * ); // Task({ a: 1, b: 2 })
1090
+ * ```
1091
+ */
1092
+ const bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
1027
1093
  }
1028
1094
 
1029
- export { Deferred as D, Equality as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithValue as W, type Err as a, Ordering as b, type WithLog as c, type WithKind as d, type WithError as e, type RetryOptions as f, type TimeoutOptions as g, type WithTimeout as h, type WithMinInterval as i, type WithCooldown as j, type WithConcurrency as k, type WithSize as l, type WithDuration as m, type WithN as n, type WithErrors as o, type WithFirst as p, type WithSecond as q };
1095
+ export { Deferred as D, Equality as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithConcurrency as W, type Err as a, Ordering as b, type RetryOptions as c, type TimeoutOptions as d, type WithCooldown as e, type WithDuration as f, type WithError as g, type WithErrors as h, type WithFirst as i, type WithKind as j, type WithLog as k, type WithMinInterval as l, type WithN as m, type WithSecond as n, type WithSize as o, type WithTimeout as p, type WithValue as q };
@@ -125,6 +125,53 @@ function flow(ab, bc, cd, de, ef, fg, gh, hi, ij, jk) {
125
125
  }
126
126
  }
127
127
  }
128
+ var when = (predicate, onTrue) => (a) => predicate(a) ? onTrue(a) : a;
129
+ var unless = (predicate, onFalse) => (a) => predicate(a) ? a : onFalse(a);
130
+ var either = (predicate, onTrue, onFalse) => (a) => predicate(a) ? onTrue(a) : onFalse(a);
131
+ var struct = (fields) => (a) => {
132
+ const result = {};
133
+ for (const key of Object.keys(fields)) {
134
+ result[key] = fields[key](a);
135
+ }
136
+ return result;
137
+ };
138
+ function safe(...fns) {
139
+ return (a) => {
140
+ let result = a;
141
+ if (result === null || result === void 0) {
142
+ return result;
143
+ }
144
+ for (const fn of fns) {
145
+ result = fn(result);
146
+ if (result === null || result === void 0) {
147
+ return result;
148
+ }
149
+ }
150
+ return result;
151
+ };
152
+ }
153
+ function async(...fns) {
154
+ return async (a) => {
155
+ let result = await a;
156
+ for (const fn of fns) {
157
+ result = await fn(result);
158
+ }
159
+ return result;
160
+ };
161
+ }
162
+ flow.when = when;
163
+ flow.unless = unless;
164
+ flow.either = either;
165
+ flow.struct = struct;
166
+ flow.safe = safe;
167
+ flow.async = async;
168
+ flow.try = (f, onError) => (a) => {
169
+ try {
170
+ return f(a);
171
+ } catch (error) {
172
+ return onError(error, a);
173
+ }
174
+ };
128
175
 
129
176
  // src/Composition/fn.ts
130
177
  var identity = (a) => a;
@@ -148,6 +195,7 @@ var once = (f) => {
148
195
  return result;
149
196
  };
150
197
  };
198
+ var defaultTo = (fallback) => (a) => a === null || a === void 0 ? fallback : a;
151
199
 
152
200
  // src/Composition/juxt.ts
153
201
  function juxt(fns) {
@@ -223,6 +271,49 @@ function pipe(a, ab, bc, cd, de, ef, fg, gh, hi, ij, jk) {
223
271
  }
224
272
  }
225
273
  }
274
+ var when2 = (predicate, onTrue) => (a) => predicate(a) ? onTrue(a) : a;
275
+ var unless2 = (predicate, onFalse) => (a) => predicate(a) ? a : onFalse(a);
276
+ var either2 = (predicate, onTrue, onFalse) => (a) => predicate(a) ? onTrue(a) : onFalse(a);
277
+ var struct2 = (fields) => (a) => {
278
+ const result = {};
279
+ for (const key of Object.keys(fields)) {
280
+ result[key] = fields[key](a);
281
+ }
282
+ return result;
283
+ };
284
+ function safe2(a, ...fns) {
285
+ let result = a;
286
+ if (result === null || result === void 0) {
287
+ return result;
288
+ }
289
+ for (const fn of fns) {
290
+ result = fn(result);
291
+ if (result === null || result === void 0) {
292
+ return result;
293
+ }
294
+ }
295
+ return result;
296
+ }
297
+ async function async2(a, ...fns) {
298
+ let result = await a;
299
+ for (const fn of fns) {
300
+ result = await fn(result);
301
+ }
302
+ return result;
303
+ }
304
+ pipe.when = when2;
305
+ pipe.unless = unless2;
306
+ pipe.either = either2;
307
+ pipe.struct = struct2;
308
+ pipe.safe = safe2;
309
+ pipe.async = async2;
310
+ pipe.try = (f, onError) => (a) => {
311
+ try {
312
+ return f(a);
313
+ } catch (error) {
314
+ return onError(error, a);
315
+ }
316
+ };
226
317
 
227
318
  // src/Composition/tap.ts
228
319
  var tap = (f) => (a) => {
@@ -258,6 +349,7 @@ export {
258
349
  and,
259
350
  or,
260
351
  once,
352
+ defaultTo,
261
353
  juxt,
262
354
  memoize,
263
355
  memoizeWeak,
@@ -3,7 +3,7 @@ import {
3
3
  Maybe,
4
4
  Result,
5
5
  Task
6
- } from "./chunk-DLBHVYII.mjs";
6
+ } from "./chunk-PUMSVZB4.mjs";
7
7
  import {
8
8
  isNonEmptyList
9
9
  } from "./chunk-DBIC62UV.mjs";
@@ -30,6 +30,10 @@ var Maybe;
30
30
  Maybe2.filter = (predicate) => (data) => (0, Maybe2.isSome)(data) ? predicate(data.value) ? data : (0, Maybe2.none)() : data;
31
31
  Maybe2.recover = (fallback) => (data) => (0, Maybe2.isSome)(data) ? data : fallback();
32
32
  Maybe2.ap = (arg) => (data) => (0, Maybe2.isSome)(data) && (0, Maybe2.isSome)(arg) ? (0, Maybe2.some)(data.value(arg.value)) : (0, Maybe2.none)();
33
+ Maybe2.bindTo = (key) => (data) => (0, Maybe2.map)((a) => ({ [key]: a }))(data);
34
+ Maybe2.bind = (key, f) => (data) => (0, Maybe2.chain)(
35
+ (a) => (0, Maybe2.map)((b) => ({ ...a, [key]: b }))(f(a))
36
+ )(data);
33
37
  })(Maybe || (Maybe = {}));
34
38
 
35
39
  // src/Core/Result.ts
@@ -78,6 +82,10 @@ var Result;
78
82
  Result2.recoverUnless = (isBlocked, fallback) => (data) => (0, Result2.isErr)(data) && !isBlocked(data.error) ? fallback() : data;
79
83
  Result2.toMaybe = (data) => (0, Result2.isOk)(data) ? Maybe.some(data.value) : Maybe.none();
80
84
  Result2.ap = (arg) => (data) => (0, Result2.isOk)(data) && (0, Result2.isOk)(arg) ? (0, Result2.ok)(data.value(arg.value)) : (0, Result2.isErr)(data) ? data : arg;
85
+ Result2.bindTo = (key) => (data) => (0, Result2.map)((a) => ({ [key]: a }))(data);
86
+ Result2.bind = (key, f) => (data) => (0, Result2.chain)(
87
+ (a) => (0, Result2.map)((b) => ({ ...a, [key]: b }))(f(a))
88
+ )(data);
81
89
  })(Result || (Result = {}));
82
90
 
83
91
  // src/Core/Deferred.ts
@@ -312,6 +320,10 @@ var Task;
312
320
  return { task, abort };
313
321
  };
314
322
  Task2.run = (signal) => (task) => Deferred.toPromise(task(signal));
323
+ Task2.bindTo = (key) => (data) => (0, Task2.map)((a) => ({ [key]: a }))(data);
324
+ Task2.bind = (key, f) => (data) => (0, Task2.chain)(
325
+ (a) => (0, Task2.map)((b) => ({ ...a, [key]: b }))(f(a))
326
+ )(data);
315
327
  })(Task || (Task = {}));
316
328
 
317
329
  export {
@@ -3,7 +3,7 @@ import {
3
3
  Maybe,
4
4
  Result,
5
5
  Task
6
- } from "./chunk-DLBHVYII.mjs";
6
+ } from "./chunk-PUMSVZB4.mjs";
7
7
  import {
8
8
  Duration
9
9
  } from "./chunk-VWVPHDZO.mjs";
@@ -103,6 +103,10 @@ var Logged;
103
103
  return data;
104
104
  };
105
105
  Logged2.run = (data) => [data.value, data.log];
106
+ Logged2.bindTo = (key) => (data) => (0, Logged2.map)((a) => ({ [key]: a }))(data);
107
+ Logged2.bind = (key, f) => (data) => (0, Logged2.chain)(
108
+ (a) => (0, Logged2.map)((b) => ({ ...a, [key]: b }))(f(a))
109
+ )(data);
106
110
  })(Logged || (Logged = {}));
107
111
 
108
112
  // src/internal/Op.util.ts
@@ -1092,7 +1096,7 @@ var Op;
1092
1096
  }
1093
1097
  return cases.nil();
1094
1098
  };
1095
- Op2.fold = (onErr, onOk, onNil) => (outcome) => {
1099
+ Op2.fold = (onErr, onNil, onOk) => (outcome) => {
1096
1100
  if (outcome.kind === "OpOk") {
1097
1101
  return onOk(outcome.value);
1098
1102
  }
@@ -1277,6 +1281,10 @@ var Reader;
1277
1281
  };
1278
1282
  Reader2.local = (f) => (data) => (env) => data(f(env));
1279
1283
  Reader2.run = (env) => (data) => data(env);
1284
+ Reader2.bindTo = (key) => (data) => (0, Reader2.map)((a) => ({ [key]: a }))(data);
1285
+ Reader2.bind = (key, f) => (data) => (0, Reader2.chain)(
1286
+ (a) => (0, Reader2.map)((b) => ({ ...a, [key]: b }))(f(a))
1287
+ )(data);
1280
1288
  })(Reader || (Reader = {}));
1281
1289
 
1282
1290
  // src/Core/Refinement.ts
@@ -1321,17 +1329,17 @@ var RemoteData;
1321
1329
  }
1322
1330
  return (0, RemoteData2.notAsked)();
1323
1331
  };
1324
- RemoteData2.fold = (onNotAsked, onLoading, onFailure, onSuccess) => (data) => {
1332
+ RemoteData2.fold = (onFailure, onNotAsked, onLoading, onSuccess) => (data) => {
1325
1333
  switch (data.kind) {
1334
+ case "Failure": {
1335
+ return onFailure(data.error);
1336
+ }
1326
1337
  case "NotAsked": {
1327
1338
  return onNotAsked();
1328
1339
  }
1329
1340
  case "Loading": {
1330
1341
  return onLoading();
1331
1342
  }
1332
- case "Failure": {
1333
- return onFailure(data.error);
1334
- }
1335
1343
  case "Success": {
1336
1344
  return onSuccess(data.value);
1337
1345
  }
@@ -1449,6 +1457,10 @@ var State;
1449
1457
  State2.run = (initialState) => (st) => st(initialState);
1450
1458
  State2.evaluate = (initialState) => (st) => st(initialState)[0];
1451
1459
  State2.execute = (initialState) => (st) => st(initialState)[1];
1460
+ State2.bindTo = (key) => (data) => (0, State2.map)((a) => ({ [key]: a }))(data);
1461
+ State2.bind = (key, f) => (data) => (0, State2.chain)(
1462
+ (a) => (0, State2.map)((b) => ({ ...a, [key]: b }))(f(a))
1463
+ )(data);
1452
1464
  })(State || (State = {}));
1453
1465
 
1454
1466
  // src/Core/TaskMaybe.ts
@@ -1474,6 +1486,10 @@ var TaskMaybe;
1474
1486
  TaskMaybe2.tap = (f) => (data) => Task.map(Maybe.tap(f))(data);
1475
1487
  TaskMaybe2.filter = (predicate) => (data) => Task.map(Maybe.filter(predicate))(data);
1476
1488
  TaskMaybe2.toTaskResult = (onNone) => (data) => Task.map(Maybe.toResult(onNone))(data);
1489
+ TaskMaybe2.bindTo = (key) => (data) => (0, TaskMaybe2.map)((a) => ({ [key]: a }))(data);
1490
+ TaskMaybe2.bind = (key, f) => (data) => (0, TaskMaybe2.chain)(
1491
+ (a) => (0, TaskMaybe2.map)((b) => ({ ...a, [key]: b }))(f(a))
1492
+ )(data);
1477
1493
  })(TaskMaybe || (TaskMaybe = {}));
1478
1494
 
1479
1495
  // src/Core/TaskResult.ts
@@ -1505,6 +1521,10 @@ var TaskResult;
1505
1521
  )
1506
1522
  );
1507
1523
  TaskResult2.run = (signal) => (task) => Deferred.toPromise(task(signal));
1524
+ TaskResult2.bindTo = (key) => (data) => (0, TaskResult2.map)((a) => ({ [key]: a }))(data);
1525
+ TaskResult2.bind = (key, f) => (data) => (0, TaskResult2.chain)(
1526
+ (a) => (0, TaskResult2.map)((b) => ({ ...a, [key]: b }))(f(a))
1527
+ )(data);
1508
1528
  })(TaskResult || (TaskResult = {}));
1509
1529
 
1510
1530
  // src/Core/Validation.ts