A tiny, zero-dependency asynchronous iterator polyfill/ponyfill for ReadableStreams.
With this package, you can consume a ReadableStream as an AsyncIterable.
- spec: https://streams.spec.whatwg.org/#rs-asynciterator
- tests: https://github.com/Sec-ant/readable-stream/blob/main/tests/asyncIterator.spec.ts (copied from wpt)
With this package, you can construct a ReadableStream from an AsyncIterable or an Iterable.
- spec: https://streams.spec.whatwg.org/#rs-from
- tests: https://github.com/Sec-ant/readable-stream/blob/main/tests/fromAnyIterable.spec.ts (copied from wpt)
This package passes all the aforementioned tests.
npm i @sec-ant/readable-streamThis package can be imported as a ponyfill to avoid side effects:
Path:
@sec-ant/readable-stream/ponyfill/asyncIterator
Example:
import {
asyncIterator,
type ReadableStreamIteratorOptions,
} from "@sec-ant/readable-stream/ponyfill/asyncIterator";
const readableStream = (await fetch("https://www.example.org/")).body;
let total = 0;
for await (const chunk of asyncIterator(readableStream)) {
total += chunk.length;
}
console.log(total);Check https://streams.spec.whatwg.org/#rs-class-definition and https://streams.spec.whatwg.org/#rs-asynciterator for further explanation on ReadableStreamIteratorOptions.
Path:
@sec-ant/readable-stream/ponyfill/fromAnyIterable
Example:
import { fromAnyIterable } from "@sec-ant/readable-stream/ponyfill/fromAnyIterable";
const readableStream = fromAnyIterable(["a", "b"]);Path:
@sec-ant/readable-stream/ponyfill
Example:
import {
fromAnyIterable,
asyncIterator,
type ReadableStreamIteratorOptions,
} from "@sec-ant/readable-stream/ponyfill";This package can be imported as a drop-in polyfill with side effects.
Path:
@sec-ant/readable-stream/polyfill/asyncIterator
Example:
import "@sec-ant/readable-stream/polyfill/asyncIterator";
const readableStream = (await fetch("https://www.example.org/")).body;
let total = 0;
for await (const chunk of readableStream) {
total += chunk.length;
}
console.log(total);Path:
@sec-ant/readable-stream/polyfill/fromAnyIterable
Example:
import "@sec-ant/readable-stream/polyfill/fromAnyIterable";
const readableStream = ReadableStream.from(["a", "b"]);The fromAnyIterable export provides TypeScript types for iterable-to-stream conversion.
Path:
@sec-ant/readable-stream/polyfill
Example:
import "@sec-ant/readable-stream/polyfill";Path:
@sec-ant/readable-stream/asyncIterator
Example:
import {
asyncIterator,
type ReadableStreamIteratorOptions,
} from "@sec-ant/readable-stream/asyncIterator";
// also with side effectsPath:
@sec-ant/readable-stream/fromAnyIterable
Example:
import { fromAnyIterable } from "@sec-ant/readable-stream/fromAnyIterable";
// also with side effectsPath:
@sec-ant/readable-stream
Example:
import {
fromAnyIterable,
asyncIterator,
type ReadableStreamIteratorOptions,
} from "@sec-ant/readable-stream";
// also with side effectsYou can also use this package to augment the ReadableStream type for async iteration if the runtime already supports it but the type system does not.
Path:
@sec-ant/readable-stream/async-iterator
Example:
/// <reference types="@sec-ant/readable-stream/async-iterator" />Use Node.js 24 and the pnpm version declared in package.json.
pnpm install --frozen-lockfile
pnpm test:coverage
pnpm test:wpt
pnpm benchmark
pnpm benchmark:memoryBrowser tests run in Chromium, Firefox, and WebKit. WPT runs the upstream async
iteration, iterable conversion, cross-realm, and Streams IDL suites in Window and
Dedicated Worker environments. The IDL suite compares polyfill results with the
browser's native baseline. The upstream revision is pinned in
compatibility/prepare.mjs and configurable through WPT_REVISION.
The verified runtime matrix includes Chromium 156, Firefox 157, WebKit 27.2,
Safari 27.2, Chrome 114, Firefox 115, and WebKit 17. These tests use native
ReadableStream support and the package's ESNext build. WebKit entries refer to
Playwright engine builds.
For Safari, enable remote automation and run safaridriver -p 4444 in a separate
terminal. The legacy installer provides isolated macOS browser downloads.
COMPAT_BROWSERS=safari pnpm test:wpt
node compatibility/install-legacy.mjs
COMPAT_BROWSERS=chrome-114,firefox-legacy,webkit-legacy pnpm test:wptBenchmarks compare the current implementation with the revision pinned in
benchmarks/prepare.mjs. Each workload has six warmup rounds and 25 measured
rounds with rotating implementation order. Node, Chromium, and Firefox run
sequentially. Individual runtimes can be selected with pnpm benchmark node or
pnpm benchmark chromium firefox.
Allocation sampling measures allocated bytes across the Node workload. The
retention check verifies collection of consumed buffers while iterators remain
alive. Reports, upstream sources, and browser downloads are generated under
.vitest/.
MIT