UNPKG

npm-storage-package

Version:

Universal cloud storage package for AWS S3, Google Cloud Storage, and Azure Blob Storage with Express.js integration

120 lines 4.92 kB
import { storageAction } from "./storageAction.js"; // Custom multer storage engine for cloud storage export class CloudStorageEngine { provider; config; generateFileName; fileFilter; destination; fieldConfigs; fileSizeLimit; constructor(options) { this.provider = options.provider; this.config = options.config; this.generateFileName = options.generateFileName; this.fileFilter = options.fileFilter; this.destination = options.destination; this.fieldConfigs = options.fieldConfigs; this.fileSizeLimit = options.fileSizeLimit; } _handleFile(req, file, callback) { // Get field-specific configuration const fieldConfig = this.fieldConfigs?.[file.fieldname]; // Apply global file filter first if (this.fileFilter && !this.fileFilter(req, file)) { return callback(new Error("File type not allowed")); } // Apply field-specific extension validation if (fieldConfig?.allowedExtensions) { const fileExtension = file.originalname.toLowerCase().split(".").pop(); if (!fileExtension || !fieldConfig.allowedExtensions.includes(`.${fileExtension}`)) { return callback(new Error(`File extension not allowed for field '${file.fieldname}'. Allowed: ${fieldConfig.allowedExtensions.join(", ")}`)); } } // Generate filename using field-specific or global generator let fileName; if (fieldConfig?.generateFileName) { fileName = fieldConfig.generateFileName(req, file); } else if (this.generateFileName) { fileName = this.generateFileName(req, file); } else { // Use field-specific destination or global destination const dest = fieldConfig?.destination || (typeof this.destination === "function" ? this.destination(req, file) : this.destination) || ""; const cleanDest = dest.replace(/[\\\/]+$/, ""); // Remove trailing slashes fileName = cleanDest ? `${cleanDest}/${Date.now()}-${file.originalname}` : `${Date.now()}-${file.originalname}`; } // Collect file data const chunks = []; let totalSize = 0; file.stream.on("data", (chunk) => { chunks.push(chunk); totalSize += chunk.length; // Check file size limit (global or field-specific) const sizeLimit = this.fileSizeLimit; if (sizeLimit && totalSize > sizeLimit) { return callback(new Error(`File size exceeds limit of ${Math.round(sizeLimit / (1024 * 1024))}MB`)); } }); file.stream.on("error", (error) => { callback(error); }); file.stream.on("end", async () => { try { // Combine all chunks into a single buffer const buffer = Buffer.concat(chunks, totalSize); // Upload to cloud storage const uploadedUrl = await storageAction(this.provider, "upload", this.config, { fileName, buffer, // Pass buffer instead of file path mimeType: file.mimetype, }); // Return file info that multer expects const fileInfo = { fieldname: file.fieldname, originalname: file.originalname, encoding: file.encoding, mimetype: file.mimetype, size: totalSize, destination: fieldConfig?.destination || this.destination || "", filename: fileName, path: uploadedUrl, // Use cloud URL as path buffer, cloudUrl: uploadedUrl, cloudKey: fileName, }; callback(null, fileInfo); } catch (error) { callback(error); } }); } _removeFile(req, file, callback) { // Implement file removal from cloud storage if (file.cloudKey) { storageAction(this.provider, "delete", this.config, { key: file.cloudKey }) .then(() => callback(null)) .catch((error) => callback(error)); } else { callback(null); } } } // Factory functions to create storage engines export function createS3Storage(options) { return new CloudStorageEngine({ ...options, provider: "s3" }); } export function createGCSStorage(options) { return new CloudStorageEngine({ ...options, provider: "gcs" }); } export function createAzureStorage(options) { return new CloudStorageEngine({ ...options, provider: "azure" }); } //# sourceMappingURL=multer-storage.js.map