since import { Request , RequestHandler , ErrorRequestHandler , Response , NextFunction } from 'express' ; import { IncomingMessage } from 'http' ; import { Connection , CookieOptions , HeadersOpen , ResponseEnded , Status , StatusOpen } from '.' ; import { Middleware , execMiddleware } from './Middleware' ; import * as E from 'fp-ts/Either' ; import { pipe } from 'fp-ts/function' ; import * as L from 'fp-ts-contrib/List' ; internal export type Action = { type : 'setBody' ; body : unknown ; } | { type : 'endResponse' ; } | { type : 'setStatus' ; status : Status ; } | { type : 'setHeader' ; name : string ; value : string ; } | { type : 'clearCookie' ; name : string ; options : CookieOptions ; } | { type : 'setCookie' ; name : string ; value : string ; options : CookieOptions ; } | { type : 'pipeStream' ; stream : NodeJS . ReadableStream ; } ; const endResponse = { type : 'endResponse' } ; category since export class ExpressConnection < S > implements Connection < S > { since readonly _S ! : S ; constructor ( readonly req , readonly res , readonly actions = L . nil , readonly ended = false ) { } since chain < T > ( action , ended = false ) { return new ExpressConnection < T > ( this . req , this . res , L . cons ( action , this . actions ) , ended ) ; } since getRequest ( ) { return this . req ; } since getBody ( ) { return this . req . body ; } since getHeader ( name ) { return this . req . header ( name ) ; } since getParams ( ) { return this . req . params ; } since getQuery ( ) { return this . req . query ; } since getOriginalUrl ( ) { return this . req . originalUrl ; } since getMethod ( ) { return this . req . method ; } since setCookie ( name , value , options ) { return this . chain ( { type : 'setCookie' , name , value , options } ) ; } since clearCookie ( name , options ) { return this . chain ( { type : 'clearCookie' , name , options } ) ; } since setHeader ( name , value ) { return this . chain ( { type : 'setHeader' , name , value } ) ; } since setStatus ( status ) { return this . chain ( { type : 'setStatus' , status } ) ; } since setBody ( body ) { return this . chain ( { type : 'setBody' , body } , true ) ; } since pipeStream ( stream ) { return this . chain ( { type : 'pipeStream' , stream } , true ) ; } since endResponse ( ) { return this . chain ( endResponse , true ) ; } } function run ( res , action ) { switch ( action . type ) { case 'clearCookie' : return res . clearCookie ( action . name , action . options ) ; case 'endResponse' : res . end ( ) ; return res ; case 'setBody' : return res . send ( action . body ) ; case 'setCookie' : return res . cookie ( action . name , action . value , action . options ) ; case 'setHeader' : res . setHeader ( action . name , action . value ) ; return res ; case 'setStatus' : return res . status ( action . status ) ; case 'pipeStream' : return action . stream . pipe ( res ) ; } } function exec < I , O , E > ( middleware , req , res , next ) { return execMiddleware ( middleware , new ExpressConnection < I > ( req , res ) ) ( ) . then ( ( e ) => pipe ( e , E . fold ( ( e ) => next ( e ) , ( c ) => { const { actions : list , res , ended } = c as ExpressConnection < O > ; const len = list . length ; const actions = L . toReversedArray ( list ) ; for ( let i = 0 ; i < len ; i ++ ) { run ( res , actions [ i ] ) ; } if ( ! ended ) { next ( ) ; } } ) ) ) ; } since export function toRequestHandler < I , O , E > ( middleware ) { return ( req , res , next ) => exec ( middleware , req , res , next ) ; } since export function toErrorRequestHandler < I , O , E > ( f ) { return ( err , req , res , next ) => exec ( f ( err ) , req , res , next ) ; } since export function fromRequestHandler < I = StatusOpen , E = never , A = never > ( requestHandler , f ) ; export function fromRequestHandler < I = StatusOpen , E = never , A = never > ( requestHandler , f , onError ) ; export function fromRequestHandler < I = StatusOpen , E = never , A = never > ( requestHandler , f , onError ? ) { return ( c ) => ( ) => new Promise ( ( resolve ) => { const { req , res } = c as ExpressConnection < I > ; const cb = onError ? ( err ) => err ? resolve ( E . left ( onError ( err ) ) ) : pipe ( req , f as ( req : Request ) => E . Either < E , A > , E . map ( ( a ) : [ A , Connection < I > ] => [ a , c ] ) , resolve ) : ( ) => resolve ( E . right ( [ ( f as ( req : Request ) => A ) ( req ) , c ] ) ) ; requestHandler ( req , res , cb ) ; } ) ; }