type ErrorTrackingModule = typeof import ( '../error-tracking' ) ; type IndexTypeModule = typeof import ( '../index' ) ; const envToken = process . env . HTK_SERVER_TOKEN ; delete process . env . HTK_SERVER_TOKEN ; import * as path from 'path' ; import { promises as fs } from 'fs' ; import * as semver from 'semver' ; import { IS_PROD_BUILD } from '../constants' ; function maybeBundleImport < T > ( moduleName ) { if ( IS_PROD_BUILD || process . env . OCLIF_TS_NODE === '0' ) { try { return require ( '../../bundle/' + moduleName ) ; } catch ( e ) { console . log ( e ) ; console . log ( `Could not load bundle ${ moduleName }, loading raw` ) ; return require ( '../' + moduleName ) ; } } else { return require ( '../' + moduleName ) ; } } const { initErrorTracking , reportError } = maybeBundleImport < ErrorTrackingModule > ( 'error-tracking' ) ; initErrorTracking ( ) ; import { Command , flags } from '@oclif/command' ; const { runHTK } = maybeBundleImport < IndexTypeModule > ( 'index' ) ; class HttpToolkitServer extends Command { static description = 'start the HTTP Toolkit server' ; static flags = { version : flags . version ( { char : 'v' } ) , help : flags . help ( { char : 'h' } ) , config : flags . string ( { char : 'c' , description : 'optional path in which to store config files' } ) , token : flags . string ( { char : 't' , description : 'optional token to authenticate local server access' } ) , } ; async run ( ) { const { flags } = this . parse ( HttpToolkitServer ) ; this . cleanupOldServers ( ) ; await runHTK ( { configPath : flags . config , authToken : envToken || flags . token } ) . catch ( async ( error ) => { await reportError ( error ) ; throw error ; } ) ; } async cleanupOldServers ( ) { if ( ! fs ) return ; const { dataDir , version : currentVersion } = this . config ; const serverUpdatesPath = process . env . OCLIF_CLIENT_HOME || path . join ( dataDir , 'client' ) ; if ( ! isOwnedPath ( serverUpdatesPath ) ) { reportError ( `Unexpected server updates path (${ serverUpdatesPath }), ignoring` ) ; return ; } const serverPaths = await fs . readdir ( serverUpdatesPath ) . catch ( ( e ) => { if ( e . code === 'ENOENT' ) return null ; else throw e ; } ) ; if ( ! serverPaths ) return ; if ( serverPaths . some ( ( filename ) => ! semver . valid ( filename . replace ( /\.partial\.\d+$/ , '' ) ) && filename !== 'bin' && filename !== 'current' && filename !== '.DS_Store' ) ) { console . log ( serverPaths ) ; reportError ( `Server path (${ serverUpdatesPath }) contains unexpected content, ignoring` ) ; return ; } const maybeReportError = ( error ) => { if ( [ 'EBUSY' , 'EPERM' ] . includes ( error . code ! ) ) return ; else reportError ( error ) ; } ; if ( serverPaths . every ( ( filename ) => { const version = semver . valid ( filename . replace ( /\.partial\.\d+$/ , '' ) ) ; return ! version || semver . lt ( version , currentVersion ) ; } ) ) { console . log ( "Downloaded server directory is entirely outdated, deleting it" ) ; deleteFolder ( serverUpdatesPath ) . catch ( maybeReportError ) ; } else { serverPaths . forEach ( ( filename ) => { const version = semver . valid ( filename . replace ( /\.partial\.\d+$/ , '' ) ) ; if ( version && semver . lt ( version , currentVersion ) ) { console . log ( `Deleting old server ${ filename }` ) ; deleteFolder ( path . join ( serverUpdatesPath , filename ) ) . catch ( maybeReportError ) ; } } ) ; } } } async function deleteFolder ( folder ) { const contents = await fs . readdir ( folder ) . catch ( ( e ) => { if ( e . code === 'ENOENT' ) return [ ] ; else throw e ; } ) ; await Promise . all ( contents . map ( async ( filename ) => { const filePath = path . join ( folder , filename ) ; if ( ( await fs . lstat ( filePath ) ) . isDirectory ( ) ) { await deleteFolder ( filePath ) ; } else if ( isOwnedPath ( filePath ) ) { await fs . unlink ( filePath ) ; } } ) ) ; if ( isOwnedPath ( folder ) ) await fs . rmdir ( folder ) ; } ; function isOwnedPath ( input ) { if ( input . split ( path . sep ) . includes ( 'httptoolkit-server' ) ) { return true ; } else { reportError ( `Unexpected unowned path ${ input }` ) ; return false ; } } export = HttpToolkitServer ;