hagemt/node-koa-omnibus

View on GitHub
index.js

Summary

Maintainability
B
4 hrs
Test Coverage
A
100%
const Application = require('koa')

const defaults = require('./defaults.js')

const debug = require('debug')('koa-omnibus')

const createOptions = (...args) => {
    //const options = _.defaultsDeep({}, defaults, ...args) // < this doesn't work
    const options = Object.assign({}, defaults, ...args) // < however, this works fine
    options.headers = Object.freeze(Object.assign({}, defaults.headers, options.headers))
    options.limits = Object.freeze(Object.assign({}, defaults.limits, options.limits))
    options.namespace = options.namespace || 'state' // whenever namespace is false-y
    return Object.freeze(options) // XXX: should Options be a class?
}

const createMiddleware = (options) => {
    const { timing, tracing } = options.headers
    const limitRate = options.limitRate(options)
    const limitTime = options.limitTime(options)
    return async function omnibus(context, next) {
        const tracer = options.targetTracer(options, context, tracing)
        const log = options.targetLogger(options, context, { tracing: tracer })
        const source = { log, timing: {}, tracing: tracer } // wrapped into:
        const target = options.targetObject(options, context, source)
        const start = (target.timing.start = process.hrtime())
        try {
            await limitRate(context, next)
            await limitTime(context, next)
            target.error = null // no throw
        } catch (error) {
            target.error = options.targetError(options, context, error)
        } finally {
            const [s, ns] = process.hrtime(start)
            const ms = Number(s * 1e3 + ns / 1e6).toFixed(6)
            tracer[timing] = `${ms} millisecond(s)` // header

            const err = options.redactedError(options, context)
            const req = options.redactedRequest(options, context)
            const res = options.redactedResponse(options, context)

            if (!err) log.trace({ req, res }, 'request')
            else log.debug({ err, req, res }, 'request')
        }
    }
}

const omnibus = (...args) => {
    const options = createOptions(...args)
    debug('create with options: %j', options)
    return createMiddleware(options)
}

const createApplication = (options = createOptions()) => {
    let application = new Application()
    for (const key of ['before', 'hooks']) {
        const all = Array.isArray(options[key]) ? options[key] : []
        for (const one of all) {
            switch (key) {
                case 'hooks':
                    application = one(application)
                    break
                default:
                    application.use(one)
            }
        }
    }
    application.use(omnibus(options))
    for (const key of ['after', 'routers']) {
        const all = Array.isArray(options[key]) ? options[key] : []
        for (const one of all) {
            switch (key) {
                case 'routers':
                    application.use(one.allowedMethods())
                    application.use(one.routes())
                    break
                default:
                    application.use(one)
            }
        }
    }
    return application
}

module.exports = Object.assign(omnibus, {
    createApplication,
    default: omnibus,
})