/** * Storage service for S3 file uploads via pre-signed URLs */ import { getApiV1Url } from "./config"; // API_URL getter - uses runtime config interface UploadUrlResponse { uploadUrl: string; key: string; publicUrl: string; expiresIn: number; } interface DownloadUrlResponse { downloadUrl: string; expiresIn: number; } /** * Get a pre-signed URL for uploading a file */ export async function getUploadUrl( filename: string, contentType: string, folder: 'logos' | 'resumes' | 'documents' | 'avatars' = 'documents' ): Promise { const response = await fetch(`${getApiV1Url()}/storage/upload-url`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', // Use httpOnly cookie body: JSON.stringify({ filename, contentType, folder, }), }); if (!response.ok) { const error = await response.text(); throw new Error(`Failed to get upload URL: ${error}`); } return response.json(); } /** * Upload a file directly to S3 using a pre-signed URL */ export async function uploadFileToS3( file: File, uploadUrl: string ): Promise { const response = await fetch(uploadUrl, { method: 'PUT', headers: { 'Content-Type': file.type, }, body: file, }); if (!response.ok) { throw new Error(`Failed to upload file: ${response.statusText}`); } } /** * Get a pre-signed URL for downloading a file */ export async function getDownloadUrl(key: string): Promise { const response = await fetch(`${getApiV1Url()}/storage/download-url`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', // Use httpOnly cookie body: JSON.stringify({ key }), }); if (!response.ok) { const error = await response.text(); throw new Error(`Failed to get download URL: ${error}`); } return response.json(); } /** * Complete file upload workflow: get pre-signed URL and upload file * Returns the public URL of the uploaded file */ export async function uploadFile( file: File, folder: 'logos' | 'resumes' | 'documents' | 'avatars' = 'documents' ): Promise<{ key: string; publicUrl: string }> { // Step 1: Get pre-signed upload URL from backend const { uploadUrl, key, publicUrl } = await getUploadUrl( file.name, file.type, folder ); // Step 2: Upload file directly to S3 await uploadFileToS3(file, uploadUrl); return { key, publicUrl }; } /** * Delete a file from storage */ export async function deleteFile(key: string): Promise { const response = await fetch(`${getApiV1Url()}/storage/files?key=${encodeURIComponent(key)}`, { method: 'DELETE', credentials: 'include', // Use httpOnly cookie }); if (!response.ok) { const error = await response.text(); throw new Error(`Failed to delete file: ${error}`); } }