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

shan

v0.0.5

Published

Shan web app framework

Readme

shan

koa with Promise-based middleware

Installation

$ npm install shan

Usage

You may need babel-node to run following code (for async arrow function).

const shan = require('shan')
const favicon = require('koa-favicon')

let app = shan()

app.useKoa(favicon())

app.use(async (ctx, next) => {
    let start = Date.now()

    await next(ctx)

    ctx.response.set('X-Response-Time', (Date.now() - start) + 'ms')
})

app.use(ctx => {
    ctx.response.body = 'hello'
})

app.listen(4321)

About

This is an application inherits from koa but override app.use to accept promise-based middleware instead of generator-based middleware.

Promise-based Middleware

Promise-based middleware is a function with two arguments, ctx and next, and return a any or Promise<any>. If any is returned, it will be wrapped to Promise using Promise.resolve(value). If there is any exception, the error will be wrapped to Promise using Promise.reject(error).

  • ctx is just instance of KoaContext.
  • next contains info about next middleware. To invoke next middleware, just call next(ctx). It will return a Promise<any> result from next middleware.
// ctx: KoaContext
// next: (KoaContext) => Promise<any>

app.use((ctx, next) => {
    console.log(1)
    return next(ctx).then(() => {
        console.log(8)
    })
})

// use async arrow function, may need help from babel
app.use(async (ctx, next) => {
    console.log(2)
    await next(ctx)
    console.log(7)
})

// use co
app.use(co.wrap(function* (ctx, next) {
    console.log(3)
    yield next(ctx)
    console.log(6)
}))

// use bluebird
app.use(Bluebird.coroutine(function* (ctx, next) {
    console.log(4)
    yield next(ctx)
    console.log(5)
}))

Utility Middleware

A few utility middleware are included for convenience.

Koa Converter Middleware

Convert koa generator-based middleware to promise-based middleware.

You can use any generator-based middleware from koa ecosystem.

app.useKoa(require('koa-favicon')())

app.useKoa(function* (next) {
    // ...
    yield next
})

Logger Middleware

Print request message to console when it flows through.

app.useLogger(ctx => `> ${ctx.method} ${ctx.path}`)

// it's equivalent to

app.use((ctx, next) => {
    console.log(`> ${ctx.method} ${ctx.path}`)
    return next(ctx)
})

Router Middleware

Simple router with fluent interface.

app.useRouter(it => it
    .get('/', (ctx, next) => {

    })
    .post('/signup', (ctx, next) => {

    })
    .all('/repos/:id', (ctx, next) => {

    })
    .route('/users/:id', {
        get: (ctx, next) => {

        },
        post: (ctx, next) => {

        },
        delete: (ctx, next) => {

        }
    })
)

Tracer Middleware

Profiling time spent within in one or multiple middleware.

app.useTracer('name1')

app.use(async (ctx, next) => {
    await sleep(100)
    await next(ctx)
    await sleep(400)
})

app.useTracer('name2')

app.use(async (ctx, next) => {
    await sleep(200)
    await next(ctx)
    await sleep(300)
})

app.useTracer('name3')

It will provide info like following:

name1 | +0           |     +403.419
name2 |   +102.017   |   +305.734  
name3 |     +202.964 | +0.449     

Try Middleware

Shortcut for try...catch...finally.

app.useTry({
    catch(ctx, err) {
        // catch block
    },
    finally(ctx) {
        // finally block
    }
})

// it's equivalent to

app.use(async (ctx, next) => {
    try {
        await next(ctx)
    }
    catch (err) {
        // catch block
    }
    finally {
        // finally block
    }
})

License

MIT