@onrails/result 0.4.2 → 0.5.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/DESIGN.md CHANGED
@@ -29,6 +29,17 @@ type Result<T, E> =
29
29
  - Optional dot-chaining via `fluent(r)` in `@onrails/result/fluent`. Mirrors every instance-appropriate core transform; `test/parity.spec.ts` enforces the mirror (both directions) across core, fluent, and the neverthrow compat shim. `ResultAsync` is already fluent (its methods return `ResultAsync`) — no `fluentAsync` wrapper; wrapping it would just be a one-line delegate to itself.
30
30
  - The fluent wrapper stays local: `fluent(r)` opens and a terminal (`toResult`/`toString`/`match`/`unwrapOr`) closes within one expression — it's a closure over data, not data, so it must never be a return type, an exported binding, a stored field, or an argument to a serialize/`postMessage`/cache call. `@onrails/eslint-plugin` and `@onrails/biome-plugin` enforce this via `fluent-stays-local` (RFC 0002 §9).
31
31
 
32
+ ## Prototype carriers (breaking)
33
+
34
+ `ok` / `err` return live carriers: `_tag` plus `value` / `error` as own enumerable properties, with `map`, `mapErr`, `flatMap`/`andThen`, `recover`, `tap`, `tapErr`, `match` and `unwrapOr` on a shared non-enumerable prototype (`src/internal/proto.ts`). `r.map(f).flatMap(g)` works on any core `Result`, with core semantics (`tap` propagates throws, `recover` keeps `T`). The neverthrow-semantics names (`andTee`, `orElse`, ...) stay in compat.
35
+
36
+ - **Serialization:** `JSON.stringify` output is unchanged (same keys, same order). `JSON.parse`, `structuredClone`, spread and `postMessage` return plain data without the methods, while the type still claims them. Lift at every such sink with `Result.from`. `ResultData<T, E>` is the plain shape `from` accepts. Suite `test/prototype-core.spec.ts` covers all four routes.
37
+ - **Literals:** a hand-written `{ _tag: "Ok", value }` is no longer a `Result` (it lacks the methods). `onrails-codemod --literals` rewrites them to `ok` / `err`.
38
+ - **Narrowed branches:** `Err<T, E>` now carries `T` through its methods, so returning a narrowed `Err` as a `Result` with a different `T` needs `err(r.error)` (the same as neverthrow).
39
+ - **Redux, immer:** carriers are not plain objects (prototype is not `Object.prototype`). Redux Toolkit's serializability check flags them, and immer will not draft them. Store `ResultData` (or call `Result.from` on read) and convert at the edge.
40
+ - **Compat shim:** `CompatResult` still wraps a core carrier (`inner`) and now delegates `map`, `mapErr`, `andThen` and `unwrapOr` to the prototype methods. It cannot collapse into the core carrier: its semantics differ by design (`orElse` widens, `andTee` swallows throws, `value` / `error` getters throw), and the differential suite (`neverthrow-diff.spec.ts`) pins exactly that.
41
+ - **Packages:** `result` does not know `maybe`. `Maybe` has the mirrored prototype and `Maybe.from`; `toResult` / `fromResult` stay in `@onrails/maybe/interop`.
42
+
32
43
  ## Sync / async interop
33
44
 
34
45
  Two distinct lift paths:
@@ -102,7 +113,7 @@ Use `flatMap` for dependent checks where later checks need earlier successful va
102
113
 
103
114
  ## v1.0 gate
104
115
 
105
- - bun tests: core ops, FL functor/monad laws (sync), neverthrow-compat fixtures.
116
+ - bun tests: core ops, functor/monad/error-functor laws on `Result` and `ResultAsync` (`test/result.laws.spec.ts`), JSON and `structuredClone` round-trips, and a neverthrow differential (`test/neverthrow-diff.spec.ts`): a surface diff against the installed package plus randomised op chains run through both libraries.
106
117
  - README with tagged-error guidance.
107
118
  - **Not** in v1.0: npm publish.
108
119
 
package/README.md CHANGED
@@ -356,6 +356,25 @@ Both cap at **12 steps**. That cap is deliberate: a single recursive variadic si
356
356
 
357
357
  ## Breaking changes
358
358
 
359
+ ### Carriers have methods; plain data needs `Result.from`
360
+
361
+ `ok` / `err` (and `some` / `none` in `@onrails/maybe`) now return carriers with `map`, `mapErr`, `flatMap` / `andThen`, `recover`, `tap`, `tapErr`, `match` and `unwrapOr` on a non-enumerable prototype, so `ok(2).map(f).flatMap(g)` works with no wrapper. `_tag` and `value` / `error` are still the only own keys, and `JSON.stringify` output is byte-identical. The module functions (`map(r, f)`, `map(f)(r)`) are unchanged.
362
+
363
+ | Before | After |
364
+ |---|---|
365
+ | `{ _tag: "Ok", value: x }` | `ok(x)` — run `onrails-codemod <dir> --literals` |
366
+ | `{ _tag: "Err", error: e }` | `err(e)` |
367
+ | `{ _tag: "Some", value: x }` / `{ _tag: "None" }` | `some(x)` / `none()` |
368
+ | `JSON.parse(raw) as Result<T, E>` | `Result.from<T, E>(JSON.parse(raw))` |
369
+ | `structuredClone(r)` used as a `Result` | `Result.from(structuredClone(r))` |
370
+ | `if (isErr(r)) return r;` returning a different `T` | `if (isErr(r)) return err(r.error);` |
371
+
372
+ `JSON.parse`, `structuredClone`, object spread, `postMessage` and IndexedDB hand back plain data without the methods, while the type still claims them. `Result.from` (and `Maybe.from`) lift it back; `ResultData<T, E>` / `MaybeData<T>` name the plain shape. `@onrails/eslint-plugin` and `@onrails/biome-plugin` ship `carrier-sinks-need-from` to flag the cast forms.
373
+
374
+ **Redux Toolkit.** Carriers are not plain objects (their prototype is not `Object.prototype`), so the serializability middleware warns on them in actions and state. Keep `ResultData` / `MaybeData` in the store and call `Result.from` / `Maybe.from` in selectors,. Both are cheap: `from` is one allocation.
375
+
376
+ **immer.** `produce` only drafts plain objects and arrays, so a carrier inside state is treated as an opaque value: replace it wholesale (`draft.user = ok(next)`), do not mutate through it. Carriers are never mutated by the library, so sharing them across drafts is safe.
377
+
359
378
  ### `ok` / `err` lock inline literals
360
379
 
361
380
  Inline literals no longer widen: `ok("a")` is `Result<"a", never>` and `err({ kind: "io" })` carries `{ readonly kind: "io" }`. Annotated values and generic type parameters are unaffected. One call shape needs a change:
@@ -405,7 +424,28 @@ import { ResultAsync, Result, ok, err, okAsync, errAsync } from "@onrails/result
405
424
  - `Result` / `ResultAsync` are class-shaped (`CompatResult` / `CompatResultAsync`).
406
425
  - `await ra` resolves to a `CompatResult<T, E>` (thenable), so `.isOk()`, `.value`, `.error`, `.match()`, `.unwrapOr()` all work without an extra `.resolve()` call.
407
426
  - `andThen` / `chain` / `flatMap` / `orElse` accept any of `CompatResultAsync` / `ResultAsync` / `CompatResult` / tagged `Result` returns and union the error type.
408
- - Supported: `andThen`, `asyncAndThen`, `chain`, `flatMap`, `map`, `mapErr`, `orElse`, `match`, `unwrapOr`, `isOk`, `isErr`, `andTee`, `orTee`, `Result.combine`, `Result.fromThrowable`, `ResultAsync.combine`, `ResultAsync.fromPromise`, `ResultAsync.fromSafePromise`, `ResultAsync.fromThrowable`, `_unsafeUnwrap` / `_unsafeUnwrapErr`.
427
+ - Supported: every public member of neverthrow 8.x. `bun test` diffs the shim's surface against the real package (`test/neverthrow-diff.spec.ts`), so a new neverthrow member fails CI until it is covered.
428
+ - Guards: `isOk()` / `isErr()` are type guards; `.value` / `.error` are visible only after narrowing, as in neverthrow. The `else` branch of an `isOk()` check is not narrowed to the error side (the shim is one class, not an `Ok | Err` union) — use `match` or `isErr()`.
429
+ - `Ok` / `Err` support `new` and `instanceof`; `safeTry` accepts sync and async generators using `.safeUnwrap()`.
430
+
431
+ #### Compat name to core name
432
+
433
+ | neverthrow / compat | core (`@onrails/result`) | Notes |
434
+ |---|---|---|
435
+ | `r.map(f)` / `r.mapErr(f)` | `map(r, f)` / `mapErr(r, f)` | same |
436
+ | `r.andThen(f)` / `chain` / `flatMap` | `flatMap(r, f)` | `flatMap` is canonical |
437
+ | `r.orElse(f)` | `recover(r, f)` | |
438
+ | `r.andTee(f)` / `r.orTee(f)` | `tap(r, f)` / `tapErr(r, f)` | `tap` takes a pure side effect; compat also swallows a throwing callback, core does not |
439
+ | `r.andThrough(f)` | `flatMap(r, (v) => map(f(v), () => v))` | keeps the original `Ok` value, surfaces the callback's `Err` |
440
+ | `r.asyncMap(f)` | `ResultAsync.fromResult(r).map(f)` | |
441
+ | `r.match(ok, err)` | `match(r, ok, err)` | |
442
+ | `r.unwrapOr(d)` | `unwrapOr(r, d)` | |
443
+ | `r._unsafeUnwrap()` | `unwrapOk(r)` | assertion tier |
444
+ | `Result.fromThrowable(f, h)` | `fromThrowable(f, h)` | |
445
+ | `Result.combine` / `combineWithAllErrors` | `combineTuple` / `validateTuple` | |
446
+ | `safeTry(function* () { ... })` | `tryGen(() => { ... })` | `yield* r.safeUnwrap()` becomes `$(r)`; `tryGen` is sync, use `ResultAsync` chains for async bodies |
447
+ | `ok(1) instanceof Ok` | `isOk(r)` | |
448
+
409
449
  - Treat the compat surface as a migration step, not the destination — once a package migrates, switch its imports to `@onrails/result` and `@onrails/result/fluent`.
410
450
 
411
451
  ## Subpaths
@@ -421,4 +461,8 @@ import { ResultAsync, Result, ok, err, okAsync, errAsync } from "@onrails/result
421
461
  | `@onrails/result/try-gen` | `tryGen`, `yieldResult`, `$` |
422
462
  | `@onrails/result/compat/neverthrow` | Migration shim |
423
463
 
464
+ ## Benchmarks
465
+
466
+ Runtime + fair import-graph size vs `neverthrow`: see [`../bench/RESULTS.md`](../bench/RESULTS.md). Regenerated with `bun run bench:md` from the repo root.
467
+
424
468
  See [DESIGN.md](./DESIGN.md).
@@ -1,14 +1,88 @@
1
1
  'use strict';
2
2
 
3
- // src/internal/ctor.ts
4
- var mkOk = (value) => ({
5
- _tag: "Ok",
6
- value
7
- });
8
- var mkErr = (error) => ({
9
- _tag: "Err",
10
- error
11
- });
3
+ // src/internal/proto.ts
4
+ var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
5
+ var OkImpl = class _OkImpl {
6
+ _tag;
7
+ value;
8
+ // explicit assignment order keeps `_tag` first, so JSON key order matches the plain-data shape
9
+ constructor(value) {
10
+ this._tag = "Ok";
11
+ this.value = value;
12
+ }
13
+ [INSPECT](_depth, options, inspect) {
14
+ return `Ok(${inspect(this.value, options)})`;
15
+ }
16
+ map(fn) {
17
+ return new _OkImpl(fn(this.value));
18
+ }
19
+ mapErr(_fn) {
20
+ return new _OkImpl(this.value);
21
+ }
22
+ flatMap(fn) {
23
+ return fn(this.value);
24
+ }
25
+ andThen(fn) {
26
+ return fn(this.value);
27
+ }
28
+ recover(_fn) {
29
+ return new _OkImpl(this.value);
30
+ }
31
+ tap(fn) {
32
+ fn(this.value);
33
+ return this;
34
+ }
35
+ tapErr(_fn) {
36
+ return this;
37
+ }
38
+ match(onOk, _onErr) {
39
+ return onOk(this.value);
40
+ }
41
+ unwrapOr(_defaultValue) {
42
+ return this.value;
43
+ }
44
+ };
45
+ var ErrImpl = class _ErrImpl {
46
+ _tag;
47
+ error;
48
+ constructor(error) {
49
+ this._tag = "Err";
50
+ this.error = error;
51
+ }
52
+ [INSPECT](_depth, options, inspect) {
53
+ return `Err(${inspect(this.error, options)})`;
54
+ }
55
+ map(_fn) {
56
+ return new _ErrImpl(this.error);
57
+ }
58
+ mapErr(fn) {
59
+ return new _ErrImpl(fn(this.error));
60
+ }
61
+ flatMap(_fn) {
62
+ return new _ErrImpl(this.error);
63
+ }
64
+ andThen(_fn) {
65
+ return new _ErrImpl(this.error);
66
+ }
67
+ recover(fn) {
68
+ return fn(this.error);
69
+ }
70
+ tap(_fn) {
71
+ return this;
72
+ }
73
+ tapErr(fn) {
74
+ fn(this.error);
75
+ return this;
76
+ }
77
+ match(_onOk, onErr) {
78
+ return onErr(this.error);
79
+ }
80
+ unwrapOr(defaultValue) {
81
+ return defaultValue;
82
+ }
83
+ };
84
+ var newOk = (value) => new OkImpl(value);
85
+ var newErr = (error) => new ErrImpl(error);
12
86
 
13
87
  // src/internal/dual.ts
14
88
  var dual = (arity, body) => {
@@ -22,30 +96,22 @@ var isOk = (result) => result._tag === "Ok";
22
96
  var isErr = (result) => result._tag === "Err";
23
97
  var map = dual(
24
98
  2,
25
- (result, fn) => isOk(result) ? mkOk(fn(result.value)) : mkErr(result.error)
99
+ (result, fn) => isOk(result) ? newOk(fn(result.value)) : newErr(result.error)
26
100
  );
27
101
  var mapErr = dual(
28
102
  2,
29
- (result, fn) => isErr(result) ? mkErr(fn(result.error)) : mkOk(result.value)
103
+ (result, fn) => isErr(result) ? newErr(fn(result.error)) : newOk(result.value)
30
104
  );
31
105
  var bimap = dual(
32
106
  3,
33
- (result, onOk, onErr) => isOk(result) ? mkOk(onOk(result.value)) : mkErr(onErr(result.error))
34
- );
35
- var flatMap = dual(
36
- 2,
37
- (result, fn) => isOk(result) ? fn(result.value) : mkErr(result.error)
38
- );
39
- var unwrapOr = dual(
40
- 2,
41
- (result, defaultValue) => isOk(result) ? result.value : defaultValue
107
+ (result, onOk, onErr) => isOk(result) ? newOk(onOk(result.value)) : newErr(onErr(result.error))
42
108
  );
43
109
  function fromThrowable(fn, onThrow) {
44
110
  return (...args) => {
45
111
  try {
46
- return mkOk(fn(...args));
112
+ return newOk(fn(...args));
47
113
  } catch (error) {
48
- return mkErr(onThrow(error));
114
+ return newErr(onThrow(error));
49
115
  }
50
116
  };
51
117
  }
@@ -65,11 +131,11 @@ var sequenceSettled = (settled) => {
65
131
  const values = [];
66
132
  for (const result of settled) {
67
133
  if (isErr(result)) {
68
- return mkErr(result.error);
134
+ return newErr(result.error);
69
135
  }
70
136
  values.push(result.value);
71
137
  }
72
- return mkOk(values);
138
+ return newOk(values);
73
139
  };
74
140
  var ResultAsync = class _ResultAsync {
75
141
  constructor(run) {
@@ -106,9 +172,9 @@ var ResultAsync = class _ResultAsync {
106
172
  static fromPromise(promise, onReject) {
107
173
  return new _ResultAsync(async () => {
108
174
  try {
109
- return mkOk(await promise);
175
+ return newOk(await promise);
110
176
  } catch (error) {
111
- return mkErr(onReject(error));
177
+ return newErr(onReject(error));
112
178
  }
113
179
  });
114
180
  }
@@ -122,7 +188,7 @@ var ResultAsync = class _ResultAsync {
122
188
  * ```
123
189
  */
124
190
  static fromSafePromise(promise) {
125
- return new _ResultAsync(async () => mkOk(await promise));
191
+ return new _ResultAsync(async () => newOk(await promise));
126
192
  }
127
193
  /**
128
194
  * Defers work until {@link resolve}. Unlike {@link fromPromise}, the factory
@@ -140,13 +206,13 @@ var ResultAsync = class _ResultAsync {
140
206
  return new _ResultAsync(fn);
141
207
  }
142
208
  static ok(value) {
143
- return new _ResultAsync(async () => mkOk(value));
209
+ return new _ResultAsync(async () => newOk(value));
144
210
  }
145
211
  static of(value) {
146
212
  return _ResultAsync.ok(value);
147
213
  }
148
214
  static err(error) {
149
- return new _ResultAsync(async () => mkErr(error));
215
+ return new _ResultAsync(async () => newErr(error));
150
216
  }
151
217
  /**
152
218
  * Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
@@ -164,7 +230,7 @@ var ResultAsync = class _ResultAsync {
164
230
  try {
165
231
  return await promise;
166
232
  } catch (error) {
167
- return mkErr(mapDefect(error));
233
+ return newErr(mapDefect(error));
168
234
  }
169
235
  });
170
236
  }
@@ -186,11 +252,11 @@ var ResultAsync = class _ResultAsync {
186
252
  for (const ra of results) {
187
253
  const result = await ra.resolve();
188
254
  if (isErr(result)) {
189
- return mkErr(result.error);
255
+ return newErr(result.error);
190
256
  }
191
257
  values.push(result.value);
192
258
  }
193
- return mkOk(values);
259
+ return newOk(values);
194
260
  });
195
261
  }
196
262
  /**
@@ -285,7 +351,7 @@ var ResultAsync = class _ResultAsync {
285
351
  return new _ResultAsync(async () => {
286
352
  const first = await this.resolve();
287
353
  if (isErr(first)) {
288
- return first;
354
+ return newErr(first.error);
289
355
  }
290
356
  const next = fn(first.value);
291
357
  return next instanceof _ResultAsync ? next.resolve() : next;
@@ -317,7 +383,7 @@ var ResultAsync = class _ResultAsync {
317
383
  return new _ResultAsync(async () => {
318
384
  const first = await this.resolve();
319
385
  if (!isErr(first)) {
320
- return first;
386
+ return newOk(first.value);
321
387
  }
322
388
  const next = fn(first.error);
323
389
  return next instanceof _ResultAsync ? next.resolve() : next;
@@ -438,15 +504,29 @@ var ResultAsync = class _ResultAsync {
438
504
  var combine = (results) => {
439
505
  const values = [];
440
506
  for (const result of results) {
441
- if (isErr(result)) return mkErr(result.error);
507
+ if (isErr(result)) return newErr(result.error);
442
508
  values.push(result.value);
443
509
  }
444
- return mkOk(values);
510
+ return newOk(values);
445
511
  };
446
512
  var combineTuple = (results, ..._guard) => (
447
513
  // Runtime identical to combine; the cast restores per-index tuple types.
514
+ // `unknown` hop: the tuple type is computed from R, which TS cannot relate to the runtime array.
448
515
  combine(results)
449
516
  );
517
+ function validateAll(results, combineErrors) {
518
+ const values = [];
519
+ const errors = [];
520
+ for (const result of results) {
521
+ if (isErr(result)) {
522
+ errors.push(result.error);
523
+ } else {
524
+ values.push(result.value);
525
+ }
526
+ }
527
+ if (errors.length === 0) return newOk(values);
528
+ return newErr(errors);
529
+ }
450
530
 
451
531
  // src/compat/neverthrow.ts
452
532
  var CompatResult = class _CompatResult {
@@ -463,11 +543,12 @@ var CompatResult = class _CompatResult {
463
543
  combineTuple(results.map((r) => r.inner))
464
544
  );
465
545
  }
466
- get value() {
467
- return this._unsafeUnwrap();
468
- }
469
- get error() {
470
- return this._unsafeUnwrapErr();
546
+ // The `as unknown as` casts below restore per-index tuple types computed from R, which TS cannot
547
+ // relate to the runtime arrays.
548
+ static combineWithAllErrors(results) {
549
+ return new _CompatResult(
550
+ validateAll(results.map((r) => r.inner))
551
+ );
471
552
  }
472
553
  isOk() {
473
554
  return isOk(this.inner);
@@ -476,25 +557,68 @@ var CompatResult = class _CompatResult {
476
557
  return isErr(this.inner);
477
558
  }
478
559
  map(fn) {
479
- return new _CompatResult(map(this.inner, fn));
560
+ return new _CompatResult(this.inner.map(fn));
480
561
  }
481
562
  mapErr(fn) {
482
- return new _CompatResult(mapErr(this.inner, fn));
563
+ return new _CompatResult(this.inner.mapErr(fn));
483
564
  }
484
565
  andThen(fn) {
485
- return new _CompatResult(flatMap(this.inner, (value) => fn(value).inner));
566
+ return new _CompatResult(this.inner.flatMap((value) => fn(value).inner));
486
567
  }
487
568
  asyncAndThen(fn) {
488
569
  return isErr(this.inner) ? CompatResultAsync.err(this.inner.error) : CompatResultAsync.fromInner(coerceToCoreAsync(fn(this.inner.value)));
489
570
  }
490
571
  orElse(fn) {
491
- return isOk(this.inner) ? new _CompatResult(this.inner) : fn(this.inner.error);
572
+ return isOk(this.inner) ? new _CompatResult(newOk(this.inner.value)) : fn(this.inner.error);
492
573
  }
493
574
  match(onOk, onErr) {
494
575
  return isOk(this.inner) ? onOk(this.inner.value) : onErr(this.inner.error);
495
576
  }
496
577
  unwrapOr(defaultValue) {
497
- return unwrapOr(this.inner, defaultValue);
578
+ return this.inner.unwrapOr(defaultValue);
579
+ }
580
+ andTee(fn) {
581
+ if (isOk(this.inner)) {
582
+ try {
583
+ fn(this.inner.value);
584
+ } catch {
585
+ }
586
+ }
587
+ return this;
588
+ }
589
+ orTee(fn) {
590
+ if (isErr(this.inner)) {
591
+ try {
592
+ fn(this.inner.error);
593
+ } catch {
594
+ }
595
+ }
596
+ return this;
597
+ }
598
+ andThrough(fn) {
599
+ if (isErr(this.inner)) return this;
600
+ const through = fn(this.inner.value).inner;
601
+ return isErr(through) ? new _CompatResult(newErr(through.error)) : this;
602
+ }
603
+ asyncAndThrough(fn) {
604
+ const inner = this.inner;
605
+ return CompatResultAsync.fromInner(
606
+ ResultAsync.defer(async () => {
607
+ if (isErr(inner)) return inner;
608
+ const through = await coerceToCoreAsync(fn(inner.value)).resolve();
609
+ return isErr(through) ? newErr(through.error) : inner;
610
+ })
611
+ );
612
+ }
613
+ asyncMap(fn) {
614
+ return isErr(this.inner) ? CompatResultAsync.err(this.inner.error) : CompatResultAsync.fromSafePromise(fn(this.inner.value));
615
+ }
616
+ /** Yields the `Err` to {@link safeTry} on failure; returns the `Ok` value otherwise. */
617
+ *safeUnwrap() {
618
+ if (isErr(this.inner)) {
619
+ yield new _CompatResult(newErr(this.inner.error));
620
+ }
621
+ return this._unsafeUnwrap();
498
622
  }
499
623
  _unsafeUnwrap() {
500
624
  if (isErr(this.inner)) {
@@ -510,8 +634,34 @@ var CompatResult = class _CompatResult {
510
634
  }
511
635
  };
512
636
  var Result = CompatResult;
513
- var ok = (value) => new CompatResult(mkOk(value));
514
- var err = (error) => new CompatResult(mkErr(error));
637
+ var ok = (value) => new CompatResult(newOk(value));
638
+ var err = (error) => new CompatResult(newErr(error));
639
+ Object.defineProperty(CompatResult.prototype, "value", {
640
+ get() {
641
+ return this._unsafeUnwrap();
642
+ }
643
+ });
644
+ Object.defineProperty(CompatResult.prototype, "error", {
645
+ get() {
646
+ return this._unsafeUnwrapErr();
647
+ }
648
+ });
649
+ var Ok = class extends CompatResult {
650
+ constructor(value) {
651
+ super(newOk(value));
652
+ }
653
+ static [Symbol.hasInstance](candidate) {
654
+ return candidate instanceof CompatResult && isOk(candidate.inner);
655
+ }
656
+ };
657
+ var Err = class extends CompatResult {
658
+ constructor(error) {
659
+ super(newErr(error));
660
+ }
661
+ static [Symbol.hasInstance](candidate) {
662
+ return candidate instanceof CompatResult && isErr(candidate.inner);
663
+ }
664
+ };
515
665
  var CompatResultAsync = class _CompatResultAsync {
516
666
  constructor(inner) {
517
667
  this.inner = inner;
@@ -543,6 +693,13 @@ var CompatResultAsync = class _CompatResultAsync {
543
693
  ResultAsync.combine(results.map((r) => r.inner))
544
694
  );
545
695
  }
696
+ static combineWithAllErrors(results) {
697
+ return new _CompatResultAsync(
698
+ ResultAsync.defer(
699
+ async () => validateAll(await Promise.all(results.map((r) => r.resolve())))
700
+ )
701
+ );
702
+ }
546
703
  // biome-ignore lint/suspicious/noThenProperty: thenable shim for `await ra` -> CompatResult
547
704
  then(onfulfilled, onrejected) {
548
705
  return this.inner.resolve().then((r) => {
@@ -607,6 +764,21 @@ var CompatResultAsync = class _CompatResultAsync {
607
764
  })
608
765
  );
609
766
  }
767
+ andThrough(fn) {
768
+ return new _CompatResultAsync(
769
+ ResultAsync.defer(async () => {
770
+ const r = await this.inner.resolve();
771
+ if (isErr(r)) return r;
772
+ const next = coerceToCore(fn(r.value));
773
+ const through = next instanceof ResultAsync ? await next.resolve() : next;
774
+ return isErr(through) ? newErr(through.error) : r;
775
+ })
776
+ );
777
+ }
778
+ /** Async twin of {@link CompatResult.safeUnwrap}. */
779
+ async *safeUnwrap() {
780
+ return yield* new CompatResult(await this.inner.resolve()).safeUnwrap();
781
+ }
610
782
  orTee(fn) {
611
783
  return new _CompatResultAsync(
612
784
  ResultAsync.defer(async () => {
@@ -629,20 +801,34 @@ function coerceToCore(next) {
629
801
  return next;
630
802
  }
631
803
  var coerceToCoreAsync = (next) => next instanceof CompatResultAsync ? next.toCore() : next;
804
+ function safeTry(body) {
805
+ const step = body().next();
806
+ if (step instanceof Promise) {
807
+ return CompatResultAsync.fromInner(ResultAsync.defer(async () => (await step).value.inner));
808
+ }
809
+ return step.value;
810
+ }
632
811
  var okAsync = CompatResultAsync.ok;
633
812
  var errAsync = CompatResultAsync.err;
634
813
  var fromPromise = CompatResultAsync.fromPromise;
635
814
  var fromSafePromise = CompatResultAsync.fromSafePromise;
815
+ var fromThrowable2 = CompatResult.fromThrowable;
816
+ var fromAsyncThrowable = CompatResultAsync.fromThrowable;
636
817
 
637
818
  exports.CompatResult = CompatResult;
638
819
  exports.CompatResultAsync = CompatResultAsync;
820
+ exports.Err = Err;
821
+ exports.Ok = Ok;
639
822
  exports.Result = Result;
640
823
  exports.ResultAsync = CompatResultAsync;
641
824
  exports.err = err;
642
825
  exports.errAsync = errAsync;
826
+ exports.fromAsyncThrowable = fromAsyncThrowable;
643
827
  exports.fromPromise = fromPromise;
644
828
  exports.fromSafePromise = fromSafePromise;
829
+ exports.fromThrowable = fromThrowable2;
645
830
  exports.ok = ok;
646
831
  exports.okAsync = okAsync;
832
+ exports.safeTry = safeTry;
647
833
  //# sourceMappingURL=neverthrow.cjs.map
648
834
  //# sourceMappingURL=neverthrow.cjs.map