import consola from 'consola' ; import WebSocket , { MessageEvent } from 'ws' ; import { RequiredAuth } from './auth' ; import { connect } from './connection' ; import { BaseMessage , buildInitialMessage , buildOTMessage } from './messages' ; import { FinishedResponse , ProblemResponse } from './responses' ; /**
 * The completed result from a Grammarly analysis session
 */ export interface GrammarlyResult { alerts : ProblemResponse [ ] ; result : FinishedResponse ; corrected ? : string ; original : string ; } export interface GrammarlyOptions { username ? : string ; password ? : string ; auth ? : RequiredAuth ; agent ? : any ; } /**
 * Manage an interactive Grammarly session.
 */ export class Grammarly { private connection ! : WebSocket ; private dialect : 'american' | 'british' ; private get isEstablished ( ) : boolean { return ( this . connection !== undefined && this . connection instanceof WebSocket && this . connection . readyState === WebSocket . OPEN ) ; } constructor ( private options = { } ) { } param text param timeout param dialect public async analyse ( text , timeout = 30000 , dialect = 'british' ) { if ( ! this . isEstablished || dialect !== this . dialect ) { await this . establish ( dialect ) ; } consola . debug ( 'Successfully connected to Grammarly!' ) ; return new Promise ( ( resolve , reject ) => { this . connection . send ( JSON . stringify ( buildOTMessage ( text ) ) ) ; consola . debug ( 'Sent text to Grammarly!' ) ; const alerts = [ ] ; /**
             * This message handler will listen for all corrections from the server. Once it receives
             * the  CompleteMessage object the promise will resolve.
              this . connection . onmessage = ( message ) => { const parsed = JSON . parse ( message . data . toString ( ) ) ; if ( parsed . action === 'alert' ) { const alert = parsed as ProblemResponse ; alerts . push ( alert ) ; } else if ( parsed . action === 'finished' ) { const result = parsed as FinishedResponse ; resolve ( { alerts , result , original : text } ) ; this . connection . close ( ) ; } } ; const interval = setInterval ( ( ) => { reject ( new Error ( 'Still waiting for results before timeout' ) ) ; this . connection . close ( ) ; clearInterval ( interval ) ; } , timeout ) ; } ) ; } param dialect returns throws private async establish ( dialect = 'british' ) { consola . debug ( 'Re-establishing connection.' ) ; const { connection } = await connect ( this . options . auth , this . options . agent ) ; this . connection = connection ; this . connection . send ( JSON . stringify ( buildInitialMessage ( dialect ) ) ) ; this . dialect = dialect ; consola . debug ( 'Sent establishing message' ) ; return new Promise ( ( resolve , reject ) => { /**
             * The first message should be in this form:
             *
             * ```js
             * { sid: 0, action: 'start', id: 0 }
             * ```
             *
             *  Receiving this, without another 'error' message, means the connection is
             *  ready to go and we can start sending text.
             */ this . connection . onmessage = ( message ) => { const parsedMessage = JSON . parse ( message . data . toString ( ) ) as BaseMessage ; if ( parsedMessage && parsedMessage . action === 'start' ) { this . connection . onmessage = ( ) => null ; resolve ( parsedMessage as BaseMessage ) ; } else { reject ( parsedMessage ) ; } } ; } ) ; } }