import { createDocument, getDocument, getDocuments, transformDocument, } from "@lib/documents.ts"; import { Root } from "https://esm.sh/remark-frontmatter@4.0.1"; import { getThumbhash } from "@lib/cache/image.ts"; type Resource = { name: string; id: string; meta: { image?: string; author?: string; thumbnail?: string; }; }; export async function addThumbnailToResource( res: T, ): Promise { const imageUrl = res?.meta?.image; if (!imageUrl) return res; const thumbhash = await getThumbhash({ url: imageUrl }); if (!thumbhash) return res; const base64String = btoa(String.fromCharCode(...thumbhash)); return { ...res, meta: { ...res?.meta, thumbnail: base64String, }, }; } export function createCrud( { prefix, parse, render, hasThumbnails = false }: { prefix: string; hasThumbnails?: boolean; render?: (doc: T) => string; parse: (doc: string, id: string) => T; }, ) { function pathFromId(id: string) { return `${prefix}${id.replaceAll(":", "")}.md`; } async function read(id: string) { const path = pathFromId(id); const content = await getDocument(path); const res = parse(content, id); if (hasThumbnails) { return addThumbnailToResource(res); } return res; } function create(id: string, content: string | ArrayBuffer | T) { const path = pathFromId(id); if ( typeof content === "string" || content instanceof ArrayBuffer ) { return createDocument(path, content); } if (render) { return createDocument(path, render(content)); } throw new Error("No renderer defined for " + prefix + " CRUD"); } async function update(id: string, updater: (r: Root) => Root) { const path = pathFromId(id); const content = await getDocument(path); const newDoc = transformDocument(content, updater); await createDocument(path, newDoc); } async function readAll() { const allDocuments = await getDocuments(); return Promise.all( allDocuments.filter((d) => { return d.name.startsWith(prefix) && d.contentType === "text/markdown" && !d.name.endsWith("index.md"); }).map((doc) => { const id = doc.name.replace(prefix, "").replace(/\.md$/, ""); return read(id); }), ); } return { read, readAll, create, update, }; }