UNPKG

myaidev-method

Version:

Comprehensive development framework with SPARC methodology for AI-assisted software development, multi-platform publishing (WordPress, PayloadCMS, Astro, Docusaurus, Mintlify), and Coolify deployment

381 lines (327 loc) 9.46 kB
/** * Coolify API Utilities * Reusable functions for Coolify deployment and resource management * Optimized for Claude Code 2.0 agent integration */ import fetch from 'node-fetch'; import { readFileSync } from 'fs'; import { parse } from 'dotenv'; export class CoolifyUtils { constructor(config = {}) { // Load config from .env if not provided if (!config.url || !config.apiKey) { const envConfig = this.loadEnvConfig(); config = { ...envConfig, ...config }; } this.url = config.url?.replace(/\/$/, ''); this.apiKey = config.apiKey; this.headers = { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', 'Accept': 'application/json' }; } loadEnvConfig() { try { const envPath = process.env.ENV_PATH || '.env'; const envContent = readFileSync(envPath, 'utf8'); const parsed = parse(envContent); return { url: parsed.COOLIFY_URL, apiKey: parsed.COOLIFY_API_KEY }; } catch (error) { throw new Error(`Failed to load Coolify configuration: ${error.message}`); } } /** * Make authenticated Coolify API request */ async request(endpoint, options = {}) { const url = `${this.url}${endpoint}`; try { const response = await fetch(url, { ...options, headers: { ...this.headers, ...options.headers } }); const data = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${data.message || response.statusText}`); } return data; } catch (error) { throw new Error(`Coolify API request failed: ${error.message}`); } } /** * Server Management */ async listServers() { return await this.request('/api/v1/servers'); } async getServer(uuid) { return await this.request(`/api/v1/servers/${uuid}`); } async getServerResources(uuid) { return await this.request(`/api/v1/servers/${uuid}/resources`); } /** * Project Management */ async listProjects() { return await this.request('/api/v1/projects'); } async getProject(uuid) { return await this.request(`/api/v1/projects/${uuid}`); } async createProject(data) { return await this.request('/api/v1/projects', { method: 'POST', body: JSON.stringify(data) }); } /** * Application Management */ async listApplications() { return await this.request('/api/v1/applications'); } async getApplication(uuid) { return await this.request(`/api/v1/applications/${uuid}`); } async createApplication(data) { // Coolify API requires /applications/public endpoint return await this.request('/api/v1/applications/public', { method: 'POST', body: JSON.stringify(data) }); } async updateApplication(uuid, data) { return await this.request(`/api/v1/applications/${uuid}`, { method: 'PATCH', body: JSON.stringify(data) }); } async deleteApplication(uuid) { return await this.request(`/api/v1/applications/${uuid}`, { method: 'DELETE' }); } /** * Deployment Operations */ async deployApplication(uuid, options = {}) { const endpoint = options.tag ? `/api/v1/deploy?tag=${options.tag}` : `/api/v1/deploy?uuid=${uuid}`; return await this.request(endpoint, { method: 'POST', body: JSON.stringify({ force: options.force || false, instant_deploy: options.instant || false, ...options.deployConfig }) }); } async getDeploymentLogs(uuid) { return await this.request(`/api/v1/applications/${uuid}/logs`); } async restartApplication(uuid) { return await this.request(`/api/v1/applications/${uuid}/restart`, { method: 'POST' }); } async stopApplication(uuid) { return await this.request(`/api/v1/applications/${uuid}/stop`, { method: 'POST' }); } /** * Environment Variables */ async getEnvironmentVariables(uuid) { return await this.request(`/api/v1/applications/${uuid}/envs`); } async updateEnvironmentVariables(uuid, envVars) { return await this.request(`/api/v1/applications/${uuid}/envs`, { method: 'POST', body: JSON.stringify(envVars) }); } /** * Database Management */ async listDatabases() { return await this.request('/api/v1/databases'); } async getDatabase(uuid) { return await this.request(`/api/v1/databases/${uuid}`); } async createDatabase(data) { return await this.request('/api/v1/databases', { method: 'POST', body: JSON.stringify(data) }); } /** * Service Management */ async listServices() { return await this.request('/api/v1/services'); } async getService(uuid) { return await this.request(`/api/v1/services/${uuid}`); } /** * Team Management */ async listTeams() { return await this.request('/api/v1/teams'); } async getCurrentTeam() { return await this.request('/api/v1/teams/current'); } /** * Health & Status */ async healthCheck() { try { const response = await fetch(`${this.url}/api/health`); return response.ok; } catch (error) { return false; } } async getSystemStatus() { const [servers, projects, applications] = await Promise.all([ this.listServers().catch(() => []), this.listProjects().catch(() => []), this.listApplications().catch(() => []) ]); return { healthy: await this.healthCheck(), servers: { total: servers.length, reachable: servers.filter(s => s.is_reachable).length, usable: servers.filter(s => s.is_usable).length }, projects: { total: projects.length }, applications: { total: applications.length } }; } /** * Deployment Helpers */ async findApplicationByName(name) { const apps = await this.listApplications(); return apps.find(app => app.name === name); } async findServerByName(name) { const servers = await this.listServers(); return servers.find(server => server.name === name); } async findProjectByName(name) { const projects = await this.listProjects(); return projects.find(project => project.name === name); } async waitForDeployment(uuid, options = {}) { const maxAttempts = options.maxAttempts || 60; const interval = options.interval || 5000; for (let i = 0; i < maxAttempts; i++) { const app = await this.getApplication(uuid); if (app.status === 'running') { return { success: true, status: 'running', attempts: i + 1 }; } if (app.status === 'error' || app.status === 'failed') { return { success: false, status: app.status, attempts: i + 1 }; } await new Promise(resolve => setTimeout(resolve, interval)); } return { success: false, status: 'timeout', attempts: maxAttempts }; } /** * Deployment Configuration Builders */ buildApplicationConfig(options) { return { name: options.name, description: options.description || '', project_uuid: options.projectUuid, server_uuid: options.serverUuid, destination_uuid: options.destinationUuid, source: { type: options.sourceType || 'git', repository: options.repository, branch: options.branch || 'main', commit: options.commit || null }, build_pack: options.buildPack || 'nixpacks', ports_exposes: options.ports || '3000', domains: options.domains || [], environment_variables: options.envVars || {}, settings: { instant_deploy: options.instantDeploy || false, auto_deploy: options.autoDeploy || true, ...options.settings } }; } buildDatabaseConfig(options) { return { name: options.name, description: options.description || '', project_uuid: options.projectUuid, server_uuid: options.serverUuid, destination_uuid: options.destinationUuid, type: options.type, // postgresql, mysql, mongodb, redis, etc. version: options.version || 'latest', public_port: options.publicPort || null, environment_variables: options.envVars || {} }; } /** * Formatted Output Helpers */ formatServerList(servers) { return servers.map(s => ({ name: s.name, uuid: s.uuid, ip: s.ip, status: s.is_reachable ? '✓ Reachable' : '✗ Unreachable', usable: s.is_usable ? '✓ Usable' : '✗ Not Usable', description: s.description || 'No description' })); } formatApplicationList(applications) { return applications.map(a => ({ name: a.name, uuid: a.uuid, status: a.status, url: a.fqdn || 'Not configured', project: a.project?.name || 'Unknown' })); } generateDeploymentReport(deployment, application) { return { timestamp: new Date().toISOString(), application: { name: application.name, uuid: application.uuid, url: application.fqdn }, deployment: { status: deployment.status, commit: deployment.commit, branch: deployment.branch, started_at: deployment.started_at, finished_at: deployment.finished_at }, success: deployment.status === 'success' }; } } export default CoolifyUtils;