// services/chibisafe.service.js // // Wraps the Chibisafe REST API. // // Environment variables expected: // CHIBISAFE_BASE_URL – e.g. https://cdn.yourdomain.com // CHIBISAFE_API_KEY – your personal / service-account API key // CHIBISAFE_ALBUM_AVATARS – album UUID for avatar images // CHIBISAFE_ALBUM_VIDEOS – album UUID for videos // CHIBISAFE_ALBUM_DOCUMENTS – album UUID for documents (pdf, docx, ppt, txt…) // CHIBISAFE_ALBUM_THUMBNAILS – album UUID for video thumbnails // CHIBISAFE_ALBUM_ARCHIVED – album UUID used as the "trash" / archived album const FormData = require("form-data"); const axios = require("axios"); // ─── Config ─────────────────────────────────────────────────────────────────── const BASE_URL = (process.env.CHIBISAFE_BASE_URL || "").replace(/\/$/, ""); const API_KEY = process.env.CHIBISAFE_API_KEY || ""; const ALBUMS = { avatars: process.env.CHIBISAFE_ALBUM_AVATARS || null, videos: process.env.CHIBISAFE_ALBUM_VIDEOS || null, documents: process.env.CHIBISAFE_ALBUM_DOCUMENTS || null, thumbnails: process.env.CHIBISAFE_ALBUM_THUMBNAILS || null, images: process.env.CHIBISAFE_ALBUM_IMAGES || null, // ← new archived: process.env.CHIBISAFE_ALBUM_ARCHIVED || null, }; // ─── Internal helpers ───────────────────────────────────────────────────────── function resolveAlbumUuid(ownerType = "") { switch (ownerType) { case "avatar": return ALBUMS.avatars; case "video": return ALBUMS.videos; case "document": return ALBUMS.documents; case "thumbnail": return ALBUMS.thumbnails; case "image": return ALBUMS.images; default: return null; } } function baseHeaders(extra = {}) { return { "x-api-key": API_KEY, ...extra, }; } // ─── Axios instance ─────────────────────────────────────────────────────────── const chibi = axios.create({ baseURL: BASE_URL, maxBodyLength: Infinity, // ← required for large file uploads maxContentLength: Infinity, }); /** * Thin axios wrapper that throws a descriptive error on non-2xx. */ async function chibiRequest(path, { method = "GET", headers = {}, data } = {}) { try { const res = await chibi.request({ url: path, method, headers, data, }); return res.data; } catch (err) { const status = err.response?.status; const body = err.response?.data ?? {}; const msg = body?.message || body?.error || err.message; const friendly = new Error(`[Chibisafe] ${status ?? "?"} – ${msg}`); friendly.status = status; friendly.chibiBody = body; throw friendly; } } // ─── Public API ─────────────────────────────────────────────────────────────── /** * Upload a file to Chibisafe, optionally straight into a typed album. */ async function uploadFile({ buffer, originalname, mimetype, ownerType = "" }) { if (!BASE_URL || !API_KEY) { throw new Error("[Chibisafe] CHIBISAFE_BASE_URL or CHIBISAFE_API_KEY is not configured."); } const albumUuid = resolveAlbumUuid(ownerType); const form = new FormData(); form.append("file", buffer, { filename: originalname, contentType: mimetype, }); const data = await chibiRequest("/api/upload", { method: "POST", headers: { ...baseHeaders(), ...form.getHeaders(), // ← axios needs these ...(albumUuid ? { albumuuid: albumUuid } : {}), }, data: form, }); return { uuid: data.uuid, url: data.url, name: data.name, }; } /** * Permanently delete one file from Chibisafe by its UUID. */ async function deleteFile(uuid) { await chibiRequest(`/api/file/${uuid}`, { method: "DELETE", headers: baseHeaders(), }); } /** * Move one or more files into the "archived" album. */ async function archiveFiles(uuids) { if (!ALBUMS.archived) { throw new Error("[Chibisafe] CHIBISAFE_ALBUM_ARCHIVED is not configured."); } const ids = Array.isArray(uuids) ? uuids : [uuids]; if (!ids.length) return; await chibiRequest("/api/files/album/add", { method: "POST", headers: { ...baseHeaders(), "Content-Type": "application/json", }, data: { files: ids, albumUuid: ALBUMS.archived, }, }); } /** * Move one or more files into a specific album by UUID. */ async function addFilesToAlbum(uuids, albumUuid) { const ids = Array.isArray(uuids) ? uuids : [uuids]; await chibiRequest("/api/files/album/add", { method: "POST", headers: { ...baseHeaders(), "Content-Type": "application/json", }, data: { files: ids, albumUuid, }, }); } module.exports = { uploadFile, deleteFile, archiveFiles, addFilesToAlbum, ALBUMS, resolveAlbumUuid, };