Wrap handlers to use pull-stream
Last updated 4 years ago by yoshuawuyts .
MIT · Repository · Bugs · Original npm · Tarball · package.json
$ cnpm install choo-pull 
SYNC missed versions from official npm registry.

choo-pull stability

npm version build status test coverage downloads js-standard-style

Wrap handlers to use pull-stream in a choo plugin. This is intended to go beyond basic choo usage, and tread into the domain of managing asynchronous complexity using streams / FRP.

While streams code takes longer to write up front, resulting code is generally stateless, pretty damn fast and surprisingly reusable. pull-streams are a minimal version of streams that weigh 200 bytes and handle backpressure phenomenally.


const pull = require('choo-pull')
const choo = require('choo')

const app = choo()

const tree = app.start()

Now each handler in a model expects a valid through pull-stream to be returned synchronously. Initial data will be passed as the source, errors handling and done() calls are appended in the sink:

const through = require('pull-through')
const ws = require('pull-ws')
const xhr = require('xhr')

module.exports = {
  namespace: 'my-model',
  state: {
    count: 0
  reducers: {
    increment: (data, state) => ({ count: state.count + data }),
    decrement: (data, state) => ({ count: state.count - data }),
  subscriptions: {
    getDataFromSocket: (Send$) => {
      const ws$ = Ws$('wss://')
      return pull(ws$, Deserialize$(), Send$('performXhr'))
  effects: {
    performXhr: (state, Send$) => pull(Xhr$(), Deserialize$())

function Xhr$ () {
  return through((data, cb) => {
    xhr('/foo/bar', { data: data }, (err, res) => {
      if (err) return cb(err)
      cb(null, res)

function Deserialize$ () {
  return through((data, cb) {
    try {
      cb(null, JSON.parse(data))
    } catch (e) {

function Ws$ (url) {
  return ws(new window.WebSocket(url))

Using send()

Like all other API methods, so too does the send() method become a pull-stream. More specifically it becomes a through stream that takes the action name as the sole arugment, and pushes any results into any a connecting through or sink stream:

const through = require('pull-through')

module.exports = {
  state: {
    count: 0
  reducers: {
    bar: (state) => ({ state.count + data })
  effects: {
    callBar: (state, prev, Send$) => Send$('bar'),
    callFoo: (state, prev, Send$) => Send$('foo')

// send('callFoo', 1)
// => state.count = 1


hooks = pull(opts)

Create an object of hooks that can be passed to app.use(). Internally ties into the following hooks:

  • wrapSubscriptions: changes the API of subscriptions to be (Send$)
  • wrapEffects: changes the API of effects to be (state, Send$)

The following options can be passed:

  • opts.subscriptions: default: true. Determine if subscriptions should be wrapped
  • opts.effects: default: true. Determine if effects should be wrapped

Incrementally enabling options can be useful when incrementally upgrading from a CSP-style codebase to a reactive / streaming one.


Wrap a single subscription. Useful to incrementally upgrade a CSP-style codebase to a reactive / streaming one.


Wrap a single effect. Useful to incrementally upgrade a CSP-style codebase to a reactive / streaming one.


Why aren't reducers wrapped in pull-streams?

In choo@3 the internal workings demand that data always be returned synchronously. Because pull-stream returns data in a callback, reducers cannot be wrapped. Perhaps at some point we'll allow for a hybrid API, but at this point it's frankly not possible.


$ npm install choo-pull



Current Tags

  • 1.0.0                                ...           latest (4 years ago)

1 Versions

  • 1.0.0                                ...           4 years ago

Copyright 2014 - 2016 © |