solver-sdk
Version:
SDK for WorkAI API - AI-powered code analysis with WorkCoins billing system
333 lines • 13.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectsApi = void 0;
/**
* API для работы с проектами
*/
class ProjectsApi {
constructor(httpClient) {
this.httpClient = httpClient;
}
// ===== ОСНОВНЫЕ МЕТОДЫ УПРАВЛЕНИЯ ПРОЕКТАМИ =====
/**
* Получает все проекты пользователя
*
* @returns {Promise<Project[] | null>} Массив проектов или null при auth ошибках (401/403)
*
* @example
* ```typescript
* const projects = await sdk.projects.getAllProjects();
* if (!projects) {
* // Auth error - токен истек
* await authManager.refreshToken();
* return;
* }
* ```
*/
async getAllProjects() {
const projects = await this.httpClient.get('/api/v1/projects');
return projects;
}
/**
* Альтернативное имя для getAllProjects() для совместимости
*
* @returns {Promise<Project[] | null>} Массив проектов или null при auth ошибках (401/403)
*/
async getProjects() {
return this.getAllProjects();
}
/**
* Находит или создает проект по имени
*
* @param {string} projectName Имя проекта
* @returns {Promise<Project | null>} Проект или null при auth ошибках (401/403)
*
* @example
* ```typescript
* const project = await sdk.projects.findOrCreateProject('MyProject');
* if (!project) {
* // Auth error - токен истек
* return;
* }
* console.log(project.id);
* ```
*/
async findOrCreateProject(projectName) {
if (!projectName?.trim()) {
throw new Error('Project name is required');
}
const response = await this.httpClient.post('/api/v1/projects/find-or-create', {
name: projectName.trim()
});
return response;
}
/**
* Получает проекты, готовые к использованию
*
* @returns {Promise<Project[] | null>} Массив проектов или null при auth ошибках (401/403)
*/
async getReadyProjects() {
const allProjects = await this.getAllProjects();
if (!allProjects)
return null;
return allProjects.filter(project => project.indexStatus === 'indexed');
}
/**
* Получает проект по ID
*
* @param {string} projectId ID проекта
* @returns {Promise<Project | null>} Проект или null при auth ошибках (401/403)
*/
async getProject(projectId) {
this.validateProjectId(projectId);
const project = await this.httpClient.get(`/api/v1/projects/${projectId}`);
return project;
}
/**
* Создает новый проект
*
* @param {string} name Имя проекта
* @param {any} data Дополнительные данные
* @param {ProjectOptions} options Опции проекта
* @returns {Promise<Project | null>} Созданный проект или null при auth ошибках (401/403)
*/
async createProject(name, data, options) {
if (!name?.trim()) {
throw new Error('Project name is required');
}
const requestData = {
name: name.trim(),
...data,
...options
};
const project = await this.httpClient.post('/api/v1/projects', requestData);
return project;
}
/**
* Удаляет проект
*/
async deleteProject(projectId) {
this.validateProjectId(projectId);
await this.httpClient.delete(`/api/v1/projects/${projectId}`);
}
// ===== ИНДЕКСАЦИЯ И СТАТУС =====
/**
* Получает статус проекта
*
* @param {string} projectId ID проекта
* @returns {Promise<any | null>} Статус проекта или null при auth ошибках (401/403)
*/
async getProjectStatus(projectId) {
this.validateProjectId(projectId);
return await this.httpClient.get(`/api/v1/projects/${projectId}/status`);
}
/**
* Получает статус индексации проекта
*
* @param {string} projectId ID проекта
* @returns {Promise<any | null>} Статус индексации или null при auth ошибках (401/403)
*/
async getIndexingStatus(projectId) {
this.validateProjectId(projectId);
return await this.httpClient.get(`/api/v1/projects/${projectId}/indexing-status`);
}
/**
* Отменяет индексацию проекта
*
* @param {string} projectId ID проекта
* @returns {Promise<boolean | null>} true если отменено, false при ошибке, null при auth ошибке (401/403)
*/
async cancelIndexing(projectId) {
this.validateProjectId(projectId);
try {
const result = await this.httpClient.post(`/api/v1/projects/${projectId}/cancel-indexing`);
if (result === null)
return null; // Auth error
return true;
}
catch (error) {
console.error('Failed to cancel indexing:', error);
return false;
}
}
/**
* Очищает ошибку индексации
*
* @param {string} projectId ID проекта
* @returns {Promise<boolean | null>} true если очищено, false при ошибке, null при auth ошибке (401/403)
*/
async clearIndexingError(projectId) {
this.validateProjectId(projectId);
try {
const result = await this.httpClient.post(`/api/v1/projects/${projectId}/clear-error`);
if (result === null)
return null; // Auth error
return true;
}
catch (error) {
console.error('Failed to clear indexing error:', error);
return false;
}
}
// ===== DELTA CHUNKING УДАЛЕНЫ =====
// Ручные методы sendInitialSync/sendDeltaSync/finalizeDeltaSync удалены
// ✅ ИСПОЛЬЗУЙТЕ: sdk.deltaManager.syncEncryptedChunks() - делает всё автоматически
// ===== PROJECT STATE И SMART SYNC =====
/**
* Получение состояния проекта с проверкой синхронизации
*
* @param projectId - ID проекта
* @param clientRootHash - Merkle root hash клиента для проверки необходимости синхронизации
* @returns ProjectState с полем syncRequired (всегда присутствует в response)
* @throws Error если backend не вернул обязательное поле syncRequired
*/
async getProjectState(projectId, clientRootHash) {
this.validateProjectId(projectId);
const url = clientRootHash
? `/api/v1/projects/${projectId}/state?clientRootHash=${encodeURIComponent(clientRootHash)}`
: `/api/v1/projects/${projectId}/state`;
const response = await this.httpClient.get(url);
// Валидация: syncRequired ДОЛЖНО присутствовать в response
if (response.syncRequired === undefined || response.syncRequired === null) {
throw new Error(`Backend did not return required field 'syncRequired' for project ${projectId}. ` +
`This indicates a backend version mismatch or API error. ` +
`Response: ${JSON.stringify(response)}`);
}
return {
projectId: response.projectId || projectId,
projectName: response.projectName || 'Unknown',
merkleRootHash: response.merkleRootHash || null,
lastIndexedAt: response.lastIndexedAt ? new Date(response.lastIndexedAt) : null,
totalChunks: response.totalChunks || 0,
totalFiles: response.totalFiles || 0,
indexingStatus: response.indexingStatus || 'unknown',
syncRequired: response.syncRequired,
lastSyncSessionId: response.lastSyncSessionId
};
}
// ===== SESSION RECOVERY =====
/**
* Получение статуса восстановления сессии
*/
async getRecoveryStatus(projectId) {
this.validateProjectId(projectId);
const response = await this.httpClient.get(`/api/v1/projects/${projectId}/recovery-status`);
return {
hasInterruptedSession: response.hasInterruptedSession || false,
recoveryInfo: response.recoveryInfo ? {
sessionId: response.recoveryInfo.sessionId,
projectId: response.recoveryInfo.projectId || projectId,
projectName: response.recoveryInfo.projectName || 'Unknown',
status: response.recoveryInfo.status || 'interrupted',
progress: {
received: response.recoveryInfo.progress?.totalChunks || 0,
processed: response.recoveryInfo.progress?.processedChunks || 0,
total: response.recoveryInfo.progress?.totalChunks || 0,
percentage: response.recoveryInfo.progress?.percentage || 0
},
interruptedAt: response.recoveryInfo.lastActivity ? new Date(response.recoveryInfo.lastActivity) : new Date(),
resumeReason: response.recoveryInfo.resumeReason || 'session_recovery',
canResume: response.recoveryInfo.canResume !== false
} : undefined
};
}
/**
* Восстановление прерванной синхронизации
*/
async resumeSync(projectId, options = {}) {
this.validateProjectId(projectId);
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/resume-sync`, {
skipDuplicates: options.skipDuplicates !== false,
continueFromLastBatch: options.continueFromLastBatch !== false
});
return {
success: response.success !== false,
message: response.message,
continueFromBatch: response.continueFromBatch,
sessionId: response.sessionId
};
}
/**
* Отмена восстановления сессии
*/
async cancelRecovery(projectId) {
this.validateProjectId(projectId);
const response = await this.httpClient.delete(`/api/v1/projects/${projectId}/recovery`);
return {
success: response.success !== false,
message: response.message
};
}
/**
* Инициализация Delta Sync
*/
async initializeDeltaSync(projectId, clientRootHash) {
this.validateProjectId(projectId);
if (!clientRootHash?.trim()) {
throw new Error('Client root hash is required');
}
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/initialize-delta-sync`, {
clientRootHash: clientRootHash.trim()
});
return {
needsSync: response.needsSync !== false,
sessionId: response.sessionId,
lastSyncHash: response.lastSyncHash
};
}
/**
* Сброс индексации проекта
*/
async resetIndexing(projectId) {
this.validateProjectId(projectId);
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/reset-indexing`);
return {
success: response.success !== false,
message: response.message || 'Reset completed',
clearedChunks: response.clearedChunks,
clearedFiles: response.clearedFiles
};
}
/**
* Перезапуск индексации проекта
*/
async restartIndexing(projectId) {
this.validateProjectId(projectId);
const response = await this.httpClient.post(`/api/v1/projects/${projectId}/restart-indexing`);
return {
success: response.success !== false,
message: response.message || 'Restart initiated',
newSessionId: response.newSessionId
};
}
/**
* Получение маппинга файловых путей
*/
async getFilePathMapping(projectId) {
this.validateProjectId(projectId);
const response = await this.httpClient.get(`/api/v1/projects/${projectId}/file-path-mapping`);
return {
success: response.success !== false,
mapping: response.mapping || [],
totalFiles: response.totalFiles || 0
};
}
// ===== УТИЛИТЫ =====
/**
* Валидация ID проекта
* @private
*/
validateProjectId(projectId) {
if (projectId === undefined || projectId === null) {
throw new Error('Project ID is required');
}
if (typeof projectId !== 'string') {
throw new Error('Project ID must be a string');
}
if (projectId.trim().length === 0) {
throw new Error('Project ID cannot be empty');
}
}
}
exports.ProjectsApi = ProjectsApi;
//# sourceMappingURL=projects-api.js.map