11const fs = require ( 'fs' ) ;
22const path = require ( 'path' ) ;
3+ const process = require ( 'process' ) ;
4+ const { Buffer } = require ( 'buffer' ) ;
35
4- const fastSafeStringify = require ( 'fast-safe-stringify' ) ;
56const Boom = require ( '@hapi/boom' ) ;
67const camelCase = require ( 'camelcase' ) ;
78const capitalize = require ( 'capitalize' ) ;
89const co = require ( 'co' ) ;
9- const htmlToText = require ( 'html-to-text ' ) ;
10+ const fastSafeStringify = require ( 'fast-safe-stringify ' ) ;
1011const humanize = require ( 'humanize-string' ) ;
1112const statuses = require ( 'statuses' ) ;
1213const toIdentifier = require ( 'toidentifier' ) ;
14+ const { convert } = require ( 'html-to-text' ) ;
1315
1416// lodash
1517const _isError = require ( 'lodash.iserror' ) ;
@@ -56,7 +58,7 @@ const opts = {
5658const _404 = fs . readFileSync ( path . join ( __dirname , '404.html' ) , opts ) ;
5759const _500 = fs . readFileSync ( path . join ( __dirname , '500.html' ) , opts ) ;
5860
59- const passportLocalMongooseErrorNames = [
61+ const passportLocalMongooseErrorNames = new Set ( [
6062 'AuthenticationError' ,
6163 'MissingPasswordError' ,
6264 'AttemptTooSoonError' ,
@@ -66,7 +68,7 @@ const passportLocalMongooseErrorNames = [
6668 'IncorrectUsernameError' ,
6769 'MissingUsernameError' ,
6870 'UserExistsError'
69- ] ;
71+ ] ) ;
7072
7173// initialize try/catch error handling right away
7274// adapted from: https://github.com/koajs/onerror/blob/master/index.js
@@ -86,6 +88,20 @@ function errorHandler(
8688 return async function ( err ) {
8789 if ( ! err ) return ;
8890
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+
89105 const logger = useCtxLogger && this . logger ? this . logger : _logger ;
90106
91107 if ( ! _isError ( err ) ) err = new Error ( err ) ;
@@ -102,7 +118,7 @@ function errorHandler(
102118 err = parseValidationError ( this , err ) ;
103119
104120 // 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 ) ;
106122 if ( _isNumber ( val ) && val >= 400 )
107123 err = Boom [ camelCase ( toIdentifier ( statuses . message [ val ] ) ) ] ( ) ;
108124
@@ -127,15 +143,6 @@ function errorHandler(
127143 // check if we're about to go into a possible endless redirect loop
128144 const noReferrer = this . get ( 'Referrer' ) === '' ;
129145
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-
139146 // populate the status and body with `boom` error message payload
140147 // (e.g. you can do `ctx.throw(404)` and it will output a beautiful err obj)
141148 err . status = err . status || 500 ;
@@ -159,8 +166,13 @@ function errorHandler(
159166 // fix page title and description
160167 if ( ! this . api ) {
161168 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+ }
164176 }
165177
166178 switch ( type ) {
@@ -227,7 +239,7 @@ function errorHandler(
227239 // <https://github.com/koajs/generic-session/pull/95#issuecomment-246308544>
228240 //
229241 // these comments may no longer be valid and need reconsidered:
230- //
242+ //
231243 // if we're using `koa-session-store` we need to add
232244 // `this._session = new Session()`, and then run this:
233245 await co.wrap(this._session._store.save).call(
@@ -261,16 +273,23 @@ function errorHandler(
261273}
262274
263275function makeAPIFriendly ( ctx , message ) {
264- return ! ctx . api
265- ? message
266- : htmlToText . fromString ( message , {
276+ return ctx . api
277+ ? convert ( message , {
267278 wordwrap : false ,
268- linkHrefBaseUrl : process . env . ERROR_HANDLER_BASE_URL
269- ? process . env . ERROR_HANDLER_BASE_URL
270- : '' ,
271279 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 ;
274293}
275294
276295function parseValidationError ( ctx , err ) {
@@ -281,7 +300,7 @@ function parseValidationError(ctx, err) {
281300 : message ;
282301
283302 // passport-local-mongoose support
284- if ( passportLocalMongooseErrorNames . includes ( err . name ) ) {
303+ if ( passportLocalMongooseErrorNames . has ( err . name ) ) {
285304 err . message = translate ( err . message ) ;
286305 // this ensures the error shows up client-side
287306 err . status = 400 ;
0 commit comments