UNPKG

express-response-middleware

Version:
1 lines 14.5 kB
{"version":3,"file":"index.mjs","sources":["../../src/utils/asyncLocalStorage.ts","../../src/utils/errorHandler.ts","../../src/jsonMiddleware.ts","../../src/endMiddleware.ts","../../src/writeMiddleware.ts","../../src/jsonpMiddleware.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\n\nexport const isInSend = new AsyncLocalStorage<boolean>();\n","import type { ErrorRequestHandler } from 'express';\n\nexport const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => {\n res\n .status(500)\n .set('content-language', 'en')\n .json({ message: err.message })\n .end();\n};\n","import type { Request, RequestHandler, Response } from 'express';\nimport { isInSend } from './utils/asyncLocalStorage.js';\nimport { errorHandler } from './utils/errorHandler.js';\n\nexport type TransformJson<T = unknown, R = T> = (\n body: T,\n request: Request,\n response: Response,\n) => R | Promise<R>;\n\nexport const jsonMiddleware =\n <T = unknown>(fn: TransformJson<T>): RequestHandler =>\n (req, res, next) => {\n const originalJsonFn = res.json;\n const originalSendFn = res.send;\n\n res.send = function (this: Response) {\n return isInSend.run(true, () =>\n originalSendFn.apply(this, arguments as any),\n );\n };\n\n res.json = function (this: Response, json) {\n const originalEndFn = res.end;\n\n if (res.headersSent) return res;\n\n let mayBePromise: T | Promise<T>;\n try {\n mayBePromise = fn(json, req, res);\n } catch (e) {\n res.json = originalJsonFn;\n errorHandler(e, req, res, next);\n return res;\n }\n\n if (mayBePromise instanceof Promise) {\n mayBePromise\n .then((result) => {\n if (res.headersSent) return;\n res.end = originalEndFn;\n\n originalJsonFn.call(this, result === undefined ? json : result);\n })\n .catch((e) => {\n res.json = originalJsonFn;\n res.end = originalEndFn;\n errorHandler(e, req, res, next);\n });\n\n // Prevent end being called wile promise still running\n res.end = function (this: Response) {\n // Res.send will call Res.end, when send is call inside the middleware, do it actually\n if (isInSend.getStore()) {\n originalEndFn.apply(this, arguments as any);\n }\n return res;\n };\n } else {\n const result = mayBePromise;\n\n if (res.headersSent) return res;\n\n originalJsonFn.call(this, result === undefined ? json : result);\n }\n\n return res;\n };\n\n next();\n };\n","import type { Request, RequestHandler, Response } from 'express';\nimport { errorHandler } from './utils/errorHandler.js';\n\nexport type TransformEnd<T = unknown> = (\n request: Request,\n response: Response,\n) => T | Promise<T>;\n\nexport const endMiddleware =\n <T = unknown>(fn: TransformEnd<T>): RequestHandler =>\n (req, res, next) => {\n const originalEndFn = res.end;\n\n res.end = function (this: Response) {\n if (res.headersSent) return originalEndFn.apply(this, arguments as any);\n\n let mayBePromise: T | Promise<T>;\n try {\n mayBePromise = fn(req, res);\n } catch (e) {\n res.end = originalEndFn;\n errorHandler(e, req, res, next);\n return res;\n }\n\n if (mayBePromise instanceof Promise) {\n mayBePromise\n .then(() => {\n if (res.headersSent) {\n console.error(\n 'sending response while in endMiddleware is undefined behaviour',\n );\n return;\n }\n\n originalEndFn.apply(this, arguments as any);\n })\n .catch((e) => {\n res.end = originalEndFn;\n errorHandler(e, req, res, next);\n });\n\n res.end = function (this: Response) {\n return res;\n };\n } else {\n if (res.headersSent) {\n console.error(\n 'sending response while in endMiddleware is undefined behaviour',\n );\n return res;\n }\n\n return originalEndFn.apply(this, arguments as any);\n }\n\n return res;\n };\n\n next();\n };\n","import type { Request, RequestHandler, Response } from 'express';\nimport { errorHandler } from './utils/errorHandler.js';\n\nexport type TransformChunk = (\n chunk: string | Buffer,\n encoding: string | null,\n request: Request,\n response: Response,\n) => void | string | Buffer | Promise<void> | Promise<string> | Promise<Buffer>;\n\nexport const writeMiddleware =\n (fn: TransformChunk): RequestHandler =>\n (req, res, next) => {\n const originalWrite = res.write;\n const originalEndFn = res.end;\n\n res.write = function (this: Response, chunk) {\n if (res.writableEnded) return false;\n\n let mayBePromise: ReturnType<TransformChunk>;\n try {\n mayBePromise = fn(\n chunk,\n // Since `encoding` is an optional argument to `res.write`,\n // make sure it is a string and not actually the callback.\n // biome-ignore lint/style/noArguments: pass argument type\n typeof arguments[1] === 'string' ? arguments[1] : null,\n req,\n res,\n );\n } catch (e) {\n errorHandler(e, req, res, next);\n return false;\n }\n\n if (mayBePromise instanceof Promise) {\n mayBePromise\n .then((result) => {\n res.end = originalEndFn;\n\n if (res.writableEnded) return false;\n\n // biome-ignore lint/style/noArguments: pass argument type\n arguments[0] = result === undefined ? chunk : result;\n\n // biome-ignore lint/style/noArguments: pass argument type\n const writeResponse = originalWrite.apply(res, arguments as any);\n\n if (res.__isEnd) res.end();\n\n return writeResponse;\n })\n .catch((e) => {\n res.end = originalEndFn;\n errorHandler(e, req, res, next);\n });\n\n res.end = function (this: Response) {\n this.__isEnd = true;\n return res;\n };\n return false;\n }\n\n const result = mayBePromise;\n if (res.writableEnded) return false;\n\n // biome-ignore lint/style/noArguments: pass argument type\n arguments[0] = result === undefined ? chunk : result;\n\n // biome-ignore lint/style/noArguments: pass argument type\n return originalWrite.apply(res, arguments as any);\n };\n\n next();\n };\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport type { Request, RequestHandler, Response } from 'express';\nimport { errorHandler } from './utils/errorHandler.js';\n\nexport type TransformJsonp<T = unknown, R = T> = (\n body: T,\n request: Request,\n response: Response,\n) => R | Promise<R>;\n\nconst isInSend = new AsyncLocalStorage<boolean>();\n\nexport const jsonpMiddleware =\n <T = unknown>(fn: TransformJsonp<T>): RequestHandler =>\n (req, res, next) => {\n const originalJsonpFn = res.jsonp;\n const originalSendFn = res.send;\n\n res.send = function (this: Response) {\n return isInSend.run(true, () =>\n originalSendFn.apply(this, arguments as any),\n );\n };\n\n res.jsonp = function (this: Response, json) {\n const originalEndFn = res.end;\n\n if (res.headersSent) return res;\n\n let mayBePromise: T | Promise<T>;\n try {\n mayBePromise = fn(json, req, res);\n } catch (e) {\n res.json = originalJsonpFn;\n errorHandler(e, req, res, next);\n return res;\n }\n\n if (mayBePromise instanceof Promise) {\n mayBePromise\n .then((result) => {\n if (res.headersSent) return;\n res.end = originalEndFn;\n\n originalJsonpFn.call(this, result === undefined ? json : result);\n })\n .catch((e) => {\n res.jsonp = originalJsonpFn;\n res.end = originalEndFn;\n errorHandler(e, req, res, next);\n });\n\n // Prevent end being called wile promise still running\n res.end = function (this: Response) {\n // Res.send will call Res.end, when send is call inside the middleware, do it actually\n if (isInSend.getStore()) {\n originalEndFn.apply(this, arguments as any);\n }\n return res;\n };\n } else {\n const result = mayBePromise;\n\n if (res.headersSent) return res;\n\n originalJsonpFn.call(this, result === undefined ? json : result);\n }\n\n return res;\n };\n\n next();\n };\n"],"names":["isInSend","result"],"mappings":"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"}