A structured, discriminable error.
-
code: Code
The discriminant. Narrow on this, never on
instanceof. -
data: Data
Structured payload supplied by the throw site.
-
toJSON(): SerializedFailure
Serializes to plain JSON so
console.log(JSON.stringify(failure))is not{}.
The exported value: builders (Stream.from, Stream.unfold, Stream.lines) are the only
entry points — there is no public constructor and no call form.
-
asyncStream<U, R>(): StreamClass<source: Source<U>,fn: () => R | PromiseLike<R>,value: Exclude<U, AnyFailure>,signal: AbortSignaloptions?: { maxConcurrency?: number; timeoutMs?: number; ordered?: boolean; }>Exclude<R, AnyFailure>,Extract<U | R, AnyFailure> | AnyFailure
Elixir's
Task.async_stream/3, living at its JS-idiomatic home: mapsfnover the source with at mostmaxConcurrencyinvocations in flight, lazily — nothing starts until a consumer pulls, and the window refills only as results are taken. Results keep source order by default (ordered: falseyields completion order — faster when element durations vary). Each element may deadline (timeoutMs) into a declaredFailure('AsyncTimeout')element — the railway, not a crash; the element's signal fires so cancellation-aware work stops. A throw fromfnstays a bug. Failure elements from the source pass through unmapped. -
channel<U, F = never>(options: ChannelOptions<U, F> & { overflow: "fail"; }): Channel<U, F | ChannelOverflowFailure>
The one push source: a handle whose producer emits whenever it likes, and a Stream that consumes what it emitted. Every other builder pulls —
unfold,resourceanditerateall ask for the next element — but the most common real source in JS cannot be asked: an EventEmitter, a WebSocket,fs.watch, SSE, a browser running tests. -
chunkBy<S>(): StreamClass<Exclude<S, AnyFailure>[], Extract<S, AnyFailure>>source: Source<S>,key: (value: Exclude<S, AnyFailure>) => unknown
StreamClass#chunkBy as a static:
Stream.chunkBy(source, …)isStream.from(source).chunkBy(…). -
chunkEvery<S>(): StreamClass<Exclude<S, AnyFailure>[], Extract<S, AnyFailure>>source: Source<S>,count: number,step?,leftover?: Exclude<S, AnyFailure>[] | "discard"
StreamClass#chunkEvery as a static:
Stream.chunkEvery(source, …)isStream.from(source).chunkEvery(…). -
chunkWhile<S, A, C>(): StreamClass<C, Extract<S, AnyFailure>>source: Source<S>,initial: A,step: () => { acc: A; emit?: C; halt?: boolean; },value: Exclude<S, AnyFailure>,accumulator: Aflush?: (accumulator: A) => C | undefined
StreamClass#chunkWhile as a static:
Stream.chunkWhile(source, …)isStream.from(source).chunkWhile(…). -
collect<S>(source: Source<S>): Task<Exclude<S, AnyFailure>[], Extract<S, AnyFailure>>
StreamClass#collect as a static:
Stream.collect(source, …)isStream.from(source).collect(…). -
concat<U>(...sources: Source<U>[]): StreamClass<Exclude<U, AnyFailure>, Extract<U, AnyFailure>>
Concatenates sources in order — Elixir's
Stream.concat, variadic. -
cycle<U>(source: Source<U>): StreamClass<Exclude<U, AnyFailure>, Extract<U, AnyFailure>>
Repeats a re-iterable source forever — always bound it (
take,takeWhile). -
dedup<S>(source: Source<S>): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>
StreamClass#dedup as a static:
Stream.dedup(source, …)isStream.from(source).dedup(…). -
dedupBy<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,key: (value: Exclude<S, AnyFailure>) => unknown
StreamClass#dedupBy as a static:
Stream.dedupBy(source, …)isStream.from(source).dedupBy(…). -
drop<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,count: number
StreamClass#drop as a static:
Stream.drop(source, …)isStream.from(source).drop(…). -
dropEvery<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,every: number
StreamClass#dropEvery as a static:
Stream.dropEvery(source, …)isStream.from(source).dropEvery(…). -
dropWhile<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,predicate: () => booleanvalue: Exclude<S, AnyFailure>,index: number
StreamClass#dropWhile as a static:
Stream.dropWhile(source, …)isStream.from(source).dropWhile(…). -
duplicate<U>(): StreamClass<U>value: U,count: number
countcopies of one value. -
every<S>(): Task<boolean, Extract<S, AnyFailure>>source: Source<S>,predicate: () => boolean | PromiseLike<boolean>value: Exclude<S, AnyFailure>,index: number
StreamClass#every as a static:
Stream.every(source, …)isStream.from(source).every(…). -
filter<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,predicate: () => booleanvalue: Exclude<S, AnyFailure>,index: number
StreamClass#filter as a static:
Stream.filter(source, …)isStream.from(source).filter(…). -
find<S>(): Task<Exclude<S, AnyFailure> | undefined, Extract<S, AnyFailure>>source: Source<S>,predicate: () => boolean | PromiseLike<boolean>value: Exclude<S, AnyFailure>,index: number
StreamClass#find as a static:
Stream.find(source, …)isStream.from(source).find(…). -
flatMap<S, U>(): StreamClass<source: Source<S>,fn: () => Source<U>value: Exclude<S, AnyFailure>,index: number>Exclude<U, AnyFailure>,Extract<S, AnyFailure> | Extract<U, AnyFailure>
StreamClass#flatMap as a static:
Stream.flatMap(source, …)isStream.from(source).flatMap(…). -
forEach<S>(): Task<void, Extract<S, AnyFailure>>source: Source<S>,fn: () => void | PromiseLike<void>value: Exclude<S, AnyFailure>,index: number
StreamClass#forEach as a static:
Stream.forEach(source, …)isStream.from(source).forEach(…). -
from<U>(source: Source<U>): StreamClass<Exclude<U, AnyFailure>, Extract<U, AnyFailure>>
Lifts a source into a Stream. Elements that are Failures are the
Echannel from the start; everything else isT. -
fromIndex(offset?: number): StreamClass<number>
The infinite integers
offset, offset + 1, …— Elixir'sStream.from_index/1. -
intersperse<S, Sep>(): StreamClass<Exclude<S, AnyFailure> | Sep, Extract<S, AnyFailure>>source: Source<S>,separator: Sep
StreamClass#intersperse as a static:
Stream.intersperse(source, …)isStream.from(source).intersperse(…). -
interval(ms: number): StreamClass<number>
Emits
0, 1, 2, …everymsmilliseconds, forever — Elixir'sStream.interval/1, onsetTimeout(universal). Infinite: always bound it. -
into<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,sink: WritableStream<Exclude<S, AnyFailure>>
StreamClass#into as a static:
Stream.into(source, …)isStream.from(source).into(…). -
iterate<U>(): StreamClass<U>seed: U,fn: (previous: U) => U
seed, fn(seed), fn(fn(seed)), …— Elixir'sStream.iterate/2, infinite. -
lines(bytes: Source<Uint8Array>): StreamClass<string>
Decodes a byte stream into text lines — the front door for NDJSON, logs, and SSE-ish feeds. Handles multi-byte characters and lines split across chunk boundaries; the final unterminated line is flushed.
-
map<S, U>(): StreamClass<source: Source<S>,fn: () => U | PromiseLike<U>value: Exclude<S, AnyFailure>,index: number>Exclude<U, AnyFailure>,Extract<S, AnyFailure> | Extract<U, AnyFailure>
StreamClass#map as a static:
Stream.map(source, …)isStream.from(source).map(…). -
mapConcurrent<S, R>(): StreamClass<source: Source<S>,fn: () => R | PromiseLike<R>,value: Exclude<S, AnyFailure>,signal: AbortSignaloptions?: { maxConcurrency?: number; timeoutMs?: number; ordered?: boolean; }>Exclude<R, AnyFailure>,Extract<S, AnyFailure> | Extract<R, AnyFailure> | AnyFailure
StreamClass#mapConcurrent as a static:
Stream.mapConcurrent(source, …)isStream.from(source).mapConcurrent(…). -
mapEvery<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,every: number,fn: (value: Exclude<S, AnyFailure>) => Exclude<S, AnyFailure> | PromiseLike<Exclude<S, AnyFailure>>
StreamClass#mapEvery as a static:
Stream.mapEvery(source, …)isStream.from(source).mapEvery(…). -
partition<S>(source: Source<S>): Task<>{ values: Exclude<S, AnyFailure>[]; errors: Extract<S, AnyFailure>[]; },never
StreamClass#partition as a static:
Stream.partition(source, …)isStream.from(source).partition(…). -
reduce<S, A>(): Task<A, Extract<S, AnyFailure>>source: Source<S>,fn: () => A | PromiseLike<A>,accumulator: A,value: Exclude<S, AnyFailure>,index: numberinitial: A
StreamClass#reduce as a static:
Stream.reduce(source, …)isStream.from(source).reduce(…). -
reject<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,predicate: () => booleanvalue: Exclude<S, AnyFailure>,index: number
StreamClass#reject as a static:
Stream.reject(source, …)isStream.from(source).reject(…). -
repeatedly<U>(fn: () => U | PromiseLike<U>): StreamClass<U>
Calls
fnfor each pull, forever — Elixir'sStream.repeatedly/1. -
resource<S, U>(): StreamClass<Exclude<U, AnyFailure>, Extract<U, AnyFailure>>start: () => S | PromiseLike<S>,next: (state: S) =>Promise<readonly [U, S | null] | null>
| readonly [U, S | null]
| null,after: (state: S) => void | PromiseLike<void>unfoldwith lifecycle hooks — Elixir'sStream.resource/3:startruns on first pull,nextis unfold's step, andafterALWAYS runs — normal end, earlytake, or a throw. (Plain generators already get this viatry/finally;resourceis for when the setup/teardown pair deserves to be explicit.) -
results<S>(source: Source<S>): Task<>Result<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>[],never
StreamClass#results as a static:
Stream.results(source, …)isStream.from(source).results(…). -
run<S>(source: Source<S>): Task<void, Extract<S, AnyFailure>>
StreamClass#run as a static:
Stream.run(source, …)isStream.from(source).run(…). -
scan(fn: () => T | PromiseLike<T>): StreamClass<T, E>accumulator: T,value: T
Emits the running fold of the values — Elixir's
Stream.scan; withoutinitialthe first value seeds the accumulator. Failures pass through and leave the accumulator untouched. -
some<S>(): Task<boolean, Extract<S, AnyFailure>>source: Source<S>,predicate: () => boolean | PromiseLike<boolean>value: Exclude<S, AnyFailure>,index: number
StreamClass#some as a static:
Stream.some(source, …)isStream.from(source).some(…). -
take<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,count: number
StreamClass#take as a static:
Stream.take(source, …)isStream.from(source).take(…). -
takeEvery<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,every: number
StreamClass#takeEvery as a static:
Stream.takeEvery(source, …)isStream.from(source).takeEvery(…). -
takeWhile<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,predicate: () => booleanvalue: Exclude<S, AnyFailure>,index: number
StreamClass#takeWhile as a static:
Stream.takeWhile(source, …)isStream.from(source).takeWhile(…). -
tap<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,fn: () => void | PromiseLike<void>value: Exclude<S, AnyFailure>,index: number
StreamClass#tap as a static:
Stream.tap(source, …)isStream.from(source).tap(…). -
through<S, U>(): StreamClass<Exclude<U, AnyFailure>, Extract<U, AnyFailure>>source: Source<S>,fn: (elements: AsyncIterable<S>) => Source<U>
StreamClass#through as a static:
Stream.through(source, …)isStream.from(source).through(…). -
timer(ms: number): StreamClass<number>
Emits a single
0aftermsmilliseconds, then ends — Elixir'sStream.timer/1. -
unfold<S, U>(): StreamClass<Exclude<U, AnyFailure>, Extract<U, AnyFailure>>seed: S,next: (state: S) =>Promise<readonly [U, S | null] | null>
| readonly [U, S | null]
| nullElixir's
Stream.unfold/2: grow a lazy stream from a seed.next(state)returns[element, nextState]to emit and continue, ornullto end; return[failure, null]to emit a declared failure and stop. Nothing runs until a consumer pulls — pagination only fetches the pages the consumer actually reaches. -
uniq<S>(source: Source<S>): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>
StreamClass#uniq as a static:
Stream.uniq(source, …)isStream.from(source).uniq(…). -
uniqBy<S>(): StreamClass<Exclude<S, AnyFailure>, Extract<S, AnyFailure>>source: Source<S>,key: (value: Exclude<S, AnyFailure>) => unknown
StreamClass#uniqBy as a static:
Stream.uniqBy(source, …)isStream.from(source).uniqBy(…). -
withIndex<S>(): StreamClass<source: Source<S>,offset?: number>readonly [Exclude<S, AnyFailure>, number],Extract<S, AnyFailure>
StreamClass#withIndex as a static:
Stream.withIndex(source, …)isStream.from(source).withIndex(…). -
zip<U extends readonly unknown[]>(...sources: [K in keyof U]: Source<U[K]>): StreamClass<>[K in keyof U]: Exclude<U[K], AnyFailure>,Extract<U[number], AnyFailure>
Zips sources in lockstep, ending at the shortest (Elixir's
Stream.zip) and closing the longer sources so their cleanup runs. JS divergences: sources are pulled sequentially per slot, and a failure element passes through bare without consuming from the other sources — failures cannot pair. -
zipWith<U extends readonly unknown[], R>(): StreamClass<Exclude<R, AnyFailure>, Extract<U[number] | R, AnyFailure>>sources: [K in keyof U]: Source<U[K]>,fn: (...values: [K in keyof U]: Exclude<U[K], AnyFailure>) => R
zipplus a combiner — Elixir'sStream.zip_with; the tuple arrives spread.
Span/log attributes a failure declares for tracing: failure.code plus whatever its
factory's trace mapper (see define) explicitly allowlisted from data. A
failure whose factory declared no mapper yields the code alone — unmapped payload
fields never leave the process, which is what makes redaction (passwords, tokens) the
default rather than a discipline.
Flattens an error's cause chain into an array, error first and the root cause last.
define() overload for failures that carry no payload.
define() overload for failures whose message is derived from their payload.
Renders an error and its whole cause chain as indented, human-readable lines.
Coerces any caught value into a Failure, leaving existing Failures untouched.
Revives a SerializedFailure into a real Failure, reconstructing the cause chain.
Narrows a Failure to one of several codes — the multi-code sibling of Factory.is.
Builds a .catch() handler for a failure that genuinely has no consequence — but says so
under QUNITX_DEBUG instead of vanishing. This is the raw handler; the ergonomic spelling
at call sites is Task(promise).ignore(context), which wraps exactly this function.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
True for a factory made by define. A factory carries the code it produces and its
own is guard; a plain error-mapper carries neither, so an API can accept both in one
position and tell them apart exactly, without guessing from arity.
Whether value is a Failure — from this realm or any other.
Whether value is a Failure — from this realm or any other.
Reports a declared failure to the observation seam — onObserved plus the
OBSERVED_CHANNEL_NAME channel. Task's consuming methods call this at their
classification points; call it yourself only for a synchronous Result flow that never
crossed a Task, so a tracing adapter sees those failures too.
Installs a process-wide observer for every ignored failure — the interception seam for
"list everything the program decided not to handle". Costs one null check on the failure
path only (nothing on success, nothing per Task), and retains nothing itself: whether the
suppressed failures accumulate, sample, or stream somewhere is the observer's decision.
Pass null to detach.
Installs a process-wide observer for every handled declared failure — the portable
(browser-friendly) counterpart of subscribing to OBSERVED_CHANNEL_NAME. Single
slot, one null check on the failure path, nothing retained; pass null to detach.
The deepest cause in the chain — the original failure, whatever wrapped it since.
Toggles ignored-failure reporting at runtime, overriding the QUNITX_DEBUG default.
Converts a Failure (or any error) into plain JSON.
The producer half of StreamClass.channel: emit into it, consume stream out of it.
-
abort(reason: unknown): void
Rejects the consuming Task with
reason— the two-tier rule's bug tier. Idempotent. -
buffered: number
Elements buffered for a consumer that has not taken them yet.
-
close(): void
Ends the stream once the buffer drains. Idempotent.
-
closed: boolean
Whether the channel has been closed, aborted, or abandoned by its consumer.
-
dropped: number
How many elements the buffer has lost to overflow.
0unless a consumer fell behind. -
emit(value: T): boolean
Offers a value. Returns
falsewhen there is no room left — Node'swrite()convention: advisory for a producer that can slow down, ignorable for one that cannot. -
fail(error: E): boolean
Offers a declared failure as an element — the railway, not a rejection.
-
ready(): Promise<void>
Resolves once there is room to emit again — Web Streams'
writer.ready, and the promise form of Node's'drain'. -
stream: Stream<T, E>
The consuming half. One consumer only; a second pass throws.
How a Channel behaves when its consumer cannot keep up.
-
capacity: number
How many elements to buffer for a consumer that has not taken them yet. Default
10_000. -
onDemand: () => void
Called once, when a consumer first attaches. A producer that can defer starting should start here: it is the difference between a buffer that stays near empty and one that races ahead of a consumer that has not arrived.
-
onDiscard: () => voiddropped: T | E,buffered: number
Called with each element the buffer actually lost, and the depth after the loss. The only place overflow is observable — make it fatal from here by calling
failorabort. -
overflow: Overflow
What to do once
capacityis reached: drop from either end, or'fail'— end the stream with a ChannelOverflowFailure element instead of losing anything quietly. Default'dropOldest'.
Per-kind options accepted by define().
-
trace: (data: Data) => TraceAttributes
Allowlist mapper from the typed payload to span/log attributes, consumed by attributes. Deliberately not a redaction filter: only what the mapper returns is ever exposed, so sensitive fields are private by omission, not by scrubbing.
A callable failure constructor produced by define(), carrying its own type guard.
-
code: Code
The literal code this factory produces. Useful as a
switchcase and in registries. -
is(value: unknown): value is Failure<Code, Data>
Cross-realm type guard narrowing to this exact failure — the flat rethrow line's guard after a
Result.try.
Options accepted by the Failure constructor and by every generated factory.
-
cause: unknown
The error this failure was derived from. Preserved verbatim and walked by
causes(). -
stackAnchor: (...args: never[]) => unknown
The function to truncate the stack at, so the top frame is the code that reported the failure rather than the plumbing that built it. Defaults to the constructor.
-
stackless: boolean
Skips stack capture. Only worth setting for failures produced in a hot loop and consumed immediately — the capture, not the allocation, is what a Failure costs. See the performance section of the docs before reaching for it.
The wire form of a Failure — what toJSON emits and fromJSON accepts.
-
cause: SerializedFailure
| { name: string; message: string; stack?: string; }The serialized cause chain: a nested Failure, or a plain error's identifying fields.
-
code: string
The discriminant. Survives the wire, unlike a prototype.
-
data: unknown
The structured payload, JSON round-tripped by
toJSONso it cannot fail later. -
failure: true
Wire marker.
Symbol.forkeys survive neitherJSON.stringifynorstructuredClone, so the serialized form carries an explicit field in the brand's place. -
message: string
The human-readable sentence, already interpolated from
data. -
stack: string
The producing process's stack. Frameless — the header line alone — when the failure was built
{ stackless: true }; the field itself is absent only ifstackwas never set.
Structured, discriminable failures — the E elements of a Stream.
The failure element a 'fail' channel ends with.
Any Failure at all — the type to reach for when a signature accepts failures it does not
enumerate, e.g. Result<T, Failure.Any> at a boundary that only logs.
The callback shape onIgnored installs: every ignored failure arrives with the label its call site declared.
The callback shape onObserved installs: every declared failure a consumer classified arrives right as it is handed to application code.
The Failure type a factory produces: Failure.Of<typeof FileMissing>.
The attribute primitives tracing systems accept (OpenTelemetry's span-attribute values) —
what a trace mapper returns and attributes yields.
What a full channel does — the two GenStage :buffer_keep choices, named for the element that
goes rather than the one that stays, plus the option of refusing to lose anything silently.
Anything a Stream can be built from or flattened into: sync or async iterables (a web ReadableStream is async-iterable on every modern runtime).
A channel with overflow: 'fail' filled up: the consumer fell far enough behind that the
buffer could not hold the difference, and dropping was not on the table.
Name of the diagnostics_channel that ignore publishes to on Node and Deno —
subscribe with the platform API, no qunitx registry involved. Messages are
{ context: string, error: unknown }. Browsers have no channel; use onIgnored.
Name of the diagnostics_channel that observed publishes to on Node and Deno.
Messages are { error: Failure.Any }. This is what a tracing adapter subscribes to —
e.g. OpenTelemetry, in its entirety:
The failure from() produces for a throwable that is not already a Failure.
Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
Usage
import * as mod from "lib/stream/index.ts";