UNPKG

smart-dropzone-react

Version:

🚀 A production-ready React dropzone component with smart defaults, drag & drop reordering, chunked uploads, resume functionality, and comprehensive provider support (Cloudinary, AWS S3, Supabase)

1 lines • 22.5 kB
{"version":3,"sources":["../src/core/upload-resume.ts"],"names":["_UploadResumeManager","options","__publicField","FILE_SIZE","UPLOAD","TIMING","file","provider","fileId","chunks","checksum","resumeState","result","error","chunk","removed","totalChunks","i","start","end","data","buffer","hashBuffer","b","uploadedChunks","index","remainingChunks","uploadPromises","activeChunks","uploadPromise","success","attempts","maxAttempts","_chunk","_resumeState","_provider","progress","event","ms","resolve","UploadResumeManager"],"mappings":"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","file":"chunk-YGRSDHFI.cjs","sourcesContent":["import { FILE_SIZE, UPLOAD, TIMING } from \"./config\";\r\n\r\nexport interface UploadChunk {\r\n id: string;\r\n start: number;\r\n end: number;\r\n data: Blob;\r\n uploaded: boolean;\r\n retryCount: number;\r\n maxRetries: number;\r\n}\r\n\r\nexport interface ResumeOptions {\r\n chunkSize?: number;\r\n maxConcurrentChunks?: number;\r\n retryAttempts?: number;\r\n retryDelay?: number;\r\n enableResume?: boolean;\r\n validateChunks?: boolean;\r\n checksumAlgorithm?: \"md5\" | \"sha1\" | \"sha256\" | \"crc32\";\r\n}\r\n\r\nexport interface ResumeState {\r\n fileId: string;\r\n fileName: string;\r\n totalSize: number;\r\n uploadedSize: number;\r\n chunks: UploadChunk[];\r\n status: \"paused\" | \"resuming\" | \"uploading\" | \"completed\" | \"failed\";\r\n lastChunkIndex: number;\r\n checksum?: string;\r\n metadata?: Record<string, any>;\r\n}\r\n\r\nexport interface ResumeResult {\r\n success: boolean;\r\n uploadedSize: number;\r\n totalSize: number;\r\n chunks: UploadChunk[];\r\n error?: string;\r\n}\r\n\r\nexport class UploadResumeManager {\r\n private static instance: UploadResumeManager;\r\n private static fileIdCounter = 0;\r\n private resumeStates: Map<string, ResumeState> = new Map();\r\n private options: Required<ResumeOptions>;\r\n private activeUploads: Set<string> = new Set();\r\n private chunkQueue: Map<string, UploadChunk[]> = new Map();\r\n\r\n constructor(options: ResumeOptions = {}) {\r\n this.options = {\r\n chunkSize: FILE_SIZE.CHUNK_SIZE,\r\n maxConcurrentChunks: UPLOAD.MAX_CONCURRENT_CHUNKS,\r\n retryAttempts: UPLOAD.MAX_RETRY_ATTEMPTS,\r\n retryDelay: TIMING.RETRY_DELAY,\r\n enableResume: true,\r\n validateChunks: true,\r\n checksumAlgorithm: \"md5\",\r\n ...options,\r\n };\r\n }\r\n\r\n static getInstance(): UploadResumeManager {\r\n if (!UploadResumeManager.instance) {\r\n UploadResumeManager.instance = new UploadResumeManager();\r\n }\r\n return UploadResumeManager.instance;\r\n }\r\n\r\n async createResumeState(file: File, provider: string): Promise<ResumeState> {\r\n const fileId = this.generateFileId(file);\r\n const chunks = this.createChunks(file);\r\n const checksum = await this.calculateChecksum(file);\r\n\r\n const resumeState: ResumeState = {\r\n fileId,\r\n fileName: file.name,\r\n totalSize: file.size,\r\n uploadedSize: 0,\r\n chunks,\r\n status: \"paused\",\r\n lastChunkIndex: -1,\r\n checksum,\r\n metadata: {\r\n provider,\r\n mimeType: file.type,\r\n lastModified: file.lastModified,\r\n createdAt: Date.now(),\r\n },\r\n };\r\n\r\n this.resumeStates.set(fileId, resumeState);\r\n this.chunkQueue.set(fileId, [...chunks]);\r\n\r\n return resumeState;\r\n }\r\n\r\n async resumeUpload(fileId: string, provider: any): Promise<ResumeResult> {\r\n const resumeState = this.resumeStates.get(fileId);\r\n if (!resumeState) {\r\n return {\r\n success: false,\r\n uploadedSize: 0,\r\n totalSize: 0,\r\n chunks: [],\r\n error: \"Resume state not found\",\r\n };\r\n }\r\n\r\n if (resumeState.status === \"completed\") {\r\n return {\r\n success: true,\r\n uploadedSize: resumeState.totalSize,\r\n totalSize: resumeState.totalSize,\r\n chunks: resumeState.chunks,\r\n };\r\n }\r\n\r\n resumeState.status = \"resuming\";\r\n this.activeUploads.add(fileId);\r\n\r\n try {\r\n // Validate existing chunks if validation is enabled\r\n if (this.options.validateChunks) {\r\n await this.validateExistingChunks(resumeState, provider);\r\n }\r\n\r\n // Resume from last successful chunk\r\n const result = await this.uploadRemainingChunks(resumeState, provider);\r\n\r\n if (result.success) {\r\n resumeState.status = \"completed\";\r\n resumeState.uploadedSize = resumeState.totalSize;\r\n } else {\r\n resumeState.status = \"failed\";\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n resumeState.status = \"failed\";\r\n return {\r\n success: false,\r\n uploadedSize: resumeState.uploadedSize,\r\n totalSize: resumeState.totalSize,\r\n chunks: resumeState.chunks,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n };\r\n } finally {\r\n this.activeUploads.delete(fileId);\r\n }\r\n }\r\n\r\n pauseUpload(fileId: string): boolean {\r\n const resumeState = this.resumeStates.get(fileId);\r\n if (!resumeState || resumeState.status === \"completed\") {\r\n return false;\r\n }\r\n\r\n resumeState.status = \"paused\";\r\n return true;\r\n }\r\n\r\n cancelUpload(fileId: string): boolean {\r\n const resumeState = this.resumeStates.get(fileId);\r\n if (!resumeState) {\r\n return false;\r\n }\r\n\r\n // Clean up chunks\r\n this.chunkQueue.delete(fileId);\r\n this.activeUploads.delete(fileId);\r\n\r\n // Reset state\r\n resumeState.status = \"paused\";\r\n resumeState.uploadedSize = 0;\r\n resumeState.chunks.forEach((chunk) => {\r\n chunk.uploaded = false;\r\n chunk.retryCount = 0;\r\n });\r\n\r\n return true;\r\n }\r\n\r\n getResumeState(fileId: string): ResumeState | undefined {\r\n return this.resumeStates.get(fileId);\r\n }\r\n\r\n getAllResumeStates(): ResumeState[] {\r\n return Array.from(this.resumeStates.values());\r\n }\r\n\r\n clearResumeState(fileId: string): boolean {\r\n const removed = this.resumeStates.delete(fileId);\r\n this.chunkQueue.delete(fileId);\r\n this.activeUploads.delete(fileId);\r\n return removed;\r\n }\r\n\r\n private createChunks(file: File): UploadChunk[] {\r\n const chunks: UploadChunk[] = [];\r\n\r\n // Handle zero-byte files\r\n if (file.size === 0) {\r\n chunks.push({\r\n id: `${file.name}-chunk-0`,\r\n start: 0,\r\n end: 0,\r\n data: new Blob(),\r\n uploaded: false,\r\n retryCount: 0,\r\n maxRetries: this.options.retryAttempts,\r\n });\r\n return chunks;\r\n }\r\n\r\n const totalChunks = Math.ceil(file.size / this.options.chunkSize);\r\n\r\n for (let i = 0; i < totalChunks; i++) {\r\n const start = i * this.options.chunkSize;\r\n const end = Math.min(start + this.options.chunkSize, file.size);\r\n const data = file.slice(start, end);\r\n\r\n chunks.push({\r\n id: `${file.name}-chunk-${i}`,\r\n start,\r\n end,\r\n data,\r\n uploaded: false,\r\n retryCount: 0,\r\n maxRetries: this.options.retryAttempts,\r\n });\r\n }\r\n\r\n return chunks;\r\n }\r\n\r\n private async calculateChecksum(file: File): Promise<string> {\r\n // This is a simplified checksum calculation\r\n // In production, you'd use a proper crypto library\r\n const buffer = await file.arrayBuffer();\r\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", buffer);\r\n const hashArray = Array.from(new Uint8Array(hashBuffer));\r\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\r\n }\r\n\r\n private async validateExistingChunks(\r\n resumeState: ResumeState,\r\n provider: any\r\n ): Promise<void> {\r\n // Check with provider which chunks are already uploaded\r\n try {\r\n const uploadedChunks =\r\n (await provider.getUploadedChunks?.(resumeState.fileId)) || [];\r\n\r\n resumeState.chunks.forEach((chunk, index) => {\r\n if (uploadedChunks.includes(index)) {\r\n chunk.uploaded = true;\r\n resumeState.uploadedSize += chunk.end - chunk.start;\r\n resumeState.lastChunkIndex = Math.max(\r\n resumeState.lastChunkIndex,\r\n index\r\n );\r\n }\r\n });\r\n } catch (error) {\r\n console.warn(\"Failed to validate existing chunks:\", error);\r\n // Continue without validation\r\n }\r\n }\r\n\r\n private async uploadRemainingChunks(\r\n resumeState: ResumeState,\r\n provider: any\r\n ): Promise<ResumeResult> {\r\n const remainingChunks = resumeState.chunks.filter(\r\n (chunk) => !chunk.uploaded\r\n );\r\n\r\n if (remainingChunks.length === 0) {\r\n return {\r\n success: true,\r\n uploadedSize: resumeState.totalSize,\r\n totalSize: resumeState.totalSize,\r\n chunks: resumeState.chunks,\r\n };\r\n }\r\n\r\n // Upload chunks with concurrency control\r\n const uploadPromises: Promise<boolean>[] = [];\r\n const activeChunks = new Set<string>();\r\n\r\n for (const chunk of remainingChunks) {\r\n if (activeChunks.size >= this.options.maxConcurrentChunks) {\r\n // Wait for a chunk to complete before starting another\r\n await Promise.race(uploadPromises);\r\n uploadPromises.splice(0, 1);\r\n }\r\n\r\n const uploadPromise = this.uploadChunk(chunk, resumeState, provider);\r\n activeChunks.add(chunk.id);\r\n\r\n uploadPromise.then(() => {\r\n activeChunks.delete(chunk.id);\r\n });\r\n\r\n uploadPromises.push(uploadPromise);\r\n }\r\n\r\n // Wait for all remaining uploads to complete\r\n const results = await Promise.all(uploadPromises);\r\n const success = results.every((result) => result);\r\n\r\n return {\r\n success,\r\n uploadedSize: resumeState.uploadedSize,\r\n totalSize: resumeState.totalSize,\r\n chunks: resumeState.chunks,\r\n error: success ? undefined : \"Some chunks failed to upload\",\r\n };\r\n }\r\n\r\n private async uploadChunk(\r\n chunk: UploadChunk,\r\n resumeState: ResumeState,\r\n provider: any\r\n ): Promise<boolean> {\r\n let attempts = 0;\r\n const maxAttempts = chunk.maxRetries + 1;\r\n\r\n while (attempts < maxAttempts) {\r\n try {\r\n const result = await this.uploadChunkToProvider(\r\n chunk,\r\n resumeState,\r\n provider\r\n );\r\n\r\n if (result) {\r\n chunk.uploaded = true;\r\n resumeState.uploadedSize += chunk.end - chunk.start;\r\n resumeState.lastChunkIndex = Math.max(\r\n resumeState.lastChunkIndex,\r\n resumeState.chunks.indexOf(chunk)\r\n );\r\n\r\n // Emit progress event\r\n this.emitProgressEvent(resumeState, chunk);\r\n return true;\r\n }\r\n } catch (error) {\r\n console.warn(`Chunk upload attempt ${attempts + 1} failed:`, error);\r\n chunk.retryCount++;\r\n\r\n if (attempts < maxAttempts - 1) {\r\n await this.delay(\r\n this.options.retryDelay *\r\n Math.pow(TIMING.RETRY_EXPONENTIAL_BASE, attempts)\r\n );\r\n }\r\n }\r\n\r\n attempts++;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n private async uploadChunkToProvider(\r\n _chunk: UploadChunk,\r\n _resumeState: ResumeState,\r\n _provider: any\r\n ): Promise<boolean> {\r\n // This would be implemented by the specific provider\r\n // For now, we'll simulate the upload\r\n try {\r\n // Simulate upload delay\r\n await this.delay(\r\n Math.random() * UPLOAD.UPLOAD_SIMULATION_DELAY_RANGE +\r\n UPLOAD.UPLOAD_SIMULATION_DELAY_MIN\r\n );\r\n\r\n // Simulate success (in real implementation, this would call provider.uploadChunk)\r\n return true;\r\n } catch (error) {\r\n throw new Error(`Failed to upload chunk: ${error}`);\r\n }\r\n }\r\n\r\n private emitProgressEvent(\r\n resumeState: ResumeState,\r\n chunk: UploadChunk\r\n ): void {\r\n const progress = (resumeState.uploadedSize / resumeState.totalSize) * 100;\r\n\r\n // Create a custom event for progress updates\r\n const event = new CustomEvent(\"uploadProgress\", {\r\n detail: {\r\n fileId: resumeState.fileId,\r\n fileName: resumeState.fileName,\r\n progress,\r\n uploadedSize: resumeState.uploadedSize,\r\n totalSize: resumeState.totalSize,\r\n chunkId: chunk.id,\r\n chunkProgress: 100,\r\n },\r\n });\r\n\r\n document.dispatchEvent(event);\r\n }\r\n\r\n private generateFileId(file: File): string {\r\n UploadResumeManager.fileIdCounter++;\r\n return `resume-${file.name}-${file.size}-${file.lastModified}-${Date.now()}-${UploadResumeManager.fileIdCounter}`;\r\n }\r\n\r\n private delay(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n }\r\n\r\n // Utility methods for external use\r\n getUploadProgress(fileId: string): number {\r\n const resumeState = this.resumeStates.get(fileId);\r\n if (!resumeState) return 0;\r\n\r\n return (resumeState.uploadedSize / resumeState.totalSize) * 100;\r\n }\r\n\r\n isUploadActive(fileId: string): boolean {\r\n return this.activeUploads.has(fileId);\r\n }\r\n\r\n getActiveUploads(): string[] {\r\n return Array.from(this.activeUploads);\r\n }\r\n\r\n // Cleanup method\r\n destroy(): void {\r\n this.resumeStates.clear();\r\n this.chunkQueue.clear();\r\n this.activeUploads.clear();\r\n }\r\n}\r\n"]}