podzahr/lib/s3.ts
nfel 9478aa319f
main: added presigned url + favicon
Signed-off-by: nfel <nfilsaraee@gmail.com>
2026-01-01 19:06:11 +03:30

121 lines
3.4 KiB
TypeScript

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<string> {
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<void> {
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<string> {
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<string> {
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<Record<string, string>> {
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}`;
}