npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

readable-stream-with-safe-resolvers

v2.0.0

Published

A safe, resolver-style wrapper for ReadableStream, allowing external push, close, and error operations safely.

Readme

readable-stream-with-safe-resolvers

npm version TypeScript

A small utility to create a ReadableStream with a resolver-style interface, similar to Promise.withResolvers().

This library provides both a low-level resolver and a safe, defensive variant; the safe variant never throws due to invalid stream state.

Installation

npm install readable-stream-with-safe-resolvers
# or
yarn add readable-stream-with-safe-resolvers

Resolvers

This library provides two resolver variants:

withResolvers<T>()

A low-level resolver that directly controls a ReadableStream.

  • Operations do not perform internal safety checks
  • Calling methods after the stream is finalized may throw
  • Intended for strict, controller-like use cases

Returned methods:

  • enqueue(chunk: T): void
  • close(): void
  • error(reason: unknown): void
  • completed: boolean — whether the stream has been finalized This flag can be used to avoid invalid operations, but it is not enforced internally.

withSafeResolvers<T>()

A defensive resolver that safely ignores invalid operations.

  • All operations are safe and never throw due to stream state
  • Each method returns a boolean indicating whether it was applied

Returned methods:

  • enqueue(chunk: T): boolean
  • close(): boolean
  • error(reason: unknown): boolean

Usage (Safe)

import { withSafeResolvers } from "readable-stream-with-safe-resolvers";

async function example() {
  const { stream, enqueue, close, error } = withSafeResolvers<number>();

  // Push values
  enqueue(1);
  // -> true
  enqueue(2);
  // -> true

  // Close the stream
  close();
  // -> true

  // Reading from the stream
  const result = [];
  for await (const value of stream) {
    result.push(value);
  }

  console.log(result); // → [1, 2]
}

example();

In typical usage, the return value can be ignored unless you need to detect whether the stream has already been finalized.

Usage (Unsafe)

import { withResolvers } from "readable-stream-with-safe-resolvers";

const { stream, enqueue, close, completed } = withResolvers<number>();

if (!completed) {
  enqueue(1);
  close();
}

Calling methods after the stream is finalized may throw.

When to Use withSafeResolvers

  • You want safety over strict control
  • Multiple async contexts may call enqueue / close
  • You want to avoid runtime errors from invalid stream state

When to Use withResolvers

  • You want strict, controller-like behavior
  • Stream lifecycle is fully controlled in one place
  • You prefer errors over silent ignoring

The caller is responsible for avoiding invalid operations.

API

withSafeResolvers<T>()

Returns an object containing:

  • stream: ReadableStream<T> — the underlying stream.
  • enqueue(chunk: T): boolean — pushes a new chunk into the stream.
    Returns false if the stream has already been finalized.
  • close(): boolean — gracefully closes the stream.
    Returns false if already finalized.
  • error(reason: unknown): boolean — terminates the stream with an error.
    Returns false if already finalized.

Important (Safe Resolver)

Once the stream is finalized—via close(), error(), or consumer cancel()— all subsequent calls to enqueue, close, or error are silently ignored and return false.

withResolvers<T>()

Returns an object containing:

  • stream: ReadableStream<T> — the underlying stream.
  • enqueue(chunk: T): void — pushes a new chunk into the stream.
  • close(): void — closes the stream.
  • error(reason: unknown): void — terminates the stream with an error.
  • completed: boolean — whether the stream has been finalized.

No internal safety checks are performed.
The caller is responsible for avoiding invalid operations.

Example: Error Handling

import { withSafeResolvers } from "readable-stream-with-safe-resolvers";

async function exampleError() {
  const { stream, enqueue, error } = withSafeResolvers<number>();

  enqueue(10);
  // -> true
  enqueue(20);
  // -> true

  error(new Error("Something went wrong"));
  // -> true

  try {
    for await (const value of stream) {
      console.log(value);
    }
  } catch (err) {
    console.error(err); // → Error: Something went wrong
  }
}

exampleError();

Example: Safe Multiple Calls

const { stream, enqueue, close, error } = withSafeResolvers<number>();

enqueue(1);
// -> true
close();
// -> true
enqueue(2);    // ignored
// -> false
close();       // ignored
// -> false
error(new Error("oops")); // ignored
// -> false

This demonstrates that operations after the stream is finalized are safe, idempotent, and never throw due to invalid stream state.

Typical Use Cases

  • Creating pushable streams controlled outside the consumer loop
  • Wrapping async generators or event emitters as streams
  • Building streaming APIs that need explicit lifecycle control

License

MIT