import { EventEmitter } from 'events'; /** * Interface for remote server connection configuration */ export interface RemoteConnectionConfig { host: string; port: number; username: string; password?: string; privateKey?: string; passphrase?: string; name?: string; useSudo?: boolean; } /** * Type for remote command execution results */ export interface CommandResult { stdout: string; stderr: string; code: number | null; } /** * Class to manage SSH connections to remote servers */ export declare class RemoteConnection extends EventEmitter { private client; private config; private _isConnected; isPM2Installed: boolean; name: string; host: string; port: number; username: string; get hasPassword(): boolean; get hasPrivateKey(): boolean; get hasPassphrase(): boolean; get secureConfig(): RemoteConnectionConfig; getFullConfig(): RemoteConnectionConfig; constructor(config: RemoteConnectionConfig); /** * Check if the connection is active */ isConnected(): boolean; /** * Connect to the remote server */ connect(): Promise; /** * Disconnect from the remote server */ disconnect(): Promise; /** * Execute a command on the remote server * @param command The command to execute * @param forceSudo Whether to force using sudo for this specific command */ executeCommand(command: string, forceSudo?: boolean): Promise; /** * Stream a remote file directly into an HTTP response without buffering. * * Strategy (tried in order): * 1. SFTP createReadStream — best; handles large files, uses file-transfer protocol * 2. exec `cat ` — current SSH user, direct pipe to response * 3. exec `sudo -S cat` — password-based sudo (when password auth is configured) * 4. exec `sudo cat` — NOPASSWD sudo (key-based auth where sudo needs no password) */ private static readonly SHELL_UNSAFE; private static validateRemotePath; streamFileToResponse(remotePath: string, res: import('express').Response, fileName: string): Promise; /** * Stream a remote .gz file to an HTTP response, decompressing it on the fly. * Uses SFTP + local zlib.createGunzip() pipeline — no server-side buffering. * Falls back to exec `zcat` if SFTP is unavailable. */ streamGzFileToResponse(remotePath: string, res: import('express').Response, fileName: string): Promise; /** * Check if PM2 is installed on the remote server * Uses multiple detection methods for better reliability */ checkPM2Installation(): Promise; /** * Ordered list of command builders tried when resolving the pm2 binary. * The index of the first successful builder is cached so that subsequent * calls (including streaming commands) reuse the same invocation. */ private static readonly PM2_BUILDERS; /** Index into PM2_BUILDERS of the invocation that actually works on this host. -1 = not yet resolved. */ private resolvedBuilderIndex; /** * Execute a PM2 command with proper PATH handling. * The first successful invocation is cached so later calls (and streaming * commands) reuse the same shell/binary path without re-probing. */ executePM2Command(pm2Args: string): Promise; /** * Build a pm2 command string using the already-resolved invocation pattern. * Falls back to bash -li -c if the resolver has not yet run. * Use this when you need the raw command string for a streaming shell exec. */ buildPM2StreamCommand(pm2Args: string): string; /** * Get PM2 processes from the remote server */ getPM2Processes(): Promise; /** * Format memory size to human readable format */ private formatMemory; /** * Format uptime to human readable format */ private formatUptime; /** * Start a PM2 process */ startPM2Process(processName: string): Promise; /** * Stop a PM2 process */ stopPM2Process(processName: string): Promise; /** * Restart a PM2 process */ restartPM2Process(processName: string): Promise; /** * Delete a PM2 process */ deletePM2Process(processName: string): Promise; /** * Install PM2 on the remote server */ installPM2(): Promise; /** * Get system information from the remote server */ getSystemInfo(): Promise; /** * Get logs for a PM2 process */ getPM2Logs(processName: string, lines?: number): Promise; /** * Create a streaming log connection for a command */ createLogStream(command: string, useSudo?: boolean): Promise; } /** * Interface for saved connection configuration */ export interface SavedConnectionConfig extends RemoteConnectionConfig { id: string; } /** * Connection manager to handle multiple remote connections */ export declare class RemoteConnectionManager { private connections; private configFilePath; constructor(); /** * Create a new remote connection * @param config Connection configuration * @returns The connection ID */ createConnection(config: RemoteConnectionConfig): string; /** * Update an existing remote connection * @param connectionId The connection ID * @param config New connection configuration * @returns True if the connection was updated, false if it didn't exist */ updateConnection(connectionId: string, config: RemoteConnectionConfig): Promise; /** * Get a connection by ID * @param connectionId The connection ID */ getConnection(connectionId: string): RemoteConnection | undefined; /** * Close a connection by ID (disconnect but keep the configuration) * @param connectionId The connection ID */ closeConnection(connectionId: string): Promise; /** * Close all connections */ closeAllConnections(): Promise; /** * Get all connections * @returns Map of all connections */ getAllConnections(): Map; /** * Delete a connection by ID * @param connectionId The connection ID * @returns True if the connection was deleted, false if it didn't exist */ deleteConnection(connectionId: string): boolean; /** * Load connection configurations from disk */ private loadConnectionsFromDisk; /** * Save connection configurations to disk */ private saveConnectionsToDisk; } export declare const remoteConnectionManager: RemoteConnectionManager;