@onrails/result 0.2.0 → 0.3.1

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 (60) hide show
  1. package/DESIGN.md +11 -18
  2. package/README.md +14 -59
  3. package/RECIPES.md +12 -25
  4. package/dist/{async-1fIhfzFu.d.ts → async-Ci6WSL5-.d.ts} +60 -18
  5. package/dist/{async-u8U5P2EH.d.cts → async-DcXR7k9K.d.cts} +60 -18
  6. package/dist/compat/neverthrow.cjs +42 -51
  7. package/dist/compat/neverthrow.cjs.map +1 -1
  8. package/dist/compat/neverthrow.d.cts +3 -3
  9. package/dist/compat/neverthrow.d.ts +3 -3
  10. package/dist/compat/neverthrow.js +42 -51
  11. package/dist/compat/neverthrow.js.map +1 -1
  12. package/dist/extra.cjs +1 -1
  13. package/dist/extra.cjs.map +1 -1
  14. package/dist/extra.d.cts +5 -11
  15. package/dist/extra.d.ts +5 -11
  16. package/dist/extra.js +1 -1
  17. package/dist/extra.js.map +1 -1
  18. package/dist/fluent.cjs +66 -28
  19. package/dist/fluent.cjs.map +1 -1
  20. package/dist/fluent.d.cts +41 -6
  21. package/dist/fluent.d.ts +41 -6
  22. package/dist/fluent.js +66 -28
  23. package/dist/fluent.js.map +1 -1
  24. package/dist/index.cjs +95 -95
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +168 -44
  27. package/dist/index.d.ts +168 -44
  28. package/dist/index.js +90 -95
  29. package/dist/index.js.map +1 -1
  30. package/dist/railway.cjs +101 -172
  31. package/dist/railway.cjs.map +1 -1
  32. package/dist/railway.d.cts +25 -179
  33. package/dist/railway.d.ts +25 -179
  34. package/dist/railway.js +102 -162
  35. package/dist/railway.js.map +1 -1
  36. package/dist/try-gen.cjs +1 -1
  37. package/dist/try-gen.cjs.map +1 -1
  38. package/dist/try-gen.js +1 -1
  39. package/dist/try-gen.js.map +1 -1
  40. package/package.json +1 -16
  41. package/skills/railway-do-notation/SKILL.md +29 -68
  42. package/skills/result-composition/SKILL.md +2 -4
  43. package/dist/$.cjs +0 -40
  44. package/dist/$.cjs.map +0 -1
  45. package/dist/$.js +0 -36
  46. package/dist/$.js.map +0 -1
  47. package/dist/_.d.cts +0 -2
  48. package/dist/_.d.ts +0 -2
  49. package/dist/interop.cjs +0 -433
  50. package/dist/interop.cjs.map +0 -1
  51. package/dist/interop.d.cts +0 -75
  52. package/dist/interop.d.ts +0 -75
  53. package/dist/interop.js +0 -429
  54. package/dist/interop.js.map +0 -1
  55. package/dist/validation.cjs +0 -53
  56. package/dist/validation.cjs.map +0 -1
  57. package/dist/validation.d.cts +0 -72
  58. package/dist/validation.d.ts +0 -72
  59. package/dist/validation.js +0 -48
  60. package/dist/validation.js.map +0 -1
package/dist/interop.d.ts DELETED
@@ -1,75 +0,0 @@
1
- import { R as ResultAsync } from './async-1fIhfzFu.js';
2
- import { R as Result, U as UnexpectedError } from './types-BQ9vv0nD.js';
3
-
4
- /**
5
- * Extracts the `Ok` value type from a {@link Result} or {@link ResultAsync},
6
- * resolving to `never` for any other type.
7
- *
8
- * @example
9
- * ```ts
10
- * type T = InferOk<Result<number, string>>; // number
11
- * type U = InferOk<ResultAsync<User, AppError>>; // User
12
- * ```
13
- */
14
- type InferOk<R> = R extends {
15
- _tag: "Ok";
16
- readonly value: infer T;
17
- } ? T : R extends ResultAsync<infer T, unknown> ? T : never;
18
- /**
19
- * Extracts the `Err` error type from a {@link Result} or {@link ResultAsync},
20
- * resolving to `never` for any other type. Mirror of {@link InferOk}.
21
- *
22
- * @example
23
- * ```ts
24
- * type E = InferErr<Result<number, string>>; // string
25
- * type F = InferErr<ResultAsync<User, AppError>>; // AppError
26
- * ```
27
- */
28
- type InferErr<R> = R extends {
29
- _tag: "Err";
30
- readonly error: infer E;
31
- } ? E : R extends ResultAsync<unknown, infer E> ? E : never;
32
- type AnyResult = Result<unknown, unknown>;
33
- /**
34
- * Lifts an already-settled sync {@link Result} into a {@link ResultAsync}, so
35
- * it can be chained alongside async steps in a railway.
36
- *
37
- * @example
38
- * ```ts
39
- * const ra = fromResult(ok(1)); // ResultAsync<number, never>
40
- * await fromResult(err(error)).resolve(); // Err(error)
41
- * ```
42
- */
43
- declare const fromResult: <T, E>(result: Result<T, E>) => ResultAsync<T, E>;
44
- /**
45
- * Bind a sync {@link Result} into an async step without widening defects.
46
- * Dual-form: data-first for one-shots, data-last (curried) for `pipe`/`flow`.
47
- *
48
- * @example
49
- * ```ts
50
- * asyncAfter(result, (u) => tryAsync(db.insert(u), toErr)); // data-first
51
- * asyncAfter((u) => tryAsync(db.insert(u), toErr)); // data-last
52
- * ```
53
- */
54
- declare function asyncAfter<T, U, E, F>(result: Result<T, E>, fn: (value: T) => ResultAsync<U, F>): ResultAsync<U, E | F>;
55
- declare function asyncAfter<T, U, F>(fn: (value: T) => ResultAsync<U, F>): <E>(result: Result<T, E>) => ResultAsync<U, E | F>;
56
- /**
57
- * Lifts a `(...args) => Promise<Result<T, E>>` function (typical of interop or
58
- * boundary code) into one returning `(...args) => ResultAsync<T, E>`. Expected
59
- * `Err`s pass through; an unexpected promise rejection (a defect) is routed via
60
- * `onDefect`, defaulting to {@link UnexpectedError} and widening the error union.
61
- *
62
- * @param fn - a function returning a promise that already yields a `Result`
63
- * @param onDefect - maps an unexpected rejection to the `Err` channel
64
- *
65
- * @example
66
- * ```ts
67
- * const loadUser = fromAsync(
68
- * (id: string): Promise<Result<User, NotFound>> => api.getUser(id),
69
- * );
70
- * const ra = loadUser("u1"); // ResultAsync<User, NotFound | UnexpectedError>
71
- * ```
72
- */
73
- declare const fromAsync: <A extends readonly unknown[], R extends AnyResult>(fn: (...args: A) => Promise<R>, onDefect?: (error: unknown) => InferErr<R> | UnexpectedError) => ((...args: A) => ResultAsync<InferOk<R>, InferErr<R> | UnexpectedError>);
74
-
75
- export { type InferErr, type InferOk, asyncAfter, fromAsync, fromResult };
package/dist/interop.js DELETED
@@ -1,429 +0,0 @@
1
- // src/result.ts
2
- var ok = (value) => ({
3
- _tag: "Ok",
4
- value
5
- });
6
- var err = (error) => ({
7
- _tag: "Err",
8
- error
9
- });
10
- var isOk = (result) => result._tag === "Ok";
11
- var isErr = (result) => result._tag === "Err";
12
- var mapImpl = (result, fn) => isOk(result) ? ok(fn(result.value)) : err(result.error);
13
- function map(...args) {
14
- if (args.length === 2) return mapImpl(args[0], args[1]);
15
- const fn = args[0];
16
- return (result) => mapImpl(result, fn);
17
- }
18
- var mapErrImpl = (result, fn) => isErr(result) ? err(fn(result.error)) : ok(result.value);
19
- function mapErr(...args) {
20
- if (args.length === 2) return mapErrImpl(args[0], args[1]);
21
- const fn = args[0];
22
- return (result) => mapErrImpl(result, fn);
23
- }
24
-
25
- // src/types.ts
26
- var UnexpectedError = class extends Error {
27
- constructor(message, cause) {
28
- super(message);
29
- this.cause = cause;
30
- this.name = "UnexpectedError";
31
- }
32
- cause;
33
- };
34
-
35
- // src/async.ts
36
- var liftPromiseResult = async (promise, onDefect) => {
37
- try {
38
- const result = await promise;
39
- if (isErr(result)) {
40
- return result;
41
- }
42
- return isResultLike(result.value) ? result.value : result;
43
- } catch (error) {
44
- return err(onDefect(error));
45
- }
46
- };
47
- var sequenceSettled = (settled) => {
48
- const values = [];
49
- for (const result of settled) {
50
- if (isErr(result)) {
51
- return err(result.error);
52
- }
53
- values.push(result.value);
54
- }
55
- return ok(values);
56
- };
57
- var ResultAsync = class _ResultAsync {
58
- constructor(run) {
59
- this.run = run;
60
- }
61
- run;
62
- promise = null;
63
- /**
64
- * Lifts an already-settled sync {@link Result} into a {@link ResultAsync}.
65
- *
66
- * @example
67
- * ```ts
68
- * const ra = ResultAsync.fromResult(ok(42)); // ResultAsync<number, never>
69
- * ```
70
- */
71
- static fromResult(result) {
72
- return new _ResultAsync(async () => result);
73
- }
74
- /**
75
- * Wraps a `PromiseLike<T>` that may reject. Rejections pass through `onReject`
76
- * to become a typed `Err`; resolution becomes `Ok<T>`.
77
- *
78
- * @param promise - the promise to wrap
79
- * @param onReject - maps a rejection reason to the `Err` channel
80
- *
81
- * @example
82
- * ```ts
83
- * const body = ResultAsync.fromPromise(
84
- * fetch(url).then((r) => r.text()),
85
- * (e): NetError => ({ kind: "net", cause: String(e) }),
86
- * );
87
- * ```
88
- */
89
- static fromPromise(promise, onReject) {
90
- return new _ResultAsync(async () => {
91
- try {
92
- return ok(await promise);
93
- } catch (error) {
94
- return err(onReject(error));
95
- }
96
- });
97
- }
98
- /**
99
- * Wraps a `PromiseLike<T>` that is **guaranteed not to reject**, skipping the
100
- * `onReject` mapper. Use only when rejection is provably impossible.
101
- *
102
- * @example
103
- * ```ts
104
- * const now = ResultAsync.fromSafePromise(Promise.resolve(Date.now()));
105
- * ```
106
- */
107
- static fromSafePromise(promise) {
108
- return new _ResultAsync(async () => ok(await promise));
109
- }
110
- /**
111
- * Defers work until {@link resolve}. Unlike {@link fromPromise}, the factory
112
- * does not run until the `ResultAsync` is resolved (e.g. by `combineTuple` /
113
- * `combineTupleParallel`). The factory runs at most once — `resolve` memoizes.
114
- *
115
- * @example
116
- * ```ts
117
- * const insert = ResultAsync.defer(() => db.orders.insert(row));
118
- * // nothing has run yet
119
- * const r = await insert; // factory runs exactly once here
120
- * ```
121
- */
122
- static defer(fn) {
123
- return new _ResultAsync(fn);
124
- }
125
- static ok(value) {
126
- return new _ResultAsync(async () => ok(value));
127
- }
128
- /**
129
- * Lifts an error into an `Err` async result.
130
- *
131
- * @example
132
- * ```ts
133
- * const r = ResultAsync.err({ kind: "not_found" as const });
134
- * ```
135
- */
136
- static err(error) {
137
- return new _ResultAsync(async () => err(error));
138
- }
139
- /**
140
- * Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
141
- * {@link ResultAsync}, auto-flattening one level of double-wrapping. A thrown
142
- * defect is routed through `onDefect`, defaulting to {@link UnexpectedError}.
143
- *
144
- * @param promise - a promise that already yields a `Result`
145
- * @param onDefect - maps an unexpected throw to the `Err` channel
146
- * @see {@link fromAsync} from `@onrails/result/interop`
147
- */
148
- static fromResultPromise(promise, onDefect) {
149
- const mapDefect = onDefect ?? ((error) => new UnexpectedError("Unexpected async defect", error));
150
- return new _ResultAsync(() => liftPromiseResult(promise, mapDefect));
151
- }
152
- /**
153
- * Combines a homogeneous array of async results into one. Resolves
154
- * **sequentially** in input order, short-circuiting on the first `Err`.
155
- * For heterogeneous tuples that preserve per-index types, use
156
- * {@link combineTuple}; for wall-clock overlap, {@link combineTupleParallel}.
157
- *
158
- * @example
159
- * ```ts
160
- * const all = ResultAsync.combine([loadA(), loadB(), loadC()]);
161
- * // ResultAsync<Item[], LoadError>
162
- * ```
163
- */
164
- static combine(results) {
165
- return new _ResultAsync(async () => {
166
- const values = [];
167
- for (const ra of results) {
168
- const result = await ra.resolve();
169
- if (isErr(result)) {
170
- return err(result.error);
171
- }
172
- values.push(result.value);
173
- }
174
- return ok(values);
175
- });
176
- }
177
- /**
178
- * Heterogeneous async tuple combine — resolves branches **sequentially**
179
- * (left-to-right), returning the first `Err` in input order. Preserves each
180
- * branch's `Ok` type by position, so the result destructures type-safely.
181
- * This is the canonical sequential async combine (replaces the former
182
- * `sequenceTupleAsync`).
183
- *
184
- * @example
185
- * ```ts
186
- * const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()] as const);
187
- * // ResultAsync<readonly [Cfg, Catalog], CfgError | CatalogError>
188
- * const r = await combined;
189
- * if (isOk(r)) {
190
- * const [cfg, catalog] = r.value; // typed per position
191
- * }
192
- * ```
193
- */
194
- static combineTuple(results) {
195
- return _ResultAsync.combine(
196
- results
197
- );
198
- }
199
- /**
200
- * Like {@link combineTuple}, but starts every branch before awaiting (wall-clock
201
- * parallel for independent IO). On failure, returns the first `Err` in input order.
202
- *
203
- * @example
204
- * ```ts
205
- * // independent IO — overlap them
206
- * const combined = ResultAsync.combineTupleParallel([
207
- * loadProfile(id),
208
- * loadMetrics(id),
209
- * ] as const);
210
- * ```
211
- */
212
- static combineTupleParallel(results) {
213
- return new _ResultAsync(
214
- async () => sequenceSettled(await Promise.all(results.map((ra) => ra.resolve())))
215
- );
216
- }
217
- /**
218
- * Transforms the `Ok` value, passing `Err` through unchanged.
219
- *
220
- * @example
221
- * ```ts
222
- * ResultAsync.ok(2).map((n) => n * 3); // ResultAsync<number> → Ok 6
223
- * ```
224
- */
225
- map(fn) {
226
- return new _ResultAsync(async () => map(await this.resolve(), fn));
227
- }
228
- /**
229
- * Transforms the `Err` value, passing `Ok` through unchanged — useful for
230
- * unifying heterogeneous failures into one app-level union.
231
- *
232
- * @example
233
- * ```ts
234
- * load(id).mapErr((e): AppError => ({ kind: "load", cause: e }));
235
- * ```
236
- */
237
- mapErr(fn) {
238
- return new _ResultAsync(async () => mapErr(await this.resolve(), fn));
239
- }
240
- /**
241
- * Canonical bind — chains a step that itself returns a `ResultAsync` or sync
242
- * `Result`, short-circuiting on `Err`. Error types accumulate (`E | F`).
243
- *
244
- * @example
245
- * ```ts
246
- * authenticate(req)
247
- * .flatMap((user) => loadProfile(user.id)) // ResultAsync
248
- * .flatMap((p) => validate(p)); // sync Result also accepted
249
- * ```
250
- */
251
- flatMap(fn) {
252
- return new _ResultAsync(async () => {
253
- const first = await this.resolve();
254
- if (isErr(first)) {
255
- return first;
256
- }
257
- const next = fn(first.value);
258
- if (next instanceof _ResultAsync) {
259
- return next.resolve();
260
- }
261
- if (isResultLike(next)) {
262
- return next;
263
- }
264
- return isCompatLike(next) ? next.inner : next;
265
- });
266
- }
267
- /**
268
- * neverthrow-compat alias of {@link flatMap}. Kept as the documented compat
269
- * tier; prefer `flatMap` in new code.
270
- *
271
- * @example
272
- * ```ts
273
- * authenticate(req).andThen((user) => loadProfile(user.id));
274
- * ```
275
- */
276
- andThen(fn) {
277
- return this.flatMap(fn);
278
- }
279
- /**
280
- * Error-channel bind — runs `fn` only on `Err`, swapping in a recovery
281
- * `ResultAsync` or sync `Result`. `Ok` passes through. The mirror of
282
- * {@link flatMap} on the error track.
283
- *
284
- * @example
285
- * ```ts
286
- * loadFromCache(id).recover(() => loadFromOrigin(id));
287
- * ```
288
- */
289
- recover(fn) {
290
- return new _ResultAsync(async () => {
291
- const first = await this.resolve();
292
- if (!isErr(first)) {
293
- return first;
294
- }
295
- const next = fn(first.error);
296
- return next instanceof _ResultAsync ? next.resolve() : next;
297
- });
298
- }
299
- /**
300
- * neverthrow-compat alias of {@link recover}. Kept as the documented compat
301
- * tier; prefer `recover` in new code.
302
- *
303
- * @example
304
- * ```ts
305
- * loadFromCache(id).orElse(() => loadFromOrigin(id));
306
- * ```
307
- */
308
- orElse(fn) {
309
- return this.recover(fn);
310
- }
311
- /**
312
- * Runs a side effect on the `Ok` value and passes the result through
313
- * unchanged; a no-op on `Err`. Mirrors {@link tapErr}.
314
- *
315
- * @example
316
- * ```ts
317
- * saveUser(u).tap((saved) => analytics.track("user_saved", saved.id));
318
- * ```
319
- */
320
- tap(fn) {
321
- return new _ResultAsync(async () => {
322
- const result = await this.resolve();
323
- if (!isErr(result)) {
324
- fn(result.value);
325
- }
326
- return result;
327
- });
328
- }
329
- /**
330
- * Runs a side effect on the `Err` value and passes the result through
331
- * unchanged; a no-op on `Ok`. The error-track mirror of {@link tap}.
332
- *
333
- * @example
334
- * ```ts
335
- * saveUser(u).tapErr((e) => logger.warn("save failed", e));
336
- * ```
337
- */
338
- tapErr(fn) {
339
- return new _ResultAsync(async () => {
340
- const result = await this.resolve();
341
- if (isErr(result)) {
342
- fn(result.error);
343
- }
344
- return result;
345
- });
346
- }
347
- /**
348
- * Settles to the `Ok` value, or `defaultValue` if `Err`. Terminal — returns a
349
- * plain `Promise`, not a `ResultAsync`.
350
- *
351
- * @example
352
- * ```ts
353
- * const profile = await loadProfile(id).unwrapOr(guestProfile);
354
- * ```
355
- */
356
- unwrapOr(defaultValue) {
357
- return this.resolve().then((result) => isErr(result) ? defaultValue : result.value);
358
- }
359
- /**
360
- * Terminal collapse — folds both tracks into a single awaited value. Returns
361
- * a plain `Promise`, settling the carrier exactly once.
362
- *
363
- * @param onOk - handles the `Ok` value
364
- * @param onErr - handles the `Err` value
365
- *
366
- * @example
367
- * ```ts
368
- * const status = await save(row).match(
369
- * () => 200,
370
- * (e) => (e.kind === "conflict" ? 409 : 500),
371
- * );
372
- * ```
373
- */
374
- match(onOk, onErr) {
375
- return this.resolve().then(
376
- (result) => isErr(result) ? onErr(result.error) : onOk(result.value)
377
- );
378
- }
379
- /**
380
- * Settles the carrier to a bare sync {@link Result}, memoizing so the
381
- * underlying factory runs at most once. Prefer `await ra` (the thenable) or
382
- * {@link match} in app code; use `resolve` when you need the tagged union back.
383
- *
384
- * @example
385
- * ```ts
386
- * const r = await load(id).resolve(); // Result<Data, LoadError>
387
- * if (isOk(r)) use(r.value);
388
- * ```
389
- */
390
- resolve() {
391
- if (!this.promise) {
392
- this.promise = this.run();
393
- }
394
- return this.promise;
395
- }
396
- /**
397
- * Thenable shim — `await ra` resolves to a bare tagged-union `Result<T, E>`.
398
- * Narrow with `isOk(r)` / `isErr(r)` to read `.value` / `.error`.
399
- */
400
- // biome-ignore lint/suspicious/noThenProperty: makes ResultAsync awaitable
401
- then(onfulfilled, onrejected) {
402
- return this.resolve().then(
403
- // Safe: without onfulfilled, R1 stays at its Result<T, E> default.
404
- (r) => onfulfilled ? onfulfilled(r) : r,
405
- onrejected ?? void 0
406
- );
407
- }
408
- };
409
- function isResultLike(v) {
410
- return typeof v === "object" && v !== null && "_tag" in v && (v._tag === "Ok" || v._tag === "Err");
411
- }
412
- function isCompatLike(v) {
413
- return typeof v === "object" && v !== null && "inner" in v && isResultLike(v.inner);
414
- }
415
-
416
- // src/interop.ts
417
- var fromResult = (result) => ResultAsync.fromResult(result);
418
- function asyncAfter(resultOrFn, fn) {
419
- if (fn === void 0) {
420
- const f = resultOrFn;
421
- return (result) => fromResult(result).flatMap(f);
422
- }
423
- return fromResult(resultOrFn).flatMap(fn);
424
- }
425
- var fromAsync = (fn, onDefect) => (...args) => ResultAsync.fromResultPromise(fn(...args), onDefect);
426
-
427
- export { asyncAfter, fromAsync, fromResult };
428
- //# sourceMappingURL=interop.js.map
429
- //# sourceMappingURL=interop.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/result.ts","../src/types.ts","../src/async.ts","../src/interop.ts"],"names":[],"mappings":"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","file":"interop.js","sourcesContent":["import type { Err, Ok, Result } from \"./types.js\";\n\nexport type { Err, Ok, Result } from \"./types.js\";\n\n/**\n * Lifts a value into the success track.\n *\n * @example\n * ```ts\n * const r = ok(42); // Result<number, never>\n * const typed: Result<number, \"parse\"> = ok(1);\n * ```\n */\nexport const ok = <T, E = never>(value: T): Result<T, E> => ({\n _tag: \"Ok\",\n value,\n});\n\n/**\n * Lifts a value into the error track.\n *\n * @example\n * ```ts\n * const r = err({ kind: \"parse\", message: \"bad json\" });\n * // Result<never, { kind: \"parse\"; message: string }>\n * ```\n */\nexport const err = <T = never, E = unknown>(error: E): Result<T, E> => ({\n _tag: \"Err\",\n error,\n});\n\n/**\n * Type-narrowing predicate: returns `true` when the result is `Ok`.\n *\n * @example\n * ```ts\n * if (isOk(r)) {\n * console.log(r.value); // narrowed to Ok branch\n * }\n * ```\n */\nexport const isOk = <T, E>(result: Result<T, E>): result is Ok<T, E> => result._tag === \"Ok\";\n\n/**\n * Type-narrowing predicate: returns `true` when the result is `Err`.\n *\n * @example\n * ```ts\n * if (isErr(r)) {\n * metrics.inc(\"error\", { kind: r.error.kind });\n * }\n * ```\n */\nexport const isErr = <T, E>(result: Result<T, E>): result is Err<T, E> => result._tag === \"Err\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each export accepts either shape:\n// data-first: `map(result, fn)`\n// curried: `map(fn)(result)`\n// Arity at the call site selects the overload.\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> =>\n isOk(result) ? ok(fn(result.value)) : err(result.error);\n\n/**\n * Transform the `Ok` value, passing `Err` through unchanged. Dual-form:\n * call data-first or curried (for use with {@link pipe}).\n *\n * @example\n * ```ts\n * map(ok(2), (n) => n * 3); // Ok 6 — data-first\n * pipe(ok(\"x\"), map((s) => s.length));// Ok 1 — curried\n * ```\n */\nexport function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;\nexport function map<T, U>(fn: (value: T) => U): <E>(result: Result<T, E>) => Result<U, E>;\nexport function map(\n ...args: [Result<unknown, unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => mapImpl(result, fn);\n}\n\nconst mapErrImpl = <T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> =>\n isErr(result) ? err(fn(result.error)) : ok(result.value);\n\n/**\n * Transform the `Err` value, passing `Ok` through unchanged. Useful for\n * unifying heterogeneous failure types into one app-level union.\n *\n * @example\n * ```ts\n * type AppError = { kind: \"http\"; status: number } | { kind: \"parse\" };\n * pipe(\n * fetchSync(url), // Result<Body, { status: number }>\n * mapErr((e): AppError => ({ kind: \"http\", status: e.status })),\n * );\n * ```\n */\nexport function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;\nexport function mapErr<E, F>(fn: (error: E) => F): <T>(result: Result<T, E>) => Result<T, F>;\nexport function mapErr(\n ...args: [Result<unknown, unknown>, (error: unknown) => unknown] | [(error: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapErrImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => mapErrImpl(result, fn);\n}\n\nconst bimapImpl = <T, U, E, F>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): Result<U, F> => (isOk(result) ? ok(onOk(result.value)) : err(onErr(result.error)));\n\n/**\n * Transform both tracks at once — `Ok` via `onOk`, `Err` via `onErr`.\n * Equivalent to `mapErr(onErr)(map(onOk)(result))` but in one pass.\n *\n * @example\n * ```ts\n * bimap(parsed, (cfg) => cfg.name, (e) => ({ kind: \"input\", cause: e }));\n * ```\n */\nexport function bimap<T, U, E, F>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): Result<U, F>;\nexport function bimap<T, U, E, F>(\n onOk: (value: T) => U,\n onErr: (error: E) => F,\n): (result: Result<T, E>) => Result<U, F>;\nexport function bimap(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => unknown, (error: unknown) => unknown]\n | [(value: unknown) => unknown, (error: unknown) => unknown]\n): unknown {\n if (args.length === 3) return bimapImpl(args[0], args[1], args[2]);\n const [onOk, onErr] = args;\n return (result: Result<unknown, unknown>) => bimapImpl(result, onOk, onErr);\n}\n\nconst flatMapImpl = <T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F>,\n): Result<U, E | F> => (isOk(result) ? fn(result.value) : err(result.error));\n\n/**\n * Canonical bind (Fantasy Land `chain`). Chains a Result-returning step,\n * widening the error union to `E | F`. Short-circuits on `Err`.\n *\n * @example\n * ```ts\n * flatMap(parseInput(raw), (data) =>\n * data.id != null ? ok(data) : err({ kind: \"missing_id\" as const }),\n * );\n * // Result<Data, ParseError | { kind: \"missing_id\" }>\n * ```\n */\nexport function flatMap<T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F>,\n): Result<U, E | F>;\nexport function flatMap<T, U, F>(\n fn: (value: T) => Result<U, F>,\n): <E>(result: Result<T, E>) => Result<U, E | F>;\nexport function flatMap(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => Result<unknown, unknown>]\n | [(value: unknown) => Result<unknown, unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => flatMapImpl(result, fn);\n}\n\nconst recoverImpl = <T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => Result<T, F>,\n): Result<T, F> => (isErr(result) ? fn(result.error) : ok(result.value));\n\n/**\n * Error-track bind — runs `fn` only when the result is `Err`, allowing\n * a failed workflow to recover to `Ok` or remap the failure. Mirror of\n * {@link flatMap} on the error channel.\n *\n * @example\n * ```ts\n * recover(networkResult, (e) =>\n * e.kind === \"rate_limit\" ? ok(cachedBody) : err(e),\n * );\n * ```\n */\nexport function recover<T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => Result<T, F>,\n): Result<T, F>;\nexport function recover<T, E, F>(\n fn: (error: E) => Result<T, F>,\n): (result: Result<T, E>) => Result<T, F>;\nexport function recover(\n ...args:\n | [Result<unknown, unknown>, (error: unknown) => Result<unknown, unknown>]\n | [(error: unknown) => Result<unknown, unknown>]\n): unknown {\n if (args.length === 2) return recoverImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => recoverImpl(result, fn);\n}\n\nconst tapImpl = <T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E> => {\n if (isOk(result)) fn(result.value);\n return result;\n};\n\n/**\n * Observe the `Ok` value for side effects (logging, metrics) without\n * changing the carried value. Passes `Err` through untouched.\n *\n * @example\n * ```ts\n * pipe(\n * parseConfig(raw),\n * tap((cfg) => log.info({ msg: \"parsed\", name: cfg.name })),\n * flatMap(validate),\n * );\n * ```\n */\nexport function tap<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;\nexport function tap<T>(fn: (value: T) => void): <E>(result: Result<T, E>) => Result<T, E>;\nexport function tap(\n ...args: [Result<unknown, unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => tapImpl(result, fn);\n}\n\nconst tapErrImpl = <T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> => {\n if (isErr(result)) fn(result.error);\n return result;\n};\n\n/**\n * Observe the `Err` value for side effects (logging, metrics) without\n * changing the carried error. Passes `Ok` through untouched.\n *\n * @example\n * ```ts\n * pipe(\n * loadUser(id),\n * tapErr((e) => metrics.inc(\"user.load.fail\", { kind: e.kind })),\n * );\n * ```\n */\nexport function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;\nexport function tapErr<E>(fn: (error: E) => void): <T>(result: Result<T, E>) => Result<T, E>;\nexport function tapErr(\n ...args: [Result<unknown, unknown>, (error: unknown) => void] | [(error: unknown) => void]\n): unknown {\n if (args.length === 2) return tapErrImpl(args[0], args[1]);\n const fn = args[0];\n return (result: Result<unknown, unknown>) => tapErrImpl(result, fn);\n}\n\nconst matchImpl = <T, E, U>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): U => (isOk(result) ? onOk(result.value) : onErr(result.error));\n\n/**\n * Terminal collapse — fold both tracks into a single value. Dual-form:\n * 3-args data-first, 2-args curried for {@link pipe}. Returns whatever\n * the handlers return.\n *\n * For files that also import `match` from `ts-pattern`, use a namespace\n * import (`import * as R from \"@onrails/result\"` → `R.match`) to dissolve\n * the collision.\n *\n * @example\n * ```ts\n * const html = match(parsed, (cfg) => render(cfg), (e) => renderError(e));\n * ```\n */\nexport function match<T, E, U>(\n result: Result<T, E>,\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): U;\nexport function match<T, E, U>(\n onOk: (value: T) => U,\n onErr: (error: E) => U,\n): (result: Result<T, E>) => U;\nexport function match(\n ...args:\n | [Result<unknown, unknown>, (value: unknown) => unknown, (error: unknown) => unknown]\n | [(value: unknown) => unknown, (error: unknown) => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onOk, onErr] = args;\n return (result: Result<unknown, unknown>) => matchImpl(result, onOk, onErr);\n}\n\n/**\n * Returns the `Ok` value, or `defaultValue` when the result is `Err`.\n *\n * @example\n * ```ts\n * unwrapOr(parsedSetting, \"default-value\");\n * ```\n */\nexport const unwrapOr = <T, E>(result: Result<T, E>, defaultValue: T): T =>\n isOk(result) ? result.value : defaultValue;\n\n/**\n * Test/assert helper — returns the `Ok` value, or **throws the original `Err`\n * value** when called on an `Err`. This is the assertion tier (RFC 0001 §4):\n * intended for `*.spec.ts` / `*.test.ts`, where throwing fails the test loudly.\n * In business logic prefer {@link match} or {@link unwrapOr}; the lint plugins\n * flag `unwrapOk` outside test files.\n *\n * @returns the unwrapped `Ok` value\n * @throws the carried `Err` value when the result is `Err`\n *\n * @example\n * ```ts\n * // in a *.spec.ts\n * expect(unwrapOk(ok(5))).toBe(5);\n * expect(() => unwrapOk(err(error))).toThrow(error);\n * ```\n */\nexport function unwrapOk<T, E>(result: Result<T, E>): T {\n if (isErr(result)) throw result.error;\n return result.value;\n}\n\n/**\n * Test/assert helper — returns the `Err` value, or **throws a `TypeError`**\n * when called on an `Ok`. Mirror of {@link unwrapOk} on the error track and\n * part of the same assertion tier (RFC 0001 §4): intended for `*.spec.ts` /\n * `*.test.ts`. Prefer {@link match} / {@link unwrapOr} in business logic; the\n * lint plugins flag `unwrapErr` outside test files.\n *\n * @returns the unwrapped `Err` value\n * @throws `TypeError` when the result is `Ok`\n *\n * @example\n * ```ts\n * // in a *.spec.ts\n * expect(unwrapErr(err(\"x\"))).toBe(\"x\");\n * expect(() => unwrapErr(ok(5))).toThrow(TypeError);\n * ```\n */\nexport function unwrapErr<T, E>(result: Result<T, E>): E {\n if (isOk(result)) throw new TypeError(\"unwrapErr called on Ok\");\n return result.error;\n}\n\n/**\n * Wraps a throwing sync function, returning a function that produces a\n * {@link Result} instead of throwing. Thrown errors pass through `onThrow` to\n * become a typed `Err`; a normal return becomes `Ok`. The neverthrow analogue\n * is `Result.fromThrowable`.\n *\n * @param fn - the throwing function to wrap\n * @param onThrow - maps a thrown value to the `Err` channel\n * @returns a function with `fn`'s parameters that returns `Result<ReturnType, E>`\n *\n * @example\n * ```ts\n * type ParseError = { kind: \"parse\"; message: string };\n * const parse = trySync(\n * JSON.parse,\n * (e): ParseError => ({ kind: \"parse\", message: String(e) }),\n * );\n * parse(\"{}\"); // Ok({})\n * parse(\"nope\"); // Err({ kind: \"parse\", … })\n * ```\n */\nexport function trySync<A extends readonly unknown[], T, E>(\n fn: (...args: A) => T,\n onThrow: (error: unknown) => E,\n): (...args: A) => Result<T, E>;\nexport function trySync<F extends (...args: never) => unknown, E>(\n fn: F,\n onThrow: (error: unknown) => E,\n): (...args: Parameters<F>) => Result<ReturnType<F>, E>;\nexport function trySync(\n fn: (...args: never) => unknown,\n onThrow: (error: unknown) => unknown,\n): (...args: never) => Result<unknown, unknown> {\n return (...args: never) => {\n try {\n return ok(fn(...args));\n } catch (error) {\n return err(onThrow(error));\n }\n };\n}\n\n/**\n * Variadic value-first pipe — threads `value` through up to nine unary fns,\n * left-to-right. Use {@link pipe} when you already have a starting value;\n * use {@link flow} to define a reusable composed function with no value yet.\n *\n * @example\n * ```ts\n * pipe(\n * parseConfig(raw),\n * map((cfg) => cfg.name),\n * flatMap((name) => (name ? ok(name) : err({ kind: \"empty\" as const }))),\n * tap(log),\n * );\n * ```\n */\nexport function pipe<A>(value: A): A;\nexport function pipe<A, B>(value: A, ab: (a: A) => B): B;\nexport function pipe<A, B, C>(value: A, ab: (a: A) => B, bc: (b: B) => C): C;\nexport function pipe<A, B, C, D>(value: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;\nexport function pipe<A, B, C, D, E>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n): E;\nexport function pipe<A, B, C, D, E, F>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n): F;\nexport function pipe<A, B, C, D, E, F, G>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n fg: (f: F) => G,\n): G;\nexport function pipe<A, B, C, D, E, F, G, H>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n fg: (f: F) => G,\n gh: (g: G) => H,\n): H;\nexport function pipe<A, B, C, D, E, F, G, H, I>(\n value: A,\n ab: (a: A) => B,\n bc: (b: B) => C,\n cd: (c: C) => D,\n de: (d: D) => E,\n ef: (e: E) => F,\n fg: (f: F) => G,\n gh: (g: G) => H,\n hi: (h: H) => I,\n): I;\nexport function pipe(value: unknown, ...fns: ReadonlyArray<(x: unknown) => unknown>): unknown {\n let acc = value;\n for (const fn of fns) {\n acc = fn(acc);\n }\n return acc;\n}\n","/**\n * The core railway type: a tagged union carrying either a success value\n * (`Ok<T>`) or a failure value (`Err<E>`). It is a plain discriminated union\n * on `_tag` — no classes — so it is immutable and tree-shake friendly. Narrow\n * with {@link isOk} / {@link isErr} to read `.value` / `.error`.\n *\n * @typeParam T - the `Ok` value type\n * @typeParam E - the `Err` error type\n *\n * @example\n * ```ts\n * function parse(raw: string): Result<number, \"nan\"> {\n * const n = Number(raw);\n * return Number.isNaN(n) ? err(\"nan\") : ok(n);\n * }\n * ```\n */\nexport type Result<T, E> =\n | { readonly _tag: \"Ok\"; readonly value: T }\n | { readonly _tag: \"Err\"; readonly error: E };\n\n/**\n * The success branch of a {@link Result} — `{ _tag: \"Ok\"; value: T }`.\n * The `E` parameter keeps the type assignable to `Result<T, E>`.\n */\nexport type Ok<T, E = never> = Extract<Result<T, E>, { _tag: \"Ok\" }>;\n\n/**\n * The failure branch of a {@link Result} — `{ _tag: \"Err\"; error: E }`.\n */\nexport type Err<T, E> = Extract<Result<T, E>, { _tag: \"Err\" }>;\n\n/**\n * Error subclass representing an **unexpected** defect — a thrown exception or\n * promise rejection that was not part of the modelled `Err` union. Used as the\n * default mapping when {@link fromAsync} is called without an `onDefect`\n * handler; the original cause is preserved on `.cause`.\n *\n * @example\n * ```ts\n * const defect = new UnexpectedError(\"Unexpected async defect\", caught);\n * defect.cause; // the original thrown value\n * ```\n */\nexport class UnexpectedError extends Error {\n constructor(\n message: string,\n override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"UnexpectedError\";\n }\n}\n","import { err, isErr, map, mapErr, ok } from \"./result.js\";\nimport type { Result } from \"./types.js\";\nimport { UnexpectedError } from \"./types.js\";\n\ntype PromiseFactory<T, E> = () => Promise<Result<T, E>>;\ntype AsyncOk<R> = R extends ResultAsync<infer T, unknown> ? T : never;\ntype AsyncErr<R> = R extends ResultAsync<unknown, infer E> ? E : never;\ntype CombineTupleAsync<R extends readonly ResultAsync<unknown, unknown>[]> = ResultAsync<\n { [K in keyof R]: AsyncOk<R[K]> },\n { [K in keyof R]: AsyncErr<R[K]> }[number]\n>;\n\nconst liftPromiseResult = async <T, E>(\n promise: Promise<Result<T, E>>,\n onDefect: (error: unknown) => E | UnexpectedError,\n): Promise<Result<T, E | UnexpectedError>> => {\n try {\n const result = await promise;\n if (isErr(result)) {\n return result;\n }\n // Auto-flatten one level: Ok<Result<…>> from double-wrapped interop.\n return isResultLike<T, E | UnexpectedError>(result.value) ? result.value : result;\n } catch (error) {\n return err(onDefect(error));\n }\n};\n\n/** Collapses settled results left-to-right, short-circuiting on the first `Err`. */\nconst sequenceSettled = (\n settled: readonly Result<unknown, unknown>[],\n): Result<unknown[], unknown> => {\n const values: unknown[] = [];\n for (const result of settled) {\n if (isErr(result)) {\n return err(result.error);\n }\n values.push(result.value);\n }\n return ok(values);\n};\n\n/**\n * Async railway carrier. Wraps a deferred `Promise<Result<T, E>>` and exposes\n * the same dual-track transforms as the sync {@link Result} — `map`, `flatMap`,\n * `recover`, `tap`, `match`. The public API never surfaces `Promise<Result<…>>`\n * directly: `await` the instance (it is thenable) or call {@link resolve} /\n * {@link match} to settle it.\n *\n * Construct via the static factories ({@link ok}, {@link err}, {@link fromPromise},\n * {@link defer}, …) rather than `new` — the constructor is `protected`.\n *\n * @typeParam T - the `Ok` value type\n * @typeParam E - the `Err` error type\n *\n * @example\n * ```ts\n * const user = ResultAsync.fromPromise(api.getUser(id), toAppError)\n * .map((u) => u.profile)\n * .recover(() => ResultAsync.ok(guestProfile));\n *\n * const r = await user; // Result<Profile, AppError>\n * ```\n */\nexport class ResultAsync<T, E> {\n private promise: Promise<Result<T, E>> | null = null;\n\n protected constructor(protected readonly run: PromiseFactory<T, E>) {}\n\n /**\n * Lifts an already-settled sync {@link Result} into a {@link ResultAsync}.\n *\n * @example\n * ```ts\n * const ra = ResultAsync.fromResult(ok(42)); // ResultAsync<number, never>\n * ```\n */\n static fromResult<T, E>(result: Result<T, E>): ResultAsync<T, E> {\n return new ResultAsync(async () => result);\n }\n\n /**\n * Wraps a `PromiseLike<T>` that may reject. Rejections pass through `onReject`\n * to become a typed `Err`; resolution becomes `Ok<T>`.\n *\n * @param promise - the promise to wrap\n * @param onReject - maps a rejection reason to the `Err` channel\n *\n * @example\n * ```ts\n * const body = ResultAsync.fromPromise(\n * fetch(url).then((r) => r.text()),\n * (e): NetError => ({ kind: \"net\", cause: String(e) }),\n * );\n * ```\n */\n static fromPromise<T, E>(\n promise: PromiseLike<T>,\n onReject: (error: unknown) => E,\n ): ResultAsync<T, E> {\n return new ResultAsync(async () => {\n try {\n return ok(await promise);\n } catch (error) {\n return err(onReject(error));\n }\n });\n }\n\n /**\n * Wraps a `PromiseLike<T>` that is **guaranteed not to reject**, skipping the\n * `onReject` mapper. Use only when rejection is provably impossible.\n *\n * @example\n * ```ts\n * const now = ResultAsync.fromSafePromise(Promise.resolve(Date.now()));\n * ```\n */\n static fromSafePromise<T, E = never>(promise: PromiseLike<T>): ResultAsync<T, E> {\n return new ResultAsync(async () => ok(await promise));\n }\n\n /**\n * Defers work until {@link resolve}. Unlike {@link fromPromise}, the factory\n * does not run until the `ResultAsync` is resolved (e.g. by `combineTuple` /\n * `combineTupleParallel`). The factory runs at most once — `resolve` memoizes.\n *\n * @example\n * ```ts\n * const insert = ResultAsync.defer(() => db.orders.insert(row));\n * // nothing has run yet\n * const r = await insert; // factory runs exactly once here\n * ```\n */\n static defer<T, E>(fn: () => Promise<Result<T, E>>): ResultAsync<T, E> {\n return new ResultAsync(fn);\n }\n\n /**\n * Lifts a value into an `Ok` async result.\n *\n * @example\n * ```ts\n * const r = ResultAsync.ok(42); // ResultAsync<number, never>\n * ```\n */\n static ok<T>(value: T): ResultAsync<T, never>;\n static ok<T, E>(value: T): ResultAsync<T, E>;\n static ok<T, E = never>(value: T): ResultAsync<T, E> {\n return new ResultAsync(async () => ok(value));\n }\n\n /**\n * Lifts an error into an `Err` async result.\n *\n * @example\n * ```ts\n * const r = ResultAsync.err({ kind: \"not_found\" as const });\n * ```\n */\n static err<T = never, E = unknown>(error: E): ResultAsync<T, E> {\n return new ResultAsync(async () => err(error));\n }\n\n /**\n * Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a\n * {@link ResultAsync}, auto-flattening one level of double-wrapping. A thrown\n * defect is routed through `onDefect`, defaulting to {@link UnexpectedError}.\n *\n * @param promise - a promise that already yields a `Result`\n * @param onDefect - maps an unexpected throw to the `Err` channel\n * @see {@link fromAsync} from `@onrails/result/interop`\n */\n static fromResultPromise<T, E>(\n promise: Promise<Result<T, E>>,\n onDefect?: (error: unknown) => E | UnexpectedError,\n ): ResultAsync<T, E | UnexpectedError> {\n const mapDefect =\n onDefect ?? ((error: unknown) => new UnexpectedError(\"Unexpected async defect\", error));\n return new ResultAsync(() => liftPromiseResult(promise, mapDefect));\n }\n\n /**\n * Combines a homogeneous array of async results into one. Resolves\n * **sequentially** in input order, short-circuiting on the first `Err`.\n * For heterogeneous tuples that preserve per-index types, use\n * {@link combineTuple}; for wall-clock overlap, {@link combineTupleParallel}.\n *\n * @example\n * ```ts\n * const all = ResultAsync.combine([loadA(), loadB(), loadC()]);\n * // ResultAsync<Item[], LoadError>\n * ```\n */\n static combine<T, E>(results: readonly ResultAsync<T, E>[]): ResultAsync<T[], E> {\n return new ResultAsync(async () => {\n const values: T[] = [];\n for (const ra of results) {\n const result = await ra.resolve();\n if (isErr(result)) {\n return err(result.error);\n }\n values.push(result.value);\n }\n return ok(values);\n });\n }\n\n /**\n * Heterogeneous async tuple combine — resolves branches **sequentially**\n * (left-to-right), returning the first `Err` in input order. Preserves each\n * branch's `Ok` type by position, so the result destructures type-safely.\n * This is the canonical sequential async combine (replaces the former\n * `sequenceTupleAsync`).\n *\n * @example\n * ```ts\n * const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()] as const);\n * // ResultAsync<readonly [Cfg, Catalog], CfgError | CatalogError>\n * const r = await combined;\n * if (isOk(r)) {\n * const [cfg, catalog] = r.value; // typed per position\n * }\n * ```\n */\n static combineTuple<const R extends readonly ResultAsync<unknown, unknown>[]>(\n results: R,\n ): CombineTupleAsync<R> {\n // Runtime identical to combine; the cast restores per-index tuple types.\n return ResultAsync.combine(\n results as readonly ResultAsync<unknown, unknown>[],\n ) as CombineTupleAsync<R>;\n }\n\n /**\n * Like {@link combineTuple}, but starts every branch before awaiting (wall-clock\n * parallel for independent IO). On failure, returns the first `Err` in input order.\n *\n * @example\n * ```ts\n * // independent IO — overlap them\n * const combined = ResultAsync.combineTupleParallel([\n * loadProfile(id),\n * loadMetrics(id),\n * ] as const);\n * ```\n */\n static combineTupleParallel<const R extends readonly ResultAsync<unknown, unknown>[]>(\n results: R,\n ): CombineTupleAsync<R> {\n // Cast restores per-index tuple types over the untyped sequence core.\n return new ResultAsync(async () =>\n sequenceSettled(await Promise.all(results.map((ra) => ra.resolve()))),\n ) as CombineTupleAsync<R>;\n }\n\n /**\n * Transforms the `Ok` value, passing `Err` through unchanged.\n *\n * @example\n * ```ts\n * ResultAsync.ok(2).map((n) => n * 3); // ResultAsync<number> → Ok 6\n * ```\n */\n map<U>(fn: (value: T) => U): ResultAsync<U, E> {\n return new ResultAsync(async () => map(await this.resolve(), fn));\n }\n\n /**\n * Transforms the `Err` value, passing `Ok` through unchanged — useful for\n * unifying heterogeneous failures into one app-level union.\n *\n * @example\n * ```ts\n * load(id).mapErr((e): AppError => ({ kind: \"load\", cause: e }));\n * ```\n */\n mapErr<F>(fn: (error: E) => F): ResultAsync<T, F> {\n return new ResultAsync(async () => mapErr(await this.resolve(), fn));\n }\n\n /**\n * Canonical bind — chains a step that itself returns a `ResultAsync` or sync\n * `Result`, short-circuiting on `Err`. Error types accumulate (`E | F`).\n *\n * @example\n * ```ts\n * authenticate(req)\n * .flatMap((user) => loadProfile(user.id)) // ResultAsync\n * .flatMap((p) => validate(p)); // sync Result also accepted\n * ```\n */\n flatMap<U, F = E>(\n fn: (value: T) => ResultAsync<U, F> | Result<U, F> | { inner: Result<U, F> },\n ): ResultAsync<U, E | F> {\n return new ResultAsync<U, E | F>(async () => {\n const first = await this.resolve();\n if (isErr(first)) {\n return first;\n }\n const next = fn(first.value);\n if (next instanceof ResultAsync) {\n return next.resolve();\n }\n if (isResultLike<U, F>(next)) {\n return next;\n }\n return isCompatLike<U, F>(next) ? next.inner : next;\n });\n }\n\n /**\n * neverthrow-compat alias of {@link flatMap}. Kept as the documented compat\n * tier; prefer `flatMap` in new code.\n *\n * @example\n * ```ts\n * authenticate(req).andThen((user) => loadProfile(user.id));\n * ```\n */\n andThen<U, F = E>(\n fn: (value: T) => ResultAsync<U, F> | Result<U, F> | { inner: Result<U, F> },\n ): ResultAsync<U, E | F> {\n return this.flatMap(fn);\n }\n\n /**\n * Error-channel bind — runs `fn` only on `Err`, swapping in a recovery\n * `ResultAsync` or sync `Result`. `Ok` passes through. The mirror of\n * {@link flatMap} on the error track.\n *\n * @example\n * ```ts\n * loadFromCache(id).recover(() => loadFromOrigin(id));\n * ```\n */\n recover<F>(fn: (error: E) => ResultAsync<T, F> | Result<T, F>): ResultAsync<T, F> {\n return new ResultAsync<T, F>(async () => {\n const first = await this.resolve();\n if (!isErr(first)) {\n return first;\n }\n const next = fn(first.error);\n return next instanceof ResultAsync ? next.resolve() : next;\n });\n }\n\n /**\n * neverthrow-compat alias of {@link recover}. Kept as the documented compat\n * tier; prefer `recover` in new code.\n *\n * @example\n * ```ts\n * loadFromCache(id).orElse(() => loadFromOrigin(id));\n * ```\n */\n orElse<F>(fn: (error: E) => ResultAsync<T, F> | Result<T, F>): ResultAsync<T, F> {\n return this.recover(fn);\n }\n\n /**\n * Runs a side effect on the `Ok` value and passes the result through\n * unchanged; a no-op on `Err`. Mirrors {@link tapErr}.\n *\n * @example\n * ```ts\n * saveUser(u).tap((saved) => analytics.track(\"user_saved\", saved.id));\n * ```\n */\n tap(fn: (value: T) => void): ResultAsync<T, E> {\n return new ResultAsync(async () => {\n const result = await this.resolve();\n if (!isErr(result)) {\n fn(result.value);\n }\n return result;\n });\n }\n\n /**\n * Runs a side effect on the `Err` value and passes the result through\n * unchanged; a no-op on `Ok`. The error-track mirror of {@link tap}.\n *\n * @example\n * ```ts\n * saveUser(u).tapErr((e) => logger.warn(\"save failed\", e));\n * ```\n */\n tapErr(fn: (error: E) => void): ResultAsync<T, E> {\n return new ResultAsync(async () => {\n const result = await this.resolve();\n if (isErr(result)) {\n fn(result.error);\n }\n return result;\n });\n }\n\n /**\n * Settles to the `Ok` value, or `defaultValue` if `Err`. Terminal — returns a\n * plain `Promise`, not a `ResultAsync`.\n *\n * @example\n * ```ts\n * const profile = await loadProfile(id).unwrapOr(guestProfile);\n * ```\n */\n unwrapOr<U>(defaultValue: U): Promise<T | U> {\n return this.resolve().then((result) => (isErr(result) ? defaultValue : result.value));\n }\n\n /**\n * Terminal collapse — folds both tracks into a single awaited value. Returns\n * a plain `Promise`, settling the carrier exactly once.\n *\n * @param onOk - handles the `Ok` value\n * @param onErr - handles the `Err` value\n *\n * @example\n * ```ts\n * const status = await save(row).match(\n * () => 200,\n * (e) => (e.kind === \"conflict\" ? 409 : 500),\n * );\n * ```\n */\n match<U1, U2 = U1>(onOk: (value: T) => U1, onErr: (error: E) => U2): Promise<U1 | U2> {\n return this.resolve().then((result) =>\n isErr(result) ? onErr(result.error) : onOk(result.value),\n );\n }\n\n /**\n * Settles the carrier to a bare sync {@link Result}, memoizing so the\n * underlying factory runs at most once. Prefer `await ra` (the thenable) or\n * {@link match} in app code; use `resolve` when you need the tagged union back.\n *\n * @example\n * ```ts\n * const r = await load(id).resolve(); // Result<Data, LoadError>\n * if (isOk(r)) use(r.value);\n * ```\n */\n resolve(): Promise<Result<T, E>> {\n if (!this.promise) {\n this.promise = this.run();\n }\n return this.promise;\n }\n\n /**\n * Thenable shim — `await ra` resolves to a bare tagged-union `Result<T, E>`.\n * Narrow with `isOk(r)` / `isErr(r)` to read `.value` / `.error`.\n */\n // biome-ignore lint/suspicious/noThenProperty: makes ResultAsync awaitable\n then<R1 = Result<T, E>, R2 = never>(\n onfulfilled?: ((value: Result<T, E>) => R1 | PromiseLike<R1>) | undefined | null,\n onrejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | undefined | null,\n ): Promise<R1 | R2> {\n return this.resolve().then(\n // Safe: without onfulfilled, R1 stays at its Result<T, E> default.\n (r) => (onfulfilled ? onfulfilled(r) : (r as unknown as R1)),\n onrejected ?? undefined,\n );\n }\n}\n\nfunction isResultLike<U, F>(v: unknown): v is Result<U, F> {\n return (\n typeof v === \"object\" &&\n v !== null &&\n \"_tag\" in v &&\n ((v as { _tag: unknown })._tag === \"Ok\" || (v as { _tag: unknown })._tag === \"Err\")\n );\n}\n\nfunction isCompatLike<U, F>(v: unknown): v is { inner: Result<U, F> } {\n return (\n typeof v === \"object\" &&\n v !== null &&\n \"inner\" in v &&\n isResultLike((v as { inner: unknown }).inner)\n );\n}\n\n/**\n * The free-function lift helpers (`okAsync`, `errAsync`, `fromPromise`,\n * `fromSafePromise`, `parallelTupleAsync`, `tryAsync`) live in `./async-lift.ts`\n * and are re-exported from the package index.\n */\n","import { ResultAsync } from \"./async.js\";\nimport type { Result, UnexpectedError } from \"./types.js\";\n\n/**\n * Extracts the `Ok` value type from a {@link Result} or {@link ResultAsync},\n * resolving to `never` for any other type.\n *\n * @example\n * ```ts\n * type T = InferOk<Result<number, string>>; // number\n * type U = InferOk<ResultAsync<User, AppError>>; // User\n * ```\n */\nexport type InferOk<R> = R extends { _tag: \"Ok\"; readonly value: infer T }\n ? T\n : R extends ResultAsync<infer T, unknown>\n ? T\n : never;\n\n/**\n * Extracts the `Err` error type from a {@link Result} or {@link ResultAsync},\n * resolving to `never` for any other type. Mirror of {@link InferOk}.\n *\n * @example\n * ```ts\n * type E = InferErr<Result<number, string>>; // string\n * type F = InferErr<ResultAsync<User, AppError>>; // AppError\n * ```\n */\nexport type InferErr<R> = R extends { _tag: \"Err\"; readonly error: infer E }\n ? E\n : R extends ResultAsync<unknown, infer E>\n ? E\n : never;\n\ntype AnyResult = Result<unknown, unknown>;\n\n/**\n * Lifts an already-settled sync {@link Result} into a {@link ResultAsync}, so\n * it can be chained alongside async steps in a railway.\n *\n * @example\n * ```ts\n * const ra = fromResult(ok(1)); // ResultAsync<number, never>\n * await fromResult(err(error)).resolve(); // Err(error)\n * ```\n */\nexport const fromResult = <T, E>(result: Result<T, E>): ResultAsync<T, E> =>\n ResultAsync.fromResult(result);\n\n/**\n * Bind a sync {@link Result} into an async step without widening defects.\n * Dual-form: data-first for one-shots, data-last (curried) for `pipe`/`flow`.\n *\n * @example\n * ```ts\n * asyncAfter(result, (u) => tryAsync(db.insert(u), toErr)); // data-first\n * asyncAfter((u) => tryAsync(db.insert(u), toErr)); // data-last\n * ```\n */\nexport function asyncAfter<T, U, E, F>(\n result: Result<T, E>,\n fn: (value: T) => ResultAsync<U, F>,\n): ResultAsync<U, E | F>;\nexport function asyncAfter<T, U, F>(\n fn: (value: T) => ResultAsync<U, F>,\n): <E>(result: Result<T, E>) => ResultAsync<U, E | F>;\nexport function asyncAfter<T, U, E, F>(\n resultOrFn: Result<T, E> | ((value: T) => ResultAsync<U, F>),\n fn?: (value: T) => ResultAsync<U, F>,\n): ResultAsync<U, E | F> | ((result: Result<T, E>) => ResultAsync<U, E | F>) {\n if (fn === undefined) {\n const f = resultOrFn as (value: T) => ResultAsync<U, F>;\n return (result: Result<T, E>): ResultAsync<U, E | F> => fromResult(result).flatMap(f);\n }\n return fromResult(resultOrFn as Result<T, E>).flatMap(fn);\n}\n\n/**\n * Lifts a `(...args) => Promise<Result<T, E>>` function (typical of interop or\n * boundary code) into one returning `(...args) => ResultAsync<T, E>`. Expected\n * `Err`s pass through; an unexpected promise rejection (a defect) is routed via\n * `onDefect`, defaulting to {@link UnexpectedError} and widening the error union.\n *\n * @param fn - a function returning a promise that already yields a `Result`\n * @param onDefect - maps an unexpected rejection to the `Err` channel\n *\n * @example\n * ```ts\n * const loadUser = fromAsync(\n * (id: string): Promise<Result<User, NotFound>> => api.getUser(id),\n * );\n * const ra = loadUser(\"u1\"); // ResultAsync<User, NotFound | UnexpectedError>\n * ```\n */\nexport const fromAsync =\n <A extends readonly unknown[], R extends AnyResult>(\n fn: (...args: A) => Promise<R>,\n onDefect?: (error: unknown) => InferErr<R> | UnexpectedError,\n ): ((...args: A) => ResultAsync<InferOk<R>, InferErr<R> | UnexpectedError>) =>\n (...args: A) =>\n ResultAsync.fromResultPromise(fn(...args), onDefect) as ResultAsync<\n InferOk<R>,\n InferErr<R> | UnexpectedError\n >;\n"]}
@@ -1,53 +0,0 @@
1
- 'use strict';
2
-
3
- // src/result.ts
4
- var ok = (value) => ({
5
- _tag: "Ok",
6
- value
7
- });
8
- var err = (error) => ({
9
- _tag: "Err",
10
- error
11
- });
12
- var isErr = (result) => result._tag === "Err";
13
-
14
- // src/validation.ts
15
- var validateAll = (results, combineErrors) => {
16
- const values = [];
17
- let accumulated;
18
- for (const result of results) {
19
- if (isErr(result)) {
20
- accumulated = accumulated === void 0 ? result.error : combineErrors(accumulated, result.error);
21
- } else {
22
- values.push(result.value);
23
- }
24
- }
25
- return accumulated === void 0 ? ok(values) : err(accumulated);
26
- };
27
- var validateTuple = (results, combineErrors) => (
28
- // Runtime identical to validateAll; the cast restores per-index tuple types.
29
- validateAll(results, combineErrors)
30
- );
31
- var validateAllArray = (results) => {
32
- const values = [];
33
- const errors = [];
34
- for (const result of results) {
35
- if (isErr(result)) {
36
- errors.push(result.error);
37
- } else {
38
- values.push(result.value);
39
- }
40
- }
41
- return errors.length === 0 ? ok(values) : err(errors);
42
- };
43
- var validateTupleArray = (results) => (
44
- // Runtime identical to validateAllArray; the cast restores per-index tuple types.
45
- validateAllArray(results)
46
- );
47
-
48
- exports.validateAll = validateAll;
49
- exports.validateAllArray = validateAllArray;
50
- exports.validateTuple = validateTuple;
51
- exports.validateTupleArray = validateTupleArray;
52
- //# sourceMappingURL=validation.cjs.map
53
- //# sourceMappingURL=validation.cjs.map