import { Client } from 'minio' import { env } from './env' // Get MinIO credentials with dev-portfolio naming first, fallback to legacy names const minioAccessKey = env.MINIO_KEY || env.MINIO_ACCESS_KEY const minioSecretKey = env.MINIO_SECRET || env.MINIO_SECRET_KEY const minioBucket = env.MINIO_IMAGE_BUCKET || env.MINIO_BUCKET // Only initialize MinIO client if ALL required configuration is available export const minioClient = (env.MINIO_ENDPOINT && minioAccessKey && minioSecretKey) ? new Client({ endPoint: env.MINIO_ENDPOINT, port: env.MINIO_PORT || 9000, useSSL: env.NODE_ENV === 'production', accessKey: minioAccessKey, secretKey: minioSecretKey, }) : null // Log MinIO initialization status if (!minioClient) { console.warn('⚠️ MinIO client not initialized. Missing configuration:', { hasEndpoint: !!env.MINIO_ENDPOINT, hasKey: !!minioAccessKey, hasSecret: !!minioSecretKey, checkedVars: ['MINIO_KEY/MINIO_ACCESS_KEY', 'MINIO_SECRET/MINIO_SECRET_KEY'] }) } else { console.log('✅ MinIO client initialized successfully with endpoint:', env.MINIO_ENDPOINT) } export const BUCKET_NAME = minioBucket || 'nextjs-boilerplate' // Initialize bucket if it doesn't exist export async function initializeBucket() { if (!minioClient) { console.error('❌ MinIO client not configured for bucket initialization') throw new Error( 'MinIO client not configured. Please set MINIO_ENDPOINT, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY environment variables.' ) } try { console.log('🔍 Checking if bucket exists:', BUCKET_NAME) const bucketExists = await minioClient.bucketExists(BUCKET_NAME) if (!bucketExists) { console.log('🚀 Creating bucket:', BUCKET_NAME) await minioClient.makeBucket(BUCKET_NAME, 'us-east-1') console.log('✅ Bucket created successfully:', BUCKET_NAME) } else { console.log('✅ Bucket already exists:', BUCKET_NAME) } } catch (error) { console.error('❌ Error initializing bucket:', { error: error.message, code: error.code, statusCode: error.statusCode, bucketName: BUCKET_NAME, endpoint: env.MINIO_ENDPOINT, port: env.MINIO_PORT }) throw error } } // Generate unique filename with timestamp and random string export function generateUniqueFilename(originalName: string): string { const timestamp = Date.now() const randomString = Math.random().toString(36).substring(2) const extension = originalName.split('.').pop() return `${timestamp}-${randomString}.${extension}` } // Upload file to MinIO export async function uploadFile( buffer: Buffer, filename: string, contentType: string ): Promise { console.log('📤 Starting file upload:', { filename, contentType, bufferSize: buffer.length }) if (!minioClient) { console.error('❌ MinIO client not configured') throw new Error( 'MinIO client not configured. Please set MINIO_ENDPOINT, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY environment variables.' ) } try { console.log('🔧 Initializing bucket:', BUCKET_NAME) await initializeBucket() const uniqueFilename = generateUniqueFilename(filename) const tempPath = `temp/${uniqueFilename}` console.log('📤 Uploading to MinIO:', { bucket: BUCKET_NAME, path: tempPath, size: buffer.length, endpoint: env.MINIO_ENDPOINT, port: env.MINIO_PORT, useSSL: env.NODE_ENV === 'production' }) await minioClient.putObject(BUCKET_NAME, tempPath, buffer, buffer.length, { 'Content-Type': contentType, }) console.log('✅ File uploaded successfully:', tempPath) return tempPath } catch (error) { console.error('❌ Error uploading file:', { error: error.message, code: error.code, statusCode: error.statusCode, resource: error.resource, region: error.region, bucketName: error.bucketName, objectName: error.objectName, }) throw error } } // Move file from temp to permanent storage export async function moveToPermStorage(tempPath: string, permanentPath: string): Promise { if (!minioClient) { throw new Error( 'MinIO client not configured. Please set MINIO_ENDPOINT, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY environment variables.' ) } try { // Copy from temp to permanent location await minioClient.copyObject(BUCKET_NAME, permanentPath, `${BUCKET_NAME}/${tempPath}`) // Remove from temp location await minioClient.removeObject(BUCKET_NAME, tempPath) } catch (error) { console.error('Error moving file to permanent storage:', error) throw error } } // Delete file from storage export async function deleteFile(filePath: string): Promise { if (!minioClient) { throw new Error( 'MinIO client not configured. Please set MINIO_ENDPOINT, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY environment variables.' ) } try { await minioClient.removeObject(BUCKET_NAME, filePath) } catch (error) { console.error('Error deleting file:', error) throw error } } // Get file URL (for serving files) export async function getFileUrl(filePath: string): Promise { if (!minioClient) { throw new Error( 'MinIO client not configured. Please set MINIO_ENDPOINT, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY environment variables.' ) } try { return await minioClient.presignedGetObject(BUCKET_NAME, filePath, 7 * 24 * 60 * 60) // 7 days } catch (error) { console.error('Error getting file URL:', error) throw error } } // Validate file type export function validateFileType(mimetype: string, allowedTypes: string[]): boolean { return allowedTypes.includes(mimetype) } // Validate file size (in bytes) export function validateFileSize(size: number, maxSize: number): boolean { return size <= maxSize }