import type { NextFunction, Response } from 'express' import statsd from '@/observability/lib/statsd' import { ExtendedRequest } from '@/types' class AbortError extends Error { statusCode: number code: string constructor(message: string, statusCode: number, code: string) { super(message) this.statusCode = statusCode this.code = code } } export default function abort(req: ExtendedRequest, res: Response, next: NextFunction) { // If the client aborts the connection, send an error req.once('aborted', () => { // ignore aborts from next, usually has to do with webpack-hmr if (req.path.startsWith('/_next')) { return } // NOTE: Node.js will also automatically set `req.aborted = true` const incrementTags = [] // Be careful with depending on attributes set on the `req` because // under certain conditions the contextualizers might not yet have // had a chance to run. if (req.pagePath) { incrementTags.push(`path:${req.pagePath}`) } if (req.context?.currentCategory) { incrementTags.push(`product:${req.context.currentCategory}`) } statsd.increment('middleware.abort', 1, incrementTags) const abortError = new AbortError('Client closed request', 499, 'ECONNRESET') // Pass the error to the Express error handler return next(abortError) }) return next() }