const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3") function createR2Client() { const endpoint = process.env.R2_ENDPOINT const accessKeyId = process.env.R2_ACCESS_KEY_ID const secretAccessKey = process.env.R2_SECRET_ACCESS_KEY if (!endpoint || !accessKeyId || !secretAccessKey) { throw new Error("R2 config missing (R2_ENDPOINT/R2_ACCESS_KEY_ID/R2_SECRET_ACCESS_KEY)") } return new S3Client({ region: process.env.R2_REGION || "auto", endpoint, credentials: { accessKeyId, secretAccessKey }, }) } let r2Client = null function getR2Client() { if (!r2Client) r2Client = createR2Client() return r2Client } function encodeObjectKey(key) { return String(key) .split("/") .map((part) => encodeURIComponent(part)) .join("/") } function toStoredPath(key) { const normalized = String(key || "").replace(/^\/+/, "") return `/${encodeObjectKey(normalized)}` } async function uploadImage({ bucket, path, fileBuffer, contentType }) { if (!path || !fileBuffer) throw new Error("uploadImage params missing") const targetBucket = bucket || process.env.R2_BUCKET_NAME if (!targetBucket) throw new Error("R2 bucket missing (R2_BUCKET_NAME)") const r2 = getR2Client() await r2.send( new PutObjectCommand({ Bucket: targetBucket, Key: path, Body: fileBuffer, ContentType: contentType || "image/webp", }) ) return toStoredPath(path) } module.exports = { uploadImage }