Skip to content

API Overview

SymbolPurposeExecution modeCommon gotcha
stream()Create cold streamLazyReturn one teardown function
pipe()Compose operatorsLazySource is first argument
of() / from()Convert known valuesSync / mixedfrom() promise cannot be aborted
fromEvent()Adapt event targetAsyncUnsubscribe removes listener
interval() / timer()Create timed valuesAsyncUse take() or unsubscribe for intervals
map() / filter() / scan()Transform valuesSyncCallback throws terminate stream
switchMap() / mergeMap() / concatMap()Flatten streamsMixedconcatMap() queue is bounded
take() / takeUntil()Stop valuesMixedNotifier emission completes output
debounce() / timeout() / retry()Control time and failuresAsynctimeout() measures inactivity
merge() / concat() / combineLatest()Combine streamsMixedcombineLatest() waits for every source
toArray() / first() / last()Consume finite valuesAsyncBound toArray() with maxItems
toAsyncIterable()Use for awaitAsyncCapacity and overflow required
createChannel()Imperative multicast boundarySyncDispose to complete subscribers

Package Entry Point

ImportPurpose
@vielzeug/fluxCore streams, operators, consumers, errors, and types
@vielzeug/flux/asynctoAsyncIterable() only
@vielzeug/flux/subjectscreateChannel() and channel types
@vielzeug/flux/rippleRipple signal adapters
@vielzeug/flux/courierCourier query and SSE adapters
@vielzeug/flux/heraldHerald bus adapters
@vielzeug/flux/pulsePulse event and presence adapters

Core

stream()

ts
stream<T>(producer: Producer<T>): Stream<T>

Creates cold reusable work. Producer runs once for every subscription.

ParameterTypeDescription
producerProducer<T>Emits through sink and returns optional teardown

Returns: Stream<T>.

ts
import { stream } from '@vielzeug/flux';

const ticks = stream<number>((sink) => {
  const id = setInterval(() => sink.next(Date.now()), 1_000);
  return () => clearInterval(id);
});

pipe()

ts
pipe<Input, Operators>(source: Stream<Input>, ...operators: Operators): Stream<Output>

Applies operators left to right while inferring output value type.

ParameterTypeDescription
sourceStream<Input>Source stream
operatorsOperator[]Operators applied in order

Returns: transformed Stream<Output>.

ts
import { map, of, pipe } from '@vielzeug/flux';

const labels = pipe(of(1, 2), map((value) => `#${value}`));

Creation

of()

ts
of<T>(...values: T[]): Stream<T>

Emits every value synchronously, then completes.

ts
import { of } from '@vielzeug/flux';

of(1, 2, 3).subscribe(console.log);

from()

ts
from<T>(source: Iterable<T> | AsyncIterable<T> | Promise<T>): Stream<T>

Converts iterable, async iterable, or promise into a stream. Cancellation stops iterable consumption and calls return() when available.

ts
import { from } from '@vielzeug/flux';

from(Promise.resolve('ready')).subscribe({ error: console.error, next: console.log });

fromEvent()

ts
fromEvent<T = Event>(target, type: string): Stream<T>

Emits target events until subscription ends.

ts
import { fromEvent } from '@vielzeug/flux';

fromEvent<MouseEvent>(document, 'click').subscribe(console.log);

interval()

ts
interval(options: IntervalOptions): Stream<number>

Emits incrementing values starting at zero.

OptionTypeDescription
everynumberNon-negative interval duration in milliseconds

timer()

ts
timer(options: TimerOptions): Stream<number>

Emits zero after delay; optionally continues at interval.

OptionTypeDescription
delaynumberNon-negative initial delay in milliseconds
intervalnumberOptional non-negative repeat duration

Transformation Operators

map()

ts
map<A, B>(project: (value: A) => B): Operator<A, B>

Maps every value. A thrown callback error terminates output.


filter()

ts
filter<T>(predicate: (value: T) => boolean): Operator<T, T>

Forwards values matching predicate.


scan()

ts
scan<T, A>(reducer: (state: A, value: T) => A, initial: A): Operator<T, A>

Emits accumulated state after every source value.


switchMap()

ts
switchMap<A, B>(project: (value: A) => Stream<B>): Operator<A, B>

Cancels previous inner stream when source emits.


mergeMap()

ts
mergeMap<A, B>(project: (value: A) => Stream<B>): Operator<A, B>

Runs every inner stream concurrently.


concatMap()

ts
concatMap<A, B>(project: (value: A) => Stream<B>, options: ConcatMapOptions): Operator<A, B>

Runs inner streams in order. Exceeding capacity errors output.

OptionTypeDescription
capacitynumberPositive maximum queued source values

Control Operators

take()

ts
take<T>(count: number): Operator<T, T>

Forwards count values, cancels upstream, then completes. Count must be non-negative integer.


takeUntil()

ts
takeUntil<T>(notifier: AbortSignal | Stream<unknown>): Operator<T, T>

Completes when notifier aborts or emits.


debounce()

ts
debounce<T>(options: DebounceOptions): Operator<T, T>

Emits latest value after configured silence. Pending value flushes on source completion.

OptionTypeDescription
fornumberNon-negative silence duration in milliseconds

timeout()

ts
timeout<T>(options: TimeoutOptions): Operator<T, T>

Errors with FluxTimeoutError when source is silent too long.

OptionTypeDescription
afternumberNon-negative inactivity duration in milliseconds

retry()

ts
retry<T>(options: RetryOptions): Operator<T, T>

Resubscribes after source errors until attempts are exhausted.

OptionTypeDescription
attemptsnumberNon-negative retry count
delaynumber | (attempt: number) => numberOptional delay or backoff function

Combination

merge()

ts
merge<T>(...sources: Stream<T>[]): Stream<T>

Forwards values from all sources and completes after every source completes.


concat()

ts
concat<T>(...sources: Stream<T>[]): Stream<T>

Subscribes to each source only after previous source completes.


combineLatest()

ts
combineLatest<T extends readonly Stream<unknown>[]>(...sources: T): Stream<{ [K in keyof T]: T[K] extends Stream<infer V> ? V : never }>

Emits latest tuple after every source emits once. Completes without emission when a source completes before first value.

Value Consumers

toArray()

ts
toArray<T>(source: Stream<T>, options: ToArrayOptions): Promise<T[]>

Collects finite output. Rejects on source error, abort, or maxItems overflow.

OptionTypeDescription
maxItemsnumberNon-negative maximum toArrayed values
signalAbortSignalOptional cancellation signal

first()

ts
first<T>(source: Stream<T>, options?: ValueOptions): Promise<T>

Resolves first value and cancels source. Rejects on source error or abort.


last()

ts
last<T>(source: Stream<T>, options?: ValueOptions): Promise<T | undefined>

Resolves last value on completion, or undefined when source completes empty.

Async Conversion

toAsyncIterable()

ts
toAsyncIterable<T>(source: Stream<T>, options: AsyncIterableOptions): AsyncIterable<T>

Converts push stream to async iterable with bounded queue.

OptionTypeDescription
capacitynumberPositive queue capacity
overflowOverflowPolicyerror, drop-oldest, or drop-newest
signalAbortSignalOptional cancellation signal

Channels

createChannel()

ts
createChannel<T>(options?: ChannelOptions<T>): Channel<T>

Creates imperative multicast boundary. Disposal completes subscribers.

initial + replay interaction: When initial is set and replay is omitted, replay defaults to 1 so the initial value is retained. Setting replay: 0 with initial throws RangeError — the initial value would be immediately dropped.

OptionTypeDescription
initialTOptional initial replay value
replaynumberNon-negative retained value count

Adapters

@vielzeug/flux/ripple

ts
fromSignal<T>(source: Readable<T>): Stream<T>
toSignal<T>(source: Stream<T>, options: ToSignalOptions<T>): SignalBinding<T>

fromSignal() emits current value first. toSignal() preserves final value then disposes binding when source completes, errors, or supplied signal aborts. On source error, toSignal() calls options.onError if provided (otherwise logs via console.error in dev — in production the log is stripped and the error is silently swallowed), then disposes — the signal freezes at its last value. Pass onError to surface source errors in production builds.

@vielzeug/flux/courier

ts
fromQuery<T extends { key: readonly unknown[]; fetch: (...args: never[]) => Promise<unknown> }>(
  cache: { getSnapshot<T>(key: readonly unknown[]): T | null; subscribe(key: readonly unknown[], listener: () => void): () => void },
  definition: T,
): Stream<AsyncState<Awaited<ReturnType<T['fetch']>>> | null>

fromQuery() infers data from definition.fetch and emits Courier-compatible AsyncState snapshots.

@vielzeug/flux/herald

ts
fromBus<T extends EventMap, K extends EventKey<T>>(bus: Bus<T>, event: K): Stream<T[K]>
toBus<T extends EventMap, K extends EventKey<T>>(bus: Bus<T>, event: K): Operator<T[K], T[K]>

@vielzeug/flux/pulse

ts
fromPulse<T extends MessageMap, K extends EventKey<T>>(pulse: Pulse<T>, event: K): Stream<T[K]>
fromPresence<T>(presence: PresenceChannel<T>): Stream<ReadonlyMap<string, T>>

Types

ts
type Teardown = () => void;

type Subscription = {
  [Symbol.dispose](): void;
  readonly closed: boolean;
  unsubscribe(): void;
};

type Observer<T> = {
  complete?: () => void;
  error?: (reason: unknown) => void;
  next: (value: T) => void;
};

type SubscribeOptions = { signal?: AbortSignal };

type Sink<T> = {
  complete(): void;
  error(reason: unknown): void;
  next(value: T): void;
};

type Producer<T> = (sink: Sink<T>, signal: AbortSignal) => Teardown | void;
type Operator<A = unknown, B = unknown> = (source: Stream<A>) => Stream<B>;

interface Stream<T> {
  subscribe(observer: Observer<T> | ((value: T) => void), options?: SubscribeOptions): Subscription;
}

type OverflowPolicy = 'drop-newest' | 'drop-oldest' | 'error';
type AsyncIterableOptions = { capacity: number; overflow: OverflowPolicy; signal?: AbortSignal };
type IntervalOptions = { every: number };
type TimerOptions = { delay: number; interval?: number };
type DebounceOptions = { for: number };
type TimeoutOptions = { after: number };
type ConcatMapOptions = { capacity: number };
type RetryOptions = { attempts: number; delay?: number | ((attempt: number) => number) };
type ToArrayOptions = { maxItems: number; signal?: AbortSignal };
type ValueOptions = { signal?: AbortSignal };
type ChannelOptions<T> = { initial?: T; replay?: number };
type ToSignalOptions<T> = { initial: T; onError?: (reason: unknown) => void; signal?: AbortSignal };
type SignalBinding<T> = {
  [Symbol.dispose](): void;
  readonly disposalSignal: AbortSignal;
  dispose(): void;
  readonly disposed: boolean;
  readonly signal: Readable<T>;
  readonly value: T;
};

Errors

FluxError

Base Flux error. Use instanceof FluxError to narrow unknown values.

FluxTimeoutError

Raised by timeout(). ms contains configured inactivity duration.