import axios from 'axios' const api = axios.create({ baseURL: '/api', timeout: 30000, headers: { 'Content-Type': 'application/json', }, }) // Request interceptor to add auth token api.interceptors.request.use((config) => { const token = localStorage.getItem('clicd_token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) // Response interceptor to handle auth errors api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { localStorage.removeItem('clicd_token') localStorage.removeItem('clicd_username') window.location.href = '/login' } return Promise.reject(error) } ) export interface LoginResponse { token: string username: string } export type ContainerIdentifier = number | string export interface PortMapping { container_port: number host_port: number protocol: string description: string } export interface Container { id: number uuid: string name: string template: string vcpu: number ram_mb: number disk_gb: number network_bw_mbps: number monthly_traffic_gb: number traffic_mode: string traffic_in_gb: number traffic_out_gb: number traffic_used_rx: number traffic_used_tx: number traffic_reset_date: string io_speed_mbps: number status: string ip: string ipv6: string ipv6_prefix_len: number ipv6_interface: string vnc_port: number ssh_port: number ssh_password: string port_mappings: PortMapping[] port_mapping_limit: number snapshot_limit: number created_at: string expires_at: string snapshot_schedule_enabled: boolean snapshot_schedule_interval_hours: number snapshot_schedule_time: string snapshot_schedule_last_run: string snapshot_schedule_next_run: string snapshot_schedule_created_by: string } export interface Template { id: string name: string distro: string release: string arch: string variant?: string description: string } export interface CreateContainerRequest { name: string template_id: string vcpu: number cpu_percent: number ram_mb: number disk_gb: number network_bw_mbps: number monthly_traffic_gb: number traffic_mode: string traffic_in_gb: number traffic_out_gb: number io_speed_mbps: number extra_ports: number[] port_mapping_count: number snapshot_limit: number assign_ipv6: boolean expires_at: string } export interface IPv6PrefixInfo { interface: string address: string prefix: string prefix_len: number gateway: string is_tunnel?: boolean source?: string } export interface IPv6Status { available: boolean reachable: boolean reason: string prefixes: IPv6PrefixInfo[] } export interface DashboardStats { total_containers: number running: number stopped: number } export interface HostInfo { cpu: { cores: number; usage_pct: number } ram: { total_mb: number; used_mb: number; free_mb: number } disk: { total_gb: number; used_gb: number; free_gb: number } network: { rx_bytes: number tx_bytes: number rx_bps: number tx_bps: number public_ipv4?: string public_ipv4_interface?: string public_ipv6?: string public_ipv6_interface?: string ipv6_prefixes?: IPv6PrefixInfo[] } disk_io: { read_bytes: number; write_bytes: number; read_bps: number; write_bps: number } load: { load1: number; load5: number; load15: number } } export interface ContainerUsage { memory_usage_bytes: number cpu_usage_usec: number cpu_usage_pct: number disk_usage_bytes: number network_rx_bytes: number network_tx_bytes: number network_rx_bps: number network_tx_bps: number disk_read_bytes: number disk_write_bytes: number disk_read_bps: number disk_write_bps: number } export interface APIResponse { success: boolean message?: string data?: T } // Auth export const login = (username: string, password: string) => api.post>('/login', { username, password }) export const checkAuth = () => api.get('/check-auth') export const changePassword = (oldPassword: string, newPassword: string) => api.post('/change-password', { old_password: oldPassword, new_password: newPassword }) export const changeUsername = (newUsername: string, password: string) => api.post('/change-username', { new_username: newUsername, password }) // Login Logs export interface LoginLog { time: string username: string ip: string user_agent: string success: boolean } export interface AuditLog { time: string action: string target: string detail: string user: string } export const getLoginLogs = () => api.get>('/login-logs') // Containers export const getContainers = () => api.get>('/containers') export const getContainer = (id: ContainerIdentifier) => api.get>(`/containers/${id}`) export const createContainer = (data: CreateContainerRequest) => api.post('/containers', data) export const deleteContainer = (id: ContainerIdentifier) => api.delete(`/containers/${id}/delete`) export const startContainer = (id: ContainerIdentifier) => api.post(`/containers/${id}/start`) export const stopContainer = (id: ContainerIdentifier) => api.post(`/containers/${id}/stop`) export const restartContainer = (id: ContainerIdentifier) => api.post(`/containers/${id}/restart`) export const reinstallContainer = (id: ContainerIdentifier, templateId: string) => api.post(`/containers/${id}/reinstall`, { template_id: templateId }) export const resetSSHPassword = (id: ContainerIdentifier) => api.post>(`/containers/${id}/reset-password`) export const getContainerUsage = (id: ContainerIdentifier) => api.get>(`/containers/${id}/usage`) export interface TrafficInfo { total_used_bytes: number rx_used_bytes: number tx_used_bytes: number mode: string limit_gb: number in_limit_gb: number out_limit_gb: number used_pct: number reset_date: string } export const getTrafficInfo = (id: ContainerIdentifier) => api.get>(`/containers/${id}/traffic`) export const resetTraffic = (id: ContainerIdentifier) => api.post(`/containers/${id}/traffic-reset`) export const updateTrafficLimit = (id: ContainerIdentifier, data: { traffic_mode: string monthly_traffic_gb: number traffic_in_gb: number traffic_out_gb: number }) => api.put(`/containers/${id}/traffic-limit`, data) export const updateResourceLimit = (id: ContainerIdentifier, data: { vcpu: number ram_mb: number io_speed_mbps: number network_bw_mbps: number }) => api.put(`/containers/${id}/resource-limit`, data) export const addPortMapping = (id: ContainerIdentifier, data: PortMapping) => api.post>(`/containers/${id}/port-mappings`, data) export const updatePortMapping = (id: ContainerIdentifier, index: number, data: PortMapping) => api.put>(`/containers/${id}/port-mappings/${index}`, data) export const deletePortMapping = (id: ContainerIdentifier, index: number) => api.delete>(`/containers/${id}/port-mappings/${index}`) export const updateContainerExpiry = (id: ContainerIdentifier, expiresAt: string) => api.put(`/containers/${id}/expiry`, { expires_at: expiresAt }) export const getIPv6Status = () => api.get>('/ipv6/status') export const assignIPv6 = (id: ContainerIdentifier) => api.post>(`/containers/${id}/ipv6`) export interface RouteCapacity { used: number remaining: string total: string } export interface NAT4Route { container_id: number container_name: string lxc_name: string status: string ip: string host_port: number container_port: number protocol: string description: string } export interface IPv6Route { container_id: number container_name: string lxc_name: string status: string address: string prefix_len: number interface: string } export interface RoutingInfo { nat4: RouteCapacity ipv6: RouteCapacity nat4_mappings: NAT4Route[] ipv6_assignments: IPv6Route[] ipv6_prefixes: IPv6PrefixInfo[] } export const getRoutingInfo = () => api.get>('/routing') // Templates export const getTemplates = () => api.get>('/templates') // Images (template download/enable management) export interface ImageInfo { id: string name: string distro: string release: string arch: string description: string downloaded: boolean enabled: boolean downloading: boolean size_bytes: number } export const getImages = () => api.get>('/images') export const downloadImage = (templateId: string) => api.post('/images/download', { template_id: templateId }, { timeout: 600000 }) // 10min timeout export const deleteImage = (templateId: string) => api.delete('/images/delete', { data: { template_id: templateId } }) export const toggleImage = (templateId: string, enabled: boolean) => api.put('/images/toggle', { template_id: templateId, enabled }) export const getEnabledImages = () => api.get>('/images/enabled') // Dashboard export const getDashboard = () => api.get>('/dashboard') export const getHostInfo = () => api.get>('/host-info') // Oversell export interface OversellConfig { cpu_overcommit: number ram_overcommit: number disk_overcommit: number ksm_enabled: boolean swappiness: number } export interface OversellStatus { ksm_active: boolean ksm_pages: number ksm_supported: boolean swappiness: number reclaim_supported: boolean allocated_cpu: number allocated_ram_mb: number allocated_disk_gb: number } export interface ReclaimResult { attempted: number reclaimed: number unsupported: number errors: string[] } export const getOversell = () => api.get>('/oversell') export const updateOversell = (data: OversellConfig) => api.post>('/oversell', data) export const getOversellStatus = () => api.get>('/oversell/status') export const reclaimMemory = () => api.post>('/oversell/reclaim') // Snapshots export interface Snapshot { id: string container_id: number container_name: string lxc_name: string created_at: string created_by: string scheduled: boolean path: string size_bytes: number } export interface SnapshotSchedule { enabled: boolean interval_hours: number time: string last_run: string next_run: string created_by: string } export interface ContainerSnapshotsResponse { snapshots: Snapshot[] quota: number schedule: SnapshotSchedule } export const getSnapshots = () => api.get>('/snapshots') export const getContainerSnapshots = (id: ContainerIdentifier) => api.get>(`/containers/${id}/snapshots`) export const createContainerSnapshot = (id: ContainerIdentifier) => api.post>(`/containers/${id}/snapshots`, {}, { timeout: 600000 }) export const deleteContainerSnapshot = (id: ContainerIdentifier, snapshotId: string) => api.delete(`/containers/${id}/snapshots/${snapshotId}`, { timeout: 600000 }) export const restoreContainerSnapshot = (id: ContainerIdentifier, snapshotId: string) => api.post(`/containers/${id}/snapshots/${snapshotId}/restore`, {}, { timeout: 600000 }) export const updateSnapshotSchedule = (id: ContainerIdentifier, enabled: boolean, intervalHours: number, time: string) => api.post>( `/containers/${id}/snapshots/schedule`, { enabled, interval_hours: intervalHours, time }, { timeout: 600000 } ) export const updateSnapshotQuota = (id: ContainerIdentifier, snapshotLimit: number) => api.put>( `/containers/${id}/snapshots/quota`, { snapshot_limit: snapshotLimit } ) // WebSSH URL generator export const getWebSSHUrl = (containerName: string) => { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' const params = new URLSearchParams({ container: containerName }) return `${protocol}//${window.location.host}/api/ssh?${params.toString()}` } // Task Queue export interface Task { id: string type: string container_id?: number container_name: string status: string error?: string created_at: string template_id?: string config?: CreateContainerRequest } export const getTasks = () => api.get>('/tasks') export const deleteTask = (taskId: string) => api.delete(`/tasks/${taskId}`) export const batchCreate = (containers: CreateContainerRequest[]) => api.post>('/batch-create', { containers }) export const batchAction = (action: string, containers: number[], templateId?: string) => api.post('/batch-action', { action, containers, template_id: templateId }) // Sub Users export interface SubUser { id: string username: string password?: string container_names: string[] container_uuids?: string[] access_code: string created_at: string } export const createSubUser = (containerId: ContainerIdentifier) => api.post>('/sub-user/create', { container_name: String(containerId) }) // Audit Logs export interface AuditLog { time: string action: string target: string detail: string user: string } export const getAuditLogs = () => api.get>('/audit-logs') // Security export interface SecurityAlert { id: string container_name: string type: string severity: string source_ip: string target_ip: string target_port: number detail: string log_line: string timestamp: string count: number } export interface SecuritySummary { total_alerts: number critical: number high: number medium: number low: number } export const getSecurityAlerts = () => api.get>('/security/alerts') export const checkContainerSecurity = (containerName: string) => api.post('/security/check', { container_name: containerName }) export const getSecurityLogs = (containerName: string) => api.get('/security/logs', { params: { container: containerName } }) export const getSecuritySummary = () => api.get>('/security/summary') export const createWebSSHTicket = (containerName: string) => api.post>('/ssh-ticket', { container_name: containerName }) // Version export const getVersion = () => api.get>('/version') export default api