UNPKG

@codervisor/devlog-cli

Version:

Command-line interface for devlog - Extract and stream chat history to devlog server

168 lines (167 loc) 6.03 kB
/** * HTTP Client for DevLog ChatHub API * * Handles communication with the devlog server API endpoints, * specifically for streaming chat data to the ChatHub service. */ import axios from 'axios'; export class DevlogApiClient { client; config; constructor(config) { this.config = { timeout: 30000, retries: 3, retryDelay: 1000, ...config, }; this.client = axios.create({ baseURL: this.config.baseURL, timeout: this.config.timeout, headers: { 'Content-Type': 'application/json', }, }); // Add request/response interceptors for error handling this.setupInterceptors(); } setupInterceptors() { // Request interceptor for logging this.client.interceptors.request.use((config) => { console.log(`[API] ${config.method?.toUpperCase()} ${config.url}`); return config; }, (error) => { console.error('[API] Request error:', error); return Promise.reject(error); }); // Response interceptor for error handling and retries this.client.interceptors.response.use((response) => { console.log(`[API] ${response.status} ${response.config.url}`); return response; }, async (error) => { const originalRequest = error.config; // Don't retry if we've exceeded max retries if (originalRequest._retryCount >= (this.config.retries || 3)) { console.error('[API] Max retries exceeded:', error.message); return Promise.reject(this.formatError(error)); } // Retry on network errors or 5xx server errors if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT' || (error.response?.status && error.response.status >= 500)) { originalRequest._retryCount = (originalRequest._retryCount || 0) + 1; console.log(`[API] Retrying request (attempt ${originalRequest._retryCount})...`); // Wait before retrying await new Promise((resolve) => setTimeout(resolve, this.config.retryDelay * originalRequest._retryCount)); return this.client(originalRequest); } return Promise.reject(this.formatError(error)); }); } formatError(error) { if (error.response) { // Server responded with error status const message = error.response.data?.error || error.response.statusText; return new Error(`API Error (${error.response.status}): ${message}`); } else if (error.request) { // Request made but no response received return new Error(`Network Error: Could not connect to server at ${this.config.baseURL}`); } else { // Something else happened return new Error(`Request Error: ${error.message}`); } } /** * Test connection to the devlog server */ async testConnection() { try { const response = await this.client.get('/api/health'); return response.status === 200; } catch (error) { console.error('[API] Connection test failed:', error); return false; } } /** * Import chat data to a workspace */ async importChatData(projectId, data) { try { const response = await this.client.post(`/api/projects/${projectId}/chat/import`, data); return response.data; } catch (error) { throw error instanceof Error ? error : new Error('Failed to import chat data'); } } /** * Get import progress status */ async getImportProgress(projectId, importId) { try { const response = await this.client.get(`/api/projects/${projectId}/chat/import?importId=${importId}`); return response.data; } catch (error) { throw error instanceof Error ? error : new Error('Failed to get import progress'); } } /** * List workspaces available on the server */ async listProjects() { try { const response = await this.client.get('/api/projects'); return response.data.workspaces || []; } catch (error) { throw error instanceof Error ? error : new Error('Failed to list workspaces'); } } /** * Get workspace details */ async getProject(projectId) { try { const response = await this.client.get(`/api/projects/${projectId}`); return response.data; } catch (error) { throw error instanceof Error ? error : new Error(`Failed to get workspace ${projectId}`); } } /** * Search chat content in a workspace */ async searchChatContent(projectId, query, options = {}) { try { const params = new URLSearchParams({ query, limit: (options.limit || 50).toString(), caseSensitive: (options.caseSensitive || false).toString(), searchType: options.searchType || 'exact', }); const response = await this.client.get(`/api/projects/${projectId}/chat/search?${params.toString()}`); return response.data; } catch (error) { throw error instanceof Error ? error : new Error('Failed to search chat content'); } } /** * Get chat statistics for a workspace */ async getChatStats(projectId) { try { const response = await this.client.get(`/api/projects/${projectId}/chat/stats`); return response.data; } catch (error) { throw error instanceof Error ? error : new Error('Failed to get chat statistics'); } } }