UNPKG

adpa-enterprise-framework-automation

Version:

Modular, standards-compliant Node.js/TypeScript automation framework for enterprise requirements, project, and data management. Provides CLI and API for BABOK v3, PMBOK 7th Edition, and DMBOK 2.0 (in progress). Production-ready Express.js API with TypeSpe

241 lines 8.38 kB
import { v4 as uuidv4 } from 'uuid'; import { ProcessingStatus, InputFormat, OutputFormat } from '../types/api.js'; /** * Document Processing Service * * Handles the core document conversion logic, integrating with * existing ADPA document processing capabilities and Adobe services. */ export class DocumentProcessor { activeJobs = new Map(); activeBatches = new Map(); /** * Start a single document conversion */ async startConversion(request) { const jobId = uuidv4(); const job = new DocumentJob(jobId, request); this.activeJobs.set(jobId, job); // Start processing asynchronously this.processDocument(job).catch(error => { console.error(`Job ${jobId} failed:`, error); job.fail(error.message); }); return job; } /** * Start batch document conversion */ async startBatchConversion(request) { const batchId = uuidv4(); const batch = new BatchJob(batchId, request); this.activeBatches.set(batchId, batch); // Start batch processing asynchronously this.processBatch(batch).catch(error => { console.error(`Batch ${batchId} failed:`, error); batch.fail(error.message); }); return batch; } /** * Process a single document conversion */ async processDocument(job) { try { job.updateStatus(ProcessingStatus.processing); // Simulate processing time based on content length const processingTime = Math.min(job.request.content.length / 100, 30000); job.estimatedCompletion = new Date(Date.now() + processingTime); // Progress simulation for (let progress = 0; progress <= 100; progress += 20) { job.updateProgress(progress); await this.delay(processingTime / 5); } // Simulate conversion based on formats const result = await this.performConversion(job.request); job.complete(result.downloadUrl, result.fileSize, result.filename); } catch (error) { job.fail(error instanceof Error ? error.message : 'Unknown error occurred'); } } /** * Process batch conversion */ async processBatch(batch) { try { batch.updateStatus(ProcessingStatus.processing); const maxParallel = batch.request.options?.maxParallel || 3; const continueOnError = batch.request.options?.continueOnError ?? true; // Process documents in parallel batches for (let i = 0; i < batch.jobs.length; i += maxParallel) { const chunk = batch.jobs.slice(i, i + maxParallel); const promises = chunk.map(async (job) => { try { await this.processDocument(job); batch.successCount++; } catch (error) { batch.failureCount++; if (!continueOnError) { throw error; } } }); await Promise.all(promises); batch.updateProgress(Math.round(((i + chunk.length) / batch.jobs.length) * 100)); } batch.complete(); } catch (error) { batch.fail(error instanceof Error ? error.message : 'Batch processing failed'); } } /** * Perform the actual document conversion */ async performConversion(request) { // Here we would integrate with existing ADPA conversion logic // For now, simulate the conversion process const conversionMap = { [`${InputFormat.markdown}-${OutputFormat.pdf}`]: 'convertMarkdownToPdf', [`${InputFormat.markdown}-${OutputFormat.docx}`]: 'convertMarkdownToDocx', [`${InputFormat.markdown}-${OutputFormat.html}`]: 'convertMarkdownToHtml', [`${InputFormat.markdown}-${OutputFormat.pptx}`]: 'convertMarkdownToPptx', [`${InputFormat.html}-${OutputFormat.pdf}`]: 'convertHtmlToPdf', [`${InputFormat.docx}-${OutputFormat.pdf}`]: 'convertDocxToPdf' }; const conversionKey = `${request.inputFormat}-${request.outputFormat}`; const conversionMethod = conversionMap[conversionKey]; if (!conversionMethod) { throw new Error(`Conversion from ${request.inputFormat} to ${request.outputFormat} is not supported`); } // Simulate file processing await this.delay(1000); // Generate mock file data const fileExtension = request.outputFormat; const filename = `converted_${Date.now()}.${fileExtension}`; const downloadUrl = `/api/v1/documents/download/${uuidv4()}`; const fileSize = Math.floor(Math.random() * 1000000) + 50000; // 50KB - 1MB return { downloadUrl, fileSize, filename }; } /** * Get conversion job by ID */ getJob(jobId) { return this.activeJobs.get(jobId); } /** * Get batch by ID */ getBatch(batchId) { return this.activeBatches.get(batchId); } /** * Utility method for delays */ delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } /** * Individual document conversion job */ export class DocumentJob { id; request; status = ProcessingStatus.queued; progress = 0; createdAt = new Date(); completedAt; estimatedCompletion; downloadUrl; fileSize; processingDuration; originalFilename; generatedFilename; outputFormat; error; logs = []; constructor(id, request) { this.id = id; this.request = request; this.outputFormat = request.outputFormat; this.logs.push(`Job ${id} created at ${this.createdAt.toISOString()}`); } updateStatus(status) { this.status = status; this.logs.push(`Status updated to ${status} at ${new Date().toISOString()}`); } updateProgress(progress) { this.progress = progress; this.logs.push(`Progress updated to ${progress}% at ${new Date().toISOString()}`); } complete(downloadUrl, fileSize, filename) { this.status = ProcessingStatus.completed; this.completedAt = new Date(); this.processingDuration = this.completedAt.getTime() - this.createdAt.getTime(); this.downloadUrl = downloadUrl; this.fileSize = fileSize; this.generatedFilename = filename; this.progress = 100; this.logs.push(`Job completed at ${this.completedAt.toISOString()}`); } fail(message, retryable = true) { this.status = ProcessingStatus.failed; this.completedAt = new Date(); this.processingDuration = this.completedAt.getTime() - this.createdAt.getTime(); this.error = { code: 'CONVERSION_FAILED', message, retryable }; this.logs.push(`Job failed at ${this.completedAt.toISOString()}: ${message}`); } } /** * Batch conversion job */ export class BatchJob { id; request; jobs = []; status = ProcessingStatus.queued; progress = 0; successCount = 0; failureCount = 0; createdAt = new Date(); completedAt; totalDuration; constructor(id, request) { this.id = id; this.request = request; // Create individual jobs for each document this.jobs = request.documents.map(doc => { const jobId = uuidv4(); return new DocumentJob(jobId, doc); }); } updateStatus(status) { this.status = status; } updateProgress(progress) { this.progress = progress; } complete() { this.status = ProcessingStatus.completed; this.completedAt = new Date(); this.totalDuration = this.completedAt.getTime() - this.createdAt.getTime(); this.progress = 100; } fail(message) { this.status = ProcessingStatus.failed; this.completedAt = new Date(); this.totalDuration = this.completedAt.getTime() - this.createdAt.getTime(); } } //# sourceMappingURL=DocumentProcessor.js.map