@eggjs/onerror 4.0.0-beta.35 → 4.0.0-beta.36

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.
@@ -1,241 +1,224 @@
1
- // modify from https://github.com/poppinss/youch/blob/develop/src/Youch/index.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
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
9
10
  const startingSlashRegex = /\\|\//;
10
- export class ErrorView {
11
- ctx;
12
- error;
13
- request;
14
- app;
15
- assets;
16
- viewTemplate;
17
- codeContext = 5;
18
- _filterHeaders = ['cookie', 'connection'];
19
- constructor(ctx, error, template) {
20
- this.ctx = ctx;
21
- this.error = error;
22
- this.request = ctx.request;
23
- this.app = ctx.app;
24
- this.assets = new Map();
25
- this.viewTemplate = template;
26
- }
27
- /**
28
- * get html error page
29
- *
30
- * @return {String} html page
31
- */
32
- toHTML() {
33
- const stack = this.parseError();
34
- const data = this.serializeData(stack, (frame, index) => {
35
- const serializedFrame = this.serializeFrame(frame);
36
- serializedFrame.classes = this.getFrameClasses(frame, index);
37
- return serializedFrame;
38
- });
39
- return this.compileView(this.viewTemplate, {
40
- ...data,
41
- appInfo: this.serializeAppInfo(),
42
- request: this.serializeRequest(),
43
- });
44
- }
45
- /**
46
- * compile view
47
- *
48
- * @param {String} tpl - template
49
- * @param {Object} locals - data used by template
50
- */
51
- compileView(tpl, locals) {
52
- return Mustache.render(tpl, locals);
53
- }
54
- /**
55
- * check if the frame is node native file.
56
- *
57
- * @param {Frame} frame - current frame
58
- */
59
- isNode(frame) {
60
- if (frame.isNative()) {
61
- return true;
62
- }
63
- const filename = frame.getFileName() || '';
64
- return !path.isAbsolute(filename) && filename[0] !== '.';
65
- }
66
- /**
67
- * check if the frame is app modules.
68
- *
69
- * @param {Object} frame - current frame
70
- */
71
- isApp(frame) {
72
- if (this.isNode(frame)) {
73
- return false;
74
- }
75
- const filename = frame.getFileName() || '';
76
- return !filename.includes('node_modules' + path.sep);
77
- }
78
- /**
79
- * cache file asserts
80
- *
81
- * @param {String} key - assert key
82
- * @param {String} value - assert content
83
- */
84
- setAssets(key, value) {
85
- this.assets.set(key, value);
86
- }
87
- /**
88
- * get cache file asserts
89
- *
90
- * @param {String} key - assert key
91
- */
92
- getAssets(key) {
93
- return this.assets.get(key);
94
- }
95
- /**
96
- * get frame source
97
- *
98
- * @param {Object} frame - current frame
99
- */
100
- getFrameSource(frame) {
101
- const filename = frame.getFileName();
102
- const lineNumber = frame.getLineNumber();
103
- let contents = this.getAssets(filename);
104
- if (!contents) {
105
- contents = fs.existsSync(filename) ? fs.readFileSync(filename, 'utf8') : '';
106
- this.setAssets(filename, contents);
107
- }
108
- const lines = contents.split(/\r?\n/);
109
- return {
110
- pre: lines.slice(Math.max(0, lineNumber - (this.codeContext + 1)), lineNumber - 1),
111
- line: lines[lineNumber - 1],
112
- post: lines.slice(lineNumber, lineNumber + this.codeContext),
113
- };
114
- }
115
- /**
116
- * parse error and return frame stack
117
- */
118
- parseError() {
119
- const stack = stackTrace.parse(this.error);
120
- return stack.map((frame) => {
121
- if (!this.isNode(frame)) {
122
- frame.context = this.getFrameSource(frame);
123
- }
124
- return frame;
125
- });
126
- }
127
- /**
128
- * get stack context
129
- *
130
- * @param {Object} frame - current frame
131
- */
132
- getContext(frame) {
133
- if (!frame.context) {
134
- return {};
135
- }
136
- return {
137
- start: frame.getLineNumber() - (frame.context.pre || []).length,
138
- pre: frame.context.pre.join('\n'),
139
- line: frame.context.line,
140
- post: frame.context.post.join('\n'),
141
- };
142
- }
143
- /**
144
- * get frame classes, let view identify the frame
145
- *
146
- * @param {any} frame - current frame
147
- * @param {any} index - current index
148
- */
149
- getFrameClasses(frame, index) {
150
- const classes = [];
151
- if (index === 0) {
152
- classes.push('active');
153
- }
154
- if (!this.isApp(frame)) {
155
- classes.push('native-frame');
156
- }
157
- return classes.join(' ');
158
- }
159
- /**
160
- * serialize frame and return meaningful data
161
- *
162
- * @param {Object} frame - current frame
163
- */
164
- serializeFrame(frame) {
165
- const filename = frame.getFileName();
166
- const relativeFileName = filename.includes(process.cwd())
167
- ? filename.replace(process.cwd(), '').replace(startingSlashRegex, '')
168
- : filename;
169
- const extname = path.extname(filename).replace('.', '');
170
- return {
171
- extname,
172
- file: relativeFileName,
173
- method: frame.getFunctionName(),
174
- line: frame.getLineNumber(),
175
- column: frame.getColumnNumber(),
176
- context: this.getContext(frame),
177
- classes: '',
178
- };
179
- }
180
- /**
181
- * serialize base data
182
- *
183
- * @param {Object} stack - frame stack
184
- * @param {Function} frameFormatter - frame formatter function
185
- */
186
- serializeData(stack, frameFormatter) {
187
- const code = Reflect.get(this.error, 'code') ?? Reflect.get(this.error, 'type');
188
- let message = detectErrorMessage(this.ctx, this.error);
189
- if (code) {
190
- message = `${message} (code: ${code})`;
191
- }
192
- return {
193
- code,
194
- message,
195
- name: this.error.name,
196
- status: this.error.status,
197
- frames: stack instanceof Array ? stack.filter((frame) => frame.getFileName()).map(frameFormatter) : [],
198
- };
199
- }
200
- /**
201
- * serialize request object
202
- */
203
- serializeRequest() {
204
- const headers = [];
205
- Object.keys(this.request.headers).forEach((key) => {
206
- if (this._filterHeaders.includes(key)) {
207
- return;
208
- }
209
- headers.push({
210
- key,
211
- value: this.request.headers[key],
212
- });
213
- });
214
- const parsedCookies = parse(this.request.headers.cookie || '');
215
- const cookies = Object.keys(parsedCookies).map((key) => {
216
- return { key, value: parsedCookies[key] };
217
- });
218
- return {
219
- url: this.request.url,
220
- httpVersion: this.request.req.httpVersion,
221
- method: this.request.method,
222
- connection: this.request.headers.connection,
223
- headers,
224
- cookies,
225
- };
226
- }
227
- /**
228
- * serialize app info object
229
- */
230
- serializeAppInfo() {
231
- let config = this.app.config;
232
- if ('dumpConfigToObject' in this.app && typeof this.app.dumpConfigToObject === 'function') {
233
- config = this.app.dumpConfigToObject().config.config;
234
- }
235
- return {
236
- baseDir: this.app.config.baseDir,
237
- config: util.inspect(config),
238
- };
239
- }
240
- }
241
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3Jfdmlldy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvZXJyb3Jfdmlldy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxnRkFBZ0Y7QUFFaEYsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFFN0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUcvQixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxVQUFVLEVBQUUsRUFBbUIsTUFBTSxhQUFhLENBQUM7QUFFMUQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRWhELE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDO0FBWW5DLE1BQU0sT0FBTyxTQUFTO0lBQ3BCLEdBQUcsQ0FBVTtJQUNiLEtBQUssQ0FBZTtJQUNwQixPQUFPLENBQXFCO0lBQzVCLEdBQUcsQ0FBaUI7SUFDcEIsTUFBTSxDQUFzQjtJQUM1QixZQUFZLENBQVM7SUFFckIsV0FBVyxHQUFHLENBQUMsQ0FBQztJQUNoQixjQUFjLEdBQWEsQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFFcEQsWUFBWSxHQUFZLEVBQUUsS0FBbUIsRUFBRSxRQUFnQjtRQUM3RCxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUMzQixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUM7UUFDbkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxZQUFZLEdBQUcsUUFBUSxDQUFDO0lBQy9CLENBQUM7SUFF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
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 };