UNPKG

effect

Version:

The missing standard library for TypeScript, for writing production-grade software.

1,580 lines (1,550 loc) 936 kB
/** * @since 2.0.0 */ import type * as RA from "./Array.js" import type * as Cause from "./Cause.js" import type * as Chunk from "./Chunk.js" import type * as Clock from "./Clock.js" import type { ConfigProvider } from "./ConfigProvider.js" import type { Console } from "./Console.js" import type * as Context from "./Context.js" import type * as Deferred from "./Deferred.js" import type * as Duration from "./Duration.js" import type * as Either from "./Either.js" import type { Equivalence } from "./Equivalence.js" import type { ExecutionPlan } from "./ExecutionPlan.js" import type { ExecutionStrategy } from "./ExecutionStrategy.js" import type * as Exit from "./Exit.js" import type * as Fiber from "./Fiber.js" import type * as FiberId from "./FiberId.js" import type * as FiberRef from "./FiberRef.js" import type * as FiberRefs from "./FiberRefs.js" import type * as FiberRefsPatch from "./FiberRefsPatch.js" import type * as FiberStatus from "./FiberStatus.js" import type { LazyArg } from "./Function.js" import { dual } from "./Function.js" import type * as HashMap from "./HashMap.js" import type * as HashSet from "./HashSet.js" import type { TypeLambda } from "./HKT.js" import * as internalCause from "./internal/cause.js" import * as console_ from "./internal/console.js" import { TagProto } from "./internal/context.js" import * as effect from "./internal/core-effect.js" import * as core from "./internal/core.js" import * as defaultServices from "./internal/defaultServices.js" import * as circular from "./internal/effect/circular.js" import * as internalExecutionPlan from "./internal/executionPlan.js" import * as fiberRuntime from "./internal/fiberRuntime.js" import * as layer from "./internal/layer.js" import * as option_ from "./internal/option.js" import * as query from "./internal/query.js" import * as runtime_ from "./internal/runtime.js" import * as schedule_ from "./internal/schedule.js" import * as internalTracer from "./internal/tracer.js" import type * as Layer from "./Layer.js" import type * as LogLevel from "./LogLevel.js" import type * as ManagedRuntime from "./ManagedRuntime.js" import type * as Metric from "./Metric.js" import type * as MetricLabel from "./MetricLabel.js" import type * as Option from "./Option.js" import type { Pipeable } from "./Pipeable.js" import type { Predicate, Refinement } from "./Predicate.js" import * as Random from "./Random.js" import type * as Ref from "./Ref.js" import * as Request from "./Request.js" import type { RequestBlock } from "./RequestBlock.js" import type { RequestResolver } from "./RequestResolver.js" import type * as Runtime from "./Runtime.js" import type * as RuntimeFlags from "./RuntimeFlags.js" import type * as RuntimeFlagsPatch from "./RuntimeFlagsPatch.js" import type * as Schedule from "./Schedule.js" import * as Scheduler from "./Scheduler.js" import type * as Scope from "./Scope.js" import type * as Supervisor from "./Supervisor.js" import type * as Tracer from "./Tracer.js" import type { Concurrency, Contravariant, Covariant, EqualsWith, NoExcessProperties, NoInfer, NotFunction } from "./Types.js" import type * as Unify from "./Unify.js" import { isGeneratorFunction, type YieldWrap } from "./Utils.js" /** * @since 2.0.0 * @category Symbols */ export const EffectTypeId: unique symbol = core.EffectTypeId /** * @since 2.0.0 * @category Symbols */ export type EffectTypeId = typeof EffectTypeId /** * The `Effect` interface defines a value that describes a workflow or job, * which can succeed or fail. * * **Details** * * The `Effect` interface represents a computation that can model a workflow * involving various types of operations, such as synchronous, asynchronous, * concurrent, and parallel interactions. It operates within a context of type * `R`, and the result can either be a success with a value of type `A` or a * failure with an error of type `E`. The `Effect` is designed to handle complex * interactions with external resources, offering advanced features such as * fiber-based concurrency, scheduling, interruption handling, and scalability. * This makes it suitable for tasks that require fine-grained control over * concurrency and error management. * * To execute an `Effect` value, you need a `Runtime`, which provides the * environment necessary to run and manage the computation. * * @since 2.0.0 * @category Models */ export interface Effect<out A, out E = never, out R = never> extends Effect.Variance<A, E, R>, Pipeable { readonly [Unify.typeSymbol]?: unknown readonly [Unify.unifySymbol]?: EffectUnify<this> readonly [Unify.ignoreSymbol]?: EffectUnifyIgnore [Symbol.iterator](): EffectGenerator<Effect<A, E, R>> } /** * @since 3.0.0 * @category Models */ export interface EffectGenerator<T extends Effect<any, any, any>> { next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Effect.Success<T>> } /** * @since 2.0.0 * @category Models */ export interface EffectUnify<A extends { [Unify.typeSymbol]?: any }> extends Either.EitherUnify<A>, Option.OptionUnify<A>, Context.TagUnify<A> { Effect?: () => A[Unify.typeSymbol] extends Effect<infer A0, infer E0, infer R0> | infer _ ? Effect<A0, E0, R0> : never } /** * @category Models * @since 2.0.0 */ export interface EffectUnifyIgnore { Tag?: true Option?: true Either?: true } /** * @category Type lambdas * @since 2.0.0 */ export interface EffectTypeLambda extends TypeLambda { readonly type: Effect<this["Target"], this["Out1"], this["Out2"]> } /** * @since 2.0.0 * @category Models */ export interface Blocked<out A, out E> extends Effect<A, E> { readonly _op: "Blocked" readonly effect_instruction_i0: RequestBlock readonly effect_instruction_i1: Effect<A, E> } /** * @since 2.0.0 * @category Models */ declare module "./Context.js" { interface Tag<Id, Value> extends Effect<Value, never, Id> { [Symbol.iterator](): EffectGenerator<Tag<Id, Value>> } interface Reference<Id, Value> extends Effect<Value> { [Symbol.iterator](): EffectGenerator<Reference<Id, Value>> } interface TagUnifyIgnore { Effect?: true Either?: true Option?: true } } /** * @since 2.0.0 * @category Models */ declare module "./Either.js" { interface Left<E, A> extends Effect<A, E> { readonly _tag: "Left" [Symbol.iterator](): EffectGenerator<Left<E, A>> } interface Right<E, A> extends Effect<A, E> { readonly _tag: "Right" [Symbol.iterator](): EffectGenerator<Right<E, A>> } interface EitherUnifyIgnore { Effect?: true Tag?: true Option?: true } } /** * @since 2.0.0 * @category Models */ declare module "./Option.js" { interface None<A> extends Effect<A, Cause.NoSuchElementException> { readonly _tag: "None" [Symbol.iterator](): EffectGenerator<None<A>> } interface Some<A> extends Effect<A, Cause.NoSuchElementException> { readonly _tag: "Some" [Symbol.iterator](): EffectGenerator<Some<A>> } interface OptionUnifyIgnore { Effect?: true Tag?: true Either?: true } } /** * @since 2.0.0 */ export declare namespace Effect { /** * @since 2.0.0 * @category Models */ export interface Variance<out A, out E, out R> { readonly [EffectTypeId]: VarianceStruct<A, E, R> } /** * @since 2.0.0 * @category Models */ export interface VarianceStruct<out A, out E, out R> { readonly _V: string readonly _A: Covariant<A> readonly _E: Covariant<E> readonly _R: Covariant<R> } /** * @since 2.0.0 * @category Effect Type Extractors */ export type Context<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _R : never /** * @since 2.0.0 * @category Effect Type Extractors */ export type Error<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _E : never /** * @since 2.0.0 * @category Effect Type Extractors */ export type Success<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _A : never /** * @since 3.15.5 * @category Effect Type Extractors */ export type AsEffect<T extends Effect<any, any, any>> = Effect< T extends Effect<infer _A, infer _E, infer _R> ? _A : never, T extends Effect<infer _A, infer _E, infer _R> ? _E : never, T extends Effect<infer _A, infer _E, infer _R> ? _R : never > extends infer Q ? Q : never } /** * Checks if a given value is an `Effect` value. * * **When to Use** * * This function can be useful for checking the type of a value before * attempting to operate on it as an `Effect` value. For example, you could use * `Effect.isEffect` to check the type of a value before using it as an argument * to a function that expects an `Effect` value. * * @since 2.0.0 * @category Guards */ export const isEffect: (u: unknown) => u is Effect<unknown, unknown, unknown> = core.isEffect /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @since 2.0.0 * @category Caching */ export const cachedWithTTL: { /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @since 2.0.0 * @category Caching */ (timeToLive: Duration.DurationInput): <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E>, never, R> /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @since 2.0.0 * @category Caching */ <A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<Effect<A, E>, never, R> } = circular.cached /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @since 2.0.0 * @category Caching */ export const cachedInvalidateWithTTL: { /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @since 2.0.0 * @category Caching */ (timeToLive: Duration.DurationInput): <A, E, R>( self: Effect<A, E, R> ) => Effect<[Effect<A, E>, Effect<void>], never, R> /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @since 2.0.0 * @category Caching */ <A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<[Effect<A, E>, Effect<void>], never, R> } = circular.cachedInvalidateWithTTL /** * Returns an effect that lazily computes a result and caches it for subsequent * evaluations. * * **Details** * * This function wraps an effect and ensures that its result is computed only * once. Once the result is computed, it is cached, meaning that subsequent * evaluations of the same effect will return the cached result without * re-executing the logic. * * **When to Use** * * Use this function when you have an expensive or time-consuming operation that * you want to avoid repeating. The first evaluation will compute the result, * and all following evaluations will immediately return the cached value, * improving performance and reducing unnecessary work. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * console.log("non-cached version:") * yield* expensiveTask.pipe(Effect.andThen(Console.log)) * yield* expensiveTask.pipe(Effect.andThen(Console.log)) * console.log("cached version:") * const cached = yield* Effect.cached(expensiveTask) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * Effect.runFork(program) * // Output: * // non-cached version: * // expensive task... * // result 1 * // expensive task... * // result 2 * // cached version: * // expensive task... * // result 3 * // result 3 * ``` * * @see {@link cachedWithTTL} for a similar function that includes a * time-to-live duration for the cached value. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @since 2.0.0 * @category Caching */ export const cached: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E, R>> = effect.memoize /** * Returns a memoized version of a function with effects, reusing results for * the same inputs. * * **Details** * * This function creates a memoized version of a given function that performs an * effect. Memoization ensures that once a result is computed for a specific * input, it is stored and reused for subsequent calls with the same input, * reducing the need to recompute the result. * * The function can optionally take an `Equivalence` parameter to * determine how inputs are compared for caching purposes. * * **When to Use** * * Use this function when you have a function that performs an effect and you * want to avoid recomputing the result for the same input multiple times. * * It's ideal for functions that produce deterministic results based on their * inputs, and you want to improve performance by caching the output. * * This is particularly useful in scenarios where the function involves * expensive calculations or operations that should be avoided after the first * execution with the same parameters. * * **Example** * * ```ts * import { Effect, Random } from "effect" * * const program = Effect.gen(function* () { * const randomNumber = (n: number) => Random.nextIntBetween(1, n) * console.log("non-memoized version:") * console.log(yield* randomNumber(10)) * console.log(yield* randomNumber(10)) * * console.log("memoized version:") * const memoized = yield* Effect.cachedFunction(randomNumber) * console.log(yield* memoized(10)) * console.log(yield* memoized(10)) * }) * * Effect.runFork(program) * // Example Output: * // non-memoized version: * // 2 * // 8 * // memoized version: * // 5 * // 5 * ``` * * @since 2.0.0 * @category Caching */ export const cachedFunction: <A, B, E, R>( f: (a: A) => Effect<B, E, R>, eq?: Equivalence<A> ) => Effect<(a: A) => Effect<B, E, R>> = circular.cachedFunction /** * Returns an effect that executes only once, regardless of how many times it's * called. * * **Details** * * This function ensures that a specific effect is executed only a single time, * no matter how many times it is invoked. The result of the effect will be * cached, and subsequent calls to the effect will immediately return the cached * result without re-executing the original logic. * * **When to Use** * * Use this function when you need to perform a task only once, regardless of * how many times the effect is triggered. It's particularly useful when you * have initialization tasks, logging, or other one-time actions that should not * be repeated. This can help optimize performance and avoid redundant actions. * * **Example** * * ```ts * import { Effect, Console } from "effect" * * const program = Effect.gen(function* () { * const task1 = Console.log("task1") * yield* Effect.repeatN(task1, 2) * const task2 = yield* Effect.once(Console.log("task2")) * yield* Effect.repeatN(task2, 2) * }) * * Effect.runFork(program) * // Output: * // task1 * // task1 * // task1 * // task2 * ``` * * @since 2.0.0 * @category Caching */ export const once: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<void, E, R>> = effect.once /** * Combines multiple effects into one, returning results based on the input * structure. * * **Details** * * Use this function when you need to run multiple effects and combine their * results into a single output. It supports tuples, iterables, structs, and * records, making it flexible for different input types. * * For instance, if the input is a tuple: * * ```ts skip-type-checking * // ┌─── a tuple of effects * // ▼ * Effect.all([effect1, effect2, ...]) * ``` * * the effects are executed sequentially, and the result is a new effect * containing the results as a tuple. The results in the tuple match the order * of the effects passed to `Effect.all`. * * **Concurrency** * * You can control the execution order (e.g., sequential vs. concurrent) using * the `concurrency` option. * * **Short-Circuiting Behavior** * * This function stops execution on the first error it encounters, this is * called "short-circuiting". If any effect in the collection fails, the * remaining effects will not run, and the error will be propagated. To change * this behavior, you can use the `mode` option, which allows all effects to run * and collect results as `Either` or `Option`. * * **The `mode` option** * * The `{ mode: "either" }` option changes the behavior of `Effect.all` to * ensure all effects run, even if some fail. Instead of stopping on the first * failure, this mode collects both successes and failures, returning an array * of `Either` instances where each result is either a `Right` (success) or a * `Left` (failure). * * Similarly, the `{ mode: "validate" }` option uses `Option` to indicate * success or failure. Each effect returns `None` for success and `Some` with * the error for failure. * * **Example** (Combining Effects in Tuples) * * ```ts * import { Effect, Console } from "effect" * * const tupleOfEffects = [ * Effect.succeed(42).pipe(Effect.tap(Console.log)), * Effect.succeed("Hello").pipe(Effect.tap(Console.log)) * ] as const * * // ┌─── Effect<[number, string], never, never> * // ▼ * const resultsAsTuple = Effect.all(tupleOfEffects) * * Effect.runPromise(resultsAsTuple).then(console.log) * // Output: * // 42 * // Hello * // [ 42, 'Hello' ] * ``` * * **Example** (Combining Effects in Iterables) * * ```ts * import { Effect, Console } from "effect" * * const iterableOfEffects: Iterable<Effect.Effect<number>> = [1, 2, 3].map( * (n) => Effect.succeed(n).pipe(Effect.tap(Console.log)) * ) * * // ┌─── Effect<number[], never, never> * // ▼ * const resultsAsArray = Effect.all(iterableOfEffects) * * Effect.runPromise(resultsAsArray).then(console.log) * // Output: * // 1 * // 2 * // 3 * // [ 1, 2, 3 ] * ``` * * **Example** (Combining Effects in Structs) * * ```ts * import { Effect, Console } from "effect" * * const structOfEffects = { * a: Effect.succeed(42).pipe(Effect.tap(Console.log)), * b: Effect.succeed("Hello").pipe(Effect.tap(Console.log)) * } * * // ┌─── Effect<{ a: number; b: string; }, never, never> * // ▼ * const resultsAsStruct = Effect.all(structOfEffects) * * Effect.runPromise(resultsAsStruct).then(console.log) * // Output: * // 42 * // Hello * // { a: 42, b: 'Hello' } * ``` * * **Example** (Combining Effects in Records) * * ```ts * import { Effect, Console } from "effect" * * const recordOfEffects: Record<string, Effect.Effect<number>> = { * key1: Effect.succeed(1).pipe(Effect.tap(Console.log)), * key2: Effect.succeed(2).pipe(Effect.tap(Console.log)) * } * * // ┌─── Effect<{ [x: string]: number; }, never, never> * // ▼ * const resultsAsRecord = Effect.all(recordOfEffects) * * Effect.runPromise(resultsAsRecord).then(console.log) * // Output: * // 1 * // 2 * // { key1: 1, key2: 2 } * ``` * * **Example** (Short-Circuiting Behavior) * * ```ts * import { Effect, Console } from "effect" * * const program = Effect.all([ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * // Won't execute due to earlier failure * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ]) * * Effect.runPromiseExit(program).then(console.log) * // Output: * // Task1 * // { * // _id: 'Exit', * // _tag: 'Failure', * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' } * // } * ``` * * **Example** (Collecting Results with `mode: "either"`) * * ```ts * import { Effect, Console } from "effect" * * const effects = [ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ] * * const program = Effect.all(effects, { mode: "either" }) * * Effect.runPromiseExit(program).then(console.log) * // Output: * // Task1 * // Task3 * // { * // _id: 'Exit', * // _tag: 'Success', * // value: [ * // { _id: 'Either', _tag: 'Right', right: 'Task1' }, * // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' }, * // { _id: 'Either', _tag: 'Right', right: 'Task3' } * // ] * // } * ``` * * **Example** (Collecting Results with `mode: "validate"`) * * ```ts * import { Effect, Console } from "effect" * * const effects = [ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ] * * const program = Effect.all(effects, { mode: "validate" }) * * Effect.runPromiseExit(program).then((result) => console.log("%o", result)) * // Output: * // Task1 * // Task3 * // { * // _id: 'Exit', * // _tag: 'Failure', * // cause: { * // _id: 'Cause', * // _tag: 'Fail', * // failure: [ * // { _id: 'Option', _tag: 'None' }, * // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' }, * // { _id: 'Option', _tag: 'None' } * // ] * // } * // } * ``` * * @see {@link forEach} for iterating over elements and applying an effect. * @see {@link allWith} for a data-last version of this function. * * @since 2.0.0 * @category Collecting */ export const all: < const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>, O extends NoExcessProperties<{ readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined readonly concurrentFinalizers?: boolean | undefined }, O> >(arg: Arg, options?: O) => All.Return<Arg, O> = fiberRuntime.all /** * A data-last version of {@link all}, designed for use in pipelines. * * **When to Use** * * This function enables you to combine multiple effects and customize execution * options such as concurrency levels. This version is useful in functional * pipelines where you first define your data and then apply operations to it. * * **Example** * * ```ts * import { Effect, pipe } from "effect" * * const task1 = Effect.succeed(1).pipe( * Effect.delay("200 millis"), * Effect.tap(Effect.log("task1 done")) * ) * * const task2 = Effect.succeed("hello").pipe( * Effect.delay("100 millis"), * Effect.tap(Effect.log("task2 done")) * ) * * const program = pipe( * [task1, task2], * // Run both effects concurrently using the concurrent option * Effect.allWith({ concurrency: 2 }) * ) * * Effect.runPromise(program).then(console.log) * // Output: * // timestamp=... level=INFO fiber=#3 message="task2 done" * // timestamp=... level=INFO fiber=#2 message="task1 done" * // [ 1, 'hello' ] * ``` * * @since 2.0.0 * @category Collecting */ export const allWith: < O extends NoExcessProperties<{ readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined readonly concurrentFinalizers?: boolean | undefined }, O> >( options?: O ) => <const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>>( arg: Arg ) => All.Return<Arg, O> = fiberRuntime.allWith /** * @since 2.0.0 */ export declare namespace All { /** * @since 2.0.0 */ export type EffectAny = Effect<any, any, any> /** * @since 2.0.0 */ export type ReturnIterable<T extends Iterable<EffectAny>, Discard extends boolean, Mode> = [T] extends [Iterable<Effect.Variance<infer R0, infer L0, infer R>>] ? Effect< Discard extends true ? void : Mode extends "either" ? Array<Either.Either<R0, L0>> : Array<R0>, Mode extends "either" ? never : Mode extends "validate" ? Array<Option.Option<L0>> : L0, R > : never /** * @since 2.0.0 */ export type ReturnTuple<T extends ReadonlyArray<unknown>, Discard extends boolean, Mode> = Effect< Discard extends true ? void : T[number] extends never ? [] : Mode extends "either" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Either.Either<_A, _E> : never } : { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? _A : never }, Mode extends "either" ? never : T[number] extends never ? never : Mode extends "validate" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Option.Option<_E> : never } : [T[number]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E } }] ? E : never, T[number] extends never ? never : [T[number]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R } }] ? R : never > extends infer X ? X : never /** * @since 2.0.0 */ export type ReturnObject<T, Discard extends boolean, Mode> = [T] extends [{ [K: string]: EffectAny }] ? Effect< Discard extends true ? void : Mode extends "either" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Either.Either<_A, _E> : never } : { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? _A : never }, Mode extends "either" ? never : keyof T extends never ? never : Mode extends "validate" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Option.Option<_E> : never } : [T[keyof T]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E } }] ? E : never, keyof T extends never ? never : [T[keyof T]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R } }] ? R : never > : never /** * @since 2.0.0 */ export type IsDiscard<A> = [Extract<A, { readonly discard: true }>] extends [never] ? false : true /** * @since 2.0.0 */ export type ExtractMode<A> = [A] extends [{ mode: infer M }] ? M : "default" /** * @since 2.0.0 */ export type Return< Arg extends Iterable<EffectAny> | Record<string, EffectAny>, O extends NoExcessProperties<{ readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined readonly concurrentFinalizers?: boolean | undefined }, O> > = [Arg] extends [ReadonlyArray<EffectAny>] ? ReturnTuple<Arg, IsDiscard<O>, ExtractMode<O>> : [Arg] extends [Iterable<EffectAny>] ? ReturnIterable<Arg, IsDiscard<O>, ExtractMode<O>> : [Arg] extends [Record<string, EffectAny>] ? ReturnObject<Arg, IsDiscard<O>, ExtractMode<O>> : never } /** * Evaluates and runs each effect in the iterable, collecting only the * successful results while discarding failures. * * **Details** * * This function function processes an iterable of effects and runs each one. If * an effect is successful, its result is collected; if it fails, the result is * discarded. This ensures that only successful outcomes are kept. * * **Options** * * The function also allows you to customize how the effects are handled by * specifying options such as concurrency, batching, and how finalizers behave. * These options provide flexibility in running the effects concurrently or * adjusting other execution details. * * **Example** * * ```ts * import { Effect } from "effect" * * const tasks = [ * Effect.succeed(1), * Effect.fail("Error 1"), * Effect.succeed(2), * Effect.fail("Error 2") * ] * * const program = Effect.gen(function*() { * const successfulResults = yield* Effect.allSuccesses(tasks) * console.log(successfulResults) * }) * * Effect.runFork(program) * // Output: [1, 2] * * ``` * * @since 2.0.0 * @category Collecting */ export const allSuccesses: <X extends Effect<any, any, any>>( elements: Iterable<X>, options?: | { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly concurrentFinalizers?: boolean | undefined } | undefined ) => Effect<Array<Effect.Success<X>>, never, Effect.Context<X>> = fiberRuntime.allSuccesses /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * **Example** * * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * Effect.runFork(program) * // Output: [5, 6] * ``` * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @since 2.0.0 * @category Collecting */ export const dropUntil: { /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * **Example** * * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * Effect.runFork(program) * // Output: [5, 6] * ``` * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @since 2.0.0 * @category Collecting */ <A, E, R>(predicate: (a: NoInfer<A>, i: number) => Effect<boolean, E, R>): (elements: Iterable<A>) => Effect<Array<A>, E, R> /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * **Example** * * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * Effect.runFork(program) * // Output: [5, 6] * ``` * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @since 2.0.0 * @category Collecting */ <A, E, R>( elements: Iterable<A>, predicate: (a: A, i: number) => Effect<boolean, E, R> ): Effect<Array<A>, E, R> } = effect.dropUntil /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * **Example** * * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropWhile(numbers, predicate) * console.log(result) * }) * * Effect.runFork(program) * // Output: [4, 5, 6] * ``` * * @see {@link dropUntil} for a similar function that drops elements until the * predicate returns `true`. * * @since 2.0.0 * @category Collecting */ export const dropWhile: { /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * **Example** * * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropWhile(numbers, predicate) * console.log(result) * }) * * Effect.runFork(program) * // Output: [4, 5, 6] * ``` * * @see {@link dropUntil} for a similar function that drops elements until the * predicate returns `true`. * * @since 2.0.0 * @category Collecting */ <A, E, R>(predicate: (a: NoInfer<A>, i: number) => Effect<boolean, E, R>): (elements: Iterable<A>) => Effect<Array<A>, E, R> /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * **Example** * * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: nu