@k-msg/messaging 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types/message.types.ts","../src/sender/single.sender.ts","../src/sender/bulk.sender.ts","../src/queue/job.processor.ts","../src/queue/retry.handler.ts","../src/delivery/tracker.ts","../src/personalization/variable.replacer.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport interface MessageRequest {\n templateId: string; // 템플릿 ID\n recipients: Recipient[]; // 수신자 목록\n variables: VariableMap; // 공통 변수\n scheduling?: SchedulingOptions; // 예약 발송\n options?: SendingOptions; // 발송 옵션\n}\n\nexport interface Recipient {\n phoneNumber: string;\n variables?: VariableMap; // 개별 변수 (공통 변수 오버라이드)\n metadata?: Record<string, any>; // 추적용 메타데이터\n}\n\nexport interface VariableMap {\n [key: string]: string | number | Date;\n}\n\nexport interface SchedulingOptions {\n scheduledAt: Date; // 예약 발송 시간\n timezone?: string; // 타임존\n retryCount?: number; // 재시도 횟수\n}\n\nexport interface SendingOptions {\n priority?: 'high' | 'normal' | 'low';\n ttl?: number; // Time to live (초)\n failover?: {\n enabled: boolean;\n fallbackChannel?: 'sms' | 'lms';\n fallbackContent?: string;\n };\n deduplication?: {\n enabled: boolean;\n window: number; // 중복 제거 시간 (초)\n };\n tracking?: {\n enabled: boolean;\n webhookUrl?: string;\n };\n}\n\nexport interface MessageResult {\n requestId: string;\n results: RecipientResult[];\n summary: {\n total: number;\n queued: number;\n sent: number;\n failed: number;\n };\n metadata: {\n createdAt: Date;\n provider: string;\n templateId: string;\n };\n}\n\nexport interface RecipientResult {\n phoneNumber: string;\n messageId?: string;\n status: MessageStatus;\n error?: MessageError;\n metadata?: Record<string, any>;\n}\n\nexport enum MessageStatus {\n QUEUED = 'QUEUED', // 큐에 대기 중\n SENDING = 'SENDING', // 발송 중\n SENT = 'SENT', // 발송 완료\n DELIVERED = 'DELIVERED', // 전달 완료\n FAILED = 'FAILED', // 발송 실패\n CLICKED = 'CLICKED', // 버튼 클릭됨\n CANCELLED = 'CANCELLED' // 취소됨\n}\n\nexport interface MessageError {\n code: string;\n message: string;\n details?: Record<string, any>;\n}\n\nexport interface DeliveryReport {\n messageId: string;\n phoneNumber: string;\n status: MessageStatus;\n sentAt?: Date;\n deliveredAt?: Date;\n clickedAt?: Date;\n failedAt?: Date;\n error?: MessageError;\n attempts: DeliveryAttempt[];\n metadata: Record<string, any>;\n}\n\nexport interface DeliveryAttempt {\n attemptNumber: number;\n attemptedAt: Date;\n status: MessageStatus;\n error?: MessageError;\n provider: string;\n}\n\n// Bulk messaging types\nexport interface BulkMessageRequest {\n templateId: string;\n recipients: BulkRecipient[];\n commonVariables?: VariableMap;\n options?: BulkSendingOptions;\n}\n\nexport interface BulkRecipient {\n phoneNumber: string;\n variables: VariableMap;\n metadata?: Record<string, any>;\n}\n\nexport interface BulkSendingOptions extends SendingOptions {\n batchSize?: number; // 배치 크기\n batchDelay?: number; // 배치 간 지연 시간 (ms)\n maxConcurrency?: number; // 최대 동시 처리 수\n}\n\nexport interface BulkMessageResult {\n requestId: string;\n totalRecipients: number;\n batches: BulkBatchResult[];\n summary: {\n queued: number;\n sent: number;\n failed: number;\n processing: number;\n };\n createdAt: Date;\n completedAt?: Date;\n}\n\nexport interface BulkBatchResult {\n batchId: string;\n batchNumber: number;\n recipients: RecipientResult[];\n status: 'pending' | 'processing' | 'completed' | 'failed';\n createdAt: Date;\n completedAt?: Date;\n}\n\n// Event types\nexport enum MessageEventType {\n // 템플릿 이벤트\n TEMPLATE_CREATED = 'template.created',\n TEMPLATE_APPROVED = 'template.approved',\n TEMPLATE_REJECTED = 'template.rejected',\n TEMPLATE_UPDATED = 'template.updated',\n TEMPLATE_DELETED = 'template.deleted',\n \n // 메시지 이벤트\n MESSAGE_QUEUED = 'message.queued',\n MESSAGE_SENT = 'message.sent',\n MESSAGE_DELIVERED = 'message.delivered',\n MESSAGE_FAILED = 'message.failed',\n MESSAGE_CLICKED = 'message.clicked',\n MESSAGE_CANCELLED = 'message.cancelled',\n \n // 채널 이벤트\n CHANNEL_CREATED = 'channel.created',\n CHANNEL_VERIFIED = 'channel.verified',\n SENDER_NUMBER_ADDED = 'sender_number.added',\n \n // 시스템 이벤트\n QUOTA_WARNING = 'system.quota_warning',\n QUOTA_EXCEEDED = 'system.quota_exceeded',\n PROVIDER_ERROR = 'system.provider_error'\n}\n\nexport interface MessageEvent<T = any> {\n id: string;\n type: MessageEventType;\n timestamp: Date;\n data: T;\n metadata: {\n providerId?: string;\n userId?: string;\n organizationId?: string;\n correlationId?: string;\n };\n}\n\n// Zod schemas\nexport const VariableMapSchema = z.record(z.string(), z.union([z.string(), z.number(), z.date()]));\n\nexport const RecipientSchema = z.object({\n phoneNumber: z.string().regex(/^[0-9]{10,11}$/),\n variables: VariableMapSchema.optional(),\n metadata: z.record(z.string(), z.any()).optional(),\n});\n\nexport const SchedulingOptionsSchema = z.object({\n scheduledAt: z.date().min(new Date()),\n timezone: z.string().optional(),\n retryCount: z.number().min(0).max(5).optional().default(3),\n});\n\nexport const SendingOptionsSchema = z.object({\n priority: z.enum(['high', 'normal', 'low']).optional().default('normal'),\n ttl: z.number().min(0).optional(),\n failover: z.object({\n enabled: z.boolean(),\n fallbackChannel: z.enum(['sms', 'lms']).optional(),\n fallbackContent: z.string().optional(),\n }).optional(),\n deduplication: z.object({\n enabled: z.boolean(),\n window: z.number().min(0).max(3600),\n }).optional(),\n tracking: z.object({\n enabled: z.boolean(),\n webhookUrl: z.string().url().optional(),\n }).optional(),\n});\n\nexport const MessageRequestSchema = z.object({\n templateId: z.string().min(1),\n recipients: z.array(RecipientSchema).min(1).max(10000),\n variables: VariableMapSchema,\n scheduling: SchedulingOptionsSchema.optional(),\n options: SendingOptionsSchema.optional(),\n});\n\nexport const MessageErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.record(z.string(), z.any()).optional(),\n});\n\nexport const RecipientResultSchema = z.object({\n phoneNumber: z.string(),\n messageId: z.string().optional(),\n status: z.nativeEnum(MessageStatus),\n error: MessageErrorSchema.optional(),\n metadata: z.record(z.string(), z.any()).optional(),\n});\n\nexport const MessageResultSchema = z.object({\n requestId: z.string(),\n results: z.array(RecipientResultSchema),\n summary: z.object({\n total: z.number().min(0),\n queued: z.number().min(0),\n sent: z.number().min(0),\n failed: z.number().min(0),\n }),\n metadata: z.object({\n createdAt: z.date(),\n provider: z.string(),\n templateId: z.string(),\n }),\n});\n\nexport type MessageRequestType = z.infer<typeof MessageRequestSchema>;\nexport type RecipientType = z.infer<typeof RecipientSchema>;\nexport type MessageResultType = z.infer<typeof MessageResultSchema>;","import { MessageRequest, MessageResult, RecipientResult, MessageStatus } from '../types/message.types';\n\nexport interface Provider {\n id: string;\n name: string;\n send(request: ProviderMessageRequest): Promise<ProviderMessageResult>;\n}\n\nexport interface ProviderMessageRequest {\n templateCode: string;\n phoneNumber: string;\n variables: Record<string, any>;\n options?: Record<string, any>;\n}\n\nexport interface ProviderMessageResult {\n messageId: string;\n status: MessageStatus;\n error?: { code: string; message: string };\n}\n\nexport class SingleMessageSender {\n private providers: Map<string, Provider> = new Map();\n private templates: Map<string, any> = new Map(); // Template cache\n\n addProvider(provider: Provider): void {\n this.providers.set(provider.id, provider);\n }\n\n removeProvider(providerId: string): void {\n this.providers.delete(providerId);\n }\n\n async send(request: MessageRequest): Promise<MessageResult> {\n const requestId = this.generateRequestId();\n const results: RecipientResult[] = [];\n\n // Get template information\n const template = await this.getTemplate(request.templateId);\n if (!template) {\n throw new Error(`Template ${request.templateId} not found`);\n }\n\n // Get provider\n const provider = this.providers.get(template.provider);\n if (!provider) {\n throw new Error(`Provider ${template.provider} not found`);\n }\n\n // Process each recipient\n for (const recipient of request.recipients) {\n try {\n const result = await this.sendToRecipient(\n provider,\n template,\n recipient,\n request.variables,\n request.options\n );\n results.push(result);\n } catch (error) {\n results.push({\n phoneNumber: recipient.phoneNumber,\n status: MessageStatus.FAILED,\n error: {\n code: 'SEND_ERROR',\n message: error instanceof Error ? error.message : 'Unknown error'\n },\n metadata: recipient.metadata\n });\n }\n }\n\n // Calculate summary\n const summary = this.calculateSummary(results);\n\n return {\n requestId,\n results,\n summary,\n metadata: {\n createdAt: new Date(),\n provider: template.provider,\n templateId: request.templateId\n }\n };\n }\n\n private async sendToRecipient(\n provider: Provider,\n template: any,\n recipient: any,\n commonVariables: Record<string, any>,\n options?: any\n ): Promise<RecipientResult> {\n // Merge common variables with recipient-specific variables\n const variables = { ...commonVariables, ...recipient.variables };\n\n // Note: Variable parsing moved to personalization system\n // Variables are now handled by VariableReplacer in the personalization package\n\n // Prepare provider request\n const providerRequest: ProviderMessageRequest = {\n templateCode: template.code,\n phoneNumber: recipient.phoneNumber,\n variables,\n options\n };\n\n // Send message\n const providerResult = await provider.send(providerRequest);\n\n return {\n phoneNumber: recipient.phoneNumber,\n messageId: providerResult.messageId,\n status: providerResult.status,\n error: providerResult.error,\n metadata: recipient.metadata\n };\n }\n\n private async getTemplate(templateId: string): Promise<any> {\n // Check cache first\n if (this.templates.has(templateId)) {\n return this.templates.get(templateId);\n }\n\n // In a real implementation, this would fetch from a database\n // For now, return a mock template\n const template = {\n id: templateId,\n code: 'TEMPLATE_CODE',\n provider: 'mock-provider',\n variables: [],\n content: 'Mock template content'\n };\n\n this.templates.set(templateId, template);\n return template;\n }\n\n private calculateSummary(results: RecipientResult[]) {\n return {\n total: results.length,\n queued: results.filter(r => r.status === MessageStatus.QUEUED).length,\n sent: results.filter(r => r.status === MessageStatus.SENT).length,\n failed: results.filter(r => r.status === MessageStatus.FAILED).length\n };\n }\n\n private generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n async cancelMessage(messageId: string): Promise<boolean> {\n // Implementation for canceling a scheduled message\n // This would interact with the queue system\n throw new Error('Not implemented');\n }\n\n async getMessageStatus(messageId: string): Promise<MessageStatus> {\n // Implementation for getting message status\n // This would query the delivery tracking system\n throw new Error('Not implemented');\n }\n\n async resendMessage(messageId: string, options?: { newRecipient?: string }): Promise<MessageResult> {\n // Implementation for resending a failed message\n throw new Error('Not implemented');\n }\n}","import { \n BulkMessageRequest, \n BulkMessageResult, \n BulkBatchResult, \n RecipientResult,\n MessageStatus \n} from '../types/message.types';\nimport { SingleMessageSender } from './single.sender';\n\nexport class BulkMessageSender {\n private singleSender: SingleMessageSender;\n private activeBulkJobs: Map<string, BulkJob> = new Map();\n\n constructor(singleSender: SingleMessageSender) {\n this.singleSender = singleSender;\n }\n\n async sendBulk(request: BulkMessageRequest): Promise<BulkMessageResult> {\n const requestId = this.generateRequestId();\n const batchSize = request.options?.batchSize || 100;\n const batchDelay = request.options?.batchDelay || 1000;\n \n // Split recipients into batches\n const batches = this.createBatches(request.recipients, batchSize);\n \n const bulkResult: BulkMessageResult = {\n requestId,\n totalRecipients: request.recipients.length,\n batches: [],\n summary: {\n queued: request.recipients.length,\n sent: 0,\n failed: 0,\n processing: 0\n },\n createdAt: new Date()\n };\n\n // Create bulk job for tracking\n const bulkJob: BulkJob = {\n id: requestId,\n request,\n result: bulkResult,\n status: 'processing',\n createdAt: new Date()\n };\n\n this.activeBulkJobs.set(requestId, bulkJob);\n\n // Process batches asynchronously\n this.processBatchesAsync(bulkJob, batches, batchDelay);\n\n return bulkResult;\n }\n\n private async processBatchesAsync(\n bulkJob: BulkJob,\n batches: any[][],\n batchDelay: number\n ): Promise<void> {\n try {\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n const batchId = `${bulkJob.id}_batch_${i + 1}`;\n\n const batchResult: BulkBatchResult = {\n batchId,\n batchNumber: i + 1,\n recipients: [],\n status: 'processing',\n createdAt: new Date()\n };\n\n bulkJob.result.batches.push(batchResult);\n bulkJob.result.summary.processing += batch.length;\n bulkJob.result.summary.queued -= batch.length;\n\n try {\n // Process batch\n const batchRecipients = await this.processBatch(\n bulkJob.request,\n batch,\n batchId\n );\n\n batchResult.recipients = batchRecipients;\n batchResult.status = 'completed';\n batchResult.completedAt = new Date();\n\n // Update summary\n const sent = batchRecipients.filter(r => r.status === MessageStatus.SENT).length;\n const failed = batchRecipients.filter(r => r.status === MessageStatus.FAILED).length;\n\n bulkJob.result.summary.sent += sent;\n bulkJob.result.summary.failed += failed;\n bulkJob.result.summary.processing -= batch.length;\n\n } catch (error) {\n batchResult.status = 'failed';\n batchResult.completedAt = new Date();\n \n // Mark all recipients in this batch as failed\n batchResult.recipients = batch.map(recipient => ({\n phoneNumber: recipient.phoneNumber,\n status: MessageStatus.FAILED,\n error: {\n code: 'BATCH_ERROR',\n message: error instanceof Error ? error.message : 'Batch processing failed'\n },\n metadata: recipient.metadata\n }));\n\n bulkJob.result.summary.failed += batch.length;\n bulkJob.result.summary.processing -= batch.length;\n }\n\n // Add delay between batches (except for the last one)\n if (i < batches.length - 1) {\n await this.delay(batchDelay);\n }\n }\n\n bulkJob.status = 'completed';\n bulkJob.result.completedAt = new Date();\n\n } catch (error) {\n bulkJob.status = 'failed';\n bulkJob.result.completedAt = new Date();\n }\n }\n\n private async processBatch(\n request: BulkMessageRequest,\n batchRecipients: any[],\n batchId: string\n ): Promise<RecipientResult[]> {\n const results: RecipientResult[] = [];\n const maxConcurrency = request.options?.maxConcurrency || 10;\n\n // Process recipients in parallel with concurrency limit\n const promises: Promise<RecipientResult>[] = [];\n \n for (let i = 0; i < batchRecipients.length; i += maxConcurrency) {\n const chunk = batchRecipients.slice(i, i + maxConcurrency);\n \n const chunkPromises = chunk.map(recipient => \n this.processRecipient(request, recipient)\n );\n\n const chunkResults = await Promise.allSettled(chunkPromises);\n \n for (const result of chunkResults) {\n if (result.status === 'fulfilled') {\n results.push(result.value);\n } else {\n // Handle promise rejection\n results.push({\n phoneNumber: 'unknown',\n status: MessageStatus.FAILED,\n error: {\n code: 'PROCESSING_ERROR',\n message: result.reason?.message || 'Unknown processing error'\n }\n });\n }\n }\n }\n\n return results;\n }\n\n private async processRecipient(\n request: BulkMessageRequest,\n recipient: any\n ): Promise<RecipientResult> {\n try {\n // Merge common variables with recipient-specific variables\n const variables = { ...request.commonVariables, ...recipient.variables };\n\n // Create single message request\n const messageRequest = {\n templateId: request.templateId,\n recipients: [{\n phoneNumber: recipient.phoneNumber,\n variables: {},\n metadata: recipient.metadata\n }],\n variables,\n options: request.options\n };\n\n const result = await this.singleSender.send(messageRequest);\n return result.results[0];\n\n } catch (error) {\n return {\n phoneNumber: recipient.phoneNumber,\n status: MessageStatus.FAILED,\n error: {\n code: 'RECIPIENT_ERROR',\n message: error instanceof Error ? error.message : 'Unknown error'\n },\n metadata: recipient.metadata\n };\n }\n }\n\n private createBatches<T>(items: T[], batchSize: number): T[][] {\n const batches: T[][] = [];\n \n for (let i = 0; i < items.length; i += batchSize) {\n batches.push(items.slice(i, i + batchSize));\n }\n \n return batches;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n private generateRequestId(): string {\n return `bulk_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n async getBulkStatus(requestId: string): Promise<BulkMessageResult | null> {\n const job = this.activeBulkJobs.get(requestId);\n return job ? job.result : null;\n }\n\n async cancelBulkJob(requestId: string): Promise<boolean> {\n const job = this.activeBulkJobs.get(requestId);\n if (!job) {\n return false;\n }\n\n job.status = 'cancelled';\n \n // Cancel pending batches\n for (const batch of job.result.batches) {\n if (batch.status === 'pending' || batch.status === 'processing') {\n batch.status = 'failed';\n batch.completedAt = new Date();\n }\n }\n\n return true;\n }\n\n async retryFailedBatch(requestId: string, batchId: string): Promise<BulkBatchResult | null> {\n const job = this.activeBulkJobs.get(requestId);\n if (!job) {\n return null;\n }\n\n const batch = job.result.batches.find(b => b.batchId === batchId);\n if (!batch || batch.status !== 'failed') {\n return null;\n }\n\n // Reset batch status\n batch.status = 'processing';\n batch.createdAt = new Date();\n delete batch.completedAt;\n\n try {\n // Extract failed recipients for retry\n const failedRecipients = batch.recipients\n .filter(r => r.status === MessageStatus.FAILED)\n .map(r => ({\n phoneNumber: r.phoneNumber,\n variables: {},\n metadata: r.metadata\n }));\n\n const retryResults = await this.processBatch(\n job.request,\n failedRecipients,\n batchId\n );\n\n batch.recipients = retryResults;\n batch.status = 'completed';\n batch.completedAt = new Date();\n\n return batch;\n\n } catch (error) {\n batch.status = 'failed';\n batch.completedAt = new Date();\n return batch;\n }\n }\n\n cleanup(): void {\n // Remove completed jobs older than 24 hours\n const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n \n for (const [id, job] of this.activeBulkJobs) {\n if (job.status === 'completed' && job.createdAt < oneDayAgo) {\n this.activeBulkJobs.delete(id);\n }\n }\n }\n}\n\ninterface BulkJob {\n id: string;\n request: BulkMessageRequest;\n result: BulkMessageResult;\n status: 'processing' | 'completed' | 'failed' | 'cancelled';\n createdAt: Date;\n}","/**\n * Job processor for message queue system\n */\n\nimport { EventEmitter } from 'events';\nimport {\n MessageRequest,\n MessageResult,\n MessageStatus,\n MessageEventType,\n MessageEvent,\n RecipientResult,\n DeliveryReport\n} from '../types/message.types';\nimport { RetryHandler, CircuitBreaker, RateLimiter } from '@k-msg/core';\n\nexport interface Job<T = any> {\n id: string;\n type: string;\n data: T;\n priority: number;\n attempts: number;\n maxAttempts: number;\n delay: number;\n createdAt: Date;\n processAt: Date;\n completedAt?: Date;\n failedAt?: Date;\n error?: string;\n metadata: Record<string, any>;\n}\n\nexport interface JobProcessorOptions {\n concurrency: number;\n retryDelays: number[];\n maxRetries: number;\n pollInterval: number;\n enableMetrics: boolean;\n rateLimiter?: {\n maxRequests: number;\n windowMs: number;\n };\n circuitBreaker?: {\n failureThreshold: number;\n timeout: number;\n resetTimeout: number;\n };\n}\n\nexport interface JobHandler<T = any> {\n (job: Job<T>): Promise<any>;\n}\n\nexport interface JobProcessorMetrics {\n processed: number;\n succeeded: number;\n failed: number;\n retried: number;\n activeJobs: number;\n queueSize: number;\n averageProcessingTime: number;\n lastProcessedAt?: Date;\n}\n\nexport class JobProcessor extends EventEmitter {\n private handlers = new Map<string, JobHandler>();\n private queue: Job[] = [];\n private processing = new Set<string>();\n private isRunning = false;\n private pollTimer?: NodeJS.Timeout;\n private metrics: JobProcessorMetrics;\n private rateLimiter?: RateLimiter;\n private circuitBreaker?: CircuitBreaker;\n\n constructor(private options: JobProcessorOptions) {\n super();\n\n this.metrics = {\n processed: 0,\n succeeded: 0,\n failed: 0,\n retried: 0,\n activeJobs: 0,\n queueSize: 0,\n averageProcessingTime: 0\n };\n\n if (options.rateLimiter) {\n this.rateLimiter = new RateLimiter(\n options.rateLimiter.maxRequests,\n options.rateLimiter.windowMs\n );\n }\n\n if (options.circuitBreaker) {\n this.circuitBreaker = new CircuitBreaker(options.circuitBreaker);\n }\n }\n\n /**\n * Register a job handler\n */\n handle<T>(jobType: string, handler: JobHandler<T>): void {\n this.handlers.set(jobType, handler);\n }\n\n /**\n * Add a job to the queue\n */\n async add<T>(\n jobType: string,\n data: T,\n options: {\n priority?: number;\n delay?: number;\n maxAttempts?: number;\n metadata?: Record<string, any>;\n } = {}\n ): Promise<string> {\n const jobId = `${jobType}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const now = new Date();\n\n const job: Job<T> = {\n id: jobId,\n type: jobType,\n data,\n priority: options.priority || 5,\n attempts: 0,\n maxAttempts: options.maxAttempts || this.options.maxRetries,\n delay: options.delay || 0,\n createdAt: now,\n processAt: new Date(now.getTime() + (options.delay || 0)),\n metadata: options.metadata || {}\n };\n\n // Insert job in priority order (higher priority first)\n const insertIndex = this.queue.findIndex(\n existingJob => existingJob.priority < job.priority\n );\n\n if (insertIndex === -1) {\n this.queue.push(job);\n } else {\n this.queue.splice(insertIndex, 0, job);\n }\n\n this.updateMetrics();\n this.emit('job:added', job);\n\n return jobId;\n }\n\n /**\n * Start processing jobs\n */\n start(): void {\n if (this.isRunning) {\n return;\n }\n\n this.isRunning = true;\n this.scheduleNextPoll();\n this.emit('processor:started');\n }\n\n /**\n * Stop processing jobs\n */\n async stop(): Promise<void> {\n this.isRunning = false;\n\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = undefined;\n }\n\n // Wait for active jobs to complete\n while (this.processing.size > 0) {\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n this.emit('processor:stopped');\n }\n\n /**\n * Get current metrics\n */\n getMetrics(): JobProcessorMetrics {\n return { ...this.metrics };\n }\n\n /**\n * Get queue status\n */\n getQueueStatus(): {\n pending: number;\n processing: number;\n failed: number;\n totalProcessed: number;\n } {\n const failed = this.queue.filter(job => job.failedAt).length;\n\n return {\n pending: this.queue.length - failed,\n processing: this.processing.size,\n failed,\n totalProcessed: this.metrics.processed\n };\n }\n\n /**\n * Remove completed jobs from queue\n */\n cleanup(): number {\n const initialLength = this.queue.length;\n\n this.queue = this.queue.filter(job =>\n !job.completedAt && !job.failedAt\n );\n\n const removed = initialLength - this.queue.length;\n this.updateMetrics();\n\n return removed;\n }\n\n /**\n * Get specific job by ID\n */\n getJob(jobId: string): Job | undefined {\n return this.queue.find(job => job.id === jobId);\n }\n\n /**\n * Remove job from queue\n */\n removeJob(jobId: string): boolean {\n const index = this.queue.findIndex(job => job.id === jobId);\n if (index !== -1) {\n this.queue.splice(index, 1);\n this.processing.delete(jobId);\n this.updateMetrics();\n return true;\n }\n return false;\n }\n\n private scheduleNextPoll(): void {\n if (!this.isRunning) {\n return;\n }\n\n this.pollTimer = setTimeout(() => {\n this.processJobs();\n this.scheduleNextPoll();\n }, this.options.pollInterval);\n }\n\n private async processJobs(): Promise<void> {\n const availableSlots = this.options.concurrency - this.processing.size;\n if (availableSlots <= 0) {\n return;\n }\n\n const now = new Date();\n const readyJobs = this.queue\n .filter(job =>\n !job.completedAt &&\n !job.failedAt &&\n !this.processing.has(job.id) &&\n job.processAt <= now\n )\n .slice(0, availableSlots);\n\n for (const job of readyJobs) {\n this.processJob(job);\n }\n }\n\n private async processJob(job: Job): Promise<void> {\n const handler = this.handlers.get(job.type);\n if (!handler) {\n this.failJob(job, `No handler registered for job type: ${job.type}`);\n return;\n }\n\n this.processing.add(job.id);\n job.attempts++;\n this.metrics.activeJobs++;\n\n const startTime = Date.now();\n\n try {\n // Apply rate limiting\n if (this.rateLimiter) {\n await this.rateLimiter.acquire();\n }\n\n // Execute through circuit breaker if configured\n const executeJob = async () => handler(job);\n const result = this.circuitBreaker\n ? await this.circuitBreaker.execute(executeJob)\n : await executeJob();\n\n // Job completed successfully\n job.completedAt = new Date();\n this.processing.delete(job.id);\n this.metrics.activeJobs--;\n this.metrics.succeeded++;\n this.metrics.processed++;\n\n const processingTime = Date.now() - startTime;\n this.updateAverageProcessingTime(processingTime);\n\n this.emit('job:completed', { job, result, processingTime });\n\n } catch (error) {\n this.processing.delete(job.id);\n this.metrics.activeJobs--;\n\n const shouldRetry = job.attempts < job.maxAttempts;\n\n if (shouldRetry) {\n // Schedule retry\n const retryDelay = this.getRetryDelay(job.attempts);\n job.processAt = new Date(Date.now() + retryDelay);\n job.error = error instanceof Error ? error.message : String(error);\n\n this.metrics.retried++;\n this.emit('job:retry', { job, error, retryDelay });\n } else {\n // Job failed permanently\n this.failJob(job, error instanceof Error ? error.message : String(error));\n }\n }\n\n this.updateMetrics();\n }\n\n private failJob(job: Job, error: string): void {\n job.failedAt = new Date();\n job.error = error;\n this.metrics.failed++;\n this.metrics.processed++;\n this.emit('job:failed', { job, error });\n }\n\n private getRetryDelay(attempt: number): number {\n const delayIndex = Math.min(attempt - 1, this.options.retryDelays.length - 1);\n return this.options.retryDelays[delayIndex] || this.options.retryDelays[this.options.retryDelays.length - 1];\n }\n\n private updateMetrics(): void {\n this.metrics.queueSize = this.queue.length;\n this.metrics.lastProcessedAt = new Date();\n }\n\n private updateAverageProcessingTime(newTime: number): void {\n const totalProcessed = this.metrics.succeeded + this.metrics.failed;\n if (totalProcessed === 1) {\n this.metrics.averageProcessingTime = newTime;\n } else {\n this.metrics.averageProcessingTime =\n (this.metrics.averageProcessingTime * (totalProcessed - 1) + newTime) / totalProcessed;\n }\n }\n}\n\n/**\n * Specific processor for message jobs\n */\nexport class MessageJobProcessor extends JobProcessor {\n constructor(options: Partial<JobProcessorOptions> = {}) {\n super({\n concurrency: 5,\n retryDelays: [1000, 5000, 15000, 60000], // 1s, 5s, 15s, 1m\n maxRetries: 3,\n pollInterval: 1000,\n enableMetrics: true,\n ...options\n });\n\n this.setupMessageHandlers();\n }\n\n private setupMessageHandlers(): void {\n // Handle single message sending\n this.handle('send_message', async (job: Job<MessageRequest>) => {\n return this.processSingleMessage(job);\n });\n\n // Handle bulk message sending\n this.handle('send_bulk_messages', async (job: Job<MessageRequest[]>) => {\n return this.processBulkMessages(job);\n });\n\n // Handle delivery status updates\n this.handle('update_delivery_status', async (job: Job<DeliveryReport>) => {\n return this.processDeliveryUpdate(job);\n });\n\n // Handle scheduled message sending\n this.handle('send_scheduled_message', async (job: Job<MessageRequest>) => {\n return this.processScheduledMessage(job);\n });\n }\n\n private async processSingleMessage(job: Job<MessageRequest>): Promise<MessageResult> {\n const { data: messageRequest } = job;\n\n // Emit processing event\n this.emit('message:processing', {\n type: MessageEventType.MESSAGE_QUEUED,\n timestamp: new Date(),\n data: { requestId: job.id, messageRequest },\n metadata: job.metadata\n } as MessageEvent);\n\n // Process message (this would integrate with actual provider)\n const results: RecipientResult[] = messageRequest.recipients.map(recipient => ({\n phoneNumber: recipient.phoneNumber,\n messageId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,\n status: MessageStatus.QUEUED,\n metadata: recipient.metadata\n }));\n\n const result: MessageResult = {\n requestId: job.id,\n results,\n summary: {\n total: messageRequest.recipients.length,\n queued: messageRequest.recipients.length,\n sent: 0,\n failed: 0\n },\n metadata: {\n createdAt: new Date(),\n provider: 'default',\n templateId: messageRequest.templateId\n }\n };\n\n // Emit completion event\n this.emit('message:queued', {\n type: MessageEventType.MESSAGE_QUEUED,\n timestamp: new Date(),\n data: result,\n metadata: job.metadata\n } as MessageEvent);\n\n return result;\n }\n\n private async processBulkMessages(job: Job<MessageRequest[]>): Promise<MessageResult[]> {\n const { data: messageRequests } = job;\n const results: MessageResult[] = [];\n\n for (const messageRequest of messageRequests) {\n const singleJob: Job<MessageRequest> = {\n ...job,\n id: `${job.id}_${results.length}`,\n data: messageRequest\n };\n\n const result = await this.processSingleMessage(singleJob);\n results.push(result);\n }\n\n return results;\n }\n\n private async processDeliveryUpdate(job: Job<DeliveryReport>): Promise<void> {\n const { data: deliveryReport } = job;\n\n // Update delivery status (this would update database)\n this.emit('delivery:updated', {\n type: MessageEventType.MESSAGE_DELIVERED,\n timestamp: new Date(),\n data: deliveryReport,\n metadata: job.metadata\n } as MessageEvent);\n }\n\n private async processScheduledMessage(job: Job<MessageRequest>): Promise<MessageResult> {\n const { data: messageRequest } = job;\n\n // Check if it's time to send\n const scheduledAt = messageRequest.scheduling?.scheduledAt;\n if (scheduledAt && scheduledAt > new Date()) {\n // Reschedule for later\n throw new Error(`Message scheduled for ${scheduledAt.toISOString()}, rescheduling`);\n }\n\n // Process as normal message\n return this.processSingleMessage(job);\n }\n\n /**\n * Add a message to the processing queue\n */\n async queueMessage(\n messageRequest: MessageRequest,\n options: {\n priority?: number;\n delay?: number;\n metadata?: Record<string, any>;\n } = {}\n ): Promise<string> {\n const priority = options.priority ||\n (messageRequest.options?.priority === 'high' ? 10 :\n messageRequest.options?.priority === 'low' ? 1 : 5);\n\n const delay = options.delay || 0;\n\n return this.add('send_message', messageRequest, {\n priority,\n delay,\n metadata: options.metadata\n });\n }\n\n /**\n * Add bulk messages to the processing queue\n */\n async queueBulkMessages(\n messageRequests: MessageRequest[],\n options: {\n priority?: number;\n delay?: number;\n metadata?: Record<string, any>;\n } = {}\n ): Promise<string> {\n return this.add('send_bulk_messages', messageRequests, {\n priority: options.priority || 3,\n delay: options.delay || 0,\n metadata: options.metadata\n });\n }\n\n /**\n * Schedule a message for future delivery\n */\n async scheduleMessage(\n messageRequest: MessageRequest,\n scheduledAt: Date,\n options: {\n metadata?: Record<string, any>;\n } = {}\n ): Promise<string> {\n const delay = Math.max(0, scheduledAt.getTime() - Date.now());\n\n return this.add('send_scheduled_message', messageRequest, {\n priority: 5,\n delay,\n metadata: options.metadata\n });\n }\n}","/**\n * Retry handler for failed message deliveries\n */\n\nimport { EventEmitter } from 'events';\nimport {\n MessageStatus,\n DeliveryReport,\n DeliveryAttempt,\n MessageEventType,\n MessageEvent\n} from '../types/message.types';\nimport { RetryHandler as CoreRetryHandler, ErrorUtils } from '@k-msg/core';\n\nexport interface RetryPolicy {\n maxAttempts: number;\n backoffMultiplier: number;\n initialDelay: number;\n maxDelay: number;\n jitter: boolean;\n retryableStatuses: MessageStatus[];\n retryableErrorCodes: string[];\n}\n\nexport interface RetryAttempt {\n messageId: string;\n phoneNumber: string;\n attemptNumber: number;\n scheduledAt: Date;\n provider: string;\n templateId: string;\n variables: Record<string, any>;\n metadata: Record<string, any>;\n}\n\nexport interface RetryQueueItem {\n id: string;\n messageId: string;\n phoneNumber: string;\n originalDeliveryReport: DeliveryReport;\n attempts: RetryAttempt[];\n nextRetryAt: Date;\n status: 'pending' | 'processing' | 'exhausted' | 'cancelled';\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface RetryHandlerOptions {\n policy: RetryPolicy;\n checkInterval: number;\n maxQueueSize: number;\n enablePersistence: boolean;\n onRetryExhausted?: (item: RetryQueueItem) => Promise<void>;\n onRetrySuccess?: (item: RetryQueueItem, result: any) => Promise<void>;\n onRetryFailed?: (item: RetryQueueItem, error: Error) => Promise<void>;\n}\n\nexport interface RetryHandlerMetrics {\n totalRetries: number;\n successfulRetries: number;\n failedRetries: number;\n exhaustedRetries: number;\n queueSize: number;\n averageRetryDelay: number;\n lastRetryAt?: Date;\n}\n\nexport class MessageRetryHandler extends EventEmitter {\n private retryQueue: RetryQueueItem[] = [];\n private processing = new Set<string>();\n private checkTimer?: NodeJS.Timeout;\n private isRunning = false;\n private metrics: RetryHandlerMetrics;\n\n private defaultPolicy: RetryPolicy = {\n maxAttempts: 3,\n backoffMultiplier: 2,\n initialDelay: 5000, // 5 seconds\n maxDelay: 300000, // 5 minutes\n jitter: true,\n retryableStatuses: [MessageStatus.FAILED],\n retryableErrorCodes: [\n 'NETWORK_TIMEOUT',\n 'PROVIDER_CONNECTION_FAILED',\n 'PROVIDER_RATE_LIMITED',\n 'PROVIDER_SERVICE_UNAVAILABLE'\n ]\n };\n\n constructor(private options: RetryHandlerOptions) {\n super();\n\n this.options.policy = { ...this.defaultPolicy, ...this.options.policy };\n\n this.metrics = {\n totalRetries: 0,\n successfulRetries: 0,\n failedRetries: 0,\n exhaustedRetries: 0,\n queueSize: 0,\n averageRetryDelay: 0\n };\n }\n\n /**\n * Start the retry handler\n */\n start(): void {\n if (this.isRunning) {\n return;\n }\n\n this.isRunning = true;\n this.scheduleNextCheck();\n this.emit('handler:started');\n }\n\n /**\n * Stop the retry handler\n */\n async stop(): Promise<void> {\n this.isRunning = false;\n\n if (this.checkTimer) {\n clearTimeout(this.checkTimer);\n this.checkTimer = undefined;\n }\n\n // Wait for active retries to complete\n while (this.processing.size > 0) {\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n this.emit('handler:stopped');\n }\n\n /**\n * Add a failed delivery for retry\n */\n async addForRetry(deliveryReport: DeliveryReport): Promise<boolean> {\n // Check if this message should be retried\n if (!this.shouldRetry(deliveryReport)) {\n return false;\n }\n\n // Check if already in retry queue\n const existingItem = this.retryQueue.find(\n item => item.messageId === deliveryReport.messageId\n );\n\n if (existingItem) {\n // Update existing item\n return this.updateRetryItem(existingItem, deliveryReport);\n }\n\n // Create new retry item\n const retryItem = await this.createRetryItem(deliveryReport);\n\n if (this.retryQueue.length >= this.options.maxQueueSize) {\n // Remove oldest exhausted items to make space\n this.cleanupQueue();\n\n if (this.retryQueue.length >= this.options.maxQueueSize) {\n this.emit('queue:full', { rejected: deliveryReport });\n return false;\n }\n }\n\n this.retryQueue.push(retryItem);\n this.updateMetrics();\n\n this.emit('retry:queued', {\n type: MessageEventType.MESSAGE_QUEUED,\n timestamp: new Date(),\n data: retryItem,\n metadata: deliveryReport.metadata\n } as MessageEvent);\n\n return true;\n }\n\n /**\n * Cancel retry for a specific message\n */\n cancelRetry(messageId: string): boolean {\n const item = this.retryQueue.find(item => item.messageId === messageId);\n if (item) {\n item.status = 'cancelled';\n item.updatedAt = new Date();\n this.updateMetrics();\n this.emit('retry:cancelled', item);\n return true;\n }\n return false;\n }\n\n /**\n * Get retry status for a message\n */\n getRetryStatus(messageId: string): RetryQueueItem | undefined {\n return this.retryQueue.find(item => item.messageId === messageId);\n }\n\n /**\n * Get all retry queue items\n */\n getRetryQueue(): RetryQueueItem[] {\n return [...this.retryQueue];\n }\n\n /**\n * Get metrics\n */\n getMetrics(): RetryHandlerMetrics {\n return { ...this.metrics };\n }\n\n /**\n * Clean up completed/exhausted retry items\n */\n cleanup(): number {\n const initialLength = this.retryQueue.length;\n\n this.retryQueue = this.retryQueue.filter(item =>\n item.status === 'pending' || item.status === 'processing'\n );\n\n const removed = initialLength - this.retryQueue.length;\n this.updateMetrics();\n\n return removed;\n }\n\n private scheduleNextCheck(): void {\n if (!this.isRunning) {\n return;\n }\n\n this.checkTimer = setTimeout(() => {\n this.processRetryQueue();\n this.scheduleNextCheck();\n }, this.options.checkInterval);\n }\n\n private async processRetryQueue(): Promise<void> {\n const now = new Date();\n\n const readyItems = this.retryQueue.filter(item =>\n item.status === 'pending' &&\n item.nextRetryAt <= now &&\n !this.processing.has(item.id)\n );\n\n for (const item of readyItems) {\n this.processRetryItem(item);\n }\n }\n\n private async processRetryItem(item: RetryQueueItem): Promise<void> {\n this.processing.add(item.id);\n item.status = 'processing';\n item.updatedAt = new Date();\n\n try {\n // Create retry attempt\n const attempt: RetryAttempt = {\n messageId: item.messageId,\n phoneNumber: item.phoneNumber,\n attemptNumber: item.attempts.length + 1,\n scheduledAt: new Date(),\n provider: item.originalDeliveryReport.attempts[0]?.provider || 'unknown',\n templateId: item.originalDeliveryReport.metadata.templateId || '',\n variables: item.originalDeliveryReport.metadata.variables || {},\n metadata: item.originalDeliveryReport.metadata\n };\n\n item.attempts.push(attempt);\n\n // Emit retry started event\n this.emit('retry:started', {\n type: MessageEventType.MESSAGE_QUEUED,\n timestamp: new Date(),\n data: { item, attempt },\n metadata: item.originalDeliveryReport.metadata\n } as MessageEvent);\n\n // Execute retry (this would integrate with actual message sender)\n const result = await this.executeRetry(attempt);\n\n // Retry succeeded\n item.status = 'exhausted'; // Mark as completed\n this.processing.delete(item.id);\n this.metrics.successfulRetries++;\n this.metrics.totalRetries++;\n this.updateMetrics();\n\n await this.options.onRetrySuccess?.(item, result);\n\n this.emit('retry:success', {\n type: MessageEventType.MESSAGE_SENT,\n timestamp: new Date(),\n data: { item, attempt, result },\n metadata: item.originalDeliveryReport.metadata\n } as MessageEvent);\n\n } catch (error) {\n this.processing.delete(item.id);\n this.metrics.failedRetries++;\n this.metrics.totalRetries++;\n\n const maxAttempts = this.options.policy.maxAttempts;\n const shouldRetryAgain = item.attempts.length < maxAttempts;\n\n if (shouldRetryAgain) {\n // Schedule next retry\n const nextDelay = this.calculateRetryDelay(item.attempts.length);\n item.nextRetryAt = new Date(Date.now() + nextDelay);\n item.status = 'pending';\n } else {\n // Retry exhausted\n item.status = 'exhausted';\n this.metrics.exhaustedRetries++;\n\n await this.options.onRetryExhausted?.(item);\n\n this.emit('retry:exhausted', {\n type: MessageEventType.MESSAGE_FAILED,\n timestamp: new Date(),\n data: { item, finalError: error },\n metadata: item.originalDeliveryReport.metadata\n } as MessageEvent);\n }\n\n item.updatedAt = new Date();\n this.updateMetrics();\n\n await this.options.onRetryFailed?.(item, error as Error);\n\n this.emit('retry:failed', {\n type: MessageEventType.MESSAGE_FAILED,\n timestamp: new Date(),\n data: { item, error, willRetry: shouldRetryAgain },\n metadata: item.originalDeliveryReport.metadata\n } as MessageEvent);\n }\n }\n\n private async executeRetry(attempt: RetryAttempt): Promise<any> {\n // This would integrate with the actual message sender\n // For now, simulate the retry operation\n return CoreRetryHandler.execute(\n async () => {\n // Simulate message sending\n if (Math.random() < 0.7) { // 70% success rate for retries\n return {\n messageId: attempt.messageId,\n status: 'sent',\n sentAt: new Date()\n };\n } else {\n throw new Error('Retry failed');\n }\n },\n {\n maxAttempts: 1, // We handle retries at a higher level\n initialDelay: 0,\n retryCondition: () => false // No retries at this level\n }\n );\n }\n\n private shouldRetry(deliveryReport: DeliveryReport): boolean {\n const { policy } = this.options;\n\n // Check if status is retryable\n if (!policy.retryableStatuses.includes(deliveryReport.status)) {\n return false;\n }\n\n // Check if error code is retryable\n // First check top-level error, then latest attempt error\n let errorToCheck = deliveryReport.error;\n if (!errorToCheck && deliveryReport.attempts.length > 0) {\n const latestAttempt = deliveryReport.attempts[deliveryReport.attempts.length - 1];\n errorToCheck = latestAttempt.error;\n }\n\n if (errorToCheck) {\n const isRetryableError = policy.retryableErrorCodes.includes(errorToCheck.code);\n if (!isRetryableError) {\n return false;\n }\n }\n\n // Check if attempts haven't been exhausted\n return deliveryReport.attempts.length < policy.maxAttempts;\n }\n\n private async createRetryItem(deliveryReport: DeliveryReport): Promise<RetryQueueItem> {\n const initialDelay = this.calculateRetryDelay(deliveryReport.attempts.length);\n\n return {\n id: `retry_${deliveryReport.messageId}_${Date.now()}`,\n messageId: deliveryReport.messageId,\n phoneNumber: deliveryReport.phoneNumber,\n originalDeliveryReport: deliveryReport,\n attempts: [],\n nextRetryAt: new Date(Date.now() + initialDelay),\n status: 'pending',\n createdAt: new Date(),\n updatedAt: new Date()\n };\n }\n\n private updateRetryItem(item: RetryQueueItem, deliveryReport: DeliveryReport): boolean {\n if (item.status === 'exhausted' || item.status === 'cancelled') {\n return false;\n }\n\n // Update the delivery report\n item.originalDeliveryReport = deliveryReport;\n item.updatedAt = new Date();\n\n // Recalculate next retry time if needed\n if (item.status === 'pending') {\n const nextDelay = this.calculateRetryDelay(item.attempts.length);\n item.nextRetryAt = new Date(Date.now() + nextDelay);\n }\n\n return true;\n }\n\n private calculateRetryDelay(attemptNumber: number): number {\n const { policy } = this.options;\n\n let delay = policy.initialDelay * Math.pow(policy.backoffMultiplier, attemptNumber);\n delay = Math.min(delay, policy.maxDelay);\n\n // Add jitter if enabled\n if (policy.jitter) {\n const jitterAmount = delay * 0.1; // 10% jitter\n delay += (Math.random() - 0.5) * 2 * jitterAmount;\n }\n\n return Math.max(0, delay);\n }\n\n private cleanupQueue(): void {\n const cutoffTime = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24 hours ago\n\n this.retryQueue = this.retryQueue.filter(item =>\n item.status === 'pending' ||\n item.status === 'processing' ||\n (item.status === 'exhausted' && item.updatedAt > cutoffTime)\n );\n }\n\n private updateMetrics(): void {\n this.metrics.queueSize = this.retryQueue.length;\n this.metrics.lastRetryAt = new Date();\n\n // Calculate average retry delay\n const pendingItems = this.retryQueue.filter(item => item.status === 'pending');\n if (pendingItems.length > 0) {\n const totalDelay = pendingItems.reduce((sum, item) => {\n return sum + Math.max(0, item.nextRetryAt.getTime() - Date.now());\n }, 0);\n this.metrics.averageRetryDelay = totalDelay / pendingItems.length;\n }\n }\n}","/**\n * Delivery tracking system for messages\n */\n\nimport { EventEmitter } from 'events';\nimport {\n DeliveryReport,\n DeliveryAttempt,\n MessageStatus,\n MessageEventType,\n MessageEvent\n} from '../types/message.types';\n\nexport interface DeliveryTrackingOptions {\n trackingInterval: number;\n maxTrackingDuration: number;\n batchSize: number;\n enableWebhooks: boolean;\n webhookRetries: number;\n webhookTimeout: number;\n persistence: {\n enabled: boolean;\n retentionDays: number;\n };\n}\n\nexport interface DeliveryWebhook {\n url: string;\n events: MessageEventType[];\n secret?: string;\n headers?: Record<string, string>;\n timeout: number;\n retries: number;\n}\n\nexport interface TrackingRecord {\n messageId: string;\n phoneNumber: string;\n templateId: string;\n provider: string;\n currentStatus: MessageStatus;\n statusHistory: StatusHistoryEntry[];\n deliveryReport: DeliveryReport;\n webhooks: DeliveryWebhook[];\n createdAt: Date;\n updatedAt: Date;\n expiresAt: Date;\n metadata: Record<string, any>;\n}\n\nexport interface StatusHistoryEntry {\n status: MessageStatus;\n timestamp: Date;\n provider: string;\n details?: Record<string, any>;\n source: 'provider' | 'webhook' | 'manual' | 'system';\n}\n\nexport interface DeliveryStats {\n totalMessages: number;\n byStatus: Record<MessageStatus, number>;\n byProvider: Record<string, number>;\n averageDeliveryTime: number;\n deliveryRate: number;\n failureRate: number;\n lastUpdated: Date;\n}\n\nexport interface WebhookDeliveryResult {\n success: boolean;\n statusCode?: number;\n error?: string;\n responseTime: number;\n attempt: number;\n}\n\nexport class DeliveryTracker extends EventEmitter {\n private trackingRecords = new Map<string, TrackingRecord>();\n private statusIndex = new Map<MessageStatus, Set<string>>();\n private trackingTimer?: NodeJS.Timeout;\n private webhookQueue: Array<{ record: TrackingRecord; event: MessageEvent }> = [];\n private isRunning = false;\n private stats: DeliveryStats;\n\n private defaultOptions: DeliveryTrackingOptions = {\n trackingInterval: 5000, // Check every 5 seconds\n maxTrackingDuration: 86400000, // 24 hours\n batchSize: 100,\n enableWebhooks: true,\n webhookRetries: 3,\n webhookTimeout: 5000,\n persistence: {\n enabled: true,\n retentionDays: 30\n }\n };\n\n constructor(private options: DeliveryTrackingOptions) {\n super();\n \n this.options = { ...this.defaultOptions, ...options };\n \n this.stats = {\n totalMessages: 0,\n byStatus: {} as Record<MessageStatus, number>,\n byProvider: {},\n averageDeliveryTime: 0,\n deliveryRate: 0,\n failureRate: 0,\n lastUpdated: new Date()\n };\n\n // Initialize status counters\n Object.values(MessageStatus).forEach(status => {\n this.stats.byStatus[status] = 0;\n this.statusIndex.set(status, new Set());\n });\n }\n\n /**\n * Start delivery tracking\n */\n start(): void {\n if (this.isRunning) {\n return;\n }\n\n this.isRunning = true;\n this.scheduleTracking();\n this.emit('tracker:started');\n }\n\n /**\n * Stop delivery tracking\n */\n stop(): void {\n this.isRunning = false;\n \n if (this.trackingTimer) {\n clearTimeout(this.trackingTimer);\n this.trackingTimer = undefined;\n }\n\n this.emit('tracker:stopped');\n }\n\n /**\n * Start tracking a message\n */\n async trackMessage(\n messageId: string,\n phoneNumber: string,\n templateId: string,\n provider: string,\n options: {\n webhooks?: DeliveryWebhook[];\n metadata?: Record<string, any>;\n initialStatus?: MessageStatus;\n } = {}\n ): Promise<void> {\n const now = new Date();\n const expiresAt = new Date(now.getTime() + this.options.maxTrackingDuration);\n \n const initialStatus = options.initialStatus || MessageStatus.QUEUED;\n \n const deliveryReport: DeliveryReport = {\n messageId,\n phoneNumber,\n status: initialStatus,\n attempts: [{\n attemptNumber: 1,\n attemptedAt: now,\n status: initialStatus,\n provider\n }],\n metadata: options.metadata || {}\n };\n\n const record: TrackingRecord = {\n messageId,\n phoneNumber,\n templateId,\n provider,\n currentStatus: initialStatus,\n statusHistory: [{\n status: initialStatus,\n timestamp: now,\n provider,\n source: 'system'\n }],\n deliveryReport,\n webhooks: options.webhooks || [],\n createdAt: now,\n updatedAt: now,\n expiresAt,\n metadata: options.metadata || {}\n };\n\n this.trackingRecords.set(messageId, record);\n this.statusIndex.get(initialStatus)?.add(messageId);\n \n this.updateStats();\n \n this.emit('tracking:started', {\n type: MessageEventType.MESSAGE_QUEUED,\n timestamp: now,\n data: record,\n metadata: record.metadata\n } as MessageEvent);\n\n // Send initial webhook if configured\n if (this.options.enableWebhooks && record.webhooks.length > 0) {\n const event: MessageEvent = {\n id: `evt_${messageId}_${Date.now()}`,\n type: MessageEventType.MESSAGE_QUEUED,\n timestamp: now,\n data: deliveryReport,\n metadata: record.metadata\n };\n \n this.queueWebhook(record, event);\n }\n }\n\n /**\n * Update message status\n */\n async updateStatus(\n messageId: string,\n status: MessageStatus,\n details: {\n provider?: string;\n error?: { code: string; message: string; details?: any };\n metadata?: Record<string, any>;\n source?: 'provider' | 'webhook' | 'manual' | 'system';\n sentAt?: Date;\n deliveredAt?: Date;\n clickedAt?: Date;\n failedAt?: Date;\n } = {}\n ): Promise<boolean> {\n const record = this.trackingRecords.get(messageId);\n if (!record) {\n return false;\n }\n\n const now = new Date();\n const oldStatus = record.currentStatus;\n \n // Update status only if it's a progression\n if (!this.isStatusProgression(oldStatus, status)) {\n return false;\n }\n\n // Remove from old status index\n this.statusIndex.get(oldStatus)?.delete(messageId);\n \n // Update record\n record.currentStatus = status;\n record.updatedAt = now;\n \n // Add to status history\n record.statusHistory.push({\n status,\n timestamp: now,\n provider: details.provider || record.provider,\n details: details.metadata,\n source: details.source || 'system'\n });\n\n // Update delivery report\n record.deliveryReport.status = status;\n record.deliveryReport.metadata = { ...record.deliveryReport.metadata, ...details.metadata };\n \n if (details.sentAt) record.deliveryReport.sentAt = details.sentAt;\n if (details.deliveredAt) record.deliveryReport.deliveredAt = details.deliveredAt;\n if (details.clickedAt) record.deliveryReport.clickedAt = details.clickedAt;\n if (details.failedAt) record.deliveryReport.failedAt = details.failedAt;\n if (details.error) record.deliveryReport.error = details.error;\n\n // Add new delivery attempt\n record.deliveryReport.attempts.push({\n attemptNumber: record.deliveryReport.attempts.length + 1,\n attemptedAt: now,\n status,\n error: details.error,\n provider: details.provider || record.provider\n });\n\n // Add to new status index\n this.statusIndex.get(status)?.add(messageId);\n \n this.updateStats();\n\n // Determine event type based on status\n const eventType = this.getEventTypeForStatus(status);\n \n const event: MessageEvent = {\n id: `evt_${messageId}_${Date.now()}`,\n type: eventType,\n timestamp: now,\n data: {\n messageId,\n previousStatus: oldStatus,\n currentStatus: status,\n deliveryReport: record.deliveryReport,\n ...details\n },\n metadata: record.metadata\n };\n\n this.emit('status:updated', event);\n\n // Send webhook if configured\n if (this.options.enableWebhooks && record.webhooks.length > 0) {\n this.queueWebhook(record, event);\n }\n\n // Check if tracking should be completed\n if (this.isTerminalStatus(status)) {\n this.emit('tracking:completed', {\n ...event,\n data: { ...event.data, trackingCompleted: true }\n });\n }\n\n return true;\n }\n\n /**\n * Get delivery report for a message\n */\n getDeliveryReport(messageId: string): DeliveryReport | undefined {\n return this.trackingRecords.get(messageId)?.deliveryReport;\n }\n\n /**\n * Get tracking record for a message\n */\n getTrackingRecord(messageId: string): TrackingRecord | undefined {\n return this.trackingRecords.get(messageId);\n }\n\n /**\n * Get messages by status\n */\n getMessagesByStatus(status: MessageStatus): TrackingRecord[] {\n const messageIds = this.statusIndex.get(status) || new Set();\n return Array.from(messageIds)\n .map(id => this.trackingRecords.get(id))\n .filter((record): record is TrackingRecord => record !== undefined);\n }\n\n /**\n * Get delivery statistics\n */\n getStats(): DeliveryStats {\n return { ...this.stats };\n }\n\n /**\n * Get delivery statistics for a specific time range\n */\n getStatsForPeriod(startDate: Date, endDate: Date): DeliveryStats {\n const records = Array.from(this.trackingRecords.values())\n .filter(record => \n record.createdAt >= startDate && record.createdAt <= endDate\n );\n\n const stats: DeliveryStats = {\n totalMessages: records.length,\n byStatus: {} as Record<MessageStatus, number>,\n byProvider: {},\n averageDeliveryTime: 0,\n deliveryRate: 0,\n failureRate: 0,\n lastUpdated: new Date()\n };\n\n // Initialize counters\n Object.values(MessageStatus).forEach(status => {\n stats.byStatus[status] = 0;\n });\n\n // Calculate statistics\n let totalDeliveryTime = 0;\n let deliveredCount = 0;\n let failedCount = 0;\n\n records.forEach(record => {\n // Count by status\n stats.byStatus[record.currentStatus]++;\n \n // Count by provider\n stats.byProvider[record.provider] = (stats.byProvider[record.provider] || 0) + 1;\n \n // Calculate delivery time for delivered messages\n if (record.deliveryReport.deliveredAt && record.deliveryReport.sentAt) {\n const deliveryTime = record.deliveryReport.deliveredAt.getTime() - \n record.deliveryReport.sentAt.getTime();\n totalDeliveryTime += deliveryTime;\n deliveredCount++;\n }\n\n // Count failures\n if (record.currentStatus === MessageStatus.FAILED) {\n failedCount++;\n }\n });\n\n // Calculate averages and rates\n if (deliveredCount > 0) {\n stats.averageDeliveryTime = totalDeliveryTime / deliveredCount;\n }\n\n if (records.length > 0) {\n stats.deliveryRate = (stats.byStatus[MessageStatus.DELIVERED] / records.length) * 100;\n stats.failureRate = (failedCount / records.length) * 100;\n }\n\n return stats;\n }\n\n /**\n * Clean up expired tracking records\n */\n cleanup(): number {\n const now = new Date();\n let removed = 0;\n\n for (const [messageId, record] of this.trackingRecords.entries()) {\n if (record.expiresAt <= now || this.isTerminalStatus(record.currentStatus)) {\n // Remove from tracking\n this.trackingRecords.delete(messageId);\n this.statusIndex.get(record.currentStatus)?.delete(messageId);\n removed++;\n }\n }\n\n if (removed > 0) {\n this.updateStats();\n this.emit('cleanup:completed', { removedCount: removed });\n }\n\n return removed;\n }\n\n /**\n * Stop tracking a specific message\n */\n stopTracking(messageId: string): boolean {\n const record = this.trackingRecords.get(messageId);\n if (!record) {\n return false;\n }\n\n this.trackingRecords.delete(messageId);\n this.statusIndex.get(record.currentStatus)?.delete(messageId);\n \n this.updateStats();\n \n this.emit('tracking:stopped', {\n type: MessageEventType.MESSAGE_CANCELLED,\n timestamp: new Date(),\n data: record,\n metadata: record.metadata\n } as MessageEvent);\n\n return true;\n }\n\n private scheduleTracking(): void {\n if (!this.isRunning) {\n return;\n }\n\n this.trackingTimer = setTimeout(() => {\n this.processTracking();\n this.processWebhookQueue();\n this.scheduleTracking();\n }, this.options.trackingInterval);\n }\n\n private async processTracking(): Promise<void> {\n // Process webhook queue\n await this.processWebhookQueue();\n \n // Clean up expired records periodically (every hour)\n const shouldCleanup = Date.now() % (60 * 60 * 1000) < this.options.trackingInterval;\n if (shouldCleanup) {\n this.cleanup();\n }\n }\n\n private async processWebhookQueue(): Promise<void> {\n if (!this.options.enableWebhooks || this.webhookQueue.length === 0) {\n return;\n }\n\n const batch = this.webhookQueue.splice(0, this.options.batchSize);\n \n for (const { record, event } of batch) {\n for (const webhook of record.webhooks) {\n if (webhook.events.includes(event.type)) {\n this.deliverWebhook(webhook, event);\n }\n }\n }\n }\n\n private async deliverWebhook(webhook: DeliveryWebhook, event: MessageEvent): Promise<void> {\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= webhook.retries + 1; attempt++) {\n try {\n const result = await this.sendWebhook(webhook, event, attempt);\n \n if (result.success) {\n this.emit('webhook:delivered', {\n webhook,\n event,\n result,\n attempt\n });\n return;\n } else {\n lastError = new Error(`HTTP ${result.statusCode}: ${result.error}`);\n }\n } catch (error) {\n lastError = error as Error;\n }\n\n // Wait before retry (exponential backoff)\n if (attempt <= webhook.retries) {\n const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n\n this.emit('webhook:failed', {\n webhook,\n event,\n error: lastError,\n attempts: webhook.retries + 1\n });\n }\n\n private async sendWebhook(\n webhook: DeliveryWebhook,\n event: MessageEvent,\n attempt: number\n ): Promise<WebhookDeliveryResult> {\n const startTime = Date.now();\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'User-Agent': 'K-Message-Delivery-Tracker/1.0',\n ...webhook.headers\n };\n\n // Add signature if secret is provided\n if (webhook.secret) {\n const payload = JSON.stringify(event);\n // This would normally use HMAC-SHA256\n headers['X-Signature'] = `sha256=${webhook.secret}`;\n }\n\n const response: Response = await fetch(webhook.url, {\n method: 'POST',\n headers,\n body: JSON.stringify(event),\n signal: AbortSignal.timeout(webhook.timeout)\n });\n\n const responseTime = Date.now() - startTime;\n\n return {\n success: response.ok,\n statusCode: response.status,\n error: response.ok ? undefined : response.statusText,\n responseTime,\n attempt\n };\n\n } catch (error) {\n const responseTime = Date.now() - startTime;\n \n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n responseTime,\n attempt\n };\n }\n }\n\n private queueWebhook(record: TrackingRecord, event: MessageEvent): void {\n this.webhookQueue.push({ record, event });\n }\n\n private isStatusProgression(oldStatus: MessageStatus, newStatus: MessageStatus): boolean {\n const statusOrder = [\n MessageStatus.QUEUED,\n MessageStatus.SENDING,\n MessageStatus.SENT,\n MessageStatus.DELIVERED,\n MessageStatus.CLICKED\n ];\n\n const oldIndex = statusOrder.indexOf(oldStatus);\n const newIndex = statusOrder.indexOf(newStatus);\n\n // Allow progression forward, or to FAILED/CANCELLED from any status\n return newIndex > oldIndex || \n newStatus === MessageStatus.FAILED || \n newStatus === MessageStatus.CANCELLED;\n }\n\n private isTerminalStatus(status: MessageStatus): boolean {\n return [\n MessageStatus.DELIVERED,\n MessageStatus.FAILED,\n MessageStatus.CANCELLED,\n MessageStatus.CLICKED\n ].includes(status);\n }\n\n private getEventTypeForStatus(status: MessageStatus): MessageEventType {\n switch (status) {\n case MessageStatus.QUEUED:\n return MessageEventType.MESSAGE_QUEUED;\n case MessageStatus.SENT:\n return MessageEventType.MESSAGE_SENT;\n case MessageStatus.DELIVERED:\n return MessageEventType.MESSAGE_DELIVERED;\n case MessageStatus.FAILED:\n return MessageEventType.MESSAGE_FAILED;\n case MessageStatus.CLICKED:\n return MessageEventType.MESSAGE_CLICKED;\n default:\n return MessageEventType.MESSAGE_QUEUED;\n }\n }\n\n private updateStats(): void {\n this.stats.totalMessages = this.trackingRecords.size;\n this.stats.lastUpdated = new Date();\n\n // Reset counters\n Object.values(MessageStatus).forEach(status => {\n this.stats.byStatus[status] = 0;\n });\n this.stats.byProvider = {};\n\n // Recalculate from current records\n let totalDeliveryTime = 0;\n let deliveredCount = 0;\n let failedCount = 0;\n\n for (const record of this.trackingRecords.values()) {\n // Count by status\n this.stats.byStatus[record.currentStatus]++;\n \n // Count by provider\n this.stats.byProvider[record.provider] = \n (this.stats.byProvider[record.provider] || 0) + 1;\n \n // Calculate delivery metrics\n if (record.deliveryReport.deliveredAt && record.deliveryReport.sentAt) {\n const deliveryTime = record.deliveryReport.deliveredAt.getTime() - \n record.deliveryReport.sentAt.getTime();\n totalDeliveryTime += deliveryTime;\n deliveredCount++;\n }\n\n if (record.currentStatus === MessageStatus.FAILED) {\n failedCount++;\n }\n }\n\n // Calculate rates and averages\n if (deliveredCount > 0) {\n this.stats.averageDeliveryTime = totalDeliveryTime / deliveredCount;\n }\n\n if (this.stats.totalMessages > 0) {\n this.stats.deliveryRate = \n (this.stats.byStatus[MessageStatus.DELIVERED] / this.stats.totalMessages) * 100;\n this.stats.failureRate = (failedCount / this.stats.totalMessages) * 100;\n }\n }\n}","/**\n * Variable replacement and personalization system\n */\n\nimport { VariableMap } from '../types/message.types';\n\nexport interface VariableReplacementOptions {\n variablePattern: RegExp;\n allowUndefined: boolean;\n undefinedReplacement: string;\n caseSensitive: boolean;\n enableFormatting: boolean;\n enableConditionals: boolean;\n enableLoops: boolean;\n maxRecursionDepth: number;\n}\n\nexport interface VariableInfo {\n name: string;\n value: any;\n formatted: string;\n type: 'string' | 'number' | 'date' | 'boolean' | 'array' | 'object' | 'undefined';\n position: { start: number; end: number };\n}\n\nexport interface ReplacementResult {\n content: string;\n variables: VariableInfo[];\n missingVariables: string[];\n errors: ReplacementError[];\n metadata: {\n originalLength: number;\n finalLength: number;\n variableCount: number;\n replacementTime: number;\n };\n}\n\nexport interface ReplacementError {\n type: 'missing_variable' | 'format_error' | 'syntax_error' | 'recursion_limit';\n message: string;\n variable?: string;\n position?: { start: number; end: number };\n}\n\nexport interface ConditionalBlock {\n condition: string;\n content: string;\n elseContent?: string;\n}\n\nexport interface LoopBlock {\n variable: string;\n array: string;\n content: string;\n}\n\nexport class VariableReplacer {\n private defaultOptions: VariableReplacementOptions = {\n variablePattern: /\\#\\{([^}]+)\\}/g,\n allowUndefined: false,\n undefinedReplacement: '',\n caseSensitive: true,\n enableFormatting: true,\n enableConditionals: true,\n enableLoops: true,\n maxRecursionDepth: 10\n };\n\n constructor(private options: Partial<VariableReplacementOptions> = {}) {\n this.options = { ...this.defaultOptions, ...options };\n }\n\n /**\n * Replace variables in content\n */\n replace(content: string, variables: VariableMap): ReplacementResult {\n const startTime = Date.now();\n const originalLength = content.length;\n \n const result: ReplacementResult = {\n content,\n variables: [],\n missingVariables: [],\n errors: [],\n metadata: {\n originalLength,\n finalLength: 0,\n variableCount: 0,\n replacementTime: 0\n }\n };\n\n try {\n // Step 1: Process conditionals if enabled\n if (this.options.enableConditionals) {\n result.content = this.processConditionals(result.content, variables, result);\n }\n\n // Step 2: Process loops if enabled\n if (this.options.enableLoops) {\n result.content = this.processLoops(result.content, variables, result);\n }\n\n // Step 3: Replace simple variables\n result.content = this.replaceSimpleVariables(result.content, variables, result);\n\n // Step 4: Handle nested replacements (recursive)\n if (this.hasVariables(result.content)) {\n result.content = this.replaceRecursive(result.content, variables, result, 0);\n }\n\n } catch (error) {\n result.errors.push({\n type: 'syntax_error',\n message: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n\n // Update metadata\n result.metadata.finalLength = result.content.length;\n result.metadata.variableCount = result.variables.length;\n result.metadata.replacementTime = Date.now() - startTime;\n\n return result;\n }\n\n /**\n * Extract variables from content without replacing\n */\n extractVariables(content: string): string[] {\n const variables = new Set<string>();\n const pattern = new RegExp(this.options.variablePattern!);\n let match;\n\n while ((match = pattern.exec(content)) !== null) {\n const variableName = this.parseVariableName(match[1]);\n variables.add(variableName);\n }\n\n // Also extract from conditionals and loops\n if (this.options.enableConditionals) {\n const conditionals = this.extractConditionals(content);\n conditionals.forEach(conditional => {\n const conditionVars = this.extractVariablesFromExpression(conditional.condition);\n conditionVars.forEach(v => variables.add(v));\n \n const contentVars = this.extractVariables(conditional.content);\n contentVars.forEach(v => variables.add(v));\n \n if (conditional.elseContent) {\n const elseVars = this.extractVariables(conditional.elseContent);\n elseVars.forEach(v => variables.add(v));\n }\n });\n }\n\n if (this.options.enableLoops) {\n const loops = this.extractLoops(content);\n loops.forEach(loop => {\n variables.add(loop.array);\n const contentVars = this.extractVariables(loop.content);\n contentVars.forEach(v => variables.add(v));\n });\n }\n\n return Array.from(variables);\n }\n\n /**\n * Validate that all required variables are provided\n */\n validate(content: string, variables: VariableMap): {\n isValid: boolean;\n missingVariables: string[];\n errors: ReplacementError[];\n } {\n const requiredVariables = this.extractVariables(content);\n const providedVariables = Object.keys(variables);\n \n const missingVariables = requiredVariables.filter(required => {\n const normalizedRequired = this.options.caseSensitive ? required : required.toLowerCase();\n return !providedVariables.some(provided => {\n const normalizedProvided = this.options.caseSensitive ? provided : provided.toLowerCase();\n return normalizedProvided === normalizedRequired;\n });\n });\n\n const errors: ReplacementError[] = missingVariables.map(variable => ({\n type: 'missing_variable',\n message: `Missing required variable: ${variable}`,\n variable\n }));\n\n return {\n isValid: missingVariables.length === 0,\n missingVariables,\n errors\n };\n }\n\n /**\n * Preview replacement result without actually replacing\n */\n preview(content: string, variables: VariableMap): {\n originalContent: string;\n previewContent: string;\n variableHighlights: Array<{\n variable: string;\n value: string;\n positions: Array<{ start: number; end: number }>;\n }>;\n } {\n const result = this.replace(content, variables);\n const highlights: { [key: string]: { value: string; positions: Array<{ start: number; end: number }> } } = {};\n\n // Find all variable positions in original content\n const pattern = new RegExp(this.options.variablePattern!);\n let match;\n\n while ((match = pattern.exec(content)) !== null) {\n const variableName = this.parseVariableName(match[1]);\n const value = this.getVariableValue(variableName, variables);\n \n if (!highlights[variableName]) {\n highlights[variableName] = { value: String(value), positions: [] };\n }\n \n highlights[variableName].positions.push({\n start: match.index,\n end: match.index + match[0].length\n });\n }\n\n const variableHighlights = Object.entries(highlights).map(([variable, info]) => ({\n variable,\n value: info.value,\n positions: info.positions\n }));\n\n return {\n originalContent: content,\n previewContent: result.content,\n variableHighlights\n };\n }\n\n private replaceSimpleVariables(\n content: string,\n variables: VariableMap,\n result: ReplacementResult\n ): string {\n const pattern = new RegExp(this.options.variablePattern!, 'g');\n \n return content.replace(pattern, (match, variableExpression, offset) => {\n try {\n const variableName = this.parseVariableName(variableExpression);\n const value = this.getVariableValue(variableName, variables);\n \n if (value === undefined || value === null) {\n if (!this.options.allowUndefined) {\n result.missingVariables.push(variableName);\n result.errors.push({\n type: 'missing_variable',\n message: `Variable '${variableName}' is not defined`,\n variable: variableName,\n position: { start: offset, end: offset + match.length }\n });\n }\n return this.options.undefinedReplacement!;\n }\n\n // Apply formatting if enabled\n const formattedValue = this.options.enableFormatting\n ? this.formatValue(value, variableExpression)\n : String(value);\n\n // Track variable info\n result.variables.push({\n name: variableName,\n value,\n formatted: formattedValue,\n type: this.getValueType(value),\n position: { start: offset, end: offset + match.length }\n });\n\n return formattedValue;\n\n } catch (error) {\n result.errors.push({\n type: 'format_error',\n message: error instanceof Error ? error.message : 'Format error',\n variable: variableExpression,\n position: { start: offset, end: offset + match.length }\n });\n return match; // Return original if error\n }\n });\n }\n\n private replaceRecursive(\n content: string,\n variables: VariableMap,\n result: ReplacementResult,\n depth: number\n ): string {\n if (depth >= this.options.maxRecursionDepth!) {\n result.errors.push({\n type: 'recursion_limit',\n message: `Maximum recursion depth (${this.options.maxRecursionDepth}) exceeded`\n });\n return content;\n }\n\n const replaced = this.replaceSimpleVariables(content, variables, result);\n \n if (this.hasVariables(replaced) && replaced !== content) {\n return this.replaceRecursive(replaced, variables, result, depth + 1);\n }\n\n return replaced;\n }\n\n private processConditionals(\n content: string,\n variables: VariableMap,\n result: ReplacementResult\n ): string {\n const conditionals = this.extractConditionals(content);\n let processedContent = content;\n\n conditionals.forEach(conditional => {\n try {\n const conditionResult = this.evaluateCondition(conditional.condition, variables);\n const replacementContent = conditionResult \n ? conditional.content \n : (conditional.elseContent || '');\n \n // Replace the entire conditional block\n const blockPattern = this.buildConditionalPattern(conditional);\n processedContent = processedContent.replace(blockPattern, replacementContent);\n \n } catch (error) {\n result.errors.push({\n type: 'syntax_error',\n message: `Error in conditional: ${error instanceof Error ? error.message : 'Unknown error'}`\n });\n }\n });\n\n return processedContent;\n }\n\n private processLoops(\n content: string,\n variables: VariableMap,\n result: ReplacementResult\n ): string {\n const loops = this.extractLoops(content);\n let processedContent = content;\n\n loops.forEach(loop => {\n try {\n const arrayValue = this.getVariableValue(loop.array, variables);\n \n if (!Array.isArray(arrayValue)) {\n result.errors.push({\n type: 'syntax_error',\n message: `Loop variable '${loop.array}' is not an array`\n });\n return;\n }\n\n let loopContent = '';\n arrayValue.forEach((item, index) => {\n const loopVariables = {\n ...variables,\n [loop.variable]: item,\n [`${loop.variable}_index`]: index,\n [`${loop.variable}_first`]: index === 0,\n [`${loop.variable}_last`]: index === arrayValue.length - 1\n };\n \n const itemContent = this.replaceSimpleVariables(loop.content, loopVariables, result);\n loopContent += itemContent;\n });\n\n // Replace the entire loop block\n const blockPattern = this.buildLoopPattern(loop);\n processedContent = processedContent.replace(blockPattern, loopContent);\n \n } catch (error) {\n result.errors.push({\n type: 'syntax_error',\n message: `Error in loop: ${error instanceof Error ? error.message : 'Unknown error'}`\n });\n }\n });\n\n return processedContent;\n }\n\n private parseVariableName(expression: string): string {\n // Handle simple variable names and complex expressions\n const parts = expression.split('|');\n return parts[0].trim();\n }\n\n private getVariableValue(name: string, variables: VariableMap): any {\n // Support dot notation for nested objects\n const parts = name.split('.');\n let value: any = variables;\n\n for (const part of parts) {\n if (value === null || value === undefined) {\n return undefined;\n }\n \n // Handle case sensitivity\n if (this.options.caseSensitive) {\n value = value[part];\n } else {\n const key = Object.keys(value).find(k => k.toLowerCase() === part.toLowerCase());\n value = key ? value[key] : undefined;\n }\n }\n\n return value;\n }\n\n private formatValue(value: any, expression: string): string {\n if (!this.options.enableFormatting) {\n return String(value);\n }\n\n // Check for formatting instructions\n const parts = expression.split('|');\n if (parts.length < 2) {\n return String(value);\n }\n\n const formatter = parts[1].trim();\n \n try {\n switch (formatter) {\n case 'upper':\n return String(value).toUpperCase();\n case 'lower':\n return String(value).toLowerCase();\n case 'capitalize':\n return String(value).charAt(0).toUpperCase() + String(value).slice(1).toLowerCase();\n case 'number':\n return Number(value).toLocaleString();\n case 'currency':\n return new Intl.NumberFormat('ko-KR', { \n style: 'currency', \n currency: 'KRW' \n }).format(Number(value));\n case 'date':\n return new Date(value).toLocaleDateString('ko-KR');\n case 'datetime':\n return new Date(value).toLocaleString('ko-KR');\n case 'time':\n return new Date(value).toLocaleTimeString('ko-KR');\n default:\n // Custom format patterns\n if (formatter.startsWith('date:')) {\n const format = formatter.substring(5);\n return this.formatDate(new Date(value), format);\n }\n if (formatter.startsWith('number:')) {\n const digits = parseInt(formatter.substring(7));\n return Number(value).toFixed(digits);\n }\n return String(value);\n }\n } catch (error) {\n // Return original value if formatting fails\n return String(value);\n }\n }\n\n private formatDate(date: Date, format: string): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n const seconds = String(date.getSeconds()).padStart(2, '0');\n\n return format\n .replace('YYYY', String(year))\n .replace('MM', month)\n .replace('DD', day)\n .replace('HH', hours)\n .replace('mm', minutes)\n .replace('ss', seconds);\n }\n\n private getValueType(value: any): 'string' | 'number' | 'date' | 'boolean' | 'array' | 'object' | 'undefined' {\n if (value === undefined || value === null) return 'undefined';\n if (typeof value === 'string') return 'string';\n if (typeof value === 'number') return 'number';\n if (typeof value === 'boolean') return 'boolean';\n if (value instanceof Date) return 'date';\n if (Array.isArray(value)) return 'array';\n if (typeof value === 'object') return 'object';\n return 'string';\n }\n\n private hasVariables(content: string): boolean {\n return this.options.variablePattern!.test(content);\n }\n\n private extractConditionals(content: string): ConditionalBlock[] {\n // Simple conditional syntax: {{if condition}}content{{else}}else-content{{/if}}\n const conditionalPattern = /\\{\\{if\\s+([^}]+)\\}\\}(.*?)\\{\\{\\/if\\}\\}/gs;\n const conditionals: ConditionalBlock[] = [];\n let match;\n\n while ((match = conditionalPattern.exec(content)) !== null) {\n const condition = match[1].trim();\n const fullContent = match[2];\n \n // Check for else block\n const elsePattern = /^(.*?)\\{\\{else\\}\\}(.*)$/s;\n const elseMatch = fullContent.match(elsePattern);\n \n if (elseMatch) {\n conditionals.push({\n condition,\n content: elseMatch[1],\n elseContent: elseMatch[2]\n });\n } else {\n conditionals.push({\n condition,\n content: fullContent\n });\n }\n }\n\n return conditionals;\n }\n\n private extractLoops(content: string): LoopBlock[] {\n // Simple loop syntax: {{for item in items}}content{{/for}}\n const loopPattern = /\\{\\{for\\s+(\\w+)\\s+in\\s+(\\w+)\\}\\}(.*?)\\{\\{\\/for\\}\\}/gs;\n const loops: LoopBlock[] = [];\n let match;\n\n while ((match = loopPattern.exec(content)) !== null) {\n loops.push({\n variable: match[1],\n array: match[2],\n content: match[3]\n });\n }\n\n return loops;\n }\n\n private extractVariablesFromExpression(expression: string): string[] {\n const variables = new Set<string>();\n const variablePattern = /\\b([a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*)\\b/g;\n let match;\n\n while ((match = variablePattern.exec(expression)) !== null) {\n variables.add(match[1]);\n }\n\n return Array.from(variables);\n }\n\n private evaluateCondition(condition: string, variables: VariableMap): boolean {\n try {\n // Simple condition evaluation (extend as needed)\n // Supports: variable, !variable, variable === value, variable !== value, etc.\n \n const normalizedCondition = condition.trim();\n \n // Handle negation\n if (normalizedCondition.startsWith('!')) {\n const variable = normalizedCondition.substring(1).trim();\n const value = this.getVariableValue(variable, variables);\n return !value;\n }\n \n // Handle equality checks\n if (normalizedCondition.includes('===')) {\n const [left, right] = normalizedCondition.split('===').map(s => s.trim());\n const leftValue = this.getVariableValue(left, variables);\n const rightValue = right.startsWith('\"') || right.startsWith(\"'\") \n ? right.slice(1, -1) \n : this.getVariableValue(right, variables);\n return leftValue === rightValue;\n }\n \n if (normalizedCondition.includes('!==')) {\n const [left, right] = normalizedCondition.split('!==').map(s => s.trim());\n const leftValue = this.getVariableValue(left, variables);\n const rightValue = right.startsWith('\"') || right.startsWith(\"'\") \n ? right.slice(1, -1) \n : this.getVariableValue(right, variables);\n return leftValue !== rightValue;\n }\n \n // Simple truthiness check\n const value = this.getVariableValue(normalizedCondition, variables);\n return Boolean(value);\n \n } catch (error) {\n return false;\n }\n }\n\n private buildConditionalPattern(conditional: ConditionalBlock): RegExp {\n const escapedCondition = conditional.condition.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const elsePattern = conditional.elseContent ? '.*?\\\\{\\\\{else\\\\}\\\\}.*?' : '.*?';\n return new RegExp(`\\\\{\\\\{if\\\\s+${escapedCondition}\\\\}\\\\}${elsePattern}\\\\{\\\\{\\/if\\\\}\\\\}`, 'gs');\n }\n\n private buildLoopPattern(loop: LoopBlock): RegExp {\n const escapedVariable = loop.variable.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const escapedArray = loop.array.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`\\\\{\\\\{for\\\\s+${escapedVariable}\\\\s+in\\\\s+${escapedArray}\\\\}\\\\}.*?\\\\{\\\\{\\/for\\\\}\\\\}`, 'gs');\n }\n}\n\n/**\n * Default instance with Korean-optimized settings\n */\nexport const defaultVariableReplacer = new VariableReplacer({\n variablePattern: /\\#\\{([^}]+)\\}/g,\n allowUndefined: false,\n undefinedReplacement: '',\n caseSensitive: false, // More flexible for Korean usage\n enableFormatting: true,\n enableConditionals: true,\n enableLoops: true,\n maxRecursionDepth: 5\n});\n\n/**\n * Utility functions\n */\nexport const VariableUtils = {\n /**\n * Extract all variables from content\n */\n extractVariables: (content: string): string[] => {\n return defaultVariableReplacer.extractVariables(content);\n },\n\n /**\n * Replace variables in content\n */\n replace: (content: string, variables: VariableMap): string => {\n return defaultVariableReplacer.replace(content, variables).content;\n },\n\n /**\n * Validate content has all required variables\n */\n validate: (content: string, variables: VariableMap): boolean => {\n return defaultVariableReplacer.validate(content, variables).isValid;\n },\n\n /**\n * Create personalized content for multiple recipients\n */\n personalize: (\n content: string,\n recipients: Array<{ phoneNumber: string; variables: VariableMap }>\n ): Array<{ phoneNumber: string; content: string; errors?: string[] }> => {\n return recipients.map(recipient => {\n const result = defaultVariableReplacer.replace(content, recipient.variables);\n \n return {\n phoneNumber: recipient.phoneNumber,\n content: result.content,\n errors: result.errors.length > 0 \n ? result.errors.map(e => e.message)\n : undefined\n };\n });\n }\n};"],"mappings":"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","names":["MessageStatus","MessageEventType","EventEmitter","EventEmitter","item","EventEmitter","EventEmitter","value"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@k-msg/messaging",
3
+ "version": "0.1.0",
4
+ "description": "AlimTalk messaging core for sending, queuing, and tracking messages",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsc --watch",
22
+ "test": "bun test",
23
+ "clean": "rm -rf dist"
24
+ },
25
+ "dependencies": {
26
+ "zod": "catalog:",
27
+ "@k-msg/core": "workspace:*"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "catalog:",
31
+ "@types/bun": "catalog:",
32
+ "@types/node": "catalog:",
33
+ "tsup": "^8.5.0"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md"
38
+ ],
39
+ "keywords": [
40
+ "alimtalk",
41
+ "messaging",
42
+ "queue",
43
+ "delivery",
44
+ "kakao"
45
+ ],
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/k-otp/k-message.git"
49
+ },
50
+ "homepage": "https://github.com/k-otp/k-message",
51
+ "bugs": {
52
+ "url": "https://github.com/k-otp/k-message/issues"
53
+ },
54
+ "author": "imjlk",
55
+ "license": "MIT"
56
+ }