@eggjs/onerror 3.0.0

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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/commonjs/agent.d.ts +6 -0
  4. package/dist/commonjs/agent.js +16 -0
  5. package/dist/commonjs/app.d.ts +12 -0
  6. package/dist/commonjs/app.js +150 -0
  7. package/dist/commonjs/config/config.default.d.ts +27 -0
  8. package/dist/commonjs/config/config.default.js +15 -0
  9. package/dist/commonjs/index.d.ts +1 -0
  10. package/dist/commonjs/index.js +4 -0
  11. package/dist/commonjs/lib/error_view.d.ts +154 -0
  12. package/dist/commonjs/lib/error_view.js +248 -0
  13. package/dist/commonjs/lib/onerror_page.mustache.html +761 -0
  14. package/dist/commonjs/lib/utils.d.ts +10 -0
  15. package/dist/commonjs/lib/utils.js +53 -0
  16. package/dist/commonjs/package.json +3 -0
  17. package/dist/commonjs/types.d.ts +7 -0
  18. package/dist/commonjs/types.js +3 -0
  19. package/dist/esm/agent.d.ts +6 -0
  20. package/dist/esm/agent.js +13 -0
  21. package/dist/esm/app.d.ts +12 -0
  22. package/dist/esm/app.js +144 -0
  23. package/dist/esm/config/config.default.d.ts +27 -0
  24. package/dist/esm/config/config.default.js +10 -0
  25. package/dist/esm/index.d.ts +1 -0
  26. package/dist/esm/index.js +2 -0
  27. package/dist/esm/lib/error_view.d.ts +154 -0
  28. package/dist/esm/lib/error_view.js +241 -0
  29. package/dist/esm/lib/onerror_page.mustache.html +761 -0
  30. package/dist/esm/lib/utils.d.ts +10 -0
  31. package/dist/esm/lib/utils.js +43 -0
  32. package/dist/esm/package.json +3 -0
  33. package/dist/esm/types.d.ts +7 -0
  34. package/dist/esm/types.js +2 -0
  35. package/dist/package.json +4 -0
  36. package/package.json +93 -0
  37. package/src/agent.ts +12 -0
  38. package/src/app.ts +160 -0
  39. package/src/config/config.default.ts +34 -0
  40. package/src/index.ts +1 -0
  41. package/src/lib/error_view.ts +281 -0
  42. package/src/lib/onerror_page.mustache.html +761 -0
  43. package/src/lib/utils.ts +47 -0
  44. package/src/types.ts +12 -0
  45. package/src/typings/index.d.ts +4 -0
@@ -0,0 +1,241 @@
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
+ import { detectErrorMessage } from './utils.js';
9
+ 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3Jfdmlldy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZXJyb3Jfdmlldy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxnRkFBZ0Y7QUFFaEYsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUMvQixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxVQUErQixNQUFNLGFBQWEsQ0FBQztBQUMxRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFJaEQsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUM7QUFZbkMsTUFBTSxPQUFPLFNBQVM7SUFDcEIsR0FBRyxDQUFVO0lBQ2IsS0FBSyxDQUFlO0lBQ3BCLE9BQU8sQ0FBcUI7SUFDNUIsR0FBRyxDQUFpQjtJQUNwQixNQUFNLENBQXNCO0lBQzVCLFlBQVksQ0FBUztJQUVyQixXQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLGNBQWMsR0FBRyxDQUFFLFFBQVEsRUFBRSxZQUFZLENBQUUsQ0FBQztJQUU1QyxZQUFZLEdBQVksRUFBRSxLQUFtQixFQUFFLFFBQWdCO1FBQzdELElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBQ2YsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDO1FBQzNCLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQztRQUNuQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLFlBQVksR0FBRyxRQUFRLENBQUM7SUFDL0IsQ0FBQztJQUVEOzs7O09B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