Understanding the Plugin System
FluxMedia's plugin system lets you extend and customize upload behavior without modifying core code. Whether you need validation, logging, optimization, or custom transformations, plugins have you covered.
Plugin Lifecycle
Plugins hook into five key lifecycle points:
Upload Flow:
beforeUpload → Upload to Provider → afterUpload
↓
onError
Delete Flow:
beforeDelete → Delete from Provider → afterDelete
↓
onError
Creating Your First Plugin
Use the createPlugin helper:
import { createPlugin } from '@fluxmedia/core';
const myPlugin = createPlugin('my-plugin', {
beforeUpload: async (file, options) => {
console.log('Before upload:', options.filename);
return { file, options }; // Must return both
},
afterUpload: async (result) => {
console.log('Upload complete:', result.url);
return result; // Must return result
},
onError: async (error, context) => {
console.error('Upload failed:', error.message);
// No return needed
}
});
Real-World Plugin Examples
Validation Plugin
Validate file types and sizes before upload:
const validationPlugin = createPlugin('validator', {
beforeUpload: async (file, options) => {
const size = file.size || file.byteLength;
const maxSize = 10 * 1024 * 1024; // 10MB
if (size > maxSize) {
throw new Error(`File exceeds ${maxSize / 1024 / 1024}MB limit`);
}
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
if (file.type && !allowedTypes.includes(file.type)) {
throw new Error(`File type ${file.type} not allowed`);
}
return { file, options };
}
});
Metadata Enrichment
Automatically add metadata to every upload:
const metadataPlugin = createPlugin('metadata', {
beforeUpload: async (file, options) => {
return {
file,
options: {
...options,
metadata: {
...options.metadata,
uploadedAt: new Date().toISOString(),
environment: process.env.NODE_ENV,
}
}
};
}
});
Analytics Logger
Track all uploads for analytics:
const analyticsPlugin = createPlugin('analytics', {
afterUpload: async (result) => {
await trackEvent('file_uploaded', {
fileId: result.id,
size: result.size,
provider: result.provider,
duration: result.duration,
});
return result;
},
onError: async (error, context) => {
await trackEvent('upload_failed', {
error: error.message,
filename: context.options?.filename,
});
}
});
Registering Plugins
Register plugins with your uploader:
const uploader = new MediaUploader(new S3Provider({ ... }));
// Register single plugin
await uploader.use(validationPlugin);
// Register multiple plugins
await uploader.use(metadataPlugin);
await uploader.use(analyticsPlugin);
// Check registered plugins
console.log(uploader.plugins.getAll().map(p => p.name));
// ['validator', 'metadata', 'analytics']
Plugin Execution Order
Plugins execute in registration order:
- All
beforeUploadhooks run in order - File uploads to provider
- All
afterUploadhooks run in order
If any hook throws, onError hooks are called and upload stops.
Graceful Degradation
Plugins are designed to degrade gracefully. If a non-critical plugin fails during afterUpload, the upload itself has already succeeded. You can catch and log plugin errors without losing the upload result. This lets you add optional enhancements like analytics or logging without risking data loss.
Official Plugins
The @fluxmedia/plugins package includes battle-tested plugins ready for production:
pnpm add @fluxmedia/plugins
import {
createFileValidationPlugin,
createImageOptimizationPlugin,
createMetadataExtractionPlugin,
createAnalyticsPlugin,
createRetryPlugin,
} from '@fluxmedia/plugins';
// Validate file type and size
await uploader.use(createFileValidationPlugin({
maxSize: 10 * 1024 * 1024,
allowedTypes: ['image/*', 'video/*'],
}));
// Automatic retry with exponential backoff
await uploader.use(createRetryPlugin({ maxRetries: 3 }));
- File Validation — Type, size, and extension checks
- Image Optimization — Resize and compress before upload
- Metadata Extraction — Extract EXIF, dimensions, file hash
- Analytics — Configurable logging and tracking
- Retry — Automatic retry with exponential backoff