import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; // Initialize S3 client const s3Client = new S3Client({ region: process.env.AWS_REGION || 'ir-thr-at1', endpoint: process.env.AWS_S3_ENDPOINT, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID || '', secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '', }, }); const BUCKET_NAME = process.env.AWS_S3_BUCKET || ''; export interface UploadFileParams { file: File; key: string; contentType?: string; makePublic?: boolean; // Set to false for private files } /** * Upload a file to S3 */ export async function uploadFileToS3(params: UploadFileParams): Promise { const { file, key, contentType, makePublic = true } = params; // Convert File to Buffer const arrayBuffer = await file.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); const command = new PutObjectCommand({ Bucket: BUCKET_NAME, Key: key, Body: buffer, ...(makePublic && { ACL: "public-read" }), // Only set ACL if makePublic is true ContentType: contentType || file.type, }); await s3Client.send(command); // Return the public URL if public, otherwise return the key if (makePublic) { return `https://${BUCKET_NAME}.s3.ir-thr-at1.arvanstorage.ir/${key}`; } else { return key; // Return just the key for private files } } /** * Delete a file from S3 */ export async function deleteFileFromS3(key: string): Promise { const command = new DeleteObjectCommand({ Bucket: BUCKET_NAME, Key: key, }); await s3Client.send(command); } /** * Generate a presigned URL for uploading */ export async function getPresignedUploadUrl(key: string, contentType: string): Promise { const command = new PutObjectCommand({ Bucket: BUCKET_NAME, Key: key, ContentType: contentType, }); const url = await getSignedUrl(s3Client, command, { expiresIn: 3600 }); // 1 hour return url; } /** * Generate a presigned URL for downloading/viewing a file * @param key - The S3 object key * @param expiresIn - Expiration time in seconds (default: 1 hour) * @returns Pre-signed URL */ export async function getPresignedUrl(key: string, expiresIn: number = 3600): Promise { const command = new GetObjectCommand({ Bucket: BUCKET_NAME, Key: key, }); const url = await getSignedUrl(s3Client, command, { expiresIn }); return url; } /** * Generate multiple presigned URLs for a list of keys * @param keys - Array of S3 object keys * @param expiresIn - Expiration time in seconds (default: 1 hour) * @returns Map of key to pre-signed URL */ export async function getMultiplePresignedUrls( keys: string[], expiresIn: number = 3600 ): Promise> { const urlPromises = keys.map(async (key) => { const url = await getPresignedUrl(key, expiresIn); return [key, url]; }); const entries = await Promise.all(urlPromises); return Object.fromEntries(entries); } /** * Generate a unique key for file uploads */ export function generateFileKey(folder: string, filename: string): string { const timestamp = Date.now(); const randomString = Math.random().toString(36).substring(2, 15); const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_'); return `${folder}/${timestamp}-${randomString}-${sanitizedFilename}`; }