1
1
const fs = require ( 'fs' ) ;
2
2
const path = require ( 'path' ) ;
3
+ const process = require ( 'process' ) ;
4
+ const { Buffer } = require ( 'buffer' ) ;
3
5
4
- const fastSafeStringify = require ( 'fast-safe-stringify' ) ;
5
6
const Boom = require ( '@hapi/boom' ) ;
6
7
const camelCase = require ( 'camelcase' ) ;
7
8
const capitalize = require ( 'capitalize' ) ;
8
9
const co = require ( 'co' ) ;
9
- const htmlToText = require ( 'html-to-text ' ) ;
10
+ const fastSafeStringify = require ( 'fast-safe-stringify ' ) ;
10
11
const humanize = require ( 'humanize-string' ) ;
11
12
const statuses = require ( 'statuses' ) ;
12
13
const toIdentifier = require ( 'toidentifier' ) ;
14
+ const { convert } = require ( 'html-to-text' ) ;
13
15
14
16
// lodash
15
17
const _isError = require ( 'lodash.iserror' ) ;
@@ -56,7 +58,7 @@ const opts = {
56
58
const _404 = fs . readFileSync ( path . join ( __dirname , '404.html' ) , opts ) ;
57
59
const _500 = fs . readFileSync ( path . join ( __dirname , '500.html' ) , opts ) ;
58
60
59
- const passportLocalMongooseErrorNames = [
61
+ const passportLocalMongooseErrorNames = new Set ( [
60
62
'AuthenticationError' ,
61
63
'MissingPasswordError' ,
62
64
'AttemptTooSoonError' ,
@@ -66,7 +68,7 @@ const passportLocalMongooseErrorNames = [
66
68
'IncorrectUsernameError' ,
67
69
'MissingUsernameError' ,
68
70
'UserExistsError'
69
- ] ;
71
+ ] ) ;
70
72
71
73
// initialize try/catch error handling right away
72
74
// adapted from: https://github.com/koajs/onerror/blob/master/index.js
@@ -86,6 +88,20 @@ function errorHandler(
86
88
return async function ( err ) {
87
89
if ( ! err ) return ;
88
90
91
+ // nothing we can do here other
92
+ // than delegate to the app-level
93
+ // handler and log.
94
+ if ( this . headerSent || ! this . writable ) {
95
+ err . headerSent = true ;
96
+ this . app . emit ( 'error' , err , this ) ;
97
+ this . app . emit (
98
+ 'error' ,
99
+ new Error ( 'Headers were already sent, returning early' ) ,
100
+ this
101
+ ) ;
102
+ return ;
103
+ }
104
+
89
105
const logger = useCtxLogger && this . logger ? this . logger : _logger ;
90
106
91
107
if ( ! _isError ( err ) ) err = new Error ( err ) ;
@@ -102,7 +118,7 @@ function errorHandler(
102
118
err = parseValidationError ( this , err ) ;
103
119
104
120
// check if we threw just a status code in order to keep it simple
105
- const val = parseInt ( err . message , 10 ) ;
121
+ const val = Number . parseInt ( err . message , 10 ) ;
106
122
if ( _isNumber ( val ) && val >= 400 )
107
123
err = Boom [ camelCase ( toIdentifier ( statuses . message [ val ] ) ) ] ( ) ;
108
124
@@ -127,15 +143,6 @@ function errorHandler(
127
143
// check if we're about to go into a possible endless redirect loop
128
144
const noReferrer = this . get ( 'Referrer' ) === '' ;
129
145
130
- // nothing we can do here other
131
- // than delegate to the app-level
132
- // handler and log.
133
- if ( this . headerSent || ! this . writable ) {
134
- logger . error ( new Error ( 'Headers were already sent, returning early' ) ) ;
135
- err . headerSent = true ;
136
- return ;
137
- }
138
-
139
146
// populate the status and body with `boom` error message payload
140
147
// (e.g. you can do `ctx.throw(404)` and it will output a beautiful err obj)
141
148
err . status = err . status || 500 ;
@@ -159,8 +166,13 @@ function errorHandler(
159
166
// fix page title and description
160
167
if ( ! this . api ) {
161
168
this . state . meta = this . state . meta || { } ;
162
- this . state . meta . title = this . body . error ;
163
- this . state . meta . description = err . message ;
169
+ if ( ! err . no_translate && _isFunction ( this . request . t ) ) {
170
+ this . state . meta . title = this . request . t ( this . body . error ) ;
171
+ this . state . meta . description = this . request . t ( err . message ) ;
172
+ } else {
173
+ this . state . meta . title = this . body . error ;
174
+ this . state . meta . description = err . message ;
175
+ }
164
176
}
165
177
166
178
switch ( type ) {
@@ -227,7 +239,7 @@ function errorHandler(
227
239
// <https://github.com/koajs/generic-session/pull/95#issuecomment-246308544>
228
240
//
229
241
// these comments may no longer be valid and need reconsidered:
230
- //
242
+ //
231
243
// if we're using `koa-session-store` we need to add
232
244
// `this._session = new Session()`, and then run this:
233
245
await co.wrap(this._session._store.save).call(
@@ -261,16 +273,23 @@ function errorHandler(
261
273
}
262
274
263
275
function makeAPIFriendly ( ctx , message ) {
264
- return ! ctx . api
265
- ? message
266
- : htmlToText . fromString ( message , {
276
+ return ctx . api
277
+ ? convert ( message , {
267
278
wordwrap : false ,
268
- linkHrefBaseUrl : process . env . ERROR_HANDLER_BASE_URL
269
- ? process . env . ERROR_HANDLER_BASE_URL
270
- : '' ,
271
279
hideLinkHrefIfSameAsText : true ,
272
- ignoreImage : true
273
- } ) ;
280
+ selectors : [
281
+ {
282
+ selector : 'a' ,
283
+ options : {
284
+ baseUrl : process . env . ERROR_HANDLER_BASE_URL
285
+ ? process . env . ERROR_HANDLER_BASE_URL
286
+ : ''
287
+ }
288
+ } ,
289
+ { selector : 'img' , format : 'skip' }
290
+ ]
291
+ } )
292
+ : message ;
274
293
}
275
294
276
295
function parseValidationError ( ctx , err ) {
@@ -281,7 +300,7 @@ function parseValidationError(ctx, err) {
281
300
: message ;
282
301
283
302
// passport-local-mongoose support
284
- if ( passportLocalMongooseErrorNames . includes ( err . name ) ) {
303
+ if ( passportLocalMongooseErrorNames . has ( err . name ) ) {
285
304
err . message = translate ( err . message ) ;
286
305
// this ensures the error shows up client-side
287
306
err . status = 400 ;
0 commit comments