-
Notifications
You must be signed in to change notification settings - Fork 168
Open
Labels
addition/proposalNew features or enhancementsNew features or enhancementsneeds implementer interestMoving the issue forward requires implementers to express interestMoving the issue forward requires implementers to express interest
Description
What problem are you trying to solve?
There is no ergonomic, standardized way to externally control a ReadableStream (i.e., enqueue, close, or error) with a safe interface.
Today:
- The only way is to keep a reference to
ReadableStreamDefaultController. - Calling
controller.enqueue(),controller.close(), orcontroller.error()after the stream is closed/errored/canceled may throw. - Developers sometimes implement ad-hoc helpers ("withResolvers"-style wrappers) to build "pushable streams", but this pattern is not standardized.
This makes event-based or imperative stream production awkward and error-prone.
What solutions exist today?
-
Manually handling
ReadableStreamDefaultController- Requires writing boilerplate.
- Unsafe: calling methods after close/error/cancel throws.
- Requires custom guarding logic.
-
Ad-hoc helper utilities
- Non-standard.
- Inconsistent behavior (especially around cancellation and error propagation).
-
Async generator wrappers
- Cannot expose a truly push-based API.
- Cannot support backpressure-compatible push-style enqueuing.
How would you solve it?
Introduce a resolver-style API, similar to Promise.withResolvers():
interface ReadableStream {
static withSafeResolvers<T = unknown>(): {
stream: ReadableStream<T>;
enqueue(chunk: T): void;
close(): void;
error(reason: unknown): void;
};
}Key behavior
enqueue(chunk)— enqueues a chunk; ignored if closed/errored/canceled.close()— closes the stream safely; ignored after finalization.error(reason)— errors the stream; ignored after finalization.- All operations after the stream is finalized (closed, errored, or canceled) are silently ignored.
This provides an ergonomic, safe way to create externally controlled pushable streams.
Anything else?
A reference implementation exists:
- NPM: https://www.npmjs.com/package/readable-stream-with-safe-resolvers
- TypeScript implementation
- Fully safe for multiple calls to enqueue/close/error even after finalization
- Already used in real-world patterns such as event streams and imperatively controlled data sources
This proposal maintains compatibility with all existing stream semantics (including backpressure). The API surface is minimal and follows existing web-standard precedents such as Promise.withResolvers().
Metadata
Metadata
Assignees
Labels
addition/proposalNew features or enhancementsNew features or enhancementsneeds implementer interestMoving the issue forward requires implementers to express interestMoving the issue forward requires implementers to express interest