unloze-wrapper/server.js
2025-05-18 19:45:30 -04:00

79 lines
2.1 KiB
JavaScript

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}`);
});