solver-sdk
Version:
SDK for WorkAI API - AI-powered code analysis with WorkCoins billing system
504 lines • 22.4 kB
JavaScript
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