unthrown 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ var UnwrapError = class extends Error {
32
32
  */
33
33
  var Res = class {
34
34
  map(f) {
35
- if (this.tag !== "Ok") return this;
35
+ if (this.tag !== "Ok") return passThrough(this);
36
36
  try {
37
37
  return okRes(f(this.value));
38
38
  } catch (cause) {
@@ -40,7 +40,7 @@ var Res = class {
40
40
  }
41
41
  }
42
42
  flatMap(f) {
43
- if (this.tag !== "Ok") return this;
43
+ if (this.tag !== "Ok") return passThrough(this);
44
44
  try {
45
45
  return f(this.value);
46
46
  } catch (cause) {
@@ -56,12 +56,45 @@ var Res = class {
56
56
  return defectRes(cause);
57
57
  }
58
58
  }
59
- as(value) {
59
+ flatTap(f) {
60
60
  if (this.tag !== "Ok") return this;
61
+ try {
62
+ const r = f(this.value);
63
+ return r.tag === "Ok" ? this : passThrough(r);
64
+ } catch (cause) {
65
+ return defectRes(cause);
66
+ }
67
+ }
68
+ bind(name, f) {
69
+ if (this.tag !== "Ok") return passThrough(this);
70
+ try {
71
+ const r = f(this.value);
72
+ if (r.tag !== "Ok") return passThrough(r);
73
+ return okRes({
74
+ ...scopeOf(this.value),
75
+ [name]: r.value
76
+ });
77
+ } catch (cause) {
78
+ return defectRes(cause);
79
+ }
80
+ }
81
+ let(name, f) {
82
+ if (this.tag !== "Ok") return passThrough(this);
83
+ try {
84
+ return okRes({
85
+ ...scopeOf(this.value),
86
+ [name]: f(this.value)
87
+ });
88
+ } catch (cause) {
89
+ return defectRes(cause);
90
+ }
91
+ }
92
+ as(value) {
93
+ if (this.tag !== "Ok") return passThrough(this);
61
94
  return okRes(value);
62
95
  }
63
96
  mapErr(f) {
64
- if (this.tag !== "Err") return this;
97
+ if (this.tag !== "Err") return passThrough(this);
65
98
  try {
66
99
  return errRes(f(this.error));
67
100
  } catch (cause) {
@@ -69,7 +102,7 @@ var Res = class {
69
102
  }
70
103
  }
71
104
  orElse(f) {
72
- if (this.tag !== "Err") return this;
105
+ if (this.tag !== "Err") return passThrough(this);
73
106
  try {
74
107
  return f(this.error);
75
108
  } catch (cause) {
@@ -77,7 +110,7 @@ var Res = class {
77
110
  }
78
111
  }
79
112
  recover(f) {
80
- if (this.tag !== "Err") return this;
113
+ if (this.tag !== "Err") return passThrough(this);
81
114
  try {
82
115
  return okRes(f(this.error));
83
116
  } catch (cause) {
@@ -198,6 +231,41 @@ function defectRes(cause) {
198
231
  });
199
232
  }
200
233
  /**
234
+ * Reuse a non-matching variant (an `Err` or `Defect`) as a differently-typed
235
+ * `Result`, with no runtime work. Sound because the passed-through variant
236
+ * carries no value of the changed success type, so retyping it is a no-op — only
237
+ * the phantom type parameter moves. This is the single sanctioned home for that
238
+ * assertion (the same one boxed applies inline at every pass-through); every
239
+ * combinator's short-circuit branch funnels through here instead of casting.
240
+ *
241
+ * @internal
242
+ */
243
+ function passThrough(self) {
244
+ return self;
245
+ }
246
+ /**
247
+ * Validate that a `bind`/`let` scope is a real (non-null) object before merging a
248
+ * key into it.
249
+ *
250
+ * @remarks
251
+ * Do-notation accumulates an **object** scope: a chain starts at `Do()` (an
252
+ * empty object) and every `bind`/`let` returns an object, so in typed code the
253
+ * scope is always an object. The method lives on the general `Result` surface,
254
+ * though, so a primitive `Ok` (e.g. `Ok(5).bind(...)`, or a chain whose value was
255
+ * `map`-ped away from its scope) could reach it. Rather than let `{ ...5 }`
256
+ * silently collapse to `{}` and drop the prior scope, we throw here — the
257
+ * surrounding `try` turns it into a {@link Defect}, surfacing the misuse as the
258
+ * bug it is (a defect is a bug, not an absent value). A `this: object` constraint
259
+ * was rejected: TypeScript does not hard-enforce a constraint inferred solely
260
+ * from `this`, and it breaks `AsyncRes implements AsyncResult`.
261
+ *
262
+ * @internal
263
+ */
264
+ function scopeOf(value) {
265
+ if (typeof value !== "object" || value === null) throw new TypeError("bind/let requires an object scope — start a do-chain with Do()");
266
+ return value;
267
+ }
268
+ /**
201
269
  * The sole runtime implementation of {@link AsyncResult}: wraps a
202
270
  * `Promise<Result>` constructed never to reject. Operates on the public `Result`
203
271
  * union (via `tag`), never on `Res` internals. Never re-exported from `index.ts`.
@@ -214,7 +282,7 @@ var AsyncRes = class AsyncRes {
214
282
  }
215
283
  map(f) {
216
284
  return new AsyncRes(this.promise.then((r) => {
217
- if (r.tag !== "Ok") return r;
285
+ if (r.tag !== "Ok") return passThrough(r);
218
286
  try {
219
287
  return okRes(f(r.value));
220
288
  } catch (cause) {
@@ -224,7 +292,7 @@ var AsyncRes = class AsyncRes {
224
292
  }
225
293
  flatMap(f) {
226
294
  return new AsyncRes(this.promise.then(async (r) => {
227
- if (r.tag !== "Ok") return r;
295
+ if (r.tag !== "Ok") return passThrough(r);
228
296
  try {
229
297
  return await f(r.value);
230
298
  } catch (cause) {
@@ -243,12 +311,51 @@ var AsyncRes = class AsyncRes {
243
311
  }
244
312
  }));
245
313
  }
314
+ flatTap(f) {
315
+ return new AsyncRes(this.promise.then(async (r) => {
316
+ if (r.tag !== "Ok") return passThrough(r);
317
+ try {
318
+ const inner = await f(r.value);
319
+ return inner.tag === "Ok" ? r : passThrough(inner);
320
+ } catch (cause) {
321
+ return defectRes(cause);
322
+ }
323
+ }));
324
+ }
325
+ bind(name, f) {
326
+ return new AsyncRes(this.promise.then(async (r) => {
327
+ if (r.tag !== "Ok") return passThrough(r);
328
+ try {
329
+ const inner = await f(r.value);
330
+ if (inner.tag !== "Ok") return passThrough(inner);
331
+ return okRes({
332
+ ...scopeOf(r.value),
333
+ [name]: inner.value
334
+ });
335
+ } catch (cause) {
336
+ return defectRes(cause);
337
+ }
338
+ }));
339
+ }
340
+ let(name, f) {
341
+ return new AsyncRes(this.promise.then((r) => {
342
+ if (r.tag !== "Ok") return passThrough(r);
343
+ try {
344
+ return okRes({
345
+ ...scopeOf(r.value),
346
+ [name]: f(r.value)
347
+ });
348
+ } catch (cause) {
349
+ return defectRes(cause);
350
+ }
351
+ }));
352
+ }
246
353
  as(value) {
247
- return new AsyncRes(this.promise.then((r) => r.tag === "Ok" ? okRes(value) : r));
354
+ return new AsyncRes(this.promise.then((r) => r.tag === "Ok" ? okRes(value) : passThrough(r)));
248
355
  }
249
356
  mapErr(f) {
250
357
  return new AsyncRes(this.promise.then((r) => {
251
- if (r.tag !== "Err") return r;
358
+ if (r.tag !== "Err") return passThrough(r);
252
359
  try {
253
360
  return errRes(f(r.error));
254
361
  } catch (cause) {
@@ -258,7 +365,7 @@ var AsyncRes = class AsyncRes {
258
365
  }
259
366
  orElse(f) {
260
367
  return new AsyncRes(this.promise.then(async (r) => {
261
- if (r.tag !== "Err") return r;
368
+ if (r.tag !== "Err") return passThrough(r);
262
369
  try {
263
370
  return await f(r.error);
264
371
  } catch (cause) {
@@ -268,7 +375,7 @@ var AsyncRes = class AsyncRes {
268
375
  }
269
376
  recover(f) {
270
377
  return new AsyncRes(this.promise.then((r) => {
271
- if (r.tag !== "Err") return r;
378
+ if (r.tag !== "Err") return passThrough(r);
272
379
  try {
273
380
  return okRes(f(r.error));
274
381
  } catch (cause) {
@@ -344,11 +451,11 @@ var AsyncRes = class AsyncRes {
344
451
  *
345
452
  * @example
346
453
  * ```ts
347
- * import { ok } from "unthrown";
348
- * ok(42).unwrap(); // 42
454
+ * import { Ok } from "unthrown";
455
+ * Ok(42).unwrap(); // 42
349
456
  * ```
350
457
  */
351
- function ok(value) {
458
+ function Ok(value) {
352
459
  return okRes(value);
353
460
  }
354
461
  /**
@@ -359,11 +466,11 @@ function ok(value) {
359
466
  *
360
467
  * @example
361
468
  * ```ts
362
- * import { err } from "unthrown";
363
- * err("not_found").unwrapErr(); // "not_found"
469
+ * import { Err } from "unthrown";
470
+ * Err("not_found").unwrapErr(); // "not_found"
364
471
  * ```
365
472
  */
366
- function err(error) {
473
+ function Err(error) {
367
474
  return errRes(error);
368
475
  }
369
476
  /**
@@ -399,24 +506,24 @@ function isDefect(r) {
399
506
  }
400
507
  //#endregion
401
508
  //#region src/defect.ts
402
- const DEFECT = Symbol("unthrown/defect");
509
+ const DEFECT = Symbol("unthrown/Defect");
403
510
  /**
404
511
  * Wrap a cause as a {@link Defect} — the value you return from a `qualify`
405
512
  * function when a failure is **not** a modeled domain error.
406
513
  *
407
514
  * @param cause - the original thrown/rejected value.
408
- * @returns an opaque defect marker carrying `cause`.
515
+ * @returns an opaque Defect marker carrying `cause`.
409
516
  *
410
517
  * @example
411
518
  * ```ts
412
- * import { fromPromise, defect } from "unthrown";
519
+ * import { fromPromise, Defect } from "unthrown";
413
520
  *
414
521
  * const user = fromPromise(fetchUser(id), (cause) =>
415
- * cause instanceof NotFoundError ? cause : defect(cause),
522
+ * cause instanceof NotFoundError ? cause : Defect(cause),
416
523
  * );
417
524
  * ```
418
525
  */
419
- function defect(cause) {
526
+ function Defect(cause) {
420
527
  return {
421
528
  [DEFECT]: true,
422
529
  cause
@@ -433,13 +540,40 @@ function isDefectMarker(x) {
433
540
  return typeof x === "object" && x !== null && x[DEFECT] === true;
434
541
  }
435
542
  //#endregion
543
+ //#region src/do.ts
544
+ /**
545
+ * Start a do-notation chain with an empty object scope, grown step by step with
546
+ * `bind` (for `Result`-returning steps) and `let` (for pure values).
547
+ *
548
+ * @remarks
549
+ * Capitalised because `do` is a reserved word. Each step receives the scope
550
+ * accumulated so far; the error types union across `bind`s, and a throw in any
551
+ * step becomes a `Defect`. To go asynchronous, lift the chain with `toAsync()`
552
+ * (then a `bind` may return an `AsyncResult`).
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * import { Do, Ok } from "unthrown";
557
+ *
558
+ * const result = Do()
559
+ * .bind("user", () => findUser(id)) // Result<User, NotFound>
560
+ * .bind("org", ({ user }) => findOrg(user.orgId)) // Result<Org, NotFound>
561
+ * .let("label", ({ user, org }) => `${user.name} @ ${org.name}`)
562
+ * .map(({ user, org, label }) => render(user, org, label));
563
+ * // Result<View, NotFound>
564
+ * ```
565
+ */
566
+ function Do() {
567
+ return Ok({});
568
+ }
569
+ //#endregion
436
570
  //#region src/interop.ts
437
571
  /**
438
572
  * Bridge a nullable value into a {@link Result}: absence becomes a **modeled**
439
573
  * `Err`. The sanctioned alternative to an `Option` type.
440
574
  *
441
575
  * @remarks
442
- * `null` and `undefined` map to `err(onAbsent())`; any other value (including
576
+ * `null` and `undefined` map to `Err(onAbsent())`; any other value (including
443
577
  * falsy ones like `0`, `""`, `false`) maps to `Ok`.
444
578
  *
445
579
  * @typeParam T - the (nullable) value type.
@@ -454,7 +588,7 @@ function isDefectMarker(x) {
454
588
  * ```
455
589
  */
456
590
  function fromNullable(value, onAbsent) {
457
- return value === null || value === void 0 ? err(onAbsent()) : ok(value);
591
+ return value === null || value === void 0 ? Err(onAbsent()) : Ok(value);
458
592
  }
459
593
  /**
460
594
  * Wrap a throwing synchronous function so it returns a {@link Result} instead of
@@ -462,14 +596,14 @@ function fromNullable(value, onAbsent) {
462
596
  *
463
597
  * @remarks
464
598
  * `qualify` **must** triage every thrown cause into a modeled error `E` or a
465
- * {@link Defect} (via {@link defect}) — there is no path that leaves `unknown`
599
+ * {@link Defect} (via {@link Defect}) — there is no path that leaves `unknown`
466
600
  * in `E`. A throw inside `qualify` itself is treated as a `Defect`.
467
601
  *
468
602
  * The modeled error type is `Exclude<R, Defect>` — the `Defect` arm of
469
603
  * `qualify`'s return is **subtracted** from `E`, never inferred into it. So a
470
- * `qualify` that returns *only* `defect(cause)` yields `E = never` (a defect is
604
+ * `qualify` that returns *only* `Defect(cause)` yields `E = never` (a Defect is
471
605
  * out-of-band and must not pollute the error channel); reach for
472
- * {@link fromSafePromise} when every failure is a defect.
606
+ * {@link fromSafePromise} when every failure is a Defect.
473
607
  *
474
608
  * @typeParam A - the wrapped function's argument tuple.
475
609
  * @typeParam T - the wrapped function's return type.
@@ -481,8 +615,8 @@ function fromNullable(value, onAbsent) {
481
615
  *
482
616
  * @example
483
617
  * ```ts
484
- * import { fromThrowable, defect } from "unthrown";
485
- * const parse = fromThrowable(JSON.parse, (cause) => defect(cause));
618
+ * import { fromThrowable, Defect } from "unthrown";
619
+ * const parse = fromThrowable(JSON.parse, (cause) => Defect(cause));
486
620
  * parse("{}").unwrap();
487
621
  * ```
488
622
  */
@@ -490,7 +624,7 @@ function fromThrowable(fn, qualify) {
490
624
  const triage = qualify;
491
625
  return (...args) => {
492
626
  try {
493
- return ok(fn(...args));
627
+ return Ok(fn(...args));
494
628
  } catch (cause) {
495
629
  return qualifyToResult(cause, triage);
496
630
  }
@@ -508,8 +642,8 @@ function fromThrowable(fn, qualify) {
508
642
  *
509
643
  * The modeled error type is `Exclude<R, Defect>` — the `Defect` arm of
510
644
  * `qualify`'s return is **subtracted** from `E`, never inferred into it. So a
511
- * `qualify` that returns *only* `defect(cause)` yields `E = never`; when every
512
- * rejection is a defect, prefer {@link fromSafePromise}.
645
+ * `qualify` that returns *only* `Defect(cause)` yields `E = never`; when every
646
+ * rejection is a Defect, prefer {@link fromSafePromise}.
513
647
  *
514
648
  * @typeParam T - the resolved value type.
515
649
  * @typeParam R - `qualify`'s return type; the modeled error `E` is
@@ -519,9 +653,9 @@ function fromThrowable(fn, qualify) {
519
653
  *
520
654
  * @example
521
655
  * ```ts
522
- * import { fromPromise, defect } from "unthrown";
656
+ * import { fromPromise, Defect } from "unthrown";
523
657
  * const user = await fromPromise(fetchUser(id), (cause) =>
524
- * cause instanceof NotFoundError ? ("not_found" as const) : defect(cause),
658
+ * cause instanceof NotFoundError ? ("not_found" as const) : Defect(cause),
525
659
  * );
526
660
  * ```
527
661
  */
@@ -553,92 +687,161 @@ function qualifyToResult(cause, qualify) {
553
687
  }
554
688
  }
555
689
  /**
556
- * Collect {@link Result}s into a single `Result` of all their success values.
690
+ * Fold an array of settled `Result`s: first `Err` wins, any `Defect` dominates,
691
+ * else `Ok` of the values array.
692
+ *
693
+ * @internal
694
+ */
695
+ function foldArray(results) {
696
+ let firstErr;
697
+ let firstDefect;
698
+ const values = [];
699
+ for (const r of results) if (r.tag === "Defect") firstDefect ??= r;
700
+ else if (r.tag === "Err") firstErr ??= r;
701
+ else values.push(r.value);
702
+ return firstDefect ?? firstErr ?? Ok(values);
703
+ }
704
+ /**
705
+ * Fold a record of settled `Result`s with the same rules, else `Ok` of the
706
+ * record of values. Keys are written with `Object.defineProperty` so a
707
+ * caller-supplied `"__proto__"` key cannot pollute the prototype.
708
+ *
709
+ * @internal
710
+ */
711
+ function foldRecord(results) {
712
+ let firstErr;
713
+ let firstDefect;
714
+ const values = {};
715
+ for (const [key, r] of Object.entries(results)) if (r.tag === "Defect") firstDefect ??= r;
716
+ else if (r.tag === "Err") firstErr ??= r;
717
+ else Object.defineProperty(values, key, {
718
+ value: r.value,
719
+ enumerable: true,
720
+ writable: true,
721
+ configurable: true
722
+ });
723
+ return firstDefect ?? firstErr ?? Ok(values);
724
+ }
725
+ /**
726
+ * Collect a tuple/array of {@link Result}s into a single `Result` of all their
727
+ * success values.
557
728
  *
558
729
  * @remarks
559
730
  * Short-circuits on the **first** `Err` (later entries are not inspected for
560
731
  * their error); any `Defect` present **dominates**, winning even over an earlier
561
- * `Err`. A **fixed tuple** keeps its positional types — `all([ok(1), ok("a")])`
732
+ * `Err`. A **fixed tuple** keeps its positional types — `all([Ok(1), Ok("a")])`
562
733
  * is `Result<[number, string], …>` — while a **dynamic array** `Result<T, E>[]`
563
- * collapses to `Result<T[], E>` with no cast.
564
- *
565
- * @typeParam Rs - the tuple/array of input `Result` types.
566
- * @param results - the results to combine.
734
+ * collapses to `Result<T[], E>` with no cast. For a **record** keyed by name,
735
+ * use {@link allFromDict}.
567
736
  *
568
737
  * @example
569
738
  * ```ts
570
- * import { all, ok } from "unthrown";
571
- * all([ok(1), ok("a"), ok(true)]).unwrap(); // [1, "a", true] (typed [number, string, boolean])
572
- * all([ok(1), ok(2)] as Result<number, never>[]).unwrap(); // number[]
739
+ * import { all, Ok } from "unthrown";
740
+ * all([Ok(1), Ok("a"), Ok(true)]).unwrap(); // [1, "a", true] (typed [number, string, boolean])
741
+ * all([Ok(1), Ok(2)] as Result<number, never>[]).unwrap(); // number[]
573
742
  * ```
574
743
  */
575
744
  function all(results) {
576
- const values = [];
577
- let firstErr;
578
- let firstDefect;
579
- for (const r of results) if (r.tag === "Defect") firstDefect ??= r;
580
- else if (r.tag === "Err") firstErr ??= r;
581
- else values.push(r.value);
582
- if (firstDefect) return firstDefect;
583
- if (firstErr) return firstErr;
584
- return ok(values);
745
+ return foldArray(results);
585
746
  }
586
747
  /**
587
- * The asynchronous counterpart of {@link all}: combine {@link AsyncResult}s into
588
- * one `AsyncResult` of all their success values.
748
+ * Collect a **record** of {@link Result}s into a single `Result` of a record of
749
+ * their success values — `allFromDict({ a: Result<A, E>, b: Result<B, E> })` is
750
+ * `Result<{ a: A; b: B }, E>`. The named counterpart of {@link all}, for
751
+ * parallel work you'd rather not tuple.
589
752
  *
590
753
  * @remarks
591
- * The inputs are resolved **concurrently** (their order is preserved); the
592
- * resolved `Result`s are then folded with the same rules as {@link all} —
593
- * first `Err` short-circuits, any `Defect` dominates. As ever, the returned
594
- * `AsyncResult`'s internal promise never rejects. A **fixed tuple** keeps its
595
- * positional types; a **dynamic array** `AsyncResult<T, E>[]` collapses to
596
- * `AsyncResult<T[], E>`.
754
+ * Same folding rules as {@link all}: first `Err` short-circuits, any `Defect`
755
+ * dominates. This is **not** error accumulation.
756
+ *
757
+ * @example
758
+ * ```ts
759
+ * import { allFromDict, Ok } from "unthrown";
760
+ * allFromDict({ id: Ok(1), name: Ok("ada") }).unwrap(); // { id: 1, name: "ada" }
761
+ * ```
762
+ */
763
+ function allFromDict(results) {
764
+ return foldRecord(results);
765
+ }
766
+ /**
767
+ * The asynchronous counterpart of {@link all}: combine a tuple/array of
768
+ * {@link AsyncResult}s into one `AsyncResult` of all their success values.
597
769
  *
598
- * @typeParam Rs - the tuple/array of input `AsyncResult` types.
599
- * @param results - the async results to combine.
770
+ * @remarks
771
+ * The inputs are resolved **concurrently** (order preserved); the resolved
772
+ * `Result`s are then folded with the same rules as {@link all} — first `Err`
773
+ * short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s
774
+ * internal promise never rejects. For a **record**, use {@link allFromDictAsync}.
600
775
  *
601
776
  * @example
602
777
  * ```ts
603
778
  * import { allAsync, fromSafePromise } from "unthrown";
604
- * const both = await allAsync([fromSafePromise(a()), fromSafePromise(b())]);
779
+ * await allAsync([fromSafePromise(a()), fromSafePromise(b())]);
605
780
  * ```
606
781
  */
607
782
  function allAsync(results) {
608
- return new AsyncRes(Promise.all(results).then((resolved) => all(resolved)));
783
+ return new AsyncRes(Promise.all(results).then((resolved) => foldArray(resolved)));
784
+ }
785
+ /**
786
+ * The asynchronous counterpart of {@link allFromDict}: combine a record of
787
+ * {@link AsyncResult}s into one `AsyncResult` of a record of their values.
788
+ *
789
+ * @remarks
790
+ * Resolved concurrently (order preserved), folded with the {@link all} rules,
791
+ * and the internal promise never rejects.
792
+ *
793
+ * @example
794
+ * ```ts
795
+ * import { allFromDictAsync, fromSafePromise } from "unthrown";
796
+ * await allFromDictAsync({ a: fromSafePromise(a()), b: fromSafePromise(b()) });
797
+ * ```
798
+ */
799
+ function allFromDictAsync(results) {
800
+ const entries = Object.entries(results);
801
+ return new AsyncRes(Promise.all(entries.map(([, ar]) => ar)).then((resolved) => {
802
+ const byKey = Object.create(null);
803
+ entries.forEach(([key], i) => {
804
+ byKey[key] = resolved[i];
805
+ });
806
+ return foldRecord(byKey);
807
+ }));
609
808
  }
610
809
  //#endregion
611
810
  //#region src/facade.ts
612
811
  /**
613
812
  * Companion object grouping the standalone entry points under a single,
614
- * discoverable namespace: {@link Result.ok}, {@link Result.err},
615
- * {@link Result.defect}, {@link Result.fromNullable}, {@link Result.fromThrowable},
813
+ * discoverable namespace: {@link Result.Ok}, {@link Result.Err},
814
+ * {@link Result.Defect}, {@link Result.fromNullable}, {@link Result.fromThrowable},
616
815
  * {@link Result.fromPromise}, {@link Result.fromSafePromise}, {@link Result.all},
617
- * {@link Result.allAsync}, {@link Result.isOk}, {@link Result.isErr},
816
+ * {@link Result.allAsync}, {@link Result.allFromDict},
817
+ * {@link Result.allFromDictAsync}, {@link Result.isOk}, {@link Result.isErr},
618
818
  * {@link Result.isDefect}.
619
819
  *
620
820
  * @remarks
621
821
  * Purely additive sugar — each member **is** the corresponding free function.
622
822
  * The free functions remain the primary, tree-shakeable API; importing only
623
- * `{ ok }` never pulls this object in. The value `Result` and the type
823
+ * `{ Ok }` never pulls this object in. The value `Result` and the type
624
824
  * {@link Result} share one name (the companion-object pattern).
625
825
  *
626
826
  * @example
627
827
  * ```ts
628
828
  * import { Result } from "unthrown";
629
- * Result.ok(1).flatMap((n) => Result.ok(n + 1)).unwrap(); // 2
829
+ * Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).unwrap(); // 2
630
830
  * ```
631
831
  */
632
832
  const Result = {
633
- ok,
634
- err,
635
- defect,
833
+ Ok,
834
+ Err,
835
+ Defect,
836
+ Do,
636
837
  fromNullable,
637
838
  fromThrowable,
638
839
  fromPromise,
639
840
  fromSafePromise,
640
841
  all,
641
842
  allAsync,
843
+ allFromDict,
844
+ allFromDictAsync,
642
845
  isOk,
643
846
  isErr,
644
847
  isDefect
@@ -711,6 +914,6 @@ function matchTags(result, handlers) {
711
914
  });
712
915
  }
713
916
  //#endregion
714
- export { Result, TaggedError, UnwrapError, all, allAsync, defect, err, fromNullable, fromPromise, fromSafePromise, fromThrowable, isDefect, isErr, isOk, matchTags, ok };
917
+ export { Defect, Do, Err, Ok, Result, TaggedError, UnwrapError, all, allAsync, allFromDict, allFromDictAsync, fromNullable, fromPromise, fromSafePromise, fromThrowable, isDefect, isErr, isOk, matchTags };
715
918
 
716
919
  //# sourceMappingURL=index.mjs.map