Repository URL to install this package:
|
Version:
2.0.12 ▾
|
import { isFunction } from 'exotic'
import { Request, Response, NextFunction } from 'express'
export interface InterceptFunction {
(req: Request, res: Response): string[] | any
}
export default function interceptFor(fn: InterceptFunction) {
const debug = require('@skava/modules/___dist/_forks/debug')(
'express-interceptor'
)
// eslint-disable-next-line
return function interceptionMiddleware(
req: Request,
res: Response,
next: NextFunction
) {
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?: string) {
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 as any).write = function onWrite(chunk, encoding, cb) {
debug('write called')
if (!intercept(chunk, encoding)) {
originalWrite.apply(res, arguments)
}
}
function afterSend(oldBody: string | Buffer, newBody: string | Buffer) {
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 as any).end = function onResEnd(chunk, encoding?: string, cb?: Function) {
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 = Object.freeze([
'isInterceptable',
'intercept',
'afterSend',
])
function _validateParams(methods: Array<string>): void {
for (const k in methods) {
if (!VALID_PARAMS.includes(k)) {
throw new Error(`${k} isn't a valid param (${VALID_PARAMS.join(', ')})`)
}
}
if (!('isInterceptable' in methods)) {
throw new Error('isInterceptable is a required param (function)')
}
}