/** * Storage utilities for file management * Provides high-level functions for common file operations */ import { uploadFile, moveToPermStorage, deleteFile, getFileUrl, validateFileType, validateFileSize, generateUniqueFilename, } from './file-vault' // File type configurations export const FILE_CONFIGS = { image: { allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/svg+xml'], maxSize: 10 * 1024 * 1024, // 10MB folder: 'images', }, document: { allowedTypes: [ 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain', 'text/csv', ], maxSize: 20 * 1024 * 1024, // 20MB folder: 'documents', }, avatar: { allowedTypes: ['image/jpeg', 'image/png', 'image/webp'], maxSize: 5 * 1024 * 1024, // 5MB folder: 'avatars', }, } as const export type FileType = keyof typeof FILE_CONFIGS // File upload result export interface UploadResult { tempPath: string filename: string size: number type: string uploadedAt: string } // File confirmation result export interface ConfirmResult { permanentPath: string filename: string folder: string url: string confirmedAt: string } /** * Upload file with type validation */ export async function uploadFileWithValidation( file: File, fileType: FileType ): Promise { const config = FILE_CONFIGS[fileType] // Validate file type if (!validateFileType(file.type, [...config.allowedTypes])) { throw new Error(`Invalid file type. Allowed: ${config.allowedTypes.join(', ')}`) } // Validate file size if (!validateFileSize(file.size, config.maxSize)) { throw new Error(`File too large. Max size: ${config.maxSize / (1024 * 1024)}MB`) } // Convert file to buffer const bytes = await file.arrayBuffer() const buffer = Buffer.from(bytes) // Upload to external API (no temporary storage needed) const uploadResult = await uploadFile(buffer, file.name, file.type) return { tempPath: uploadResult.url, // Use URL as tempPath for compatibility filename: uploadResult.filename, size: file.size, type: file.type, uploadedAt: new Date().toISOString(), } } /** * Confirm upload and move to permanent storage * With the new API, files are already in permanent storage */ export async function confirmUpload( tempPath: string, fileType: FileType, customFilename?: string ): Promise { const config = FILE_CONFIGS[fileType] // With the new API, tempPath is already the permanent URL const url = tempPath const filename = url.split('/').pop() || 'file' return { permanentPath: url, filename: filename, folder: config.folder, url: url, confirmedAt: new Date().toISOString(), } } /** * Delete file from storage */ export async function removeFile(filePath: string): Promise { await deleteFile(filePath) } /** * Get signed URL for file access */ export async function getSignedUrl(filePath: string): Promise { return await getFileUrl(filePath) } /** * Validate file before upload */ export function validateFile(file: File, fileType: FileType): { valid: boolean; error?: string } { const config = FILE_CONFIGS[fileType] // Check file type if (!validateFileType(file.type, [...config.allowedTypes])) { return { valid: false, error: `Invalid file type. Allowed: ${config.allowedTypes.join(', ')}`, } } // Check file size if (!validateFileSize(file.size, config.maxSize)) { return { valid: false, error: `File too large. Max size: ${config.maxSize / (1024 * 1024)}MB`, } } return { valid: true } } /** * Batch file operations */ export class FileBatch { private tempPaths: string[] = [] async uploadFile(file: File, fileType: FileType): Promise { const result = await uploadFileWithValidation(file, fileType) this.tempPaths.push(result.tempPath) return result } async confirmAll(fileType: FileType): Promise { const results = [] for (const tempPath of this.tempPaths) { const result = await confirmUpload(tempPath, fileType) results.push(result) } this.tempPaths = [] // Clear after confirmation return results } async cleanup(): Promise { for (const tempPath of this.tempPaths) { try { await removeFile(tempPath) } catch (error) { console.error(`Failed to cleanup ${tempPath}:`, error) } } this.tempPaths = [] } } /** * File metadata for database storage */ export interface FileMetadata { id: string filename: string originalName: string path: string size: number mimeType: string fileType: FileType uploadedBy: string uploadedAt: Date url?: string } /** * Helper to create file metadata */ export function createFileMetadata( uploadResult: UploadResult, confirmResult: ConfirmResult, fileType: FileType, uploadedBy: string ): Omit { return { filename: confirmResult.filename, originalName: uploadResult.filename, path: confirmResult.permanentPath, size: uploadResult.size, mimeType: uploadResult.type, fileType, uploadedBy, uploadedAt: new Date(uploadResult.uploadedAt), url: confirmResult.url, } }