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

wchain

v1.3.3

Published

A middleware chain framework for processing streams and their meta data.

Readme

wchain: a streaming process middleware system

Installation

This is a Node.js module available through the npm registry.

Installation is done using the npm install command:

npm install wchain

Features

  • Chaining stream processing by define series of middlewares
  • Functional, nestable and easily-used middleware framework
  • User-friendly APIs

Useage

How to define a wchain middleware

A wchain middleware is a function with 4 inputs:

  • meta: A object. It contains all the input for the middleware except the stream input. It will been input by the user when the wchain running.
  • stream: A stream. It is the stream input for the middleware. It will been input by previous middleware when the wchain running.
  • next: A function with 1 input. When you finished constructing your middleware, you must call this function. The input of this function is the meta data and stream you want to input to next middleware.
  • end: A function with no input. In most cases, next(meta, stream) have been called in a middleware does not mean the process in the middleware was finished —— because the stream is asynchronous. You must call this function when the stream process is ended or wchain will not exit. Besides, if you are using event emitter, it is recommanded that when to call end() should be determine before call next(meta, stream)

Here are some example of defining a wchain middleware.

First is a very simple middleware to get a file path from the meta and read the file as a stream to next middleware:

function Readfile(meta, stream, next, end) {
    let path = meta.file.path;
    stream = fs.createReadStream(path);
    stream.on("end", end);//When file is ended, call the end()
    next(meta, stream);//When the construction is over, call the next(meta, stream) to deliver the meta data and stream to next middleware
}

You will want to make some parameter of the middleware be constant, while others be variable. It is recommanded to define a construct function, and put the constant parameter in construct function, and put the variable parameter in meta. Just like this two middleware used for encrypt:

const crypto = require("crypto");

function EncryptMiddleware(encoding) {//I want the encoding of the encryption being constant and not change in this middleware
    return function (meta, stream, next, end) {
        let meta_next = meta;
        meta = meta["encrypt"];
        let crypto_stream = crypto.createCipheriv(meta.algorithm, meta.key, meta.iv);//And I want the algorithm, the key, and the initial vector of the encryption being variable
        crypto_stream.on("end", () => {
            meta.onFinish(crypto_stream.final(encoding));
            end();
        });
        next(meta_next, stream.pipe(crypto_stream));
    }//The construct function construct a middleware and return it
}

function HashMiddleware(encoding) {
    return function (meta, stream, next, end) {
        let meta_next = meta;
        meta = meta["hash"];
        let hash_stream = crypto.createHash(meta.algorithm);
        stream.pipe(hash_stream);
        stream.on("end", () => {
            meta.onFinish(hash_stream.digest(encoding));
            end();
        });
        next(meta_next, stream);
    }
}

How to define a wchain and connect the middlewares

To define a wchain and connect the middlewares is very easy. For example, when I want to define a wchain and connect the three middlewares above, just import the package and call the method use:

const wchain = require("./wchain");
let crypto_wchain = wchain();
crypto_wchain.use(Readfile);
crypto_wchain.use(HashMiddleware("hex"));
crypto_wchain.use(EncryptMiddleware("hex"));

That's it!

How to run a wchain

After define a wchain, next step is to make it running. Run a wchain is also very easy, just call the method run, and input the meta and the stream.

The function wchain.run have 4 inputs, just like a middleware. In fact, a wchain can itself used as a wchain middleware, which means that you could run a wchain like a middleware, or use a wchain as a input of another wchain's use method. For example, if we have 4 input variables meta, stream, next, end:

let meta = {
    file: {path: "test/test.txt"},
    hash: {
        algorithm: "md5",
        onFinish(h) {
            console.log("\nHash was finished. Here is the result: " + h)
        }
    },
    encrypt: {
        algorithm: "aes-128-cbc",
        key: "Here is the key.",
        iv: "I'm init vector."
    }
};
let stream = null;
let next = (stream) => {
    stream.pipe(process.stdout)
};
let end = () => {
    console.log("\nThe crypto_wchain was ended.")
};

Then wchain crypto_wchain above can run using wchain.run, like this:

try {
    crypto_wchain.run(meta, stream, next, end);
} catch (e) {
    console.log(e)
}

Or it can also run like a middleware:

crypto_wchain(meta, stream, next, end);

The two above have exactly the same effect.

This feature make the wchain nestable. You can use the crypto_wchain just like a middleware and put it to another wchain:

another_wchain.use(crypto_wchain);

How if I want to include Promise or acync/await into a middleware?

Sometimes you would want to use some other asynchronous operations besides stream in middleware. For example, if I want to confirm that a file is exists before read the file, I will define a Promise function to determine the existance:

function FileExists(path){
    return new Promise((resolve, reject) => {
        fs.stat(path,(err, stats) => {
            if (err) {
                if (err.code === "ENOENT")
                    return resolve(false);
                return reject(err);
            }
            return resolve(true);
        })
    })
}

Undoubted that Readfile middleware can be reformed the like this:

function ReadfilePromise(meta, stream, next, end) {
    let path = meta.file.path;
    return new Promise((resolve, reject) => {
        FileExists(path).then((ex) => {
            if (ex) stream = fs.createReadStream(path);
            else return reject(new Error("File not exists!"));
            stream.on("end", end);
            next(meta, stream);
            return resolve();
        });
    })
}

Above from ES7, two powerful keywords was added: async/await. You could use async/await in middleware with ease:

async function ReadfileAwait(meta, stream, next, end) {
    let path = meta.file.path;
    if (await FileExists(path)) {
        stream = fs.createReadStream(path);
    } else throw new Error("File not exists!");
    stream.on("end", end);
    next(meta, stream);
}

Promise is a significant and powerful feature of node. From wchain 1.2.0, wchain supports those middleware function that is defined a asynchronous operation and return a Promise. To use this feature, you should turn on the async_meta in options, like this:

let crypto_wchain_Await = wchain({async_meta: true});//Options here
crypto_wchain_Await.use(ReadfileAwait);
crypto_wchain_Await.use(HashMiddleware("hex"));
crypto_wchain_Await.use(EncryptMiddleware("hex"));
meta.file.path = "not exists";
crypto_wchain_Await.run(meta, stream, next, end).catch(e => {
    console.log("catched!");
    console.log(e)
});

The run function in a wchain with async_meta turned on will return a Promise, and its resolve means that all the next functions have been called successfully in the wchain. You can also see it as that all the meta data haa been processed correctly because it will be called after the last next has been called (the last next function is what you input to next when call wchain.run).

Change meta in middleware to shield low-level details or avoid error

For example, someone defined a middleware to write the stream into a file, but unfortunately, it use the same field in the meta with Readfile middleware:

function FilewriteMiddleware() {
    return function (meta, stream, next, end) {
        meta = meta["file"];
        let write_stream = fs.createWriteStream(meta.path);
        stream.on("end", end);
        stream.pipe(write_stream);
        next(meta, stream);
    }
}

Now if you want to use this middleware to write the encrypt result into a file, but you cannot modify FilewriteMiddleware, without modify Readfile, how can you avoid error? The answer is, add a middleware to change meta between crypto_wchain and FilewriteMiddleware, in which change the meta.file.path into the path to write before call next:

let another_wchain = wchain();
another_wchain.use(crypto_wchain);
another_wchain.use((meta, stream, next, end) => {
    meta.file.path = "test/result.txt";
    next(meta, stream);
    end();
});
another_wchain.use(FilewriteMiddleware());

Run the another_wchain, you will see the file was created correctly.

One more thing

All the code above is the test code of this package. Run npm test to see the result.