82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
|
||
|
||
// R2 configuration
|
||
const R2_ACCOUNT_ID = process.env.R2_ACCOUNT_ID || "";
|
||
const R2_ACCESS_KEY_ID = process.env.R2_ACCESS_KEY_ID || "";
|
||
const R2_SECRET_ACCESS_KEY = process.env.R2_SECRET_ACCESS_KEY || "";
|
||
const R2_BUCKET_NAME = process.env.R2_BUCKET_NAME || "";
|
||
const R2_PUBLIC_URL = process.env.R2_PUBLIC_URL || "";
|
||
|
||
// S3 client configuration for Cloudflare R2
|
||
const s3Client = new S3Client({
|
||
region: "auto",
|
||
endpoint: `https://${R2_ACCOUNT_ID}.eu.r2.cloudflarestorage.com`,
|
||
credentials: {
|
||
accessKeyId: R2_ACCESS_KEY_ID,
|
||
secretAccessKey: R2_SECRET_ACCESS_KEY,
|
||
},
|
||
});
|
||
|
||
export interface UploadOptions {
|
||
buffer: Buffer;
|
||
fileName: string;
|
||
contentType: string;
|
||
}
|
||
|
||
/**
|
||
* Upload a file to R2
|
||
*/
|
||
export async function uploadToR2(options: UploadOptions): Promise<string> {
|
||
const { buffer, fileName, contentType } = options;
|
||
|
||
try {
|
||
const command = new PutObjectCommand({
|
||
Bucket: R2_BUCKET_NAME,
|
||
Key: fileName,
|
||
Body: buffer,
|
||
ContentType: contentType,
|
||
});
|
||
|
||
await s3Client.send(command);
|
||
|
||
// Return the public URL
|
||
return `${R2_PUBLIC_URL}/${fileName}`;
|
||
} catch (error) {
|
||
console.error("R2 upload error:", error);
|
||
throw new Error(`R2'ye yükleme başarısız: ${error}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Delete a file from R2
|
||
*/
|
||
export async function deleteFromR2(fileName: string): Promise<void> {
|
||
try {
|
||
const command = new DeleteObjectCommand({
|
||
Bucket: R2_BUCKET_NAME,
|
||
Key: fileName,
|
||
});
|
||
|
||
await s3Client.send(command);
|
||
} catch (error) {
|
||
console.error("R2 delete error:", error);
|
||
throw new Error(`R2'den silme başarısız: ${error}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get content type from file extension
|
||
*/
|
||
export function getContentType(format: string): string {
|
||
const contentTypeMap: Record<string, string> = {
|
||
jpg: "image/jpeg",
|
||
jpeg: "image/jpeg",
|
||
png: "image/png",
|
||
gif: "image/gif",
|
||
webp: "image/webp",
|
||
avif: "image/avif",
|
||
};
|
||
|
||
return contentTypeMap[format] || "application/octet-stream";
|
||
}
|