UNPKG

@snehal96/unimail

Version:

Unified email fetching & document extraction layer for modern web apps

136 lines (135 loc) 4.91 kB
/** * Common streaming utility for email adapters * Provides shared functionality for streaming emails in batches */ export class EmailStreamService { /** * Creates an async generator that yields email batches * This is the core streaming implementation that adapters can use */ static async *createEmailStream(fetchPageFn, options) { const batchSize = options.batchSize || 50; const maxEmails = options.maxEmails; let pageToken = options.pageToken; let totalProcessed = 0; let hasMore = true; while (hasMore) { try { // Determine how many emails to fetch in this request let requestSize = batchSize; if (maxEmails && (totalProcessed + requestSize) > maxEmails) { requestSize = maxEmails - totalProcessed; } if (requestSize <= 0) { break; } // Fetch the page const response = await fetchPageFn(pageToken, requestSize); if (!response.emails || response.emails.length === 0) { break; } // Yield this batch yield response.emails; totalProcessed += response.emails.length; pageToken = response.nextPageToken; hasMore = !!pageToken; // Check if we've reached the maximum if (maxEmails && totalProcessed >= maxEmails) { break; } } catch (error) { console.error('Error in email stream:', error); throw error; } } } /** * Executes email streaming with callbacks for progress tracking */ static async processEmailStream(streamGenerator, callbacks) { const summary = { totalProcessed: 0, totalBatches: 0, errors: 0, startTime: new Date(), endTime: new Date(), duration: 0 }; try { let batchNumber = 0; for await (const emailBatch of streamGenerator) { batchNumber++; summary.totalBatches = batchNumber; summary.totalProcessed += emailBatch.length; const progress = { current: summary.totalProcessed, batchCount: batchNumber, // Note: total and estimatedRemaining would need to be set by the adapter // since we don't have access to that information at this level }; try { // Call the batch callback if (callbacks.onBatch) { await callbacks.onBatch(emailBatch, progress); } // Call the progress callback if (callbacks.onProgress) { await callbacks.onProgress(progress); } } catch (error) { summary.errors++; if (callbacks.onError) { await callbacks.onError(error, progress); } else { // Re-throw if no error handler is provided throw error; } } } } finally { summary.endTime = new Date(); summary.duration = summary.endTime.getTime() - summary.startTime.getTime(); if (callbacks.onComplete) { await callbacks.onComplete(summary); } } } /** * Utility to create a stream batch object with metadata */ static createStreamBatch(emails, batchNumber, progress, isLastBatch = false) { return { emails, batchNumber, progress, isLastBatch }; } /** * Utility to calculate estimated remaining emails */ static calculateEstimatedRemaining(totalCount, currentProcessed) { if (!totalCount || totalCount <= currentProcessed) { return undefined; } return totalCount - currentProcessed; } /** * Utility to validate streaming options */ static validateStreamOptions(options) { if (options.batchSize && options.batchSize <= 0) { throw new Error('batchSize must be greater than 0'); } if (options.maxEmails && options.maxEmails <= 0) { throw new Error('maxEmails must be greater than 0'); } if (options.batchSize && options.batchSize > 1000) { console.warn('Warning: Large batch sizes may cause memory issues. Consider using smaller batches.'); } } }