@unthrown/effect 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Benoit Travers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @unthrown/effect
2
+
3
+ > [Effect](https://effect.website) interop for
4
+ > [unthrown](https://github.com/btravstack/unthrown)'s `Result`.
5
+
6
+ 📖 **[Documentation](https://btravstack.github.io/unthrown/guide/interop)** ·
7
+ [API Reference](https://btravstack.github.io/unthrown/api/effect/)
8
+
9
+ ```sh
10
+ pnpm add @unthrown/effect effect
11
+ ```
12
+
13
+ Effect is the one neighbour that shares unthrown's three-channel shape: an
14
+ `Exit<A, E>` is a success or a `Cause`, and a `Cause` distinguishes a modeled
15
+ failure (`Cause.fail` ↔ `Err`) from an unexpected one (`Cause.die` ↔ `Defect`).
16
+ So `Result ↔ Exit` is a genuine **bijection**.
17
+
18
+ ```ts
19
+ import { ok, err } from "unthrown";
20
+ import { toExit, fromEffect, toEither } from "@unthrown/effect";
21
+ import { Effect } from "effect";
22
+
23
+ toExit(ok(1)); // Exit.succeed(1)
24
+ toExit(err("e")); // Exit.fail("e") — a modeled Cause.fail
25
+
26
+ // Run an Effect and collect its outcome (die/interrupt become a Defect):
27
+ await fromEffect(Effect.succeed(1)).match({ ok, err, defect: String });
28
+ ```
29
+
30
+ - `toExit` / `fromExit` — the bijection: `Ok↔succeed`, `Err↔Cause.fail`,
31
+ `Defect↔Cause.die`. On the way back a die/interruption becomes a `Defect`, and
32
+ a `Defect` **dominates** a modeled failure in a composite cause (same rule as
33
+ `all`).
34
+ - `toEither` / `fromEither` — `Either` has no defect channel, so `toEither(r,
35
+ onDefect)` **forces** you to triage the defect into `E` (Thesis #3). `fromEither`
36
+ never yields a `Defect`.
37
+ - `toEffect` / `fromEffect` — `toEffect` lifts a `Result` **or** `AsyncResult`
38
+ into an `Effect<T, E>` (`Defect → Effect.die`); `fromEffect` runs an
39
+ environment-free `Effect<T, E>` to an `AsyncResult<T, E>`.
40
+
41
+ `effect` is a peer dependency.
42
+
43
+ ## License
44
+
45
+ [MIT](../../LICENSE) © Benoit TRAVERS
package/dist/index.cjs ADDED
@@ -0,0 +1,145 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let effect = require("effect");
3
+ let unthrown = require("unthrown");
4
+ //#region src/index.ts
5
+ /**
6
+ * Convert a `Result` into an Effect `Exit` — a **bijection**, since both
7
+ * carry three channels.
8
+ *
9
+ * @remarks
10
+ * `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and
11
+ * `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with
12
+ * {@link fromExit}.
13
+ *
14
+ * @typeParam T - the success value type.
15
+ * @typeParam E - the modeled error type.
16
+ * @param result - the result to convert.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { ok } from "unthrown";
21
+ * import { toExit } from "@unthrown/effect";
22
+ * toExit(ok(1)); // Exit.succeed(1)
23
+ * ```
24
+ */
25
+ function toExit(result) {
26
+ return result.match({
27
+ ok: (value) => effect.Exit.succeed(value),
28
+ err: (error) => effect.Exit.fail(error),
29
+ defect: (cause) => effect.Exit.die(cause)
30
+ });
31
+ }
32
+ /**
33
+ * Convert an Effect `Exit` into a `Result` — the inverse of
34
+ * {@link toExit}.
35
+ *
36
+ * @remarks
37
+ * `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced:
38
+ *
39
+ * - a `Cause.die` becomes a `Defect`,
40
+ * - otherwise a `Cause.fail` becomes the modeled `Err`,
41
+ * - a pure interruption (or empty cause) becomes a `Defect`.
42
+ *
43
+ * A `Defect` **dominates** a modeled failure in a composite cause — the same
44
+ * rule unthrown's `all` uses, on the principle that an unexpected failure is the
45
+ * more severe signal.
46
+ *
47
+ * @typeParam T - the success value type.
48
+ * @typeParam E - the modeled error type.
49
+ * @param exit - the exit to convert.
50
+ */
51
+ function fromExit(exit) {
52
+ return effect.Exit.match(exit, {
53
+ onSuccess: (value) => (0, unthrown.ok)(value),
54
+ onFailure: (cause) => {
55
+ const die = effect.Cause.dieOption(cause);
56
+ if (effect.Option.isSome(die)) return dieToResult(die.value);
57
+ const failure = effect.Cause.failureOption(cause);
58
+ if (effect.Option.isSome(failure)) return (0, unthrown.err)(failure.value);
59
+ return dieToResult(effect.Cause.squash(cause));
60
+ }
61
+ });
62
+ }
63
+ /**
64
+ * Convert a `Result` into an Effect `Either`, triaging any defect.
65
+ *
66
+ * @remarks
67
+ * `Either` has no defect channel, so a `Defect` cannot pass through silently —
68
+ * `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This
69
+ * is the boundary-qualification rule (Thesis #3) applied on the way out:
70
+ * `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`.
71
+ *
72
+ * @typeParam T - the success value type.
73
+ * @typeParam E - the modeled error type.
74
+ * @param result - the result to convert.
75
+ * @param onDefect - folds a defect's unknown cause into a modeled `E`.
76
+ */
77
+ function toEither(result, onDefect) {
78
+ return result.match({
79
+ ok: (value) => effect.Either.right(value),
80
+ err: (error) => effect.Either.left(error),
81
+ defect: (cause) => effect.Either.left(onDefect(cause))
82
+ });
83
+ }
84
+ /**
85
+ * Convert an Effect `Either` into a `Result`.
86
+ *
87
+ * @remarks
88
+ * `Right → Ok`, `Left → Err`. An `Either` carries no defect, so the result is
89
+ * never a `Defect`.
90
+ *
91
+ * @typeParam T - the success value type.
92
+ * @typeParam E - the modeled error type.
93
+ * @param either - the either to convert.
94
+ */
95
+ function fromEither(either) {
96
+ return effect.Either.match(either, {
97
+ onLeft: (error) => (0, unthrown.err)(error),
98
+ onRight: (value) => (0, unthrown.ok)(value)
99
+ });
100
+ }
101
+ function toEffect(source) {
102
+ if (isAsyncResult(source)) return effect.Effect.flatMap(effect.Effect.promise(() => settle(source)), (result) => resultToEffect(result));
103
+ return resultToEffect(source);
104
+ }
105
+ /**
106
+ * Run an `Effect` and collect its outcome as an `AsyncResult`.
107
+ *
108
+ * @remarks
109
+ * The effect must need no environment (`R = never`). It is run to an `Exit`
110
+ * (which never rejects), then folded with {@link fromExit}: success → `Ok`, a
111
+ * modeled failure → `Err`, a die/interruption → `Defect`. The returned
112
+ * `AsyncResult` never throws when awaited.
113
+ *
114
+ * @typeParam T - the success value type.
115
+ * @typeParam E - the modeled error type.
116
+ * @param effect - the effect to run.
117
+ */
118
+ function fromEffect(effect$1) {
119
+ return (0, unthrown.fromSafePromise)(effect.Effect.runPromiseExit(effect$1)).flatMap((exit) => fromExit(exit));
120
+ }
121
+ function resultToEffect(result) {
122
+ return result.match({
123
+ ok: (value) => effect.Effect.succeed(value),
124
+ err: (error) => effect.Effect.fail(error),
125
+ defect: (cause) => effect.Effect.die(cause)
126
+ });
127
+ }
128
+ function dieToResult(cause) {
129
+ return (0, unthrown.fromThrowable)(() => {
130
+ throw cause;
131
+ }, unthrown.defect)();
132
+ }
133
+ function settle(asyncResult) {
134
+ return (async () => await asyncResult)();
135
+ }
136
+ function isAsyncResult(source) {
137
+ return typeof source.then === "function";
138
+ }
139
+ //#endregion
140
+ exports.fromEffect = fromEffect;
141
+ exports.fromEither = fromEither;
142
+ exports.fromExit = fromExit;
143
+ exports.toEffect = toEffect;
144
+ exports.toEither = toEither;
145
+ exports.toExit = toExit;
@@ -0,0 +1,104 @@
1
+ import { Effect, Either, Exit } from "effect";
2
+ import { AsyncResult, Result } from "unthrown";
3
+
4
+ //#region src/index.d.ts
5
+ /**
6
+ * Convert a `Result` into an Effect `Exit` — a **bijection**, since both
7
+ * carry three channels.
8
+ *
9
+ * @remarks
10
+ * `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and
11
+ * `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with
12
+ * {@link fromExit}.
13
+ *
14
+ * @typeParam T - the success value type.
15
+ * @typeParam E - the modeled error type.
16
+ * @param result - the result to convert.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { ok } from "unthrown";
21
+ * import { toExit } from "@unthrown/effect";
22
+ * toExit(ok(1)); // Exit.succeed(1)
23
+ * ```
24
+ */
25
+ declare function toExit<T, E>(result: Result<T, E>): Exit.Exit<T, E>;
26
+ /**
27
+ * Convert an Effect `Exit` into a `Result` — the inverse of
28
+ * {@link toExit}.
29
+ *
30
+ * @remarks
31
+ * `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced:
32
+ *
33
+ * - a `Cause.die` becomes a `Defect`,
34
+ * - otherwise a `Cause.fail` becomes the modeled `Err`,
35
+ * - a pure interruption (or empty cause) becomes a `Defect`.
36
+ *
37
+ * A `Defect` **dominates** a modeled failure in a composite cause — the same
38
+ * rule unthrown's `all` uses, on the principle that an unexpected failure is the
39
+ * more severe signal.
40
+ *
41
+ * @typeParam T - the success value type.
42
+ * @typeParam E - the modeled error type.
43
+ * @param exit - the exit to convert.
44
+ */
45
+ declare function fromExit<T, E>(exit: Exit.Exit<T, E>): Result<T, E>;
46
+ /**
47
+ * Convert a `Result` into an Effect `Either`, triaging any defect.
48
+ *
49
+ * @remarks
50
+ * `Either` has no defect channel, so a `Defect` cannot pass through silently —
51
+ * `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This
52
+ * is the boundary-qualification rule (Thesis #3) applied on the way out:
53
+ * `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`.
54
+ *
55
+ * @typeParam T - the success value type.
56
+ * @typeParam E - the modeled error type.
57
+ * @param result - the result to convert.
58
+ * @param onDefect - folds a defect's unknown cause into a modeled `E`.
59
+ */
60
+ declare function toEither<T, E>(result: Result<T, E>, onDefect: (cause: unknown) => E): Either.Either<T, E>;
61
+ /**
62
+ * Convert an Effect `Either` into a `Result`.
63
+ *
64
+ * @remarks
65
+ * `Right → Ok`, `Left → Err`. An `Either` carries no defect, so the result is
66
+ * never a `Defect`.
67
+ *
68
+ * @typeParam T - the success value type.
69
+ * @typeParam E - the modeled error type.
70
+ * @param either - the either to convert.
71
+ */
72
+ declare function fromEither<T, E>(either: Either.Either<T, E>): Result<T, E>;
73
+ /**
74
+ * Lift a `Result` or `AsyncResult` into an `Effect`.
75
+ *
76
+ * @remarks
77
+ * `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The
78
+ * resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is
79
+ * awaited inside the effect (it never rejects), so this is the `AsyncResult →
80
+ * Effect` direction too.
81
+ *
82
+ * @typeParam T - the success value type.
83
+ * @typeParam E - the modeled error type.
84
+ * @param source - the result, or async result, to lift.
85
+ */
86
+ declare function toEffect<T, E>(source: Result<T, E>): Effect.Effect<T, E>;
87
+ declare function toEffect<T, E>(source: AsyncResult<T, E>): Effect.Effect<T, E>;
88
+ /**
89
+ * Run an `Effect` and collect its outcome as an `AsyncResult`.
90
+ *
91
+ * @remarks
92
+ * The effect must need no environment (`R = never`). It is run to an `Exit`
93
+ * (which never rejects), then folded with {@link fromExit}: success → `Ok`, a
94
+ * modeled failure → `Err`, a die/interruption → `Defect`. The returned
95
+ * `AsyncResult` never throws when awaited.
96
+ *
97
+ * @typeParam T - the success value type.
98
+ * @typeParam E - the modeled error type.
99
+ * @param effect - the effect to run.
100
+ */
101
+ declare function fromEffect<T, E>(effect: Effect.Effect<T, E>): AsyncResult<T, E>;
102
+ //#endregion
103
+ export { fromEffect, fromEither, fromExit, toEffect, toEither, toExit };
104
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;AA0CA;;;;;;;;;;;;;;;;;;iBAAgB,MAAA,OAAa,MAAA,EAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,CAAA,EAAG,CAAA;;;;AAAC;AA2BlE;;;;;;;;;;;;;;;iBAAgB,QAAA,OAAe,IAAA,EAAM,IAAA,CAAK,IAAA,CAAK,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;AAAC;AA4BlE;;;;;;;iBAAgB,QAAA,OACd,MAAA,EAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,GAClB,QAAA,GAAW,KAAA,cAAmB,CAAA,GAC7B,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;;;;;;iBAmBJ,UAAA,OAAiB,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;AAnBpD;AAmBrB;;;;;;iBAoBgB,QAAA,OAAe,MAAA,EAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA;AAAA,iBACvD,QAAA,OAAe,MAAA,EAAQ,WAAA,CAAY,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;;;;;;;;iBAwB5D,UAAA,OAAiB,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,WAAA,CAAY,CAAA,EAAG,CAAA"}
@@ -0,0 +1,104 @@
1
+ import { Effect, Either, Exit } from "effect";
2
+ import { AsyncResult, Result } from "unthrown";
3
+
4
+ //#region src/index.d.ts
5
+ /**
6
+ * Convert a `Result` into an Effect `Exit` — a **bijection**, since both
7
+ * carry three channels.
8
+ *
9
+ * @remarks
10
+ * `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and
11
+ * `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with
12
+ * {@link fromExit}.
13
+ *
14
+ * @typeParam T - the success value type.
15
+ * @typeParam E - the modeled error type.
16
+ * @param result - the result to convert.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { ok } from "unthrown";
21
+ * import { toExit } from "@unthrown/effect";
22
+ * toExit(ok(1)); // Exit.succeed(1)
23
+ * ```
24
+ */
25
+ declare function toExit<T, E>(result: Result<T, E>): Exit.Exit<T, E>;
26
+ /**
27
+ * Convert an Effect `Exit` into a `Result` — the inverse of
28
+ * {@link toExit}.
29
+ *
30
+ * @remarks
31
+ * `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced:
32
+ *
33
+ * - a `Cause.die` becomes a `Defect`,
34
+ * - otherwise a `Cause.fail` becomes the modeled `Err`,
35
+ * - a pure interruption (or empty cause) becomes a `Defect`.
36
+ *
37
+ * A `Defect` **dominates** a modeled failure in a composite cause — the same
38
+ * rule unthrown's `all` uses, on the principle that an unexpected failure is the
39
+ * more severe signal.
40
+ *
41
+ * @typeParam T - the success value type.
42
+ * @typeParam E - the modeled error type.
43
+ * @param exit - the exit to convert.
44
+ */
45
+ declare function fromExit<T, E>(exit: Exit.Exit<T, E>): Result<T, E>;
46
+ /**
47
+ * Convert a `Result` into an Effect `Either`, triaging any defect.
48
+ *
49
+ * @remarks
50
+ * `Either` has no defect channel, so a `Defect` cannot pass through silently —
51
+ * `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This
52
+ * is the boundary-qualification rule (Thesis #3) applied on the way out:
53
+ * `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`.
54
+ *
55
+ * @typeParam T - the success value type.
56
+ * @typeParam E - the modeled error type.
57
+ * @param result - the result to convert.
58
+ * @param onDefect - folds a defect's unknown cause into a modeled `E`.
59
+ */
60
+ declare function toEither<T, E>(result: Result<T, E>, onDefect: (cause: unknown) => E): Either.Either<T, E>;
61
+ /**
62
+ * Convert an Effect `Either` into a `Result`.
63
+ *
64
+ * @remarks
65
+ * `Right → Ok`, `Left → Err`. An `Either` carries no defect, so the result is
66
+ * never a `Defect`.
67
+ *
68
+ * @typeParam T - the success value type.
69
+ * @typeParam E - the modeled error type.
70
+ * @param either - the either to convert.
71
+ */
72
+ declare function fromEither<T, E>(either: Either.Either<T, E>): Result<T, E>;
73
+ /**
74
+ * Lift a `Result` or `AsyncResult` into an `Effect`.
75
+ *
76
+ * @remarks
77
+ * `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The
78
+ * resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is
79
+ * awaited inside the effect (it never rejects), so this is the `AsyncResult →
80
+ * Effect` direction too.
81
+ *
82
+ * @typeParam T - the success value type.
83
+ * @typeParam E - the modeled error type.
84
+ * @param source - the result, or async result, to lift.
85
+ */
86
+ declare function toEffect<T, E>(source: Result<T, E>): Effect.Effect<T, E>;
87
+ declare function toEffect<T, E>(source: AsyncResult<T, E>): Effect.Effect<T, E>;
88
+ /**
89
+ * Run an `Effect` and collect its outcome as an `AsyncResult`.
90
+ *
91
+ * @remarks
92
+ * The effect must need no environment (`R = never`). It is run to an `Exit`
93
+ * (which never rejects), then folded with {@link fromExit}: success → `Ok`, a
94
+ * modeled failure → `Err`, a die/interruption → `Defect`. The returned
95
+ * `AsyncResult` never throws when awaited.
96
+ *
97
+ * @typeParam T - the success value type.
98
+ * @typeParam E - the modeled error type.
99
+ * @param effect - the effect to run.
100
+ */
101
+ declare function fromEffect<T, E>(effect: Effect.Effect<T, E>): AsyncResult<T, E>;
102
+ //#endregion
103
+ export { fromEffect, fromEither, fromExit, toEffect, toEither, toExit };
104
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;AA0CA;;;;;;;;;;;;;;;;;;iBAAgB,MAAA,OAAa,MAAA,EAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,CAAA,EAAG,CAAA;;;;AAAC;AA2BlE;;;;;;;;;;;;;;;iBAAgB,QAAA,OAAe,IAAA,EAAM,IAAA,CAAK,IAAA,CAAK,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;AAAC;AA4BlE;;;;;;;iBAAgB,QAAA,OACd,MAAA,EAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,GAClB,QAAA,GAAW,KAAA,cAAmB,CAAA,GAC7B,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;;;;;;iBAmBJ,UAAA,OAAiB,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;AAnBpD;AAmBrB;;;;;;iBAoBgB,QAAA,OAAe,MAAA,EAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA;AAAA,iBACvD,QAAA,OAAe,MAAA,EAAQ,WAAA,CAAY,CAAA,EAAG,CAAA,IAAK,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA;;;;;;;;;;;;;;iBAwB5D,UAAA,OAAiB,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,IAAK,WAAA,CAAY,CAAA,EAAG,CAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,141 @@
1
+ import { Cause, Effect, Either, Exit, Option } from "effect";
2
+ import { defect, err, fromSafePromise, fromThrowable, ok } from "unthrown";
3
+ //#region src/index.ts
4
+ /**
5
+ * Convert a `Result` into an Effect `Exit` — a **bijection**, since both
6
+ * carry three channels.
7
+ *
8
+ * @remarks
9
+ * `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and
10
+ * `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with
11
+ * {@link fromExit}.
12
+ *
13
+ * @typeParam T - the success value type.
14
+ * @typeParam E - the modeled error type.
15
+ * @param result - the result to convert.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { ok } from "unthrown";
20
+ * import { toExit } from "@unthrown/effect";
21
+ * toExit(ok(1)); // Exit.succeed(1)
22
+ * ```
23
+ */
24
+ function toExit(result) {
25
+ return result.match({
26
+ ok: (value) => Exit.succeed(value),
27
+ err: (error) => Exit.fail(error),
28
+ defect: (cause) => Exit.die(cause)
29
+ });
30
+ }
31
+ /**
32
+ * Convert an Effect `Exit` into a `Result` — the inverse of
33
+ * {@link toExit}.
34
+ *
35
+ * @remarks
36
+ * `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced:
37
+ *
38
+ * - a `Cause.die` becomes a `Defect`,
39
+ * - otherwise a `Cause.fail` becomes the modeled `Err`,
40
+ * - a pure interruption (or empty cause) becomes a `Defect`.
41
+ *
42
+ * A `Defect` **dominates** a modeled failure in a composite cause — the same
43
+ * rule unthrown's `all` uses, on the principle that an unexpected failure is the
44
+ * more severe signal.
45
+ *
46
+ * @typeParam T - the success value type.
47
+ * @typeParam E - the modeled error type.
48
+ * @param exit - the exit to convert.
49
+ */
50
+ function fromExit(exit) {
51
+ return Exit.match(exit, {
52
+ onSuccess: (value) => ok(value),
53
+ onFailure: (cause) => {
54
+ const die = Cause.dieOption(cause);
55
+ if (Option.isSome(die)) return dieToResult(die.value);
56
+ const failure = Cause.failureOption(cause);
57
+ if (Option.isSome(failure)) return err(failure.value);
58
+ return dieToResult(Cause.squash(cause));
59
+ }
60
+ });
61
+ }
62
+ /**
63
+ * Convert a `Result` into an Effect `Either`, triaging any defect.
64
+ *
65
+ * @remarks
66
+ * `Either` has no defect channel, so a `Defect` cannot pass through silently —
67
+ * `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This
68
+ * is the boundary-qualification rule (Thesis #3) applied on the way out:
69
+ * `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`.
70
+ *
71
+ * @typeParam T - the success value type.
72
+ * @typeParam E - the modeled error type.
73
+ * @param result - the result to convert.
74
+ * @param onDefect - folds a defect's unknown cause into a modeled `E`.
75
+ */
76
+ function toEither(result, onDefect) {
77
+ return result.match({
78
+ ok: (value) => Either.right(value),
79
+ err: (error) => Either.left(error),
80
+ defect: (cause) => Either.left(onDefect(cause))
81
+ });
82
+ }
83
+ /**
84
+ * Convert an Effect `Either` into a `Result`.
85
+ *
86
+ * @remarks
87
+ * `Right → Ok`, `Left → Err`. An `Either` carries no defect, so the result is
88
+ * never a `Defect`.
89
+ *
90
+ * @typeParam T - the success value type.
91
+ * @typeParam E - the modeled error type.
92
+ * @param either - the either to convert.
93
+ */
94
+ function fromEither(either) {
95
+ return Either.match(either, {
96
+ onLeft: (error) => err(error),
97
+ onRight: (value) => ok(value)
98
+ });
99
+ }
100
+ function toEffect(source) {
101
+ if (isAsyncResult(source)) return Effect.flatMap(Effect.promise(() => settle(source)), (result) => resultToEffect(result));
102
+ return resultToEffect(source);
103
+ }
104
+ /**
105
+ * Run an `Effect` and collect its outcome as an `AsyncResult`.
106
+ *
107
+ * @remarks
108
+ * The effect must need no environment (`R = never`). It is run to an `Exit`
109
+ * (which never rejects), then folded with {@link fromExit}: success → `Ok`, a
110
+ * modeled failure → `Err`, a die/interruption → `Defect`. The returned
111
+ * `AsyncResult` never throws when awaited.
112
+ *
113
+ * @typeParam T - the success value type.
114
+ * @typeParam E - the modeled error type.
115
+ * @param effect - the effect to run.
116
+ */
117
+ function fromEffect(effect) {
118
+ return fromSafePromise(Effect.runPromiseExit(effect)).flatMap((exit) => fromExit(exit));
119
+ }
120
+ function resultToEffect(result) {
121
+ return result.match({
122
+ ok: (value) => Effect.succeed(value),
123
+ err: (error) => Effect.fail(error),
124
+ defect: (cause) => Effect.die(cause)
125
+ });
126
+ }
127
+ function dieToResult(cause) {
128
+ return fromThrowable(() => {
129
+ throw cause;
130
+ }, defect)();
131
+ }
132
+ function settle(asyncResult) {
133
+ return (async () => await asyncResult)();
134
+ }
135
+ function isAsyncResult(source) {
136
+ return typeof source.then === "function";
137
+ }
138
+ //#endregion
139
+ export { fromEffect, fromEither, fromExit, toEffect, toEither, toExit };
140
+
141
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["// @unthrown/effect — interop between unthrown's `Result`/`AsyncResult` and\n// Effect's `Exit`, `Either`, and `Effect`.\n//\n// Effect is the one neighbour that shares unthrown's three-channel shape: an\n// `Exit<A, E>` is `Success` | `Failure(Cause)`, and a `Cause` distinguishes a\n// modeled failure (`Cause.fail`, ↔ `Err`) from an unexpected one (`Cause.die`,\n// ↔ `Defect`). So `Result ↔ Exit` is a genuine bijection — the showcase here.\n//\n// import { ok } from \"unthrown\";\n// import { toExit, fromEffect } from \"@unthrown/effect\";\n//\n// toExit(ok(1)); // Exit.succeed(1)\n// await fromEffect(Effect.succeed(1)).match({ ok, err, defect });\n//\n// `Either` has only two channels, so converting a `Result` *into* an `Either`\n// forces you to triage the defect with `onDefect` (Thesis #3): there is no\n// silent path that drops it.\n\nimport { Cause, Effect, Either, Exit, Option } from \"effect\";\nimport { defect, err, fromSafePromise, fromThrowable, ok } from \"unthrown\";\nimport type { AsyncResult, Result } from \"unthrown\";\n\n/**\n * Convert a `Result` into an Effect `Exit` — a **bijection**, since both\n * carry three channels.\n *\n * @remarks\n * `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and\n * `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with\n * {@link fromExit}.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param result - the result to convert.\n *\n * @example\n * ```ts\n * import { ok } from \"unthrown\";\n * import { toExit } from \"@unthrown/effect\";\n * toExit(ok(1)); // Exit.succeed(1)\n * ```\n */\nexport function toExit<T, E>(result: Result<T, E>): Exit.Exit<T, E> {\n return result.match<Exit.Exit<T, E>>({\n ok: (value) => Exit.succeed(value),\n err: (error) => Exit.fail(error),\n defect: (cause) => Exit.die(cause),\n });\n}\n\n/**\n * Convert an Effect `Exit` into a `Result` — the inverse of\n * {@link toExit}.\n *\n * @remarks\n * `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced:\n *\n * - a `Cause.die` becomes a `Defect`,\n * - otherwise a `Cause.fail` becomes the modeled `Err`,\n * - a pure interruption (or empty cause) becomes a `Defect`.\n *\n * A `Defect` **dominates** a modeled failure in a composite cause — the same\n * rule unthrown's `all` uses, on the principle that an unexpected failure is the\n * more severe signal.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param exit - the exit to convert.\n */\nexport function fromExit<T, E>(exit: Exit.Exit<T, E>): Result<T, E> {\n return Exit.match(exit, {\n onSuccess: (value) => ok(value),\n onFailure: (cause) => {\n const die = Cause.dieOption(cause);\n if (Option.isSome(die)) return dieToResult<T, E>(die.value);\n const failure = Cause.failureOption(cause);\n if (Option.isSome(failure)) return err(failure.value);\n // No modeled failure and no die: a pure interruption (or empty cause).\n return dieToResult<T, E>(Cause.squash(cause));\n },\n });\n}\n\n/**\n * Convert a `Result` into an Effect `Either`, triaging any defect.\n *\n * @remarks\n * `Either` has no defect channel, so a `Defect` cannot pass through silently —\n * `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This\n * is the boundary-qualification rule (Thesis #3) applied on the way out:\n * `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param result - the result to convert.\n * @param onDefect - folds a defect's unknown cause into a modeled `E`.\n */\nexport function toEither<T, E>(\n result: Result<T, E>,\n onDefect: (cause: unknown) => E,\n): Either.Either<T, E> {\n return result.match<Either.Either<T, E>>({\n ok: (value) => Either.right(value),\n err: (error) => Either.left(error),\n defect: (cause) => Either.left(onDefect(cause)),\n });\n}\n\n/**\n * Convert an Effect `Either` into a `Result`.\n *\n * @remarks\n * `Right → Ok`, `Left → Err`. An `Either` carries no defect, so the result is\n * never a `Defect`.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param either - the either to convert.\n */\nexport function fromEither<T, E>(either: Either.Either<T, E>): Result<T, E> {\n return Either.match(either, {\n onLeft: (error) => err(error),\n onRight: (value) => ok(value),\n });\n}\n\n/**\n * Lift a `Result` or `AsyncResult` into an `Effect`.\n *\n * @remarks\n * `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The\n * resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is\n * awaited inside the effect (it never rejects), so this is the `AsyncResult →\n * Effect` direction too.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param source - the result, or async result, to lift.\n */\nexport function toEffect<T, E>(source: Result<T, E>): Effect.Effect<T, E>;\nexport function toEffect<T, E>(source: AsyncResult<T, E>): Effect.Effect<T, E>;\nexport function toEffect<T, E>(source: Result<T, E> | AsyncResult<T, E>): Effect.Effect<T, E> {\n if (isAsyncResult(source)) {\n return Effect.flatMap(\n Effect.promise(() => settle(source)),\n (result) => resultToEffect(result),\n );\n }\n return resultToEffect(source);\n}\n\n/**\n * Run an `Effect` and collect its outcome as an `AsyncResult`.\n *\n * @remarks\n * The effect must need no environment (`R = never`). It is run to an `Exit`\n * (which never rejects), then folded with {@link fromExit}: success → `Ok`, a\n * modeled failure → `Err`, a die/interruption → `Defect`. The returned\n * `AsyncResult` never throws when awaited.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param effect - the effect to run.\n */\nexport function fromEffect<T, E>(effect: Effect.Effect<T, E>): AsyncResult<T, E> {\n return fromSafePromise(Effect.runPromiseExit(effect)).flatMap((exit) => fromExit(exit));\n}\n\nfunction resultToEffect<T, E>(result: Result<T, E>): Effect.Effect<T, E> {\n return result.match<Effect.Effect<T, E>>({\n ok: (value) => Effect.succeed(value),\n err: (error) => Effect.fail(error),\n defect: (cause) => Effect.die(cause),\n });\n}\n\n// Effect's `die`/interruption channel is an un-triaged failure crossing into\n// unthrown; replaying it through the throwable boundary lands it in the `Defect`\n// state — the sanctioned (boundary-only) way to mint a defect `Result`.\nfunction dieToResult<T, E>(cause: unknown): Result<T, E> {\n return fromThrowable<[], never, never>((): never => {\n throw cause;\n }, defect)();\n}\n\nfunction settle<T, E>(asyncResult: AsyncResult<T, E>): Promise<Result<T, E>> {\n return (async () => await asyncResult)();\n}\n\nfunction isAsyncResult<T, E>(\n source: Result<T, E> | AsyncResult<T, E>,\n): source is AsyncResult<T, E> {\n return typeof (source as { then?: unknown }).then === \"function\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,OAAa,QAAuC;CAClE,OAAO,OAAO,MAAuB;EACnC,KAAK,UAAU,KAAK,QAAQ,KAAK;EACjC,MAAM,UAAU,KAAK,KAAK,KAAK;EAC/B,SAAS,UAAU,KAAK,IAAI,KAAK;CACnC,CAAC;AACH;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,SAAe,MAAqC;CAClE,OAAO,KAAK,MAAM,MAAM;EACtB,YAAY,UAAU,GAAG,KAAK;EAC9B,YAAY,UAAU;GACpB,MAAM,MAAM,MAAM,UAAU,KAAK;GACjC,IAAI,OAAO,OAAO,GAAG,GAAG,OAAO,YAAkB,IAAI,KAAK;GAC1D,MAAM,UAAU,MAAM,cAAc,KAAK;GACzC,IAAI,OAAO,OAAO,OAAO,GAAG,OAAO,IAAI,QAAQ,KAAK;GAEpD,OAAO,YAAkB,MAAM,OAAO,KAAK,CAAC;EAC9C;CACF,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAgB,SACd,QACA,UACqB;CACrB,OAAO,OAAO,MAA2B;EACvC,KAAK,UAAU,OAAO,MAAM,KAAK;EACjC,MAAM,UAAU,OAAO,KAAK,KAAK;EACjC,SAAS,UAAU,OAAO,KAAK,SAAS,KAAK,CAAC;CAChD,CAAC;AACH;;;;;;;;;;;;AAaA,SAAgB,WAAiB,QAA2C;CAC1E,OAAO,OAAO,MAAM,QAAQ;EAC1B,SAAS,UAAU,IAAI,KAAK;EAC5B,UAAU,UAAU,GAAG,KAAK;CAC9B,CAAC;AACH;AAiBA,SAAgB,SAAe,QAA+D;CAC5F,IAAI,cAAc,MAAM,GACtB,OAAO,OAAO,QACZ,OAAO,cAAc,OAAO,MAAM,CAAC,IAClC,WAAW,eAAe,MAAM,CACnC;CAEF,OAAO,eAAe,MAAM;AAC9B;;;;;;;;;;;;;;AAeA,SAAgB,WAAiB,QAAgD;CAC/E,OAAO,gBAAgB,OAAO,eAAe,MAAM,CAAC,CAAC,CAAC,SAAS,SAAS,SAAS,IAAI,CAAC;AACxF;AAEA,SAAS,eAAqB,QAA2C;CACvE,OAAO,OAAO,MAA2B;EACvC,KAAK,UAAU,OAAO,QAAQ,KAAK;EACnC,MAAM,UAAU,OAAO,KAAK,KAAK;EACjC,SAAS,UAAU,OAAO,IAAI,KAAK;CACrC,CAAC;AACH;AAKA,SAAS,YAAkB,OAA8B;CACvD,OAAO,oBAA6C;EAClD,MAAM;CACR,GAAG,MAAM,CAAC,CAAC;AACb;AAEA,SAAS,OAAa,aAAuD;CAC3E,QAAQ,YAAY,MAAM,YAAA,CAAa;AACzC;AAEA,SAAS,cACP,QAC6B;CAC7B,OAAO,OAAQ,OAA8B,SAAS;AACxD"}
package/docs/index.md ADDED
@@ -0,0 +1,270 @@
1
+ **@unthrown/effect**
2
+
3
+ ***
4
+
5
+ # @unthrown/effect
6
+
7
+ ## Functions
8
+
9
+ ### fromEffect()
10
+
11
+ ```ts
12
+ function fromEffect<T, E>(effect): AsyncResult<T, E>;
13
+ ```
14
+
15
+ Defined in: index.ts:165
16
+
17
+ Run an `Effect` and collect its outcome as an `AsyncResult`.
18
+
19
+ #### Type Parameters
20
+
21
+ | Type Parameter | Description |
22
+ | ------ | ------ |
23
+ | `T` | the success value type. |
24
+ | `E` | the modeled error type. |
25
+
26
+ #### Parameters
27
+
28
+ | Parameter | Type | Description |
29
+ | ------ | ------ | ------ |
30
+ | `effect` | `Effect`&lt;`T`, `E`&gt; | the effect to run. |
31
+
32
+ #### Returns
33
+
34
+ `AsyncResult`&lt;`T`, `E`&gt;
35
+
36
+ #### Remarks
37
+
38
+ The effect must need no environment (`R = never`). It is run to an `Exit`
39
+ (which never rejects), then folded with [fromExit](#fromexit): success → `Ok`, a
40
+ modeled failure → `Err`, a die/interruption → `Defect`. The returned
41
+ `AsyncResult` never throws when awaited.
42
+
43
+ ***
44
+
45
+ ### fromEither()
46
+
47
+ ```ts
48
+ function fromEither<T, E>(either): Result<T, E>;
49
+ ```
50
+
51
+ Defined in: index.ts:120
52
+
53
+ Convert an Effect `Either` into a `Result`.
54
+
55
+ #### Type Parameters
56
+
57
+ | Type Parameter | Description |
58
+ | ------ | ------ |
59
+ | `T` | the success value type. |
60
+ | `E` | the modeled error type. |
61
+
62
+ #### Parameters
63
+
64
+ | Parameter | Type | Description |
65
+ | ------ | ------ | ------ |
66
+ | `either` | `Either`&lt;`T`, `E`&gt; | the either to convert. |
67
+
68
+ #### Returns
69
+
70
+ `Result`&lt;`T`, `E`&gt;
71
+
72
+ #### Remarks
73
+
74
+ `Right → Ok`, `Left → Err`. An `Either` carries no defect, so the result is
75
+ never a `Defect`.
76
+
77
+ ***
78
+
79
+ ### fromExit()
80
+
81
+ ```ts
82
+ function fromExit<T, E>(exit): Result<T, E>;
83
+ ```
84
+
85
+ Defined in: index.ts:70
86
+
87
+ Convert an Effect `Exit` into a `Result` — the inverse of
88
+ [toExit](#toexit).
89
+
90
+ #### Type Parameters
91
+
92
+ | Type Parameter | Description |
93
+ | ------ | ------ |
94
+ | `T` | the success value type. |
95
+ | `E` | the modeled error type. |
96
+
97
+ #### Parameters
98
+
99
+ | Parameter | Type | Description |
100
+ | ------ | ------ | ------ |
101
+ | `exit` | `Exit`&lt;`T`, `E`&gt; | the exit to convert. |
102
+
103
+ #### Returns
104
+
105
+ `Result`&lt;`T`, `E`&gt;
106
+
107
+ #### Remarks
108
+
109
+ `Exit.Success → Ok`. For a failure, the enclosing `Cause` is reduced:
110
+
111
+ - a `Cause.die` becomes a `Defect`,
112
+ - otherwise a `Cause.fail` becomes the modeled `Err`,
113
+ - a pure interruption (or empty cause) becomes a `Defect`.
114
+
115
+ A `Defect` **dominates** a modeled failure in a composite cause — the same
116
+ rule unthrown's `all` uses, on the principle that an unexpected failure is the
117
+ more severe signal.
118
+
119
+ ***
120
+
121
+ ### toEffect()
122
+
123
+ #### Call Signature
124
+
125
+ ```ts
126
+ function toEffect<T, E>(source): Effect<T, E>;
127
+ ```
128
+
129
+ Defined in: index.ts:140
130
+
131
+ Lift a `Result` or `AsyncResult` into an `Effect`.
132
+
133
+ ##### Type Parameters
134
+
135
+ | Type Parameter | Description |
136
+ | ------ | ------ |
137
+ | `T` | the success value type. |
138
+ | `E` | the modeled error type. |
139
+
140
+ ##### Parameters
141
+
142
+ | Parameter | Type | Description |
143
+ | ------ | ------ | ------ |
144
+ | `source` | `Result`&lt;`T`, `E`&gt; | the result, or async result, to lift. |
145
+
146
+ ##### Returns
147
+
148
+ `Effect`&lt;`T`, `E`&gt;
149
+
150
+ ##### Remarks
151
+
152
+ `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The
153
+ resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is
154
+ awaited inside the effect (it never rejects), so this is the `AsyncResult →
155
+ Effect` direction too.
156
+
157
+ #### Call Signature
158
+
159
+ ```ts
160
+ function toEffect<T, E>(source): Effect<T, E>;
161
+ ```
162
+
163
+ Defined in: index.ts:141
164
+
165
+ Lift a `Result` or `AsyncResult` into an `Effect`.
166
+
167
+ ##### Type Parameters
168
+
169
+ | Type Parameter | Description |
170
+ | ------ | ------ |
171
+ | `T` | the success value type. |
172
+ | `E` | the modeled error type. |
173
+
174
+ ##### Parameters
175
+
176
+ | Parameter | Type | Description |
177
+ | ------ | ------ | ------ |
178
+ | `source` | `AsyncResult`&lt;`T`, `E`&gt; | the result, or async result, to lift. |
179
+
180
+ ##### Returns
181
+
182
+ `Effect`&lt;`T`, `E`&gt;
183
+
184
+ ##### Remarks
185
+
186
+ `Ok → Effect.succeed`, `Err → Effect.fail`, `Defect → Effect.die`. The
187
+ resulting `Effect` needs no environment (`R = never`). An `AsyncResult` is
188
+ awaited inside the effect (it never rejects), so this is the `AsyncResult →
189
+ Effect` direction too.
190
+
191
+ ***
192
+
193
+ ### toEither()
194
+
195
+ ```ts
196
+ function toEither<T, E>(result, onDefect): Either<T, E>;
197
+ ```
198
+
199
+ Defined in: index.ts:98
200
+
201
+ Convert a `Result` into an Effect `Either`, triaging any defect.
202
+
203
+ #### Type Parameters
204
+
205
+ | Type Parameter | Description |
206
+ | ------ | ------ |
207
+ | `T` | the success value type. |
208
+ | `E` | the modeled error type. |
209
+
210
+ #### Parameters
211
+
212
+ | Parameter | Type | Description |
213
+ | ------ | ------ | ------ |
214
+ | `result` | `Result`&lt;`T`, `E`&gt; | the result to convert. |
215
+ | `onDefect` | (`cause`) => `E` | folds a defect's unknown cause into a modeled `E`. |
216
+
217
+ #### Returns
218
+
219
+ `Either`&lt;`T`, `E`&gt;
220
+
221
+ #### Remarks
222
+
223
+ `Either` has no defect channel, so a `Defect` cannot pass through silently —
224
+ `onDefect` **must** fold its cause into a modeled error `E` (a `Left`). This
225
+ is the boundary-qualification rule (Thesis #3) applied on the way out:
226
+ `Ok → Right`, `Err → Left`, `Defect → Left(onDefect(cause))`.
227
+
228
+ ***
229
+
230
+ ### toExit()
231
+
232
+ ```ts
233
+ function toExit<T, E>(result): Exit<T, E>;
234
+ ```
235
+
236
+ Defined in: index.ts:43
237
+
238
+ Convert a `Result` into an Effect `Exit` — a **bijection**, since both
239
+ carry three channels.
240
+
241
+ #### Type Parameters
242
+
243
+ | Type Parameter | Description |
244
+ | ------ | ------ |
245
+ | `T` | the success value type. |
246
+ | `E` | the modeled error type. |
247
+
248
+ #### Parameters
249
+
250
+ | Parameter | Type | Description |
251
+ | ------ | ------ | ------ |
252
+ | `result` | `Result`&lt;`T`, `E`&gt; | the result to convert. |
253
+
254
+ #### Returns
255
+
256
+ `Exit`&lt;`T`, `E`&gt;
257
+
258
+ #### Remarks
259
+
260
+ `Ok → Exit.succeed`, `Err → Exit.fail` (a modeled `Cause.fail`), and
261
+ `Defect → Exit.die` (an unexpected `Cause.die`). Round-trips with
262
+ [fromExit](#fromexit).
263
+
264
+ #### Example
265
+
266
+ ```ts
267
+ import { ok } from "unthrown";
268
+ import { toExit } from "@unthrown/effect";
269
+ toExit(ok(1)); // Exit.succeed(1)
270
+ ```
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@unthrown/effect",
3
+ "version": "0.1.0",
4
+ "description": "Effect interop for unthrown",
5
+ "keywords": [
6
+ "effect",
7
+ "either",
8
+ "errors-as-values",
9
+ "exit",
10
+ "result",
11
+ "typescript",
12
+ "unthrown"
13
+ ],
14
+ "homepage": "https://github.com/btravstack/unthrown#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/btravstack/unthrown/issues"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Benoit TRAVERS <benoit.travers.fr@gmail.com>",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/btravstack/unthrown.git",
23
+ "directory": "packages/effect"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "docs"
28
+ ],
29
+ "type": "module",
30
+ "main": "./dist/index.cjs",
31
+ "module": "./dist/index.mjs",
32
+ "types": "./dist/index.d.mts",
33
+ "exports": {
34
+ ".": {
35
+ "import": {
36
+ "types": "./dist/index.d.mts",
37
+ "default": "./dist/index.mjs"
38
+ },
39
+ "require": {
40
+ "types": "./dist/index.d.cts",
41
+ "default": "./dist/index.cjs"
42
+ }
43
+ },
44
+ "./package.json": "./package.json"
45
+ },
46
+ "dependencies": {
47
+ "unthrown": "0.1.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "24.13.2",
51
+ "@vitest/coverage-v8": "4.1.8",
52
+ "effect": "3.21.4",
53
+ "tsdown": "0.22.2",
54
+ "typedoc": "0.28.19",
55
+ "typedoc-plugin-markdown": "4.12.0",
56
+ "typescript": "6.0.3",
57
+ "vitest": "4.1.8",
58
+ "@unthrown/typedoc": "0.1.0",
59
+ "@unthrown/tsconfig": "0.1.0"
60
+ },
61
+ "peerDependencies": {
62
+ "effect": "^3"
63
+ },
64
+ "engines": {
65
+ "node": ">=22.19"
66
+ },
67
+ "scripts": {
68
+ "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
69
+ "build:docs": "typedoc",
70
+ "dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
71
+ "test": "vitest run",
72
+ "typecheck": "tsc --noEmit"
73
+ }
74
+ }