@aerocorp/cli
Version:
AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps
295 lines ⢠13 kB
JavaScript
;
/**
* AeroCorp CLI 5.0.0 - Vercel-like Deployment Service
* Windows-native deployment that works like "npx vercel --prod"
* Uses HTTP APIs primarily, SSH only as fallback
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VercelLikeDeployService = void 0;
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const fs_1 = require("fs");
const config_1 = require("./config");
const coolify_1 = require("./coolify");
const ssh_native_1 = require("./ssh-native");
const windows_native_1 = require("./windows-native");
class VercelLikeDeployService {
constructor() {
this.configService = new config_1.ConfigService();
this.coolifyService = new coolify_1.CoolifyService();
this.sshService = new ssh_native_1.NativeSSHService();
this.windowsService = new windows_native_1.WindowsNativeService();
}
/**
* Main deployment function - works like "npx vercel --prod"
*/
async deploy(options = {}) {
const startTime = Date.now();
console.log(chalk_1.default.cyan.bold('\nš AeroCorp Deployment (Vercel-like)'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
try {
// Step 1: Environment validation
await this.validateEnvironment();
// Step 2: Project detection
const project = await this.detectProject();
console.log(chalk_1.default.blue(`š¦ Detected: ${project.type} project`));
// Step 3: Build if needed
if (options.build !== false && project.buildCommand) {
await this.buildProject(project);
}
// Step 4: Deploy via Coolify API (primary method)
const deployResult = await this.deployViaCoolify(project, options);
const duration = Date.now() - startTime;
console.log(chalk_1.default.green.bold('\nš Deployment completed successfully!'));
console.log(chalk_1.default.white(`ā±ļø Duration: ${Math.round(duration / 1000)}s`));
if (deployResult.url) {
console.log(chalk_1.default.blue(`š URL: ${deployResult.url}`));
}
return {
success: true,
url: deployResult.url,
deploymentId: deployResult.deploymentId,
duration
};
}
catch (error) {
const duration = Date.now() - startTime;
console.log(chalk_1.default.red.bold('\nā Deployment failed'));
console.log(chalk_1.default.white(`ā±ļø Duration: ${Math.round(duration / 1000)}s`));
console.error(chalk_1.default.red('Error:'), error.message);
return {
success: false,
duration
};
}
}
/**
* Validate deployment environment
*/
async validateEnvironment() {
const spinner = (0, ora_1.default)('Validating environment...').start();
try {
// Check authentication
if (!this.coolifyService.isAuthenticated()) {
spinner.fail('Authentication required');
console.log(chalk_1.default.red('ā Not authenticated with Coolify'));
console.log(chalk_1.default.yellow('š” Run: aerocorp coolify login'));
throw new Error('Authentication required');
}
// Check Coolify connectivity
const healthCheck = await this.coolifyService.healthCheck();
if (!healthCheck) {
throw new Error('Coolify health check failed');
}
spinner.succeed('Environment validated');
}
catch (error) {
spinner.fail('Environment validation failed');
throw error;
}
}
/**
* Detect project type and configuration
*/
async detectProject() {
const spinner = (0, ora_1.default)('Detecting project type...').start();
try {
let type = 'unknown';
let buildCommand;
let outputDir;
let packageManager = 'npm';
// Check for package manager
if ((0, fs_1.existsSync)('pnpm-lock.yaml')) {
packageManager = 'pnpm';
}
else if ((0, fs_1.existsSync)('yarn.lock')) {
packageManager = 'yarn';
}
// Check for project type
if ((0, fs_1.existsSync)('vite.config.ts') || (0, fs_1.existsSync)('vite.config.js')) {
type = 'vite';
buildCommand = `${packageManager} run build`;
outputDir = 'dist';
}
else if ((0, fs_1.existsSync)('next.config.js') || (0, fs_1.existsSync)('next.config.ts')) {
type = 'next';
buildCommand = `${packageManager} run build`;
outputDir = '.next';
}
else if ((0, fs_1.existsSync)('package.json')) {
const pkg = JSON.parse((0, fs_1.readFileSync)('package.json', 'utf8'));
if (pkg.dependencies?.react || pkg.devDependencies?.react) {
type = 'react';
buildCommand = `${packageManager} run build`;
outputDir = 'build';
}
else {
type = 'node';
buildCommand = pkg.scripts?.build ? `${packageManager} run build` : undefined;
}
}
else if ((0, fs_1.existsSync)('index.html')) {
type = 'static';
outputDir = '.';
}
const hasDockerfile = (0, fs_1.existsSync)('Dockerfile');
spinner.succeed(`Project detected: ${type}`);
return {
type,
buildCommand,
outputDir,
packageManager,
hasDockerfile
};
}
catch (error) {
spinner.fail('Project detection failed');
throw error;
}
}
/**
* Build project using detected package manager
*/
async buildProject(project) {
if (!project.buildCommand) {
console.log(chalk_1.default.blue('š¦ No build command detected, skipping build'));
return;
}
const spinner = (0, ora_1.default)(`Building project with ${project.packageManager}...`).start();
try {
const { spawn } = require('child_process');
const [command, ...args] = project.buildCommand.split(' ');
const buildProcess = spawn(command, args, {
stdio: ['pipe', 'pipe', 'pipe'],
shell: true,
cwd: process.cwd()
});
let buildOutput = '';
let buildError = '';
buildProcess.stdout?.on('data', (data) => {
buildOutput += data.toString();
});
buildProcess.stderr?.on('data', (data) => {
buildError += data.toString();
});
await new Promise((resolve, reject) => {
buildProcess.on('close', (code) => {
if (code === 0) {
resolve(void 0);
}
else {
reject(new Error(`Build failed with code ${code}\n${buildError}`));
}
});
buildProcess.on('error', (error) => {
reject(new Error(`Build process error: ${error.message}`));
});
});
spinner.succeed('Project built successfully');
console.log(chalk_1.default.green('ā
Build completed'));
}
catch (error) {
spinner.fail('Build failed');
throw error;
}
}
/**
* Deploy via Coolify API (primary method - like Vercel)
*/
async deployViaCoolify(project, options) {
const spinner = (0, ora_1.default)('Deploying via Coolify API...').start();
try {
// Determine environment
const environment = options.prod ? 'production' : (options.preview ? 'preview' : 'staging');
spinner.text = `Deploying to ${environment}...`;
// Use Coolify service for deployment
const deployResult = await this.coolifyService.deploy({
app: options.app,
branch: options.branch,
tag: options.tag,
environment
});
spinner.succeed(`Deployed to ${environment}`);
return {
url: deployResult.url,
deploymentId: deployResult.deployment_id
};
}
catch (error) {
spinner.fail('Coolify API deployment failed');
// Fallback to SSH deployment if API fails
console.log(chalk_1.default.yellow('š Falling back to SSH deployment...'));
return await this.deployViaSSH(project, options);
}
}
/**
* Fallback SSH deployment method
*/
async deployViaSSH(project, options) {
const spinner = (0, ora_1.default)('Deploying via SSH fallback...').start();
try {
// Connect to server
const connected = await this.sshService.connect();
if (!connected) {
throw new Error('SSH connection failed');
}
// Execute deployment commands via SSH
const deployCommands = [
'cd /opt/coolify',
`docker-compose exec coolify php artisan app:deploy ${options.app || 'default'}`
];
for (const command of deployCommands) {
spinner.text = `Executing: ${command}`;
const result = await this.sshService.executeCommand(command);
if (!result.success) {
throw new Error(`SSH command failed: ${command}\n${result.error}`);
}
}
spinner.succeed('SSH deployment completed');
return {
url: `https://${options.app || 'app'}.aerocorpindustries.org`,
deploymentId: `ssh-${Date.now()}`
};
}
catch (error) {
spinner.fail('SSH deployment failed');
throw error;
}
finally {
await this.sshService.disconnect();
}
}
/**
* Show deployment help (Vercel-like)
*/
showDeploymentHelp() {
console.log(chalk_1.default.cyan.bold('\nš AeroCorp Deployment Commands'));
console.log(chalk_1.default.gray('ā'.repeat(50)));
console.log(chalk_1.default.white('\nš Basic Usage:'));
console.log(chalk_1.default.blue(' aerocorp deploy # Deploy to staging'));
console.log(chalk_1.default.blue(' aerocorp deploy --prod # Deploy to production'));
console.log(chalk_1.default.blue(' aerocorp deploy --preview # Deploy preview'));
console.log(chalk_1.default.white('\nšÆ Advanced Options:'));
console.log(chalk_1.default.blue(' aerocorp deploy --app <uuid> # Specific application'));
console.log(chalk_1.default.blue(' aerocorp deploy --branch <name> # Specific branch'));
console.log(chalk_1.default.blue(' aerocorp deploy --tag <version> # Specific tag'));
console.log(chalk_1.default.blue(' aerocorp deploy --no-build # Skip build step'));
console.log(chalk_1.default.white('\nš PR Previews:'));
console.log(chalk_1.default.blue(' aerocorp preview up --pr 123 --app <uuid> --branch <name>'));
console.log(chalk_1.default.blue(' aerocorp preview down --pr 123 --app <uuid>'));
console.log(chalk_1.default.white('\nšŖ Windows-Specific:'));
console.log(chalk_1.default.blue(' aerocorp windows check # Check Windows environment'));
console.log(chalk_1.default.blue(' aerocorp windows setup-ssh # Setup SSH (fallback)'));
console.log(chalk_1.default.blue(' aerocorp windows test # Test all functionality'));
console.log(chalk_1.default.white('\nš” Pro Tips:'));
console.log(chalk_1.default.gray(' ⢠Set COOLIFY_TOKEN environment variable for automation'));
console.log(chalk_1.default.gray(' ⢠Use --prod flag for production deployments'));
console.log(chalk_1.default.gray(' ⢠SSH is only used as fallback - HTTP API is primary'));
console.log(chalk_1.default.gray(' ⢠Works natively on Windows, macOS, and Linux'));
}
}
exports.VercelLikeDeployService = VercelLikeDeployService;
//# sourceMappingURL=vercel-like-deploy.js.map