UNPKG

@aerocorp/cli

Version:

AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps

313 lines (261 loc) • 10.4 kB
/** * AeroCorp CLI 4.0.0 - Database Management Service * Comprehensive database operations for hybrid infrastructure */ import axios from 'axios'; import chalk from 'chalk'; import inquirer from 'inquirer'; import { ConfigService } from './config'; import { AuthService } from './auth'; export interface DatabaseInstance { id: string; name: string; type: 'postgresql' | 'mysql' | 'mongodb' | 'redis'; status: 'running' | 'stopped' | 'maintenance'; version: string; size: string; connections: number; maxConnections: number; lastBackup: string; platform: 'coolify' | 'caprover'; url: string; } export interface BackupInfo { id: string; databaseId: string; database: string; size: string; timestamp: string; type: 'automatic' | 'manual'; status: 'completed' | 'failed' | 'in_progress'; location: string; } export class DatabaseService { private configService: ConfigService; private authService: AuthService; constructor() { this.configService = new ConfigService(); this.authService = new AuthService(); } async listDatabases(options: { platform?: string; type?: string; status?: string } = {}): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); const params = new URLSearchParams(); if (options.platform) params.append('platform', options.platform); if (options.type) params.append('type', options.type); if (options.status) params.append('status', options.status); const response = await axios.get(`${config.apiUrl}/api/databases?${params}`, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); const data = response.data; console.log(chalk.cyan.bold('\nšŸ’¾ Database Instances')); console.log(chalk.gray(`Total: ${data.total} databases`)); console.log(chalk.gray(`Running: ${data.summary.running} | Stopped: ${data.summary.stopped} | Maintenance: ${data.summary.maintenance}`)); if (data.databases.length === 0) { console.log(chalk.yellow('No databases found')); return; } console.log('\n' + chalk.white('Name'.padEnd(25) + 'Type'.padEnd(12) + 'Status'.padEnd(12) + 'Platform'.padEnd(12) + 'Size'.padEnd(10) + 'Connections')); console.log(chalk.gray('─'.repeat(80))); data.databases.forEach((db: DatabaseInstance) => { const statusIcon = db.status === 'running' ? 'āœ…' : db.status === 'maintenance' ? 'āš ļø' : 'āŒ'; const statusColor = db.status === 'running' ? chalk.green : db.status === 'maintenance' ? chalk.yellow : chalk.red; console.log( `${statusIcon} ${chalk.white(db.name.padEnd(22))} ` + `${chalk.blue(db.type.padEnd(11))} ` + `${statusColor(db.status.padEnd(11))} ` + `${chalk.cyan(db.platform.padEnd(11))} ` + `${chalk.white(db.size.padEnd(9))} ` + `${chalk.white(db.connections + '/' + db.maxConnections)}` ); }); } catch (error) { throw new Error(`Failed to list databases: ${error.message}`); } } async createDatabase(options: any = {}): Promise<void> { try { let dbConfig; if (options.interactive !== false) { dbConfig = await inquirer.prompt([ { type: 'input', name: 'name', message: 'Database name:', default: options.name, validate: (input) => input.length > 0 || 'Name is required' }, { type: 'list', name: 'type', message: 'Database type:', choices: ['postgresql', 'mysql', 'mongodb', 'redis'], default: options.type || 'postgresql' }, { type: 'list', name: 'platform', message: 'Deployment platform:', choices: ['coolify', 'caprover'], default: options.platform || 'coolify' }, { type: 'input', name: 'version', message: 'Version (leave empty for latest):', default: options.version || '' }, { type: 'input', name: 'initialSize', message: 'Initial storage size:', default: options.initialSize || '1GB' } ]); } else { dbConfig = options; } const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Creating database...')); const response = await axios.post(`${config.apiUrl}/api/databases`, dbConfig, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 30000 }); const database = response.data.database; console.log(chalk.green('āœ… Database created successfully!')); console.log(chalk.white(`Name: ${database.name}`)); console.log(chalk.white(`Type: ${database.type}`)); console.log(chalk.white(`Platform: ${database.platform}`)); console.log(chalk.white(`URL: ${database.url}`)); } catch (error) { throw new Error(`Failed to create database: ${error.message}`); } } async backupDatabase(databaseId: string, options: { type?: string } = {}): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Starting database backup...')); const response = await axios.post(`${config.apiUrl}/api/databases/${databaseId}/backup`, { type: options.type || 'manual' }, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 30000 }); const backup = response.data.backup; console.log(chalk.green('āœ… Backup started successfully!')); console.log(chalk.white(`Backup ID: ${backup.id}`)); console.log(chalk.white(`Database: ${backup.database}`)); console.log(chalk.white(`Type: ${backup.type}`)); console.log(chalk.white(`Status: ${backup.status}`)); } catch (error) { throw new Error(`Failed to backup database: ${error.message}`); } } async restoreDatabase(databaseId: string, backupId: string): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Starting database restore...')); const response = await axios.post(`${config.apiUrl}/api/databases/${databaseId}/restore`, { backupId }, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 60000 }); console.log(chalk.green('āœ… Restore started successfully!')); console.log(chalk.yellow('āš ļø Database will be in maintenance mode during restore')); } catch (error) { throw new Error(`Failed to restore database: ${error.message}`); } } async listBackups(databaseId?: string): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); const url = databaseId ? `${config.apiUrl}/api/databases/${databaseId}/backups` : `${config.apiUrl}/api/databases/backups`; const response = await axios.get(url, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); const data = response.data; console.log(chalk.cyan.bold('\nšŸ’¾ Database Backups')); console.log(chalk.gray(`Total: ${data.total} backups`)); if (data.backups.length === 0) { console.log(chalk.yellow('No backups found')); return; } console.log('\n' + chalk.white('Database'.padEnd(25) + 'Size'.padEnd(10) + 'Type'.padEnd(12) + 'Status'.padEnd(12) + 'Date')); console.log(chalk.gray('─'.repeat(80))); data.backups.forEach((backup: BackupInfo) => { const statusIcon = backup.status === 'completed' ? 'āœ…' : backup.status === 'in_progress' ? 'šŸ”„' : 'āŒ'; const statusColor = backup.status === 'completed' ? chalk.green : backup.status === 'in_progress' ? chalk.blue : chalk.red; console.log( `${statusIcon} ${chalk.white(backup.database.padEnd(22))} ` + `${chalk.white(backup.size.padEnd(9))} ` + `${chalk.cyan(backup.type.padEnd(11))} ` + `${statusColor(backup.status.padEnd(11))} ` + `${chalk.gray(new Date(backup.timestamp).toLocaleDateString())}` ); }); } catch (error) { throw new Error(`Failed to list backups: ${error.message}`); } } async deleteDatabase(databaseId: string, options: { force?: boolean } = {}): Promise<void> { try { if (!options.force) { const confirm = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message: 'Are you sure you want to delete this database? This action cannot be undone.', default: false } ]); if (!confirm.confirmed) { console.log(chalk.yellow('āŒ Database deletion cancelled')); return; } } const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Deleting database...')); const response = await axios.delete(`${config.apiUrl}/api/databases/${databaseId}`, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 30000 }); console.log(chalk.green('āœ… Database deleted successfully!')); console.log(chalk.gray(`Removed ${response.data.removedBackups} associated backups`)); } catch (error) { throw new Error(`Failed to delete database: ${error.message}`); } } }