just-upload-it
v1.1.2
Published
Universal file/image uploader with pluggable drivers
Maintainers
Readme
just-upload-it
Universal file upload abstraction for Node.js
Switch between local storage, Cloudinary, S3, and more with a single API.
⚠️ Under active development - Not recommended for production use yet.
🎯 Why just-upload-it?
- 🔄 Provider-agnostic - Switch storage providers without changing your code
- 📦 Normalized API - Consistent input/output across all drivers
- 🎨 Auto-detection - Automatically detects file types and metadata
- 📝 TypeScript - Fully typed with comprehensive interfaces
- 🧩 Extensible - Easy to add custom drivers
- 🪶 Lightweight - Minimal dependencies
Installation
npm install just-upload-it🚀 Quick Start
import { Uploader } from 'just-upload-it';
import fs from 'fs';
const uploader = new Uploader({ provider: 'local' });
const fileBuffer = fs.readFileSync('./photo.jpg');
const result = await uploader.upload(fileBuffer, {
rename: 'profile-pic',
path: 'users-123',
});
await uploader.delete(result.publicId);🎨 Supported Providers
| Provider | Status | Features | | ------------ | :-----: | ------------------------------- | | Local | Stable | File system storage | | Cloudinary | Stable | Cloud storage with CDN delivery | | AWS S3 | Stable | Scalable cloud storage | | Google Cloud | Planned | - | | Azure Blob | Planned | - |
📖 API Reference
new Uploader(config)
Creates a new uploader instance.
const uploader = new Uploader({
provider: 'local' | 'cloudinary' | 'aws-s3',
config: <ProviderConfig>,
});uploader.upload(buffer, options?)
Uploads a file buffer.
Parameters:
buffer: Buffer- File content as Bufferoptions?: UploadOptions- Upload configuration
Returns: Promise<UploadResult>
interface UploadOptions {
rename?: string; // Custom filename (without extension)
path?: string; // Subfolder path
metadata?: {
format?: string; // File extension (auto-detected if omitted)
resourceType?: 'image' | 'video' | 'raw'; // Auto-detected
[key: string]: any; // Custom metadata
};
}
interface UploadResult {
url: string; // Public URL of uploaded file
publicId: string; // Unique identifier for deletion
metadata?: {
size: number; // File size in bytes
format: string; // File extension
resourceType: 'image' | 'video' | 'raw';
[key: string]: any;
};
}uploader.delete(publicId, options?)
Deletes an uploaded file.
Parameters:
publicId: string- File identifier from upload resultoptions?: DeleteOptions- Deletion configuration
Returns: Promise<DeleteResult>
interface DeleteOptions {
resourceType?: 'image' | 'video' | 'raw'; // Required for some providers
}
interface DeleteResult {
result: 'ok' | 'not found' | 'error';
}🔧 Provider Configuration
Local Storage
import { Uploader, LocalConfig } from 'just-upload-it';
const config: LocalConfig = {
baseDir: './uploads', // Upload directory (default: './uploads')
baseUrl: 'http://localhost:3000/uploads', // Base URL for files
overwrite: false, // Allow overwriting existing files
};
const uploader = new Uploader({ provider: 'local', config });Cloudinary
import { Uploader, CloudinaryConfig } from 'just-upload-it';
const config: CloudinaryConfig = {
cloudName: 'your-cloud-name',
apiKey: 'your-api-key',
apiSecret: 'your-api-secret',
};
const uploader = new Uploader({ provider: 'cloudinary', config });
const result = await uploader.upload(fileBuffer, {
rename: 'my-file',
path: 'test-folder',
metadata: { description: 'Example file' },
});
await uploader.delete(result.publicId);⚠️ Important: For non-image files (
video,raw), always setresourceTypeinoptions.
This ensures correct deletion of the file.
await uploader.delete(publicId, { resourceType: 'raw' });AWS S3
import { Uploader, S3Config } from 'just-upload-it';
const config: S3Config = {
region: 'your-bucket-region',
bucket: 'your-bucket-name',
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
};
const uploader = new Uploader({ provider: 'aws-s3', config });
const result = await uploader.upload(fileBuffer, {
rename: 'document',
path: 'uploads',
metadata: {
format: 'pdf',
resourceType: 'raw',
},
});💡 Examples
Upload with auto-detection
File type, format, and resource type are automatically detected:
const result = await uploader.upload(imageBuffer);
// No need to specify format or resourceTypeUpload with custom metadata
const result = await uploader.upload(fileBuffer, {
rename: 'user-avatar',
path: 'users',
metadata: {
userId: '12345',
uploadedBy: '[email protected]',
},
});Upload to organized folders
const today = new Date().toISOString().split('T')[0];
const result = await uploader.upload(buffer, {
path: `uploads-${today}`,
rename: 'document',
});Switch providers without code changes
// Development: local storage
const uploader = new Uploader({
provider: process.env.NODE_ENV === 'production' ? 'cloudinary' : 'local',
config: process.env.NODE_ENV === 'production' ? cloudinaryConfig : localConfig,
});
// Same code works for both!
await uploader.upload(buffer);Testing
Unit Tests (always run)
npm testIntegration Tests
Integration tests for Cloudinary and AWS S3 are optional. If credentials are not provided:
- Tests will be skipped gracefully
- Coverage threshold is adjusted automatically (65% instead of 80%)
- Local driver tests still run and provide good coverage
To run full integration tests, create a .env file:
cp .env.example .env
# Edit .env with your credentialsThen run: npm test
License
MIT License © 2025 EstebanSD
