solver-sdk
Version:
SDK for WorkAI API - AI-powered code analysis with WorkCoins billing system
183 lines • 7.66 kB
JavaScript
/**
* 🚀 Delta-Chunking API клиент
* Интеграция с backend endpoints
*/
/**
* API клиент для delta-chunking операций
*/
export class DeltaChunkingApi {
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Инициализация синхронизации проекта
*/
async initSync(projectId, request) {
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/sync-init`, request);
// ✅ ИСПРАВЛЕНО: Проверяем sessionId только если needsSync = true
if (response.needsSync && !response.sessionId) {
throw new Error('Server did not return sessionId when sync is needed');
}
return response;
}
/**
* Отправка батча зашифрованных чанков
*/
async uploadChunkBatch(projectId, batchRequest) {
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/delta-chunks`, batchRequest);
return response;
}
/**
* Получение статуса синхронизации
*/
async getSyncStatus(projectId) {
const response = await this.httpClient.get(`/api/v1/projects/${projectId}/sync-status`);
return {
projectId,
sessionId: response.sessionId,
status: response.status || 'idle',
progress: response.progress || 0,
chunksReceived: response.chunksReceived || 0,
chunksProcessed: response.chunksProcessed || 0,
errorCount: response.errorCount || 0,
startedAt: response.startedAt ? new Date(response.startedAt) : undefined,
completedAt: response.completedAt ? new Date(response.completedAt) : undefined,
lastActivity: response.lastActivity ? new Date(response.lastActivity) : undefined,
error: response.error
};
}
/**
* Завершение синхронизации
*/
async finalizeSync(projectId) {
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/sync-finalize`, {});
return {
success: response.success || false,
projectId,
sessionId: response.sessionId,
processedChunks: response.processedChunks || 0,
totalChunks: response.totalChunks || 0,
duration: response.duration || 0,
error: response.error,
details: response.details
};
}
/**
* Отмена синхронизации
*/
async cancelSync(projectId) {
const response = await this.httpClient.delete(`/api/v1/projects/${projectId}/sync-cancel`);
return {
success: response.success || false,
message: response.message
};
}
/**
* Batch upload с retry логикой
*/
async uploadChunksWithRetry(projectId, chunks, options = {}) {
const { batchSize = 50, maxRetries = 3, onProgress } = options;
const totalChunks = chunks.length;
const totalBatches = Math.ceil(totalChunks / batchSize);
let processedChunks = 0;
let failedChunks = 0;
const errors = [];
for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
const startIdx = batchIndex * batchSize;
const endIdx = Math.min(startIdx + batchSize, totalChunks);
const batchChunks = chunks.slice(startIdx, endIdx);
const batchRequest = {
batchIndex,
totalBatches,
chunks: batchChunks
};
let success = false;
let retryCount = 0;
while (!success && retryCount < maxRetries) {
try {
const result = await this.uploadChunkBatch(projectId, batchRequest);
processedChunks += result.processed;
failedChunks += result.failed;
if (result.errors) {
errors.push(...result.errors);
}
success = true;
// Уведомляем о прогрессе
if (onProgress) {
onProgress(processedChunks, totalChunks);
}
}
catch (error) {
retryCount++;
if (retryCount >= maxRetries) {
const errorMessage = error instanceof Error ? error.message : String(error);
errors.push(`Batch ${batchIndex} failed after ${maxRetries} retries: ${errorMessage}`);
failedChunks += batchChunks.length;
}
else {
// Экспоненциальная задержка перед повтором
await new Promise(resolve => setTimeout(resolve, Math.pow(2, retryCount) * 1000));
}
}
}
}
return {
success: failedChunks === 0,
projectId,
processedChunks,
totalChunks,
duration: 0, // Будет заполнено на уровне SDK
error: errors.length > 0 ? errors.join('; ') : undefined,
details: {
newFiles: 0, // Будет заполнено на уровне SDK
changedFiles: 0,
deletedFiles: 0
}
};
}
/**
* Очистка удаленных файлов из векторной базы
* @param projectId ID проекта
* @param activeFiles Список активных файлов (оставшихся после удаления)
* @param deletedFiles ОПЦИОНАЛЬНО: Явно удаленные файлы (пути)
*/
async cleanupFiles(projectId, activeFiles, deletedFiles) {
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/cleanup-files`, { activeFiles, deletedFiles });
return response;
}
/**
* Инвалидировать chunks измененного файла
*/
async invalidateFile(projectId, options) {
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/delta/invalidate-file`, {
filePath: options.filePath,
reason: options.reason || 'file_changed'
});
return {
success: response.success !== false,
chunksInvalidated: response.chunksInvalidated || 0,
cacheInvalidated: response.cacheInvalidated !== false,
filePath: response.filePath || options.filePath
};
}
/**
* Batch инвалидация chunks для нескольких файлов
* (для предотвращения rate limiting)
*/
async invalidateFiles(projectId, files) {
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/delta/invalidate-files`, {
files: files.map(f => ({
filePath: f.filePath,
reason: f.reason || 'file_changed'
}))
});
return {
success: response.success !== false,
totalFiles: response.totalFiles || files.length,
totalChunksInvalidated: response.totalChunksInvalidated || 0,
totalCacheInvalidated: response.totalCacheInvalidated || 0,
results: response.results || []
};
}
}
//# sourceMappingURL=delta-chunking-api.js.map