initial commit
This commit is contained in:
152
lib/file-vault.ts
Normal file
152
lib/file-vault.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* File upload service using external API
|
||||
* Replaces MINIO with custom file upload API
|
||||
*/
|
||||
|
||||
import { env } from './env'
|
||||
|
||||
// File upload result from the API
|
||||
export interface FileUploadResponse {
|
||||
success: boolean
|
||||
url: string
|
||||
filename: string
|
||||
}
|
||||
|
||||
// File upload result for internal use
|
||||
export interface UploadResult {
|
||||
url: string
|
||||
filename: string
|
||||
originalName: string
|
||||
size: number
|
||||
type: string
|
||||
uploadedAt: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file to external API
|
||||
*/
|
||||
export async function uploadFile(
|
||||
buffer: Buffer,
|
||||
filename: string,
|
||||
contentType: string,
|
||||
userId?: string
|
||||
): Promise<UploadResult> {
|
||||
console.log('📤 Starting file upload:', { filename, contentType, bufferSize: buffer.length })
|
||||
|
||||
try {
|
||||
// Create FormData for multipart upload
|
||||
const formData = new FormData()
|
||||
const blob = new Blob([buffer], { type: contentType })
|
||||
formData.append('file', blob, filename)
|
||||
|
||||
// Prepare headers
|
||||
const headers: Record<string, string> = {
|
||||
'x-user-data': userId || 'default-user',
|
||||
Authorization: `Bearer ${env.FILE_UPLOAD_TOKEN || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlRlc3QgVXNlciIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'}`,
|
||||
}
|
||||
|
||||
console.log('📤 Uploading to external API:', {
|
||||
url: process.env.UPLOAD_API_URL,
|
||||
filename,
|
||||
size: buffer.length,
|
||||
userId: userId || 'default-user',
|
||||
})
|
||||
|
||||
// Make the upload request
|
||||
const response = await fetch(process.env.UPLOAD_API_URL, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: formData,
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Upload failed: ${response.status} ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
const result: FileUploadResponse = await response.json()
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error('Upload API returned success: false')
|
||||
}
|
||||
|
||||
console.log('✅ File uploaded successfully:', result)
|
||||
|
||||
return {
|
||||
url: result.url,
|
||||
filename: result.filename,
|
||||
originalName: filename,
|
||||
size: buffer.length,
|
||||
type: contentType,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error uploading file:', error)
|
||||
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}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file URL (files are already publicly accessible)
|
||||
*/
|
||||
export async function getFileUrl(filePath: string): Promise<string> {
|
||||
// Files from the upload API are already publicly accessible
|
||||
// If filePath is already a full URL, return it as is
|
||||
if (filePath.startsWith('http')) {
|
||||
return filePath
|
||||
}
|
||||
|
||||
// Otherwise, construct the URL using the delivery base URL
|
||||
return `${process.env.DELIVERY_BASE_URL}/${filePath}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete file (not supported by the current API)
|
||||
*/
|
||||
export async function deleteFile(filePath: string): Promise<void> {
|
||||
console.warn('⚠️ File deletion not supported by current upload API:', filePath)
|
||||
// The external API doesn't provide a delete endpoint
|
||||
// This is a no-op for now
|
||||
}
|
||||
|
||||
/**
|
||||
* Move file to permanent storage (not needed with new API)
|
||||
*/
|
||||
export async function moveToPermStorage(tempPath: string, permanentPath: string): Promise<void> {
|
||||
console.log('ℹ️ Move to permanent storage not needed with new API')
|
||||
// The new API directly uploads to permanent storage
|
||||
// This is a no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize bucket (not needed with new API)
|
||||
*/
|
||||
export async function initializeBucket(): Promise<void> {
|
||||
console.log('ℹ️ Bucket initialization not needed with new API')
|
||||
// The new API handles storage internally
|
||||
// This is a no-op
|
||||
}
|
||||
Reference in New Issue
Block a user