@nlozgachev/pipelined 0.63.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.d.ts CHANGED
@@ -1,2529 +1,3 @@
1
- import { M as Maybe, R as Result, T as Task } from './Validation-C5RGZUXy.js';
2
- export { E as Equality, a as Err, F as Failed, N as None, O as Ok, b as Ordering, P as Passed, S as Some, V as Validation } from './Validation-C5RGZUXy.js';
3
- import { o as WithValue, i as WithLog, D as Deferred, R as RetryOptions, n as WithTimeout, j as WithMinInterval, c as WithCooldown, W as WithConcurrency, m as WithSize, d as WithDuration, k as WithN, h as WithKind, e as WithError, b as TimeoutOptions, g as WithFirst, l as WithSecond } from './InternalTypes-CCXa8Kvr.js';
4
- import { D as Duration } from './Duration-DeyxG6VQ.js';
5
- import './types.js';
6
-
7
- /**
8
- * A type that can combine two values of type `A` into one, with a neutral starting value.
9
- * `empty` is the identity: `combine(empty)(a) === a` and `combine(a)(empty) === a`.
10
- * `combine(b)(a)` appends `b` onto `a` — `a` is the accumulated value, `b` is the new element.
11
- *
12
- * @example
13
- * ```ts
14
- * pipe(["hello", ", ", "world"], Combinable.fold(Combinable.string)); // "hello, world"
15
- * pipe([1, 2, 3, 4, 5], Combinable.fold(Combinable.sum)); // 15
16
- * ```
17
- */
18
- type Combinable<A> = {
19
- readonly empty: A;
20
- readonly combine: (b: A) => (a: A) => A;
21
- };
22
- declare const Combinable: {
23
- /**
24
- * Combines strings by concatenation. Empty string is the neutral element.
25
- *
26
- * @example
27
- * ```ts
28
- * pipe(["a", "b", "c"], Combinable.fold(Combinable.string)); // "abc"
29
- * ```
30
- */
31
- string: Combinable<string>;
32
- /**
33
- * Combines numbers by addition. `0` is the neutral element.
34
- *
35
- * @example
36
- * ```ts
37
- * pipe([1, 2, 3], Combinable.fold(Combinable.sum)); // 6
38
- * ```
39
- */
40
- sum: Combinable<number>;
41
- /**
42
- * Combines numbers by multiplication. `1` is the neutral element.
43
- *
44
- * @example
45
- * ```ts
46
- * pipe([2, 3, 4], Combinable.fold(Combinable.product)); // 24
47
- * ```
48
- */
49
- product: Combinable<number>;
50
- /**
51
- * Combines booleans with logical AND. `true` is the neutral element.
52
- *
53
- * @example
54
- * ```ts
55
- * pipe([true, true, false], Combinable.fold(Combinable.all)); // false
56
- * ```
57
- */
58
- all: Combinable<boolean>;
59
- /**
60
- * Combines booleans with logical OR. `false` is the neutral element.
61
- *
62
- * @example
63
- * ```ts
64
- * pipe([false, false, true], Combinable.fold(Combinable.any)); // true
65
- * ```
66
- */
67
- any: Combinable<boolean>;
68
- /**
69
- * Combines arrays by concatenation. Empty array is the neutral element.
70
- *
71
- * @example
72
- * ```ts
73
- * pipe([[1, 2], [3], [4, 5]], Combinable.fold(Combinable.array<number>())); // [1, 2, 3, 4, 5]
74
- * ```
75
- */
76
- array: <A>() => Combinable<readonly A[]>;
77
- /**
78
- * Lifts a `Combinable<A>` to `Combinable<Maybe<A>>`. `None` is the neutral element —
79
- * combining with `None` on either side returns the other value unchanged.
80
- * Two `Some` values combine their inner values using the inner `Combinable`.
81
- *
82
- * @example
83
- * ```ts
84
- * const c = Combinable.maybe(Combinable.sum);
85
- * c.combine(Maybe.make.some(3))(Maybe.make.some(2)); // Some(5)
86
- * c.combine(Maybe.make.none())(Maybe.make.some(5)); // Some(5)
87
- * ```
88
- */
89
- maybe: <A>(inner: Combinable<A>) => Combinable<Maybe<A>>;
90
- /**
91
- * Folds an array into a single value using the `Combinable`'s `empty` as the starting point.
92
- *
93
- * @example
94
- * ```ts
95
- * pipe([1, 2, 3, 4, 5], Combinable.fold(Combinable.sum)); // 15
96
- * pipe([], Combinable.fold(Combinable.sum)); // 0
97
- * ```
98
- */
99
- fold: <A>(c: Combinable<A>) => (data: readonly A[]) => A;
100
- /**
101
- * Derives a `Combinable` for a record of fields from field-level `Combinable` instances.
102
- *
103
- * @example
104
- * ```ts
105
- * const StatsCombinable = Combinable.struct({
106
- * count: Combinable.sum,
107
- * tags: Combinable.array<string>(),
108
- * });
109
- * ```
110
- */
111
- struct: <R extends Record<string, unknown>>(fields: { [K in keyof R]: Combinable<R[K]>; }) => Combinable<R>;
112
- };
113
-
114
- /**
115
- * A synchronous memoized computation. The factory function runs exactly once —
116
- * on the first call to `Lazy.evaluate` — and the result is cached for all subsequent calls.
117
- *
118
- * @example
119
- * ```ts
120
- * const config = Lazy.from(() => parseConfig(rawInput));
121
- *
122
- * pipe(
123
- * config,
124
- * Lazy.map(cfg => cfg.port),
125
- * Lazy.evaluate,
126
- * ); // parseConfig ran once; cfg.port returned
127
- * ```
128
- */
129
- type Lazy<A> = {
130
- readonly get: () => A;
131
- };
132
- declare const Lazy: {
133
- /**
134
- * Wraps a thunk in a `Lazy`. The thunk runs exactly once, on first `evaluate`.
135
- *
136
- * @example
137
- * ```ts
138
- * const expensive = Lazy.from(() => computeExpensiveValue(input));
139
- * ```
140
- */
141
- from: <A>(f: () => A) => Lazy<A>;
142
- /**
143
- * Forces evaluation and returns the cached result. Safe to call multiple times.
144
- *
145
- * @example
146
- * ```ts
147
- * const value = Lazy.evaluate(Lazy.from(() => 42)); // 42
148
- * ```
149
- */
150
- evaluate: <A>(lazy: Lazy<A>) => A;
151
- /**
152
- * Transforms the result of a `Lazy` without triggering evaluation.
153
- *
154
- * @example
155
- * ```ts
156
- * pipe(Lazy.from(() => loadConfig()), Lazy.map(cfg => cfg.port));
157
- * ```
158
- */
159
- map: <A, B>(f: (a: A) => B) => (lazy: Lazy<A>) => Lazy<B>;
160
- /**
161
- * Chains a `Lazy`-returning transformation without triggering evaluation.
162
- *
163
- * @example
164
- * ```ts
165
- * pipe(
166
- * Lazy.from(() => loadConfig()),
167
- * Lazy.chain(cfg => Lazy.from(() => openConnection(cfg.dbUrl))),
168
- * );
169
- * ```
170
- */
171
- chain: <A, B>(f: (a: A) => Lazy<B>) => (lazy: Lazy<A>) => Lazy<B>;
172
- /**
173
- * Runs a side effect on the value without changing it. Fires once, on first `evaluate`.
174
- *
175
- * @example
176
- * ```ts
177
- * pipe(Lazy.from(() => compute()), Lazy.tap(v => console.log("computed:", v)));
178
- * ```
179
- */
180
- tap: <A>(f: (a: A) => void) => (lazy: Lazy<A>) => Lazy<A>;
181
- };
182
-
183
- /**
184
- * Lens<S, A> focuses on a single value A inside a structure S, providing
185
- * a composable way to read and immutably update nested data.
186
- *
187
- * A Lens always succeeds: the focused value is guaranteed to exist.
188
- * For optional or indexed focuses, use Optional<S, A>.
189
- *
190
- * @example
191
- * ```ts
192
- * type Address = { city: string; zip: string };
193
- * type User = { name: string; address: Address };
194
- *
195
- * const addressLens = Lens.from.property<User>()("address");
196
- * const cityLens = Lens.from.property<Address>()("city");
197
- * const userCityLens = pipe(addressLens, Lens.andThen(cityLens));
198
- *
199
- * pipe(user, Lens.get(userCityLens)); // "Berlin"
200
- * pipe(user, Lens.set(userCityLens)("Hamburg")); // new User with city updated
201
- * pipe(user, Lens.modify(userCityLens)(c => c.toUpperCase())); // "BERLIN"
202
- * ```
203
- */
204
- type Lens<S, A> = {
205
- readonly get: (s: S) => A;
206
- readonly set: (a: A) => (s: S) => S;
207
- };
208
- declare const Lens: {
209
- from: {
210
- /**
211
- * Constructs a Lens from a getter and a setter.
212
- *
213
- * @example
214
- * ```ts
215
- * const nameLens = Lens.from.accessors(
216
- * (user: User) => user.name,
217
- * (name) => (user) => ({ ...user, name }),
218
- * );
219
- * ```
220
- */
221
- accessors: <S, A>(get: (s: S) => A, set: (a: A) => (s: S) => S) => Lens<S, A>;
222
- /**
223
- * Creates a Lens that focuses on a property of an object.
224
- * Call with the structure type first, then the key.
225
- *
226
- * @example
227
- * ```ts
228
- * const nameLens = Lens.from.property<User>()("name");
229
- * ```
230
- */
231
- property: <S>() => <K extends keyof S>(key: K) => Lens<S, S[K]>;
232
- };
233
- /**
234
- * Reads the focused value from a structure.
235
- *
236
- * @example
237
- * ```ts
238
- * pipe(user, Lens.get(nameLens)); // "Alice"
239
- * ```
240
- */
241
- get: <S, A>(lens: Lens<S, A>) => (s: S) => A;
242
- /**
243
- * Replaces the focused value within a structure, returning a new structure.
244
- *
245
- * @example
246
- * ```ts
247
- * pipe(user, Lens.set(nameLens)("Bob")); // new User with name "Bob"
248
- * ```
249
- */
250
- set: <S, A>(lens: Lens<S, A>) => (a: A) => (s: S) => S;
251
- /**
252
- * Applies a function to the focused value, returning a new structure.
253
- *
254
- * @example
255
- * ```ts
256
- * pipe(user, Lens.modify(nameLens)(n => n.toUpperCase())); // "ALICE"
257
- * ```
258
- */
259
- modify: <S, A>(lens: Lens<S, A>) => (f: (a: A) => A) => (s: S) => S;
260
- /**
261
- * Composes two Lenses: focuses through the outer, then through the inner.
262
- * Use in a pipe chain to build up a deep focus step by step.
263
- *
264
- * @example
265
- * ```ts
266
- * const userCityLens = pipe(
267
- * Lens.from.property<User>()("address"),
268
- * Lens.andThen(Lens.from.property<Address>()("city")),
269
- * );
270
- * ```
271
- */
272
- andThen: <A, B>(inner: Lens<A, B>) => <S>(outer: Lens<S, A>) => Lens<S, B>;
273
- /**
274
- * Composes a Lens with an Optional, producing an Optional.
275
- * Use when the next step in the focus is optional (may be absent).
276
- *
277
- * @example
278
- * ```ts
279
- * const userBioOpt = pipe(
280
- * Lens.from.property<User>()("profile"),
281
- * Lens.andThenOptional(Optional.from.property<Profile>()("bio")),
282
- * );
283
- * ```
284
- */
285
- andThenOptional: <A, B>(inner: Optional<A, B>) => <S>(outer: Lens<S, A>) => Optional<S, B>;
286
- /**
287
- * Converts a Lens to an Optional. Every Lens is a valid Optional
288
- * whose get always returns Some.
289
- *
290
- * @example
291
- * ```ts
292
- * pipe(
293
- * Lens.from.property<User>()("address"),
294
- * Lens.toOptional,
295
- * Optional.andThen(Optional.from.property<Address>()("landmark")),
296
- * );
297
- * ```
298
- */
299
- toOptional: <S, A>(lens: Lens<S, A>) => Optional<S, A>;
300
- };
301
-
302
- /**
303
- * A value paired with an accumulated log.
304
- *
305
- * `Logged<W, A>` pairs a result `A` with a sequence of log entries `W`. When
306
- * you sequence two `Logged` computations with `chain`, the logs are
307
- * automatically concatenated — you never have to thread the log array through
308
- * your code manually.
309
- *
310
- * @example
311
- * ```ts
312
- * const program = pipe(
313
- * Logged.from.value<string, number>(0),
314
- * Logged.chain(n => pipe(
315
- * Logged.from.entry("start"),
316
- * Logged.map(() => n + 1),
317
- * )),
318
- * Logged.chain(n => pipe(
319
- * Logged.from.entry("done"),
320
- * Logged.map(() => n * 10),
321
- * )),
322
- * );
323
- *
324
- * Logged.run(program); // [10, ["start", "done"]]
325
- * ```
326
- */
327
- type Logged<L, A> = WithValue<A> & WithLog<L>;
328
- declare const Logged: {
329
- from: {
330
- /**
331
- * Wraps a pure value into a `Logged` with an empty log.
332
- *
333
- * @example
334
- * ```ts
335
- * Logged.from.value<string, number>(42); // { value: 42, log: [] }
336
- * ```
337
- */
338
- value: <W, A>(val: A) => Logged<W, A>;
339
- /**
340
- * Creates a `Logged` that records a single log entry and produces no
341
- * meaningful value. Use this to append to the log inside a `chain`.
342
- *
343
- * @example
344
- * ```ts
345
- * Logged.from.entry("operation completed"); // { value: undefined, log: ["operation completed"] }
346
- * ```
347
- */
348
- entry: <W>(logEntry: W) => Logged<W, undefined>;
349
- };
350
- /**
351
- * Transforms the value inside a `Logged` without affecting the log.
352
- *
353
- * @example
354
- * ```ts
355
- * pipe(
356
- * Logged.from.value<string, number>(5),
357
- * Logged.map(n => n * 2),
358
- * ); // { value: 10, log: [] }
359
- * ```
360
- */
361
- map: <W, A, B>(f: (a: A) => B) => (data: Logged<W, A>) => Logged<W, B>;
362
- /**
363
- * Sequences two `Logged` computations, concatenating their logs.
364
- * The value from the first is passed to `f`; the resulting log entries are
365
- * appended after the entries from the first.
366
- *
367
- * Data-last — the first computation is the data being piped.
368
- *
369
- * @example
370
- * ```ts
371
- * const result = pipe(
372
- * Logged.from.value<string, number>(1),
373
- * Logged.chain(n => pipe(Logged.from.entry("step"), Logged.map(() => n + 1))),
374
- * Logged.chain(n => pipe(Logged.from.entry("done"), Logged.map(() => n * 10))),
375
- * );
376
- *
377
- * Logged.run(result); // [20, ["step", "done"]]
378
- * ```
379
- */
380
- chain: <W, A, B>(f: (a: A) => Logged<W, B>) => (data: Logged<W, A>) => Logged<W, B>;
381
- /**
382
- * Applies a function wrapped in a `Logged` to a value wrapped in a `Logged`,
383
- * concatenating both logs.
384
- *
385
- * @example
386
- * ```ts
387
- * const fn: Logged<string, (n: number) => number> = {
388
- * value: n => n * 2,
389
- * log: ["fn-loaded"],
390
- * };
391
- * const arg: Logged<string, number> = { value: 5, log: ["arg-loaded"] };
392
- *
393
- * const result = pipe(fn, Logged.ap(arg));
394
- * Logged.run(result); // [10, ["fn-loaded", "arg-loaded"]]
395
- * ```
396
- */
397
- ap: <W, A>(arg: Logged<W, A>) => <B>(data: Logged<W, (a: A) => B>) => Logged<W, B>;
398
- /**
399
- * Runs a side effect on the value without changing the `Logged`.
400
- * Useful for debugging or inspecting intermediate values.
401
- *
402
- * @example
403
- * ```ts
404
- * pipe(
405
- * Logged.from.value<string, number>(42),
406
- * Logged.tap(n => console.log("value:", n)),
407
- * );
408
- * ```
409
- */
410
- tap: <W, A>(f: (a: A) => void) => (data: Logged<W, A>) => Logged<W, A>;
411
- /**
412
- * Extracts the value and log as a `readonly [A, ReadonlyArray<W>]` tuple.
413
- * Use this at the boundary where you need to consume both.
414
- *
415
- * @example
416
- * ```ts
417
- * const result = pipe(
418
- * Logged.from.value<string, number>(1),
419
- * Logged.chain(n => pipe(Logged.from.entry("incremented"), Logged.map(() => n + 1))),
420
- * );
421
- *
422
- * const [value, log] = Logged.run(result);
423
- * // value = 2, log = ["incremented"]
424
- * ```
425
- */
426
- run: <W, A>(data: Logged<W, A>) => readonly [A, ReadonlyArray<W>];
427
- /**
428
- * Lifts a Logged value into an accumulator object.
429
- *
430
- * @example
431
- * ```ts
432
- * pipe(Logged.from.value<string, number>(42), Logged.bindTo("value")); // Logged({ value: 42 })
433
- * ```
434
- */
435
- bindTo: <K extends string>(key: K) => <W, A>(data: Logged<W, A>) => Logged<W, { [P in K]: A; }>;
436
- /**
437
- * Evaluates a new Logged using the current accumulator and attaches the output to a new key.
438
- *
439
- * @example
440
- * ```ts
441
- * pipe(
442
- * Logged.from.value<string, { a: number }>({ a: 1 }),
443
- * Logged.bind("b", ({ a }) => Logged.from.value<string, number>(a + 1))
444
- * ); // Logged({ value: { a: 1, b: 2 } })
445
- * ```
446
- */
447
- bind: <K extends string, W, A, B>(key: K, f: (a: A) => Logged<W, B>) => (data: Logged<W, A>) => Logged<W, A & { [P in K]: B; }>;
448
- /**
449
- * Focuses a Logged computation's value transformation using a Lens.
450
- *
451
- * @example
452
- * ```ts
453
- * const nameLens = Lens.from.property<{ name: string }>()("name");
454
- * const logged = Logged.from.value<string, { name: string }>({ name: "alice" });
455
- * pipe(logged, Logged.focus(nameLens)(s => s.toUpperCase()));
456
- * ```
457
- */
458
- focus: <S, A>(lens: Lens<S, A>) => <W>(f: (a: A) => A) => (data: Logged<W, S>) => Logged<W, S>;
459
- };
460
-
461
- type MaybeRetry<E, O> = O extends {
462
- retry: RetryOptions<E>;
463
- } ? Op.Retrying<E> : never;
464
- type AllInterpretOptions<I, E> = ({
465
- strategy: "once";
466
- retry?: RetryOptions<E>;
467
- } & WithTimeout<E>) | ({
468
- strategy: "restartable";
469
- retry?: RetryOptions<E>;
470
- } & WithMinInterval & WithTimeout<E>) | ({
471
- strategy: "exclusive";
472
- retry?: RetryOptions<E>;
473
- } & WithCooldown & WithTimeout<E>) | ({
474
- strategy: "queue";
475
- retry?: RetryOptions<E>;
476
- maxSize?: number;
477
- overflow?: "drop" | "replace-last";
478
- dedupe?: (a: I, b: I) => boolean;
479
- } & WithConcurrency & WithTimeout<E>) | ({
480
- strategy: "buffered";
481
- retry?: RetryOptions<E>;
482
- } & WithSize & WithTimeout<E>) | ({
483
- strategy: "debounced";
484
- retry?: RetryOptions<E>;
485
- leading?: true;
486
- maxWait?: Duration;
487
- } & WithDuration & WithTimeout<E>) | ({
488
- strategy: "throttled";
489
- retry?: RetryOptions<E>;
490
- trailing?: true;
491
- } & WithDuration & WithTimeout<E>) | ({
492
- strategy: "concurrent";
493
- retry?: RetryOptions<E>;
494
- overflow?: "queue" | "drop";
495
- } & WithN & WithTimeout<E>) | ({
496
- strategy: "keyed";
497
- perKey?: "exclusive" | "restartable";
498
- key: (input: I) => unknown;
499
- } & WithTimeout<E>);
500
- type KeyType<I, O> = O extends {
501
- key: (input: I) => infer K;
502
- } ? K : unknown;
503
- type InterpretResult<I, E, A, O> = [O] extends [{
504
- strategy: "throttled";
505
- trailing: true;
506
- }] ? Op.Manager<I, E, A, Op.ThrottledTrailingState<E, A> | MaybeRetry<E, O>> : [O] extends [{
507
- strategy: "throttled";
508
- }] ? Op.Manager<I, E, A, Op.ThrottledState<E, A> | MaybeRetry<E, O>> : [O] extends [{
509
- strategy: "debounced";
510
- }] ? Op.Manager<I, E, A, Op.DebouncedState<E, A> | MaybeRetry<E, O>> : [O] extends [{
511
- strategy: "concurrent";
512
- overflow: "queue";
513
- }] ? Op.Manager<I, E, A, Op.ConcurrentQueueState<E, A> | MaybeRetry<E, O>> : [O] extends [{
514
- strategy: "concurrent";
515
- }] ? Op.Manager<I, E, A, Op.ConcurrentDropState<E, A> | MaybeRetry<E, O>> : [O] extends [{
516
- strategy: "keyed";
517
- perKey: "restartable";
518
- }] ? Op.KeyedManager<I, KeyType<I, O>, E, Op.KeyedRestartablePerKey<E, A>> : [O] extends [{
519
- strategy: "keyed";
520
- }] ? Op.KeyedManager<I, KeyType<I, O>, E, Op.KeyedExclusivePerKey<E, A>> : [O] extends [{
521
- strategy: "once";
522
- }] ? Op.Manager<I, E, A, Op.OnceState<E, A> | MaybeRetry<E, O>> : [O] extends [{
523
- strategy: "restartable";
524
- }] ? Op.Manager<I, E, A, Op.RestartableState<E, A> | MaybeRetry<E, O>> : [O] extends [{
525
- strategy: "exclusive";
526
- }] ? Op.Manager<I, E, A, Op.ExclusiveState<E, A> | MaybeRetry<E, O>> : [O] extends [{
527
- strategy: "queue";
528
- overflow: "replace-last";
529
- dedupe: (a: I, b: I) => boolean;
530
- }] ? Op.Manager<I, E, A, Op.QueueDropAndReplaceState<E, A> | MaybeRetry<E, O>> : [O] extends [{
531
- strategy: "queue";
532
- overflow: "replace-last";
533
- }] ? Op.Manager<I, E, A, Op.QueueReplaceState<E, A> | MaybeRetry<E, O>> : [O] extends [{
534
- strategy: "queue";
535
- maxSize: number;
536
- }] ? Op.Manager<I, E, A, Op.QueueDropState<E, A> | MaybeRetry<E, O>> : [O] extends [{
537
- strategy: "queue";
538
- dedupe: (a: I, b: I) => boolean;
539
- }] ? Op.Manager<I, E, A, Op.QueueDropState<E, A> | MaybeRetry<E, O>> : [O] extends [{
540
- strategy: "queue";
541
- }] ? Op.Manager<I, E, A, Op.QueueState<E, A> | MaybeRetry<E, O>> : [O] extends [{
542
- strategy: "buffered";
543
- }] ? Op.Manager<I, E, A, Op.BufferedState<E, A> | MaybeRetry<E, O>> : never;
544
- declare function interpretFn<I, E, A, O extends AllInterpretOptions<I, E>>(op: Op<I, E, A>, options: O): InterpretResult<I, E, A, O>;
545
- /**
546
- * A reusable description of async work — decoupled from execution strategy and lifetime.
547
- *
548
- * Separate concerns:
549
- * - **What** to do: encoded in the `Op` via `Op.create`
550
- * - **How** to execute: chosen at `Op.interpret` time (restartable, exclusive, queue, etc.)
551
- *
552
- * An `Op` never runs on its own. It only executes when passed to `Op.interpret`, which
553
- * attaches a concurrency strategy and returns a `Manager` that owns the execution.
554
- *
555
- * @example
556
- * ```ts
557
- * const fetchUser = Op.create(
558
- * (signal) => (id: string) =>
559
- * fetch(`/users/${id}`, { signal }).then(r => {
560
- * if (!r.ok) throw new Error(`${r.status} ${r.statusText}`);
561
- * return r.json() as Promise<User>;
562
- * }),
563
- * (e) => new ApiError(e),
564
- * );
565
- *
566
- * const manager = Op.interpret(fetchUser, { strategy: "restartable" });
567
- * manager.subscribe(state => {
568
- * if (Op.isPending(state)) showSpinner();
569
- * if (Op.isOk(state)) render(state.value);
570
- * if (Op.isErr(state)) showError(state.error);
571
- * if (Op.isNil(state)) resetUI();
572
- * });
573
- * manager.run(userId);
574
- * ```
575
- */
576
- type Op<I, E, A> = {
577
- /**
578
- * @internal — Used by `Op.interpret`. Do not call directly.
579
- * Returns `null` when the operation was aborted (signal fired before factory resolved).
580
- */
581
- readonly _factory: (input: I, signal: AbortSignal) => Deferred<Result<E, A> | null>;
582
- };
583
- declare const Op: {
584
- nil: (reason: Op.NilReason) => Op.Nil;
585
- create: <E, A, I = void>(factory: (signal: AbortSignal) => (input: I) => Promise<A>, onError: (e: unknown) => E) => Op<I, E, A>;
586
- lift: <I, A>(f: (input: I, signal: AbortSignal) => Promise<A>) => Op<I, unknown, A>;
587
- ok: <A>(value: A) => Op.Ok<A>;
588
- err: <E>(error: E) => Op.Err<E>;
589
- isIdle: <E, A>(state: Op.State<E, A>) => state is Op.Idle;
590
- isPending: <E, A>(state: Op.State<E, A>) => state is Op.Pending;
591
- isQueued: <E, A>(state: Op.State<E, A>) => state is Op.Queued;
592
- isRetrying: <E, A>(state: Op.State<E, A>) => state is Op.Retrying<E>;
593
- isOk: <E, A>(state: Op.State<E, A>) => state is Op.Ok<A>;
594
- isErr: <E, A>(state: Op.State<E, A>) => state is Op.Err<E>;
595
- isNil: <E, A>(state: Op.State<E, A>) => state is Op.Nil;
596
- match: <E, A, B>(cases: {
597
- ok: (a: A) => B;
598
- err: (e: E) => B;
599
- nil: () => B;
600
- }) => (outcome: Op.Outcome<E, A>) => B;
601
- fold: <E, A, B>(onErr: (e: E) => B, onNil: () => B, onOk: (a: A) => B) => (outcome: Op.Outcome<E, A>) => B;
602
- getOrElse: <E, A, B>(defaultValue: () => B) => (outcome: Op.Outcome<E, A>) => A | B;
603
- map: <E, A, B>(f: (a: A) => B) => (outcome: Op.Outcome<E, A>) => Op.Outcome<E, B>;
604
- mapError: <E, F, A>(f: (e: E) => F) => (outcome: Op.Outcome<E, A>) => Op.Outcome<F, A>;
605
- chain: <E, A, B>(f: (a: A) => Op.Outcome<E, B>) => (outcome: Op.Outcome<E, A>) => Op.Outcome<E, B>;
606
- tap: <E, A>(f: (a: A) => void) => (outcome: Op.Outcome<E, A>) => Op.Outcome<E, A>;
607
- recover: <E, A, B>(f: (e: E) => Op.Outcome<E, B>) => (outcome: Op.Outcome<E, A>) => Op.Outcome<E, A | B>;
608
- to: {
609
- Result: <E, A>(onNil: () => E) => (outcome: Op.Outcome<E, A>) => Result<E, A>;
610
- Maybe: <E, A>(outcome: Op.Outcome<E, A>) => Maybe<A>;
611
- };
612
- all: <E, A>(invocations: ReadonlyArray<Deferred<Op.Outcome<E, A>>>) => Deferred<ReadonlyArray<Op.Outcome<E, A>>>;
613
- race: <E, A>(invocations: ReadonlyArray<Deferred<Op.Outcome<E, A>>>) => Deferred<Op.Outcome<E, A>>;
614
- wire: <I, E, A, S extends Op.State<E, A>>(source: Op.Manager<I, E, A, S>, f: (a: A) => void) => () => void;
615
- interpret: typeof interpretFn;
616
- };
617
- declare namespace Op {
618
- type Outcome<E, A> = Ok<A> | Err<E> | Nil;
619
- type Ok<A> = WithKind<"OpOk"> & WithValue<A>;
620
- type Err<E> = WithKind<"OpErr"> & WithError<E>;
621
- type Nil = WithKind<"OpNil"> & {
622
- readonly reason: NilReason;
623
- };
624
- type NilReason = "aborted" | "dropped" | "replaced" | "evicted";
625
- type AbortedNil = Nil & {
626
- readonly reason: "aborted";
627
- };
628
- type DroppedNil = Nil & {
629
- readonly reason: "dropped";
630
- };
631
- type ReplacedNil = Nil & {
632
- readonly reason: "replaced";
633
- };
634
- type EvictedNil = Nil & {
635
- readonly reason: "evicted";
636
- };
637
- type State<E, A> = Idle | Pending | Queued | Retrying<E> | Outcome<E, A>;
638
- type Idle = WithKind<"Idle">;
639
- type Pending = WithKind<"Pending">;
640
- type Queued = WithKind<"Queued"> & {
641
- readonly position: number;
642
- };
643
- type Retrying<E> = WithKind<"Retrying"> & {
644
- readonly attempt: number;
645
- readonly lastError: E;
646
- readonly nextRetryIn?: number;
647
- };
648
- type Manager<I, E, A, S extends State<E, A>> = {
649
- readonly state: S;
650
- run: (input: I) => Deferred<Exclude<S, Idle | Pending | Queued | Retrying<E>>>;
651
- abort: () => void;
652
- subscribe: (cb: (state: S) => void) => () => void;
653
- reset: () => void;
654
- poll: (input: I, options: {
655
- interval: Duration;
656
- }) => () => void;
657
- };
658
- type KeyedManager<I, K, E, PerKeyS> = {
659
- readonly state: ReadonlyMap<K, PerKeyS>;
660
- run: (input: I) => Deferred<Exclude<PerKeyS, Pending | Retrying<E>>>;
661
- abort: (key?: K) => void;
662
- subscribe: (cb: (state: ReadonlyMap<K, PerKeyS>) => void) => () => void;
663
- reset: () => void;
664
- poll: (input: I, options: {
665
- interval: Duration;
666
- }) => () => void;
667
- };
668
- type OnceState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | DroppedNil;
669
- type RetryableOnceState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | DroppedNil;
670
- type RestartableState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | ReplacedNil;
671
- type RetryableRestartableState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | ReplacedNil;
672
- type ExclusiveState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | DroppedNil;
673
- type RetryableExclusiveState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | DroppedNil;
674
- type QueueState<E, A> = Idle | Pending | Queued | Ok<A> | Err<E> | AbortedNil;
675
- type RetryableQueueState<E, A> = Idle | Pending | Queued | Retrying<E> | Ok<A> | Err<E> | AbortedNil;
676
- type QueueDropState<E, A> = Idle | Pending | Queued | Ok<A> | Err<E> | AbortedNil | DroppedNil;
677
- type RetryableQueueDropState<E, A> = Idle | Pending | Queued | Retrying<E> | Ok<A> | Err<E> | AbortedNil | DroppedNil;
678
- type QueueReplaceState<E, A> = Idle | Pending | Queued | Ok<A> | Err<E> | AbortedNil | EvictedNil;
679
- type RetryableQueueReplaceState<E, A> = Idle | Pending | Queued | Retrying<E> | Ok<A> | Err<E> | AbortedNil | EvictedNil;
680
- type QueueDropAndReplaceState<E, A> = Idle | Pending | Queued | Ok<A> | Err<E> | AbortedNil | DroppedNil | EvictedNil;
681
- type RetryableQueueDropAndReplaceState<E, A> = Idle | Pending | Queued | Retrying<E> | Ok<A> | Err<E> | AbortedNil | DroppedNil | EvictedNil;
682
- type BufferedState<E, A> = Idle | Pending | Queued | Ok<A> | Err<E> | AbortedNil | EvictedNil;
683
- type RetryableBufferedState<E, A> = Idle | Pending | Queued | Retrying<E> | Ok<A> | Err<E> | AbortedNil | EvictedNil;
684
- type DebouncedState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | EvictedNil;
685
- type RetryableDebouncedState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | EvictedNil;
686
- type ThrottledState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | DroppedNil;
687
- type RetryableThrottledState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | DroppedNil;
688
- type ThrottledTrailingState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | EvictedNil;
689
- type RetryableThrottledTrailingState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | EvictedNil;
690
- type ConcurrentQueueState<E, A> = Idle | Pending | Queued | Ok<A> | Err<E> | AbortedNil;
691
- type RetryableConcurrentQueueState<E, A> = Idle | Pending | Queued | Retrying<E> | Ok<A> | Err<E> | AbortedNil;
692
- type ConcurrentDropState<E, A> = Idle | Pending | Ok<A> | Err<E> | AbortedNil | DroppedNil;
693
- type RetryableConcurrentDropState<E, A> = Idle | Pending | Retrying<E> | Ok<A> | Err<E> | AbortedNil | DroppedNil;
694
- type KeyedExclusivePerKey<E, A> = Pending | Ok<A> | Err<E> | AbortedNil | DroppedNil;
695
- type KeyedRestartablePerKey<E, A> = Pending | Ok<A> | Err<E> | AbortedNil | ReplacedNil;
696
- type RetryOptions<E> = RetryOptions<E>;
697
- type TimeoutOptions<E> = TimeoutOptions<E>;
698
- }
699
-
700
- /** Keys of T for which undefined is assignable (i.e. optional fields). */
701
- type OptionalKeys<T> = {
702
- [K in keyof T]-?: undefined extends T[K] ? K : never;
703
- }[keyof T];
704
- /**
705
- * Optional<S, A> focuses on a value A inside a structure S that may or may
706
- * not be present. Like a Lens, but get returns Maybe<A>.
707
- *
708
- * Compose with other Optionals via `andThen`, or with a Lens via `andThenLens`.
709
- * Convert a Lens to an Optional with `Lens.toOptional`.
710
- *
711
- * @example
712
- * ```ts
713
- * type Profile = { username: string; bio?: string };
714
- *
715
- * const bioOpt = Optional.from.property<Profile>()("bio");
716
- *
717
- * pipe(profile, Optional.get(bioOpt)); // Some("hello") or None
718
- * pipe(profile, Optional.set(bioOpt)("hello")); // new Profile with bio set
719
- * pipe(profile, Optional.modify(bioOpt)(s => s + "!")); // appends if present
720
- * ```
721
- */
722
- type Optional<S, A> = {
723
- readonly get: (s: S) => Maybe<A>;
724
- readonly set: (a: A) => (s: S) => S;
725
- };
726
- declare const Optional: {
727
- from: {
728
- /**
729
- * Constructs an Optional from a getter (returning Maybe<A>) and a setter.
730
- *
731
- * @example
732
- * ```ts
733
- * const firstChar = Optional.from.accessors(
734
- * (s: string) => s.length > 0 ? Maybe.make.some(s[0]) : Maybe.make.none(),
735
- * (c) => (s) => s.length > 0 ? c + s.slice(1) : s,
736
- * );
737
- * ```
738
- */
739
- accessors: <S, A>(get: (s: S) => Maybe<A>, set: (a: A) => (s: S) => S) => Optional<S, A>;
740
- /**
741
- * Creates an Optional that focuses on an optional property of an object.
742
- * Only keys whose type includes undefined (i.e. `field?: T`) are accepted.
743
- * Call with the structure type first, then the key.
744
- *
745
- * @example
746
- * ```ts
747
- * type Profile = { username: string; bio?: string };
748
- * const bioOpt = Optional.from.property<Profile>()("bio");
749
- * ```
750
- */
751
- property: <S>() => <K extends OptionalKeys<S>>(key: K) => Optional<S, NonNullable<S[K]>>;
752
- };
753
- /**
754
- * Creates an Optional that focuses on an element at a given index in an array.
755
- * Returns None when the index is out of bounds; set is a no-op when out of bounds.
756
- *
757
- * @example
758
- * ```ts
759
- * const firstItem = Optional.index<string>(0);
760
- *
761
- * pipe(["a", "b"], Optional.get(firstItem)); // Some("a")
762
- * pipe([], Optional.get(firstItem)); // None
763
- * ```
764
- */
765
- index: <A>(i: number) => Optional<A[], A>;
766
- /**
767
- * Reads the focused value from a structure, returning Maybe<A>.
768
- *
769
- * @example
770
- * ```ts
771
- * pipe(profile, Optional.get(bioOpt)); // Some("...") or None
772
- * ```
773
- */
774
- get: <S, A>(opt: Optional<S, A>) => (s: S) => Maybe<A>;
775
- /**
776
- * Replaces the focused value within a structure.
777
- * For indexed focuses, this is a no-op when the index is out of bounds.
778
- *
779
- * @example
780
- * ```ts
781
- * pipe(profile, Optional.set(bioOpt)("hello"));
782
- * ```
783
- */
784
- set: <S, A>(opt: Optional<S, A>) => (a: A) => (s: S) => S;
785
- /**
786
- * Applies a function to the focused value if it is present; returns the
787
- * structure unchanged if the focus is absent.
788
- *
789
- * @example
790
- * ```ts
791
- * pipe(profile, Optional.modify(bioOpt)(s => s.toUpperCase()));
792
- * ```
793
- */
794
- modify: <S, A>(opt: Optional<S, A>) => (f: (a: A) => A) => (s: S) => S;
795
- /**
796
- * Returns the focused value or a default when the focus is absent.
797
- *
798
- * @example
799
- * ```ts
800
- * pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
801
- * ```
802
- */
803
- getOrElse: <S, A>(opt: Optional<S, A>) => (defaultValue: () => A) => (s: S) => A;
804
- /**
805
- * Extracts a value from an Optional focus using handlers for the present
806
- * and absent cases.
807
- *
808
- * @example
809
- * ```ts
810
- * pipe(profile, Optional.fold(bioOpt)(() => "no bio", (bio) => bio.toUpperCase()));
811
- * ```
812
- */
813
- fold: <S, A>(opt: Optional<S, A>) => <B>(onNone: () => B, onSome: (a: A) => B) => (s: S) => B;
814
- /**
815
- * Pattern matches on an Optional focus using a named-case object.
816
- *
817
- * @example
818
- * ```ts
819
- * pipe(
820
- * profile,
821
- * Optional.match(bioOpt)({ none: () => "no bio", some: (bio) => bio }),
822
- * );
823
- * ```
824
- */
825
- match: <S, A>(opt: Optional<S, A>) => <B>(cases: {
826
- none: () => B;
827
- some: (a: A) => B;
828
- }) => (s: S) => B;
829
- /**
830
- * Composes two Optionals: focuses through the outer, then through the inner.
831
- * Returns None if either focus is absent.
832
- *
833
- * @example
834
- * ```ts
835
- * const deepOpt = pipe(
836
- * Optional.from.property<User>()("address"),
837
- * Optional.andThen(Optional.from.property<Address>()("landmark")),
838
- * );
839
- * ```
840
- */
841
- andThen: <A, B>(inner: Optional<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
842
- /**
843
- * Composes an Optional with a Lens, producing an Optional.
844
- * The Lens focuses within the value found by the Optional.
845
- *
846
- * @example
847
- * ```ts
848
- * const cityOpt = pipe(
849
- * Optional.from.property<User>()("address"),
850
- * Optional.andThenLens(Lens.from.property<Address>()("city")),
851
- * );
852
- * ```
853
- */
854
- andThenLens: <A, B>(inner: Lens<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
855
- };
856
-
857
- /**
858
- * Pair<A, B> represents a pair of two values that are always both present.
859
- * It is a typed alias for `readonly [A, B]`.
860
- *
861
- * Use Pair when two values always travel together through a pipeline and you
862
- * want to transform either or both sides without destructuring.
863
- *
864
- * @example
865
- * ```ts
866
- * import { Pair } from "@nlozgachev/pipelined/core";
867
- * import { pipe } from "@nlozgachev/pipelined/composition";
868
- *
869
- * const entry = Pair.from.pair("alice", 42);
870
- *
871
- * pipe(
872
- * entry,
873
- * Pair.mapFirst((name) => name.toUpperCase()),
874
- * Pair.mapSecond((score) => score * 2),
875
- * Pair.fold((name, score) => `${name}: ${score}`),
876
- * ); // "ALICE: 84"
877
- * ```
878
- */
879
- type Pair<A, B> = readonly [A, B];
880
- declare const Pair: {
881
- from: {
882
- /**
883
- * Creates a Pair from two values.
884
- *
885
- * @example
886
- * ```ts
887
- * Pair.from.pair("Paris", 2_161_000); // ["Paris", 2161000]
888
- * ```
889
- */
890
- pair: <A, B>(first: A, second: B) => Pair<A, B>;
891
- /**
892
- * Creates a Pair from a two-element array.
893
- *
894
- * @example
895
- * ```ts
896
- * Pair.from.array(["Paris", 2_161_000] as const); // ["Paris", 2161000]
897
- * ```
898
- */
899
- array: <A, B>(arr: readonly [A, B]) => Pair<A, B>;
900
- };
901
- /**
902
- * Returns the first value from the pair.
903
- *
904
- * @example
905
- * ```ts
906
- * Pair.first(Pair.from.pair("Paris", 2_161_000)); // "Paris"
907
- * ```
908
- */
909
- first: <A, B>(p: Pair<A, B>) => A;
910
- /**
911
- * Returns the second value from the pair.
912
- *
913
- * @example
914
- * ```ts
915
- * Pair.second(Pair.from.pair("Paris", 2_161_000)); // 2161000
916
- * ```
917
- */
918
- second: <A, B>(p: Pair<A, B>) => B;
919
- /**
920
- * Transforms the first value, leaving the second unchanged.
921
- *
922
- * @example
923
- * ```ts
924
- * pipe(Pair.from.pair("alice", 42), Pair.mapFirst((s) => s.toUpperCase())); // ["ALICE", 42]
925
- * ```
926
- */
927
- mapFirst: <A, C>(f: (a: A) => C) => <B>(p: Pair<A, B>) => Pair<C, B>;
928
- /**
929
- * Transforms the second value, leaving the first unchanged.
930
- *
931
- * @example
932
- * ```ts
933
- * pipe(Pair.from.pair("alice", 42), Pair.mapSecond((n) => n * 2)); // ["alice", 84]
934
- * ```
935
- */
936
- mapSecond: <B, D>(f: (b: B) => D) => <A>(p: Pair<A, B>) => Pair<A, D>;
937
- /**
938
- * Transforms both values independently in a single step.
939
- *
940
- * @example
941
- * ```ts
942
- * pipe(
943
- * Pair.from.pair("alice", 42),
944
- * Pair.mapBoth(
945
- * (name) => name.toUpperCase(),
946
- * (score) => score * 2,
947
- * ),
948
- * ); // ["ALICE", 84]
949
- * ```
950
- */
951
- mapBoth: <A, C, B, D>(onFirst: (a: A) => C, onSecond: (b: B) => D) => (p: Pair<A, B>) => Pair<C, D>;
952
- /**
953
- * Applies a binary function to both values, collapsing the pair into a single value.
954
- * Useful as the final step when consuming a pair in a pipeline.
955
- *
956
- * @example
957
- * ```ts
958
- * pipe(Pair.from.pair("Alice", 100), Pair.fold((name, score) => `${name}: ${score}`));
959
- * // "Alice: 100"
960
- * ```
961
- */
962
- fold: <A, B, C>(f: (a: A, b: B) => C) => (p: Pair<A, B>) => C;
963
- /**
964
- * Swaps the two values: `[A, B]` becomes `[B, A]`.
965
- *
966
- * @example
967
- * ```ts
968
- * Pair.swap(Pair.from.pair("key", 1)); // [1, "key"]
969
- * ```
970
- */
971
- swap: <A, B>(p: Pair<A, B>) => Pair<B, A>;
972
- to: {
973
- /**
974
- * Converts the pair to a heterogeneous readonly array `readonly (A | B)[]`.
975
- *
976
- * @example
977
- * ```ts
978
- * Pair.to.Array(Pair.from.pair("hello", 42)); // ["hello", 42]
979
- * ```
980
- */
981
- Array: <A, B>(p: Pair<A, B>) => readonly (A | B)[];
982
- };
983
- /**
984
- * Runs a side effect with both values without changing the pair.
985
- * Useful for logging or debugging in the middle of a pipeline.
986
- *
987
- * @example
988
- * ```ts
989
- * pipe(
990
- * Pair.from.pair("Paris", 2_161_000),
991
- * Pair.tap((city, pop) => console.log(`${city}: ${pop}`)),
992
- * Pair.mapSecond((n) => n / 1_000_000),
993
- * ); // logs "Paris: 2161000", returns ["Paris", 2.161]
994
- * ```
995
- */
996
- tap: <A, B>(f: (a: A, b: B) => void) => (p: Pair<A, B>) => Pair<A, B>;
997
- };
998
-
999
- /**
1000
- * A boolean-valued function over a type `A`.
1001
- *
1002
- * A `Predicate<A>` is the simpler sibling of `Refinement<A, B>`: it tests whether a
1003
- * value satisfies a condition at runtime but carries no compile-time narrowing guarantee.
1004
- * Use it when you need to combine, negate, or adapt boolean checks as first-class values
1005
- * and do not require the extra type information that a `Refinement` provides.
1006
- *
1007
- * Every `Refinement<A, B>` is a `Predicate<A>` — convert with `Predicate.from.Refinement`
1008
- * when you want to compose a narrowing check alongside plain predicates.
1009
- *
1010
- * @example
1011
- * ```ts
1012
- * const isAdult: Predicate<number> = n => n >= 18;
1013
- * const isRetired: Predicate<number> = n => n >= 65;
1014
- *
1015
- * const isWorkingAge: Predicate<number> = pipe(
1016
- * isAdult,
1017
- * Predicate.and(Predicate.not(isRetired))
1018
- * );
1019
- *
1020
- * isWorkingAge(30); // true
1021
- * isWorkingAge(15); // false
1022
- * isWorkingAge(70); // false
1023
- * ```
1024
- */
1025
- type Predicate<A> = (a: A) => boolean;
1026
- declare const Predicate: {
1027
- /**
1028
- * Negates a predicate: the result passes exactly when the original fails.
1029
- *
1030
- * @example
1031
- * ```ts
1032
- * const isBlank: Predicate<string> = s => s.trim().length === 0;
1033
- * const isNotBlank = Predicate.not(isBlank);
1034
- *
1035
- * isNotBlank("hello"); // true
1036
- * isNotBlank(" "); // false
1037
- * ```
1038
- */
1039
- not: <A>(p: Predicate<A>) => Predicate<A>;
1040
- /**
1041
- * Combines two predicates with logical AND: passes only when both hold.
1042
- *
1043
- * Data-last — the first predicate is the data being piped.
1044
- *
1045
- * @example
1046
- * ```ts
1047
- * const isPositive: Predicate<number> = n => n > 0;
1048
- * const isEven: Predicate<number> = n => n % 2 === 0;
1049
- *
1050
- * const isPositiveEven: Predicate<number> = pipe(isPositive, Predicate.and(isEven));
1051
- *
1052
- * isPositiveEven(4); // true
1053
- * isPositiveEven(3); // false — positive but odd
1054
- * isPositiveEven(-2); // false — even but not positive
1055
- * ```
1056
- */
1057
- and: <A>(second: Predicate<A>) => (first: Predicate<A>) => Predicate<A>;
1058
- /**
1059
- * Combines two predicates with logical OR: passes when either holds.
1060
- *
1061
- * Data-last — the first predicate is the data being piped.
1062
- *
1063
- * @example
1064
- * ```ts
1065
- * const isChild: Predicate<number> = n => n < 13;
1066
- * const isSenior: Predicate<number> = n => n >= 65;
1067
- *
1068
- * const getsDiscount: Predicate<number> = pipe(isChild, Predicate.or(isSenior));
1069
- *
1070
- * getsDiscount(8); // true
1071
- * getsDiscount(70); // true
1072
- * getsDiscount(30); // false
1073
- * ```
1074
- */
1075
- or: <A>(second: Predicate<A>) => (first: Predicate<A>) => Predicate<A>;
1076
- /**
1077
- * Adapts a `Predicate<A>` to work on a different input type `B` by applying `f`
1078
- * to extract the relevant `A` from a `B` before running the check.
1079
- *
1080
- * Data-last — the predicate is the data being piped; `f` is the extractor.
1081
- *
1082
- * @example
1083
- * ```ts
1084
- * type User = { name: string; age: number };
1085
- *
1086
- * const isAdult: Predicate<number> = n => n >= 18;
1087
- *
1088
- * // Lift isAdult to work on Users by extracting the age field
1089
- * const isAdultUser: Predicate<User> = pipe(
1090
- * isAdult,
1091
- * Predicate.using((u: User) => u.age)
1092
- * );
1093
- *
1094
- * isAdultUser({ name: "Alice", age: 30 }); // true
1095
- * isAdultUser({ name: "Bob", age: 15 }); // false
1096
- * ```
1097
- */
1098
- using: <A, B>(f: (b: B) => A) => (p: Predicate<A>) => Predicate<B>;
1099
- /**
1100
- * Combines an array of predicates with AND: passes only when every predicate holds.
1101
- * Returns `true` for an empty array (vacuous truth).
1102
- *
1103
- * @example
1104
- * ```ts
1105
- * const checks: Predicate<string>[] = [
1106
- * s => s.length > 0,
1107
- * s => s.length <= 100,
1108
- * s => !s.includes("<"),
1109
- * ];
1110
- *
1111
- * Predicate.all(checks)("hello"); // true
1112
- * Predicate.all(checks)(""); // false — too short
1113
- * Predicate.all(checks)("<b>"); // false — contains "<"
1114
- * Predicate.all([])("anything"); // true
1115
- * ```
1116
- */
1117
- all: <A>(predicates: ReadonlyArray<Predicate<A>>) => Predicate<A>;
1118
- /**
1119
- * Combines an array of predicates with OR: passes when at least one holds.
1120
- * Returns `false` for an empty array.
1121
- *
1122
- * @example
1123
- * ```ts
1124
- * const acceptedFormats: Predicate<string>[] = [
1125
- * s => s.endsWith(".jpg"),
1126
- * s => s.endsWith(".png"),
1127
- * s => s.endsWith(".webp"),
1128
- * ];
1129
- *
1130
- * Predicate.any(acceptedFormats)("photo.jpg"); // true
1131
- * Predicate.any(acceptedFormats)("photo.gif"); // false
1132
- * Predicate.any([])("anything"); // false
1133
- * ```
1134
- */
1135
- any: <A>(predicates: ReadonlyArray<Predicate<A>>) => Predicate<A>;
1136
- from: {
1137
- /**
1138
- * Converts a `Refinement<A, B>` into a `Predicate<A>`, discarding the compile-time
1139
- * narrowing. Use this when you want to combine a type guard with plain predicates
1140
- * using `and`, `or`, or `all`.
1141
- *
1142
- * This is a zero-cost runtime type cast.
1143
- *
1144
- * @example
1145
- * ```ts
1146
- * const isString: Refinement<unknown, string> =
1147
- * Refinement.from.predicate(x => typeof x === "string");
1148
- *
1149
- * const isShortString: Predicate<unknown> = pipe(
1150
- * Predicate.from.Refinement(isString),
1151
- * Predicate.and(x => (x as string).length < 10)
1152
- * );
1153
- *
1154
- * isShortString("hi"); // true
1155
- * isShortString("a very long string that exceeds ten characters"); // false
1156
- * isShortString(42); // false
1157
- * ```
1158
- */
1159
- Refinement: <A, B extends A>(r: Refinement<A, B>) => Predicate<A>;
1160
- };
1161
- /**
1162
- * Performs declarative conditional branching over `[predicate, handler]` pairs,
1163
- * returning the handler result of the first matching predicate or evaluating the fallback.
1164
- *
1165
- * @example
1166
- * ```ts
1167
- * const classifyNumber = Predicate.match(
1168
- * [
1169
- * [(n: number) => n < 0, () => "negative"],
1170
- * [(n: number) => n === 0, () => "zero"],
1171
- * ],
1172
- * () => "positive",
1173
- * );
1174
- * classifyNumber(-5); // "negative"
1175
- * ```
1176
- */
1177
- match: <A, B>(branches: ReadonlyArray<readonly [Predicate<A>, (a: A) => B]>, fallback: (a: A) => B) => (a: A) => B;
1178
- };
1179
-
1180
- /**
1181
- * A computation that reads from a shared environment `R` and produces a value `A`.
1182
- * Use Reader to thread a dependency (config, logger, DB pool) through a pipeline
1183
- * without passing it explicitly to every function.
1184
- *
1185
- * @example
1186
- * ```ts
1187
- * type Config = { baseUrl: string; apiKey: string };
1188
- *
1189
- * const buildUrl = (path: string): Reader<Config, string> =>
1190
- * (config) => `${config.baseUrl}${path}`;
1191
- *
1192
- * const withAuth = (url: string): Reader<Config, string> =>
1193
- * (config) => `${url}?key=${config.apiKey}`;
1194
- *
1195
- * const fetchEndpoint = (path: string): Reader<Config, string> =>
1196
- * pipe(
1197
- * buildUrl(path),
1198
- * Reader.chain(withAuth)
1199
- * );
1200
- *
1201
- * // Inject the config once at the edge
1202
- * fetchEndpoint("/users")(appConfig); // "https://api.example.com/users?key=secret"
1203
- * ```
1204
- */
1205
- type Reader<R, A> = (env: R) => A;
1206
- declare const Reader: {
1207
- /**
1208
- * Lifts a pure value into a Reader. The environment is ignored.
1209
- *
1210
- * @example
1211
- * ```ts
1212
- * const always42: Reader<Config, number> = Reader.resolve(42);
1213
- * always42(anyConfig); // 42
1214
- * ```
1215
- */
1216
- resolve: <R, A>(value: A) => Reader<R, A>;
1217
- /**
1218
- * Returns the full environment as the result.
1219
- * The fundamental way to access the environment in a pipeline.
1220
- *
1221
- * @example
1222
- * ```ts
1223
- * pipe(
1224
- * Reader.ask<Config>(),
1225
- * Reader.map(config => config.baseUrl)
1226
- * )(appConfig); // "https://api.example.com"
1227
- * ```
1228
- */
1229
- ask: <R>() => Reader<R, R>;
1230
- /**
1231
- * Projects a value from the environment using a selector function.
1232
- * Equivalent to `pipe(Reader.ask(), Reader.map(f))` but more direct.
1233
- *
1234
- * @example
1235
- * ```ts
1236
- * const getBaseUrl: Reader<Config, string> = Reader.asks(c => c.baseUrl);
1237
- * getBaseUrl(appConfig); // "https://api.example.com"
1238
- * ```
1239
- */
1240
- asks: <R, A>(f: (env: R) => A) => Reader<R, A>;
1241
- /**
1242
- * Transforms the value produced by a Reader.
1243
- *
1244
- * @example
1245
- * ```ts
1246
- * pipe(
1247
- * Reader.asks((c: Config) => c.baseUrl),
1248
- * Reader.map(url => url.toUpperCase())
1249
- * )(appConfig); // "HTTPS://API.EXAMPLE.COM"
1250
- * ```
1251
- */
1252
- map: <R, A, B>(f: (a: A) => B) => (data: Reader<R, A>) => Reader<R, B>;
1253
- /**
1254
- * Sequences two Readers. Both see the same environment.
1255
- * The output of the first is passed to `f`, which returns the next Reader.
1256
- *
1257
- * @example
1258
- * ```ts
1259
- * const buildUrl = (path: string): Reader<Config, string> =>
1260
- * Reader.asks(c => `${c.baseUrl}${path}`);
1261
- *
1262
- * const addAuth = (url: string): Reader<Config, string> =>
1263
- * Reader.asks(c => `${url}?key=${c.apiKey}`);
1264
- *
1265
- * pipe(
1266
- * buildUrl("/items"),
1267
- * Reader.chain(addAuth)
1268
- * )(appConfig); // "https://api.example.com/items?key=secret"
1269
- * ```
1270
- */
1271
- chain: <R, A, B>(f: (a: A) => Reader<R, B>) => (data: Reader<R, A>) => Reader<R, B>;
1272
- /**
1273
- * Applies a function wrapped in a Reader to a value wrapped in a Reader.
1274
- * Both Readers see the same environment.
1275
- *
1276
- * @example
1277
- * ```ts
1278
- * const add = (a: number) => (b: number) => a + b;
1279
- * pipe(
1280
- * Reader.resolve<Config, typeof add>(add),
1281
- * Reader.ap(Reader.asks(c => c.timeout)),
1282
- * Reader.ap(Reader.resolve(5))
1283
- * )(appConfig);
1284
- * ```
1285
- */
1286
- ap: <R, A>(arg: Reader<R, A>) => <B>(data: Reader<R, (a: A) => B>) => Reader<R, B>;
1287
- /**
1288
- * Executes a side effect on the produced value without changing the Reader.
1289
- * Useful for logging or debugging inside a pipeline.
1290
- *
1291
- * @example
1292
- * ```ts
1293
- * pipe(
1294
- * buildUrl("/users"),
1295
- * Reader.tap(url => console.log("Requesting:", url)),
1296
- * Reader.chain(addAuth)
1297
- * )(appConfig);
1298
- * ```
1299
- */
1300
- tap: <R, A>(f: (a: A) => void) => (data: Reader<R, A>) => Reader<R, A>;
1301
- /**
1302
- * Adapts a Reader to work with a different (typically wider) environment
1303
- * by transforming the environment before passing it to the Reader.
1304
- * This lets you compose Readers that expect different environments.
1305
- *
1306
- * @example
1307
- * ```ts
1308
- * type AppEnv = { db: DbPool; config: Config; logger: Logger };
1309
- *
1310
- * // buildUrl only needs Config
1311
- * const buildUrl: Reader<Config, string> = Reader.asks(c => c.baseUrl);
1312
- *
1313
- * // Zoom in from AppEnv to Config
1314
- * const buildUrlFromApp: Reader<AppEnv, string> =
1315
- * pipe(buildUrl, Reader.local((env: AppEnv) => env.config));
1316
- *
1317
- * buildUrlFromApp(appEnv); // works with the full AppEnv
1318
- * ```
1319
- */
1320
- local: <R2, R>(f: (env: R2) => R) => <A>(data: Reader<R, A>) => Reader<R2, A>;
1321
- /**
1322
- * Runs a Reader by supplying the environment. Use this at the edge of your
1323
- * program where the environment is available.
1324
- *
1325
- * @example
1326
- * ```ts
1327
- * pipe(
1328
- * buildEndpoint("/users"),
1329
- * Reader.run(appConfig)
1330
- * ); // "https://api.example.com/users?key=secret"
1331
- * ```
1332
- */
1333
- run: <R>(env: R) => <A>(data: Reader<R, A>) => A;
1334
- /**
1335
- * Lifts a Reader value into an accumulator object.
1336
- *
1337
- * @example
1338
- * ```ts
1339
- * pipe(Reader.resolve(42), Reader.bindTo("value")); // Reader({ value: 42 })
1340
- * ```
1341
- */
1342
- bindTo: <K extends string>(key: K) => <R, A>(data: Reader<R, A>) => Reader<R, { [P in K]: A; }>;
1343
- /**
1344
- * Evaluates a new Reader using the current accumulator and attaches the output to a new key.
1345
- *
1346
- * @example
1347
- * ```ts
1348
- * pipe(
1349
- * Reader.resolve({ a: 1 }),
1350
- * Reader.bind("b", ({ a }) => Reader.resolve(a + 1))
1351
- * ); // Reader({ a: 1, b: 2 })
1352
- * ```
1353
- */
1354
- bind: <K extends string, R, A, B>(key: K, f: (a: A) => Reader<R, B>) => (data: Reader<R, A>) => Reader<R, A & { [P in K]: B; }>;
1355
- };
1356
-
1357
- /**
1358
- * A function from `A` to `A is B` — a type predicate paired with a runtime check.
1359
- *
1360
- * A `Refinement<A, B>` proves at compile time that a value of type `A` is actually
1361
- * the narrower type `B extends A`, backed by a runtime boolean test. Use it to
1362
- * express domain invariants (non-empty strings, positive numbers, valid emails) as
1363
- * first-class, composable values rather than one-off type guards scattered across
1364
- * the codebase.
1365
- *
1366
- * @example
1367
- * ```ts
1368
- * type NonEmptyString = string & { readonly _tag: "NonEmptyString" };
1369
- *
1370
- * const isNonEmpty: Refinement<string, NonEmptyString> =
1371
- * Refinement.from.predicate(s => s.length > 0);
1372
- *
1373
- * pipe(
1374
- * "hello",
1375
- * Refinement.to.Maybe(isNonEmpty)
1376
- * ); // Some("hello")
1377
- * ```
1378
- */
1379
- type Refinement<A, B extends A> = (a: A) => a is B;
1380
- declare const Refinement: {
1381
- from: {
1382
- /**
1383
- * Creates a `Refinement<A, B>` from a plain boolean predicate.
1384
- *
1385
- * This is an unsafe cast — the caller is responsible for ensuring that the
1386
- * predicate truly characterises values of type `B`. Use this only when
1387
- * bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
1388
- * derived refinements from existing ones.
1389
- *
1390
- * @example
1391
- * ```ts
1392
- * type PositiveNumber = number & { readonly _tag: "PositiveNumber" };
1393
- *
1394
- * const isPositive: Refinement<number, PositiveNumber> =
1395
- * Refinement.from.predicate(n => n > 0);
1396
- * ```
1397
- */
1398
- predicate: <A, B extends A>(f: (a: A) => boolean) => Refinement<A, B>;
1399
- };
1400
- /**
1401
- * Chains two refinements: if `ab` narrows `A` to `B` and `bc` narrows `B` to `C`,
1402
- * the result narrows `A` directly to `C`.
1403
- *
1404
- * Data-last — the first refinement `ab` is the data being piped.
1405
- *
1406
- * @example
1407
- * ```ts
1408
- * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
1409
- * type TrimmedString = NonEmptyString & { readonly _tag: "Trimmed" };
1410
- *
1411
- * const isNonEmpty: Refinement<string, NonEmptyString> =
1412
- * Refinement.from.predicate(s => s.length > 0);
1413
- * const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
1414
- * Refinement.from.predicate(s => s === s.trim());
1415
- *
1416
- * const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
1417
- * isNonEmpty,
1418
- * Refinement.compose(isTrimmed)
1419
- * );
1420
- * ```
1421
- */
1422
- compose: <A, B extends A, C extends B>(bc: Refinement<B, C>) => (ab: Refinement<A, B>) => Refinement<A, C>;
1423
- /**
1424
- * Intersects two refinements: the result narrows `A` to `B & C`, passing only
1425
- * when both refinements hold simultaneously.
1426
- *
1427
- * Data-last — the first refinement is the data being piped.
1428
- *
1429
- * @example
1430
- * ```ts
1431
- * const isString: Refinement<unknown, string> = Refinement.from.predicate(x => typeof x === "string");
1432
- * const isNonEmpty: Refinement<unknown, { length: number }> =
1433
- * Refinement.from.predicate(x => (x as any).length > 0);
1434
- *
1435
- * const isNonEmptyString = pipe(isString, Refinement.and(isNonEmpty));
1436
- * isNonEmptyString("hi"); // true
1437
- * isNonEmptyString(""); // false
1438
- * ```
1439
- */
1440
- and: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B & C>;
1441
- /**
1442
- * Unions two refinements: the result narrows `A` to `B | C`, passing when either
1443
- * refinement holds.
1444
- *
1445
- * Data-last — the first refinement is the data being piped.
1446
- *
1447
- * @example
1448
- * ```ts
1449
- * const isString: Refinement<unknown, string> = Refinement.from.predicate(x => typeof x === "string");
1450
- * const isNumber: Refinement<unknown, number> = Refinement.from.predicate(x => typeof x === "number");
1451
- *
1452
- * const isStringOrNumber = pipe(isString, Refinement.or(isNumber));
1453
- * isStringOrNumber("hi"); // true
1454
- * isStringOrNumber(42); // true
1455
- * isStringOrNumber(true); // false
1456
- * ```
1457
- */
1458
- or: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B | C>;
1459
- to: {
1460
- /**
1461
- * Converts a `Refinement<A, B>` into a function `(a: A) => Maybe<B>`.
1462
- *
1463
- * Returns `Some(a)` when the refinement holds, `None` otherwise. Useful for
1464
- * integrating runtime validation into a `Maybe`-based pipeline.
1465
- *
1466
- * @example
1467
- * ```ts
1468
- * type PositiveNumber = number & { readonly _tag: "Positive" };
1469
- * const isPositive: Refinement<number, PositiveNumber> =
1470
- * Refinement.from.predicate(n => n > 0);
1471
- *
1472
- * pipe(-1, Refinement.to.Maybe(isPositive)); // None
1473
- * pipe(42, Refinement.to.Maybe(isPositive)); // Some(42)
1474
- * ```
1475
- */
1476
- Maybe: <A, B extends A>(r: Refinement<A, B>) => (a: A) => Maybe<B>;
1477
- /**
1478
- * Converts a `Refinement<A, B>` into a function `(a: A) => Result<E, B>`.
1479
- *
1480
- * Returns `Ok(a)` when the refinement holds, `Err(onFail(a))` otherwise. Use
1481
- * this to surface validation failures as typed errors inside a `Result` pipeline.
1482
- *
1483
- * @example
1484
- * ```ts
1485
- * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
1486
- * const isNonEmpty: Refinement<string, NonEmptyString> =
1487
- * Refinement.from.predicate(s => s.length > 0);
1488
- *
1489
- * pipe("", Refinement.to.Result(isNonEmpty, () => "must not be empty")); // Err(...)
1490
- * pipe("hi", Refinement.to.Result(isNonEmpty, () => "must not be empty")); // Ok("hi")
1491
- * ```
1492
- */
1493
- Result: <A, B extends A, E>(r: Refinement<A, B>, onFail: (a: A) => E) => (a: A) => Result<E, B>;
1494
- };
1495
- };
1496
-
1497
- type NotAsked = WithKind<"NotAsked">;
1498
- type Loading = WithKind<"Loading">;
1499
- type Failure<E> = WithKind<"Failure"> & WithError<E>;
1500
- type Success<A> = WithKind<"Success"> & WithValue<A>;
1501
- /**
1502
- * RemoteData represents the state of an async data fetch.
1503
- * It has four states: NotAsked, Loading, Failure, and Success.
1504
- *
1505
- * Use RemoteData to model data fetching states explicitly,
1506
- * replacing the common `{ data: T | null; loading: boolean; error: Error | null }` pattern.
1507
- *
1508
- * @example
1509
- * ```ts
1510
- * const renderUser = pipe(
1511
- * userData,
1512
- * RemoteData.match({
1513
- * notAsked: () => "Click to load",
1514
- * loading: () => "Loading...",
1515
- * failure: e => `Error: ${e.message}`,
1516
- * success: user => `Hello, ${user.name}!`
1517
- * })
1518
- * );
1519
- * ```
1520
- */
1521
- type RemoteData<E, A> = NotAsked | Loading | Failure<E> | Success<A>;
1522
- declare const RemoteData: {
1523
- make: {
1524
- /**
1525
- * Creates a NotAsked RemoteData.
1526
- *
1527
- * @example
1528
- * ```ts
1529
- * RemoteData.make.notAsked(); // NotAsked
1530
- * ```
1531
- */
1532
- notAsked: () => NotAsked;
1533
- /**
1534
- * Creates a Loading RemoteData.
1535
- *
1536
- * @example
1537
- * ```ts
1538
- * RemoteData.make.loading(); // Loading
1539
- * ```
1540
- */
1541
- loading: () => Loading;
1542
- /**
1543
- * Creates a Failure RemoteData with the given error.
1544
- *
1545
- * @example
1546
- * ```ts
1547
- * RemoteData.make.failure("Network error"); // Failure("Network error")
1548
- * ```
1549
- */
1550
- failure: <E>(error: E) => Failure<E>;
1551
- /**
1552
- * Creates a Success RemoteData with the given value.
1553
- *
1554
- * @example
1555
- * ```ts
1556
- * RemoteData.make.success(42); // Success(42)
1557
- * ```
1558
- */
1559
- success: <A>(value: A) => Success<A>;
1560
- };
1561
- is: {
1562
- /**
1563
- * Type guard that checks if a RemoteData is NotAsked.
1564
- *
1565
- * @example
1566
- * ```ts
1567
- * const data = RemoteData.make.notAsked();
1568
- * if (RemoteData.is.notAsked(data)) {
1569
- * console.log("Data fetch not initiated");
1570
- * }
1571
- * ```
1572
- */
1573
- notAsked: <E, A>(data: RemoteData<E, A>) => data is NotAsked;
1574
- /**
1575
- * Type guard that checks if a RemoteData is Loading.
1576
- *
1577
- * @example
1578
- * ```ts
1579
- * const data = RemoteData.make.loading();
1580
- * if (RemoteData.is.loading(data)) {
1581
- * console.log("Data is loading");
1582
- * }
1583
- * ```
1584
- */
1585
- loading: <E, A>(data: RemoteData<E, A>) => data is Loading;
1586
- /**
1587
- * Type guard that checks if a RemoteData is Failure.
1588
- *
1589
- * @example
1590
- * ```ts
1591
- * const data = RemoteData.make.failure("Failed");
1592
- * if (RemoteData.is.failure(data)) {
1593
- * console.log(data.error); // "Failed"
1594
- * }
1595
- * ```
1596
- */
1597
- failure: <E, A>(data: RemoteData<E, A>) => data is Failure<E>;
1598
- /**
1599
- * Type guard that checks if a RemoteData is Success.
1600
- *
1601
- * @example
1602
- * ```ts
1603
- * const data = RemoteData.make.success(42);
1604
- * if (RemoteData.is.success(data)) {
1605
- * console.log(data.value); // 42
1606
- * }
1607
- * ```
1608
- */
1609
- success: <E, A>(data: RemoteData<E, A>) => data is Success<A>;
1610
- };
1611
- /**
1612
- * Transforms the success value inside a RemoteData.
1613
- *
1614
- * @example
1615
- * ```ts
1616
- * pipe(RemoteData.make.success(5), RemoteData.map(n => n * 2)); // Success(10)
1617
- * pipe(RemoteData.make.loading(), RemoteData.map(n => n * 2)); // Loading
1618
- * ```
1619
- */
1620
- map: <A, B>(f: (a: A) => B) => <E>(data: RemoteData<E, A>) => RemoteData<E, B>;
1621
- /**
1622
- * Transforms the error value inside a RemoteData.
1623
- *
1624
- * @example
1625
- * ```ts
1626
- * pipe(RemoteData.make.failure("oops"), RemoteData.mapError(e => e.toUpperCase())); // Failure("OOPS")
1627
- * ```
1628
- */
1629
- mapError: <E, F>(f: (e: E) => F) => <A>(data: RemoteData<E, A>) => RemoteData<F, A>;
1630
- /**
1631
- * Chains RemoteData computations. If the input is Success, passes the value to f.
1632
- * Otherwise, propagates the current state.
1633
- *
1634
- * @example
1635
- * ```ts
1636
- * pipe(
1637
- * RemoteData.make.success(5),
1638
- * RemoteData.chain(n => n > 0 ? RemoteData.make.success(n) : RemoteData.make.failure("negative"))
1639
- * );
1640
- * ```
1641
- */
1642
- chain: <E2, A, B>(f: (a: A) => RemoteData<E2, B>) => <E1 = never>(data: RemoteData<E1, A>) => RemoteData<E1 | E2, B>;
1643
- /**
1644
- * Applies a function wrapped in a RemoteData to a value wrapped in a RemoteData.
1645
- *
1646
- * @example
1647
- * ```ts
1648
- * const add = (a: number) => (b: number) => a + b;
1649
- * pipe(
1650
- * RemoteData.make.success(add),
1651
- * RemoteData.ap(RemoteData.make.success(5)),
1652
- * RemoteData.ap(RemoteData.make.success(3))
1653
- * ); // Success(8)
1654
- * ```
1655
- */
1656
- ap: <E, A>(arg: RemoteData<E, A>) => <B>(data: RemoteData<E, (a: A) => B>) => RemoteData<E, B>;
1657
- /**
1658
- * Extracts the value from a RemoteData by providing handlers for all four cases.
1659
- *
1660
- * @example
1661
- * ```ts
1662
- * pipe(
1663
- * userData,
1664
- * RemoteData.fold(
1665
- * e => `Error: ${e}`,
1666
- * () => "Not asked",
1667
- * () => "Loading...",
1668
- * value => `Got: ${value}`
1669
- * )
1670
- * );
1671
- * ```
1672
- */
1673
- fold: <E, A, B>(onFailure: (e: E) => B, onNotAsked: () => B, onLoading: () => B, onSuccess: (a: A) => B) => (data: RemoteData<E, A>) => B;
1674
- /**
1675
- * Pattern matches on a RemoteData, returning the result of the matching case.
1676
- *
1677
- * @example
1678
- * ```ts
1679
- * pipe(
1680
- * userData,
1681
- * RemoteData.match({
1682
- * notAsked: () => "Click to load",
1683
- * loading: () => "Loading...",
1684
- * failure: e => `Error: ${e}`,
1685
- * success: user => `Hello, ${user.name}!`
1686
- * })
1687
- * );
1688
- * ```
1689
- */
1690
- match: <E, A, B>(cases: {
1691
- notAsked: () => B;
1692
- loading: () => B;
1693
- failure: (e: E) => B;
1694
- success: (a: A) => B;
1695
- }) => (data: RemoteData<E, A>) => B;
1696
- /**
1697
- * Returns the success value or a default value if the RemoteData is not Success.
1698
- * The default can be a different type, widening the result to `A | B`.
1699
- *
1700
- * @example
1701
- * ```ts
1702
- * pipe(RemoteData.make.success(5), RemoteData.getOrElse(() => 0)); // 5
1703
- * pipe(RemoteData.make.loading(), RemoteData.getOrElse(() => 0)); // 0
1704
- * pipe(RemoteData.make.loading<string, number>(), RemoteData.getOrElse(() => null)); // null — typed as number | null
1705
- * ```
1706
- */
1707
- getOrElse: <B>(defaultValue: () => B) => <E, A>(data: RemoteData<E, A>) => A | B;
1708
- /**
1709
- * Executes a side effect on the success value without changing the RemoteData.
1710
- *
1711
- * @example
1712
- * ```ts
1713
- * pipe(
1714
- * RemoteData.make.success(5),
1715
- * RemoteData.tap(n => console.log("Value:", n)),
1716
- * RemoteData.map(n => n * 2)
1717
- * );
1718
- * ```
1719
- */
1720
- tap: <E, A>(f: (a: A) => void) => (data: RemoteData<E, A>) => RemoteData<E, A>;
1721
- /**
1722
- * Executes a side effect on the failure error without changing the RemoteData.
1723
- * Useful for logging errors.
1724
- *
1725
- * @example
1726
- * ```ts
1727
- * pipe(
1728
- * RemoteData.make.failure("not found"),
1729
- * RemoteData.tapError(e => console.error("fetch failed:", e)),
1730
- * RemoteData.map(render)
1731
- * );
1732
- * ```
1733
- */
1734
- tapError: <E, A>(f: (e: E) => void) => (data: RemoteData<E, A>) => RemoteData<E, A>;
1735
- /**
1736
- * Recovers from a Failure state by providing a fallback RemoteData.
1737
- * The fallback can produce a different success type, widening the result to `RemoteData<E, A | B>`.
1738
- */
1739
- recover: <E, B>(fallback: (e: E) => RemoteData<E, B>) => <A>(data: RemoteData<E, A>) => RemoteData<E, A | B>;
1740
- to: {
1741
- /**
1742
- * Converts a RemoteData to a Maybe.
1743
- * Success becomes Some, all other states become None.
1744
- */
1745
- Maybe: <E, A>(data: RemoteData<E, A>) => Maybe<A>;
1746
- /**
1747
- * Converts a RemoteData to a Result.
1748
- * Success becomes Ok, Failure becomes Err.
1749
- * NotAsked and Loading become Err with the provided fallback error.
1750
- *
1751
- * @example
1752
- * ```ts
1753
- * pipe(
1754
- * RemoteData.make.success(42),
1755
- * RemoteData.to.Result(() => "not loaded")
1756
- * ); // Ok(42)
1757
- * ```
1758
- */
1759
- Result: <E>(onNotReady: () => E) => <A>(data: RemoteData<E, A>) => Result<E, A>;
1760
- };
1761
- from: {
1762
- /**
1763
- * Converts a Result to a RemoteData.
1764
- * Ok becomes Success, Err becomes Failure.
1765
- *
1766
- * @example
1767
- * ```ts
1768
- * const result = await Task.Result.tryCatch(() => loadUser(), { onError: String })();
1769
- * setState(RemoteData.from.Result(result)); // Success(user) or Failure(msg)
1770
- * ```
1771
- */
1772
- Result: <E, A>(data: Result<E, A>) => RemoteData<E, A>;
1773
- /**
1774
- * Converts a Maybe to a RemoteData.
1775
- * Some becomes Success, None becomes Failure using the onNone error producer.
1776
- *
1777
- * @example
1778
- * ```ts
1779
- * pipe(Maybe.make.some(user), RemoteData.from.Maybe(() => "not found")); // Success(user)
1780
- * pipe(Maybe.make.none(), RemoteData.from.Maybe(() => "not found")); // Failure("not found")
1781
- * ```
1782
- */
1783
- Maybe: <E>(onNone: () => E) => <A>(data: Maybe<A>) => RemoteData<E, A>;
1784
- };
1785
- /**
1786
- * Filters a `Success` value. When the predicate passes, the value is kept. When it fails,
1787
- * `Success` becomes `Failure` using the error produced by `onFalse`. All other states pass through unchanged.
1788
- *
1789
- * @example
1790
- * ```ts
1791
- * RemoteData.filter(n => n > 0, n => `${n} is not a valid price`)(RemoteData.make.success(9.99));
1792
- * // Success(9.99)
1793
- * RemoteData.filter(n => n > 0, n => `${n} is not a valid price`)(RemoteData.make.success(-1));
1794
- * // Failure("-1 is not a valid price")
1795
- * RemoteData.filter(n => n > 0, () => "error")(RemoteData.make.loading()); // Loading
1796
- * ```
1797
- */
1798
- filter: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (data: RemoteData<E, A>) => RemoteData<E, A>;
1799
- };
1800
-
1801
- /**
1802
- * A Resource pairs an async acquisition step with a guaranteed cleanup step.
1803
- *
1804
- * Use it whenever something must be explicitly closed, released, or torn down
1805
- * after you are done with it — database connections, file handles, locks,
1806
- * temporary directories, or any object with a lifecycle.
1807
- *
1808
- * The key guarantee: `release` always runs after `Resource.use`, even when
1809
- * the work function returns an error. If `acquire` itself fails, `release` is
1810
- * skipped — there is nothing to clean up.
1811
- *
1812
- * Build a Resource with `Resource.from.handlers` or `Resource.from.Task`, then run it
1813
- * with `Resource.use`.
1814
- *
1815
- * @example
1816
- * ```ts
1817
- * const dbResource = Resource.from.handlers(
1818
- * Task.Result.tryCatch(() => openConnection(config), { onError: (e) => new DbError(e) }),
1819
- * (conn) => Task.tryCatch(() => conn.close(), { onError: () => {} })
1820
- * );
1821
- *
1822
- * const result = await pipe(
1823
- * dbResource,
1824
- * Resource.use((conn) => queryUser(conn, userId))
1825
- * )();
1826
- * // conn.close() is called whether queryUser succeeds or fails
1827
- * ```
1828
- */
1829
- type Resource<E, A> = {
1830
- readonly acquire: Task.Result<E, A>;
1831
- readonly release: (a: A) => Task<void>;
1832
- };
1833
- declare const Resource: {
1834
- from: {
1835
- /**
1836
- * Creates a Resource from an acquire operation that may fail and a release function.
1837
- *
1838
- * @example
1839
- * ```ts
1840
- * const fileResource = Resource.from.handlers(
1841
- * Task.Result.tryCatch(() => fs.promises.open("data.csv", "r"), { onError: toFileError }),
1842
- * (handle) => Task.tryCatch(() => handle.close(), { onError: () => {} })
1843
- * );
1844
- * ```
1845
- */
1846
- handlers: <E, A>(acquire: Task.Result<E, A>, release: (a: A) => Task<void>) => Resource<E, A>;
1847
- /**
1848
- * Creates a Resource from an acquire operation that cannot fail.
1849
- * Use this when opening the resource is guaranteed to succeed, such as
1850
- * in-memory locks, counters, or timers.
1851
- *
1852
- * @example
1853
- * ```ts
1854
- * const timerResource = Resource.from.Task<never, Timer>(
1855
- * Task.tryCatch(() => Promise.resolve(startTimer()), { onError: () => defaultTimer }),
1856
- * (timer) => Task.tryCatch(() => Promise.resolve(timer.stop()), { onError: () => {} })
1857
- * );
1858
- * ```
1859
- */
1860
- Task: <E, A>(acquire: Task<A>, release: (a: A) => Task<void>) => Resource<E, A>;
1861
- };
1862
- /**
1863
- * Acquires the resource, runs `f` with it, then releases it.
1864
- *
1865
- * Release always runs, even when `f` returns an error.
1866
- * If acquire fails, `f` and release are both skipped and the error is returned.
1867
- *
1868
- * @example
1869
- * ```ts
1870
- * const rows = await pipe(
1871
- * dbResource,
1872
- * Resource.use((conn) => runQuery(conn, "SELECT * FROM users"))
1873
- * )();
1874
- * // conn is closed whether the query succeeds or fails
1875
- * ```
1876
- */
1877
- use: <E, A, B>(f: (a: A) => Task.Result<E, B>) => (resource: Resource<E, A>) => Task.Result<E, B>;
1878
- /**
1879
- * Acquires two resources in sequence and presents them as a tuple.
1880
- * Resources are released in reverse order: the second is released before the first.
1881
- *
1882
- * If the second resource fails to acquire, the first is released immediately
1883
- * before returning the error.
1884
- *
1885
- * @example
1886
- * ```ts
1887
- * const combined = Resource.combine(dbResource, cacheResource);
1888
- *
1889
- * const result = await pipe(
1890
- * combined,
1891
- * Resource.use(([conn, cache]) => lookupWithFallback(conn, cache, userId))
1892
- * )();
1893
- * ```
1894
- */
1895
- combine: <E, A, B>(resourceA: Resource<E, A>, resourceB: Resource<E, B>) => Resource<E, readonly [A, B]>;
1896
- };
1897
-
1898
- /**
1899
- * A synchronous computation that threads a piece of mutable state `S` through
1900
- * a pipeline without exposing mutation at call sites.
1901
- *
1902
- * At runtime a `State<S, A>` is just a function from an initial state to a pair
1903
- * `[value, nextState]`. Nothing runs until you supply the initial state with
1904
- * `State.run`, `State.evaluate`, or `State.execute`.
1905
- *
1906
- * @example
1907
- * ```ts
1908
- * type Counter = number;
1909
- *
1910
- * const increment: State<Counter, undefined> = State.modify(n => n + 1);
1911
- * const getCount: State<Counter, Counter> = State.get();
1912
- *
1913
- * const program = pipe(
1914
- * increment,
1915
- * State.chain(() => increment),
1916
- * State.chain(() => getCount),
1917
- * );
1918
- *
1919
- * State.run(0)(program); // [2, 2] — value is 2, final state is 2
1920
- * ```
1921
- */
1922
- type State<S, A> = (s: S) => readonly [A, S];
1923
- declare const State: {
1924
- /**
1925
- * Lifts a pure value into a State computation. The state passes through unchanged.
1926
- *
1927
- * @example
1928
- * ```ts
1929
- * State.run(10)(State.resolve(42)); // [42, 10] — value 42, state unchanged
1930
- * ```
1931
- */
1932
- resolve: <S, A>(value: A) => State<S, A>;
1933
- /**
1934
- * Produces the current state as the value, without modifying it.
1935
- *
1936
- * @example
1937
- * ```ts
1938
- * const readStack: State<string[], string[]> = State.get();
1939
- * State.run(["a", "b"])(readStack); // [["a", "b"], ["a", "b"]]
1940
- * ```
1941
- */
1942
- get: <S>() => State<S, S>;
1943
- /**
1944
- * Reads a projection of the state without modifying it.
1945
- * Equivalent to `pipe(State.get(), State.map(f))` but more direct.
1946
- *
1947
- * @example
1948
- * ```ts
1949
- * type AppState = { count: number; label: string };
1950
- * const readCount: State<AppState, number> = State.gets(s => s.count);
1951
- * State.run({ count: 5, label: "x" })(readCount); // [5, { count: 5, label: "x" }]
1952
- * ```
1953
- */
1954
- gets: <S, A>(f: (s: S) => A) => State<S, A>;
1955
- /**
1956
- * Replaces the current state with a new value. Produces no meaningful value.
1957
- *
1958
- * @example
1959
- * ```ts
1960
- * const reset: State<number, undefined> = State.put(0);
1961
- * State.run(99)(reset); // [undefined, 0]
1962
- * ```
1963
- */
1964
- put: <S>(newState: S) => State<S, undefined>;
1965
- /**
1966
- * Applies a function to the current state to produce the next state.
1967
- * Produces no meaningful value.
1968
- *
1969
- * @example
1970
- * ```ts
1971
- * const push = (item: string): State<string[], undefined> =>
1972
- * State.modify(stack => [...stack, item]);
1973
- *
1974
- * State.run(["a"])(push("b")); // [undefined, ["a", "b"]]
1975
- * ```
1976
- */
1977
- modify: <S>(f: (s: S) => S) => State<S, undefined>;
1978
- /**
1979
- * Transforms the value produced by a State computation.
1980
- * The state transformation is unchanged.
1981
- *
1982
- * @example
1983
- * ```ts
1984
- * const readLength: State<string[], number> = pipe(
1985
- * State.get<string[]>(),
1986
- * State.map(stack => stack.length),
1987
- * );
1988
- *
1989
- * State.run(["a", "b", "c"])(readLength); // [3, ["a", "b", "c"]]
1990
- * ```
1991
- */
1992
- map: <S, A, B>(f: (a: A) => B) => (st: State<S, A>) => State<S, B>;
1993
- /**
1994
- * Sequences two State computations. The state output of the first is passed
1995
- * as the state input to the second.
1996
- *
1997
- * Data-last — the first computation is the data being piped.
1998
- *
1999
- * @example
2000
- * ```ts
2001
- * const push = (item: string): State<string[], undefined> =>
2002
- * State.modify(stack => [...stack, item]);
2003
- *
2004
- * const program = pipe(
2005
- * push("a"),
2006
- * State.chain(() => push("b")),
2007
- * State.chain(() => State.get<string[]>()),
2008
- * );
2009
- *
2010
- * State.evaluate([])(program); // ["a", "b"]
2011
- * ```
2012
- */
2013
- chain: <S, A, B>(f: (a: A) => State<S, B>) => (st: State<S, A>) => State<S, B>;
2014
- /**
2015
- * Applies a function wrapped in a State to a value wrapped in a State.
2016
- * The function computation runs first; its output state is the input to the
2017
- * argument computation.
2018
- *
2019
- * @example
2020
- * ```ts
2021
- * const addCounted = (n: number) => (m: number) => n + m;
2022
- * const program = pipe(
2023
- * State.resolve<number, typeof addCounted>(addCounted),
2024
- * State.ap(State.gets((s: number) => s * 2)),
2025
- * State.ap(State.gets((s: number) => s)),
2026
- * );
2027
- *
2028
- * State.evaluate(3)(program); // 6 + 3 = 9
2029
- * ```
2030
- */
2031
- ap: <S, A>(arg: State<S, A>) => <B>(fn: State<S, (a: A) => B>) => State<S, B>;
2032
- /**
2033
- * Runs a side effect on the produced value without changing the State computation.
2034
- *
2035
- * @example
2036
- * ```ts
2037
- * pipe(
2038
- * State.get<number>(),
2039
- * State.tap(n => console.log("current:", n)),
2040
- * State.chain(() => State.modify(n => n + 1)),
2041
- * );
2042
- * ```
2043
- */
2044
- tap: <S, A>(f: (a: A) => void) => (st: State<S, A>) => State<S, A>;
2045
- /**
2046
- * Runs a State computation with an initial state, returning both the
2047
- * produced value and the final state as a pair.
2048
- *
2049
- * Data-last — the computation is the data being piped.
2050
- *
2051
- * @example
2052
- * ```ts
2053
- * const program = pipe(
2054
- * State.modify<number>(n => n + 1),
2055
- * State.chain(() => State.get<number>()),
2056
- * );
2057
- *
2058
- * State.run(0)(program); // [1, 1]
2059
- * ```
2060
- */
2061
- run: <S>(initialState: S) => <A>(st: State<S, A>) => readonly [A, S];
2062
- /**
2063
- * Runs a State computation with an initial state, returning only the
2064
- * produced value (discarding the final state).
2065
- *
2066
- * @example
2067
- * ```ts
2068
- * State.evaluate([])(pipe(
2069
- * State.modify<string[]>(s => [...s, "x"]),
2070
- * State.chain(() => State.get<string[]>()),
2071
- * )); // ["x"]
2072
- * ```
2073
- */
2074
- evaluate: <S>(initialState: S) => <A>(st: State<S, A>) => A;
2075
- /**
2076
- * Runs a State computation with an initial state, returning only the
2077
- * final state (discarding the produced value).
2078
- *
2079
- * @example
2080
- * ```ts
2081
- * State.execute(0)(pipe(
2082
- * State.modify<number>(n => n + 10),
2083
- * State.chain(() => State.modify<number>(n => n * 2)),
2084
- * )); // 20
2085
- * ```
2086
- */
2087
- execute: <S>(initialState: S) => <A>(st: State<S, A>) => S;
2088
- /**
2089
- * Lifts a State value into an accumulator object.
2090
- *
2091
- * @example
2092
- * ```ts
2093
- * pipe(State.resolve(42), State.bindTo("value")); // State({ value: 42 })
2094
- * ```
2095
- */
2096
- bindTo: <K extends string>(key: K) => <S, A>(data: State<S, A>) => State<S, { [P in K]: A; }>;
2097
- /**
2098
- * Evaluates a new State using the current accumulator and attaches the output to a new key.
2099
- *
2100
- * @example
2101
- * ```ts
2102
- * pipe(
2103
- * State.resolve({ a: 1 }),
2104
- * State.bind("b", ({ a }) => State.resolve(a + 1))
2105
- * ); // State({ a: 1, b: 2 })
2106
- * ```
2107
- */
2108
- bind: <K extends string, S, A, B>(key: K, f: (a: A) => State<S, B>) => (data: State<S, A>) => State<S, A & { [P in K]: B; }>;
2109
- /**
2110
- * Focuses a State computation on a sub-state using a Lens.
2111
- *
2112
- * @example
2113
- * ```ts
2114
- * type AppState = { count: number; name: string };
2115
- * const countLens = Lens.from.property<AppState>()("count");
2116
- * const increment = State.modify((c: number) => c + 1);
2117
- * const focusedProgram = pipe(increment, State.focus(countLens));
2118
- * ```
2119
- */
2120
- focus: <S, A>(lens: Lens<S, A>) => <B>(stateOp: State<A, B>) => State<S, B>;
2121
- };
2122
-
2123
- /**
2124
- * An event stream pipeline for a typed message schema `S`.
2125
- *
2126
- * `Stream` provides typed event emission, sequence matching, state reduction,
2127
- * and structural stream forwarding.
2128
- *
2129
- * @example
2130
- * ```ts
2131
- * type AppMessages = {
2132
- * userLoggedIn: { userId: string };
2133
- * checkoutStarted: { amount: number };
2134
- * };
2135
- *
2136
- * const appStream = Stream.make<AppMessages>();
2137
- *
2138
- * const subscription = Stream.listen(
2139
- * appStream,
2140
- * ["userLoggedIn", "checkoutStarted"],
2141
- * { ordered: true }
2142
- * ).reduce(
2143
- * (msg, state) => {
2144
- * if (msg.kind === "checkoutStarted") {
2145
- * return { count: state.count + 1 };
2146
- * }
2147
- * return state;
2148
- * },
2149
- * { count: 0 }
2150
- * );
2151
- *
2152
- * Stream.emit(appStream, {
2153
- * kind: "userLoggedIn",
2154
- * value: { userId: "user-1" },
2155
- * });
2156
- * ```
2157
- */
2158
- type Stream<S extends Record<string, unknown>> = {
2159
- readonly options?: Stream.Options;
2160
- /** @internal */
2161
- readonly _listeners: Set<(msg: Stream.Message<S>) => void>;
2162
- /**
2163
- * @internal
2164
- * Lazy array snapshot of `_listeners`. Avoids allocating new array objects on every `emit` call
2165
- * (2.98x emission speedup, 0 heap allocations). Rebuilt whenever `_listeners` is mutated,
2166
- * guaranteeing reentrancy safety and preventing listeners subscribed mid-emission from executing early.
2167
- */
2168
- _listenerArray: Array<(msg: Stream.Message<S>) => void> | null;
2169
- /** @internal */
2170
- readonly _queue: Array<Stream.Message<S>>;
2171
- /** @internal */
2172
- _isEmitting: boolean;
2173
- };
2174
- declare const Stream: {
2175
- /**
2176
- * Constructs a new `Stream` instance.
2177
- *
2178
- * @example
2179
- * ```ts
2180
- * const stream = Stream.make<AppMessages>({ name: "app" });
2181
- * ```
2182
- */
2183
- make: <S extends Record<string, unknown>>(options?: Stream.Options) => Stream<S>;
2184
- /**
2185
- * Emits a message payload to one or more target streams.
2186
- *
2187
- * Uses a synchronous breadth-first trampoline queue to handle re-entrant emissions deterministically.
2188
- *
2189
- * @example
2190
- * ```ts
2191
- * Stream.emit(streamA, {
2192
- * kind: "userLoggedIn",
2193
- * value: { userId: "user-1" },
2194
- * });
2195
- *
2196
- * Stream.emit([streamA, streamB], {
2197
- * kind: "userLoggedIn",
2198
- * value: { userId: "user-1" },
2199
- * });
2200
- * ```
2201
- */
2202
- emit: <S extends Record<string, unknown>, K extends keyof S & string>(target: Stream<S> | ReadonlyArray<Stream<S>>, message: WithKind<K> & WithValue<S[K]>) => void;
2203
- /**
2204
- * Forwards messages from one stream to another (or multiple).
2205
- *
2206
- * @example
2207
- * ```ts
2208
- * const stop = Stream.forward({
2209
- * from: authStream,
2210
- * to: analyticsStream,
2211
- * only: ["userLoggedIn"],
2212
- * });
2213
- * ```
2214
- */
2215
- forward: <S extends Record<string, unknown>>(options: Stream.ForwardOptions<S>) => () => void;
2216
- /**
2217
- * Initiates listener registration on a stream for specific event kind(s) or sequence.
2218
- *
2219
- * @example
2220
- * ```ts
2221
- * const sub = Stream.listen(
2222
- * appStream,
2223
- * ["userLoggedIn", "checkoutStarted"],
2224
- * { ordered: true }
2225
- * ).reduce(
2226
- * (msg, state) => ({ count: state.count + 1 }),
2227
- * { count: 0 }
2228
- * );
2229
- * ```
2230
- */
2231
- listen: <S extends Record<string, unknown>, K extends keyof S & string>(stream: Stream<S>, events: K | ReadonlyArray<K>, options?: Stream.SequenceOptions<S>) => Stream.ListenerBuilder<S>;
2232
- };
2233
- declare namespace Stream {
2234
- type Message<S extends Record<string, unknown>> = {
2235
- [K in keyof S & string]: WithKind<K> & WithValue<S[K]>;
2236
- }[keyof S & string];
2237
- type Options = {
2238
- readonly name?: string;
2239
- readonly onError?: (error: unknown) => void;
2240
- };
2241
- type SequenceOptions<S extends Record<string, unknown>> = {
2242
- readonly ordered?: boolean;
2243
- readonly strict?: boolean;
2244
- readonly once?: boolean;
2245
- readonly reset?: (keyof S & string) | ReadonlyArray<keyof S & string>;
2246
- readonly optional?: (keyof S & string) | ReadonlyArray<keyof S & string>;
2247
- };
2248
- type Subscription<State> = {
2249
- readonly unsubscribe: () => void;
2250
- readonly getState: () => State;
2251
- };
2252
- type ForwardOptions<S extends Record<string, unknown>> = {
2253
- readonly from: Stream<S>;
2254
- readonly to: Stream<S> | ReadonlyArray<Stream<S>>;
2255
- readonly only?: ReadonlyArray<keyof S & string>;
2256
- };
2257
- type ListenerBuilder<S extends Record<string, unknown>> = {
2258
- readonly reduce: <State>(reducer: (msg: Message<S>, state: State) => State, initialState: State) => Subscription<State>;
2259
- readonly tap: (effect: (msg: Message<S>) => void) => () => void;
2260
- };
2261
- }
2262
-
2263
- type TheseFirst<T> = WithKind<"First"> & WithFirst<T>;
2264
- type TheseSecond<T> = WithKind<"Second"> & WithSecond<T>;
2265
- type TheseBoth<First, Second> = WithKind<"Both"> & WithFirst<First> & WithSecond<Second>;
2266
- /**
2267
- * These<A, B> is an inclusive-OR type: it holds a first value (A), a second
2268
- * value (B), or both simultaneously. Neither side carries a success/failure
2269
- * connotation — it is a neutral pair where any combination is valid.
2270
- *
2271
- * - First(a) — only a first value
2272
- * - Second(b) — only a second value
2273
- * - Both(a, b) — first and second values simultaneously
2274
- *
2275
- * A common use: lenient parsers or processors that carry a diagnostic note
2276
- * alongside a result, without losing either piece of information.
2277
- *
2278
- * @example
2279
- * ```ts
2280
- * const parse = (s: string): These<number, string> => {
2281
- * const trimmed = s.trim();
2282
- * const n = parseFloat(trimmed);
2283
- * if (isNaN(n)) return These.make.second("Not a number");
2284
- * if (s !== trimmed) return These.make.both(n, "Leading/trailing whitespace trimmed");
2285
- * return These.make.first(n);
2286
- * };
2287
- * ```
2288
- */
2289
- type These<A, B> = TheseFirst<A> | TheseSecond<B> | TheseBoth<A, B>;
2290
- declare const These: {
2291
- make: {
2292
- /**
2293
- * Creates a These holding only a first value.
2294
- *
2295
- * @example
2296
- * ```ts
2297
- * These.make.first(42); // { kind: "First", first: 42 }
2298
- * ```
2299
- */
2300
- first: <A>(value: A) => TheseFirst<A>;
2301
- /**
2302
- * Creates a These holding only a second value.
2303
- *
2304
- * @example
2305
- * ```ts
2306
- * These.make.second("warning"); // { kind: "Second", second: "warning" }
2307
- * ```
2308
- */
2309
- second: <B>(value: B) => TheseSecond<B>;
2310
- /**
2311
- * Creates a These holding both a first and a second value simultaneously.
2312
- *
2313
- * @example
2314
- * ```ts
2315
- * These.make.both(42, "Deprecated API used"); // { kind: "Both", first: 42, second: "Deprecated API used" }
2316
- * ```
2317
- */
2318
- both: <A, B>(f: A, s: B) => TheseBoth<A, B>;
2319
- };
2320
- is: {
2321
- /**
2322
- * Type guard — checks if a These holds only a first value.
2323
- *
2324
- * @example
2325
- * ```ts
2326
- * const val = These.make.first(42);
2327
- * if (These.is.first(val)) {
2328
- * console.log(val.first); // 42
2329
- * }
2330
- * ```
2331
- */
2332
- first: <A, B>(data: These<A, B>) => data is TheseFirst<A>;
2333
- /**
2334
- * Type guard — checks if a These holds only a second value.
2335
- *
2336
- * @example
2337
- * ```ts
2338
- * const val = These.make.second("warning");
2339
- * if (These.is.second(val)) {
2340
- * console.log(val.second); // "warning"
2341
- * }
2342
- * ```
2343
- */
2344
- second: <A, B>(data: These<A, B>) => data is TheseSecond<B>;
2345
- /**
2346
- * Type guard — checks if a These holds both values simultaneously.
2347
- *
2348
- * @example
2349
- * ```ts
2350
- * const val = These.make.both(42, "warning");
2351
- * if (These.is.both(val)) {
2352
- * console.log(val.first, val.second); // 42 "warning"
2353
- * }
2354
- * ```
2355
- */
2356
- both: <A, B>(data: These<A, B>) => data is TheseBoth<A, B>;
2357
- };
2358
- /**
2359
- * Returns true if the These contains a first value (First or Both).
2360
- *
2361
- * @example
2362
- * ```ts
2363
- * These.hasFirst(These.make.first(42)); // true
2364
- * These.hasFirst(These.make.both(42, "warn"));// true
2365
- * These.hasFirst(These.make.second("warn")); // false
2366
- * ```
2367
- */
2368
- hasFirst: <A, B>(data: These<A, B>) => data is TheseFirst<A> | TheseBoth<A, B>;
2369
- /**
2370
- * Returns true if the These contains a second value (Second or Both).
2371
- *
2372
- * @example
2373
- * ```ts
2374
- * These.hasSecond(These.make.second("warn")); // true
2375
- * These.hasSecond(These.make.both(42, "warn"));// true
2376
- * These.hasSecond(These.make.first(42)); // false
2377
- * ```
2378
- */
2379
- hasSecond: <A, B>(data: These<A, B>) => data is TheseSecond<B> | TheseBoth<A, B>;
2380
- /**
2381
- * Transforms the first value, leaving the second unchanged.
2382
- *
2383
- * @example
2384
- * ```ts
2385
- * pipe(These.make.first(5), These.mapFirst(n => n * 2)); // First(10)
2386
- * pipe(These.make.both(5, "warn"), These.mapFirst(n => n * 2)); // Both(10, "warn")
2387
- * pipe(These.make.second("warn"), These.mapFirst(n => n * 2)); // Second("warn")
2388
- * ```
2389
- */
2390
- mapFirst: <A, C>(f: (a: A) => C) => <B>(data: These<A, B>) => These<C, B>;
2391
- /**
2392
- * Transforms the second value, leaving the first unchanged.
2393
- *
2394
- * @example
2395
- * ```ts
2396
- * pipe(These.make.second("warn"), These.mapSecond(e => e.toUpperCase())); // Second("WARN")
2397
- * pipe(These.make.both(5, "warn"), These.mapSecond(e => e.toUpperCase())); // Both(5, "WARN")
2398
- * ```
2399
- */
2400
- mapSecond: <B, D>(f: (b: B) => D) => <A>(data: These<A, B>) => These<A, D>;
2401
- /**
2402
- * Transforms both the first and second values independently.
2403
- *
2404
- * @example
2405
- * ```ts
2406
- * pipe(
2407
- * These.make.both(5, "warn"),
2408
- * These.mapBoth(n => n * 2, e => e.toUpperCase())
2409
- * ); // Both(10, "WARN")
2410
- * ```
2411
- */
2412
- mapBoth: <A, C, B, D>(onFirst: (a: A) => C, onSecond: (b: B) => D) => (data: These<A, B>) => These<C, D>;
2413
- /**
2414
- * Chains These computations by passing the first value to f.
2415
- * Second propagates unchanged; First and Both apply f to the first value.
2416
- *
2417
- * @example
2418
- * ```ts
2419
- * const double = (n: number): These<number, string> => These.make.first(n * 2);
2420
- *
2421
- * pipe(These.make.first(5), These.chainFirst(double)); // First(10)
2422
- * pipe(These.make.both(5, "warn"), These.chainFirst(double)); // First(10)
2423
- * pipe(These.make.second("warn"), These.chainFirst(double)); // Second("warn")
2424
- * ```
2425
- */
2426
- chainFirst: <A, B, C>(f: (a: A) => These<C, B>) => (data: These<A, B>) => These<C, B>;
2427
- /**
2428
- * Chains These computations by passing the second value to f.
2429
- * First propagates unchanged; Second and Both apply f to the second value.
2430
- *
2431
- * @example
2432
- * ```ts
2433
- * const shout = (s: string): These<number, string> => These.make.second(s.toUpperCase());
2434
- *
2435
- * pipe(These.make.second("warn"), These.chainSecond(shout)); // Second("WARN")
2436
- * pipe(These.make.both(5, "warn"), These.chainSecond(shout)); // Second("WARN")
2437
- * pipe(These.make.first(5), These.chainSecond(shout)); // First(5)
2438
- * ```
2439
- */
2440
- chainSecond: <A, B, D>(f: (b: B) => These<A, D>) => (data: These<A, B>) => These<A, D>;
2441
- /**
2442
- * Extracts a value from a These by providing handlers for all three cases.
2443
- *
2444
- * @example
2445
- * ```ts
2446
- * pipe(
2447
- * these,
2448
- * These.fold(
2449
- * a => `First: ${a}`,
2450
- * b => `Second: ${b}`,
2451
- * (a, b) => `Both: ${a} / ${b}`
2452
- * )
2453
- * );
2454
- * ```
2455
- */
2456
- fold: <A, B, C>(onFirst: (a: A) => C, onSecond: (b: B) => C, onBoth: (a: A, b: B) => C) => (data: These<A, B>) => C;
2457
- /**
2458
- * Pattern matches on a These, returning the result of the matching case.
2459
- *
2460
- * @example
2461
- * ```ts
2462
- * pipe(
2463
- * these,
2464
- * These.match({
2465
- * first: a => `First: ${a}`,
2466
- * second: b => `Second: ${b}`,
2467
- * both: (a, b) => `Both: ${a} / ${b}`
2468
- * })
2469
- * );
2470
- * ```
2471
- */
2472
- match: <A, B, C>(cases: {
2473
- first: (a: A) => C;
2474
- second: (b: B) => C;
2475
- both: (a: A, b: B) => C;
2476
- }) => (data: These<A, B>) => C;
2477
- /**
2478
- * Returns the first value, or a default if the These has no first value.
2479
- * The default can be a different type, widening the result to `A | C`.
2480
- *
2481
- * @example
2482
- * ```ts
2483
- * pipe(These.make.first(5), These.getFirstOrElse(() => 0)); // 5
2484
- * pipe(These.make.both(5, "warn"), These.getFirstOrElse(() => 0)); // 5
2485
- * pipe(These.make.second("warn"), These.getFirstOrElse(() => 0)); // 0
2486
- * pipe(These.make.second("warn"), These.getFirstOrElse(() => null)); // null — typed as number | null
2487
- * ```
2488
- */
2489
- getFirstOrElse: <A, C>(defaultValue: () => C) => <B>(data: These<A, B>) => A | C;
2490
- /**
2491
- * Returns the second value, or a default if the These has no second value.
2492
- * The default can be a different type, widening the result to `B | D`.
2493
- *
2494
- * @example
2495
- * ```ts
2496
- * pipe(These.make.second("warn"), These.getSecondOrElse(() => "none")); // "warn"
2497
- * pipe(These.make.both(5, "warn"), These.getSecondOrElse(() => "none")); // "warn"
2498
- * pipe(These.make.first(5), These.getSecondOrElse(() => "none")); // "none"
2499
- * pipe(These.make.first(5), These.getSecondOrElse(() => null)); // null — typed as string | null
2500
- * ```
2501
- */
2502
- getSecondOrElse: <B, D>(defaultValue: () => D) => <A>(data: These<A, B>) => B | D;
2503
- /**
2504
- * Runs a side effect on the first value without changing the These.
2505
- * Useful for logging or debugging.
2506
- *
2507
- * @example
2508
- * ```ts
2509
- * pipe(These.make.first(5), These.tap(console.log)); // logs 5, returns First(5)
2510
- * ```
2511
- */
2512
- tap: <A>(f: (a: A) => void) => <B>(data: These<A, B>) => These<A, B>;
2513
- /**
2514
- * Swaps the roles of first and second values.
2515
- * - First(a) → Second(a)
2516
- * - Second(b) → First(b)
2517
- * - Both(a, b) → Both(b, a)
2518
- *
2519
- * @example
2520
- * ```ts
2521
- * These.swap(These.make.first(5)); // Second(5)
2522
- * These.swap(These.make.second("warn")); // First("warn")
2523
- * These.swap(These.make.both(5, "warn")); // Both("warn", 5)
2524
- * ```
2525
- */
2526
- swap: <A, B>(data: These<A, B>) => These<B, A>;
2527
- };
2528
-
2529
- export { Combinable, Deferred, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, Pair, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, Stream, type Success, Task, These, type TheseBoth, type TheseFirst, type TheseSecond };
1
+ import { x as Deferred } from "./InternalTypes-DzDey5Do.js";
2
+ import { A as Logged, C as Pair, D as Maybe, E as Op, M as Lazy, N as Equality, O as None, P as Combinable, S as Predicate, T as Optional, _ as NotAsked, a as Task, b as Refinement, c as Validation, d as Err, f as Ok, g as Loading, h as Failure, i as TheseSecond, j as Lens, k as Some, l as Stream, m as Resource, n as TheseBoth, o as Failed, p as Result, r as TheseFirst, s as Passed, t as These, u as State, v as RemoteData, w as Ordering, x as Reader, y as Success } from "./index-B07Wr815.js";
3
+ export { Combinable, Deferred, Equality, Err, Failed, Failure, Lazy, Lens, Loading, Logged, Maybe, None, NotAsked, Ok, Op, Optional, Ordering, Pair, Passed, Predicate, Reader, Refinement, RemoteData, Resource, Result, Some, State, Stream, Success, Task, These, TheseBoth, TheseFirst, TheseSecond, Validation };