const express = require("express"); const path = require("path"); const app = express(); const PORT = process.env.PORT || 8082; const MEDIA_API_BASE_URL = process.env.MEDIA_API_BASE_URL || "http://media-access-api:8081"; const CORS_ALLOWED_ORIGIN = process.env.CORS_ALLOWED_ORIGIN || "*"; app.use(express.json({ limit: "1mb" })); app.use((req, res, next) => { res.setHeader("Access-Control-Allow-Origin", CORS_ALLOWED_ORIGIN); res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS"); res.setHeader("Access-Control-Allow-Headers", "Authorization,Content-Type"); if (req.method === "OPTIONS") { return res.sendStatus(204); } return next(); }); app.use(express.static(path.join(__dirname, "public"))); app.get("/health", (_req, res) => { res.json({ status: "ok", service: "viewer-bff", mediaApiBaseUrl: MEDIA_API_BASE_URL }); }); function getBearerToken(req) { const authHeader = req.headers.authorization || ""; if (!authHeader.startsWith("Bearer ")) { return null; } return authHeader.slice("Bearer ".length).trim(); } async function proxyJson(req, res, targetPath, method = "GET", body) { const token = getBearerToken(req); if (!token) { return res.status(401).json({ error: "missing_token", message: "Header Authorization Bearer requis" }); } try { const response = await fetch(`${MEDIA_API_BASE_URL}${targetPath}`, { method, headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }, body: body ? JSON.stringify(body) : undefined }); const text = await response.text(); let payload = {}; if (text) { try { payload = JSON.parse(text); } catch (_err) { payload = { raw: text }; } } if (!response.ok) { return res.status(response.status).json({ error: "media_api_error", status: response.status, message: payload.message || "Erreur retour media-access-api", details: payload }); } return res.status(response.status).json(payload); } catch (error) { return res.status(502).json({ error: "media_api_unreachable", message: "Impossible de joindre media-access-api", details: error.message }); } } app.get("/api/me/permissions", async (req, res) => { return proxyJson(req, res, "/v1/permissions", "GET"); }); app.post("/api/media/presign", async (req, res) => { const objectKey = req.body?.objectKey; if (!objectKey || typeof objectKey !== "string") { return res.status(400).json({ error: "invalid_payload", message: "Champ objectKey requis" }); } return proxyJson(req, res, "/v1/presign", "POST", { objectKey }); }); app.get("*", (req, res) => { if (req.path.startsWith("/api/")) { return res.status(404).json({ error: "not_found" }); } return res.sendFile(path.join(__dirname, "public", "index.html")); }); app.listen(PORT, () => { // eslint-disable-next-line no-console console.log(`viewer-bff listening on port ${PORT}`); });