@nlozgachev/pipelined 0.65.0 → 0.67.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.
@@ -284,6 +284,189 @@ const Equality = {
284
284
  }
285
285
  };
286
286
  //#endregion
287
+ //#region src/Core/EventBus.ts
288
+ const makeEventBus = (options) => ({
289
+ options,
290
+ _listeners: /* @__PURE__ */ new Set(),
291
+ _listenerArray: null,
292
+ _queue: [],
293
+ _isEmitting: false
294
+ });
295
+ const emitEventBus = (target, message) => {
296
+ const targets = Array.isArray(target) ? target : [target];
297
+ const msg = message;
298
+ for (const bus of targets) {
299
+ bus._queue.push(msg);
300
+ if (!bus._isEmitting) {
301
+ bus._isEmitting = true;
302
+ try {
303
+ while (bus._queue.length > 0) {
304
+ const nextMsg = bus._queue.shift();
305
+ if (bus._listenerArray === null) bus._listenerArray = Array.from(bus._listeners);
306
+ const listeners = bus._listenerArray;
307
+ for (const listener of listeners) try {
308
+ listener(nextMsg);
309
+ } catch (err) {
310
+ if (bus.options?.onError) bus.options.onError(err);
311
+ else throw err;
312
+ }
313
+ }
314
+ } finally {
315
+ bus._isEmitting = false;
316
+ }
317
+ }
318
+ }
319
+ };
320
+ const forwardEventBus = (options) => {
321
+ const targets = Array.isArray(options.to) ? options.to : [options.to];
322
+ const filterSet = options.only ? new Set(options.only) : null;
323
+ const handler = (msg) => {
324
+ if (filterSet !== null && !filterSet.has(msg.kind)) return;
325
+ for (const target of targets) emitEventBus(target, msg);
326
+ };
327
+ options.from._listeners.add(handler);
328
+ options.from._listenerArray = null;
329
+ return () => {
330
+ options.from._listeners.delete(handler);
331
+ options.from._listenerArray = null;
332
+ };
333
+ };
334
+ const listenEventBus = (bus, events, options) => {
335
+ const eventList = Array.isArray(events) ? events : [events];
336
+ const isOrdered = options?.ordered ?? false;
337
+ const isStrict = options?.strict ?? false;
338
+ const isOnce = options?.once ?? false;
339
+ const resetKinds = options?.reset ? new Set(Array.isArray(options.reset) ? options.reset : [options.reset]) : null;
340
+ const optionalKinds = options?.optional ? new Set(Array.isArray(options.optional) ? options.optional : [options.optional]) : null;
341
+ const createMatcher = (onMatch) => {
342
+ let sequenceIndex = 0;
343
+ return (msg) => {
344
+ if (resetKinds !== null && resetKinds.has(msg.kind)) {
345
+ sequenceIndex = 0;
346
+ return;
347
+ }
348
+ if (!isOrdered) {
349
+ if (eventList.includes(msg.kind)) onMatch(msg);
350
+ return;
351
+ }
352
+ let expectedKind = eventList[sequenceIndex];
353
+ if (expectedKind !== msg.kind && optionalKinds !== null) {
354
+ let lookaheadIndex = sequenceIndex;
355
+ while (lookaheadIndex < eventList.length && optionalKinds.has(eventList[lookaheadIndex]) && eventList[lookaheadIndex] !== msg.kind) lookaheadIndex++;
356
+ if (lookaheadIndex < eventList.length && eventList[lookaheadIndex] === msg.kind) {
357
+ sequenceIndex = lookaheadIndex;
358
+ expectedKind = eventList[sequenceIndex];
359
+ }
360
+ }
361
+ if (msg.kind === expectedKind) {
362
+ sequenceIndex++;
363
+ if (sequenceIndex === eventList.length) {
364
+ sequenceIndex = 0;
365
+ onMatch(msg);
366
+ }
367
+ } else if (isStrict) sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
368
+ else if (eventList.includes(msg.kind)) sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
369
+ };
370
+ };
371
+ return {
372
+ reduce: (reducer, initialState) => {
373
+ let currentState = initialState;
374
+ const listenerFn = createMatcher((msg) => {
375
+ currentState = reducer(msg, currentState);
376
+ if (isOnce) {
377
+ bus._listeners.delete(listenerFn);
378
+ bus._listenerArray = null;
379
+ }
380
+ });
381
+ const unsubscribe = () => {
382
+ bus._listeners.delete(listenerFn);
383
+ bus._listenerArray = null;
384
+ };
385
+ bus._listeners.add(listenerFn);
386
+ bus._listenerArray = null;
387
+ return {
388
+ unsubscribe,
389
+ getState: () => currentState
390
+ };
391
+ },
392
+ tap: (effect) => {
393
+ const listenerFn = createMatcher((msg) => {
394
+ effect(msg);
395
+ if (isOnce) {
396
+ bus._listeners.delete(listenerFn);
397
+ bus._listenerArray = null;
398
+ }
399
+ });
400
+ const unsubscribe = () => {
401
+ bus._listeners.delete(listenerFn);
402
+ bus._listenerArray = null;
403
+ };
404
+ bus._listeners.add(listenerFn);
405
+ bus._listenerArray = null;
406
+ return unsubscribe;
407
+ }
408
+ };
409
+ };
410
+ const EventBus = {
411
+ /**
412
+ * Constructs a new `EventBus` instance.
413
+ *
414
+ * @example
415
+ * ```ts
416
+ * const bus = EventBus.make<AppMessages>({ name: "app" });
417
+ * ```
418
+ */
419
+ make: makeEventBus,
420
+ /**
421
+ * Emits a message payload to one or more target event buses.
422
+ *
423
+ * Uses a synchronous breadth-first trampoline queue to handle re-entrant emissions deterministically.
424
+ *
425
+ * @example
426
+ * ```ts
427
+ * EventBus.emit(busA, {
428
+ * kind: "userLoggedIn",
429
+ * value: { userId: "user-1" },
430
+ * });
431
+ *
432
+ * EventBus.emit([busA, busB], {
433
+ * kind: "userLoggedIn",
434
+ * value: { userId: "user-1" },
435
+ * });
436
+ * ```
437
+ */
438
+ emit: emitEventBus,
439
+ /**
440
+ * Forwards messages from one event bus to another (or multiple).
441
+ *
442
+ * @example
443
+ * ```ts
444
+ * const stop = EventBus.forward({
445
+ * from: authBus,
446
+ * to: analyticsBus,
447
+ * only: ["userLoggedIn"],
448
+ * });
449
+ * ```
450
+ */
451
+ forward: forwardEventBus,
452
+ /**
453
+ * Initiates listener registration on an event bus for specific event kind(s) or sequence.
454
+ *
455
+ * @example
456
+ * ```ts
457
+ * const sub = EventBus.listen(
458
+ * appBus,
459
+ * ["userLoggedIn", "checkoutStarted"],
460
+ * { ordered: true }
461
+ * ).reduce(
462
+ * (msg, state) => ({ count: state.count + 1 }),
463
+ * { count: 0 }
464
+ * );
465
+ * ```
466
+ */
467
+ listen: listenEventBus
468
+ };
469
+ //#endregion
287
470
  //#region src/Core/Lazy.ts
288
471
  const fromFn = (f) => {
289
472
  let done = false;
@@ -484,6 +667,19 @@ const chainLogged = (f) => (data) => {
484
667
  };
485
668
  };
486
669
  const Logged = {
670
+ /**
671
+ * Creates a `Logged` with a value and an optional initial log array.
672
+ *
673
+ * @example
674
+ * ```ts
675
+ * Logged.make(42); // { value: 42, log: [] }
676
+ * Logged.make(42, ["initialized"]); // { value: 42, log: ["initialized"] }
677
+ * ```
678
+ */
679
+ make: (value, log = []) => ({
680
+ value,
681
+ log: [...log]
682
+ }),
487
683
  from: {
488
684
  /**
489
685
  * Wraps a pure value into a `Logged` with an empty log.
@@ -548,11 +744,11 @@ const Logged = {
548
744
  * };
549
745
  * const arg: Logged<string, number> = { value: 5, log: ["arg-loaded"] };
550
746
  *
551
- * const result = pipe(fn, Logged.ap(arg));
747
+ * const result = pipe(fn, Logged.apply(arg));
552
748
  * Logged.run(result); // [10, ["fn-loaded", "arg-loaded"]]
553
749
  * ```
554
750
  */
555
- ap: (arg) => (data) => ({
751
+ apply: (arg) => (data) => ({
556
752
  value: data.value(arg.value),
557
753
  log: [...data.log, ...arg.log]
558
754
  }),
@@ -662,6 +858,8 @@ const Maybe = {
662
858
  /**
663
859
  * Type guard that checks if a Maybe is Some.
664
860
  *
861
+ * @see {@link Maybe.is.none}
862
+ *
665
863
  * @example
666
864
  * ```ts
667
865
  * const value = Maybe.make.some(42);
@@ -674,6 +872,8 @@ const Maybe = {
674
872
  /**
675
873
  * Type guard that checks if a Maybe is None.
676
874
  *
875
+ * @see {@link Maybe.is.some}
876
+ *
677
877
  * @example
678
878
  * ```ts
679
879
  * const value = Maybe.make.none();
@@ -722,7 +922,18 @@ const Maybe = {
722
922
  * ); // Err("Value was missing")
723
923
  * ```
724
924
  */
725
- Result: (onNone) => (data) => isSome(data) ? Result.make.ok(data.value) : Result.make.err(onNone())
925
+ Result: (onNone) => (data) => isSome(data) ? Result.make.ok(data.value) : Result.make.err(onNone()),
926
+ /**
927
+ * Converts a Maybe to a Validation.
928
+ * Some becomes Passed, None becomes Failed with error produced by `onNone`.
929
+ *
930
+ * @example
931
+ * ```ts
932
+ * pipe(Maybe.make.some(42), Maybe.to.Validation(() => "missing")); // Passed(42)
933
+ * pipe(Maybe.make.none(), Maybe.to.Validation(() => "missing")); // Failed(["missing"])
934
+ * ```
935
+ */
936
+ Validation: (onNone) => (data) => isSome(data) ? Validation.make.passed(data.value) : Validation.make.failed(onNone())
726
937
  },
727
938
  from: {
728
939
  /**
@@ -763,19 +974,41 @@ const Maybe = {
763
974
  Result: (data) => Result.is.ok(data) ? makeSome$1(data.value) : makeNone$1()
764
975
  },
765
976
  /**
977
+ * Wraps a synchronous operation that may throw, returning a `Maybe<A>`.
978
+ * Returns `Some(value)` if successful, or `None` if an exception is thrown.
979
+ *
980
+ * @example
981
+ * ```ts
982
+ * const safeParse = (s: string) => Maybe.tryCatch(() => JSON.parse(s));
983
+ * safeParse('{"a": 1}'); // Some({ a: 1 })
984
+ * safeParse('invalid'); // None
985
+ * ```
986
+ */
987
+ tryCatch: (f) => {
988
+ try {
989
+ return makeSome$1(f());
990
+ } catch {
991
+ return makeNone$1();
992
+ }
993
+ },
994
+ /**
766
995
  * Transforms the value inside a Maybe if it exists.
767
996
  *
997
+ * @see {@link Maybe.chain} for functions that return a Maybe.
998
+ *
768
999
  * @example
769
1000
  * ```ts
770
1001
  * pipe(Maybe.make.some(5), Maybe.map(n => n * 2)); // Some(10)
771
1002
  * pipe(Maybe.make.none(), Maybe.map(n => n * 2)); // None
772
1003
  * ```
773
1004
  */
774
- map: (f) => (data) => isSome(data) ? makeSome$1(f(data.value)) : data,
1005
+ map: (transform) => (maybe) => isSome(maybe) ? makeSome$1(transform(maybe.value)) : maybe,
775
1006
  /**
776
- * Chains Maybe computations. If the first is Some, passes the value to f.
1007
+ * Chains Maybe computations. If the first is Some, passes the value to `transform`.
777
1008
  * If the first is None, propagates None.
778
1009
  *
1010
+ * @see {@link Maybe.map} for transforming with plain non-optional functions.
1011
+ *
779
1012
  * @example
780
1013
  * ```ts
781
1014
  * const parseNumber = (s: string): Maybe<number> => {
@@ -787,10 +1020,12 @@ const Maybe = {
787
1020
  * pipe(Maybe.make.some("abc"), Maybe.chain(parseNumber)); // None
788
1021
  * ```
789
1022
  */
790
- chain: (f) => (data) => isSome(data) ? f(data.value) : data,
1023
+ chain: (transform) => (maybe) => isSome(maybe) ? transform(maybe.value) : maybe,
791
1024
  /**
792
1025
  * Extracts the value from a Maybe by providing handlers for both cases.
793
1026
  *
1027
+ * @see {@link Maybe.match} for named-case handling using an object.
1028
+ *
794
1029
  * @example
795
1030
  * ```ts
796
1031
  * pipe(
@@ -802,10 +1037,12 @@ const Maybe = {
802
1037
  * ); // "Value: 5"
803
1038
  * ```
804
1039
  */
805
- fold: (onNone, onSome) => (data) => isSome(data) ? onSome(data.value) : onNone(),
1040
+ fold: (onNone, onSome) => (maybe) => isSome(maybe) ? onSome(maybe.value) : onNone(),
806
1041
  /**
807
1042
  * Pattern matches on a Maybe, returning the result of the matching case.
808
1043
  *
1044
+ * @see {@link Maybe.fold} for positional arguments (onNone, onSome).
1045
+ *
809
1046
  * @example
810
1047
  * ```ts
811
1048
  * pipe(
@@ -817,12 +1054,15 @@ const Maybe = {
817
1054
  * );
818
1055
  * ```
819
1056
  */
820
- match: (cases) => (data) => isSome(data) ? cases.some(data.value) : cases.none(),
1057
+ match: (cases) => (maybe) => isSome(maybe) ? cases.some(maybe.value) : cases.none(),
821
1058
  /**
822
1059
  * Returns the value inside a Maybe, or a default value if None.
823
1060
  * The default is a thunk `() => B` — evaluated only when the Maybe is None.
824
1061
  * The default can be a different type, widening the result to `A | B`.
825
1062
  *
1063
+ * @see {@link Maybe.match}
1064
+ * @see {@link Maybe.to.nullable}
1065
+ *
826
1066
  * @example
827
1067
  * ```ts
828
1068
  * pipe(Maybe.make.some(5), Maybe.getOrElse(() => 0)); // 5
@@ -830,11 +1070,13 @@ const Maybe = {
830
1070
  * pipe(Maybe.make.none<string>(), Maybe.getOrElse(() => null)); // null — typed as string | null
831
1071
  * ```
832
1072
  */
833
- getOrElse: (defaultValue) => (data) => isSome(data) ? data.value : defaultValue(),
1073
+ getOrElse: (defaultValue) => (maybe) => isSome(maybe) ? maybe.value : defaultValue(),
834
1074
  /**
835
1075
  * Executes a side effect on the value without changing the Maybe.
836
1076
  * Useful for logging or debugging.
837
1077
  *
1078
+ * @see {@link Maybe.tapNone} for running side effects on None.
1079
+ *
838
1080
  * @example
839
1081
  * ```ts
840
1082
  * pipe(
@@ -844,32 +1086,54 @@ const Maybe = {
844
1086
  * );
845
1087
  * ```
846
1088
  */
847
- tap: (f) => (data) => {
848
- if (isSome(data)) f(data.value);
849
- return data;
1089
+ tap: (sideEffect) => (maybe) => {
1090
+ if (isSome(maybe)) sideEffect(maybe.value);
1091
+ return maybe;
1092
+ },
1093
+ /**
1094
+ * Executes a side effect when the Maybe is None, without changing the Maybe.
1095
+ *
1096
+ * @see {@link Maybe.tap} for running side effects on Some.
1097
+ *
1098
+ * @example
1099
+ * ```ts
1100
+ * pipe(
1101
+ * Maybe.make.none(),
1102
+ * Maybe.tapNone(() => console.log("Value missing")),
1103
+ * );
1104
+ * ```
1105
+ */
1106
+ tapNone: (sideEffect) => (maybe) => {
1107
+ if (isNone(maybe)) sideEffect();
1108
+ return maybe;
850
1109
  },
851
1110
  /**
852
- * Filters a Maybe based on a predicate.
1111
+ * Filters a Maybe based on a predicate or type guard.
853
1112
  * Returns None if the predicate returns false or if the Maybe is already None.
854
1113
  *
1114
+ * @see {@link Maybe.map}
1115
+ *
855
1116
  * @example
856
1117
  * ```ts
857
1118
  * pipe(Maybe.make.some(5), Maybe.filter(n => n > 3)); // Some(5)
858
1119
  * pipe(Maybe.make.some(2), Maybe.filter(n => n > 3)); // None
1120
+ * pipe(Maybe.make.some("hi"), Maybe.filter((x): x is string => typeof x === "string")); // Some("hi")
859
1121
  * ```
860
1122
  */
861
- filter: (predicate) => (data) => isSome(data) ? predicate(data.value) ? data : makeNone$1() : data,
1123
+ filter: ((predicate) => (maybe) => isSome(maybe) ? predicate(maybe.value) ? maybe : makeNone$1() : maybe),
862
1124
  /**
863
1125
  * Recovers from a None by providing a fallback Maybe.
864
1126
  * The fallback can produce a different type, widening the result to `Maybe<A | B>`.
865
1127
  *
1128
+ * @see {@link Maybe.getOrElse}
1129
+ *
866
1130
  * @example
867
1131
  * ```ts
868
1132
  * pipe(Maybe.make.none(), Maybe.recover(() => Maybe.make.some(42))); // Some(42)
869
1133
  * pipe(Maybe.make.some(10), Maybe.recover(() => Maybe.make.some(42))); // Some(10)
870
1134
  * ```
871
1135
  */
872
- recover: (fallback) => (data) => isSome(data) ? data : fallback(),
1136
+ recover: (fallback) => (maybe) => isSome(maybe) ? maybe : fallback(),
873
1137
  /**
874
1138
  * Applies a function wrapped in a Maybe to a value wrapped in a Maybe.
875
1139
  *
@@ -878,12 +1142,12 @@ const Maybe = {
878
1142
  * const add = (a: number) => (b: number) => a + b;
879
1143
  * pipe(
880
1144
  * Maybe.make.some(add),
881
- * Maybe.ap(Maybe.make.some(5)),
882
- * Maybe.ap(Maybe.make.some(3))
1145
+ * Maybe.apply(Maybe.make.some(5)),
1146
+ * Maybe.apply(Maybe.make.some(3))
883
1147
  * ); // Some(8)
884
1148
  * ```
885
1149
  */
886
- ap: (arg) => (data) => isSome(data) && isSome(arg) ? makeSome$1(data.value(arg.value)) : makeNone$1(),
1150
+ apply: (arg) => (data) => isSome(data) && isSome(arg) ? makeSome$1(data.value(arg.value)) : makeNone$1(),
887
1151
  /**
888
1152
  * Converts a Maybe value into an object containing a single property.
889
1153
  * Initiates the pipeline accumulator record.
@@ -980,6 +1244,8 @@ const err = (error) => ({
980
1244
  error
981
1245
  });
982
1246
  const getMs$1 = (duration) => Duration.to.milliseconds(duration);
1247
+ const OP_FACTORY = Symbol.for("@nlozgachev/pipelined/Op.factory");
1248
+ const toInternalOp = (op) => op;
983
1249
  /** Waits by the specified duration. Resolves early if the signal fires (non-blocking abort). */
984
1250
  const cancellableWait = (duration, signal) => {
985
1251
  const rawMs = getMs$1(duration);
@@ -996,14 +1262,14 @@ const cancellableWait = (duration, signal) => {
996
1262
  * Runs the factory with retry logic. Calls `onRetrying` before each retry delay.
997
1263
  * Stops on Ok, Nil (null), abort, or exhausted attempts.
998
1264
  */
999
- const runWithRetry = (op, input, signal, options, onRetrying) => {
1265
+ const runWithRetry = (op, args, signal, options, onRetrying) => {
1000
1266
  const { attempts, backoff, when: shouldRetry } = options;
1001
1267
  const getDelay = (n) => {
1002
1268
  if (backoff === void 0) return;
1003
1269
  return typeof backoff === "function" ? backoff(n) : backoff;
1004
1270
  };
1005
1271
  const attempt = async (left) => {
1006
- const result = await Deferred.to.Promise(op._factory(input, signal));
1272
+ const result = await Deferred.to.Promise(toInternalOp(op)[OP_FACTORY](args, signal));
1007
1273
  if (result === null || signal.aborted) return null;
1008
1274
  if (result.kind === "Ok") return result;
1009
1275
  if (left <= 1) return result;
@@ -1029,10 +1295,10 @@ const runWithRetry = (op, input, signal, options, onRetrying) => {
1029
1295
  * If the deadline fires, it aborts the `controller` and returns `Err(onTimeout())`.
1030
1296
  * A null result from the factory (signal aborted) becomes `_abortedNil`.
1031
1297
  */
1032
- const execute = (op, input, controller, retryOptions, timeoutOptions, onRetrying) => {
1298
+ const execute = (op, args, controller, retryOptions, timeoutOptions, onRetrying) => {
1033
1299
  const { signal } = controller;
1034
1300
  const toOutcome = (r) => r === null ? _abortedNil : r.kind === "Ok" ? ok(r.value) : err(r.error);
1035
- const runPromise = retryOptions !== void 0 && onRetrying !== void 0 ? runWithRetry(op, input, signal, retryOptions, onRetrying).then(toOutcome) : Deferred.to.Promise(op._factory(input, signal)).then(toOutcome);
1301
+ const runPromise = retryOptions !== void 0 && onRetrying !== void 0 ? runWithRetry(op, args, signal, retryOptions, onRetrying).then(toOutcome) : Deferred.to.Promise(toInternalOp(op)[OP_FACTORY](args, signal)).then(toOutcome);
1036
1302
  if (timeoutOptions === void 0) return Deferred.from.Promise(runPromise);
1037
1303
  let timerId;
1038
1304
  return Deferred.from.Promise(Promise.race([runPromise.then((outcome) => {
@@ -1056,7 +1322,7 @@ const makeRestartable = (op, minInterval, retryOptions, timeoutOptions) => {
1056
1322
  currentState = state;
1057
1323
  subscribers.forEach((cb) => cb(state));
1058
1324
  };
1059
- const run = (input) => Deferred.from.Promise(new Promise((resolve) => {
1325
+ const run = (...args) => Deferred.from.Promise(new Promise((resolve) => {
1060
1326
  waitController?.abort();
1061
1327
  waitController = void 0;
1062
1328
  currentController?.abort();
@@ -1069,7 +1335,7 @@ const makeRestartable = (op, minInterval, retryOptions, timeoutOptions) => {
1069
1335
  if (currentController !== controller) return;
1070
1336
  lastStartTime = Date.now();
1071
1337
  emit(_pending);
1072
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1338
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1073
1339
  if (currentController === controller) emit(r);
1074
1340
  } : void 0).then((outcome) => {
1075
1341
  if (currentController !== controller) return;
@@ -1112,9 +1378,9 @@ const makeRestartable = (op, minInterval, retryOptions, timeoutOptions) => {
1112
1378
  return () => subscribers.delete(cb);
1113
1379
  },
1114
1380
  reset: () => emit(_idle),
1115
- poll: (input, { interval }) => {
1116
- run(input);
1117
- const id = setInterval(() => void run(input), getMs$1(interval));
1381
+ poll: ({ interval }) => (...args) => {
1382
+ run(...args);
1383
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1118
1384
  return () => clearInterval(id);
1119
1385
  }
1120
1386
  };
@@ -1129,14 +1395,14 @@ const makeExclusive = (op, cooldown, retryOptions, timeoutOptions) => {
1129
1395
  currentState = state;
1130
1396
  subscribers.forEach((cb) => cb(state));
1131
1397
  };
1132
- const run = (input) => {
1398
+ const run = (...args) => {
1133
1399
  if (currentController !== void 0 || cooldownTimer !== void 0) return Deferred.from.Promise(Promise.resolve(_droppedNil));
1134
1400
  return Deferred.from.Promise(new Promise((resolve) => {
1135
1401
  currentResolve = resolve;
1136
1402
  currentController = new AbortController();
1137
1403
  const controller = currentController;
1138
1404
  emit(_pending);
1139
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1405
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1140
1406
  if (currentController === controller) emit(r);
1141
1407
  } : void 0).then((outcome) => {
1142
1408
  if (currentController !== controller) return;
@@ -1178,9 +1444,9 @@ const makeExclusive = (op, cooldown, retryOptions, timeoutOptions) => {
1178
1444
  return () => subscribers.delete(cb);
1179
1445
  },
1180
1446
  reset: () => emit(_idle),
1181
- poll: (input, { interval }) => {
1182
- run(input);
1183
- const id = setInterval(() => void run(input), getMs$1(interval));
1447
+ poll: ({ interval }) => (...args) => {
1448
+ run(...args);
1449
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1184
1450
  return () => clearInterval(id);
1185
1451
  }
1186
1452
  };
@@ -1198,13 +1464,13 @@ const makeQueue = (op, maxSize, overflow, concurrency, dedupe, retryOptions, tim
1198
1464
  currentState = state;
1199
1465
  subscribers.forEach((cb) => cb(state));
1200
1466
  };
1201
- const startOne = (input, resolve, myGeneration) => {
1467
+ const startOne = (args, resolve, myGeneration) => {
1202
1468
  inFlight++;
1203
1469
  const controller = new AbortController();
1204
1470
  inflightControllers.add(controller);
1205
1471
  inflightResolvers.push(resolve);
1206
1472
  emit(_pending);
1207
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1473
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1208
1474
  if (generation === myGeneration && inflightControllers.has(controller)) emit(r);
1209
1475
  } : void 0).then((outcome) => {
1210
1476
  inflightControllers.delete(controller);
@@ -1223,18 +1489,18 @@ const makeQueue = (op, maxSize, overflow, concurrency, dedupe, retryOptions, tim
1223
1489
  }
1224
1490
  });
1225
1491
  };
1226
- const run = (input) => {
1492
+ const run = (...args) => {
1227
1493
  const myGeneration = generation;
1228
1494
  if (dedupe !== void 0) {
1229
- const idx = queue.findIndex((item) => dedupe(input, item.input));
1495
+ const idx = queue.findIndex((item) => dedupe(args, item.input));
1230
1496
  if (idx !== -1) queue.splice(idx, 1)[0].resolve(_droppedNil);
1231
1497
  }
1232
1498
  if (inFlight < maxConcurrency) return Deferred.from.Promise(new Promise((resolve) => {
1233
- startOne(input, resolve, myGeneration);
1499
+ startOne(args, resolve, myGeneration);
1234
1500
  }));
1235
1501
  if (maxSize === void 0 || queue.length < maxSize) return Deferred.from.Promise(new Promise((resolve) => {
1236
1502
  queue.push({
1237
- input,
1503
+ input: args,
1238
1504
  resolve
1239
1505
  });
1240
1506
  emit({
@@ -1245,7 +1511,7 @@ const makeQueue = (op, maxSize, overflow, concurrency, dedupe, retryOptions, tim
1245
1511
  if (overflow === "replace-last") return Deferred.from.Promise(new Promise((resolve) => {
1246
1512
  queue.pop().resolve(_evictedNil);
1247
1513
  queue.push({
1248
- input,
1514
+ input: args,
1249
1515
  resolve
1250
1516
  });
1251
1517
  emit({
@@ -1278,9 +1544,9 @@ const makeQueue = (op, maxSize, overflow, concurrency, dedupe, retryOptions, tim
1278
1544
  return () => subscribers.delete(cb);
1279
1545
  },
1280
1546
  reset: () => emit(_idle),
1281
- poll: (input, { interval }) => {
1282
- run(input);
1283
- const id = setInterval(() => void run(input), getMs$1(interval));
1547
+ poll: ({ interval }) => (...args) => {
1548
+ run(...args);
1549
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1284
1550
  return () => clearInterval(id);
1285
1551
  }
1286
1552
  };
@@ -1296,12 +1562,12 @@ const makeBuffered = (op, size, retryOptions, timeoutOptions) => {
1296
1562
  currentState = state;
1297
1563
  subscribers.forEach((cb) => cb(state));
1298
1564
  };
1299
- const startRun = (input, resolve) => {
1565
+ const startRun = (args, resolve) => {
1300
1566
  currentResolve = resolve;
1301
1567
  currentController = new AbortController();
1302
1568
  const controller = currentController;
1303
1569
  emit(_pending);
1304
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1570
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1305
1571
  if (currentController === controller) emit(r);
1306
1572
  } : void 0).then((outcome) => {
1307
1573
  if (currentController !== controller) return;
@@ -1316,11 +1582,11 @@ const makeBuffered = (op, size, retryOptions, timeoutOptions) => {
1316
1582
  }
1317
1583
  });
1318
1584
  };
1319
- const run = (input) => Deferred.from.Promise(new Promise((resolve) => {
1320
- if (currentController === void 0) startRun(input, resolve);
1585
+ const run = (...args) => Deferred.from.Promise(new Promise((resolve) => {
1586
+ if (currentController === void 0) startRun(args, resolve);
1321
1587
  else if (buffer.length < bufferSize) {
1322
1588
  buffer.push({
1323
- input,
1589
+ input: args,
1324
1590
  resolve
1325
1591
  });
1326
1592
  emit({
@@ -1330,7 +1596,7 @@ const makeBuffered = (op, size, retryOptions, timeoutOptions) => {
1330
1596
  } else {
1331
1597
  buffer.shift().resolve(_evictedNil);
1332
1598
  buffer.push({
1333
- input,
1599
+ input: args,
1334
1600
  resolve
1335
1601
  });
1336
1602
  emit({
@@ -1361,9 +1627,9 @@ const makeBuffered = (op, size, retryOptions, timeoutOptions) => {
1361
1627
  return () => subscribers.delete(cb);
1362
1628
  },
1363
1629
  reset: () => emit(_idle),
1364
- poll: (input, { interval }) => {
1365
- run(input);
1366
- const id = setInterval(() => void run(input), getMs$1(interval));
1630
+ poll: ({ interval }) => (...args) => {
1631
+ run(...args);
1632
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1367
1633
  return () => clearInterval(id);
1368
1634
  }
1369
1635
  };
@@ -1383,12 +1649,12 @@ const makeDebounced = (op, duration, leading, maxWait, retryOptions, timeoutOpti
1383
1649
  currentState = state;
1384
1650
  subscribers.forEach((cb) => cb(state));
1385
1651
  };
1386
- const fireLeading = (input, resolve) => {
1652
+ const fireLeading = (args, resolve) => {
1387
1653
  leadingController = new AbortController();
1388
1654
  const controller = leadingController;
1389
1655
  leadingResolve = resolve;
1390
1656
  emit(_pending);
1391
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1657
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1392
1658
  if (leadingController === controller) emit(r);
1393
1659
  } : void 0).then((outcome) => {
1394
1660
  if (leadingController !== controller) return;
@@ -1432,20 +1698,20 @@ const makeDebounced = (op, duration, leading, maxWait, retryOptions, timeoutOpti
1432
1698
  timerId = setTimeout(fireTrailing, delay);
1433
1699
  };
1434
1700
  const inDebounceWindow = () => timerId !== void 0 || leadingController !== void 0 || currentController !== void 0;
1435
- const run = (input) => Deferred.from.Promise(new Promise((resolve) => {
1701
+ const run = (...args) => Deferred.from.Promise(new Promise((resolve) => {
1436
1702
  if (!inDebounceWindow()) {
1437
1703
  firstCallAt = Date.now();
1438
1704
  if (leading) {
1439
- fireLeading(input, resolve);
1705
+ fireLeading(args, resolve);
1440
1706
  scheduleTrailing();
1441
1707
  } else {
1442
- pendingInput = input;
1708
+ pendingInput = args;
1443
1709
  pendingResolve = resolve;
1444
1710
  scheduleTrailing();
1445
1711
  }
1446
1712
  } else {
1447
1713
  const prev = pendingResolve;
1448
- pendingInput = input;
1714
+ pendingInput = args;
1449
1715
  pendingResolve = resolve;
1450
1716
  prev?.(_evictedNil);
1451
1717
  scheduleTrailing();
@@ -1485,9 +1751,9 @@ const makeDebounced = (op, duration, leading, maxWait, retryOptions, timeoutOpti
1485
1751
  return () => subscribers.delete(cb);
1486
1752
  },
1487
1753
  reset: () => emit(_idle),
1488
- poll: (input, { interval }) => {
1489
- run(input);
1490
- const id = setInterval(() => void run(input), getMs$1(interval));
1754
+ poll: ({ interval }) => (...args) => {
1755
+ run(...args);
1756
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1491
1757
  return () => clearInterval(id);
1492
1758
  }
1493
1759
  };
@@ -1504,12 +1770,12 @@ const makeThrottled = (op, duration, trailing, retryOptions, timeoutOptions) =>
1504
1770
  currentState = state;
1505
1771
  subscribers.forEach((cb) => cb(state));
1506
1772
  };
1507
- const fireOp = (input, resolve) => {
1773
+ const fireOp = (args, resolve) => {
1508
1774
  currentResolve = resolve;
1509
1775
  currentController = new AbortController();
1510
1776
  const controller = currentController;
1511
1777
  emit(_pending);
1512
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1778
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1513
1779
  if (currentController === controller) emit(r);
1514
1780
  } : void 0).then((outcome) => {
1515
1781
  if (currentController !== controller) return;
@@ -1524,27 +1790,27 @@ const makeThrottled = (op, duration, trailing, retryOptions, timeoutOptions) =>
1524
1790
  cooldownTimer = setTimeout(() => {
1525
1791
  cooldownTimer = void 0;
1526
1792
  if (trailing && pendingInput !== void 0) {
1527
- const input = pendingInput;
1793
+ const toRun = pendingInput;
1528
1794
  const resolve = pendingResolve;
1529
1795
  pendingInput = void 0;
1530
1796
  pendingResolve = void 0;
1531
- fireOp(input, resolve);
1797
+ fireOp(toRun, resolve);
1532
1798
  startCooldown();
1533
1799
  }
1534
1800
  }, getMs$1(duration));
1535
1801
  };
1536
- const run = (input) => {
1802
+ const run = (...args) => {
1537
1803
  if (cooldownTimer !== void 0) {
1538
1804
  if (!trailing) return Deferred.from.Promise(Promise.resolve(_droppedNil));
1539
1805
  return Deferred.from.Promise(new Promise((resolve) => {
1540
1806
  const prev = pendingResolve;
1541
- pendingInput = input;
1807
+ pendingInput = args;
1542
1808
  pendingResolve = resolve;
1543
1809
  prev?.(_evictedNil);
1544
1810
  }));
1545
1811
  }
1546
1812
  return Deferred.from.Promise(new Promise((resolve) => {
1547
- fireOp(input, resolve);
1813
+ fireOp(args, resolve);
1548
1814
  startCooldown();
1549
1815
  }));
1550
1816
  };
@@ -1576,9 +1842,9 @@ const makeThrottled = (op, duration, trailing, retryOptions, timeoutOptions) =>
1576
1842
  return () => subscribers.delete(cb);
1577
1843
  },
1578
1844
  reset: () => emit(_idle),
1579
- poll: (input, { interval }) => {
1580
- run(input);
1581
- const id = setInterval(() => void run(input), getMs$1(interval));
1845
+ poll: ({ interval }) => (...args) => {
1846
+ run(...args);
1847
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1582
1848
  return () => clearInterval(id);
1583
1849
  }
1584
1850
  };
@@ -1595,13 +1861,13 @@ const makeConcurrent = (op, n, overflow, retryOptions, timeoutOptions) => {
1595
1861
  currentState = state;
1596
1862
  subscribers.forEach((cb) => cb(state));
1597
1863
  };
1598
- const startOne = (input, resolve, myGeneration) => {
1864
+ const startOne = (args, resolve, myGeneration) => {
1599
1865
  inflight++;
1600
1866
  const controller = new AbortController();
1601
1867
  controllers.add(controller);
1602
1868
  inflightResolvers.push(resolve);
1603
1869
  emit(_pending);
1604
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1870
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1605
1871
  if (generation === myGeneration && controllers.has(controller)) emit(r);
1606
1872
  } : void 0).then((outcome) => {
1607
1873
  controllers.delete(controller);
@@ -1620,15 +1886,15 @@ const makeConcurrent = (op, n, overflow, retryOptions, timeoutOptions) => {
1620
1886
  }
1621
1887
  });
1622
1888
  };
1623
- const run = (input) => {
1889
+ const run = (...args) => {
1624
1890
  const myGeneration = generation;
1625
1891
  if (inflight < n) return Deferred.from.Promise(new Promise((resolve) => {
1626
- startOne(input, resolve, myGeneration);
1892
+ startOne(args, resolve, myGeneration);
1627
1893
  }));
1628
1894
  if (overflow === "drop") return Deferred.from.Promise(Promise.resolve(_droppedNil));
1629
1895
  return Deferred.from.Promise(new Promise((resolve) => {
1630
1896
  overflowQueue.push({
1631
- input,
1897
+ input: args,
1632
1898
  resolve
1633
1899
  });
1634
1900
  emit({
@@ -1660,9 +1926,9 @@ const makeConcurrent = (op, n, overflow, retryOptions, timeoutOptions) => {
1660
1926
  return () => subscribers.delete(cb);
1661
1927
  },
1662
1928
  reset: () => emit(_idle),
1663
- poll: (input, { interval }) => {
1664
- run(input);
1665
- const id = setInterval(() => void run(input), getMs$1(interval));
1929
+ poll: ({ interval }) => (...args) => {
1930
+ run(...args);
1931
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1666
1932
  return () => clearInterval(id);
1667
1933
  }
1668
1934
  };
@@ -1675,8 +1941,8 @@ const makeKeyed = (op, keyFn, perKey, timeoutOptions) => {
1675
1941
  const snapshot = new Map(stateMap);
1676
1942
  subscribers.forEach((cb) => cb(snapshot));
1677
1943
  };
1678
- const run = (input) => {
1679
- const k = keyFn(input);
1944
+ const run = (...args) => {
1945
+ const k = keyFn(...args);
1680
1946
  if (slots.has(k)) {
1681
1947
  if (perKey === "exclusive") return Deferred.from.Promise(Promise.resolve(_droppedNil));
1682
1948
  const existing = slots.get(k);
@@ -1693,7 +1959,7 @@ const makeKeyed = (op, keyFn, perKey, timeoutOptions) => {
1693
1959
  });
1694
1960
  stateMap.set(k, _pending);
1695
1961
  emitSnapshot();
1696
- execute(op, input, controller, void 0, timeoutOptions).then((outcome) => {
1962
+ execute(op, args, controller, void 0, timeoutOptions).then((outcome) => {
1697
1963
  const slot = slots.get(k);
1698
1964
  if (!slot || slot.controller !== controller) {
1699
1965
  resolve(_abortedNil);
@@ -1744,9 +2010,9 @@ const makeKeyed = (op, keyFn, perKey, timeoutOptions) => {
1744
2010
  stateMap.clear();
1745
2011
  emitSnapshot();
1746
2012
  },
1747
- poll: (input, { interval }) => {
1748
- run(input);
1749
- const id = setInterval(() => void run(input), getMs$1(interval));
2013
+ poll: ({ interval }) => (...args) => {
2014
+ run(...args);
2015
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1750
2016
  return () => clearInterval(id);
1751
2017
  }
1752
2018
  };
@@ -1760,14 +2026,14 @@ const makeOnce = (op, retryOptions, timeoutOptions) => {
1760
2026
  currentState = state;
1761
2027
  subscribers.forEach((cb) => cb(state));
1762
2028
  };
1763
- const run = (input) => {
2029
+ const run = (...args) => {
1764
2030
  if (currentState.kind !== "Idle") return Deferred.from.Promise(Promise.resolve(_droppedNil));
1765
2031
  return Deferred.from.Promise(new Promise((resolve) => {
1766
2032
  currentResolve = resolve;
1767
2033
  currentController = new AbortController();
1768
2034
  const controller = currentController;
1769
2035
  emit(_pending);
1770
- execute(op, input, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
2036
+ execute(op, args, controller, retryOptions, timeoutOptions, retryOptions ? (r) => {
1771
2037
  if (currentController === controller) emit(r);
1772
2038
  } : void 0).then((outcome) => {
1773
2039
  if (currentController !== controller) return;
@@ -1799,9 +2065,9 @@ const makeOnce = (op, retryOptions, timeoutOptions) => {
1799
2065
  return () => subscribers.delete(cb);
1800
2066
  },
1801
2067
  reset: () => emit(_idle),
1802
- poll: (input, { interval }) => {
1803
- run(input);
1804
- const id = setInterval(() => void run(input), getMs$1(interval));
2068
+ poll: ({ interval }) => (...args) => {
2069
+ run(...args);
2070
+ const id = setInterval(() => void run(...args), getMs$1(interval));
1805
2071
  return () => clearInterval(id);
1806
2072
  }
1807
2073
  };
@@ -1838,7 +2104,7 @@ function interpretFn(op, options) {
1838
2104
  case "debounced": return makeDebounced(op, options.duration, options.leading ?? false, options.maxWait, retryOptions, timeoutOptions);
1839
2105
  case "throttled": return makeThrottled(op, options.duration, options.trailing ?? false, retryOptions, timeoutOptions);
1840
2106
  case "concurrent": return makeConcurrent(op, options.n ?? 1, options.overflow ?? "drop", retryOptions, timeoutOptions);
1841
- case "keyed": return makeKeyed(op, options.key ?? ((i) => i), options.perKey ?? "exclusive", timeoutOptions);
2107
+ case "keyed": return makeKeyed(op, options.key ?? ((...args) => args[0]), options.perKey ?? "exclusive", timeoutOptions);
1842
2108
  }
1843
2109
  }
1844
2110
  const Op = {
@@ -1950,8 +2216,24 @@ const Op = {
1950
2216
  */
1951
2217
  nil: isNil
1952
2218
  },
1953
- create: (factory, onError) => ({ _factory: (input, signal) => Deferred.from.Promise(factory(signal)(input).then((value) => Result.make.ok(value)).catch((error) => signal.aborted ? null : Result.make.err(onError(error)))) }),
1954
- lift: (f) => Op.create((signal) => (input) => f(input, signal), (e) => e),
2219
+ /**
2220
+ * Creates an Op from a signal-accepting factory function that returns the async action,
2221
+ * along with an error mapping handler.
2222
+ *
2223
+ * Arguments to the returned function are automatically inferred as tuple parameters via `Parameters<Fn>`.
2224
+ *
2225
+ * @example
2226
+ * ```ts
2227
+ * const fetchUser = Op.create(
2228
+ * (signal) => (id: string) => fetch(`/users/${id}`, { signal }).then(r => r.json() as Promise<User>),
2229
+ * { onError: (e) => new ApiError(e) },
2230
+ * );
2231
+ * ```
2232
+ */
2233
+ create: (factory, options) => ({ [OP_FACTORY]: (args, signal) => Deferred.from.Promise((async () => {
2234
+ return await factory(signal)(...args);
2235
+ })().then((value) => Result.make.ok(value)).catch((error) => signal.aborted ? null : Result.make.err(options.onError(error)))) }),
2236
+ lift: (f) => Op.create(f, { onError: (e) => e }),
1955
2237
  match: (cases) => (outcome) => {
1956
2238
  if (outcome.kind === "OpOk") return cases.ok(outcome.value);
1957
2239
  if (outcome.kind === "OpErr") return cases.err(outcome.error);
@@ -2261,71 +2543,79 @@ const Ordering = {
2261
2543
  //#endregion
2262
2544
  //#region src/Core/Pair.ts
2263
2545
  const makePair = (first, second) => [first, second];
2264
- const makeArray = (arr) => arr;
2546
+ const makeArray = (items) => items;
2265
2547
  const Pair = {
2266
- from: {
2267
- /**
2268
- * Creates a Pair from two values.
2269
- *
2270
- * @example
2271
- * ```ts
2272
- * Pair.from.pair("Paris", 2_161_000); // ["Paris", 2161000]
2273
- * ```
2274
- */
2275
- pair: makePair,
2276
- /**
2277
- * Creates a Pair from a two-element array.
2278
- *
2279
- * @example
2280
- * ```ts
2281
- * Pair.from.array(["Paris", 2_161_000] as const); // ["Paris", 2161000]
2282
- * ```
2283
- */
2284
- array: makeArray
2285
- },
2548
+ /**
2549
+ * Creates a Pair from two values.
2550
+ *
2551
+ * @example
2552
+ * ```ts
2553
+ * Pair.make("Paris", 2_161_000); // ["Paris", 2161000]
2554
+ * ```
2555
+ */
2556
+ make: makePair,
2557
+ from: {
2558
+ /**
2559
+ * Creates a Pair from a two-element array.
2560
+ *
2561
+ * @example
2562
+ * ```ts
2563
+ * Pair.from.array(["Paris", 2_161_000] as const); // ["Paris", 2161000]
2564
+ * ```
2565
+ */
2566
+ array: makeArray },
2286
2567
  /**
2287
2568
  * Returns the first value from the pair.
2288
2569
  *
2289
2570
  * @example
2290
2571
  * ```ts
2291
- * Pair.first(Pair.from.pair("Paris", 2_161_000)); // "Paris"
2572
+ * Pair.first(Pair.make("Paris", 2_161_000)); // "Paris"
2292
2573
  * ```
2293
2574
  */
2294
- first: (p) => p[0],
2575
+ first: (pair) => pair[0],
2295
2576
  /**
2296
2577
  * Returns the second value from the pair.
2297
2578
  *
2298
2579
  * @example
2299
2580
  * ```ts
2300
- * Pair.second(Pair.from.pair("Paris", 2_161_000)); // 2161000
2581
+ * Pair.second(Pair.make("Paris", 2_161_000)); // 2161000
2301
2582
  * ```
2302
2583
  */
2303
- second: (p) => p[1],
2584
+ second: (pair) => pair[1],
2304
2585
  /**
2305
2586
  * Transforms the first value, leaving the second unchanged.
2306
2587
  *
2588
+ * @see {@link Pair.mapSecond} to transform the second element instead.
2589
+ * @see {@link Pair.mapBoth} to transform both elements at once.
2590
+ *
2307
2591
  * @example
2308
2592
  * ```ts
2309
- * pipe(Pair.from.pair("alice", 42), Pair.mapFirst((s) => s.toUpperCase())); // ["ALICE", 42]
2593
+ * pipe(Pair.make("alice", 42), Pair.mapFirst((s) => s.toUpperCase())); // ["ALICE", 42]
2310
2594
  * ```
2311
2595
  */
2312
- mapFirst: (f) => (p) => [f(p[0]), p[1]],
2596
+ mapFirst: (transform) => (pair) => [transform(pair[0]), pair[1]],
2313
2597
  /**
2314
2598
  * Transforms the second value, leaving the first unchanged.
2315
2599
  *
2600
+ * @see {@link Pair.mapFirst} to transform the first element instead.
2601
+ * @see {@link Pair.mapBoth} to transform both elements at once.
2602
+ *
2316
2603
  * @example
2317
2604
  * ```ts
2318
- * pipe(Pair.from.pair("alice", 42), Pair.mapSecond((n) => n * 2)); // ["alice", 84]
2605
+ * pipe(Pair.make("alice", 42), Pair.mapSecond((n) => n * 2)); // ["alice", 84]
2319
2606
  * ```
2320
2607
  */
2321
- mapSecond: (f) => (p) => [p[0], f(p[1])],
2608
+ mapSecond: (transform) => (pair) => [pair[0], transform(pair[1])],
2322
2609
  /**
2323
2610
  * Transforms both values independently in a single step.
2324
2611
  *
2612
+ * @see {@link Pair.mapFirst} to transform only the first element.
2613
+ * @see {@link Pair.mapSecond} to transform only the second element.
2614
+ *
2325
2615
  * @example
2326
2616
  * ```ts
2327
2617
  * pipe(
2328
- * Pair.from.pair("alice", 42),
2618
+ * Pair.make("alice", 42),
2329
2619
  * Pair.mapBoth(
2330
2620
  * (name) => name.toUpperCase(),
2331
2621
  * (score) => score * 2,
@@ -2333,37 +2623,37 @@ const Pair = {
2333
2623
  * ); // ["ALICE", 84]
2334
2624
  * ```
2335
2625
  */
2336
- mapBoth: (onFirst, onSecond) => (p) => [onFirst(p[0]), onSecond(p[1])],
2626
+ mapBoth: (onFirst, onSecond) => (pair) => [onFirst(pair[0]), onSecond(pair[1])],
2337
2627
  /**
2338
2628
  * Applies a binary function to both values, collapsing the pair into a single value.
2339
2629
  * Useful as the final step when consuming a pair in a pipeline.
2340
2630
  *
2341
2631
  * @example
2342
2632
  * ```ts
2343
- * pipe(Pair.from.pair("Alice", 100), Pair.fold((name, score) => `${name}: ${score}`));
2633
+ * pipe(Pair.make("Alice", 100), Pair.fold((name, score) => `${name}: ${score}`));
2344
2634
  * // "Alice: 100"
2345
2635
  * ```
2346
2636
  */
2347
- fold: (f) => (p) => f(p[0], p[1]),
2637
+ fold: (reducer) => (pair) => reducer(pair[0], pair[1]),
2348
2638
  /**
2349
2639
  * Swaps the two values: `[A, B]` becomes `[B, A]`.
2350
2640
  *
2351
2641
  * @example
2352
2642
  * ```ts
2353
- * Pair.swap(Pair.from.pair("key", 1)); // [1, "key"]
2643
+ * Pair.swap(Pair.make("key", 1)); // [1, "key"]
2354
2644
  * ```
2355
2645
  */
2356
- swap: (p) => [p[1], p[0]],
2646
+ swap: (pair) => [pair[1], pair[0]],
2357
2647
  to: {
2358
2648
  /**
2359
2649
  * Converts the pair to a heterogeneous readonly array `readonly (A | B)[]`.
2360
2650
  *
2361
2651
  * @example
2362
2652
  * ```ts
2363
- * Pair.to.Array(Pair.from.pair("hello", 42)); // ["hello", 42]
2653
+ * Pair.to.array(Pair.make("hello", 42)); // ["hello", 42]
2364
2654
  * ```
2365
2655
  */
2366
- Array: (p) => [...p] },
2656
+ array: (pair) => [...pair] },
2367
2657
  /**
2368
2658
  * Runs a side effect with both values without changing the pair.
2369
2659
  * Useful for logging or debugging in the middle of a pipeline.
@@ -2371,15 +2661,15 @@ Array: (p) => [...p] },
2371
2661
  * @example
2372
2662
  * ```ts
2373
2663
  * pipe(
2374
- * Pair.from.pair("Paris", 2_161_000),
2664
+ * Pair.make("Paris", 2_161_000),
2375
2665
  * Pair.tap((city, pop) => console.log(`${city}: ${pop}`)),
2376
2666
  * Pair.mapSecond((n) => n / 1_000_000),
2377
2667
  * ); // logs "Paris: 2161000", returns ["Paris", 2.161]
2378
2668
  * ```
2379
2669
  */
2380
- tap: (f) => (p) => {
2381
- f(p[0], p[1]);
2382
- return p;
2670
+ tap: (sideEffect) => (pair) => {
2671
+ sideEffect(pair[0], pair[1]);
2672
+ return pair;
2383
2673
  }
2384
2674
  };
2385
2675
  //#endregion
@@ -2622,12 +2912,12 @@ const Reader = {
2622
2912
  * const add = (a: number) => (b: number) => a + b;
2623
2913
  * pipe(
2624
2914
  * Reader.resolve<Config, typeof add>(add),
2625
- * Reader.ap(Reader.asks(c => c.timeout)),
2626
- * Reader.ap(Reader.resolve(5))
2915
+ * Reader.apply(Reader.asks(c => c.timeout)),
2916
+ * Reader.apply(Reader.resolve(5))
2627
2917
  * )(appConfig);
2628
2918
  * ```
2629
2919
  */
2630
- ap: (arg) => (data) => (env) => data(env)(arg(env)),
2920
+ apply: (arg) => (data) => (env) => data(env)(arg(env)),
2631
2921
  /**
2632
2922
  * Executes a side effect on the produced value without changing the Reader.
2633
2923
  * Useful for logging or debugging inside a pipeline.
@@ -2836,10 +3126,10 @@ const makeSuccess = (value) => ({
2836
3126
  kind: "Success",
2837
3127
  value
2838
3128
  });
2839
- const isNotAsked = (data) => data.kind === "NotAsked";
2840
- const isLoading = (data) => data.kind === "Loading";
2841
- const isFailure = (data) => data.kind === "Failure";
2842
- const isSuccess = (data) => data.kind === "Success";
3129
+ const isNotAsked = (remoteData) => remoteData.kind === "NotAsked";
3130
+ const isLoading = (remoteData) => remoteData.kind === "Loading";
3131
+ const isFailure = (remoteData) => remoteData.kind === "Failure";
3132
+ const isSuccess = (remoteData) => remoteData.kind === "Success";
2843
3133
  const RemoteData = {
2844
3134
  make: {
2845
3135
  /**
@@ -2907,6 +3197,8 @@ const RemoteData = {
2907
3197
  /**
2908
3198
  * Type guard that checks if a RemoteData is Failure.
2909
3199
  *
3200
+ * @see {@link RemoteData.is.success} to check if data loaded successfully.
3201
+ *
2910
3202
  * @example
2911
3203
  * ```ts
2912
3204
  * const data = RemoteData.make.failure("Failed");
@@ -2919,6 +3211,8 @@ const RemoteData = {
2919
3211
  /**
2920
3212
  * Type guard that checks if a RemoteData is Success.
2921
3213
  *
3214
+ * @see {@link RemoteData.is.failure} to check if data loading failed.
3215
+ *
2922
3216
  * @example
2923
3217
  * ```ts
2924
3218
  * const data = RemoteData.make.success(42);
@@ -2932,26 +3226,33 @@ const RemoteData = {
2932
3226
  /**
2933
3227
  * Transforms the success value inside a RemoteData.
2934
3228
  *
3229
+ * @see {@link RemoteData.chain} to sequence operations that themselves return a RemoteData.
3230
+ * @see {@link RemoteData.mapError} to transform the error value instead of the success value.
3231
+ *
2935
3232
  * @example
2936
3233
  * ```ts
2937
3234
  * pipe(RemoteData.make.success(5), RemoteData.map(n => n * 2)); // Success(10)
2938
3235
  * pipe(RemoteData.make.loading(), RemoteData.map(n => n * 2)); // Loading
2939
3236
  * ```
2940
3237
  */
2941
- map: (f) => (data) => isSuccess(data) ? makeSuccess(f(data.value)) : data,
3238
+ map: (transform) => (remoteData) => isSuccess(remoteData) ? makeSuccess(transform(remoteData.value)) : remoteData,
2942
3239
  /**
2943
3240
  * Transforms the error value inside a RemoteData.
2944
3241
  *
3242
+ * @see {@link RemoteData.map} to transform the success value instead of the error value.
3243
+ *
2945
3244
  * @example
2946
3245
  * ```ts
2947
3246
  * pipe(RemoteData.make.failure("oops"), RemoteData.mapError(e => e.toUpperCase())); // Failure("OOPS")
2948
3247
  * ```
2949
3248
  */
2950
- mapError: (f) => (data) => isFailure(data) ? makeFailure(f(data.error)) : data,
3249
+ mapError: (transform) => (remoteData) => isFailure(remoteData) ? makeFailure(transform(remoteData.error)) : remoteData,
2951
3250
  /**
2952
- * Chains RemoteData computations. If the input is Success, passes the value to f.
3251
+ * Chains RemoteData computations. If the input is Success, passes the value to transform.
2953
3252
  * Otherwise, propagates the current state.
2954
3253
  *
3254
+ * @see {@link RemoteData.map} to transform the success value without returning a new RemoteData.
3255
+ *
2955
3256
  * @example
2956
3257
  * ```ts
2957
3258
  * pipe(
@@ -2960,7 +3261,7 @@ const RemoteData = {
2960
3261
  * );
2961
3262
  * ```
2962
3263
  */
2963
- chain: (f) => (data) => isSuccess(data) ? f(data.value) : data,
3264
+ chain: (transform) => (remoteData) => isSuccess(remoteData) ? transform(remoteData.value) : remoteData,
2964
3265
  /**
2965
3266
  * Applies a function wrapped in a RemoteData to a value wrapped in a RemoteData.
2966
3267
  *
@@ -2969,27 +3270,29 @@ const RemoteData = {
2969
3270
  * const add = (a: number) => (b: number) => a + b;
2970
3271
  * pipe(
2971
3272
  * RemoteData.make.success(add),
2972
- * RemoteData.ap(RemoteData.make.success(5)),
2973
- * RemoteData.ap(RemoteData.make.success(3))
3273
+ * RemoteData.apply(RemoteData.make.success(5)),
3274
+ * RemoteData.apply(RemoteData.make.success(3))
2974
3275
  * ); // Success(8)
2975
3276
  * ```
2976
3277
  */
2977
- ap: (arg) => (data) => {
2978
- if (isSuccess(data) && isSuccess(arg)) return makeSuccess(data.value(arg.value));
2979
- if (isFailure(data)) return data;
3278
+ apply: (arg) => (remoteData) => {
3279
+ if (isSuccess(remoteData) && isSuccess(arg)) return makeSuccess(remoteData.value(arg.value));
3280
+ if (isFailure(remoteData)) return remoteData;
2980
3281
  if (isFailure(arg)) return arg;
2981
- if (isLoading(data) || isLoading(arg)) return makeLoading();
3282
+ if (isLoading(remoteData) || isLoading(arg)) return makeLoading();
2982
3283
  return makeNotAsked();
2983
3284
  },
2984
3285
  /**
2985
3286
  * Extracts the value from a RemoteData by providing handlers for all four cases.
2986
3287
  *
3288
+ * @see {@link RemoteData.match} for named-case pattern matching with an object literal.
3289
+ *
2987
3290
  * @example
2988
3291
  * ```ts
2989
3292
  * pipe(
2990
3293
  * userData,
2991
3294
  * RemoteData.fold(
2992
- * e => `Error: ${e}`,
3295
+ * error => `Error: ${error}`,
2993
3296
  * () => "Not asked",
2994
3297
  * () => "Loading...",
2995
3298
  * value => `Got: ${value}`
@@ -2997,17 +3300,19 @@ const RemoteData = {
2997
3300
  * );
2998
3301
  * ```
2999
3302
  */
3000
- fold: (onFailure, onNotAsked, onLoading, onSuccess) => (data) => {
3001
- switch (data.kind) {
3002
- case "Failure": return onFailure(data.error);
3303
+ fold: (onFailure, onNotAsked, onLoading, onSuccess) => (remoteData) => {
3304
+ switch (remoteData.kind) {
3305
+ case "Failure": return onFailure(remoteData.error);
3003
3306
  case "NotAsked": return onNotAsked();
3004
3307
  case "Loading": return onLoading();
3005
- case "Success": return onSuccess(data.value);
3308
+ case "Success": return onSuccess(remoteData.value);
3006
3309
  }
3007
3310
  },
3008
3311
  /**
3009
3312
  * Pattern matches on a RemoteData, returning the result of the matching case.
3010
3313
  *
3314
+ * @see {@link RemoteData.fold} for positional argument pattern matching.
3315
+ *
3011
3316
  * @example
3012
3317
  * ```ts
3013
3318
  * pipe(
@@ -3015,24 +3320,26 @@ const RemoteData = {
3015
3320
  * RemoteData.match({
3016
3321
  * notAsked: () => "Click to load",
3017
3322
  * loading: () => "Loading...",
3018
- * failure: e => `Error: ${e}`,
3323
+ * failure: error => `Error: ${error}`,
3019
3324
  * success: user => `Hello, ${user.name}!`
3020
3325
  * })
3021
3326
  * );
3022
3327
  * ```
3023
3328
  */
3024
- match: (cases) => (data) => {
3025
- switch (data.kind) {
3329
+ match: (cases) => (remoteData) => {
3330
+ switch (remoteData.kind) {
3026
3331
  case "NotAsked": return cases.notAsked();
3027
3332
  case "Loading": return cases.loading();
3028
- case "Failure": return cases.failure(data.error);
3029
- case "Success": return cases.success(data.value);
3333
+ case "Failure": return cases.failure(remoteData.error);
3334
+ case "Success": return cases.success(remoteData.value);
3030
3335
  }
3031
3336
  },
3032
3337
  /**
3033
3338
  * Returns the success value or a default value if the RemoteData is not Success.
3034
3339
  * The default can be a different type, widening the result to `A | B`.
3035
3340
  *
3341
+ * @see {@link RemoteData.fold} to handle all four lifecycle states.
3342
+ *
3036
3343
  * @example
3037
3344
  * ```ts
3038
3345
  * pipe(RemoteData.make.success(5), RemoteData.getOrElse(() => 0)); // 5
@@ -3040,10 +3347,12 @@ const RemoteData = {
3040
3347
  * pipe(RemoteData.make.loading<string, number>(), RemoteData.getOrElse(() => null)); // null — typed as number | null
3041
3348
  * ```
3042
3349
  */
3043
- getOrElse: (defaultValue) => (data) => isSuccess(data) ? data.value : defaultValue(),
3350
+ getOrElse: (fallback) => (remoteData) => isSuccess(remoteData) ? remoteData.value : fallback(),
3044
3351
  /**
3045
3352
  * Executes a side effect on the success value without changing the RemoteData.
3046
3353
  *
3354
+ * @see {@link RemoteData.tapError} to perform a side effect on the failure error.
3355
+ *
3047
3356
  * @example
3048
3357
  * ```ts
3049
3358
  * pipe(
@@ -3053,14 +3362,16 @@ const RemoteData = {
3053
3362
  * );
3054
3363
  * ```
3055
3364
  */
3056
- tap: (f) => (data) => {
3057
- if (isSuccess(data)) f(data.value);
3058
- return data;
3365
+ tap: (sideEffect) => (remoteData) => {
3366
+ if (isSuccess(remoteData)) sideEffect(remoteData.value);
3367
+ return remoteData;
3059
3368
  },
3060
3369
  /**
3061
3370
  * Executes a side effect on the failure error without changing the RemoteData.
3062
3371
  * Useful for logging errors.
3063
3372
  *
3373
+ * @see {@link RemoteData.tap} to perform a side effect on the success value.
3374
+ *
3064
3375
  * @example
3065
3376
  * ```ts
3066
3377
  * pipe(
@@ -3070,21 +3381,21 @@ const RemoteData = {
3070
3381
  * );
3071
3382
  * ```
3072
3383
  */
3073
- tapError: (f) => (data) => {
3074
- if (isFailure(data)) f(data.error);
3075
- return data;
3384
+ tapError: (sideEffect) => (remoteData) => {
3385
+ if (isFailure(remoteData)) sideEffect(remoteData.error);
3386
+ return remoteData;
3076
3387
  },
3077
3388
  /**
3078
3389
  * Recovers from a Failure state by providing a fallback RemoteData.
3079
- * The fallback can produce a different success type, widening the result to `RemoteData<E, A | B>`.
3390
+ * The fallback can produce a different success type or resolve with a different error type.
3080
3391
  */
3081
- recover: (fallback) => (data) => isFailure(data) ? fallback(data.error) : data,
3392
+ recover: (fallback) => (remoteData) => isFailure(remoteData) ? fallback(remoteData.error) : remoteData,
3082
3393
  to: {
3083
3394
  /**
3084
3395
  * Converts a RemoteData to a Maybe.
3085
3396
  * Success becomes Some, all other states become None.
3086
3397
  */
3087
- Maybe: (data) => isSuccess(data) ? Maybe.make.some(data.value) : Maybe.make.none(),
3398
+ Maybe: (remoteData) => isSuccess(remoteData) ? Maybe.make.some(remoteData.value) : Maybe.make.none(),
3088
3399
  /**
3089
3400
  * Converts a RemoteData to a Result.
3090
3401
  * Success becomes Ok, Failure becomes Err.
@@ -3098,7 +3409,7 @@ const RemoteData = {
3098
3409
  * ); // Ok(42)
3099
3410
  * ```
3100
3411
  */
3101
- Result: (onNotReady) => (data) => isSuccess(data) ? Result.make.ok(data.value) : Result.make.err(isFailure(data) ? data.error : onNotReady())
3412
+ Result: (onNotReady) => (remoteData) => isSuccess(remoteData) ? Result.make.ok(remoteData.value) : Result.make.err(isFailure(remoteData) ? remoteData.error : onNotReady())
3102
3413
  },
3103
3414
  from: {
3104
3415
  /**
@@ -3111,7 +3422,7 @@ const RemoteData = {
3111
3422
  * setState(RemoteData.from.Result(result)); // Success(user) or Failure(msg)
3112
3423
  * ```
3113
3424
  */
3114
- Result: (data) => Result.is.ok(data) ? makeSuccess(data.value) : makeFailure(data.error),
3425
+ Result: (result) => Result.is.ok(result) ? makeSuccess(result.value) : makeFailure(result.error),
3115
3426
  /**
3116
3427
  * Converts a Maybe to a RemoteData.
3117
3428
  * Some becomes Success, None becomes Failure using the onNone error producer.
@@ -3122,7 +3433,7 @@ const RemoteData = {
3122
3433
  * pipe(Maybe.make.none(), RemoteData.from.Maybe(() => "not found")); // Failure("not found")
3123
3434
  * ```
3124
3435
  */
3125
- Maybe: (onNone) => (data) => Maybe.is.some(data) ? makeSuccess(data.value) : makeFailure(onNone())
3436
+ Maybe: (onNone) => (maybe) => Maybe.is.some(maybe) ? makeSuccess(maybe.value) : makeFailure(onNone())
3126
3437
  },
3127
3438
  /**
3128
3439
  * Filters a `Success` value. When the predicate passes, the value is kept. When it fails,
@@ -3137,7 +3448,7 @@ const RemoteData = {
3137
3448
  * RemoteData.filter(n => n > 0, () => "error")(RemoteData.make.loading()); // Loading
3138
3449
  * ```
3139
3450
  */
3140
- filter: (pred, onFalse) => (data) => isSuccess(data) ? pred(data.value) ? data : makeFailure(onFalse(data.value)) : data
3451
+ filter: (predicate, onFalse) => (remoteData) => isSuccess(remoteData) ? predicate(remoteData.value) ? remoteData : makeFailure(onFalse(remoteData.value)) : remoteData
3141
3452
  };
3142
3453
  //#endregion
3143
3454
  //#region src/Core/Resource.ts
@@ -3145,7 +3456,7 @@ const makeHandlers = (acquire, release) => ({
3145
3456
  acquire,
3146
3457
  release
3147
3458
  });
3148
- const makeTask = (acquire, release) => ({
3459
+ const makeTask$1 = (acquire, release) => ({
3149
3460
  acquire: Task.map((a) => Result.make.ok(a))(acquire),
3150
3461
  release
3151
3462
  });
@@ -3176,7 +3487,7 @@ const Resource = {
3176
3487
  * );
3177
3488
  * ```
3178
3489
  */
3179
- Task: makeTask
3490
+ Task: makeTask$1
3180
3491
  },
3181
3492
  /**
3182
3493
  * Acquires the resource, runs `f` with it, then releases it.
@@ -3239,12 +3550,12 @@ const makeOk$1 = (value) => ({
3239
3550
  kind: "Ok",
3240
3551
  value
3241
3552
  });
3242
- const makeErr$1 = (e) => ({
3553
+ const makeErr$1 = (error) => ({
3243
3554
  kind: "Err",
3244
- error: e
3555
+ error
3245
3556
  });
3246
- const isOk = (data) => data.kind === "Ok";
3247
- const isErr = (data) => data.kind === "Err";
3557
+ const isOk = (result) => result.kind === "Ok";
3558
+ const isErr = (result) => result.kind === "Err";
3248
3559
  const Result = {
3249
3560
  make: {
3250
3561
  /**
@@ -3270,6 +3581,8 @@ const Result = {
3270
3581
  /**
3271
3582
  * Type guard that checks if a Result is Ok.
3272
3583
  *
3584
+ * @see {@link Result.is.err} to check if a Result is an Err failure.
3585
+ *
3273
3586
  * @example
3274
3587
  * ```ts
3275
3588
  * const res = Result.make.ok(42);
@@ -3282,6 +3595,8 @@ const Result = {
3282
3595
  /**
3283
3596
  * Type guard that checks if a Result is Err.
3284
3597
  *
3598
+ * @see {@link Result.is.ok} to check if a Result is an Ok success.
3599
+ *
3285
3600
  * @example
3286
3601
  * ```ts
3287
3602
  * const res = Result.make.err("failed");
@@ -3300,13 +3615,13 @@ const Result = {
3300
3615
  * ```ts
3301
3616
  * const result = Result.tryCatch(
3302
3617
  * () => JSON.parse(rawString),
3303
- * { onError: (e) => `Parse error: ${e}` }
3618
+ * { onError: (error) => `Parse error: ${error}` }
3304
3619
  * );
3305
3620
  * ```
3306
3621
  */
3307
- tryCatch: (f, options) => {
3622
+ tryCatch: (fn, options) => {
3308
3623
  try {
3309
- return makeOk$1(f());
3624
+ return makeOk$1(fn());
3310
3625
  } catch (error) {
3311
3626
  return makeErr$1(options.onError(error));
3312
3627
  }
@@ -3314,26 +3629,33 @@ const Result = {
3314
3629
  /**
3315
3630
  * Transforms the success value inside a Result.
3316
3631
  *
3632
+ * @see {@link Result.chain} to sequence operations that themselves return a Result.
3633
+ * @see {@link Result.mapError} to transform the error value instead of the success value.
3634
+ *
3317
3635
  * @example
3318
3636
  * ```ts
3319
3637
  * pipe(Result.make.ok(5), Result.map(n => n * 2)); // Ok(10)
3320
3638
  * pipe(Result.make.err("error"), Result.map(n => n * 2)); // Err("error")
3321
3639
  * ```
3322
3640
  */
3323
- map: (f) => (data) => isOk(data) ? makeOk$1(f(data.value)) : data,
3641
+ map: (transform) => (result) => isOk(result) ? makeOk$1(transform(result.value)) : result,
3324
3642
  /**
3325
3643
  * Transforms the error value inside a Result.
3326
3644
  *
3645
+ * @see {@link Result.map} to transform the success value instead of the error value.
3646
+ *
3327
3647
  * @example
3328
3648
  * ```ts
3329
3649
  * pipe(Result.make.err("oops"), Result.mapError(e => e.toUpperCase())); // Err("OOPS")
3330
3650
  * ```
3331
3651
  */
3332
- mapError: (f) => (data) => isErr(data) ? makeErr$1(f(data.error)) : data,
3652
+ mapError: (transform) => (result) => isErr(result) ? makeErr$1(transform(result.error)) : result,
3333
3653
  /**
3334
- * Chains Result computations. If the first is Ok, passes the value to f.
3654
+ * Chains Result computations. If the first is Ok, passes the value to transform.
3335
3655
  * If the first is Err, propagates the error.
3336
3656
  *
3657
+ * @see {@link Result.map} to transform the inner value without returning a new Result.
3658
+ *
3337
3659
  * @example
3338
3660
  * ```ts
3339
3661
  * const validatePositive = (n: number): Result<string, number> =>
@@ -3343,25 +3665,29 @@ const Result = {
3343
3665
  * pipe(Result.make.ok(-1), Result.chain(validatePositive)); // Err("Must be positive")
3344
3666
  * ```
3345
3667
  */
3346
- chain: (f) => (data) => isOk(data) ? f(data.value) : data,
3668
+ chain: (transform) => (result) => isOk(result) ? transform(result.value) : result,
3347
3669
  /**
3348
3670
  * Extracts the value from a Result by providing handlers for both cases.
3349
3671
  *
3672
+ * @see {@link Result.match} for named-case pattern matching with an object literal.
3673
+ *
3350
3674
  * @example
3351
3675
  * ```ts
3352
3676
  * pipe(
3353
3677
  * Result.make.ok(5),
3354
3678
  * Result.fold(
3355
- * e => `Error: ${e}`,
3356
- * n => `Value: ${n}`
3679
+ * error => `Error: ${error}`,
3680
+ * value => `Value: ${value}`
3357
3681
  * )
3358
3682
  * ); // "Value: 5"
3359
3683
  * ```
3360
3684
  */
3361
- fold: (onErr, onOk) => (data) => isOk(data) ? onOk(data.value) : onErr(data.error),
3685
+ fold: (onErr, onOk) => (result) => isOk(result) ? onOk(result.value) : onErr(result.error),
3362
3686
  /**
3363
3687
  * Pattern matches on a Result, returning the result of the matching case.
3364
3688
  *
3689
+ * @see {@link Result.fold} for positional argument pattern matching.
3690
+ *
3365
3691
  * @example
3366
3692
  * ```ts
3367
3693
  * pipe(
@@ -3373,12 +3699,14 @@ const Result = {
3373
3699
  * );
3374
3700
  * ```
3375
3701
  */
3376
- match: (cases) => (data) => isOk(data) ? cases.ok(data.value) : cases.err(data.error),
3702
+ match: (cases) => (result) => isOk(result) ? cases.ok(result.value) : cases.err(result.error),
3377
3703
  /**
3378
3704
  * Returns the success value or a default value if the Result is an error.
3379
3705
  * The default is a thunk `() => B` — evaluated only when the Result is Err.
3380
3706
  * The default can be a different type, widening the result to `A | B`.
3381
3707
  *
3708
+ * @see {@link Result.fold} to handle both the Ok and Err cases.
3709
+ *
3382
3710
  * @example
3383
3711
  * ```ts
3384
3712
  * pipe(Result.make.ok(5), Result.getOrElse(() => 0)); // 5
@@ -3386,11 +3714,13 @@ const Result = {
3386
3714
  * pipe(Result.make.err("error"), Result.getOrElse(() => null)); // null — typed as number | null
3387
3715
  * ```
3388
3716
  */
3389
- getOrElse: (defaultValue) => (data) => isOk(data) ? data.value : defaultValue(),
3717
+ getOrElse: (fallback) => (result) => isOk(result) ? result.value : fallback(),
3390
3718
  /**
3391
3719
  * Executes a side effect on the success value without changing the Result.
3392
3720
  * Useful for logging or debugging.
3393
3721
  *
3722
+ * @see {@link Result.tapError} to perform a side effect on the error value.
3723
+ *
3394
3724
  * @example
3395
3725
  * ```ts
3396
3726
  * pipe(
@@ -3400,14 +3730,16 @@ const Result = {
3400
3730
  * );
3401
3731
  * ```
3402
3732
  */
3403
- tap: (f) => (data) => {
3404
- if (isOk(data)) f(data.value);
3405
- return data;
3733
+ tap: (sideEffect) => (result) => {
3734
+ if (isOk(result)) sideEffect(result.value);
3735
+ return result;
3406
3736
  },
3407
3737
  /**
3408
3738
  * Executes a side effect on the error value without changing the Result.
3409
3739
  * Useful for logging or reporting errors.
3410
3740
  *
3741
+ * @see {@link Result.tap} to perform a side effect on the success value.
3742
+ *
3411
3743
  * @example
3412
3744
  * ```ts
3413
3745
  * pipe(
@@ -3417,9 +3749,9 @@ const Result = {
3417
3749
  * )
3418
3750
  * ```
3419
3751
  */
3420
- tapError: (f) => (data) => {
3421
- if (isErr(data)) f(data.error);
3422
- return data;
3752
+ tapError: (sideEffect) => (result) => {
3753
+ if (isErr(result)) sideEffect(result.error);
3754
+ return result;
3423
3755
  },
3424
3756
  from: {
3425
3757
  /**
@@ -3433,7 +3765,7 @@ const Result = {
3433
3765
  * pipe("", Result.from.Predicate(s => s.length > 0, () => "empty string")); // Err("empty string")
3434
3766
  * ```
3435
3767
  */
3436
- Predicate: (pred, onFalse) => (a) => pred(a) ? makeOk$1(a) : makeErr$1(onFalse(a)),
3768
+ Predicate: (predicate, onFalse) => (value) => predicate(value) ? makeOk$1(value) : makeErr$1(onFalse(value)),
3437
3769
  /**
3438
3770
  * Creates a Result from a nullable value.
3439
3771
  * Returns Ok if the value is not null or undefined, error from onNull otherwise.
@@ -3465,16 +3797,20 @@ const Result = {
3465
3797
  * Result.from.Validation((errors) => errors.join(", "))(Validation.make.failed("error1")); // Err("error1")
3466
3798
  * ```
3467
3799
  */
3468
- Validation: (combineErrors) => (val) => Validation.is.passed(val) ? makeOk$1(val.value) : makeErr$1(combineErrors(val.errors))
3800
+ Validation: (combineErrors) => (validation) => Validation.is.passed(validation) ? makeOk$1(validation.value) : makeErr$1(combineErrors(validation.errors))
3469
3801
  },
3470
3802
  /**
3471
3803
  * Recovers from an error by providing a fallback Result.
3472
- * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
3804
+ * The fallback can produce a different success type or resolve with a different error type.
3805
+ *
3806
+ * @see {@link Result.recoverUnless} to conditionally recover based on the error value.
3473
3807
  */
3474
- recover: (fallback) => (data) => isOk(data) ? data : fallback(data.error),
3808
+ recover: (fallback) => (result) => isOk(result) ? result : fallback(result.error),
3475
3809
  /**
3476
3810
  * Recovers from an error unless the predicate `isBlocked` returns true for that error.
3477
- * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
3811
+ * The fallback can produce a different success type, widening the result to `Result<E1 | E2, A | B>`.
3812
+ *
3813
+ * @see {@link Result.recover} for unconditional error recovery.
3478
3814
  *
3479
3815
  * @example
3480
3816
  * ```ts
@@ -3484,7 +3820,7 @@ const Result = {
3484
3820
  * ); // Ok(0)
3485
3821
  * ```
3486
3822
  */
3487
- recoverUnless: (isBlocked, fallback) => (data) => isErr(data) && !isBlocked(data.error) ? fallback() : data,
3823
+ recoverUnless: (isBlocked, fallback) => (result) => isErr(result) && !isBlocked(result.error) ? fallback(result.error) : result,
3488
3824
  to: {
3489
3825
  /**
3490
3826
  * Converts a Result to a Maybe.
@@ -3496,7 +3832,7 @@ const Result = {
3496
3832
  * Result.to.Maybe(Result.make.err("oops")); // None
3497
3833
  * ```
3498
3834
  */
3499
- Maybe: (data) => isOk(data) ? Maybe.make.some(data.value) : Maybe.make.none(),
3835
+ Maybe: (result) => isOk(result) ? Maybe.make.some(result.value) : Maybe.make.none(),
3500
3836
  /**
3501
3837
  * Converts a `Result` to a `Validation`. `Ok(a)` becomes `Passed(a)`; `Err(e)` becomes `Failed([e])`.
3502
3838
  *
@@ -3506,7 +3842,7 @@ const Result = {
3506
3842
  * Result.to.Validation(Result.make.err("bad")); // Failed(["bad"])
3507
3843
  * ```
3508
3844
  */
3509
- Validation: (data) => Validation.from.Result(data)
3845
+ Validation: (result) => Validation.from.Result(result)
3510
3846
  },
3511
3847
  /**
3512
3848
  * Swaps the outer `Result` and inner `Maybe` context.
@@ -3519,7 +3855,7 @@ const Result = {
3519
3855
  * Result.transposeMaybe(Result.make.err("error")); // Some(Err("error"))
3520
3856
  * ```
3521
3857
  */
3522
- transposeMaybe: (data) => isErr(data) ? Maybe.make.some(data) : Maybe.is.some(data.value) ? Maybe.make.some(makeOk$1(data.value.value)) : Maybe.make.none(),
3858
+ transposeMaybe: (result) => isErr(result) ? Maybe.make.some(result) : Maybe.is.some(result.value) ? Maybe.make.some(makeOk$1(result.value.value)) : Maybe.make.none(),
3523
3859
  /**
3524
3860
  * Applies a function wrapped in a Result to a value wrapped in a Result.
3525
3861
  *
@@ -3528,12 +3864,12 @@ const Result = {
3528
3864
  * const add = (a: number) => (b: number) => a + b;
3529
3865
  * pipe(
3530
3866
  * Result.make.ok(add),
3531
- * Result.ap(Result.make.ok(5)),
3532
- * Result.ap(Result.make.ok(3))
3867
+ * Result.apply(Result.make.ok(5)),
3868
+ * Result.apply(Result.make.ok(3))
3533
3869
  * ); // Ok(8)
3534
3870
  * ```
3535
3871
  */
3536
- ap: (arg) => (data) => isOk(data) && isOk(arg) ? makeOk$1(data.value(arg.value)) : isErr(data) ? data : arg,
3872
+ apply: (arg) => (result) => isOk(result) && isOk(arg) ? makeOk$1(result.value(arg.value)) : isErr(result) ? result : arg,
3537
3873
  /**
3538
3874
  * Converts a Result value into an object containing a single property.
3539
3875
  * Initiates the pipeline accumulator record.
@@ -3543,7 +3879,7 @@ const Result = {
3543
3879
  * pipe(Result.make.ok(42), Result.bindTo("value")); // Ok({ value: 42 })
3544
3880
  * ```
3545
3881
  */
3546
- bindTo: (key) => (data) => isOk(data) ? makeOk$1({ [key]: data.value }) : data,
3882
+ bindTo: (key) => (result) => isOk(result) ? makeOk$1({ [key]: result.value }) : result,
3547
3883
  /**
3548
3884
  * Evaluates a new Result using the current accumulator and attaches the output to a new key.
3549
3885
  *
@@ -3555,11 +3891,11 @@ const Result = {
3555
3891
  * ); // Ok({ a: 1, b: 2 })
3556
3892
  * ```
3557
3893
  */
3558
- bind: (key, f) => (data) => {
3559
- if (!isOk(data)) return data;
3560
- const res = f(data.value);
3894
+ bind: (key, transform) => (result) => {
3895
+ if (!isOk(result)) return result;
3896
+ const res = transform(result.value);
3561
3897
  return isOk(res) ? makeOk$1({
3562
- ...data.value,
3898
+ ...result.value,
3563
3899
  [key]: res.value
3564
3900
  }) : res;
3565
3901
  },
@@ -3585,7 +3921,7 @@ const Result = {
3585
3921
  return makeOk$1(result);
3586
3922
  },
3587
3923
  /**
3588
- * Narrows an `Ok` value with a predicate, converting to `Err(onFail(a))` if the predicate returns false.
3924
+ * Narrows an `Ok` value with a predicate, converting to `Err(onFail(value))` if the predicate returns false.
3589
3925
  *
3590
3926
  * @example
3591
3927
  * ```ts
@@ -3595,7 +3931,7 @@ const Result = {
3595
3931
  * ); // Err("Age 15 is below 18")
3596
3932
  * ```
3597
3933
  */
3598
- ensure: (predicate, onFail) => (data) => isErr(data) ? data : predicate(data.value) ? data : makeErr$1(onFail(data.value)),
3934
+ ensure: (predicate, onFail) => (result) => isErr(result) ? result : predicate(result.value) ? result : makeErr$1(onFail(result.value)),
3599
3935
  /**
3600
3936
  * Transforms both branches of a Result simultaneously.
3601
3937
  * Applies `onErr` to `Err` values and `onOk` to `Ok` values.
@@ -3611,7 +3947,7 @@ const Result = {
3611
3947
  * ); // Ok(10)
3612
3948
  * ```
3613
3949
  */
3614
- bimap: (onErr, onOk) => (data) => isOk(data) ? makeOk$1(onOk(data.value)) : makeErr$1(onErr(data.error))
3950
+ bimap: (onErr, onOk) => (result) => isOk(result) ? makeOk$1(onOk(result.value)) : makeErr$1(onErr(result.error))
3615
3951
  };
3616
3952
  //#endregion
3617
3953
  //#region src/Core/State.ts
@@ -3724,14 +4060,14 @@ const State = {
3724
4060
  * const addCounted = (n: number) => (m: number) => n + m;
3725
4061
  * const program = pipe(
3726
4062
  * State.resolve<number, typeof addCounted>(addCounted),
3727
- * State.ap(State.gets((s: number) => s * 2)),
3728
- * State.ap(State.gets((s: number) => s)),
4063
+ * State.apply(State.gets((s: number) => s * 2)),
4064
+ * State.apply(State.gets((s: number) => s)),
3729
4065
  * );
3730
4066
  *
3731
4067
  * State.evaluate(3)(program); // 6 + 3 = 9
3732
4068
  * ```
3733
4069
  */
3734
- ap: (arg) => (fn) => (s) => {
4070
+ apply: (arg) => (fn) => (s) => {
3735
4071
  const [f, s1] = fn(s);
3736
4072
  const [a, s2] = arg(s1);
3737
4073
  return [f(a), s2];
@@ -3837,194 +4173,11 @@ const State = {
3837
4173
  }
3838
4174
  };
3839
4175
  //#endregion
3840
- //#region src/Core/Stream.ts
3841
- const makeStream = (options) => ({
3842
- options,
3843
- _listeners: /* @__PURE__ */ new Set(),
3844
- _listenerArray: null,
3845
- _queue: [],
3846
- _isEmitting: false
3847
- });
3848
- const emitStream = (target, message) => {
3849
- const targets = Array.isArray(target) ? target : [target];
3850
- const msg = message;
3851
- for (const stream of targets) {
3852
- stream._queue.push(msg);
3853
- if (!stream._isEmitting) {
3854
- stream._isEmitting = true;
3855
- try {
3856
- while (stream._queue.length > 0) {
3857
- const nextMsg = stream._queue.shift();
3858
- if (stream._listenerArray === null) stream._listenerArray = Array.from(stream._listeners);
3859
- const listeners = stream._listenerArray;
3860
- for (const listener of listeners) try {
3861
- listener(nextMsg);
3862
- } catch (err) {
3863
- if (stream.options?.onError) stream.options.onError(err);
3864
- else throw err;
3865
- }
3866
- }
3867
- } finally {
3868
- stream._isEmitting = false;
3869
- }
3870
- }
3871
- }
3872
- };
3873
- const forwardStream = (options) => {
3874
- const targets = Array.isArray(options.to) ? options.to : [options.to];
3875
- const filterSet = options.only ? new Set(options.only) : null;
3876
- const handler = (msg) => {
3877
- if (filterSet !== null && !filterSet.has(msg.kind)) return;
3878
- for (const target of targets) emitStream(target, msg);
3879
- };
3880
- options.from._listeners.add(handler);
3881
- options.from._listenerArray = null;
3882
- return () => {
3883
- options.from._listeners.delete(handler);
3884
- options.from._listenerArray = null;
3885
- };
3886
- };
3887
- const listenStream = (stream, events, options) => {
3888
- const eventList = Array.isArray(events) ? events : [events];
3889
- const isOrdered = options?.ordered ?? false;
3890
- const isStrict = options?.strict ?? false;
3891
- const isOnce = options?.once ?? false;
3892
- const resetKinds = options?.reset ? new Set(Array.isArray(options.reset) ? options.reset : [options.reset]) : null;
3893
- const optionalKinds = options?.optional ? new Set(Array.isArray(options.optional) ? options.optional : [options.optional]) : null;
3894
- const createMatcher = (onMatch) => {
3895
- let sequenceIndex = 0;
3896
- return (msg) => {
3897
- if (resetKinds !== null && resetKinds.has(msg.kind)) {
3898
- sequenceIndex = 0;
3899
- return;
3900
- }
3901
- if (!isOrdered) {
3902
- if (eventList.includes(msg.kind)) onMatch(msg);
3903
- return;
3904
- }
3905
- let expectedKind = eventList[sequenceIndex];
3906
- if (expectedKind !== msg.kind && optionalKinds !== null) {
3907
- let lookaheadIndex = sequenceIndex;
3908
- while (lookaheadIndex < eventList.length && optionalKinds.has(eventList[lookaheadIndex]) && eventList[lookaheadIndex] !== msg.kind) lookaheadIndex++;
3909
- if (lookaheadIndex < eventList.length && eventList[lookaheadIndex] === msg.kind) {
3910
- sequenceIndex = lookaheadIndex;
3911
- expectedKind = eventList[sequenceIndex];
3912
- }
3913
- }
3914
- if (msg.kind === expectedKind) {
3915
- sequenceIndex++;
3916
- if (sequenceIndex === eventList.length) {
3917
- sequenceIndex = 0;
3918
- onMatch(msg);
3919
- }
3920
- } else if (isStrict) sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
3921
- else if (eventList.includes(msg.kind)) sequenceIndex = msg.kind === eventList[0] ? 1 : 0;
3922
- };
3923
- };
3924
- return {
3925
- reduce: (reducer, initialState) => {
3926
- let currentState = initialState;
3927
- const listenerFn = createMatcher((msg) => {
3928
- currentState = reducer(msg, currentState);
3929
- if (isOnce) {
3930
- stream._listeners.delete(listenerFn);
3931
- stream._listenerArray = null;
3932
- }
3933
- });
3934
- const unsubscribe = () => {
3935
- stream._listeners.delete(listenerFn);
3936
- stream._listenerArray = null;
3937
- };
3938
- stream._listeners.add(listenerFn);
3939
- stream._listenerArray = null;
3940
- return {
3941
- unsubscribe,
3942
- getState: () => currentState
3943
- };
3944
- },
3945
- tap: (effect) => {
3946
- const listenerFn = createMatcher((msg) => {
3947
- effect(msg);
3948
- if (isOnce) {
3949
- stream._listeners.delete(listenerFn);
3950
- stream._listenerArray = null;
3951
- }
3952
- });
3953
- const unsubscribe = () => {
3954
- stream._listeners.delete(listenerFn);
3955
- stream._listenerArray = null;
3956
- };
3957
- stream._listeners.add(listenerFn);
3958
- stream._listenerArray = null;
3959
- return unsubscribe;
3960
- }
3961
- };
3962
- };
3963
- const Stream = {
3964
- /**
3965
- * Constructs a new `Stream` instance.
3966
- *
3967
- * @example
3968
- * ```ts
3969
- * const stream = Stream.make<AppMessages>({ name: "app" });
3970
- * ```
3971
- */
3972
- make: makeStream,
3973
- /**
3974
- * Emits a message payload to one or more target streams.
3975
- *
3976
- * Uses a synchronous breadth-first trampoline queue to handle re-entrant emissions deterministically.
3977
- *
3978
- * @example
3979
- * ```ts
3980
- * Stream.emit(streamA, {
3981
- * kind: "userLoggedIn",
3982
- * value: { userId: "user-1" },
3983
- * });
3984
- *
3985
- * Stream.emit([streamA, streamB], {
3986
- * kind: "userLoggedIn",
3987
- * value: { userId: "user-1" },
3988
- * });
3989
- * ```
3990
- */
3991
- emit: emitStream,
3992
- /**
3993
- * Forwards messages from one stream to another (or multiple).
3994
- *
3995
- * @example
3996
- * ```ts
3997
- * const stop = Stream.forward({
3998
- * from: authStream,
3999
- * to: analyticsStream,
4000
- * only: ["userLoggedIn"],
4001
- * });
4002
- * ```
4003
- */
4004
- forward: forwardStream,
4005
- /**
4006
- * Initiates listener registration on a stream for specific event kind(s) or sequence.
4007
- *
4008
- * @example
4009
- * ```ts
4010
- * const sub = Stream.listen(
4011
- * appStream,
4012
- * ["userLoggedIn", "checkoutStarted"],
4013
- * { ordered: true }
4014
- * ).reduce(
4015
- * (msg, state) => ({ count: state.count + 1 }),
4016
- * { count: 0 }
4017
- * );
4018
- * ```
4019
- */
4020
- listen: listenStream
4021
- };
4022
- //#endregion
4023
4176
  //#region src/Core/TaskMaybe.ts
4024
- const makeSome = (value) => Task.resolve(Maybe.make.some(value));
4025
- const makeNone = () => Task.resolve(Maybe.make.none());
4026
- const mapTaskMaybe = (f) => (data) => Task.map(Maybe.map(f))(data);
4027
- const chainTaskMaybe = (f) => (data) => Task.chain((option) => Maybe.is.some(option) ? f(option.value) : Task.resolve(Maybe.make.none()))(data);
4177
+ const makeSome = (value) => Task.make(Maybe.make.some(value));
4178
+ const makeNone = () => Task.make(Maybe.make.none());
4179
+ const mapTaskMaybe = (transform) => (task) => Task.map(Maybe.map(transform))(task);
4180
+ const chainTaskMaybe = (transform) => (task) => Task.chain((maybe) => Maybe.is.some(maybe) ? transform(maybe.value) : Task.make(Maybe.make.none()))(task);
4028
4181
  const TaskMaybe = {
4029
4182
  /**
4030
4183
  * Wraps a value in a Some inside a Task.
@@ -4066,7 +4219,7 @@ const TaskMaybe = {
4066
4219
  * Task.Maybe.from.Maybe(Maybe.make.some(42));
4067
4220
  * ```
4068
4221
  */
4069
- Maybe: (option) => Task.resolve(option),
4222
+ Maybe: (maybe) => Task.make(maybe),
4070
4223
  /**
4071
4224
  * Creates a Task.Maybe from a nullable value.
4072
4225
  * Returns Some if the value is not null or undefined, None otherwise.
@@ -4077,7 +4230,7 @@ const TaskMaybe = {
4077
4230
  * Task.Maybe.from.nullable(null); // resolves to None
4078
4231
  * ```
4079
4232
  */
4080
- nullable: (value) => Task.resolve(Maybe.from.nullable(value)),
4233
+ nullable: (value) => Task.make(Maybe.from.nullable(value)),
4081
4234
  /**
4082
4235
  * Creates a Task.Maybe from a Result.
4083
4236
  * Ok becomes Some, Error becomes None (the error value is discarded).
@@ -4088,7 +4241,7 @@ const TaskMaybe = {
4088
4241
  * Task.Maybe.from.Result(Result.make.err("e")); // resolves to None
4089
4242
  * ```
4090
4243
  */
4091
- Result: (result) => Task.resolve(Result.to.Maybe(result)),
4244
+ Result: (result) => Task.make(Result.to.Maybe(result)),
4092
4245
  /**
4093
4246
  * Lifts a Task into a Task.Maybe by wrapping its result in Some.
4094
4247
  *
@@ -4111,14 +4264,18 @@ const TaskMaybe = {
4111
4264
  * );
4112
4265
  * ```
4113
4266
  */
4114
- tryCatch: (f) => (signal) => Deferred.from.Promise(Promise.resolve(f(signal)).then(Maybe.make.some).catch(() => Maybe.make.none())),
4267
+ tryCatch: (fn) => (signal) => Deferred.from.Promise(Promise.resolve(fn(signal)).then(Maybe.make.some).catch(() => Maybe.make.none())),
4115
4268
  /**
4116
4269
  * Transforms the value inside a Task.Maybe.
4270
+ *
4271
+ * @see {@link Task.Maybe.chain} to sequence operations that themselves return a Task.Maybe.
4117
4272
  */
4118
4273
  map: mapTaskMaybe,
4119
4274
  /**
4120
4275
  * Chains Task.Maybe computations. If the first resolves to Some, passes the
4121
- * value to f. If the first resolves to None, propagates None.
4276
+ * value to transform. If the first resolves to None, propagates None.
4277
+ *
4278
+ * @see {@link Task.Maybe.map} to transform the inner value without returning a new Task.Maybe.
4122
4279
  *
4123
4280
  * @example
4124
4281
  * ```ts
@@ -4133,14 +4290,18 @@ const TaskMaybe = {
4133
4290
  * Applies a function wrapped in a Task.Maybe to a value wrapped in a Task.Maybe.
4134
4291
  * Both Tasks run in parallel.
4135
4292
  */
4136
- ap: (arg) => (data) => (signal) => Deferred.from.Promise(Promise.all([Deferred.to.Promise(data(signal)), Deferred.to.Promise(arg(signal))]).then(([of_, oa]) => Maybe.ap(oa)(of_))),
4293
+ apply: (arg) => (task) => (signal) => Deferred.from.Promise(Promise.all([Deferred.to.Promise(task(signal)), Deferred.to.Promise(arg(signal))]).then(([of_, oa]) => Maybe.apply(oa)(of_))),
4137
4294
  /**
4138
4295
  * Extracts a value from a Task.Maybe by providing handlers for both cases.
4296
+ *
4297
+ * @see {@link Task.Maybe.match} for named-case pattern matching with an object literal.
4139
4298
  */
4140
- fold: (onNone, onSome) => (data) => Task.map(Maybe.fold(onNone, onSome))(data),
4299
+ fold: (onNone, onSome) => (task) => Task.map(Maybe.fold(onNone, onSome))(task),
4141
4300
  /**
4142
4301
  * Pattern matches on a Task.Maybe, returning a Task of the result.
4143
4302
  *
4303
+ * @see {@link Task.Maybe.fold} for positional argument pattern matching.
4304
+ *
4144
4305
  * @example
4145
4306
  * ```ts
4146
4307
  * pipe(
@@ -4152,21 +4313,21 @@ const TaskMaybe = {
4152
4313
  * )();
4153
4314
  * ```
4154
4315
  */
4155
- match: (cases) => (data) => Task.map(Maybe.match(cases))(data),
4316
+ match: (cases) => (task) => Task.map(Maybe.match(cases))(task),
4156
4317
  /**
4157
4318
  * Returns the value or a default if the Task.Maybe resolves to None.
4158
4319
  * The default can be a different type, widening the result to `Task<A | B>`.
4159
4320
  */
4160
- getOrElse: (defaultValue) => (data) => Task.map(Maybe.getOrElse(defaultValue))(data),
4321
+ getOrElse: (fallback) => (task) => Task.map(Maybe.getOrElse(fallback))(task),
4161
4322
  /**
4162
4323
  * Executes a side effect on the value without changing the Task.Maybe.
4163
4324
  * Useful for logging or debugging.
4164
4325
  */
4165
- tap: (f) => (data) => Task.map(Maybe.tap(f))(data),
4326
+ tap: (sideEffect) => (task) => Task.map(Maybe.tap(sideEffect))(task),
4166
4327
  /**
4167
4328
  * Filters the value inside a Task.Maybe. Returns None if the predicate fails.
4168
4329
  */
4169
- filter: (predicate) => (data) => Task.map(Maybe.filter(predicate))(data),
4330
+ filter: (predicate) => (task) => Task.map(Maybe.filter(predicate))(task),
4170
4331
  to: {
4171
4332
  /**
4172
4333
  * Converts a Task.Maybe to a Task.Result, using onNone to produce the error value.
@@ -4179,7 +4340,7 @@ const TaskMaybe = {
4179
4340
  * );
4180
4341
  * ```
4181
4342
  */
4182
- Result: (onNone) => (data) => Task.map(Maybe.to.Result(onNone))(data) },
4343
+ Result: (onNone) => (task) => Task.map(Maybe.to.Result(onNone))(task) },
4183
4344
  /**
4184
4345
  * Lifts a Task.Maybe value into an accumulator object.
4185
4346
  *
@@ -4188,7 +4349,7 @@ Result: (onNone) => (data) => Task.map(Maybe.to.Result(onNone))(data) },
4188
4349
  * pipe(Task.Maybe.make.some(42), Task.Maybe.bindTo("value")); // Task.Maybe({ value: 42 })
4189
4350
  * ```
4190
4351
  */
4191
- bindTo: (key) => (data) => mapTaskMaybe((a) => ({ [key]: a }))(data),
4352
+ bindTo: (key) => (task) => mapTaskMaybe((value) => ({ [key]: value }))(task),
4192
4353
  /**
4193
4354
  * Evaluates a new Task.Maybe using the current accumulator and attaches the output to a new key.
4194
4355
  *
@@ -4200,10 +4361,10 @@ Result: (onNone) => (data) => Task.map(Maybe.to.Result(onNone))(data) },
4200
4361
  * ); // Task.Maybe({ a: 1, b: 2 })
4201
4362
  * ```
4202
4363
  */
4203
- bind: (key, f) => (data) => chainTaskMaybe((a) => mapTaskMaybe((b) => ({
4204
- ...a,
4205
- [key]: b
4206
- }))(f(a)))(data),
4364
+ bind: (key, transform) => (task) => chainTaskMaybe((acc) => mapTaskMaybe((val) => ({
4365
+ ...acc,
4366
+ [key]: val
4367
+ }))(transform(acc)))(task),
4207
4368
  /**
4208
4369
  * Recovers from a None state by providing a fallback Task.Maybe.
4209
4370
  *
@@ -4215,7 +4376,7 @@ Result: (onNone) => (data) => Task.map(Maybe.to.Result(onNone))(data) },
4215
4376
  * ); // Task.Maybe(42)
4216
4377
  * ```
4217
4378
  */
4218
- recover: (fallback) => (data) => Task.chain((maybe) => Maybe.is.none(maybe) ? fallback() : Task.resolve(maybe))(data),
4379
+ recover: (fallback) => (task) => Task.chain((maybe) => Maybe.is.none(maybe) ? fallback() : Task.make(maybe))(task),
4219
4380
  /**
4220
4381
  * Combines a record of Task.Maybes into a single Task.Maybe of a record.
4221
4382
  * Evaluates fields in parallel and returns None if any task resolves to None.
@@ -4254,10 +4415,10 @@ Result: (onNone) => (data) => Task.map(Maybe.to.Result(onNone))(data) },
4254
4415
  };
4255
4416
  //#endregion
4256
4417
  //#region src/Core/TaskResult.ts
4257
- const makeOk = (value) => Task.resolve(Result.make.ok(value));
4258
- const makeErr = (error) => Task.resolve(Result.make.err(error));
4259
- const mapTaskResult = (f) => (data) => Task.map(Result.map(f))(data);
4260
- const chainTaskResult = (f) => (data) => Task.chain((result) => Result.is.ok(result) ? f(result.value) : Task.resolve(Result.make.err(result.error)))(data);
4418
+ const makeOk = (value) => Task.make(Result.make.ok(value));
4419
+ const makeErr = (error) => Task.make(Result.make.err(error));
4420
+ const mapTaskResult = (transform) => (task) => Task.map(Result.map(transform))(task);
4421
+ const chainTaskResult = (transform) => (task) => Task.chain((result) => Result.is.ok(result) ? transform(result.value) : Task.make(Result.make.err(result.error)))(task);
4261
4422
  const TaskResult = {
4262
4423
  make: {
4263
4424
  /**
@@ -4292,7 +4453,7 @@ const TaskResult = {
4292
4453
  * Task.Result.from.nullable(() => "missing")(null); // resolves to Err("missing")
4293
4454
  * ```
4294
4455
  */
4295
- nullable: (onNull) => (value) => Task.resolve(value === null || value === void 0 ? Result.make.err(onNull()) : Result.make.ok(value)),
4456
+ nullable: (onNull) => (value) => Task.make(value === null || value === void 0 ? Result.make.err(onNull()) : Result.make.ok(value)),
4296
4457
  /**
4297
4458
  * Creates a Task.Result from a Maybe.
4298
4459
  * Some becomes Ok, None becomes err from onNone.
@@ -4303,7 +4464,7 @@ const TaskResult = {
4303
4464
  * Task.Result.from.Maybe(() => "empty")(Maybe.make.none()); // resolves to Err("empty")
4304
4465
  * ```
4305
4466
  */
4306
- Maybe: (onNone) => (maybe) => Task.resolve(Maybe.is.none(maybe) ? Result.make.err(onNone()) : Result.make.ok(maybe.value)),
4467
+ Maybe: (onNone) => (maybe) => Task.make(Maybe.is.none(maybe) ? Result.make.err(onNone()) : Result.make.ok(maybe.value)),
4307
4468
  /**
4308
4469
  * Lifts a Result into a Task.Result.
4309
4470
  *
@@ -4312,7 +4473,7 @@ const TaskResult = {
4312
4473
  * Task.Result.from.Result(Result.make.ok(42)); // resolves to Ok(42)
4313
4474
  * ```
4314
4475
  */
4315
- Result: (result) => Task.resolve(result)
4476
+ Result: (result) => Task.make(result)
4316
4477
  },
4317
4478
  to: {
4318
4479
  /**
@@ -4324,7 +4485,7 @@ const TaskResult = {
4324
4485
  * const taskMaybe = pipe(taskResult, Task.Result.to.Maybe);
4325
4486
  * ```
4326
4487
  */
4327
- Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4488
+ Maybe: (task) => Task.map(Result.to.Maybe)(task) },
4328
4489
  /**
4329
4490
  * Creates a Task.Result from a Promise-returning thunk that may throw or reject.
4330
4491
  * Catches any errors and transforms them using the `onError` function into an `Err`.
@@ -4338,36 +4499,51 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4338
4499
  * );
4339
4500
  * ```
4340
4501
  */
4341
- tryCatch: (f, options) => (signal) => Deferred.from.Promise(globalThis.Promise.resolve().then(async () => f(signal)).then(Result.make.ok).catch((error) => Result.make.err(options.onError(error)))),
4502
+ tryCatch: (fn, options) => (signal) => Deferred.from.Promise(globalThis.Promise.resolve().then(async () => fn(signal)).then(Result.make.ok).catch((error) => Result.make.err(options.onError(error)))),
4342
4503
  /**
4343
4504
  * Transforms the success value inside a Task.Result.
4505
+ *
4506
+ * @see {@link Task.Result.chain} to sequence operations that themselves return a Task.Result.
4507
+ * @see {@link Task.Result.mapError} to transform the error value instead of the success value.
4344
4508
  */
4345
4509
  map: mapTaskResult,
4346
4510
  /**
4347
4511
  * Transforms the error value inside a Task.Result.
4512
+ *
4513
+ * @see {@link Task.Result.map} to transform the success value instead of the error value.
4348
4514
  */
4349
- mapError: (f) => (data) => Task.map(Result.mapError(f))(data),
4515
+ mapError: (transform) => (task) => Task.map(Result.mapError(transform))(task),
4350
4516
  /**
4351
- * Chains Task.Result computations. If the first succeeds, passes the value to f.
4517
+ * Chains Task.Result computations. If the first succeeds, passes the value to transform.
4352
4518
  * If the first fails, propagates the error.
4519
+ *
4520
+ * @see {@link Task.Result.map} to transform the inner value without returning a new Task.Result.
4353
4521
  */
4354
4522
  chain: chainTaskResult,
4355
4523
  /**
4356
4524
  * Extracts the value from a Task.Result by providing handlers for both cases.
4525
+ *
4526
+ * @see {@link Task.Result.match} for named-case pattern matching with an object literal.
4357
4527
  */
4358
- fold: (onErr, onOk) => (data) => Task.map(Result.fold(onErr, onOk))(data),
4528
+ fold: (onErr, onOk) => (task) => Task.map(Result.fold(onErr, onOk))(task),
4359
4529
  /**
4360
4530
  * Pattern matches on a Task.Result, returning a Task of the result.
4531
+ *
4532
+ * @see {@link Task.Result.fold} for positional argument pattern matching.
4361
4533
  */
4362
- match: (cases) => (data) => Task.map(Result.match(cases))(data),
4534
+ match: (cases) => (task) => Task.map(Result.match(cases))(task),
4363
4535
  /**
4364
4536
  * Recovers from an error by providing a fallback Task.Result.
4365
- * The fallback can produce a different success type, widening the result to `Task.Result<E, A | B>`.
4537
+ * The fallback can produce a different success type or resolve with a different error type.
4538
+ *
4539
+ * @see {@link Task.Result.recoverUnless} to conditionally recover based on the error value.
4366
4540
  */
4367
- recover: (fallback) => (data) => Task.chain((result) => Result.is.err(result) ? fallback(result.error) : Task.resolve(result))(data),
4541
+ recover: (fallback) => (task) => Task.chain((result) => Result.is.err(result) ? fallback(result.error) : Task.make(result))(task),
4368
4542
  /**
4369
4543
  * Recovers from an error unless the predicate `isBlocked` returns true for that error.
4370
- * The fallback can produce a different success type, widening the result to `Task.Result<E, A | B>`.
4544
+ * The fallback can produce a different success type, widening the result to `Task.Result<E1 | E2, A | B>`.
4545
+ *
4546
+ * @see {@link Task.Result.recover} for unconditional error recovery.
4371
4547
  *
4372
4548
  * @example
4373
4549
  * ```ts
@@ -4380,21 +4556,25 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4380
4556
  * );
4381
4557
  * ```
4382
4558
  */
4383
- recoverUnless: (isBlocked, fallback) => (data) => Task.chain((result) => Result.is.err(result) && !isBlocked(result.error) ? fallback(result.error) : Task.resolve(result))(data),
4559
+ recoverUnless: (isBlocked, fallback) => (task) => Task.chain((result) => Result.is.err(result) && !isBlocked(result.error) ? fallback(result.error) : Task.make(result))(task),
4384
4560
  /**
4385
4561
  * Returns the success value or a default value if the Task.Result is an error.
4386
4562
  * The default can be a different type, widening the result to `Task<A | B>`.
4387
4563
  */
4388
- getOrElse: (defaultValue) => (data) => Task.map(Result.getOrElse(defaultValue))(data),
4564
+ getOrElse: (fallback) => (task) => Task.map(Result.getOrElse(fallback))(task),
4389
4565
  /**
4390
4566
  * Executes a side effect on the success value without changing the Task.Result.
4391
4567
  * Useful for logging or debugging.
4568
+ *
4569
+ * @see {@link Task.Result.tapError} to perform a side effect on the error value.
4392
4570
  */
4393
- tap: (f) => (data) => Task.map(Result.tap(f))(data),
4571
+ tap: (sideEffect) => (task) => Task.map(Result.tap(sideEffect))(task),
4394
4572
  /**
4395
4573
  * Executes a side effect on the error value without changing the Task.Result.
4396
4574
  * Useful for logging or reporting async errors.
4397
4575
  *
4576
+ * @see {@link Task.Result.tap} to perform a side effect on the success value.
4577
+ *
4398
4578
  * @example
4399
4579
  * ```ts
4400
4580
  * pipe(
@@ -4404,12 +4584,12 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4404
4584
  * )
4405
4585
  * ```
4406
4586
  */
4407
- tapError: (f) => (data) => Task.map(Result.tapError(f))(data),
4587
+ tapError: (sideEffect) => (task) => Task.map(Result.tapError(sideEffect))(task),
4408
4588
  /**
4409
4589
  * Applies a function wrapped in a Task.Result to a value wrapped in a Task.Result.
4410
4590
  * Both Tasks run in parallel.
4411
4591
  */
4412
- ap: (arg) => (data) => (signal) => Deferred.from.Promise(Promise.all([Deferred.to.Promise(data(signal)), Deferred.to.Promise(arg(signal))]).then(([of_, oa]) => Result.ap(oa)(of_))),
4592
+ apply: (arg) => (task) => (signal) => Deferred.from.Promise(Promise.all([Deferred.to.Promise(task(signal)), Deferred.to.Promise(arg(signal))]).then(([of_, oa]) => Result.apply(oa)(of_))),
4413
4593
  /**
4414
4594
  * Executes a `Task.Result` with an optional signal, returning `Promise<Result<E, A>>`.
4415
4595
  * Use as a terminal step in a `pipe` chain.
@@ -4435,7 +4615,7 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4435
4615
  * pipe(Task.Result.make.ok(42), Task.Result.bindTo("value")); // Task.Result({ value: 42 })
4436
4616
  * ```
4437
4617
  */
4438
- bindTo: (key) => (data) => mapTaskResult((a) => ({ [key]: a }))(data),
4618
+ bindTo: (key) => (task) => mapTaskResult((value) => ({ [key]: value }))(task),
4439
4619
  /**
4440
4620
  * Evaluates a new Task.Result using the current accumulator and attaches the output to a new key.
4441
4621
  *
@@ -4447,10 +4627,10 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4447
4627
  * ); // Task.Result({ a: 1, b: 2 })
4448
4628
  * ```
4449
4629
  */
4450
- bind: (key, f) => (data) => chainTaskResult((a) => mapTaskResult((b) => ({
4451
- ...a,
4452
- [key]: b
4453
- }))(f(a)))(data),
4630
+ bind: (key, transform) => (task) => chainTaskResult((acc) => mapTaskResult((val) => ({
4631
+ ...acc,
4632
+ [key]: val
4633
+ }))(transform(acc)))(task),
4454
4634
  /**
4455
4635
  * Combines a record of Task.Results into a single Task.Result of a record.
4456
4636
  * Evaluates all tasks in parallel, forwarding the AbortSignal down to each sub-task.
@@ -4481,14 +4661,15 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4481
4661
  * Retries a fallible Task.Result according to a RetryPolicy.
4482
4662
  * If the task succeeds, returns Ok immediately.
4483
4663
  * If the task fails, retries up to policy.attempts times with delays generated by policy.
4664
+ * An optional `when` predicate selectively retries only specific errors (e.g. transient network errors).
4484
4665
  *
4485
4666
  * @example
4486
4667
  * ```ts
4487
4668
  * const policy = RetryPolicy.exponential({ attempts: 3, initial: Duration.milliseconds(100) });
4488
- * const retryableFetch = pipe(fetchData, Task.Result.retry(policy));
4669
+ * const retryableFetch = pipe(fetchData, Task.Result.retry(policy, { when: (err) => isTransient(err) }));
4489
4670
  * ```
4490
4671
  */
4491
- retry: (policy) => (task) => (signal) => Deferred.from.Promise((() => {
4672
+ retry: (policy, options) => (task) => (signal) => Deferred.from.Promise((() => {
4492
4673
  const { attempts } = policy;
4493
4674
  const wait = (duration) => new Promise((res) => {
4494
4675
  let timerId;
@@ -4496,10 +4677,7 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4496
4677
  clearTimeout(timerId);
4497
4678
  res();
4498
4679
  };
4499
- if (signal) {
4500
- if (signal.aborted) return res();
4501
- signal.addEventListener("abort", onAbort, { once: true });
4502
- }
4680
+ if (signal) signal.addEventListener("abort", onAbort, { once: true });
4503
4681
  timerId = setTimeout(() => {
4504
4682
  signal?.removeEventListener("abort", onAbort);
4505
4683
  res();
@@ -4507,6 +4685,7 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4507
4685
  });
4508
4686
  const executeAttempt = (attempt) => Deferred.to.Promise(task(signal)).then((res) => {
4509
4687
  if (Result.is.ok(res) || attempt >= attempts || signal?.aborted) return res;
4688
+ if (options?.when && !options.when(res.error)) return res;
4510
4689
  const delay = policy.getDelay(attempt);
4511
4690
  return wait(delay).then(() => executeAttempt(attempt + 1));
4512
4691
  });
@@ -4564,7 +4743,35 @@ Maybe: (data) => Task.map(Result.to.Maybe)(data) },
4564
4743
  * // [Ok(val1), Err(err2), Ok(val3)]
4565
4744
  * ```
4566
4745
  */
4567
- allSettled: (tasks) => (signal) => Deferred.from.Promise(Promise.all(tasks.map((task) => Deferred.to.Promise(task(signal)))))
4746
+ allSettled: (tasks) => (signal) => Deferred.from.Promise(Promise.all(tasks.map((task) => Deferred.to.Promise(task(signal))))),
4747
+ /**
4748
+ * Narrows the Ok value with a predicate. If the predicate returns false,
4749
+ * converts the value to an Err using onFail.
4750
+ *
4751
+ * @example
4752
+ * ```ts
4753
+ * pipe(
4754
+ * Task.Result.make.ok(42),
4755
+ * Task.Result.ensure(n => n > 50, () => "too small")
4756
+ * ); // Task.Result resolving to Err("too small")
4757
+ * ```
4758
+ */
4759
+ ensure: (predicate, onFail) => (task) => (signal) => Deferred.from.Promise(Deferred.to.Promise(task(signal)).then(Result.ensure(predicate, onFail))),
4760
+ /**
4761
+ * Maps both the Err and Ok channels simultaneously.
4762
+ *
4763
+ * @example
4764
+ * ```ts
4765
+ * pipe(
4766
+ * Task.Result.make.ok(42),
4767
+ * Task.Result.bimap(
4768
+ * (err: string) => new Error(err),
4769
+ * (n: number) => n * 2
4770
+ * )
4771
+ * ); // Task.Result resolving to Ok(84)
4772
+ * ```
4773
+ */
4774
+ bimap: (onErr, onOk) => (task) => (signal) => Deferred.from.Promise(Deferred.to.Promise(task(signal)).then(Result.bimap(onErr, onOk)))
4568
4775
  };
4569
4776
  //#endregion
4570
4777
  //#region src/internal/InternalTypes.ts
@@ -4583,12 +4790,12 @@ const makeFailedAll$1 = (errors) => ({
4583
4790
  kind: "Failed",
4584
4791
  errors
4585
4792
  });
4586
- const isPassed = (data) => data.kind === "Passed";
4587
- const isFailed = (data) => data.kind === "Failed";
4793
+ const isPassed = (validation) => validation.kind === "Passed";
4794
+ const isFailed = (validation) => validation.kind === "Failed";
4588
4795
  function toResult(arg) {
4589
4796
  if (typeof arg === "function") {
4590
4797
  const combine = arg;
4591
- return (val) => isPassed(val) ? Result.make.ok(val.value) : Result.make.err(combine(val.errors));
4798
+ return (validation) => isPassed(validation) ? Result.make.ok(validation.value) : Result.make.err(combine(validation.errors));
4592
4799
  }
4593
4800
  return isPassed(arg) ? Result.make.ok(arg.value) : Result.make.err(arg.errors);
4594
4801
  }
@@ -4626,6 +4833,8 @@ const Validation = {
4626
4833
  /**
4627
4834
  * Type guard that checks if a Validation is passed.
4628
4835
  *
4836
+ * @see {@link Validation.is.failed} to check if a Validation is failed.
4837
+ *
4629
4838
  * @example
4630
4839
  * ```ts
4631
4840
  * const v = Validation.make.passed(42);
@@ -4638,6 +4847,8 @@ const Validation = {
4638
4847
  /**
4639
4848
  * Type guard that checks if a Validation is failed.
4640
4849
  *
4850
+ * @see {@link Validation.is.passed} to check if a Validation is passed.
4851
+ *
4641
4852
  * @example
4642
4853
  * ```ts
4643
4854
  * const v = Validation.make.failed("invalid");
@@ -4656,13 +4867,13 @@ const Validation = {
4656
4867
  * ```ts
4657
4868
  * const result = Validation.tryCatch(
4658
4869
  * () => JSON.parse(rawString),
4659
- * { onError: (e) => `Parse error: ${e}` }
4870
+ * { onError: (error) => `Parse error: ${error}` }
4660
4871
  * );
4661
4872
  * ```
4662
4873
  */
4663
- tryCatch: (f, options) => {
4874
+ tryCatch: (fn, options) => {
4664
4875
  try {
4665
- return makePassed$1(f());
4876
+ return makePassed$1(fn());
4666
4877
  } catch (error) {
4667
4878
  return makeFailed$1(options.onError(error));
4668
4879
  }
@@ -4683,7 +4894,7 @@ const Validation = {
4683
4894
  * validateName(""); // Failed(["Name is required"])
4684
4895
  * ```
4685
4896
  */
4686
- Predicate: (pred, onFalse) => (a) => pred(a) ? makePassed$1(a) : makeFailed$1(onFalse(a)),
4897
+ Predicate: (predicate, onFalse) => (value) => predicate(value) ? makePassed$1(value) : makeFailed$1(onFalse(value)),
4687
4898
  /**
4688
4899
  * Creates a Validation from a nullable value.
4689
4900
  * If the value is null or undefined, returns Failed with the error from onNull.
@@ -4720,69 +4931,74 @@ const Validation = {
4720
4931
  * Validation.from.Result(Result.make.err("bad")); // Failed(["bad"])
4721
4932
  * ```
4722
4933
  */
4723
- Result: (data) => data.kind === "Ok" ? makePassed$1(data.value) : makeFailed$1(data.error)
4934
+ Result: (result) => result.kind === "Ok" ? makePassed$1(result.value) : makeFailed$1(result.error)
4724
4935
  },
4725
4936
  /**
4726
4937
  * Transforms the success value inside a Validation.
4727
4938
  *
4939
+ * @see {@link Validation.mapError} to transform accumulated errors.
4940
+ * @see {@link Validation.apply} to combine multiple validations.
4941
+ *
4728
4942
  * @example
4729
4943
  * ```ts
4730
4944
  * pipe(Validation.make.passed(5), Validation.map(n => n * 2)); // Passed(10)
4731
4945
  * pipe(Validation.make.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
4732
4946
  * ```
4733
4947
  */
4734
- map: (f) => (data) => isPassed(data) ? makePassed$1(f(data.value)) : data,
4948
+ map: (transform) => (validation) => isPassed(validation) ? makePassed$1(transform(validation.value)) : validation,
4735
4949
  /**
4736
4950
  * Transforms the error list inside a Validation.
4737
4951
  *
4952
+ * @see {@link Validation.map} to transform the success value.
4953
+ *
4738
4954
  * @example
4739
4955
  * ```ts
4740
4956
  * pipe(Validation.make.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
4741
4957
  * ```
4742
4958
  */
4743
- mapError: (f) => (data) => isFailed(data) ? makeFailedAll$1(data.errors.map(f)) : data,
4959
+ mapError: (transform) => (validation) => isFailed(validation) ? makeFailedAll$1(validation.errors.map(transform)) : validation,
4744
4960
  /**
4745
4961
  * Applies a function wrapped in a Validation to a value wrapped in a Validation.
4746
- * Accumulates errors from both sides.
4962
+ * Accumulates errors from both sides if both fail, using optional `combineErrors`
4963
+ * or default concatenation.
4964
+ *
4965
+ * @see {@link Validation.product} to combine two validations into a tuple.
4747
4966
  *
4748
4967
  * @example
4749
4968
  * ```ts
4750
4969
  * const add = (a: number) => (b: number) => a + b;
4751
4970
  * pipe(
4752
4971
  * Validation.make.passed(add),
4753
- * Validation.ap(Validation.make.passed(5)),
4754
- * Validation.ap(Validation.make.passed(3))
4972
+ * Validation.apply(Validation.make.passed(5)),
4973
+ * Validation.apply(Validation.make.passed(3))
4755
4974
  * ); // Passed(8)
4756
4975
  *
4757
4976
  * pipe(
4758
4977
  * Validation.make.passed(add),
4759
- * Validation.ap(Validation.make.failed<string>("bad a")),
4760
- * Validation.ap(Validation.make.failed<string>("bad b"))
4978
+ * Validation.apply(Validation.make.failed<string>("bad a")),
4979
+ * Validation.apply(Validation.make.failed<string>("bad b"))
4761
4980
  * ); // Failed(["bad a", "bad b"])
4762
- * ```
4763
- */
4764
- ap: (arg) => (data) => {
4765
- if (isPassed(data)) return isPassed(arg) ? makePassed$1(data.value(arg.value)) : makeFailedAll$1(arg.errors);
4766
- return isPassed(arg) ? makeFailedAll$1(data.errors) : makeFailedAll$1([...data.errors, ...arg.errors]);
4767
- },
4768
- /**
4769
- * Applies a function wrapped in a Validation to a value wrapped in a Validation,
4770
- * using a custom error concatenator function when both sides fail.
4771
4981
  *
4772
- * @example
4773
- * ```ts
4774
- * const concat = (e1: NonEmptyArr<string>, e2: NonEmptyArr<string>): NonEmptyArr<string> =>
4775
- * [...e1, ...e2];
4776
- * pipe(fnVal, Validation.apCustom(concat)(argVal));
4982
+ * // Custom error combination:
4983
+ * pipe(
4984
+ * Validation.make.passed(add),
4985
+ * Validation.apply(Validation.make.failed("err"), {
4986
+ * combineErrors: (e1, e2) => [...e1, ...e2],
4987
+ * })
4988
+ * );
4777
4989
  * ```
4778
4990
  */
4779
- apCustom: (concat) => (arg) => (data) => {
4780
- if (isPassed(data)) return isPassed(arg) ? makePassed$1(data.value(arg.value)) : makeFailedAll$1(arg.errors);
4781
- return isPassed(arg) ? makeFailedAll$1(data.errors) : makeFailedAll$1(concat(data.errors, arg.errors));
4991
+ apply: (arg, options) => (validation) => {
4992
+ if (isPassed(validation)) return isPassed(arg) ? makePassed$1(validation.value(arg.value)) : makeFailedAll$1(arg.errors);
4993
+ if (isPassed(arg)) return makeFailedAll$1(validation.errors);
4994
+ const combined = options?.combineErrors ? options.combineErrors(validation.errors, arg.errors) : [...validation.errors, ...arg.errors];
4995
+ return makeFailedAll$1(combined);
4782
4996
  },
4783
4997
  /**
4784
4998
  * Extracts the value from a Validation by providing handlers for both cases.
4785
4999
  *
5000
+ * @see {@link Validation.match} for named-case pattern matching with an object literal.
5001
+ *
4786
5002
  * @example
4787
5003
  * ```ts
4788
5004
  * pipe(
@@ -4794,10 +5010,12 @@ const Validation = {
4794
5010
  * );
4795
5011
  * ```
4796
5012
  */
4797
- fold: (onFailed, onPassed) => (data) => isPassed(data) ? onPassed(data.value) : onFailed(data.errors),
5013
+ fold: (onFailed, onPassed) => (validation) => isPassed(validation) ? onPassed(validation.value) : onFailed(validation.errors),
4798
5014
  /**
4799
5015
  * Pattern matches on a Validation, returning the result of the matching case.
4800
5016
  *
5017
+ * @see {@link Validation.fold} for positional argument pattern matching.
5018
+ *
4801
5019
  * @example
4802
5020
  * ```ts
4803
5021
  * pipe(
@@ -4809,11 +5027,13 @@ const Validation = {
4809
5027
  * );
4810
5028
  * ```
4811
5029
  */
4812
- match: (cases) => (data) => isPassed(data) ? cases.passed(data.value) : cases.failed(data.errors),
5030
+ match: (cases) => (validation) => isPassed(validation) ? cases.passed(validation.value) : cases.failed(validation.errors),
4813
5031
  /**
4814
5032
  * Returns the success value or a default value if the Validation is failed.
4815
5033
  * The default can be a different type, widening the result to `A | B`.
4816
5034
  *
5035
+ * @see {@link Validation.fold} to handle both the passed and failed cases.
5036
+ *
4817
5037
  * @example
4818
5038
  * ```ts
4819
5039
  * pipe(Validation.make.passed(5), Validation.getOrElse(() => 0)); // 5
@@ -4821,10 +5041,12 @@ const Validation = {
4821
5041
  * pipe(Validation.make.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
4822
5042
  * ```
4823
5043
  */
4824
- getOrElse: (defaultValue) => (data) => isPassed(data) ? data.value : defaultValue(),
5044
+ getOrElse: (fallback) => (validation) => isPassed(validation) ? validation.value : fallback(),
4825
5045
  /**
4826
5046
  * Executes a side effect on the success value without changing the Validation.
4827
5047
  *
5048
+ * @see {@link Validation.tapError} to perform a side effect on accumulated errors.
5049
+ *
4828
5050
  * @example
4829
5051
  * ```ts
4830
5052
  * pipe(
@@ -4834,14 +5056,16 @@ const Validation = {
4834
5056
  * );
4835
5057
  * ```
4836
5058
  */
4837
- tap: (f) => (data) => {
4838
- if (isPassed(data)) f(data.value);
4839
- return data;
5059
+ tap: (sideEffect) => (validation) => {
5060
+ if (isPassed(validation)) sideEffect(validation.value);
5061
+ return validation;
4840
5062
  },
4841
5063
  /**
4842
5064
  * Executes a side effect on the accumulated errors without changing the Validation.
4843
5065
  * Useful for logging or reporting validation failures.
4844
5066
  *
5067
+ * @see {@link Validation.tap} to perform a side effect on the success value.
5068
+ *
4845
5069
  * @example
4846
5070
  * ```ts
4847
5071
  * pipe(
@@ -4851,19 +5075,23 @@ const Validation = {
4851
5075
  * );
4852
5076
  * ```
4853
5077
  */
4854
- tapError: (f) => (data) => {
4855
- if (isFailed(data)) f(data.errors);
4856
- return data;
5078
+ tapError: (sideEffect) => (validation) => {
5079
+ if (isFailed(validation)) sideEffect(validation.errors);
5080
+ return validation;
4857
5081
  },
4858
5082
  /**
4859
5083
  * Recovers from a Failed state by providing a fallback Validation.
4860
5084
  * The fallback receives the accumulated error list so callers can inspect which errors occurred.
4861
- * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
5085
+ * The fallback can produce a different success type or resolve with a different error type.
5086
+ *
5087
+ * @see {@link Validation.recoverUnless} to conditionally recover based on accumulated errors.
4862
5088
  */
4863
- recover: (fallback) => (data) => isPassed(data) ? data : fallback(data.errors),
5089
+ recover: (fallback) => (validation) => isPassed(validation) ? validation : fallback(validation.errors),
4864
5090
  /**
4865
5091
  * Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
4866
- * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
5092
+ * The fallback can produce a different success type, widening the result to `Validation<E1 | E2, A | B>`.
5093
+ *
5094
+ * @see {@link Validation.recover} for unconditional error recovery.
4867
5095
  *
4868
5096
  * @example
4869
5097
  * ```ts
@@ -4873,7 +5101,7 @@ const Validation = {
4873
5101
  * ); // Passed(0)
4874
5102
  * ```
4875
5103
  */
4876
- recoverUnless: (isBlocked, fallback) => (data) => isFailed(data) && !data.errors.some(isBlocked) ? fallback() : data,
5104
+ recoverUnless: (isBlocked, fallback) => (validation) => isFailed(validation) && !validation.errors.some(isBlocked) ? fallback(validation.errors) : validation,
4877
5105
  to: {
4878
5106
  /**
4879
5107
  * Converts a Validation to a Result.
@@ -4899,13 +5127,16 @@ const Validation = {
4899
5127
  * Validation.to.Maybe(Validation.make.failed("bad")); // None
4900
5128
  * ```
4901
5129
  */
4902
- Maybe: (data) => isPassed(data) ? Maybe.make.some(data.value) : Maybe.make.none()
5130
+ Maybe: (validation) => isPassed(validation) ? Maybe.make.some(validation.value) : Maybe.make.none()
4903
5131
  },
4904
5132
  /**
4905
5133
  * Combines two independent Validation instances into a tuple.
4906
5134
  * If both are Passed, returns Passed with both values as a tuple.
4907
5135
  * If either is Failed, accumulates errors from both sides.
4908
5136
  *
5137
+ * @see {@link Validation.productAll} to combine a non-empty list of validations.
5138
+ * @see {@link Validation.apply} to apply a curried function across validations.
5139
+ *
4909
5140
  * @example
4910
5141
  * ```ts
4911
5142
  * Validation.product(
@@ -4928,6 +5159,8 @@ const Validation = {
4928
5159
  * If all are Passed, returns Passed with all values collected into an array.
4929
5160
  * If any are Failed, returns Failed with all accumulated errors.
4930
5161
  *
5162
+ * @see {@link Validation.product} to combine exactly two validations into a pair.
5163
+ *
4931
5164
  * @example
4932
5165
  * ```ts
4933
5166
  * Validation.productAll([
@@ -4938,10 +5171,10 @@ const Validation = {
4938
5171
  * // Passed([name, email, age]) or Failed([...all errors])
4939
5172
  * ```
4940
5173
  */
4941
- productAll: (data) => {
5174
+ productAll: (validations) => {
4942
5175
  const values = [];
4943
5176
  const errors = [];
4944
- for (const v of data) if (isPassed(v)) values.push(v.value);
5177
+ for (const v of validations) if (isPassed(v)) values.push(v.value);
4945
5178
  else errors.push(...v.errors);
4946
5179
  return isNonEmptyArr(errors) ? makeFailedAll$1(errors) : makePassed$1(values);
4947
5180
  },
@@ -4971,13 +5204,116 @@ const Validation = {
4971
5204
  else errors.push(...val.errors);
4972
5205
  }
4973
5206
  return isNonEmptyArr(errors) ? makeFailedAll$1(errors) : makePassed$1(record);
5207
+ },
5208
+ keyed: {
5209
+ /**
5210
+ * Creates a keyed validator function from a schema of field validators.
5211
+ * Evaluates each validator against its corresponding field in the input object,
5212
+ * returning a record where every key holds its own Validation outcome.
5213
+ *
5214
+ * @example
5215
+ * ```ts
5216
+ * const validateUser = Validation.keyed.make({
5217
+ * name: (s: string) => s.length > 0 ? Validation.make.passed(s) : Validation.make.failed("Name required"),
5218
+ * age: (n: number) => n >= 18 ? Validation.make.passed(n) : Validation.make.failed("Must be 18+"),
5219
+ * });
5220
+ *
5221
+ * const result = validateUser({ name: "", age: 16 });
5222
+ * // { name: Failed(["Name required"]), age: Failed(["Must be 18+"]) }
5223
+ * ```
5224
+ */
5225
+ make: (validators) => (input) => {
5226
+ const out = {};
5227
+ for (const key of Object.keys(validators)) out[key] = validators[key](input[key]);
5228
+ return out;
5229
+ },
5230
+ is: {
5231
+ /**
5232
+ * Type guard checking if every keyed field is Passed.
5233
+ *
5234
+ * @see {@link Validation.keyed.is.failed} to check if any keyed field failed.
5235
+ *
5236
+ * @example
5237
+ * ```ts
5238
+ * if (Validation.keyed.is.passed(results)) {
5239
+ * // results.name is Passed<string>, results.age is Passed<number>
5240
+ * }
5241
+ * ```
5242
+ */
5243
+ passed: (keyed) => {
5244
+ for (const key of Object.keys(keyed)) if (keyed[key].kind !== "Passed") return false;
5245
+ return true;
5246
+ },
5247
+ /**
5248
+ * Checks if at least one keyed field is Failed.
5249
+ *
5250
+ * @see {@link Validation.keyed.is.passed} to check if all keyed fields passed.
5251
+ *
5252
+ * @example
5253
+ * ```ts
5254
+ * if (Validation.keyed.is.failed(results)) {
5255
+ * console.log("Validation errors occurred");
5256
+ * }
5257
+ * ```
5258
+ */
5259
+ failed: (keyed) => {
5260
+ for (const key of Object.keys(keyed)) if (keyed[key].kind === "Failed") return true;
5261
+ return false;
5262
+ }
5263
+ },
5264
+ /**
5265
+ * Extracts all validated field values if every field passed.
5266
+ * Returns `Some(data)` if all passed, `None` if any field failed.
5267
+ *
5268
+ * @see {@link Validation.keyed.getErrors} to extract keyed field errors when failures occur.
5269
+ *
5270
+ * @example
5271
+ * ```ts
5272
+ * const passed = Validation.keyed.getPassed(results);
5273
+ * // Some({ name: "Alice", age: 30 }) or None
5274
+ * ```
5275
+ */
5276
+ getPassed: (keyed) => {
5277
+ const out = {};
5278
+ for (const key of Object.keys(keyed)) {
5279
+ const v = keyed[key];
5280
+ if (v.kind !== "Passed") return Maybe.make.none();
5281
+ out[key] = v.value;
5282
+ }
5283
+ return Maybe.make.some(out);
5284
+ },
5285
+ /**
5286
+ * Extracts keyed field errors if any field failed.
5287
+ * Symmetrical to `getPassed`: returns `Some(errors)` when there are failures,
5288
+ * or `None` if every field passed.
5289
+ *
5290
+ * @see {@link Validation.keyed.getPassed} to extract keyed values when all fields pass.
5291
+ *
5292
+ * @example
5293
+ * ```ts
5294
+ * const errors = Validation.keyed.getErrors(results);
5295
+ * // Some({ name: ["Name required"] }) or None
5296
+ * ```
5297
+ */
5298
+ getErrors: (keyed) => {
5299
+ let hasFailed = false;
5300
+ const out = {};
5301
+ for (const key of Object.keys(keyed)) {
5302
+ const v = keyed[key];
5303
+ if (v.kind === "Failed") {
5304
+ hasFailed = true;
5305
+ out[key] = v.errors;
5306
+ }
5307
+ }
5308
+ return hasFailed ? Maybe.make.some(out) : Maybe.make.none();
5309
+ }
4974
5310
  }
4975
5311
  };
4976
5312
  //#endregion
4977
5313
  //#region src/Core/TaskValidation.ts
4978
- const makePassed = (value) => Task.resolve(Validation.make.passed(value));
4979
- const makeFailed = (error) => Task.resolve(Validation.make.failed(error));
4980
- const makeFailedAll = (errors) => Task.resolve(Validation.make.failedAll(errors));
5314
+ const makePassed = (value) => Task.make(Validation.make.passed(value));
5315
+ const makeFailed = (error) => Task.make(Validation.make.failed(error));
5316
+ const makeFailedAll = (errors) => Task.make(Validation.make.failedAll(errors));
4981
5317
  const TaskValidation = {
4982
5318
  make: {
4983
5319
  /**
@@ -5020,7 +5356,7 @@ const TaskValidation = {
5020
5356
  * Task.Validation.from.Validation(Validation.make.passed(42));
5021
5357
  * ```
5022
5358
  */
5023
- Validation: (validation) => Task.resolve(validation),
5359
+ Validation: (validation) => Task.make(validation),
5024
5360
  /**
5025
5361
  * Creates a Task.Validation from a nullable value.
5026
5362
  * If the value is null or undefined, returns Failed with the error from onNull.
@@ -5032,7 +5368,7 @@ const TaskValidation = {
5032
5368
  * Task.Validation.from.nullable(() => "missing")(null); // resolves to Failed(["missing"])
5033
5369
  * ```
5034
5370
  */
5035
- nullable: (onNull) => (value) => Task.resolve(value === null || value === void 0 ? Validation.make.failed(onNull()) : Validation.make.passed(value)),
5371
+ nullable: (onNull) => (value) => Task.make(value === null || value === void 0 ? Validation.make.failed(onNull()) : Validation.make.passed(value)),
5036
5372
  /**
5037
5373
  * Creates a Task.Validation from a Maybe.
5038
5374
  * Some becomes Passed, None becomes Failed with the error from onNone.
@@ -5043,7 +5379,7 @@ const TaskValidation = {
5043
5379
  * Task.Validation.from.Maybe(() => "empty")(Maybe.make.none()); // resolves to Failed(["empty"])
5044
5380
  * ```
5045
5381
  */
5046
- Maybe: (onNone) => (maybe) => Task.resolve(Maybe.is.none(maybe) ? Validation.make.failed(onNone()) : Validation.make.passed(maybe.value)),
5382
+ Maybe: (onNone) => (maybe) => Task.make(Maybe.is.none(maybe) ? Validation.make.failed(onNone()) : Validation.make.passed(maybe.value)),
5047
5383
  /**
5048
5384
  * Creates a Task.Validation from a Result.
5049
5385
  * Ok becomes Passed, Err(e) becomes Failed([e]).
@@ -5054,7 +5390,7 @@ const TaskValidation = {
5054
5390
  * Task.Validation.from.Result(Result.make.err("bad")); // resolves to Failed(["bad"])
5055
5391
  * ```
5056
5392
  */
5057
- Result: (result) => Task.resolve(Validation.from.Result(result))
5393
+ Result: (result) => Task.make(Validation.from.Result(result))
5058
5394
  },
5059
5395
  to: {
5060
5396
  /**
@@ -5066,7 +5402,7 @@ const TaskValidation = {
5066
5402
  * Task.Validation.to.Result((errors) => errors.join(", "))(validationTask);
5067
5403
  * ```
5068
5404
  */
5069
- Result: (combineErrors) => (data) => Task.map(Validation.to.Result(combineErrors))(data),
5405
+ Result: (combineErrors) => (task) => Task.map(Validation.to.Result(combineErrors))(task),
5070
5406
  /**
5071
5407
  * Converts a `Task.Validation` to a `Task.Maybe`.
5072
5408
  * `Passed(a)` becomes `Some(a)`; `Failed(errors)` becomes `None` (errors are discarded).
@@ -5076,7 +5412,7 @@ const TaskValidation = {
5076
5412
  * Task.Validation.to.Maybe(validationTask);
5077
5413
  * ```
5078
5414
  */
5079
- Maybe: (data) => Task.map(Validation.to.Maybe)(data)
5415
+ Maybe: (task) => Task.map(Validation.to.Maybe)(task)
5080
5416
  },
5081
5417
  /**
5082
5418
  * Creates a Task.Validation from a Promise-returning thunk that may throw or reject.
@@ -5091,33 +5427,42 @@ const TaskValidation = {
5091
5427
  * );
5092
5428
  * ```
5093
5429
  */
5094
- tryCatch: (f, options) => (signal) => Deferred.from.Promise(globalThis.Promise.resolve().then(async () => f(signal)).then(Validation.make.passed).catch((error) => Validation.make.failed(options.onError(error)))),
5430
+ tryCatch: (fn, options) => (signal) => Deferred.from.Promise(globalThis.Promise.resolve().then(async () => fn(signal)).then(Validation.make.passed).catch((error) => Validation.make.failed(options.onError(error)))),
5095
5431
  /**
5096
5432
  * Transforms the success value inside a Task.Validation.
5433
+ *
5434
+ * @see {@link Task.Validation.mapError} to transform accumulated errors.
5435
+ * @see {@link Task.Validation.apply} to combine multiple validations in parallel.
5097
5436
  */
5098
- map: (f) => (data) => Task.map(Validation.map(f))(data),
5437
+ map: (transform) => (task) => Task.map(Validation.map(transform))(task),
5099
5438
  /**
5100
5439
  * Applies a function wrapped in a Task.Validation to a value wrapped in a
5101
5440
  * Task.Validation. Both Tasks run in parallel and errors from both sides
5102
5441
  * are accumulated.
5103
5442
  *
5443
+ * @see {@link Task.Validation.product} to combine two validations into a tuple.
5444
+ *
5104
5445
  * @example
5105
5446
  * ```ts
5106
5447
  * pipe(
5107
5448
  * Task.Validation.make.passed((name: string) => (age: number) => ({ name, age })),
5108
- * Task.Validation.ap(validateName(name)),
5109
- * Task.Validation.ap(validateAge(age))
5449
+ * Task.Validation.apply(validateName(name)),
5450
+ * Task.Validation.apply(validateAge(age))
5110
5451
  * )();
5111
5452
  * ```
5112
5453
  */
5113
- ap: (arg) => (data) => (signal) => Deferred.from.Promise(Promise.all([Deferred.to.Promise(data(signal)), Deferred.to.Promise(arg(signal))]).then(([vf, va]) => Validation.ap(va)(vf))),
5454
+ apply: (arg) => (task) => (signal) => Deferred.from.Promise(Promise.all([Deferred.to.Promise(task(signal)), Deferred.to.Promise(arg(signal))]).then(([vf, va]) => Validation.apply(va)(vf))),
5114
5455
  /**
5115
5456
  * Extracts a value from a Task.Validation by providing handlers for both cases.
5457
+ *
5458
+ * @see {@link Task.Validation.match} for named-case pattern matching with an object literal.
5116
5459
  */
5117
- fold: (onFailed, onPassed) => (data) => Task.map(Validation.fold(onFailed, onPassed))(data),
5460
+ fold: (onFailed, onPassed) => (task) => Task.map(Validation.fold(onFailed, onPassed))(task),
5118
5461
  /**
5119
5462
  * Pattern matches on a Task.Validation, returning a Task of the result.
5120
5463
  *
5464
+ * @see {@link Task.Validation.fold} for positional argument pattern matching.
5465
+ *
5121
5466
  * @example
5122
5467
  * ```ts
5123
5468
  * pipe(
@@ -5129,26 +5474,32 @@ const TaskValidation = {
5129
5474
  * )();
5130
5475
  * ```
5131
5476
  */
5132
- match: (cases) => (data) => Task.map(Validation.match(cases))(data),
5477
+ match: (cases) => (task) => Task.map(Validation.match(cases))(task),
5133
5478
  /**
5134
5479
  * Returns the success value or a default value if the Task.Validation is failed.
5135
5480
  * The default can be a different type, widening the result to `Task<A | B>`.
5136
5481
  */
5137
- getOrElse: (defaultValue) => (data) => Task.map(Validation.getOrElse(defaultValue))(data),
5482
+ getOrElse: (fallback) => (task) => Task.map(Validation.getOrElse(fallback))(task),
5138
5483
  /**
5139
5484
  * Executes a side effect on the success value without changing the Task.Validation.
5140
5485
  * Useful for logging or debugging.
5486
+ *
5487
+ * @see {@link Task.Validation.tapError} to perform a side effect on accumulated errors.
5141
5488
  */
5142
- tap: (f) => (data) => Task.map(Validation.tap(f))(data),
5489
+ tap: (sideEffect) => (task) => Task.map(Validation.tap(sideEffect))(task),
5143
5490
  /**
5144
5491
  * Recovers from a Failed state by providing a fallback Task.Validation.
5145
5492
  * The fallback receives the accumulated error list so callers can inspect which errors occurred.
5146
- * The fallback can produce a different success type, widening the result to `Task.Validation<E, A | B>`.
5493
+ * The fallback can produce a different success type or resolve with a different error type.
5494
+ *
5495
+ * @see {@link Task.Validation.recoverUnless} to conditionally recover based on accumulated errors.
5147
5496
  */
5148
- recover: (fallback) => (data) => Task.chain((validation) => Validation.is.passed(validation) ? Task.resolve(validation) : fallback(validation.errors))(data),
5497
+ recover: (fallback) => (task) => Task.chain((validation) => Validation.is.passed(validation) ? Task.make(validation) : fallback(validation.errors))(task),
5149
5498
  /**
5150
5499
  * Recovers from a Failed state unless the predicate `isBlocked` returns true for the accumulated errors.
5151
- * The fallback receives the accumulated errors and can produce a different success type, widening the result to `Task.Validation<E, A | B>`.
5500
+ * The fallback receives the accumulated errors and can produce a different success type, widening the result to `Task.Validation<E1 | E2, A | B>`.
5501
+ *
5502
+ * @see {@link Task.Validation.recover} for unconditional error recovery.
5152
5503
  *
5153
5504
  * @example
5154
5505
  * ```ts
@@ -5161,12 +5512,15 @@ const TaskValidation = {
5161
5512
  * );
5162
5513
  * ```
5163
5514
  */
5164
- recoverUnless: (isBlocked, fallback) => (data) => Task.chain((validation) => Validation.is.passed(validation) ? Task.resolve(validation) : isBlocked(validation.errors) ? Task.resolve(validation) : fallback(validation.errors))(data),
5515
+ recoverUnless: (isBlocked, fallback) => (task) => Task.chain((validation) => Validation.is.passed(validation) ? Task.make(validation) : isBlocked(validation.errors) ? Task.make(validation) : fallback(validation.errors))(task),
5165
5516
  /**
5166
5517
  * Runs two Task.Validations concurrently and combines their results into a tuple.
5167
5518
  * If both are Passed, returns Passed with both values. If either fails, accumulates
5168
5519
  * errors from both sides.
5169
5520
  *
5521
+ * @see {@link Task.Validation.productAll} to combine a list of validations.
5522
+ * @see {@link Task.Validation.apply} to apply a curried function across validations.
5523
+ *
5170
5524
  * @example
5171
5525
  * ```ts
5172
5526
  * await Task.Validation.product(
@@ -5181,6 +5535,8 @@ const TaskValidation = {
5181
5535
  * If all are Passed, returns Passed with all values as an array.
5182
5536
  * If any fail, returns Failed with all accumulated errors.
5183
5537
  *
5538
+ * @see {@link Task.Validation.product} to combine two validations into a pair.
5539
+ *
5184
5540
  * @example
5185
5541
  * ```ts
5186
5542
  * await Task.Validation.productAll([
@@ -5190,13 +5546,15 @@ const TaskValidation = {
5190
5546
  * ])(); // Passed([name, email, age]) or Failed([...all errors])
5191
5547
  * ```
5192
5548
  */
5193
- productAll: (data) => (signal) => Deferred.from.Promise(Promise.all(data.map((t) => Deferred.to.Promise(t(signal)))).then((results) => {
5549
+ productAll: (validations) => (signal) => Deferred.from.Promise(Promise.all(validations.map((t) => Deferred.to.Promise(t(signal)))).then((results) => {
5194
5550
  const [first, ...rest] = results;
5195
5551
  return Validation.productAll([first, ...rest]);
5196
5552
  })),
5197
5553
  /**
5198
5554
  * Transforms all accumulated errors inside a Task.Validation.
5199
5555
  *
5556
+ * @see {@link Task.Validation.map} to transform the success value.
5557
+ *
5200
5558
  * @example
5201
5559
  * ```ts
5202
5560
  * pipe(
@@ -5205,10 +5563,12 @@ const TaskValidation = {
5205
5563
  * ); // Task.Validation(Failed(["OOPS"]))
5206
5564
  * ```
5207
5565
  */
5208
- mapError: (f) => (data) => Task.map(Validation.mapError(f))(data),
5566
+ mapError: (transform) => (task) => Task.map(Validation.mapError(transform))(task),
5209
5567
  /**
5210
5568
  * Executes a side effect on the accumulated errors without changing the Task.Validation.
5211
5569
  *
5570
+ * @see {@link Task.Validation.tap} to perform a side effect on the success value.
5571
+ *
5212
5572
  * @example
5213
5573
  * ```ts
5214
5574
  * pipe(
@@ -5217,7 +5577,7 @@ const TaskValidation = {
5217
5577
  * );
5218
5578
  * ```
5219
5579
  */
5220
- tapError: (f) => (data) => Task.map(Validation.tapError(f))(data),
5580
+ tapError: (sideEffect) => (task) => Task.map(Validation.tapError(sideEffect))(task),
5221
5581
  /**
5222
5582
  * Combines a record of Task.Validations into a single Task.Validation of a record.
5223
5583
  * Evaluates fields in parallel and accumulates all validation errors.
@@ -5260,23 +5620,23 @@ const TaskValidation = {
5260
5620
  const toPromise = (task, signal) => Deferred.to.Promise(task(signal));
5261
5621
  const fromPromise = (f) => (signal) => Deferred.from.Promise(f(signal));
5262
5622
  const getMs = (duration) => Duration.to.milliseconds(duration);
5263
- const resolveTask = (value) => () => Deferred.from.Promise(globalThis.Promise.resolve(value));
5264
- const syncTask = (f) => () => Deferred.from.Promise(globalThis.Promise.resolve(f()));
5623
+ const makeTask = (value) => () => Deferred.from.Promise(globalThis.Promise.resolve(value));
5624
+ const syncTask = (fn) => () => Deferred.from.Promise(globalThis.Promise.resolve(fn()));
5265
5625
  const Task = {
5266
5626
  /**
5267
5627
  * Creates a Task that immediately resolves to the given value.
5268
5628
  *
5269
5629
  * @example
5270
5630
  * ```ts
5271
- * const task = Task.resolve(42);
5631
+ * const task = Task.make(42);
5272
5632
  * const value = await task(); // 42
5273
5633
  * ```
5274
5634
  */
5275
- resolve: resolveTask,
5635
+ make: makeTask,
5276
5636
  from: {
5277
5637
  /**
5278
5638
  * Creates a Task from a lazy synchronous thunk.
5279
- * Unlike `Task.resolve(f())`, `from.sync` does not evaluate `f` until the Task is called.
5639
+ * Unlike `Task.make(f())`, `from.sync` does not evaluate `f` until the Task is called.
5280
5640
  *
5281
5641
  * @example
5282
5642
  * ```ts
@@ -5297,10 +5657,12 @@ sync: syncTask },
5297
5657
  * );
5298
5658
  * ```
5299
5659
  */
5300
- tryCatch: (f, options) => fromPromise((signal) => globalThis.Promise.resolve().then(() => f(signal)).catch((err) => options.onError(err))),
5660
+ tryCatch: (fn, options) => fromPromise((signal) => globalThis.Promise.resolve().then(() => fn(signal)).catch((err) => options.onError(err))),
5301
5661
  /**
5302
5662
  * Transforms the value inside a Task.
5303
5663
  *
5664
+ * @see {@link Task.chain} to sequence operations that return a Task.
5665
+ *
5304
5666
  * @example
5305
5667
  * ```ts
5306
5668
  * pipe(
@@ -5309,9 +5671,11 @@ sync: syncTask },
5309
5671
  * )(); // Deferred<10>
5310
5672
  * ```
5311
5673
  */
5312
- map: (f) => (data) => fromPromise((signal) => toPromise(data, signal).then(f)),
5674
+ map: (transform) => (task) => fromPromise((signal) => toPromise(task, signal).then(transform)),
5313
5675
  /**
5314
- * Chains Task computations. Passes the resolved value of the first Task to f.
5676
+ * Chains Task computations. Passes the resolved value of the first Task to transform.
5677
+ *
5678
+ * @see {@link Task.map} to transform the resolved value without creating a new Task.
5315
5679
  *
5316
5680
  * @example
5317
5681
  * ```ts
@@ -5325,22 +5689,24 @@ sync: syncTask },
5325
5689
  * )(); // Deferred<Preferences>
5326
5690
  * ```
5327
5691
  */
5328
- chain: (f) => (data) => fromPromise((signal) => toPromise(data, signal).then((a) => toPromise(f(a), signal))),
5692
+ chain: (transform) => (task) => fromPromise((signal) => toPromise(task, signal).then((a) => toPromise(transform(a), signal))),
5329
5693
  /**
5330
5694
  * Applies a function wrapped in a Task to a value wrapped in a Task.
5331
5695
  * Both Tasks run in parallel.
5332
5696
  *
5697
+ * @see {@link Task.all} to run multiple independent Tasks in parallel.
5698
+ *
5333
5699
  * @example
5334
5700
  * ```ts
5335
5701
  * const add = (a: number) => (b: number) => a + b;
5336
5702
  * pipe(
5337
- * Task.resolve(add),
5338
- * Task.ap(Task.resolve(5)),
5339
- * Task.ap(Task.resolve(3))
5703
+ * Task.make(add),
5704
+ * Task.apply(Task.make(5)),
5705
+ * Task.apply(Task.make(3))
5340
5706
  * )(); // Deferred<8>
5341
5707
  * ```
5342
5708
  */
5343
- ap: (arg) => (data) => fromPromise((signal) => Promise.all([toPromise(data, signal), toPromise(arg, signal)]).then(([f, a]) => f(a))),
5709
+ apply: (arg) => (task) => fromPromise((signal) => Promise.all([toPromise(task, signal), toPromise(arg, signal)]).then(([f, a]) => f(a))),
5344
5710
  /**
5345
5711
  * Executes a side effect on the value without changing the Task.
5346
5712
  * Useful for logging or debugging.
@@ -5354,20 +5720,42 @@ sync: syncTask },
5354
5720
  * );
5355
5721
  * ```
5356
5722
  */
5357
- tap: (f) => (data) => fromPromise((signal) => toPromise(data, signal).then((a) => {
5358
- f(a);
5723
+ tap: (sideEffect) => (task) => fromPromise((signal) => toPromise(task, signal).then((a) => {
5724
+ sideEffect(a);
5359
5725
  return a;
5360
5726
  })),
5361
5727
  /**
5362
5728
  * Runs multiple Tasks in parallel and collects their results.
5729
+ * An optional `concurrency` option limits the number of tasks executing at any given time.
5730
+ *
5731
+ * @see {@link Task.sequence} to run an array of Tasks concurrently.
5732
+ * @see {@link Task.sequential} to run an array of Tasks one after another in order.
5363
5733
  *
5364
5734
  * @example
5365
5735
  * ```ts
5366
5736
  * Task.all([loadConfig, detectLocale, loadTheme])();
5367
5737
  * // Deferred<[Config, string, Theme]>
5738
+ *
5739
+ * Task.all([loadConfig, detectLocale, loadTheme], { concurrency: 2 })();
5368
5740
  * ```
5369
5741
  */
5370
- all: (tasks) => fromPromise((signal) => Promise.all(tasks.map((t) => toPromise(t, signal)))),
5742
+ all: (tasks, options) => fromPromise((signal) => {
5743
+ const concurrency = options?.concurrency;
5744
+ if (concurrency === void 0 || concurrency <= 0 || tasks.length <= concurrency) return Promise.all(tasks.map((t) => toPromise(t, signal)));
5745
+ const len = tasks.length;
5746
+ const results = new Array(len);
5747
+ let nextIndex = 0;
5748
+ const worker = async () => {
5749
+ while (nextIndex < len) {
5750
+ const currentIndex = nextIndex++;
5751
+ results[currentIndex] = await toPromise(tasks[currentIndex], signal);
5752
+ }
5753
+ };
5754
+ const workerCount = Math.min(concurrency, len);
5755
+ const workers = [];
5756
+ for (let i = 0; i < workerCount; i++) workers.push(worker());
5757
+ return Promise.all(workers).then(() => results);
5758
+ }),
5371
5759
  /**
5372
5760
  * Delays the execution of a Task by the specified duration.
5373
5761
  * Useful for debouncing or rate limiting.
@@ -5375,30 +5763,32 @@ sync: syncTask },
5375
5763
  * @example
5376
5764
  * ```ts
5377
5765
  * pipe(
5378
- * Task.resolve(42),
5766
+ * Task.make(42),
5379
5767
  * Task.delay(Duration.seconds(1))
5380
5768
  * )(); // Resolves after 1 second
5381
5769
  * ```
5382
5770
  */
5383
- delay: (duration) => (data) => fromPromise((signal) => new Promise((res) => {
5771
+ delay: (duration) => (task) => fromPromise((signal) => new Promise((res) => {
5384
5772
  let timerId;
5385
5773
  const onAbort = () => {
5386
5774
  clearTimeout(timerId);
5387
- res(toPromise(data, signal));
5775
+ res(toPromise(task, signal));
5388
5776
  };
5389
5777
  if (signal) {
5390
- if (signal.aborted) return res(toPromise(data, signal));
5778
+ if (signal.aborted) return res(toPromise(task, signal));
5391
5779
  signal.addEventListener("abort", onAbort, { once: true });
5392
5780
  }
5393
5781
  timerId = setTimeout(() => {
5394
5782
  signal?.removeEventListener("abort", onAbort);
5395
- res(toPromise(data, signal));
5783
+ res(toPromise(task, signal));
5396
5784
  }, getMs(duration));
5397
5785
  })),
5398
5786
  /**
5399
5787
  * Runs a Task a fixed number of times sequentially, collecting all results into an array.
5400
5788
  * An optional delay duration can be inserted between runs.
5401
5789
  *
5790
+ * @see {@link Task.poll} to repeatedly run a Task until a predicate is satisfied.
5791
+ *
5402
5792
  * @example
5403
5793
  * ```ts
5404
5794
  * pipe(
@@ -5434,21 +5824,23 @@ sync: syncTask },
5434
5824
  return run(times);
5435
5825
  }),
5436
5826
  /**
5437
- * Runs a Task repeatedly until the result satisfies a predicate, returning that result.
5438
- * An optional delay duration can be inserted between runs.
5439
- * An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
5827
+ * Polls a Task repeatedly until the result satisfies a predicate, returning that result.
5828
+ * An optional delay duration can be inserted between polling runs.
5829
+ * An optional `attempts` cap stops the loop after N calls — the last value is returned
5440
5830
  * regardless of whether the predicate was satisfied.
5441
5831
  *
5832
+ * @see {@link Task.repeat} to run a Task a fixed number of times.
5833
+ *
5442
5834
  * @example
5443
5835
  * ```ts
5444
5836
  * pipe(
5445
5837
  * checkStatus,
5446
- * Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
5838
+ * Task.poll({ until: (s) => s === "ready", delay: Duration.milliseconds(500) })
5447
5839
  * )(); // polls every 500ms until status is "ready"
5448
5840
  * ```
5449
5841
  */
5450
- repeatUntil: (options) => (task) => fromPromise((signal) => {
5451
- const { when: predicate, delay: delayDuration, maxAttempts } = options;
5842
+ poll: (options) => (task) => fromPromise((signal) => {
5843
+ const { until: predicate, delay: delayDuration, attempts } = options;
5452
5844
  const wait = () => new Promise((r) => {
5453
5845
  let timerId;
5454
5846
  const onAbort = () => {
@@ -5465,7 +5857,7 @@ sync: syncTask },
5465
5857
  if (signal?.aborted && lastValue !== void 0) return Promise.resolve(lastValue);
5466
5858
  return toPromise(task, signal).then((a) => {
5467
5859
  if (predicate(a)) return a;
5468
- if (maxAttempts !== void 0 && attempt >= maxAttempts) return a;
5860
+ if (attempts !== void 0 && attempt >= attempts) return a;
5469
5861
  if (signal?.aborted) return a;
5470
5862
  return wait().then(() => run(attempt + 1, a));
5471
5863
  });
@@ -5479,8 +5871,8 @@ sync: syncTask },
5479
5871
  *
5480
5872
  * @example
5481
5873
  * ```ts
5482
- * const fast = Task.resolve("fast");
5483
- * const slow = Task.delay(Duration.milliseconds(200))(Task.resolve("slow"));
5874
+ * const fast = Task.make("fast");
5875
+ * const slow = Task.delay(Duration.milliseconds(200))(Task.make("slow"));
5484
5876
  *
5485
5877
  * await Task.race([fast, slow])(); // "fast"
5486
5878
  * ```
@@ -5511,6 +5903,9 @@ sync: syncTask },
5511
5903
  * Runs an array of Tasks concurrently and collects their results in an array.
5512
5904
  * Forward-propagates the call site's AbortSignal to all subtasks concurrently.
5513
5905
  *
5906
+ * @see {@link Task.sequential} to run an array of tasks one after another in order.
5907
+ * @see {@link Task.all} to run an array or tuple of tasks in parallel with optional concurrency limit.
5908
+ *
5514
5909
  * @example
5515
5910
  * ```ts
5516
5911
  * Task.sequence([loadConfig, detectLocale, loadTheme])();
@@ -5522,10 +5917,12 @@ sync: syncTask },
5522
5917
  * Runs an array of Tasks one at a time in order, collecting all results.
5523
5918
  * Each Task starts only after the previous one resolves.
5524
5919
  *
5920
+ * @see {@link Task.sequence} to run an array of tasks concurrently.
5921
+ *
5525
5922
  * @example
5526
5923
  * ```ts
5527
5924
  * let log: number[] = [];
5528
- * const makeTask = (n: number) => Task.resolve(n);
5925
+ * const makeTask = (n: number) => Task.make(n);
5529
5926
  *
5530
5927
  * await Task.sequential([makeTask(1), makeTask(2), makeTask(3)])();
5531
5928
  * // log = [1, 2, 3] — tasks ran in order
@@ -5640,22 +6037,22 @@ sync: syncTask },
5640
6037
  *
5641
6038
  * @example
5642
6039
  * ```ts
5643
- * pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
6040
+ * pipe(Task.make(42), Task.bindTo("value")); // Task({ value: 42 })
5644
6041
  * ```
5645
6042
  */
5646
- bindTo: (key) => (data) => fromPromise((signal) => toPromise(data, signal).then((a) => ({ [key]: a }))),
6043
+ bindTo: (key) => (task) => fromPromise((signal) => toPromise(task, signal).then((a) => ({ [key]: a }))),
5647
6044
  /**
5648
6045
  * Evaluates a new Task using the current accumulator and attaches the output to a new key.
5649
6046
  *
5650
6047
  * @example
5651
6048
  * ```ts
5652
6049
  * pipe(
5653
- * Task.resolve({ a: 1 }),
5654
- * Task.bind("b", ({ a }) => Task.resolve(a + 1))
6050
+ * Task.make({ a: 1 }),
6051
+ * Task.bind("b", ({ a }) => Task.make(a + 1))
5655
6052
  * ); // Task({ a: 1, b: 2 })
5656
6053
  * ```
5657
6054
  */
5658
- bind: (key, f) => (data) => fromPromise((signal) => toPromise(data, signal).then((a) => toPromise(f(a), signal).then((b) => ({
6055
+ bind: (key, transform) => (task) => fromPromise((signal) => toPromise(task, signal).then((a) => toPromise(transform(a), signal).then((b) => ({
5659
6056
  ...a,
5660
6057
  [key]: b
5661
6058
  })))),
@@ -5729,16 +6126,16 @@ const makeSecond = (value) => ({
5729
6126
  kind: "Second",
5730
6127
  second: value
5731
6128
  });
5732
- const makeBoth = (f, s) => ({
6129
+ const makeBoth = (first, second) => ({
5733
6130
  kind: "Both",
5734
- first: f,
5735
- second: s
6131
+ first,
6132
+ second
5736
6133
  });
5737
- const isFirst = (data) => data.kind === "First";
5738
- const isSecond = (data) => data.kind === "Second";
5739
- const isBoth = (data) => data.kind === "Both";
5740
- const hasFirst = (data) => data.kind === "First" || data.kind === "Both";
5741
- const hasSecond = (data) => data.kind === "Second" || data.kind === "Both";
6134
+ const isFirst = (these) => these.kind === "First";
6135
+ const isSecond = (these) => these.kind === "Second";
6136
+ const isBoth = (these) => these.kind === "Both";
6137
+ const hasFirst = (these) => these.kind === "First" || these.kind === "Both";
6138
+ const hasSecond = (these) => these.kind === "Second" || these.kind === "Both";
5742
6139
  const These = {
5743
6140
  make: {
5744
6141
  /**
@@ -5810,6 +6207,8 @@ const These = {
5810
6207
  /**
5811
6208
  * Returns true if the These contains a first value (First or Both).
5812
6209
  *
6210
+ * @see {@link These.hasSecond} to check if These contains a second value.
6211
+ *
5813
6212
  * @example
5814
6213
  * ```ts
5815
6214
  * These.hasFirst(These.make.first(42)); // true
@@ -5821,6 +6220,8 @@ const These = {
5821
6220
  /**
5822
6221
  * Returns true if the These contains a second value (Second or Both).
5823
6222
  *
6223
+ * @see {@link These.hasFirst} to check if These contains a first value.
6224
+ *
5824
6225
  * @example
5825
6226
  * ```ts
5826
6227
  * These.hasSecond(These.make.second("warn")); // true
@@ -5832,6 +6233,9 @@ const These = {
5832
6233
  /**
5833
6234
  * Transforms the first value, leaving the second unchanged.
5834
6235
  *
6236
+ * @see {@link These.mapSecond} to transform the second element.
6237
+ * @see {@link These.mapBoth} to transform both elements.
6238
+ *
5835
6239
  * @example
5836
6240
  * ```ts
5837
6241
  * pipe(These.make.first(5), These.mapFirst(n => n * 2)); // First(10)
@@ -5839,28 +6243,34 @@ const These = {
5839
6243
  * pipe(These.make.second("warn"), These.mapFirst(n => n * 2)); // Second("warn")
5840
6244
  * ```
5841
6245
  */
5842
- mapFirst: (f) => (data) => {
5843
- if (isSecond(data)) return data;
5844
- if (isFirst(data)) return makeFirst(f(data.first));
5845
- return makeBoth(f(data.first), data.second);
6246
+ mapFirst: (transform) => (these) => {
6247
+ if (isSecond(these)) return these;
6248
+ if (isFirst(these)) return makeFirst(transform(these.first));
6249
+ return makeBoth(transform(these.first), these.second);
5846
6250
  },
5847
6251
  /**
5848
6252
  * Transforms the second value, leaving the first unchanged.
5849
6253
  *
6254
+ * @see {@link These.mapFirst} to transform the first element.
6255
+ * @see {@link These.mapBoth} to transform both elements.
6256
+ *
5850
6257
  * @example
5851
6258
  * ```ts
5852
6259
  * pipe(These.make.second("warn"), These.mapSecond(e => e.toUpperCase())); // Second("WARN")
5853
6260
  * pipe(These.make.both(5, "warn"), These.mapSecond(e => e.toUpperCase())); // Both(5, "WARN")
5854
6261
  * ```
5855
6262
  */
5856
- mapSecond: (f) => (data) => {
5857
- if (isFirst(data)) return data;
5858
- if (isSecond(data)) return makeSecond(f(data.second));
5859
- return makeBoth(data.first, f(data.second));
6263
+ mapSecond: (transform) => (these) => {
6264
+ if (isFirst(these)) return these;
6265
+ if (isSecond(these)) return makeSecond(transform(these.second));
6266
+ return makeBoth(these.first, transform(these.second));
5860
6267
  },
5861
6268
  /**
5862
6269
  * Transforms both the first and second values independently.
5863
6270
  *
6271
+ * @see {@link These.mapFirst} to transform only the first element.
6272
+ * @see {@link These.mapSecond} to transform only the second element.
6273
+ *
5864
6274
  * @example
5865
6275
  * ```ts
5866
6276
  * pipe(
@@ -5869,14 +6279,16 @@ const These = {
5869
6279
  * ); // Both(10, "WARN")
5870
6280
  * ```
5871
6281
  */
5872
- mapBoth: (onFirst, onSecond) => (data) => {
5873
- if (isSecond(data)) return makeSecond(onSecond(data.second));
5874
- if (isFirst(data)) return makeFirst(onFirst(data.first));
5875
- return makeBoth(onFirst(data.first), onSecond(data.second));
6282
+ mapBoth: (onFirst, onSecond) => (these) => {
6283
+ if (isSecond(these)) return makeSecond(onSecond(these.second));
6284
+ if (isFirst(these)) return makeFirst(onFirst(these.first));
6285
+ return makeBoth(onFirst(these.first), onSecond(these.second));
5876
6286
  },
5877
6287
  /**
5878
- * Chains These computations by passing the first value to f.
5879
- * Second propagates unchanged; First and Both apply f to the first value.
6288
+ * Chains These computations by passing the first value to transform.
6289
+ * Second propagates unchanged; First and Both apply transform to the first value.
6290
+ *
6291
+ * @see {@link These.chainSecond} to chain based on the second value.
5880
6292
  *
5881
6293
  * @example
5882
6294
  * ```ts
@@ -5887,13 +6299,15 @@ const These = {
5887
6299
  * pipe(These.make.second("warn"), These.chainFirst(double)); // Second("warn")
5888
6300
  * ```
5889
6301
  */
5890
- chainFirst: (f) => (data) => {
5891
- if (isSecond(data)) return data;
5892
- return f(data.first);
6302
+ chainFirst: (transform) => (these) => {
6303
+ if (isSecond(these)) return these;
6304
+ return transform(these.first);
5893
6305
  },
5894
6306
  /**
5895
- * Chains These computations by passing the second value to f.
5896
- * First propagates unchanged; Second and Both apply f to the second value.
6307
+ * Chains These computations by passing the second value to transform.
6308
+ * First propagates unchanged; Second and Both apply transform to the second value.
6309
+ *
6310
+ * @see {@link These.chainFirst} to chain based on the first value.
5897
6311
  *
5898
6312
  * @example
5899
6313
  * ```ts
@@ -5904,13 +6318,15 @@ const These = {
5904
6318
  * pipe(These.make.first(5), These.chainSecond(shout)); // First(5)
5905
6319
  * ```
5906
6320
  */
5907
- chainSecond: (f) => (data) => {
5908
- if (isFirst(data)) return data;
5909
- return f(data.second);
6321
+ chainSecond: (transform) => (these) => {
6322
+ if (isFirst(these)) return these;
6323
+ return transform(these.second);
5910
6324
  },
5911
6325
  /**
5912
6326
  * Extracts a value from a These by providing handlers for all three cases.
5913
6327
  *
6328
+ * @see {@link These.match} for named-case pattern matching with an object literal.
6329
+ *
5914
6330
  * @example
5915
6331
  * ```ts
5916
6332
  * pipe(
@@ -5923,14 +6339,16 @@ const These = {
5923
6339
  * );
5924
6340
  * ```
5925
6341
  */
5926
- fold: (onFirst, onSecond, onBoth) => (data) => {
5927
- if (isSecond(data)) return onSecond(data.second);
5928
- if (isFirst(data)) return onFirst(data.first);
5929
- return onBoth(data.first, data.second);
6342
+ fold: (onFirst, onSecond, onBoth) => (these) => {
6343
+ if (isSecond(these)) return onSecond(these.second);
6344
+ if (isFirst(these)) return onFirst(these.first);
6345
+ return onBoth(these.first, these.second);
5930
6346
  },
5931
6347
  /**
5932
6348
  * Pattern matches on a These, returning the result of the matching case.
5933
6349
  *
6350
+ * @see {@link These.fold} for positional argument pattern matching.
6351
+ *
5934
6352
  * @example
5935
6353
  * ```ts
5936
6354
  * pipe(
@@ -5943,15 +6361,17 @@ const These = {
5943
6361
  * );
5944
6362
  * ```
5945
6363
  */
5946
- match: (cases) => (data) => {
5947
- if (isSecond(data)) return cases.second(data.second);
5948
- if (isFirst(data)) return cases.first(data.first);
5949
- return cases.both(data.first, data.second);
6364
+ match: (cases) => (these) => {
6365
+ if (isSecond(these)) return cases.second(these.second);
6366
+ if (isFirst(these)) return cases.first(these.first);
6367
+ return cases.both(these.first, these.second);
5950
6368
  },
5951
6369
  /**
5952
6370
  * Returns the first value, or a default if the These has no first value.
5953
6371
  * The default can be a different type, widening the result to `A | C`.
5954
6372
  *
6373
+ * @see {@link These.getSecondOrElse} to retrieve the second value with fallback.
6374
+ *
5955
6375
  * @example
5956
6376
  * ```ts
5957
6377
  * pipe(These.make.first(5), These.getFirstOrElse(() => 0)); // 5
@@ -5960,11 +6380,13 @@ const These = {
5960
6380
  * pipe(These.make.second("warn"), These.getFirstOrElse(() => null)); // null — typed as number | null
5961
6381
  * ```
5962
6382
  */
5963
- getFirstOrElse: (defaultValue) => (data) => hasFirst(data) ? data.first : defaultValue(),
6383
+ getFirstOrElse: (fallback) => (these) => hasFirst(these) ? these.first : fallback(),
5964
6384
  /**
5965
6385
  * Returns the second value, or a default if the These has no second value.
5966
6386
  * The default can be a different type, widening the result to `B | D`.
5967
6387
  *
6388
+ * @see {@link These.getFirstOrElse} to retrieve the first value with fallback.
6389
+ *
5968
6390
  * @example
5969
6391
  * ```ts
5970
6392
  * pipe(These.make.second("warn"), These.getSecondOrElse(() => "none")); // "warn"
@@ -5973,7 +6395,7 @@ const These = {
5973
6395
  * pipe(These.make.first(5), These.getSecondOrElse(() => null)); // null — typed as string | null
5974
6396
  * ```
5975
6397
  */
5976
- getSecondOrElse: (defaultValue) => (data) => hasSecond(data) ? data.second : defaultValue(),
6398
+ getSecondOrElse: (fallback) => (these) => hasSecond(these) ? these.second : fallback(),
5977
6399
  /**
5978
6400
  * Runs a side effect on the first value without changing the These.
5979
6401
  * Useful for logging or debugging.
@@ -5983,9 +6405,9 @@ const These = {
5983
6405
  * pipe(These.make.first(5), These.tap(console.log)); // logs 5, returns First(5)
5984
6406
  * ```
5985
6407
  */
5986
- tap: (f) => (data) => {
5987
- if (hasFirst(data)) f(data.first);
5988
- return data;
6408
+ tap: (sideEffect) => (these) => {
6409
+ if (hasFirst(these)) sideEffect(these.first);
6410
+ return these;
5989
6411
  },
5990
6412
  /**
5991
6413
  * Swaps the roles of first and second values.
@@ -6000,11 +6422,11 @@ const These = {
6000
6422
  * These.swap(These.make.both(5, "warn")); // Both("warn", 5)
6001
6423
  * ```
6002
6424
  */
6003
- swap: (data) => {
6004
- if (isSecond(data)) return makeFirst(data.second);
6005
- if (isFirst(data)) return makeSecond(data.first);
6006
- return makeBoth(data.second, data.first);
6425
+ swap: (these) => {
6426
+ if (isSecond(these)) return makeFirst(these.second);
6427
+ if (isFirst(these)) return makeSecond(these.first);
6428
+ return makeBoth(these.second, these.first);
6007
6429
  }
6008
6430
  };
6009
6431
  //#endregion
6010
- export { Combinable as C, Deferred as S, Maybe as _, Stream as a, Lazy as b, Resource as c, Reader as d, Predicate as f, Op as g, Optional as h, isNonEmptyArr as i, RemoteData as l, Ordering as m, Task as n, State as o, Pair as p, Validation as r, Result as s, These as t, Refinement as u, Logged as v, Equality as x, Lens as y };
6432
+ export { Combinable as C, Deferred as S, Logged as _, State as a, EventBus as b, RemoteData as c, Predicate as d, Pair as f, Maybe as g, Op as h, isNonEmptyArr as i, Refinement as l, Optional as m, Task as n, Result as o, Ordering as p, Validation as r, Resource as s, These as t, Reader as u, Lens as v, Equality as x, Lazy as y };