@designbycode/uploader-core
v1.0.2
Published
A framework-agnostic file uploader library with queue management, progress tracking, and abort support
Downloads
60
Maintainers
Readme
@designbycode/uploader-core
A framework-agnostic JavaScript file uploader library with queue management, progress tracking, abort support, and file validation.
Features
- Framework-agnostic — Works in browsers and Node.js
- Dual module support — ESM and CommonJS
- Queue management — Add multiple files and upload them in sequence or parallel
- Progress tracking — Real-time upload progress via events
- Abort support — Cancel individual uploads or all at once
- File validation — Built-in size and MIME type validation with glob patterns
- Custom validators — Support for async validation functions
- Concurrency control — Limit simultaneous uploads with
maxConcurrent - Retry logic — Automatic retry for failed uploads
- Event-driven — Subscribe to
add,progress,success,error,remove,retryevents - TypeScript — Full TypeScript support with type definitions
Installation
# Using bun
bun add @designbycode/uploader-core
# Using npm
npm install @designbycode/uploader-core
# Using pnpm
pnpm add @designbycode/uploader-coreQuick Start
import { Uploader } from "@designbycode/uploader-core";
const uploader = new Uploader({
process: async (file, { signal, onProgress }) => {
const formData = new FormData();
formData.append("file", file);
const response = await fetch("/api/upload", {
method: "POST",
body: formData,
signal,
});
return { serverId: response.json().id };
},
});
// Add files and upload
const input = document.querySelector('input[type="file"]');
input.addEventListener("change", async () => {
const added = await uploader.addFiles(Array.from(input.files));
uploader.uploadAll();
});
// Listen for events
uploader.on("progress", (file) => {
console.log(`${file.file.name}: ${file.progress}%`);
});
uploader.on("success", (file) => {
console.log(`${file.file.name} uploaded successfully`);
});API
new Uploader(options?)
Creates a new uploader instance.
const uploader = new Uploader({
autoUpload: false, // Automatically upload files when added
maxConcurrent: 2, // Limit simultaneous uploads
validation: {
// File validation rules
maxSize: 10 * 1024 * 1024, // 10MB
acceptedMimeTypes: ["image/png", "image/jpeg"],
},
process: async (file, { signal, onProgress }) => {
// Your upload logic here
return { serverId: "file-id" };
},
});Options
| Option | Type | Description |
| ------------------- | --------------------------------- | -------------------------------------------------- |
| autoUpload | boolean | Automatically upload files when added |
| maxConcurrent | number | Maximum simultaneous uploads (default: unlimited) |
| validation | ValidationRule \| FileValidator | File validation rules or custom validator |
| maxRetries | number | Maximum retry attempts for failed uploads |
| retryDelay | number | Delay between retries in ms (default: 1000) |
| process | ProcessFn | Function to handle the actual upload |
| revert | RevertFn | Function to undo upload (e.g., delete from server) |
| onAdd | Callback | Called when a file is added |
| onProgress | Callback | Called when upload progress updates |
| onSuccess | Callback | Called when upload succeeds |
| onError | Callback | Called when upload fails |
| onRemove | Callback | Called when a file is removed |
| onRetry | Callback | Called when upload is retried |
| onValidationError | Callback | Called when validation fails |
Methods
addFiles(files: File[]): Promise<UploadFile[]>
Add files to the upload queue. Returns the added UploadFile objects.
const added = await uploader.addFiles([file1, file2, file3]);
console.log(`Added ${added.length} files`);uploadFile(id: string): Promise<void>
Upload a single file by its ID.
await uploader.uploadFile("file-uuid");uploadAll(): void
Upload all queued files.
uploader.uploadAll();cancelFile(id: string): void
Cancel an in-progress upload.
uploader.cancelFile("file-uuid");cancelAll(): void
Cancel all in-progress uploads.
uploader.cancelAll();removeFile(id: string): Promise<void>
Remove a file from the queue. Calls revert() if the file was uploaded.
await uploader.removeFile("file-uuid");getFiles(): ReadonlyArray<UploadFile>
Get all files in the queue.
const files = uploader.getFiles();
files.forEach((f) => console.log(f.file.name, f.status));getFile(id: string): UploadFile | undefined
Get a single file by ID.
const file = uploader.getFile("file-uuid");getFileByServerId(serverId: string): UploadFile | undefined
Get a single file by its server ID (after upload).
const file = uploader.getFileByServerId("server-123");clear(): void
Clear all files from the queue.
uploader.clear();Events
on(event, callback): () => void
Subscribe to an event. Returns an unsubscribe function.
const unsubscribe = uploader.on("success", (file) => {
console.log(`${file.file.name} uploaded!`);
});
// Later, unsubscribe
unsubscribe();once(event, callback): () => void
Subscribe to an event for a single execution.
uploader.once("success", (file) => {
console.log("First upload completed!");
});off(event, callback): void
Unsubscribe from an event.
const handler = (file) => console.log(file.file.name);
uploader.on("success", handler);
uploader.off("success", handler);Event Types
| Event | Payload | Description |
| ---------- | --------------------------------------- | ----------------------- |
| add | UploadFile | File added to queue |
| progress | UploadFile | Upload progress updated |
| success | UploadFile | Upload completed |
| error | UploadFile | Upload failed |
| remove | UploadFile | File removed from queue |
| retry | { file: UploadFile, attempt: number } | Upload being retried |
Validation
Built-in Rules
const uploader = new Uploader({
validation: {
maxSize: 5 * 1024 * 1024, // 5MB max
minSize: 1000, // 1KB min
acceptedMimeTypes: ["image/png", "image/jpeg", "image/gif"],
rejectedMimeTypes: ["application/exe"],
},
process: async (file, { signal, onProgress }) => {
// ...
},
});
uploader.on("validationError", (file, error) => {
console.error(`${file.name} rejected: ${error}`);
});Custom Validator
const uploader = new Uploader({
validation: async (file) => {
// Check file name
if (!file.name.match(/^[a-zA-Z0-9-_]+\.[a-z]+$/)) {
return { valid: false, error: "Invalid file name format" };
}
// Async validation (e.g., check against API)
const isAllowed = await checkFileAllowed(file);
if (!isAllowed) {
return { valid: false, error: "File not allowed" };
}
return { valid: true };
},
});Concurrency Control
Limit simultaneous uploads:
const uploader = new Uploader({
maxConcurrent: 2, // Only 2 uploads at a time
process: async (file, { signal, onProgress }) => {
// ...
},
});
// Add 10 files, only 2 will upload at once
await uploader.addFiles(files);
uploader.uploadAll();Retry Logic
Automatically retry failed uploads:
const uploader = new Uploader({
maxRetries: 3, // Retry up to 3 times
retryDelay: 1000, // Wait 1 second between retries
process: async (file, { signal, onProgress }) => {
// ...
},
});
uploader.on("retry", ({ file, attempt }) => {
console.log(`Retrying ${file.file.name} (attempt ${attempt})`);
});Types
UploadFile
interface UploadFile {
id: string;
file: File;
status: "idle" | "queued" | "uploading" | "success" | "error" | "cancelled";
progress: number;
serverId?: string;
error?: string;
}UploadStatus
type UploadStatus =
| "idle"
| "queued"
| "uploading"
| "success"
| "error"
| "cancelled";ValidationRule
interface ValidationRule {
maxSize?: number;
minSize?: number;
acceptedMimeTypes?: string[];
rejectedMimeTypes?: string[];
}License
MIT
