coolify-client.ts•6.84 kB
import {
  CoolifyConfig,
  ErrorResponse,
  ServerInfo,
  ServerResources,
  ServerDomain,
  ValidationResponse,
  Project,
  CreateProjectRequest,
  UpdateProjectRequest,
  Environment,
  Deployment,
  Database,
  DatabaseUpdateRequest,
  Service,
  CreateServiceRequest,
  DeleteServiceOptions,
} from '../types/coolify.js';
export class CoolifyClient {
  private baseUrl: string;
  private accessToken: string;
  constructor(config: CoolifyConfig) {
    if (!config.baseUrl) {
      throw new Error('Coolify base URL is required');
    }
    if (!config.accessToken) {
      throw new Error('Coolify access token is required');
    }
    this.baseUrl = config.baseUrl.replace(/\/$/, '');
    this.accessToken = config.accessToken;
  }
  private async request<T>(path: string, options: RequestInit = {}): Promise<T> {
    try {
      const url = `${this.baseUrl}/api/v1${path}`;
      const response = await fetch(url, {
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${this.accessToken}`,
        },
        ...options,
      });
      const data = await response.json();
      if (!response.ok) {
        const error = data as ErrorResponse;
        throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
      }
      return data as T;
    } catch (error) {
      if (error instanceof TypeError && error.message.includes('fetch')) {
        throw new Error(
          `Failed to connect to Coolify server at ${this.baseUrl}. Please check if the server is running and the URL is correct.`,
        );
      }
      throw error;
    }
  }
  async listServers(): Promise<ServerInfo[]> {
    return this.request<ServerInfo[]>('/servers');
  }
  async getServer(uuid: string): Promise<ServerInfo> {
    return this.request<ServerInfo>(`/servers/${uuid}`);
  }
  async getServerResources(uuid: string): Promise<ServerResources> {
    return this.request<ServerResources>(`/servers/${uuid}/resources`);
  }
  async getServerDomains(uuid: string): Promise<ServerDomain[]> {
    return this.request<ServerDomain[]>(`/servers/${uuid}/domains`);
  }
  async validateServer(uuid: string): Promise<ValidationResponse> {
    return this.request<ValidationResponse>(`/servers/${uuid}/validate`);
  }
  async validateConnection(): Promise<void> {
    try {
      await this.listServers();
    } catch (error) {
      throw new Error(
        `Failed to connect to Coolify server: ${error instanceof Error ? error.message : 'Unknown error'}`,
      );
    }
  }
  async listProjects(): Promise<Project[]> {
    return this.request<Project[]>('/projects');
  }
  async getProject(uuid: string): Promise<Project> {
    return this.request<Project>(`/projects/${uuid}`);
  }
  async createProject(project: CreateProjectRequest): Promise<{ uuid: string }> {
    return this.request<{ uuid: string }>('/projects', {
      method: 'POST',
      body: JSON.stringify(project),
    });
  }
  async updateProject(uuid: string, project: UpdateProjectRequest): Promise<Project> {
    return this.request<Project>(`/projects/${uuid}`, {
      method: 'PATCH',
      body: JSON.stringify(project),
    });
  }
  async deleteProject(uuid: string): Promise<{ message: string }> {
    return this.request<{ message: string }>(`/projects/${uuid}`, {
      method: 'DELETE',
    });
  }
  async getProjectEnvironment(
    projectUuid: string,
    environmentNameOrUuid: string,
  ): Promise<Environment> {
    return this.request<Environment>(`/projects/${projectUuid}/${environmentNameOrUuid}`);
  }
  async deployApplication(uuid: string): Promise<Deployment> {
    const response = await this.request<Deployment>(`/applications/${uuid}/deploy`, {
      method: 'POST',
    });
    return response;
  }
  async listDatabases(): Promise<Database[]> {
    return this.request<Database[]>('/databases');
  }
  async getDatabase(uuid: string): Promise<Database> {
    return this.request<Database>(`/databases/${uuid}`);
  }
  async updateDatabase(uuid: string, data: DatabaseUpdateRequest): Promise<Database> {
    return this.request<Database>(`/databases/${uuid}`, {
      method: 'PATCH',
      body: JSON.stringify(data),
    });
  }
  async deleteDatabase(
    uuid: string,
    options?: {
      deleteConfigurations?: boolean;
      deleteVolumes?: boolean;
      dockerCleanup?: boolean;
      deleteConnectedNetworks?: boolean;
    },
  ): Promise<{ message: string }> {
    const queryParams = new URLSearchParams();
    if (options) {
      if (options.deleteConfigurations !== undefined) {
        queryParams.set('delete_configurations', options.deleteConfigurations.toString());
      }
      if (options.deleteVolumes !== undefined) {
        queryParams.set('delete_volumes', options.deleteVolumes.toString());
      }
      if (options.dockerCleanup !== undefined) {
        queryParams.set('docker_cleanup', options.dockerCleanup.toString());
      }
      if (options.deleteConnectedNetworks !== undefined) {
        queryParams.set('delete_connected_networks', options.deleteConnectedNetworks.toString());
      }
    }
    const queryString = queryParams.toString();
    const url = queryString ? `/databases/${uuid}?${queryString}` : `/databases/${uuid}`;
    return this.request<{ message: string }>(url, {
      method: 'DELETE',
    });
  }
  async listServices(): Promise<Service[]> {
    return this.request<Service[]>('/services');
  }
  async getService(uuid: string): Promise<Service> {
    return this.request<Service>(`/services/${uuid}`);
  }
  async createService(data: CreateServiceRequest): Promise<{ uuid: string; domains: string[] }> {
    return this.request<{ uuid: string; domains: string[] }>('/services', {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }
  async deleteService(uuid: string, options?: DeleteServiceOptions): Promise<{ message: string }> {
    const queryParams = new URLSearchParams();
    if (options) {
      if (options.deleteConfigurations !== undefined) {
        queryParams.set('delete_configurations', options.deleteConfigurations.toString());
      }
      if (options.deleteVolumes !== undefined) {
        queryParams.set('delete_volumes', options.deleteVolumes.toString());
      }
      if (options.dockerCleanup !== undefined) {
        queryParams.set('docker_cleanup', options.dockerCleanup.toString());
      }
      if (options.deleteConnectedNetworks !== undefined) {
        queryParams.set('delete_connected_networks', options.deleteConnectedNetworks.toString());
      }
    }
    const queryString = queryParams.toString();
    const url = queryString ? `/services/${uuid}?${queryString}` : `/services/${uuid}`;
    return this.request<{ message: string }>(url, {
      method: 'DELETE',
    });
  }
  // Add more methods as needed for other endpoints
}