UNPKG

@maxlkatze/cms

Version:

A git based Nuxt Module CMS - zero effort, zero cost

176 lines (175 loc) 5.3 kB
import fs from "node:fs/promises"; import path from "node:path"; import { createStorage } from "unstorage"; import fsDriver from "unstorage/drivers/fs"; import { useAuthentication } from "../../client/composables/cms/useAuthentication.js"; import { useContentStorage } from "../../storage/ContentStorage.js"; import { defineEventHandler, readBody, useRuntimeConfig, createError } from "#imports"; export default defineEventHandler(async (event) => { try { const body = await readBody(event) || {}; const { token, action, content } = body; await verifyAuth(event, token); switch (action) { case "save": return await handleSaveContent(event, content); case "imageList": return await handleImageList(); case "deploy": return await handleDeploy(); default: return createError({ statusCode: 400, statusMessage: "Invalid action" }); } } catch (error) { return { success: false, body: { message: error || "An error occurred" } }; } }); async function verifyAuth(event, token) { if (!token) { throw createError({ statusCode: 401, statusMessage: "No token provided" }); } const runtimeConfig = useRuntimeConfig(); const authentication = useAuthentication(); const isValid = await authentication.verifyToken(token, runtimeConfig.secret || ""); if (!isValid) { throw createError({ statusCode: 401, statusMessage: "Invalid token" }); } } async function handleSaveContent(event, content) { if (!content || Object.keys(content).length === 0) { throw createError({ statusCode: 400, statusMessage: "No content provided" }); } const runtimeConfig = useRuntimeConfig(); const storage = await useContentStorage(runtimeConfig); let savedContent = await storage.getItem(runtimeConfig.storageKey); savedContent = { ...savedContent, ...content }; await storage.setItem(runtimeConfig.storageKey, savedContent); if (runtimeConfig.storage.type === "fs") { console.log("\x1B[42m\x1B[30m Katze \x1B[0m Restarting Nuxt..."); try { await triggerNuxtRestart(); } catch (error) { console.warn("Could not trigger Nuxt restart:", error); } } return { success: true, body: { message: "Content saved" } }; } async function handleImageList() { const runtimeConfig = useRuntimeConfig(); const extensions = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"]; const localStorage = createStorage({ driver: fsDriver({ base: `${runtimeConfig.projectLocation}/public/` }) }); const imageStorage = createStorage({ driver: fsDriver({ base: `${runtimeConfig.projectLocation}/images/` }) }); const imageKeys = await localStorage.getKeys("", {}); const imageKeys2 = await imageStorage.getKeys("", {}); const mergedKeys = [...imageKeys, ...imageKeys2]; const filteredImages = mergedKeys.filter((key) => extensions.some((ext) => key.toLowerCase().endsWith(ext))).map((key) => `/${key.replace(/:/g, "/")}`); return { success: true, body: { message: "Images fetched", images: filteredImages } }; } async function handleDeploy() { const runtimeConfig = useRuntimeConfig(); const deployHookURL = runtimeConfig.deployHookURL; if (!deployHookURL) { return { success: false, missingDeployHookURL: true, body: { message: "No deploy hook URL provided" } }; } try { const response = await fetch(deployHookURL, { method: "GET" }); if (!response.ok) { throw new Error(`Deploy failed with status: ${response.status}`); } return { success: true, body: { message: "Content deployed successfully" } }; } catch (error) { return { success: false, body: { message: `Deploy failed: ${error}` } }; } } async function triggerNuxtRestart() { const projectRoot = process.cwd(); const restartFilePath = path.join(projectRoot, ".nuxt", "restart.mjs"); try { try { await fs.access(restartFilePath); const now = /* @__PURE__ */ new Date(); await fs.utimes(restartFilePath, now, now); } catch { const restartContent = ` // This file is used to trigger Nuxt restart // Updated: ${(/* @__PURE__ */ new Date()).toISOString()} export default {} `; await fs.writeFile(restartFilePath, restartContent, "utf-8"); } try { const configFiles = [ path.join(projectRoot, "nuxt.config.js"), path.join(projectRoot, "nuxt.config.mjs"), path.join(projectRoot, "nuxt.config.ts"), path.join(projectRoot, "playground", "nuxt.config.ts") ]; for (const configFile of configFiles) { try { await fs.access(configFile); const now = /* @__PURE__ */ new Date(); await fs.utimes(configFile, now, now); console.log("\x1B[42m\x1B[30m Katze \x1B[0m Touched configuration file:", configFile); break; } catch { } } } catch (error) { console.warn("Could not touch nuxt.config file:", error); } return true; } catch (error) { console.error("Failed to trigger Nuxt restart:", error); return false; } }