1/**
2 * Provides low-level building blocks for streaming data through Effect.
3 *
4 * A `Channel` can read input elements, write output elements, fail with a typed
5 * error, and finish with a typed result while managing resources safely.
6 * Streams and sinks are built on channels, so most application code uses those
7 * higher-level modules instead. This module is useful when implementing stream
8 * operators or specialized streaming workflows.
9 *
10 * @since 2.0.0
11 */
12// @effect-diagnostics returnEffectInGen:off
13import * as Arr from "./Array.ts"
14import * as Cause from "./Cause.ts"
15import * as Chunk from "./Chunk.ts"
16import * as Context from "./Context.ts"
17import * as Effect from "./Effect.ts"
18import * as Exit from "./Exit.ts"
19import * as Fiber from "./Fiber.ts"
20import type * as Filter from "./Filter.ts"
21import type { LazyArg } from "./Function.ts"
22import { constant, constTrue, constVoid, dual, identity as identity_ } from "./Function.ts"
23import * as Count from "./internal/count.ts"
24import { ClockRef, endSpan } from "./internal/effect.ts"
25import { addSpanStackTrace } from "./internal/tracer.ts"
26import * as Iterable from "./Iterable.ts"
27import * as Latch from "./Latch.ts"
28import * as Layer from "./Layer.ts"
29import type { Severity } from "./LogLevel.ts"
30import * as MutableRef from "./MutableRef.ts"
31import * as Option from "./Option.ts"
32import type { Pipeable } from "./Pipeable.ts"
33import { pipeArguments } from "./Pipeable.ts"
34import type * as Predicate from "./Predicate.ts"
35import { hasProperty, isTagged } from "./Predicate.ts"
36import * as PubSub from "./PubSub.ts"
37import * as Pull from "./Pull.ts"
38import * as Queue from "./Queue.ts"
39import { TracerTimingEnabled } from "./References.ts"
40import * as Result from "./Result.ts"
41import * as Schedule from "./Schedule.ts"
42import * as Scope from "./Scope.ts"
43import * as Semaphore from "./Semaphore.ts"
44import * as String from "./String.ts"
45import * as Take from "./Take.ts"
46import { ParentSpan, type SpanOptions } from "./Tracer.ts"
47import type * as Types from "./Types.ts"
48import type * as Unify from "./Unify.ts"
49
50/**
51 * String literal type used as the unique brand for `Channel` values.
52 *
53 * @category type IDs
54 * @since 4.0.0
55 */
56export type TypeId = "~effect/Channel"
57
58/**
59 * Runtime identifier stored on `Channel` values and used by `isChannel` to
60 * recognize them.
61 *
62 * @category type IDs
63 * @since 4.0.0
64 */
65export const TypeId: TypeId = "~effect/Channel"
66
67/**
68 * Checks whether a value is a `Channel`.
69 *
70 * **Example** (Checking for channels)
71 *
72 * ```ts import.meta.vitest
73 * import { Channel } from "effect"
74 *
75 * const channel = Channel.succeed(42)
76 * Channel.isChannel(channel) // => true
77 * Channel.isChannel("not a channel") // => false
78 * ```
79 *
80 * @category guards
81 * @since 3.5.4
82 */
83export const isChannel = (
84 u: unknown
85): u is Channel<unknown, unknown, unknown, unknown, unknown, unknown, unknown> => hasProperty(u, TypeId)
86
87/**
88 * A `Channel` is a nexus of I/O operations, which supports both reading and
89 * writing. A channel may read values of type `InElem` and write values of type
90 * `OutElem`. When the channel finishes, it yields a value of type `OutDone`. A
91 * channel may fail with a value of type `OutErr`.
92 *
93 * **Details**
94 *
95 * Channels are the foundation of Streams: both streams and sinks are built on
96 * channels. Most users shouldn't have to use channels directly, as streams and
97 * sinks are much more convenient and cover all common use cases. However, when
98 * adding new stream and sink operators, or doing something highly specialized,
99 * it may be useful to use channels directly.
100 *
101 * Channels compose in a variety of ways:
102 *
103 * - **Piping**: One channel can be piped to another channel, assuming the
104 * input type of the second is the same as the output type of the first.
105 * - **Sequencing**: The terminal value of one channel can be used to create
106 * another channel, and both the first channel and the function that makes
107 * the second channel can be composed into a channel.
108 * - **Concatenating**: The output of one channel can be used to create other
109 * channels, which are all concatenated together. The first channel and the
110 * function that makes the other channels can be composed into a channel.
111 *
112 * **Example** (Typing channels)
113 *
114 * ```ts import.meta.vitest
115 * import { Channel, Effect } from "effect"
116 *
117 * // A channel that outputs numbers and requires no environment
118 * type NumberChannel = Channel.Channel<number>
119 *
120 * // A channel that outputs strings, can fail with Error, completes with boolean
121 * type StringChannel = Channel.Channel<string, Error, boolean>
122 *
123 * // A channel with all type parameters specified
124 * type FullChannel = Channel.Channel<
125 * string, // OutElem - output elements
126 * Error, // OutErr - output errors
127 * number, // OutDone - completion value
128 * number, // InElem - input elements
129 * string, // InErr - input errors
130 * boolean, // InDone - input completion
131 * { db: string } // Env - required environment
132 * >
133 *
134 * const channel: NumberChannel = Channel.succeed(1)
135 * Effect.runSync(Channel.runCollect(channel)) // => [1]
136 * ```
137 *
138 * @category models
139 * @since 2.0.0
140 */
141export interface Channel<
142 out OutElem,
143 out OutErr = never,
144 out OutDone = void,
145 in InElem = unknown,
146 in InErr = unknown,
147 in InDone = unknown,
148 out Env = never
149> extends Variance<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>, Pipeable {
150 [Unify.typeSymbol]?: unknown
151 [Unify.unifySymbol]?: ChannelUnify<this>
152 [Unify.ignoreSymbol]?: ChannelUnifyIgnore
153}
154
155/**
156 * Type-level unification support for `Channel` values.
157 *
158 * **Details**
159 *
160 * This preserves all `Channel` type parameters when `Unify` normalizes unions
161 * or generic return types that include channels. Users normally do not need to
162 * reference this interface directly.
163 *
164 * @category models
165 * @since 2.0.0
166 */
167export interface ChannelUnify<A extends { [Unify.typeSymbol]?: any }> extends Effect.EffectUnify<A> {
168 Channel?: () => A[Unify.typeSymbol] extends
169 | Channel<infer OutElem, infer OutErr, infer OutDone, infer InElem, infer InErr, infer InDone, infer Env>
170 | infer _ ? Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
171 : never
172}
173
174/**
175 * Marker used by `Unify` while resolving `Channel` values.
176 *
177 * **Details**
178 *
179 * It prevents the inherited `Effect` unifier from being selected when the
180 * channel-specific unifier should preserve `Channel` input, output, and
181 * environment type parameters. Users normally do not need to reference this
182 * interface directly.
183 *
184 * @category models
185 * @since 2.0.0
186 */
187export interface ChannelUnifyIgnore {
188 Effect?: true
189}
190
191type TagsWithReason<E> = {
192 [T in Types.Tags<E>]: Types.ReasonTags<Types.ExtractTag<E, T>> extends never ? never : T
193}[Types.Tags<E>]
194
195/**
196 * Phantom variance marker for the type parameters of `Channel`.
197 *
198 * **Details**
199 *
200 * Output element, output error, output done, and environment types are
201 * covariant. Input element, input error, and input done types are
202 * contravariant. This is type-level machinery and is not used directly at
203 * runtime.
204 *
205 * @category models
206 * @since 2.0.0
207 */
208export interface Variance<
209 out OutElem,
210 out OutErr,
211 out OutDone,
212 in InElem,
213 in InErr,
214 in InDone,
215 out Env
216> {
217 readonly [TypeId]: VarianceStruct<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
218}
219/**
220 * Structural encoding used by `Variance` to record each `Channel` type
221 * parameter's variance.
222 *
223 * **Details**
224 *
225 * The `_OutElem`, `_OutErr`, `_OutDone`, and `_Env` fields are covariant; the
226 * `_InElem`, `_InErr`, and `_InDone` fields are contravariant. Users normally
227 * do not need to reference this interface directly.
228 *
229 * @category models
230 * @since 2.0.0
231 */
232export interface VarianceStruct<
233 out OutElem,
234 out OutErr,
235 out OutDone,
236 in InElem,
237 in InErr,
238 in InDone,
239 out Env
240> {
241 _Env: Types.Covariant<Env>
242 _InErr: Types.Contravariant<InErr>
243 _InElem: Types.Contravariant<InElem>
244 _InDone: Types.Contravariant<InDone>
245 _OutErr: Types.Covariant<OutErr>
246 _OutElem: Types.Covariant<OutElem>
247 _OutDone: Types.Covariant<OutDone>
248}
249
250const ChannelProto = {
251 [TypeId]: {
252 _Env: identity_,
253 _InErr: identity_,
254 _InElem: identity_,
255 _OutErr: identity_,
256 _OutElem: identity_
257 },
258 pipe() {
259 return pipeArguments(this, arguments)
260 }
261}
262
263// -----------------------------------------------------------------------------
264// Constructors
265// -----------------------------------------------------------------------------
266
267/**
268 * Creates a `Channel` from a transformation function that operates on upstream pulls.
269 *
270 * **Example** (Creating channels from transforms)
271 *
272 * ```ts import.meta.vitest
273 * import { Channel, Effect } from "effect"
274 *
275 * const channel = Channel.fromTransform((upstream, scope) =>
276 * Effect.succeed(upstream)
277 * )
278 * await Effect.runPromise(Channel.runCollect(channel)) // => []
279 * ```
280 *
281 * @category constructors
282 * @since 4.0.0
283 */
284export const fromTransform = <OutElem, OutErr, OutDone, InElem, InErr, InDone, EX, EnvX, Env>(
285 transform: (
286 upstream: Pull.Pull<InElem, InErr, InDone>,
287 scope: Scope.Scope
288 ) => Effect.Effect<Pull.Pull<OutElem, OutErr, OutDone, EnvX>, EX, Env>
289): Channel<
290 OutElem,
291 Pull.ExcludeDone<OutErr> | EX,
292 OutDone,
293 InElem,
294 InErr,
295 InDone,
296 Env | EnvX
297> => {
298 const self = Object.create(ChannelProto)
299 self.transform = (upstream: any, scope: Scope.Scope) =>
300 Effect.catchCause(transform(upstream, scope), (cause) => Effect.succeed(Effect.failCause(cause)))
301 return self
302}
303
304/**
305 * Transforms a Channel by applying a function to its Pull implementation.
306 *
307 * **Example** (Transforming pull behavior)
308 *
309 * ```ts import.meta.vitest
310 * import { Channel, Effect } from "effect"
311 *
312 * // Transform a channel by modifying its pull behavior
313 * const originalChannel = Channel.fromIterable([1, 2, 3])
314 *
315 * const transformedChannel = Channel.transformPull(
316 * originalChannel,
317 * (pull, scope) =>
318 * Effect.succeed(
319 * Effect.map(pull, (value) => value * 2)
320 * )
321 * )
322 * await Effect.runPromise(Channel.runCollect(transformedChannel)) // => [2, 4, 6]
323 * ```
324 *
325 * @category constructors
326 * @since 4.0.0
327 */
328export const transformPull = <
329 OutElem,
330 OutErr,
331 OutDone,
332 InElem,
333 InErr,
334 InDone,
335 Env,
336 OutElem2,
337 OutErr2,
338 OutDone2,
339 Env2,
340 OutErrX,
341 EnvX
342>(
343 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
344 f: (
345 pull: Pull.Pull<OutElem, OutErr, OutDone>,
346 scope: Scope.Scope
347 ) => Effect.Effect<Pull.Pull<OutElem2, OutErr2, OutDone2, Env2>, OutErrX, EnvX>
348): Channel<
349 OutElem2,
350 Pull.ExcludeDone<OutErr2> | OutErrX,
351 OutDone2,
352 InElem,
353 InErr,
354 InDone,
355 Env | Env2 | EnvX
356> => fromTransform((upstream, scope) => Effect.flatMap(toTransform(self)(upstream, scope), (pull) => f(pull, scope)))
357
358/**
359 * Creates a `Channel` from an `Effect` that produces a `Pull`.
360 *
361 * **Example** (Creating channels from pulls)
362 *
363 * ```ts import.meta.vitest
364 * import { Cause, Channel, Effect } from "effect"
365 *
366 * const channel = Channel.fromPull(Effect.sync(() => {
367 * let emitted = false
368 * return Effect.suspend(() => {
369 * if (emitted) return Cause.done()
370 * emitted = true
371 * return Effect.succeed(42)
372 * })
373 * }))
374 * await Effect.runPromise(Channel.runCollect(channel)) // => [42]
375 * ```
376 *
377 * @category constructors
378 * @since 4.0.0
379 */
380export const fromPull = <OutElem, OutErr, OutDone, EX, EnvX, Env>(
381 effect: Effect.Effect<Pull.Pull<OutElem, OutErr, OutDone, EnvX>, EX, Env>
382): Channel<OutElem, Pull.ExcludeDone<OutErr> | EX, OutDone, unknown, unknown, unknown, Env | EnvX> =>
383 fromTransform((_, __) => effect) as any
384
385/**
386 * Creates a `Channel` from a transformation function that operates on upstream
387 * pulls, but also provides a forked scope that closes when the resulting
388 * Channel completes.
389 *
390 * **When to use**
391 *
392 * Use when building channels that require scoped resource lifecycle management,
393 * providing both the channel scope and a forked scope that automatically closes
394 * when the channel completes.
395 *
396 * @see {@link fromTransform} for a simpler transformation without a forked scope
397 * @category constructors
398 * @since 4.0.0
399 */
400export const fromTransformBracket = <OutElem, OutErr, OutDone, InElem, InErr, InDone, EX, EnvX, Env>(
401 f: (
402 upstream: Pull.Pull<InElem, InErr, InDone>,
403 scope: Scope.Scope,
404 forkedScope: Scope.Scope
405 ) => Effect.Effect<Pull.Pull<OutElem, OutErr, OutDone, EnvX>, EX, Env>
406): Channel<OutElem, Pull.ExcludeDone<OutErr> | EX, OutDone, InElem, InErr, InDone, Env | EnvX> =>
407 fromTransform(
408 Effect.fnUntraced(function*(upstream, scope) {
409 const closableScope = Scope.forkUnsafe(scope)
410 const onCause = (cause: Cause.Cause<EX | OutErr | Cause.Done<OutDone>>) =>
411 Scope.close(closableScope, Pull.doneExitFromCause(cause))
412 const pull = yield* Effect.onError(
413 f(upstream, scope, closableScope),
414 onCause
415 )
416 return Effect.onError(pull, onCause)
417 })
418 )
419
420/**
421 * Converts a `Channel` back to its underlying transformation function.
422 *
423 * **Example** (Extracting channel transforms)
424 *
425 * ```ts import.meta.vitest
426 * import { Channel, Effect } from "effect"
427 *
428 * const channel = Channel.succeed(42)
429 * const transform = Channel.toTransform(channel)
430 * typeof transform // => "function"
431 * Effect.runSync(Channel.runCollect(channel)) // => [42]
432 * ```
433 *
434 * @category destructors
435 * @since 4.0.0
436 */
437export const toTransform = <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
438 channel: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
439): (
440 upstream: Pull.Pull<InElem, InErr, InDone>,
441 scope: Scope.Scope
442) => Effect.Effect<Pull.Pull<OutElem, OutErr, OutDone>, never, Env> => (channel as any).transform
443
444/**
445 * The default chunk size used by channels for batching operations.
446 *
447 * **Example** (Reading the default chunk size)
448 *
449 * ```ts import.meta.vitest
450 * import { Channel } from "effect"
451 *
452 * Channel.DefaultChunkSize // => 4096
453 * ```
454 *
455 * @category constants
456 * @since 4.0.0
457 */
458export const DefaultChunkSize: number = 4096
459
460const asyncQueue = <A, E = never, R = never>(
461 scope: Scope.Scope,
462 f: (queue: Queue.Queue<A, E | Cause.Done>) => Effect.Effect<unknown, E, R | Scope.Scope>,
463 options?: {
464 readonly bufferSize?: number | undefined
465 readonly strategy?: "sliding" | "dropping" | "suspend" | undefined
466 }
467) =>
468 Queue.make<A, E | Cause.Done>({
469 capacity: options?.bufferSize,
470 strategy: options?.strategy
471 }).pipe(
472 Effect.tap((queue) => Scope.addFinalizer(scope, Queue.shutdown(queue))),
473 Effect.tap((queue) => Effect.forkIn(Scope.provide(f(queue), scope), scope))
474 )
475
476/**
477 * Creates a `Channel` that interacts with a callback function using a queue.
478 *
479 * **Example** (Creating channels from callbacks)
480 *
481 * ```ts import.meta.vitest
482 * import { Channel, Effect, Queue } from "effect"
483 *
484 * const channel = Channel.callback<number>((queue) =>
485 * Effect.gen(function*() {
486 * yield* Queue.offer(queue, 1)
487 * yield* Queue.offer(queue, 2)
488 * yield* Queue.offer(queue, 3)
489 * yield* Queue.end(queue)
490 * })
491 * )
492 * await Effect.runPromise(Channel.runCollect(channel)) // => [1, 2, 3]
493 * ```
494 *
495 * @category constructors
496 * @since 4.0.0
497 */
498export const callback = <A, E = never, R = never>(
499 f: (queue: Queue.Queue<A, E | Cause.Done>) => Effect.Effect<unknown, E, R | Scope.Scope>,
500 options?: {
501 readonly bufferSize?: number | undefined
502 readonly strategy?: "sliding" | "dropping" | "suspend" | undefined
503 }
504): Channel<A, E, void, unknown, unknown, unknown, Exclude<R, Scope.Scope>> =>
505 fromTransform((_, scope) => Effect.map(asyncQueue(scope, f, options), Queue.take))
506
507/**
508 * Creates a `Channel` that interacts with a callback function using a queue, emitting arrays.
509 *
510 * **Example** (Creating array channels from callbacks)
511 *
512 * ```ts import.meta.vitest
513 * import { Channel, Effect, Queue } from "effect"
514 *
515 * const channel = Channel.callbackArray<number>(Effect.fn(function*(queue) {
516 * yield* Queue.offer(queue, 1)
517 * yield* Queue.offer(queue, 2)
518 * yield* Queue.end(queue)
519 * }))
520 * await Effect.runPromise(Channel.runCollect(channel)) // => [[1, 2]]
521 * ```
522 *
523 * @category constructors
524 * @since 4.0.0
525 */
526export const callbackArray = <A, E = never, R = never>(
527 f: (queue: Queue.Queue<A, E | Cause.Done>) => Effect.Effect<unknown, E, R | Scope.Scope>,
528 options?: {
529 readonly bufferSize?: number | undefined
530 readonly strategy?: "sliding" | "dropping" | "suspend" | undefined
531 }
532): Channel<Arr.NonEmptyReadonlyArray<A>, E, void, unknown, unknown, unknown, Exclude<R, Scope.Scope>> =>
533 fromTransform((_, scope) => Effect.map(asyncQueue(scope, f, options), Queue.takeAll))
534
535/**
536 * Creates a `Channel` that lazily evaluates to another channel.
537 *
538 * **Example** (Suspending channel creation)
539 *
540 * ```ts import.meta.vitest
541 * import { Channel, Effect } from "effect"
542 *
543 * const channel = Channel.suspend(() => Channel.succeed(42))
544 * Effect.runSync(Channel.runCollect(channel)) // => [42]
545 * ```
546 *
547 * @category constructors
548 * @since 2.0.0
549 */
550export const suspend = <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
551 evaluate: LazyArg<Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>>
552): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env> =>
553 fromTransform((upstream, scope) => Effect.suspend(() => toTransform(evaluate())(upstream, scope)))
554
555/**
556 * Acquires a resource, uses it to build a `Channel`, and guarantees that
557 * `release` runs with the channel's `Exit` when the channel completes, fails,
558 * or is interrupted.
559 *
560 * **Details**
561 *
562 * Acquisition is uninterruptible. If acquisition fails, `use` is not run and
563 * `release` is not registered.
564 *
565 * **Example** (Managing resources with acquire-use-release)
566 *
567 * ```ts import.meta.vitest
568 * import { Channel, Effect } from "effect"
569 *
570 * const released: Array<string> = []
571 * const channel = Channel.acquireUseRelease(
572 * Effect.succeed("resource"),
573 * (resource) => Channel.succeed(resource.toUpperCase()),
574 * (resource, exit) => Effect.sync(() => released.push(resource))
575 * )
576 * const observed = [await Effect.runPromise(Channel.runCollect(channel)), released] // => [["RESOURCE"], ["resource"]]
577 * ```
578 *
579 * @category constructors
580 * @since 2.0.0
581 */
582export const acquireUseRelease = <A, E, R, OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
583 acquire: Effect.Effect<A, E, R>,
584 use: (a: A) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
585 release: (a: A, exit: Exit.Exit<OutDone, OutErr>) => Effect.Effect<unknown>
586): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
587 fromTransformBracket(
588 Effect.fnUntraced(function*(upstream, scope, forkedScope) {
589 let option = Option.none<A>()
590 yield* Scope.addFinalizerExit(forkedScope, (exit) =>
591 Option.isSome(option)
592 ? release(option.value, exit as any)
593 : Effect.void)
594 const value = yield* Effect.uninterruptible(acquire)
595 option = Option.some(value)
596 return yield* toTransform(use(value))(upstream, scope)
597 })
598 )
599
600/**
601 * Acquires a resource, emits the acquired value as a single channel element,
602 * and registers `release` in the channel scope.
603 *
604 * **Details**
605 *
606 * The release action runs when the channel scope closes and receives the scope
607 * exit. If acquisition fails, no element is emitted and `release` is not
608 * registered.
609 *
610 * **Example** (Managing resources with acquire-release)
611 *
612 * ```ts import.meta.vitest
613 * import { Channel, Effect } from "effect"
614 *
615 * const released: Array<string> = []
616 * const channel = Channel.acquireRelease(
617 * Effect.succeed("resource"),
618 * (resource, exit) => Effect.sync(() => released.push(resource))
619 * )
620 * const observed = [await Effect.runPromise(Channel.runCollect(channel)), released] // => [["resource"], ["resource"]]
621 * ```
622 *
623 * @category constructors
624 * @since 4.0.0
625 */
626export const acquireRelease: {
627 <Z>(
628 release: (z: Z, e: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown>
629 ): <E, R>(self: Effect.Effect<Z, E, R>) => Channel<Z, E, void, unknown, unknown, unknown, R>
630 <Z, E, R>(
631 self: Effect.Effect<Z, E, R>,
632 release: (z: Z, e: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown>
633 ): Channel<Z, E, void, unknown, unknown, unknown, R>
634} = dual(2, <Z, E, R>(
635 self: Effect.Effect<Z, E, R>,
636 release: (z: Z, e: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown>
637): Channel<Z, E, void, unknown, unknown, unknown, R> =>
638 unwrap(Effect.map(
639 Effect.acquireRelease(self, release),
640 succeed
641 )))
642
643/**
644 * Creates a `Channel` from an iterator.
645 *
646 * **Example** (Creating channels from iterators)
647 *
648 * ```ts import.meta.vitest
649 * import { Channel, Effect } from "effect"
650 *
651 * const numbers = [1, 2, 3, 4, 5]
652 * const channel = Channel.fromIterator(() => numbers[Symbol.iterator]())
653 * Effect.runSync(Channel.runCollect(channel)) // => [1, 2, 3, 4, 5]
654 * ```
655 *
656 * @category constructors
657 * @since 4.0.0
658 */
659export const fromIterator = <A, L>(iterator: LazyArg<Iterator<A, L>>): Channel<A, never, L> =>
660 fromPull(
661 Effect.sync(() => {
662 const iter = iterator()
663 return Effect.suspend(() => {
664 const state = iter.next()
665 return state.done ? Cause.done(state.value) : Effect.succeed(state.value)
666 })
667 })
668 )
669
670/**
671 * Creates a `Channel` that emits all elements from an array.
672 *
673 * **Example** (Creating channels from arrays)
674 *
675 * ```ts import.meta.vitest
676 * import { Channel, Effect } from "effect"
677 *
678 * const channel = Channel.fromArray([1, 2, 3, 4, 5])
679 * Effect.runSync(Channel.runCollect(channel)) // => [1, 2, 3, 4, 5]
680 * ```
681 *
682 * @category constructors
683 * @since 4.0.0
684 */
685export const fromArray = <A>(array: ReadonlyArray<A>): Channel<A> =>
686 fromPull(Effect.sync(() => {
687 let index = 0
688 return Effect.suspend(() => index >= array.length ? Cause.done() : Effect.succeed(array[index++]))
689 }))
690
691/**
692 * Creates a `Channel` that emits all elements from a chunk.
693 *
694 * **Example** (Creating channels from chunks)
695 *
696 * ```ts import.meta.vitest
697 * import { Channel, Chunk, Effect } from "effect"
698 *
699 * const chunk = Chunk.make(1, 2, 3)
700 * const channel = Channel.fromChunk(chunk)
701 * Effect.runSync(Channel.runCollect(channel)) // => [1, 2, 3]
702 * ```
703 *
704 * @category constructors
705 * @since 4.0.0
706 */
707export const fromChunk = <A>(chunk: Chunk.Chunk<A>): Channel<A> => fromArray(Chunk.toReadonlyArray(chunk))
708
709/**
710 * Creates a `Channel` from an iterator that emits arrays of elements.
711 *
712 * **Details**
713 *
714 * Finite fractional `chunkSize` values are rounded down. `NaN` and non-positive
715 * values are treated as `1` so every successful pull emits a non-empty array.
716 *
717 * **Example** (Batching iterator output)
718 *
719 * ```ts import.meta.vitest
720 * import { Channel, Effect } from "effect"
721 *
722 * // Create a channel from a simple iterator
723 * const numberIterator = (): Iterator<number, string> => {
724 * let count = 0
725 * return {
726 * next: () => {
727 * if (count < 3) {
728 * return { value: count++, done: false }
729 * }
730 * return { value: "finished", done: true }
731 * }
732 * }
733 * }
734 *
735 * const channel = Channel.fromIteratorArray(() => numberIterator(), 2)
736 * Effect.runSync(Channel.runCollect(channel)) // => [[0, 1], [2]]
737 * ```
738 *
739 * **Example** (Batching generator output)
740 *
741 * ```ts import.meta.vitest
742 * import { Channel, Effect } from "effect"
743 *
744 * // Create channel from a generator function
745 * function* fibonacci(): Generator<number, void, unknown> {
746 * let a = 0, b = 1
747 * for (let i = 0; i < 5; i++) {
748 * yield a
749 * ;[a, b] = [b, a + b]
750 * }
751 * }
752 *
753 * const fibChannel = Channel.fromIteratorArray(() => fibonacci(), 3)
754 * Effect.runSync(Channel.runCollect(fibChannel)) // => [[0, 1, 1], [2, 3]]
755 * ```
756 *
757 * @category constructors
758 * @since 4.0.0
759 */
760export const fromIteratorArray = <A, L>(
761 iterator: LazyArg<Iterator<A, L>>,
762 chunkSize = DefaultChunkSize
763): Channel<Arr.NonEmptyReadonlyArray<A>, never, L> => {
764 const size = Count.normalizeNonEmpty(chunkSize)
765 return fromPull(
766 Effect.sync(() => {
767 const iter = iterator()
768 let done = Option.none<L>()
769 return Effect.suspend(() => {
770 if (done._tag === "Some") return Cause.done(done.value)
771 const buffer: Array<A> = []
772 while (buffer.length < size) {
773 const state = iter.next()
774 if (state.done) {
775 if (buffer.length === 0) {
776 return Cause.done(state.value)
777 }
778 done = Option.some(state.value)
779 break
780 }
781 buffer.push(state.value)
782 }
783 return Effect.succeed(buffer as any as Arr.NonEmptyReadonlyArray<A>)
784 })
785 })
786 )
787}
788
789/**
790 * Creates a `Channel` that emits all elements from an iterable.
791 *
792 * **Example** (Creating channels from iterables)
793 *
794 * ```ts import.meta.vitest
795 * import { Channel, Effect } from "effect"
796 *
797 * const set = new Set([1, 2, 3])
798 * const channel = Channel.fromIterable(set)
799 * Effect.runSync(Channel.runCollect(channel)) // => [1, 2, 3]
800 * ```
801 *
802 * @category constructors
803 * @since 4.0.0
804 */
805export const fromIterable = <A, L>(iterable: Iterable<A, L>): Channel<A, never, L> =>
806 fromIterator(() => iterable[Symbol.iterator]())
807
808/**
809 * Creates a `Channel` that emits arrays of elements from an iterable.
810 *
811 * **Details**
812 *
813 * Finite fractional `chunkSize` values are rounded down. `NaN` and non-positive
814 * values are treated as `1`.
815 *
816 * **Example** (Batching iterable output)
817 *
818 * ```ts import.meta.vitest
819 * import { Channel, Effect } from "effect"
820 *
821 * const numbers = [1, 2, 3, 4, 5]
822 * const channel = Channel.fromIterableArray(numbers, 4)
823 * Effect.runSync(Channel.runCollect(channel)) // => [[1, 2, 3, 4], [5]]
824 * ```
825 *
826 * @category constructors
827 * @since 4.0.0
828 */
829export const fromIterableArray = <A, L>(
830 iterable: Iterable<A, L>,
831 chunkSize = DefaultChunkSize
832): Channel<Arr.NonEmptyReadonlyArray<A>, never, L> => fromIteratorArray(() => iterable[Symbol.iterator](), chunkSize)
833
834/**
835 * Creates a `Channel` that emits a single value and then ends.
836 *
837 * **Example** (Creating channels that succeed)
838 *
839 * ```ts import.meta.vitest
840 * import { Channel, Effect } from "effect"
841 *
842 * const channel = Channel.succeed(42)
843 * Effect.runSync(Channel.runCollect(channel)) // => [42]
844 * ```
845 *
846 * @category constructors
847 * @since 2.0.0
848 */
849export const succeed = <A>(value: A): Channel<A> => fromEffect(Effect.succeed(value))
850
851/**
852 * Creates a `Channel` that immediately ends with the specified value.
853 *
854 * **Example** (Ending with a value)
855 *
856 * ```ts import.meta.vitest
857 * import { Channel, Effect } from "effect"
858 *
859 * const channel = Channel.end("done")
860 * Effect.runSync(Channel.runCollect(channel)) // => []
861 * ```
862 *
863 * @category constructors
864 * @since 4.0.0
865 */
866export const end = <A>(value: A): Channel<never, never, A> => fromPull(Effect.succeed(Cause.done(value)))
867
868/**
869 * Creates a `Channel` that immediately ends with the lazily evaluated value.
870 *
871 * @category constructors
872 * @since 4.0.0
873 */
874export const endSync = <A>(evaluate: LazyArg<A>): Channel<never, never, A> =>
875 fromPull(Effect.sync(() => Cause.done(evaluate())))
876
877/**
878 * Creates a `Channel` that emits a single value computed by a lazy evaluation.
879 *
880 * **Example** (Computing values lazily)
881 *
882 * ```ts import.meta.vitest
883 * import { Channel, Effect } from "effect"
884 *
885 * let requests = 0
886 *
887 * const channel = Channel.sync(() => {
888 * requests += 1
889 * return `request-${requests}`
890 * })
891 * Effect.runSync(Channel.runCollect(channel)) // => ["request-1"]
892 * ```
893 *
894 * @category constructors
895 * @since 2.0.0
896 */
897export const sync = <A>(evaluate: LazyArg<A>): Channel<A> => fromEffect(Effect.sync(evaluate))
898
899/**
900 * Represents a `Channel` that emits no elements.
901 *
902 * **Example** (Creating empty channels)
903 *
904 * ```ts import.meta.vitest
905 * import { Channel, Effect } from "effect"
906 *
907 * // Create an empty channel
908 * const emptyChannel = Channel.empty
909 *
910 * // Use empty channel in composition
911 * const combined = Channel.concatWith(emptyChannel, () => Channel.succeed(42))
912 * // Will immediately provide the second channel's output
913 *
914 * // Empty channel can be used as a no-op in conditional logic
915 * const conditionalChannel = (shouldEmit: boolean) =>
916 * shouldEmit ? Channel.succeed("data") : Channel.empty
917 *
918 * Effect.runSync(Channel.runCollect(conditionalChannel(true))) // => ["data"]
919 * ```
920 *
921 * @category constructors
922 * @since 4.0.0
923 */
924export const empty: Channel<never> = fromPull(Effect.succeed(Cause.done()))
925
926/**
927 * Represents a `Channel` that never completes.
928 *
929 * **Example** (Creating non-terminating channels)
930 *
931 * ```ts import.meta.vitest
932 * import { Channel } from "effect"
933 *
934 * // Create a channel that never completes
935 * const neverChannel = Channel.never
936 *
937 * // Use in conditional logic
938 * const withFallback = Channel.concatWith(
939 * neverChannel,
940 * () => Channel.succeed("fallback")
941 * )
942 *
943 * // Never channel is useful for testing or as a placeholder
944 * const conditionalChannel = (shouldComplete: boolean) =>
945 * shouldComplete ? Channel.succeed("done") : Channel.never
946 *
947 * Channel.isChannel(conditionalChannel(false)) // => true
948 * ```
949 *
950 * @category constructors
951 * @since 2.0.0
952 */
953export const never: Channel<never, never, never> = fromPull(Effect.succeed(Effect.never))
954
955/**
956 * Constructs a channel that fails immediately with the specified error.
957 *
958 * **Example** (Failing with an error)
959 *
960 * ```ts import.meta.vitest
961 * import { Channel, Effect, Exit } from "effect"
962 *
963 * const failedChannel = Channel.fail("Something went wrong")
964 * Effect.runSync(Effect.exit(Channel.runCollect(failedChannel))) // => Exit.fail("Something went wrong")
965 * ```
966 *
967 * @category constructors
968 * @since 2.0.0
969 */
970export const fail = <E>(error: E): Channel<never, E, never> => fromPull(Effect.succeed(Effect.fail(error)))
971
972/**
973 * Constructs a channel that fails immediately with the specified lazily
974 * evaluated error.
975 *
976 * **When to use**
977 *
978 * Use when the error value should be computed each time the channel runs instead
979 * of when the channel is constructed.
980 *
981 * **Example** (Failing with a lazy error)
982 *
983 * ```ts import.meta.vitest
984 * import { Channel, Effect, Exit } from "effect"
985 *
986 * let attempts = 0
987 * const conditionalError = Channel.failSync(() => {
988 * attempts += 1
989 * return `Error after attempt ${attempts}`
990 * })
991 * const observed = [
992 * Effect.runSync(Effect.exit(Channel.runCollect(conditionalError))),
993 * attempts
994 * ] // => [Exit.fail("Error after attempt 1"), 1]
995 * ```
996 *
997 * @category constructors
998 * @since 2.0.0
999 */
1000export const failSync = <E>(evaluate: LazyArg<E>): Channel<never, E, never> => fromPull(Effect.failSync(evaluate))
1001
1002/**
1003 * Constructs a channel that fails immediately with the specified `Cause`.
1004 *
1005 * **When to use**
1006 *
1007 * Use when the channel failure must preserve a full `Cause`, such as defects,
1008 * interruptions, or combined failures.
1009 *
1010 * **Example** (Failing with causes)
1011 *
1012 * ```ts import.meta.vitest
1013 * import { Cause, Channel, Effect, Exit } from "effect"
1014 *
1015 * const simpleCause = Cause.fail("Simple error")
1016 * const failedChannel = Channel.failCause(simpleCause)
1017 * Effect.runSync(Effect.exit(Channel.runCollect(failedChannel))) // => Exit.failCause(simpleCause)
1018 * ```
1019 *
1020 * @category constructors
1021 * @since 2.0.0
1022 */
1023export const failCause = <E>(cause: Cause.Cause<E>): Channel<never, E, never> => fromPull(Effect.failCause(cause))
1024
1025/**
1026 * Constructs a channel that fails immediately with the specified lazily
1027 * evaluated `Cause`.
1028 *
1029 * **Example** (Failing with lazy causes)
1030 *
1031 * ```ts import.meta.vitest
1032 * import { Cause, Channel, Effect, Exit } from "effect"
1033 *
1034 * // Create a channel that fails with a lazily computed cause
1035 * let attempts = 0
1036 * const failedChannel = Channel.failCauseSync(() => {
1037 * attempts += 1
1038 * return Cause.fail(`Runtime error after attempt ${attempts}`)
1039 * })
1040 *
1041 * const observed = [
1042 * Effect.runSync(Effect.exit(Channel.runCollect(failedChannel))),
1043 * attempts
1044 * ] // => [Exit.fail("Runtime error after attempt 1"), 1]
1045 * ```
1046 *
1047 * @category constructors
1048 * @since 2.0.0
1049 */
1050export const failCauseSync = <E>(
1051 evaluate: LazyArg<Cause.Cause<E>>
1052): Channel<never, E, never> => fromPull(Effect.failCauseSync(evaluate))
1053
1054/**
1055 * Constructs a channel that fails immediately with the specified defect.
1056 *
1057 * **Example** (Dying with defects)
1058 *
1059 * ```ts import.meta.vitest
1060 * import { Cause, Channel, Effect, Exit } from "effect"
1061 *
1062 * const defect = "Unrecoverable error"
1063 * const diedChannel = Channel.die(defect)
1064 * Effect.runSync(Effect.exit(Channel.runCollect(diedChannel))) // => Exit.failCause(Cause.die(defect))
1065 * ```
1066 *
1067 * @category constructors
1068 * @since 4.0.0
1069 */
1070export const die = (defect: unknown): Channel<never, never, never> => failCause(Cause.die(defect))
1071
1072/**
1073 * Uses an effect to write a single value to the channel.
1074 *
1075 * **Example** (Creating channels from effects)
1076 *
1077 * ```ts import.meta.vitest
1078 * import { Channel, Effect } from "effect"
1079 *
1080 * const successChannel = Channel.fromEffect(
1081 * Effect.succeed("Hello from effect!")
1082 * )
1083 * Effect.runSync(Channel.runCollect(successChannel)) // => ["Hello from effect!"]
1084 * ```
1085 *
1086 * @category constructors
1087 * @since 2.0.0
1088 */
1089export const fromEffect = <A, E, R>(
1090 effect: Effect.Effect<A, E, R>
1091): Channel<A, Pull.ExcludeDone<E>, void, unknown, unknown, unknown, R> =>
1092 fromPull(
1093 Effect.sync(() => {
1094 let done = false
1095 return Effect.suspend((): Pull.Pull<A, E, void, R> => {
1096 if (done) return Cause.done()
1097 done = true
1098 return effect
1099 })
1100 })
1101 )
1102
1103/**
1104 * Creates a channel that evaluates an effect and uses its successful value as
1105 * the channel's done value without emitting any output elements.
1106 *
1107 * **Details**
1108 *
1109 * If the effect fails, the channel fails with the effect's error.
1110 *
1111 * @category constructors
1112 * @since 4.0.0
1113 */
1114export const fromEffectDone = <A, E, R>(
1115 effect: Effect.Effect<A, E, R>
1116): Channel<never, Pull.ExcludeDone<E>, A, unknown, unknown, unknown, R> =>
1117 fromPull(Effect.succeed(Effect.flatMap(effect, Cause.done)))
1118
1119/**
1120 * Uses an effect and discards its result.
1121 *
1122 * @category constructors
1123 * @since 4.0.0
1124 */
1125export const fromEffectDrain = <A, E, R>(
1126 effect: Effect.Effect<A, E, R>
1127): Channel<never, E, void, unknown, unknown, unknown, R> => fromPull(Effect.flatMap(effect, () => Cause.done())) as any
1128
1129/**
1130 * Creates a channel from an effect that produces a `Take`.
1131 *
1132 * **Details**
1133 *
1134 * A successful `Take` emits a non-empty array of output elements. A failed
1135 * `Take` fails the channel. A done `Take` completes the channel with its done
1136 * value.
1137 *
1138 * @category constructors
1139 * @since 4.0.0
1140 */
1141export const fromEffectTake = <A, E, Done, E2, R>(
1142 effect: Effect.Effect<Take.Take<A, E, Done>, E2, R>
1143): Channel<Arr.NonEmptyReadonlyArray<A>, E | E2, Done, unknown, unknown, unknown, R> =>
1144 fromPull(Effect.succeed(Effect.flatMap(effect, Take.toPull)))
1145
1146/**
1147 * Creates a channel from a queue.
1148 *
1149 * **Example** (Creating channels from queues)
1150 *
1151 * ```ts import.meta.vitest
1152 * import { Cause, Channel, Effect, Queue } from "effect"
1153 *
1154 * const program = Effect.gen(function*() {
1155 * const queue = yield* Queue.bounded<string, Cause.Done>(3)
1156 * yield* Queue.offerAll(queue, ["item1", "item2", "item3"])
1157 * yield* Queue.end(queue)
1158 * const channel = Channel.fromQueue(queue)
1159 * return yield* Channel.runCollect(channel)
1160 * })
1161 * await Effect.runPromise(program) // => ["item1", "item2", "item3"]
1162 * ```
1163 *
1164 * @category constructors
1165 * @since 2.0.0
1166 */
1167export const fromQueue = <A, E>(
1168 queue: Queue.Dequeue<A, E>
1169): Channel<A, Exclude<E, Cause.Done>> => fromPull(Effect.succeed(Queue.take(queue)))
1170
1171/**
1172 * Creates a channel from a queue that emits arrays of elements.
1173 *
1174 * **Example** (Creating batched channels from queues)
1175 *
1176 * ```ts import.meta.vitest
1177 * import { Cause, Channel, Effect, Queue } from "effect"
1178 *
1179 * const program = Effect.gen(function*() {
1180 * const queue = yield* Queue.bounded<number, Cause.Done>(4)
1181 * yield* Queue.offerAll(queue, [1, 2, 3, 4])
1182 * yield* Queue.end(queue)
1183 * const arrayChannel = Channel.fromQueueArray(queue)
1184 * return yield* Channel.runCollect(arrayChannel)
1185 * })
1186 * await Effect.runPromise(program) // => [[1, 2, 3, 4]]
1187 * ```
1188 *
1189 * @category constructors
1190 * @since 4.0.0
1191 */
1192export const fromQueueArray = <A, E>(
1193 queue: Queue.Dequeue<A, E>
1194): Channel<Arr.NonEmptyReadonlyArray<A>, Exclude<E, Cause.Done>> => fromPull(Effect.succeed(Queue.takeAll(queue)))
1195
1196/**
1197 * Creates a channel that forwards upstream input elements, input errors, and
1198 * the upstream done value unchanged.
1199 *
1200 * @category constructors
1201 * @since 2.0.0
1202 */
1203export const identity = <Elem, Err, Done>(): Channel<Elem, Err, Done, Elem, Err, Done> =>
1204 fromTransform((upstream, _scope) => Effect.succeed(upstream))
1205
1206/**
1207 * Creates a channel from a PubSub subscription.
1208 *
1209 * **Example** (Creating channels from subscriptions)
1210 *
1211 * ```ts import.meta.vitest
1212 * import { Channel, Data, Effect, Option, PubSub } from "effect"
1213 *
1214 * class SubscriptionError extends Data.TaggedError("SubscriptionError")<{
1215 * readonly reason: string
1216 * }> {}
1217 *
1218 * const program = Effect.gen(function*() {
1219 * // Create a PubSub
1220 * const pubsub = yield* PubSub.bounded<string>(32)
1221 *
1222 * // Create a subscription
1223 * const subscription = yield* PubSub.subscribe(pubsub)
1224 *
1225 * // Publish some messages
1226 * yield* PubSub.publish(pubsub, "Hello")
1227 * yield* PubSub.publish(pubsub, "World")
1228 * yield* PubSub.publish(pubsub, "from")
1229 * yield* PubSub.publish(pubsub, "PubSub")
1230 *
1231 * // Create a channel from the subscription
1232 * const channel = Channel.fromSubscription(subscription)
1233 *
1234 * // The channel will receive all published messages
1235 * return channel
1236 * })
1237 * const result = Effect.scoped(Effect.flatMap(program, Channel.runHead))
1238 * await Effect.runPromise(result) // => Option.some("Hello")
1239 *
1240 * // Real-time notifications example
1241 * const notificationChannel = Effect.gen(function*() {
1242 * const eventBus = yield* PubSub.unbounded<{ type: string; payload: any }>()
1243 * const userSubscription = yield* PubSub.subscribe(eventBus)
1244 *
1245 * return Channel.fromSubscription(userSubscription)
1246 * })
1247 * ```
1248 *
1249 * @category constructors
1250 * @since 4.0.0
1251 */
1252export const fromSubscription = <A>(
1253 subscription: PubSub.Subscription<A>
1254): Channel<A> => fromPull(Effect.succeed(Effect.onInterrupt(PubSub.take(subscription), () => Cause.done())))
1255
1256/**
1257 * Creates a channel from a PubSub subscription that outputs arrays of values.
1258 *
1259 * **Details**
1260 *
1261 * This constructor creates a channel that reads from a PubSub subscription and outputs
1262 * arrays of values in chunks. It's useful when you want to process multiple values at once
1263 * for better performance.
1264 *
1265 * **Example** (Batching subscription values)
1266 *
1267 * ```ts import.meta.vitest
1268 * import { Channel, Data, Effect, Option, PubSub } from "effect"
1269 *
1270 * class StreamError extends Data.TaggedError("StreamError")<{
1271 * readonly message: string
1272 * }> {}
1273 *
1274 * const program = Effect.gen(function*() {
1275 * const pubsub = yield* PubSub.bounded<number>(16)
1276 * const subscription = yield* PubSub.subscribe(pubsub)
1277 *
1278 * // Create a channel that reads arrays of values
1279 * const channel = Channel.fromSubscriptionArray(subscription)
1280 *
1281 * // Publish some values
1282 * yield* PubSub.publish(pubsub, 1)
1283 * yield* PubSub.publish(pubsub, 2)
1284 * yield* PubSub.publish(pubsub, 3)
1285 * yield* PubSub.publish(pubsub, 4)
1286 *
1287 * // The channel will output arrays like [1, 2, 3] and [4]
1288 * return channel
1289 * })
1290 * const result = Effect.scoped(Effect.flatMap(program, Channel.runHead))
1291 * await Effect.runPromise(result) // => Option.some([1, 2, 3, 4])
1292 * ```
1293 *
1294 * **Example** (Processing subscription values in batches)
1295 *
1296 * ```ts import.meta.vitest
1297 * import { Channel, Data, Effect, Option, PubSub } from "effect"
1298 *
1299 * class BatchProcessingError extends Data.TaggedError("BatchProcessingError")<{
1300 * readonly reason: string
1301 * }> {}
1302 *
1303 * const batchProcessor = Effect.gen(function*() {
1304 * const pubsub = yield* PubSub.bounded<string>(32)
1305 * const subscription = yield* PubSub.subscribe(pubsub)
1306 *
1307 * // Create a channel that processes items in batches
1308 * const batchChannel = Channel.fromSubscriptionArray(subscription)
1309 *
1310 * // Transform to process each batch
1311 * const processedChannel = Channel.map(batchChannel, (batch) =>
1312 * batch.map((item) => item.toUpperCase())
1313 * )
1314 *
1315 * yield* PubSub.publishAll(pubsub, ["one", "two"])
1316 * return processedChannel
1317 * })
1318 * const batch = Effect.scoped(Effect.flatMap(batchProcessor, Channel.runHead))
1319 * await Effect.runPromise(batch) // => Option.some(["ONE", "TWO"])
1320 * ```
1321 *
1322 * **Example** (Aggregating subscription metrics)
1323 *
1324 * ```ts import.meta.vitest
1325 * import { Channel, Effect, Option, PubSub } from "effect"
1326 *
1327 * const metricsAggregator = Effect.gen(function*() {
1328 * const metricsPubSub = yield* PubSub.bounded<
1329 * { timestamp: number; value: number }
1330 * >(100)
1331 * const subscription = yield* PubSub.subscribe(metricsPubSub)
1332 *
1333 * // Create a channel that collects metrics in chunks
1334 * const metricsChannel = Channel.fromSubscriptionArray(subscription)
1335 *
1336 * // Transform to calculate aggregate statistics
1337 * const aggregatedChannel = Channel.map(metricsChannel, (metrics) => {
1338 * const values = metrics.map((m) => m.value)
1339 * const sum = values.reduce((a, b) => a + b, 0)
1340 * const avg = sum / values.length
1341 * const min = Math.min(...values)
1342 * const max = Math.max(...values)
1343 *
1344 * return {
1345 * count: values.length,
1346 * sum,
1347 * average: avg,
1348 * min,
1349 * max,
1350 * firstTimestamp: Math.min(...metrics.map((m) => m.timestamp)),
1351 * lastTimestamp: Math.max(...metrics.map((m) => m.timestamp))
1352 * }
1353 * })
1354 *
1355 * yield* PubSub.publish(metricsPubSub, { timestamp: 1, value: 10 })
1356 * return aggregatedChannel
1357 * })
1358 * const metric = Effect.scoped(Effect.flatMap(metricsAggregator, Channel.runHead))
1359 * const result = await Effect.runPromise(metric)
1360 * Option.map(result, ({ count, sum, average, min, max }) => ({ count, sum, average, min, max })) // => Option.some({ count: 1, sum: 10, average: 10, min: 10, max: 10 })
1361 * ```
1362 *
1363 * @category constructors
1364 * @since 4.0.0
1365 */
1366export const fromSubscriptionArray = <A>(
1367 subscription: PubSub.Subscription<A>
1368): Channel<Arr.NonEmptyReadonlyArray<A>> =>
1369 fromPull(Effect.succeed(Effect.onInterrupt(PubSub.takeAll(subscription), () => Cause.done())))
1370
1371/**
1372 * Creates a channel from a PubSub that outputs individual values.
1373 *
1374 * **Details**
1375 *
1376 * This constructor creates a channel that reads from a PubSub by automatically
1377 * subscribing to it. The channel outputs individual values as they are published
1378 * to the PubSub, making it ideal for real-time streaming scenarios.
1379 *
1380 * **Example** (Creating channels from PubSubs)
1381 *
1382 * ```ts import.meta.vitest
1383 * import { Channel, Data, Effect, Option, PubSub } from "effect"
1384 *
1385 * class StreamError extends Data.TaggedError("StreamError")<{
1386 * readonly message: string
1387 * }> {}
1388 *
1389 * const program = Effect.gen(function*() {
1390 * const pubsub = yield* PubSub.unbounded<number>({ replay: 3 })
1391 *
1392 * // Create a channel that reads individual values
1393 * const channel = Channel.fromPubSub(pubsub)
1394 *
1395 * // Publish some values
1396 * yield* PubSub.publish(pubsub, 1)
1397 * yield* PubSub.publish(pubsub, 2)
1398 * yield* PubSub.publish(pubsub, 3)
1399 *
1400 * // The channel will output: 1, 2, 3 (individual values)
1401 * return channel
1402 * })
1403 * const result = Effect.scoped(Effect.flatMap(program, Channel.runHead))
1404 * await Effect.runPromise(result) // => Option.some(1)
1405 * ```
1406 *
1407 * **Example** (Streaming PubSub notifications)
1408 *
1409 * ```ts import.meta.vitest
1410 * import { Channel, Effect, Option, PubSub } from "effect"
1411 *
1412 * const notificationService = Effect.gen(function*() {
1413 * const notificationPubSub = yield* PubSub.unbounded<string>({ replay: 1 })
1414 *
1415 * // Create a channel for real-time notifications
1416 * const notificationChannel = Channel.fromPubSub(notificationPubSub)
1417 *
1418 * // Transform notifications to add timestamps
1419 * const receivedAt = "2024-01-01T00:00:00.000Z"
1420 * const timestampedChannel = Channel.map(notificationChannel, (message) => ({
1421 * message,
1422 * receivedAt,
1423 * id: `notification:${message}`
1424 * }))
1425 *
1426 * yield* PubSub.publish(notificationPubSub, "ready")
1427 * return timestampedChannel
1428 * })
1429 * const notification = Effect.scoped(Effect.flatMap(notificationService, Channel.runHead))
1430 * await Effect.runPromise(notification) // => Option.some({ message: "ready", receivedAt: "2024-01-01T00:00:00.000Z", id: "notification:ready" })
1431 * ```
1432 *
1433 * **Example** (Processing PubSub events)
1434 *
1435 * ```ts import.meta.vitest
1436 * import { Channel, Effect, Option, PubSub } from "effect"
1437 *
1438 * interface DomainEvent {
1439 * readonly type: string
1440 * readonly payload: unknown
1441 * readonly timestamp: number
1442 * }
1443 *
1444 * const eventProcessor = Effect.gen(function*() {
1445 * const eventPubSub = yield* PubSub.unbounded<DomainEvent>({ replay: 1 })
1446 *
1447 * // Create a channel for processing domain events
1448 * const eventChannel = Channel.fromPubSub(eventPubSub)
1449 *
1450 * // Filter and transform events
1451 * const processedChannel = Channel.map(eventChannel, (event) => {
1452 * if (event.type === "user.created") {
1453 * return {
1454 * ...event,
1455 * processed: true,
1456 * processedAt: event.timestamp + 1
1457 * }
1458 * }
1459 * return event
1460 * })
1461 *
1462 * yield* PubSub.publish(eventPubSub, { type: "user.created", payload: {}, timestamp: 1 })
1463 * return processedChannel
1464 * })
1465 * const event = Effect.scoped(Effect.flatMap(eventProcessor, Channel.runHead))
1466 * const result = await Effect.runPromise(event) // => Option.some({ type: "user.created", payload: {}, timestamp: 1, processed: true, processedAt: 2 })
1467 * ```
1468 *
1469 * @category constructors
1470 * @since 2.0.0
1471 */
1472export const fromPubSub = <A>(
1473 pubsub: PubSub.PubSub<A>
1474): Channel<A> => unwrap(Effect.map(PubSub.subscribe(pubsub), fromSubscription))
1475
1476/**
1477 * Creates a channel from a PubSub that outputs arrays of values.
1478 *
1479 * **Details**
1480 *
1481 * This constructor creates a channel that reads from a PubSub by automatically
1482 * subscribing to it and collecting values into arrays. The channel outputs
1483 * arrays of values in chunks, making it ideal for batch processing scenarios.
1484 *
1485 * **Example** (Batching PubSub values)
1486 *
1487 * ```ts import.meta.vitest
1488 * import { Channel, Data, Effect, Option, PubSub } from "effect"
1489 *
1490 * class BatchError extends Data.TaggedError("BatchError")<{
1491 * readonly message: string
1492 * }> {}
1493 *
1494 * const program = Effect.gen(function*() {
1495 * const pubsub = yield* PubSub.unbounded<number>({ replay: 4 })
1496 *
1497 * // Create a channel that reads arrays of values
1498 * const channel = Channel.fromPubSubArray(pubsub)
1499 *
1500 * // Publish some values
1501 * yield* PubSub.publish(pubsub, 1)
1502 * yield* PubSub.publish(pubsub, 2)
1503 * yield* PubSub.publish(pubsub, 3)
1504 * yield* PubSub.publish(pubsub, 4)
1505 *
1506 * // The channel will output arrays like [1, 2, 3] and [4]
1507 * return channel
1508 * })
1509 * const result = Effect.scoped(Effect.flatMap(program, Channel.runHead))
1510 * await Effect.runPromise(result) // => Option.some([1, 2, 3, 4])
1511 * ```
1512 *
1513 * **Example** (Processing PubSub orders in batches)
1514 *
1515 * ```ts import.meta.vitest
1516 * import { Channel, Effect, Option, PubSub } from "effect"
1517 *
1518 * interface Order {
1519 * readonly id: string
1520 * readonly customerId: string
1521 * readonly items: ReadonlyArray<string>
1522 * readonly total: number
1523 * readonly submittedAt: number
1524 * }
1525 *
1526 * const orderBatchProcessor = Effect.gen(function*() {
1527 * const orderPubSub = yield* PubSub.unbounded<Order>({ replay: 1 })
1528 *
1529 * // Create a channel that processes orders in batches
1530 * const orderChannel = Channel.fromPubSubArray(orderPubSub)
1531 *
1532 * // Transform to process each batch of orders
1533 * const processedChannel = Channel.map(orderChannel, (orderBatch) => {
1534 * const totalRevenue = orderBatch.reduce((sum, order) => sum + order.total, 0)
1535 * const customerCount = new Set(orderBatch.map((order) =>
1536 * order.customerId
1537 * )).size
1538 *
1539 * return {
1540 * batchSize: orderBatch.length,
1541 * totalRevenue,
1542 * uniqueCustomers: customerCount,
1543 * firstSubmittedAt: Math.min(...orderBatch.map((order) => order.submittedAt)),
1544 * orders: orderBatch
1545 * }
1546 * })
1547 *
1548 * yield* PubSub.publish(orderPubSub, {
1549 * id: "1", customerId: "a", items: ["book"], total: 10, submittedAt: 1
1550 * })
1551 * return processedChannel
1552 * })
1553 * const order = Effect.scoped(Effect.flatMap(orderBatchProcessor, Channel.runHead))
1554 * const result = await Effect.runPromise(order)
1555 * Option.map(result, (batch) => [batch.batchSize, batch.totalRevenue, batch.uniqueCustomers]) // => Option.some([1, 10, 1])
1556 * ```
1557 *
1558 * **Example** (Processing PubSub logs in batches)
1559 *
1560 * ```ts import.meta.vitest
1561 * import { Channel, Effect, Option, PubSub } from "effect"
1562 *
1563 * interface LogEntry {
1564 * readonly timestamp: number
1565 * readonly level: "info" | "warn" | "error"
1566 * readonly message: string
1567 * readonly source: string
1568 * }
1569 *
1570 * const logAggregator = Effect.gen(function*() {
1571 * const logPubSub = yield* PubSub.unbounded<LogEntry>({ replay: 1 })
1572 *
1573 * // Create a channel that collects logs in batches
1574 * const logChannel = Channel.fromPubSubArray(logPubSub)
1575 *
1576 * // Transform to analyze log batches
1577 * const analysisChannel = Channel.map(logChannel, (logBatch) => {
1578 * const errorCount = logBatch.filter((log) => log.level === "error").length
1579 * const warnCount = logBatch.filter((log) => log.level === "warn").length
1580 * const infoCount = logBatch.filter((log) => log.level === "info").length
1581 *
1582 * const timeRange = {
1583 * start: Math.min(...logBatch.map((log) => log.timestamp)),
1584 * end: Math.max(...logBatch.map((log) => log.timestamp))
1585 * }
1586 *
1587 * return {
1588 * batchId: `${timeRange.start}-${timeRange.end}`,
1589 * totalEntries: logBatch.length,
1590 * errorCount,
1591 * warnCount,
1592 * infoCount,
1593 * timeRange,
1594 * sources: [...new Set(logBatch.map((log) => log.source))]
1595 * }
1596 * })
1597 *
1598 * yield* PubSub.publish(logPubSub, {
1599 * timestamp: 1,
1600 * level: "info",
1601 * message: "ready",
1602 * source: "app"
1603 * } satisfies LogEntry)
1604 * return analysisChannel
1605 * })
1606 * const log = Effect.scoped(Effect.flatMap(logAggregator, Channel.runHead))
1607 * const result = await Effect.runPromise(log)
1608 * Option.map(result, (batch) => [batch.batchId, batch.totalEntries, batch.infoCount]) // => Option.some(["1-1", 1, 1])
1609 * ```
1610 *
1611 * @category constructors
1612 * @since 4.0.0
1613 */
1614export const fromPubSubArray = <A>(pubsub: PubSub.PubSub<A>): Channel<Arr.NonEmptyReadonlyArray<A>> =>
1615 unwrap(Effect.map(PubSub.subscribe(pubsub), fromSubscriptionArray))
1616
1617/**
1618 * Subscribes to a `PubSub` of `Take` values and exposes them as a channel.
1619 *
1620 * **Details**
1621 *
1622 * Output `Take` values are emitted as non-empty arrays. Failed `Take` values
1623 * fail the channel. Done `Take` values complete the channel.
1624 *
1625 * @category constructors
1626 * @since 4.0.0
1627 */
1628export const fromPubSubTake = <A, E, Done>(
1629 pubsub: PubSub.PubSub<Take.Take<A, E, Done>>
1630): Channel<Arr.NonEmptyReadonlyArray<A>, E, Done> =>
1631 unwrap(Effect.map(PubSub.subscribe(pubsub), (sub) => fromEffectTake(PubSub.take(sub))))
1632
1633/**
1634 * Creates a Channel from a Schedule.
1635 *
1636 * @category constructors
1637 * @since 4.0.0
1638 */
1639export const fromSchedule = <O, E, R>(
1640 schedule: Schedule.Schedule<O, unknown, E, R>
1641): Channel<O, E, O, unknown, unknown, unknown, R> =>
1642 fromPull(Effect.map(Schedule.toStepWithSleep(schedule), (step) => step(void 0)))
1643
1644/**
1645 * Creates a channel from a lazily supplied Web `ReadableStream`.
1646 *
1647 * **Example** (Reading from a Web stream)
1648 *
1649 * ```ts import.meta.vitest
1650 * import { Channel, Effect } from "effect"
1651 *
1652 * const channel = Channel.fromReadableStream({
1653 * evaluate: () => new ReadableStream({
1654 * start(controller) {
1655 * controller.enqueue(1)
1656 * controller.close()
1657 * }
1658 * }),
1659 * onError: (cause) => new Error(String(cause))
1660 * })
1661 *
1662 * await Effect.runPromise(Channel.runCollect(channel)) // => [[1]]
1663 * ```
1664 *
1665 * @category constructors
1666 * @since 4.0.0
1667 */
1668export const fromReadableStream = <A, E>(options: {
1669 readonly evaluate: LazyArg<ReadableStream<A>>
1670 readonly onError: (error: unknown) => E
1671 readonly releaseLockOnEnd?: boolean | undefined
1672}): Channel<Arr.NonEmptyReadonlyArray<A>, E> =>
1673 fromTransform((_, scope) =>
1674 readableStreamToPullUnsafe({
1675 scope,
1676 readable: options.evaluate(),
1677 onError: options.onError,
1678 releaseLockOnEnd: options.releaseLockOnEnd
1679 })
1680 )
1681
1682/** @internal */
1683export const pullIntoWritableStream = <A, IE, E>(options: {
1684 readonly pull: Pull.Pull<Arr.NonEmptyReadonlyArray<A>, IE, unknown>
1685 readonly writable: WritableStream<A>
1686 readonly onError: (error: unknown) => E
1687 readonly closeOnDone?: boolean | undefined
1688}): Pull.Pull<never, IE | E, unknown> =>
1689 Effect.acquireUseRelease(
1690 Effect.sync(() => options.writable.getWriter()),
1691 (writer) => {
1692 const loop = options.pull.pipe(
1693 Effect.flatMap((chunk) =>
1694 Effect.forEach(
1695 chunk,
1696 (value) =>
1697 Effect.tryPromise({
1698 try: () => writer.ready.then(() => writer.write(value)),
1699 catch: options.onError
1700 }),
1701 { discard: true }
1702 )
1703 ),
1704 Effect.forever({ disableYield: true })
1705 )
1706 const withClose = options.closeOnDone !== false
1707 ? Pull.catchDone(loop, (done) =>
1708 Effect.andThen(
1709 Effect.tryPromise({
1710 try: () => writer.close(),
1711 catch: options.onError
1712 }),
1713 Cause.done(done)
1714 ))
1715 : loop
1716 return Effect.onError(
1717 withClose,
1718 (cause) =>
1719 Pull.isDoneCause(cause)
1720 ? Effect.void
1721 : Effect.promise(() => writer.abort(cause).catch(constVoid))
1722 )
1723 },
1724 (writer) => Effect.sync(() => writer.releaseLock())
1725 )
1726
1727/**
1728 * Creates a channel that writes upstream values to a lazily supplied Web
1729 * `WritableStream`.
1730 *
1731 * **Example** (Writing channel input)
1732 *
1733 * ```ts import.meta.vitest
1734 * import { Channel, Effect } from "effect"
1735 *
1736 * const written: Array<number> = []
1737 * const sink = Channel.fromWritableStream<never, Error, number>({
1738 * evaluate: () => new WritableStream({
1739 * write(value) {
1740 * written.push(value)
1741 * }
1742 * }),
1743 * onError: (cause) => new Error(String(cause))
1744 * })
1745 *
1746 * const program = Channel.fromArray([[1, 2] as [number, number]]).pipe(
1747 * Channel.pipeTo(sink),
1748 * Channel.runDrain
1749 * )
1750 *
1751 * await Effect.runPromise(program)
1752 * written // => [1, 2]
1753 * ```
1754 *
1755 * @category constructors
1756 * @since 4.0.0
1757 */
1758export const fromWritableStream = <IE, E, A>(options: {
1759 readonly evaluate: LazyArg<WritableStream<A>>
1760 readonly onError: (error: unknown) => E
1761 readonly closeOnDone?: boolean | undefined
1762}): Channel<never, IE | E, void, Arr.NonEmptyReadonlyArray<A>, IE> =>
1763 fromTransform((pull: Pull.Pull<Arr.NonEmptyReadonlyArray<A>, IE, unknown>) => {
1764 const writable = options.evaluate()
1765 return Effect.succeed(pullIntoWritableStream({ ...options, writable, pull }))
1766 })
1767
1768/**
1769 * Creates a channel backed by a Web `TransformStream`, writing upstream values
1770 * while emitting transformed values from its readable side.
1771 *
1772 * **Example** (Transforming channel input)
1773 *
1774 * ```ts import.meta.vitest
1775 * import { Channel, Effect } from "effect"
1776 *
1777 * const transform = Channel.fromTransformStream<never, number, number, Error>({
1778 * evaluate: () => new TransformStream({
1779 * transform(value, controller) {
1780 * controller.enqueue(value * 2)
1781 * }
1782 * }),
1783 * onError: (cause) => new Error(String(cause))
1784 * })
1785 *
1786 * const program = Channel.fromArray([[1, 2] as [number, number]]).pipe(
1787 * Channel.pipeTo(transform),
1788 * Channel.runCollect
1789 * )
1790 *
1791 * await Effect.runPromise(program) // => [[2], [4]]
1792 * ```
1793 *
1794 * @category constructors
1795 * @since 4.0.0
1796 */
1797export const fromTransformStream = <IE, I, O, E>(options: {
1798 readonly evaluate: LazyArg<TransformStream<I, O>>
1799 readonly onError: (error: unknown) => E
1800 readonly closeOnDone?: boolean | undefined
1801 readonly releaseLockOnEnd?: boolean | undefined
1802}): Channel<Arr.NonEmptyReadonlyArray<O>, IE | E, void, Arr.NonEmptyReadonlyArray<I>, IE> =>
1803 fromTransform((upstream, scope) => {
1804 const transform = options.evaluate()
1805 const exit = MutableRef.make<Exit.Exit<never, IE | E | Cause.Done> | undefined>(undefined)
1806 return pullIntoWritableStream({
1807 pull: upstream,
1808 writable: transform.writable,
1809 onError: options.onError,
1810 closeOnDone: options.closeOnDone
1811 }).pipe(
1812 Effect.catchCause((cause) => {
1813 if (!Pull.isDoneCause(cause)) {
1814 exit.current = Exit.failCause(cause as Cause.Cause<IE | E | Cause.Done>)
1815 }
1816 return Effect.void
1817 }),
1818 Effect.forkIn(scope),
1819 Effect.flatMap(() =>
1820 readableStreamToPullUnsafe({
1821 scope,
1822 exit,
1823 readable: transform.readable,
1824 onError: options.onError,
1825 releaseLockOnEnd: options.releaseLockOnEnd
1826 })
1827 )
1828 )
1829 })
1830
1831const readableStreamToPullUnsafe = <A, E, E2 = never>(options: {
1832 readonly scope: Scope.Scope
1833 readonly exit?: MutableRef.MutableRef<Exit.Exit<never, E | E2 | Cause.Done> | undefined> | undefined
1834 readonly readable: ReadableStream<A>
1835 readonly onError: (error: unknown) => E
1836 readonly releaseLockOnEnd?: boolean | undefined
1837}): Effect.Effect<Pull.Pull<Arr.NonEmptyReadonlyArray<A>, E | E2>, never> => {
1838 const reader = options.readable.getReader()
1839 const exit = options.exit ?? MutableRef.make(undefined)
1840 const pull = Effect.suspend(() => {
1841 if (exit.current) return exit.current
1842 return Effect.matchCauseEffect(
1843 Effect.tryPromise({
1844 try: () => reader.read(),
1845 catch: options.onError
1846 }),
1847 {
1848 onFailure: (cause) => exit.current ?? Effect.failCause(cause),
1849 onSuccess: ({ done, value }) => {
1850 if (exit.current) return exit.current
1851 return done ? Cause.done() : Effect.succeed(Arr.of(value))
1852 }
1853 }
1854 )
1855 })
1856 return Effect.as(
1857 Scope.addFinalizer(
1858 options.scope,
1859 options.releaseLockOnEnd
1860 ? Effect.sync(() => reader.releaseLock())
1861 : Effect.promise(() => reader.cancel().catch(constVoid))
1862 ),
1863 pull
1864 )
1865}
1866
1867/**
1868 * Creates a channel that pulls values from an `AsyncIterable`.
1869 *
1870 * **Details**
1871 *
1872 * Each yielded value is emitted as an output element. The iterator's return
1873 * value becomes the channel's done value. Thrown or rejected iterator errors
1874 * are converted with `onError`. If the channel scope closes early and the
1875 * iterator has a `return` method, that method is called.
1876 *
1877 * @category constructors
1878 * @since 4.0.0
1879 */
1880export const fromAsyncIterable = <A, D, E>(
1881 iterable: AsyncIterable<A, D>,
1882 onError: (error: unknown) => E
1883): Channel<A, E, D> =>
1884 fromTransform(Effect.fnUntraced(function*(_, scope) {
1885 const iter = iterable[Symbol.asyncIterator]()
1886 if (iter.return) {
1887 yield* Scope.addFinalizer(scope, Effect.promise(() => iter.return!()))
1888 }
1889 return Effect.flatMap(
1890 Effect.tryPromise({
1891 try: () => iter.next(),
1892 catch: onError
1893 }),
1894 (result) => result.done ? Cause.done(result.value) : Effect.succeed(result.value)
1895 )
1896 }))
1897
1898/**
1899 * Creates a channel from an `AsyncIterable`, emitting each yielded value as a
1900 * single-element non-empty array.
1901 *
1902 * **Details**
1903 *
1904 * The iterator's return value becomes the channel's done value. Thrown or
1905 * rejected iterator errors are converted with `onError`. If the channel scope
1906 * closes early and the iterator has a `return` method, that method is called.
1907 *
1908 * @category constructors
1909 * @since 4.0.0
1910 */
1911export const fromAsyncIterableArray = <A, D, E>(
1912 iterable: AsyncIterable<A, D>,
1913 onError: (error: unknown) => E
1914): Channel<Arr.NonEmptyReadonlyArray<A>, E, D> => map(fromAsyncIterable(iterable, onError), Arr.of)
1915
1916/**
1917 * Maps the output of this channel using the specified function.
1918 *
1919 * **Example** (Mapping channel output)
1920 *
1921 * ```ts import.meta.vitest
1922 * import { Channel, Data, Effect } from "effect"
1923 *
1924 * class TransformError extends Data.TaggedError("TransformError")<{
1925 * readonly reason: string
1926 * }> {}
1927 *
1928 * // Basic mapping of channel values
1929 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5])
1930 * const doubledChannel = Channel.map(numbersChannel, (n) => n * 2)
1931 * Effect.runSync(Channel.runCollect(doubledChannel)) // => [2, 4, 6, 8, 10]
1932 *
1933 * // Transform string data
1934 * const wordsChannel = Channel.fromIterable(["hello", "world", "effect"])
1935 * const upperCaseChannel = Channel.map(wordsChannel, (word) => word.toUpperCase())
1936 * Effect.runSync(Channel.runCollect(upperCaseChannel)) // => ["HELLO", "WORLD", "EFFECT"]
1937 *
1938 * // Complex object transformation
1939 * type User = { id: number; name: string }
1940 * type UserDisplay = { displayName: string; isActive: boolean }
1941 *
1942 * const usersChannel = Channel.fromIterable([
1943 * { id: 1, name: "Alice" },
1944 * { id: 2, name: "Bob" }
1945 * ])
1946 * const displayChannel = Channel.map(usersChannel, (user): UserDisplay => ({
1947 * displayName: `User: ${user.name}`,
1948 * isActive: true
1949 * }))
1950 * Effect.runSync(Channel.runCollect(displayChannel)) // => [{ displayName: "User: Alice", isActive: true }, { displayName: "User: Bob", isActive: true }]
1951 * ```
1952 *
1953 * @category sequencing
1954 * @since 2.0.0
1955 */
1956export const map: {
1957 <OutElem, OutElem2>(
1958 f: (o: OutElem, i: number) => OutElem2
1959 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
1960 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
1961 ) => Channel<OutElem2, OutErr, OutDone, InElem, InErr, InDone, Env>
1962 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem2>(
1963 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
1964 f: (o: OutElem, i: number) => OutElem2
1965 ): Channel<OutElem2, OutErr, OutDone, InElem, InErr, InDone, Env>
1966} = dual(
1967 2,
1968 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem2>(
1969 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
1970 f: (o: OutElem, i: number) => OutElem2
1971 ): Channel<OutElem2, OutErr, OutDone, InElem, InErr, InDone, Env> =>
1972 transformPull(self, (pull) =>
1973 Effect.sync(() => {
1974 let i = 0
1975 return Effect.map(pull, (o) => f(o, i++))
1976 }))
1977)
1978
1979/**
1980 * Maps the done value of this channel using the specified function.
1981 *
1982 * @category sequencing
1983 * @since 4.0.0
1984 */
1985export const mapDone: {
1986 <OutDone, OutDone2>(
1987 f: (o: OutDone) => OutDone2
1988 ): <OutElem, OutErr, InElem, InErr, InDone, Env>(
1989 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
1990 ) => Channel<OutElem, OutErr, OutDone2, InElem, InErr, InDone, Env>
1991 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2>(
1992 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
1993 f: (o: OutDone) => OutDone2
1994 ): Channel<OutElem, OutErr, OutDone2, InElem, InErr, InDone, Env>
1995} = dual(
1996 2,
1997 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2>(
1998 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
1999 f: (o: OutDone) => OutDone2
2000 ): Channel<OutElem, OutErr, OutDone2, InElem, InErr, InDone, Env> => mapDoneEffect(self, (o) => Effect.succeed(f(o)))
2001)
2002
2003/**
2004 * Maps the done value of this channel using the specified effectful function.
2005 *
2006 * **When to use**
2007 *
2008 * Use when the terminal done value transformation needs services or can fail,
2009 * while emitted elements should pass through unchanged.
2010 *
2011 * @category sequencing
2012 * @since 4.0.0
2013 */
2014export const mapDoneEffect: {
2015 <OutDone, OutDone2, E, R>(
2016 f: (o: OutDone) => Effect.Effect<OutDone2, E, R>
2017 ): <OutElem, OutErr, InElem, InErr, InDone, Env>(
2018 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2019 ) => Channel<OutElem, OutErr | E, OutDone2, InElem, InErr, InDone, Env | R>
2020 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2, E, R>(
2021 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2022 f: (o: OutDone) => Effect.Effect<OutDone2, E, R>
2023 ): Channel<OutElem, OutErr | E, OutDone2, InElem, InErr, InDone, Env | R>
2024} = dual(
2025 2,
2026 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2, E, R>(
2027 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2028 f: (o: OutDone) => Effect.Effect<OutDone2, E, R>
2029 ): Channel<OutElem, OutErr | E, OutDone2, InElem, InErr, InDone, Env | R> =>
2030 transformPull(self, (pull) =>
2031 Effect.succeed(Pull.catchDone(
2032 pull,
2033 (done) => Effect.flatMap(f(done as OutDone), Cause.done)
2034 )))
2035)
2036
2037const concurrencyIsSequential = (
2038 concurrency: Types.Concurrency | undefined
2039) => concurrency === undefined || (concurrency !== "unbounded" && concurrency <= 1)
2040
2041/**
2042 * Maps each output element with an effectful function, preserving the source
2043 * channel's done value.
2044 *
2045 * **When to use**
2046 *
2047 * Use when transforming each channel output needs an Effect, service
2048 * dependency, failure channel, or configured concurrency.
2049 *
2050 * **Details**
2051 *
2052 * The mapping function receives the output element and its zero-based index.
2053 * By default elements are mapped sequentially. Use `options.concurrency` to
2054 * map multiple elements concurrently, and `options.unordered` to allow
2055 * concurrently mapped outputs to be emitted as soon as they complete.
2056 *
2057 * **Example** (Mapping channel output with effects)
2058 *
2059 * ```ts import.meta.vitest
2060 * import { Channel, Effect } from "effect"
2061 *
2062 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5])
2063 * const processedChannel = Channel.mapEffect(
2064 * numbersChannel,
2065 * (n) => Effect.succeed(n * n)
2066 * )
2067 * await Effect.runPromise(Channel.runCollect(processedChannel)) // => [1, 4, 9, 16, 25]
2068 * ```
2069 *
2070 * @category sequencing
2071 * @since 2.0.0
2072 */
2073export const mapEffect: {
2074 <OutElem, OutElem1, OutErr1, Env1>(
2075 f: (d: OutElem, i: number) => Effect.Effect<OutElem1, OutErr1, Env1>,
2076 options?: {
2077 readonly concurrency?: Types.Concurrency | undefined
2078 readonly unordered?: boolean | undefined
2079 }
2080 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
2081 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2082 ) => Channel<OutElem1, OutErr1 | OutErr, OutDone, InElem, InErr, InDone, Env1 | Env>
2083 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem1, OutErr1, Env1>(
2084 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2085 f: (d: OutElem, i: number) => Effect.Effect<OutElem1, OutErr1, Env1>,
2086 options?: {
2087 readonly concurrency?: Types.Concurrency | undefined
2088 readonly unordered?: boolean | undefined
2089 }
2090 ): Channel<OutElem1, OutErr | OutErr1, OutDone, InElem, InErr, InDone, Env | Env1>
2091} = dual(
2092 (args) => isChannel(args[0]),
2093 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem1, OutErr1, Env1>(
2094 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2095 f: (d: OutElem, i: number) => Effect.Effect<OutElem1, OutErr1, Env1>,
2096 options?: {
2097 readonly concurrency?: Types.Concurrency | undefined
2098 readonly unordered?: boolean | undefined
2099 }
2100 ): Channel<OutElem1, OutErr | OutErr1, OutDone, InElem, InErr, InDone, Env | Env1> =>
2101 concurrencyIsSequential(options?.concurrency)
2102 ? mapEffectSequential(self, f)
2103 : mapEffectConcurrent(self, f, options as any)
2104)
2105
2106const mapEffectSequential = <
2107 OutElem,
2108 OutErr,
2109 OutDone,
2110 InElem,
2111 InErr,
2112 InDone,
2113 Env,
2114 OutElem2,
2115 EX,
2116 RX
2117>(
2118 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2119 f: (o: OutElem, i: number) => Effect.Effect<OutElem2, EX, RX>
2120): Channel<OutElem2, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX> =>
2121 fromTransform((upstream, scope) => {
2122 let i = 0
2123 return Effect.map(toTransform(self)(upstream, scope), Effect.flatMap((o) => f(o, i++)))
2124 })
2125
2126const mapEffectConcurrent = <
2127 OutElem,
2128 OutErr,
2129 OutDone,
2130 InElem,
2131 InErr,
2132 InDone,
2133 Env,
2134 OutElem2,
2135 EX,
2136 RX
2137>(
2138 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2139 f: (o: OutElem, i: number) => Effect.Effect<OutElem2, EX, RX>,
2140 options: {
2141 readonly concurrency: Types.Concurrency
2142 readonly unordered?: boolean | undefined
2143 }
2144): Channel<OutElem2, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX> =>
2145 fromTransformBracket(
2146 Effect.fnUntraced(function*(upstream, scope, forkedScope) {
2147 let i = 0
2148 const pull = yield* toTransform(self)(upstream, scope)
2149 const concurrencyN = options.concurrency === "unbounded"
2150 ? Number.MAX_SAFE_INTEGER
2151 : options.concurrency
2152 const queue = yield* Queue.bounded<OutElem2, OutErr | EX | Cause.Done<OutDone>>(0)
2153 yield* Scope.addFinalizer(forkedScope, Queue.shutdown(queue))
2154
2155 const runFork = Effect.runForkWith(yield* Effect.context<RX>())
2156 const trackFiber = Fiber.runIn(forkedScope)
2157
2158 if (options.unordered) {
2159 const semaphore = Semaphore.makeUnsafe(concurrencyN)
2160 const release = constant(semaphore.release(1))
2161 const handle = Effect.matchCauseEffect({
2162 onFailure: (cause: Cause.Cause<EX>) => Effect.flatMap(Queue.failCause(queue, cause), release),
2163 onSuccess: (value: OutElem2) => Effect.flatMap(Queue.offer(queue, value), release)
2164 })
2165 yield* semaphore.take(1).pipe(
2166 Effect.flatMap(() => pull),
2167 Effect.flatMap((value) => {
2168 const index = i++
2169 trackFiber(runFork(handle(Effect.suspend(() => f(value, index)))))
2170 return Effect.void
2171 }),
2172 Effect.forever({ disableYield: true }),
2173 Effect.catchCause((cause) =>
2174 semaphore.withPermits(concurrencyN - 1)(
2175 Queue.failCause(queue, cause)
2176 )
2177 ),
2178 Effect.forkIn(forkedScope)
2179 )
2180 } else {
2181 // capacity is n - 2 because
2182 // - 1 for the offer *after* starting a fiber
2183 // - 1 for the current processing fiber
2184 const effects = yield* Queue.bounded<
2185 Effect.Effect<OutElem2, OutErr | EX | Cause.Done<OutDone>>,
2186 OutErr | EX | Cause.Done<OutDone>
2187 >(concurrencyN - 2)
2188 yield* Scope.addFinalizer(forkedScope, Queue.shutdown(effects))
2189
2190 yield* Queue.take(effects).pipe(
2191 Effect.flatten,
2192 Effect.flatMap((value) => Queue.offer(queue, value)),
2193 Effect.forever({ disableYield: true }),
2194 Effect.catchCause((cause) => Queue.failCause(queue, cause)),
2195 Effect.forkIn(forkedScope)
2196 )
2197
2198 let errorCause: Cause.Cause<EX> | undefined
2199 const onExit = (exit: Exit.Exit<OutElem2, EX>) => {
2200 if (exit._tag === "Success") return
2201 errorCause = exit.cause
2202 Queue.failCauseUnsafe(queue, exit.cause)
2203 }
2204 yield* pull.pipe(
2205 Effect.flatMap((value) => {
2206 if (errorCause) return Effect.failCause(errorCause)
2207 const index = i++
2208 const fiber = runFork(Effect.suspend(() => f(value, index)))
2209 trackFiber(fiber)
2210 fiber.addObserver(onExit)
2211 return Queue.offer(effects, Fiber.join(fiber))
2212 }),
2213 Effect.forever({ disableYield: true }),
2214 Effect.catchCause((cause) =>
2215 Queue.offer(effects, Exit.failCause(cause)).pipe(
2216 Effect.andThen(Queue.failCause(effects, cause))
2217 )
2218 ),
2219 Effect.forkIn(forkedScope)
2220 )
2221 }
2222
2223 return Queue.take(queue)
2224 })
2225 )
2226
2227/**
2228 * Returns a new channel which is the same as this one but applies the given
2229 * function to the input channel’s input elements.
2230 *
2231 * @category sequencing
2232 * @since 2.0.0
2233 */
2234export const mapInput: {
2235 <InElem, InElem2, InErr, R = never>(
2236 f: (i: InElem2) => Effect.Effect<InElem, InErr, R>
2237 ): <OutElem, OutErr, OutDone, InErr, InDone, Env>(
2238 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env | R>
2239 ) => Channel<OutElem, OutErr, OutDone, InElem2, InErr, InDone, Env>
2240 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, InElem2, R = never>(
2241 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2242 f: (i: InElem2) => Effect.Effect<InElem, InErr, R>
2243 ): Channel<OutElem, OutErr, OutDone, InElem2, InErr, InDone, Env | R>
2244} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, InElem2, R = never>(
2245 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2246 f: (i: InElem2) => Effect.Effect<InElem, InErr, R>
2247): Channel<OutElem, OutErr, OutDone, InElem2, InErr, InDone, Env | R> =>
2248 fromTransform((upstream, scope) =>
2249 toTransform(self)(
2250 Effect.flatMap(upstream, (el) => f(el)) as Pull.Pull<InElem, InErr, InDone>,
2251 scope
2252 )
2253 ))
2254
2255/**
2256 * Returns a new channel which is the same as this one but applies the given
2257 * function to the input errors.
2258 *
2259 * @category sequencing
2260 * @since 2.0.0
2261 */
2262export const mapInputError: {
2263 <InErr, InErr2, R = never>(
2264 f: (i: InErr2) => Effect.Effect<InErr, InErr, R>
2265 ): <OutElem, OutErr, OutDone, InElem, InDone, Env>(
2266 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env | R>
2267 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr2, InDone, Env>
2268 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, InErr2, R = never>(
2269 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2270 f: (i: InErr2) => Effect.Effect<InErr, InErr, R>
2271 ): Channel<OutElem, OutErr, OutDone, InElem, InErr2, InDone, Env | R>
2272} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, InErr2, R = never>(
2273 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2274 f: (i: InErr2) => Effect.Effect<InErr, InErr, R>
2275): Channel<OutElem, OutErr, OutDone, InElem, InErr2, InDone, Env | R> =>
2276 fromTransform((upstream, scope) =>
2277 toTransform(self)(
2278 Effect.catch(upstream, (err): Pull.Pull<never, InErr, InDone> => {
2279 if (Cause.isDone(err)) return Effect.fail(err)
2280 return Effect.flatMap(f(err), Effect.fail) as Pull.Pull<never, InErr, InDone>
2281 }),
2282 scope
2283 )
2284 ))
2285
2286/**
2287 * Applies a side effect function to each output element of the channel,
2288 * returning a new channel that emits the same elements.
2289 *
2290 * **Details**
2291 *
2292 * The `tap` function allows you to perform side effects (like logging or
2293 * debugging) on each element emitted by a channel without modifying the
2294 * elements themselves.
2295 *
2296 * **Example** (Tapping channel output)
2297 *
2298 * ```ts import.meta.vitest
2299 * import { Channel, Data, Effect } from "effect"
2300 *
2301 * class LogError extends Data.TaggedError("LogError")<{
2302 * readonly message: string
2303 * }> {}
2304 *
2305 * // Create a channel that outputs numbers
2306 * const numberChannel = Channel.fromIterable([1, 2, 3])
2307 *
2308 * // Tap into each output element to perform side effects
2309 * const processed: Array<number> = []
2310 * const tappedChannel = Channel.tap(
2311 * numberChannel,
2312 * (n) => Effect.sync(() => processed.push(n))
2313 * )
2314 *
2315 * const observed = [await Effect.runPromise(Channel.runCollect(tappedChannel)), processed] // => [[1, 2, 3], [1, 2, 3]]
2316 * ```
2317 *
2318 * @category sequencing
2319 * @since 4.0.0
2320 */
2321export const tap: {
2322 <OutElem, X, OutErr1, Env1>(
2323 f: (d: Types.NoInfer<OutElem>) => Effect.Effect<X, OutErr1, Env1>,
2324 options?: {
2325 readonly concurrency?: Types.Concurrency | undefined
2326 }
2327 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
2328 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2329 ) => Channel<OutElem, OutErr1 | OutErr, OutDone, InElem, InErr, InDone, Env1 | Env>
2330 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, X, OutErr1, Env1>(
2331 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2332 f: (d: Types.NoInfer<OutElem>) => Effect.Effect<X, OutErr1, Env1>,
2333 options?: {
2334 readonly concurrency?: Types.Concurrency | undefined
2335 }
2336 ): Channel<OutElem, OutErr | OutErr1, OutDone, InElem, InErr, InDone, Env | Env1>
2337} = dual(
2338 (args) => isChannel(args[0]),
2339 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, X, OutErr1, Env1>(
2340 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2341 f: (d: Types.NoInfer<OutElem>) => Effect.Effect<X, OutErr1, Env1>,
2342 options?: {
2343 readonly concurrency?: Types.Concurrency | undefined
2344 }
2345 ): Channel<OutElem, OutErr | OutErr1, OutDone, InElem, InErr, InDone, Env | Env1> =>
2346 mapEffect(self, (a) => Effect.as(f(a), a), options)
2347)
2348
2349/**
2350 * Maps each output element to a channel and flattens the child channel
2351 * outputs.
2352 *
2353 * **Details**
2354 *
2355 * The source channel's done value is preserved. Child channel done values are
2356 * used only for child-channel completion. By default child channels are run
2357 * sequentially. Use `options.concurrency` and `options.bufferSize` to run child
2358 * channels concurrently.
2359 *
2360 * **Example** (Flat mapping channel output)
2361 *
2362 * ```ts import.meta.vitest
2363 * import { Channel, Data, Effect } from "effect"
2364 *
2365 * class ProcessError extends Data.TaggedError("ProcessError")<{
2366 * readonly cause: string
2367 * }> {}
2368 *
2369 * // Create a channel that outputs numbers
2370 * const numberChannel = Channel.fromIterable([1, 2, 3])
2371 *
2372 * // FlatMap each number to create new channels
2373 * const flatMappedChannel = Channel.flatMap(
2374 * numberChannel,
2375 * (n) =>
2376 * Channel.fromIterable(Array.from({ length: n }, (_, i) => `item-${n}-${i}`))
2377 * )
2378 *
2379 * Effect.runSync(Channel.runCollect(flatMappedChannel)) // => ["item-1-0", "item-2-0", "item-2-1", "item-3-0", "item-3-1", "item-3-2"]
2380 * ```
2381 *
2382 * @category sequencing
2383 * @since 2.0.0
2384 */
2385export const flatMap: {
2386 <OutElem, OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
2387 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
2388 options?: {
2389 readonly concurrency?: Types.Concurrency | undefined
2390 readonly bufferSize?: number | undefined
2391 }
2392 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
2393 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2394 ) => Channel<
2395 OutElem1,
2396 OutErr1 | OutErr,
2397 OutDone,
2398 InElem & InElem1,
2399 InErr & InErr1,
2400 InDone & InDone1,
2401 Env1 | Env
2402 >
2403 <
2404 OutElem,
2405 OutErr,
2406 OutDone,
2407 InElem,
2408 InErr,
2409 InDone,
2410 Env,
2411 OutElem1,
2412 OutErr1,
2413 OutDone1,
2414 InElem1,
2415 InErr1,
2416 InDone1,
2417 Env1
2418 >(
2419 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2420 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
2421 options?: {
2422 readonly concurrency?: Types.Concurrency | undefined
2423 readonly bufferSize?: number | undefined
2424 }
2425 ): Channel<
2426 OutElem1,
2427 OutErr | OutErr1,
2428 OutDone,
2429 InElem & InElem1,
2430 InErr & InErr1,
2431 InDone & InDone1,
2432 Env | Env1
2433 >
2434} = dual(
2435 (args) => isChannel(args[0]),
2436 <
2437 OutElem,
2438 OutErr,
2439 OutDone,
2440 InElem,
2441 InErr,
2442 InDone,
2443 Env,
2444 OutElem1,
2445 OutErr1,
2446 OutDone1,
2447 InElem1,
2448 InErr1,
2449 InDone1,
2450 Env1
2451 >(
2452 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2453 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
2454 options?: {
2455 readonly concurrency?: Types.Concurrency | undefined
2456 readonly bufferSize?: number | undefined
2457 }
2458 ): Channel<
2459 OutElem1,
2460 OutErr | OutErr1,
2461 OutDone,
2462 InElem & InElem1,
2463 InErr & InErr1,
2464 InDone & InDone1,
2465 Env | Env1
2466 > =>
2467 concurrencyIsSequential(options?.concurrency)
2468 ? flatMapSequential(self, f)
2469 : flatMapConcurrent(self, f, options as any)
2470)
2471
2472const flatMapSequential = <
2473 OutElem,
2474 OutErr,
2475 OutDone,
2476 InElem,
2477 InErr,
2478 InDone,
2479 Env,
2480 OutElem1,
2481 OutErr1,
2482 OutDone1,
2483 InElem1,
2484 InErr1,
2485 InDone1,
2486 Env1
2487>(
2488 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2489 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2490): Channel<
2491 OutElem1,
2492 OutErr | OutErr1,
2493 OutDone,
2494 InElem & InElem1,
2495 InErr & InErr1,
2496 InDone & InDone1,
2497 Env | Env1
2498> =>
2499 fromTransform((upstream, scope) =>
2500 Effect.map(toTransform(self)(upstream, scope), (pull) => {
2501 let childPull: Effect.Effect<OutElem1, OutErr1, Env1> | undefined
2502 let childScope: Scope.Closeable | undefined
2503 const makePull: Pull.Pull<
2504 OutElem1,
2505 OutErr | OutErr1,
2506 OutDone,
2507 Env1
2508 > = Effect.flatMap(pull, (value) => {
2509 childScope ??= Scope.forkUnsafe(scope)
2510 return Effect.flatMapEager(toTransform(f(value))(upstream, childScope), (pull) => {
2511 childPull = catchHalt(pull) as any
2512 return childPull!
2513 })
2514 })
2515 const catchHalt = Pull.catchDone((_) => {
2516 childPull = undefined
2517 // the scope can be reused if the inner channel left no finalizers behind
2518 if (childScope!.state._tag === "Empty") {
2519 return makePull
2520 }
2521 const close = Scope.close(childScope!, Exit.void)
2522 childScope = undefined
2523 return Effect.flatMap(close, () => makePull)
2524 })
2525 return Effect.suspend(() => childPull ?? makePull)
2526 })
2527 )
2528
2529const flatMapConcurrent = <
2530 OutElem,
2531 OutErr,
2532 OutDone,
2533 InElem,
2534 InErr,
2535 InDone,
2536 Env,
2537 OutElem1,
2538 OutErr1,
2539 OutDone1,
2540 InElem1,
2541 InErr1,
2542 InDone1,
2543 Env1
2544>(
2545 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2546 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
2547 options: {
2548 readonly concurrency: Types.Concurrency
2549 readonly bufferSize?: number | undefined
2550 }
2551): Channel<
2552 OutElem1,
2553 OutErr | OutErr1,
2554 OutDone,
2555 InElem & InElem1,
2556 InErr & InErr1,
2557 InDone & InDone1,
2558 Env | Env1
2559> => self.pipe(map(f), mergeAll(options))
2560
2561/**
2562 * Concatenates this channel with another channel created from the terminal value
2563 * of this channel. The new channel is created using the provided function.
2564 *
2565 * **Example** (Concatenating with completion values)
2566 *
2567 * ```ts import.meta.vitest
2568 * import { Channel, Data, Effect } from "effect"
2569 *
2570 * class ConcatError extends Data.TaggedError("ConcatError")<{
2571 * readonly reason: string
2572 * }> {}
2573 *
2574 * // Create a channel that outputs numbers and terminates with sum
2575 * const numberChannel = Channel.fromIterable([1, 2, 3]).pipe(
2576 * Channel.concatWith((sum: void) => Channel.succeed(`Completed processing`))
2577 * )
2578 *
2579 * Effect.runSync(Channel.runCollect(numberChannel)) // => [1, 2, 3, "Completed processing"]
2580 * ```
2581 *
2582 * @category sequencing
2583 * @since 4.0.0
2584 */
2585export const concatWith: {
2586 <OutDone, OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
2587 f: (leftover: Types.NoInfer<OutDone>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2588 ): <OutElem, OutErr, InElem, InErr, InDone, Env>(
2589 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2590 ) => Channel<
2591 OutElem | OutElem1,
2592 OutErr1 | OutErr,
2593 OutDone1,
2594 InElem & InElem1,
2595 InErr & InErr1,
2596 InDone & InDone1,
2597 Env1 | Env
2598 >
2599 <
2600 OutElem,
2601 OutErr,
2602 OutDone,
2603 InElem,
2604 InErr,
2605 InDone,
2606 Env,
2607 OutElem1,
2608 OutErr1,
2609 OutDone1,
2610 InElem1,
2611 InErr1,
2612 InDone1,
2613 Env1
2614 >(
2615 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2616 f: (leftover: Types.NoInfer<OutDone>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2617 ): Channel<
2618 OutElem | OutElem1,
2619 OutErr1 | OutErr,
2620 OutDone1,
2621 InElem & InElem1,
2622 InErr & InErr1,
2623 InDone & InDone1,
2624 Env1 | Env
2625 >
2626} = dual(2, <
2627 OutElem,
2628 OutErr,
2629 OutDone,
2630 InElem,
2631 InErr,
2632 InDone,
2633 Env,
2634 OutElem1,
2635 OutErr1,
2636 OutDone1,
2637 InElem1,
2638 InErr1,
2639 InDone1,
2640 Env1
2641>(
2642 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2643 f: (leftover: Types.NoInfer<OutDone>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2644): Channel<
2645 OutElem | OutElem1,
2646 OutErr1 | OutErr,
2647 OutDone1,
2648 InElem & InElem1,
2649 InErr & InErr1,
2650 InDone & InDone1,
2651 Env1 | Env
2652> =>
2653 fromTransform((upstream, scope) =>
2654 Effect.sync(() => {
2655 let currentPull: Pull.Pull<OutElem | OutElem1, OutErr1 | OutErr, OutDone1, Env1 | Env> | undefined
2656 const forkedScope = Scope.forkUnsafe(scope)
2657 const makePull = Effect.flatMap(toTransform(self)(upstream, forkedScope), (pull) => {
2658 currentPull = Pull.catchDone(pull, (leftover) => {
2659 return Scope.close(forkedScope, Exit.void).pipe(
2660 Effect.flatMap(() => toTransform(f(leftover as OutDone))(upstream, scope)),
2661 Effect.flatMap((pull) => {
2662 currentPull = pull
2663 return pull
2664 })
2665 )
2666 })
2667 return currentPull
2668 })
2669 return Effect.suspend(() => currentPull ?? makePull)
2670 })
2671 ))
2672
2673/**
2674 * Concatenates this channel with another channel, so that the second channel
2675 * starts emitting values after the first channel has completed.
2676 *
2677 * **Example** (Concatenating channels)
2678 *
2679 * ```ts import.meta.vitest
2680 * import { Channel, Data, Effect } from "effect"
2681 *
2682 * class ConcatError extends Data.TaggedError("ConcatError")<{
2683 * readonly reason: string
2684 * }> {}
2685 *
2686 * // Create two channels
2687 * const firstChannel = Channel.fromIterable([1, 2, 3])
2688 * const secondChannel = Channel.fromIterable(["a", "b", "c"])
2689 *
2690 * // Concatenate them
2691 * const concatenatedChannel = Channel.concat(firstChannel, secondChannel)
2692 *
2693 * Effect.runSync(Channel.runCollect(concatenatedChannel)) // => [1, 2, 3, "a", "b", "c"]
2694 * ```
2695 *
2696 * @category sequencing
2697 * @since 4.0.0
2698 */
2699export const concat: {
2700 <OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
2701 that: Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2702 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
2703 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2704 ) => Channel<
2705 OutElem | OutElem1,
2706 OutErr1 | OutErr,
2707 OutDone1,
2708 InElem & InElem1,
2709 InErr & InErr1,
2710 InDone & InDone1,
2711 Env1 | Env
2712 >
2713 <
2714 OutElem,
2715 OutErr,
2716 OutDone,
2717 InElem,
2718 InErr,
2719 InDone,
2720 Env,
2721 OutElem1,
2722 OutErr1,
2723 OutDone1,
2724 InElem1,
2725 InErr1,
2726 InDone1,
2727 Env1
2728 >(
2729 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2730 that: Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2731 ): Channel<
2732 OutElem | OutElem1,
2733 OutErr1 | OutErr,
2734 OutDone1,
2735 InElem & InElem1,
2736 InErr & InErr1,
2737 InDone & InDone1,
2738 Env1 | Env
2739 >
2740} = dual(2, <
2741 OutElem,
2742 OutErr,
2743 OutDone,
2744 InElem,
2745 InErr,
2746 InDone,
2747 Env,
2748 OutElem1,
2749 OutErr1,
2750 OutDone1,
2751 InElem1,
2752 InErr1,
2753 InDone1,
2754 Env1
2755>(
2756 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2757 that: Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2758): Channel<
2759 OutElem | OutElem1,
2760 OutErr1 | OutErr,
2761 OutDone1,
2762 InElem & InElem1,
2763 InErr & InErr1,
2764 InDone & InDone1,
2765 Env1 | Env
2766> => concatWith(self, (_) => that))
2767
2768/**
2769 * Combines two channels with a stateful pull function.
2770 *
2771 * **When to use**
2772 *
2773 * Use to coordinate pulling from two channels when each output element depends
2774 * on both sides and local state.
2775 *
2776 * **Details**
2777 *
2778 * The combining function receives the current state and pull functions for the
2779 * left and right channels. It returns the next output element together with the
2780 * next state.
2781 *
2782 * @category sequencing
2783 * @since 4.0.0
2784 */
2785export const combine: {
2786 <OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2, S, OutElem, OutErr, OutDone, A, E, R>(
2787 that: Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>,
2788 s: LazyArg<S>,
2789 f: (
2790 s: S,
2791 pullLeft: Pull.Pull<OutElem, OutErr, OutDone>,
2792 pullRight: Pull.Pull<OutElem2, OutErr2, OutDone2>
2793 ) => Effect.Effect<readonly [A, S], E, R>
2794 ): <InElem, InErr, InDone, Env>(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
2795 A,
2796 Pull.ExcludeDone<E>,
2797 Cause.Done.Extract<E>,
2798 InElem & InElem2,
2799 InErr & InErr2,
2800 InDone & InDone2,
2801 Env | Env2 | R
2802 >
2803 <
2804 OutElem,
2805 OutErr,
2806 OutDone,
2807 InElem,
2808 InErr,
2809 InDone,
2810 Env,
2811 OutElem2,
2812 OutErr2,
2813 OutDone2,
2814 InElem2,
2815 InErr2,
2816 InDone2,
2817 Env2,
2818 S,
2819 A,
2820 E,
2821 R
2822 >(
2823 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2824 that: Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>,
2825 s: LazyArg<S>,
2826 f: (
2827 s: S,
2828 pullLeft: Pull.Pull<OutElem, OutErr, OutDone>,
2829 pullRight: Pull.Pull<OutElem2, OutErr2, OutDone2>
2830 ) => Effect.Effect<readonly [A, S], E, R>
2831 ): Channel<
2832 A,
2833 Pull.ExcludeDone<E>,
2834 Cause.Done.Extract<E>,
2835 InElem & InElem2,
2836 InErr & InErr2,
2837 InDone & InDone2,
2838 Env | Env2 | R
2839 >
2840} = dual(4, <
2841 OutElem,
2842 OutErr,
2843 OutDone,
2844 InElem,
2845 InErr,
2846 InDone,
2847 Env,
2848 OutElem2,
2849 OutErr2,
2850 OutDone2,
2851 InElem2,
2852 InErr2,
2853 InDone2,
2854 Env2,
2855 S,
2856 A,
2857 E,
2858 R
2859>(
2860 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2861 that: Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>,
2862 s: LazyArg<S>,
2863 f: (
2864 s: S,
2865 pullLeft: Pull.Pull<OutElem, OutErr, OutDone>,
2866 pullRight: Pull.Pull<OutElem2, OutErr2, OutDone2>
2867 ) => Effect.Effect<readonly [A, S], E, R>
2868): Channel<
2869 A,
2870 Pull.ExcludeDone<E>,
2871 Cause.Done.Extract<E>,
2872 InElem & InElem2,
2873 InErr & InErr2,
2874 InDone & InDone2,
2875 Env | Env2 | R
2876> =>
2877 fromTransform(Effect.fnUntraced(function*(upstream, scope) {
2878 const leftPull = yield* toTransform(self)(upstream, scope)
2879 const rightPull = yield* toTransform(that)(upstream, scope)
2880 let state = s()
2881 return Effect.suspend(() => {
2882 const combinedPull = f(state, leftPull, rightPull)
2883 return Effect.map(combinedPull, ([a, s1]) => {
2884 state = s1
2885 return a
2886 })
2887 })
2888 })))
2889
2890/**
2891 * Runs a fallback channel if this channel completes without emitting any
2892 * output elements.
2893 *
2894 * **Details**
2895 *
2896 * If the source emits at least one element, the source is used unchanged. If
2897 * the source completes before emitting an element, the fallback function
2898 * receives the source done value and returns the replacement channel.
2899 *
2900 * @category sequencing
2901 * @since 4.0.0
2902 */
2903export const orElseIfEmpty: {
2904 <OutDone, OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
2905 f: (leftover: Types.NoInfer<OutDone>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2906 ): <OutElem, OutErr, InElem, InErr, InDone, Env>(
2907 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
2908 ) => Channel<
2909 OutElem | OutElem1,
2910 OutErr1 | OutErr,
2911 OutDone | OutDone1,
2912 InElem & InElem1,
2913 InErr & InErr1,
2914 InDone & InDone1,
2915 Env1 | Env
2916 >
2917 <
2918 OutElem,
2919 OutErr,
2920 OutDone,
2921 InElem,
2922 InErr,
2923 InDone,
2924 Env,
2925 OutElem1,
2926 OutErr1,
2927 OutDone1,
2928 InElem1,
2929 InErr1,
2930 InDone1,
2931 Env1
2932 >(
2933 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2934 f: (leftover: Types.NoInfer<OutDone>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2935 ): Channel<
2936 OutElem | OutElem1,
2937 OutErr1 | OutErr,
2938 OutDone | OutDone1,
2939 InElem & InElem1,
2940 InErr & InErr1,
2941 InDone & InDone1,
2942 Env1 | Env
2943 >
2944} = dual(2, <
2945 OutElem,
2946 OutErr,
2947 OutDone,
2948 InElem,
2949 InErr,
2950 InDone,
2951 Env,
2952 OutElem1,
2953 OutErr1,
2954 OutDone1,
2955 InElem1,
2956 InErr1,
2957 InDone1,
2958 Env1
2959>(
2960 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
2961 f: (leftover: Types.NoInfer<OutDone>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
2962): Channel<
2963 OutElem | OutElem1,
2964 OutErr1 | OutErr,
2965 OutDone | OutDone1,
2966 InElem & InElem1,
2967 InErr & InErr1,
2968 InDone & InDone1,
2969 Env1 | Env
2970> =>
2971 fromTransform((upstream, scope) =>
2972 Effect.sync(() => {
2973 let currentPull: Pull.Pull<OutElem | OutElem1, OutErr1 | OutErr, OutDone | OutDone1, Env1 | Env> | undefined
2974 const forkedScope = Scope.forkUnsafe(scope)
2975 const makePull = Effect.flatMap(toTransform(self)(upstream, forkedScope), (pull) => {
2976 const next = pull.pipe(
2977 Effect.tap(() => {
2978 currentPull = pull
2979 return Effect.void
2980 }),
2981 Pull.catchDone((leftover) =>
2982 Scope.close(forkedScope, Exit.succeed(leftover)).pipe(
2983 Effect.andThen(toTransform(f(leftover as OutDone))(upstream, scope)),
2984 Effect.flatMap((pull) => {
2985 currentPull = pull
2986 return pull
2987 })
2988 )
2989 )
2990 )
2991 currentPull = next
2992 return next
2993 })
2994 return Effect.suspend(() => currentPull ?? makePull)
2995 })
2996 ))
2997
2998/**
2999 * Flattens a channel of channels.
3000 *
3001 * **Example** (Flattening nested channels)
3002 *
3003 * ```ts import.meta.vitest
3004 * import { Channel, Data, Effect } from "effect"
3005 *
3006 * class FlattenError extends Data.TaggedError("FlattenError")<{
3007 * readonly cause: string
3008 * }> {}
3009 *
3010 * // Create a channel that outputs channels
3011 * const nestedChannels = Channel.fromIterable([
3012 * Channel.fromIterable([1, 2]),
3013 * Channel.fromIterable([3, 4]),
3014 * Channel.fromIterable([5, 6])
3015 * ])
3016 *
3017 * // Flatten the nested channels
3018 * const flattenedChannel = Channel.flatten(nestedChannels)
3019 *
3020 * Effect.runSync(Channel.runCollect(flattenedChannel)) // => [1, 2, 3, 4, 5, 6]
3021 * ```
3022 *
3023 * @category constructors
3024 * @since 2.0.0
3025 */
3026export const flatten = <
3027 OutElem,
3028 OutErr,
3029 OutDone,
3030 InElem,
3031 InErr,
3032 InDone,
3033 Env,
3034 OutErr1,
3035 OutDone1,
3036 InElem1,
3037 InErr1,
3038 InDone1,
3039 Env1
3040>(
3041 channels: Channel<
3042 Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3043 OutErr1,
3044 OutDone1,
3045 InElem1,
3046 InErr1,
3047 InDone1,
3048 Env1
3049 >
3050): Channel<OutElem, OutErr | OutErr1, OutDone1, InElem & InElem1, InErr & InErr1, InDone & InDone1, Env | Env1> =>
3051 flatMap(channels, identity_)
3052
3053/**
3054 * Flattens a channel that outputs arrays into a channel that outputs individual elements.
3055 *
3056 * **Example** (Flattening arrays of channel output)
3057 *
3058 * ```ts import.meta.vitest
3059 * import { Channel, Data, Effect } from "effect"
3060 *
3061 * class FlattenError extends Data.TaggedError("FlattenError")<{
3062 * readonly message: string
3063 * }> {}
3064 *
3065 * // Create a channel that outputs arrays
3066 * const arrayChannel = Channel.fromIterable([
3067 * [1, 2, 3],
3068 * [4, 5],
3069 * [6, 7, 8, 9]
3070 * ])
3071 *
3072 * // Flatten the arrays into individual elements
3073 * const flattenedChannel = Channel.flattenArray(arrayChannel)
3074 *
3075 * Effect.runSync(Channel.runCollect(flattenedChannel)) // => [1, 2, 3, 4, 5, 6, 7, 8, 9]
3076 * ```
3077 *
3078 * @category transforming
3079 * @since 4.0.0
3080 */
3081export const flattenArray = <
3082 OutElem,
3083 OutErr,
3084 OutDone,
3085 InElem,
3086 InErr,
3087 InDone,
3088 Env
3089>(
3090 self: Channel<ReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3091): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3092 transformPull(self, (pull) => {
3093 let array: ReadonlyArray<OutElem> | undefined
3094 let index = 0
3095 const pump = Effect.suspend(function loop(): Pull.Pull<OutElem, OutErr, OutDone> {
3096 if (array === undefined) {
3097 return Effect.flatMap(pull, (array_) => {
3098 switch (array_.length) {
3099 case 0:
3100 return loop()
3101 case 1:
3102 return Effect.succeed(array_[0])
3103 default: {
3104 array = array_
3105 return Effect.succeed(array_[index++])
3106 }
3107 }
3108 })
3109 }
3110 const next = array[index++]
3111 if (index >= array.length) {
3112 array = undefined
3113 index = 0
3114 }
3115 return Effect.succeed(next)
3116 })
3117 return Effect.succeed(pump)
3118 })
3119
3120/**
3121 * Flattens a channel that emits `Take` values into a channel that emits the
3122 * `Take` outputs directly.
3123 *
3124 * **Details**
3125 *
3126 * Output `Take` values are emitted as non-empty arrays. Failed `Take` values
3127 * fail the returned channel. Done `Take` values complete the returned channel.
3128 *
3129 * @category transforming
3130 * @since 4.0.0
3131 */
3132export const flattenTake = <
3133 OutElem,
3134 OutErr,
3135 OutDone,
3136 OutErr2,
3137 OutDone2,
3138 InElem,
3139 InErr,
3140 InDone,
3141 Env
3142>(
3143 self: Channel<Take.Take<OutElem, OutErr, OutDone>, OutErr2, OutDone2, InElem, InErr, InDone, Env>
3144): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr | OutErr2, OutDone, InElem, InErr, InDone, Env> =>
3145 mapEffectSequential(self, Take.toPull) as any
3146
3147/**
3148 * Creates a new channel that consumes all output from the source channel
3149 * but emits nothing, preserving only the completion value.
3150 *
3151 * **Example** (Draining channel output)
3152 *
3153 * ```ts import.meta.vitest
3154 * import { Channel, Effect } from "effect"
3155 *
3156 * // Create a channel that outputs values
3157 * const sourceChannel = Channel.fromIterable([1, 2, 3, 4, 5])
3158 *
3159 * // Drain all output, keeping only the completion
3160 * const drainedChannel = Channel.drain(sourceChannel)
3161 *
3162 * Effect.runSync(Channel.runCollect(drainedChannel)) // => []
3163 * ```
3164 *
3165 * @category constructors
3166 * @since 2.0.0
3167 */
3168export const drain = <
3169 OutElem,
3170 OutErr,
3171 OutDone,
3172 InElem,
3173 InErr,
3174 InDone,
3175 Env
3176>(
3177 self: Channel<
3178 OutElem,
3179 OutErr,
3180 OutDone,
3181 InElem,
3182 InErr,
3183 InDone,
3184 Env
3185 >
3186): Channel<never, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3187 transformPull(self, (pull) => Effect.succeed(Effect.forever(pull, { disableYield: true })))
3188
3189/**
3190 * Repeats this channel according to the provided schedule.
3191 *
3192 * @category repetition
3193 * @since 4.0.0
3194 */
3195export const repeat: {
3196 <SO, OutDone, SE, SR>(
3197 schedule:
3198 | Schedule.Schedule<SO, Types.NoInfer<OutDone>, SE, SR>
3199 | ((
3200 $: <SO, SE, SR>(_: Schedule.Schedule<SO, NoInfer<OutDone>, SE, SR>) => Schedule.Schedule<SO, OutDone, SE, SR>
3201 ) => Schedule.Schedule<SO, Types.NoInfer<OutDone>, SE, SR>)
3202 ): <OutElem, OutErr, InElem, InErr, InDone, Env>(
3203 self: Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
3204 ) => Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
3205 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, SO, SE, SR>(
3206 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3207 schedule:
3208 | Schedule.Schedule<SO, OutDone, SE, SR>
3209 | ((
3210 $: <SO, SE, SR>(_: Schedule.Schedule<SO, NoInfer<OutDone>, SE, SR>) => Schedule.Schedule<SO, OutDone, SE, SR>
3211 ) => Schedule.Schedule<SO, Types.NoInfer<OutDone>, SE, SR>)
3212 ): Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
3213} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, SO, SE, SR>(
3214 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3215 schedule:
3216 | Schedule.Schedule<SO, OutDone, SE, SR>
3217 | ((
3218 $: <SO, SE, SR>(_: Schedule.Schedule<SO, NoInfer<OutDone>, SE, SR>) => Schedule.Schedule<SO, OutDone, SE, SR>
3219 ) => Schedule.Schedule<SO, Types.NoInfer<OutDone>, SE, SR>)
3220): Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR> =>
3221 Schedule.toStepWithMetadata(typeof schedule === "function" ? schedule(identity_) : schedule).pipe(
3222 Effect.map((step) => {
3223 let meta = Schedule.CurrentMetadata.defaultValue()
3224 return repeatLoop(
3225 provideServiceEffect(self, Schedule.CurrentMetadata, Effect.sync(() => meta)),
3226 (done) =>
3227 step(done).pipe(
3228 Effect.map((meta_) => {
3229 meta = meta_
3230 }),
3231 Pull.catchDone(() => Cause.done(done))
3232 )
3233 )
3234 }),
3235 unwrap
3236 ))
3237
3238const repeatLoop = <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, E, OutDone2, R>(
3239 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3240 onDone: (done: OutDone) => Pull.Pull<void, E, OutDone2, R>
3241): Channel<OutElem, OutErr | E, OutDone2, InElem, InErr, InDone, Env | R> =>
3242 fromTransform((upstream, scope) =>
3243 Effect.sync(() => {
3244 let currentPull: Pull.Pull<OutElem, OutErr | E, OutDone2, Env | R> | undefined
3245 const makePull = (): Pull.Pull<OutElem, OutErr | E, OutDone2, Env | R> => {
3246 const runScope = Scope.forkUnsafe(scope)
3247 return Effect.flatMap(toTransform(self)(upstream, runScope), (pull) => {
3248 currentPull = Pull.catchDone(pull, (done) =>
3249 Scope.close(runScope, Exit.void).pipe(
3250 Effect.flatMap(() => onDone(done as OutDone)),
3251 Effect.flatMap(makePull)
3252 ))
3253 return currentPull
3254 })
3255 }
3256 return Effect.suspend(() => currentPull ?? makePull())
3257 })
3258 )
3259
3260/**
3261 * Repeats this channel forever.
3262 *
3263 * @category repetition
3264 * @since 4.0.0
3265 */
3266export const forever = <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
3267 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3268): Channel<OutElem, OutErr, never, InElem, InErr, InDone, Env> => repeatLoop(self, () => Effect.void)
3269
3270/**
3271 * Runs a schedule step for each output element while preserving the emitted
3272 * elements.
3273 *
3274 * **Details**
3275 *
3276 * The schedule receives each output element as input. Schedule delays are
3277 * applied between emitted elements. If the schedule fails, the returned channel
3278 * fails. If the schedule finishes, the returned channel completes with the
3279 * schedule output.
3280 *
3281 * @category sequencing
3282 * @since 4.0.0
3283 */
3284export const schedule: {
3285 <SO, OutElem, SE, SR>(
3286 schedule: Schedule.Schedule<SO, Types.NoInfer<OutElem>, SE, SR>
3287 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3288 self: Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
3289 ) => Channel<OutElem, OutErr | SE, OutDone | SO, InElem, InErr, InDone, Env | SR>
3290 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, SO, SE, SR>(
3291 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3292 schedule: Schedule.Schedule<SO, OutElem, SE, SR>
3293 ): Channel<OutElem, OutErr | SE, OutDone | SO, InElem, InErr, InDone, Env | SR>
3294} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, SO, SE, SR>(
3295 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3296 schedule: Schedule.Schedule<SO, OutElem, SE, SR>
3297): Channel<OutElem, OutErr | SE, OutDone | SO, InElem, InErr, InDone, Env | SR> =>
3298 transformPull(
3299 self,
3300 (pull, _scope) =>
3301 Effect.map(
3302 Schedule.toStepWithSleep(schedule),
3303 (step) => {
3304 const pullWithStep: Pull.Pull<
3305 OutElem,
3306 OutErr | SE,
3307 OutDone | SO,
3308 SR
3309 > = Effect.tap(pull, step)
3310 return pullWithStep
3311 }
3312 )
3313 ))
3314
3315/**
3316 * Filters the output elements of a channel using a predicate function.
3317 * Elements that don't match the predicate are discarded.
3318 *
3319 * **Example** (Filtering channel output)
3320 *
3321 * ```ts import.meta.vitest
3322 * import { Channel, Effect } from "effect"
3323 *
3324 * // Create a channel with mixed numbers
3325 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5, 6, 7, 8])
3326 *
3327 * // Filter to keep only even numbers
3328 * const evenChannel = Channel.filter(numbersChannel, (n) => n % 2 === 0)
3329 * Effect.runSync(Channel.runCollect(evenChannel)) // => [2, 4, 6, 8]
3330 *
3331 * // Filter with type refinement
3332 * const mixedChannel = Channel.fromIterable([1, "hello", 2, "world", 3])
3333 * const numbersOnlyChannel = Channel.filter(
3334 * mixedChannel,
3335 * (value): value is number => typeof value === "number"
3336 * )
3337 * Effect.runSync(Channel.runCollect(numbersOnlyChannel)) // => [1, 2, 3]
3338 * ```
3339 *
3340 * @category filtering
3341 * @since 4.0.0
3342 */
3343export const filter: {
3344 <OutElem, B extends OutElem>(
3345 refinement: Predicate.Refinement<OutElem, B>
3346 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3347 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3348 ) => Channel<B, OutErr, OutDone, InElem, InErr, InDone, Env>
3349 <OutElem>(
3350 predicate: Predicate.Predicate<OutElem>
3351 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3352 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3353 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3354 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B extends OutElem>(
3355 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3356 refinement: Predicate.Refinement<OutElem, B>
3357 ): Channel<B, OutErr, OutDone, InElem, InErr, InDone, Env>
3358 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
3359 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3360 predicate: Predicate.Predicate<OutElem>
3361 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3362} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
3363 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3364 predicate: Predicate.Predicate<OutElem>
3365): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3366 fromTransform((upstream, scope) =>
3367 Effect.map(
3368 toTransform(self)(upstream, scope),
3369 (pull) =>
3370 Effect.flatMap(pull, function loop(elem): Pull.Pull<OutElem, OutErr, OutDone> {
3371 return predicate(elem)
3372 ? Effect.succeed(elem)
3373 : Effect.flatMap(pull, loop)
3374 })
3375 )
3376 ))
3377
3378/**
3379 * Filters and maps output elements using a `Filter`.
3380 *
3381 * **When to use**
3382 *
3383 * Use to keep only channel output elements accepted by a `Filter` and emit
3384 * each filter success value.
3385 *
3386 * **Details**
3387 *
3388 * Successful filter results are emitted as mapped values. Failed filter
3389 * results are discarded. The source channel's errors and done value are
3390 * preserved.
3391 *
3392 * @see {@link filter} for keeping original output elements with a predicate
3393 * @see {@link filterMapEffect} for using an effectful `Filter`
3394 * @see {@link filterMapArray} for filtering arrays of output elements
3395 *
3396 * @category filtering
3397 * @since 4.0.0
3398 */
3399export const filterMap: {
3400 <OutElem, B, X>(
3401 filter: Filter.Filter<OutElem, B, X>
3402 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3403 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3404 ) => Channel<B, OutErr, OutDone, InElem, InErr, InDone, Env>
3405 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X>(
3406 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3407 filter: Filter.Filter<OutElem, B, X>
3408 ): Channel<B, OutErr, OutDone, InElem, InErr, InDone, Env>
3409} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X>(
3410 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3411 filter: Filter.Filter<OutElem, B, X>
3412): Channel<B, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3413 fromTransform((upstream, scope) =>
3414 Effect.map(
3415 toTransform(self)(upstream, scope),
3416 (pull) =>
3417 Effect.flatMap(pull, function loop(elem): Pull.Pull<B, OutErr, OutDone> {
3418 const result = filter(elem)
3419 return Result.isFailure(result)
3420 ? Effect.flatMap(pull, loop)
3421 : Effect.succeed(result.success)
3422 })
3423 )
3424 ))
3425
3426/**
3427 * Filters output elements with an effectful predicate.
3428 *
3429 * **When to use**
3430 *
3431 * Use when the keep/discard decision depends on an Effect or service and
3432 * predicate failures should fail the returned channel.
3433 *
3434 * **Details**
3435 *
3436 * Elements for which the predicate succeeds with `true` are emitted. Elements
3437 * for which the predicate succeeds with `false` are discarded. Predicate
3438 * failures fail the returned channel.
3439 *
3440 * @category filtering
3441 * @since 4.0.0
3442 */
3443export const filterEffect: {
3444 <OutElem, E, R>(
3445 predicate: (a: OutElem) => Effect.Effect<boolean, E, R>
3446 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3447 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3448 ) => Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
3449 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, E, R>(
3450 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3451 predicate: (a: OutElem) => Effect.Effect<boolean, E, R>
3452 ): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
3453} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, E, R>(
3454 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3455 predicate: (a: OutElem) => Effect.Effect<boolean, E, R>
3456): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
3457 fromTransform((upstream, scope) =>
3458 Effect.map(
3459 toTransform(self)(upstream, scope),
3460 (pull) =>
3461 Effect.flatMap(pull, function loop(elem): Pull.Pull<OutElem, OutErr | E, OutDone, R> {
3462 return Effect.flatMap(
3463 predicate(elem),
3464 (passes) =>
3465 passes
3466 ? Effect.succeed(elem)
3467 : Effect.flatMap(pull, loop)
3468 )
3469 })
3470 )
3471 ))
3472
3473/**
3474 * Filters and maps output elements using an effectful `Filter`.
3475 *
3476 * **When to use**
3477 *
3478 * Use to apply effectful logic that can discard channel output elements and
3479 * emit transformed values for the elements that pass.
3480 *
3481 * **Details**
3482 *
3483 * Successful filter results are emitted as mapped values. Failed filter
3484 * results are discarded. Failures from the effectful filter fail the returned
3485 * channel.
3486 *
3487 * @see {@link filterMap} for using a synchronous `Filter`
3488 * @see {@link filterEffect} for effectfully keeping original output elements
3489 * @see {@link mapEffect} for effectfully transforming every output element
3490 * @see {@link filterMapArrayEffect} for effectful filtering of array outputs
3491 *
3492 * @category filtering
3493 * @since 4.0.0
3494 */
3495export const filterMapEffect: {
3496 <OutElem, B, X, EX, RX>(
3497 filter: Filter.FilterEffect<OutElem, B, X, EX, RX>
3498 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3499 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
3500 ) => Channel<B, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX>
3501 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X, EX, RX>(
3502 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3503 filter: Filter.FilterEffect<OutElem, B, X, EX, RX>
3504 ): Channel<B, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX>
3505} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X, EX, RX>(
3506 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3507 filter: Filter.FilterEffect<OutElem, B, X, EX, RX>
3508): Channel<B, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX> =>
3509 fromTransform((upstream, scope) =>
3510 Effect.map(
3511 toTransform(self)(upstream, scope),
3512 (pull) =>
3513 Effect.flatMap(pull, function loop(elem): Pull.Pull<B, OutErr | EX, OutDone, RX> {
3514 return Effect.flatMap(
3515 filter(elem),
3516 (result) =>
3517 Result.isFailure(result)
3518 ? Effect.flatMap(pull, loop)
3519 : Effect.succeed(result.success)
3520 )
3521 })
3522 )
3523 ))
3524
3525/**
3526 * Filters arrays of elements emitted by a channel, applying the filter
3527 * to each element within the arrays and only emitting non-empty filtered arrays.
3528 *
3529 * **Example** (Filtering array output)
3530 *
3531 * ```ts import.meta.vitest
3532 * import { Array, Channel, Effect } from "effect"
3533 *
3534 * const nonEmptyArrayPredicate = Array.isReadonlyArrayNonEmpty
3535 *
3536 * // Create a channel that outputs arrays of mixed data
3537 * const arrayChannel = Channel.fromIterable([
3538 * Array.make(1, 2, 3, 4, 5),
3539 * Array.make(6, 7, 8, 9, 10),
3540 * Array.make(11, 12, 13, 14, 15)
3541 * ]).pipe(Channel.filter(nonEmptyArrayPredicate))
3542 *
3543 * // Filter arrays to keep only even numbers
3544 * const evenArraysChannel = Channel.filterArray(arrayChannel, (n) => n % 2 === 0)
3545 * Effect.runSync(Channel.runCollect(evenArraysChannel)) // => [[2, 4], [6, 8, 10], [12, 14]]
3546 * // Note: Only non-empty filtered arrays are emitted
3547 *
3548 * // Arrays that would become empty after filtering are discarded entirely
3549 * const oddChannel = Channel.fromIterable([
3550 * Array.make(1, 3, 5),
3551 * Array.make(2, 4),
3552 * Array.make(7, 9)
3553 * ]).pipe(Channel.filter(nonEmptyArrayPredicate))
3554 * const filteredOddChannel = Channel.filterArray(oddChannel, (n) => n % 2 === 0)
3555 * Effect.runSync(Channel.runCollect(filteredOddChannel)) // => [[2, 4]]
3556 * ```
3557 *
3558 * @category filtering
3559 * @since 4.0.0
3560 */
3561export const filterArray: {
3562 <OutElem, B extends OutElem>(
3563 refinement: Predicate.Refinement<OutElem, B>
3564 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3565 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3566 ) => Channel<Arr.NonEmptyReadonlyArray<B>, OutErr, OutDone, InElem, InErr, InDone, Env>
3567 <OutElem>(
3568 predicate: Predicate.Predicate<Types.NoInfer<OutElem>>
3569 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3570 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3571 ) => Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3572 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B extends OutElem>(
3573 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3574 refinement: Predicate.Refinement<OutElem, B>
3575 ): Channel<Arr.NonEmptyReadonlyArray<B>, OutErr, OutDone, InElem, InErr, InDone, Env>
3576 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
3577 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3578 predicate: Predicate.Predicate<Types.NoInfer<OutElem>>
3579 ): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3580} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
3581 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3582 predicate: Predicate.Predicate<Types.NoInfer<OutElem>>
3583): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3584 transformPull(self, (pull) =>
3585 Effect.succeed(Effect.flatMap(
3586 pull,
3587 function loop(arr): Pull.Pull<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone> {
3588 const passes: Array<OutElem> = []
3589 for (let i = 0; i < arr.length; i++) {
3590 if (predicate(arr[i] as Types.NoInfer<OutElem>)) {
3591 passes.push(arr[i])
3592 }
3593 }
3594 return Arr.isReadonlyArrayNonEmpty(passes)
3595 ? Effect.succeed(passes)
3596 : Effect.flatMap(pull, loop)
3597 }
3598 ))))
3599
3600/**
3601 * Filters and maps each element inside emitted non-empty arrays using a
3602 * `Filter`.
3603 *
3604 * **Details**
3605 *
3606 * Successful filter results are kept as mapped values. Failed filter results
3607 * are removed from the array. Arrays that become empty are discarded.
3608 *
3609 * @category filtering
3610 * @since 4.0.0
3611 */
3612export const filterMapArray: {
3613 <OutElem, B, X>(
3614 filter: Filter.Filter<Types.NoInfer<OutElem>, B, X>
3615 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3616 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3617 ) => Channel<Arr.NonEmptyReadonlyArray<B>, OutErr, OutDone, InElem, InErr, InDone, Env>
3618 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X>(
3619 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3620 filter: Filter.Filter<OutElem, B, X>
3621 ): Channel<Arr.NonEmptyReadonlyArray<B>, OutErr, OutDone, InElem, InErr, InDone, Env>
3622} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X>(
3623 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3624 filter: Filter.Filter<OutElem, B, X>
3625): Channel<Arr.NonEmptyReadonlyArray<B>, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3626 transformPull(self, (pull) =>
3627 Effect.succeed(Effect.flatMap(
3628 pull,
3629 function loop(arr): Pull.Pull<Arr.NonEmptyReadonlyArray<B>, OutErr, OutDone> {
3630 const passes: Array<B> = []
3631 for (let i = 0; i < arr.length; i++) {
3632 const result = filter(arr[i])
3633 if (Result.isSuccess(result)) {
3634 passes.push(result.success)
3635 }
3636 }
3637 return Arr.isReadonlyArrayNonEmpty(passes)
3638 ? Effect.succeed(passes)
3639 : Effect.flatMap(pull, loop)
3640 }
3641 ))))
3642
3643/**
3644 * Filters each element inside emitted non-empty arrays with an effectful
3645 * predicate.
3646 *
3647 * **When to use**
3648 *
3649 * Use when filtering array-valued channel outputs requires Effects or services,
3650 * and arrays that become empty should be skipped.
3651 *
3652 * **Details**
3653 *
3654 * The predicate receives the element and its index within the array. Elements
3655 * for which the predicate succeeds with `true` are kept. Arrays that become
3656 * empty are discarded. Predicate failures fail the returned channel.
3657 *
3658 * @category filtering
3659 * @since 4.0.0
3660 */
3661export const filterArrayEffect: {
3662 <OutElem, E, R>(
3663 predicate: (a: Types.NoInfer<OutElem>, index: number) => Effect.Effect<boolean, E, R>
3664 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3665 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3666 ) => Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
3667 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, E, R>(
3668 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3669 predicate: (a: Types.NoInfer<OutElem>, index: number) => Effect.Effect<boolean, E, R>
3670 ): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
3671} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, E, R>(
3672 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3673 predicate: (a: Types.NoInfer<OutElem>, index: number) => Effect.Effect<boolean, E, R>
3674): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
3675 transformPull(self, (pull) => {
3676 const f = Effect.flatMap(pull, (arr) => Effect.filter(arr, predicate))
3677 return Effect.succeed(Effect.flatMap(
3678 f,
3679 function loop(arr): Pull.Pull<Arr.NonEmptyReadonlyArray<OutElem>, OutErr | E, OutDone, R> {
3680 return Arr.isReadonlyArrayNonEmpty(arr) ? Effect.succeed(arr) : Effect.flatMap(f, loop)
3681 }
3682 ))
3683 }))
3684
3685/**
3686 * Filters and maps each element inside emitted non-empty arrays using an
3687 * effectful `Filter`.
3688 *
3689 * **When to use**
3690 *
3691 * Use when array-valued channel outputs need an effectful filter-map that can
3692 * fail and can discard arrays that become empty.
3693 *
3694 * **Details**
3695 *
3696 * Successful filter results are kept as mapped values. Failed filter results
3697 * are removed from the array. Arrays that become empty are discarded. Failures
3698 * from the effectful filter fail the returned channel.
3699 *
3700 * @category filtering
3701 * @since 4.0.0
3702 */
3703export const filterMapArrayEffect: {
3704 <OutElem, B, X, EX, RX>(
3705 filter: Filter.FilterEffect<Types.NoInfer<OutElem>, B, X, EX, RX>
3706 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
3707 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
3708 ) => Channel<Arr.NonEmptyReadonlyArray<B>, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX>
3709 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X, EX, RX>(
3710 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3711 filter: Filter.FilterEffect<OutElem, B, X, EX, RX>
3712 ): Channel<Arr.NonEmptyReadonlyArray<B>, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX>
3713} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, B, X, EX, RX>(
3714 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
3715 filter: Filter.FilterEffect<OutElem, B, X, EX, RX>
3716): Channel<Arr.NonEmptyReadonlyArray<B>, OutErr | EX, OutDone, InElem, InErr, InDone, Env | RX> =>
3717 transformPull(self, (pull) =>
3718 Effect.succeed(Effect.flatMap(
3719 pull,
3720 function loop(arr): Pull.Pull<Arr.NonEmptyReadonlyArray<B>, OutErr | EX, OutDone, RX> {
3721 return Effect.flatMap(
3722 Effect.filterMapEffect(arr, filter as any),
3723 (passes) =>
3724 Arr.isReadonlyArrayNonEmpty(passes)
3725 ? Effect.succeed(passes as Arr.NonEmptyReadonlyArray<B>)
3726 : Effect.flatMap(pull, loop)
3727 )
3728 }
3729 ))))
3730
3731/**
3732 * Maps over a channel statefully with an accumulator, where each element can produce multiple output values.
3733 *
3734 * **Example** (Mapping with accumulated state)
3735 *
3736 * ```ts import.meta.vitest
3737 * import { Channel, Effect } from "effect"
3738 *
3739 * // Create a channel with numbers
3740 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4])
3741 *
3742 * // Use mapAccum to create running sums and emit both current and sum
3743 * const runningSum = Channel.mapAccum(
3744 * numbersChannel,
3745 * () => 0, // initial accumulator state
3746 * (sum, current) => {
3747 * const newSum = sum + current
3748 * // Return [newState, outputValues]
3749 * return [newSum, [current, newSum]] as const
3750 * }
3751 * )
3752 * // Using with Effect for async processing
3753 * const asyncMapAccum = Channel.mapAccum(
3754 * numbersChannel,
3755 * () => "",
3756 * (acc, value) =>
3757 * Effect.gen(function*() {
3758 * const newAcc = acc + value.toString()
3759 * return [newAcc, [`${value}-processed`, newAcc]] as const
3760 * })
3761 * )
3762 * Effect.runSync(Channel.runCollect(runningSum)) // => [1, 1, 2, 3, 3, 6, 4, 10]
3763 * Effect.runSync(Channel.runCollect(asyncMapAccum)) // => ["1-processed", "1", "2-processed", "12", "3-processed", "123", "4-processed", "1234"]
3764 * ```
3765 *
3766 * @category sequencing
3767 * @since 4.0.0
3768 */
3769export const mapAccum: {
3770 <S, OutElem, B, E = never, R = never>(
3771 initial: LazyArg<S>,
3772 f: (
3773 s: S,
3774 a: Types.NoInfer<OutElem>
3775 ) =>
3776 | Effect.Effect<readonly [state: S, values: ReadonlyArray<B>], E, R>
3777 | readonly [state: S, values: ReadonlyArray<B>],
3778 options?: {
3779 readonly onHalt?: ((state: S) => Array<B>) | undefined
3780 }
3781 ): <
3782 OutErr,
3783 OutDone,
3784 InElem,
3785 InErr,
3786 InDone,
3787 Env
3788 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
3789 B,
3790 OutErr | E,
3791 OutDone,
3792 InElem,
3793 InErr,
3794 InDone,
3795 Env | R
3796 >
3797 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, S, B, E = never, R = never>(
3798 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3799 initial: LazyArg<S>,
3800 f: (
3801 s: S,
3802 a: Types.NoInfer<OutElem>
3803 ) =>
3804 | Effect.Effect<readonly [state: S, values: ReadonlyArray<B>], E, R>
3805 | readonly [state: S, values: ReadonlyArray<B>],
3806 options?: {
3807 readonly onHalt?: ((state: S) => Array<B>) | undefined
3808 }
3809 ): Channel<B, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
3810} = dual(
3811 (args) => isChannel(args[0]),
3812 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, S, B, E = never, R = never>(
3813 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3814 initial: LazyArg<S>,
3815 f: (
3816 s: S,
3817 a: Types.NoInfer<OutElem>
3818 ) =>
3819 | Effect.Effect<readonly [state: S, values: ReadonlyArray<B>], E, R>
3820 | readonly [state: S, values: ReadonlyArray<B>],
3821 options?: {
3822 readonly onHalt?: ((state: S) => ReadonlyArray<B>) | undefined
3823 }
3824 ): Channel<B, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
3825 fromTransform((upstream, scope) =>
3826 Effect.map(toTransform(self)(upstream, scope), (pull) => {
3827 let state = initial()
3828 let current: ReadonlyArray<B> | undefined
3829 let index = 0
3830 let cause: Cause.Cause<OutErr | Cause.Done<OutDone>> | undefined
3831 const pullNext = Effect.matchCauseEffect(pull, {
3832 onFailure(cause_) {
3833 cause = cause_
3834 const b = options?.onHalt && options.onHalt(state)
3835 return b && b.length > 0
3836 ? Effect.succeed([state, b] as const)
3837 : Effect.failCause(cause_)
3838 },
3839 onSuccess(a): Effect.Effect<readonly [state: S, values: ReadonlyArray<B>], E, R> {
3840 const b = f(state, a)
3841 return Arr.isArray(b)
3842 ? Effect.succeed(b as any)
3843 : b as any
3844 }
3845 })
3846 const pump = Effect.suspend(function loop(): Pull.Pull<B, OutErr | E, OutDone, R> {
3847 if (current === undefined) {
3848 if (cause) return Effect.failCause(cause)
3849 return Effect.flatMap(pullNext, ([newState, values]) => {
3850 state = newState
3851 if (values.length === 0) {
3852 return loop()
3853 } else if (values.length === 1) {
3854 return Effect.succeed(values[0])
3855 }
3856 current = values
3857 return loop()
3858 })
3859 }
3860 const next = current[index++]
3861 if (index >= current.length) {
3862 current = undefined
3863 index = 0
3864 }
3865 return Effect.succeed(next)
3866 })
3867 return pump
3868 })
3869 )
3870)
3871
3872/**
3873 * Transforms a channel statefully by scanning over its output with an accumulator function.
3874 * Emits the intermediate results of the scan operation.
3875 *
3876 * **Example** (Scanning channel output)
3877 *
3878 * ```ts import.meta.vitest
3879 * import { Channel, Effect } from "effect"
3880 *
3881 * // Create a channel with numbers
3882 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5])
3883 *
3884 * // Scan to create running sum
3885 * const runningSumChannel = Channel.scan(numbersChannel, 0, (sum, n) => sum + n)
3886 * Effect.runSync(Channel.runCollect(runningSumChannel)) // => [0, 1, 3, 6, 10, 15]
3887 * // Note: emits the initial value and each intermediate result
3888 *
3889 * // Scan with string concatenation
3890 * const wordsChannel = Channel.fromIterable(["hello", "world", "from", "effect"])
3891 * const sentenceChannel = Channel.scan(
3892 * wordsChannel,
3893 * "",
3894 * (sentence, word) => sentence === "" ? word : `${sentence} ${word}`
3895 * )
3896 * Effect.runSync(Channel.runCollect(sentenceChannel)) // => ["", "hello", "hello world", "hello world from", "hello world from effect"]
3897 * ```
3898 *
3899 * @category sequencing
3900 * @since 4.0.0
3901 */
3902export const scan: {
3903 <S, OutElem>(initial: S, f: (s: S, a: Types.NoInfer<OutElem>) => S): <
3904 OutErr,
3905 OutDone,
3906 InElem,
3907 InErr,
3908 InDone,
3909 Env
3910 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
3911 S,
3912 OutErr,
3913 OutDone,
3914 InElem,
3915 InErr,
3916 InDone,
3917 Env
3918 >
3919 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, S>(
3920 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3921 initial: S,
3922 f: (s: S, a: Types.NoInfer<OutElem>) => S
3923 ): Channel<S, OutErr, OutDone, InElem, InErr, InDone, Env>
3924} = dual(3, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, S>(
3925 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3926 initial: S,
3927 f: (s: S, a: Types.NoInfer<OutElem>) => S
3928): Channel<S, OutErr, OutDone, InElem, InErr, InDone, Env> =>
3929 scanEffect(self, initial, (s, a) => Effect.succeed(f(s, a))))
3930
3931/**
3932 * Transforms a channel statefully by scanning over its output with an effectful accumulator function.
3933 * Emits the intermediate results of the scan operation.
3934 *
3935 * **When to use**
3936 *
3937 * Use when maintaining accumulated state over channel output requires Effects
3938 * or can fail, while still emitting each intermediate state.
3939 *
3940 * **Example** (Scanning channel output with effects)
3941 *
3942 * ```ts import.meta.vitest
3943 * import { Channel, Data, Effect } from "effect"
3944 *
3945 * class ScanError extends Data.TaggedError("ScanError")<{
3946 * readonly reason: string
3947 * }> {}
3948 *
3949 * // Create a channel with numbers
3950 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4])
3951 *
3952 * // Effectful scan with async operations
3953 * const asyncScanChannel = Channel.scanEffect(
3954 * numbersChannel,
3955 * "",
3956 * (acc, value) =>
3957 * Effect.gen(function*() {
3958 * return acc + value.toString()
3959 * })
3960 * )
3961 * await Effect.runPromise(Channel.runCollect(asyncScanChannel)) // => ["", "1", "12", "123", "1234"]
3962 *
3963 * // Scan with error handling
3964 * const errorHandlingScan = Channel.scanEffect(
3965 * numbersChannel,
3966 * 0,
3967 * (sum, n) => {
3968 * if (n < 0) {
3969 * return Effect.fail(new ScanError({ reason: "negative number" }))
3970 * }
3971 * return Effect.succeed(sum + n)
3972 * }
3973 * )
3974 * await Effect.runPromise(Channel.runCollect(errorHandlingScan)) // => [0, 1, 3, 6, 10]
3975 * ```
3976 *
3977 * @category sequencing
3978 * @since 4.0.0
3979 */
3980export const scanEffect: {
3981 <S, OutElem, E, R>(initial: S, f: (s: S, a: Types.NoInfer<OutElem>) => Effect.Effect<S, E, R>): <
3982 OutErr,
3983 OutDone,
3984 InElem,
3985 InErr,
3986 InDone,
3987 Env
3988 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
3989 S,
3990 OutErr | E,
3991 OutDone,
3992 InElem,
3993 InErr,
3994 InDone,
3995 Env | R
3996 >
3997 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, S, E, R>(
3998 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
3999 initial: S,
4000 f: (s: S, a: Types.NoInfer<OutElem>) => Effect.Effect<S, E, R>
4001 ): Channel<S, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
4002} = dual(3, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, S, E, R>(
4003 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4004 initial: S,
4005 f: (s: S, a: Types.NoInfer<OutElem>) => Effect.Effect<S, E, R>
4006): Channel<S, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
4007 fromTransform((upstream, scope) =>
4008 Effect.map(toTransform(self)(upstream, scope), (pull) => {
4009 let state = initial
4010 let isFirst = true
4011 return Effect.suspend(() => {
4012 if (isFirst) {
4013 isFirst = false
4014 return Effect.succeed(state)
4015 }
4016 return Effect.map(
4017 Effect.flatMap(pull, (a) => f(state, a)),
4018 (newState) => {
4019 state = newState
4020 return state
4021 }
4022 )
4023 })
4024 })
4025 ))
4026
4027/**
4028 * Catches any cause of failure from the channel and allows recovery by
4029 * creating a new channel based on the caught cause.
4030 *
4031 * **Example** (Recovering from failure causes)
4032 *
4033 * ```ts import.meta.vitest
4034 * import { Cause, Channel, Data, Effect } from "effect"
4035 *
4036 * class ProcessError extends Data.TaggedError("ProcessError")<{
4037 * readonly reason: string
4038 * }> {}
4039 *
4040 * class RecoveryError extends Data.TaggedError("RecoveryError")<{
4041 * readonly message: string
4042 * }> {}
4043 *
4044 * // Create a failing channel
4045 * const failingChannel = Channel.fail(
4046 * new ProcessError({ reason: "network error" })
4047 * )
4048 *
4049 * // Catch the cause and provide recovery
4050 * const recoveredChannel = Channel.catchCause(failingChannel, (cause) => {
4051 * if (Cause.hasFails(cause)) {
4052 * return Channel.succeed("Recovered from failure")
4053 * }
4054 * return Channel.succeed("Recovered from interruption")
4055 * })
4056 *
4057 * Effect.runSync(Channel.runCollect(recoveredChannel)) // => ["Recovered from failure"]
4058 * ```
4059 *
4060 * @category error handling
4061 * @since 2.0.0
4062 */
4063export const catchCause: {
4064 <OutErr, OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
4065 f: (d: Cause.Cause<OutErr>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4066 ): <
4067 OutElem,
4068 OutDone,
4069 InElem,
4070 InErr,
4071 InDone,
4072 Env
4073 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4074 OutElem | OutElem1,
4075 OutErr1,
4076 OutDone | OutDone1,
4077 InElem & InElem1,
4078 InErr & InErr1,
4079 InDone & InDone1,
4080 Env | Env1
4081 >
4082 <
4083 OutElem,
4084 OutErr,
4085 OutDone,
4086 InElem,
4087 InErr,
4088 InDone,
4089 Env,
4090 OutElem1,
4091 OutErr1,
4092 OutDone1,
4093 InElem1,
4094 InErr1,
4095 InDone1,
4096 Env1
4097 >(
4098 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4099 f: (d: Cause.Cause<OutErr>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4100 ): Channel<
4101 OutElem | OutElem1,
4102 OutErr1,
4103 OutDone | OutDone1,
4104 InElem & InElem1,
4105 InErr & InErr1,
4106 InDone & InDone1,
4107 Env | Env1
4108 >
4109} = dual(2, <
4110 OutElem,
4111 OutErr,
4112 OutDone,
4113 InElem,
4114 InErr,
4115 InDone,
4116 Env,
4117 OutElem1,
4118 OutErr1,
4119 OutDone1,
4120 InElem1,
4121 InErr1,
4122 InDone1,
4123 Env1
4124>(
4125 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4126 f: (d: Cause.Cause<OutErr>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4127): Channel<
4128 OutElem | OutElem1,
4129 OutErr1,
4130 OutDone | OutDone1,
4131 InElem & InElem1,
4132 InErr & InErr1,
4133 InDone & InDone1,
4134 Env | Env1
4135> =>
4136 fromTransform((upstream, scope) => {
4137 let forkedScope = Scope.forkUnsafe(scope)
4138 return Effect.map(toTransform(self)(upstream, forkedScope), (pull) => {
4139 let currentPull: Pull.Pull<OutElem | OutElem1, OutErr1, OutDone | OutDone1, Env | Env1> = pull.pipe(
4140 Effect.catchCause((cause): Pull.Pull<OutElem1, OutErr1, OutDone | OutDone1, Env1> => {
4141 if (Pull.isDoneCause(cause)) {
4142 return Effect.failCause(cause as Cause.Cause<Cause.Done<OutDone>>)
4143 }
4144 const toClose = forkedScope
4145 forkedScope = Scope.forkUnsafe(scope)
4146 return Scope.close(toClose, Exit.failCause(cause)).pipe(
4147 Effect.andThen(toTransform(f(cause as Cause.Cause<OutErr>))(upstream, forkedScope)),
4148 Effect.flatMap((childPull) => {
4149 currentPull = childPull
4150 return childPull
4151 })
4152 )
4153 })
4154 )
4155 return Effect.suspend(() => currentPull)
4156 })
4157 }))
4158
4159/**
4160 * Recovers from defects using the provided function.
4161 *
4162 * **Details**
4163 *
4164 * Typed failures and interruptions are not caught.
4165 *
4166 * **Example** (Recovering from a defect)
4167 *
4168 * ```ts import.meta.vitest
4169 * import { Channel, Effect } from "effect"
4170 *
4171 * const channel = Channel.fromEffect(Effect.die("boom")).pipe(
4172 * Channel.catchDefect((defect) => Channel.succeed(`recovered: ${defect}`))
4173 * )
4174 *
4175 * Effect.runSync(Channel.runCollect(channel)) // => ["recovered: boom"]
4176 * ```
4177 *
4178 * @category error handling
4179 * @since 4.0.0
4180 */
4181export const catchDefect: {
4182 <OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
4183 f: (defect: unknown) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4184 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
4185 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
4186 ) => Channel<
4187 OutElem | OutElem1,
4188 OutErr | OutErr1,
4189 OutDone | OutDone1,
4190 InElem & InElem1,
4191 InErr & InErr1,
4192 InDone & InDone1,
4193 Env | Env1
4194 >
4195 <
4196 OutElem,
4197 OutErr,
4198 OutDone,
4199 InElem,
4200 InErr,
4201 InDone,
4202 Env,
4203 OutElem1,
4204 OutErr1,
4205 OutDone1,
4206 InElem1,
4207 InErr1,
4208 InDone1,
4209 Env1
4210 >(
4211 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4212 f: (defect: unknown) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4213 ): Channel<
4214 OutElem | OutElem1,
4215 OutErr | OutErr1,
4216 OutDone | OutDone1,
4217 InElem & InElem1,
4218 InErr & InErr1,
4219 InDone & InDone1,
4220 Env | Env1
4221 >
4222} = dual(2, <
4223 OutElem,
4224 OutErr,
4225 OutDone,
4226 InElem,
4227 InErr,
4228 InDone,
4229 Env,
4230 OutElem1,
4231 OutErr1,
4232 OutDone1,
4233 InElem1,
4234 InErr1,
4235 InDone1,
4236 Env1
4237>(
4238 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4239 f: (defect: unknown) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4240): Channel<
4241 OutElem | OutElem1,
4242 OutErr | OutErr1,
4243 OutDone | OutDone1,
4244 InElem & InElem1,
4245 InErr & InErr1,
4246 InDone & InDone1,
4247 Env | Env1
4248> => catchCauseFilter(self, Cause.findDefect, f))
4249
4250/**
4251 * Runs an effect with the full failure `Cause` when the channel fails, then
4252 * fails the returned channel with the original cause.
4253 *
4254 * **When to use**
4255 *
4256 * Use when observing the full channel failure `Cause` is needed without
4257 * changing successful output or replacing the original cause.
4258 *
4259 * **Details**
4260 *
4261 * Use this for observing failures, such as logging or metrics. If the observer
4262 * effect fails, that failure can fail the returned channel.
4263 *
4264 * @category error handling
4265 * @since 4.0.0
4266 */
4267export const tapCause: {
4268 <OutErr, A, E, R>(
4269 f: (d: Cause.Cause<OutErr>) => Effect.Effect<A, E, R>
4270 ): <
4271 OutElem,
4272 OutDone,
4273 InElem,
4274 InErr,
4275 InDone,
4276 Env
4277 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4278 OutElem,
4279 OutErr | E,
4280 OutDone | void,
4281 InElem,
4282 InErr,
4283 InDone,
4284 Env | R
4285 >
4286 <
4287 OutElem,
4288 OutErr,
4289 OutDone,
4290 InElem,
4291 InErr,
4292 InDone,
4293 Env,
4294 A,
4295 E,
4296 R
4297 >(
4298 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4299 f: (d: Cause.Cause<OutErr>) => Effect.Effect<A, E, R>
4300 ): Channel<
4301 OutElem,
4302 OutErr | E,
4303 OutDone | void,
4304 InElem,
4305 InErr,
4306 InDone,
4307 Env | R
4308 >
4309} = dual(2, <
4310 OutElem,
4311 OutErr,
4312 OutDone,
4313 InElem,
4314 InErr,
4315 InDone,
4316 Env,
4317 A,
4318 E,
4319 R
4320>(
4321 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4322 f: (d: Cause.Cause<OutErr>) => Effect.Effect<A, E, R>
4323): Channel<
4324 OutElem,
4325 OutErr | E,
4326 OutDone | void,
4327 InElem,
4328 InErr,
4329 InDone,
4330 Env | R
4331> => catchCause(self, (cause) => fromEffectDrain(Effect.flatMap(f(cause), (_) => Effect.failCause(cause)))))
4332
4333/**
4334 * Catches causes of failure that match a specific filter, allowing
4335 * conditional error recovery based on the type of failure.
4336 *
4337 * **When to use**
4338 *
4339 * Use to recover a channel only when its full `Cause` satisfies a boolean
4340 * predicate.
4341 *
4342 * **Details**
4343 *
4344 * When the predicate matches, the recovery function receives the original
4345 * cause. When it does not match, the returned channel fails with the original
4346 * cause.
4347 *
4348 * @see {@link catchCauseFilter} for selecting causes with a `Filter`
4349 * @see {@link catchCause} for recovering from every cause
4350 * @see {@link catchIf} for recovering from typed channel errors
4351 *
4352 * @category error handling
4353 * @since 4.0.0
4354 */
4355export const catchCauseIf: {
4356 <
4357 OutErr,
4358 OutElem1,
4359 OutErr1,
4360 OutDone1,
4361 InElem1,
4362 InErr1,
4363 InDone1,
4364 Env1
4365 >(
4366 predicate: Predicate.Predicate<Cause.Cause<OutErr>>,
4367 f: (cause: Cause.Cause<OutErr>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4368 ): <
4369 OutElem,
4370 OutDone,
4371 InElem,
4372 InErr,
4373 InDone,
4374 Env
4375 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4376 OutElem | OutElem1,
4377 OutErr | OutErr1,
4378 OutDone | OutDone1,
4379 InElem & InElem1,
4380 InErr & InErr1,
4381 InDone & InDone1,
4382 Env | Env1
4383 >
4384 <
4385 OutElem,
4386 OutErr,
4387 OutDone,
4388 InElem,
4389 InErr,
4390 InDone,
4391 Env,
4392 OutElem1,
4393 OutErr1,
4394 OutDone1,
4395 InElem1,
4396 InErr1,
4397 InDone1,
4398 Env1
4399 >(
4400 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4401 predicate: Predicate.Predicate<Cause.Cause<OutErr>>,
4402 f: (cause: Cause.Cause<OutErr>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4403 ): Channel<
4404 OutElem | OutElem1,
4405 OutErr | OutErr1,
4406 OutDone | OutDone1,
4407 InElem & InElem1,
4408 InErr & InErr1,
4409 InDone & InDone1,
4410 Env | Env1
4411 >
4412} = dual(3, <
4413 OutElem,
4414 OutErr,
4415 OutDone,
4416 InElem,
4417 InErr,
4418 InDone,
4419 Env,
4420 OutElem1,
4421 OutErr1,
4422 OutDone1,
4423 InElem1,
4424 InErr1,
4425 InDone1,
4426 Env1
4427>(
4428 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4429 predicate: Predicate.Predicate<Cause.Cause<OutErr>>,
4430 f: (cause: Cause.Cause<OutErr>) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4431): Channel<
4432 OutElem | OutElem1,
4433 OutErr | OutErr1,
4434 OutDone | OutDone1,
4435 InElem & InElem1,
4436 InErr & InErr1,
4437 InDone & InDone1,
4438 Env | Env1
4439> =>
4440 catchCause(
4441 self,
4442 (
4443 cause
4444 ): Channel<
4445 OutElem1,
4446 OutErr | OutErr1,
4447 OutDone1,
4448 InElem1,
4449 InErr1,
4450 InDone1,
4451 Env1
4452 > => {
4453 return predicate(cause)
4454 ? f(cause)
4455 : failCause(cause as any)
4456 }
4457 ))
4458
4459/**
4460 * Recovers from channel failures whose full `Cause` is selected by a `Filter`.
4461 *
4462 * **When to use**
4463 *
4464 * Use when you need to recover a channel only from causes selected by a
4465 * `Filter`, while giving the recovery both the selected value and the original
4466 * `Cause`.
4467 *
4468 * **Details**
4469 *
4470 * When the filter succeeds, the recovery function receives the selected value
4471 * and the original cause. When the filter fails, the returned channel fails
4472 * with the residual cause produced by the filter.
4473 *
4474 * @see {@link catchCauseIf} for selecting causes with a predicate
4475 * @see {@link catchFilter} for selecting typed errors with a `Filter`
4476 * @see {@link catchCause} for recovering from every cause
4477 *
4478 * @category error handling
4479 * @since 4.0.0
4480 */
4481export const catchCauseFilter: {
4482 <
4483 OutErr,
4484 EB,
4485 X extends Cause.Cause<any>,
4486 OutElem1,
4487 OutErr1,
4488 OutDone1,
4489 InElem1,
4490 InErr1,
4491 InDone1,
4492 Env1
4493 >(
4494 filter: Filter.Filter<Cause.Cause<OutErr>, EB, X>,
4495 f: (
4496 failure: EB,
4497 cause: Cause.Cause<OutErr>
4498 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4499 ): <
4500 OutElem,
4501 OutDone,
4502 InElem,
4503 InErr,
4504 InDone,
4505 Env
4506 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4507 OutElem | OutElem1,
4508 Cause.Cause.Error<X> | OutErr1,
4509 OutDone | OutDone1,
4510 InElem & InElem1,
4511 InErr & InErr1,
4512 InDone & InDone1,
4513 Env | Env1
4514 >
4515 <
4516 OutElem,
4517 OutErr,
4518 OutDone,
4519 InElem,
4520 InErr,
4521 InDone,
4522 Env,
4523 EB,
4524 X extends Cause.Cause<any>,
4525 OutElem1,
4526 OutErr1,
4527 OutDone1,
4528 InElem1,
4529 InErr1,
4530 InDone1,
4531 Env1
4532 >(
4533 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4534 filter: Filter.Filter<Cause.Cause<OutErr>, EB, X>,
4535 f: (
4536 failure: EB,
4537 cause: Cause.Cause<OutErr>
4538 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4539 ): Channel<
4540 OutElem | OutElem1,
4541 Cause.Cause.Error<X> | OutErr1,
4542 OutDone | OutDone1,
4543 InElem & InElem1,
4544 InErr & InErr1,
4545 InDone & InDone1,
4546 Env | Env1
4547 >
4548} = dual(3, <
4549 OutElem,
4550 OutErr,
4551 OutDone,
4552 InElem,
4553 InErr,
4554 InDone,
4555 Env,
4556 EB,
4557 X extends Cause.Cause<any>,
4558 OutElem1,
4559 OutErr1,
4560 OutDone1,
4561 InElem1,
4562 InErr1,
4563 InDone1,
4564 Env1
4565>(
4566 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4567 filter: Filter.Filter<Cause.Cause<OutErr>, EB, X>,
4568 f: (
4569 failure: EB,
4570 cause: Cause.Cause<OutErr>
4571 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4572): Channel<
4573 OutElem | OutElem1,
4574 Cause.Cause.Error<X> | OutErr1,
4575 OutDone | OutDone1,
4576 InElem & InElem1,
4577 InErr & InErr1,
4578 InDone & InDone1,
4579 Env | Env1
4580> =>
4581 catchCause(
4582 self,
4583 (
4584 cause
4585 ): Channel<
4586 OutElem1,
4587 Cause.Cause.Error<X> | OutErr1,
4588 OutDone1,
4589 InElem1,
4590 InErr1,
4591 InDone1,
4592 Env1
4593 > => {
4594 const result = filter(cause)
4595 return Result.isFailure(result)
4596 ? failCause(result.failure)
4597 : f(result.success, cause)
4598 }
4599 ))
4600
4601const catch_: {
4602 <OutErr, OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
4603 f: (d: OutErr) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4604 ): <
4605 OutElem,
4606 OutDone,
4607 InElem,
4608 InErr,
4609 InDone,
4610 Env
4611 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4612 OutElem | OutElem1,
4613 OutErr1,
4614 OutDone | OutDone1,
4615 InElem & InElem1,
4616 InErr & InErr1,
4617 InDone & InDone1,
4618 Env | Env1
4619 >
4620 <
4621 OutElem,
4622 OutErr,
4623 OutDone,
4624 InElem,
4625 InErr,
4626 InDone,
4627 Env,
4628 OutElem1,
4629 OutErr1,
4630 OutDone1,
4631 InElem1,
4632 InErr1,
4633 InDone1,
4634 Env1
4635 >(
4636 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4637 f: (d: OutErr) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4638 ): Channel<
4639 OutElem | OutElem1,
4640 OutErr1,
4641 OutDone | OutDone1,
4642 InElem & InElem1,
4643 InErr & InErr1,
4644 InDone & InDone1,
4645 Env | Env1
4646 >
4647} = dual(2, <
4648 OutElem,
4649 OutErr,
4650 OutDone,
4651 InElem,
4652 InErr,
4653 InDone,
4654 Env,
4655 OutElem1,
4656 OutErr1,
4657 OutDone1,
4658 InElem1,
4659 InErr1,
4660 InDone1,
4661 Env1
4662>(
4663 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4664 f: (d: OutErr) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>
4665): Channel<
4666 OutElem | OutElem1,
4667 OutErr1,
4668 OutDone | OutDone1,
4669 InElem & InElem1,
4670 InErr & InErr1,
4671 InDone & InDone1,
4672 Env | Env1
4673> => catchCauseFilter(self, Cause.findError, (e) => f(e)))
4674
4675export {
4676 /**
4677 * Recovers from typed channel errors by running a fallback channel.
4678 *
4679 * @category error handling
4680 * @since 4.0.0
4681 */
4682 catch_ as catch
4683}
4684
4685/**
4686 * Runs an effect when the channel fails with a typed error, then preserves the
4687 * original channel failure.
4688 *
4689 * **Details**
4690 *
4691 * The effect is not run for normal channel completion. If the observer effect
4692 * fails, that failure can fail the returned channel.
4693 *
4694 * @category error handling
4695 * @since 4.0.0
4696 */
4697export const tapError: {
4698 <OutErr, A, E, R>(
4699 f: (d: OutErr) => Effect.Effect<A, E, R>
4700 ): <
4701 OutElem,
4702 OutDone,
4703 InElem,
4704 InErr,
4705 InDone,
4706 Env
4707 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4708 OutElem,
4709 OutErr | E,
4710 OutDone | void,
4711 InElem,
4712 InErr,
4713 InDone,
4714 Env | R
4715 >
4716 <
4717 OutElem,
4718 OutErr,
4719 OutDone,
4720 InElem,
4721 InErr,
4722 InDone,
4723 Env,
4724 A,
4725 E,
4726 R
4727 >(
4728 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4729 f: (d: OutErr) => Effect.Effect<A, E, R>
4730 ): Channel<
4731 OutElem,
4732 OutErr | E,
4733 OutDone | void,
4734 InElem,
4735 InErr,
4736 InDone,
4737 Env | R
4738 >
4739} = dual(2, <
4740 OutElem,
4741 OutErr,
4742 OutDone,
4743 InElem,
4744 InErr,
4745 InDone,
4746 Env,
4747 A,
4748 E,
4749 R
4750>(
4751 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4752 f: (d: OutErr) => Effect.Effect<A, E, R>
4753): Channel<
4754 OutElem,
4755 OutErr | E,
4756 OutDone | void,
4757 InElem,
4758 InErr,
4759 InDone,
4760 Env | R
4761> =>
4762 transformPull(
4763 self,
4764 (pull) =>
4765 Effect.succeed(Effect.tapError(
4766 pull,
4767 (err) => Cause.isDone(err) ? Effect.void : Effect.asVoid(f(err))
4768 ))
4769 ))
4770
4771/**
4772 * Recovers from typed channel errors that match a predicate or refinement.
4773 *
4774 * **When to use**
4775 *
4776 * Use to recover from typed channel errors when a predicate or refinement
4777 * selects the failures that should switch to a recovery channel.
4778 *
4779 * **Details**
4780 *
4781 * Matching errors are handled by the recovery function. Non-matching errors
4782 * are handled by `orElse` when provided. Without `orElse`, non-matching errors
4783 * are re-failed.
4784 *
4785 * @see {@link catch_ catch} for recovering from every typed channel error
4786 * @see {@link catchFilter} for selecting typed errors with a `Filter`
4787 * @see {@link catchTag} for selecting tagged typed errors
4788 * @see {@link catchCauseFilter} for selecting full causes with a `Filter`
4789 *
4790 * @category error handling
4791 * @since 4.0.0
4792 */
4793export const catchIf: {
4794 <
4795 OutErr,
4796 EB extends OutErr,
4797 OutElem1,
4798 OutErr1,
4799 OutDone1,
4800 InElem1,
4801 InErr1,
4802 InDone1,
4803 Env1,
4804 OutElem2 = Types.unassigned,
4805 OutErr2 = never,
4806 OutDone2 = never,
4807 InElem2 = unknown,
4808 InErr2 = unknown,
4809 InDone2 = unknown,
4810 Env2 = never
4811 >(
4812 refinement: Predicate.Refinement<OutErr, EB>,
4813 f: (failure: EB) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
4814 orElse?:
4815 | ((
4816 failure: Exclude<OutErr, EB>
4817 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
4818 | undefined
4819 ): <
4820 OutElem,
4821 OutDone,
4822 InElem,
4823 InErr,
4824 InDone,
4825 Env
4826 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4827 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
4828 OutErr1 | OutErr2 | (OutElem2 extends Types.unassigned ? Exclude<OutErr, EB> : never),
4829 OutDone | OutDone1 | OutDone2,
4830 InElem & InElem1 & InElem2,
4831 InErr & InErr1 & InErr2,
4832 InDone & InDone1 & InDone2,
4833 Env | Env1 | Env2
4834 >
4835 <
4836 OutErr,
4837 OutElem1,
4838 OutErr1,
4839 OutDone1,
4840 InElem1,
4841 InErr1,
4842 InDone1,
4843 Env1,
4844 OutElem2 = Types.unassigned,
4845 OutErr2 = never,
4846 OutDone2 = never,
4847 InElem2 = unknown,
4848 InErr2 = unknown,
4849 InDone2 = unknown,
4850 Env2 = never
4851 >(
4852 predicate: Predicate.Predicate<OutErr>,
4853 f: (failure: OutErr) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
4854 orElse?:
4855 | ((
4856 failure: OutErr
4857 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
4858 | undefined
4859 ): <
4860 OutElem,
4861 OutDone,
4862 InElem,
4863 InErr,
4864 InDone,
4865 Env
4866 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
4867 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
4868 OutErr1 | OutErr2 | (OutElem2 extends Types.unassigned ? OutErr : never),
4869 OutDone | OutDone1 | OutDone2,
4870 InElem & InElem1 & InElem2,
4871 InErr & InErr1 & InErr2,
4872 InDone & InDone1 & InDone2,
4873 Env | Env1 | Env2
4874 >
4875 <
4876 OutElem,
4877 OutErr,
4878 OutDone,
4879 InElem,
4880 InErr,
4881 InDone,
4882 Env,
4883 EB extends OutErr,
4884 OutElem1,
4885 OutErr1,
4886 OutDone1,
4887 InElem1,
4888 InErr1,
4889 InDone1,
4890 Env1,
4891 OutElem2 = Types.unassigned,
4892 OutErr2 = never,
4893 OutDone2 = never,
4894 InElem2 = unknown,
4895 InErr2 = unknown,
4896 InDone2 = unknown,
4897 Env2 = never
4898 >(
4899 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4900 refinement: Predicate.Refinement<OutErr, EB>,
4901 f: (failure: EB) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
4902 orElse?:
4903 | ((
4904 failure: Exclude<OutErr, EB>
4905 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
4906 | undefined
4907 ): Channel<
4908 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
4909 OutErr1 | OutErr2 | (OutElem2 extends Types.unassigned ? Exclude<OutErr, EB> : never),
4910 OutDone | OutDone1 | OutDone2,
4911 InElem & InElem1 & InElem2,
4912 InErr & InErr1 & InErr2,
4913 InDone & InDone1 & InDone2,
4914 Env | Env1 | Env2
4915 >
4916 <
4917 OutElem,
4918 OutErr,
4919 OutDone,
4920 InElem,
4921 InErr,
4922 InDone,
4923 Env,
4924 OutElem1,
4925 OutErr1,
4926 OutDone1,
4927 InElem1,
4928 InErr1,
4929 InDone1,
4930 Env1,
4931 OutElem2 = Types.unassigned,
4932 OutErr2 = never,
4933 OutDone2 = never,
4934 InElem2 = unknown,
4935 InErr2 = unknown,
4936 InDone2 = unknown,
4937 Env2 = never
4938 >(
4939 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4940 predicate: Predicate.Predicate<OutErr>,
4941 f: (failure: OutErr) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
4942 orElse?:
4943 | ((
4944 failure: OutErr
4945 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
4946 | undefined
4947 ): Channel<
4948 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
4949 OutErr1 | OutErr2 | (OutElem2 extends Types.unassigned ? OutErr : never),
4950 OutDone | OutDone1 | OutDone2,
4951 InElem & InElem1 & InElem2,
4952 InErr & InErr1 & InErr2,
4953 InDone & InDone1 & InDone2,
4954 Env | Env1 | Env2
4955 >
4956} = dual((args) => isChannel(args[0]), <
4957 OutElem,
4958 OutErr,
4959 OutDone,
4960 InElem,
4961 InErr,
4962 InDone,
4963 Env,
4964 OutElem1,
4965 OutErr1,
4966 OutDone1,
4967 InElem1,
4968 InErr1,
4969 InDone1,
4970 Env1,
4971 OutElem2 = never,
4972 OutErr2 = OutErr,
4973 OutDone2 = never,
4974 InElem2 = unknown,
4975 InErr2 = unknown,
4976 InDone2 = unknown,
4977 Env2 = never
4978>(
4979 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
4980 predicate: Predicate.Predicate<OutErr>,
4981 f: (failure: OutErr) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
4982 orElse?:
4983 | ((
4984 failure: OutErr
4985 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
4986 | undefined
4987): Channel<
4988 OutElem | OutElem1 | OutElem2,
4989 OutErr1 | OutErr2,
4990 OutDone | OutDone1 | OutDone2,
4991 InElem & InElem1 & InElem2,
4992 InErr & InErr1 & InErr2,
4993 InDone & InDone1 & InDone2,
4994 Env | Env1 | Env2
4995> =>
4996 catch_(
4997 self,
4998 (err): Channel<
4999 OutElem1 | OutElem2,
5000 OutErr1 | OutErr2,
5001 OutDone1 | OutDone2,
5002 InElem1 & InElem2,
5003 InErr1 & InErr2,
5004 InDone1 & InDone2,
5005 Env1 | Env2
5006 > => {
5007 return predicate(err)
5008 ? f(err)
5009 : orElse
5010 ? orElse(err)
5011 : fail(err as any) as any
5012 }
5013 ))
5014
5015/**
5016 * Recovers from typed channel errors selected by a `Filter`.
5017 *
5018 * **When to use**
5019 *
5020 * Use to recover from channel errors with a reusable `Filter` when matching
5021 * can also narrow or transform the error before choosing the recovery channel.
5022 *
5023 * **Details**
5024 *
5025 * Successful filter results are handled by the recovery function. Failed
5026 * filter results are handled by `orElse` when provided. Without `orElse`,
5027 * failed filter results are re-failed.
5028 *
5029 * @see {@link catchIf} for selecting typed errors with a predicate
5030 * @see {@link catchTag} for selecting tagged typed errors
5031 * @see {@link catchCauseFilter} for selecting full causes with a `Filter`
5032 *
5033 * @category error handling
5034 * @since 4.0.0
5035 */
5036export const catchFilter: {
5037 <
5038 OutErr,
5039 EB,
5040 X,
5041 OutElem1,
5042 OutErr1,
5043 OutDone1,
5044 InElem1,
5045 InErr1,
5046 InDone1,
5047 Env1,
5048 OutElem2 = Types.unassigned,
5049 OutErr2 = never,
5050 OutDone2 = never,
5051 InElem2 = unknown,
5052 InErr2 = unknown,
5053 InDone2 = unknown,
5054 Env2 = never
5055 >(
5056 filter: Filter.Filter<OutErr, EB, X>,
5057 f: (failure: EB) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5058 orElse?:
5059 | ((
5060 failure: X
5061 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5062 | undefined
5063 ): <
5064 OutElem,
5065 OutDone,
5066 InElem,
5067 InErr,
5068 InDone,
5069 Env
5070 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
5071 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5072 OutErr1 | OutErr2 | (OutElem2 extends Types.unassigned ? X : never),
5073 OutDone | OutDone1 | OutDone2,
5074 InElem & InElem1 & InElem2,
5075 InErr & InErr1 & InErr2,
5076 InDone & InDone1 & InDone2,
5077 Env | Env1 | Env2
5078 >
5079 <
5080 OutElem,
5081 OutErr,
5082 OutDone,
5083 InElem,
5084 InErr,
5085 InDone,
5086 Env,
5087 EB,
5088 X,
5089 OutElem1,
5090 OutErr1,
5091 OutDone1,
5092 InElem1,
5093 InErr1,
5094 InDone1,
5095 Env1,
5096 OutElem2 = Types.unassigned,
5097 OutErr2 = never,
5098 OutDone2 = never,
5099 InElem2 = unknown,
5100 InErr2 = unknown,
5101 InDone2 = unknown,
5102 Env2 = never
5103 >(
5104 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5105 filter: Filter.Filter<OutErr, EB, X>,
5106 f: (failure: EB) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5107 orElse?:
5108 | ((
5109 failure: X
5110 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5111 | undefined
5112 ): Channel<
5113 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5114 OutErr1 | OutErr2 | (OutElem2 extends Types.unassigned ? X : never),
5115 OutDone | OutDone1 | OutDone2,
5116 InElem & InElem1 & InElem2,
5117 InErr & InErr1 & InErr2,
5118 InDone & InDone1 & InDone2,
5119 Env | Env1 | Env2
5120 >
5121} = dual((args) => isChannel(args[0]), <
5122 OutElem,
5123 OutErr,
5124 OutDone,
5125 InElem,
5126 InErr,
5127 InDone,
5128 Env,
5129 EB,
5130 X,
5131 OutElem1,
5132 OutErr1,
5133 OutDone1,
5134 InElem1,
5135 InErr1,
5136 InDone1,
5137 Env1,
5138 OutElem2 = never,
5139 OutErr2 = X,
5140 OutDone2 = never,
5141 InElem2 = unknown,
5142 InErr2 = unknown,
5143 InDone2 = unknown,
5144 Env2 = never
5145>(
5146 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5147 filter: Filter.Filter<OutErr, EB, X>,
5148 f: (failure: EB) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5149 orElse?:
5150 | ((
5151 failure: X
5152 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5153 | undefined
5154): Channel<
5155 OutElem | OutElem1 | OutElem2,
5156 OutErr1 | OutErr2,
5157 OutDone | OutDone1 | OutDone2,
5158 InElem & InElem1 & InElem2,
5159 InErr & InErr1 & InErr2,
5160 InDone & InDone1 & InDone2,
5161 Env | Env1 | Env2
5162> =>
5163 catch_(
5164 self,
5165 (err): Channel<
5166 OutElem1 | OutElem2,
5167 OutErr1 | OutErr2,
5168 OutDone1 | OutDone2,
5169 InElem1 & InElem2,
5170 InErr1 & InErr2,
5171 InDone1 & InDone2,
5172 Env1 | Env2
5173 > => {
5174 const result = filter(err)
5175 return Result.isFailure(result)
5176 ? orElse
5177 ? orElse(result.failure)
5178 : fail(result.failure as any) as any
5179 : f(result.success)
5180 }
5181 ))
5182
5183/**
5184 * Recovers from tagged channel errors whose `_tag` matches one or more tags.
5185 *
5186 * **Details**
5187 *
5188 * Matching tagged errors are handled by the recovery function. Non-matching
5189 * errors are handled by `orElse` when provided. Without `orElse`,
5190 * non-matching errors are re-failed.
5191 *
5192 * @category error handling
5193 * @since 4.0.0
5194 */
5195export const catchTag: {
5196 <
5197 OutErr,
5198 const K extends Types.Tags<OutErr> | Arr.NonEmptyReadonlyArray<Types.Tags<OutErr>>,
5199 OutElem1,
5200 OutErr1,
5201 OutDone1,
5202 InElem1,
5203 InErr1,
5204 InDone1,
5205 Env1,
5206 OutElem2 = Types.unassigned,
5207 OutErr2 = never,
5208 OutDone2 = never,
5209 InElem2 = unknown,
5210 InErr2 = unknown,
5211 InDone2 = unknown,
5212 Env2 = never
5213 >(
5214 k: K,
5215 f: (
5216 e: Types.ExtractTag<NoInfer<OutErr>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5217 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5218 orElse?:
5219 | ((
5220 e: Types.ExcludeTag<NoInfer<OutErr>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5221 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5222 | undefined
5223 ): <
5224 OutElem,
5225 OutDone,
5226 InElem,
5227 InErr,
5228 InDone,
5229 Env
5230 >(self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>) => Channel<
5231 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5232 | OutErr1
5233 | OutErr2
5234 | (OutElem2 extends Types.unassigned
5235 ? Types.ExcludeTag<OutErr, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5236 : never),
5237 OutDone | OutDone1 | OutDone2,
5238 InElem & InElem1 & InElem2,
5239 InErr & InErr1 & InErr2,
5240 InDone & InDone1 & InDone2,
5241 Env | Env1 | Env2
5242 >
5243 <
5244 OutElem,
5245 OutErr,
5246 OutDone,
5247 InElem,
5248 InErr,
5249 InDone,
5250 Env,
5251 const K extends Types.Tags<OutErr> | Arr.NonEmptyReadonlyArray<Types.Tags<OutErr>>,
5252 OutElem1,
5253 OutErr1,
5254 OutDone1,
5255 InElem1,
5256 InErr1,
5257 InDone1,
5258 Env1,
5259 OutElem2 = Types.unassigned,
5260 OutErr2 = never,
5261 OutDone2 = never,
5262 InElem2 = unknown,
5263 InErr2 = unknown,
5264 InDone2 = unknown,
5265 Env2 = never
5266 >(
5267 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5268 k: K,
5269 f: (
5270 e: Types.ExtractTag<NoInfer<OutErr>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5271 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5272 orElse?:
5273 | ((
5274 e: Types.ExcludeTag<NoInfer<OutErr>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5275 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5276 | undefined
5277 ): Channel<
5278 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5279 | OutErr1
5280 | OutErr2
5281 | (OutElem2 extends Types.unassigned
5282 ? Types.ExcludeTag<OutErr, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5283 : never),
5284 OutDone | OutDone1 | OutDone2,
5285 InElem & InElem1 & InElem2,
5286 InErr & InErr1 & InErr2,
5287 InDone & InDone1 & InDone2,
5288 Env | Env1 | Env2
5289 >
5290} = dual((args) => isChannel(args[0]), <
5291 OutElem,
5292 OutErr,
5293 OutDone,
5294 InElem,
5295 InErr,
5296 InDone,
5297 Env,
5298 const K extends Types.Tags<OutErr> | Arr.NonEmptyReadonlyArray<Types.Tags<OutErr>>,
5299 OutElem1,
5300 OutErr1,
5301 OutDone1,
5302 InElem1,
5303 InErr1,
5304 InDone1,
5305 Env1,
5306 OutElem2 = never,
5307 OutErr2 = Types.ExcludeTag<OutErr, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>,
5308 OutDone2 = never,
5309 InElem2 = unknown,
5310 InErr2 = unknown,
5311 InDone2 = unknown,
5312 Env2 = never
5313>(
5314 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5315 k: K,
5316 f: (
5317 e: Types.ExtractTag<NoInfer<OutErr>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5318 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5319 orElse?:
5320 | ((
5321 e: Types.ExcludeTag<NoInfer<OutErr>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>
5322 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5323 | undefined
5324): Channel<
5325 OutElem | OutElem1 | OutElem2,
5326 OutErr1 | OutErr2,
5327 OutDone | OutDone1 | OutDone2,
5328 InElem & InElem1 & InElem2,
5329 InErr & InErr1 & InErr2,
5330 InDone & InDone1 & InDone2,
5331 Env | Env1 | Env2
5332> => {
5333 const pred = Array.isArray(k)
5334 ? ((e: OutErr): e is any => hasProperty(e, "_tag") && k.includes(e._tag))
5335 : isTagged(k as string)
5336 return catchIf(self, pred, f, orElse as any) as any
5337})
5338
5339/**
5340 * Catches a specific reason within a tagged error.
5341 *
5342 * **Example** (Recovering from nested reasons)
5343 *
5344 * ```ts import.meta.vitest
5345 * import { Channel, Data, Effect } from "effect"
5346 *
5347 * class RateLimitError extends Data.TaggedError("RateLimitError")<{
5348 * retryAfter: number
5349 * }> {}
5350 *
5351 * class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{
5352 * limit: number
5353 * }> {}
5354 *
5355 * class AiError extends Data.TaggedError("AiError")<{
5356 * reason: RateLimitError | QuotaExceededError
5357 * }> {}
5358 *
5359 * const reason = new RateLimitError({ retryAfter: 60 })
5360 * const channel = Channel.fail(new AiError({ reason }))
5361 *
5362 * const recovered = channel.pipe(
5363 * Channel.catchReason("AiError", "RateLimitError", (reason) =>
5364 * Channel.succeed(`retry: ${reason.retryAfter}`)
5365 * )
5366 * )
5367 * Effect.runSync(Channel.runCollect(recovered)) // => ["retry: 60"]
5368 * ```
5369 *
5370 * @category error handling
5371 * @since 4.0.0
5372 */
5373export const catchReason: {
5374 <
5375 OutErr,
5376 K extends Types.Tags<OutErr>,
5377 RK extends Types.ReasonTags<Types.ExtractTag<Types.NoInfer<OutErr>, K>>,
5378 OutElem1,
5379 OutErr1,
5380 OutDone1,
5381 InElem1,
5382 InErr1,
5383 InDone1,
5384 Env1,
5385 OutElem2 = Types.unassigned,
5386 OutErr2 = never,
5387 OutDone2 = never,
5388 InElem2 = unknown,
5389 InErr2 = unknown,
5390 InDone2 = unknown,
5391 Env2 = never
5392 >(
5393 errorTag: K,
5394 reasonTag: RK,
5395 f: (
5396 reason: Types.ExtractReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5397 error: Types.NarrowReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5398 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5399 orElse?:
5400 | ((
5401 reason: Types.ExcludeReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5402 error: Types.OmitReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5403 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5404 | undefined
5405 ): <
5406 OutElem,
5407 OutDone,
5408 InElem,
5409 InErr,
5410 InDone,
5411 Env
5412 >(
5413 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5414 ) => Channel<
5415 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5416 | Types.ExcludeTag<OutErr, K>
5417 | OutErr1
5418 | OutErr2
5419 | (OutElem2 extends Types.unassigned ? Types.ExtractTag<OutErr, K> : never),
5420 OutDone | OutDone1 | OutDone2,
5421 InElem & InElem1 & InElem2,
5422 InErr & InErr1 & InErr2,
5423 InDone & InDone1 & InDone2,
5424 Env | Env1 | Env2
5425 >
5426 <
5427 OutElem,
5428 OutErr,
5429 OutDone,
5430 InElem,
5431 InErr,
5432 InDone,
5433 Env,
5434 K extends Types.Tags<OutErr>,
5435 RK extends Types.ReasonTags<Types.ExtractTag<Types.NoInfer<OutErr>, K>>,
5436 OutElem1,
5437 OutErr1,
5438 OutDone1,
5439 InElem1,
5440 InErr1,
5441 InDone1,
5442 Env1,
5443 OutElem2 = Types.unassigned,
5444 OutErr2 = never,
5445 OutDone2 = never,
5446 InElem2 = unknown,
5447 InErr2 = unknown,
5448 InDone2 = unknown,
5449 Env2 = never
5450 >(
5451 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5452 errorTag: K,
5453 reasonTag: RK,
5454 f: (
5455 reason: Types.ExtractReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5456 error: Types.NarrowReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5457 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5458 orElse?:
5459 | ((
5460 reason: Types.ExcludeReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5461 error: Types.OmitReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5462 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5463 | undefined
5464 ): Channel<
5465 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5466 | Types.ExcludeTag<OutErr, K>
5467 | OutErr1
5468 | OutErr2
5469 | (OutElem2 extends Types.unassigned ? Types.ExtractTag<OutErr, K> : never),
5470 OutDone | OutDone1 | OutDone2,
5471 InElem & InElem1 & InElem2,
5472 InErr & InErr1 & InErr2,
5473 InDone & InDone1 & InDone2,
5474 Env | Env1 | Env2
5475 >
5476} = dual((args) => isChannel(args[0]), <
5477 OutElem,
5478 OutErr,
5479 OutDone,
5480 InElem,
5481 InErr,
5482 InDone,
5483 Env,
5484 K extends Types.Tags<OutErr>,
5485 RK extends Types.ReasonTags<Types.ExtractTag<Types.NoInfer<OutErr>, K>>,
5486 OutElem1,
5487 OutErr1,
5488 OutDone1,
5489 InElem1,
5490 InErr1,
5491 InDone1,
5492 Env1,
5493 OutElem2 = Types.unassigned,
5494 OutErr2 = never,
5495 OutDone2 = never,
5496 InElem2 = unknown,
5497 InErr2 = unknown,
5498 InDone2 = unknown,
5499 Env2 = never
5500>(
5501 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5502 errorTag: K,
5503 reasonTag: RK,
5504 f: (
5505 reason: Types.ExtractReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5506 error: Types.NarrowReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5507 ) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
5508 orElse?:
5509 | ((
5510 reason: Types.ExcludeReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5511 error: Types.OmitReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5512 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5513 | undefined
5514): Channel<
5515 OutElem | OutElem1 | Exclude<OutElem2, Types.unassigned>,
5516 | Types.ExcludeTag<OutErr, K>
5517 | OutErr1
5518 | OutErr2
5519 | (OutElem2 extends Types.unassigned ? Types.ExtractTag<OutErr, K> : never),
5520 OutDone | OutDone1 | OutDone2,
5521 InElem & InElem1 & InElem2,
5522 InErr & InErr1 & InErr2,
5523 InDone & InDone1 & InDone2,
5524 Env | Env1 | Env2
5525> =>
5526 catch_(
5527 self,
5528 (error): Channel<
5529 OutElem1 | Exclude<OutElem2, Types.unassigned>,
5530 OutErr1 | OutErr2,
5531 OutDone1 | OutDone2,
5532 InElem1 & InElem2,
5533 InErr1 & InErr2,
5534 InDone1 & InDone2,
5535 Env1 | Env2
5536 > => {
5537 if (isTagged(error, errorTag) && hasProperty(error, "reason")) {
5538 const reason = error.reason as Types.ExcludeReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5539 if (isTagged(reason, reasonTag)) {
5540 return f(reason as any, error as any)
5541 }
5542 return orElse ? orElse(reason, error as any) as any : fail(error) as any
5543 }
5544 return fail(error) as any
5545 }
5546 ))
5547
5548/**
5549 * Catches multiple reasons within a tagged error using an object of handlers.
5550 *
5551 * @category error handling
5552 * @since 4.0.0
5553 */
5554export const catchReasons: {
5555 <
5556 K extends Types.Tags<OutErr>,
5557 OutErr,
5558 Cases extends {
5559 [RK in Types.ReasonTags<Types.ExtractTag<Types.NoInfer<OutErr>, K>>]+?: (
5560 reason: Types.ExtractReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>,
5561 error: Types.NarrowReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, RK>
5562 ) => Channel<any, any, any, any, any, any, any>
5563 },
5564 OutElem2 = Types.unassigned,
5565 OutErr2 = never,
5566 OutDone2 = never,
5567 InElem2 = unknown,
5568 InErr2 = unknown,
5569 InDone2 = unknown,
5570 Env2 = never
5571 >(
5572 errorTag: K,
5573 cases: Cases,
5574 orElse?:
5575 | ((
5576 reason: Types.ExcludeReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, Extract<keyof Cases, string>>,
5577 error: Types.OmitReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, Extract<keyof Cases, string>>
5578 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5579 | undefined
5580 ): <OutElem, OutDone, InElem, InErr, InDone, Env>(
5581 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5582 ) => Channel<
5583 | OutElem
5584 | Exclude<OutElem2, Types.unassigned>
5585 | {
5586 [RK in keyof Cases]: Cases[RK] extends
5587 (...args: Array<any>) => Channel<infer OutElem1, any, any, any, any, any, any> ? OutElem1 : never
5588 }[keyof Cases],
5589 | Types.ExcludeTag<OutErr, K>
5590 | OutErr2
5591 | (OutElem2 extends Types.unassigned ? Types.ExtractTag<OutErr, K> : never)
5592 | {
5593 [RK in keyof Cases]: Cases[RK] extends
5594 (...args: Array<any>) => Channel<any, infer OutErr1, any, any, any, any, any> ? OutErr1 : never
5595 }[keyof Cases],
5596 | OutDone
5597 | OutDone2
5598 | {
5599 [RK in keyof Cases]: Cases[RK] extends
5600 (...args: Array<any>) => Channel<any, any, infer OutDone1, any, any, any, any> ? OutDone1 : never
5601 }[keyof Cases],
5602 & InElem
5603 & InElem2
5604 & {
5605 [RK in keyof Cases]: Cases[RK] extends
5606 (...args: Array<any>) => Channel<any, any, any, infer InElem1, any, any, any> ? InElem1 : never
5607 }[keyof Cases],
5608 & InErr
5609 & InErr2
5610 & {
5611 [RK in keyof Cases]: Cases[RK] extends
5612 (...args: Array<any>) => Channel<any, any, any, any, infer InErr1, any, any> ? InErr1 : never
5613 }[keyof Cases],
5614 & InDone
5615 & InDone2
5616 & {
5617 [RK in keyof Cases]: Cases[RK] extends
5618 (...args: Array<any>) => Channel<any, any, any, any, any, infer InDone1, any> ? InDone1 : never
5619 }[keyof Cases],
5620 | Env
5621 | Env2
5622 | {
5623 [RK in keyof Cases]: Cases[RK] extends
5624 (...args: Array<any>) => Channel<any, any, any, any, any, any, infer Env1> ? Env1 : never
5625 }[keyof Cases]
5626 >
5627 <
5628 OutElem,
5629 OutErr,
5630 OutDone,
5631 InElem,
5632 InErr,
5633 InDone,
5634 Env,
5635 K extends Types.Tags<OutErr>,
5636 Cases extends {
5637 [RK in Types.ReasonTags<Types.ExtractTag<OutErr, K>>]+?: (
5638 reason: Types.ExtractReason<Types.ExtractTag<OutErr, K>, RK>,
5639 error: Types.NarrowReason<Types.ExtractTag<OutErr, K>, RK>
5640 ) => Channel<any, any, any, any, any, any, any>
5641 },
5642 OutElem2 = Types.unassigned,
5643 OutErr2 = never,
5644 OutDone2 = never,
5645 InElem2 = unknown,
5646 InErr2 = unknown,
5647 InDone2 = unknown,
5648 Env2 = never
5649 >(
5650 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5651 errorTag: K,
5652 cases: Cases,
5653 orElse?:
5654 | ((
5655 reason: Types.ExcludeReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, Extract<keyof Cases, string>>,
5656 error: Types.OmitReason<Types.ExtractTag<Types.NoInfer<OutErr>, K>, Extract<keyof Cases, string>>
5657 ) => Channel<OutElem2, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>)
5658 | undefined
5659 ): Channel<
5660 | OutElem
5661 | Exclude<OutElem2, Types.unassigned>
5662 | {
5663 [RK in keyof Cases]: Cases[RK] extends
5664 (...args: Array<any>) => Channel<infer OutElem1, any, any, any, any, any, any> ? OutElem1 : never
5665 }[keyof Cases],
5666 | Types.ExcludeTag<OutErr, K>
5667 | OutErr2
5668 | (OutElem2 extends Types.unassigned ? Types.ExtractTag<OutErr, K> : never)
5669 | {
5670 [RK in keyof Cases]: Cases[RK] extends
5671 (...args: Array<any>) => Channel<any, infer OutErr1, any, any, any, any, any> ? OutErr1 : never
5672 }[keyof Cases],
5673 | OutDone
5674 | OutDone2
5675 | {
5676 [RK in keyof Cases]: Cases[RK] extends
5677 (...args: Array<any>) => Channel<any, any, infer OutDone1, any, any, any, any> ? OutDone1 : never
5678 }[keyof Cases],
5679 & InElem
5680 & InElem2
5681 & {
5682 [RK in keyof Cases]: Cases[RK] extends
5683 (...args: Array<any>) => Channel<any, any, any, infer InElem1, any, any, any> ? InElem1 : never
5684 }[keyof Cases],
5685 & InErr
5686 & InErr2
5687 & {
5688 [RK in keyof Cases]: Cases[RK] extends
5689 (...args: Array<any>) => Channel<any, any, any, any, infer InErr1, any, any> ? InErr1 : never
5690 }[keyof Cases],
5691 & InDone
5692 & InDone2
5693 & {
5694 [RK in keyof Cases]: Cases[RK] extends
5695 (...args: Array<any>) => Channel<any, any, any, any, any, infer InDone1, any> ? InDone1 : never
5696 }[keyof Cases],
5697 | Env
5698 | Env2
5699 | {
5700 [RK in keyof Cases]: Cases[RK] extends
5701 (...args: Array<any>) => Channel<any, any, any, any, any, any, infer Env1> ? Env1 : never
5702 }[keyof Cases]
5703 >
5704} = dual((args) => isChannel(args[0]), (self, errorTag, cases, orElse) => {
5705 let keys: Set<string>
5706 return catch_(self, (error) => {
5707 if (
5708 isTagged(error, errorTag) &&
5709 hasProperty(error, "reason") &&
5710 hasProperty(error.reason, "_tag") &&
5711 String.isString(error.reason._tag)
5712 ) {
5713 const reason = error.reason as { readonly _tag: string }
5714 keys ??= new Set(Object.keys(cases))
5715 if (keys.has(reason._tag)) {
5716 return (cases as any)[reason._tag](reason as any, error)
5717 }
5718 return orElse ? orElse(reason, error) as any : fail(error) as any
5719 }
5720 return fail(error) as any
5721 })
5722})
5723
5724/**
5725 * Promotes nested reason errors into the channel error, replacing the parent error.
5726 *
5727 * **Example** (Promoting nested reasons)
5728 *
5729 * ```ts import.meta.vitest
5730 * import { Channel, Data, Effect, Exit } from "effect"
5731 *
5732 * class RateLimitError extends Data.TaggedError("RateLimitError")<{
5733 * retryAfter: number
5734 * }> {}
5735 *
5736 * class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{
5737 * limit: number
5738 * }> {}
5739 *
5740 * class AiError extends Data.TaggedError("AiError")<{
5741 * reason: RateLimitError | QuotaExceededError
5742 * }> {}
5743 *
5744 * const reason = new RateLimitError({ retryAfter: 60 })
5745 * const channel = Channel.fail(new AiError({ reason }))
5746 *
5747 * const unwrapped = channel.pipe(Channel.unwrapReason("AiError"))
5748 * Effect.runSync(Effect.exit(Channel.runCollect(unwrapped))) // => Exit.fail(reason)
5749 * ```
5750 *
5751 * @category error handling
5752 * @since 4.0.0
5753 */
5754export const unwrapReason: {
5755 <
5756 K extends TagsWithReason<OutErr>,
5757 OutErr
5758 >(
5759 errorTag: K
5760 ): <OutElem, OutDone, InElem, InErr, InDone, Env>(
5761 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5762 ) => Channel<
5763 OutElem,
5764 Types.ExcludeTag<OutErr, K> | Types.ReasonOf<Types.ExtractTag<OutErr, K>>,
5765 OutDone,
5766 InElem,
5767 InErr,
5768 InDone,
5769 Env
5770 >
5771 <
5772 OutElem,
5773 OutErr,
5774 OutDone,
5775 InElem,
5776 InErr,
5777 InDone,
5778 Env,
5779 K extends TagsWithReason<OutErr>
5780 >(
5781 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5782 errorTag: K
5783 ): Channel<
5784 OutElem,
5785 Types.ExcludeTag<OutErr, K> | Types.ReasonOf<Types.ExtractTag<OutErr, K>>,
5786 OutDone,
5787 InElem,
5788 InErr,
5789 InDone,
5790 Env
5791 >
5792} = dual(2, <
5793 OutElem,
5794 OutErr,
5795 OutDone,
5796 InElem,
5797 InErr,
5798 InDone,
5799 Env,
5800 K extends TagsWithReason<OutErr>
5801>(
5802 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5803 errorTag: K
5804): Channel<
5805 OutElem,
5806 Types.ExcludeTag<OutErr, K> | Types.ReasonOf<Types.ExtractTag<OutErr, K>>,
5807 OutDone,
5808 InElem,
5809 InErr,
5810 InDone,
5811 Env
5812> =>
5813 catchFilter(
5814 self,
5815 (error) =>
5816 isTagged(error, errorTag) && hasProperty(error, "reason") ? Result.succeed(error.reason) : Result.fail(error),
5817 fail
5818 ) as any)
5819
5820/**
5821 * Returns a new channel, which is the same as this one, except the failure
5822 * value of the returned channel is created by applying the specified function
5823 * to the failure value of this channel.
5824 *
5825 * @category error handling
5826 * @since 2.0.0
5827 */
5828export const mapError: {
5829 <OutErr, OutErr2>(
5830 f: (err: OutErr) => OutErr2
5831 ): <OutElem, OutDone, InElem, InErr, InDone, Env>(
5832 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5833 ) => Channel<OutElem, OutErr2, OutDone, InElem, InErr, InDone, Env>
5834 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutErr2>(
5835 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5836 f: (err: OutErr) => OutErr2
5837 ): Channel<OutElem, OutErr2, OutDone, InElem, InErr, InDone, Env>
5838} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutErr2>(
5839 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5840 f: (err: OutErr) => OutErr2
5841): Channel<OutElem, OutErr2, OutDone, InElem, InErr, InDone, Env> => catch_(self, (err) => fail(f(err))))
5842
5843/**
5844 * Converts all errors in the channel to defects (unrecoverable failures).
5845 * This is useful when you want to treat errors as programming errors.
5846 *
5847 * **Example** (Converting failures to defects)
5848 *
5849 * ```ts import.meta.vitest
5850 * import { Cause, Channel, Data, Effect, Exit } from "effect"
5851 *
5852 * class ValidationError extends Data.TaggedError("ValidationError")<{
5853 * readonly field: string
5854 * }> {}
5855 *
5856 * // Create a channel that might fail
5857 * const error = new ValidationError({ field: "email" })
5858 * const failingChannel = Channel.fail(error)
5859 *
5860 * // Convert failures to defects
5861 * const fatalChannel = Channel.orDie(failingChannel)
5862 *
5863 * Effect.runSync(Effect.exit(Channel.runCollect(fatalChannel))) // => Exit.failCause(Cause.die(error))
5864 * ```
5865 *
5866 * @category error handling
5867 * @since 2.0.0
5868 */
5869export const orDie = <
5870 OutElem,
5871 OutErr,
5872 OutDone,
5873 InElem,
5874 InErr,
5875 InDone,
5876 Env
5877>(
5878 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5879): Channel<OutElem, never, OutDone, InElem, InErr, InDone, Env> => catch_(self, die)
5880
5881/**
5882 * Ignores all errors in the channel, converting them to an empty channel.
5883 *
5884 * **Details**
5885 *
5886 * Use the `log` option to emit the full {@link Cause} when the channel fails.
5887 *
5888 * @category error handling
5889 * @since 4.0.0
5890 */
5891export const ignore: <
5892 Arg extends Channel<any, any, any, any, any, any, any> | {
5893 readonly log?: boolean | Severity | undefined
5894 } | undefined = {
5895 readonly log?: boolean | Severity | undefined
5896 }
5897>(
5898 selfOrOptions: Arg,
5899 options?: {
5900 readonly log?: boolean | Severity | undefined
5901 } | undefined
5902) => [Arg] extends
5903 [Channel<infer OutElem, infer _OutErr, infer OutDone, infer InElem, infer InErr, infer InDone, infer Env>]
5904 ? Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env>
5905 : <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
5906 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5907 ) => Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env> = dual(
5908 (args) => isChannel(args[0]),
5909 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
5910 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5911 options?: {
5912 readonly log?: boolean | Severity | undefined
5913 } | undefined
5914 ): Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env> => {
5915 if (!options?.log) {
5916 return catch_(self, () => empty)
5917 }
5918 const logEffect = Effect.logWithLevel(options.log === true ? undefined : options.log)
5919 return catch_(
5920 tapCause(self, (cause) => Cause.hasFails(cause) ? logEffect(cause) : Effect.void),
5921 () => empty
5922 )
5923 }
5924 )
5925
5926const ignoreCause_ = <
5927 OutElem,
5928 OutErr,
5929 OutDone,
5930 InElem,
5931 InErr,
5932 InDone,
5933 Env
5934>(
5935 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5936): Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env> => catchCause(self, () => empty)
5937
5938/**
5939 * Ignores all errors in the channel including defects, converting them to an empty channel.
5940 *
5941 * **When to use**
5942 *
5943 * Use when a channel should become best-effort and all failure causes, including
5944 * defects and interruptions, can be converted to empty output.
5945 *
5946 * **Details**
5947 *
5948 * Use the `log` option to emit the full {@link Cause} when the channel fails.
5949 *
5950 * @category error handling
5951 * @since 4.0.0
5952 */
5953export const ignoreCause: <
5954 Arg extends Channel<any, any, any, any, any, any, any> | {
5955 readonly log?: boolean | Severity | undefined
5956 } | undefined = {
5957 readonly log?: boolean | Severity | undefined
5958 }
5959>(
5960 selfOrOptions: Arg,
5961 options?: {
5962 readonly log?: boolean | Severity | undefined
5963 } | undefined
5964) => [Arg] extends
5965 [Channel<infer OutElem, infer _OutErr, infer OutDone, infer InElem, infer InErr, infer InDone, infer Env>]
5966 ? Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env>
5967 : <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
5968 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
5969 ) => Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env> = dual(
5970 (args) => isChannel(args[0]),
5971 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
5972 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
5973 options?: { readonly log?: boolean | Severity | undefined } | undefined
5974 ): Channel<OutElem, never, OutDone | void, InElem, InErr, InDone, Env> => {
5975 if (!options?.log) return ignoreCause_(self)
5976 const logEffect = Effect.logWithLevel(options.log === true ? undefined : options.log)
5977 return ignoreCause_(tapCause(self, (cause) => logEffect(cause)))
5978 }
5979 )
5980
5981/**
5982 * Returns a new channel that retries this channel according to the specified
5983 * schedule whenever it fails.
5984 *
5985 * @category error handling
5986 * @since 4.0.0
5987 */
5988export const retry: {
5989 <SO, OutErr, SE, SR>(
5990 schedule:
5991 | Schedule.Schedule<SO, Types.NoInfer<OutErr>, SE, SR>
5992 | ((
5993 $: <SO, SE, SR>(
5994 _: Schedule.Schedule<SO, Types.NoInfer<OutErr>, SE, SR>
5995 ) => Schedule.Schedule<SO, OutErr, SE, SR>
5996 ) => Schedule.Schedule<SO, Types.NoInfer<OutErr>, SE, SR>)
5997 ): <OutElem, OutDone, InElem, InErr, InDone, Env>(
5998 self: Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
5999 ) => Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
6000 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, SO, SE, SR>(
6001 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6002 schedule:
6003 | Schedule.Schedule<SO, OutErr, SE, SR>
6004 | ((
6005 $: <SO, SE, SR>(
6006 _: Schedule.Schedule<SO, Types.NoInfer<OutErr>, SE, SR>
6007 ) => Schedule.Schedule<SO, OutErr, SE, SR>
6008 ) => Schedule.Schedule<SO, Types.NoInfer<OutErr>, SE, SR>)
6009 ): Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR>
6010} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, SO, SE, SR>(
6011 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6012 schedule:
6013 | Schedule.Schedule<SO, OutErr, SE, SR>
6014 | ((
6015 $: <O, SE, R>(_: Schedule.Schedule<O, Types.NoInfer<OutErr>, SE, R>) => Schedule.Schedule<O, OutErr, SE, R>
6016 ) => Schedule.Schedule<SO, Types.NoInfer<OutErr>, SE, SR>)
6017): Channel<OutElem, OutErr | SE, OutDone, InElem, InErr, InDone, Env | SR> =>
6018 suspend(() => {
6019 let step: ((input: OutErr) => Pull.Pull<Schedule.Metadata<SO, OutErr>, SE, SO, SR>) | undefined = undefined
6020 let meta = Schedule.CurrentMetadata.defaultValue()
6021 const selfWithMeta = provideServiceEffect(self, Schedule.CurrentMetadata, Effect.sync(() => meta))
6022 const withReset = onFirst(selfWithMeta, () => {
6023 step = undefined
6024 return Effect.void
6025 })
6026 const resolvedSchedule = typeof schedule === "function" ? schedule(identity_) : schedule
6027 const loop: Channel<
6028 OutElem,
6029 OutErr | SE,
6030 OutDone,
6031 InElem,
6032 InErr,
6033 InDone,
6034 Env | SR
6035 > = catch_(
6036 withReset,
6037 Effect.fnUntraced(
6038 function*(error) {
6039 if (!step) {
6040 step = yield* Schedule.toStepWithMetadata(resolvedSchedule)
6041 }
6042 meta = yield* step(error)
6043 return loop
6044 },
6045 (effect, error) => Pull.catchDone(effect, () => Effect.succeed(fail(error))),
6046 unwrap
6047 )
6048 )
6049 return loop
6050 }))
6051
6052/**
6053 * Maps each output element to a channel and emits values from the most recent
6054 * active child channels.
6055 *
6056 * **Details**
6057 *
6058 * With the default concurrency of `1`, starting a new child channel interrupts
6059 * the previous child channel. Use `options.concurrency` to allow more active
6060 * child channels. The source channel's done value is preserved.
6061 *
6062 * **Example** (Switching mapped channels)
6063 *
6064 * ```ts import.meta.vitest
6065 * import { Channel, Data, Effect } from "effect"
6066 *
6067 * class SwitchError extends Data.TaggedError("SwitchError")<{
6068 * readonly reason: string
6069 * }> {}
6070 *
6071 * // Create a channel that outputs numbers
6072 * const numberChannel = Channel.fromIterable([1, 2, 3])
6073 *
6074 * // Switch to new channels based on each value
6075 * const switchedChannel = Channel.switchMap(
6076 * numberChannel,
6077 * (n) => Channel.fromIterable([`value-${n}`])
6078 * )
6079 *
6080 * await Effect.runPromise(Channel.runCollect(switchedChannel)) // => ["value-3"]
6081 * ```
6082 *
6083 * @category sequencing
6084 * @since 4.0.0
6085 */
6086export const switchMap: {
6087 <OutElem, OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
6088 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6089 options?: {
6090 readonly concurrency?: Types.Concurrency | undefined
6091 readonly bufferSize?: number | undefined
6092 }
6093 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
6094 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
6095 ) => Channel<
6096 OutElem1,
6097 OutErr1 | OutErr,
6098 OutDone,
6099 InElem & InElem1,
6100 InErr & InErr1,
6101 InDone & InDone1,
6102 Env1 | Env
6103 >
6104 <
6105 OutElem,
6106 OutErr,
6107 OutDone,
6108 InElem,
6109 InErr,
6110 InDone,
6111 Env,
6112 OutElem1,
6113 OutErr1,
6114 OutDone1,
6115 InElem1,
6116 InErr1,
6117 InDone1,
6118 Env1
6119 >(
6120 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6121 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6122 options?: {
6123 readonly concurrency?: Types.Concurrency | undefined
6124 readonly bufferSize?: number | undefined
6125 }
6126 ): Channel<
6127 OutElem1,
6128 OutErr | OutErr1,
6129 OutDone,
6130 InElem & InElem1,
6131 InErr & InErr1,
6132 InDone & InDone1,
6133 Env | Env1
6134 >
6135} = dual(
6136 (args) => isChannel(args[0]),
6137 <
6138 OutElem,
6139 OutErr,
6140 OutDone,
6141 InElem,
6142 InErr,
6143 InDone,
6144 Env,
6145 OutElem1,
6146 OutErr1,
6147 OutDone1,
6148 InElem1,
6149 InErr1,
6150 InDone1,
6151 Env1
6152 >(
6153 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6154 f: (d: OutElem) => Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6155 options?: {
6156 readonly concurrency?: Types.Concurrency | undefined
6157 readonly bufferSize?: number | undefined
6158 }
6159 ): Channel<
6160 OutElem1,
6161 OutErr | OutErr1,
6162 OutDone,
6163 InElem & InElem1,
6164 InErr & InErr1,
6165 InDone & InDone1,
6166 Env | Env1
6167 > =>
6168 self.pipe(
6169 map(f),
6170 mergeAll({
6171 ...options,
6172 concurrency: options?.concurrency ?? 1,
6173 switch: true
6174 })
6175 )
6176)
6177
6178/**
6179 * Merges multiple channels with specified concurrency and buffering options.
6180 *
6181 * **When to use**
6182 *
6183 * Use when channel outputs are themselves channels and multiple inner channels
6184 * should run with configured concurrency and buffering.
6185 *
6186 * **Example** (Merging nested channels)
6187 *
6188 * ```ts import.meta.vitest
6189 * import { Channel, Data, Effect } from "effect"
6190 *
6191 * class MergeAllError extends Data.TaggedError("MergeAllError")<{
6192 * readonly reason: string
6193 * }> {}
6194 *
6195 * // Create channels that output other channels
6196 * const nestedChannels = Channel.fromIterable([
6197 * Channel.fromIterable([1, 2]),
6198 * Channel.fromIterable([3, 4]),
6199 * Channel.fromIterable([5, 6])
6200 * ])
6201 *
6202 * // Merge all channels with bounded concurrency
6203 * const mergedChannel = Channel.mergeAll({
6204 * concurrency: 1,
6205 * bufferSize: 16
6206 * })(nestedChannels)
6207 *
6208 * await Effect.runPromise(Channel.runCollect(mergedChannel)) // => [1, 2, 3, 4, 5, 6]
6209 * ```
6210 *
6211 * @category combining
6212 * @since 2.0.0
6213 */
6214export const mergeAll: {
6215 (options: {
6216 readonly concurrency: Types.Concurrency
6217 readonly bufferSize?: number | undefined
6218 readonly switch?: boolean | undefined
6219 }): <OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1, OutErr, OutDone, InElem, InErr, InDone, Env>(
6220 channels: Channel<
6221 Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6222 OutErr,
6223 OutDone,
6224 InElem,
6225 InErr,
6226 InDone,
6227 Env
6228 >
6229 ) => Channel<
6230 OutElem,
6231 OutErr1 | OutErr,
6232 OutDone,
6233 InElem & InElem1,
6234 InErr & InErr1,
6235 InDone & InDone1,
6236 Env1 | Env
6237 >
6238 <OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1, OutErr, OutDone, InElem, InErr, InDone, Env>(
6239 channels: Channel<
6240 Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6241 OutErr,
6242 OutDone,
6243 InElem,
6244 InErr,
6245 InDone,
6246 Env
6247 >,
6248 options: {
6249 readonly concurrency: Types.Concurrency
6250 readonly bufferSize?: number | undefined
6251 readonly switch?: boolean | undefined
6252 }
6253 ): Channel<
6254 OutElem,
6255 OutErr1 | OutErr,
6256 OutDone,
6257 InElem & InElem1,
6258 InErr & InErr1,
6259 InDone & InDone1,
6260 Env1 | Env
6261 >
6262} = dual(
6263 2,
6264 <OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1, OutErr, OutDone, InElem, InErr, InDone, Env>(
6265 channels: Channel<
6266 Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6267 OutErr,
6268 OutDone,
6269 InElem,
6270 InErr,
6271 InDone,
6272 Env
6273 >,
6274 { bufferSize = 16, concurrency, switch: switch_ = false }: {
6275 readonly concurrency: Types.Concurrency
6276 readonly bufferSize?: number | undefined
6277 readonly switch?: boolean | undefined
6278 }
6279 ): Channel<
6280 OutElem,
6281 OutErr1 | OutErr,
6282 OutDone,
6283 InElem & InElem1,
6284 InErr & InErr1,
6285 InDone & InDone1,
6286 Env1 | Env
6287 > =>
6288 fromTransformBracket(
6289 Effect.fnUntraced(function*(upstream, scope, forkedScope) {
6290 const concurrencyN = concurrency === "unbounded"
6291 ? Number.MAX_SAFE_INTEGER
6292 : Math.max(1, concurrency)
6293 const semaphore = switch_ ? undefined : Semaphore.makeUnsafe(concurrencyN)
6294 const doneLatch = yield* Latch.make(true)
6295 const fibers = new Set<Fiber.Fiber<any, any>>()
6296
6297 const queue = yield* Queue.bounded<OutElem, OutErr | OutErr1 | Cause.Done<OutDone>>(
6298 bufferSize
6299 )
6300 yield* Scope.addFinalizer(forkedScope, Queue.shutdown(queue))
6301
6302 const pull = yield* toTransform(channels)(upstream, scope)
6303
6304 yield* Effect.gen(function*() {
6305 while (true) {
6306 let pullFiber: Fiber.Fiber<Pull.Success<typeof pull>, any> | undefined
6307 if (semaphore) {
6308 if (fibers.size < concurrencyN) {
6309 yield* semaphore.take(1)
6310 } else {
6311 pullFiber = yield* Effect.forkChild(pull)
6312 yield* Effect.raceFirst(
6313 semaphore.take(1),
6314 Effect.andThen(Fiber.join(pullFiber), Effect.never)
6315 )
6316 }
6317 }
6318 const channel = pullFiber === undefined
6319 ? yield* pull
6320 : yield* Fiber.join(pullFiber)
6321 const childScope = Scope.forkUnsafe(forkedScope)
6322 const childPull = yield* toTransform(channel)(upstream, childScope)
6323
6324 while (fibers.size >= concurrencyN) {
6325 const fiber = Iterable.headUnsafe(fibers)
6326 fibers.delete(fiber)
6327 if (fibers.size === 0) yield* doneLatch.open
6328 yield* Fiber.interrupt(fiber)
6329 }
6330
6331 const fiber = yield* childPull.pipe(
6332 Effect.tap(() => Effect.yieldNow),
6333 Effect.flatMap((value) => Queue.offer(queue, value)),
6334 Effect.forever({ disableYield: true }),
6335 Effect.onError(Effect.fnUntraced(function*(cause) {
6336 const halt = Pull.filterDone(cause)
6337 yield* Effect.exit(Scope.close(
6338 childScope,
6339 !Result.isFailure(halt) ? Exit.succeed(halt.success.value) : Exit.failCause(halt.failure)
6340 ))
6341 if (!fibers.has(fiber)) return
6342 fibers.delete(fiber)
6343 if (semaphore) yield* semaphore.release(1)
6344 if (fibers.size === 0) yield* doneLatch.open
6345 if (Result.isSuccess(halt)) return
6346 return yield* Queue.failCause(queue, cause as any)
6347 })),
6348 Effect.forkChild
6349 )
6350
6351 doneLatch.closeUnsafe()
6352 fibers.add(fiber)
6353 }
6354 }).pipe(
6355 Effect.catchCause((cause) => {
6356 const halt = Pull.filterDone(cause)
6357 if (Result.isSuccess(halt)) {
6358 return doneLatch.whenOpen(Queue.failCause(queue, cause))
6359 }
6360 return Queue.failCause(queue, cause)
6361 }),
6362 Effect.forkIn(forkedScope)
6363 )
6364
6365 return Queue.take(queue)
6366 })
6367 )
6368)
6369
6370/**
6371 * Represents strategies for halting merged channels when one completes or fails.
6372 *
6373 * **Example** (Choosing merge halt strategies)
6374 *
6375 * ```ts import.meta.vitest
6376 * import { Channel } from "effect"
6377 *
6378 * // Different halt strategies for channel merging
6379 * const strategies: Array<Channel.HaltStrategy> = ["left", "right", "both", "either"] // => ["left", "right", "both", "either"]
6380 * ```
6381 *
6382 * @category models
6383 * @since 4.0.0
6384 */
6385export type HaltStrategy = "left" | "right" | "both" | "either"
6386
6387/**
6388 * Returns a new channel, which is the merge of this channel and the specified
6389 * channel.
6390 *
6391 * **Example** (Merging channels)
6392 *
6393 * ```ts import.meta.vitest
6394 * import { Channel, Effect } from "effect"
6395 *
6396 * // Create two channels
6397 * const leftChannel = Channel.fromIterable([1, 2, 3])
6398 * const rightChannel = Channel.fromIterable(["a", "b", "c"])
6399 *
6400 * // The default "both" strategy waits for both channels to complete
6401 * const mergedChannel = Channel.merge(leftChannel, rightChannel)
6402 *
6403 * const values = await Effect.runPromise(Channel.runCollect(mergedChannel))
6404 * values.map(String).sort() // => ["1", "2", "3", "a", "b", "c"]
6405 * ```
6406 *
6407 * @category combining
6408 * @since 4.0.0
6409 */
6410export const merge: {
6411 <OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>(
6412 right: Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6413 options?: {
6414 readonly haltStrategy?: HaltStrategy | undefined
6415 } | undefined
6416 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
6417 left: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
6418 ) => Channel<
6419 OutElem1 | OutElem,
6420 OutErr | OutErr1,
6421 OutDone | OutDone1,
6422 InElem & InElem1,
6423 InErr & InErr1,
6424 InDone & InDone1,
6425 Env1 | Env
6426 >
6427 <
6428 OutElem,
6429 OutErr,
6430 OutDone,
6431 InElem,
6432 InErr,
6433 InDone,
6434 Env,
6435 OutElem1,
6436 OutErr1,
6437 OutDone1,
6438 InElem1,
6439 InErr1,
6440 InDone1,
6441 Env1
6442 >(
6443 left: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6444 right: Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6445 options?: {
6446 readonly haltStrategy?: HaltStrategy | undefined
6447 } | undefined
6448 ): Channel<
6449 OutElem | OutElem1,
6450 OutErr | OutErr1,
6451 OutDone | OutDone1,
6452 InElem & InElem1,
6453 InErr & InErr1,
6454 InDone & InDone1,
6455 Env | Env1
6456 >
6457} = dual((args) => isChannel(args[0]) && isChannel(args[1]), <
6458 OutElem,
6459 OutErr,
6460 OutDone,
6461 InElem,
6462 InErr,
6463 InDone,
6464 Env,
6465 OutElem1,
6466 OutErr1,
6467 OutDone1,
6468 InElem1,
6469 InErr1,
6470 InDone1,
6471 Env1
6472>(
6473 left: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6474 right: Channel<OutElem1, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
6475 options?: {
6476 readonly haltStrategy?: HaltStrategy | undefined
6477 } | undefined
6478): Channel<
6479 OutElem | OutElem1,
6480 OutErr | OutErr1,
6481 OutDone | OutDone1,
6482 InElem & InElem1,
6483 InErr & InErr1,
6484 InDone & InDone1,
6485 Env | Env1
6486> =>
6487 fromTransformBracket(Effect.fnUntraced(function*(upstream, _scope, forkedScope) {
6488 const strategy = options?.haltStrategy ?? "both"
6489 const queue = yield* Queue.bounded<OutElem | OutElem1, OutErr | OutErr1 | Cause.Done<OutDone | OutDone1>>(0)
6490 yield* Scope.addFinalizer(forkedScope, Queue.shutdown(queue))
6491 let done = 0
6492 function onExit(
6493 side: "left" | "right",
6494 cause: Cause.Cause<OutErr | OutErr1 | Cause.Done<OutDone | OutDone1>>
6495 ): Effect.Effect<void> {
6496 done++
6497 if (!Pull.isDoneCause(cause)) {
6498 return Queue.failCause(queue, cause)
6499 }
6500 switch (strategy) {
6501 case "both": {
6502 return done === 2 ? Queue.failCause(queue, cause) : Effect.void
6503 }
6504 case "left":
6505 case "right": {
6506 return side === strategy ? Queue.failCause(queue, cause) : Effect.void
6507 }
6508 case "either": {
6509 return Queue.failCause(queue, cause)
6510 }
6511 }
6512 }
6513 const runSide = (
6514 side: "left" | "right",
6515 channel: Channel<
6516 OutElem | OutElem1,
6517 OutErr | OutErr1,
6518 OutDone | OutDone1,
6519 InElem & InElem1,
6520 InErr & InErr1,
6521 InDone & InDone1,
6522 Env | Env1
6523 >,
6524 scope: Scope.Closeable
6525 ) =>
6526 toTransform(channel)(upstream, scope).pipe(
6527 Effect.flatMap((pull) =>
6528 pull.pipe(
6529 Effect.flatMap((value) => Queue.offer(queue, value)),
6530 Effect.forever
6531 )
6532 ),
6533 Effect.onError((cause) =>
6534 Effect.andThen(
6535 Scope.close(scope, Pull.doneExitFromCause(cause)),
6536 onExit(side, cause)
6537 )
6538 ),
6539 Effect.forkIn(forkedScope)
6540 )
6541 yield* runSide("left", left, Scope.forkUnsafe(forkedScope))
6542 yield* runSide("right", right, Scope.forkUnsafe(forkedScope))
6543 return Queue.take(queue)
6544 })))
6545
6546/**
6547 * Runs an effect concurrently with a channel while emitting only the channel's
6548 * output elements.
6549 *
6550 * **When to use**
6551 *
6552 * Use when a side effect should run for the lifetime of a channel and only the
6553 * channel's output elements should be emitted.
6554 *
6555 * **Details**
6556 *
6557 * The effect's successful value is ignored. If the effect fails while the
6558 * channel is running, the returned channel fails with that error.
6559 *
6560 * @category combining
6561 * @since 4.0.0
6562 */
6563export const mergeEffect: {
6564 <X, E, R>(
6565 effect: Effect.Effect<X, E, R>
6566 ): <OutElem, OutDone, OutErr, InElem, InErr, InDone, Env>(
6567 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
6568 ) => Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
6569 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, X, E, R>(
6570 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6571 effect: Effect.Effect<X, E, R>
6572 ): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
6573} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, X, E, R>(
6574 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6575 effect: Effect.Effect<X, E, R>
6576): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
6577 merge(
6578 self,
6579 fromEffectDrain(effect),
6580 { haltStrategy: "left" }
6581 ) as any)
6582
6583/**
6584 * Splits upstream string chunks into lines, recognizing `\n`, `\r\n`, and
6585 * standalone `\r` as line terminators. The behavior matches
6586 * `String.linesIterator` regardless of how the input is chunked.
6587 *
6588 * **Details**
6589 *
6590 * A line terminator at the very end of the stream does **not** produce a
6591 * trailing empty line (consistent with `String.linesIterator`). Conversely,
6592 * if the stream ends without a terminator the final partial line is still
6593 * emitted.
6594 *
6595 * **Example** (Splitting string chunks into lines)
6596 *
6597 * ```ts import.meta.vitest
6598 * import { Effect, Stream } from "effect"
6599 *
6600 * const result = await Effect.runPromise(Stream.runCollect(
6601 * Stream.splitLines(Stream.make("hel", "lo\r\nwor", "ld\n"))
6602 * ))
6603 * result // => ["hello", "world"]
6604 * ```
6605 *
6606 * @category splitting
6607 * @since 2.0.0
6608 */
6609export const splitLines = <Err, Done>(): Channel<
6610 Arr.NonEmptyReadonlyArray<string>,
6611 Err,
6612 Done,
6613 Arr.NonEmptyReadonlyArray<string>,
6614 Err,
6615 Done
6616> =>
6617 fromTransform((upstream, _scope) =>
6618 Effect.sync(() => {
6619 // Accumulates text that has not yet been terminated by a line break.
6620 // Content is carried across chunks until a terminator is found.
6621 let stringBuilder = ""
6622 // A trailing \r completes the line immediately. Remember it only to
6623 // suppress a leading \n in the next nonempty string.
6624 let midCRLF = false
6625 // Remembers the upstream Done value after the first time the upstream
6626 // signals completion, so subsequent pulls return Done immediately
6627 // without pulling upstream again.
6628 let done = Option.none<Done>()
6629
6630 function splitLinesArray(chunk: Arr.NonEmptyReadonlyArray<string>): Arr.NonEmptyReadonlyArray<string> | null {
6631 const chunkBuilder: Array<string> = []
6632
6633 function pushLine(segment: string): void {
6634 if (stringBuilder.length === 0) {
6635 chunkBuilder.push(segment)
6636 } else {
6637 chunkBuilder.push(stringBuilder + segment)
6638 stringBuilder = ""
6639 }
6640 }
6641
6642 for (let i = 0; i < chunk.length; i++) {
6643 const str = chunk[i]
6644 if (str.length !== 0) {
6645 let from = 0
6646 let indexOfCR = str.indexOf("\r")
6647 let indexOfLF = str.indexOf("\n")
6648 if (midCRLF) {
6649 if (indexOfLF === 0) {
6650 from = 1
6651 indexOfLF = str.indexOf("\n", from)
6652 }
6653 midCRLF = false
6654 }
6655 while (indexOfCR !== -1 || indexOfLF !== -1) {
6656 if (indexOfCR === -1 || (indexOfLF !== -1 && indexOfLF < indexOfCR)) {
6657 pushLine(str.substring(from, indexOfLF))
6658 from = indexOfLF + 1
6659 indexOfLF = str.indexOf("\n", from)
6660 } else {
6661 pushLine(str.substring(from, indexOfCR))
6662 if (str.length === indexOfCR + 1) {
6663 midCRLF = true
6664 from = str.length
6665 indexOfCR = -1
6666 } else {
6667 from = indexOfCR + (indexOfLF === indexOfCR + 1 ? 2 : 1)
6668 indexOfCR = str.indexOf("\r", from)
6669 indexOfLF = str.indexOf("\n", from)
6670 }
6671 }
6672 }
6673 stringBuilder = stringBuilder + str.substring(from)
6674 }
6675 }
6676 return Arr.isReadonlyArrayNonEmpty(chunkBuilder) ? chunkBuilder : null
6677 }
6678
6679 const pullOrFlush: Pull.Pull<Arr.NonEmptyReadonlyArray<string>, Err, Done> = Effect.suspend(() => {
6680 if (done._tag === "Some") {
6681 return Cause.done(done.value)
6682 }
6683 return Pull.matchEffect(upstream, {
6684 onSuccess: loop,
6685 onFailure: Effect.failCause,
6686 onDone: (leftover) => {
6687 done = Option.some(leftover)
6688 if (stringBuilder.length > 0) {
6689 const last = stringBuilder
6690 stringBuilder = ""
6691 midCRLF = false
6692 return Effect.succeed([last] as Arr.NonEmptyReadonlyArray<string>)
6693 }
6694 return Cause.done(leftover)
6695 }
6696 })
6697 })
6698
6699 function loop(chunk: Arr.NonEmptyReadonlyArray<string>): Pull.Pull<Arr.NonEmptyReadonlyArray<string>, Err, Done> {
6700 const lines = splitLinesArray(chunk)
6701 return lines !== null ? Effect.succeed(lines) : pullOrFlush
6702 }
6703
6704 return pullOrFlush
6705 })
6706 )
6707
6708/**
6709 * Decodes incoming `Uint8Array` chunks into strings using `TextDecoder`.
6710 *
6711 * **Details**
6712 *
6713 * Input chunks are decoded with streaming enabled so multi-byte characters may
6714 * span `Uint8Array` boundaries. The optional `encoding` and `options` are
6715 * passed to `TextDecoder`.
6716 *
6717 * @category decoding
6718 * @since 4.0.0
6719 */
6720export const decodeText = <Err, Done>(encoding?: string, options?: TextDecoderOptions): Channel<
6721 Arr.NonEmptyReadonlyArray<string>,
6722 Err,
6723 Done,
6724 Arr.NonEmptyReadonlyArray<Uint8Array>,
6725 Err,
6726 Done
6727> =>
6728 fromTransform((upstream, _scope) =>
6729 Effect.sync(() => {
6730 const decoder = new TextDecoder(encoding, options)
6731 const streamOptions = { stream: true }
6732 return Effect.map(upstream, Arr.map((line) => decoder.decode(line, streamOptions)))
6733 })
6734 )
6735
6736/**
6737 * Encodes incoming string chunks into `Uint8Array` values using `TextEncoder`.
6738 *
6739 * **Details**
6740 *
6741 * Each string inside an emitted array is encoded independently.
6742 *
6743 * @category encoding
6744 * @since 4.0.0
6745 */
6746export const encodeText = <Err, Done>(): Channel<
6747 Arr.NonEmptyReadonlyArray<Uint8Array>,
6748 Err,
6749 Done,
6750 Arr.NonEmptyReadonlyArray<string>,
6751 Err,
6752 Done
6753> =>
6754 fromTransform((upstream, _scope) =>
6755 Effect.sync(() => {
6756 const encoder = new TextEncoder()
6757 return Effect.map(upstream, Arr.map((line) => encoder.encode(line)))
6758 })
6759 )
6760
6761/**
6762 * Returns a new channel that pipes the output of this channel into the
6763 * specified channel. The returned channel has the input type of this channel,
6764 * and the output type of the specified channel, terminating with the value of
6765 * the specified channel.
6766 *
6767 * **Example** (Piping one channel into another)
6768 *
6769 * ```ts import.meta.vitest
6770 * import { Channel, Data, Effect } from "effect"
6771 *
6772 * class PipeError extends Data.TaggedError("PipeError")<{
6773 * readonly stage: string
6774 * }> {}
6775 *
6776 * // Create source and transform channels
6777 * const sourceChannel = Channel.fromIterable([1, 2, 3])
6778 * const transformChannel = Channel.map(sourceChannel, (n: number) => n * 2)
6779 *
6780 * // Pipe the source into the transform
6781 * const pipedChannel = Channel.pipeTo(sourceChannel, transformChannel)
6782 *
6783 * Effect.runSync(Channel.runCollect(pipedChannel)) // => [2, 4, 6]
6784 * ```
6785 *
6786 * @category sequencing
6787 * @since 2.0.0
6788 */
6789export const pipeTo: {
6790 <OutElem2, OutErr2, OutDone2, OutElem, OutErr, OutDone, Env2>(
6791 that: Channel<OutElem2, OutErr2, OutDone2, OutElem, OutErr, OutDone, Env2>
6792 ): <InElem, InErr, InDone, Env>(
6793 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
6794 ) => Channel<OutElem2, OutErr2, OutDone2, InElem, InErr, InDone, Env2 | Env>
6795 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem2, OutErr2, OutDone2, Env2>(
6796 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6797 that: Channel<OutElem2, OutErr2, OutDone2, OutElem, OutErr, OutDone, Env2>
6798 ): Channel<OutElem2, OutErr2, OutDone2, InElem, InErr, InDone, Env2 | Env>
6799} = dual(
6800 2,
6801 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem2, OutErr2, OutDone2, Env2>(
6802 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6803 that: Channel<OutElem2, OutErr2, OutDone2, OutElem, OutErr, OutDone, Env2>
6804 ): Channel<OutElem2, OutErr2, OutDone2, InElem, InErr, InDone, Env2 | Env> =>
6805 fromTransform((upstream, scope) =>
6806 Effect.flatMap(toTransform(self)(upstream, scope), (upstream) => toTransform(that)(upstream, scope))
6807 )
6808)
6809
6810/**
6811 * Returns a new channel that pipes the output of this channel into the
6812 * specified channel and preserves this channel's failures without providing
6813 * them to the other channel for observation.
6814 *
6815 * **Example** (Piping while preserving failures)
6816 *
6817 * ```ts import.meta.vitest
6818 * import { Channel, Data, Effect, Exit } from "effect"
6819 *
6820 * class SourceError extends Data.TaggedError("SourceError")<{
6821 * readonly code: number
6822 * }> {}
6823 *
6824 * // Create a failing source channel
6825 * const error = new SourceError({ code: 404 })
6826 * const failingSource = Channel.fail(error)
6827 * const safeTransform = Channel.identity<never, never, never>()
6828 *
6829 * // Pipe while preserving source failures
6830 * const safePipedChannel = Channel.pipeToOrFail(failingSource, safeTransform)
6831 *
6832 * Effect.runSync(Effect.exit(Channel.runCollect(safePipedChannel))) // => Exit.fail(error)
6833 * ```
6834 *
6835 * @category sequencing
6836 * @since 2.0.0
6837 */
6838export const pipeToOrFail: {
6839 <OutElem2, OutErr2, OutDone2, OutElem, OutDone, Env2>(
6840 that: Channel<OutElem2, OutErr2, OutDone2, OutElem, never, OutDone, Env2>
6841 ): <OutErr, InElem, InErr, InDone, Env>(
6842 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
6843 ) => Channel<OutElem2, OutErr | OutErr2, OutDone2, InElem, InErr, InDone, Env2 | Env>
6844 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem2, OutErr2, OutDone2, Env2>(
6845 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6846 that: Channel<OutElem2, OutErr2, OutDone2, OutElem, never, OutDone, Env2>
6847 ): Channel<OutElem2, OutErr | OutErr2, OutDone2, InElem, InErr, InDone, Env2 | Env>
6848} = dual(
6849 2,
6850 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutElem2, OutErr2, OutDone2, Env2>(
6851 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
6852 that: Channel<OutElem2, OutErr2, OutDone2, OutElem, never, OutDone, Env2>
6853 ): Channel<OutElem2, OutErr | OutErr2, OutDone2, InElem, InErr, InDone, Env2 | Env> =>
6854 fromTransform((upstream, scope) =>
6855 Effect.flatMap(toTransform(self)(upstream, scope), (upstream) => {
6856 const upstreamPull = Effect.catchCause(
6857 upstream,
6858 (cause) => Pull.isDoneCause(cause) ? Effect.failCause(cause) : Effect.die(Cause.Done(cause))
6859 ) as Pull.Pull<OutElem, never, OutDone>
6860
6861 return Effect.map(
6862 toTransform(that)(upstreamPull, scope),
6863 (pull) =>
6864 Effect.catchDefect(
6865 pull,
6866 (defect) =>
6867 Cause.isDone(defect) ? Effect.failCause(defect.value as Cause.Cause<OutErr>) : Effect.die(defect)
6868 )
6869 )
6870 })
6871 )
6872)
6873
6874/**
6875 * Constructs a `Channel` from a scoped effect that will result in a
6876 * `Channel` if successful.
6877 *
6878 * **Example** (Unwrapping channel effects)
6879 *
6880 * ```ts import.meta.vitest
6881 * import { Channel, Data, Effect } from "effect"
6882 *
6883 * class UnwrapError extends Data.TaggedError("UnwrapError")<{
6884 * readonly reason: string
6885 * }> {}
6886 *
6887 * // Create an effect that produces a channel
6888 * const channelEffect = Effect.succeed(
6889 * Channel.fromIterable([1, 2, 3])
6890 * )
6891 *
6892 * // Unwrap the effect to get the channel
6893 * const unwrappedChannel = Channel.unwrap(channelEffect)
6894 *
6895 * Effect.runSync(Channel.runCollect(unwrappedChannel)) // => [1, 2, 3]
6896 * ```
6897 *
6898 * @category constructors
6899 * @since 2.0.0
6900 */
6901export const unwrap = <OutElem, OutErr, OutDone, InElem, InErr, InDone, R2, E, R>(
6902 channel: Effect.Effect<Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, R2>, E, R>
6903): Channel<OutElem, E | OutErr, OutDone, InElem, InErr, InDone, Exclude<R, Scope.Scope> | R2> =>
6904 fromTransform((upstream, scope) => {
6905 let pull: Pull.Pull<OutElem, E | OutErr, OutDone> | undefined
6906 return Effect.succeed(Effect.suspend(() => {
6907 if (pull) return pull
6908 return channel.pipe(
6909 Scope.provide(scope),
6910 Effect.flatMap((channel) => toTransform(channel)(upstream, scope)),
6911 Effect.flatMap((pull_) => pull = pull_)
6912 )
6913 }))
6914 })
6915
6916/**
6917 * Runs a channel with a scope provided for the duration of the channel
6918 * execution, removing the channel's `Scope` requirement.
6919 *
6920 * @category resource management
6921 * @since 2.0.0
6922 */
6923export const scoped = <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
6924 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
6925): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, Scope.Scope>> =>
6926 fromTransformBracket((upstream, scope, forkedScope) =>
6927 Effect.map(
6928 Scope.provide(toTransform(self)(upstream, scope), forkedScope),
6929 Scope.provide(forkedScope)
6930 )
6931 )
6932
6933/**
6934 * Runs an input handler against the upstream pull while the wrapped channel
6935 * runs without receiving upstream input directly.
6936 *
6937 * **Details**
6938 *
6939 * The input handler is forked in the channel scope. The wrapped channel is run
6940 * with an already-completed input.
6941 *
6942 * **Example** (Embedding custom input handling)
6943 *
6944 * ```ts import.meta.vitest
6945 * import { Channel, Effect } from "effect"
6946 *
6947 * // Create a base channel
6948 * const baseChannel = Channel.fromIterable([1, 2, 3])
6949 *
6950 * // Drain the embedded input while the base channel runs
6951 * const embeddedChannel = Channel.embedInput(
6952 * baseChannel,
6953 * (upstream) =>
6954 * upstream.pipe(
6955 * Effect.forever,
6956 * Effect.ignore
6957 * )
6958 * )
6959 * await Effect.runPromise(Channel.runCollect(embeddedChannel)) // => [1, 2, 3]
6960 * ```
6961 *
6962 * @category sequencing
6963 * @since 2.0.0
6964 */
6965export const embedInput: {
6966 <InElem, InErr, InDone, R>(
6967 input: (
6968 upstream: Pull.Pull<InElem, InErr, InDone>
6969 ) => Effect.Effect<void, never, R>
6970 ): <OutElem, OutErr, OutDone, Env>(
6971 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
6972 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env | R>
6973 <OutElem, OutErr, OutDone, Env, InErr, InElem, InDone, R>(
6974 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
6975 input: (
6976 upstream: Pull.Pull<InElem, InErr, InDone>
6977 ) => Effect.Effect<void, never, R>
6978 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env | R>
6979} = dual(
6980 2,
6981 <OutElem, OutErr, OutDone, Env, InErr, InElem, InDone, R>(
6982 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
6983 input: (
6984 upstream: Pull.Pull<InElem, InErr, InDone>
6985 ) => Effect.Effect<void, never, R>
6986 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env | R> =>
6987 fromTransformBracket((upstream, scope, forkedScope) =>
6988 Effect.andThen(
6989 Effect.forkIn(input(upstream), forkedScope),
6990 toTransform(self)(Cause.done(), scope)
6991 )
6992 )
6993)
6994
6995/**
6996 * Buffers individual output elements in a queue with the configured `capacity`
6997 * so a faster producer can progress independently of a slower consumer.
6998 *
6999 * **When to use**
7000 *
7001 * Use when output elements can be decoupled from downstream demand and the
7002 * configured backpressure or loss strategy is acceptable.
7003 *
7004 * **Details**
7005 *
7006 * Finite queues use the `strategy` option. The default `"suspend"` strategy
7007 * applies backpressure, while `"dropping"` and `"sliding"` can discard output
7008 * elements when the queue is full. `"unbounded"` capacity does not use a finite
7009 * capacity strategy.
7010 *
7011 * **Gotchas**
7012 *
7013 * Dropping and sliding strategies can lose output elements under backpressure.
7014 *
7015 * @see {@link bufferArray} for buffering elements from array outputs
7016 *
7017 * @category buffering
7018 * @since 2.0.0
7019 */
7020export const buffer: {
7021 (
7022 options: { readonly capacity: "unbounded" } | {
7023 readonly capacity: number
7024 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
7025 }
7026 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7027 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7028 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7029 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7030 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7031 options: { readonly capacity: "unbounded" } | {
7032 readonly capacity: number
7033 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
7034 }
7035 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7036} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7037 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7038 options: { readonly capacity: "unbounded" } | {
7039 readonly capacity: number
7040 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
7041 }
7042): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env> =>
7043 fromTransform(Effect.fnUntraced(function*(upstream, scope) {
7044 const pull = yield* toTransform(self)(upstream, scope)
7045 const queue = yield* Queue.make<OutElem, OutErr | Cause.Done<OutDone>>({
7046 capacity: options.capacity === "unbounded" ? undefined : options.capacity,
7047 strategy: options.capacity === "unbounded" ? undefined : options.strategy
7048 })
7049 yield* Scope.addFinalizer(scope, Queue.shutdown(queue))
7050 yield* pull.pipe(
7051 Effect.flatMap((value) => Queue.offer(queue, value)),
7052 Effect.forever({ disableYield: true }),
7053 Effect.onError((cause) => Queue.failCause(queue, cause)),
7054 Effect.forkIn(scope)
7055 )
7056 return Queue.take(queue)
7057 })))
7058
7059/**
7060 * Buffers array output elements in a queue with the configured `capacity` so a
7061 * faster producer can progress independently of a slower consumer.
7062 *
7063 * **When to use**
7064 *
7065 * Use when emitted arrays are batches of elements and it is acceptable for
7066 * buffering to flatten and rebuild those batches.
7067 *
7068 * **Details**
7069 *
7070 * Finite queues use the `strategy` option. The default `"suspend"` strategy
7071 * applies backpressure, while `"dropping"` and `"sliding"` can discard output
7072 * elements when the queue is full. `"unbounded"` capacity does not use a finite
7073 * capacity strategy.
7074 *
7075 * **Gotchas**
7076 *
7077 * Input arrays are offered to the queue element-by-element and outputs are
7078 * rebuilt from the currently available queued elements, so upstream array
7079 * boundaries are not preserved.
7080 *
7081 * @see {@link buffer} for buffering output elements without flattening arrays
7082 *
7083 * @category buffering
7084 * @since 4.0.0
7085 */
7086export const bufferArray: {
7087 (
7088 options: { readonly capacity: "unbounded" } | {
7089 readonly capacity: number
7090 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
7091 }
7092 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7093 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
7094 ) => Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
7095 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7096 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
7097 options: { readonly capacity: "unbounded" } | {
7098 readonly capacity: number
7099 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
7100 }
7101 ): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>
7102} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7103 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env>,
7104 options: { readonly capacity: "unbounded" } | {
7105 readonly capacity: number
7106 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
7107 }
7108): Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, InElem, InErr, InDone, Env> =>
7109 fromTransform(Effect.fnUntraced(function*(upstream, scope) {
7110 const pull = yield* toTransform(self)(upstream, scope)
7111 const queue = yield* Queue.make<OutElem, OutErr | Cause.Done<OutDone>>({
7112 capacity: options.capacity === "unbounded" ? undefined : options.capacity,
7113 strategy: options.capacity === "unbounded" ? undefined : options.strategy
7114 })
7115 yield* Scope.addFinalizer(scope, Queue.shutdown(queue))
7116 yield* pull.pipe(
7117 Effect.flatMap((value) => Queue.offerAll(queue, value)),
7118 Effect.forever({ disableYield: true }),
7119 Effect.onError((cause) => Queue.failCause(queue, cause)),
7120 Effect.forkIn(scope)
7121 )
7122 return Queue.takeAll(queue)
7123 })))
7124
7125/**
7126 * Interrupts a channel when another effect completes.
7127 *
7128 * **When to use**
7129 *
7130 * Use to race channel execution against an external effect whose success can
7131 * become the channel's done value.
7132 *
7133 * **Details**
7134 *
7135 * If the effect completes first, its success value becomes the returned
7136 * channel's done value. If the channel completes first, the original channel's
7137 * done value is preserved.
7138 *
7139 * @category interruption
7140 * @since 2.0.0
7141 */
7142export const interruptWhen: {
7143 <OutDone2, OutErr2, Env2>(
7144 effect: Effect.Effect<OutDone2, OutErr2, Env2>
7145 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7146 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7147 ) => Channel<OutElem, OutErr | OutErr2, OutDone | OutDone2, InElem, InErr, InDone, Env2 | Env>
7148 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2, OutErr2, Env2>(
7149 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7150 effect: Effect.Effect<OutDone2, OutErr2, Env2>
7151 ): Channel<OutElem, OutErr | OutErr2, OutDone | OutDone2, InElem, InErr, InDone, Env2 | Env>
7152} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2, OutErr2, Env2>(
7153 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7154 effect: Effect.Effect<OutDone2, OutErr2, Env2>
7155): Channel<OutElem, OutErr | OutErr2, OutDone | OutDone2, InElem, InErr, InDone, Env2 | Env> =>
7156 merge(
7157 self,
7158 fromPull(Effect.succeed(Effect.flatMap(effect, Cause.done))),
7159 { haltStrategy: "either" }
7160 ))
7161
7162/**
7163 * Stops a channel when the specified effect completes or fails.
7164 *
7165 * **Details**
7166 *
7167 * If the effect completes before the channel is done, its success value becomes
7168 * the returned channel's done value. If the effect fails, the returned channel
7169 * fails with that error. If the channel completes first, the channel's done
7170 * value is preserved.
7171 *
7172 * @category interruption
7173 * @since 4.0.0
7174 */
7175export const haltWhen: {
7176 <OutDone2, OutErr2, Env2>(
7177 effect: Effect.Effect<OutDone2, OutErr2, Env2>
7178 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7179 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7180 ) => Channel<OutElem, OutErr | OutErr2, OutDone | OutDone2, InElem, InErr, InDone, Env2 | Env>
7181 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2, OutErr2, Env2>(
7182 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7183 effect: Effect.Effect<OutDone2, OutErr2, Env2>
7184 ): Channel<OutElem, OutErr | OutErr2, OutDone | OutDone2, InElem, InErr, InDone, Env2 | Env>
7185} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, OutDone2, OutErr2, Env2>(
7186 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7187 effect: Effect.Effect<OutDone2, OutErr2, Env2>
7188): Channel<OutElem, OutErr | OutErr2, OutDone | OutDone2, InElem, InErr, InDone, Env2 | Env> =>
7189 fromTransformBracket(Effect.fnUntraced(function*(upstream, scope, forkedScope) {
7190 const pull = yield* toTransform(self)(upstream, scope)
7191 const fiber = yield* Effect.forkIn(effect, forkedScope, { startImmediately: true })
7192 return Effect.suspend((): Pull.Pull<OutElem, OutErr | OutErr2, OutDone | OutDone2> => {
7193 const exit = fiber.pollUnsafe()
7194 return exit === undefined
7195 ? pull
7196 : Exit.match(exit, {
7197 onFailure: Effect.failCause,
7198 onSuccess: Cause.done
7199 })
7200 })
7201 })))
7202
7203/**
7204 * Attaches a finalizer that runs only when the channel exits with failure.
7205 *
7206 * **Details**
7207 *
7208 * The finalizer receives the failure `Cause`. The original channel failure is
7209 * preserved. The finalizer itself must not fail.
7210 *
7211 * @category error handling
7212 * @since 4.0.0
7213 */
7214export const onError: {
7215 <OutDone, OutErr, Env2>(
7216 finalizer: (cause: Cause.Cause<OutErr>) => Effect.Effect<unknown, never, Env2>
7217 ): <OutElem, InElem, InErr, InDone, Env>(
7218 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7219 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env>
7220 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, Env2>(
7221 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7222 finalizer: (cause: Cause.Cause<OutErr>) => Effect.Effect<unknown, never, Env2>
7223 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env>
7224} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, Env2>(
7225 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7226 finalizer: (cause: Cause.Cause<OutErr>) => Effect.Effect<unknown, never, Env2>
7227): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env> =>
7228 onExit(self, (exit) => Exit.isFailure(exit) ? finalizer(exit.cause) : Effect.void))
7229
7230/**
7231 * Returns a channel with an exit-aware finalizer that is guaranteed to run once
7232 * the channel begins execution, whether it succeeds or fails.
7233 *
7234 * **Example** (Running exit finalizers)
7235 *
7236 * ```ts import.meta.vitest
7237 * import { Channel, Data, Effect, Exit } from "effect"
7238 *
7239 * class ExitError extends Data.TaggedError("ExitError")<{
7240 * readonly stage: string
7241 * }> {}
7242 *
7243 * // Create a channel
7244 * const dataChannel = Channel.fromIterable([1, 2, 3])
7245 *
7246 * // Attach exit handler
7247 * const exits: Array<Exit.Exit<void, ExitError>> = []
7248 * const channelWithExit = Channel.onExit(dataChannel, (exit) => {
7249 * exits.push(exit)
7250 * return Effect.void
7251 * })
7252 * const observed = [await Effect.runPromise(Channel.runCollect(channelWithExit)), exits] // => [[1, 2, 3], [Exit.void]]
7253 * ```
7254 *
7255 * @category resource management
7256 * @since 4.0.0
7257 */
7258export const onExit: {
7259 <OutDone, OutErr, Env2>(
7260 finalizer: (e: Exit.Exit<OutDone, OutErr>) => Effect.Effect<unknown, never, Env2>
7261 ): <OutElem, InElem, InErr, InDone, Env>(
7262 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7263 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env>
7264 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, Env2>(
7265 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7266 finalizer: (e: Exit.Exit<OutDone, OutErr>) => Effect.Effect<unknown, never, Env2>
7267 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env>
7268} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, Env2>(
7269 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7270 finalizer: (e: Exit.Exit<OutDone, OutErr>) => Effect.Effect<unknown, never, Env2>
7271): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env> =>
7272 fromTransformBracket((upstream, scope, forkedScope) =>
7273 Scope.addFinalizerExit(forkedScope, finalizer as any).pipe(
7274 Effect.andThen(toTransform(self)(upstream, scope))
7275 )
7276 ))
7277
7278/**
7279 * Runs an effect before the channel starts.
7280 *
7281 * **Details**
7282 *
7283 * The effect's successful value is ignored. If the effect fails, the returned
7284 * channel fails before running the source channel.
7285 *
7286 * @category hooks
7287 * @since 4.0.0
7288 */
7289export const onStart: {
7290 <A, E, R>(
7291 onStart: Effect.Effect<A, E, R>
7292 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7293 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7294 ) => Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
7295 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E, R>(
7296 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7297 onStart: Effect.Effect<A, E, R>
7298 ): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
7299} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E, R>(
7300 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7301 onStart: Effect.Effect<A, E, R>
7302): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> => unwrap(Effect.as(onStart, self)))
7303
7304/**
7305 * Runs an effect the first time the channel emits an output element.
7306 *
7307 * **When to use**
7308 *
7309 * Use when initialization depends on the first output element rather than only
7310 * on channel startup.
7311 *
7312 * **Details**
7313 *
7314 * The effect receives the first emitted element. The first element is still
7315 * emitted unchanged. The effect is not run if the channel completes without
7316 * emitting an element.
7317 *
7318 * @category hooks
7319 * @since 4.0.0
7320 */
7321export const onFirst: {
7322 <OutElem, A, E, R>(
7323 onFirst: (element: Types.NoInfer<OutElem>) => Effect.Effect<A, E, R>
7324 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
7325 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7326 ) => Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
7327 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E, R>(
7328 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7329 onFirst: (element: Types.NoInfer<OutElem>) => Effect.Effect<A, E, R>
7330 ): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
7331} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E, R>(
7332 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7333 onFirst: (element: Types.NoInfer<OutElem>) => Effect.Effect<A, E, R>
7334): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
7335 transformPull(self, (pull) =>
7336 Effect.sync(() => {
7337 let isFirst = true
7338 const pullFirst = Effect.tap(pull, (element) => {
7339 isFirst = false
7340 return onFirst(element)
7341 })
7342 return Effect.suspend(() => isFirst ? pullFirst : pull)
7343 })))
7344
7345/**
7346 * Runs an effect when the channel completes successfully.
7347 *
7348 * **Details**
7349 *
7350 * The effect runs before the original done value is propagated. The effect is
7351 * not run when the channel fails. If the effect fails, the returned channel
7352 * fails with that error.
7353 *
7354 * @category hooks
7355 * @since 4.0.0
7356 */
7357export const onEnd: {
7358 <A, E, R>(
7359 onEnd: Effect.Effect<A, E, R>
7360 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7361 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7362 ) => Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
7363 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E, R>(
7364 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7365 onEnd: Effect.Effect<A, E, R>
7366 ): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R>
7367} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E, R>(
7368 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7369 onEnd: Effect.Effect<A, E, R>
7370): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Env | R> =>
7371 transformPull(self, (pull) =>
7372 Effect.succeed(Pull.catchDone(
7373 pull,
7374 (leftover) => Effect.flatMap(onEnd, () => Cause.done(leftover as OutDone))
7375 ))))
7376
7377/**
7378 * Returns a channel with a finalizer effect that is guaranteed to run once the
7379 * channel begins execution, whether it succeeds or fails.
7380 *
7381 * **Example** (Ensuring cleanup runs)
7382 *
7383 * ```ts import.meta.vitest
7384 * import { Channel, Data, Effect } from "effect"
7385 *
7386 * class EnsureError extends Data.TaggedError("EnsureError")<{
7387 * readonly operation: string
7388 * }> {}
7389 *
7390 * // Create a channel
7391 * const dataChannel = Channel.fromIterable([1, 2, 3])
7392 *
7393 * // Ensure cleanup always runs
7394 * const events: Array<string> = []
7395 * const channelWithCleanup = Channel.ensuring(
7396 * dataChannel,
7397 * Effect.sync(() => events.push("cleanup"))
7398 * )
7399 * const observed = [await Effect.runPromise(Channel.runCollect(channelWithCleanup)), events] // => [[1, 2, 3], ["cleanup"]]
7400 * ```
7401 *
7402 * @category resource management
7403 * @since 2.0.0
7404 */
7405export const ensuring: {
7406 <Env2>(
7407 finalizer: Effect.Effect<unknown, never, Env2>
7408 ): <OutElem, OutDone, OutErr, InElem, InErr, InDone, Env>(
7409 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7410 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env>
7411 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, Env2>(
7412 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7413 finalizer: Effect.Effect<unknown, never, Env2>
7414 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env>
7415} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, Env2>(
7416 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7417 finalizer: Effect.Effect<unknown, never, Env2>
7418): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2 | Env> => onExit(self, (_) => finalizer))
7419
7420const runWith = <
7421 OutElem,
7422 OutErr,
7423 OutDone,
7424 Env,
7425 EX,
7426 RX,
7427 AH = OutDone,
7428 EH = never,
7429 RH = never
7430>(
7431 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
7432 f: (pull: Pull.Pull<OutElem, OutErr, OutDone>) => Effect.Effect<void, EX, RX>,
7433 onHalt?: (leftover: OutDone) => Effect.Effect<AH, EH, RH>
7434): Effect.Effect<AH, Pull.ExcludeDone<EX> | EH, Env | RX | RH> =>
7435 Effect.suspend(() => {
7436 const scope = Scope.makeUnsafe()
7437 const makePull = toTransform(self)(Cause.done(), scope)
7438 return Pull.catchDone(Effect.flatMap(makePull, f), onHalt ? onHalt : Effect.succeed as any).pipe(
7439 Effect.onExit((exit) => Scope.close(scope, exit))
7440 ) as any
7441 })
7442
7443/**
7444 * Creates a channel from the specified services.
7445 *
7446 * @category accessors
7447 * @since 2.0.0
7448 */
7449export const contextWith = <Env, OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2>(
7450 f: (context: Context.Context<Env>) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env2>
7451): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env | Env2> =>
7452 fromTransform((upstream, scope) =>
7453 Effect.contextWith((context: Context.Context<Env>) => toTransform(f(context))(upstream, scope))
7454 )
7455
7456/**
7457 * Provides a `Context` to the channel, removing the corresponding service
7458 * requirements from the returned channel.
7459 *
7460 * @category providing services
7461 * @since 2.0.0
7462 */
7463export const provideContext: {
7464 <R2>(
7465 context: Context.Context<R2>
7466 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7467 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7468 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, R2>>
7469 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, R2>(
7470 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7471 context: Context.Context<R2>
7472 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, R2>>
7473} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, R2>(
7474 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7475 context: Context.Context<R2>
7476): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, R2>> =>
7477 fromTransform((upstream, scope) =>
7478 Effect.map(
7479 Effect.provideContext(toTransform(self)(upstream, scope), context),
7480 Effect.provideContext(context)
7481 )
7482 ))
7483
7484/**
7485 * Provides a concrete service for a context key, removing that service
7486 * requirement from the returned channel.
7487 *
7488 * @category providing services
7489 * @since 2.0.0
7490 */
7491export const provideService: {
7492 <I, S>(
7493 key: Context.Key<I, S>,
7494 service: NoInfer<S>
7495 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7496 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7497 ) => Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, I>>
7498 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, I, S>(
7499 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7500 key: Context.Key<I, S>,
7501 service: NoInfer<S>
7502 ): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, I>>
7503} = dual(3, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, I, S>(
7504 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7505 key: Context.Key<I, S>,
7506 service: NoInfer<S>
7507): Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Exclude<Env, I>> =>
7508 fromTransform((upstream, scope) =>
7509 Effect.map(
7510 Effect.provideService(toTransform(self)(upstream, scope), key, service),
7511 Effect.provideService(key, service)
7512 )
7513 ))
7514
7515/**
7516 * Provides a service to the channel after obtaining it from an effect.
7517 *
7518 * **When to use**
7519 *
7520 * Use to supply a channel dependency when constructing the service itself is
7521 * effectful or can fail.
7522 *
7523 * **Details**
7524 *
7525 * If the service effect fails, the returned channel fails. The provided service
7526 * removes the corresponding service requirement from the returned channel.
7527 *
7528 * @category providing services
7529 * @since 4.0.0
7530 */
7531export const provideServiceEffect: {
7532 <I, S, ES, RS>(
7533 key: Context.Key<I, S>,
7534 service: Effect.Effect<NoInfer<S>, ES, RS>
7535 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7536 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7537 ) => Channel<OutElem, OutErr | ES, OutDone, InElem, InErr, InDone, Exclude<Env, I> | RS>
7538 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, I, S, ES, RS>(
7539 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7540 key: Context.Key<I, S>,
7541 service: Effect.Effect<NoInfer<S>, ES, RS>
7542 ): Channel<OutElem, OutErr | ES, OutDone, InElem, InErr, InDone, Exclude<Env, I> | RS>
7543} = dual(3, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, I, S, ES, RS>(
7544 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7545 key: Context.Key<I, S>,
7546 service: Effect.Effect<NoInfer<S>, ES, RS>
7547): Channel<OutElem, OutErr | ES, OutDone, InElem, InErr, InDone, Exclude<Env, I> | RS> =>
7548 fromTransform((upstream, scope) =>
7549 Effect.flatMap(
7550 service,
7551 (s) => toTransform(provideService(self, key, s))(upstream, scope)
7552 )
7553 ))
7554
7555/**
7556 * Provides a `Layer` or `Context` to the channel, removing the corresponding
7557 * service requirements.
7558 *
7559 * **Details**
7560 *
7561 * Providing a `Context` delegates to `provideContext`. Providing a `Layer`
7562 * builds the layer in the channel scope. Use `options.local` to build a fresh
7563 * layer instance for this provision.
7564 *
7565 * @category providing services
7566 * @since 4.0.0
7567 */
7568export const provide: {
7569 <A, E = never, R = never>(
7570 layer: Layer.Layer<A, E, R> | Context.Context<A>,
7571 options?: {
7572 readonly local?: boolean | undefined
7573 } | undefined
7574 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7575 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7576 ) => Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Exclude<Env, A> | R>
7577 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E = never, R = never>(
7578 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7579 layer: Layer.Layer<A, E, R> | Context.Context<A>,
7580 options?: {
7581 readonly local?: boolean | undefined
7582 } | undefined
7583 ): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Exclude<Env, A> | R>
7584} = dual((args) => isChannel(args[0]), <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, A, E = never, R = never>(
7585 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7586 layer: Layer.Layer<A, E, R> | Context.Context<A>,
7587 options?: {
7588 readonly local?: boolean | undefined
7589 } | undefined
7590): Channel<OutElem, OutErr | E, OutDone, InElem, InErr, InDone, Exclude<Env, A> | R> =>
7591 Context.isContext(layer) ? provideContext(self, layer) : fromTransform((upstream, scope) =>
7592 Effect.flatMap(
7593 options?.local
7594 ? Layer.buildWithMemoMap(layer, Layer.makeMemoMapUnsafe(), scope)
7595 : Layer.buildWithScope(layer, scope),
7596 (context) =>
7597 Effect.map(
7598 Effect.provideContext(toTransform(self)(upstream, scope), context),
7599 Effect.provideContext(context)
7600 )
7601 )
7602 ))
7603
7604/**
7605 * Transforms the current context before running the channel.
7606 *
7607 * **Details**
7608 *
7609 * The function receives the surrounding context and returns the context to
7610 * provide to the channel. The returned channel requires the services needed to
7611 * build that context.
7612 *
7613 * @category providing services
7614 * @since 4.0.0
7615 */
7616export const updateContext: {
7617 <Env, R2>(
7618 f: (context: Context.Context<R2>) => Context.Context<Env>
7619 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone>(
7620 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
7621 ) => Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, R2>
7622 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, R2>(
7623 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
7624 f: (context: Context.Context<R2>) => Context.Context<Env>
7625 ): Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, R2>
7626} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, R2>(
7627 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
7628 f: (context: Context.Context<R2>) => Context.Context<Env>
7629): Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, R2> =>
7630 fromTransform((upstream, scope) =>
7631 Effect.contextWith((context) => {
7632 const toProvide = f(context)
7633 return toTransform(provideContext(self, toProvide))(upstream, scope)
7634 })
7635 ))
7636
7637/**
7638 * Updates a service in the current context before running the channel.
7639 *
7640 * **Details**
7641 *
7642 * The existing service is read from the context. The updated service is
7643 * provided to the channel under the same key.
7644 *
7645 * @category providing services
7646 * @since 2.0.0
7647 */
7648export const updateService: {
7649 <I, S>(
7650 key: Context.Key<I, S>,
7651 f: (service: NoInfer<S>) => S
7652 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7653 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
7654 ) => Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env | I>
7655 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, I, S>(
7656 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
7657 service: Context.Key<I, S>,
7658 f: (service: NoInfer<S>) => S
7659 ): Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env | I>
7660} = dual(3, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, I, S>(
7661 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
7662 service: Context.Key<I, S>,
7663 f: (service: NoInfer<S>) => S
7664): Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env | I> =>
7665 updateContext(self, (context) =>
7666 Context.add(
7667 context,
7668 service,
7669 f(Context.get(context, service))
7670 )))
7671
7672/**
7673 * Runs the channel inside a tracing span with the specified name and options.
7674 *
7675 * **Details**
7676 *
7677 * The created span is provided as the current parent span while the channel
7678 * runs. The span is ended with the channel's exit value.
7679 *
7680 * @category tracing
7681 * @since 2.0.0
7682 */
7683export const withSpan: {
7684 (
7685 name: string,
7686 options?: SpanOptions
7687 ): <OutElem, OutErr, OutDone, InElem, InErr, InDone, R>(
7688 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, R>
7689 ) => Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<R, ParentSpan>>
7690 <OutElem, OutErr, OutDone, InElem, InErr, InDone, R>(
7691 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, R>,
7692 name: string,
7693 options?: SpanOptions
7694 ): Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<R, ParentSpan>>
7695} = function() {
7696 const dataFirst = isChannel(arguments[0])
7697 const name = dataFirst ? arguments[1] : arguments[0]
7698 const options = addSpanStackTrace(dataFirst ? arguments[2] : arguments[1])
7699 if (dataFirst) {
7700 const self = arguments[0]
7701 return withSpanImpl(self, name, options)
7702 }
7703 return (self: any) => withSpanImpl(self, name, options)
7704} as any
7705
7706const withSpanImpl = <OutElem, OutErr, OutDone, InElem, InErr, InDone, R>(
7707 self: Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, R>,
7708 name: string,
7709 options?: SpanOptions
7710): Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<R, ParentSpan>> =>
7711 acquireUseRelease(
7712 Effect.makeSpan(name, options),
7713 (span) => provideService(self, ParentSpan, span),
7714 (span, exit) =>
7715 Effect.withFiber((fiber) => {
7716 const clock = fiber.getRef(ClockRef)
7717 const timingEnabled = fiber.getRef(TracerTimingEnabled)
7718 return endSpan(span, exit, clock, timingEnabled)
7719 })
7720 )
7721
7722/**
7723 * The starting channel for Do notation, emitting an empty object.
7724 *
7725 * @category constructors
7726 * @since 4.0.0
7727 */
7728export const Do: Channel<{}> = succeed({})
7729
7730const let_: {
7731 <N extends string, OutElem extends object, B>(
7732 name: Exclude<N, keyof OutElem>,
7733 f: (a: NoInfer<OutElem>) => B
7734 ): <OutErr, OutDone, InElem, InErr, InDone, R>(
7735 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, R>
7736 ) => Channel<
7737 { [K in N | keyof OutElem]: K extends keyof OutElem ? OutElem[K] : B },
7738 OutErr,
7739 OutDone,
7740 InElem,
7741 InErr,
7742 InDone,
7743 R
7744 >
7745 <OutElem extends object, OutErr, OutDone, InElem, InErr, InDone, R, N extends string, B>(
7746 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, R>,
7747 name: Exclude<N, keyof OutElem>,
7748 f: (a: NoInfer<OutElem>) => B
7749 ): Channel<
7750 { [K in N | keyof OutElem]: K extends keyof OutElem ? OutElem[K] : B },
7751 OutErr,
7752 OutDone,
7753 InElem,
7754 InErr,
7755 InDone,
7756 R
7757 >
7758} = dual(3, <OutElem extends object, OutErr, OutDone, InElem, InErr, InDone, R, N extends string, B>(
7759 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, R>,
7760 name: Exclude<N, keyof OutElem>,
7761 f: (a: NoInfer<OutElem>) => B
7762): Channel<
7763 { [K in N | keyof OutElem]: K extends keyof OutElem ? OutElem[K] : B },
7764 OutErr,
7765 OutDone,
7766 InElem,
7767 InErr,
7768 InDone,
7769 R
7770> =>
7771 map(self, (elem) => (({
7772 ...elem,
7773 [name]: f(elem)
7774 }) as any)))
7775export {
7776 /**
7777 * Adds a computed field to each object emitted by a channel.
7778 *
7779 * @category mapping
7780 * @since 4.0.0
7781 */
7782 let_ as let
7783}
7784
7785/**
7786 * Adds a field to each object emitted by a channel by running another channel
7787 * derived from that object.
7788 *
7789 * **Details**
7790 *
7791 * The field name must not already exist on the emitted object. The derived
7792 * channel's output becomes the value of the new field. `options.concurrency`
7793 * and `options.bufferSize` control how derived channels are flattened.
7794 *
7795 * @category sequencing
7796 * @since 4.0.0
7797 */
7798export const bind: {
7799 <N extends string, OutElem extends object, B, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>(
7800 name: Exclude<N, keyof OutElem>,
7801 f: (a: NoInfer<OutElem>) => Channel<B, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>,
7802 options?: {
7803 readonly concurrency?: Types.Concurrency | undefined
7804 readonly bufferSize?: number | undefined
7805 }
7806 ): <OutErr, OutDone, InElem, InErr, InDone, Env>(
7807 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7808 ) => Channel<
7809 { [K in N | keyof OutElem]: K extends keyof OutElem ? OutElem[K] : B },
7810 OutErr2 | OutErr,
7811 OutDone,
7812 InElem & InElem2,
7813 InErr & InErr2,
7814 InDone & InDone2,
7815 Env2 | Env
7816 >
7817 <
7818 OutElem extends object,
7819 OutErr,
7820 OutDone,
7821 InElem,
7822 InErr,
7823 InDone,
7824 Env,
7825 N extends string,
7826 B,
7827 OutErr2,
7828 OutDone2,
7829 InElem2,
7830 InErr2,
7831 InDone2,
7832 Env2
7833 >(
7834 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7835 name: Exclude<N, keyof OutElem>,
7836 f: (a: NoInfer<OutElem>) => Channel<B, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>,
7837 options?: {
7838 readonly concurrency?: Types.Concurrency | undefined
7839 readonly bufferSize?: number | undefined
7840 }
7841 ): Channel<
7842 { [K in N | keyof OutElem]: K extends keyof OutElem ? OutElem[K] : B },
7843 OutErr2 | OutErr,
7844 OutDone,
7845 InElem & InElem2,
7846 InErr & InErr2,
7847 InDone & InDone2,
7848 Env2 | Env
7849 >
7850} = dual((args) => isChannel(args[0]), <
7851 OutElem extends object,
7852 OutErr,
7853 OutDone,
7854 InElem,
7855 InErr,
7856 InDone,
7857 Env,
7858 N extends string,
7859 B,
7860 OutErr2,
7861 OutDone2,
7862 InElem2,
7863 InErr2,
7864 InDone2,
7865 Env2
7866>(
7867 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7868 name: Exclude<N, keyof OutElem>,
7869 f: (a: NoInfer<OutElem>) => Channel<B, OutErr2, OutDone2, InElem2, InErr2, InDone2, Env2>,
7870 options?: {
7871 readonly concurrency?: Types.Concurrency | undefined
7872 readonly bufferSize?: number | undefined
7873 }
7874): Channel<
7875 { [K in N | keyof OutElem]: K extends keyof OutElem ? OutElem[K] : B },
7876 OutErr2 | OutErr,
7877 OutDone,
7878 InElem & InElem2,
7879 InErr & InErr2,
7880 InDone & InDone2,
7881 Env2 | Env
7882> =>
7883 flatMap(
7884 self,
7885 (elem) => map(f(elem), (b) => ({ ...elem, [name]: b } as any)),
7886 options
7887 ))
7888
7889/**
7890 * Wraps each output element in an object under the specified field name.
7891 *
7892 * **When to use**
7893 *
7894 * Use when you need to start a Channel Do-notation chain from an existing
7895 * output value by assigning that value to a field name.
7896 *
7897 * @see {@link Do} for starting Do notation from an empty object
7898 * @see {@link bind} for adding a field produced by another channel
7899 * @see {@link let_ let} for adding a computed field
7900 *
7901 * @category mapping
7902 * @since 4.0.0
7903 */
7904export const bindTo: {
7905 <N extends string>(name: N): <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>(
7906 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>
7907 ) => Channel<
7908 { [K in N]: OutElem },
7909 OutErr,
7910 OutDone,
7911 InElem,
7912 InErr,
7913 InDone,
7914 Env
7915 >
7916 <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, N extends string>(
7917 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7918 name: N
7919 ): Channel<
7920 { [K in N]: OutElem },
7921 OutErr,
7922 OutDone,
7923 InElem,
7924 InErr,
7925 InDone,
7926 Env
7927 >
7928} = dual(2, <OutElem, OutErr, OutDone, InElem, InErr, InDone, Env, N extends string>(
7929 self: Channel<OutElem, OutErr, OutDone, InElem, InErr, InDone, Env>,
7930 name: N
7931): Channel<
7932 { [K in N]: OutElem },
7933 OutErr,
7934 OutDone,
7935 InElem,
7936 InErr,
7937 InDone,
7938 Env
7939> => map(self, (elem) => ({ [name]: elem } as any)))
7940
7941/**
7942 * Runs a channel and counts the number of elements it outputs.
7943 *
7944 * **Example** (Counting channel output)
7945 *
7946 * ```ts import.meta.vitest
7947 * import { Channel, Data, Effect } from "effect"
7948 *
7949 * class CountError extends Data.TaggedError("CountError")<{
7950 * readonly reason: string
7951 * }> {}
7952 *
7953 * // Create a channel with multiple elements
7954 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5])
7955 *
7956 * // Count the elements
7957 * const countEffect = Channel.runCount(numbersChannel)
7958 *
7959 * Effect.runSync(countEffect) // => 5
7960 * ```
7961 *
7962 * @category running
7963 * @since 4.0.0
7964 */
7965export const runCount = <OutElem, OutErr, OutDone, Env>(
7966 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
7967): Effect.Effect<number, OutErr, Env> => runFold(self, () => 0, (acc) => acc + 1)
7968
7969/**
7970 * Runs a channel and discards all output elements, returning only the final result.
7971 *
7972 * **Example** (Draining channel output at runtime)
7973 *
7974 * ```ts import.meta.vitest
7975 * import { Channel, Data, Effect } from "effect"
7976 *
7977 * class DrainError extends Data.TaggedError("DrainError")<{
7978 * readonly stage: string
7979 * }> {}
7980 *
7981 * // Create a channel that outputs elements and completes with a result
7982 * const resultChannel = Channel.fromIterable([1, 2, 3])
7983 * const completedChannel = Channel.concat(resultChannel, Channel.end("completed"))
7984 *
7985 * // Drain all elements and get only the final result
7986 * const drainEffect = Channel.runDrain(completedChannel)
7987 *
7988 * Effect.runSync(drainEffect) // => "completed"
7989 * ```
7990 *
7991 * @category running
7992 * @since 2.0.0
7993 */
7994export const runDrain = <OutElem, OutErr, OutDone, Env>(
7995 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
7996): Effect.Effect<OutDone, OutErr, Env> => runWith(self, (pull) => Effect.forever(pull, { disableYield: true }))
7997
7998/**
7999 * Runs a channel and applies an effect to each output element.
8000 *
8001 * **Example** (Running effects for each output)
8002 *
8003 * ```ts import.meta.vitest
8004 * import { Channel, Data, Effect } from "effect"
8005 *
8006 * class ForEachError extends Data.TaggedError("ForEachError")<{
8007 * readonly element: unknown
8008 * }> {}
8009 *
8010 * // Create a channel with numbers
8011 * const numbersChannel = Channel.fromIterable([1, 2, 3])
8012 *
8013 * // Run forEach to process each element
8014 * const processed: Array<number> = []
8015 * const forEachEffect = Channel.runForEach(
8016 * numbersChannel,
8017 * (n) => Effect.sync(() => processed.push(n))
8018 * )
8019 *
8020 * await Effect.runPromise(forEachEffect)
8021 * processed // => [1, 2, 3]
8022 * ```
8023 *
8024 * @category running
8025 * @since 4.0.0
8026 */
8027export const runForEach: {
8028 <OutElem, EX, RX>(
8029 f: (o: OutElem) => Effect.Effect<void, EX, RX>
8030 ): <OutErr, OutDone, Env>(
8031 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8032 ) => Effect.Effect<OutDone, OutErr | EX, Env | RX>
8033 <OutElem, OutErr, OutDone, Env, EX, RX>(
8034 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8035 f: (o: OutElem) => Effect.Effect<void, EX, RX>
8036 ): Effect.Effect<OutDone, OutErr | EX, Env | RX>
8037} = dual(
8038 2,
8039 <OutElem, OutErr, OutDone, Env, EX, RX>(
8040 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8041 f: (o: OutElem) => Effect.Effect<void, EX, RX>
8042 ): Effect.Effect<OutDone, OutErr | EX, Env | RX> =>
8043 runWith(self, (pull) => Effect.forever(Effect.flatMap(pull, f), { disableYield: true }))
8044)
8045
8046/**
8047 * Runs a channel and applies an effectful predicate to each output element
8048 * until the predicate returns `false`.
8049 *
8050 * **Details**
8051 *
8052 * Returning `true` continues consuming the channel. Returning `false` stops
8053 * consumption early. The returned effect completes with `void`.
8054 *
8055 * @category running
8056 * @since 4.0.0
8057 */
8058export const runForEachWhile: {
8059 <OutElem, EX, RX>(
8060 f: (o: OutElem) => Effect.Effect<boolean, EX, RX>
8061 ): <OutErr, OutDone, Env>(
8062 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8063 ) => Effect.Effect<void, OutErr | EX, Env | RX>
8064 <OutElem, OutErr, OutDone, Env, EX, RX>(
8065 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8066 f: (o: OutElem) => Effect.Effect<boolean, EX, RX>
8067 ): Effect.Effect<void, OutErr | EX, Env | RX>
8068} = dual(
8069 2,
8070 <OutElem, OutErr, OutDone, Env, EX, RX>(
8071 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8072 f: (o: OutElem) => Effect.Effect<boolean, EX, RX>
8073 ): Effect.Effect<void, OutErr | EX, Env | RX> =>
8074 runWith(self, (pull) =>
8075 pull.pipe(
8076 Effect.flatMap(f),
8077 Effect.flatMap((cont) => (cont ? Effect.void : Cause.done())),
8078 Effect.forever({ disableYield: true })
8079 ))
8080)
8081
8082/**
8083 * Concatenates a channel's `Uint8Array` chunks into a single `Uint8Array`.
8084 *
8085 * **Gotchas**
8086 *
8087 * This materializes the full content in memory. The source channel must not
8088 * reuse or mutate emitted buffers, which are retained until collection completes.
8089 *
8090 * **Example** (Joining channel byte chunks)
8091 *
8092 * ```ts import.meta.vitest
8093 * import { Channel, Effect } from "effect"
8094 *
8095 * const channel = Channel.fromArray([
8096 * [new Uint8Array([1, 2])],
8097 * [new Uint8Array([3, 4])]
8098 * ] as const)
8099 *
8100 * const bytes = Effect.runSync(Channel.mkUint8Array(channel))
8101 * Array.from(bytes) // => [1, 2, 3, 4]
8102 * ```
8103 *
8104 * @category running
8105 * @since 4.0.0
8106 */
8107export const mkUint8Array = <OutErr, OutDone, Env>(
8108 self: Channel<Arr.NonEmptyReadonlyArray<Uint8Array>, OutErr, OutDone, unknown, unknown, unknown, Env>
8109): Effect.Effect<Uint8Array<ArrayBuffer>, OutErr, Env> =>
8110 Effect.map(
8111 runFold(
8112 self,
8113 (): {
8114 bytes: number
8115 readonly arrays: Array<Uint8Array>
8116 } => ({
8117 bytes: 0,
8118 arrays: []
8119 }),
8120 (acc, chunk) => {
8121 for (let i = 0; i < chunk.length; i++) {
8122 acc.bytes += chunk[i].length
8123 acc.arrays.push(chunk[i])
8124 }
8125 return acc
8126 }
8127 ),
8128 ({ arrays, bytes }) => {
8129 const result = new Uint8Array(bytes)
8130 let offset = 0
8131 for (let i = 0; i < arrays.length; i++) {
8132 const array = arrays[i]
8133 result.set(array, offset)
8134 offset += array.length
8135 }
8136 return result
8137 }
8138 )
8139
8140/**
8141 * Runs a channel and collects all output elements into an array.
8142 *
8143 * **Example** (Collecting channel output)
8144 *
8145 * ```ts import.meta.vitest
8146 * import { Channel, Data, Effect } from "effect"
8147 *
8148 * class CollectError extends Data.TaggedError("CollectError")<{
8149 * readonly reason: string
8150 * }> {}
8151 *
8152 * // Create a channel with elements
8153 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5])
8154 *
8155 * // Collect all elements into an array
8156 * const collectEffect = Channel.runCollect(numbersChannel)
8157 *
8158 * Effect.runSync(collectEffect) // => [1, 2, 3, 4, 5]
8159 * ```
8160 *
8161 * @category running
8162 * @since 2.0.0
8163 */
8164export const runCollect = <OutElem, OutErr, OutDone, Env>(
8165 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8166): Effect.Effect<Array<OutElem>, OutErr, Env> =>
8167 runFold(self, () => [] as Array<OutElem>, (acc, o) => {
8168 acc.push(o)
8169 return acc
8170 })
8171
8172/**
8173 * Runs a channel until the first output element is available, returning it in
8174 * an `Option`.
8175 *
8176 * **Details**
8177 *
8178 * Returns `Option.some` with the first output element, or `Option.none` if the
8179 * channel completes without emitting output.
8180 *
8181 * @category running
8182 * @since 4.0.0
8183 */
8184export const runHead = <OutElem, OutErr, OutDone, Env>(
8185 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8186): Effect.Effect<Option.Option<OutElem>, OutErr, Env> =>
8187 Effect.suspend(() => {
8188 let head = Option.none<OutElem>()
8189 return runWith(self, (pull) =>
8190 pull.pipe(
8191 Effect.asSome,
8192 Effect.flatMap((head_) => {
8193 head = head_
8194 return Cause.done()
8195 })
8196 ), () => Effect.succeed(head))
8197 })
8198
8199/**
8200 * Runs a channel to completion and returns the last output element in an
8201 * `Option`.
8202 *
8203 * **Details**
8204 *
8205 * Returns `Option.some` with the last emitted element, or `Option.none` if the
8206 * channel completes without emitting output.
8207 *
8208 * @category running
8209 * @since 4.0.0
8210 */
8211export const runLast = <OutElem, OutErr, OutDone, Env>(
8212 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8213): Effect.Effect<Option.Option<OutElem>, OutErr, Env> =>
8214 Effect.suspend(() => {
8215 const absent = Symbol() // Prevent boxing
8216 let last: typeof absent | OutElem = absent
8217 return runWith(
8218 self,
8219 (pull) =>
8220 Effect.forever(
8221 Effect.flatMap(pull, (item) => {
8222 last = item
8223 return Effect.void
8224 }),
8225 { disableYield: true }
8226 ),
8227 () => last === absent ? Effect.succeedNone : Effect.succeedSome(last)
8228 )
8229 })
8230
8231/**
8232 * Runs a channel and folds over all output elements with an accumulator.
8233 *
8234 * **Example** (Folding channel output)
8235 *
8236 * ```ts import.meta.vitest
8237 * import { Channel, Data, Effect } from "effect"
8238 *
8239 * class FoldError extends Data.TaggedError("FoldError")<{
8240 * readonly operation: string
8241 * }> {}
8242 *
8243 * // Create a channel with numbers
8244 * const numbersChannel = Channel.fromIterable([1, 2, 3, 4, 5])
8245 *
8246 * // Fold to calculate sum
8247 * const sumEffect = Channel.runFold(numbersChannel, () => 0, (acc, n) => acc + n)
8248 *
8249 * Effect.runSync(sumEffect) // => 15
8250 * ```
8251 *
8252 * @category running
8253 * @since 4.0.0
8254 */
8255export const runFold: {
8256 <Z, OutElem>(
8257 initial: LazyArg<Z>,
8258 f: (acc: Z, o: OutElem) => Z
8259 ): <OutErr, OutDone, Env>(
8260 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8261 ) => Effect.Effect<Z, OutErr, Env>
8262 <OutElem, OutErr, OutDone, Env, Z>(
8263 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8264 initial: LazyArg<Z>,
8265 f: (acc: Z, o: OutElem) => Z
8266 ): Effect.Effect<Z, OutErr, Env>
8267} = dual(3, <OutElem, OutErr, OutDone, Env, Z>(
8268 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8269 initial: LazyArg<Z>,
8270 f: (acc: Z, o: OutElem) => Z
8271): Effect.Effect<Z, OutErr, Env> =>
8272 Effect.suspend(() => {
8273 let state = initial()
8274 return runWith(
8275 self,
8276 (pull) =>
8277 Effect.whileLoop({
8278 while: constTrue,
8279 body: () => pull,
8280 step: (value) => {
8281 state = f(state, value)
8282 }
8283 }),
8284 () => Effect.succeed(state)
8285 )
8286 }))
8287
8288/**
8289 * Runs a channel and effectfully folds all output elements with an accumulator.
8290 *
8291 * **When to use**
8292 *
8293 * Use when folding channel output needs effects, services, or an additional
8294 * failure channel during accumulation.
8295 *
8296 * **Details**
8297 *
8298 * The initial accumulator is evaluated lazily. Each output element is passed to
8299 * the effectful accumulator function. The returned effect succeeds with the
8300 * final accumulator value.
8301 *
8302 * @category running
8303 * @since 4.0.0
8304 */
8305export const runFoldEffect: {
8306 <OutElem, Z, E, R>(
8307 initial: LazyArg<Z>,
8308 f: (acc: Z, o: OutElem) => Effect.Effect<Z, E, R>
8309 ): <OutErr, OutDone, Env>(
8310 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8311 ) => Effect.Effect<Z, OutErr | E, Env | R>
8312 <OutElem, OutErr, OutDone, Env, Z, E, R>(
8313 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8314 initial: LazyArg<Z>,
8315 f: (acc: Z, o: OutElem) => Effect.Effect<Z, E, R>
8316 ): Effect.Effect<Z, OutErr | E, Env | R>
8317} = dual(3, <OutElem, OutErr, OutDone, Env, Z, E, R>(
8318 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8319 initial: LazyArg<Z>,
8320 f: (acc: Z, o: OutElem) => Effect.Effect<Z, E, R>
8321): Effect.Effect<Z, OutErr | E, Env | R> =>
8322 Effect.suspend(() => {
8323 let state = initial()
8324 return runWith(
8325 self,
8326 (pull) =>
8327 Effect.whileLoop({
8328 while: constTrue,
8329 body: constant(pull.pipe(
8330 Effect.flatMap((o) => f(state, o)),
8331 Effect.map((s) => {
8332 state = s
8333 })
8334 )),
8335 step: constVoid
8336 }),
8337 () => Effect.succeed(state)
8338 )
8339 }))
8340
8341/**
8342 * Converts a channel to a scoped `Pull` for low-level consumption.
8343 *
8344 * **Details**
8345 *
8346 * The effect requires a `Scope`. The returned pull should be consumed only
8347 * while that scope remains open. Pulls are serialized so only one pull is
8348 * evaluated at a time.
8349 *
8350 * **Example** (Converting channels to pulls)
8351 *
8352 * ```ts import.meta.vitest
8353 * import { Channel, Data, Effect } from "effect"
8354 *
8355 * class PullError extends Data.TaggedError("PullError")<{
8356 * readonly step: string
8357 * }> {}
8358 *
8359 * // Create a channel
8360 * const numbersChannel = Channel.fromIterable([1, 2, 3])
8361 *
8362 * const program = Effect.scoped(Effect.gen(function*() {
8363 * const pull = yield* Channel.toPull(numbersChannel)
8364 * return [yield* pull, yield* pull, yield* pull]
8365 * }))
8366 * await Effect.runPromise(program) // => [1, 2, 3]
8367 * ```
8368 *
8369 * @category destructors
8370 * @since 2.0.0
8371 */
8372export const toPull: <OutElem, OutErr, OutDone, Env>(
8373 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8374) => Effect.Effect<
8375 Pull.Pull<OutElem, OutErr, OutDone>,
8376 never,
8377 Env | Scope.Scope
8378> = Effect.fnUntraced(
8379 function*<OutElem, OutErr, OutDone, Env>(
8380 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8381 ) {
8382 const semaphore = Semaphore.makeUnsafe(1)
8383 const context = yield* Effect.context<Env | Scope.Scope>()
8384 const scope = Context.get(context, Scope.Scope)
8385 const pull = yield* toTransform(self)(Cause.done(), scope)
8386 return pull.pipe(
8387 Effect.provideContext(context),
8388 semaphore.withPermits(1)
8389 )
8390 },
8391 // ensure errors are redirected to the pull effect
8392 Effect.catchCause((cause) => Effect.succeed(Effect.failCause(cause)))
8393) as any
8394
8395/**
8396 * Converts a channel to a Pull within an existing scope.
8397 *
8398 * **Example** (Converting channels to scoped pulls)
8399 *
8400 * ```ts import.meta.vitest
8401 * import { Channel, Data, Effect, Scope } from "effect"
8402 *
8403 * class ScopedPullError extends Data.TaggedError("ScopedPullError")<{
8404 * readonly reason: string
8405 * }> {}
8406 *
8407 * // Create a channel
8408 * const numbersChannel = Channel.fromIterable([1, 2, 3])
8409 *
8410 * // Convert to Pull with explicit scope
8411 * const scopedPullEffect = Effect.gen(function*() {
8412 * const scope = yield* Effect.scope
8413 * const pull = yield* Channel.toPullScoped(numbersChannel, scope)
8414 * return [yield* pull, yield* pull, yield* pull]
8415 * })
8416 * await Effect.runPromise(Effect.scoped(scopedPullEffect)) // => [1, 2, 3]
8417 * ```
8418 *
8419 * @category destructors
8420 * @since 4.0.0
8421 */
8422export const toPullScoped = <OutElem, OutErr, OutDone, Env>(
8423 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8424 scope: Scope.Scope
8425): Effect.Effect<Pull.Pull<OutElem, OutErr, OutDone, Env>, never, Env> => toTransform(self)(Cause.done(), scope)
8426
8427/**
8428 * Runs a channel and offers each output element into a queue.
8429 *
8430 * **Details**
8431 *
8432 * When the channel completes, the queue is ended. When the channel fails, the
8433 * queue is failed with the channel's cause. The returned effect itself
8434 * completes with `void`.
8435 *
8436 * @category destructors
8437 * @since 4.0.0
8438 */
8439export const runIntoQueue: {
8440 <OutElem, OutErr>(queue: Queue.Queue<OutElem, OutErr | Cause.Done>): <OutDone, Env>(
8441 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8442 ) => Effect.Effect<void, never, Env>
8443 <OutElem, OutErr, OutDone, Env>(
8444 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8445 queue: Queue.Queue<OutElem, OutErr | Cause.Done>
8446 ): Effect.Effect<void, never, Env>
8447} = dual(
8448 (args) => isChannel(args[0]),
8449 <OutElem, OutErr, OutDone, Env>(
8450 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8451 queue: Queue.Queue<OutElem, OutErr | Cause.Done>
8452 ): Effect.Effect<void, never, Env> =>
8453 Effect.uninterruptibleMask((restore) =>
8454 runForEach(self, (value) => Queue.offer(queue, value)).pipe(
8455 restore,
8456 Effect.exit,
8457 Effect.flatMap((exit) => {
8458 if (Exit.isSuccess(exit)) {
8459 Queue.endUnsafe(queue)
8460 } else {
8461 Queue.failCauseUnsafe(queue, exit.cause)
8462 }
8463 return Effect.void
8464 })
8465 )
8466 )
8467)
8468
8469/**
8470 * Runs a channel that emits non-empty arrays and offers each array element into
8471 * a queue.
8472 *
8473 * **Details**
8474 *
8475 * When the channel completes, the queue is ended. When the channel fails, the
8476 * queue is failed with the channel's cause. The returned effect itself
8477 * completes with `void`.
8478 *
8479 * @category destructors
8480 * @since 4.0.0
8481 */
8482export const runIntoQueueArray: {
8483 <OutElem, OutErr>(queue: Queue.Queue<OutElem, OutErr | Cause.Done>): <OutDone, Env>(
8484 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>
8485 ) => Effect.Effect<void, never, Env>
8486 <OutElem, OutErr, OutDone, Env>(
8487 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8488 queue: Queue.Queue<OutElem, OutErr | Cause.Done>
8489 ): Effect.Effect<void, never, Env>
8490} = dual(
8491 (args) => isChannel(args[0]),
8492 <OutElem, OutErr, OutDone, Env>(
8493 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8494 queue: Queue.Queue<OutElem, OutErr | Cause.Done>
8495 ): Effect.Effect<void, never, Env> =>
8496 Effect.uninterruptibleMask((restore) =>
8497 runForEach(self, (value) => Queue.offerAll(queue, value)).pipe(
8498 restore,
8499 Effect.exit,
8500 Effect.flatMap((exit) => {
8501 if (Exit.isSuccess(exit)) {
8502 Queue.endUnsafe(queue)
8503 } else {
8504 Queue.failCauseUnsafe(queue, exit.cause)
8505 }
8506 return Effect.void
8507 })
8508 )
8509 )
8510)
8511
8512/**
8513 * Creates a scoped queue and forks the channel to feed it for concurrent
8514 * consumption.
8515 *
8516 * **Details**
8517 *
8518 * Output elements are offered to the queue. Channel completion and failure are
8519 * signaled through the queue. The queue is shut down when the surrounding scope
8520 * closes.
8521 *
8522 * **Example** (Converting channels to queues)
8523 *
8524 * ```ts import.meta.vitest
8525 * import { Channel, Data, Effect, Queue } from "effect"
8526 *
8527 * class QueueError extends Data.TaggedError("QueueError")<{
8528 * readonly operation: string
8529 * }> {}
8530 *
8531 * // Create a channel with data
8532 * const dataChannel = Channel.fromIterable([1, 2, 3, 4, 5])
8533 *
8534 * // Convert to queue for concurrent processing
8535 * const program = Effect.scoped(Effect.gen(function*() {
8536 * const queue = yield* Channel.toQueue(dataChannel, { capacity: 32 })
8537 * return yield* Queue.takeBetween(queue, 5, 5)
8538 * }))
8539 * await Effect.runPromise(program) // => [1, 2, 3, 4, 5]
8540 * ```
8541 *
8542 * @category destructors
8543 * @since 2.0.0
8544 */
8545export const toQueue: {
8546 (
8547 options: {
8548 readonly capacity: "unbounded"
8549 } | {
8550 readonly capacity: number
8551 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8552 }
8553 ): <OutElem, OutErr, OutDone, Env>(
8554 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8555 ) => Effect.Effect<Queue.Dequeue<OutElem, OutErr | Cause.Done>, never, Env | Scope.Scope>
8556 <OutElem, OutErr, OutDone, Env>(
8557 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8558 options: {
8559 readonly capacity: "unbounded"
8560 } | {
8561 readonly capacity: number
8562 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8563 }
8564 ): Effect.Effect<Queue.Dequeue<OutElem, OutErr | Cause.Done>, never, Env | Scope.Scope>
8565} = dual(
8566 (args) => isChannel(args[0]),
8567 Effect.fnUntraced(function*<OutElem, OutErr, OutDone, Env>(
8568 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8569 options: {
8570 readonly capacity: "unbounded"
8571 } | {
8572 readonly capacity: number
8573 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8574 }
8575 ) {
8576 const scope = yield* Effect.scope
8577 const queue = yield* Queue.make<OutElem, OutErr | Cause.Done>({
8578 capacity: typeof options.capacity === "number" ? options.capacity : undefined,
8579 strategy: typeof options.capacity === "number" ? options.strategy : undefined
8580 })
8581 yield* Scope.addFinalizer(scope, Queue.shutdown(queue))
8582 yield* Effect.forkIn(runIntoQueue(self, queue), scope)
8583 return queue
8584 })
8585)
8586
8587/**
8588 * Creates a scoped queue and forks an array-emitting channel to feed it.
8589 *
8590 * **Details**
8591 *
8592 * Each element inside emitted non-empty arrays is offered to the queue. Channel
8593 * completion and failure are signaled through the queue. The queue is shut down
8594 * when the surrounding scope closes.
8595 *
8596 * @category destructors
8597 * @since 4.0.0
8598 */
8599export const toQueueArray: {
8600 (
8601 options: {
8602 readonly capacity: "unbounded"
8603 } | {
8604 readonly capacity: number
8605 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8606 }
8607 ): <OutElem, OutErr, OutDone, Env>(
8608 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>
8609 ) => Effect.Effect<Queue.Dequeue<OutElem, OutErr | Cause.Done>, never, Env | Scope.Scope>
8610 <OutElem, OutErr, OutDone, Env>(
8611 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8612 options: {
8613 readonly capacity: "unbounded"
8614 } | {
8615 readonly capacity: number
8616 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8617 }
8618 ): Effect.Effect<Queue.Dequeue<OutElem, OutErr | Cause.Done>, never, Env | Scope.Scope>
8619} = dual(
8620 (args) => isChannel(args[0]),
8621 Effect.fnUntraced(function*<OutElem, OutErr, OutDone, Env>(
8622 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8623 options: {
8624 readonly capacity: "unbounded"
8625 } | {
8626 readonly capacity: number
8627 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8628 }
8629 ) {
8630 const scope = yield* Effect.scope
8631 const queue = yield* Queue.make<OutElem, OutErr | Cause.Done>({
8632 capacity: typeof options.capacity === "number" ? options.capacity : undefined,
8633 strategy: typeof options.capacity === "number" ? options.strategy : undefined
8634 })
8635 yield* Scope.addFinalizer(scope, Queue.shutdown(queue))
8636 yield* Effect.forkIn(runIntoQueueArray(self, queue), scope)
8637 return queue
8638 })
8639)
8640
8641/**
8642 * Converts a channel to a PubSub for concurrent consumption.
8643 *
8644 * **Details**
8645 *
8646 * `shutdownOnEnd` indicates whether the PubSub should be shut down when the
8647 * channel ends. By default this is `true`.
8648 *
8649 * @category destructors
8650 * @since 2.0.0
8651 */
8652export const toPubSub: {
8653 (
8654 options: {
8655 readonly capacity: "unbounded"
8656 readonly replay?: number | undefined
8657 readonly shutdownOnEnd?: boolean | undefined
8658 } | {
8659 readonly capacity: number
8660 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8661 readonly replay?: number | undefined
8662 readonly shutdownOnEnd?: boolean | undefined
8663 }
8664 ): <OutElem, OutErr, OutDone, Env>(
8665 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8666 ) => Effect.Effect<PubSub.PubSub<OutElem>, never, Env | Scope.Scope>
8667 <OutElem, OutErr, OutDone, Env>(
8668 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8669 options: {
8670 readonly capacity: "unbounded"
8671 readonly replay?: number | undefined
8672 readonly shutdownOnEnd?: boolean | undefined
8673 } | {
8674 readonly capacity: number
8675 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8676 readonly replay?: number | undefined
8677 readonly shutdownOnEnd?: boolean | undefined
8678 }
8679 ): Effect.Effect<PubSub.PubSub<OutElem>, never, Env | Scope.Scope>
8680} = dual(
8681 2,
8682 Effect.fnUntraced(function*<OutElem, OutErr, OutDone, Env>(
8683 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8684 options: {
8685 readonly capacity: "unbounded"
8686 readonly replay?: number | undefined
8687 readonly shutdownOnEnd?: boolean | undefined
8688 } | {
8689 readonly capacity: number
8690 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8691 readonly replay?: number | undefined
8692 readonly shutdownOnEnd?: boolean | undefined
8693 }
8694 ) {
8695 const pubsub = yield* makePubSub<OutElem>(options)
8696 yield* Effect.forkScoped(runIntoPubSub(self, pubsub, {
8697 shutdownOnEnd: options.shutdownOnEnd !== false
8698 }))
8699 return pubsub
8700 })
8701)
8702
8703/**
8704 * Runs a channel and publishes each output element to a `PubSub`.
8705 *
8706 * **Details**
8707 *
8708 * The channel's output values are published as individual PubSub messages. Use
8709 * `options.shutdownOnEnd` to shut down the PubSub when channel execution ends.
8710 *
8711 * @category destructors
8712 * @since 4.0.0
8713 */
8714export const runIntoPubSub: {
8715 <OutElem>(
8716 pubsub: PubSub.PubSub<OutElem>,
8717 options?: {
8718 readonly shutdownOnEnd?: boolean | undefined
8719 } | undefined
8720 ): <OutErr, OutDone, Env>(
8721 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>
8722 ) => Effect.Effect<void, never, Env>
8723 <OutElem, OutErr, OutDone, Env>(
8724 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8725 pubsub: PubSub.PubSub<OutElem>,
8726 options?: {
8727 readonly shutdownOnEnd?: boolean | undefined
8728 } | undefined
8729 ): Effect.Effect<void, never, Env>
8730} = dual(
8731 (args) => isChannel(args[0]),
8732 <OutElem, OutErr, OutDone, Env>(
8733 self: Channel<OutElem, OutErr, OutDone, unknown, unknown, unknown, Env>,
8734 pubsub: PubSub.PubSub<OutElem>,
8735 options?: {
8736 readonly shutdownOnEnd?: boolean | undefined
8737 } | undefined
8738 ) =>
8739 runForEach(self, (value) => PubSub.publish(pubsub, value)).pipe(
8740 options?.shutdownOnEnd === true ? Effect.ensuring(PubSub.shutdown(pubsub)) : identity_
8741 )
8742)
8743
8744const makePubSub = <A>(
8745 options: {
8746 readonly capacity: "unbounded"
8747 readonly replay?: number | undefined
8748 } | {
8749 readonly capacity: number
8750 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8751 readonly replay?: number | undefined
8752 }
8753) =>
8754 Effect.acquireRelease(
8755 options.capacity === "unbounded"
8756 ? PubSub.unbounded<A>(options)
8757 : options.strategy === "dropping"
8758 ? PubSub.dropping<A>(options)
8759 : options.strategy === "sliding"
8760 ? PubSub.sliding<A>(options)
8761 : PubSub.bounded<A>(options),
8762 PubSub.shutdown
8763 )
8764
8765/**
8766 * Converts an array-emitting channel to a scoped `PubSub` for concurrent
8767 * consumption.
8768 *
8769 * **Details**
8770 *
8771 * Each element inside emitted non-empty arrays is published as an individual
8772 * PubSub message. `shutdownOnEnd` indicates whether the PubSub should be shut
8773 * down when the channel ends. By default this is `true`.
8774 *
8775 * @category destructors
8776 * @since 4.0.0
8777 */
8778export const toPubSubArray: {
8779 (
8780 options: {
8781 readonly capacity: "unbounded"
8782 readonly replay?: number | undefined
8783 readonly shutdownOnEnd?: boolean | undefined
8784 } | {
8785 readonly capacity: number
8786 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8787 readonly replay?: number | undefined
8788 readonly shutdownOnEnd?: boolean | undefined
8789 }
8790 ): <OutElem, OutErr, OutDone, Env>(
8791 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>
8792 ) => Effect.Effect<PubSub.PubSub<OutElem>, never, Env | Scope.Scope>
8793 <OutElem, OutErr, OutDone, Env>(
8794 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8795 options: {
8796 readonly capacity: "unbounded"
8797 readonly replay?: number | undefined
8798 readonly shutdownOnEnd?: boolean | undefined
8799 } | {
8800 readonly capacity: number
8801 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8802 readonly replay?: number | undefined
8803 readonly shutdownOnEnd?: boolean | undefined
8804 }
8805 ): Effect.Effect<PubSub.PubSub<OutElem>, never, Env | Scope.Scope>
8806} = dual(
8807 2,
8808 Effect.fnUntraced(function*<OutElem, OutErr, OutDone, Env>(
8809 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8810 options: {
8811 readonly capacity: "unbounded"
8812 readonly replay?: number | undefined
8813 readonly shutdownOnEnd?: boolean | undefined
8814 } | {
8815 readonly capacity: number
8816 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8817 readonly replay?: number | undefined
8818 readonly shutdownOnEnd?: boolean | undefined
8819 }
8820 ) {
8821 const pubsub = yield* makePubSub<OutElem>(options)
8822 yield* Effect.forkScoped(runIntoPubSubArray(self, pubsub, {
8823 shutdownOnEnd: options.shutdownOnEnd !== false
8824 }))
8825 return pubsub
8826 })
8827)
8828
8829/**
8830 * Runs an array-emitting channel and publishes each array element to a
8831 * `PubSub`.
8832 *
8833 * **Details**
8834 *
8835 * Each element inside emitted non-empty arrays is published as an individual
8836 * PubSub message. Use `options.shutdownOnEnd` to shut down the PubSub when
8837 * channel execution ends.
8838 *
8839 * @category destructors
8840 * @since 4.0.0
8841 */
8842export const runIntoPubSubArray: {
8843 <OutElem>(
8844 pubsub: PubSub.PubSub<OutElem>,
8845 options?: {
8846 readonly shutdownOnEnd?: boolean | undefined
8847 } | undefined
8848 ): <OutErr, OutDone, Env>(
8849 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>
8850 ) => Effect.Effect<OutDone, OutErr, Env>
8851 <OutElem, OutErr, OutDone, Env>(
8852 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8853 pubsub: PubSub.PubSub<OutElem>,
8854 options?: {
8855 readonly shutdownOnEnd?: boolean | undefined
8856 } | undefined
8857 ): Effect.Effect<OutDone, OutErr, Env>
8858} = dual(
8859 (args) => isChannel(args[0]),
8860 <OutElem, OutErr, OutDone, Env>(
8861 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8862 pubsub: PubSub.PubSub<OutElem>,
8863 options?: {
8864 readonly shutdownOnEnd?: boolean | undefined
8865 } | undefined
8866 ) =>
8867 runForEach(self, (value) => PubSub.publishAll(pubsub, value)).pipe(
8868 options?.shutdownOnEnd === true ? Effect.ensuring(PubSub.shutdown(pubsub)) : identity_
8869 )
8870)
8871
8872/**
8873 * Converts a channel to a scoped `PubSub` of `Take` values.
8874 *
8875 * **Details**
8876 *
8877 * Emitted non-empty arrays are published as output `Take` values. When the
8878 * channel ends, the `PubSub` is ended with its final `Exit`, so every
8879 * subscriber, including one that subscribes later, observes completion or
8880 * failure once it has consumed its buffered values.
8881 *
8882 * @category destructors
8883 * @since 4.0.0
8884 */
8885export const toPubSubTake: {
8886 (
8887 options: {
8888 readonly capacity: "unbounded"
8889 readonly replay?: number | undefined
8890 } | {
8891 readonly capacity: number
8892 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8893 readonly replay?: number | undefined
8894 }
8895 ): <OutElem, OutErr, OutDone, Env>(
8896 self: Channel<Arr.NonEmptyReadonlyArray<OutDone>, OutErr, OutDone, unknown, unknown, unknown, Env>
8897 ) => Effect.Effect<
8898 PubSub.PubSub<Take.Take<OutElem, OutErr, OutDone>>,
8899 never,
8900 Env | Scope.Scope
8901 >
8902 <OutElem, OutErr, OutDone, Env>(
8903 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8904 options: {
8905 readonly capacity: "unbounded"
8906 readonly replay?: number | undefined
8907 } | {
8908 readonly capacity: number
8909 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8910 readonly replay?: number | undefined
8911 }
8912 ): Effect.Effect<
8913 PubSub.PubSub<Take.Take<OutElem, OutErr, OutDone>>,
8914 never,
8915 Env | Scope.Scope
8916 >
8917} = dual(
8918 2,
8919 Effect.fnUntraced(function*<OutElem, OutErr, OutDone, Env>(
8920 self: Channel<Arr.NonEmptyReadonlyArray<OutElem>, OutErr, OutDone, unknown, unknown, unknown, Env>,
8921 options: {
8922 readonly capacity: "unbounded"
8923 readonly replay?: number | undefined
8924 } | {
8925 readonly capacity: number
8926 readonly strategy?: "dropping" | "sliding" | "suspend" | undefined
8927 readonly replay?: number | undefined
8928 }
8929 ) {
8930 const pubsub = yield* makePubSub<Take.Take<OutElem, OutErr, OutDone>>(options)
8931 yield* runForEach(self, (value) => PubSub.publish(pubsub, value)).pipe(
8932 Effect.onExit((exit) => PubSub.end(pubsub, exit)),
8933 Effect.forkScoped
8934 )
8935 return pubsub
8936 })
8937)