Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/react-server / src / deps / intercept.ts
Size: Mime:
const { isFunction } = require('uxui-modules/exotic')

module.exports = function interceptFor(fn) {
  // const debug = require('uxui-modules/_forks/debug')('express-interceptor')

  // eslint-disable-next-line
  return function interceptionMiddleware(req, res, next) {
    const methods = fn(req, res)
    _validateParams(methods)

    const originalEnd = res.end
    const originalWrite = res.write
    const chunks = []
    let isFirstWrite = true
    let isIntercepting

    // eslint-disable-next-line
    function intercept(rawChunk, encoding) {
      if (isFirstWrite) {
        isFirstWrite = false
        isIntercepting = methods.isInterceptable()
      }

      // debug('isIntercepting? %s', isIntercepting)
      if (isIntercepting) {
        // collect all the parts of a response
        if (rawChunk) {
          let chunk = rawChunk
          if (
            rawChunk !== null &&
            !Buffer.isBuffer(chunk) &&
            encoding !== 'buffer'
          ) {
            if (!encoding) {
              chunk = new Buffer(rawChunk)
            } else {
              chunk = new Buffer(rawChunk, encoding)
            }
          }
          chunks.push(chunk)
        }

        // @todo @hack - very bad scope leak
        if (typeof cb === 'object') {
          cb()
        }
      }

      return isIntercepting
    }

    res.write = function onWrite(chunk, encoding, cb) {
      // debug('write called')

      if (!intercept(chunk, encoding)) {
        originalWrite.apply(res, arguments)
      }
    }

    function afterSend(oldBody, newBody) {
      if (isFunction(methods.afterSend)) {
        const onTick = () => {
          // debug(
          //   'methods.afterSend running now, body size: %s %s',
          //   oldBody.length,
          //   newBody.length
          // )
          methods.afterSend(oldBody, newBody)
        }
        process.nextTick(onTick)
      }
    }

    // eslint-disable-next-line
    res.end = function onResEnd(chunk, encoding, cb) {
      // debug('end called')
      const args = Array.prototype.slice.call(arguments)

      if (intercept(chunk, encoding)) {
        isIntercepting = false
        const oldBody = Buffer.concat(chunks).toString('utf-8')

        if (methods.intercept) {
          if (typeof methods.intercept !== 'function') {
            throw new Error(
              '`send` must be a function with the body to be sent as the only param'
            )
          }

          res.removeHeader('Content-Length')
          // allow the user to re-write response
          const onIntercept = newBody => {
            args[0] = newBody
            originalEnd.apply(res, args)
            afterSend(oldBody, newBody)
          }
          methods.intercept(oldBody, onIntercept)
        } else {
          // debug(' methods.send isnt defined')
          afterSend(oldBody, oldBody)
          originalEnd.apply(res, args)
        }
      } else {
        originalEnd.apply(res, args)
      }
    }

    next()
  }
}

const VALID_PARAMS = ['isInterceptable', 'intercept', 'afterSend']
function _validateParams(methods) {
  for (const k in methods) {
    if (VALID_PARAMS.indexOf(k) < 0) {
      throw new Error(
        k + " isn't a valid param (" + VALID_PARAMS.join(', ') + ')'
      )
    }
  }

  if (!('isInterceptable' in methods)) {
    throw 'isInterceptable is a required param (function)'
  }
}