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

io-square

v0.1.5

Published

IO Monad library for JavaScript

Downloads

59

Readme

IO^2

What is this?

So in JavaScript we now have promises, async/await, babelify etc. And I have a problem with these. We still can't cleanly separate pure and impure functions.

The problem

We want a clean separation of pure and impure functions. In JavaScript your impure functions are callbacks (mostly). A typical scenario -

  1. Handle Post request - Impure function
  2. Validate Post Input - Pure function
  3. Read from DB with input - Impure function
  4. Handle DB error - Pure function
  5. Do some validation - Pure function
  6. Create response and send - Pure function

Typically all the six functions above would have been one impure callback function (callback hell). IO^2 will help you split monolothic callbacks into bite size pieces. Bonus, your pure functions can be easily tested. Another bonus, you write code the way you reason about your program.

The Solution


const IO = require('io-square')
const express = require('express')
const app = express()
 
new IO(callback => app.post('/', callback))                                 // Impure Function
  .reject((req, res) => {                                                   // Pure Function
    if (!req.body.email) {
      res.redirect('/')
      return null
    }
    return [req, res]
  })
  .bind(req => new IO(callback => client.hget(req.body.email, callback)))  // Impure function
  .error(err => {                                                          // Pure function
    res.send({error: true, message: 'Could not get user record from db'})
  })
  .reject((req, res, reply) => {                                           // Pure function
    if (reply.authorised !== true) {
      res.send({error: true, message: 'Not authorised'})
      return null
    }
    return [req, res]
  })
  .then((req, res) => {                                                    // Pure function
    // do something
    req.authSession.email = req.body.email
    res.send({success: true})
  })

Install

$ npm install io-square --save

How does it work?

Every asynchronous function is wrapped in an IO instance.

new IO(callback => app.post('/', callback))

Create an instance of an IO Object. Provide the constructor with an io-function. This function should take a result function as the only argument. In the asynchronous call, pass the result function ass the callback.

Provide an error function if the result 'maybe' an Error instance

  .error(err => {                                                          // Pure function
    res.send({error: true, message: 'Could not get user record from db'})
  })

Call methods of the IO instance with pure functions

  .reject((req, res) => {
    if (!req.body.email) {
      res.redirect('/')
      return null
    }
    return [req, res]
  })

Available methods

  1. reject - will stop propagation if the pure function given returns null. Otherwise passes on the value(s) returned as arguments to the next method. Multiple value should be returned in an Array.
  2. map - will take a set of values, modify them, and passes on a new set of values to the next method called.
  3. bind - is used to bind another asynchronous (nested) function to the data flow. It takes a function whose arguments are the values passed and whose return value is a new IO instance. It will pass a new set of arguments to the next method. The original args passed to it + the arguments passed to the new IO instance callback. Look at this carefully in the bind example above.
  4. then - is the final method you must always call. This will activate the whole flow. then cannot be called multiple times. It is always the final call.