@aerocorp/cli
Version:
AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps
195 lines (158 loc) ⢠6.39 kB
text/typescript
import axios from 'axios';
import chalk from 'chalk';
import ora from 'ora';
import { AuthService } from './auth';
export class ProjectService {
private authService = new AuthService();
async list(options: any) {
if (!this.authService.isAuthenticated()) {
throw new Error('Not authenticated. Run "aerocorp login" first.');
}
const spinner = ora('Fetching projects...').start();
try {
const coolifyUrl = this.authService.getCoolifyUrl();
const headers = this.authService.getAuthHeaders();
// Get projects
const projectsResponse = await axios.get(`${coolifyUrl}/api/v1/projects`, { headers });
const projects = projectsResponse.data;
// Get applications for each project
const projectsWithApps = await Promise.all(
projects.map(async (project: any) => {
try {
const appsResponse = await axios.get(
`${coolifyUrl}/api/v1/projects/${project.id}/applications`,
{ headers }
);
return {
...project,
applications: appsResponse.data || []
};
} catch (error) {
return {
...project,
applications: []
};
}
})
);
spinner.succeed('Projects fetched successfully');
if (options.format === 'json') {
console.log(JSON.stringify(projectsWithApps, null, 2));
return;
}
// Display in table format
this.displayProjectsTable(projectsWithApps);
} catch (error) {
spinner.fail('Failed to fetch projects');
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please run "aerocorp login" again.');
} else if (error.response?.status === 403) {
throw new Error('Access forbidden. Check your API token permissions.');
} else {
throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
}
}
}
private displayProjectsTable(projects: any[]) {
console.log(chalk.cyan('\nš AeroCorp Projects & Applications'));
console.log(chalk.cyan('====================================='));
if (projects.length === 0) {
console.log(chalk.yellow('ā No projects found'));
return;
}
projects.forEach((project, index) => {
console.log(chalk.blue(`\n${index + 1}. ${project.name}`));
console.log(chalk.gray(` UUID: ${project.uuid}`));
console.log(chalk.gray(` Description: ${project.description || 'No description'}`));
if (project.applications && project.applications.length > 0) {
console.log(chalk.green(` Applications (${project.applications.length}):`));
project.applications.forEach((app: any, appIndex: number) => {
const status = this.getStatusIcon(app.status);
const url = app.url ? chalk.blue(app.url) : chalk.gray('No URL');
console.log(chalk.white(` ${appIndex + 1}. ${status} ${app.name}`));
console.log(chalk.gray(` Environment: ${app.environment || 'default'}`));
console.log(chalk.gray(` URL: ${url}`));
console.log(chalk.gray(` Status: ${app.status || 'unknown'}`));
if (app.last_deployment) {
const deployTime = new Date(app.last_deployment).toLocaleString();
console.log(chalk.gray(` Last Deploy: ${deployTime}`));
}
});
} else {
console.log(chalk.gray(' Applications: None'));
}
});
// Summary
const totalApps = projects.reduce((sum, project) => sum + (project.applications?.length || 0), 0);
console.log(chalk.cyan(`\nš Summary: ${projects.length} projects, ${totalApps} applications`));
}
private getStatusIcon(status?: string): string {
switch (status?.toLowerCase()) {
case 'running':
case 'active':
case 'healthy':
return chalk.green('ā');
case 'stopped':
case 'inactive':
return chalk.red('ā');
case 'building':
case 'deploying':
return chalk.yellow('ā');
case 'error':
case 'failed':
return chalk.red('ā');
default:
return chalk.gray('ā');
}
}
async create(name: string, description?: string) {
if (!this.authService.isAuthenticated()) {
throw new Error('Not authenticated. Run "aerocorp login" first.');
}
const spinner = ora(`Creating project: ${name}...`).start();
try {
const coolifyUrl = this.authService.getCoolifyUrl();
const headers = this.authService.getAuthHeaders();
const response = await axios.post(
`${coolifyUrl}/api/v1/projects`,
{
name,
description: description || `AeroCorp project: ${name}`
},
{ headers }
);
spinner.succeed(`Project '${name}' created successfully`);
console.log(chalk.green('ā Project created'));
console.log(chalk.blue(`š¦ Name: ${response.data.name}`));
console.log(chalk.blue(`š UUID: ${response.data.uuid}`));
return response.data;
} catch (error) {
spinner.fail(`Failed to create project: ${name}`);
if (error.response?.status === 409) {
throw new Error(`Project '${name}' already exists`);
} else {
throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
}
}
}
async delete(projectId: string) {
if (!this.authService.isAuthenticated()) {
throw new Error('Not authenticated. Run "aerocorp login" first.');
}
const spinner = ora(`Deleting project: ${projectId}...`).start();
try {
const coolifyUrl = this.authService.getCoolifyUrl();
const headers = this.authService.getAuthHeaders();
await axios.delete(`${coolifyUrl}/api/v1/projects/${projectId}`, { headers });
spinner.succeed(`Project '${projectId}' deleted successfully`);
console.log(chalk.green('ā Project deleted'));
} catch (error) {
spinner.fail(`Failed to delete project: ${projectId}`);
if (error.response?.status === 404) {
throw new Error(`Project '${projectId}' not found`);
} else {
throw new Error(`API Error: ${error.response?.data?.message || error.message}`);
}
}
}
}