@unthrown/boxed 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 +21 -0
- package/README.md +40 -0
- package/dist/index.cjs +85 -0
- package/dist/index.d.cts +61 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +61 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +83 -0
- package/dist/index.mjs.map +1 -0
- package/docs/index.md +147 -0
- package/package.json +74 -0
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,40 @@
|
|
|
1
|
+
# @unthrown/boxed
|
|
2
|
+
|
|
3
|
+
> [Boxed](https://boxed.cool) 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/boxed/)
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @unthrown/boxed @bloodyowl/boxed
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Boxed's `Result` has two channels (`Ok`/`Error`) and no defect channel. Coming
|
|
14
|
+
**in**, every Boxed result is an `Ok` or `Error` โ never a `Defect`. Going
|
|
15
|
+
**out**, a `Defect` has nowhere to live, so `toBoxed` **forces** you to triage it
|
|
16
|
+
with `onDefect` โ no defect is ever silently folded into your domain error type.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { ok } from "unthrown";
|
|
20
|
+
import { toBoxed, fromBoxed } from "@unthrown/boxed";
|
|
21
|
+
import { Result } from "@bloodyowl/boxed";
|
|
22
|
+
|
|
23
|
+
toBoxed(ok(1), (cause) => ({ _tag: "Bug", cause })); // Result.Ok(1)
|
|
24
|
+
fromBoxed(Result.Ok(1)); // Result<number, never>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- `toBoxed(r, onDefect)` / `fromBoxed(r)` โ sync `Result โ Result`.
|
|
28
|
+
- `toBoxedFuture(ar, onDefect)` / `fromBoxedFuture(future)` โ async
|
|
29
|
+
`AsyncResult โ Future<Result>`.
|
|
30
|
+
|
|
31
|
+
> Boxed's `Option` has no analogue here โ per unthrown's design, absence is
|
|
32
|
+
> expressed with `T | undefined` or `Result<T, NotFound>` (see `fromNullable`),
|
|
33
|
+
> not a dedicated `Option` type.
|
|
34
|
+
|
|
35
|
+
`@bloodyowl/boxed` is a peer dependency. (Boxed was formerly published as
|
|
36
|
+
`@swan-io/boxed`, now deprecated in favour of this maintained scope.)
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
[MIT](../../LICENSE) ยฉ Benoit TRAVERS
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _bloodyowl_boxed = require("@bloodyowl/boxed");
|
|
3
|
+
let unthrown = require("unthrown");
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Convert a `Result` into a Boxed `Result`, triaging any defect.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Boxed's `Result` has no defect channel, so `onDefect` **must** fold a
|
|
10
|
+
* `Defect`'s cause into a modeled error `E` (an `Error`). `Ok โ Result.Ok`,
|
|
11
|
+
* `Err โ Result.Error`, `Defect โ Result.Error(onDefect(cause))`.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - the success value type.
|
|
14
|
+
* @typeParam E - the modeled error type.
|
|
15
|
+
* @param result - the result to convert.
|
|
16
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
17
|
+
*/
|
|
18
|
+
function toBoxed(result, onDefect) {
|
|
19
|
+
return result.match({
|
|
20
|
+
ok: (value) => _bloodyowl_boxed.Result.Ok(value),
|
|
21
|
+
err: (error) => _bloodyowl_boxed.Result.Error(error),
|
|
22
|
+
defect: (cause) => _bloodyowl_boxed.Result.Error(onDefect(cause))
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert a Boxed `Result` into a `Result`.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* `Result.Ok โ Ok`, `Result.Error โ Err`. Boxed's `Result` carries no defect, so
|
|
30
|
+
* the result is never a `Defect`.
|
|
31
|
+
*
|
|
32
|
+
* @typeParam T - the success value type.
|
|
33
|
+
* @typeParam E - the modeled error type.
|
|
34
|
+
* @param result - the Boxed result to convert.
|
|
35
|
+
*/
|
|
36
|
+
function fromBoxed(result) {
|
|
37
|
+
return result.match({
|
|
38
|
+
Ok: (value) => (0, unthrown.ok)(value),
|
|
39
|
+
Error: (error) => (0, unthrown.err)(error)
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Convert an `AsyncResult` into a Boxed `Future<Result>`, triaging any
|
|
44
|
+
* defect.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* The async counterpart of {@link toBoxed}: `onDefect` is required for the same
|
|
48
|
+
* reason. The `AsyncResult` is awaited (it never rejects) and its settled
|
|
49
|
+
* `Result` is converted, then resolved into the `Future`.
|
|
50
|
+
*
|
|
51
|
+
* @typeParam T - the success value type.
|
|
52
|
+
* @typeParam E - the modeled error type.
|
|
53
|
+
* @param asyncResult - the async result to convert.
|
|
54
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
55
|
+
*/
|
|
56
|
+
function toBoxedFuture(asyncResult, onDefect) {
|
|
57
|
+
return _bloodyowl_boxed.Future.make((resolve) => {
|
|
58
|
+
settle(asyncResult).then((result) => {
|
|
59
|
+
resolve(toBoxed(result, onDefect));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert a Boxed `Future<Result>` into an `AsyncResult`.
|
|
65
|
+
*
|
|
66
|
+
* @remarks
|
|
67
|
+
* The async counterpart of {@link fromBoxed}. A `Result.Error` stays an `Err`;
|
|
68
|
+
* an *unexpected* rejection of the underlying promise becomes a `Defect`. The
|
|
69
|
+
* returned `AsyncResult` never throws when awaited.
|
|
70
|
+
*
|
|
71
|
+
* @typeParam T - the success value type.
|
|
72
|
+
* @typeParam E - the modeled error type.
|
|
73
|
+
* @param future - the Boxed future to convert.
|
|
74
|
+
*/
|
|
75
|
+
function fromBoxedFuture(future) {
|
|
76
|
+
return (0, unthrown.fromSafePromise)(future.toPromise()).flatMap((result) => fromBoxed(result));
|
|
77
|
+
}
|
|
78
|
+
function settle(asyncResult) {
|
|
79
|
+
return (async () => await asyncResult)();
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
exports.fromBoxed = fromBoxed;
|
|
83
|
+
exports.fromBoxedFuture = fromBoxedFuture;
|
|
84
|
+
exports.toBoxed = toBoxed;
|
|
85
|
+
exports.toBoxedFuture = toBoxedFuture;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Future, Result } from "@bloodyowl/boxed";
|
|
2
|
+
import { AsyncResult, Result as Result$1 } from "unthrown";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Convert a `Result` into a Boxed `Result`, triaging any defect.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Boxed's `Result` has no defect channel, so `onDefect` **must** fold a
|
|
10
|
+
* `Defect`'s cause into a modeled error `E` (an `Error`). `Ok โ Result.Ok`,
|
|
11
|
+
* `Err โ Result.Error`, `Defect โ Result.Error(onDefect(cause))`.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - the success value type.
|
|
14
|
+
* @typeParam E - the modeled error type.
|
|
15
|
+
* @param result - the result to convert.
|
|
16
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
17
|
+
*/
|
|
18
|
+
declare function toBoxed<T, E>(result: Result$1<T, E>, onDefect: (cause: unknown) => E): Result<T, E>;
|
|
19
|
+
/**
|
|
20
|
+
* Convert a Boxed `Result` into a `Result`.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* `Result.Ok โ Ok`, `Result.Error โ Err`. Boxed's `Result` carries no defect, so
|
|
24
|
+
* the result is never a `Defect`.
|
|
25
|
+
*
|
|
26
|
+
* @typeParam T - the success value type.
|
|
27
|
+
* @typeParam E - the modeled error type.
|
|
28
|
+
* @param result - the Boxed result to convert.
|
|
29
|
+
*/
|
|
30
|
+
declare function fromBoxed<T, E>(result: Result<T, E>): Result$1<T, E>;
|
|
31
|
+
/**
|
|
32
|
+
* Convert an `AsyncResult` into a Boxed `Future<Result>`, triaging any
|
|
33
|
+
* defect.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* The async counterpart of {@link toBoxed}: `onDefect` is required for the same
|
|
37
|
+
* reason. The `AsyncResult` is awaited (it never rejects) and its settled
|
|
38
|
+
* `Result` is converted, then resolved into the `Future`.
|
|
39
|
+
*
|
|
40
|
+
* @typeParam T - the success value type.
|
|
41
|
+
* @typeParam E - the modeled error type.
|
|
42
|
+
* @param asyncResult - the async result to convert.
|
|
43
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
44
|
+
*/
|
|
45
|
+
declare function toBoxedFuture<T, E>(asyncResult: AsyncResult<T, E>, onDefect: (cause: unknown) => E): Future<Result<T, E>>;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a Boxed `Future<Result>` into an `AsyncResult`.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* The async counterpart of {@link fromBoxed}. A `Result.Error` stays an `Err`;
|
|
51
|
+
* an *unexpected* rejection of the underlying promise becomes a `Defect`. The
|
|
52
|
+
* returned `AsyncResult` never throws when awaited.
|
|
53
|
+
*
|
|
54
|
+
* @typeParam T - the success value type.
|
|
55
|
+
* @typeParam E - the modeled error type.
|
|
56
|
+
* @param future - the Boxed future to convert.
|
|
57
|
+
*/
|
|
58
|
+
declare function fromBoxedFuture<T, E>(future: Future<Result<T, E>>): AsyncResult<T, E>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { fromBoxed, fromBoxedFuture, toBoxed, toBoxedFuture };
|
|
61
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;AAgCA;;;;;;;;;;;iBAAgB,OAAA,OACd,MAAA,EAAQ,QAAA,CAAO,CAAA,EAAG,CAAA,GAClB,QAAA,GAAW,KAAA,cAAmB,CAAA,GAC7B,MAAA,CAAY,CAAA,EAAG,CAAA;;;;;;;;;;;;iBAmBF,SAAA,OAAgB,MAAA,EAAQ,MAAA,CAAY,CAAA,EAAG,CAAA,IAAK,QAAA,CAAO,CAAA,EAAG,CAAA;;AAnBnD;AAmBnB;;;;;;;;;;;;iBAqBgB,aAAA,OACd,WAAA,EAAa,WAAA,CAAY,CAAA,EAAG,CAAA,GAC5B,QAAA,GAAW,KAAA,cAAmB,CAAA,GAC7B,MAAA,CAAO,MAAA,CAAY,CAAA,EAAG,CAAA;;;;;;;;;AAxB8C;AAqBvE;;;iBAuBgB,eAAA,OAAsB,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAY,CAAA,EAAG,CAAA,KAAM,WAAA,CAAY,CAAA,EAAG,CAAA"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Future, Result } from "@bloodyowl/boxed";
|
|
2
|
+
import { AsyncResult, Result as Result$1 } from "unthrown";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Convert a `Result` into a Boxed `Result`, triaging any defect.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Boxed's `Result` has no defect channel, so `onDefect` **must** fold a
|
|
10
|
+
* `Defect`'s cause into a modeled error `E` (an `Error`). `Ok โ Result.Ok`,
|
|
11
|
+
* `Err โ Result.Error`, `Defect โ Result.Error(onDefect(cause))`.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - the success value type.
|
|
14
|
+
* @typeParam E - the modeled error type.
|
|
15
|
+
* @param result - the result to convert.
|
|
16
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
17
|
+
*/
|
|
18
|
+
declare function toBoxed<T, E>(result: Result$1<T, E>, onDefect: (cause: unknown) => E): Result<T, E>;
|
|
19
|
+
/**
|
|
20
|
+
* Convert a Boxed `Result` into a `Result`.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* `Result.Ok โ Ok`, `Result.Error โ Err`. Boxed's `Result` carries no defect, so
|
|
24
|
+
* the result is never a `Defect`.
|
|
25
|
+
*
|
|
26
|
+
* @typeParam T - the success value type.
|
|
27
|
+
* @typeParam E - the modeled error type.
|
|
28
|
+
* @param result - the Boxed result to convert.
|
|
29
|
+
*/
|
|
30
|
+
declare function fromBoxed<T, E>(result: Result<T, E>): Result$1<T, E>;
|
|
31
|
+
/**
|
|
32
|
+
* Convert an `AsyncResult` into a Boxed `Future<Result>`, triaging any
|
|
33
|
+
* defect.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* The async counterpart of {@link toBoxed}: `onDefect` is required for the same
|
|
37
|
+
* reason. The `AsyncResult` is awaited (it never rejects) and its settled
|
|
38
|
+
* `Result` is converted, then resolved into the `Future`.
|
|
39
|
+
*
|
|
40
|
+
* @typeParam T - the success value type.
|
|
41
|
+
* @typeParam E - the modeled error type.
|
|
42
|
+
* @param asyncResult - the async result to convert.
|
|
43
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
44
|
+
*/
|
|
45
|
+
declare function toBoxedFuture<T, E>(asyncResult: AsyncResult<T, E>, onDefect: (cause: unknown) => E): Future<Result<T, E>>;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a Boxed `Future<Result>` into an `AsyncResult`.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* The async counterpart of {@link fromBoxed}. A `Result.Error` stays an `Err`;
|
|
51
|
+
* an *unexpected* rejection of the underlying promise becomes a `Defect`. The
|
|
52
|
+
* returned `AsyncResult` never throws when awaited.
|
|
53
|
+
*
|
|
54
|
+
* @typeParam T - the success value type.
|
|
55
|
+
* @typeParam E - the modeled error type.
|
|
56
|
+
* @param future - the Boxed future to convert.
|
|
57
|
+
*/
|
|
58
|
+
declare function fromBoxedFuture<T, E>(future: Future<Result<T, E>>): AsyncResult<T, E>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { fromBoxed, fromBoxedFuture, toBoxed, toBoxedFuture };
|
|
61
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;AAgCA;;;;;;;;;;;iBAAgB,OAAA,OACd,MAAA,EAAQ,QAAA,CAAO,CAAA,EAAG,CAAA,GAClB,QAAA,GAAW,KAAA,cAAmB,CAAA,GAC7B,MAAA,CAAY,CAAA,EAAG,CAAA;;;;;;;;;;;;iBAmBF,SAAA,OAAgB,MAAA,EAAQ,MAAA,CAAY,CAAA,EAAG,CAAA,IAAK,QAAA,CAAO,CAAA,EAAG,CAAA;;AAnBnD;AAmBnB;;;;;;;;;;;;iBAqBgB,aAAA,OACd,WAAA,EAAa,WAAA,CAAY,CAAA,EAAG,CAAA,GAC5B,QAAA,GAAW,KAAA,cAAmB,CAAA,GAC7B,MAAA,CAAO,MAAA,CAAY,CAAA,EAAG,CAAA;;;;;;;;;AAxB8C;AAqBvE;;;iBAuBgB,eAAA,OAAsB,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAY,CAAA,EAAG,CAAA,KAAM,WAAA,CAAY,CAAA,EAAG,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Future, Result } from "@bloodyowl/boxed";
|
|
2
|
+
import { err, fromSafePromise, ok } from "unthrown";
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* Convert a `Result` into a Boxed `Result`, triaging any defect.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Boxed's `Result` has no defect channel, so `onDefect` **must** fold a
|
|
9
|
+
* `Defect`'s cause into a modeled error `E` (an `Error`). `Ok โ Result.Ok`,
|
|
10
|
+
* `Err โ Result.Error`, `Defect โ Result.Error(onDefect(cause))`.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - the success value type.
|
|
13
|
+
* @typeParam E - the modeled error type.
|
|
14
|
+
* @param result - the result to convert.
|
|
15
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
16
|
+
*/
|
|
17
|
+
function toBoxed(result, onDefect) {
|
|
18
|
+
return result.match({
|
|
19
|
+
ok: (value) => Result.Ok(value),
|
|
20
|
+
err: (error) => Result.Error(error),
|
|
21
|
+
defect: (cause) => Result.Error(onDefect(cause))
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Convert a Boxed `Result` into a `Result`.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* `Result.Ok โ Ok`, `Result.Error โ Err`. Boxed's `Result` carries no defect, so
|
|
29
|
+
* the result is never a `Defect`.
|
|
30
|
+
*
|
|
31
|
+
* @typeParam T - the success value type.
|
|
32
|
+
* @typeParam E - the modeled error type.
|
|
33
|
+
* @param result - the Boxed result to convert.
|
|
34
|
+
*/
|
|
35
|
+
function fromBoxed(result) {
|
|
36
|
+
return result.match({
|
|
37
|
+
Ok: (value) => ok(value),
|
|
38
|
+
Error: (error) => err(error)
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convert an `AsyncResult` into a Boxed `Future<Result>`, triaging any
|
|
43
|
+
* defect.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* The async counterpart of {@link toBoxed}: `onDefect` is required for the same
|
|
47
|
+
* reason. The `AsyncResult` is awaited (it never rejects) and its settled
|
|
48
|
+
* `Result` is converted, then resolved into the `Future`.
|
|
49
|
+
*
|
|
50
|
+
* @typeParam T - the success value type.
|
|
51
|
+
* @typeParam E - the modeled error type.
|
|
52
|
+
* @param asyncResult - the async result to convert.
|
|
53
|
+
* @param onDefect - folds a defect's unknown cause into a modeled `E`.
|
|
54
|
+
*/
|
|
55
|
+
function toBoxedFuture(asyncResult, onDefect) {
|
|
56
|
+
return Future.make((resolve) => {
|
|
57
|
+
settle(asyncResult).then((result) => {
|
|
58
|
+
resolve(toBoxed(result, onDefect));
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert a Boxed `Future<Result>` into an `AsyncResult`.
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* The async counterpart of {@link fromBoxed}. A `Result.Error` stays an `Err`;
|
|
67
|
+
* an *unexpected* rejection of the underlying promise becomes a `Defect`. The
|
|
68
|
+
* returned `AsyncResult` never throws when awaited.
|
|
69
|
+
*
|
|
70
|
+
* @typeParam T - the success value type.
|
|
71
|
+
* @typeParam E - the modeled error type.
|
|
72
|
+
* @param future - the Boxed future to convert.
|
|
73
|
+
*/
|
|
74
|
+
function fromBoxedFuture(future) {
|
|
75
|
+
return fromSafePromise(future.toPromise()).flatMap((result) => fromBoxed(result));
|
|
76
|
+
}
|
|
77
|
+
function settle(asyncResult) {
|
|
78
|
+
return (async () => await asyncResult)();
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
export { fromBoxed, fromBoxedFuture, toBoxed, toBoxedFuture };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["BoxedResult"],"sources":["../src/index.ts"],"sourcesContent":["// @unthrown/boxed โ interop between unthrown's `Result`/`AsyncResult` and\n// Boxed's `Result`/`Future<Result>`.\n//\n// Boxed's `Result` has two channels (`Ok`/`Error`) and no defect channel.\n// Coming *in*, every Boxed result is an `Ok` or `Error` โ never a `Defect`.\n// Going *out*, a `Defect` has nowhere to live, so `toBoxed` forces you to triage\n// it with `onDefect` (Thesis #3): no defect is ever silently folded into your\n// domain error type.\n//\n// import { ok } from \"unthrown\";\n// import { toBoxed, fromBoxed } from \"@unthrown/boxed\";\n//\n// toBoxed(ok(1), (cause) => ({ _tag: \"Bug\", cause })); // Result.Ok(1)\n// fromBoxed(Result.Ok(1)); // Result<number, never>\n\nimport { Future, Result as BoxedResult } from \"@bloodyowl/boxed\";\nimport { err, fromSafePromise, ok } from \"unthrown\";\nimport type { AsyncResult, Result } from \"unthrown\";\n\n/**\n * Convert a `Result` into a Boxed `Result`, triaging any defect.\n *\n * @remarks\n * Boxed's `Result` has no defect channel, so `onDefect` **must** fold a\n * `Defect`'s cause into a modeled error `E` (an `Error`). `Ok โ Result.Ok`,\n * `Err โ Result.Error`, `Defect โ Result.Error(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 toBoxed<T, E>(\n result: Result<T, E>,\n onDefect: (cause: unknown) => E,\n): BoxedResult<T, E> {\n return result.match<BoxedResult<T, E>>({\n ok: (value) => BoxedResult.Ok(value),\n err: (error) => BoxedResult.Error(error),\n defect: (cause) => BoxedResult.Error(onDefect(cause)),\n });\n}\n\n/**\n * Convert a Boxed `Result` into a `Result`.\n *\n * @remarks\n * `Result.Ok โ Ok`, `Result.Error โ Err`. Boxed's `Result` carries no defect, so\n * the result is never a `Defect`.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param result - the Boxed result to convert.\n */\nexport function fromBoxed<T, E>(result: BoxedResult<T, E>): Result<T, E> {\n return result.match({\n Ok: (value) => ok(value),\n Error: (error) => err(error),\n });\n}\n\n/**\n * Convert an `AsyncResult` into a Boxed `Future<Result>`, triaging any\n * defect.\n *\n * @remarks\n * The async counterpart of {@link toBoxed}: `onDefect` is required for the same\n * reason. The `AsyncResult` is awaited (it never rejects) and its settled\n * `Result` is converted, then resolved into the `Future`.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param asyncResult - the async result to convert.\n * @param onDefect - folds a defect's unknown cause into a modeled `E`.\n */\nexport function toBoxedFuture<T, E>(\n asyncResult: AsyncResult<T, E>,\n onDefect: (cause: unknown) => E,\n): Future<BoxedResult<T, E>> {\n return Future.make<BoxedResult<T, E>>((resolve) => {\n void settle(asyncResult).then((result) => {\n resolve(toBoxed(result, onDefect));\n });\n });\n}\n\n/**\n * Convert a Boxed `Future<Result>` into an `AsyncResult`.\n *\n * @remarks\n * The async counterpart of {@link fromBoxed}. A `Result.Error` stays an `Err`;\n * an *unexpected* rejection of the underlying promise becomes a `Defect`. The\n * returned `AsyncResult` never throws when awaited.\n *\n * @typeParam T - the success value type.\n * @typeParam E - the modeled error type.\n * @param future - the Boxed future to convert.\n */\nexport function fromBoxedFuture<T, E>(future: Future<BoxedResult<T, E>>): AsyncResult<T, E> {\n return fromSafePromise(future.toPromise()).flatMap((result) => fromBoxed(result));\n}\n\nfunction settle<T, E>(asyncResult: AsyncResult<T, E>): Promise<Result<T, E>> {\n return (async () => await asyncResult)();\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgCA,SAAgB,QACd,QACA,UACmB;CACnB,OAAO,OAAO,MAAyB;EACrC,KAAK,UAAUA,OAAY,GAAG,KAAK;EACnC,MAAM,UAAUA,OAAY,MAAM,KAAK;EACvC,SAAS,UAAUA,OAAY,MAAM,SAAS,KAAK,CAAC;CACtD,CAAC;AACH;;;;;;;;;;;;AAaA,SAAgB,UAAgB,QAAyC;CACvE,OAAO,OAAO,MAAM;EAClB,KAAK,UAAU,GAAG,KAAK;EACvB,QAAQ,UAAU,IAAI,KAAK;CAC7B,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAgB,cACd,aACA,UAC2B;CAC3B,OAAO,OAAO,MAAyB,YAAY;EACjD,OAAY,WAAW,CAAC,CAAC,MAAM,WAAW;GACxC,QAAQ,QAAQ,QAAQ,QAAQ,CAAC;EACnC,CAAC;CACH,CAAC;AACH;;;;;;;;;;;;;AAcA,SAAgB,gBAAsB,QAAsD;CAC1F,OAAO,gBAAgB,OAAO,UAAU,CAAC,CAAC,CAAC,SAAS,WAAW,UAAU,MAAM,CAAC;AAClF;AAEA,SAAS,OAAa,aAAuD;CAC3E,QAAQ,YAAY,MAAM,YAAA,CAAa;AACzC"}
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
**@unthrown/boxed**
|
|
2
|
+
|
|
3
|
+
***
|
|
4
|
+
|
|
5
|
+
# @unthrown/boxed
|
|
6
|
+
|
|
7
|
+
## Functions
|
|
8
|
+
|
|
9
|
+
### fromBoxed()
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
function fromBoxed<T, E>(result): Result<T, E>;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Defined in: index.ts:55
|
|
16
|
+
|
|
17
|
+
Convert a Boxed `Result` into a `Result`.
|
|
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
|
+
| `result` | `Result`<`T`, `E`> | the Boxed result to convert. |
|
|
31
|
+
|
|
32
|
+
#### Returns
|
|
33
|
+
|
|
34
|
+
`Result`<`T`, `E`>
|
|
35
|
+
|
|
36
|
+
#### Remarks
|
|
37
|
+
|
|
38
|
+
`Result.Ok โ Ok`, `Result.Error โ Err`. Boxed's `Result` carries no defect, so
|
|
39
|
+
the result is never a `Defect`.
|
|
40
|
+
|
|
41
|
+
***
|
|
42
|
+
|
|
43
|
+
### fromBoxedFuture()
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
function fromBoxedFuture<T, E>(future): AsyncResult<T, E>;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Defined in: index.ts:99
|
|
50
|
+
|
|
51
|
+
Convert a Boxed `Future<Result>` into an `AsyncResult`.
|
|
52
|
+
|
|
53
|
+
#### Type Parameters
|
|
54
|
+
|
|
55
|
+
| Type Parameter | Description |
|
|
56
|
+
| ------ | ------ |
|
|
57
|
+
| `T` | the success value type. |
|
|
58
|
+
| `E` | the modeled error type. |
|
|
59
|
+
|
|
60
|
+
#### Parameters
|
|
61
|
+
|
|
62
|
+
| Parameter | Type | Description |
|
|
63
|
+
| ------ | ------ | ------ |
|
|
64
|
+
| `future` | `Future`<`Result`<`T`, `E`>> | the Boxed future to convert. |
|
|
65
|
+
|
|
66
|
+
#### Returns
|
|
67
|
+
|
|
68
|
+
`AsyncResult`<`T`, `E`>
|
|
69
|
+
|
|
70
|
+
#### Remarks
|
|
71
|
+
|
|
72
|
+
The async counterpart of [fromBoxed](#fromboxed). A `Result.Error` stays an `Err`;
|
|
73
|
+
an *unexpected* rejection of the underlying promise becomes a `Defect`. The
|
|
74
|
+
returned `AsyncResult` never throws when awaited.
|
|
75
|
+
|
|
76
|
+
***
|
|
77
|
+
|
|
78
|
+
### toBoxed()
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
function toBoxed<T, E>(result, onDefect): Result<T, E>;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Defined in: index.ts:33
|
|
85
|
+
|
|
86
|
+
Convert a `Result` into a Boxed `Result`, triaging any defect.
|
|
87
|
+
|
|
88
|
+
#### Type Parameters
|
|
89
|
+
|
|
90
|
+
| Type Parameter | Description |
|
|
91
|
+
| ------ | ------ |
|
|
92
|
+
| `T` | the success value type. |
|
|
93
|
+
| `E` | the modeled error type. |
|
|
94
|
+
|
|
95
|
+
#### Parameters
|
|
96
|
+
|
|
97
|
+
| Parameter | Type | Description |
|
|
98
|
+
| ------ | ------ | ------ |
|
|
99
|
+
| `result` | `Result`<`T`, `E`> | the result to convert. |
|
|
100
|
+
| `onDefect` | (`cause`) => `E` | folds a defect's unknown cause into a modeled `E`. |
|
|
101
|
+
|
|
102
|
+
#### Returns
|
|
103
|
+
|
|
104
|
+
`Result`<`T`, `E`>
|
|
105
|
+
|
|
106
|
+
#### Remarks
|
|
107
|
+
|
|
108
|
+
Boxed's `Result` has no defect channel, so `onDefect` **must** fold a
|
|
109
|
+
`Defect`'s cause into a modeled error `E` (an `Error`). `Ok โ Result.Ok`,
|
|
110
|
+
`Err โ Result.Error`, `Defect โ Result.Error(onDefect(cause))`.
|
|
111
|
+
|
|
112
|
+
***
|
|
113
|
+
|
|
114
|
+
### toBoxedFuture()
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
function toBoxedFuture<T, E>(asyncResult, onDefect): Future<Result<T, E>>;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Defined in: index.ts:76
|
|
121
|
+
|
|
122
|
+
Convert an `AsyncResult` into a Boxed `Future<Result>`, triaging any
|
|
123
|
+
defect.
|
|
124
|
+
|
|
125
|
+
#### Type Parameters
|
|
126
|
+
|
|
127
|
+
| Type Parameter | Description |
|
|
128
|
+
| ------ | ------ |
|
|
129
|
+
| `T` | the success value type. |
|
|
130
|
+
| `E` | the modeled error type. |
|
|
131
|
+
|
|
132
|
+
#### Parameters
|
|
133
|
+
|
|
134
|
+
| Parameter | Type | Description |
|
|
135
|
+
| ------ | ------ | ------ |
|
|
136
|
+
| `asyncResult` | `AsyncResult`<`T`, `E`> | the async result to convert. |
|
|
137
|
+
| `onDefect` | (`cause`) => `E` | folds a defect's unknown cause into a modeled `E`. |
|
|
138
|
+
|
|
139
|
+
#### Returns
|
|
140
|
+
|
|
141
|
+
`Future`<`Result`<`T`, `E`>>
|
|
142
|
+
|
|
143
|
+
#### Remarks
|
|
144
|
+
|
|
145
|
+
The async counterpart of [toBoxed](#toboxed): `onDefect` is required for the same
|
|
146
|
+
reason. The `AsyncResult` is awaited (it never rejects) and its settled
|
|
147
|
+
`Result` is converted, then resolved into the `Future`.
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unthrown/boxed",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Boxed interop for unthrown",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"boxed",
|
|
7
|
+
"errors-as-values",
|
|
8
|
+
"future",
|
|
9
|
+
"result",
|
|
10
|
+
"swan-io",
|
|
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/boxed"
|
|
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
|
+
"@bloodyowl/boxed": "3.4.0",
|
|
51
|
+
"@types/node": "24.13.2",
|
|
52
|
+
"@vitest/coverage-v8": "4.1.8",
|
|
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
|
+
"@bloodyowl/boxed": "^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
|
+
}
|