wellcrafted 0.35.0 → 0.37.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 (41) hide show
  1. package/dist/error/index.d.ts +4 -74
  2. package/dist/error/index.js +3 -106
  3. package/dist/error-DLVm7dsh.js +150 -0
  4. package/dist/error-DLVm7dsh.js.map +1 -0
  5. package/dist/index-BNWUFJ69.d.ts +129 -0
  6. package/dist/index-BNWUFJ69.d.ts.map +1 -0
  7. package/dist/{index-mb9iYu0a.d.ts → index-DnoV2ZDO.d.ts} +2 -2
  8. package/dist/{index-mb9iYu0a.d.ts.map → index-DnoV2ZDO.d.ts.map} +1 -1
  9. package/dist/json.d.ts +57 -1
  10. package/dist/json.d.ts.map +1 -1
  11. package/dist/json.js +51 -0
  12. package/dist/json.js.map +1 -0
  13. package/dist/logger/index.d.ts +40 -6
  14. package/dist/logger/index.d.ts.map +1 -1
  15. package/dist/logger/index.js +39 -5
  16. package/dist/logger/index.js.map +1 -1
  17. package/dist/query/index.d.ts +3 -3
  18. package/dist/query/index.js +3 -3
  19. package/dist/result/index.d.ts +3 -3
  20. package/dist/result/index.js +3 -3
  21. package/dist/{result-DzL3K2yA.js → result-C5cJ1_WU.js} +9 -4
  22. package/dist/result-C5cJ1_WU.js.map +1 -0
  23. package/dist/{result-corfYKOe.js → result-C9V2Knvt.js} +2 -2
  24. package/dist/{result-corfYKOe.js.map → result-C9V2Knvt.js.map} +1 -1
  25. package/dist/{result-BongGO2O.d.ts → result-DKwq9BCr.d.ts} +9 -4
  26. package/dist/result-DKwq9BCr.d.ts.map +1 -0
  27. package/dist/{tap-err-Bqs9aQpZ.d.ts → tap-err-CFhHBPfH.d.ts} +2 -2
  28. package/dist/{tap-err-Bqs9aQpZ.d.ts.map → tap-err-CFhHBPfH.d.ts.map} +1 -1
  29. package/dist/{tap-err-Bf6rQ4Cw.js → tap-err-CP-re1HT.js} +2 -2
  30. package/dist/{tap-err-Bf6rQ4Cw.js.map → tap-err-CP-re1HT.js.map} +1 -1
  31. package/dist/testing.d.ts +53 -0
  32. package/dist/testing.d.ts.map +1 -0
  33. package/dist/testing.js +59 -0
  34. package/dist/testing.js.map +1 -0
  35. package/dist/{types-cY80Bw6u.d.ts → types-tXXk7K9Q.d.ts} +2 -2
  36. package/dist/{types-cY80Bw6u.d.ts.map → types-tXXk7K9Q.d.ts.map} +1 -1
  37. package/package.json +5 -1
  38. package/dist/error/index.d.ts.map +0 -1
  39. package/dist/error/index.js.map +0 -1
  40. package/dist/result-BongGO2O.d.ts.map +0 -1
  41. package/dist/result-DzL3K2yA.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { Err } from "../result-BongGO2O.js";
2
- import { AnyTaggedError } from "../types-cY80Bw6u.js";
3
- import { tapErr } from "../tap-err-Bqs9aQpZ.js";
1
+ import { Err } from "../result-DKwq9BCr.js";
2
+ import { AnyTaggedError } from "../types-tXXk7K9Q.js";
3
+ import { tapErr } from "../tap-err-CFhHBPfH.js";
4
4
 
5
5
  //#region src/logger/types.d.ts
6
6
 
@@ -123,6 +123,18 @@ type Logger = {
123
123
  * annotation form would widen an unnecessary Partial into the value type.
124
124
  *
125
125
  * No dispose handler — `console` is not a resource.
126
+ *
127
+ * ### CLI authors: stream routing
128
+ *
129
+ * `console[level]` routes by level, not uniformly to stdout:
130
+ * - `console.log` (not used here) is the only method that writes stdout.
131
+ * - `console.info`, `console.debug`, `console.warn`, `console.error`,
132
+ * `console.trace` all write **stderr** in Node/Bun.
133
+ *
134
+ * For a CLI that emits structured program output on stdout and diagnostics
135
+ * on stderr, this default is correct — every logger event goes to stderr.
136
+ * Authors who expect `log.info` to print to stdout will be surprised; write
137
+ * a custom sink that routes to `process.stdout` if that's the requirement.
126
138
  */
127
139
  declare const consoleSink: (event: LogEvent) => void;
128
140
  //# sourceMappingURL=console-sink.d.ts.map
@@ -147,16 +159,38 @@ declare const consoleSink: (event: LogEvent) => void;
147
159
  * plus the level string); spelling them out beats an `emitErr("warn")`
148
160
  * riddle.
149
161
  *
162
+ * ### Source convention
163
+ *
164
+ * `source` is a free-form string, but downstream filtering and tail-log
165
+ * grep become much easier when call sites converge on a shape. Recommended:
166
+ *
167
+ * '<package>/<module>' e.g. 'workspace/sync-supervisor'
168
+ * '<app>/<feature>' e.g. 'fuji/daemon-route'
169
+ * '<package>/<area>' e.g. 'auth/oauth-app'
170
+ *
171
+ * Keep it lowercase-kebab. Avoid bare factory names like
172
+ * `'attachSqliteMaterializer'`: they don't carry package context.
173
+ *
174
+ * ### Module-scope vs injected
175
+ *
176
+ * `const log = createLogger('source')` at module scope is fine for
177
+ * process-singleton modules (CLI commands, app bootstrap, leaf utilities
178
+ * the host does not customize per instance). For anything that can be
179
+ * instantiated more than once per process with different routing needs
180
+ * (per-document attach primitives, per-account auth state, per-workspace
181
+ * services), accept `log?: Logger` at the factory boundary and default
182
+ * to `createLogger('source')` for development ergonomics.
183
+ *
150
184
  * @example Library code (caller wires the sink)
151
185
  * function attachThing(ydoc: Doc, opts: { log?: Logger }) {
152
- * const log = opts.log ?? createLogger('thing');
186
+ * const log = opts.log ?? createLogger('workspace/thing');
153
187
  * // ...
154
188
  * }
155
189
  *
156
190
  * @example App wiring (share one sink, multiple loggers)
157
191
  * const sink = composeSinks(consoleSink, myCustomSink);
158
- * attachThing(ydoc, { log: createLogger('thing', sink) });
159
- * attachOther(ydoc, { log: createLogger('other', sink) });
192
+ * attachThing(ydoc, { log: createLogger('workspace/thing', sink) });
193
+ * attachOther(ydoc, { log: createLogger('workspace/other', sink) });
160
194
  */
161
195
  declare function createLogger(source: string, sink?: LogSink): Logger;
162
196
  //# sourceMappingURL=create-logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/logger/types.ts","../../src/logger/console-sink.ts","../../src/logger/create-logger.ts","../../src/logger/memory-sink.ts","../../src/logger/compose-sinks.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAUA;AAoBA;AAgBA;;AAA+B,KApCnB,QAAA,GAoCmB,OAAA,GAAA,OAAA,GAAA,MAAA,GAAA,MAAA,GAAA,OAAA;;;AAA4B;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;AC/ExB;KDSY,QAAA;;SAEJ;EEMQ,MAAA,EAAA,MAAA;EAAY,OAAA,EAAA,MAAA;EAAA,IAErB,CAAA,EAAA,OAAA;CAAqB;AACnB;;;;ACjBT;;;;AAA+D,KHsBnD,OAAA,GGtBmD,CAAA,CAAA,KAAA,EHsBhC,QGtBgC,EAAA,GAAA,IAAA,CAAA,GHsBX,OGtBW,CHsBH,eGtBG,CAAA;;;;ACM/D;;;;AAA0D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KJuD9C,aAAA,GAAgB,iBAAiB,IAAI;;;;;;;;;;;;KAarC,MAAA;aACA;YACD;;;;;;;;;;;;;AA1FX;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAapC,cC7EC,WD6EK,EAAA,CAAA,KAAA,ECtEE,QDsEF,EAAA,GAAA,IAAA;;;;;;;;;AAxFlB;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;AC/ExB;;;iBCiBgB,YAAA,wBAET,UACJ;AAHH;;;;;;;AF5BA;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB,iBG5ER,UAAA,CAAA,CH4EQ,EAAA;QG5Ec;UAAiB;;AFHvD;;;;;;;;ADXA;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;AC/ExB;;iBGSgB,YAAA,WAAuB,YAAY"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/logger/types.ts","../../src/logger/console-sink.ts","../../src/logger/create-logger.ts","../../src/logger/memory-sink.ts","../../src/logger/compose-sinks.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAUA;AAoBA;AAgBA;;AAA+B,KApCnB,QAAA,GAoCmB,OAAA,GAAA,OAAA,GAAA,MAAA,GAAA,MAAA,GAAA,OAAA;;;AAA4B;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;ACnExB;KDHY,QAAA;;SAEJ;EE4BQ,MAAA,EAAA,MAAA;EAAY,OAAA,EAAA,MAAA;EAAA,IAErB,CAAA,EAAA,OAAA;CAAqB;AACnB;;;;ACvCT;;;;AAA+D,KHsBnD,OAAA,GGtBmD,CAAA,CAAA,KAAA,EHsBhC,QGtBgC,EAAA,GAAA,IAAA,CAAA,GHsBX,OGtBW,CHsBH,eGtBG,CAAA;;;;ACM/D;;;;AAA0D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KJuD9C,aAAA,GAAgB,iBAAiB,IAAI;;;;;;;;;;;;KAarC,MAAA;aACA;YACD;;;;;;;;;;;;;AA1FX;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;ACnExB;;;;AC2BgB,cD3BH,WC2Be,EAAA,CAAA,KAAA,EDpBR,QCoBQ,EAAA,GAAA,IAAA;;;;;;;;;AFlD5B;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;ACnExB;;;;AC2BA;;;;AAGS;;;;ACvCT;;;;AAA+D;;;;ACM/D;;;;AAA0D;iBF8B1C,YAAA,wBAET,UACJ;;;;;;;;AFrDH;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB,iBG5ER,UAAA,CAAA,CH4EQ,EAAA;QG5Ec;UAAiB;;AFSvD;;;;;;;;ADvBA;AAoBA;AAgBA;;;;;AAA2D;AAuC3D;;;;;AAAgD;AAahD;;;;AAEwB;;;;ACnExB;;iBGHgB,YAAA,WAAuB,YAAY"}
@@ -1,5 +1,5 @@
1
- import "../result-DzL3K2yA.js";
2
- import { tapErr } from "../tap-err-Bf6rQ4Cw.js";
1
+ import "../result-C5cJ1_WU.js";
2
+ import { tapErr } from "../tap-err-CP-re1HT.js";
3
3
 
4
4
  //#region src/logger/console-sink.ts
5
5
  /**
@@ -20,6 +20,18 @@ import { tapErr } from "../tap-err-Bf6rQ4Cw.js";
20
20
  * annotation form would widen an unnecessary Partial into the value type.
21
21
  *
22
22
  * No dispose handler — `console` is not a resource.
23
+ *
24
+ * ### CLI authors: stream routing
25
+ *
26
+ * `console[level]` routes by level, not uniformly to stdout:
27
+ * - `console.log` (not used here) is the only method that writes stdout.
28
+ * - `console.info`, `console.debug`, `console.warn`, `console.error`,
29
+ * `console.trace` all write **stderr** in Node/Bun.
30
+ *
31
+ * For a CLI that emits structured program output on stdout and diagnostics
32
+ * on stderr, this default is correct — every logger event goes to stderr.
33
+ * Authors who expect `log.info` to print to stdout will be surprised; write
34
+ * a custom sink that routes to `process.stdout` if that's the requirement.
23
35
  */
24
36
  const consoleSink = (event) => {
25
37
  const prefix = `[${event.source}]`;
@@ -51,16 +63,38 @@ function unwrapLoggable(err) {
51
63
  * plus the level string); spelling them out beats an `emitErr("warn")`
52
64
  * riddle.
53
65
  *
66
+ * ### Source convention
67
+ *
68
+ * `source` is a free-form string, but downstream filtering and tail-log
69
+ * grep become much easier when call sites converge on a shape. Recommended:
70
+ *
71
+ * '<package>/<module>' e.g. 'workspace/sync-supervisor'
72
+ * '<app>/<feature>' e.g. 'fuji/daemon-route'
73
+ * '<package>/<area>' e.g. 'auth/oauth-app'
74
+ *
75
+ * Keep it lowercase-kebab. Avoid bare factory names like
76
+ * `'attachSqliteMaterializer'`: they don't carry package context.
77
+ *
78
+ * ### Module-scope vs injected
79
+ *
80
+ * `const log = createLogger('source')` at module scope is fine for
81
+ * process-singleton modules (CLI commands, app bootstrap, leaf utilities
82
+ * the host does not customize per instance). For anything that can be
83
+ * instantiated more than once per process with different routing needs
84
+ * (per-document attach primitives, per-account auth state, per-workspace
85
+ * services), accept `log?: Logger` at the factory boundary and default
86
+ * to `createLogger('source')` for development ergonomics.
87
+ *
54
88
  * @example Library code (caller wires the sink)
55
89
  * function attachThing(ydoc: Doc, opts: { log?: Logger }) {
56
- * const log = opts.log ?? createLogger('thing');
90
+ * const log = opts.log ?? createLogger('workspace/thing');
57
91
  * // ...
58
92
  * }
59
93
  *
60
94
  * @example App wiring (share one sink, multiple loggers)
61
95
  * const sink = composeSinks(consoleSink, myCustomSink);
62
- * attachThing(ydoc, { log: createLogger('thing', sink) });
63
- * attachOther(ydoc, { log: createLogger('other', sink) });
96
+ * attachThing(ydoc, { log: createLogger('workspace/thing', sink) });
97
+ * attachOther(ydoc, { log: createLogger('workspace/other', sink) });
64
98
  */
65
99
  function createLogger(source, sink = consoleSink) {
66
100
  const emit = (level, message, data) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["err: LoggableError","source: string","sink: LogSink","level: LogLevel","message: string","data?: unknown","events: LogEvent[]","event: LogEvent"],"sources":["../../src/logger/console-sink.ts","../../src/logger/create-logger.ts","../../src/logger/memory-sink.ts","../../src/logger/compose-sinks.ts"],"sourcesContent":["import type { LogSink } from \"./types.js\";\n\n/**\n * Default sink. Writes to `console.*` with a `[source]` prefix.\n *\n * Kept as a singleton value (not a factory) because it takes no config —\n * adding `createConsoleSink({ format })` would be ceremony for a pattern\n * the user can trivially replace by writing their own sink.\n *\n * `console[event.level]` routes directly without a detached lookup table.\n * `LogLevel` is a subset of the Console method keys, so TS errors at this\n * access if a future level drifts (e.g. adding `fatal`). Calling the method\n * through `console[...]` preserves the `this` binding — avoids \"Illegal\n * invocation\" in runtimes that require it.\n *\n * `satisfies LogSink` (not `: LogSink`) keeps the inferred callable type\n * precise — `LogSink` is an intersection with optional dispose, and the\n * annotation form would widen an unnecessary Partial into the value type.\n *\n * No dispose handler — `console` is not a resource.\n */\nexport const consoleSink = ((event) => {\n\tconst prefix = `[${event.source}]`;\n\tif (event.data === undefined) {\n\t\tconsole[event.level](prefix, event.message);\n\t} else {\n\t\tconsole[event.level](prefix, event.message, event.data);\n\t}\n}) satisfies LogSink;\n","import type { AnyTaggedError } from \"../error/types.js\";\nimport { consoleSink } from \"./console-sink.js\";\nimport type { LoggableError, LogLevel, Logger, LogSink } from \"./types.js\";\n\n/** Narrow `LoggableError` to the raw tagged object. See `LoggableError` in `types.ts` for the discriminator rationale. */\nfunction unwrapLoggable(err: LoggableError): AnyTaggedError {\n\treturn \"name\" in err ? err : err.error;\n}\n\n/**\n * Create a logger bound to a `source` namespace and a sink.\n *\n * Design choices:\n * - **Positional args, not a bag.** Two arguments, both with obvious meaning;\n * a `{ source, sink }` object would be ceremony.\n * - **`sink` defaults to `consoleSink`.** Most callers during development\n * want console output with zero setup. Production apps swap it out via DI\n * at the attach/wire-up site.\n * - **No global default logger.** There is no `setDefaultLogger()` and no\n * module-level registry. Every consumer takes a `log?: Logger` option\n * and defaults to `createLogger('<source>')` if omitted. Globals make\n * test isolation and sink composition painful.\n * - **Method shorthand in the return object** over higher-order factories.\n * The five methods differ in two simple ways (error-unary vs free-form,\n * plus the level string); spelling them out beats an `emitErr(\"warn\")`\n * riddle.\n *\n * @example Library code (caller wires the sink)\n * function attachThing(ydoc: Doc, opts: { log?: Logger }) {\n * const log = opts.log ?? createLogger('thing');\n * // ...\n * }\n *\n * @example App wiring (share one sink, multiple loggers)\n * const sink = composeSinks(consoleSink, myCustomSink);\n * attachThing(ydoc, { log: createLogger('thing', sink) });\n * attachOther(ydoc, { log: createLogger('other', sink) });\n */\nexport function createLogger(\n\tsource: string,\n\tsink: LogSink = consoleSink,\n): Logger {\n\tconst emit = (level: LogLevel, message: string, data?: unknown): void => {\n\t\tsink({ ts: Date.now(), level, source, message, data });\n\t};\n\treturn {\n\t\terror(err) {\n\t\t\tconst tagged = unwrapLoggable(err);\n\t\t\temit(\"error\", tagged.message, tagged);\n\t\t},\n\t\twarn(err) {\n\t\t\tconst tagged = unwrapLoggable(err);\n\t\t\temit(\"warn\", tagged.message, tagged);\n\t\t},\n\t\tinfo(message, data) {\n\t\t\temit(\"info\", message, data);\n\t\t},\n\t\tdebug(message, data) {\n\t\t\temit(\"debug\", message, data);\n\t\t},\n\t\ttrace(message, data) {\n\t\t\temit(\"trace\", message, data);\n\t\t},\n\t};\n}\n","import type { LogEvent, LogSink } from \"./types.js\";\n\n/**\n * In-memory sink for tests. Returns `{ sink, events }` so callers can\n * both wire the sink and inspect captured events without a module-level\n * spy or `console.*` interception.\n *\n * A factory (not a singleton) so each test gets an isolated array; sharing\n * state across tests would leak events.\n *\n * Returning `{ sink, events }` (rather than an array with a method) keeps\n * the two roles separate — `sink` goes to `createLogger`, `events` goes to\n * assertions.\n *\n * Uses `satisfies LogSink` on the sink expression rather than `: LogSink =`\n * to preserve the precise inferred callable type.\n *\n * @example\n * const { sink, events } = memorySink();\n * const log = createLogger(\"test\", sink);\n * log.warn(MyError.Thing({ cause: new Error(\"boom\") }));\n * expect(events).toHaveLength(1);\n * expect(events[0]).toMatchObject({ level: \"warn\", source: \"test\" });\n */\nexport function memorySink(): { sink: LogSink; events: LogEvent[] } {\n\tconst events: LogEvent[] = [];\n\tconst sink = ((event) => {\n\t\tevents.push(event);\n\t}) satisfies LogSink;\n\treturn { sink, events };\n}\n","import type { LogEvent, LogSink } from \"./types.js\";\n\n/**\n * Fan one event out to every sink in order.\n *\n * Disposal: the returned sink has a `[Symbol.asyncDispose]` that forwards\n * to each member via optional chaining. Members without dispose (e.g.\n * `consoleSink`) are silent no-ops; members that own resources (file,\n * network) flush and close. Mix pure and stateful sinks freely — no\n * wrapping required.\n *\n * Fan-out is sequential and unguarded. If a member sink throws on emit,\n * later members do not receive the event — by design, since swallowing\n * sink errors hides real bugs. Wrap individual sinks yourself for\n * best-effort delivery.\n *\n * Dispose is sequential and awaits each member. If one throws, later\n * members don't get their chance; callers who want best-effort cleanup\n * should wrap the composed dispose themselves.\n *\n * Built with `Object.assign` + `satisfies LogSink` rather than mutating a\n * pre-typed `const` — avoids the widening that comes with `: LogSink =` and\n * keeps the inferred type precise (callable + definite dispose, not\n * callable + Partial dispose).\n *\n * @example\n * await using file = jsonlFileSink(\"/tmp/app.jsonl\");\n * const sink = composeSinks(consoleSink, file);\n * const log = createLogger(\"source\", sink);\n */\nexport function composeSinks(...sinks: LogSink[]): LogSink {\n\tconst emit = (event: LogEvent) => {\n\t\tfor (const sink of sinks) sink(event);\n\t};\n\tconst dispose = async (): Promise<void> => {\n\t\tfor (const sink of sinks) await sink[Symbol.asyncDispose]?.();\n\t};\n\treturn Object.assign(emit, {\n\t\t[Symbol.asyncDispose]: dispose,\n\t}) satisfies LogSink;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,cAAe,CAAC,UAAU;CACtC,MAAM,SAAS,CAAC,CAAC,EAAE,MAAM,OAAO,CAAC,CAAC;AAClC,KAAI,MAAM,gBACT,SAAQ,MAAM,OAAO,QAAQ,MAAM,QAAQ;KAE3C,SAAQ,MAAM,OAAO,QAAQ,MAAM,SAAS,MAAM,KAAK;AAExD;;;;;ACvBD,SAAS,eAAeA,KAAoC;AAC3D,QAAO,UAAU,MAAM,MAAM,IAAI;AACjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BD,SAAgB,aACfC,QACAC,OAAgB,aACP;CACT,MAAM,OAAO,CAACC,OAAiBC,SAAiBC,SAAyB;AACxE,OAAK;GAAE,IAAI,KAAK,KAAK;GAAE;GAAO;GAAQ;GAAS;EAAM,EAAC;CACtD;AACD,QAAO;EACN,MAAM,KAAK;GACV,MAAM,SAAS,eAAe,IAAI;AAClC,QAAK,SAAS,OAAO,SAAS,OAAO;EACrC;EACD,KAAK,KAAK;GACT,MAAM,SAAS,eAAe,IAAI;AAClC,QAAK,QAAQ,OAAO,SAAS,OAAO;EACpC;EACD,KAAK,SAAS,MAAM;AACnB,QAAK,QAAQ,SAAS,KAAK;EAC3B;EACD,MAAM,SAAS,MAAM;AACpB,QAAK,SAAS,SAAS,KAAK;EAC5B;EACD,MAAM,SAAS,MAAM;AACpB,QAAK,SAAS,SAAS,KAAK;EAC5B;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCD,SAAgB,aAAoD;CACnE,MAAMC,SAAqB,CAAE;CAC7B,MAAM,OAAQ,CAAC,UAAU;AACxB,SAAO,KAAK,MAAM;CAClB;AACD,QAAO;EAAE;EAAM;CAAQ;AACvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAD,SAAgB,aAAa,GAAG,OAA2B;CAC1D,MAAM,OAAO,CAACC,UAAoB;AACjC,OAAK,MAAM,QAAQ,MAAO,MAAK,MAAM;CACrC;CACD,MAAM,UAAU,YAA2B;AAC1C,OAAK,MAAM,QAAQ,MAAO,OAAM,KAAK,OAAO,iBAAiB;CAC7D;AACD,QAAO,OAAO,OAAO,MAAM,GACzB,OAAO,eAAe,QACvB,EAAC;AACF"}
1
+ {"version":3,"file":"index.js","names":["err: LoggableError","source: string","sink: LogSink","level: LogLevel","message: string","data?: unknown","events: LogEvent[]","event: LogEvent"],"sources":["../../src/logger/console-sink.ts","../../src/logger/create-logger.ts","../../src/logger/memory-sink.ts","../../src/logger/compose-sinks.ts"],"sourcesContent":["import type { LogSink } from \"./types.js\";\n\n/**\n * Default sink. Writes to `console.*` with a `[source]` prefix.\n *\n * Kept as a singleton value (not a factory) because it takes no config —\n * adding `createConsoleSink({ format })` would be ceremony for a pattern\n * the user can trivially replace by writing their own sink.\n *\n * `console[event.level]` routes directly without a detached lookup table.\n * `LogLevel` is a subset of the Console method keys, so TS errors at this\n * access if a future level drifts (e.g. adding `fatal`). Calling the method\n * through `console[...]` preserves the `this` binding — avoids \"Illegal\n * invocation\" in runtimes that require it.\n *\n * `satisfies LogSink` (not `: LogSink`) keeps the inferred callable type\n * precise — `LogSink` is an intersection with optional dispose, and the\n * annotation form would widen an unnecessary Partial into the value type.\n *\n * No dispose handler — `console` is not a resource.\n *\n * ### CLI authors: stream routing\n *\n * `console[level]` routes by level, not uniformly to stdout:\n * - `console.log` (not used here) is the only method that writes stdout.\n * - `console.info`, `console.debug`, `console.warn`, `console.error`,\n * `console.trace` all write **stderr** in Node/Bun.\n *\n * For a CLI that emits structured program output on stdout and diagnostics\n * on stderr, this default is correct — every logger event goes to stderr.\n * Authors who expect `log.info` to print to stdout will be surprised; write\n * a custom sink that routes to `process.stdout` if that's the requirement.\n */\nexport const consoleSink = ((event) => {\n\tconst prefix = `[${event.source}]`;\n\tif (event.data === undefined) {\n\t\tconsole[event.level](prefix, event.message);\n\t} else {\n\t\tconsole[event.level](prefix, event.message, event.data);\n\t}\n}) satisfies LogSink;\n","import type { AnyTaggedError } from \"../error/types.js\";\nimport { consoleSink } from \"./console-sink.js\";\nimport type { LoggableError, LogLevel, Logger, LogSink } from \"./types.js\";\n\n/** Narrow `LoggableError` to the raw tagged object. See `LoggableError` in `types.ts` for the discriminator rationale. */\nfunction unwrapLoggable(err: LoggableError): AnyTaggedError {\n\treturn \"name\" in err ? err : err.error;\n}\n\n/**\n * Create a logger bound to a `source` namespace and a sink.\n *\n * Design choices:\n * - **Positional args, not a bag.** Two arguments, both with obvious meaning;\n * a `{ source, sink }` object would be ceremony.\n * - **`sink` defaults to `consoleSink`.** Most callers during development\n * want console output with zero setup. Production apps swap it out via DI\n * at the attach/wire-up site.\n * - **No global default logger.** There is no `setDefaultLogger()` and no\n * module-level registry. Every consumer takes a `log?: Logger` option\n * and defaults to `createLogger('<source>')` if omitted. Globals make\n * test isolation and sink composition painful.\n * - **Method shorthand in the return object** over higher-order factories.\n * The five methods differ in two simple ways (error-unary vs free-form,\n * plus the level string); spelling them out beats an `emitErr(\"warn\")`\n * riddle.\n *\n * ### Source convention\n *\n * `source` is a free-form string, but downstream filtering and tail-log\n * grep become much easier when call sites converge on a shape. Recommended:\n *\n * '<package>/<module>' e.g. 'workspace/sync-supervisor'\n * '<app>/<feature>' e.g. 'fuji/daemon-route'\n * '<package>/<area>' e.g. 'auth/oauth-app'\n *\n * Keep it lowercase-kebab. Avoid bare factory names like\n * `'attachSqliteMaterializer'`: they don't carry package context.\n *\n * ### Module-scope vs injected\n *\n * `const log = createLogger('source')` at module scope is fine for\n * process-singleton modules (CLI commands, app bootstrap, leaf utilities\n * the host does not customize per instance). For anything that can be\n * instantiated more than once per process with different routing needs\n * (per-document attach primitives, per-account auth state, per-workspace\n * services), accept `log?: Logger` at the factory boundary and default\n * to `createLogger('source')` for development ergonomics.\n *\n * @example Library code (caller wires the sink)\n * function attachThing(ydoc: Doc, opts: { log?: Logger }) {\n * const log = opts.log ?? createLogger('workspace/thing');\n * // ...\n * }\n *\n * @example App wiring (share one sink, multiple loggers)\n * const sink = composeSinks(consoleSink, myCustomSink);\n * attachThing(ydoc, { log: createLogger('workspace/thing', sink) });\n * attachOther(ydoc, { log: createLogger('workspace/other', sink) });\n */\nexport function createLogger(\n\tsource: string,\n\tsink: LogSink = consoleSink,\n): Logger {\n\tconst emit = (level: LogLevel, message: string, data?: unknown): void => {\n\t\tsink({ ts: Date.now(), level, source, message, data });\n\t};\n\treturn {\n\t\terror(err) {\n\t\t\tconst tagged = unwrapLoggable(err);\n\t\t\temit(\"error\", tagged.message, tagged);\n\t\t},\n\t\twarn(err) {\n\t\t\tconst tagged = unwrapLoggable(err);\n\t\t\temit(\"warn\", tagged.message, tagged);\n\t\t},\n\t\tinfo(message, data) {\n\t\t\temit(\"info\", message, data);\n\t\t},\n\t\tdebug(message, data) {\n\t\t\temit(\"debug\", message, data);\n\t\t},\n\t\ttrace(message, data) {\n\t\t\temit(\"trace\", message, data);\n\t\t},\n\t};\n}\n","import type { LogEvent, LogSink } from \"./types.js\";\n\n/**\n * In-memory sink for tests. Returns `{ sink, events }` so callers can\n * both wire the sink and inspect captured events without a module-level\n * spy or `console.*` interception.\n *\n * A factory (not a singleton) so each test gets an isolated array; sharing\n * state across tests would leak events.\n *\n * Returning `{ sink, events }` (rather than an array with a method) keeps\n * the two roles separate — `sink` goes to `createLogger`, `events` goes to\n * assertions.\n *\n * Uses `satisfies LogSink` on the sink expression rather than `: LogSink =`\n * to preserve the precise inferred callable type.\n *\n * @example\n * const { sink, events } = memorySink();\n * const log = createLogger(\"test\", sink);\n * log.warn(MyError.Thing({ cause: new Error(\"boom\") }));\n * expect(events).toHaveLength(1);\n * expect(events[0]).toMatchObject({ level: \"warn\", source: \"test\" });\n */\nexport function memorySink(): { sink: LogSink; events: LogEvent[] } {\n\tconst events: LogEvent[] = [];\n\tconst sink = ((event) => {\n\t\tevents.push(event);\n\t}) satisfies LogSink;\n\treturn { sink, events };\n}\n","import type { LogEvent, LogSink } from \"./types.js\";\n\n/**\n * Fan one event out to every sink in order.\n *\n * Disposal: the returned sink has a `[Symbol.asyncDispose]` that forwards\n * to each member via optional chaining. Members without dispose (e.g.\n * `consoleSink`) are silent no-ops; members that own resources (file,\n * network) flush and close. Mix pure and stateful sinks freely — no\n * wrapping required.\n *\n * Fan-out is sequential and unguarded. If a member sink throws on emit,\n * later members do not receive the event — by design, since swallowing\n * sink errors hides real bugs. Wrap individual sinks yourself for\n * best-effort delivery.\n *\n * Dispose is sequential and awaits each member. If one throws, later\n * members don't get their chance; callers who want best-effort cleanup\n * should wrap the composed dispose themselves.\n *\n * Built with `Object.assign` + `satisfies LogSink` rather than mutating a\n * pre-typed `const` — avoids the widening that comes with `: LogSink =` and\n * keeps the inferred type precise (callable + definite dispose, not\n * callable + Partial dispose).\n *\n * @example\n * await using file = jsonlFileSink(\"/tmp/app.jsonl\");\n * const sink = composeSinks(consoleSink, file);\n * const log = createLogger(\"source\", sink);\n */\nexport function composeSinks(...sinks: LogSink[]): LogSink {\n\tconst emit = (event: LogEvent) => {\n\t\tfor (const sink of sinks) sink(event);\n\t};\n\tconst dispose = async (): Promise<void> => {\n\t\tfor (const sink of sinks) await sink[Symbol.asyncDispose]?.();\n\t};\n\treturn Object.assign(emit, {\n\t\t[Symbol.asyncDispose]: dispose,\n\t}) satisfies LogSink;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,cAAe,CAAC,UAAU;CACtC,MAAM,SAAS,CAAC,CAAC,EAAE,MAAM,OAAO,CAAC,CAAC;AAClC,KAAI,MAAM,gBACT,SAAQ,MAAM,OAAO,QAAQ,MAAM,QAAQ;KAE3C,SAAQ,MAAM,OAAO,QAAQ,MAAM,SAAS,MAAM,KAAK;AAExD;;;;;ACnCD,SAAS,eAAeA,KAAoC;AAC3D,QAAO,UAAU,MAAM,MAAM,IAAI;AACjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDD,SAAgB,aACfC,QACAC,OAAgB,aACP;CACT,MAAM,OAAO,CAACC,OAAiBC,SAAiBC,SAAyB;AACxE,OAAK;GAAE,IAAI,KAAK,KAAK;GAAE;GAAO;GAAQ;GAAS;EAAM,EAAC;CACtD;AACD,QAAO;EACN,MAAM,KAAK;GACV,MAAM,SAAS,eAAe,IAAI;AAClC,QAAK,SAAS,OAAO,SAAS,OAAO;EACrC;EACD,KAAK,KAAK;GACT,MAAM,SAAS,eAAe,IAAI;AAClC,QAAK,QAAQ,OAAO,SAAS,OAAO;EACpC;EACD,KAAK,SAAS,MAAM;AACnB,QAAK,QAAQ,SAAS,KAAK;EAC3B;EACD,MAAM,SAAS,MAAM;AACpB,QAAK,SAAS,SAAS,KAAK;EAC5B;EACD,MAAM,SAAS,MAAM;AACpB,QAAK,SAAS,SAAS,KAAK;EAC5B;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;AC9DD,SAAgB,aAAoD;CACnE,MAAMC,SAAqB,CAAE;CAC7B,MAAM,OAAQ,CAAC,UAAU;AACxB,SAAO,KAAK,MAAM;CAClB;AACD,QAAO;EAAE;EAAM;CAAQ;AACvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAD,SAAgB,aAAa,GAAG,OAA2B;CAC1D,MAAM,OAAO,CAACC,UAAoB;AACjC,OAAK,MAAM,QAAQ,MAAO,MAAK,MAAM;CACrC;CACD,MAAM,UAAU,YAA2B;AAC1C,OAAK,MAAM,QAAQ,MAAO,OAAM,KAAK,OAAO,iBAAiB;CAC7D;AACD,QAAO,OAAO,OAAO,MAAM,GACzB,OAAO,eAAe,QACvB,EAAC;AACF"}
@@ -1,6 +1,6 @@
1
- import { Result } from "../result-BongGO2O.js";
2
- import "../tap-err-Bqs9aQpZ.js";
3
- import "../index-mb9iYu0a.js";
1
+ import { Result } from "../result-DKwq9BCr.js";
2
+ import "../tap-err-CFhHBPfH.js";
3
+ import "../index-DnoV2ZDO.js";
4
4
  import { DefaultError, MutationFunction, MutationKey, MutationOptions, QueryClient, QueryFunction, QueryKey, QueryObserverOptions } from "@tanstack/query-core";
5
5
 
6
6
  //#region src/query/utils.d.ts
@@ -1,6 +1,6 @@
1
- import { Err, Ok, resolve } from "../result-DzL3K2yA.js";
2
- import "../tap-err-Bf6rQ4Cw.js";
3
- import "../result-corfYKOe.js";
1
+ import { Err, Ok, resolve } from "../result-C5cJ1_WU.js";
2
+ import "../tap-err-CP-re1HT.js";
3
+ import "../result-C9V2Knvt.js";
4
4
 
5
5
  //#region src/query/utils.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { Err, Ok, Result, UnwrapErr, UnwrapOk, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap } from "../result-BongGO2O.js";
2
- import { tapErr } from "../tap-err-Bqs9aQpZ.js";
3
- import { partitionResults } from "../index-mb9iYu0a.js";
1
+ import { Err, Ok, Result, UnwrapErr, UnwrapOk, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap } from "../result-DKwq9BCr.js";
2
+ import { tapErr } from "../tap-err-CFhHBPfH.js";
3
+ import { partitionResults } from "../index-DnoV2ZDO.js";
4
4
  export { Err, Ok, Result, UnwrapErr, UnwrapOk, isErr, isOk, isResult, partitionResults, resolve, tapErr, tryAsync, trySync, unwrap };
@@ -1,5 +1,5 @@
1
- import { Err, Ok, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap } from "../result-DzL3K2yA.js";
2
- import { tapErr } from "../tap-err-Bf6rQ4Cw.js";
3
- import { partitionResults } from "../result-corfYKOe.js";
1
+ import { Err, Ok, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap } from "../result-C5cJ1_WU.js";
2
+ import { tapErr } from "../tap-err-CP-re1HT.js";
3
+ import { partitionResults } from "../result-C9V2Knvt.js";
4
4
 
5
5
  export { Err, Ok, isErr, isOk, isResult, partitionResults, resolve, tapErr, tryAsync, trySync, unwrap };
@@ -59,9 +59,13 @@ const Err = (error) => ({
59
59
  * A value is considered a valid `Result` if:
60
60
  * 1. It is a non-null object.
61
61
  * 2. It has both `data` and `error` properties.
62
- * 3. At least one of the `data` or `error` channels is `null`. Both being `null` represents `Ok(null)`.
63
62
  *
64
- * This function does not validate the types of `data` or `error` beyond `null` checks.
63
+ * The `error` property is the runtime discriminant:
64
+ * - `error === null` represents `Ok<T>`, even when `data` is also `null` (`Ok(null)`).
65
+ * - `error !== null` represents `Err<E>`, even if external data also includes a non-null `data` value.
66
+ *
67
+ * This function checks only the Result shape. It does not validate the
68
+ * success or error payload types.
65
69
  *
66
70
  * @template T - The expected type of the success value if the value is an `Ok` variant (defaults to `unknown`).
67
71
  * @template E - The expected type of the error value if the value is an `Err` variant (defaults to `unknown`).
@@ -118,7 +122,8 @@ function isOk(result) {
118
122
  * Type guard to runtime check if a `Result<T, E>` is an `Err<E>` variant.
119
123
  *
120
124
  * This function narrows the type of a `Result` to `Err<E>` if it represents a failure outcome.
121
- * An `Err<E>` variant is identified by its `error` property being non-`null` (and thus `data` being `null`).
125
+ * An `Err<E>` variant is identified by its `error` property being non-`null`.
126
+ * The error side is the reliable discriminator because `Ok(null)` is valid.
122
127
  *
123
128
  * @template T - The success value type.
124
129
  * @template E - The error value type.
@@ -356,4 +361,4 @@ function resolve(value) {
356
361
 
357
362
  //#endregion
358
363
  export { Err, Ok, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap };
359
- //# sourceMappingURL=result-DzL3K2yA.js.map
364
+ //# sourceMappingURL=result-C5cJ1_WU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-C5cJ1_WU.js","names":["data: T","error: E","value: unknown","result: Result<T, E>","value: T | Result<T, E>"],"sources":["../src/result/result.ts"],"sourcesContent":["/**\n * Represents the successful outcome of an operation, encapsulating the success value.\n *\n * This is the 'Ok' variant of the `Result` type. It holds a `data` property\n * of type `T` (the success value) and an `error` property explicitly set to `null`,\n * signifying no error occurred.\n *\n * Use this type in conjunction with `Err<E>` and `Result<T, E>`.\n *\n * @template T - The type of the success value contained within.\n */\nexport type Ok<T> = { data: T; error: null };\n\n/**\n * Represents the failure outcome of an operation, encapsulating the error value.\n *\n * This is the 'Err' variant of the `Result` type. It holds an `error` property\n * of type `E` (the error value) and a `data` property explicitly set to `null`,\n * signifying that no success value is present due to the failure.\n *\n * Use this type in conjunction with `Ok<T>` and `Result<T, E>`.\n *\n * @template E - The type of the error value contained within.\n */\nexport type Err<E> = { error: E; data: null };\n\n/**\n * A type that represents the outcome of an operation that can either succeed or fail.\n *\n * `Result<T, E>` is a discriminated union type with two possible variants:\n * - `Ok<T>`: Represents a successful outcome, containing a `data` field with the success value of type `T`.\n * In this case, the `error` field is `null`.\n * - `Err<E>`: Represents a failure outcome, containing an `error` field with the error value of type `E`.\n * In this case, the `data` field is `null`.\n *\n * This type promotes explicit error handling by requiring developers to check\n * the variant of the `Result` before accessing its potential value or error.\n * It helps avoid runtime errors often associated with implicit error handling (e.g., relying on `try-catch` for all errors).\n *\n * @template T - The type of the success value if the operation is successful (held in `Ok<T>`).\n * @template E - The type of the error value if the operation fails (held in `Err<E>`).\n * @example\n * ```ts\n * function divide(numerator: number, denominator: number): Result<number, string> {\n * if (denominator === 0) {\n * return Err(\"Cannot divide by zero\");\n * }\n * return Ok(numerator / denominator);\n * }\n *\n * const result1 = divide(10, 2);\n * if (isOk(result1)) {\n * console.log(\"Success:\", result1.data); // Output: Success: 5\n * }\n *\n * const result2 = divide(10, 0);\n * if (isErr(result2)) {\n * console.error(\"Failure:\", result2.error); // Output: Failure: Cannot divide by zero\n * }\n * ```\n */\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/**\n * Constructs an `Ok<T>` variant, representing a successful outcome.\n *\n * This factory function creates the success variant of a `Result`.\n * It wraps the provided `data` (the success value) and ensures the `error` property is `null`.\n *\n * @template T - The type of the success value.\n * @param data - The success value to be wrapped in the `Ok` variant.\n * @returns An `Ok<T>` object with the provided data and `error` set to `null`.\n * @example\n * ```ts\n * const successfulResult = Ok(\"Operation completed successfully\");\n * // successfulResult is { data: \"Operation completed successfully\", error: null }\n * ```\n */\nexport const Ok = <T>(data: T): Ok<T> => ({ data, error: null });\n\n/**\n * Constructs an `Err<E>` variant, representing a failure outcome.\n *\n * Wraps the provided `error` (the failure value) and sets `data` to `null`.\n *\n * **Don't call `Err(null)`.** It produces `{ data: null, error: null }` —\n * structurally identical to `Ok(null)`. The built-in `isErr` check\n * (`result.error !== null`) reads it as Ok, silently misclassifying your\n * failure as success. `Err(undefined)` is also discouraged: the discriminator\n * technically works (`undefined !== null`), but `undefined` is falsy, so\n * downstream `if (error)` checks trip and the error carries no information\n * anyway. Pass a meaningful error value (a string, a tagged error from\n * `defineErrors`, an `Error` instance), or use `Ok(null)`/`Ok(undefined)` if\n * what you meant was success-with-no-payload.\n *\n * At `catch (error: unknown)` boundaries, wrap the caught value in a tagged\n * error rather than passing it through — `TaggedError.X({ cause: error })`\n * is always non-null by construction, so the discriminator works regardless\n * of what was thrown.\n *\n * See `docs/philosophy/err-null-is-ok-null.md` for the full rationale.\n *\n * @template E - The type of the error value.\n * @param error - The error value to wrap. Don't pass `null` or `undefined`.\n * @returns An `Err<E>` object with the provided error and `data` set to `null`.\n * @example\n * ```ts\n * const failedResult = Err(new TypeError(\"Invalid input\"));\n * // failedResult is { error: TypeError(\"Invalid input\"), data: null }\n * ```\n */\nexport const Err = <E>(error: E): Err<E> => ({ error, data: null });\n\n/**\n * Utility type to extract the success value's type `T` from a `Result<T, E>` type.\n *\n * If `R` is an `Ok<T>` variant (or a `Result<T, E>` that could be an `Ok<T>`),\n * this type resolves to `T`. If `R` can only be an `Err<E>` variant, it resolves to `never`.\n * This is useful for obtaining the type of the `data` field when you know you have a success.\n *\n * @template R - The `Result<T, E>` type from which to extract the success value's type.\n * Must extend `Result<unknown, unknown>`.\n * @example\n * ```ts\n * type MyResult = Result<number, string>;\n * type SuccessValueType = UnwrapOk<MyResult>; // SuccessValueType is number\n *\n * type MyErrorResult = Err<string>;\n * type ErrorValueType = UnwrapOk<MyErrorResult>; // ErrorValueType is never\n * ```\n */\nexport type UnwrapOk<R extends Result<unknown, unknown>> = R extends Ok<infer U>\n\t? U\n\t: never;\n\n/**\n * Utility type to extract the error value's type `E` from a `Result<T, E>` type.\n *\n * If `R` is an `Err<E>` variant (or a `Result<T, E>` that could be an `Err<E>`),\n * this type resolves to `E`. If `R` can only be an `Ok<T>` variant, it resolves to `never`.\n * This is useful for obtaining the type of the `error` field when you know you have a failure.\n *\n * @template R - The `Result<T, E>` type from which to extract the error value's type.\n * Must extend `Result<unknown, unknown>`.\n * @example\n * ```ts\n * type MyResult = Result<number, string>;\n * type ErrorValueType = UnwrapErr<MyResult>; // ErrorValueType is string\n *\n * type MySuccessResult = Ok<number>;\n * type SuccessValueType = UnwrapErr<MySuccessResult>; // SuccessValueType is never\n * ```\n */\nexport type UnwrapErr<R extends Result<unknown, unknown>> = R extends Err<\n\tinfer E\n>\n\t? E\n\t: never;\n\n/**\n * Type guard to runtime check if an unknown value is a valid `Result<T, E>`.\n *\n * A value is considered a valid `Result` if:\n * 1. It is a non-null object.\n * 2. It has both `data` and `error` properties.\n *\n * The `error` property is the runtime discriminant:\n * - `error === null` represents `Ok<T>`, even when `data` is also `null` (`Ok(null)`).\n * - `error !== null` represents `Err<E>`, even if external data also includes a non-null `data` value.\n *\n * This function checks only the Result shape. It does not validate the\n * success or error payload types.\n *\n * @template T - The expected type of the success value if the value is an `Ok` variant (defaults to `unknown`).\n * @template E - The expected type of the error value if the value is an `Err` variant (defaults to `unknown`).\n * @param value - The value to check.\n * @returns `true` if the value conforms to the `Result` structure, `false` otherwise.\n * If `true`, TypeScript's type system will narrow `value` to `Result<T, E>`.\n * @example\n * ```ts\n * declare const someValue: unknown;\n *\n * if (isResult<string, Error>(someValue)) {\n * // someValue is now typed as Result<string, Error>\n * if (isOk(someValue)) {\n * console.log(someValue.data); // string\n * } else {\n * console.error(someValue.error); // Error\n * }\n * }\n * ```\n */\nexport function isResult<T = unknown, E = unknown>(\n\tvalue: unknown,\n): value is Result<T, E> {\n\tconst isNonNullObject = typeof value === \"object\" && value !== null;\n\tif (!isNonNullObject) return false;\n\n\tconst hasDataProperty = \"data\" in value;\n\tconst hasErrorProperty = \"error\" in value;\n\tif (!hasDataProperty || !hasErrorProperty) return false;\n\n\treturn true;\n}\n\n/**\n * Type guard to runtime check if a `Result<T, E>` is an `Ok<T>` variant.\n *\n * This function narrows the type of a `Result` to `Ok<T>` if it represents a successful outcome.\n * An `Ok<T>` variant is identified by its `error` property being `null`.\n *\n * @template T - The success value type.\n * @template E - The error value type.\n * @param result - The `Result<T, E>` to check.\n * @returns `true` if the `result` is an `Ok<T>` variant, `false` otherwise.\n * If `true`, TypeScript's type system will narrow `result` to `Ok<T>`.\n * @example\n * ```ts\n * declare const myResult: Result<number, string>;\n *\n * if (isOk(myResult)) {\n * // myResult is now typed as Ok<number>\n * console.log(\"Success value:\", myResult.data); // myResult.data is number\n * }\n * ```\n */\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T> {\n\treturn result.error === null;\n}\n\n/**\n * Type guard to runtime check if a `Result<T, E>` is an `Err<E>` variant.\n *\n * This function narrows the type of a `Result` to `Err<E>` if it represents a failure outcome.\n * An `Err<E>` variant is identified by its `error` property being non-`null`.\n * The error side is the reliable discriminator because `Ok(null)` is valid.\n *\n * @template T - The success value type.\n * @template E - The error value type.\n * @param result - The `Result<T, E>` to check.\n * @returns `true` if the `result` is an `Err<E>` variant, `false` otherwise.\n * If `true`, TypeScript's type system will narrow `result` to `Err<E>`.\n * @example\n * ```ts\n * declare const myResult: Result<number, string>;\n *\n * if (isErr(myResult)) {\n * // myResult is now typed as Err<string>\n * console.error(\"Error value:\", myResult.error); // myResult.error is string\n * }\n * ```\n */\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E> {\n\treturn result.error !== null;\n}\n\n/**\n * Executes a synchronous operation and wraps its outcome in a Result type.\n *\n * This function attempts to execute the `try` operation:\n * - If the `try` operation completes successfully, its return value is wrapped in an `Ok<T>` variant.\n * - If the `try` operation throws an exception, the caught exception (of type `unknown`) is passed to\n * the `catch` function, which transforms it into either an `Ok<T>` (recovery) or `Err<E>` (propagation).\n *\n * The return type is automatically determined by what your catch function returns:\n * - If catch always returns `Ok<T>`, the return type collapses to `Ok<T>` (guaranteed success)\n * - If catch always returns `Err<E>`, the return type is `Ok<T> | Err<E>` (may succeed or fail)\n * - If catch returns a union like `Err<A> | Err<B>`, the return type is `Ok<T> | Err<A> | Err<B>` (union propagation)\n * - If catch can return either `Ok<T>` or `Err<E>`, the return type is `Ok<T> | Err<E>` (conditional recovery)\n *\n * @template T - The success value type\n * @template R - The return type of the catch handler (`Ok<T>` for recovery, `Err<E>` for propagation, or a union)\n * @param options - Configuration object\n * @param options.try - The operation to execute\n * @param options.catch - Error handler that transforms caught exceptions into either `Ok<T>` (recovery) or `Err<E>` (propagation)\n * @returns `Ok<T> | R` — the union of the success path and whatever the catch handler returns\n *\n * @example\n * ```ts\n * // Returns Ok<string> - guaranteed success since catch always returns Ok\n * const alwaysOk = trySync({\n * try: () => JSON.parse(input),\n * catch: () => Ok(\"fallback\") // Always Ok<T>\n * });\n *\n * // Returns Result<object, string> - may fail since catch always returns Err\n * const mayFail = trySync({\n * try: () => JSON.parse(input),\n * catch: (err) => Err(\"Parse failed\") // Returns Err<E>\n * });\n *\n * // Returns Result<void, MyError> - conditional recovery based on error type\n * const conditional = trySync({\n * try: () => riskyOperation(),\n * catch: (err) => {\n * if (isRecoverable(err)) return Ok(undefined);\n * return MyErr({ message: \"Unrecoverable\" });\n * }\n * });\n * ```\n */\n// biome-ignore lint/suspicious/noExplicitAny: required for union type inference in catch handlers\nexport function trySync<T, R extends Ok<T> | Err<any>>({\n\ttry: operation,\n\tcatch: catchFn,\n}: {\n\ttry: () => T;\n\tcatch: (error: unknown) => R;\n}): Ok<T> | R {\n\ttry {\n\t\tconst data = operation();\n\t\treturn Ok(data);\n\t} catch (error) {\n\t\treturn catchFn(error);\n\t}\n}\n\n/**\n * Executes an asynchronous operation and wraps its outcome in a Promise<Result>.\n *\n * This function attempts to execute the `try` operation:\n * - If the `try` operation resolves successfully, its resolved value is wrapped in an `Ok<T>` variant.\n * - If the `try` operation rejects or throws an exception, the caught error (of type `unknown`) is passed to\n * the `catch` function, which transforms it into either an `Ok<T>` (recovery) or `Err<E>` (propagation).\n *\n * The return type is automatically determined by what your catch function returns:\n * - If catch always returns `Ok<T>`, the return type collapses to `Promise<Ok<T>>` (guaranteed success)\n * - If catch always returns `Err<E>`, the return type is `Promise<Ok<T> | Err<E>>` (may succeed or fail)\n * - If catch returns a union like `Err<A> | Err<B>`, the return type is `Promise<Ok<T> | Err<A> | Err<B>>` (union propagation)\n * - If catch can return either `Ok<T>` or `Err<E>`, the return type is `Promise<Ok<T> | Err<E>>` (conditional recovery)\n *\n * @template T - The success value type\n * @template R - The return type of the catch handler (`Ok<T>` for recovery, `Err<E>` for propagation, or a union)\n * @param options - Configuration object\n * @param options.try - The async operation to execute\n * @param options.catch - Error handler that transforms caught exceptions/rejections into either `Ok<T>` (recovery) or `Err<E>` (propagation)\n * @returns `Promise<Ok<T> | R>` — the union of the success path and whatever the catch handler returns\n *\n * @example\n * ```ts\n * // Returns Promise<Ok<Response>> - guaranteed success since catch always returns Ok\n * const alwaysOk = tryAsync({\n * try: async () => fetch(url),\n * catch: () => Ok(new Response()) // Always Ok<T>\n * });\n *\n * // Returns Promise<Result<Response, Error>> - may fail since catch always returns Err\n * const mayFail = tryAsync({\n * try: async () => fetch(url),\n * catch: (err) => Err(new Error(\"Fetch failed\")) // Returns Err<E>\n * });\n *\n * // Returns Promise<Result<void, BlobError>> - conditional recovery based on error type\n * const conditional = await tryAsync({\n * try: async () => {\n * await deleteFile(filename);\n * },\n * catch: (err) => {\n * if ((err as { name?: string }).name === 'NotFoundError') {\n * return Ok(undefined); // Already deleted, that's fine\n * }\n * return BlobErr({ message: \"Delete failed\" });\n * }\n * });\n * ```\n */\n// biome-ignore lint/suspicious/noExplicitAny: required for union type inference in catch handlers\nexport async function tryAsync<T, R extends Ok<T> | Err<any>>({\n\ttry: operation,\n\tcatch: catchFn,\n}: {\n\ttry: () => Promise<T>;\n\tcatch: (error: unknown) => R;\n}): Promise<Ok<T> | R> {\n\ttry {\n\t\tconst data = await operation();\n\t\treturn Ok(data);\n\t} catch (error) {\n\t\treturn catchFn(error);\n\t}\n}\n\n/**\n * Resolves a value that may or may not be wrapped in a `Result`, returning the final value.\n *\n * This function handles the common pattern where a value might be a `Result<T, E>` or a plain `T`:\n * - If `value` is an `Ok<T>` variant, returns the contained success value.\n * - If `value` is an `Err<E>` variant, throws the contained error value.\n * - If `value` is not a `Result` (i.e., it's already a plain value of type `T`),\n * returns it as-is.\n *\n * This is useful when working with APIs that might return either direct values or Results,\n * allowing you to normalize them to the actual value or propagate errors via throwing.\n *\n * Use `resolve` when the input might or might not be a Result.\n * Use `unwrap` when you know the input is definitely a Result.\n *\n * @template T - The type of the success value (if `value` is `Ok<T>`) or the type of the plain value.\n * @template E - The type of the error value (if `value` is `Err<E>`).\n * @param value - The value to resolve. Can be a `Result<T, E>` or a plain value of type `T`.\n * @returns The final value of type `T` if `value` is `Ok<T>` or if `value` is already a plain `T`.\n * @throws The error value `E` if `value` is an `Err<E>` variant.\n *\n * @example\n * ```ts\n * // Example with an Ok variant\n * const okResult = Ok(\"success data\");\n * const resolved = resolve(okResult); // \"success data\"\n *\n * // Example with an Err variant\n * const errResult = Err(new Error(\"failure\"));\n * try {\n * resolve(errResult);\n * } catch (e) {\n * console.error(e.message); // \"failure\"\n * }\n *\n * // Example with a plain value\n * const plainValue = \"plain data\";\n * const resolved = resolve(plainValue); // \"plain data\"\n *\n * // Example with a function that might return Result or plain value\n * declare function mightReturnResult(): string | Result<string, Error>;\n * const outcome = mightReturnResult();\n * try {\n * const finalValue = resolve(outcome); // handles both cases\n * console.log(\"Final value:\", finalValue);\n * } catch (e) {\n * console.error(\"Operation failed:\", e);\n * }\n * ```\n */\n/**\n * Unwraps a `Result<T, E>`, returning the success value or throwing the error.\n *\n * This function extracts the data from a `Result`:\n * - If the `Result` is an `Ok<T>` variant, returns the contained success value of type `T`.\n * - If the `Result` is an `Err<E>` variant, throws the contained error value of type `E`.\n *\n * Unlike `resolve`, this function expects the input to always be a `Result` type,\n * making it more direct for cases where you know you're working with a `Result`.\n *\n * @template T - The type of the success value contained in the `Ok<T>` variant.\n * @template E - The type of the error value contained in the `Err<E>` variant.\n * @param result - The `Result<T, E>` to unwrap.\n * @returns The success value of type `T` if the `Result` is `Ok<T>`.\n * @throws The error value of type `E` if the `Result` is `Err<E>`.\n *\n * @example\n * ```ts\n * // Example with an Ok variant\n * const okResult = Ok(\"success data\");\n * const value = unwrap(okResult); // \"success data\"\n *\n * // Example with an Err variant\n * const errResult = Err(new Error(\"something went wrong\"));\n * try {\n * unwrap(errResult);\n * } catch (error) {\n * console.error(error.message); // \"something went wrong\"\n * }\n *\n * // Usage in a function that returns Result\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) return Err(\"Division by zero\");\n * return Ok(a / b);\n * }\n *\n * try {\n * const result = unwrap(divide(10, 2)); // 5\n * console.log(\"Result:\", result);\n * } catch (error) {\n * console.error(\"Division failed:\", error);\n * }\n * ```\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n\tif (isOk(result)) {\n\t\treturn result.data;\n\t}\n\tthrow result.error;\n}\n\nexport function resolve<T, E>(value: T | Result<T, E>): T {\n\tif (isResult<T, E>(value)) {\n\t\tif (isOk(value)) {\n\t\t\treturn value.data;\n\t\t}\n\t\t// If it's a Result and not Ok, it must be Err.\n\t\t// The type guard isResult<T,E>(value) and isOk(value) already refine the type.\n\t\t// So, 'value' here is known to be Err<E>.\n\t\tthrow value.error;\n\t}\n\n\t// If it's not a Result type, return the value as-is.\n\t// 'value' here is known to be of type T.\n\treturn value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA8EA,MAAa,KAAK,CAAIA,UAAoB;CAAE;CAAM,OAAO;AAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiC/D,MAAa,MAAM,CAAIC,WAAsB;CAAE;CAAO,MAAM;AAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiFlE,SAAgB,SACfC,OACwB;CACxB,MAAM,yBAAyB,UAAU,YAAY,UAAU;AAC/D,MAAK,gBAAiB,QAAO;CAE7B,MAAM,kBAAkB,UAAU;CAClC,MAAM,mBAAmB,WAAW;AACpC,MAAK,oBAAoB,iBAAkB,QAAO;AAElD,QAAO;AACP;;;;;;;;;;;;;;;;;;;;;;AAuBD,SAAgB,KAAWC,QAAuC;AACjE,QAAO,OAAO,UAAU;AACxB;;;;;;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,MAAYA,QAAwC;AACnE,QAAO,OAAO,UAAU;AACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDD,SAAgB,QAAuC,EACtD,KAAK,WACL,OAAO,SAIP,EAAa;AACb,KAAI;EACH,MAAM,OAAO,WAAW;AACxB,SAAO,GAAG,KAAK;CACf,SAAQ,OAAO;AACf,SAAO,QAAQ,MAAM;CACrB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDD,eAAsB,SAAwC,EAC7D,KAAK,WACL,OAAO,SAIP,EAAsB;AACtB,KAAI;EACH,MAAM,OAAO,MAAM,WAAW;AAC9B,SAAO,GAAG,KAAK;CACf,SAAQ,OAAO;AACf,SAAO,QAAQ,MAAM;CACrB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgGD,SAAgB,OAAaA,QAAyB;AACrD,KAAI,KAAK,OAAO,CACf,QAAO,OAAO;AAEf,OAAM,OAAO;AACb;AAED,SAAgB,QAAcC,OAA4B;AACzD,KAAI,SAAe,MAAM,EAAE;AAC1B,MAAI,KAAK,MAAM,CACd,QAAO,MAAM;AAKd,QAAM,MAAM;CACZ;AAID,QAAO;AACP"}
@@ -1,4 +1,4 @@
1
- import { isOk } from "./result-DzL3K2yA.js";
1
+ import { isOk } from "./result-C5cJ1_WU.js";
2
2
 
3
3
  //#region src/result/utils.ts
4
4
  /**
@@ -27,4 +27,4 @@ function partitionResults(results) {
27
27
 
28
28
  //#endregion
29
29
  export { partitionResults };
30
- //# sourceMappingURL=result-corfYKOe.js.map
30
+ //# sourceMappingURL=result-C9V2Knvt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"result-corfYKOe.js","names":["results: Result<T, E>[]"],"sources":["../src/result/utils.ts"],"sourcesContent":["import type { Err, Ok, Result } from \"./result.js\";\nimport { isOk } from \"./result.js\";\n\n/**\n * Partitions an array of Result objects into two separate arrays based on their status.\n *\n * @template T - The success type\n * @template E - The error type\n * @param results - An array of Result objects to partition\n * @returns An object containing two arrays:\n * - `oks`: Array of successful Result objects (Ok<T>[])\n * - `errs`: Array of error Result objects (Err<E>[])\n *\n * @example\n * const results = [Ok(1), Err(\"error\"), Ok(2)];\n * const { oks, errs } = partitionResults(results);\n * // oks = [Ok(1), Ok(2)]\n * // errs = [Err(\"error\")]\n */\nexport function partitionResults<T, E>(results: Result<T, E>[]) {\n\treturn {\n\t\toks: [],\n\t\terrs: [],\n\t\t...Object.groupBy(results, (result) => (isOk(result) ? \"oks\" : \"errs\")),\n\t} as { oks: Ok<T>[]; errs: Err<E>[] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,iBAAuBA,SAAyB;AAC/D,QAAO;EACN,KAAK,CAAE;EACP,MAAM,CAAE;EACR,GAAG,OAAO,QAAQ,SAAS,CAAC,WAAY,KAAK,OAAO,GAAG,QAAQ,OAAQ;CACvE;AACD"}
1
+ {"version":3,"file":"result-C9V2Knvt.js","names":["results: Result<T, E>[]"],"sources":["../src/result/utils.ts"],"sourcesContent":["import type { Err, Ok, Result } from \"./result.js\";\nimport { isOk } from \"./result.js\";\n\n/**\n * Partitions an array of Result objects into two separate arrays based on their status.\n *\n * @template T - The success type\n * @template E - The error type\n * @param results - An array of Result objects to partition\n * @returns An object containing two arrays:\n * - `oks`: Array of successful Result objects (Ok<T>[])\n * - `errs`: Array of error Result objects (Err<E>[])\n *\n * @example\n * const results = [Ok(1), Err(\"error\"), Ok(2)];\n * const { oks, errs } = partitionResults(results);\n * // oks = [Ok(1), Ok(2)]\n * // errs = [Err(\"error\")]\n */\nexport function partitionResults<T, E>(results: Result<T, E>[]) {\n\treturn {\n\t\toks: [],\n\t\terrs: [],\n\t\t...Object.groupBy(results, (result) => (isOk(result) ? \"oks\" : \"errs\")),\n\t} as { oks: Ok<T>[]; errs: Err<E>[] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,iBAAuBA,SAAyB;AAC/D,QAAO;EACN,KAAK,CAAE;EACP,MAAM,CAAE;EACR,GAAG,OAAO,QAAQ,SAAS,CAAC,WAAY,KAAK,OAAO,GAAG,QAAQ,OAAQ;CACvE;AACD"}
@@ -157,9 +157,13 @@ type UnwrapErr<R extends Result<unknown, unknown>> = R extends Err<infer E> ? E
157
157
  * A value is considered a valid `Result` if:
158
158
  * 1. It is a non-null object.
159
159
  * 2. It has both `data` and `error` properties.
160
- * 3. At least one of the `data` or `error` channels is `null`. Both being `null` represents `Ok(null)`.
161
160
  *
162
- * This function does not validate the types of `data` or `error` beyond `null` checks.
161
+ * The `error` property is the runtime discriminant:
162
+ * - `error === null` represents `Ok<T>`, even when `data` is also `null` (`Ok(null)`).
163
+ * - `error !== null` represents `Err<E>`, even if external data also includes a non-null `data` value.
164
+ *
165
+ * This function checks only the Result shape. It does not validate the
166
+ * success or error payload types.
163
167
  *
164
168
  * @template T - The expected type of the success value if the value is an `Ok` variant (defaults to `unknown`).
165
169
  * @template E - The expected type of the error value if the value is an `Err` variant (defaults to `unknown`).
@@ -207,7 +211,8 @@ declare function isOk<T, E>(result: Result<T, E>): result is Ok<T>;
207
211
  * Type guard to runtime check if a `Result<T, E>` is an `Err<E>` variant.
208
212
  *
209
213
  * This function narrows the type of a `Result` to `Err<E>` if it represents a failure outcome.
210
- * An `Err<E>` variant is identified by its `error` property being non-`null` (and thus `data` being `null`).
214
+ * An `Err<E>` variant is identified by its `error` property being non-`null`.
215
+ * The error side is the reliable discriminator because `Ok(null)` is valid.
211
216
  *
212
217
  * @template T - The success value type.
213
218
  * @template E - The error value type.
@@ -432,4 +437,4 @@ declare function resolve<T, E>(value: T | Result<T, E>): T;
432
437
  //# sourceMappingURL=result.d.ts.map
433
438
  //#endregion
434
439
  export { Err, Ok, Result, UnwrapErr, UnwrapOk, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap };
435
- //# sourceMappingURL=result-BongGO2O.d.ts.map
440
+ //# sourceMappingURL=result-DKwq9BCr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-DKwq9BCr.d.ts","names":[],"sources":["../src/result/result.ts"],"sourcesContent":[],"mappings":";;AAWA;AAaA;AAqCA;;;;;;AAAsC;AAiBtC;AAAgE,KAnEpD,EAmEoD,CAAA,CAAA,CAAA,GAAA;EAAA,IAApC,EAnEA,CAmEA;EAAC,KAAM,EAAA,IAAA;CAAC;AAAF;AAiClC;;;;;AAAqC;AAoBrC;;;;AAAqE,KA3GzD,GA2GyD,CAAA,CAAA,CAAA,GAAA;EAAE,KACpE,EA5G2B,CA4G3B;EAAC,IAAA,EAAA,IAAA;AAqBJ,CAAA;;;;;;AAGI;AAoCJ;;;;;AAEkB;AAgClB;;;;;;;AAA8D;AA0B9D;;;;;;;AAAgE;AAkDhE;;;;;;;AAIY,KArPA,MAqPA,CAAA,CAAA,EAAA,CAAA,CAAA,GArPe,EAqPf,CArPkB,CAqPlB,CAAA,GArPuB,GAqPvB,CArP2B,CAqP3B,CAAA;;;;;AAEC;AA2Db;;;;;;;;;;AAMe,cAvSF,EAuSE,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAvSa,CAuSb,EAAA,GAvSiB,EAuSjB,CAvSoB,CAuSpB,CAAA;;;;AAAJ;AAuGX;;;;;;AAAqD;AAOrD;;;;;;;AAAyD;;;;;;;;;;;;;cApX5C,gBAAiB,MAAI,IAAI;;;;;;;;;;;;;;;;;;;KAoB1B,mBAAmB,4BAA4B,UAAU,cAClE;;;;;;;;;;;;;;;;;;;KAqBS,oBAAoB,4BAA4B,UAAU,eAGnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCa,6DAEJ,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;iBAgCN,mBAAmB,OAAO,GAAG,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;iBA0B/C,oBAAoB,OAAO,GAAG,eAAe,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkDjD,qBAAqB,GAAG,KAAK;OACvC;SACE;;aAEI;6BACgB;IACxB,GAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2DU,sBAAsB,GAAG,KAAK;OAC9C;SACE;;aAEI,QAAQ;6BACQ;IACxB,QAAQ,GAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuGJ,qBAAqB,OAAO,GAAG,KAAK;iBAOpC,qBAAqB,IAAI,OAAO,GAAG,KAAK"}
@@ -1,4 +1,4 @@
1
- import { Result } from "./result-BongGO2O.js";
1
+ import { Result } from "./result-DKwq9BCr.js";
2
2
 
3
3
  //#region src/result/tap-err.d.ts
4
4
 
@@ -30,4 +30,4 @@ declare function tapErr<T, E>(logFn: (err: E) => void): (result: Result<T, E>) =
30
30
  //# sourceMappingURL=tap-err.d.ts.map
31
31
  //#endregion
32
32
  export { tapErr };
33
- //# sourceMappingURL=tap-err-Bqs9aQpZ.d.ts.map
33
+ //# sourceMappingURL=tap-err-CFhHBPfH.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tap-err-Bqs9aQpZ.d.ts","names":[],"sources":["../src/result/tap-err.ts"],"sourcesContent":[],"mappings":";;;;;;AA2BA;;;;;;;;;AAEmC;;;;;;;;;;;;;iBAFnB,0BACF,sBACF,OAAO,GAAG,OAAO,OAAO,GAAG"}
1
+ {"version":3,"file":"tap-err-CFhHBPfH.d.ts","names":[],"sources":["../src/result/tap-err.ts"],"sourcesContent":[],"mappings":";;;;;;AA2BA;;;;;;;;;AAEmC;;;;;;;;;;;;;iBAFnB,0BACF,sBACF,OAAO,GAAG,OAAO,OAAO,GAAG"}
@@ -1,4 +1,4 @@
1
- import { isErr } from "./result-DzL3K2yA.js";
1
+ import { isErr } from "./result-C5cJ1_WU.js";
2
2
 
3
3
  //#region src/result/tap-err.ts
4
4
  /**
@@ -34,4 +34,4 @@ function tapErr(logFn) {
34
34
 
35
35
  //#endregion
36
36
  export { tapErr };
37
- //# sourceMappingURL=tap-err-Bf6rQ4Cw.js.map
37
+ //# sourceMappingURL=tap-err-CP-re1HT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tap-err-Bf6rQ4Cw.js","names":["logFn: (err: E) => void"],"sources":["../src/result/tap-err.ts"],"sourcesContent":["import { isErr } from \"./result.js\";\nimport type { Result } from \"./result.js\";\n\n/**\n * Result-flow combinator. Logs on the `Err` branch and returns the `Result`\n * unchanged. Mirrors Rust's `Result::inspect_err` and Effect's\n * `tapErrorCause`.\n *\n * Takes a log **method**, not a whole logger. The caller picks the level at\n * the pipeline site — the same typed error can be logged as `warn` inside a\n * retry loop and as `error` on the last attempt, without the variant itself\n * carrying level. This is the `tracing::warn!(?err)` vs\n * `tracing::error!(?err)` idiom translated to Result-flow.\n *\n * No message argument. The typed error owns its message; a message\n * parameter here would drift away from the variant's template over time.\n *\n * @example\n * const result = await tryAsync({\n * try: () => writeTable(path),\n * catch: (cause) => MarkdownError.TableWrite({ path, cause }),\n * }).then(tapErr(log.warn));\n *\n * @example Level chosen at call site\n * await tryAttempt().then(tapErr(log.warn)); // inside retry\n * await tryFinal().then(tapErr(log.error)); // last try, giving up\n */\nexport function tapErr<T, E>(\n\tlogFn: (err: E) => void,\n): (result: Result<T, E>) => Result<T, E> {\n\treturn (result) => {\n\t\tif (isErr(result)) logFn(result.error);\n\t\treturn result;\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,OACfA,OACyC;AACzC,QAAO,CAAC,WAAW;AAClB,MAAI,MAAM,OAAO,CAAE,OAAM,OAAO,MAAM;AACtC,SAAO;CACP;AACD"}
1
+ {"version":3,"file":"tap-err-CP-re1HT.js","names":["logFn: (err: E) => void"],"sources":["../src/result/tap-err.ts"],"sourcesContent":["import { isErr } from \"./result.js\";\nimport type { Result } from \"./result.js\";\n\n/**\n * Result-flow combinator. Logs on the `Err` branch and returns the `Result`\n * unchanged. Mirrors Rust's `Result::inspect_err` and Effect's\n * `tapErrorCause`.\n *\n * Takes a log **method**, not a whole logger. The caller picks the level at\n * the pipeline site — the same typed error can be logged as `warn` inside a\n * retry loop and as `error` on the last attempt, without the variant itself\n * carrying level. This is the `tracing::warn!(?err)` vs\n * `tracing::error!(?err)` idiom translated to Result-flow.\n *\n * No message argument. The typed error owns its message; a message\n * parameter here would drift away from the variant's template over time.\n *\n * @example\n * const result = await tryAsync({\n * try: () => writeTable(path),\n * catch: (cause) => MarkdownError.TableWrite({ path, cause }),\n * }).then(tapErr(log.warn));\n *\n * @example Level chosen at call site\n * await tryAttempt().then(tapErr(log.warn)); // inside retry\n * await tryFinal().then(tapErr(log.error)); // last try, giving up\n */\nexport function tapErr<T, E>(\n\tlogFn: (err: E) => void,\n): (result: Result<T, E>) => Result<T, E> {\n\treturn (result) => {\n\t\tif (isErr(result)) logFn(result.error);\n\t\treturn result;\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,OACfA,OACyC;AACzC,QAAO,CAAC,WAAW;AAClB,MAAI,MAAM,OAAO,CAAE,OAAM,OAAO,MAAM;AACtC,SAAO;CACP;AACD"}
@@ -0,0 +1,53 @@
1
+ import { Result } from "./result-DKwq9BCr.js";
2
+ import "./tap-err-CFhHBPfH.js";
3
+ import "./index-DnoV2ZDO.js";
4
+
5
+ //#region src/testing.d.ts
6
+
7
+ /**
8
+ * Test-only assertion helpers for `Result` values.
9
+ *
10
+ * These helpers intentionally **throw**. A failed expectation should abort the
11
+ * test, and every test runner reports a thrown error as a failure. Tests are
12
+ * the one place throwing is the correct control flow, so these are fenced into
13
+ * the `wellcrafted/testing` entry point and kept out of `wellcrafted/result`,
14
+ * which stays throw-free. Importing from `wellcrafted/testing` in production
15
+ * code is a smell worth linting against.
16
+ *
17
+ * They are framework-agnostic: they throw a plain `Error` rather than calling
18
+ * into a specific runner, so they work under bun, vitest, jest, or
19
+ * `node:test`.
20
+ */
21
+ /**
22
+ * Asserts that `result` is `Ok` and returns its `data`.
23
+ *
24
+ * Throws if `result` is `Err`. The returned value is narrowed to the success
25
+ * type, so no optional chaining or casting is needed at the call site.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { expectOk } from "wellcrafted/testing";
30
+ *
31
+ * const value = expectOk(parseConfig(raw)); // typed as the success value
32
+ * ```
33
+ */
34
+ declare function expectOk<T>(result: Result<T, unknown>): T;
35
+ /**
36
+ * Asserts that `result` is `Err` and returns its `error`.
37
+ *
38
+ * Throws if `result` is `Ok`. The returned value is narrowed to the error
39
+ * type, so no optional chaining or casting is needed at the call site.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { expectErr } from "wellcrafted/testing";
44
+ *
45
+ * const error = expectErr(parseConfig("not valid"));
46
+ * expect(error.name).toBe("ConfigParseError");
47
+ * ```
48
+ */
49
+ declare function expectErr<E>(result: Result<unknown, E>): E;
50
+ //# sourceMappingURL=testing.d.ts.map
51
+ //#endregion
52
+ export { expectErr, expectOk };
53
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","names":[],"sources":["../src/testing.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AA+BA;;;;;AAA0D;AAuB1D;;;;;AAA2D;;;;;;;;;;;;iBAvB3C,oBAAoB,OAAO,cAAc;;;;;;;;;;;;;;;iBAuBzC,qBAAqB,gBAAgB,KAAK"}
@@ -0,0 +1,59 @@
1
+ import { isErr, isOk } from "./result-C5cJ1_WU.js";
2
+ import { extractErrorMessage } from "./error-DLVm7dsh.js";
3
+ import "./tap-err-CP-re1HT.js";
4
+ import "./result-C9V2Knvt.js";
5
+
6
+ //#region src/testing.ts
7
+ /**
8
+ * Test-only assertion helpers for `Result` values.
9
+ *
10
+ * These helpers intentionally **throw**. A failed expectation should abort the
11
+ * test, and every test runner reports a thrown error as a failure. Tests are
12
+ * the one place throwing is the correct control flow, so these are fenced into
13
+ * the `wellcrafted/testing` entry point and kept out of `wellcrafted/result`,
14
+ * which stays throw-free. Importing from `wellcrafted/testing` in production
15
+ * code is a smell worth linting against.
16
+ *
17
+ * They are framework-agnostic: they throw a plain `Error` rather than calling
18
+ * into a specific runner, so they work under bun, vitest, jest, or
19
+ * `node:test`.
20
+ */
21
+ /**
22
+ * Asserts that `result` is `Ok` and returns its `data`.
23
+ *
24
+ * Throws if `result` is `Err`. The returned value is narrowed to the success
25
+ * type, so no optional chaining or casting is needed at the call site.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { expectOk } from "wellcrafted/testing";
30
+ *
31
+ * const value = expectOk(parseConfig(raw)); // typed as the success value
32
+ * ```
33
+ */
34
+ function expectOk(result) {
35
+ if (!isOk(result)) throw new Error(`Expected Ok, but got Err: ${extractErrorMessage(result.error)}`);
36
+ return result.data;
37
+ }
38
+ /**
39
+ * Asserts that `result` is `Err` and returns its `error`.
40
+ *
41
+ * Throws if `result` is `Ok`. The returned value is narrowed to the error
42
+ * type, so no optional chaining or casting is needed at the call site.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { expectErr } from "wellcrafted/testing";
47
+ *
48
+ * const error = expectErr(parseConfig("not valid"));
49
+ * expect(error.name).toBe("ConfigParseError");
50
+ * ```
51
+ */
52
+ function expectErr(result) {
53
+ if (!isErr(result)) throw new Error("Expected Err, but got Ok");
54
+ return result.error;
55
+ }
56
+
57
+ //#endregion
58
+ export { expectErr, expectOk };
59
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","names":["result: Result<T, unknown>","result: Result<unknown, E>"],"sources":["../src/testing.ts"],"sourcesContent":["import { extractErrorMessage } from \"./error/index.js\";\nimport { isErr, isOk, type Result } from \"./result/index.js\";\n\n/**\n * Test-only assertion helpers for `Result` values.\n *\n * These helpers intentionally **throw**. A failed expectation should abort the\n * test, and every test runner reports a thrown error as a failure. Tests are\n * the one place throwing is the correct control flow, so these are fenced into\n * the `wellcrafted/testing` entry point and kept out of `wellcrafted/result`,\n * which stays throw-free. Importing from `wellcrafted/testing` in production\n * code is a smell worth linting against.\n *\n * They are framework-agnostic: they throw a plain `Error` rather than calling\n * into a specific runner, so they work under bun, vitest, jest, or\n * `node:test`.\n */\n\n/**\n * Asserts that `result` is `Ok` and returns its `data`.\n *\n * Throws if `result` is `Err`. The returned value is narrowed to the success\n * type, so no optional chaining or casting is needed at the call site.\n *\n * @example\n * ```ts\n * import { expectOk } from \"wellcrafted/testing\";\n *\n * const value = expectOk(parseConfig(raw)); // typed as the success value\n * ```\n */\nexport function expectOk<T>(result: Result<T, unknown>): T {\n\tif (!isOk(result)) {\n\t\tthrow new Error(\n\t\t\t`Expected Ok, but got Err: ${extractErrorMessage(result.error)}`,\n\t\t);\n\t}\n\treturn result.data;\n}\n\n/**\n * Asserts that `result` is `Err` and returns its `error`.\n *\n * Throws if `result` is `Ok`. The returned value is narrowed to the error\n * type, so no optional chaining or casting is needed at the call site.\n *\n * @example\n * ```ts\n * import { expectErr } from \"wellcrafted/testing\";\n *\n * const error = expectErr(parseConfig(\"not valid\"));\n * expect(error.name).toBe(\"ConfigParseError\");\n * ```\n */\nexport function expectErr<E>(result: Result<unknown, E>): E {\n\tif (!isErr(result)) {\n\t\tthrow new Error(\"Expected Err, but got Ok\");\n\t}\n\treturn result.error;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,SAAYA,QAA+B;AAC1D,MAAK,KAAK,OAAO,CAChB,OAAM,IAAI,MACT,CAAC,0BAA0B,EAAE,oBAAoB,OAAO,MAAM,EAAE;AAGlE,QAAO,OAAO;AACd;;;;;;;;;;;;;;;AAgBD,SAAgB,UAAaC,QAA+B;AAC3D,MAAK,MAAM,OAAO,CACjB,OAAM,IAAI,MAAM;AAEjB,QAAO,OAAO;AACd"}
@@ -1,4 +1,4 @@
1
- import { Err } from "./result-BongGO2O.js";
1
+ import { Err } from "./result-DKwq9BCr.js";
2
2
 
3
3
  //#region src/error/types.d.ts
4
4
 
@@ -44,4 +44,4 @@ type InferError<T> = T extends ((...args: any[]) => Err<infer R>) ? R : never;
44
44
  type InferErrors<T> = { [K in keyof T]: T[K] extends ((...args: any[]) => Err<infer R>) ? R : never }[keyof T];
45
45
  //#endregion
46
46
  export { AnyTaggedError, DefineErrorsReturn, ErrorBody, ErrorsConfig, InferError, InferErrors, ValidatedConfig };
47
- //# sourceMappingURL=types-cY80Bw6u.d.ts.map
47
+ //# sourceMappingURL=types-tXXk7K9Q.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-cY80Bw6u.d.ts","names":[],"sources":["../src/error/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAWY,KAXA,cAAA,GAWS;EAQhB,IAAA,EAAA,MAAA;EAOO,OAAA,EAAA,MAAY;CAAA;;;AAAS;AAGjC;;AAAsC,KAlB1B,SAAA,GAkB0B;EAAY,OAErC,EAAA,MAAA;CAAC;;;;;;;KAZT,iBAcC,CAAA,UAAA,MAAA,CAAA,GAAA;EAAC,OAAA,EAAA,MAAA;EAIF,IAAA,CAAA,EAAA,kCAhBqC,CAgBzB,eAAA;CAAA;;AAKV,KAhBK,YAAA,GAAe,MAgBpB,CAAA,MAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAhBuD,SAgBvD,CAAA;;AACI,KAdC,eAcD,CAAA,UAd2B,YAc3B,CAAA,GAAA,QACgB,MAbd,CAac,GAAA,MAAA,GAbD,CAaC,CAbC,CAaD,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,KAAA,EAAA,EAAA,GAAA,KAAA,EAAA,IAAA,CAAA,GAAA,IAAA,EAZb,CAYa,EAAA,GAZP,CAYO,GAZH,iBAYG,CAZe,CAYf,CAAA,GAXvB,CAWuB,CAXrB,CAWqB,CAAA,EAAK;;KAP3B,YAOK,CAAA,cAAA,MAAA,EAAA,YAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAJuB,SAIvB,CAAA,GAAA,QAFH,KAED,GAAA,CAAA,GAAA,IAAA,EADK,UACL,CADgB,GAChB,CAAA,EAAA,GAAA,GAAA,CAAI,QAAJ,CAAA;EAAG,IAAA,EAAkB,KAAlB;AAIJ,CAAA,GAJgC,UAIhC,CAJ2C,GAI3C,CAAA,CAAA,CAAA,EAAmB;KAAnB,mBAA0B,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,SAAA,GAAA,GAAA,CAAA,CAAA,EAAoB,CAApB,EAAA,GAAA,IAAA,GAAA,KAAA,CAAA,UAAA,CAAA,CAAA,EAAA,KAAA,EAAA,EAAA,GAAA,IAAA,IAG5B,CAH4B,GAAA,KAAA;;AAG5B,KAIS,kBAJT,CAAA,gBAI4C,YAJ5C,CAAA,GAKF,mBALE,CAAA,QAAC,MAOW,OAPX,GAAA,MAAA,GAO8B,YAP9B,CAO2C,CAP3C,EAO8C,OAP9C,CAOsD,CAPtD,CAAA,CAAA,EAIJ,CAAA,MAIU,OAJE,GAAA,MAAA,CAAkB,CAAA;;AAAiB,KAQnC,UARmC,CAAA,CAAA,CAAA,GAU9C,CAV8C,UAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAUhB,GAVgB,CAAA,KAAA,EAAA,CAAA,IAUD,CAVC,GAAA,KAAA;;AAGA,KAUnC,WAVmC,CAAA,CAAA,CAAA,GAAA,QAAG,MAYrC,CAZqC,GAYjC,CAZiC,CAY/B,CAZ+B,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAYA,GAZA,CAAA,KAAA,EAAA,CAAA,IAYe,CAZf,GAAA,KAAA,EAAO,CAAA,MAajD,CAbkD,CAAA"}
1
+ {"version":3,"file":"types-tXXk7K9Q.d.ts","names":[],"sources":["../src/error/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAWY,KAXA,cAAA,GAWS;EAQhB,IAAA,EAAA,MAAA;EAOO,OAAA,EAAA,MAAY;CAAA;;;AAAS;AAGjC;;AAAsC,KAlB1B,SAAA,GAkB0B;EAAY,OAErC,EAAA,MAAA;CAAC;;;;;;;KAZT,iBAcC,CAAA,UAAA,MAAA,CAAA,GAAA;EAAC,OAAA,EAAA,MAAA;EAIF,IAAA,CAAA,EAAA,kCAhBqC,CAgBzB,eAAA;CAAA;;AAKV,KAhBK,YAAA,GAAe,MAgBpB,CAAA,MAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAhBuD,SAgBvD,CAAA;;AACI,KAdC,eAcD,CAAA,UAd2B,YAc3B,CAAA,GAAA,QACgB,MAbd,CAac,GAAA,MAAA,GAbD,CAaC,CAbC,CAaD,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,KAAA,EAAA,EAAA,GAAA,KAAA,EAAA,IAAA,CAAA,GAAA,IAAA,EAZb,CAYa,EAAA,GAZP,CAYO,GAZH,iBAYG,CAZe,CAYf,CAAA,GAXvB,CAWuB,CAXrB,CAWqB,CAAA,EAAK;;KAP3B,YAOK,CAAA,cAAA,MAAA,EAAA,YAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAJuB,SAIvB,CAAA,GAAA,QAFH,KAED,GAAA,CAAA,GAAA,IAAA,EADK,UACL,CADgB,GAChB,CAAA,EAAA,GAAA,GAAA,CAAI,QAAJ,CAAA;EAAG,IAAA,EAAkB,KAAlB;AAIJ,CAAA,GAJgC,UAIhC,CAJ2C,GAI3C,CAAA,CAAA,CAAA,EAAmB;KAAnB,mBAA0B,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,SAAA,GAAA,GAAA,CAAA,CAAA,EAAoB,CAApB,EAAA,GAAA,IAAA,GAAA,KAAA,CAAA,UAAA,CAAA,CAAA,EAAA,KAAA,EAAA,EAAA,GAAA,IAAA,IAG5B,CAH4B,GAAA,KAAA;;AAG5B,KAIS,kBAJT,CAAA,gBAI4C,YAJ5C,CAAA,GAKF,mBALE,CAAA,QAAC,MAOW,OAPX,GAAA,MAAA,GAO8B,YAP9B,CAO2C,CAP3C,EAO8C,OAP9C,CAOsD,CAPtD,CAAA,CAAA,EAIJ,CAAA,MAIU,OAJE,GAAA,MAAA,CAAkB,CAAA;;AAAiB,KAQnC,UARmC,CAAA,CAAA,CAAA,GAU9C,CAV8C,UAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAUhB,GAVgB,CAAA,KAAA,EAAA,CAAA,IAUD,CAVC,GAAA,KAAA;;AAGA,KAUnC,WAVmC,CAAA,CAAA,CAAA,GAAA,QAAG,MAYrC,CAZqC,GAYjC,CAZiC,CAY/B,CAZ+B,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAYA,GAZA,CAAA,KAAA,EAAA,CAAA,IAYe,CAZf,GAAA,KAAA,EAAO,CAAA,MAajD,CAbkD,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wellcrafted",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "description": "Delightful TypeScript patterns for elegant, type-safe applications",
5
5
  "type": "module",
6
6
  "files": [
@@ -36,6 +36,10 @@
36
36
  "./standard-schema": {
37
37
  "types": "./dist/standard-schema/index.d.ts",
38
38
  "import": "./dist/standard-schema/index.js"
39
+ },
40
+ "./testing": {
41
+ "types": "./dist/testing.d.ts",
42
+ "import": "./dist/testing.js"
39
43
  }
40
44
  },
41
45
  "scripts": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.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;;AAAmD,iBCtDnC,mBAAA,CDsDmC,KAAA,EAAA,OAAA,CAAA,EAAA,MAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.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"}