import { sign } from "jsonwebtoken"; import { file } from "bun"; const getAdminApiKey = async () => { const keyPath = process.env.GHOST_ADMIN_API_KEY_PATH; if (!keyPath) { throw new Error( "Environment variable GHOST_ADMIN_API_KEY_PATH is not set.", ); } const keyFile = file(keyPath); if (!(await keyFile.exists())) { throw new Error(`Key file not found at path: ${keyPath}`); } return await keyFile.text(); }; const getEndpoint = () => { const endpoint = process.env.GHOST_URL; if (!endpoint) { throw new Error("Environment variable GHOST_URL is not set."); } return endpoint; }; const createJwt = (key: string) => { const [id, secret] = key.split(":"); if (!id || !secret) { throw new Error("Invalid API key format. Expected format: {id}:{secret}"); } return sign({}, Buffer.from(secret, "hex"), { keyid: id, algorithm: "HS256", expiresIn: "5m", audience: `/admin/`, }); }; const upload = async ( slug: string, path: string, type: string | undefined, ): Promise => { const endpoint = getEndpoint(); const fullEndpoint = `${endpoint}${slug}`; const key = await getAdminApiKey(); const token = createJwt(key); const f = Bun.file(path, { type }); const formData = new FormData(); formData.append("file", f); const response = await fetch(fullEndpoint, { method: "POST", headers: { Authorization: `Ghost ${token}`, }, body: formData, }); if (!response.ok) { throw new Error( `Failed to upload to ${fullEndpoint}: ${response.status} ${response.statusText}`, ); } return await response.json(); }; export const uploadImage = async (imagePath: string): Promise => { const slug = `/ghost/api/admin/images/upload`; return (await upload(slug, imagePath, "image/jpeg")).images[0].url; }; export const uploadFile = async (filePath: string): Promise => { const slug = `/ghost/api/admin/files/upload`; return (await upload(slug, filePath, undefined)).files[0].url; }; export const uploadPost = async (post: any): Promise => { const endpoint = getEndpoint(); const fullEndpoint = `${endpoint}/ghost/api/admin/posts`; const key = await getAdminApiKey(); const token = createJwt(key); const response = await fetch(fullEndpoint, { method: "POST", headers: { Authorization: `Ghost ${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ posts: [post], }), }); if (!response.ok) { throw new Error( `Failed to upload to ${fullEndpoint}: ${response.status} ${response.statusText}`, ); } return (await response.json()).posts[0].url; };