import { ResponseObject as HapiResponseObject , ResponseToolkit as HapiResponseToolkit , } from '@hapi/hapi' ; import typeDetect from 'type-detect' ; import Boom from '@hapi/boom' ; import * as stream from 'stream' ; import { HttpResponsePayload , OpenSearchDashboardsResponse , ResponseError , ResponseErrorAttributes , } from './response' ; function setHeaders ( response , headers = { } ) { Object . entries ( headers ) . forEach ( ( [ header , value ] ) => { if ( value !== undefined ) { response . header ( header , value as any ) ; } } ) ; return response ; } const statusHelpers = { isSuccess : ( code ) => code >= 100 && code < 300 , isRedirect : ( code ) => code >= 300 && code < 400 , isError : ( code ) => code >= 400 && code < 600 , } ; export class HapiResponseAdapter { constructor ( private readonly responseToolkit ) { } public toBadRequest ( message ) { const error = Boom . badRequest ( ) ; error . output . payload . message = message ; return error ; } public toInternalError ( ) { const error = new Boom . Boom ( '' , { statusCode : 500 , } ) ; error . output . payload . message = 'An internal server error occurred.' ; return error ; } public handle ( opensearchDashboardsResponse ) { if ( ! ( opensearchDashboardsResponse instanceof OpenSearchDashboardsResponse ) ) { throw new Error ( `Unexpected result from Route Handler. Expected OpenSearchDashboardsResponse, but given: ${ typeDetect ( opensearchDashboardsResponse ) }.` ) ; } return this . toHapiResponse ( opensearchDashboardsResponse ) ; } private toHapiResponse ( opensearchDashboardsResponse ) { if ( statusHelpers . isError ( opensearchDashboardsResponse . status ) ) { return this . toError ( opensearchDashboardsResponse ) ; } if ( statusHelpers . isSuccess ( opensearchDashboardsResponse . status ) ) { return this . toSuccess ( opensearchDashboardsResponse ) ; } if ( statusHelpers . isRedirect ( opensearchDashboardsResponse . status ) ) { return this . toRedirect ( opensearchDashboardsResponse ) ; } throw new Error ( `Unexpected Http status code. Expected from 100 to 599, but given: ${ opensearchDashboardsResponse . status }.` ) ; } private toSuccess ( opensearchDashboardsResponse ) { const response = this . responseToolkit . response ( opensearchDashboardsResponse . payload ) . code ( opensearchDashboardsResponse . status ) ; setHeaders ( response , opensearchDashboardsResponse . options . headers ) ; return response ; } private toRedirect ( opensearchDashboardsResponse ) { const { headers } = opensearchDashboardsResponse . options ; if ( ! headers || typeof headers . location !== 'string' ) { throw new Error ( "expected 'location' header to be set" ) ; } const response = this . responseToolkit . response ( opensearchDashboardsResponse . payload ) . redirect ( headers . location ) . code ( opensearchDashboardsResponse . status ) . takeover ( ) ; setHeaders ( response , opensearchDashboardsResponse . options . headers ) ; return response ; } private toError ( opensearchDashboardsResponse ) { const { payload } = opensearchDashboardsResponse ; if ( Buffer . isBuffer ( payload ) || payload instanceof stream . Readable ) { const response = this . responseToolkit . response ( opensearchDashboardsResponse . payload ) . code ( opensearchDashboardsResponse . status ) ; setHeaders ( response , opensearchDashboardsResponse . options . headers ) ; return response ; } const error = new Boom . Boom ( '' , { statusCode : opensearchDashboardsResponse . status , } ) ; error . output . payload . message = getErrorMessage ( payload ) ; const attributes = getErrorAttributes ( payload ) ; if ( attributes ) { error . output . payload . attributes = attributes ; } const headers = opensearchDashboardsResponse . options . headers ; if ( headers ) { error . output . headers = headers ; } return error ; } } function getErrorMessage ( payload ? ) { if ( ! payload ) { throw new Error ( 'expected error message to be provided' ) ; } if ( typeof payload === 'string' ) return payload ; return getErrorMessage ( payload . message ) ; } function getErrorAttributes ( payload ? ) { return typeof payload === 'object' && 'attributes' in payload ? payload . attributes : undefined ; }