@bulkimport/core 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/index.ts","../src/domain/model/ImportStatus.ts","../src/domain/model/Batch.ts","../src/domain/model/Record.ts","../src/domain/model/ValidationResult.ts","../src/domain/services/SchemaValidator.ts","../src/application/EventBus.ts","../src/infrastructure/state/InMemoryStateStore.ts","../src/BulkImport.ts","../src/domain/model/BatchStatus.ts","../src/infrastructure/parsers/CsvParser.ts","../src/infrastructure/sources/BufferSource.ts"],"sourcesContent":["// Main entry point\nexport { BulkImport } from './BulkImport.js';\nexport type { BulkImportConfig } from './BulkImport.js';\n\n// Domain model\nexport type { SchemaDefinition } from './domain/model/Schema.js';\nexport type { FieldDefinition, FieldType, ValidationFieldResult } from './domain/model/FieldDefinition.js';\nexport type { ImportJobState, ImportJobConfig, ImportProgress, ImportSummary, PreviewResult } from './domain/model/ImportJob.js';\nexport type { ProcessedRecord, RawRecord, RecordStatus } from './domain/model/Record.js';\nexport type { Batch } from './domain/model/Batch.js';\nexport type { ValidationResult, ValidationError, ValidationErrorCode } from './domain/model/ValidationResult.js';\nexport { ImportStatus } from './domain/model/ImportStatus.js';\nexport { BatchStatus } from './domain/model/BatchStatus.js';\n\n// Ports (for custom implementations)\nexport type { SourceParser, ParserOptions } from './domain/ports/SourceParser.js';\nexport type { DataSource, SourceMetadata } from './domain/ports/DataSource.js';\nexport type { StateStore } from './domain/ports/StateStore.js';\nexport type { RecordProcessorFn, ProcessingContext } from './domain/ports/RecordProcessor.js';\n\n// Domain events\nexport type {\n DomainEvent,\n EventType,\n EventPayload,\n ImportStartedEvent,\n ImportCompletedEvent,\n ImportPausedEvent,\n ImportAbortedEvent,\n ImportFailedEvent,\n ImportProgressEvent,\n BatchStartedEvent,\n BatchCompletedEvent,\n BatchFailedEvent,\n RecordProcessedEvent,\n RecordFailedEvent,\n} from './domain/events/DomainEvents.js';\n\n// Infrastructure adapters (built-in)\nexport { CsvParser } from './infrastructure/parsers/CsvParser.js';\nexport { BufferSource } from './infrastructure/sources/BufferSource.js';\nexport { InMemoryStateStore } from './infrastructure/state/InMemoryStateStore.js';\n","export const ImportStatus = {\n CREATED: 'CREATED',\n PREVIEWING: 'PREVIEWING',\n PREVIEWED: 'PREVIEWED',\n PROCESSING: 'PROCESSING',\n PAUSED: 'PAUSED',\n COMPLETED: 'COMPLETED',\n ABORTED: 'ABORTED',\n FAILED: 'FAILED',\n} as const;\n\nexport type ImportStatus = (typeof ImportStatus)[keyof typeof ImportStatus];\n\nconst VALID_TRANSITIONS: Record<ImportStatus, readonly ImportStatus[]> = {\n [ImportStatus.CREATED]: [ImportStatus.PREVIEWING, ImportStatus.PROCESSING],\n [ImportStatus.PREVIEWING]: [ImportStatus.PREVIEWED, ImportStatus.FAILED],\n [ImportStatus.PREVIEWED]: [ImportStatus.PROCESSING],\n [ImportStatus.PROCESSING]: [ImportStatus.PAUSED, ImportStatus.COMPLETED, ImportStatus.ABORTED, ImportStatus.FAILED],\n [ImportStatus.PAUSED]: [ImportStatus.PROCESSING, ImportStatus.ABORTED],\n [ImportStatus.COMPLETED]: [],\n [ImportStatus.ABORTED]: [],\n [ImportStatus.FAILED]: [],\n};\n\nexport function canTransition(from: ImportStatus, to: ImportStatus): boolean {\n return VALID_TRANSITIONS[from].includes(to);\n}\n","import type { BatchStatus } from './BatchStatus.js';\nimport type { ProcessedRecord } from './Record.js';\n\nexport interface Batch {\n readonly id: string;\n readonly index: number;\n readonly status: BatchStatus;\n readonly records: readonly ProcessedRecord[];\n readonly processedCount: number;\n readonly failedCount: number;\n}\n\nexport function createBatch(id: string, index: number, records: readonly ProcessedRecord[]): Batch {\n return {\n id,\n index,\n status: 'PENDING',\n records,\n processedCount: 0,\n failedCount: 0,\n };\n}\n\nexport function updateBatch(batch: Batch, updates: Partial<Pick<Batch, 'status' | 'records' | 'processedCount' | 'failedCount'>>): Batch {\n return { ...batch, ...updates };\n}\n","import type { ValidationError } from './ValidationResult.js';\n\nexport type RecordStatus = 'valid' | 'invalid' | 'processed' | 'failed' | 'pending';\n\nexport interface RawRecord {\n readonly [key: string]: unknown;\n}\n\nexport interface ProcessedRecord {\n readonly index: number;\n readonly raw: RawRecord;\n readonly parsed: RawRecord;\n readonly status: RecordStatus;\n readonly errors: readonly ValidationError[];\n readonly processingError?: string;\n}\n\nexport function createPendingRecord(index: number, raw: RawRecord): ProcessedRecord {\n return {\n index,\n raw,\n parsed: raw,\n status: 'pending',\n errors: [],\n };\n}\n\nexport function markRecordValid(record: ProcessedRecord, parsed: RawRecord): ProcessedRecord {\n return { ...record, parsed, status: 'valid', errors: [] };\n}\n\nexport function markRecordInvalid(record: ProcessedRecord, errors: readonly ValidationError[]): ProcessedRecord {\n return { ...record, status: 'invalid', errors };\n}\n\nexport function markRecordProcessed(record: ProcessedRecord): ProcessedRecord {\n return { ...record, status: 'processed' };\n}\n\nexport function markRecordFailed(record: ProcessedRecord, error: string): ProcessedRecord {\n return { ...record, status: 'failed', processingError: error };\n}\n","export type ValidationErrorCode =\n | 'REQUIRED'\n | 'TYPE_MISMATCH'\n | 'PATTERN_MISMATCH'\n | 'CUSTOM_VALIDATION'\n | 'UNKNOWN_FIELD';\n\nexport interface ValidationError {\n readonly field: string;\n readonly message: string;\n readonly code: ValidationErrorCode;\n readonly value?: unknown;\n}\n\nexport interface ValidationResult {\n readonly isValid: boolean;\n readonly errors: readonly ValidationError[];\n}\n\nexport function validResult(): ValidationResult {\n return { isValid: true, errors: [] };\n}\n\nexport function invalidResult(errors: readonly ValidationError[]): ValidationResult {\n return { isValid: false, errors };\n}\n","import type { SchemaDefinition } from '../model/Schema.js';\nimport type { RawRecord } from '../model/Record.js';\nimport type { ValidationResult, ValidationError } from '../model/ValidationResult.js';\nimport type { FieldDefinition } from '../model/FieldDefinition.js';\nimport { validResult, invalidResult } from '../model/ValidationResult.js';\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nexport class SchemaValidator {\n constructor(private readonly schema: SchemaDefinition) {}\n\n validate(record: RawRecord): ValidationResult {\n const errors: ValidationError[] = [];\n\n for (const field of this.schema.fields) {\n const value = record[field.name];\n const fieldErrors = this.validateField(field, value);\n errors.push(...fieldErrors);\n }\n\n if (this.schema.strict) {\n const definedFields = new Set(this.schema.fields.map((f) => f.name));\n for (const key of Object.keys(record)) {\n if (!definedFields.has(key)) {\n errors.push({\n field: key,\n message: `Unknown field '${key}' is not allowed in strict mode`,\n code: 'UNKNOWN_FIELD',\n value: record[key],\n });\n }\n }\n }\n\n return errors.length === 0 ? validResult() : invalidResult(errors);\n }\n\n applyTransforms(record: RawRecord): RawRecord {\n const transformed: Record<string, unknown> = { ...record };\n\n for (const field of this.schema.fields) {\n if (field.transform && transformed[field.name] !== undefined) {\n transformed[field.name] = field.transform(transformed[field.name]);\n }\n if (transformed[field.name] === undefined && field.defaultValue !== undefined) {\n transformed[field.name] = field.defaultValue;\n }\n }\n\n return transformed as RawRecord;\n }\n\n private validateField(field: FieldDefinition, value: unknown): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (this.isEmpty(value)) {\n if (field.required) {\n errors.push({\n field: field.name,\n message: `Field '${field.name}' is required`,\n code: 'REQUIRED',\n value,\n });\n }\n return errors;\n }\n\n if (field.type !== 'custom') {\n const typeError = this.validateType(field, value);\n if (typeError) {\n errors.push(typeError);\n return errors;\n }\n }\n\n if (field.pattern) {\n const stringValue = String(value);\n if (!field.pattern.test(stringValue)) {\n errors.push({\n field: field.name,\n message: `Field '${field.name}' does not match pattern ${String(field.pattern)}`,\n code: 'PATTERN_MISMATCH',\n value,\n });\n }\n }\n\n if (field.customValidator) {\n const result = field.customValidator(value);\n if (!result.valid) {\n errors.push({\n field: field.name,\n message: result.message ?? `Custom validation failed for field '${field.name}'`,\n code: 'CUSTOM_VALIDATION',\n value,\n });\n }\n }\n\n return errors;\n }\n\n private validateType(field: FieldDefinition, value: unknown): ValidationError | null {\n const stringValue = String(value);\n\n switch (field.type) {\n case 'number': {\n const num = Number(stringValue);\n if (isNaN(num)) {\n return {\n field: field.name,\n message: `Field '${field.name}' must be a number`,\n code: 'TYPE_MISMATCH',\n value,\n };\n }\n return null;\n }\n case 'boolean': {\n const lower = stringValue.toLowerCase();\n if (!['true', 'false', '1', '0', 'yes', 'no'].includes(lower)) {\n return {\n field: field.name,\n message: `Field '${field.name}' must be a boolean`,\n code: 'TYPE_MISMATCH',\n value,\n };\n }\n return null;\n }\n case 'date': {\n const date = new Date(stringValue);\n if (isNaN(date.getTime())) {\n return {\n field: field.name,\n message: `Field '${field.name}' must be a valid date`,\n code: 'TYPE_MISMATCH',\n value,\n };\n }\n return null;\n }\n case 'email': {\n if (!EMAIL_PATTERN.test(stringValue)) {\n return {\n field: field.name,\n message: `Field '${field.name}' must be a valid email`,\n code: 'TYPE_MISMATCH',\n value,\n };\n }\n return null;\n }\n case 'string':\n return null;\n default:\n return null;\n }\n }\n\n private isEmpty(value: unknown): boolean {\n return value === undefined || value === null || value === '';\n }\n}\n","import type { EventType, EventPayload, DomainEvent } from '../domain/events/DomainEvents.js';\n\ntype EventHandler<T extends EventType> = (event: EventPayload<T>) => void;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyHandler = (event: any) => void;\n\nexport class EventBus {\n private readonly handlers = new Map<string, Set<AnyHandler>>();\n\n on<T extends EventType>(type: T, handler: EventHandler<T>): void {\n const existing = this.handlers.get(type) ?? new Set<AnyHandler>();\n existing.add(handler as AnyHandler);\n this.handlers.set(type, existing);\n }\n\n off<T extends EventType>(type: T, handler: EventHandler<T>): void {\n const existing = this.handlers.get(type);\n if (existing) {\n existing.delete(handler as AnyHandler);\n }\n }\n\n emit(event: DomainEvent): void {\n const handlers = this.handlers.get(event.type);\n if (handlers) {\n for (const handler of handlers) {\n handler(event);\n }\n }\n }\n}\n","import type { StateStore, BatchState } from '../../domain/ports/StateStore.js';\nimport type { ImportJobState, ImportProgress } from '../../domain/model/ImportJob.js';\nimport type { ProcessedRecord } from '../../domain/model/Record.js';\n\nexport class InMemoryStateStore implements StateStore {\n private jobs = new Map<string, ImportJobState>();\n private records = new Map<string, ProcessedRecord[]>();\n\n saveJobState(job: ImportJobState): Promise<void> {\n this.jobs.set(job.id, job);\n return Promise.resolve();\n }\n\n getJobState(jobId: string): Promise<ImportJobState | null> {\n return Promise.resolve(this.jobs.get(jobId) ?? null);\n }\n\n updateBatchState(jobId: string, batchId: string, state: BatchState): Promise<void> {\n const job = this.jobs.get(jobId);\n if (!job) return Promise.resolve();\n\n const batches = job.batches.map((b) =>\n b.id === batchId\n ? { ...b, status: state.status, processedCount: state.processedCount, failedCount: state.failedCount }\n : b,\n );\n\n this.jobs.set(jobId, { ...job, batches });\n return Promise.resolve();\n }\n\n saveProcessedRecord(jobId: string, _batchId: string, record: ProcessedRecord): Promise<void> {\n const key = jobId;\n const existing = this.records.get(key) ?? [];\n const index = existing.findIndex((r) => r.index === record.index);\n if (index >= 0) {\n existing[index] = record;\n } else {\n existing.push(record);\n }\n this.records.set(key, existing);\n return Promise.resolve();\n }\n\n getFailedRecords(jobId: string): Promise<readonly ProcessedRecord[]> {\n const all = this.records.get(jobId) ?? [];\n return Promise.resolve(all.filter((r) => r.status === 'failed' || r.status === 'invalid'));\n }\n\n getPendingRecords(jobId: string): Promise<readonly ProcessedRecord[]> {\n const all = this.records.get(jobId) ?? [];\n return Promise.resolve(all.filter((r) => r.status === 'pending' || r.status === 'valid'));\n }\n\n getProcessedRecords(jobId: string): Promise<readonly ProcessedRecord[]> {\n const all = this.records.get(jobId) ?? [];\n return Promise.resolve(all.filter((r) => r.status === 'processed'));\n }\n\n getProgress(jobId: string): Promise<ImportProgress> {\n const job = this.jobs.get(jobId);\n const all = this.records.get(jobId) ?? [];\n const processed = all.filter((r) => r.status === 'processed').length;\n const failed = all.filter((r) => r.status === 'failed' || r.status === 'invalid').length;\n const total = job?.totalRecords ?? all.length;\n const pending = total - processed - failed;\n const elapsed = job?.startedAt ? Date.now() - job.startedAt : 0;\n\n const currentBatch = job?.batches.filter((b) => b.status === 'COMPLETED').length ?? 0;\n const totalBatches = job?.batches.length ?? 0;\n\n return Promise.resolve({\n totalRecords: total,\n processedRecords: processed,\n failedRecords: failed,\n pendingRecords: pending,\n percentage: total > 0 ? Math.round((processed / total) * 100) : 0,\n currentBatch,\n totalBatches,\n elapsedMs: elapsed,\n });\n }\n}\n","import type { SchemaDefinition } from './domain/model/Schema.js';\nimport type { ImportJobState, ImportProgress, ImportSummary, PreviewResult } from './domain/model/ImportJob.js';\nimport type { ProcessedRecord } from './domain/model/Record.js';\nimport type { Batch } from './domain/model/Batch.js';\nimport type { ImportStatus } from './domain/model/ImportStatus.js';\nimport type { SourceParser } from './domain/ports/SourceParser.js';\nimport type { DataSource } from './domain/ports/DataSource.js';\nimport type { StateStore } from './domain/ports/StateStore.js';\nimport type { RecordProcessorFn, ProcessingContext } from './domain/ports/RecordProcessor.js';\nimport type { EventType, EventPayload } from './domain/events/DomainEvents.js';\nimport { canTransition } from './domain/model/ImportStatus.js';\nimport { createBatch } from './domain/model/Batch.js';\nimport { createPendingRecord, markRecordValid, markRecordInvalid, markRecordProcessed, markRecordFailed } from './domain/model/Record.js';\nimport { SchemaValidator } from './domain/services/SchemaValidator.js';\nimport { EventBus } from './application/EventBus.js';\nimport { InMemoryStateStore } from './infrastructure/state/InMemoryStateStore.js';\n\nexport interface BulkImportConfig {\n readonly schema: SchemaDefinition;\n readonly batchSize?: number;\n readonly maxConcurrentBatches?: number;\n readonly continueOnError?: boolean;\n readonly stateStore?: StateStore;\n}\n\nexport class BulkImport {\n private readonly config: Required<Pick<BulkImportConfig, 'batchSize' | 'continueOnError'>> & BulkImportConfig;\n private readonly validator: SchemaValidator;\n private readonly eventBus: EventBus;\n private readonly stateStore: StateStore;\n\n private source: DataSource | null = null;\n private parser: SourceParser | null = null;\n\n private jobId: string;\n private status: ImportStatus = 'CREATED';\n private batches: Batch[] = [];\n private allRecords: ProcessedRecord[] = [];\n private totalRecords = 0;\n private startedAt?: number;\n\n private abortController: AbortController | null = null;\n private pausePromise: { resolve: () => void; promise: Promise<void> } | null = null;\n\n constructor(config: BulkImportConfig) {\n this.config = {\n ...config,\n batchSize: config.batchSize ?? 100,\n continueOnError: config.continueOnError ?? false,\n };\n this.validator = new SchemaValidator(config.schema);\n this.eventBus = new EventBus();\n this.stateStore = config.stateStore ?? new InMemoryStateStore();\n this.jobId = crypto.randomUUID();\n }\n\n from(source: DataSource, parser: SourceParser): this {\n this.source = source;\n this.parser = parser;\n return this;\n }\n\n on<T extends EventType>(type: T, handler: (event: EventPayload<T>) => void): this {\n this.eventBus.on(type, handler);\n return this;\n }\n\n async preview(maxRecords = 10): Promise<PreviewResult> {\n this.assertSourceConfigured();\n this.transitionTo('PREVIEWING');\n\n const records = await this.parseRecords(maxRecords);\n const validRecords: ProcessedRecord[] = [];\n const invalidRecords: ProcessedRecord[] = [];\n const columns = new Set<string>();\n\n for (const record of records) {\n for (const key of Object.keys(record.raw)) {\n columns.add(key);\n }\n const transformed = this.validator.applyTransforms(record.raw);\n const result = this.validator.validate(transformed);\n\n if (result.isValid) {\n validRecords.push(markRecordValid(record, transformed));\n } else {\n invalidRecords.push(markRecordInvalid(record, result.errors));\n }\n }\n\n this.transitionTo('PREVIEWED');\n\n return {\n validRecords,\n invalidRecords,\n totalSampled: records.length,\n columns: [...columns],\n };\n }\n\n async start(processor: RecordProcessorFn): Promise<void> {\n this.assertSourceConfigured();\n\n this.assertCanStart();\n\n this.transitionTo('PROCESSING');\n this.abortController = new AbortController();\n this.startedAt = Date.now();\n\n const allRawRecords = await this.parseRecords();\n this.totalRecords = allRawRecords.length;\n\n this.batches = this.splitIntoBatches(allRawRecords);\n\n await this.saveState();\n\n this.eventBus.emit({\n type: 'import:started',\n jobId: this.jobId,\n totalRecords: this.totalRecords,\n totalBatches: this.batches.length,\n timestamp: Date.now(),\n });\n\n try {\n for (let i = 0; i < this.batches.length; i++) {\n if (this.abortController.signal.aborted) break;\n await this.checkPause();\n\n const batch = this.batches[i];\n if (!batch) break;\n await this.processBatch(batch, processor);\n }\n\n if (!this.abortController.signal.aborted && this.status !== 'ABORTED') {\n this.transitionTo('COMPLETED');\n const summary = this.buildSummary();\n\n this.eventBus.emit({\n type: 'import:completed',\n jobId: this.jobId,\n summary,\n timestamp: Date.now(),\n });\n }\n } catch (error) {\n if (this.status !== 'ABORTED') {\n this.transitionTo('FAILED');\n this.eventBus.emit({\n type: 'import:failed',\n jobId: this.jobId,\n error: error instanceof Error ? error.message : String(error),\n timestamp: Date.now(),\n });\n }\n }\n\n await this.saveState();\n }\n\n async pause(): Promise<void> {\n if (this.status !== 'PROCESSING') {\n throw new Error(`Cannot pause import from status '${this.status}'`);\n }\n\n this.transitionTo('PAUSED');\n this.pausePromise = this.createPausePromise();\n\n const progress = this.buildProgress();\n this.eventBus.emit({\n type: 'import:paused',\n jobId: this.jobId,\n progress,\n timestamp: Date.now(),\n });\n\n await this.saveState();\n }\n\n resume(): void {\n if (this.status === 'ABORTED') {\n throw new Error('Cannot resume an aborted import');\n }\n if (this.status !== 'PAUSED') {\n throw new Error(`Cannot resume import from status '${this.status}'`);\n }\n\n this.transitionTo('PROCESSING');\n if (this.pausePromise) {\n this.pausePromise.resolve();\n this.pausePromise = null;\n }\n }\n\n async abort(): Promise<void> {\n if (this.status !== 'PROCESSING' && this.status !== 'PAUSED') {\n throw new Error(`Cannot abort import from status '${this.status}'`);\n }\n\n this.transitionTo('ABORTED');\n this.abortController?.abort();\n\n if (this.pausePromise) {\n this.pausePromise.resolve();\n this.pausePromise = null;\n }\n\n const progress = this.buildProgress();\n this.eventBus.emit({\n type: 'import:aborted',\n jobId: this.jobId,\n progress,\n timestamp: Date.now(),\n });\n\n await this.saveState();\n }\n\n getStatus(): { state: ImportStatus; progress: ImportProgress; batches: readonly Batch[] } {\n return {\n state: this.status,\n progress: this.buildProgress(),\n batches: this.batches,\n };\n }\n\n getFailedRecords(): readonly ProcessedRecord[] {\n return this.allRecords.filter((r) => r.status === 'failed' || r.status === 'invalid');\n }\n\n getPendingRecords(): readonly ProcessedRecord[] {\n return this.allRecords.filter((r) => r.status === 'pending' || r.status === 'valid');\n }\n\n getJobId(): string {\n return this.jobId;\n }\n\n // --- Private methods ---\n\n private async processBatch(batch: Batch, processor: RecordProcessorFn): Promise<void> {\n const batchIndex = this.batches.indexOf(batch);\n\n this.updateBatchStatus(batch.id, 'PROCESSING');\n\n this.eventBus.emit({\n type: 'batch:started',\n jobId: this.jobId,\n batchId: batch.id,\n batchIndex,\n recordCount: batch.records.length,\n timestamp: Date.now(),\n });\n\n let processedCount = 0;\n let failedCount = 0;\n\n for (const record of batch.records) {\n if (this.abortController?.signal.aborted) break;\n await this.checkPause();\n\n const transformed = this.validator.applyTransforms(record.raw);\n const validation = this.validator.validate(transformed);\n\n if (!validation.isValid) {\n const invalidRecord = markRecordInvalid(record, validation.errors);\n this.updateRecord(record.index, invalidRecord);\n failedCount++;\n\n this.eventBus.emit({\n type: 'record:failed',\n jobId: this.jobId,\n batchId: batch.id,\n recordIndex: record.index,\n error: validation.errors.map((e) => e.message).join('; '),\n record: invalidRecord,\n timestamp: Date.now(),\n });\n\n if (!this.config.continueOnError) {\n throw new Error(`Validation failed for record ${String(record.index)}`);\n }\n continue;\n }\n\n const validRecord = markRecordValid(record, transformed);\n\n try {\n const context: ProcessingContext = {\n jobId: this.jobId,\n batchId: batch.id,\n batchIndex,\n recordIndex: record.index,\n totalRecords: this.totalRecords,\n signal: this.abortController?.signal ?? new AbortController().signal,\n };\n\n await processor(validRecord.parsed, context);\n\n const processed = markRecordProcessed(validRecord);\n this.updateRecord(record.index, processed);\n processedCount++;\n\n this.eventBus.emit({\n type: 'record:processed',\n jobId: this.jobId,\n batchId: batch.id,\n recordIndex: record.index,\n timestamp: Date.now(),\n });\n } catch (error) {\n const failedRecord = markRecordFailed(validRecord, error instanceof Error ? error.message : String(error));\n this.updateRecord(record.index, failedRecord);\n failedCount++;\n\n this.eventBus.emit({\n type: 'record:failed',\n jobId: this.jobId,\n batchId: batch.id,\n recordIndex: record.index,\n error: error instanceof Error ? error.message : String(error),\n record: failedRecord,\n timestamp: Date.now(),\n });\n\n if (!this.config.continueOnError) {\n throw error;\n }\n }\n }\n\n this.updateBatchStatus(batch.id, 'COMPLETED', processedCount, failedCount);\n\n this.eventBus.emit({\n type: 'batch:completed',\n jobId: this.jobId,\n batchId: batch.id,\n batchIndex,\n processedCount,\n failedCount,\n totalCount: batch.records.length,\n timestamp: Date.now(),\n });\n\n this.emitProgress();\n }\n\n private async parseRecords(maxRecords?: number): Promise<ProcessedRecord[]> {\n const source = this.source;\n const parser = this.parser;\n if (!source || !parser) {\n throw new Error('Source and parser must be configured. Call .from(source, parser) first.');\n }\n\n const records: ProcessedRecord[] = [];\n let index = 0;\n\n for await (const chunk of source.read()) {\n for await (const raw of parser.parse(chunk)) {\n if (maxRecords !== undefined && records.length >= maxRecords) {\n return records;\n }\n records.push(createPendingRecord(index, raw));\n index++;\n }\n }\n\n return records;\n }\n\n private splitIntoBatches(records: ProcessedRecord[]): Batch[] {\n const batches: Batch[] = [];\n const { batchSize } = this.config;\n\n for (let i = 0; i < records.length; i += batchSize) {\n const batchRecords = records.slice(i, i + batchSize);\n const batchId = crypto.randomUUID();\n batches.push(createBatch(batchId, batches.length, batchRecords));\n }\n\n this.allRecords = [...records];\n return batches;\n }\n\n private updateRecord(index: number, record: ProcessedRecord): void {\n const pos = this.allRecords.findIndex((r) => r.index === index);\n if (pos >= 0) {\n this.allRecords[pos] = record;\n }\n }\n\n private updateBatchStatus(batchId: string, status: Batch['status'], processedCount?: number, failedCount?: number): void {\n this.batches = this.batches.map((b) =>\n b.id === batchId\n ? {\n ...b,\n status,\n processedCount: processedCount ?? b.processedCount,\n failedCount: failedCount ?? b.failedCount,\n }\n : b,\n );\n }\n\n private transitionTo(newStatus: ImportStatus): void {\n if (!canTransition(this.status, newStatus)) {\n throw new Error(`Invalid state transition: ${this.status} → ${newStatus}`);\n }\n this.status = newStatus;\n }\n\n private buildProgress(): ImportProgress {\n const processed = this.allRecords.filter((r) => r.status === 'processed').length;\n const failed = this.allRecords.filter((r) => r.status === 'failed' || r.status === 'invalid').length;\n const pending = this.totalRecords - processed - failed;\n const completedBatches = this.batches.filter((b) => b.status === 'COMPLETED').length;\n const elapsed = this.startedAt ? Date.now() - this.startedAt : 0;\n\n return {\n totalRecords: this.totalRecords,\n processedRecords: processed,\n failedRecords: failed,\n pendingRecords: pending,\n percentage: this.totalRecords > 0 ? Math.round((processed / this.totalRecords) * 100) : 0,\n currentBatch: completedBatches,\n totalBatches: this.batches.length,\n elapsedMs: elapsed,\n };\n }\n\n private buildSummary(): ImportSummary {\n const processed = this.allRecords.filter((r) => r.status === 'processed').length;\n const failed = this.allRecords.filter((r) => r.status === 'failed' || r.status === 'invalid').length;\n const skipped = this.totalRecords - processed - failed;\n const elapsed = this.startedAt ? Date.now() - this.startedAt : 0;\n\n return { total: this.totalRecords, processed, failed, skipped, elapsedMs: elapsed };\n }\n\n private emitProgress(): void {\n this.eventBus.emit({\n type: 'import:progress',\n jobId: this.jobId,\n progress: this.buildProgress(),\n timestamp: Date.now(),\n });\n }\n\n private async saveState(): Promise<void> {\n const state: ImportJobState = {\n id: this.jobId,\n config: {\n schema: this.config.schema,\n batchSize: this.config.batchSize,\n continueOnError: this.config.continueOnError,\n },\n status: this.status,\n batches: this.batches,\n totalRecords: this.totalRecords,\n startedAt: this.startedAt,\n };\n await this.stateStore.saveJobState(state);\n }\n\n private async checkPause(): Promise<void> {\n if (this.pausePromise) {\n await this.pausePromise.promise;\n }\n }\n\n private createPausePromise(): { resolve: () => void; promise: Promise<void> } {\n let resolveRef!: () => void;\n const promise = new Promise<void>((resolve) => {\n resolveRef = resolve;\n });\n return { resolve: resolveRef, promise };\n }\n\n private assertSourceConfigured(): void {\n if (!this.source || !this.parser) {\n throw new Error('Source and parser must be configured. Call .from(source, parser) first.');\n }\n }\n\n private assertCanStart(): void {\n if (this.status !== 'PREVIEWED' && this.status !== 'CREATED') {\n throw new Error(`Cannot start import from status '${this.status}'`);\n }\n }\n}\n","export const BatchStatus = {\n PENDING: 'PENDING',\n PROCESSING: 'PROCESSING',\n PAUSED: 'PAUSED',\n COMPLETED: 'COMPLETED',\n FAILED: 'FAILED',\n} as const;\n\nexport type BatchStatus = (typeof BatchStatus)[keyof typeof BatchStatus];\n","import Papa from 'papaparse';\nimport type { SourceParser, ParserOptions } from '../../domain/ports/SourceParser.js';\nimport type { RawRecord } from '../../domain/model/Record.js';\n\nexport class CsvParser implements SourceParser {\n private readonly options: ParserOptions;\n\n constructor(options?: Partial<ParserOptions>) {\n this.options = {\n delimiter: options?.delimiter,\n encoding: options?.encoding ?? 'utf-8',\n hasHeader: options?.hasHeader ?? true,\n };\n }\n\n *parse(data: string | Buffer): Iterable<RawRecord> {\n const content = typeof data === 'string' ? data : data.toString('utf-8');\n\n const result = Papa.parse(content, {\n header: this.options.hasHeader,\n delimiter: this.options.delimiter || undefined,\n skipEmptyLines: true,\n dynamicTyping: false,\n });\n\n for (const row of result.data as Record<string, unknown>[]) {\n if (this.isEmptyRow(row)) continue;\n yield row as RawRecord;\n }\n }\n\n detect(sample: string | Buffer): ParserOptions {\n const content = typeof sample === 'string' ? sample : sample.toString('utf-8');\n const firstLines = content.split('\\n').slice(0, 5).join('\\n');\n\n const delimiters = [',', ';', '\\t', '|'];\n let bestDelimiter = ',';\n let maxColumns = 0;\n\n for (const delimiter of delimiters) {\n const result = Papa.parse(firstLines, { delimiter, header: false });\n const firstRow = result.data[0] as string[] | undefined;\n if (firstRow && firstRow.length > maxColumns) {\n maxColumns = firstRow.length;\n bestDelimiter = delimiter;\n }\n }\n\n return {\n delimiter: bestDelimiter,\n encoding: 'utf-8',\n hasHeader: true,\n };\n }\n\n private isEmptyRow(row: Record<string, unknown>): boolean {\n return Object.values(row).every((v) => v === null || v === undefined || v === '');\n }\n}\n","import type { DataSource, SourceMetadata } from '../../domain/ports/DataSource.js';\n\nexport class BufferSource implements DataSource {\n private readonly content: string;\n private readonly meta: SourceMetadata;\n\n constructor(data: string | Buffer, metadata?: Partial<SourceMetadata>) {\n this.content = typeof data === 'string' ? data : data.toString('utf-8');\n this.meta = {\n fileName: metadata?.fileName ?? 'buffer-input',\n fileSize: this.content.length,\n mimeType: metadata?.mimeType ?? 'text/plain',\n };\n }\n\n async *read(): AsyncIterable<string> {\n yield await Promise.resolve(this.content);\n }\n\n sample(maxBytes?: number): Promise<string> {\n if (maxBytes && maxBytes < this.content.length) {\n return Promise.resolve(this.content.slice(0, maxBytes));\n }\n return Promise.resolve(this.content);\n }\n\n metadata(): SourceMetadata {\n return this.meta;\n }\n}\n"],"mappings":"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","names":["Papa"]}
@@ -0,0 +1,335 @@
1
+ type FieldType = 'string' | 'number' | 'boolean' | 'date' | 'email' | 'custom';
2
+ interface ValidationFieldResult {
3
+ valid: boolean;
4
+ message?: string;
5
+ }
6
+ interface FieldDefinition {
7
+ readonly name: string;
8
+ readonly type: FieldType;
9
+ readonly required: boolean;
10
+ readonly pattern?: RegExp;
11
+ readonly customValidator?: (value: unknown) => ValidationFieldResult;
12
+ readonly transform?: (value: unknown) => unknown;
13
+ readonly defaultValue?: unknown;
14
+ }
15
+
16
+ interface SchemaDefinition {
17
+ readonly fields: readonly FieldDefinition[];
18
+ readonly strict?: boolean;
19
+ readonly skipEmptyRows?: boolean;
20
+ }
21
+
22
+ declare const ImportStatus: {
23
+ readonly CREATED: "CREATED";
24
+ readonly PREVIEWING: "PREVIEWING";
25
+ readonly PREVIEWED: "PREVIEWED";
26
+ readonly PROCESSING: "PROCESSING";
27
+ readonly PAUSED: "PAUSED";
28
+ readonly COMPLETED: "COMPLETED";
29
+ readonly ABORTED: "ABORTED";
30
+ readonly FAILED: "FAILED";
31
+ };
32
+ type ImportStatus = (typeof ImportStatus)[keyof typeof ImportStatus];
33
+
34
+ declare const BatchStatus: {
35
+ readonly PENDING: "PENDING";
36
+ readonly PROCESSING: "PROCESSING";
37
+ readonly PAUSED: "PAUSED";
38
+ readonly COMPLETED: "COMPLETED";
39
+ readonly FAILED: "FAILED";
40
+ };
41
+ type BatchStatus = (typeof BatchStatus)[keyof typeof BatchStatus];
42
+
43
+ type ValidationErrorCode = 'REQUIRED' | 'TYPE_MISMATCH' | 'PATTERN_MISMATCH' | 'CUSTOM_VALIDATION' | 'UNKNOWN_FIELD';
44
+ interface ValidationError {
45
+ readonly field: string;
46
+ readonly message: string;
47
+ readonly code: ValidationErrorCode;
48
+ readonly value?: unknown;
49
+ }
50
+ interface ValidationResult {
51
+ readonly isValid: boolean;
52
+ readonly errors: readonly ValidationError[];
53
+ }
54
+
55
+ type RecordStatus = 'valid' | 'invalid' | 'processed' | 'failed' | 'pending';
56
+ interface RawRecord {
57
+ readonly [key: string]: unknown;
58
+ }
59
+ interface ProcessedRecord {
60
+ readonly index: number;
61
+ readonly raw: RawRecord;
62
+ readonly parsed: RawRecord;
63
+ readonly status: RecordStatus;
64
+ readonly errors: readonly ValidationError[];
65
+ readonly processingError?: string;
66
+ }
67
+
68
+ interface Batch {
69
+ readonly id: string;
70
+ readonly index: number;
71
+ readonly status: BatchStatus;
72
+ readonly records: readonly ProcessedRecord[];
73
+ readonly processedCount: number;
74
+ readonly failedCount: number;
75
+ }
76
+
77
+ interface ImportJobConfig {
78
+ readonly id?: string;
79
+ readonly schema: SchemaDefinition;
80
+ readonly batchSize: number;
81
+ readonly maxConcurrentBatches?: number;
82
+ readonly continueOnError?: boolean;
83
+ }
84
+ interface ImportJobState {
85
+ readonly id: string;
86
+ readonly config: ImportJobConfig;
87
+ readonly status: ImportStatus;
88
+ readonly batches: readonly Batch[];
89
+ readonly totalRecords: number;
90
+ readonly startedAt?: number;
91
+ readonly completedAt?: number;
92
+ }
93
+ interface ImportProgress {
94
+ readonly totalRecords: number;
95
+ readonly processedRecords: number;
96
+ readonly failedRecords: number;
97
+ readonly pendingRecords: number;
98
+ readonly percentage: number;
99
+ readonly currentBatch: number;
100
+ readonly totalBatches: number;
101
+ readonly elapsedMs: number;
102
+ readonly estimatedRemainingMs?: number;
103
+ }
104
+ interface ImportSummary {
105
+ readonly total: number;
106
+ readonly processed: number;
107
+ readonly failed: number;
108
+ readonly skipped: number;
109
+ readonly elapsedMs: number;
110
+ }
111
+ interface PreviewResult {
112
+ readonly validRecords: readonly ProcessedRecord[];
113
+ readonly invalidRecords: readonly ProcessedRecord[];
114
+ readonly totalSampled: number;
115
+ readonly columns: readonly string[];
116
+ }
117
+
118
+ interface ParserOptions {
119
+ readonly delimiter?: string;
120
+ readonly encoding?: string;
121
+ readonly hasHeader?: boolean;
122
+ }
123
+ interface SourceParser {
124
+ parse(data: string | Buffer): AsyncIterable<RawRecord> | Iterable<RawRecord>;
125
+ detect?(sample: string | Buffer): ParserOptions;
126
+ }
127
+
128
+ interface SourceMetadata {
129
+ readonly fileName?: string;
130
+ readonly fileSize?: number;
131
+ readonly mimeType?: string;
132
+ }
133
+ interface DataSource {
134
+ read(): AsyncIterable<string | Buffer>;
135
+ sample(maxBytes?: number): Promise<string | Buffer>;
136
+ metadata(): SourceMetadata;
137
+ }
138
+
139
+ interface BatchState {
140
+ readonly batchId: string;
141
+ readonly status: BatchStatus;
142
+ readonly processedCount: number;
143
+ readonly failedCount: number;
144
+ }
145
+ interface StateStore {
146
+ saveJobState(job: ImportJobState): Promise<void>;
147
+ getJobState(jobId: string): Promise<ImportJobState | null>;
148
+ updateBatchState(jobId: string, batchId: string, state: BatchState): Promise<void>;
149
+ saveProcessedRecord(jobId: string, batchId: string, record: ProcessedRecord): Promise<void>;
150
+ getFailedRecords(jobId: string): Promise<readonly ProcessedRecord[]>;
151
+ getPendingRecords(jobId: string): Promise<readonly ProcessedRecord[]>;
152
+ getProcessedRecords(jobId: string): Promise<readonly ProcessedRecord[]>;
153
+ getProgress(jobId: string): Promise<ImportProgress>;
154
+ }
155
+
156
+ interface ProcessingContext {
157
+ readonly jobId: string;
158
+ readonly batchId: string;
159
+ readonly batchIndex: number;
160
+ readonly recordIndex: number;
161
+ readonly totalRecords: number;
162
+ readonly signal: AbortSignal;
163
+ }
164
+ type RecordProcessorFn = (record: RawRecord, context: ProcessingContext) => Promise<void>;
165
+
166
+ interface ImportStartedEvent {
167
+ readonly type: 'import:started';
168
+ readonly jobId: string;
169
+ readonly totalRecords: number;
170
+ readonly totalBatches: number;
171
+ readonly timestamp: number;
172
+ }
173
+ interface ImportCompletedEvent {
174
+ readonly type: 'import:completed';
175
+ readonly jobId: string;
176
+ readonly summary: ImportSummary;
177
+ readonly timestamp: number;
178
+ }
179
+ interface ImportPausedEvent {
180
+ readonly type: 'import:paused';
181
+ readonly jobId: string;
182
+ readonly progress: ImportProgress;
183
+ readonly timestamp: number;
184
+ }
185
+ interface ImportAbortedEvent {
186
+ readonly type: 'import:aborted';
187
+ readonly jobId: string;
188
+ readonly progress: ImportProgress;
189
+ readonly timestamp: number;
190
+ }
191
+ interface ImportFailedEvent {
192
+ readonly type: 'import:failed';
193
+ readonly jobId: string;
194
+ readonly error: string;
195
+ readonly timestamp: number;
196
+ }
197
+ interface ImportProgressEvent {
198
+ readonly type: 'import:progress';
199
+ readonly jobId: string;
200
+ readonly progress: ImportProgress;
201
+ readonly timestamp: number;
202
+ }
203
+ interface BatchStartedEvent {
204
+ readonly type: 'batch:started';
205
+ readonly jobId: string;
206
+ readonly batchId: string;
207
+ readonly batchIndex: number;
208
+ readonly recordCount: number;
209
+ readonly timestamp: number;
210
+ }
211
+ interface BatchCompletedEvent {
212
+ readonly type: 'batch:completed';
213
+ readonly jobId: string;
214
+ readonly batchId: string;
215
+ readonly batchIndex: number;
216
+ readonly processedCount: number;
217
+ readonly failedCount: number;
218
+ readonly totalCount: number;
219
+ readonly timestamp: number;
220
+ }
221
+ interface BatchFailedEvent {
222
+ readonly type: 'batch:failed';
223
+ readonly jobId: string;
224
+ readonly batchId: string;
225
+ readonly batchIndex: number;
226
+ readonly error: string;
227
+ readonly timestamp: number;
228
+ }
229
+ interface RecordProcessedEvent {
230
+ readonly type: 'record:processed';
231
+ readonly jobId: string;
232
+ readonly batchId: string;
233
+ readonly recordIndex: number;
234
+ readonly timestamp: number;
235
+ }
236
+ interface RecordFailedEvent {
237
+ readonly type: 'record:failed';
238
+ readonly jobId: string;
239
+ readonly batchId: string;
240
+ readonly recordIndex: number;
241
+ readonly error: string;
242
+ readonly record: ProcessedRecord;
243
+ readonly timestamp: number;
244
+ }
245
+ type DomainEvent = ImportStartedEvent | ImportCompletedEvent | ImportPausedEvent | ImportAbortedEvent | ImportFailedEvent | ImportProgressEvent | BatchStartedEvent | BatchCompletedEvent | BatchFailedEvent | RecordProcessedEvent | RecordFailedEvent;
246
+ type EventType = DomainEvent['type'];
247
+ type EventPayload<T extends EventType> = Extract<DomainEvent, {
248
+ type: T;
249
+ }>;
250
+
251
+ interface BulkImportConfig {
252
+ readonly schema: SchemaDefinition;
253
+ readonly batchSize?: number;
254
+ readonly maxConcurrentBatches?: number;
255
+ readonly continueOnError?: boolean;
256
+ readonly stateStore?: StateStore;
257
+ }
258
+ declare class BulkImport {
259
+ private readonly config;
260
+ private readonly validator;
261
+ private readonly eventBus;
262
+ private readonly stateStore;
263
+ private source;
264
+ private parser;
265
+ private jobId;
266
+ private status;
267
+ private batches;
268
+ private allRecords;
269
+ private totalRecords;
270
+ private startedAt?;
271
+ private abortController;
272
+ private pausePromise;
273
+ constructor(config: BulkImportConfig);
274
+ from(source: DataSource, parser: SourceParser): this;
275
+ on<T extends EventType>(type: T, handler: (event: EventPayload<T>) => void): this;
276
+ preview(maxRecords?: number): Promise<PreviewResult>;
277
+ start(processor: RecordProcessorFn): Promise<void>;
278
+ pause(): Promise<void>;
279
+ resume(): void;
280
+ abort(): Promise<void>;
281
+ getStatus(): {
282
+ state: ImportStatus;
283
+ progress: ImportProgress;
284
+ batches: readonly Batch[];
285
+ };
286
+ getFailedRecords(): readonly ProcessedRecord[];
287
+ getPendingRecords(): readonly ProcessedRecord[];
288
+ getJobId(): string;
289
+ private processBatch;
290
+ private parseRecords;
291
+ private splitIntoBatches;
292
+ private updateRecord;
293
+ private updateBatchStatus;
294
+ private transitionTo;
295
+ private buildProgress;
296
+ private buildSummary;
297
+ private emitProgress;
298
+ private saveState;
299
+ private checkPause;
300
+ private createPausePromise;
301
+ private assertSourceConfigured;
302
+ private assertCanStart;
303
+ }
304
+
305
+ declare class CsvParser implements SourceParser {
306
+ private readonly options;
307
+ constructor(options?: Partial<ParserOptions>);
308
+ parse(data: string | Buffer): Iterable<RawRecord>;
309
+ detect(sample: string | Buffer): ParserOptions;
310
+ private isEmptyRow;
311
+ }
312
+
313
+ declare class BufferSource implements DataSource {
314
+ private readonly content;
315
+ private readonly meta;
316
+ constructor(data: string | Buffer, metadata?: Partial<SourceMetadata>);
317
+ read(): AsyncIterable<string>;
318
+ sample(maxBytes?: number): Promise<string>;
319
+ metadata(): SourceMetadata;
320
+ }
321
+
322
+ declare class InMemoryStateStore implements StateStore {
323
+ private jobs;
324
+ private records;
325
+ saveJobState(job: ImportJobState): Promise<void>;
326
+ getJobState(jobId: string): Promise<ImportJobState | null>;
327
+ updateBatchState(jobId: string, batchId: string, state: BatchState): Promise<void>;
328
+ saveProcessedRecord(jobId: string, _batchId: string, record: ProcessedRecord): Promise<void>;
329
+ getFailedRecords(jobId: string): Promise<readonly ProcessedRecord[]>;
330
+ getPendingRecords(jobId: string): Promise<readonly ProcessedRecord[]>;
331
+ getProcessedRecords(jobId: string): Promise<readonly ProcessedRecord[]>;
332
+ getProgress(jobId: string): Promise<ImportProgress>;
333
+ }
334
+
335
+ export { type Batch, type BatchCompletedEvent, type BatchFailedEvent, type BatchStartedEvent, BatchStatus, BufferSource, BulkImport, type BulkImportConfig, CsvParser, type DataSource, type DomainEvent, type EventPayload, type EventType, type FieldDefinition, type FieldType, type ImportAbortedEvent, type ImportCompletedEvent, type ImportFailedEvent, type ImportJobConfig, type ImportJobState, type ImportPausedEvent, type ImportProgress, type ImportProgressEvent, type ImportStartedEvent, ImportStatus, type ImportSummary, InMemoryStateStore, type ParserOptions, type PreviewResult, type ProcessedRecord, type ProcessingContext, type RawRecord, type RecordFailedEvent, type RecordProcessedEvent, type RecordProcessorFn, type RecordStatus, type SchemaDefinition, type SourceMetadata, type SourceParser, type StateStore, type ValidationError, type ValidationErrorCode, type ValidationFieldResult, type ValidationResult };