@pencroff-lab/kore 0.1.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 (51) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cjs/index.d.ts +3 -0
  3. package/dist/cjs/index.d.ts.map +1 -0
  4. package/dist/cjs/index.js +19 -0
  5. package/dist/cjs/index.js.map +1 -0
  6. package/dist/cjs/package.json +3 -0
  7. package/dist/cjs/src/types/err.d.ts +1116 -0
  8. package/dist/cjs/src/types/err.d.ts.map +1 -0
  9. package/dist/cjs/src/types/err.js +1324 -0
  10. package/dist/cjs/src/types/err.js.map +1 -0
  11. package/dist/cjs/src/types/index.d.ts +3 -0
  12. package/dist/cjs/src/types/index.d.ts.map +1 -0
  13. package/dist/cjs/src/types/index.js +19 -0
  14. package/dist/cjs/src/types/index.js.map +1 -0
  15. package/dist/cjs/src/types/outcome.d.ts +1002 -0
  16. package/dist/cjs/src/types/outcome.d.ts.map +1 -0
  17. package/dist/cjs/src/types/outcome.js +958 -0
  18. package/dist/cjs/src/types/outcome.js.map +1 -0
  19. package/dist/cjs/src/utils/format_dt.d.ts +9 -0
  20. package/dist/cjs/src/utils/format_dt.d.ts.map +1 -0
  21. package/dist/cjs/src/utils/format_dt.js +29 -0
  22. package/dist/cjs/src/utils/format_dt.js.map +1 -0
  23. package/dist/cjs/src/utils/index.d.ts +2 -0
  24. package/dist/cjs/src/utils/index.d.ts.map +1 -0
  25. package/dist/cjs/src/utils/index.js +18 -0
  26. package/dist/cjs/src/utils/index.js.map +1 -0
  27. package/dist/esm/index.d.ts +3 -0
  28. package/dist/esm/index.d.ts.map +1 -0
  29. package/dist/esm/index.js +3 -0
  30. package/dist/esm/index.js.map +1 -0
  31. package/dist/esm/src/types/err.d.ts +1116 -0
  32. package/dist/esm/src/types/err.d.ts.map +1 -0
  33. package/dist/esm/src/types/err.js +1320 -0
  34. package/dist/esm/src/types/err.js.map +1 -0
  35. package/dist/esm/src/types/index.d.ts +3 -0
  36. package/dist/esm/src/types/index.d.ts.map +1 -0
  37. package/dist/esm/src/types/index.js +3 -0
  38. package/dist/esm/src/types/index.js.map +1 -0
  39. package/dist/esm/src/types/outcome.d.ts +1002 -0
  40. package/dist/esm/src/types/outcome.d.ts.map +1 -0
  41. package/dist/esm/src/types/outcome.js +954 -0
  42. package/dist/esm/src/types/outcome.js.map +1 -0
  43. package/dist/esm/src/utils/format_dt.d.ts +9 -0
  44. package/dist/esm/src/utils/format_dt.d.ts.map +1 -0
  45. package/dist/esm/src/utils/format_dt.js +26 -0
  46. package/dist/esm/src/utils/format_dt.js.map +1 -0
  47. package/dist/esm/src/utils/index.d.ts +2 -0
  48. package/dist/esm/src/utils/index.d.ts.map +1 -0
  49. package/dist/esm/src/utils/index.js +2 -0
  50. package/dist/esm/src/utils/index.js.map +1 -0
  51. package/package.json +56 -0
@@ -0,0 +1,1002 @@
1
+ /**
2
+ * @fileoverview
3
+ * Monadic container for handling success and error states using tuple-first API design.
4
+ *
5
+ * This module provides the `Outcome<T>` class and related types for implementing
6
+ * type-safe error handling without exceptions. All operations favor immutability.
7
+ *
8
+ * @example Basic usage
9
+ * ```typescript
10
+ * import { Outcome } from './outcome';
11
+ *
12
+ * const [val, err] = Outcome.from(() => [42, null]).toTuple();
13
+ * ```
14
+ *
15
+ * @example Migration from throwing functions
16
+ * ```typescript
17
+ * // Before (throwing):
18
+ * function getUser(id: string): User {
19
+ * const user = db.find(id);
20
+ * if (!user) throw new Error("Not found");
21
+ * return user;
22
+ * }
23
+ * try {
24
+ * const user = getUser("123");
25
+ * console.log(user.name);
26
+ * } catch (e) {
27
+ * console.error(e.message);
28
+ * }
29
+ *
30
+ * // After (Outcome):
31
+ * function getUser(id: string): Outcome<User> {
32
+ * return Outcome.from(() => {
33
+ * const user = db.find(id);
34
+ * if (!user) return Err.from("Not found", "NOT_FOUND");
35
+ * return [user, null];
36
+ * });
37
+ * }
38
+ * const [user, err] = getUser("123").toTuple();
39
+ * if (err) {
40
+ * console.error(err.message);
41
+ * return;
42
+ * }
43
+ * console.log(user.name);
44
+ * ```
45
+ */
46
+ import { Err, type ErrCode, type ErrOptions } from "./err";
47
+ /**
48
+ * Direct return types for errors or void success.
49
+ * - `null`: void success (function completed, no value to return)
50
+ * - `Err`: error (shorthand for `[null, Err]`)
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * function saveConfig(config: Config): NullErr {
55
+ * if (!config.valid) return Err.from('Invalid config');
56
+ * fs.writeFileSync('config.json', JSON.stringify(config));
57
+ * return null; // void success
58
+ * }
59
+ * ```
60
+ */
61
+ export type NullErr = null | Err;
62
+ /**
63
+ * Tuple-based result with positional semantics.
64
+ * - `[T, null]`: success with value
65
+ * - `[null, Err]`: error
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * function divide(a: number, b: number): ResultTuple<number> {
70
+ * if (b === 0) return [null, Err.from('Division by zero')];
71
+ * return [a / b, null];
72
+ * }
73
+ *
74
+ * const [result, err] = divide(10, 2);
75
+ * if (err) console.error(err.message);
76
+ * else console.log(result); // 5
77
+ * ```
78
+ */
79
+ export type ResultTuple<T> = [T, null] | [null, Err];
80
+ /**
81
+ * Combined callback return type for `Outcome.from()` and `Outcome.fromAsync()`.
82
+ * Supports all patterns:
83
+ * - `[T, null]`: success with value (tuple)
84
+ * - `[null, Err]`: error (tuple)
85
+ * - `null`: void success
86
+ * - `Err`: error (shorthand)
87
+ *
88
+ * Discrimination order: `Err.isErr()` → `=== null` → destructure tuple
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * Outcome.from(() => {
93
+ * if (badInput) return Err.from('Bad input'); // Err shorthand
94
+ * if (noResult) return null; // void success
95
+ * if (hasError) return [null, Err.from('Error')]; // tuple error
96
+ * return [value, null]; // tuple success
97
+ * });
98
+ * ```
99
+ */
100
+ export type CallbackReturn<T> = ResultTuple<T> | NullErr;
101
+ /**
102
+ * Synchronous pipe function type.
103
+ * Receives a ResultTuple and returns a CallbackReturn.
104
+ *
105
+ * @typeParam In - Input value type
106
+ * @typeParam Out - Output value type
107
+ */
108
+ export type PipeFn<In, Out> = (tuple: ResultTuple<In>) => CallbackReturn<Out>;
109
+ /**
110
+ * Asynchronous pipe function type.
111
+ * Receives a ResultTuple and returns a Promise of CallbackReturn.
112
+ *
113
+ * @typeParam In - Input value type
114
+ * @typeParam Out - Output value type
115
+ */
116
+ export type PipeFnAsync<In, Out> = (tuple: ResultTuple<In>) => Promise<CallbackReturn<Out>>;
117
+ /**
118
+ * A monadic container for handling success and error states.
119
+ *
120
+ * `Outcome<T>` provides a type-safe way to handle operations that can fail,
121
+ * using tuples as the primary interface. All instances are immutable.
122
+ *
123
+ * ## Core Patterns
124
+ *
125
+ * - **Construction**: Use static methods `ok()`, `err()`, `from()`, `fromAsync()`
126
+ * - **Inspection**: Use `isOk`, `isErr`, `value`, `error` properties
127
+ * - **Transformation**: Use `map()`, `mapErr()` for chained operations
128
+ * - **Extraction**: Use `toTuple()` for final value extraction
129
+ *
130
+ * @example Basic usage
131
+ * ```typescript
132
+ * const outcome = Outcome.from(() => {
133
+ * if (Math.random() > 0.5) return [42, null];
134
+ * return Err.from('Bad luck');
135
+ * });
136
+ *
137
+ * const [value, err] = outcome.toTuple();
138
+ * if (err) {
139
+ * console.error('Failed:', err.message);
140
+ * } else {
141
+ * console.log('Success:', value);
142
+ * }
143
+ * ```
144
+ *
145
+ * @example Chaining transformations
146
+ * ```typescript
147
+ * const result = Outcome.ok(5)
148
+ * .map(n => [n * 2, null])
149
+ * .map(n => [n.toString(), null])
150
+ * .toTuple();
151
+ * // result: ['10', null]
152
+ * ```
153
+ *
154
+ * @typeParam T - The type of the success value
155
+ */
156
+ export declare class Outcome<T> {
157
+ /**
158
+ * Discriminator property for type narrowing.
159
+ * `true` for success outcomes, `false` for error outcomes.
160
+ */
161
+ readonly isOk: boolean;
162
+ /** Internal tuple storage */
163
+ private readonly _tuple;
164
+ /**
165
+ * Private constructor - use static factory methods.
166
+ * @internal
167
+ */
168
+ private constructor();
169
+ /**
170
+ * Process a CallbackReturn value into an Outcome.
171
+ * Handles discrimination: Err → null (void) → tuple destructure.
172
+ * @internal
173
+ */
174
+ private static _processCallbackReturn;
175
+ /**
176
+ * Create a success Outcome with the given value.
177
+ *
178
+ * @param value - The success value
179
+ * @returns Outcome containing the success value
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const outcome = Outcome.ok(42);
184
+ * console.log(outcome.isOk); // true
185
+ * console.log(outcome.value); // 42
186
+ *
187
+ * const [val, err] = outcome.toTuple();
188
+ * // val: 42, err: null
189
+ * ```
190
+ */
191
+ static ok<T>(value: T): Outcome<T>;
192
+ /**
193
+ * Create an error Outcome from an existing Err.
194
+ *
195
+ * @param error - The Err instance
196
+ * @returns Outcome in error state
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const err = Err.from('Something failed');
201
+ * const outcome = Outcome.err(err);
202
+ * ```
203
+ */
204
+ static err(error: Err): Outcome<never>;
205
+ /**
206
+ * Create an error Outcome from a message with optional code.
207
+ *
208
+ * @param message - Error message
209
+ * @param code - Optional error code
210
+ * @returns Outcome in error state
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * const outcome = Outcome.err('Not found', 'NOT_FOUND');
215
+ * const [, err] = outcome.toTuple();
216
+ * console.log(err?.code); // 'NOT_FOUND'
217
+ * ```
218
+ */
219
+ static err(message: string, code?: ErrCode): Outcome<never>;
220
+ /**
221
+ * Create an error Outcome from a message with options.
222
+ *
223
+ * @param message - Error message
224
+ * @param options - Error options (code, metadata)
225
+ * @returns Outcome in error state
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * const outcome = Outcome.err('Timeout', {
230
+ * code: 'TIMEOUT',
231
+ * metadata: { durationMs: 5000 }
232
+ * });
233
+ * ```
234
+ */
235
+ static err(message: string, options: ErrOptions): Outcome<never>;
236
+ /**
237
+ * Create an error Outcome by wrapping another error.
238
+ *
239
+ * @param message - Context message
240
+ * @param error - Original error to wrap
241
+ * @param options - Optional additional options
242
+ * @returns Outcome in error state with wrapped cause
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * try {
247
+ * JSON.parse(invalid);
248
+ * } catch (e) {
249
+ * return Outcome.err('Parse failed', e as Error, { code: 'PARSE_ERROR' });
250
+ * }
251
+ * ```
252
+ */
253
+ static err(message: string, error: Err | Error, options?: ErrOptions): Outcome<never>;
254
+ /**
255
+ * Create a success Outcome with null value (void success).
256
+ *
257
+ * Use for operations that succeed but have no meaningful return value.
258
+ *
259
+ * @returns Outcome<null> representing void success
260
+ *
261
+ * @remarks
262
+ * Returns `Outcome<null>` (not `Outcome<undefined>` or `Outcome<void>`).
263
+ * This is intentional for consistency with the tuple pattern where `null`
264
+ * indicates absence of error in `[value, null]`.
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * function logMessage(msg: string): Outcome<null> {
269
+ * console.log(msg);
270
+ * return Outcome.unit();
271
+ * }
272
+ *
273
+ * const outcome = logMessage('Hello');
274
+ * console.log(outcome.isOk); // true
275
+ * console.log(outcome.value); // null
276
+ * ```
277
+ */
278
+ static unit(): Outcome<null>;
279
+ /**
280
+ * Create an Outcome from a callback that returns `CallbackReturn<T>`.
281
+ *
282
+ * The callback can return:
283
+ * - `[value, null]` - success with value
284
+ * - `[null, Err]` - error as tuple
285
+ * - `null` - void success
286
+ * - `Err` - error directly
287
+ *
288
+ * If the callback throws, the exception is caught and wrapped in an error Outcome.
289
+ *
290
+ * @param fn - Callback returning CallbackReturn<T>
291
+ * @returns Outcome<T>
292
+ *
293
+ * @see {@link fromAsync} for the async version
294
+ *
295
+ * @example Success with value
296
+ * ```typescript
297
+ * const outcome = Outcome.from(() => {
298
+ * return [42, null];
299
+ * });
300
+ * console.log(outcome.value); // 42
301
+ * ```
302
+ *
303
+ * @example Error shorthand
304
+ * ```typescript
305
+ * const outcome = Outcome.from(() => {
306
+ * if (invalid) return Err.from('Invalid input');
307
+ * return [result, null];
308
+ * });
309
+ * ```
310
+ *
311
+ * @example Catching throws from external libraries
312
+ * ```typescript
313
+ * const outcome = Outcome.from(() => {
314
+ * const data = JSON.parse(untrustedInput); // may throw
315
+ * return [data, null];
316
+ * });
317
+ * // If JSON.parse throws, outcome.isErr === true
318
+ * ```
319
+ */
320
+ static from<T>(fn: () => CallbackReturn<T>): Outcome<T>;
321
+ /**
322
+ * Create an Outcome from an async callback that returns `Promise<CallbackReturn<T>>`.
323
+ *
324
+ * Async version of `from()` with identical semantics.
325
+ *
326
+ * @param fn - Async callback returning Promise<CallbackReturn<T>>
327
+ * @returns Promise<Outcome<T>>
328
+ *
329
+ * @see {@link from} for the synchronous version
330
+ *
331
+ * @example Async operation
332
+ * ```typescript
333
+ * const outcome = await Outcome.fromAsync(async () => {
334
+ * const response = await fetch('/api/data');
335
+ * if (!response.ok) {
336
+ * return Err.from('Request failed', { code: 'HTTP_ERROR' });
337
+ * }
338
+ * const data = await response.json();
339
+ * return [data, null];
340
+ * });
341
+ * ```
342
+ *
343
+ * @example With error aggregation
344
+ * ```typescript
345
+ * const outcome = await Outcome.fromAsync(async () => {
346
+ * let errors = Err.aggregate('Batch failed');
347
+ *
348
+ * const [a, errA] = await taskA().toTuple();
349
+ * if (errA) errors = errors.add(errA);
350
+ *
351
+ * const [b, errB] = await taskB().toTuple();
352
+ * if (errB) errors = errors.add(errB);
353
+ *
354
+ * if (errors.count > 0) return errors;
355
+ * return [{ a, b }, null];
356
+ * });
357
+ * ```
358
+ */
359
+ static fromAsync<T>(fn: () => Promise<CallbackReturn<T>>): Promise<Outcome<T>>;
360
+ /**
361
+ * Create an Outcome from an existing ResultTuple.
362
+ *
363
+ * Useful for deserializing Outcomes or converting from external tuple sources.
364
+ *
365
+ * @param tuple - A ResultTuple<T>
366
+ * @returns Outcome<T>
367
+ *
368
+ * @see {@link toTuple} for extracting the tuple from an Outcome
369
+ *
370
+ * @example Deserializing from JSON
371
+ * ```typescript
372
+ * const json = '["hello", null]';
373
+ * const tuple = JSON.parse(json) as ResultTuple<string>;
374
+ * const outcome = Outcome.fromTuple(tuple);
375
+ * console.log(outcome.value); // 'hello'
376
+ * ```
377
+ *
378
+ * @example Round-trip serialization
379
+ * ```typescript
380
+ * const original = Outcome.ok(42);
381
+ * const json = JSON.stringify(original.toJSON());
382
+ * const restored = Outcome.fromTuple(JSON.parse(json));
383
+ * console.log(restored.value); // 42
384
+ * ```
385
+ */
386
+ static fromTuple<T>(tuple: ResultTuple<T>): Outcome<T>;
387
+ /**
388
+ * Create an Outcome from a JSON tuple produced by `toJSON()`.
389
+ *
390
+ * Accepts `[value, null]` for success or `[null, errJSON]` for errors.
391
+ * Errors are rehydrated with `Err.fromJSON()`.
392
+ *
393
+ * @param payload - JSON tuple from `Outcome.toJSON()`
394
+ * @returns Outcome<T>
395
+ *
396
+ * @see {@link toJSON} for serializing an Outcome to JSON
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * const json = JSON.stringify(outcome.toJSON());
401
+ * const restored = Outcome.fromJSON(JSON.parse(json));
402
+ * ```
403
+ */
404
+ static fromJSON<T>(payload: [T, null] | [null, ReturnType<Err["toJSON"]>]): Outcome<T>;
405
+ /**
406
+ * Combines multiple Outcomes, succeeding if all succeed with an array of values.
407
+ * If any Outcome fails, returns an Err containing all failures aggregated via Err.aggregate().
408
+ *
409
+ * This is useful for validation scenarios where you need to collect all errors.
410
+ *
411
+ * For empty arrays, returns `Outcome.ok([])` (vacuous truth).
412
+ *
413
+ * @param outcomes - Array of Outcomes to combine
414
+ * @returns Outcome containing array of all success values, or aggregate error
415
+ *
416
+ * @remarks
417
+ * Time complexity: O(n) where n is the number of outcomes.
418
+ * All outcomes are evaluated (non-short-circuiting) to collect all errors.
419
+ *
420
+ * @example All succeed
421
+ * ```typescript
422
+ * const outcomes = [Outcome.ok(1), Outcome.ok(2), Outcome.ok(3)];
423
+ * const combined = Outcome.all(outcomes);
424
+ * console.log(combined.value); // [1, 2, 3]
425
+ * ```
426
+ *
427
+ * @example One fails
428
+ * ```typescript
429
+ * const outcomes = [
430
+ * Outcome.ok(1),
431
+ * Outcome.err('Failed'),
432
+ * Outcome.ok(3)
433
+ * ];
434
+ * const combined = Outcome.all(outcomes);
435
+ * console.log(combined.isErr); // true
436
+ * console.log(combined.error?.message); // 'Failed'
437
+ * ```
438
+ *
439
+ * @example Many fails
440
+ * ```typescript
441
+ * const mixed = [
442
+ * Outcome.ok(1),
443
+ * Outcome.err("Error A"),
444
+ * Outcome.err("Error B")
445
+ * ];
446
+ * const failed = Outcome.all(mixed);
447
+ * console.log(failed.isErr); // true
448
+ * // Error contains both "Error A" and "Error B"
449
+ * ```
450
+ *
451
+ * @example Empty array
452
+ * ```typescript
453
+ * const combined = Outcome.all([]);
454
+ * console.log(combined.value); // []
455
+ * ```
456
+ */
457
+ static all<T>(outcomes: Outcome<T>[]): Outcome<T[]>;
458
+ /**
459
+ * Return the first successful Outcome from an array.
460
+ *
461
+ * Returns the first success encountered.
462
+ * Returns an aggregate error if ALL outcomes fail.
463
+ *
464
+ * For empty arrays, returns an error (no value to return).
465
+ *
466
+ * @param outcomes - Array of Outcomes to check
467
+ * @returns First successful Outcome, or aggregate of all errors
468
+ *
469
+ * @remarks
470
+ * Time complexity: O(n) worst case, but short-circuits on first success.
471
+ * Best case: O(1) if first outcome is successful.
472
+ *
473
+ * @example First success wins
474
+ * ```typescript
475
+ * const outcomes = [
476
+ * Outcome.err('First failed'),
477
+ * Outcome.ok(42),
478
+ * Outcome.ok(100)
479
+ * ];
480
+ * const result = Outcome.any(outcomes);
481
+ * console.log(result.value); // 42
482
+ * ```
483
+ *
484
+ * @example All fail
485
+ * ```typescript
486
+ * const outcomes = [
487
+ * Outcome.err('Error 1'),
488
+ * Outcome.err('Error 2')
489
+ * ];
490
+ * const result = Outcome.any(outcomes);
491
+ * console.log(result.isErr); // true
492
+ * console.log(result.error?.isAggregate); // true
493
+ * ```
494
+ *
495
+ * @example Empty array
496
+ * ```typescript
497
+ * const result = Outcome.any([]);
498
+ * console.log(result.isErr); // true
499
+ * console.log(result.error?.message); // 'No outcomes provided'
500
+ * ```
501
+ */
502
+ static any<T>(outcomes: Outcome<T>[]): Outcome<T>;
503
+ /**
504
+ * Whether this Outcome is in error state.
505
+ *
506
+ * @example
507
+ * ```typescript
508
+ * const success = Outcome.ok(42);
509
+ * const failure = Outcome.err('Failed');
510
+ *
511
+ * console.log(success.isErr); // false
512
+ * console.log(failure.isErr); // true
513
+ * ```
514
+ */
515
+ get isErr(): boolean;
516
+ /**
517
+ * The success value, or null if in error state.
518
+ *
519
+ * @example
520
+ * ```typescript
521
+ * const success = Outcome.ok(42);
522
+ * const failure = Outcome.err('Failed');
523
+ *
524
+ * console.log(success.value); // 42
525
+ * console.log(failure.value); // null
526
+ * ```
527
+ */
528
+ get value(): T | null;
529
+ /**
530
+ * The error, or null if in success state.
531
+ *
532
+ * @example
533
+ * ```typescript
534
+ * const success = Outcome.ok(42);
535
+ * const failure = Outcome.err('Failed');
536
+ *
537
+ * console.log(success.error); // null
538
+ * console.log(failure.error?.message); // 'Failed'
539
+ * ```
540
+ */
541
+ get error(): Err | null;
542
+ /**
543
+ * Transform the success value using a callback.
544
+ *
545
+ * Only called if this Outcome is successful. Errors pass through unchanged.
546
+ * The callback can return any `CallbackReturn<U>` pattern.
547
+ * If the callback throws, the exception is caught and wrapped.
548
+ *
549
+ * @param fn - Transformation function receiving the success value
550
+ * @returns New Outcome with transformed value or original/new error
551
+ *
552
+ * @see {@link mapAsync} for the async version
553
+ * @see {@link mapErr} for transforming or recovering from errors
554
+ *
555
+ * @example Simple transformation
556
+ * ```typescript
557
+ * const outcome = Outcome.ok(5)
558
+ * .map(n => [n * 2, null])
559
+ * .map(n => [n.toString(), null]);
560
+ *
561
+ * console.log(outcome.value); // '10'
562
+ * ```
563
+ *
564
+ * @example Transformation that can fail
565
+ * ```typescript
566
+ * const outcome = Outcome.ok('{"name":"John"}')
567
+ * .map(json => {
568
+ * try {
569
+ * return [JSON.parse(json), null];
570
+ * } catch {
571
+ * return Err.from('Invalid JSON');
572
+ * }
573
+ * });
574
+ * ```
575
+ *
576
+ * @example Error passes through
577
+ * ```typescript
578
+ * const outcome = Outcome.err('Original error')
579
+ * .map(v => [v * 2, null]); // Never called
580
+ *
581
+ * console.log(outcome.error?.message); // 'Original error'
582
+ * ```
583
+ */
584
+ map<U>(fn: (value: T) => CallbackReturn<U>): Outcome<U>;
585
+ /**
586
+ * Async version of `map()`.
587
+ *
588
+ * @param fn - Async transformation function
589
+ * @returns Promise of new Outcome
590
+ *
591
+ * @see {@link map} for the synchronous version
592
+ *
593
+ * @example
594
+ * ```typescript
595
+ * const outcome = await Outcome.ok(userId)
596
+ * .mapAsync(async id => {
597
+ * const user = await fetchUser(id);
598
+ * return [user, null];
599
+ * });
600
+ * ```
601
+ */
602
+ mapAsync<U>(fn: (value: T) => Promise<CallbackReturn<U>>): Promise<Outcome<U>>;
603
+ /**
604
+ * Transform or recover from an error using a callback.
605
+ *
606
+ * Only called if this Outcome is in error state. Success passes through unchanged.
607
+ * The callback can return any `CallbackReturn<U>` pattern, allowing:
608
+ * - Recovery: return `[value, null]` to convert error to success
609
+ * - Transform: return `Err` or `[null, Err]` to change the error
610
+ *
611
+ * @param fn - Function receiving the error
612
+ * @returns New Outcome with transformed error or recovered value
613
+ *
614
+ * @see {@link mapErrAsync} for the async version
615
+ * @see {@link map} for transforming success values
616
+ *
617
+ * @example Recovery
618
+ * ```typescript
619
+ * const outcome = Outcome.err('Not found')
620
+ * .mapErr(err => {
621
+ * if (err.hasCode('NOT_FOUND')) {
622
+ * return [defaultValue, null]; // recover with default
623
+ * }
624
+ * return err; // pass through other errors
625
+ * });
626
+ * ```
627
+ *
628
+ * @example Error transformation
629
+ * ```typescript
630
+ * const outcome = Outcome.err('Low-level error')
631
+ * .mapErr(err => err.wrap('High-level context'));
632
+ * ```
633
+ *
634
+ * @example Logging and pass-through
635
+ * ```typescript
636
+ * const outcome = Outcome.err('Something failed')
637
+ * .mapErr(err => {
638
+ * console.error('Error occurred:', err.message);
639
+ * return err; // pass through unchanged
640
+ * });
641
+ * ```
642
+ */
643
+ mapErr<U>(fn: (error: Err) => CallbackReturn<U>): Outcome<T | U>;
644
+ /**
645
+ * Async version of `mapErr()`.
646
+ *
647
+ * @param fn - Async function receiving the error
648
+ * @returns Promise of new Outcome
649
+ *
650
+ * @see {@link mapErr} for the synchronous version
651
+ *
652
+ * @example Async recovery with fallback fetch
653
+ * ```typescript
654
+ * const outcome = await Outcome.err('Primary failed')
655
+ * .mapErrAsync(async err => {
656
+ * const fallback = await fetchFromBackup();
657
+ * if (fallback) return [fallback, null];
658
+ * return err.wrap('Backup also failed');
659
+ * });
660
+ * ```
661
+ */
662
+ mapErrAsync<U>(fn: (error: Err) => Promise<CallbackReturn<U>>): Promise<Outcome<T | U>>;
663
+ /**
664
+ * Execute a side effect with access to the full tuple.
665
+ *
666
+ * The callback receives the tuple `[value, error]` regardless of state.
667
+ * Returns `this` unchanged for chaining.
668
+ * If the callback throws, the exception is caught and the Outcome becomes an error.
669
+ *
670
+ * @param fn - Side effect function receiving the tuple
671
+ * @returns This Outcome (for chaining), or error Outcome if callback throws
672
+ *
673
+ * @see {@link effectAsync} for the async version
674
+ *
675
+ * @example Logging
676
+ * ```typescript
677
+ * const outcome = Outcome.ok(42)
678
+ * .effect(([val, err]) => {
679
+ * if (err) console.error('Failed:', err.message);
680
+ * else console.log('Success:', val);
681
+ * })
682
+ * .map(v => [v * 2, null]);
683
+ * ```
684
+ *
685
+ * @example Metrics
686
+ * ```typescript
687
+ * outcome.effect(([val, err]) => {
688
+ * metrics.record({
689
+ * success: !err,
690
+ * value: val,
691
+ * errorCode: err?.code
692
+ * });
693
+ * });
694
+ * ```
695
+ */
696
+ effect(fn: (tuple: ResultTuple<T>) => void): Outcome<T>;
697
+ /**
698
+ * Async version of `effect()`.
699
+ *
700
+ * @param fn - Async side effect function
701
+ * @returns Promise of this Outcome
702
+ *
703
+ * @see {@link effect} for the synchronous version
704
+ *
705
+ * @example Async logging
706
+ * ```typescript
707
+ * const outcome = await Outcome.ok(data)
708
+ * .effectAsync(async ([val, err]) => {
709
+ * await logger.log({ value: val, error: err?.toJSON() });
710
+ * });
711
+ * ```
712
+ */
713
+ effectAsync(fn: (tuple: ResultTuple<T>) => Promise<void>): Promise<Outcome<T>>;
714
+ /**
715
+ * Extract the success value, or use a fallback value on error.
716
+ *
717
+ * This is a terminal operation that exits the Outcome chain.
718
+ * Returns `T` directly, not wrapped in Outcome.
719
+ *
720
+ * @param fallback - The fallback value to use if in error state
721
+ * @returns The success value or the fallback
722
+ * @throws If the outcome is an error and computing fallback throws
723
+ *
724
+ * @see {@link either} for transforming both cases with custom logic
725
+ * @see {@link toTuple} for raw tuple extraction
726
+ *
727
+ * @example Static fallback
728
+ * ```typescript
729
+ * const count = parseNumber(input).defaultTo(0);
730
+ * // Returns parsed number or 0 on error
731
+ * ```
732
+ *
733
+ * @example With objects
734
+ * ```typescript
735
+ * const config = loadConfig().defaultTo({ port: 3000, host: 'localhost' });
736
+ * ```
737
+ */
738
+ defaultTo(fallback: T): T;
739
+ /**
740
+ * Extract the success value, or compute a fallback from the error.
741
+ *
742
+ * This is a terminal operation that exits the Outcome chain.
743
+ * The handler receives the `Err` and can use it to compute the fallback.
744
+ *
745
+ * @param handler - Function to compute fallback from error
746
+ * @returns The success value or computed fallback
747
+ * @throws If the handler throws, the exception propagates to the caller
748
+ *
749
+ * @example Computed fallback
750
+ * ```typescript
751
+ * const name = fetchUser(id).defaultTo(err =>
752
+ * err.hasCode('NOT_FOUND') ? 'Guest' : 'Unknown'
753
+ * );
754
+ * ```
755
+ *
756
+ * @example Logging and fallback
757
+ * ```typescript
758
+ * const data = loadData().defaultTo(err => {
759
+ * console.error('Load failed:', err.message);
760
+ * return cachedData;
761
+ * });
762
+ * ```
763
+ */
764
+ defaultTo(handler: (error: Err) => T): T;
765
+ /**
766
+ * Extract the success value, or use the provided fallback value.
767
+ *
768
+ * When T is a function type, use this overload with `asValue: true`
769
+ * to force treating the fallback as a static value rather than an error handler.
770
+ *
771
+ * @param fallback - The fallback value to use when error
772
+ * @param asValue - Must be `true` to use this overload
773
+ * @returns The success value or the fallback
774
+ *
775
+ * @example Function as a fallback value
776
+ * ```typescript
777
+ * const defaultHandler = () => console.log('default');
778
+ * const handler = getHandler().defaultTo(defaultHandler, true);
779
+ * ```
780
+ */
781
+ defaultTo(fallback: T, asValue: true): T;
782
+ /**
783
+ * Transform the Outcome into a final value by handling both cases.
784
+ *
785
+ * This is a terminal operation that exits the Outcome chain, similar to
786
+ * `toTuple()` but with transformation logic applied.
787
+ *
788
+ * Each handler receives only its relevant type with full type safety:
789
+ * - `onOk` receives `T` (guaranteed non-null value)
790
+ * - `onErr` receives `Err` (guaranteed error)
791
+ *
792
+ * @param onOk - Function to transform success value into final result
793
+ * @param onErr - Function to transform error into final result
794
+ * @returns The transformed value (not wrapped in Outcome)
795
+ * @throws If either callback throws, the exception propagates to the caller
796
+ *
797
+ * @see {@link defaultTo} for simple value extraction with fallback
798
+ * @see {@link toTuple} for raw tuple extraction
799
+ * @see {@link toJSON} for JSON serialization
800
+ *
801
+ * @example Basic transformation
802
+ * ```typescript
803
+ * const message = fetchUser(id).either(
804
+ * user => `Welcome, ${user.name}!`,
805
+ * err => `Error: ${err.message}`
806
+ * );
807
+ * // message is string, not Outcome<string>
808
+ * ```
809
+ *
810
+ * @example HTTP response building
811
+ * ```typescript
812
+ * const response = processOrder(orderId).either(
813
+ * order => ({ status: 200, body: { id: order.id, total: order.total } }),
814
+ * err => ({
815
+ * status: err.hasCode('NOT_FOUND') ? 404 : 500,
816
+ * body: { error: err.message }
817
+ * })
818
+ * );
819
+ * ```
820
+ *
821
+ * @example Default value on error
822
+ * ```typescript
823
+ * const count = parseNumber(input).either(n => n, () => 0);
824
+ * ```
825
+ *
826
+ * @example Type transformation
827
+ * ```typescript
828
+ * const status: 'success' | 'error' = outcomeEntity.either(
829
+ * () => 'success',
830
+ * () => 'error'
831
+ * );
832
+ * ```
833
+ */
834
+ either<U>(onOk: (value: T) => U, onErr: (error: Err) => U): U;
835
+ /**
836
+ * Chain synchronous transformations using tuple-based predicates.
837
+ *
838
+ * Each predicate receives `ResultTuple<T>` and returns `CallbackReturn<U>`.
839
+ * This allows handling both success and error cases at each step,
840
+ * enabling mid-chain recovery or conditional transformations.
841
+ *
842
+ * @see {@link pipeAsync} for async transformations
843
+ * @see {@link map} for simple success-only transformation
844
+ * @see {@link mapErr} for error-only transformation
845
+ *
846
+ * @example Basic pipeline
847
+ * ```typescript
848
+ * const result = Outcome.ok(rawInput).pipe(
849
+ * ([val, err]) => {
850
+ * if (err) return err;
851
+ * return [validate(val), null];
852
+ * },
853
+ * ([val, err]) => {
854
+ * if (err) return err;
855
+ * return [transform(val), null];
856
+ * }
857
+ * );
858
+ * ```
859
+ *
860
+ * @example Mid-chain recovery
861
+ * ```typescript
862
+ * const result = Outcome.ok(input).pipe(
863
+ * ([val, err]) => {
864
+ * if (err) return err;
865
+ * if (!val.isValid) return Err.from('Invalid', 'VALIDATION');
866
+ * return [val, null];
867
+ * },
868
+ * ([val, err]) => {
869
+ * // Recover from validation error
870
+ * if (err?.hasCode('VALIDATION')) {
871
+ * return [DEFAULT_VALUE, null];
872
+ * }
873
+ * if (err) return err;
874
+ * return [val.process(), null];
875
+ * }
876
+ * );
877
+ * ```
878
+ */
879
+ pipe<A>(f1: PipeFn<T, A>): Outcome<A>;
880
+ pipe<A, B>(f1: PipeFn<T, A>, f2: PipeFn<A, B>): Outcome<B>;
881
+ pipe<A, B, C>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>): Outcome<C>;
882
+ pipe<A, B, C, D>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>): Outcome<D>;
883
+ pipe<A, B, C, D, E>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>): Outcome<E>;
884
+ pipe<A, B, C, D, E, F>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>): Outcome<F>;
885
+ pipe<A, B, C, D, E, F, G>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>): Outcome<G>;
886
+ pipe<A, B, C, D, E, F, G, H>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>, f8: PipeFn<G, H>): Outcome<H>;
887
+ pipe<A, B, C, D, E, F, G, H, I>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>, f8: PipeFn<G, H>, f9: PipeFn<H, I>): Outcome<I>;
888
+ pipe<A, B, C, D, E, F, G, H, I, J>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>, f8: PipeFn<G, H>, f9: PipeFn<H, I>, f10: PipeFn<I, J>): Outcome<J>;
889
+ /**
890
+ * Chain asynchronous transformations using tuple-based predicates.
891
+ *
892
+ * Each predicate receives `ResultTuple<T>` and returns `Promise<CallbackReturn<U>>`.
893
+ * Predicates are executed sequentially, each awaiting the previous result.
894
+ *
895
+ * @see {@link pipe} for synchronous transformations
896
+ * @see {@link mapAsync} for simple async success-only transformation
897
+ * @see {@link mapErrAsync} for async error-only transformation
898
+ *
899
+ * @example Async pipeline
900
+ * ```typescript
901
+ * const result = await Outcome.ok(userId).pipeAsync(
902
+ * async ([val, err]) => {
903
+ * if (err) return err;
904
+ * const user = await fetchUser(val);
905
+ * return [user, null];
906
+ * },
907
+ * async ([user, err]) => {
908
+ * if (err) return err;
909
+ * const profile = await fetchProfile(user.profileId);
910
+ * return [{ ...user, profile }, null];
911
+ * }
912
+ * );
913
+ * ```
914
+ *
915
+ * @example Async recovery
916
+ * ```typescript
917
+ * const result = await Outcome.ok(id).pipeAsync(
918
+ * async ([val, err]) => {
919
+ * if (err) return err;
920
+ * return await fetchFromPrimary(val);
921
+ * },
922
+ * async ([val, err]) => {
923
+ * // Fallback to secondary on error
924
+ * if (err) {
925
+ * return await fetchFromSecondary(id);
926
+ * }
927
+ * return [val, null];
928
+ * }
929
+ * );
930
+ * ```
931
+ */
932
+ pipeAsync<A>(f1: PipeFnAsync<T, A>): Promise<Outcome<A>>;
933
+ pipeAsync<A, B>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>): Promise<Outcome<B>>;
934
+ pipeAsync<A, B, C>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>): Promise<Outcome<C>>;
935
+ pipeAsync<A, B, C, D>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>): Promise<Outcome<D>>;
936
+ pipeAsync<A, B, C, D, E>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>): Promise<Outcome<E>>;
937
+ pipeAsync<A, B, C, D, E, F>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>): Promise<Outcome<F>>;
938
+ pipeAsync<A, B, C, D, E, F, G>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>): Promise<Outcome<G>>;
939
+ pipeAsync<A, B, C, D, E, F, G, H>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>, f8: PipeFnAsync<G, H>): Promise<Outcome<H>>;
940
+ pipeAsync<A, B, C, D, E, F, G, H, I>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>, f8: PipeFnAsync<G, H>, f9: PipeFnAsync<H, I>): Promise<Outcome<I>>;
941
+ pipeAsync<A, B, C, D, E, F, G, H, I, J>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>, f8: PipeFnAsync<G, H>, f9: PipeFnAsync<H, I>, f10: PipeFnAsync<I, J>): Promise<Outcome<J>>;
942
+ /**
943
+ * Extract the internal tuple.
944
+ *
945
+ * Primary method for extracting values from an Outcome.
946
+ * Use destructuring for ergonomic access.
947
+ *
948
+ * @returns The internal ResultTuple<T>
949
+ *
950
+ * @see {@link fromTuple} for creating an Outcome from a tuple
951
+ *
952
+ * @example
953
+ * ```typescript
954
+ * const outcome = Outcome.ok(42);
955
+ * const [value, error] = outcome.toTuple();
956
+ *
957
+ * if (error) {
958
+ * console.error('Failed:', error.message);
959
+ * return;
960
+ * }
961
+ * console.log('Value:', value); // 42
962
+ * ```
963
+ */
964
+ toTuple(): ResultTuple<T>;
965
+ /**
966
+ * Convert to JSON-serializable tuple.
967
+ *
968
+ * For success: returns `[value, null]`
969
+ * For error: returns `[null, errJSON]` where errJSON is from `Err.toJSON()`
970
+ *
971
+ * @returns JSON-serializable representation
972
+ *
973
+ * @see {@link fromJSON} for deserializing an Outcome from JSON
974
+ *
975
+ * @example
976
+ * ```typescript
977
+ * const outcome = Outcome.ok({ name: 'John' });
978
+ * const json = JSON.stringify(outcome.toJSON());
979
+ * // '[{"name":"John"},null]'
980
+ *
981
+ * // Deserialize
982
+ * const restored = Outcome.fromJSON(JSON.parse(json));
983
+ * ```
984
+ */
985
+ toJSON(): [T, null] | [null, ReturnType<Err["toJSON"]>];
986
+ /**
987
+ * Convert to a human-readable string.
988
+ *
989
+ * @returns String representation
990
+ *
991
+ * @example
992
+ * ```typescript
993
+ * console.log(Outcome.ok(42).toString());
994
+ * // 'Outcome.ok(42)'
995
+ *
996
+ * console.log(Outcome.err('Failed').toString());
997
+ * // 'Outcome.err([ERROR] Failed)'
998
+ * ```
999
+ */
1000
+ toString(): string;
1001
+ }
1002
+ //# sourceMappingURL=outcome.d.ts.map