ai-wpa/lib/file-vault.ts

153 lines
4.1 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 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
}