|
1 | 1 | # @cometloop/safe |
2 | 2 |
|
3 | | -Type-safe error handling for TypeScript using the Result pattern. Zero dependencies. |
| 3 | +Type-safe error handling library for TypeScript using the Result pattern. Zero dependencies. |
4 | 4 |
|
5 | | -Instead of `try/catch`, functions return a `SafeResult` tuple `[value, null]` or `[null, error]` — with full type inference and tagged access via `.ok`, `.value`, and `.error`. |
| 5 | +## **Wrap any function** |
| 6 | + |
| 7 | +- Flexible wrapping — single function, domain scope, or app-wide |
| 8 | +- Type-safe results — tuples or objects |
| 9 | +- Flexible parsing — transform results and errors with full type inference |
| 10 | +- Built in hooks — run side effects automatically |
| 11 | +- Async utils included — retry, timeout, abort, all, allSettled |
| 12 | +- No try/catch clutter — clean, concise call sites |
| 13 | + |
| 14 | +## Documentation |
| 15 | + |
| 16 | +Full API reference, examples, and guides: |
| 17 | + |
| 18 | +[https://cometloop.github.io/safe/](https://cometloop.github.io/safe/) |
| 19 | + |
| 20 | +How we recommend using this library: |
| 21 | + |
| 22 | +[https://cometloop.github.io/safe/docs/recommended-patterns](https://cometloop.github.io/safe/docs/recommended-patterns) |
| 23 | + |
| 24 | +## Example usage: |
| 25 | + |
| 26 | +```typescript |
| 27 | +import { createSafe, safe } from '@cometloop/safe' |
| 28 | + |
| 29 | +// Wrap any function — zero config |
| 30 | +const safeParse = safe.wrap(JSON.parse) |
| 31 | +const [data, err] = safeParse(rawInput) |
| 32 | + |
| 33 | +// Shared config for a whole domain |
| 34 | +const apiSafe = createSafe({ |
| 35 | + parseError: errorParser, |
| 36 | + defaultError: fallbackError, |
| 37 | + onError: errorHook, |
| 38 | +}) |
| 39 | + |
| 40 | +const fetchUser = apiSafe.wrapAsync(fetchUserAsync) |
| 41 | +const fetchPosts = apiSafe.wrapAsync(fetchPostsAsync) |
| 42 | + |
| 43 | +// Same config. Full type narrowing. |
| 44 | +const [user, userErr] = await fetchUser('123') |
| 45 | +if (userErr) return |
| 46 | + |
| 47 | +const [posts, postsErr] = await fetchPosts(user.id) |
| 48 | +console.log(user.name, posts.length) |
| 49 | + |
| 50 | +// Prefer objects? One call to switch. |
| 51 | +const objSafe = withObjects(apiSafe) |
| 52 | +const fetchPostsObj = objSafe.wrapAsync(fetchPostsAsync) |
| 53 | +const { ok, data, error } = await fetchPostsObj('123') |
| 54 | +``` |
6 | 55 |
|
7 | 56 | ## Installation |
8 | 57 |
|
| 58 | +```bash |
| 59 | +pnpm add @cometloop/safe |
| 60 | +``` |
| 61 | + |
| 62 | +```bash |
| 63 | +bun add @cometloop/safe |
| 64 | +``` |
| 65 | + |
| 66 | +```bash |
| 67 | +yarn add @cometloop/safe |
| 68 | +``` |
| 69 | + |
9 | 70 | ```bash |
10 | 71 | npm install @cometloop/safe |
11 | 72 | ``` |
@@ -65,14 +126,13 @@ All methods support optional `parseError` for custom error types, `parseResult` |
65 | 126 |
|
66 | 127 | - **Clean call sites** — configure once with `createSafe`, then call functions normally |
67 | 128 | - **Result tuples** — `[value, null]` or `[null, error]` with TypeScript narrowing |
68 | | -- **Tagged results** — `.ok`, `.value`, `.error` properties for pattern matching |
| 129 | +- **Object results** — prefer `{ ok, data, error }` over tuples? Use `withObjects` |
69 | 130 | - **Custom error types** — `parseError` maps caught errors to your domain types |
70 | 131 | - **Result transformation** — `parseResult` transforms successful values |
71 | 132 | - **Lifecycle hooks** — `onSuccess`, `onError`, `onSettled`, `onRetry`, `onHookError` |
72 | 133 | - **Retry with backoff** — configurable retry for async operations |
73 | 134 | - **Timeout/abort** — `abortAfter` with `AbortSignal` integration |
74 | 135 | - **Error normalization** — non-`Error` thrown values are automatically normalized |
75 | | -- **Object results** — prefer `{ ok, data, error }` over tuples? Use `withObjects` |
76 | 136 | - **Zero dependencies** |
77 | 137 |
|
78 | 138 | ## Documentation |
|
0 commit comments