Fix TypeScript and ESLint errors (#31)

- Add proper type annotations for WebSocketMessage and ServerInfo types
- Fix type imports to use type-only imports where appropriate
- Replace logical OR operators with nullish coalescing operators
- Fix floating promises by adding void operator
- Add proper type assertions for database results
- Fix useEffect dependencies in Terminal component
- Remove unused variables and fix unescaped entities
- Add JSDoc type annotations for database methods
- Fix singleton instance type annotations
This commit is contained in:
Michel Roegl-Brunner
2025-09-30 11:30:43 +02:00
committed by GitHub
parent 2f1df95d90
commit 433d8121e8
23 changed files with 2964 additions and 183 deletions

View File

@@ -1,6 +1,8 @@
import { WebSocketServer, WebSocket } from 'ws';
import type { IncomingMessage } from 'http';
import { scriptManager } from '~/server/lib/scripts';
import { getSSHExecutionService } from '~/server/ssh-execution-service';
import type { Server } from '~/types/server';
interface ScriptExecutionMessage {
type: 'start' | 'output' | 'error' | 'end';
@@ -48,13 +50,15 @@ export class ScriptExecutionHandler {
});
}
private async handleMessage(ws: WebSocket, message: { action: string; scriptPath?: string; executionId?: string }) {
const { action, scriptPath, executionId } = message;
private async handleMessage(ws: WebSocket, message: { action: string; scriptPath?: string; executionId?: string; mode?: 'local' | 'ssh'; server?: any }) {
const { action, scriptPath, executionId, mode, server } = message;
console.log('WebSocket message received:', { action, scriptPath, executionId, mode, server: server ? { name: server.name, ip: server.ip } : null });
switch (action) {
case 'start':
if (scriptPath && executionId) {
await this.startScriptExecution(ws, scriptPath, executionId);
await this.startScriptExecution(ws, scriptPath, executionId, mode, server);
} else {
this.sendMessage(ws, {
type: 'error',
@@ -79,19 +83,10 @@ export class ScriptExecutionHandler {
}
}
private async startScriptExecution(ws: WebSocket, scriptPath: string, executionId: string) {
private async startScriptExecution(ws: WebSocket, scriptPath: string, executionId: string, mode?: 'local' | 'ssh', server?: any) {
console.log('startScriptExecution called with:', { scriptPath, executionId, mode, server: server ? { name: server.name, ip: server.ip } : null });
try {
// Validate script path
const validation = scriptManager.validateScriptPath(scriptPath);
if (!validation.valid) {
this.sendMessage(ws, {
type: 'error',
data: validation.message ?? 'Invalid script path',
timestamp: Date.now()
});
return;
}
// Check if execution is already running
if (this.activeExecutions.has(executionId)) {
this.sendMessage(ws, {
@@ -102,61 +97,135 @@ export class ScriptExecutionHandler {
return;
}
// Start script execution
const process = await scriptManager.executeScript(scriptPath);
let process: any;
if (mode === 'ssh' && server) {
// SSH execution
console.log('Starting SSH execution:', { scriptPath, server });
console.log('SSH execution mode detected, calling SSH service...');
console.log('Mode check: mode=', mode, 'server=', !!server);
this.sendMessage(ws, {
type: 'start',
data: `Starting SSH execution of ${scriptPath} on ${server.name ?? server.ip}`,
timestamp: Date.now()
});
const sshService = getSSHExecutionService();
console.log('SSH service obtained, calling executeScript...');
console.log('SSH service object:', typeof sshService, sshService.constructor.name);
try {
const result = await sshService.executeScript(server as Server, scriptPath,
(data: string) => {
console.log('SSH onData callback:', data.substring(0, 100) + '...');
this.sendMessage(ws, {
type: 'output',
data: data,
timestamp: Date.now()
});
},
(error: string) => {
console.log('SSH onError callback:', error);
this.sendMessage(ws, {
type: 'error',
data: error,
timestamp: Date.now()
});
},
(code: number) => {
console.log('SSH onExit callback, code:', code);
this.sendMessage(ws, {
type: 'end',
data: `SSH script execution finished with code: ${code}`,
timestamp: Date.now()
});
this.activeExecutions.delete(executionId);
}
);
console.log('SSH service executeScript completed, result:', result);
process = (result as any).process;
} catch (sshError) {
console.error('SSH service executeScript failed:', sshError);
this.sendMessage(ws, {
type: 'error',
data: `SSH execution failed: ${sshError instanceof Error ? sshError.message : String(sshError)}`,
timestamp: Date.now()
});
return;
}
} else {
// Local execution
console.log('Starting local execution:', { scriptPath });
console.log('Local execution mode detected, calling local script manager...');
console.log('Mode check: mode=', mode, 'server=', !!server, 'condition result:', mode === 'ssh' && server);
// Validate script path
const validation = scriptManager.validateScriptPath(scriptPath);
if (!validation.valid) {
this.sendMessage(ws, {
type: 'error',
data: validation.message ?? 'Invalid script path',
timestamp: Date.now()
});
return;
}
// Start script execution
process = await scriptManager.executeScript(scriptPath);
// Send start message
this.sendMessage(ws, {
type: 'start',
data: `Starting execution of ${scriptPath}`,
timestamp: Date.now()
});
// Handle stdout
process.stdout?.on('data', (data: Buffer) => {
this.sendMessage(ws, {
type: 'output',
data: data.toString(),
timestamp: Date.now()
});
});
// Handle stderr
process.stderr?.on('data', (data: Buffer) => {
this.sendMessage(ws, {
type: 'error',
data: data.toString(),
timestamp: Date.now()
});
});
// Handle process exit
process.on('exit', (code: number | null, signal: string | null) => {
this.sendMessage(ws, {
type: 'end',
data: `Script execution finished with code: ${code}, signal: ${signal}`,
timestamp: Date.now()
});
// Clean up
this.activeExecutions.delete(executionId);
});
// Handle process error
process.on('error', (error: Error) => {
this.sendMessage(ws, {
type: 'error',
data: `Process error: ${error.message}`,
timestamp: Date.now()
});
// Clean up
this.activeExecutions.delete(executionId);
});
}
// Store the execution
this.activeExecutions.set(executionId, { process, ws });
// Send start message
this.sendMessage(ws, {
type: 'start',
data: `Starting execution of ${scriptPath}`,
timestamp: Date.now()
});
// Handle stdout
process.stdout?.on('data', (data: Buffer) => {
this.sendMessage(ws, {
type: 'output',
data: data.toString(),
timestamp: Date.now()
});
});
// Handle stderr
process.stderr?.on('data', (data: Buffer) => {
this.sendMessage(ws, {
type: 'error',
data: data.toString(),
timestamp: Date.now()
});
});
// Handle process exit
process.on('exit', (code: number | null, signal: string | null) => {
this.sendMessage(ws, {
type: 'end',
data: `Script execution finished with code: ${code}, signal: ${signal}`,
timestamp: Date.now()
});
// Clean up
this.activeExecutions.delete(executionId);
});
// Handle process error
process.on('error', (error: Error) => {
this.sendMessage(ws, {
type: 'error',
data: `Process error: ${error.message}`,
timestamp: Date.now()
});
// Clean up
this.activeExecutions.delete(executionId);
});
} catch (error) {
this.sendMessage(ws, {
type: 'error',