UNPKG

koa-onerror

Version:

koa error handler, hack ctx.onerror

155 lines 11.9 kB
import http from 'node:http'; import path from 'node:path'; import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import { debuglog, format } from 'node:util'; import escapeHtml from 'escape-html'; import { sendToWormhole } from 'stream-wormhole'; const debug = debuglog('koa-onerror'); const defaultOptions = { text, json, html, }; export function onerror(app, options) { options = { ...defaultOptions, ...options }; app.context.onerror = function (err) { debug('onerror: %s', err); // don't do anything if there is no error. // this allows you to pass `this.onerror` // to node-style callbacks. if (err == null) { return; } // ignore all padding request stream if (this.req) { sendToWormhole(this.req); debug('send the req to wormhole'); } // wrap non-error object if (!(err instanceof Error)) { debug('err is not an instance of Error'); let errMsg = err; if (typeof err === 'object') { try { errMsg = JSON.stringify(err); } catch (e) { debug('stringify error: %s', e); errMsg = format('%s', e); } } const newError = new Error('non-error thrown: ' + errMsg); // err maybe an object, try to copy the name, message and stack to the new error instance if (err) { if (err.name) newError.name = err.name; if (err.message) newError.message = err.message; if (err.stack) newError.stack = err.stack; if (err.status) { Reflect.set(newError, 'status', err.status); } if (err.headers) { Reflect.set(newError, 'headers', err.headers); } } err = newError; debug('wrap err: %s', err); } const headerSent = this.headerSent || !this.writable; if (headerSent) { debug('headerSent is true'); err.headerSent = true; } // delegate this.app.emit('error', err, this); // nothing we can do here other // than delegate to the app-level // handler and log. if (headerSent) return; // ENOENT support if (err.code === 'ENOENT') { err.status = 404; } if (typeof err.status !== 'number' || !http.STATUS_CODES[err.status]) { err.status = 500; } this.status = err.status; this.set(err.headers); let type = 'text'; if (options.accepts) { type = options.accepts.call(this, 'html', 'text', 'json'); } else { type = this.accepts('html', 'text', 'json'); } debug('accepts type: %s', type); type = type || 'text'; if (options.all) { options.all.call(this, err, this); } else { if (options.redirect && type !== 'json') { this.redirect(options.redirect); } else { options[type].call(this, err, this); this.type = type; } } if (type === 'json') { this.body = JSON.stringify(this.body); } debug('end the response, body: %s', this.body); this.res.end(this.body); }; return app; } const devTemplate = fs.readFileSync(path.join(getSourceDirname(), 'templates/dev_error.html'), 'utf8'); const prodTemplate = fs.readFileSync(path.join(getSourceDirname(), 'templates/prod_error.html'), 'utf8'); function isDev() { return !process.env.NODE_ENV || process.env.NODE_ENV === 'development'; } /** * default text error handler */ function text(err, ctx) { // unset all headers, and set those specified ctx.res._headers = {}; ctx.set(err.headers); ctx.body = (isDev() || err.expose) && err.message ? err.message : http.STATUS_CODES[ctx.status]; } /** * default json error handler */ function json(err, ctx) { const message = (isDev() || err.expose) && err.message ? err.message : http.STATUS_CODES[ctx.status]; ctx.body = { error: message }; } /** * default html error handler */ function html(err, ctx) { const template = isDev() ? devTemplate : prodTemplate; ctx.body = template .replace('{{status}}', escapeHtml(String(err.status))) .replace('{{stack}}', escapeHtml(err.stack)); ctx.type = 'html'; } function getSourceDirname() { if (typeof __dirname === 'string') { return __dirname; } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const __filename = fileURLToPath(import.meta.url); return path.dirname(__filename); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDekIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUM3QyxPQUFPLFVBQVUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWpELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQztBQW9CdEMsTUFBTSxjQUFjLEdBQW1CO0lBQ3JDLElBQUk7SUFDSixJQUFJO0lBQ0osSUFBSTtDQUNMLENBQUM7QUFFRixNQUFNLFVBQVUsT0FBTyxDQUFDLEdBQVEsRUFBRSxPQUF3QjtJQUN4RCxPQUFPLEdBQUcsRUFBRSxHQUFHLGNBQWMsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO0lBRTVDLEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxHQUFHLFVBQVMsR0FBUTtRQUNyQyxLQUFLLENBQUMsYUFBYSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzFCLDBDQUEwQztRQUMxQyx5Q0FBeUM7UUFDekMsMkJBQTJCO1FBQzNCLElBQUksR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ2hCLE9BQU87UUFDVCxDQUFDO1FBRUQsb0NBQW9DO1FBQ3BDLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2IsY0FBYyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN6QixLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUNwQyxDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxDQUFDLEdBQUcsWUFBWSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzVCLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1lBQ3pDLElBQUksTUFBTSxHQUFHLEdBQUcsQ0FBQztZQUNqQixJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUM1QixJQUFJLENBQUM7b0JBQ0gsTUFBTSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQy9CLENBQUM7Z0JBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztvQkFDWCxLQUFLLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxDQUFDLENBQUM7b0JBQ2hDLE1BQU0sR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUMzQixDQUFDO1lBQ0gsQ0FBQztZQUNELE1BQU0sUUFBUSxHQUFHLElBQUksS0FBSyxDQUFDLG9CQUFvQixHQUFHLE1BQU0sQ0FBQyxDQUFDO1lBQzFELHlGQUF5RjtZQUN6RixJQUFJLEdBQUcsRUFBRSxDQUFDO2dCQUNSLElBQUksR0FBRyxDQUFDLElBQUk7b0JBQUUsUUFBUSxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDO2dCQUN2QyxJQUFJLEdBQUcsQ0FBQyxPQUFPO29CQUFFLFFBQVEsQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztnQkFDaEQsSUFBSSxHQUFHLENBQUMsS0FBSztvQkFBRSxRQUFRLENBQUMsS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUM7Z0JBQzFDLElBQUksR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNmLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzlDLENBQUM7Z0JBQ0QsSUFBSSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQ2hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ2hELENBQUM7WUFDSCxDQUFDO1lBQ0QsR0FBRyxHQUFHLFFBQVEsQ0FBQztZQUNmLEtBQUssQ0FBQyxjQUFjLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDN0IsQ0FBQztRQUVELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ3JELElBQUksVUFBVSxFQUFFLENBQUM7WUFDZixLQUFLLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUM1QixHQUFHLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztRQUN4QixDQUFDO1FBRUQsV0FBVztRQUNYLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFbEMsK0JBQStCO1FBQy9CLGlDQUFpQztRQUNqQyxtQkFBbUI7UUFDbkIsSUFBSSxVQUFVO1lBQUUsT0FBTztRQUV2QixpQkFBaUI7UUFDakIsSUFBSSxHQUFHLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzFCLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO1FBQ25CLENBQUM7UUFFRCxJQUFJLE9BQU8sR0FBRyxDQUFDLE1BQU0sS0FBSyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ3JFLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO1FBQ25CLENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7UUFFekIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEIsSUFBSSxJQUFJLEdBQUcsTUFBTSxDQUFDO1FBQ2xCLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3BCLElBQUksR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM1RCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUNELEtBQUssQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNoQyxJQUFJLEdBQUcsSUFBSSxJQUFJLE1BQU0sQ0FBQztRQUN0QixJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNoQixPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3BDLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxPQUFPLENBQUMsUUFBUSxJQUFJLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDeEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbEMsQ0FBQztpQkFBTSxDQUFDO2dCQUNMLE9BQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDN0MsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7WUFDbkIsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFDRCxLQUFLLENBQUMsNEJBQTRCLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQixDQUFDLENBQUM7SUFFRixPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCxNQUFNLFdBQVcsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsRUFBRSwwQkFBMEIsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ3ZHLE1BQU0sWUFBWSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLDJCQUEyQixDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFFekcsU0FBUyxLQUFLO0lBQ1osT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLGFBQWEsQ0FBQztBQUN6RSxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLElBQUksQ0FBQyxHQUFpQixFQUFFLEdBQVE7SUFDdkMsNkNBQTZDO0lBQzdDLEdBQUcsQ0FBQyxHQUFHLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQztJQUN0QixHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUVyQixHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEdBQUcsQ0FBQyxPQUFPO1FBQy9DLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTztRQUNiLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLElBQUksQ0FBQyxHQUFpQixFQUFFLEdBQVE7SUFDdkMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksR0FBRyxDQUFDLE9BQU87UUFDcEQsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPO1FBQ2IsQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRWxDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDaEMsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxJQUFJLENBQUMsR0FBaUIsRUFBRSxHQUFRO0lBQ3ZDLE1BQU0sUUFBUSxHQUFHLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQztJQUN0RCxHQUFHLENBQUMsSUFBSSxHQUFHLFFBQVE7U0FDaEIsT0FBTyxDQUFDLFlBQVksRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1NBQ3JELE9BQU8sQ0FBQyxXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQy9DLEdBQUcsQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDO0FBQ3BCLENBQUM7QUFFRCxTQUFTLGdCQUFnQjtJQUN2QixJQUFJLE9BQU8sU0FBUyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ2xDLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFDRCw2REFBNkQ7SUFDN0QsYUFBYTtJQUNiLE1BQU0sVUFBVSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUNsQyxDQUFDIn0=