UNPKG

solver-sdk

Version:

SDK for WorkAI API - AI-powered code analysis with WorkCoins billing system

504 lines 22.4 kB
import { HttpClient } from './utils/http-client.js'; import { ProjectsApi } from './api/projects-api.js'; import { SearchApi } from './api/search-api.js'; import { ChatApi } from './api/chat-api/index.js'; import { ToolsApi } from './api/tools-api.js'; import { UpdatesApi } from './api/updates-api.js'; import { UserApi } from './api/user-api.js'; import { AuthApi } from './api/auth-api.js'; import { CreditsApi } from './api/credits-api.js'; import { ModelsApi } from './api/models-api.js'; import { VERSION } from './version.js'; // 🔄 Delta-Chunking imports import { DeltaChunkingApi } from './api/delta-chunking-api.js'; import { DeltaChunkingManager } from './delta-chunking/delta-chunking-manager.js'; import { DeltaChunkingUtils } from './delta-chunking/delta-chunking-utils.js'; /** * Определение типа среды выполнения * @returns 'browser' | 'node' | 'unknown' */ function getEnvironment() { if (typeof window !== 'undefined' && typeof window.document !== 'undefined') { return 'browser'; } else if (typeof process !== 'undefined' && process.versions && process.versions.node) { return 'node'; } return 'unknown'; } /** * Основной класс SDK для работы с Code Solver API * Версия 5.1+ - HTTP + WebSocket для real-time уведомлений */ export class CodeSolverSDK { /** * ✅ РЕКОМЕНДУЕМЫЙ СПОСОБ: Создает SDK * @param {CodeSolverSDKOptions} options Опции SDK * @returns {Promise<CodeSolverSDK>} Инициализированный SDK * * @remarks * Health check НЕ выполняется автоматически. * OAuth и первые API запросы сами проверят connectivity. * Если нужна явная проверка - вызовите sdk.checkHealth() вручную. */ static async create(options) { return new CodeSolverSDK(options); } /** * Создает новый экземпляр SDK * @param {CodeSolverSDKOptions} options Опции SDK */ constructor(options) { // 🔌 External ProjectSyncClient singleton (ОБЯЗАТЕЛЬНО устанавливается координатором) this.externalProjectSyncClient = null; /** Logger для внутреннего использования */ this.logger = { log: (message) => { const debugLevel = this._options.debug; if (debugLevel && debugLevel !== 'silent' && debugLevel !== 'error' && debugLevel !== 'warn') { console.log(`${message}`); } }, warn: (message) => { const debugLevel = this._options.debug; if (debugLevel && debugLevel !== 'silent' && debugLevel !== 'error') { console.warn(`⚠️ ${message}`); } }, error: (message) => { const debugLevel = this._options.debug; if (debugLevel !== 'silent') { console.error(`🔴 ${message}`); } }, debug: (message) => { const debugLevel = this._options.debug; if (debugLevel === 'verbose' || debugLevel === 'debug') { console.debug(`🔍 ${message}`); } }, // ✅ НОВЫЕ методы для контроля стрим логирования streamEvent: (message, data) => { const debugLevel = this._options.debug; const streamLogging = this._options.streamLogging; if (debugLevel === 'silent') return; if (streamLogging?.sseEvents || (debugLevel === 'verbose' || debugLevel === 'debug')) { console.log(`STREAM: ${message}`, data); } }, streamChunk: (message, data) => { const debugLevel = this._options.debug; const streamLogging = this._options.streamLogging; if (debugLevel === 'silent') return; if (streamLogging?.streamChunks || (debugLevel === 'verbose' || debugLevel === 'debug')) { console.log(`CHUNK: ${message}`, data); } }, eventCallback: (message, data) => { const debugLevel = this._options.debug; const streamLogging = this._options.streamLogging; if (debugLevel === 'silent') return; if (streamLogging?.eventCallbacks || (debugLevel === 'verbose' || debugLevel === 'debug')) { console.log(`EVENT: ${message}`, data); } } }; this._options = { ...options, mode: options.mode || 'auto' }; // Определяем среду выполнения this.environment = this._options.mode === 'auto' ? getEnvironment() : this._options.mode === 'browser' ? 'browser' : 'node'; // Инициализируем HTTP клиент this.httpClient = new HttpClient(this._options.baseURL, { headers: { ...(this._options.apiKey ? { 'Authorization': `Bearer ${this._options.apiKey}` } : {}), ...(this._options.headers || {}) }, timeout: this._options.timeout, httpsAgent: this.environment === 'node' ? this._options.httpsAgent : undefined, getAuthToken: this._options.getAuthToken // 🔑 Динамическое получение токена }); // Инициализируем API клиенты this._projects = new ProjectsApi(this.httpClient); this._search = new SearchApi(this.httpClient); this._chat = new ChatApi(this.httpClient, { debug: this._options.debug, streamLogging: this._options.streamLogging }); // 🔧 Инициализация Tools API this._tools = new ToolsApi(this.httpClient); this._models = new ModelsApi(this.httpClient); this._updates = new UpdatesApi(this.httpClient); this._user = new UserApi(this.httpClient); this._auth = new AuthApi(this.httpClient); this._credits = new CreditsApi(this.httpClient); // 🔄 Инициализируем Delta-Chunking если включен if (this._options.deltaChunking?.enabled) { // Создаем отдельный DeltaChunkingApi для delta операций const deltaApi = new DeltaChunkingApi(this.httpClient); const deltaUtils = new DeltaChunkingUtils(this._projects, this._options, this.environment, this.logger); this._deltaManager = new DeltaChunkingManager(deltaApi, // ✅ Передаем правильный DeltaChunkingApi deltaUtils, this._options, this.logger); this.logger.log('🔄 Delta-Chunking инициализирован'); } // 🔌 WebSocket ВСЕГДА управляется внешним coordinator // SDK никогда не создаёт ProjectSyncClient самостоятельно // Используйте setProjectSyncClient() после создания SDK this.logger.debug('[WebSocket] External WebSocket management required'); this.logger.log('✅ CodeSolverSDK инициализирован'); } /** * Получает версию SDK * @returns {string} Версия SDK */ static getVersion() { return VERSION; } /** * Обновляет опции SDK * @param {Partial<CodeSolverSDKOptions>} newOptions Новые опции */ updateOptions(newOptions) { Object.assign(this._options, newOptions); // Обновляем HTTP клиент при необходимости if (newOptions.apiKey || newOptions.headers || newOptions.timeout) { this.httpClient = new HttpClient(this._options.baseURL, { headers: { ...(this._options.apiKey ? { 'Authorization': `Bearer ${this._options.apiKey}` } : {}), ...(this._options.headers || {}) }, timeout: this._options.timeout, httpsAgent: this.environment === 'node' ? this._options.httpsAgent : undefined }); } } /** * Проверяет здоровье API * @returns {Promise<boolean>} Результат проверки */ async checkHealth() { try { const response = await this.httpClient.get('/health'); return response?.status === 'ok'; } catch (error) { this.logger.error(`Ошибка проверки здоровья API: ${error instanceof Error ? error.message : 'неизвестная ошибка'}`); return false; } } /** * Диагностирует состояние API - правильная диагностика * @returns {Promise<object>} Результат диагностики */ async diagnoseAPI() { const diagnosis = { healthy: true, endpoints: {}, errors: [] }; // Проверяем основные эндпоинты согласно актуальной документации const endpoints = [ '/health', '/api/v1/projects' // Убираем несуществующие endpoints: '/api/v1/status', '/api/v1/models' ]; for (const endpoint of endpoints) { try { await this.httpClient.get(endpoint); diagnosis.endpoints[endpoint] = true; } catch (error) { diagnosis.endpoints[endpoint] = false; diagnosis.healthy = false; diagnosis.errors.push(`${endpoint}: ${error instanceof Error ? error.message : 'неизвестная ошибка'}`); } } return diagnosis; } /** * Получает API для работы с проектами * @returns {ProjectsApi} API для работы с проектами */ get projects() { return this._projects; } /** * Получает API для поиска кода * @returns {SearchApi} API для поиска кода */ get search() { return this._search; } /** * Получает API для работы с чатом * @returns {ChatApi} API для работы с чатом */ get chat() { return this._chat; } /** * Получает API для работы с инструментами * @returns {ToolsApi} API для работы с инструментами */ get tools() { return this._tools; } /** * Получает API для работы с моделями * @returns {ModelsApi} API для работы с моделями */ get models() { return this._models; } /** * Получает экземпляр API для работы с обновлениями * @returns {UpdatesApi} API для работы с обновлениями */ get updates() { return this._updates; } /** * Получает API для работы с профилем пользователя * @returns {UserApi} API для работы с профилем пользователя */ get user() { return this._user; } /** * Получает API для работы с credits системой * @returns {CreditsApi} API для работы с credits */ get credits() { return this._credits; } /** * Получает API для работы с авторизацией и управлением токенами * @returns {AuthApi} API для работы с авторизацией * * @example * ```typescript * // Revoke access token * await sdk.auth.revokeToken(accessToken); * * // Logout (cookie-based) * await sdk.auth.logout(); * ``` */ get auth() { return this._auth; } // 🔄 DELTA-CHUNKING МЕТОДЫ /** * Проверяет активность delta-chunking функциональности * @returns {boolean} true если delta-chunking включен и инициализирован */ get isDeltaChunkingEnabled() { return !!this._deltaManager?.isEnabled; } /** * 📤 Синхронизация готовых зашифрованных чанков (для Extension) * @param {string} projectId ID проекта * @param {any[]} encryptedChunks Готовые зашифрованные чанки * @param {string} rootHash Root hash для синхронизации * @param {SyncOptions} options Опции синхронизации * @returns {Promise<SyncResult>} Результат синхронизации */ async syncEncryptedChunks(projectId, encryptedChunks, rootHash, options = {}) { if (!this._deltaManager) { throw new Error('Delta-chunking не включен. Установите deltaChunking.enabled = true в конфигурации SDK'); } return await this._deltaManager.syncEncryptedChunks(projectId, encryptedChunks, rootHash, options); } /** * 📊 Получение статуса синхронизации * @param {string} projectId ID проекта * @returns {Promise<SyncStatus>} Статус синхронизации */ async getSyncStatus(projectId) { if (!this._deltaManager) { throw new Error('Delta-chunking не включен. Установите deltaChunking.enabled = true в конфигурации SDK'); } return await this._deltaManager.getSyncStatus(projectId); } /** * ❌ Отмена активной синхронизации * @param {string} projectId ID проекта * @returns {Promise<boolean>} true если синхронизация отменена */ async cancelSync(projectId) { if (!this._deltaManager) { throw new Error('Delta-chunking не включен. Установите deltaChunking.enabled = true в конфигурации SDK'); } return await this._deltaManager.cancelSync(projectId); } /** * 🧹 Очистка удаленных файлов из векторной базы (отдельный метод) * @param {string} projectId ID проекта * @param {ActiveFile[]} activeFiles Список активных файлов * @param {string[]} deletedFiles ОПЦИОНАЛЬНО: Явно удаленные файлы (пути) * @returns {Promise<FileCleanupResult>} Результат очистки */ async cleanupDeletedFiles(projectId, activeFiles, deletedFiles) { if (!this._deltaManager) { throw new Error('Delta-chunking не включен. Установите deltaChunking.enabled = true в конфигурации SDK'); } // Используем публичный метод DeltaChunkingManager return await this._deltaManager.performCleanup(projectId, activeFiles, deletedFiles); } /** * Обрабатывает ошибки SDK * @param {Error} error Ошибка */ static handleError(error) { if (CodeSolverSDK.errorHandler) { CodeSolverSDK.errorHandler(error); } else { console.error('Необработанная ошибка:', error); } } /** * Устанавливает глобальный обработчик ошибок * @param {Function} handler Обработчик ошибок */ static setErrorHandler(handler) { CodeSolverSDK.errorHandler = handler; } /** * Освобождает ресурсы SDK */ async dispose() { this.logger.debug('Освобождение ресурсов SDK'); } /** * Устанавливает новый API ключ * @param {string} apiKey Новый API ключ */ setApiKey(apiKey) { this._options.apiKey = apiKey; this.updateOptions({ apiKey }); } /** * Получает информацию о SDK * @returns {object} Информация о SDK */ getInfo() { return { version: VERSION, environment: this.environment, baseURL: this._options.baseURL, hasApiKey: !!this._options.apiKey, deltaChunkingEnabled: this.isDeltaChunkingEnabled }; } /** * 🔄 Получение менеджера Delta-Chunking для расширенного API * @returns {DeltaChunkingManager | undefined} Менеджер delta-chunking или undefined если отключен */ get deltaManager() { return this._deltaManager; } /** * 🔌 НОВОЕ: Установка внешнего ProjectSyncClient singleton * Используется WebSocketConnectionCoordinator на клиенте для обеспечения * singleton паттерна согласно Socket.IO best practices * * @param client External ProjectSyncClient proxy от координатора */ setProjectSyncClient(client) { this.externalProjectSyncClient = client; this.logger.debug('[SDK] External ProjectSyncClient attached (singleton mode)'); } /** * 🔌 Получение WebSocket клиента для project-sync уведомлений * @returns {any} WebSocket клиент (должен быть установлен через setProjectSyncClient) * @throws {Error} Если external client не установлен */ get projectSync() { if (!this.externalProjectSyncClient) { throw new Error('[SDK] ProjectSyncClient not set. Call setProjectSyncClient() first.'); } return this.externalProjectSyncClient; } /** * 🔌 PROXY: Подключение к WebSocket через coordinator * Делегирует вызов external coordinator для singleton управления * * @returns {Promise<void>} Promise который разрешается при успешном подключении * @throws {Error} Если external client не установлен или метод недоступен */ async connectWebSocket() { if (!this.externalProjectSyncClient) { throw new Error('[SDK] ProjectSyncClient not set. Call setProjectSyncClient() first.'); } if (!this.externalProjectSyncClient.connect) { throw new Error('[SDK] External ProjectSyncClient does not have connect method'); } await this.externalProjectSyncClient.connect(); this.logger.debug('[SDK] WebSocket connect delegated to coordinator'); } /** * 🔌 PROXY: Отключение от WebSocket через coordinator * @throws {Error} Если external client не установлен или метод недоступен */ disconnectWebSocket() { if (!this.externalProjectSyncClient) { throw new Error('[SDK] ProjectSyncClient not set. Call setProjectSyncClient() first.'); } if (!this.externalProjectSyncClient.disconnect) { throw new Error('[SDK] External ProjectSyncClient does not have disconnect method'); } this.externalProjectSyncClient.disconnect(); this.logger.debug('[SDK] WebSocket disconnect delegated to coordinator'); } /** * 🔌 PROXY: Проверка статуса WebSocket подключения * @returns {boolean} true если WebSocket подключен */ get isWebSocketConnected() { if (!this.externalProjectSyncClient) { return false; } return this.externalProjectSyncClient.isConnected ?? false; } /** * 🔌 PROXY: Подписка на проект для получения real-time уведомлений * @param projectId ID проекта для подписки * @param userId Опциональный ID пользователя * @throws {Error} Если external client не установлен или метод недоступен */ subscribeToProject(projectId, userId) { if (!this.externalProjectSyncClient) { throw new Error('[SDK] ProjectSyncClient not set. Call setProjectSyncClient() first.'); } if (!this.externalProjectSyncClient.subscribeToProject) { throw new Error('[SDK] External ProjectSyncClient does not have subscribeToProject method'); } this.externalProjectSyncClient.subscribeToProject(projectId, userId); this.logger.debug(`[SDK] Subscribe to project delegated: ${projectId.slice(-8)}`); } /** * 🔌 PROXY: Отписка от проекта * @param projectId ID проекта для отписки * @throws {Error} Если external client не установлен или метод недоступен */ unsubscribeFromProject(projectId) { if (!this.externalProjectSyncClient) { throw new Error('[SDK] ProjectSyncClient not set. Call setProjectSyncClient() first.'); } if (!this.externalProjectSyncClient.unsubscribeFromProject) { throw new Error('[SDK] External ProjectSyncClient does not have unsubscribeFromProject method'); } this.externalProjectSyncClient.unsubscribeFromProject(projectId); this.logger.debug(`[SDK] Unsubscribe from project delegated: ${projectId.slice(-8)}`); } } /** Глобальный обработчик ошибок */ CodeSolverSDK.errorHandler = null; //# sourceMappingURL=code-solver-sdk.js.map