import express from 'express'; import path from 'path'; import { fileURLToPath } from 'url'; import dotenv from 'dotenv'; import cors from "cors"; import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3"; // Load environment variables dotenv.config(); // Set up __dirname in ESM const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const app = express(); const port = process.env.PORT || 3000; app.use(cors()); const s3 = new S3Client({ region: "auto", endpoint: process.env.R2_ENDPOINT, credentials: { accessKeyId: process.env.R2_ACCESS_KEY, secretAccessKey: process.env.R2_SECRET_KEY, }, }); app.get("/api/list", async (req, res) => { const prefix = req.query.prefix || ""; const token = req.query.token; const search = req.query.search?.toLowerCase(); try { const response = await s3.send( new ListObjectsV2Command({ Bucket: process.env.R2_BUCKET, Prefix: prefix, ContinuationToken: token, Delimiter: "/", }) ); const filteredFolders = (response.CommonPrefixes || []).filter( (p) => !search || p.Prefix.toLowerCase().includes(search) ); const filteredFiles = (response.Contents || []) .filter((obj) => obj.Size > 0) .filter((obj) => !search || obj.Key.toLowerCase().includes(search)); res.json({ folders: filteredFolders.map((p) => p.Prefix), files: filteredFiles.map((obj) => ({ key: obj.Key, size: obj.Size, lastModified: obj.LastModified, })), nextToken: response.NextContinuationToken || null, isTruncated: response.IsTruncated || false, }); } catch (err) { console.error(err); res.status(500).json({ error: "Failed to list objects" }); } }); // === STATIC FRONTEND === app.use(express.static(path.join(__dirname, 'dist'))); // === Fallback to index.html for client-side routing === app.get('/{*splat}', (req, res) => { res.sendFile(path.join(__dirname, 'dist', 'index.html')); }); // === START SERVER === app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); });