first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:11:03 +03:00
commit 031582ea2c
98 changed files with 13281 additions and 0 deletions

81
app/lib/r2-storage.ts Normal file
View File

@@ -0,0 +1,81 @@
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";
}