-
Notifications
You must be signed in to change notification settings - Fork 2
Release notes
Two big changes that ship together because they share the same migration burden for consumers. ESM unlocks the Web variant — Web Streams aren't usable from CommonJS without await import() gymnastics — and the new src/web/ tree lives alongside the renamed-and-converted Node tree under a single ESM-only package.
-
Same three primitives, two flavors. The Node Streams API (
fork,route,filterwrappingWritable) is unchanged in shape; a parallel Web Streams API atstream-fork/webships the same three primitives wrappingWritableStreamwith the same options surface (predicates,pick,ignoreErrors). -
Web
forkreplacesReadableStream.tee()for the common N-output case. Unliketee, the Webforkis backpressure-preserving — a slow branch slows upstream rather than ballooning a per-branch infinite buffer. -
Picker helpers (
stream-fork/utils/*) are shared between flavors. Pure functions, no runtime imports; the samepickRoundRobin/pickByHash/pickByKey/pickFirstMatchwork in both trees. -
New internal
makeWebStreamPusher(stream)mirrorsmakeStreamPusher: acquires a writer, awaitswriter.readybefore each write, listens onwriter.closedfor async errors, swallows write/close rejections intoError | nullso the primitives can resume after a downstream fails. -
Web-side introspection mirrors Node. Both flavors expose
.outputs(live snapshot) and.isEmpty()(trueonce every downstream has failed).
-
ESM-only.
"type": "module"inpackage.json.require()is no longer supported; consumers must useimport(orawait import()from a CommonJS host).// before (2.x, CommonJS) const fork = require('stream-fork'); // after (3.x, ESM) import fork from 'stream-fork';
-
Source layout split. The Node primitives still live at
src/{fork,route,filter}.js, but the new Web primitives live atsrc/web/{fork,route,filter}.js. Thesrc/utils/picker helpers are unchanged in location but are now shared between both trees. -
Subpath imports (
stream-fork/web,stream-fork/web/fork.js, etc.) added; the existingstream-fork/{fork,route,filter}.jsandstream-fork/utils/<name>.jscontinue to work. -
Tests restructured.
tests/test-*.mjsbecomestests/node/test-*.js(Node) +tests/web/test-*.js(Web + pure picker tests). Helpers split intotests/helpers.js(Node-only) +tests/web-helpers.js(Web Streams). The browser-runnable set runs undertape-six-playwrightvianpm run test:browser.
- All
.jssources now follow theesm-default-export-with-named-mirrorrule: everyexport default Xis paired withexport {X}so CJS hosts can destructure viaawait import(const {fork} = await import('stream-fork')). -
tape-six-playwrightadded as adevDependencyfor the browser test workflow. -
.windsurfrules/.cursorrules/.clinerulesnow byte-identical toAGENTS.mdper fleet slice 1 (previously a shorter directive form, now full mirror). -
package.json#keywordsaddsweb-streams.
Functional rewrite around three primitives plus a picker helper layer. Adopts fleet conventions (source layout, AI-agent docs, CI matrix).
- The package now exports three primitives:
fork(broadcast, the default export),route(per-chunk single-target dispatch), andfilter(per-chunk predicate-per-output subset). All three areWritables and gate upstream backpressure on the receiving downstreams' write callbacks — forforkevery live output, forroutethe single picked one, forfilterthe predicate-matched subset. - All primitives expose
.outputs(read-only snapshot of the live downstreams) and.isEmpty()(trueonce every downstream has failed). Dead downstreams are filtered out of subsequent writes automatically. - All primitives accept
options.ignoreErrors: when truthy, downstream errors are silently swallowed and the failing stream is dropped from the live set; when falsy (default), the first error per round is forwarded to the primitive's own'error'event. - New picker helpers under
stream-fork/utils/:-
pickRoundRobin(count)— load-balance. -
pickByHash(keyFn, count)— stable shard via djb2 (numeric keys used directly modulocount). -
pickByKey(keyFn, table)— explicit key→index lookup (plain object orMap). -
pickFirstMatch(predicates)— first-true predicate's index; append() => truefor catch-all.
-
- All three primitives are built on a shared internal
makeStreamPusher(stream)(src/stream-pusher.js) that wrapsstream.write/stream.endin a Promise-based interface and installs its own'error'listener so Node never crashes on otherwise-unhandled downstream errors. Mirrorsstream-join'smakeStreamPullersubstrate.
-
Functional API.
new Fork(outputs, options)from 1.x becomesfork(outputs, options)— nonew, no class. The staticFork.fork(...)factory is gone (the function IS the factory). - Node 22+ required. 1.x supported Node 6+ via the old CI matrix.
-
Subpath imports for non-default primitives.
routeandfilterimport asstream-fork/route.jsandstream-fork/filter.js; picker helpers asstream-fork/utils/<name>.js. The default export (require('stream-fork')orimport fork from 'stream-fork') remainsfork()for back-compat with 1.x callers.
-
src/layout with.jssource and hand-written.d.tssidecar per file (// @ts-self-types="./<name>.d.ts"directive at the top of each.js). - Added:
AGENTS.md,CLAUDE.md,.github/COPILOT-INSTRUCTIONS.md, byte-identical.windsurfrules/.cursorrules/.clinerules,llms.txt,llms-full.txt,ARCHITECTURE.md,LICENSE. - Paired
.claude/commands/+.windsurf/workflows/forai-docs-updateandrelease-check. - Tests migrated from
heya-unittotape-six(.mjstest files). - CI: Node 22, 24, 26 on
ubuntu-latest,windows-latest,macos-latest;actions/checkout@v6+actions/setup-node@v6; runsts-check+js-checkin addition to tests. - Added
.github/dependabot.yml(npm + github-actions, weekly, grouped, npmversioning-strategy: increase-if-necessary). - Added
.github/FUNDING.yml. - Wiki content refreshed (this page + per-primitive references) and the wiki repository is mounted as a submodule in the package repo.
No functional changes; metadata only. Safe to skip.
- Errors from downstream streams are now forwarded correctly. Thanks to dbubovych.
Republished to support Node 14.
Switched from _final() to the 'finish' event so the package would work on Node 6.
Documentation polish; no behavior change.
First public release. A single Fork class — a Writable that broadcast every chunk to every output, with proper backpressure handling.