UNPKG

semanticpen

Version:

AI Article Writer & SEO Blog Generator SDK - Professional TypeScript/JavaScript library for automated content creation, AI-powered article generation, and SEO blog writing with SemanticPen

170 lines 6.61 kB
import { ValidationError } from '../errors'; export class StatusPoller { constructor(articleService) { this.defaultConfig = { interval: 5000, maxAttempts: 60, backoffMultiplier: 1.2 }; this.articleService = articleService; } async pollUntilComplete(articleId, config, callbacks) { const pollingConfig = { ...this.defaultConfig, ...config }; this.validatePollingConfig(pollingConfig); const startTime = Date.now(); let currentInterval = pollingConfig.interval; let attempts = 0; while (attempts < pollingConfig.maxAttempts) { attempts++; try { const article = await this.articleService.getArticle(articleId); if (callbacks?.onProgress) { callbacks.onProgress(attempts, article.status, article); } if (this.isComplete(article)) { const totalTime = Date.now() - startTime; if (article.status === 'finished' && callbacks?.onComplete) { callbacks.onComplete(article); } return { success: article.status === 'finished', article, error: article.status === 'failed' ? article.error_message : undefined, attempts, totalTime }; } if (attempts < pollingConfig.maxAttempts) { await this.sleep(currentInterval); if (pollingConfig.backoffMultiplier && pollingConfig.backoffMultiplier > 1) { currentInterval = Math.floor(currentInterval * pollingConfig.backoffMultiplier); currentInterval = Math.min(currentInterval, 30000); } } } catch (error) { if (callbacks?.onError) { callbacks.onError(error.message || 'Polling error', attempts); } if (error.statusCode === 404 && attempts < pollingConfig.maxAttempts) { await this.sleep(currentInterval); continue; } return { success: false, error: error.message || 'Failed to poll article status', attempts, totalTime: Date.now() - startTime }; } } const totalTime = Date.now() - startTime; if (callbacks?.onTimeout) { callbacks.onTimeout(attempts, totalTime); } return { success: false, error: `Polling timed out after ${attempts} attempts (${totalTime}ms)`, attempts, totalTime }; } async pollMultipleArticles(articleIds, config, callbacks) { if (!articleIds || articleIds.length === 0) { throw new ValidationError('Article IDs array cannot be empty'); } const pollingPromises = articleIds.map(articleId => this.pollUntilComplete(articleId, config, callbacks)); return Promise.all(pollingPromises); } async waitForGenerationComplete(articleIds, config, onProgress) { const startTime = Date.now(); const completed = []; const failed = []; const results = await this.pollMultipleArticles(articleIds, config, { onComplete: (article) => { completed.push(article); if (onProgress) { onProgress(completed.length, articleIds.length, [...completed]); } }, onError: (error, attempt) => { } }); results.forEach((result, index) => { const articleId = articleIds[index]; if (result.success && result.article) { if (!completed.find(a => a.id === articleId)) { completed.push(result.article); } } else { failed.push({ articleId, error: result.error || 'Unknown error' }); } }); return { completed, failed, totalTime: Date.now() - startTime }; } async getMultipleStatus(articleIds) { const completed = []; const pending = []; const failed = []; const notFound = []; const promises = articleIds.map(async (articleId) => { try { const article = await this.articleService.getArticle(articleId); switch (article.status.toLowerCase()) { case 'finished': completed.push(article); break; case 'failed': failed.push(article); break; default: pending.push(article); } } catch (error) { if (error.statusCode === 404) { notFound.push(articleId); } else { failed.push({ id: articleId, status: 'failed', error_message: error.message }); } } }); await Promise.all(promises); return { completed, pending, failed, notFound }; } isComplete(article) { const completedStatuses = ['finished', 'failed']; return completedStatuses.includes(article.status.toLowerCase()); } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } validatePollingConfig(config) { if (config.interval < 1000) { throw new ValidationError('Polling interval must be at least 1000ms'); } if (config.maxAttempts < 1) { throw new ValidationError('Max attempts must be at least 1'); } if (config.backoffMultiplier && config.backoffMultiplier < 1) { throw new ValidationError('Backoff multiplier must be >= 1'); } if (config.interval < 2000 && config.maxAttempts > 10) { console.warn('[SemanticPen SDK] Warning: Very aggressive polling detected. Consider increasing interval or reducing max attempts.'); } } } //# sourceMappingURL=StatusPoller.js.map