@eggjs/onerror 3.0.0 → 3.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -6
- package/dist/agent.d.ts +10 -0
- package/dist/agent.js +15 -0
- package/dist/app.d.ts +16 -0
- package/dist/app.js +111 -0
- package/{src/config/config.default.ts → dist/config/config.default.d.ts} +8 -12
- package/dist/config/config.default.js +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/error_view.d.ts +158 -0
- package/dist/lib/error_view.js +224 -0
- package/dist/{commonjs/lib → lib}/onerror_page.mustache.html +1 -1
- package/dist/lib/utils.d.ts +10 -0
- package/dist/lib/utils.js +21 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.js +1 -0
- package/package.json +33 -55
- package/dist/commonjs/agent.d.ts +0 -6
- package/dist/commonjs/agent.js +0 -16
- package/dist/commonjs/app.d.ts +0 -12
- package/dist/commonjs/app.js +0 -150
- package/dist/commonjs/config/config.default.d.ts +0 -27
- package/dist/commonjs/config/config.default.js +0 -15
- package/dist/commonjs/index.d.ts +0 -1
- package/dist/commonjs/index.js +0 -4
- package/dist/commonjs/lib/error_view.d.ts +0 -154
- package/dist/commonjs/lib/error_view.js +0 -248
- package/dist/commonjs/lib/utils.d.ts +0 -10
- package/dist/commonjs/lib/utils.js +0 -53
- package/dist/commonjs/package.json +0 -3
- package/dist/commonjs/types.d.ts +0 -7
- package/dist/commonjs/types.js +0 -3
- package/dist/esm/agent.d.ts +0 -6
- package/dist/esm/agent.js +0 -13
- package/dist/esm/app.d.ts +0 -12
- package/dist/esm/app.js +0 -144
- package/dist/esm/config/config.default.d.ts +0 -27
- package/dist/esm/config/config.default.js +0 -10
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -2
- package/dist/esm/lib/error_view.d.ts +0 -154
- package/dist/esm/lib/error_view.js +0 -241
- package/dist/esm/lib/onerror_page.mustache.html +0 -761
- package/dist/esm/lib/utils.d.ts +0 -10
- package/dist/esm/lib/utils.js +0 -43
- package/dist/esm/package.json +0 -3
- package/dist/esm/types.d.ts +0 -7
- package/dist/esm/types.js +0 -2
- package/dist/package.json +0 -4
- package/src/agent.ts +0 -12
- package/src/app.ts +0 -160
- package/src/index.ts +0 -1
- package/src/lib/error_view.ts +0 -281
- package/src/lib/onerror_page.mustache.html +0 -761
- package/src/lib/utils.ts +0 -47
- package/src/types.ts +0 -12
- package/src/typings/index.d.ts +0 -4
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# @eggjs/onerror
|
|
2
2
|
|
|
3
3
|
[![NPM version][npm-image]][npm-url]
|
|
4
|
-
[](https://github.com/eggjs/onerror/actions/workflows/nodejs.yml)
|
|
5
|
-
[![Test coverage][codecov-image]][codecov-url]
|
|
6
4
|
[![Known Vulnerabilities][snyk-image]][snyk-url]
|
|
7
5
|
[![npm download][download-image]][download-url]
|
|
8
6
|
[](https://nodejs.org/en/download/)
|
|
@@ -11,8 +9,6 @@
|
|
|
11
9
|
|
|
12
10
|
[npm-image]: https://img.shields.io/npm/v/@eggjs/onerror.svg?style=flat-square
|
|
13
11
|
[npm-url]: https://npmjs.org/package/@eggjs/onerror
|
|
14
|
-
[codecov-image]: https://codecov.io/github/eggjs/onerror/coverage.svg?branch=master
|
|
15
|
-
[codecov-url]: https://codecov.io/github/eggjs/onerror?branch=master
|
|
16
12
|
[snyk-image]: https://snyk.io/test/npm/@eggjs/onerror/badge.svg?style=flat-square
|
|
17
13
|
[snyk-url]: https://snyk.io/test/npm/@eggjs/onerror
|
|
18
14
|
[download-image]: https://img.shields.io/npm/dm/@eggjs/onerror.svg?style=flat-square
|
|
@@ -58,10 +54,10 @@ Please open an issue [here](https://github.com/eggjs/egg/issues).
|
|
|
58
54
|
|
|
59
55
|
## License
|
|
60
56
|
|
|
61
|
-
[MIT](
|
|
57
|
+
[MIT](LICENSE)
|
|
62
58
|
|
|
63
59
|
## Contributors
|
|
64
60
|
|
|
65
|
-
[](https://github.com/eggjs/egg/graphs/contributors)
|
|
66
62
|
|
|
67
63
|
Made with [contributors-img](https://contrib.rocks).
|
package/dist/agent.d.ts
ADDED
package/dist/agent.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/agent.ts
|
|
2
|
+
var Boot = class {
|
|
3
|
+
agent;
|
|
4
|
+
constructor(agent) {
|
|
5
|
+
this.agent = agent;
|
|
6
|
+
}
|
|
7
|
+
async didLoad() {
|
|
8
|
+
this.agent.on("error", (err) => {
|
|
9
|
+
this.agent.coreLogger.error(err);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Boot as default };
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { OnerrorError } from "koa-onerror";
|
|
2
|
+
import { Application, ILifecycleBoot } from "egg";
|
|
3
|
+
|
|
4
|
+
//#region src/app.d.ts
|
|
5
|
+
interface OnerrorErrorWithCode extends OnerrorError {
|
|
6
|
+
code?: string;
|
|
7
|
+
type?: string;
|
|
8
|
+
errors?: any[];
|
|
9
|
+
}
|
|
10
|
+
declare class Boot implements ILifecycleBoot {
|
|
11
|
+
private app;
|
|
12
|
+
constructor(app: Application);
|
|
13
|
+
didLoad(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { OnerrorErrorWithCode, Boot as default };
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { accepts, detectErrorMessage, detectStatus, isProd } from "./lib/utils.js";
|
|
2
|
+
import { ErrorView } from "./lib/error_view.js";
|
|
3
|
+
import http from "node:http";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { onerror } from "koa-onerror";
|
|
6
|
+
|
|
7
|
+
//#region src/app.ts
|
|
8
|
+
var Boot = class {
|
|
9
|
+
app;
|
|
10
|
+
constructor(app) {
|
|
11
|
+
this.app = app;
|
|
12
|
+
}
|
|
13
|
+
async didLoad() {
|
|
14
|
+
const config = this.app.config.onerror;
|
|
15
|
+
const viewTemplate = fs.readFileSync(config.templatePath, "utf8");
|
|
16
|
+
const app = this.app;
|
|
17
|
+
app.on("error", (err, ctx) => {
|
|
18
|
+
if (!ctx) ctx = app.currentContext || app.createAnonymousContext();
|
|
19
|
+
if (config.appErrorFilter && !config.appErrorFilter(err, ctx)) return;
|
|
20
|
+
if (detectStatus(err) >= 500) {
|
|
21
|
+
try {
|
|
22
|
+
ctx.logger.error(err);
|
|
23
|
+
} catch (ex) {
|
|
24
|
+
app.logger.error(err);
|
|
25
|
+
app.logger.error(ex);
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
ctx.logger.warn(err);
|
|
31
|
+
} catch (ex) {
|
|
32
|
+
app.logger.warn(err);
|
|
33
|
+
app.logger.error(ex);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const errorOptions = {
|
|
37
|
+
accepts() {
|
|
38
|
+
return (config.accepts || accepts)(this);
|
|
39
|
+
},
|
|
40
|
+
html(err, ctx) {
|
|
41
|
+
const status = detectStatus(err);
|
|
42
|
+
const errorPageUrl = typeof config.errorPageUrl === "function" ? config.errorPageUrl(err, ctx) : config.errorPageUrl;
|
|
43
|
+
ctx.realStatus = status;
|
|
44
|
+
if (isProd(app)) {
|
|
45
|
+
if (status >= 500) {
|
|
46
|
+
if (errorPageUrl) {
|
|
47
|
+
const statusQuery = (errorPageUrl.indexOf("?") > 0 ? "&" : "?") + `real_status=${status}`;
|
|
48
|
+
return ctx.redirect(errorPageUrl + statusQuery);
|
|
49
|
+
}
|
|
50
|
+
ctx.status = 500;
|
|
51
|
+
ctx.body = `<h2>Internal Server Error, real status: ${status}</h2>`;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
ctx.status = status;
|
|
55
|
+
ctx.body = `<h2>${status} ${http.STATUS_CODES[status]}</h2>`;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (app.config.env === "unittest") {
|
|
59
|
+
ctx.status = status;
|
|
60
|
+
ctx.body = `${err.name}: ${err.message}\n${err.stack}`;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
ctx.body = new ErrorView(ctx, err, viewTemplate).toHTML();
|
|
64
|
+
},
|
|
65
|
+
json(err, ctx) {
|
|
66
|
+
const status = detectStatus(err);
|
|
67
|
+
let errorJson = {};
|
|
68
|
+
ctx.status = status;
|
|
69
|
+
const code = err.code ?? err.type;
|
|
70
|
+
const message = detectErrorMessage(ctx, err);
|
|
71
|
+
if (isProd(app)) if (status >= 500) errorJson = {
|
|
72
|
+
code,
|
|
73
|
+
message: http.STATUS_CODES[status]
|
|
74
|
+
};
|
|
75
|
+
else errorJson = {
|
|
76
|
+
code,
|
|
77
|
+
message,
|
|
78
|
+
errors: err.errors
|
|
79
|
+
};
|
|
80
|
+
else {
|
|
81
|
+
errorJson = {
|
|
82
|
+
code,
|
|
83
|
+
message,
|
|
84
|
+
errors: err.errors
|
|
85
|
+
};
|
|
86
|
+
if (status >= 500) {
|
|
87
|
+
errorJson.stack = err.stack;
|
|
88
|
+
errorJson.name = err.name;
|
|
89
|
+
for (const key in err) if (!errorJson[key]) errorJson[key] = err[key];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
ctx.body = errorJson;
|
|
93
|
+
},
|
|
94
|
+
js(err, ctx) {
|
|
95
|
+
errorOptions.json.call(ctx, err, ctx);
|
|
96
|
+
if (typeof ctx.createJsonpBody === "function") ctx.createJsonpBody(ctx.body);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
for (const type of [
|
|
100
|
+
"all",
|
|
101
|
+
"html",
|
|
102
|
+
"json",
|
|
103
|
+
"text",
|
|
104
|
+
"js"
|
|
105
|
+
]) if (config[type]) Reflect.set(errorOptions, type, config[type]);
|
|
106
|
+
onerror(app, errorOptions);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
export { Boot as default };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import type { OnerrorError, OnerrorOptions } from 'koa-onerror';
|
|
4
|
-
import { getSourceDirname } from '../lib/utils.js';
|
|
1
|
+
import { OnerrorError, OnerrorOptions } from "koa-onerror";
|
|
2
|
+
import { Context } from "egg";
|
|
5
3
|
|
|
6
|
-
|
|
4
|
+
//#region src/config/config.default.d.ts
|
|
5
|
+
interface OnerrorConfig extends OnerrorOptions {
|
|
7
6
|
/**
|
|
8
7
|
* 5xx error will redirect to ${errorPageUrl}
|
|
9
8
|
* won't redirect in local env
|
|
@@ -24,11 +23,8 @@ export interface OnerrorConfig extends OnerrorOptions {
|
|
|
24
23
|
*/
|
|
25
24
|
templatePath: string;
|
|
26
25
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
onerror: {
|
|
30
|
-
errorPageUrl: '',
|
|
31
|
-
appErrorFilter: undefined,
|
|
32
|
-
templatePath: path.join(getSourceDirname(), 'lib/onerror_page.mustache.html'),
|
|
33
|
-
} as OnerrorConfig,
|
|
26
|
+
declare const _default: {
|
|
27
|
+
onerror: OnerrorConfig;
|
|
34
28
|
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { OnerrorConfig, _default as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/config/config.default.ts
|
|
4
|
+
var config_default_default = { onerror: {
|
|
5
|
+
errorPageUrl: "",
|
|
6
|
+
appErrorFilter: void 0,
|
|
7
|
+
templatePath: path.join(import.meta.dirname, "../lib/onerror_page.mustache.html")
|
|
8
|
+
} };
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { config_default_default as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { OnerrorError } from "koa-onerror";
|
|
2
|
+
import { StackFrame } from "stack-trace";
|
|
3
|
+
import { Context } from "egg";
|
|
4
|
+
|
|
5
|
+
//#region src/lib/error_view.d.ts
|
|
6
|
+
interface FrameSource {
|
|
7
|
+
pre: string[];
|
|
8
|
+
line: string;
|
|
9
|
+
post: string[];
|
|
10
|
+
}
|
|
11
|
+
interface Frame extends StackFrame {
|
|
12
|
+
context?: FrameSource;
|
|
13
|
+
}
|
|
14
|
+
declare class ErrorView {
|
|
15
|
+
ctx: Context;
|
|
16
|
+
error: OnerrorError;
|
|
17
|
+
request: Context['request'];
|
|
18
|
+
app: Context['app'];
|
|
19
|
+
assets: Map<string, string>;
|
|
20
|
+
viewTemplate: string;
|
|
21
|
+
codeContext: number;
|
|
22
|
+
_filterHeaders: string[];
|
|
23
|
+
constructor(ctx: Context, error: OnerrorError, template: string);
|
|
24
|
+
/**
|
|
25
|
+
* get html error page
|
|
26
|
+
*
|
|
27
|
+
* @return {String} html page
|
|
28
|
+
*/
|
|
29
|
+
toHTML(): string;
|
|
30
|
+
/**
|
|
31
|
+
* compile view
|
|
32
|
+
*
|
|
33
|
+
* @param {String} tpl - template
|
|
34
|
+
* @param {Object} locals - data used by template
|
|
35
|
+
*/
|
|
36
|
+
compileView(tpl: string, locals: Record<string, unknown>): string;
|
|
37
|
+
/**
|
|
38
|
+
* check if the frame is node native file.
|
|
39
|
+
*
|
|
40
|
+
* @param {Frame} frame - current frame
|
|
41
|
+
*/
|
|
42
|
+
isNode(frame: Frame): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* check if the frame is app modules.
|
|
45
|
+
*
|
|
46
|
+
* @param {Object} frame - current frame
|
|
47
|
+
*/
|
|
48
|
+
isApp(frame: Frame): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* cache file asserts
|
|
51
|
+
*
|
|
52
|
+
* @param {String} key - assert key
|
|
53
|
+
* @param {String} value - assert content
|
|
54
|
+
*/
|
|
55
|
+
setAssets(key: string, value: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* get cache file asserts
|
|
58
|
+
*
|
|
59
|
+
* @param {String} key - assert key
|
|
60
|
+
*/
|
|
61
|
+
getAssets(key: string): string | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* get frame source
|
|
64
|
+
*
|
|
65
|
+
* @param {Object} frame - current frame
|
|
66
|
+
*/
|
|
67
|
+
getFrameSource(frame: StackFrame): FrameSource;
|
|
68
|
+
/**
|
|
69
|
+
* parse error and return frame stack
|
|
70
|
+
*/
|
|
71
|
+
parseError(): Frame[];
|
|
72
|
+
/**
|
|
73
|
+
* get stack context
|
|
74
|
+
*
|
|
75
|
+
* @param {Object} frame - current frame
|
|
76
|
+
*/
|
|
77
|
+
getContext(frame: Frame): {
|
|
78
|
+
start?: undefined;
|
|
79
|
+
pre?: undefined;
|
|
80
|
+
line?: undefined;
|
|
81
|
+
post?: undefined;
|
|
82
|
+
} | {
|
|
83
|
+
start: number;
|
|
84
|
+
pre: string;
|
|
85
|
+
line: string;
|
|
86
|
+
post: string;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* get frame classes, let view identify the frame
|
|
90
|
+
*
|
|
91
|
+
* @param {any} frame - current frame
|
|
92
|
+
* @param {any} index - current index
|
|
93
|
+
*/
|
|
94
|
+
getFrameClasses(frame: Frame, index: number): string;
|
|
95
|
+
/**
|
|
96
|
+
* serialize frame and return meaningful data
|
|
97
|
+
*
|
|
98
|
+
* @param {Object} frame - current frame
|
|
99
|
+
*/
|
|
100
|
+
serializeFrame(frame: Frame): {
|
|
101
|
+
extname: string;
|
|
102
|
+
file: string;
|
|
103
|
+
method: string;
|
|
104
|
+
line: number;
|
|
105
|
+
column: number;
|
|
106
|
+
context: {
|
|
107
|
+
start?: undefined;
|
|
108
|
+
pre?: undefined;
|
|
109
|
+
line?: undefined;
|
|
110
|
+
post?: undefined;
|
|
111
|
+
} | {
|
|
112
|
+
start: number;
|
|
113
|
+
pre: string;
|
|
114
|
+
line: string;
|
|
115
|
+
post: string;
|
|
116
|
+
};
|
|
117
|
+
classes: string;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* serialize base data
|
|
121
|
+
*
|
|
122
|
+
* @param {Object} stack - frame stack
|
|
123
|
+
* @param {Function} frameFormatter - frame formatter function
|
|
124
|
+
*/
|
|
125
|
+
serializeData(stack: Frame[], frameFormatter: (frame: Frame, index: number) => any): {
|
|
126
|
+
code: any;
|
|
127
|
+
message: string;
|
|
128
|
+
name: string;
|
|
129
|
+
status: number;
|
|
130
|
+
frames: any[];
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* serialize request object
|
|
134
|
+
*/
|
|
135
|
+
serializeRequest(): {
|
|
136
|
+
url: string;
|
|
137
|
+
httpVersion: string;
|
|
138
|
+
method: string;
|
|
139
|
+
connection: string | undefined;
|
|
140
|
+
headers: {
|
|
141
|
+
key: string;
|
|
142
|
+
value: string | string[] | undefined;
|
|
143
|
+
}[];
|
|
144
|
+
cookies: {
|
|
145
|
+
key: string;
|
|
146
|
+
value: string | undefined;
|
|
147
|
+
}[];
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* serialize app info object
|
|
151
|
+
*/
|
|
152
|
+
serializeAppInfo(): {
|
|
153
|
+
baseDir: string;
|
|
154
|
+
config: string;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
export { ErrorView, Frame, FrameSource };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { detectErrorMessage } from "./utils.js";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import util from "node:util";
|
|
5
|
+
import { parse } from "cookie";
|
|
6
|
+
import Mustache from "mustache";
|
|
7
|
+
import stackTrace from "stack-trace";
|
|
8
|
+
|
|
9
|
+
//#region src/lib/error_view.ts
|
|
10
|
+
const startingSlashRegex = /\\|\//;
|
|
11
|
+
var ErrorView = class {
|
|
12
|
+
ctx;
|
|
13
|
+
error;
|
|
14
|
+
request;
|
|
15
|
+
app;
|
|
16
|
+
assets;
|
|
17
|
+
viewTemplate;
|
|
18
|
+
codeContext = 5;
|
|
19
|
+
_filterHeaders = ["cookie", "connection"];
|
|
20
|
+
constructor(ctx, error, template) {
|
|
21
|
+
this.ctx = ctx;
|
|
22
|
+
this.error = error;
|
|
23
|
+
this.request = ctx.request;
|
|
24
|
+
this.app = ctx.app;
|
|
25
|
+
this.assets = /* @__PURE__ */ new Map();
|
|
26
|
+
this.viewTemplate = template;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* get html error page
|
|
30
|
+
*
|
|
31
|
+
* @return {String} html page
|
|
32
|
+
*/
|
|
33
|
+
toHTML() {
|
|
34
|
+
const stack = this.parseError();
|
|
35
|
+
const data = this.serializeData(stack, (frame, index) => {
|
|
36
|
+
const serializedFrame = this.serializeFrame(frame);
|
|
37
|
+
serializedFrame.classes = this.getFrameClasses(frame, index);
|
|
38
|
+
return serializedFrame;
|
|
39
|
+
});
|
|
40
|
+
return this.compileView(this.viewTemplate, {
|
|
41
|
+
...data,
|
|
42
|
+
appInfo: this.serializeAppInfo(),
|
|
43
|
+
request: this.serializeRequest()
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* compile view
|
|
48
|
+
*
|
|
49
|
+
* @param {String} tpl - template
|
|
50
|
+
* @param {Object} locals - data used by template
|
|
51
|
+
*/
|
|
52
|
+
compileView(tpl, locals) {
|
|
53
|
+
return Mustache.render(tpl, locals);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* check if the frame is node native file.
|
|
57
|
+
*
|
|
58
|
+
* @param {Frame} frame - current frame
|
|
59
|
+
*/
|
|
60
|
+
isNode(frame) {
|
|
61
|
+
if (frame.isNative()) return true;
|
|
62
|
+
const filename = frame.getFileName() || "";
|
|
63
|
+
return !path.isAbsolute(filename) && filename[0] !== ".";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* check if the frame is app modules.
|
|
67
|
+
*
|
|
68
|
+
* @param {Object} frame - current frame
|
|
69
|
+
*/
|
|
70
|
+
isApp(frame) {
|
|
71
|
+
if (this.isNode(frame)) return false;
|
|
72
|
+
return !(frame.getFileName() || "").includes("node_modules" + path.sep);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* cache file asserts
|
|
76
|
+
*
|
|
77
|
+
* @param {String} key - assert key
|
|
78
|
+
* @param {String} value - assert content
|
|
79
|
+
*/
|
|
80
|
+
setAssets(key, value) {
|
|
81
|
+
this.assets.set(key, value);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* get cache file asserts
|
|
85
|
+
*
|
|
86
|
+
* @param {String} key - assert key
|
|
87
|
+
*/
|
|
88
|
+
getAssets(key) {
|
|
89
|
+
return this.assets.get(key);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* get frame source
|
|
93
|
+
*
|
|
94
|
+
* @param {Object} frame - current frame
|
|
95
|
+
*/
|
|
96
|
+
getFrameSource(frame) {
|
|
97
|
+
const filename = frame.getFileName();
|
|
98
|
+
const lineNumber = frame.getLineNumber();
|
|
99
|
+
let contents = this.getAssets(filename);
|
|
100
|
+
if (!contents) {
|
|
101
|
+
contents = fs.existsSync(filename) ? fs.readFileSync(filename, "utf8") : "";
|
|
102
|
+
this.setAssets(filename, contents);
|
|
103
|
+
}
|
|
104
|
+
const lines = contents.split(/\r?\n/);
|
|
105
|
+
return {
|
|
106
|
+
pre: lines.slice(Math.max(0, lineNumber - (this.codeContext + 1)), lineNumber - 1),
|
|
107
|
+
line: lines[lineNumber - 1],
|
|
108
|
+
post: lines.slice(lineNumber, lineNumber + this.codeContext)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* parse error and return frame stack
|
|
113
|
+
*/
|
|
114
|
+
parseError() {
|
|
115
|
+
return stackTrace.parse(this.error).map((frame) => {
|
|
116
|
+
if (!this.isNode(frame)) frame.context = this.getFrameSource(frame);
|
|
117
|
+
return frame;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* get stack context
|
|
122
|
+
*
|
|
123
|
+
* @param {Object} frame - current frame
|
|
124
|
+
*/
|
|
125
|
+
getContext(frame) {
|
|
126
|
+
if (!frame.context) return {};
|
|
127
|
+
return {
|
|
128
|
+
start: frame.getLineNumber() - (frame.context.pre || []).length,
|
|
129
|
+
pre: frame.context.pre.join("\n"),
|
|
130
|
+
line: frame.context.line,
|
|
131
|
+
post: frame.context.post.join("\n")
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* get frame classes, let view identify the frame
|
|
136
|
+
*
|
|
137
|
+
* @param {any} frame - current frame
|
|
138
|
+
* @param {any} index - current index
|
|
139
|
+
*/
|
|
140
|
+
getFrameClasses(frame, index) {
|
|
141
|
+
const classes = [];
|
|
142
|
+
if (index === 0) classes.push("active");
|
|
143
|
+
if (!this.isApp(frame)) classes.push("native-frame");
|
|
144
|
+
return classes.join(" ");
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* serialize frame and return meaningful data
|
|
148
|
+
*
|
|
149
|
+
* @param {Object} frame - current frame
|
|
150
|
+
*/
|
|
151
|
+
serializeFrame(frame) {
|
|
152
|
+
const filename = frame.getFileName();
|
|
153
|
+
const relativeFileName = filename.includes(process.cwd()) ? filename.replace(process.cwd(), "").replace(startingSlashRegex, "") : filename;
|
|
154
|
+
return {
|
|
155
|
+
extname: path.extname(filename).replace(".", ""),
|
|
156
|
+
file: relativeFileName,
|
|
157
|
+
method: frame.getFunctionName(),
|
|
158
|
+
line: frame.getLineNumber(),
|
|
159
|
+
column: frame.getColumnNumber(),
|
|
160
|
+
context: this.getContext(frame),
|
|
161
|
+
classes: ""
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* serialize base data
|
|
166
|
+
*
|
|
167
|
+
* @param {Object} stack - frame stack
|
|
168
|
+
* @param {Function} frameFormatter - frame formatter function
|
|
169
|
+
*/
|
|
170
|
+
serializeData(stack, frameFormatter) {
|
|
171
|
+
const code = Reflect.get(this.error, "code") ?? Reflect.get(this.error, "type");
|
|
172
|
+
let message = detectErrorMessage(this.ctx, this.error);
|
|
173
|
+
if (code) message = `${message} (code: ${code})`;
|
|
174
|
+
return {
|
|
175
|
+
code,
|
|
176
|
+
message,
|
|
177
|
+
name: this.error.name,
|
|
178
|
+
status: this.error.status,
|
|
179
|
+
frames: stack instanceof Array ? stack.filter((frame) => frame.getFileName()).map(frameFormatter) : []
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* serialize request object
|
|
184
|
+
*/
|
|
185
|
+
serializeRequest() {
|
|
186
|
+
const headers = [];
|
|
187
|
+
Object.keys(this.request.headers).forEach((key) => {
|
|
188
|
+
if (this._filterHeaders.includes(key)) return;
|
|
189
|
+
headers.push({
|
|
190
|
+
key,
|
|
191
|
+
value: this.request.headers[key]
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
const parsedCookies = parse(this.request.headers.cookie || "");
|
|
195
|
+
const cookies = Object.keys(parsedCookies).map((key) => {
|
|
196
|
+
return {
|
|
197
|
+
key,
|
|
198
|
+
value: parsedCookies[key]
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
return {
|
|
202
|
+
url: this.request.url,
|
|
203
|
+
httpVersion: this.request.req.httpVersion,
|
|
204
|
+
method: this.request.method,
|
|
205
|
+
connection: this.request.headers.connection,
|
|
206
|
+
headers,
|
|
207
|
+
cookies
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* serialize app info object
|
|
212
|
+
*/
|
|
213
|
+
serializeAppInfo() {
|
|
214
|
+
let config = this.app.config;
|
|
215
|
+
if ("dumpConfigToObject" in this.app && typeof this.app.dumpConfigToObject === "function") config = this.app.dumpConfigToObject().config.config;
|
|
216
|
+
return {
|
|
217
|
+
baseDir: this.app.config.baseDir,
|
|
218
|
+
config: util.inspect(config)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
//#endregion
|
|
224
|
+
export { ErrorView };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { OnerrorError } from "koa-onerror";
|
|
2
|
+
import { Application, Context } from "egg";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/utils.d.ts
|
|
5
|
+
declare function detectErrorMessage(ctx: Context, err: OnerrorError): string;
|
|
6
|
+
declare function detectStatus(err: OnerrorError): number;
|
|
7
|
+
declare function accepts(ctx: Context): "json" | "js" | "html";
|
|
8
|
+
declare function isProd(app: Application): boolean;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { accepts, detectErrorMessage, detectStatus, isProd };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/lib/utils.ts
|
|
2
|
+
function detectErrorMessage(ctx, err) {
|
|
3
|
+
if (err.status === 400 && err.name === "SyntaxError" && ctx.request.is("application/json", "application/vnd.api+json", "application/csp-report")) return "Problems parsing JSON";
|
|
4
|
+
return err.message;
|
|
5
|
+
}
|
|
6
|
+
function detectStatus(err) {
|
|
7
|
+
let status = err.status || 500;
|
|
8
|
+
if (status < 200) status = 500;
|
|
9
|
+
return status;
|
|
10
|
+
}
|
|
11
|
+
function accepts(ctx) {
|
|
12
|
+
if (ctx.acceptJSON) return "json";
|
|
13
|
+
if (ctx.acceptJSONP) return "js";
|
|
14
|
+
return "html";
|
|
15
|
+
}
|
|
16
|
+
function isProd(app) {
|
|
17
|
+
return app.config.env !== "local" && app.config.env !== "unittest";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { accepts, detectErrorMessage, detectStatus, isProd };
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|