import path from "path" ; import { inspect } from "util" ; import { HttpStatusCodes } from "../errors/httpStatusCodes" ; import { IDataResponse } from "../models/api/IDataResponse" ; import { IResponse } from "../models/api/IResponse" ; import { IHttpRequest } from "../models/app/IHttpRequest" ; import { IHttpResponse } from "../models/app/IHttpResponse" ; import { IRoute } from "../models/app/IRoute" ; import { IConfiguration } from "../models/configuration/IConfiguration" ; param findRoutes param url param method returns export function findRoute ( findRoutes , url , method ) { const urlParts = url . replace ( /\/$/ , "" ) . split ( "/" ) ; for ( const route of findRoutes ) { if ( route . method === method ) { const routeParts = route . path . split ( "/" ) ; const params = { } ; let i ; for ( i = 0 ; i < urlParts . length && i < routeParts . length ; i ++ ) { if ( routeParts [ i ] === urlParts [ i ] ) { } else if ( routeParts [ i ] . startsWith ( ":" ) && ( i < urlParts . length || routeParts [ i ] . endsWith ( "?" ) ) ) { if ( i < urlParts . length ) { params [ routeParts [ i ] . slice ( 1 ) . replace ( "?" , "" ) ] = urlParts [ i ] ; } } else { break ; } } if ( i === urlParts . length ) { return { route , params } ; } } } } param req param res param config param route param pathParams param verboseLogging export async function executeRoute ( req , res , config , route , pathParams , verboseLogging ) { let response ; const start = Date . now ( ) ; let filteredParams ; let status = HttpStatusCodes . BAD_REQUEST ; try { let params ; let body ; if ( route . dataBody ) { body = req . body ; params = { ... pathParams , ... req . query } ; } else { params = { ... pathParams , ... req . query , ... req . body } ; } filteredParams = logParams ( params ) ; if ( verboseLogging ) { console . log ( `===> ${ route . method . toUpperCase ( ) } ${ route . path }` ) ; console . log ( inspect ( filteredParams , false , undefined , false ) ) ; } if ( route . func ) { const modulePath = route . folder ? path . join ( __dirname , ".." , "routes" , route . folder , route . func ) : path . join ( __dirname , ".." , "routes" , route . func ) ; let mod ; try { mod = require ( modulePath ) ; } catch ( err ) { console . error ( err ) ; } if ( mod ) { if ( mod [ route . func ] ) { response = await mod [ route . func ] ( config , params , body , req . headers || { } ) ; if ( ! response . error ) { status = HttpStatusCodes . SUCCESS ; } } else { response = { error : `Route '${ route . path }' module '${ modulePath }' does not contain a method '${ route . func }'` } ; } } else { response = { error : `Route '${ route . path }' module '${ modulePath }' failed to load` } ; } } else if ( route . inline ) { response = await route . inline ( config , params , body , req . headers || { } ) ; if ( ! response . error ) { status = HttpStatusCodes . SUCCESS ; } } else { response = { error : `Route ${ route . path } has no func or inline property set` } ; } } catch ( err ) { status = err . httpCode || status ; response = { error : err . message } ; } if ( verboseLogging || response . error ) { console . log ( `<=== duration: ${ Date . now ( ) - start }ms` ) ; console . log ( inspect ( response , false , undefined , false ) ) ; } if ( response . status ) { status = response . status ; delete response . status ; } if ( response . headers ) { for ( const header in response . headers ) { res . setHeader ( header , response . headers [ header ] ) ; } delete response . headers ; } if ( route . dataResponse ) { const dataResponse = response as IDataResponse ; res . status ( status ) ; if ( dataResponse . contentType ) { res . setHeader ( "Content-Type" , dataResponse . contentType ) ; } let filename = "" ; if ( dataResponse . filename ) { filename = `; filename="${ dataResponse . filename }"` ; } res . setHeader ( "Content-Disposition" , `${ dataResponse . inline ? "inline" : "attachment" }${ filename }` ) ; if ( dataResponse . data ) { res . setHeader ( "Content-Length" , dataResponse . data . length ) ; res . send ( dataResponse . data ) ; } } else { res . setHeader ( "Content-Type" , "application/json" ) ; res . status ( status ) . send ( JSON . stringify ( response ) ) ; } res . end ( ) ; } param obj returns function logParams ( obj ) { const newobj = { } ; for ( const key in obj ) { if ( key . includes ( "pass" ) ) { newobj [ key ] = "*************" ; } else if ( key . includes ( "base64" ) || key . includes ( "binaryData" ) ) { newobj [ key ] = "<base64>" ; } else if ( obj [ key ] !== undefined && obj [ key ] !== null ) { const prop = obj [ key ] as any ; if ( prop . constructor . name === "Object" ) { newobj [ key ] = logParams ( prop as { [ id ] : unknown ; } ) ; } else if ( Array . isArray ( prop ) ) { newobj [ key ] = prop . map ( ( item ) => logParams ( item ) ) ; } else { newobj [ key ] = prop ; } } else { newobj [ key ] = obj [ key ] ; } } return newobj ; } param req param res param allowOrigins param allowMethods param allowHeaders export function cors ( req , res , allowOrigins ? , allowMethods ? , allowHeaders ? ) { if ( ! allowOrigins || allowOrigins === "*" ) { res . setHeader ( "Access-Control-Allow-Origin" , "*" ) ; } else if ( allowOrigins ) { const requestOrigin = req . headers . origin ; const origins = Array . isArray ( allowOrigins ) ? allowOrigins : allowOrigins . split ( ";" ) ; let isAllowed ; for ( const origin of origins ) { if ( requestOrigin === origin || origin === "*" ) { isAllowed = origin ; break ; } } if ( isAllowed ) { res . setHeader ( "Access-Control-Allow-Origin" , isAllowed ) ; } } if ( req . method === "OPTIONS" ) { res . setHeader ( "Access-Control-Allow-Methods" , allowMethods ?? "GET, POST, OPTIONS, PUT, PATCH, DELETE" ) ; res . setHeader ( "Access-Control-Allow-Headers" , allowHeaders ?? [ "X-Requested-With" , "Access-Control-Allow-Origin" , "X-HTTP-Method-Override" , "Content-Type" , "Authorization" , "Accept" , "Accept-Encoding" , "X-API-KEY" ] . join ( "," ) ) ; } }