@eggjs/onerror
Version:
error handler for egg
248 lines • 16.2 kB
JavaScript
"use strict";
// modify from https://github.com/poppinss/youch/blob/develop/src/Youch/index.js
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorView = void 0;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const node_util_1 = __importDefault(require("node:util"));
const cookie_1 = require("cookie");
const mustache_1 = __importDefault(require("mustache"));
const stack_trace_1 = __importDefault(require("stack-trace"));
const utils_js_1 = require("./utils.js");
const startingSlashRegex = /\\|\//;
class ErrorView {
ctx;
error;
request;
app;
assets;
viewTemplate;
codeContext = 5;
_filterHeaders = ['cookie', 'connection'];
constructor(ctx, error, template) {
this.ctx = ctx;
this.error = error;
this.request = ctx.request;
this.app = ctx.app;
this.assets = new Map();
this.viewTemplate = template;
}
/**
* get html error page
*
* @return {String} html page
*/
toHTML() {
const stack = this.parseError();
const data = this.serializeData(stack, (frame, index) => {
const serializedFrame = this.serializeFrame(frame);
serializedFrame.classes = this.getFrameClasses(frame, index);
return serializedFrame;
});
return this.compileView(this.viewTemplate, {
...data,
appInfo: this.serializeAppInfo(),
request: this.serializeRequest(),
});
}
/**
* compile view
*
* @param {String} tpl - template
* @param {Object} locals - data used by template
*/
compileView(tpl, locals) {
return mustache_1.default.render(tpl, locals);
}
/**
* check if the frame is node native file.
*
* @param {Frame} frame - current frame
*/
isNode(frame) {
if (frame.isNative()) {
return true;
}
const filename = frame.getFileName() || '';
return !node_path_1.default.isAbsolute(filename) && filename[0] !== '.';
}
/**
* check if the frame is app modules.
*
* @param {Object} frame - current frame
*/
isApp(frame) {
if (this.isNode(frame)) {
return false;
}
const filename = frame.getFileName() || '';
return !filename.includes('node_modules' + node_path_1.default.sep);
}
/**
* cache file asserts
*
* @param {String} key - assert key
* @param {String} value - assert content
*/
setAssets(key, value) {
this.assets.set(key, value);
}
/**
* get cache file asserts
*
* @param {String} key - assert key
*/
getAssets(key) {
return this.assets.get(key);
}
/**
* get frame source
*
* @param {Object} frame - current frame
*/
getFrameSource(frame) {
const filename = frame.getFileName();
const lineNumber = frame.getLineNumber();
let contents = this.getAssets(filename);
if (!contents) {
contents = node_fs_1.default.existsSync(filename) ? node_fs_1.default.readFileSync(filename, 'utf8') : '';
this.setAssets(filename, contents);
}
const lines = contents.split(/\r?\n/);
return {
pre: lines.slice(Math.max(0, lineNumber - (this.codeContext + 1)), lineNumber - 1),
line: lines[lineNumber - 1],
post: lines.slice(lineNumber, lineNumber + this.codeContext),
};
}
/**
* parse error and return frame stack
*/
parseError() {
const stack = stack_trace_1.default.parse(this.error);
return stack.map((frame) => {
if (!this.isNode(frame)) {
frame.context = this.getFrameSource(frame);
}
return frame;
});
}
/**
* get stack context
*
* @param {Object} frame - current frame
*/
getContext(frame) {
if (!frame.context) {
return {};
}
return {
start: frame.getLineNumber() - (frame.context.pre || []).length,
pre: frame.context.pre.join('\n'),
line: frame.context.line,
post: frame.context.post.join('\n'),
};
}
/**
* get frame classes, let view identify the frame
*
* @param {any} frame - current frame
* @param {any} index - current index
*/
getFrameClasses(frame, index) {
const classes = [];
if (index === 0) {
classes.push('active');
}
if (!this.isApp(frame)) {
classes.push('native-frame');
}
return classes.join(' ');
}
/**
* serialize frame and return meaningful data
*
* @param {Object} frame - current frame
*/
serializeFrame(frame) {
const filename = frame.getFileName();
const relativeFileName = filename.includes(process.cwd())
? filename.replace(process.cwd(), '').replace(startingSlashRegex, '')
: filename;
const extname = node_path_1.default.extname(filename).replace('.', '');
return {
extname,
file: relativeFileName,
method: frame.getFunctionName(),
line: frame.getLineNumber(),
column: frame.getColumnNumber(),
context: this.getContext(frame),
classes: '',
};
}
/**
* serialize base data
*
* @param {Object} stack - frame stack
* @param {Function} frameFormatter - frame formatter function
*/
serializeData(stack, frameFormatter) {
const code = Reflect.get(this.error, 'code') ?? Reflect.get(this.error, 'type');
let message = (0, utils_js_1.detectErrorMessage)(this.ctx, this.error);
if (code) {
message = `${message} (code: ${code})`;
}
return {
code,
message,
name: this.error.name,
status: this.error.status,
frames: stack instanceof Array ? stack.filter(frame => frame.getFileName()).map(frameFormatter) : [],
};
}
/**
* serialize request object
*/
serializeRequest() {
const headers = [];
Object.keys(this.request.headers).forEach(key => {
if (this._filterHeaders.includes(key)) {
return;
}
headers.push({
key,
value: this.request.headers[key],
});
});
const parsedCookies = (0, cookie_1.parse)(this.request.headers.cookie || '');
const cookies = Object.keys(parsedCookies).map(key => {
return { key, value: parsedCookies[key] };
});
return {
url: this.request.url,
httpVersion: this.request.req.httpVersion,
method: this.request.method,
connection: this.request.headers.connection,
headers,
cookies,
};
}
/**
* serialize app info object
*/
serializeAppInfo() {
let config = this.app.config;
if ('dumpConfigToObject' in this.app && typeof this.app.dumpConfigToObject === 'function') {
config = this.app.dumpConfigToObject().config.config;
}
return {
baseDir: this.app.config.baseDir,
config: node_util_1.default.inspect(config),
};
}
}
exports.ErrorView = ErrorView;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3Jfdmlldy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZXJyb3Jfdmlldy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsZ0ZBQWdGOzs7Ozs7QUFFaEYsc0RBQXlCO0FBQ3pCLDBEQUE2QjtBQUM3QiwwREFBNkI7QUFDN0IsbUNBQStCO0FBQy9CLHdEQUFnQztBQUNoQyw4REFBMEQ7QUFDMUQseUNBQWdEO0FBSWhELE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDO0FBWW5DLE1BQWEsU0FBUztJQUNwQixHQUFHLENBQVU7SUFDYixLQUFLLENBQWU7SUFDcEIsT0FBTyxDQUFxQjtJQUM1QixHQUFHLENBQWlCO0lBQ3BCLE1BQU0sQ0FBc0I7SUFDNUIsWUFBWSxDQUFTO0lBRXJCLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFDaEIsY0FBYyxHQUFHLENBQUUsUUFBUSxFQUFFLFlBQVksQ0FBRSxDQUFDO0lBRTVDLFlBQVksR0FBWSxFQUFFLEtBQW1CLEVBQUUsUUFBZ0I7UUFDN0QsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDZixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUM7UUFDM0IsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDO1FBQ25CLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsWUFBWSxHQUFHLFFBQVEsQ0FBQztJQUMvQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU07UUFDSixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDdEQsTUFB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