@jagreehal/workflow 1.5.0 → 1.7.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.
package/dist/core.d.cts CHANGED
@@ -463,23 +463,37 @@ interface RunStep<E = unknown> {
463
463
  key?: string;
464
464
  }) => Promise<T>;
465
465
  /**
466
- * Execute a parallel operation (allAsync) with scope events for visualization.
466
+ * Execute parallel operations with scope events for visualization.
467
467
  *
468
- * This wraps the operation with scope_start and scope_end events, enabling
468
+ * This wraps the operations with scope_start and scope_end events, enabling
469
469
  * visualization of parallel execution branches.
470
470
  *
471
- * @param name - Name for this parallel block (used in visualization)
472
- * @param operation - A function that returns a Result from allAsync or allSettledAsync
473
- * @returns The success value (unwrapped array)
471
+ * @overload Named object form - returns typed object with named results
472
+ * @overload Array form - wraps allAsync result with scope events
474
473
  *
475
- * @example
474
+ * @example Named object form
475
+ * ```typescript
476
+ * const { user, posts } = await step.parallel({
477
+ * user: () => fetchUser(id),
478
+ * posts: () => fetchPosts(id),
479
+ * }, { name: 'Fetch user data' });
480
+ * ```
481
+ *
482
+ * @example Array form
476
483
  * ```typescript
477
484
  * const [user, posts] = await step.parallel('Fetch all data', () =>
478
485
  * allAsync([fetchUser(id), fetchPosts(id)])
479
486
  * );
480
487
  * ```
481
488
  */
482
- parallel: <T, StepE extends E, StepC = unknown>(name: string, operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>) => Promise<T[]>;
489
+ parallel: {
490
+ <TOperations extends Record<string, () => MaybeAsyncResult<unknown, E, unknown>>>(operations: TOperations, options?: {
491
+ name?: string;
492
+ }): Promise<{
493
+ [K in keyof TOperations]: TOperations[K] extends () => MaybeAsyncResult<infer V, E, unknown> ? V : never;
494
+ }>;
495
+ <T, StepE extends E, StepC = unknown>(name: string, operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>): Promise<T[]>;
496
+ };
483
497
  /**
484
498
  * Execute a race operation (anyAsync) with scope events for visualization.
485
499
  *
@@ -716,6 +730,45 @@ type WorkflowEvent<E> = {
716
730
  ts: number;
717
731
  timeoutMs: number;
718
732
  attempt?: number;
733
+ } | {
734
+ type: "hook_should_run";
735
+ workflowId: string;
736
+ ts: number;
737
+ durationMs: number;
738
+ result: boolean;
739
+ skipped: boolean;
740
+ } | {
741
+ type: "hook_should_run_error";
742
+ workflowId: string;
743
+ ts: number;
744
+ durationMs: number;
745
+ error: E;
746
+ } | {
747
+ type: "hook_before_start";
748
+ workflowId: string;
749
+ ts: number;
750
+ durationMs: number;
751
+ result: boolean;
752
+ skipped: boolean;
753
+ } | {
754
+ type: "hook_before_start_error";
755
+ workflowId: string;
756
+ ts: number;
757
+ durationMs: number;
758
+ error: E;
759
+ } | {
760
+ type: "hook_after_step";
761
+ workflowId: string;
762
+ stepKey: string;
763
+ ts: number;
764
+ durationMs: number;
765
+ } | {
766
+ type: "hook_after_step_error";
767
+ workflowId: string;
768
+ stepKey: string;
769
+ ts: number;
770
+ durationMs: number;
771
+ error: E;
719
772
  };
720
773
  type RunOptionsWithCatch<E, C = void> = {
721
774
  /**
@@ -1605,6 +1658,184 @@ declare function mapTry<T, U, E, F, C>(result: Result<T, E, C>, transform: (valu
1605
1658
  * ```
1606
1659
  */
1607
1660
  declare function mapErrorTry<T, E, F, G, C>(result: Result<T, E, C>, transform: (error: E) => F, onError: (cause: unknown) => G): Result<T, F | G, C | unknown>;
1661
+ /**
1662
+ * Transforms both the success value and error value of a Result simultaneously.
1663
+ *
1664
+ * ## When to Use
1665
+ *
1666
+ * Use `bimap()` when:
1667
+ * - You need to transform both success and error in one operation
1668
+ * - You're normalizing Results to a common format
1669
+ * - You want symmetric transformation of both cases
1670
+ * - You're building adapters between different Result types
1671
+ *
1672
+ * ## Why Use This Instead of `map` + `mapError`
1673
+ *
1674
+ * - **Single operation**: Transforms both cases in one call
1675
+ * - **Clearer intent**: Shows you're handling both cases symmetrically
1676
+ * - **Less code**: Avoids chaining map and mapError
1677
+ *
1678
+ * @param r - The Result to transform
1679
+ * @param onOk - Function that transforms the success value
1680
+ * @param onErr - Function that transforms the error value
1681
+ * @returns A new Result with transformed value or transformed error
1682
+ *
1683
+ * @example
1684
+ * ```typescript
1685
+ * // Normalize to API response format
1686
+ * const response = bimap(
1687
+ * fetchUser(id),
1688
+ * user => ({ status: 'success', data: user }),
1689
+ * error => ({ status: 'error', code: error })
1690
+ * );
1691
+ *
1692
+ * // Transform types
1693
+ * const stringified = bimap(
1694
+ * parseNumber(input),
1695
+ * n => `Value: ${n}`,
1696
+ * e => `Error: ${e}`
1697
+ * );
1698
+ *
1699
+ * // Adapt between error types
1700
+ * const adapted = bimap(
1701
+ * externalResult,
1702
+ * value => internalValue(value),
1703
+ * error => internalError(error)
1704
+ * );
1705
+ * ```
1706
+ */
1707
+ declare function bimap<T, U, E, F, C>(r: Result<T, E, C>, onOk: (value: T) => U, onErr: (error: E) => F): Result<U, F, C>;
1708
+ /**
1709
+ * Recovers from an error by returning a new Result.
1710
+ * Similar to neverthrow's `.orElse()`.
1711
+ *
1712
+ * ## When to Use
1713
+ *
1714
+ * Use `orElse()` when:
1715
+ * - You want to recover from errors with fallback operations
1716
+ * - The recovery might also fail (returns a Result)
1717
+ * - You need to chain fallback strategies
1718
+ * - You're implementing retry or fallback patterns
1719
+ *
1720
+ * ## Why Use This
1721
+ *
1722
+ * - **Fallback chains**: Try alternative operations on failure
1723
+ * - **Error recovery**: Convert errors to success with fallback values
1724
+ * - **Composable**: Can chain multiple orElse calls for cascading fallbacks
1725
+ * - **Type-safe**: TypeScript tracks the error union through recovery
1726
+ *
1727
+ * @param r - The Result to potentially recover from
1728
+ * @param fn - Function that takes the error and returns a new Result (may succeed or fail)
1729
+ * @returns The original Result if successful, or the result of the recovery function
1730
+ *
1731
+ * @example
1732
+ * ```typescript
1733
+ * // Fallback to default user
1734
+ * const user = orElse(
1735
+ * fetchUser(id),
1736
+ * error => error === 'NOT_FOUND' ? ok(defaultUser) : err(error)
1737
+ * );
1738
+ *
1739
+ * // Try cache, then database, then fail
1740
+ * const data = orElse(
1741
+ * orElse(
1742
+ * fetchFromCache(key),
1743
+ * () => fetchFromDatabase(key)
1744
+ * ),
1745
+ * () => err('DATA_UNAVAILABLE' as const)
1746
+ * );
1747
+ *
1748
+ * // Convert specific errors to success
1749
+ * const result = orElse(
1750
+ * riskyOperation(),
1751
+ * error => error.code === 'RETRY' ? ok(defaultValue) : err(error)
1752
+ * );
1753
+ * ```
1754
+ */
1755
+ declare function orElse<T, E, E2, C, C2>(r: Result<T, E, C>, fn: (error: E, cause?: C) => Result<T, E2, C2>): Result<T, E2, C2>;
1756
+ /**
1757
+ * Async version of orElse for recovering from errors with async operations.
1758
+ *
1759
+ * @param r - The Result or AsyncResult to potentially recover from
1760
+ * @param fn - Async function that takes the error and returns a new Result
1761
+ * @returns Promise of the original Result if successful, or the result of the recovery function
1762
+ *
1763
+ * @example
1764
+ * ```typescript
1765
+ * // Try primary API, fall back to secondary
1766
+ * const data = await orElseAsync(
1767
+ * await fetchFromPrimaryApi(),
1768
+ * async (error) => {
1769
+ * if (error === 'UNAVAILABLE') {
1770
+ * return await fetchFromSecondaryApi();
1771
+ * }
1772
+ * return err(error);
1773
+ * }
1774
+ * );
1775
+ * ```
1776
+ */
1777
+ declare function orElseAsync<T, E, E2, C, C2>(r: Result<T, E, C> | Promise<Result<T, E, C>>, fn: (error: E, cause?: C) => Result<T, E2, C2> | Promise<Result<T, E2, C2>>): Promise<Result<T, E2, C2>>;
1778
+ /**
1779
+ * Recovers from an error by returning a plain value (not a Result).
1780
+ * Useful when you want to provide a default value on error.
1781
+ *
1782
+ * ## When to Use
1783
+ *
1784
+ * Use `recover()` when:
1785
+ * - You want to provide a fallback value on error
1786
+ * - Recovery cannot fail (unlike orElse which returns a Result)
1787
+ * - You're implementing default value patterns
1788
+ * - You want to guarantee a successful Result
1789
+ *
1790
+ * ## Why Use This Instead of `orElse`
1791
+ *
1792
+ * - **Simpler**: Recovery function returns plain value, not Result
1793
+ * - **Guaranteed success**: Always returns ok() after recovery
1794
+ * - **Clearer intent**: Shows recovery cannot fail
1795
+ *
1796
+ * @param r - The Result to potentially recover from
1797
+ * @param fn - Function that takes the error and returns a recovery value
1798
+ * @returns The original Result if successful, or ok(recoveryValue) if error
1799
+ *
1800
+ * @example
1801
+ * ```typescript
1802
+ * // Provide default user on NOT_FOUND
1803
+ * const user = recover(
1804
+ * fetchUser(id),
1805
+ * error => error === 'NOT_FOUND' ? defaultUser : guestUser
1806
+ * );
1807
+ *
1808
+ * // Convert all errors to default
1809
+ * const config = recover(
1810
+ * loadConfig(),
1811
+ * () => defaultConfig
1812
+ * );
1813
+ *
1814
+ * // Recover with error-based defaults
1815
+ * const value = recover(
1816
+ * parseNumber(input),
1817
+ * error => error === 'EMPTY' ? 0 : -1
1818
+ * );
1819
+ * ```
1820
+ */
1821
+ declare function recover<T, E, C>(r: Result<T, E, C>, fn: (error: E, cause?: C) => T): Result<T, never, never>;
1822
+ /**
1823
+ * Async version of recover for recovering with async operations.
1824
+ *
1825
+ * @param r - The Result or AsyncResult to potentially recover from
1826
+ * @param fn - Async function that takes the error and returns a recovery value
1827
+ * @returns Promise of ok(value) - either original or recovered
1828
+ *
1829
+ * @example
1830
+ * ```typescript
1831
+ * // Recover by fetching default from API
1832
+ * const user = await recoverAsync(
1833
+ * await fetchUser(id),
1834
+ * async (error) => await fetchDefaultUser()
1835
+ * );
1836
+ * ```
1837
+ */
1838
+ declare function recoverAsync<T, E, C>(r: Result<T, E, C> | Promise<Result<T, E, C>>, fn: (error: E, cause?: C) => T | Promise<T>): Promise<Result<T, never, never>>;
1608
1839
  type AllValues<T extends readonly Result<unknown, unknown, unknown>[]> = {
1609
1840
  [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> ? V : never;
1610
1841
  };
@@ -1992,4 +2223,4 @@ type AllAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknow
1992
2223
  */
1993
2224
  declare function allSettledAsync<const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]>(results: T): Promise<Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>>;
1994
2225
 
1995
- export { type AsyncResult, type BackoffStrategy, type CauseOf, EARLY_EXIT_SYMBOL, type EarlyExit, type EmptyInputError, type ErrorOf, type Errors, type ExtractCause, type ExtractError, type ExtractValue, type MaybeAsyncResult, type PromiseRejectedError, type PromiseRejectionCause, type Result, type RetryOptions, type RunOptions, type RunOptionsWithCatch, type RunOptionsWithoutCatch, type RunStep, STEP_TIMEOUT_MARKER, type ScopeType, type SettledError, type StepFailureMeta, type StepOptions, type StepTimeoutError, type StepTimeoutMarkerMeta, type TimeoutOptions, type UnexpectedCause, type UnexpectedError, type UnexpectedStepFailureCause, UnwrapError, type WorkflowEvent, all, allAsync, allSettled, allSettledAsync, andThen, any, anyAsync, createEarlyExit, err, from, fromNullable, fromPromise, getStepTimeoutMeta, isEarlyExit, isErr, isOk, isStepTimeoutError, isUnexpectedError, map, mapError, mapErrorTry, mapTry, match, ok, partition, run, tap, tapError, tryAsync, unwrap, unwrapOr, unwrapOrElse };
2226
+ export { type AsyncResult, type BackoffStrategy, type CauseOf, EARLY_EXIT_SYMBOL, type EarlyExit, type EmptyInputError, type ErrorOf, type Errors, type ExtractCause, type ExtractError, type ExtractValue, type MaybeAsyncResult, type PromiseRejectedError, type PromiseRejectionCause, type Result, type RetryOptions, type RunOptions, type RunOptionsWithCatch, type RunOptionsWithoutCatch, type RunStep, STEP_TIMEOUT_MARKER, type ScopeType, type SettledError, type StepFailureMeta, type StepOptions, type StepTimeoutError, type StepTimeoutMarkerMeta, type TimeoutOptions, type UnexpectedCause, type UnexpectedError, type UnexpectedStepFailureCause, UnwrapError, type WorkflowEvent, all, allAsync, allSettled, allSettledAsync, andThen, any, anyAsync, bimap, createEarlyExit, err, from, fromNullable, fromPromise, getStepTimeoutMeta, isEarlyExit, isErr, isOk, isStepTimeoutError, isUnexpectedError, map, mapError, mapErrorTry, mapTry, match, ok, orElse, orElseAsync, partition, recover, recoverAsync, run, tap, tapError, tryAsync, unwrap, unwrapOr, unwrapOrElse };
package/dist/core.d.ts CHANGED
@@ -463,23 +463,37 @@ interface RunStep<E = unknown> {
463
463
  key?: string;
464
464
  }) => Promise<T>;
465
465
  /**
466
- * Execute a parallel operation (allAsync) with scope events for visualization.
466
+ * Execute parallel operations with scope events for visualization.
467
467
  *
468
- * This wraps the operation with scope_start and scope_end events, enabling
468
+ * This wraps the operations with scope_start and scope_end events, enabling
469
469
  * visualization of parallel execution branches.
470
470
  *
471
- * @param name - Name for this parallel block (used in visualization)
472
- * @param operation - A function that returns a Result from allAsync or allSettledAsync
473
- * @returns The success value (unwrapped array)
471
+ * @overload Named object form - returns typed object with named results
472
+ * @overload Array form - wraps allAsync result with scope events
474
473
  *
475
- * @example
474
+ * @example Named object form
475
+ * ```typescript
476
+ * const { user, posts } = await step.parallel({
477
+ * user: () => fetchUser(id),
478
+ * posts: () => fetchPosts(id),
479
+ * }, { name: 'Fetch user data' });
480
+ * ```
481
+ *
482
+ * @example Array form
476
483
  * ```typescript
477
484
  * const [user, posts] = await step.parallel('Fetch all data', () =>
478
485
  * allAsync([fetchUser(id), fetchPosts(id)])
479
486
  * );
480
487
  * ```
481
488
  */
482
- parallel: <T, StepE extends E, StepC = unknown>(name: string, operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>) => Promise<T[]>;
489
+ parallel: {
490
+ <TOperations extends Record<string, () => MaybeAsyncResult<unknown, E, unknown>>>(operations: TOperations, options?: {
491
+ name?: string;
492
+ }): Promise<{
493
+ [K in keyof TOperations]: TOperations[K] extends () => MaybeAsyncResult<infer V, E, unknown> ? V : never;
494
+ }>;
495
+ <T, StepE extends E, StepC = unknown>(name: string, operation: () => Result<T[], StepE, StepC> | AsyncResult<T[], StepE, StepC>): Promise<T[]>;
496
+ };
483
497
  /**
484
498
  * Execute a race operation (anyAsync) with scope events for visualization.
485
499
  *
@@ -716,6 +730,45 @@ type WorkflowEvent<E> = {
716
730
  ts: number;
717
731
  timeoutMs: number;
718
732
  attempt?: number;
733
+ } | {
734
+ type: "hook_should_run";
735
+ workflowId: string;
736
+ ts: number;
737
+ durationMs: number;
738
+ result: boolean;
739
+ skipped: boolean;
740
+ } | {
741
+ type: "hook_should_run_error";
742
+ workflowId: string;
743
+ ts: number;
744
+ durationMs: number;
745
+ error: E;
746
+ } | {
747
+ type: "hook_before_start";
748
+ workflowId: string;
749
+ ts: number;
750
+ durationMs: number;
751
+ result: boolean;
752
+ skipped: boolean;
753
+ } | {
754
+ type: "hook_before_start_error";
755
+ workflowId: string;
756
+ ts: number;
757
+ durationMs: number;
758
+ error: E;
759
+ } | {
760
+ type: "hook_after_step";
761
+ workflowId: string;
762
+ stepKey: string;
763
+ ts: number;
764
+ durationMs: number;
765
+ } | {
766
+ type: "hook_after_step_error";
767
+ workflowId: string;
768
+ stepKey: string;
769
+ ts: number;
770
+ durationMs: number;
771
+ error: E;
719
772
  };
720
773
  type RunOptionsWithCatch<E, C = void> = {
721
774
  /**
@@ -1605,6 +1658,184 @@ declare function mapTry<T, U, E, F, C>(result: Result<T, E, C>, transform: (valu
1605
1658
  * ```
1606
1659
  */
1607
1660
  declare function mapErrorTry<T, E, F, G, C>(result: Result<T, E, C>, transform: (error: E) => F, onError: (cause: unknown) => G): Result<T, F | G, C | unknown>;
1661
+ /**
1662
+ * Transforms both the success value and error value of a Result simultaneously.
1663
+ *
1664
+ * ## When to Use
1665
+ *
1666
+ * Use `bimap()` when:
1667
+ * - You need to transform both success and error in one operation
1668
+ * - You're normalizing Results to a common format
1669
+ * - You want symmetric transformation of both cases
1670
+ * - You're building adapters between different Result types
1671
+ *
1672
+ * ## Why Use This Instead of `map` + `mapError`
1673
+ *
1674
+ * - **Single operation**: Transforms both cases in one call
1675
+ * - **Clearer intent**: Shows you're handling both cases symmetrically
1676
+ * - **Less code**: Avoids chaining map and mapError
1677
+ *
1678
+ * @param r - The Result to transform
1679
+ * @param onOk - Function that transforms the success value
1680
+ * @param onErr - Function that transforms the error value
1681
+ * @returns A new Result with transformed value or transformed error
1682
+ *
1683
+ * @example
1684
+ * ```typescript
1685
+ * // Normalize to API response format
1686
+ * const response = bimap(
1687
+ * fetchUser(id),
1688
+ * user => ({ status: 'success', data: user }),
1689
+ * error => ({ status: 'error', code: error })
1690
+ * );
1691
+ *
1692
+ * // Transform types
1693
+ * const stringified = bimap(
1694
+ * parseNumber(input),
1695
+ * n => `Value: ${n}`,
1696
+ * e => `Error: ${e}`
1697
+ * );
1698
+ *
1699
+ * // Adapt between error types
1700
+ * const adapted = bimap(
1701
+ * externalResult,
1702
+ * value => internalValue(value),
1703
+ * error => internalError(error)
1704
+ * );
1705
+ * ```
1706
+ */
1707
+ declare function bimap<T, U, E, F, C>(r: Result<T, E, C>, onOk: (value: T) => U, onErr: (error: E) => F): Result<U, F, C>;
1708
+ /**
1709
+ * Recovers from an error by returning a new Result.
1710
+ * Similar to neverthrow's `.orElse()`.
1711
+ *
1712
+ * ## When to Use
1713
+ *
1714
+ * Use `orElse()` when:
1715
+ * - You want to recover from errors with fallback operations
1716
+ * - The recovery might also fail (returns a Result)
1717
+ * - You need to chain fallback strategies
1718
+ * - You're implementing retry or fallback patterns
1719
+ *
1720
+ * ## Why Use This
1721
+ *
1722
+ * - **Fallback chains**: Try alternative operations on failure
1723
+ * - **Error recovery**: Convert errors to success with fallback values
1724
+ * - **Composable**: Can chain multiple orElse calls for cascading fallbacks
1725
+ * - **Type-safe**: TypeScript tracks the error union through recovery
1726
+ *
1727
+ * @param r - The Result to potentially recover from
1728
+ * @param fn - Function that takes the error and returns a new Result (may succeed or fail)
1729
+ * @returns The original Result if successful, or the result of the recovery function
1730
+ *
1731
+ * @example
1732
+ * ```typescript
1733
+ * // Fallback to default user
1734
+ * const user = orElse(
1735
+ * fetchUser(id),
1736
+ * error => error === 'NOT_FOUND' ? ok(defaultUser) : err(error)
1737
+ * );
1738
+ *
1739
+ * // Try cache, then database, then fail
1740
+ * const data = orElse(
1741
+ * orElse(
1742
+ * fetchFromCache(key),
1743
+ * () => fetchFromDatabase(key)
1744
+ * ),
1745
+ * () => err('DATA_UNAVAILABLE' as const)
1746
+ * );
1747
+ *
1748
+ * // Convert specific errors to success
1749
+ * const result = orElse(
1750
+ * riskyOperation(),
1751
+ * error => error.code === 'RETRY' ? ok(defaultValue) : err(error)
1752
+ * );
1753
+ * ```
1754
+ */
1755
+ declare function orElse<T, E, E2, C, C2>(r: Result<T, E, C>, fn: (error: E, cause?: C) => Result<T, E2, C2>): Result<T, E2, C2>;
1756
+ /**
1757
+ * Async version of orElse for recovering from errors with async operations.
1758
+ *
1759
+ * @param r - The Result or AsyncResult to potentially recover from
1760
+ * @param fn - Async function that takes the error and returns a new Result
1761
+ * @returns Promise of the original Result if successful, or the result of the recovery function
1762
+ *
1763
+ * @example
1764
+ * ```typescript
1765
+ * // Try primary API, fall back to secondary
1766
+ * const data = await orElseAsync(
1767
+ * await fetchFromPrimaryApi(),
1768
+ * async (error) => {
1769
+ * if (error === 'UNAVAILABLE') {
1770
+ * return await fetchFromSecondaryApi();
1771
+ * }
1772
+ * return err(error);
1773
+ * }
1774
+ * );
1775
+ * ```
1776
+ */
1777
+ declare function orElseAsync<T, E, E2, C, C2>(r: Result<T, E, C> | Promise<Result<T, E, C>>, fn: (error: E, cause?: C) => Result<T, E2, C2> | Promise<Result<T, E2, C2>>): Promise<Result<T, E2, C2>>;
1778
+ /**
1779
+ * Recovers from an error by returning a plain value (not a Result).
1780
+ * Useful when you want to provide a default value on error.
1781
+ *
1782
+ * ## When to Use
1783
+ *
1784
+ * Use `recover()` when:
1785
+ * - You want to provide a fallback value on error
1786
+ * - Recovery cannot fail (unlike orElse which returns a Result)
1787
+ * - You're implementing default value patterns
1788
+ * - You want to guarantee a successful Result
1789
+ *
1790
+ * ## Why Use This Instead of `orElse`
1791
+ *
1792
+ * - **Simpler**: Recovery function returns plain value, not Result
1793
+ * - **Guaranteed success**: Always returns ok() after recovery
1794
+ * - **Clearer intent**: Shows recovery cannot fail
1795
+ *
1796
+ * @param r - The Result to potentially recover from
1797
+ * @param fn - Function that takes the error and returns a recovery value
1798
+ * @returns The original Result if successful, or ok(recoveryValue) if error
1799
+ *
1800
+ * @example
1801
+ * ```typescript
1802
+ * // Provide default user on NOT_FOUND
1803
+ * const user = recover(
1804
+ * fetchUser(id),
1805
+ * error => error === 'NOT_FOUND' ? defaultUser : guestUser
1806
+ * );
1807
+ *
1808
+ * // Convert all errors to default
1809
+ * const config = recover(
1810
+ * loadConfig(),
1811
+ * () => defaultConfig
1812
+ * );
1813
+ *
1814
+ * // Recover with error-based defaults
1815
+ * const value = recover(
1816
+ * parseNumber(input),
1817
+ * error => error === 'EMPTY' ? 0 : -1
1818
+ * );
1819
+ * ```
1820
+ */
1821
+ declare function recover<T, E, C>(r: Result<T, E, C>, fn: (error: E, cause?: C) => T): Result<T, never, never>;
1822
+ /**
1823
+ * Async version of recover for recovering with async operations.
1824
+ *
1825
+ * @param r - The Result or AsyncResult to potentially recover from
1826
+ * @param fn - Async function that takes the error and returns a recovery value
1827
+ * @returns Promise of ok(value) - either original or recovered
1828
+ *
1829
+ * @example
1830
+ * ```typescript
1831
+ * // Recover by fetching default from API
1832
+ * const user = await recoverAsync(
1833
+ * await fetchUser(id),
1834
+ * async (error) => await fetchDefaultUser()
1835
+ * );
1836
+ * ```
1837
+ */
1838
+ declare function recoverAsync<T, E, C>(r: Result<T, E, C> | Promise<Result<T, E, C>>, fn: (error: E, cause?: C) => T | Promise<T>): Promise<Result<T, never, never>>;
1608
1839
  type AllValues<T extends readonly Result<unknown, unknown, unknown>[]> = {
1609
1840
  [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> ? V : never;
1610
1841
  };
@@ -1992,4 +2223,4 @@ type AllAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknow
1992
2223
  */
1993
2224
  declare function allSettledAsync<const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]>(results: T): Promise<Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>>;
1994
2225
 
1995
- export { type AsyncResult, type BackoffStrategy, type CauseOf, EARLY_EXIT_SYMBOL, type EarlyExit, type EmptyInputError, type ErrorOf, type Errors, type ExtractCause, type ExtractError, type ExtractValue, type MaybeAsyncResult, type PromiseRejectedError, type PromiseRejectionCause, type Result, type RetryOptions, type RunOptions, type RunOptionsWithCatch, type RunOptionsWithoutCatch, type RunStep, STEP_TIMEOUT_MARKER, type ScopeType, type SettledError, type StepFailureMeta, type StepOptions, type StepTimeoutError, type StepTimeoutMarkerMeta, type TimeoutOptions, type UnexpectedCause, type UnexpectedError, type UnexpectedStepFailureCause, UnwrapError, type WorkflowEvent, all, allAsync, allSettled, allSettledAsync, andThen, any, anyAsync, createEarlyExit, err, from, fromNullable, fromPromise, getStepTimeoutMeta, isEarlyExit, isErr, isOk, isStepTimeoutError, isUnexpectedError, map, mapError, mapErrorTry, mapTry, match, ok, partition, run, tap, tapError, tryAsync, unwrap, unwrapOr, unwrapOrElse };
2226
+ export { type AsyncResult, type BackoffStrategy, type CauseOf, EARLY_EXIT_SYMBOL, type EarlyExit, type EmptyInputError, type ErrorOf, type Errors, type ExtractCause, type ExtractError, type ExtractValue, type MaybeAsyncResult, type PromiseRejectedError, type PromiseRejectionCause, type Result, type RetryOptions, type RunOptions, type RunOptionsWithCatch, type RunOptionsWithoutCatch, type RunStep, STEP_TIMEOUT_MARKER, type ScopeType, type SettledError, type StepFailureMeta, type StepOptions, type StepTimeoutError, type StepTimeoutMarkerMeta, type TimeoutOptions, type UnexpectedCause, type UnexpectedError, type UnexpectedStepFailureCause, UnwrapError, type WorkflowEvent, all, allAsync, allSettled, allSettledAsync, andThen, any, anyAsync, bimap, createEarlyExit, err, from, fromNullable, fromPromise, getStepTimeoutMeta, isEarlyExit, isErr, isOk, isStepTimeoutError, isUnexpectedError, map, mapError, mapErrorTry, mapTry, match, ok, orElse, orElseAsync, partition, recover, recoverAsync, run, tap, tapError, tryAsync, unwrap, unwrapOr, unwrapOrElse };
package/dist/core.js CHANGED
@@ -1,2 +1,2 @@
1
- var P=e=>({ok:!0,value:e}),T=(e,t)=>({ok:!1,error:e,...t?.cause!==void 0?{cause:t.cause}:{}}),Ee=e=>e.ok,ye=e=>!e.ok,oe=e=>typeof e=="object"&&e!==null&&e.type==="UNEXPECTED_ERROR",D=Symbol.for("step_timeout_marker");function G(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:D in e}function se(e){if(!(typeof e!="object"||e===null)){if(e.type==="STEP_TIMEOUT"){let t=e;return{timeoutMs:t.timeoutMs,stepName:t.stepName,stepKey:t.stepKey,attempt:t.attempt}}if(D in e)return e[D]}}var Q=Symbol("early-exit");function ue(e,t){return{[Q]:!0,error:e,meta:t}}function ae(e){return typeof e=="object"&&e!==null&&e[Q]===!0}var Z=Symbol("mapper-exception");function ie(e){return{[Z]:!0,thrown:e}}function pe(e){return typeof e=="object"&&e!==null&&e[Z]===!0}function le(e){return typeof e=="string"?{name:e}:e??{}}function X(e,t){let{backoff:n,initialDelay:u,maxDelay:w,jitter:g}=t,k;switch(n){case"fixed":k=u;break;case"linear":k=u*e;break;case"exponential":k=u*Math.pow(2,e-1);break}if(k=Math.min(k,w),g){let o=k*.25*Math.random();k=k+o}return Math.floor(k)}function Y(e){return new Promise(t=>setTimeout(t,e))}var H=Symbol("timeout");async function ce(e,t,n){let u=new AbortController,w=t.error??{type:"STEP_TIMEOUT",stepName:n.name,stepKey:n.key,timeoutMs:t.ms,attempt:n.attempt},g,k=new Promise((v,x)=>{g=setTimeout(()=>{u.abort(),x({[H]:!0,error:w})},t.ms)}),o;t.signal?o=Promise.resolve(e(u.signal)):o=Promise.resolve(e());try{return await Promise.race([o,k])}catch(v){if(typeof v=="object"&&v!==null&&v[H]===!0){let x=v.error;if(typeof x=="object"&&x!==null&&x.type!=="STEP_TIMEOUT"){let K={timeoutMs:t.ms,stepName:n.name,stepKey:n.key,attempt:n.attempt};D in x?x[D]=K:Object.defineProperty(x,D,{value:K,enumerable:!1,writable:!0,configurable:!1})}throw x}throw v}finally{clearTimeout(g)}}var U={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,retryOn:()=>!0,onRetry:()=>{}};async function z(e,t){let{onError:n,onEvent:u,catchUnexpected:w,workflowId:g,context:k}=t&&typeof t=="object"?t:{},o=g??crypto.randomUUID(),v=!n&&!w,x=[],K=0,N=r=>r??`step_${++K}`,l=r=>{if(r.type==="step_success"){let h=r.stepId;for(let b=x.length-1;b>=0;b--){let m=x[b];if(m.type==="race"&&!m.winnerId){m.winnerId=h;break}}}u?.(r,k)},M=ue,q=r=>ae(r),V=(r,h)=>v?h?.origin==="result"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:r,...h.resultCause!==void 0?{cause:h.resultCause}:{}}}:h?.origin==="throw"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"throw",error:r,thrown:h.thrown}}:{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:r}}:r,ee=r=>r.origin==="result"?r.resultCause:r.thrown,te=r=>({type:"UNEXPECTED_ERROR",cause:r.meta.origin==="result"?{type:"STEP_FAILURE",origin:"result",error:r.error,...r.meta.resultCause!==void 0?{cause:r.meta.resultCause}:{}}:{type:"STEP_FAILURE",origin:"throw",error:r.error,thrown:r.meta.thrown}});try{let r=(m,i)=>(async()=>{let y=le(i),{name:s,key:a,retry:d,timeout:c}=y,p=N(a),f=u,R=f?performance.now():0;if(!(typeof m=="function")){if(d&&d.attempts>1)throw new Error("step: retry options require a function operation. Direct Promise/Result values cannot be re-executed on retry. Wrap your operation in a function: step(() => yourOperation, { retry: {...} })");if(c)throw new Error("step: timeout options require a function operation. Direct Promise/Result values cannot be wrapped with timeout after they've started. Wrap your operation in a function: step(() => yourOperation, { timeout: {...} })")}let S={attempts:Math.max(1,d?.attempts??1),backoff:d?.backoff??U.backoff,initialDelay:d?.initialDelay??U.initialDelay,maxDelay:d?.maxDelay??U.maxDelay,jitter:d?.jitter??U.jitter,retryOn:d?.retryOn??U.retryOn,onRetry:d?.onRetry??U.onRetry};u&&l({type:"step_start",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now()});let J;for(let C=1;C<=S.attempts;C++){let re=f?performance.now():0;try{let E;if(typeof m=="function"?c?E=await ce(m,c,{name:s,key:a,attempt:C}):E=await m():E=await m,E.ok){let _=performance.now()-R;return l({type:"step_success",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:_}),a&&l({type:"step_complete",workflowId:o,stepKey:a,name:s,ts:Date.now(),durationMs:_,result:E}),E.value}if(J=E,C<S.attempts&&S.retryOn(E.error,C)){let _=X(C,S);l({type:"step_retry",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),attempt:C+1,maxAttempts:S.attempts,delayMs:_,error:E.error}),S.onRetry(E.error,C,_),await Y(_);continue}S.attempts>1&&l({type:"step_retries_exhausted",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:performance.now()-R,attempts:C,lastError:E.error});break}catch(E){let _=performance.now()-re;if(q(E))throw l({type:"step_aborted",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:_}),E;if(G(E)){let A=se(E),L=c?.ms??A?.timeoutMs??0;if(l({type:"step_timeout",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),timeoutMs:L,attempt:C}),C<S.attempts&&S.retryOn(E,C)){let W=X(C,S);l({type:"step_retry",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),attempt:C+1,maxAttempts:S.attempts,delayMs:W,error:E}),S.onRetry(E,C,W),await Y(W);continue}S.attempts>1&&l({type:"step_retries_exhausted",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:performance.now()-R,attempts:C,lastError:E})}if(C<S.attempts&&S.retryOn(E,C)){let A=X(C,S);l({type:"step_retry",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),attempt:C+1,maxAttempts:S.attempts,delayMs:A,error:E}),S.onRetry(E,C,A),await Y(A);continue}S.attempts>1&&!G(E)&&l({type:"step_retries_exhausted",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:performance.now()-R,attempts:C,lastError:E});let F=performance.now()-R;if(w){let A;try{A=w(E)}catch(L){throw ie(L)}throw l({type:"step_error",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:F,error:A}),a&&l({type:"step_complete",workflowId:o,stepKey:a,name:s,ts:Date.now(),durationMs:F,result:T(A,{cause:E}),meta:{origin:"throw",thrown:E}}),n?.(A,s),M(A,{origin:"throw",thrown:E})}else{let A={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:E}};throw l({type:"step_error",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:F,error:A}),a&&l({type:"step_complete",workflowId:o,stepKey:a,name:s,ts:Date.now(),durationMs:F,result:T(A,{cause:E}),meta:{origin:"throw",thrown:E}}),E}}}let I=J,$=performance.now()-R,ne=V(I.error,{origin:"result",resultCause:I.cause});throw l({type:"step_error",workflowId:o,stepId:p,stepKey:a,name:s,ts:Date.now(),durationMs:$,error:ne}),a&&l({type:"step_complete",workflowId:o,stepKey:a,name:s,ts:Date.now(),durationMs:$,result:I,meta:{origin:"result",resultCause:I.cause}}),n?.(I.error,s),M(I.error,{origin:"result",resultCause:I.cause})})();r.try=(m,i)=>{let y=i.name,s=i.key,a=N(s),d="error"in i?()=>i.error:i.onError,c=u;return(async()=>{let p=c?performance.now():0;u&&l({type:"step_start",workflowId:o,stepId:a,stepKey:s,name:y,ts:Date.now()});try{let f=await m(),R=performance.now()-p;return l({type:"step_success",workflowId:o,stepId:a,stepKey:s,name:y,ts:Date.now(),durationMs:R}),s&&l({type:"step_complete",workflowId:o,stepKey:s,name:y,ts:Date.now(),durationMs:R,result:P(f)}),f}catch(f){let R=d(f),O=performance.now()-p,j=V(R,{origin:"throw",thrown:f});throw l({type:"step_error",workflowId:o,stepId:a,stepKey:s,name:y,ts:Date.now(),durationMs:O,error:j}),s&&l({type:"step_complete",workflowId:o,stepKey:s,name:y,ts:Date.now(),durationMs:O,result:T(R,{cause:f}),meta:{origin:"throw",thrown:f}}),n?.(R,y),M(R,{origin:"throw",thrown:f})}})()},r.fromResult=(m,i)=>{let y=i.name,s=i.key,a=N(s),d="error"in i?()=>i.error:i.onError,c=u;return(async()=>{let p=c?performance.now():0;u&&l({type:"step_start",workflowId:o,stepId:a,stepKey:s,name:y,ts:Date.now()});let f=await m();if(f.ok){let R=performance.now()-p;return l({type:"step_success",workflowId:o,stepId:a,stepKey:s,name:y,ts:Date.now(),durationMs:R}),s&&l({type:"step_complete",workflowId:o,stepKey:s,name:y,ts:Date.now(),durationMs:R,result:P(f.value)}),f.value}else{let R=d(f.error),O=performance.now()-p,j=V(R,{origin:"result",resultCause:f.error});throw l({type:"step_error",workflowId:o,stepId:a,stepKey:s,name:y,ts:Date.now(),durationMs:O,error:j}),s&&l({type:"step_complete",workflowId:o,stepKey:s,name:y,ts:Date.now(),durationMs:O,result:T(R,{cause:f.error}),meta:{origin:"result",resultCause:f.error}}),n?.(R,y),M(R,{origin:"result",resultCause:f.error})}})()},r.retry=(m,i)=>r(m,{name:i.name,key:i.key,retry:{attempts:i.attempts,backoff:i.backoff,initialDelay:i.initialDelay,maxDelay:i.maxDelay,jitter:i.jitter,retryOn:i.retryOn,onRetry:i.onRetry},timeout:i.timeout}),r.withTimeout=(m,i)=>r(m,{name:i.name,key:i.key,timeout:i}),r.parallel=(m,i)=>{let y=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),a=!1;x.push({scopeId:y,type:"parallel"});let d=()=>{if(a)return;a=!0;let c=x.findIndex(p=>p.scopeId===y);c!==-1&&x.splice(c,1),l({type:"scope_end",workflowId:o,scopeId:y,ts:Date.now(),durationMs:performance.now()-s})};l({type:"scope_start",workflowId:o,scopeId:y,scopeType:"parallel",name:m,ts:Date.now()});try{let c=await i();if(d(),!c.ok)throw n?.(c.error,m),M(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw d(),c}})()},r.race=(m,i)=>{let y=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),a=!1,d={scopeId:y,type:"race",winnerId:void 0};x.push(d);let c=()=>{if(a)return;a=!0;let p=x.findIndex(f=>f.scopeId===y);p!==-1&&x.splice(p,1),l({type:"scope_end",workflowId:o,scopeId:y,ts:Date.now(),durationMs:performance.now()-s,winnerId:d.winnerId})};l({type:"scope_start",workflowId:o,scopeId:y,scopeType:"race",name:m,ts:Date.now()});try{let p=await i();if(c(),!p.ok)throw n?.(p.error,m),M(p.error,{origin:"result",resultCause:p.cause});return p.value}catch(p){throw c(),p}})()},r.allSettled=(m,i)=>{let y=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),a=!1;x.push({scopeId:y,type:"allSettled"});let d=()=>{if(a)return;a=!0;let c=x.findIndex(p=>p.scopeId===y);c!==-1&&x.splice(c,1),l({type:"scope_end",workflowId:o,scopeId:y,ts:Date.now(),durationMs:performance.now()-s})};l({type:"scope_start",workflowId:o,scopeId:y,scopeType:"allSettled",name:m,ts:Date.now()});try{let c=await i();if(d(),!c.ok)throw n?.(c.error,m),M(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw d(),c}})()};let b=await e(r);return P(b)}catch(r){if(pe(r))throw r.thrown;if(q(r)){let b=ee(r.meta);if(w||n)return T(r.error,{cause:b});if(oe(r.error))return T(r.error,{cause:b});let m=te(r);return T(m,{cause:b})}if(w){let b=w(r);return n?.(b,"unexpected"),T(b,{cause:r})}let h={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:r}};return n?.(h,"unexpected"),T(h,{cause:r})}}z.strict=(e,t)=>z(e,t);var B=class extends Error{constructor(n,u){super(`Unwrap called on an error result: ${String(n)}`);this.error=n;this.cause=u;this.name="UnwrapError"}},me=e=>{if(e.ok)return e.value;throw new B(e.error,e.cause)},we=(e,t)=>e.ok?e.value:t,Te=(e,t)=>e.ok?e.value:t(e.error,e.cause);function ke(e,t){try{return P(e())}catch(n){return t?T(t(n),{cause:n}):T(n)}}async function de(e,t){try{return P(await e)}catch(n){return t?T(t(n),{cause:n}):T(n)}}async function fe(e,t){try{return P(await e())}catch(n){return t?T(t(n),{cause:n}):T(n)}}function Re(e,t){return e!=null?P(e):T(t())}function Ce(e,t){return e.ok?P(t(e.value)):e}function xe(e,t){return e.ok?e:T(t(e.error),{cause:e.cause})}function Se(e,t){return e.ok?t.ok(e.value):t.err(e.error,e.cause)}function ge(e,t){return e.ok?t(e.value):e}function Ae(e,t){return e.ok&&t(e.value),e}function Pe(e,t){return e.ok||t(e.error,e.cause),e}function be(e,t,n){if(!e.ok)return e;try{return P(t(e.value))}catch(u){return T(n(u),{cause:u})}}function he(e,t,n){if(e.ok)return e;try{return T(t(e.error),{cause:e.cause})}catch(u){return T(n(u),{cause:u})}}function ve(e){let t=[];for(let n of e){if(!n.ok)return n;t.push(n.value)}return P(t)}async function _e(e){return e.length===0?P([]):new Promise(t=>{let n=!1,u=e.length,w=new Array(e.length);for(let g=0;g<e.length;g++){let k=g;Promise.resolve(e[k]).catch(o=>T({type:"PROMISE_REJECTED",cause:o},{cause:{type:"PROMISE_REJECTION",reason:o}})).then(o=>{if(!n){if(!o.ok){n=!0,t(o);return}w[k]=o.value,u--,u===0&&t(P(w))}})}})}function Me(e){let t=[],n=[];for(let u of e)u.ok?t.push(u.value):n.push({error:u.error,cause:u.cause});return n.length>0?T(n):P(t)}function Ie(e){let t=[],n=[];for(let u of e)u.ok?t.push(u.value):n.push(u.error);return{values:t,errors:n}}function Oe(e){if(e.length===0)return T({type:"EMPTY_INPUT",message:"any() requires at least one Result"});let t=null;for(let n of e){if(n.ok)return n;t||(t=n)}return t}async function Ue(e){return e.length===0?T({type:"EMPTY_INPUT",message:"anyAsync() requires at least one Result"}):new Promise(t=>{let n=!1,u=e.length,w=null;for(let g of e)Promise.resolve(g).catch(k=>T({type:"PROMISE_REJECTED",cause:k},{cause:{type:"PROMISE_REJECTION",reason:k}})).then(k=>{if(!n){if(k.ok){n=!0,t(k);return}w||(w=k),u--,u===0&&t(w)}})})}async function De(e){let t=await Promise.all(e.map(w=>Promise.resolve(w).then(g=>({status:"result",result:g})).catch(g=>({status:"rejected",error:{type:"PROMISE_REJECTED",cause:g},cause:{type:"PROMISE_REJECTION",reason:g}})))),n=[],u=[];for(let w of t)w.status==="rejected"?u.push({error:w.error,cause:w.cause}):w.result.ok?n.push(w.result.value):u.push({error:w.result.error,cause:w.result.cause});return u.length>0?T(u):P(n)}export{Q as EARLY_EXIT_SYMBOL,D as STEP_TIMEOUT_MARKER,B as UnwrapError,ve as all,_e as allAsync,Me as allSettled,De as allSettledAsync,ge as andThen,Oe as any,Ue as anyAsync,ue as createEarlyExit,T as err,ke as from,Re as fromNullable,de as fromPromise,se as getStepTimeoutMeta,ae as isEarlyExit,ye as isErr,Ee as isOk,G as isStepTimeoutError,oe as isUnexpectedError,Ce as map,xe as mapError,he as mapErrorTry,be as mapTry,Se as match,P as ok,Ie as partition,z as run,Ae as tap,Pe as tapError,fe as tryAsync,me as unwrap,we as unwrapOr,Te as unwrapOrElse};
1
+ var g=e=>({ok:!0,value:e}),k=(e,t)=>({ok:!1,error:e,...t?.cause!==void 0?{cause:t.cause}:{}}),Te=e=>e.ok,ke=e=>!e.ok,ue=e=>typeof e=="object"&&e!==null&&e.type==="UNEXPECTED_ERROR",F=Symbol.for("step_timeout_marker");function z(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:F in e}function ae(e){if(!(typeof e!="object"||e===null)){if(e.type==="STEP_TIMEOUT"){let t=e;return{timeoutMs:t.timeoutMs,stepName:t.stepName,stepKey:t.stepKey,attempt:t.attempt}}if(F in e)return e[F]}}var ee=Symbol("early-exit");function ie(e,t){return{[ee]:!0,error:e,meta:t}}function pe(e){return typeof e=="object"&&e!==null&&e[ee]===!0}var te=Symbol("mapper-exception");function le(e){return{[te]:!0,thrown:e}}function ce(e){return typeof e=="object"&&e!==null&&e[te]===!0}function Ee(e){return typeof e=="string"?{name:e}:e??{}}function B(e,t){let{backoff:n,initialDelay:a,maxDelay:d,jitter:A}=t,x;switch(n){case"fixed":x=a;break;case"linear":x=a*e;break;case"exponential":x=a*Math.pow(2,e-1);break}if(x=Math.min(x,d),A){let r=x*.25*Math.random();x=x+r}return Math.floor(x)}function q(e){return new Promise(t=>setTimeout(t,e))}var Q=Symbol("timeout");async function ye(e,t,n){let a=new AbortController,d=t.error??{type:"STEP_TIMEOUT",stepName:n.name,stepKey:n.key,timeoutMs:t.ms,attempt:n.attempt},A,x=new Promise((I,R)=>{A=setTimeout(()=>{a.abort(),R({[Q]:!0,error:d})},t.ms)}),r;t.signal?r=Promise.resolve(e(a.signal)):r=Promise.resolve(e());try{return await Promise.race([r,x])}catch(I){if(typeof I=="object"&&I!==null&&I[Q]===!0){let R=I.error;if(typeof R=="object"&&R!==null&&R.type!=="STEP_TIMEOUT"){let V={timeoutMs:t.ms,stepName:n.name,stepKey:n.key,attempt:n.attempt};F in R?R[F]=V:Object.defineProperty(R,F,{value:V,enumerable:!1,writable:!0,configurable:!1})}throw R}throw I}finally{clearTimeout(A)}}var j={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,retryOn:()=>!0,onRetry:()=>{}};async function Z(e,t){let{onError:n,onEvent:a,catchUnexpected:d,workflowId:A,context:x}=t&&typeof t=="object"?t:{},r=A??crypto.randomUUID(),I=!n&&!d,R=[],V=0,W=o=>o??`step_${++V}`,E=o=>{if(o.type==="step_success"){let P=o.stepId;for(let h=R.length-1;h>=0;h--){let D=R[h];if(D.type==="race"&&!D.winnerId){D.winnerId=P;break}}}a?.(o,x)},O=ie,H=o=>pe(o),X=(o,P)=>I?P?.origin==="result"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:o,...P.resultCause!==void 0?{cause:P.resultCause}:{}}}:P?.origin==="throw"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"throw",error:o,thrown:P.thrown}}:{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:o}}:o,ne=o=>o.origin==="result"?o.resultCause:o.thrown,re=o=>({type:"UNEXPECTED_ERROR",cause:o.meta.origin==="result"?{type:"STEP_FAILURE",origin:"result",error:o.error,...o.meta.resultCause!==void 0?{cause:o.meta.resultCause}:{}}:{type:"STEP_FAILURE",origin:"throw",error:o.error,thrown:o.meta.thrown}});try{let P=function(m,p){let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),u=!1;R.push({scopeId:i,type:"parallel"});let C=()=>{if(u)return;u=!0;let c=R.findIndex(l=>l.scopeId===i);c!==-1&&R.splice(c,1),E({type:"scope_end",workflowId:r,scopeId:i,ts:Date.now(),durationMs:performance.now()-s})};E({type:"scope_start",workflowId:r,scopeId:i,scopeType:"parallel",name:m,ts:Date.now()});try{let c=await p();if(C(),!c.ok)throw n?.(c.error,m),O(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw C(),c}})()},h=function(m,p){let i=Object.keys(m),s=p.name??`Parallel(${i.join(", ")})`,u=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let C=performance.now(),c=!1;R.push({scopeId:u,type:"parallel"});let l=()=>{if(c)return;c=!0;let w=R.findIndex(f=>f.scopeId===u);w!==-1&&R.splice(w,1),E({type:"scope_end",workflowId:r,scopeId:u,ts:Date.now(),durationMs:performance.now()-C})};E({type:"scope_start",workflowId:r,scopeId:u,scopeType:"parallel",name:s,ts:Date.now()});try{let w=await new Promise(_=>{if(i.length===0){_([]);return}let v=!1,S=i.length,N=new Array(i.length);for(let M=0;M<i.length;M++){let K=i[M],Y=M;Promise.resolve(m[K]()).catch(T=>k({type:"PROMISE_REJECTED",cause:T},{cause:{type:"PROMISE_REJECTION",reason:T}})).then(T=>{if(!v){if(!T.ok){v=!0,_([{key:K,result:T}]);return}N[Y]={key:K,result:T},S--,S===0&&_(N)}})}});l();let f={};for(let{key:_,result:v}of w){if(!v.ok)throw n?.(v.error,_),O(v.error,{origin:"result",resultCause:v.cause});f[_]=v.value}return f}catch(w){throw l(),w}})()};var me=P,we=h;let o=(m,p)=>(async()=>{let i=Ee(p),{name:s,key:u,retry:C,timeout:c}=i,l=W(u),w=a,f=w?performance.now():0;if(!(typeof m=="function")){if(C&&C.attempts>1)throw new Error("step: retry options require a function operation. Direct Promise/Result values cannot be re-executed on retry. Wrap your operation in a function: step(() => yourOperation, { retry: {...} })");if(c)throw new Error("step: timeout options require a function operation. Direct Promise/Result values cannot be wrapped with timeout after they've started. Wrap your operation in a function: step(() => yourOperation, { timeout: {...} })")}let S={attempts:Math.max(1,C?.attempts??1),backoff:C?.backoff??j.backoff,initialDelay:C?.initialDelay??j.initialDelay,maxDelay:C?.maxDelay??j.maxDelay,jitter:C?.jitter??j.jitter,retryOn:C?.retryOn??j.retryOn,onRetry:C?.onRetry??j.onRetry};a&&E({type:"step_start",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now()});let N;for(let T=1;T<=S.attempts;T++){let se=w?performance.now():0;try{let y;if(typeof m=="function"?c?y=await ye(m,c,{name:s,key:u,attempt:T}):y=await m():y=await m,y.ok){let U=performance.now()-f;return E({type:"step_success",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:U}),u&&E({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:U,result:y}),y.value}if(N=y,T<S.attempts&&S.retryOn(y.error,T)){let U=B(T,S);E({type:"step_retry",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),attempt:T+1,maxAttempts:S.attempts,delayMs:U,error:y.error}),S.onRetry(y.error,T,U),await q(U);continue}S.attempts>1&&E({type:"step_retries_exhausted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:performance.now()-f,attempts:T,lastError:y.error});break}catch(y){let U=performance.now()-se;if(H(y))throw E({type:"step_aborted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:U}),y;if(z(y)){let b=ae(y),$=c?.ms??b?.timeoutMs??0;if(E({type:"step_timeout",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),timeoutMs:$,attempt:T}),T<S.attempts&&S.retryOn(y,T)){let J=B(T,S);E({type:"step_retry",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),attempt:T+1,maxAttempts:S.attempts,delayMs:J,error:y}),S.onRetry(y,T,J),await q(J);continue}S.attempts>1&&E({type:"step_retries_exhausted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:performance.now()-f,attempts:T,lastError:y})}if(T<S.attempts&&S.retryOn(y,T)){let b=B(T,S);E({type:"step_retry",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),attempt:T+1,maxAttempts:S.attempts,delayMs:b,error:y}),S.onRetry(y,T,b),await q(b);continue}S.attempts>1&&!z(y)&&E({type:"step_retries_exhausted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:performance.now()-f,attempts:T,lastError:y});let L=performance.now()-f;if(d){let b;try{b=d(y)}catch($){throw le($)}throw E({type:"step_error",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:L,error:b}),u&&E({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:L,result:k(b,{cause:y}),meta:{origin:"throw",thrown:y}}),n?.(b,s),O(b,{origin:"throw",thrown:y})}else{let b={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:y}};throw E({type:"step_error",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:L,error:b}),u&&E({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:L,result:k(b,{cause:y}),meta:{origin:"throw",thrown:y}}),y}}}let M=N,K=performance.now()-f,Y=X(M.error,{origin:"result",resultCause:M.cause});throw E({type:"step_error",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:K,error:Y}),u&&E({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:K,result:M,meta:{origin:"result",resultCause:M.cause}}),n?.(M.error,s),O(M.error,{origin:"result",resultCause:M.cause})})();o.try=(m,p)=>{let i=p.name,s=p.key,u=W(s),C="error"in p?()=>p.error:p.onError,c=a;return(async()=>{let l=c?performance.now():0;a&&E({type:"step_start",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now()});try{let w=await m(),f=performance.now()-l;return E({type:"step_success",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:f}),s&&E({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:f,result:g(w)}),w}catch(w){let f=C(w),_=performance.now()-l,v=X(f,{origin:"throw",thrown:w});throw E({type:"step_error",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:_,error:v}),s&&E({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:_,result:k(f,{cause:w}),meta:{origin:"throw",thrown:w}}),n?.(f,i),O(f,{origin:"throw",thrown:w})}})()},o.fromResult=(m,p)=>{let i=p.name,s=p.key,u=W(s),C="error"in p?()=>p.error:p.onError,c=a;return(async()=>{let l=c?performance.now():0;a&&E({type:"step_start",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now()});let w=await m();if(w.ok){let f=performance.now()-l;return E({type:"step_success",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:f}),s&&E({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:f,result:g(w.value)}),w.value}else{let f=C(w.error),_=performance.now()-l,v=X(f,{origin:"result",resultCause:w.error});throw E({type:"step_error",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:_,error:v}),s&&E({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:_,result:k(f,{cause:w.error}),meta:{origin:"result",resultCause:w.error}}),n?.(f,i),O(f,{origin:"result",resultCause:w.error})}})()},o.retry=(m,p)=>o(m,{name:p.name,key:p.key,retry:{attempts:p.attempts,backoff:p.backoff,initialDelay:p.initialDelay,maxDelay:p.maxDelay,jitter:p.jitter,retryOn:p.retryOn,onRetry:p.onRetry},timeout:p.timeout}),o.withTimeout=(m,p)=>o(m,{name:p.name,key:p.key,timeout:p}),o.parallel=((...m)=>{if(typeof m[0]=="string"){let p=m[0],i=m[1];return P(p,i)}else{let p=m[0],i=m[1]??{};return h(p,i)}}),o.race=(m,p)=>{let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),u=!1,C={scopeId:i,type:"race",winnerId:void 0};R.push(C);let c=()=>{if(u)return;u=!0;let l=R.findIndex(w=>w.scopeId===i);l!==-1&&R.splice(l,1),E({type:"scope_end",workflowId:r,scopeId:i,ts:Date.now(),durationMs:performance.now()-s,winnerId:C.winnerId})};E({type:"scope_start",workflowId:r,scopeId:i,scopeType:"race",name:m,ts:Date.now()});try{let l=await p();if(c(),!l.ok)throw n?.(l.error,m),O(l.error,{origin:"result",resultCause:l.cause});return l.value}catch(l){throw c(),l}})()},o.allSettled=(m,p)=>{let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),u=!1;R.push({scopeId:i,type:"allSettled"});let C=()=>{if(u)return;u=!0;let c=R.findIndex(l=>l.scopeId===i);c!==-1&&R.splice(c,1),E({type:"scope_end",workflowId:r,scopeId:i,ts:Date.now(),durationMs:performance.now()-s})};E({type:"scope_start",workflowId:r,scopeId:i,scopeType:"allSettled",name:m,ts:Date.now()});try{let c=await p();if(C(),!c.ok)throw n?.(c.error,m),O(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw C(),c}})()};let oe=await e(o);return g(oe)}catch(o){if(ce(o))throw o.thrown;if(H(o)){let h=ne(o.meta);if(d||n)return k(o.error,{cause:h});if(ue(o.error))return k(o.error,{cause:h});let D=re(o);return k(D,{cause:h})}if(d){let h=d(o);return n?.(h,"unexpected"),k(h,{cause:o})}let P={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:o}};return n?.(P,"unexpected"),k(P,{cause:o})}}Z.strict=(e,t)=>Z(e,t);var G=class extends Error{constructor(n,a){super(`Unwrap called on an error result: ${String(n)}`);this.error=n;this.cause=a;this.name="UnwrapError"}},de=e=>{if(e.ok)return e.value;throw new G(e.error,e.cause)},fe=(e,t)=>e.ok?e.value:t,Re=(e,t)=>e.ok?e.value:t(e.error,e.cause);function Ce(e,t){try{return g(e())}catch(n){return t?k(t(n),{cause:n}):k(n)}}async function xe(e,t){try{return g(await e)}catch(n){return t?k(t(n),{cause:n}):k(n)}}async function Se(e,t){try{return g(await e())}catch(n){return t?k(t(n),{cause:n}):k(n)}}function ge(e,t){return e!=null?g(e):k(t())}function Ae(e,t){return e.ok?g(t(e.value)):e}function be(e,t){return e.ok?e:k(t(e.error),{cause:e.cause})}function Pe(e,t){return e.ok?t.ok(e.value):t.err(e.error,e.cause)}function he(e,t){return e.ok?t(e.value):e}function _e(e,t){return e.ok&&t(e.value),e}function ve(e,t){return e.ok||t(e.error,e.cause),e}function Me(e,t,n){if(!e.ok)return e;try{return g(t(e.value))}catch(a){return k(n(a),{cause:a})}}function Ie(e,t,n){if(e.ok)return e;try{return k(t(e.error),{cause:e.cause})}catch(a){return k(n(a),{cause:a})}}function Oe(e,t,n){return e.ok?g(t(e.value)):k(n(e.error),{cause:e.cause})}function Ue(e,t){return e.ok?e:t(e.error,e.cause)}async function De(e,t){let n=await e;return n.ok?n:t(n.error,n.cause)}function Ke(e,t){return e.ok?g(e.value):g(t(e.error,e.cause))}async function je(e,t){let n=await e;return n.ok?g(n.value):g(await t(n.error,n.cause))}function Fe(e){let t=[];for(let n of e){if(!n.ok)return n;t.push(n.value)}return g(t)}async function Ne(e){return e.length===0?g([]):new Promise(t=>{let n=!1,a=e.length,d=new Array(e.length);for(let A=0;A<e.length;A++){let x=A;Promise.resolve(e[x]).catch(r=>k({type:"PROMISE_REJECTED",cause:r},{cause:{type:"PROMISE_REJECTION",reason:r}})).then(r=>{if(!n){if(!r.ok){n=!0,t(r);return}d[x]=r.value,a--,a===0&&t(g(d))}})}})}function Ve(e){let t=[],n=[];for(let a of e)a.ok?t.push(a.value):n.push({error:a.error,cause:a.cause});return n.length>0?k(n):g(t)}function Le(e){let t=[],n=[];for(let a of e)a.ok?t.push(a.value):n.push(a.error);return{values:t,errors:n}}function We(e){if(e.length===0)return k({type:"EMPTY_INPUT",message:"any() requires at least one Result"});let t=null;for(let n of e){if(n.ok)return n;t||(t=n)}return t}async function Xe(e){return e.length===0?k({type:"EMPTY_INPUT",message:"anyAsync() requires at least one Result"}):new Promise(t=>{let n=!1,a=e.length,d=null;for(let A of e)Promise.resolve(A).catch(x=>k({type:"PROMISE_REJECTED",cause:x},{cause:{type:"PROMISE_REJECTION",reason:x}})).then(x=>{if(!n){if(x.ok){n=!0,t(x);return}d||(d=x),a--,a===0&&t(d)}})})}async function Ye(e){let t=await Promise.all(e.map(d=>Promise.resolve(d).then(A=>({status:"result",result:A})).catch(A=>({status:"rejected",error:{type:"PROMISE_REJECTED",cause:A},cause:{type:"PROMISE_REJECTION",reason:A}})))),n=[],a=[];for(let d of t)d.status==="rejected"?a.push({error:d.error,cause:d.cause}):d.result.ok?n.push(d.result.value):a.push({error:d.result.error,cause:d.result.cause});return a.length>0?k(a):g(n)}export{ee as EARLY_EXIT_SYMBOL,F as STEP_TIMEOUT_MARKER,G as UnwrapError,Fe as all,Ne as allAsync,Ve as allSettled,Ye as allSettledAsync,he as andThen,We as any,Xe as anyAsync,Oe as bimap,ie as createEarlyExit,k as err,Ce as from,ge as fromNullable,xe as fromPromise,ae as getStepTimeoutMeta,pe as isEarlyExit,ke as isErr,Te as isOk,z as isStepTimeoutError,ue as isUnexpectedError,Ae as map,be as mapError,Ie as mapErrorTry,Me as mapTry,Pe as match,g as ok,Ue as orElse,De as orElseAsync,Le as partition,Ke as recover,je as recoverAsync,Z as run,_e as tap,ve as tapError,Se as tryAsync,de as unwrap,fe as unwrapOr,Re as unwrapOrElse};
2
2
  //# sourceMappingURL=core.js.map