Skip to content

Commit ec0f8b6

Browse files
chore: release packages
1 parent 625f985 commit ec0f8b6

22 files changed

Lines changed: 331 additions & 195 deletions

.changeset/nervous-moons-judge.md

Lines changed: 0 additions & 27 deletions
This file was deleted.

.changeset/seven-rules-no-unused-matcher.md

Lines changed: 0 additions & 26 deletions
This file was deleted.

.changeset/tall-spoons-listen.md

Lines changed: 0 additions & 63 deletions
This file was deleted.

.changeset/wild-moons-smoke.md

Lines changed: 0 additions & 70 deletions
This file was deleted.

packages/boxed/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# @unthrown/boxed
22

3+
## 5.1.0
4+
5+
### Patch Changes
6+
7+
- Updated dependencies [625f985]
8+
- Updated dependencies [5ead919]
9+
- unthrown@5.1.0
10+
311
## 5.0.0
412

513
### Patch Changes

packages/boxed/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@unthrown/boxed",
3-
"version": "5.0.0",
3+
"version": "5.1.0",
44
"description": "Boxed interop for unthrown",
55
"keywords": [
66
"boxed",

packages/core/CHANGELOG.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,95 @@
11
# unthrown
22

3+
## 5.1.0
4+
5+
### Minor Changes
6+
7+
- 5ead919: Close a boundary hole where an `async` function's rejection escaped
8+
qualification, stop `toBeErrTagged` counting a message as payload, and name the
9+
value in `NonExhaustiveError`.
10+
11+
**`fromThrowable` / `fromSafeThrowable` now reject an `async` `fn`.** These wrap a
12+
**synchronous** function, so they only ever see a synchronous `throw`: an async
13+
`fn` rejects long after the boundary has returned, and its rejection could never
14+
reach `qualify`. It used to produce `Ok(<Promise>)` — un-triaged — and the
15+
rejection then floated as an unhandled rejection, which terminates the process on
16+
Node by default:
17+
18+
```ts
19+
const f = fromThrowable(
20+
async () => {
21+
throw new Error("boom");
22+
},
23+
(cause, defect) => defect(cause),
24+
);
25+
f(); // before: Ok(<Promise>) + an unhandled rejection
26+
// now: Defect(TypeError: … `fn` returned a thenable …)
27+
```
28+
29+
The orphaned rejection is adopted and silenced, so it cannot float. Reach for
30+
`fromPromise` / `fromSafePromise` for async work.
31+
32+
This is caught at runtime rather than by the type system — the one thenable ban
33+
in the library that is not a compile error. Putting `NotThenable` on `fn`'s return
34+
also makes **generic** functions unassignable, so `fromSafeThrowable(structuredClone)`
35+
would stop compiling with `T` collapsed to `unknown`; the phantom rest-tuple guard
36+
`fromPromise` uses fares worse. The success type is therefore slightly over-stated
37+
(`Result<Promise<T>, E>` is spellable but never inhabited) — the mirror of
38+
`recoverErrCases`'s `never` under-stating the error channel.
39+
40+
**`toBeErrTagged`'s exact-payload form now ignores every reserved key.** The
41+
documented way to set a `TaggedError`'s message is a subclass field —
42+
`override message = "…"` — which lands as an own **enumerable** property, so it
43+
leaked into the payload and failed an exact assertion on the very pattern the
44+
library prescribes:
45+
46+
```ts
47+
class HttpError extends TaggedError("HttpError")<{ status: number }> {
48+
override message = `http ${this.status}`;
49+
}
50+
expect(Err(new HttpError({ status: 500 }))).toBeErrTagged("HttpError", {
51+
status: 500,
52+
});
53+
// before: failed — the payload was seen as { status: 500, message: "http 500" }
54+
// now: passes
55+
```
56+
57+
The matcher now skips `_tag`, `name`, `message` and `stack` — exactly the keys
58+
`TaggedErrorInstance` omits and the constructor types `?: never`, so none of them
59+
can legitimately be payload. Assertions using `expect.objectContaining` are
60+
unaffected (they were already tolerant of the extra key).
61+
62+
**`NonExhaustiveError` now names the value it could not match.** `JSON.stringify`
63+
_returns_ `undefined` — it does not throw — for a function, a symbol, or
64+
`undefined`, so the `String(input)` fallback never fired and the message read
65+
"no pattern matched the value undefined" for exactly the rogue inputs this error
66+
exists to describe. It now falls back correctly (`… the value function rogueFn() {}`).
67+
68+
### Patch Changes
69+
70+
- 625f985: Adopt a discarded thenable so its rejection can't float, and stop
71+
`createResultClient`'s proxy from ever exposing a callable `then`.
72+
73+
**Core: the observers now adopt-and-silence a smuggled thenable.** `tap`,
74+
`tapErrCases`, `tapDefect` and `tapFailure` throw their callback's return value
75+
away, and the `Result`-returning combinators (`flatMap`, `flatTap`, `bind`,
76+
`flatMapErrCases`, `flatTapErrCases`, `recoverDefect`) reject a non-`Result`
77+
one. Either way a thenable that slipped past `NotThenable` — via a cast or a
78+
raw-JS caller — was dropped mid-flight, so a later rejection floated unhandled
79+
and took the process down on Node by default. Worse for an observer: its whole
80+
job is to make a failure visible, and this was the one path where the failure
81+
was invisible.
82+
83+
The boundaries already did exactly this for a thenable `qualify` and a thenable
84+
`fn`; this is the same net on the combinator side. The observed result still
85+
passes through unchanged — silencing does not change any outcome.
86+
87+
**`@unthrown/orpc`: `createResultClient` now answers `then` with `undefined`.**
88+
The proxy's `get` trap wraps every object/function property, so on a client
89+
whose own proxy answers _any_ key with a nested procedure, `rc.then` would be
90+
callable and `await rc` would invoke it. oRPC's client proxy happens to guard
91+
`then` today, but that is its invariant to change, not ours to depend on.
92+
393
## 5.0.0
494

595
### Major Changes

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "unthrown",
3-
"version": "5.0.0",
3+
"version": "5.1.0",
44
"description": "Explicit errors as values, with a separate defect (panic) channel",
55
"keywords": [
66
"defect",

packages/effect/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# @unthrown/effect
22

3+
## 5.1.0
4+
5+
### Patch Changes
6+
7+
- Updated dependencies [625f985]
8+
- Updated dependencies [5ead919]
9+
- unthrown@5.1.0
10+
311
## 5.0.0
412

513
### Patch Changes

packages/effect/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@unthrown/effect",
3-
"version": "5.0.0",
3+
"version": "5.1.0",
44
"description": "Effect interop for unthrown",
55
"keywords": [
66
"effect",

0 commit comments

Comments
 (0)