wonka

A tiny but capable push and pull stream library for TypeScript

Library
npm
v6.3.6
737stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
47/100Fair
Development Activity16
Maintenance32
Community52
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture82
Code Quality85
Innovation78
Learning Curve55

Wonka is a lightweight stream library for TypeScript and Flow, loosely based on the callbag spec, that unifies push-based (observable-like) and pull-based (iterable-like) streams behind one small set of primitives: sources, operators, and sinks. It ships composable operators for mapping, filtering, combining, debouncing, and buffering streams, along with sinks like subscribe, toPromise, and toArray to consume them.

Wonka is best known as the streaming engine underneath the urql GraphQL client, where it powers the exchange pipeline that request, cache, and network operations flow through, but it works standalone for any event-stream or async-iterable use case that needs a minimal footprint.

What You Get

  • A pipe() function for composing sources through a chain of operators into a sink, similar to RxJS but with a much smaller bundle size
  • Stream-creation helpers like fromArray, fromValue, fromPromise, fromIterable, interval, subject, and make
  • A large operator library covering map, filter, merge, combine, switchMap, debounce, buffer, takeUntil, share, and dozens more
  • Sinks for consuming streams as callbacks, Promises, arrays, or async iterables (subscribe, toPromise, toArray, toAsyncIterable)
  • Full TypeScript types and a Flow type definition (index.js.flow) for teams on either type system

Common Use Cases

  • Powering an exchange/middleware pipeline for a GraphQL or HTTP client (as urql does) where requests flow through composable transform stages
  • Coordinating async UI state (loading, debounced search input, cancellable requests) without pulling in the full RxJS library
  • Bridging between push-based event sources and pull-based async iteration in the same codebase
  • Building custom reactive data pipelines where bundle size matters more than the full RxJS operator surface

Under The Hood

Architecture — Wonka’s core model is a callbag-style function contract: a Source<T> is a function that accepts a Sink, and a Sink is a function that receives SignalKind-tagged push/pull/end signals; pipe() (src/pipe.ts) threads a source through a chain of Operator functions before handing it to a terminal sink, and helpers.ts centralizes the low-level push/start/teardown signal plumbing shared by every source and operator. Tech Stack — Pure TypeScript with a Flow type-definition file for interop, built with Rollup (scripts/rollup.config.mjs) into CJS/ESM/type-only outputs, tested with Vitest, and versioned via Changesets; it has zero runtime dependencies. Code Quality — The operator surface (src/operators.ts, ~1,460 lines) and sources module (src/sources.ts, ~400 lines) are both extensively TSDoc-commented with @example blocks, and are backed by a dedicated __tests__ suite including a compliance.ts harness that checks operators against the callbag spec’s signal contract. API Design — The pipe(source, operator1, operator2, ..., sink) shape mirrors RxJS closely enough to be familiar, while staying tree-shakeable and dependency-free; the tradeoff is that its lower-level, signal-based mental model (push/pull/end via SignalKind) takes more upfront learning than a plain Promise or EventEmitter API.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search