Hyperlinkv0.8.0-beta.28

Hyperlink

Hyperlink.runForEachTagScopedconstsrc/Hyperlink.ts:5874
<A extends TaggedEvent, Cases extends TagHandlers<A, unknown, unknown>>(
  handlers: Cases
): (
  self: Stream.Stream<A>
) => Effect.Effect<
  Fiber.Fiber<void, HandlersError<Cases>>,
  never,
  HandlersContext<Cases> | Scope.Scope
>
<A extends TaggedEvent, const K extends A["_tag"], E, R>(
  tag: K,
  f: (
    event: Extract<A, { readonly _tag: K }>
  ) => Effect.Effect<void, E, R>
): (
  self: Stream.Stream<A>
) => Effect.Effect<Fiber.Fiber<void, E>, never, R | Scope.Scope>
<A extends TaggedEvent, const K extends A["_tag"], E, R>(
  self: Stream.Stream<A>,
  tag: K,
  f: (
    event: Extract<A, { readonly _tag: K }>
  ) => Effect.Effect<void, E, R>
): Effect.Effect<Fiber.Fiber<void, E>, never, R | Scope.Scope>
<A extends TaggedEvent, Cases extends TagHandlers<A, unknown, unknown>>(
  self: Stream.Stream<A>,
  handlers: Cases
): Effect.Effect<
  Fiber.Fiber<void, HandlersError<Cases>>,
  never,
  HandlersContext<Cases> | Scope.Scope
>

Like runForEachTag, but non-blocking: it forks the consumer into the enclosing Scope (Effect.forkScoped) and hands back the Fiber, instead of running the stream to completion. This is the common case for live observation — start watching the events/status/metrics of a queue (or any tagged stream) in the background while the rest of your program runs; the fiber is interrupted automatically when the scope closes (the Effect.scoped block ends, or the owning layer is torn down), so you never track or kill it.

Each handler's error surfaces in the fiber's failure channel (not the caller's). If you instead want to block until a (finite) stream drains — e.g. in a test — use runForEachTag and yield* it directly, or Fiber.join the fiber this returns.

// no manual `Effect.forkScoped` — observation runs in the background, bound to the scope
yield* queue.events.pipe(Hyperlink.runForEachTagScoped({
  Completed: ({ entry }) => Effect.log(`done ${entry.entryId}`),
  Failed:    ({ cause }) => Effect.logError("job failed", cause),
}))
reactivityrunForEachTagScopeEffect.forkScopedFiber
Source src/Hyperlink.ts:587446 lines
export const runForEachTagScoped: {
  // ── data-last (pipeable) ──
  <A extends TaggedEvent, Cases extends TagHandlers<A, unknown, unknown>>(
    handlers: Cases,
  ): (
    self: Stream.Stream<A>,
  ) => Effect.Effect<
    Fiber.Fiber<void, HandlersError<Cases>>,
    never,
    HandlersContext<Cases> | Scope.Scope
  >;
  <A extends TaggedEvent, const K extends A["_tag"], E, R>(
    tag: K,
    f: (event: Extract<A, { readonly _tag: K }>) => Effect.Effect<void, E, R>,
  ): (
    self: Stream.Stream<A>,
  ) => Effect.Effect<Fiber.Fiber<void, E>, never, R | Scope.Scope>;
  // ── data-first ──
  <A extends TaggedEvent, const K extends A["_tag"], E, R>(
    self: Stream.Stream<A>,
    tag: K,
    f: (event: Extract<A, { readonly _tag: K }>) => Effect.Effect<void, E, R>,
  ): Effect.Effect<Fiber.Fiber<void, E>, never, R | Scope.Scope>;
  <A extends TaggedEvent, Cases extends TagHandlers<A, unknown, unknown>>(
    self: Stream.Stream<A>,
    handlers: Cases,
  ): Effect.Effect<
    Fiber.Fiber<void, HandlersError<Cases>>,
    never,
    HandlersContext<Cases> | Scope.Scope
  >;
} = Fn.dual(
  (args) => Stream.isStream(args[0]),
  <E, R>(
    self: Stream.Stream<TaggedEvent>,
    tagOrHandlers: string | TagHandlers<TaggedEvent, E, R>,
    f?: (event: TaggedEvent) => Effect.Effect<void, E, R>,
  ): Effect.Effect<Fiber.Fiber<void, E>, never, R | Scope.Scope> =>
    // Delegate to the blocking consumer, then fork it into the enclosing scope. The two-arg
    // (single-tag) and one-arg (handler-map) shapes are dispatched by `runForEachTag` itself.
    Effect.forkScoped(
      f === undefined
        ? runForEachTag(self, tagOrHandlers as TagHandlers<TaggedEvent, E, R>)
        : runForEachTag(self, tagOrHandlers as string, f),
    ),
);