wellcrafted 0.43.0 → 0.44.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.
Files changed (35) hide show
  1. package/README.md +157 -203
  2. package/dist/error/index.d.ts +3 -3
  3. package/dist/error/index.js +2 -2
  4. package/dist/{error-Dy9wXt5_.js → error-BkeqDeUq.js} +2 -2
  5. package/dist/{error-Dy9wXt5_.js.map → error-BkeqDeUq.js.map} +1 -1
  6. package/dist/{index-B9PnZCTt.d.ts → index-ByVX3bXz.d.ts} +2 -2
  7. package/dist/{index-B9PnZCTt.d.ts.map → index-ByVX3bXz.d.ts.map} +1 -1
  8. package/dist/{index-DnoV2ZDO.d.ts → index-D0f5JWiT.d.ts} +2 -2
  9. package/dist/{index-DnoV2ZDO.d.ts.map → index-D0f5JWiT.d.ts.map} +1 -1
  10. package/dist/json.d.ts +5 -5
  11. package/dist/json.js +4 -4
  12. package/dist/logger/index.d.ts +3 -3
  13. package/dist/logger/index.js +2 -2
  14. package/dist/query/index.d.ts +19 -19
  15. package/dist/query/index.d.ts.map +1 -1
  16. package/dist/query/index.js +15 -15
  17. package/dist/query/index.js.map +1 -1
  18. package/dist/result/index.d.ts +3 -3
  19. package/dist/result/index.js +3 -3
  20. package/dist/{result-C5cJ1_WU.js → result-C_ph_izC.js} +5 -5
  21. package/dist/result-C_ph_izC.js.map +1 -0
  22. package/dist/{result-DKwq9BCr.d.ts → result-_socO0Ud.d.ts} +5 -5
  23. package/dist/{result-DKwq9BCr.d.ts.map → result-_socO0Ud.d.ts.map} +1 -1
  24. package/dist/{result-C9V2Knvt.js → result-pV2mfn0W.js} +2 -2
  25. package/dist/{result-C9V2Knvt.js.map → result-pV2mfn0W.js.map} +1 -1
  26. package/dist/{tap-err-CP-re1HT.js → tap-err-BENAkFsH.js} +2 -2
  27. package/dist/{tap-err-CP-re1HT.js.map → tap-err-BENAkFsH.js.map} +1 -1
  28. package/dist/{tap-err-CFhHBPfH.d.ts → tap-err-C0xfVXtz.d.ts} +2 -2
  29. package/dist/{tap-err-CFhHBPfH.d.ts.map → tap-err-C0xfVXtz.d.ts.map} +1 -1
  30. package/dist/testing.d.ts +3 -3
  31. package/dist/testing.js +4 -4
  32. package/dist/{types-tXXk7K9Q.d.ts → types-ojNaDB4n.d.ts} +2 -2
  33. package/dist/{types-tXXk7K9Q.d.ts.map → types-ojNaDB4n.d.ts.map} +1 -1
  34. package/package.json +5 -2
  35. package/dist/result-C5cJ1_WU.js.map +0 -1
package/README.md CHANGED
@@ -9,84 +9,141 @@
9
9
 
10
10
  Tagged errors and Result types as plain objects. < 2KB, zero dependencies.
11
11
 
12
- Most Result libraries hand you a container and leave the error type as an exercise. You get `Ok` and `Err` but nothing to help you define, compose, or serialize the errors themselves. So you end up with string literals, ad-hoc objects, or class hierarchies that break the moment you call `JSON.stringify`.
12
+ `try/catch` throws away your error's type the moment you catch it. You get `catch (error: unknown)` and you're guessing again. And a thrown `Error` travels badly: `JSON.stringify(new Error("boom"))` is `{}`, so the message vanishes the moment it hits a log line, a Web Worker, or an IPC boundary, where `instanceof` stops working too.
13
13
 
14
- wellcrafted takes the opposite approach: start with the errors. `defineErrors` gives you typed, serializable, composable error variants inspired by Rust's [thiserror](https://docs.rs/thiserror). The Result type is just `{ data, error }` destructuring — the same shape you already know from Supabase, SvelteKit load functions, and TanStack Query. No `.isOk()` method chains, no `.map().andThen().orElse()` pipelines. Check `error`, use `data`. That's it.
14
+ wellcrafted fixes both. Define your errors once as plain data, return them instead of throwing, and check them with the `{ data, error }` shape you already know from Supabase, SvelteKit load functions, and TanStack Query. No `.isOk()` method chains, no `.map().andThen().orElse()` pipelines. Check `error`, use `data`.
15
15
 
16
16
  ```typescript
17
- import { defineErrors, extractErrorMessage, type InferErrors } from "wellcrafted/error";
18
- import { tryAsync, Ok, type Result } from "wellcrafted/result";
17
+ import { defineErrors } from "wellcrafted/error";
18
+ import { trySync } from "wellcrafted/result";
19
+
20
+ // The key becomes error.name. The fields you return are typed on the error.
21
+ const { ParseError } = defineErrors({
22
+ ParseError: ({ path }: { path: string }) => ({
23
+ message: `Could not parse ${path}`,
24
+ path,
25
+ }),
26
+ });
19
27
 
20
- // Define domain errors all variants in one call
21
- const UserError = defineErrors({
22
- AlreadyExists: ({ email }: { email: string }) => ({
23
- message: `User ${email} already exists`,
24
- email,
28
+ const { data, error } = trySync({
29
+ try: () => JSON.parse(raw),
30
+ catch: () => ParseError({ path: "config.json" }),
31
+ });
32
+
33
+ if (error) {
34
+ // error is { name: "ParseError"; message: string; path: string }
35
+ console.error(error.message, error.path);
36
+ } else {
37
+ // data is the parsed value, error is null
38
+ use(data);
39
+ }
40
+ ```
41
+
42
+ That's the whole idea: define an error, wrap the throwing call, destructure the result, check `error`. A *tagged error* is just an object with a `name` field you can `switch` on. Everything below is that pattern at scale.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ npm install wellcrafted
48
+ ```
49
+
50
+ ## A real service
51
+
52
+ Here is the pattern in shipping code, lightly trimmed from [Whispering](https://github.com/EpicenterHQ/epicenter)'s transcription layer. Each service owns a small vocabulary of things that can go wrong, declared up front with `defineErrors`.
53
+
54
+ ```typescript
55
+ import {
56
+ defineErrors,
57
+ extractErrorMessage,
58
+ type InferErrors,
59
+ } from "wellcrafted/error";
60
+ import { type Result, tryAsync } from "wellcrafted/result";
61
+
62
+ export const ElevenLabsError = defineErrors({
63
+ MissingApiKey: () => ({ message: "ElevenLabs API key is required" }),
64
+ FileTooLarge: ({ sizeMb, maxMb }: { sizeMb: number; maxMb: number }) => ({
65
+ message: `File ${sizeMb.toFixed(1)}MB exceeds ${maxMb}MB limit`,
66
+ sizeMb,
67
+ maxMb,
25
68
  }),
26
- CreateFailed: ({ email, cause }: { email: string; cause: unknown }) => ({
27
- message: `Failed to create user ${email}: ${extractErrorMessage(cause)}`,
28
- email,
69
+ Unexpected: ({ cause }: { cause: unknown }) => ({
70
+ message: extractErrorMessage(cause),
29
71
  cause,
30
72
  }),
31
73
  });
32
- type UserError = InferErrors<typeof UserError>;
33
- // ^? { name: "AlreadyExists"; message: string; email: string }
34
- // | { name: "CreateFailed"; message: string; email: string; cause: unknown }
74
+ export type ElevenLabsError = InferErrors<typeof ElevenLabsError>;
35
75
 
36
- // Each factory returns Err<...> directly — no wrapping needed
37
- async function createUser(email: string): Promise<Result<User, UserError>> {
38
- const existing = await db.findByEmail(email);
39
- if (existing) return UserError.AlreadyExists({ email });
76
+ async function transcribe(
77
+ audio: Blob,
78
+ apiKey: string,
79
+ ): Promise<Result<string, ElevenLabsError>> {
80
+ if (!apiKey) return ElevenLabsError.MissingApiKey(); // a factory already is an Err
81
+
82
+ const sizeMb = audio.size / (1024 * 1024);
83
+ if (sizeMb > 1000) return ElevenLabsError.FileTooLarge({ sizeMb, maxMb: 1000 });
40
84
 
41
85
  return tryAsync({
42
- try: () => db.users.create({ email }),
43
- catch: (error) => UserError.CreateFailed({ email, cause: error }),
86
+ try: () => callElevenLabs(apiKey, audio), // may throw
87
+ catch: (cause) => ElevenLabsError.Unexpected({ cause }),
44
88
  });
45
89
  }
90
+ ```
46
91
 
47
- // Discriminate with switch TypeScript narrows automatically
48
- const { data, error } = await createUser("alice@example.com");
92
+ The caller checks `error`, then `switch`es on `error.name` to handle each case with the right fields in scope:
93
+
94
+ ```typescript
95
+ const { data, error } = await transcribe(audio, apiKey);
49
96
  if (error) {
50
97
  switch (error.name) {
51
- case "AlreadyExists": console.log(error.email); break;
52
- case "CreateFailed": console.log(error.email); break;
53
- // ^ TypeScript knows exactly which fields exist
98
+ case "MissingApiKey": return promptForKey();
99
+ case "FileTooLarge": return warn(`Audio too large: ${error.sizeMb}MB`);
100
+ case "Unexpected": return report(error.cause);
54
101
  }
55
102
  }
103
+ showTranscript(data); // data is string, error is null
56
104
  ```
57
105
 
58
- ## Install
106
+ Three things are doing the work here, and the rest of this README is just those three things.
59
107
 
60
- ```bash
61
- npm install wellcrafted
62
- ```
108
+ ## Define your errors
63
109
 
64
- ## Why define errors at all?
110
+ You can put any value in `Ok` and `Err`. So why `defineErrors`?
65
111
 
66
- You can use `Ok` and `Err` with any value. So why bother with `defineErrors`?
112
+ Because errors aren't random. A function fails in a handful of known ways, and a namespace is where you enumerate them up front: the closed set of what can go wrong. A user service fails with `AlreadyExists`, `CreateFailed`, or `InvalidEmail`, and nothing else. That set is exactly a Rust error enum: the namespace is the enum, each key is a variant, and `switch (error.name)` is the `match`. `defineErrors` brings the [thiserror](https://docs.rs/thiserror) pattern to TypeScript as plain objects instead of classes.
67
113
 
68
- Because in practice, errors aren't random. Every service has a handful of things that can go wrong, and you want to enumerate them upfront. A user service has `AlreadyExists`, `CreateFailed`, `InvalidEmail`. An HTTP client has `Connection`, `Timeout`, `Response`. These are logical groups — the error vocabulary for a domain. Rust codified this with [thiserror](https://docs.rs/thiserror). `defineErrors` brings the same pattern to TypeScript, but outputs plain objects instead of classes.
114
+ Enumerating the set up front is what makes the rest pay off. The union flows into your `Result<T, E>` signature, so a caller sees every way the call can fail right in the type, and a `switch` with a [`never` guard](#exhaustiveness) turns a forgotten variant into a compile error.
69
115
 
70
- **Errors are data, not classes.** Plain frozen objects with no prototype chain. `JSON.stringify` just works no `stack` property eating up your logs, no `instanceof` checks that break across package boundaries. This matters anywhere errors cross a serialization boundary: Web Workers, server actions, sync engines, IPC. The error you create is the error that arrives.
116
+ Each key becomes a variant. Your constructor returns `{ message, ...fields }`; `defineErrors` stamps the key on as `name` and hands back a factory that returns `Err<...>` directly. `InferErrors` extracts the union of every variant for your `Result<T, E>` signatures.
71
117
 
72
- **Every factory returns `Err<...>` directly.** No wrapping step. Return it from a `tryAsync` catch handler or as a standalone early return — `if (existing) return UserError.AlreadyExists({ email })`. The Result type flows naturally.
118
+ ```typescript
119
+ const UserError = defineErrors({
120
+ AlreadyExists: ({ email }: { email: string }) => ({
121
+ message: `User ${email} already exists`,
122
+ email,
123
+ }),
124
+ CreateFailed: ({ email, cause }: { email: string; cause: unknown }) => ({
125
+ message: `Failed to create user ${email}: ${extractErrorMessage(cause)}`,
126
+ email,
127
+ cause,
128
+ }),
129
+ });
130
+ type UserError = InferErrors<typeof UserError>;
131
+ // ^? { name: "AlreadyExists"; message: string; email: string }
132
+ // | { name: "CreateFailed"; message: string; email: string; cause: unknown }
133
+ ```
73
134
 
74
- **Discriminated unions for free.** `switch (error.name)` gives you full TypeScript narrowing. No `instanceof`, no type predicates, no manual union types. Add a new variant and every consumer that switches gets a compile error until they handle it.
135
+ Two properties make this pay off:
75
136
 
76
- ## Wrapping unsafe code
137
+ **Errors are data, not classes.** Plain frozen objects, no prototype chain. The fields you put on them are plain own properties, so they survive `JSON.stringify`, a Web Worker, or an IPC hop with no `stack` noise and no `instanceof` that breaks across package boundaries. The error you create is the error that arrives.
77
138
 
78
- `trySync` and `tryAsync` turn throwing operations into `Result` types. The `catch` handler receives the raw error and returns an `Err<...>` from your `defineErrors` factories.
139
+ **Every factory returns `Err<...>` directly.** No wrapping step. Return it from a `tryAsync` catch handler or as a standalone early return (`if (existing) return UserError.AlreadyExists({ email })`). The `Result` type flows out naturally.
79
140
 
80
- ```typescript
81
- import { trySync, tryAsync } from "wellcrafted/result";
141
+ ## Wrap throwing code
82
142
 
83
- const JsonError = defineErrors({
84
- ParseFailed: ({ input, cause }: { input: string; cause: unknown }) => ({
85
- message: `Invalid JSON: ${extractErrorMessage(cause)}`,
86
- input: input.slice(0, 100),
87
- cause,
88
- }),
89
- });
143
+ `trySync` and `tryAsync` turn a throwing operation into a `Result`. The `catch` handler receives the raw error and returns one of your `defineErrors` variants. Anything you don't wrap keeps throwing exactly as before, so you can adopt this one function at a time.
144
+
145
+ ```typescript
146
+ import { trySync, tryAsync, Ok } from "wellcrafted/result";
90
147
 
91
148
  // Synchronous
92
149
  const { data, error } = trySync({
@@ -101,135 +158,88 @@ const { data, error } = await tryAsync({
101
158
  });
102
159
  ```
103
160
 
104
- When `catch` returns `Ok(fallback)` instead of `Err`, the return type narrows to `Ok<T>` no error checking needed:
161
+ When `catch` returns `Ok(fallback)` instead of an error, there is no error branch left: the return type narrows to `Ok<T>`, so `error` is always `null` and you can skip the check.
105
162
 
106
163
  ```typescript
107
- const { data: parsed } = trySync({
108
- try: (): unknown => JSON.parse(riskyJson),
109
- catch: () => Ok([]),
164
+ const { data: items } = trySync({
165
+ try: (): string[] => JSON.parse(riskyJson),
166
+ catch: () => Ok([] as string[]), // recovered; there is no error to check
110
167
  });
111
- // parsed is always defined — the catch recovered
112
168
  ```
113
169
 
114
- ## Composing errors across layers
170
+ ## Compose across layers
115
171
 
116
- This is where the pattern pays off. Each layer defines its own error vocabulary; inner errors become `cause` fields, and `extractErrorMessage` formats them inside the factory so call sites stay clean.
172
+ Each layer defines its own vocabulary and folds the layer below into a `cause` field. `extractErrorMessage` formats that cause inside the factory, so call sites stay clean. You propagate with a plain `if (error) return` (there is no `?` operator; see [what you give up](#what-you-give-up)).
117
173
 
118
174
  ```typescript
119
- // Service layer: domain errors wrap raw failures via cause
120
- const UserServiceError = defineErrors({
121
- NotFound: ({ userId }: { userId: string }) => ({
122
- message: `User ${userId} not found`,
123
- userId,
124
- }),
125
- FetchFailed: ({ userId, cause }: { userId: string; cause: unknown }) => ({
126
- message: `Failed to fetch user ${userId}: ${extractErrorMessage(cause)}`,
127
- userId,
128
- cause,
129
- }),
130
- });
131
- type UserServiceError = InferErrors<typeof UserServiceError>;
132
-
133
175
  async function getUser(userId: string): Promise<Result<User, UserServiceError>> {
134
- const response = await tryAsync({
176
+ const { data: response, error } = await tryAsync({
135
177
  try: () => fetch(`/api/users/${userId}`),
136
178
  catch: (cause) => UserServiceError.FetchFailed({ userId, cause }),
137
- // raw fetch error becomes cause ^^^^^
138
- });
139
- if (response.error) return response;
140
-
141
- if (response.data.status === 404) return UserServiceError.NotFound({ userId });
142
-
143
- return tryAsync({
144
- try: () => response.data.json() as Promise<User>,
145
- catch: (cause) => UserServiceError.FetchFailed({ userId, cause }),
179
+ // raw fetch error becomes cause ^^^^^
146
180
  });
147
- }
181
+ if (error) return Err(error); // propagate as-is
148
182
 
149
- // API handler: maps domain errors to HTTP responses
150
- async function handleGetUser(request: Request, userId: string) {
151
- const { data, error } = await getUser(userId);
152
-
153
- if (error) {
154
- switch (error.name) {
155
- case "NotFound":
156
- return Response.json({ error: error.message }, { status: 404 });
157
- case "FetchFailed":
158
- return Response.json({ error: error.message }, { status: 502 });
159
- }
160
- }
161
-
162
- return Response.json(data);
183
+ if (response.status === 404) return UserServiceError.NotFound({ userId });
184
+ return Ok(await response.json());
163
185
  }
164
186
  ```
165
187
 
166
- The full error chain is JSON-serializable at every level. Log it, send it over the wire, display it in a toast. The structure survives.
188
+ Your tagged fields are plain data, so the chain logs and crosses the wire cleanly. The raw `cause` is the exception: it serializes only as well as whatever you caught, which is why the factories above fold it through `extractErrorMessage` into the `message` string.
167
189
 
168
190
  ## The Result type
169
191
 
170
- The foundation is a simple discriminated union:
192
+ The foundation is one discriminated union:
171
193
 
172
194
  ```typescript
173
- import { Ok, Err, trySync, tryAsync, type Result } from "wellcrafted/result";
174
-
175
- type Ok<T> = { data: T; error: null };
176
- type Err<E> = { error: E; data: null };
195
+ type Ok<T> = { data: T; error: null };
196
+ type Err<E> = { error: E; data: null };
177
197
  type Result<T, E> = Ok<T> | Err<E>;
178
198
  ```
179
199
 
180
- Check `error` first, and TypeScript narrows `data` automatically:
200
+ Check `error` first and TypeScript narrows `data` for you:
181
201
 
182
202
  ```typescript
183
203
  const { data, error } = await someOperation();
184
- if (error) {
185
- // error is E, data is null
186
- return;
187
- }
204
+ if (error) return; // error is E, data is null
188
205
  // data is T, error is null
189
206
  ```
190
207
 
191
- ## Also in the box
208
+ `if (error)` works because errors from `defineErrors` are always objects, and an object is truthy. The exact check is `error !== null` (or the `isErr` guard); reach for it if you ever put a falsy value like `0` or `""` in an `Err`.
192
209
 
193
- ### Brand Types
210
+ ### Exhaustiveness
194
211
 
195
- Create distinct types from primitives so TypeScript catches mix-ups at compile time. Zero runtime footprint purely a type utility.
212
+ `switch (error.name)` narrows each case, and your editor autocompletes every variant. To make a *new* variant a compile error until it is handled, add a `never` check in `default`:
196
213
 
197
214
  ```typescript
198
- import type { Brand } from "wellcrafted/brand";
199
-
200
- type UserId = string & Brand<"UserId">;
201
- type OrderId = string & Brand<"OrderId">;
202
-
203
- function getUser(id: UserId) { /* ... */ }
204
-
205
- const userId = "abc" as UserId;
206
- const orderId = "xyz" as OrderId;
207
- getUser(userId); // compiles
208
- getUser(orderId); // type error
215
+ switch (error.name) {
216
+ case "NotFound": return notFound();
217
+ case "FetchFailed": return badGateway();
218
+ default:
219
+ error satisfies never; // add a variant and this line fails to compile
220
+ }
209
221
  ```
210
222
 
211
- ### Query Integration
223
+ Plain TypeScript does not enforce exhaustive `switch` on its own; this one line is how you opt in.
212
224
 
213
- TanStack Query factories with `.options` for reactive components and explicit imperative helpers for event handlers.
225
+ ## What you give up
214
226
 
215
- ```typescript
216
- import { createQueryFactories } from "wellcrafted/query";
227
+ wellcrafted is not an effect system, and the honest cost is control flow. There is no `?` operator, so you propagate with an explicit `if (error) return` at each step. There is no dependency injection, no automatic short-circuiting, and no built-in concurrency. If you need those, reach for [Effect](https://effect.website); that is what it is for.
217
228
 
218
- const { defineQuery, defineMutation } = createQueryFactories(queryClient);
229
+ In exchange, the whole API is `{ data, error }`, `async/await`, and `switch`: no new runtime, no generators, no pipe operators to learn.
219
230
 
220
- const userQuery = defineQuery({
221
- queryKey: ["users", userId],
222
- queryFn: () => getUser(userId), // returns Result<User, UserError>
223
- });
231
+ ## Also in the box
224
232
 
225
- // Reactive: pass to useQuery (React) or createQuery (Svelte)
226
- const query = createQuery(() => userQuery.options);
233
+ Each lives behind its own subpath import, so you pay for only what you use.
227
234
 
228
- // Imperative: choose the query read policy explicitly
229
- const { data, error } = await userQuery.fetch();
230
- ```
235
+ - `wellcrafted/brand`: `Brand<T>` makes distinct types from primitives (`type UserId = string & Brand<"UserId">`) so the compiler catches mix-ups. Zero runtime.
236
+ - `wellcrafted/logger`: a small DI-based structured logger keyed on log level, built to take your `defineErrors` types directly. No global singleton.
237
+ - `wellcrafted/testing`: `expectOk` / `expectErr` unwrap a `Result` in a test, or throw with a readable message.
238
+ - `wellcrafted/json`: `parseJson` is `JSON.parse` that returns a `Result` instead of throwing.
239
+ - `wellcrafted/query`: TanStack Query adapters for Result-returning functions. Queries expose `.options`, `.fetch`, and `.ensure`; mutations are callable and expose `.options`.
240
+ - `wellcrafted/standard-schema`: wrap a `Result` as a [Standard Schema](https://github.com/standard-schema/standard-schema) for validators that speak the spec.
231
241
 
232
- ## Comparison
242
+ ## How it compares
233
243
 
234
244
  | | wellcrafted | neverthrow | better-result | fp-ts | Effect |
235
245
  |---|---|---|---|---|---|
@@ -239,89 +249,33 @@ const { data, error } = await userQuery.fetch();
239
249
  | Bundle size | < 2KB | ~5KB | ~2KB | ~30KB | ~50KB |
240
250
  | Syntax | async/await | Method chains | Method chains + generators | Pipe operators | Generators |
241
251
 
242
- Every Result library gives you a container. wellcrafted gives you what goes inside it then gets out of the way.
243
-
244
- ## Philosophy
245
-
246
- wellcrafted is deliberately idiomatic to JavaScript. The `{ data, error }` shape isn't novel — it's the same pattern used by Supabase, SvelteKit load functions, and TanStack Query. We chose it because it's already familiar, already destructurable, and requires zero new mental models.
247
-
248
- The same principle applies throughout: async/await instead of generators, `switch` instead of `.match()`, plain objects instead of class hierarchies. The best abstractions are the ones your team already knows. wellcrafted adds type-safe error definition on top of patterns that JavaScript developers use every day — it doesn't ask you to learn a new programming paradigm to handle errors.
249
-
250
- ## API Reference
251
-
252
- ### Error functions
253
-
254
- - **`defineErrors(config)`** — define multiple error factories in a single call. Each key becomes a variant; the value is a factory returning `{ message, ...fields }`. Every factory returns `Err<...>` directly.
255
- - **`extractErrorMessage(error)`** — extract a readable string from any `unknown` error value.
256
-
257
- ### Error types
258
-
259
- - **`InferErrors<T>`** — extract union of all error types from a `defineErrors` return value.
260
- - **`InferError<T>`** — extract a single variant's error type from one factory.
261
-
262
- ### Result functions
252
+ Every Result library hands you a container. wellcrafted hands you what goes inside it, then gets out of the way.
263
253
 
264
- - **`Ok(data)`** create a success result
265
- - **`Err(error)`** — create a failure result
266
- - **`trySync({ try, catch })`** — wrap a synchronous throwing operation
267
- - **`tryAsync({ try, catch })`** — wrap an async throwing operation
268
- - **`isOk(result)` / `isErr(result)`** — type guards
269
- - **`unwrap(result)`** — extract data or throw error
270
- - **`resolve(value)`** — handle values that may or may not be Results
271
- - **`partitionResults(results)`** — split an array of Results into separate ok/err arrays
254
+ ## API at a glance
272
255
 
273
- ### Query functions
256
+ From `wellcrafted/result`:
274
257
 
275
- - **`createQueryFactories(client)`** create query/mutation factories for TanStack Query
276
- - **`defineQuery(options)`**: define a query with `.options`, `.fetch()`, and `.ensure()`
277
- - **`defineMutation(options)`**: define a callable mutation with `.options` for hooks
258
+ - `Ok(data)` / `Err(error)`: construct a success or failure
259
+ - `trySync` / `tryAsync`: wrap a throwing operation, sync or async
260
+ - `Result<T, E>`: the `Ok<T> | Err<E>` union
278
261
 
279
- ### Standard Schema
262
+ From `wellcrafted/error`:
280
263
 
281
- - **`ResultSchema(dataSchema, errorSchema)`** [Standard Schema](https://github.com/standard-schema/standard-schema) wrapper for Result types, interoperable with any validator that supports the spec.
264
+ - `defineErrors(config)`: define a namespace of error variant factories
265
+ - `extractErrorMessage(value)`: pull a readable string out of any `unknown`
266
+ - `InferErrors<typeof MyError>`: the union of all variants; `InferError<typeof MyError.Variant>`: one variant
282
267
 
283
- ### Other types
268
+ Less common but there when you need them: `isOk` / `isErr` type guards, `unwrap` (extract or throw), `partitionResults` (split an array of Results), and `resolve` (handle values that may or may not be Results).
284
269
 
285
- - **`Result<T, E>`** union of `Ok<T> | Err<E>`
286
- - **`Brand<T, B>`** — branded type wrapper for distinct primitives
270
+ ## Teach your AI agent
287
271
 
288
- ## AI Agent Skills
289
-
290
- If you use an AI coding agent (Claude Code, Cursor, etc.), teach it how to use wellcrafted correctly:
272
+ If you use an AI coding agent, install the skills that teach it the patterns and anti-patterns directly:
291
273
 
292
274
  ```bash
293
275
  npx skills add wellcrafted-dev/wellcrafted
294
276
  ```
295
277
 
296
- This installs 5 skills that teach your agent the patterns, anti-patterns, and API conventions:
297
-
298
- | Skill | What it teaches |
299
- | --- | --- |
300
- | `define-errors` | `defineErrors` variants, `extractErrorMessage`, `InferErrors`/`InferError` type extraction |
301
- | `result-types` | `Ok`, `Err`, `trySync`/`tryAsync`, the `{ data, error }` destructuring pattern |
302
- | `query-factories` | `createQueryFactories`, `defineQuery`/`defineMutation`, reactive options, and imperative helpers |
303
- | `branded-types` | `Brand<T>`, brand constructor pattern, when to add runtime validation |
304
- | `patterns` | Architectural style guide: control flow, factory composition, service layers, error composition |
305
-
306
- Skills work with any agent that supports [`npx skills`](https://www.npmjs.com/package/skills). Install once, update with `npx skills update`.
307
-
308
-
309
- ## Development Setup
310
-
311
- ### AI Agent Skills
312
-
313
- AI agent skills are managed via [`npx skills`](https://www.npmjs.com/package/skills), sourced from [Epicenter](https://github.com/EpicenterHQ/epicenter). Only skills relevant to wellcrafted's domain are installed.
314
-
315
- ```bash
316
- # Install skills (already committed, but can be refreshed)
317
- npx skills add EpicenterHQ/epicenter --skill error-handling --skill define-errors -a claude-code -y
318
-
319
- # Update all installed skills
320
- npx skills update
321
-
322
- # List installed skills
323
- npx skills list
324
- ```
278
+ This installs five skills: `define-errors`, `result-types`, `query-factories`, `branded-types`, and `patterns` (the architectural style guide). They work with any agent that supports [`npx skills`](https://www.npmjs.com/package/skills). Install once, update with `npx skills update`.
325
279
 
326
280
  ## License
327
281
 
@@ -1,4 +1,4 @@
1
- import "../result-DKwq9BCr.js";
2
- import { AnyTaggedError, DefineErrorsReturn, ErrorBody, ErrorsConfig, InferError, InferErrors, ValidatedConfig } from "../types-tXXk7K9Q.js";
3
- import { defineErrors, extractErrorMessage } from "../index-B9PnZCTt.js";
1
+ import "../result-_socO0Ud.js";
2
+ import { AnyTaggedError, DefineErrorsReturn, ErrorBody, ErrorsConfig, InferError, InferErrors, ValidatedConfig } from "../types-ojNaDB4n.js";
3
+ import { defineErrors, extractErrorMessage } from "../index-ByVX3bXz.js";
4
4
  export { AnyTaggedError, DefineErrorsReturn, ErrorBody, ErrorsConfig, InferError, InferErrors, ValidatedConfig, defineErrors, extractErrorMessage };
@@ -1,4 +1,4 @@
1
- import "../result-C5cJ1_WU.js";
2
- import { defineErrors, extractErrorMessage } from "../error-Dy9wXt5_.js";
1
+ import "../result-C_ph_izC.js";
2
+ import { defineErrors, extractErrorMessage } from "../error-BkeqDeUq.js";
3
3
 
4
4
  export { defineErrors, extractErrorMessage };
@@ -1,4 +1,4 @@
1
- import { Err } from "./result-C5cJ1_WU.js";
1
+ import { Err } from "./result-C_ph_izC.js";
2
2
 
3
3
  //#region src/error/defineErrors.ts
4
4
  /**
@@ -104,4 +104,4 @@ function extractErrorMessage(error) {
104
104
 
105
105
  //#endregion
106
106
  export { defineErrors, extractErrorMessage };
107
- //# sourceMappingURL=error-Dy9wXt5_.js.map
107
+ //# sourceMappingURL=error-BkeqDeUq.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-Dy9wXt5_.js","names":["config: TConfig & ValidatedConfig<TConfig>","result: Record<string, unknown>","error: unknown"],"sources":["../src/error/defineErrors.ts","../src/error/extractErrorMessage.ts"],"sourcesContent":["import { Err } from \"../result/result.js\";\nimport type {\n\tDefineErrorsReturn,\n\tErrorsConfig,\n\tValidatedConfig,\n} from \"./types.js\";\n\n/**\n * Defines a set of typed error factories using Rust-style namespaced variants.\n *\n * Each key is a short variant name (the namespace provides context). Every\n * factory returns `Err<...>` directly — ready for `trySync`/`tryAsync` catch\n * handlers. The variant name is stamped as `name` on the error object.\n *\n * @example\n * ```ts\n * const HttpError = defineErrors({\n * Connection: ({ cause }: { cause: unknown }) => ({\n * message: `Failed to connect: ${extractErrorMessage(cause)}`,\n * cause,\n * }),\n * Response: ({ status }: { status: number; bodyMessage?: string }) => ({\n * message: `HTTP ${status}`,\n * status,\n * }),\n * Parse: ({ cause }: { cause: unknown }) => ({\n * message: `Failed to parse response body: ${extractErrorMessage(cause)}`,\n * cause,\n * }),\n * });\n *\n * type HttpError = InferErrors<typeof HttpError>;\n *\n * const result = HttpError.Connection({ cause: 'timeout' }); // Err<...>\n * ```\n *\n * Inspired by Rust's {@link https://docs.rs/thiserror | thiserror} crate. The\n * mapping is nearly 1:1:\n *\n * - `enum HttpError` → `const HttpError = defineErrors(...)`\n * - Variant `Connection { cause: String }` → key `Connection: ({ cause }: { cause: unknown }) => (...)`\n * - `#[error(\"Failed: {cause}\")]` → `` message: `Failed: ${extractErrorMessage(cause)}` ``\n * - `HttpError::Connection { ... }` → `HttpError.Connection({ ... })`\n * - `match error { Connection { .. } => }` → `switch (error.name) { case 'Connection': }`\n *\n * The equivalent Rust `thiserror` enum:\n * ```rust\n * #[derive(Error, Debug)]\n * enum HttpError {\n * #[error(\"Failed to connect: {cause}\")]\n * Connection { cause: String },\n *\n * #[error(\"HTTP {status}\")]\n * Response { status: u16, body_message: Option<String> },\n *\n * #[error(\"Failed to parse response body: {cause}\")]\n * Parse { cause: String },\n * }\n * ```\n */\nexport function defineErrors<const TConfig extends ErrorsConfig>(\n\tconfig: TConfig & ValidatedConfig<TConfig>,\n): DefineErrorsReturn<TConfig> {\n\tconst result: Record<string, unknown> = {};\n\n\tfor (const [name, ctor] of Object.entries(config)) {\n\t\tresult[name] = (...args: unknown[]) => {\n\t\t\tconst body = (ctor as (...a: unknown[]) => Record<string, unknown>)(\n\t\t\t\t...args,\n\t\t\t);\n\t\t\treturn Err(Object.freeze({ ...body, name }));\n\t\t};\n\t}\n\n\treturn result as DefineErrorsReturn<TConfig>;\n}\n","/**\n * Extracts a readable error message from an unknown error value\n *\n * @param error - The unknown error to extract a message from\n * @returns A string representation of the error\n */\nexport function extractErrorMessage(error: unknown): string {\n\t// Handle Error instances\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\n\t// Handle primitives\n\tif (typeof error === \"string\") return error;\n\tif (\n\t\ttypeof error === \"number\" ||\n\t\ttypeof error === \"boolean\" ||\n\t\ttypeof error === \"bigint\"\n\t)\n\t\treturn String(error);\n\tif (typeof error === \"symbol\") return error.toString();\n\tif (error === null) return \"null\";\n\tif (error === undefined) return \"undefined\";\n\n\t// Handle arrays\n\tif (Array.isArray(error)) return JSON.stringify(error);\n\n\t// Handle plain objects\n\tif (typeof error === \"object\") {\n\t\tconst errorObj = error as Record<string, unknown>;\n\n\t\t// Check common error properties\n\t\tconst messageProps = [\n\t\t\t\"message\",\n\t\t\t\"error\",\n\t\t\t\"description\",\n\t\t\t\"title\",\n\t\t\t\"reason\",\n\t\t\t\"details\",\n\t\t] as const;\n\t\tfor (const prop of messageProps) {\n\t\t\tif (prop in errorObj && typeof errorObj[prop] === \"string\") {\n\t\t\t\treturn errorObj[prop];\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to JSON stringification\n\t\ttry {\n\t\t\treturn JSON.stringify(error);\n\t\t} catch {\n\t\t\treturn String(error);\n\t\t}\n\t}\n\n\t// Final fallback\n\treturn String(error);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA,SAAgB,aACfA,QAC8B;CAC9B,MAAMC,SAAkC,CAAE;AAE1C,MAAK,MAAM,CAAC,MAAM,KAAK,IAAI,OAAO,QAAQ,OAAO,CAChD,QAAO,QAAQ,CAAC,GAAG,SAAoB;EACtC,MAAM,OAAO,AAAC,KACb,GAAG,KACH;AACD,SAAO,IAAI,OAAO,OAAO;GAAE,GAAG;GAAM;EAAM,EAAC,CAAC;CAC5C;AAGF,QAAO;AACP;;;;;;;;;;ACrED,SAAgB,oBAAoBC,OAAwB;AAE3D,KAAI,iBAAiB,MACpB,QAAO,MAAM;AAId,YAAW,UAAU,SAAU,QAAO;AACtC,YACQ,UAAU,mBACV,UAAU,oBACV,UAAU,SAEjB,QAAO,OAAO,MAAM;AACrB,YAAW,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KAAI,UAAU,KAAM,QAAO;AAC3B,KAAI,iBAAqB,QAAO;AAGhC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,UAAU,MAAM;AAGtD,YAAW,UAAU,UAAU;EAC9B,MAAM,WAAW;EAGjB,MAAM,eAAe;GACpB;GACA;GACA;GACA;GACA;GACA;EACA;AACD,OAAK,MAAM,QAAQ,aAClB,KAAI,QAAQ,mBAAmB,SAAS,UAAU,SACjD,QAAO,SAAS;AAKlB,MAAI;AACH,UAAO,KAAK,UAAU,MAAM;EAC5B,QAAO;AACP,UAAO,OAAO,MAAM;EACpB;CACD;AAGD,QAAO,OAAO,MAAM;AACpB"}
1
+ {"version":3,"file":"error-BkeqDeUq.js","names":["config: TConfig & ValidatedConfig<TConfig>","result: Record<string, unknown>","error: unknown"],"sources":["../src/error/defineErrors.ts","../src/error/extractErrorMessage.ts"],"sourcesContent":["import { Err } from \"../result/result.js\";\nimport type {\n\tDefineErrorsReturn,\n\tErrorsConfig,\n\tValidatedConfig,\n} from \"./types.js\";\n\n/**\n * Defines a set of typed error factories using Rust-style namespaced variants.\n *\n * Each key is a short variant name (the namespace provides context). Every\n * factory returns `Err<...>` directly — ready for `trySync`/`tryAsync` catch\n * handlers. The variant name is stamped as `name` on the error object.\n *\n * @example\n * ```ts\n * const HttpError = defineErrors({\n * Connection: ({ cause }: { cause: unknown }) => ({\n * message: `Failed to connect: ${extractErrorMessage(cause)}`,\n * cause,\n * }),\n * Response: ({ status }: { status: number; bodyMessage?: string }) => ({\n * message: `HTTP ${status}`,\n * status,\n * }),\n * Parse: ({ cause }: { cause: unknown }) => ({\n * message: `Failed to parse response body: ${extractErrorMessage(cause)}`,\n * cause,\n * }),\n * });\n *\n * type HttpError = InferErrors<typeof HttpError>;\n *\n * const result = HttpError.Connection({ cause: 'timeout' }); // Err<...>\n * ```\n *\n * Inspired by Rust's {@link https://docs.rs/thiserror | thiserror} crate. The\n * mapping is nearly 1:1:\n *\n * - `enum HttpError` → `const HttpError = defineErrors(...)`\n * - Variant `Connection { cause: String }` → key `Connection: ({ cause }: { cause: unknown }) => (...)`\n * - `#[error(\"Failed: {cause}\")]` → `` message: `Failed: ${extractErrorMessage(cause)}` ``\n * - `HttpError::Connection { ... }` → `HttpError.Connection({ ... })`\n * - `match error { Connection { .. } => }` → `switch (error.name) { case 'Connection': }`\n *\n * The equivalent Rust `thiserror` enum:\n * ```rust\n * #[derive(Error, Debug)]\n * enum HttpError {\n * #[error(\"Failed to connect: {cause}\")]\n * Connection { cause: String },\n *\n * #[error(\"HTTP {status}\")]\n * Response { status: u16, body_message: Option<String> },\n *\n * #[error(\"Failed to parse response body: {cause}\")]\n * Parse { cause: String },\n * }\n * ```\n */\nexport function defineErrors<const TConfig extends ErrorsConfig>(\n\tconfig: TConfig & ValidatedConfig<TConfig>,\n): DefineErrorsReturn<TConfig> {\n\tconst result: Record<string, unknown> = {};\n\n\tfor (const [name, ctor] of Object.entries(config)) {\n\t\tresult[name] = (...args: unknown[]) => {\n\t\t\tconst body = (ctor as (...a: unknown[]) => Record<string, unknown>)(\n\t\t\t\t...args,\n\t\t\t);\n\t\t\treturn Err(Object.freeze({ ...body, name }));\n\t\t};\n\t}\n\n\treturn result as DefineErrorsReturn<TConfig>;\n}\n","/**\n * Extracts a readable error message from an unknown error value\n *\n * @param error - The unknown error to extract a message from\n * @returns A string representation of the error\n */\nexport function extractErrorMessage(error: unknown): string {\n\t// Handle Error instances\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\n\t// Handle primitives\n\tif (typeof error === \"string\") return error;\n\tif (\n\t\ttypeof error === \"number\" ||\n\t\ttypeof error === \"boolean\" ||\n\t\ttypeof error === \"bigint\"\n\t)\n\t\treturn String(error);\n\tif (typeof error === \"symbol\") return error.toString();\n\tif (error === null) return \"null\";\n\tif (error === undefined) return \"undefined\";\n\n\t// Handle arrays\n\tif (Array.isArray(error)) return JSON.stringify(error);\n\n\t// Handle plain objects\n\tif (typeof error === \"object\") {\n\t\tconst errorObj = error as Record<string, unknown>;\n\n\t\t// Check common error properties\n\t\tconst messageProps = [\n\t\t\t\"message\",\n\t\t\t\"error\",\n\t\t\t\"description\",\n\t\t\t\"title\",\n\t\t\t\"reason\",\n\t\t\t\"details\",\n\t\t] as const;\n\t\tfor (const prop of messageProps) {\n\t\t\tif (prop in errorObj && typeof errorObj[prop] === \"string\") {\n\t\t\t\treturn errorObj[prop];\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to JSON stringification\n\t\ttry {\n\t\t\treturn JSON.stringify(error);\n\t\t} catch {\n\t\t\treturn String(error);\n\t\t}\n\t}\n\n\t// Final fallback\n\treturn String(error);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA,SAAgB,aACfA,QAC8B;CAC9B,MAAMC,SAAkC,CAAE;AAE1C,MAAK,MAAM,CAAC,MAAM,KAAK,IAAI,OAAO,QAAQ,OAAO,CAChD,QAAO,QAAQ,CAAC,GAAG,SAAoB;EACtC,MAAM,OAAO,AAAC,KACb,GAAG,KACH;AACD,SAAO,IAAI,OAAO,OAAO;GAAE,GAAG;GAAM;EAAM,EAAC,CAAC;CAC5C;AAGF,QAAO;AACP;;;;;;;;;;ACrED,SAAgB,oBAAoBC,OAAwB;AAE3D,KAAI,iBAAiB,MACpB,QAAO,MAAM;AAId,YAAW,UAAU,SAAU,QAAO;AACtC,YACQ,UAAU,mBACV,UAAU,oBACV,UAAU,SAEjB,QAAO,OAAO,MAAM;AACrB,YAAW,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KAAI,UAAU,KAAM,QAAO;AAC3B,KAAI,iBAAqB,QAAO;AAGhC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,UAAU,MAAM;AAGtD,YAAW,UAAU,UAAU;EAC9B,MAAM,WAAW;EAGjB,MAAM,eAAe;GACpB;GACA;GACA;GACA;GACA;GACA;EACA;AACD,OAAK,MAAM,QAAQ,aAClB,KAAI,QAAQ,mBAAmB,SAAS,UAAU,SACjD,QAAO,SAAS;AAKlB,MAAI;AACH,UAAO,KAAK,UAAU,MAAM;EAC5B,QAAO;AACP,UAAO,OAAO,MAAM;EACpB;CACD;AAGD,QAAO,OAAO,MAAM;AACpB"}
@@ -1,4 +1,4 @@
1
- import { DefineErrorsReturn, ErrorsConfig, ValidatedConfig } from "./types-tXXk7K9Q.js";
1
+ import { DefineErrorsReturn, ErrorsConfig, ValidatedConfig } from "./types-ojNaDB4n.js";
2
2
 
3
3
  //#region src/error/defineErrors.d.ts
4
4
 
@@ -70,4 +70,4 @@ declare function extractErrorMessage(error: unknown): string;
70
70
 
71
71
  //#endregion
72
72
  export { defineErrors, extractErrorMessage };
73
- //# sourceMappingURL=index-B9PnZCTt.d.ts.map
73
+ //# sourceMappingURL=index-ByVX3bXz.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-B9PnZCTt.d.ts","names":[],"sources":["../src/error/defineErrors.ts","../src/error/extractErrorMessage.ts"],"sourcesContent":[],"mappings":";;;;;;AA4DA;;;;;;;;AAEqB;;;;ACxDrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBDsDgB,mCAAmC,sBAC1C,UAAU,gBAAgB,WAChC,mBAAmB;;;;;;;AAFtB;;;AACS,iBCvDO,mBAAA,CDuDP,KAAA,EAAA,OAAA,CAAA,EAAA,MAAA"}
1
+ {"version":3,"file":"index-ByVX3bXz.d.ts","names":[],"sources":["../src/error/defineErrors.ts","../src/error/extractErrorMessage.ts"],"sourcesContent":[],"mappings":";;;;;;AA4DA;;;;;;;;AAEqB;;;;ACxDrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBDsDgB,mCAAmC,sBAC1C,UAAU,gBAAgB,WAChC,mBAAmB;;;;;;;AAFtB;;;AACS,iBCvDO,mBAAA,CDuDP,KAAA,EAAA,OAAA,CAAA,EAAA,MAAA"}
@@ -1,4 +1,4 @@
1
- import { Err, Ok, Result } from "./result-DKwq9BCr.js";
1
+ import { Err, Ok, Result } from "./result-_socO0Ud.js";
2
2
 
3
3
  //#region src/result/utils.d.ts
4
4
 
@@ -25,4 +25,4 @@ declare function partitionResults<T, E>(results: Result<T, E>[]): {
25
25
  //# sourceMappingURL=utils.d.ts.map
26
26
  //#endregion
27
27
  export { partitionResults };
28
- //# sourceMappingURL=index-DnoV2ZDO.d.ts.map
28
+ //# sourceMappingURL=index-D0f5JWiT.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-DnoV2ZDO.d.ts","names":[],"sources":["../src/result/utils.ts"],"sourcesContent":[],"mappings":";;;;;;AAmBA;;;;;;;;;AAK+B;;;;;iBALf,gCAAgC,OAAO,GAAG;OAK7C,GAAG;QAAY,IAAI"}
1
+ {"version":3,"file":"index-D0f5JWiT.d.ts","names":[],"sources":["../src/result/utils.ts"],"sourcesContent":[],"mappings":";;;;;;AAmBA;;;;;;;;;AAK+B;;;;;iBALf,gCAAgC,OAAO,GAAG;OAK7C,GAAG;QAAY,IAAI"}
package/dist/json.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { Err, Result } from "./result-DKwq9BCr.js";
2
- import { InferError } from "./types-tXXk7K9Q.js";
3
- import "./index-B9PnZCTt.js";
4
- import "./tap-err-CFhHBPfH.js";
5
- import "./index-DnoV2ZDO.js";
1
+ import { Err, Result } from "./result-_socO0Ud.js";
2
+ import { InferError } from "./types-ojNaDB4n.js";
3
+ import "./index-ByVX3bXz.js";
4
+ import "./tap-err-C0xfVXtz.js";
5
+ import "./index-D0f5JWiT.js";
6
6
 
7
7
  //#region src/json.d.ts
8
8
 
package/dist/json.js CHANGED
@@ -1,7 +1,7 @@
1
- import { trySync } from "./result-C5cJ1_WU.js";
2
- import { defineErrors, extractErrorMessage } from "./error-Dy9wXt5_.js";
3
- import "./tap-err-CP-re1HT.js";
4
- import "./result-C9V2Knvt.js";
1
+ import { trySync } from "./result-C_ph_izC.js";
2
+ import { defineErrors, extractErrorMessage } from "./error-BkeqDeUq.js";
3
+ import "./tap-err-BENAkFsH.js";
4
+ import "./result-pV2mfn0W.js";
5
5
 
6
6
  //#region src/json.ts
7
7
  /**
@@ -1,6 +1,6 @@
1
- import { Err } from "../result-DKwq9BCr.js";
2
- import { AnyTaggedError } from "../types-tXXk7K9Q.js";
3
- import { tapErr } from "../tap-err-CFhHBPfH.js";
1
+ import { Err } from "../result-_socO0Ud.js";
2
+ import { AnyTaggedError } from "../types-ojNaDB4n.js";
3
+ import { tapErr } from "../tap-err-C0xfVXtz.js";
4
4
 
5
5
  //#region src/logger/types.d.ts
6
6
 
@@ -1,5 +1,5 @@
1
- import "../result-C5cJ1_WU.js";
2
- import { tapErr } from "../tap-err-CP-re1HT.js";
1
+ import "../result-C_ph_izC.js";
2
+ import { tapErr } from "../tap-err-BENAkFsH.js";
3
3
 
4
4
  //#region src/logger/console-sink.ts
5
5
  /**