Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 2m55s
Build & Deploy / 🏗️ Build (push) Successful in 11m40s
Build & Deploy / 🚀 Deploy (push) Failing after 8s
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
87 lines
2.9 KiB
TypeScript
87 lines
2.9 KiB
TypeScript
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
import * as fs from "fs";
|
|
import * as path from "path";
|
|
|
|
const S3_ENDPOINT = process.env.S3_ENDPOINT;
|
|
const S3_REGION = process.env.S3_REGION || "fsn1";
|
|
const S3_BUCKET = process.env.S3_BUCKET;
|
|
const S3_PREFIX = process.env.S3_PREFIX;
|
|
const S3_ACCESS_KEY = process.env.S3_ACCESS_KEY;
|
|
const S3_SECRET_KEY = process.env.S3_SECRET_KEY;
|
|
|
|
if (!S3_ENDPOINT || !S3_BUCKET || !S3_ACCESS_KEY || !S3_SECRET_KEY) {
|
|
console.error("Missing S3 credentials in environment");
|
|
process.exit(1);
|
|
}
|
|
|
|
const s3Client = new S3Client({
|
|
region: S3_REGION,
|
|
endpoint: S3_ENDPOINT,
|
|
credentials: {
|
|
accessKeyId: S3_ACCESS_KEY,
|
|
secretAccessKey: S3_SECRET_KEY,
|
|
},
|
|
forcePathStyle: true,
|
|
});
|
|
|
|
async function uploadDirectory(dirPath: string, prefix: string) {
|
|
const files = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
|
|
for (const file of files) {
|
|
if (file.name === ".DS_Store" || file.name === ".gitkeep") continue;
|
|
|
|
const fullPath = path.join(dirPath, file.name);
|
|
// Combine prefix with filename, ensuring no double slashes, e.g., mb-grid-solutions/media/filename.ext
|
|
const s3Key = `${prefix}/${file.name}`.replace(/\/+/g, "/");
|
|
|
|
if (file.isDirectory()) {
|
|
await uploadDirectory(fullPath, s3Key);
|
|
} else {
|
|
const fileContent = fs.readFileSync(fullPath);
|
|
let contentType = "application/octet-stream";
|
|
if (file.name.endsWith(".png")) contentType = "image/png";
|
|
else if (file.name.endsWith(".jpg") || file.name.endsWith(".jpeg"))
|
|
contentType = "image/jpeg";
|
|
else if (file.name.endsWith(".svg")) contentType = "image/svg+xml";
|
|
else if (file.name.endsWith(".webp")) contentType = "image/webp";
|
|
else if (file.name.endsWith(".pdf")) contentType = "application/pdf";
|
|
|
|
try {
|
|
await s3Client.send(
|
|
new PutObjectCommand({
|
|
Bucket: S3_BUCKET,
|
|
Key: s3Key,
|
|
Body: fileContent,
|
|
ContentType: contentType,
|
|
ACL: "public-read", // Hetzner requires public-read for public access usually
|
|
}),
|
|
);
|
|
console.log(`✅ Uploaded ${file.name} to ${S3_BUCKET}/${s3Key}`);
|
|
} catch (err) {
|
|
console.error(`❌ Failed to upload ${file.name}:`, err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const mediaDir = path.resolve(process.cwd(), "public/media");
|
|
if (fs.existsSync(mediaDir)) {
|
|
console.log("Uploading public/media...");
|
|
// Media inside Payload CMS uses prefix/media usually, like mb-grid-solutions/media
|
|
await uploadDirectory(mediaDir, `${S3_PREFIX}/media`);
|
|
} else {
|
|
console.log("No public/media directory found.");
|
|
}
|
|
|
|
const assetsDir = path.resolve(process.cwd(), "public/assets");
|
|
if (fs.existsSync(assetsDir)) {
|
|
console.log("Uploading public/assets...");
|
|
await uploadDirectory(assetsDir, `${S3_PREFIX}/assets`);
|
|
} else {
|
|
console.log("No public/assets directory found.");
|
|
}
|
|
}
|
|
|
|
main().catch(console.error);
|