export interface Response { message : string ; payload : any ; query : string ; status : number ; type : string ; } export default class Client { private ws : WebSocket ; private index : number ; private callbacks : object ; static async connect ( uri , onClose = null ) { return new Promise ( ( resolve , reject ) => { const instance = new Client ( ) ; const ws = new WebSocket ( uri ) ; ws . onopen = ( ) => { resolve ( instance ) ; } ; ws . onerror = reject ; ws . onclose = < any > onClose || undefined ; ws . onmessage = ( msg ) => { const data = JSON . parse ( msg . data ) ; Object . entries ( data ) . forEach ( ( [ req , res ] ) => { instance . callbacks [ req ] ( res ) ; } ) ; } ; instance . ws = ws ; instance . index = 0 ; instance . callbacks = { } ; } ) ; } async request ( method , path , args = { } ) { return new Promise ( ( resolve , reject ) => { const req = `${ method } ${ path } ${ this . index ++ }` ; this . callbacks [ req ] = ( res ) => { delete this . callbacks [ req ] ; resolve ( res ) ; } ; this . ws . send ( JSON . stringify ( { [ req ] : args } ) ) ; } ) ; } async get ( path , args = { } ) { return this . request ( 'GET' , path , args ) ; } async post ( path , args = { } ) { return this . request ( 'POST' , path , args ) ; } async put ( path , args = { } ) { return this . request ( 'PUT' , path , args ) ; } async patch ( path , args = { } ) { return this . request ( 'PATCH' , path , args ) ; } async delete ( path , args = { } ) { return this . request ( 'DELETE' , path , args ) ; } async options ( path , args = { } ) { return this . request ( 'OPTIONS' , path , args ) ; } async subscribe ( path , args = { } , onChange = null ) { return this . request ( 'SUBSCRIBE' , path , args ) . then ( ( res ) => { if ( res . status . toString ( ) [ 0 ] !== '2' ) { return Promise . reject ( res ) ; } this . callbacks [ res . query ] = ( state ) => { if ( onChange ) { onChange ( state , res . query ) ; } } ; return res ; } ) ; } async unsubscribe ( query ) { this . request ( 'UNSUBSCRIBE' , query ) . then ( ( res ) => { if ( res . status . toString ( ) [ 0 ] !== '2' ) { return Promise . reject ( res ) ; } delete this . callbacks [ res . query ] ; return res ; } ) ; } disconnect ( ) { this . ws . close ( ) ; } }