nestjs-minio-backend
Version:
NestJS module for MinIO integration
123 lines • 5.9 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var MinioFileInterceptor_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MinioFileInterceptor = void 0;
const common_1 = require("@nestjs/common");
const rxjs_1 = require("rxjs");
const minio_service_1 = require("../minio.service");
const operators_1 = require("rxjs/operators");
let MinioFileInterceptor = MinioFileInterceptor_1 = class MinioFileInterceptor {
constructor(minioService) {
this.minioService = minioService;
this.logger = new common_1.Logger(MinioFileInterceptor_1.name);
}
intercept(context, next) {
const request = context.switchToHttp().getRequest();
const files = request.files || {};
const handler = context.getHandler();
const fileFieldsConfig = Reflect.getMetadata('fileField', handler) || [];
let fileProcessingPromise = Promise.resolve({});
for (const fieldConfig of fileFieldsConfig) {
const fieldName = fieldConfig.name;
const fieldFiles = files[fieldName];
if (fieldFiles && fieldFiles.length > 0) {
const file = fieldFiles[0];
const bucketName = fieldConfig.bucketName;
if (!bucketName) {
throw new Error(`Bucket name is required for file field ${fieldName}`);
}
fileProcessingPromise = fileProcessingPromise.then(async (processedData) => {
try {
this.validateFile(file, fieldConfig);
const fileUrl = await this.minioService.uploadFile(file, bucketName);
return { ...processedData, [fieldName]: fileUrl };
}
catch (error) {
if (error instanceof common_1.BadRequestException) {
throw error;
}
if (fieldConfig.required) {
throw new Error(`Failed to upload required file for ${fieldName}`);
}
return processedData;
}
});
}
else if (fieldConfig.required) {
throw new Error(`Required file ${fieldName} is missing`);
}
}
return new rxjs_1.Observable((subscriber) => {
fileProcessingPromise
.then((processedFiles) => {
request.body = {
...request.body,
...processedFiles,
};
return next
.handle()
.pipe((0, operators_1.map)(async (data) => {
if (Array.isArray(data)) {
return Promise.all(data.map((item) => this.transformUrls(item)));
}
return this.transformUrls(data);
}))
.subscribe(subscriber);
})
.catch((error) => {
subscriber.error(error);
});
});
}
async transformUrls(data) {
if (!data)
return data;
const obj = data.toJSON ? await data.toJSON() : data;
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'string' && value.includes('/')) {
const [bucketName, ...pathParts] = value.split('/');
if (pathParts.length > 0) {
try {
obj[key] = await this.minioService.getPresignedUrl(bucketName, pathParts.join('/'));
}
catch (error) {
this.logger.error(`Error generating presigned URL for ${key}:`, error);
}
}
}
}
return obj;
}
validateFile(file, config) {
const validationConfig = {
allowedMimeTypes: config.allowedMimeTypes || [],
maxSize: config.maxSize,
required: config.required,
};
if (validationConfig.maxSize && file.size > validationConfig.maxSize) {
throw new common_1.BadRequestException(`File ${file.originalname} exceeds maximum size of ${validationConfig.maxSize / 1024 / 1024}MB`);
}
if (validationConfig.allowedMimeTypes.length > 0) {
const normalizedMimetype = file.mimetype.toLowerCase();
const normalizedAllowedTypes = validationConfig.allowedMimeTypes.map((type) => type.toLowerCase());
if (!normalizedAllowedTypes.includes(normalizedMimetype)) {
throw new common_1.BadRequestException(`File ${file.originalname} has invalid type. Received: ${file.mimetype}, Allowed types: ${validationConfig.allowedMimeTypes.join(', ')}`);
}
}
}
};
exports.MinioFileInterceptor = MinioFileInterceptor;
exports.MinioFileInterceptor = MinioFileInterceptor = MinioFileInterceptor_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [minio_service_1.MinioService])
], MinioFileInterceptor);
//# sourceMappingURL=file.interceptor.js.map