import type { GenerateConfig } from "@/lib/card-gen/id-config"; import { savePreset, type CardPreset } from "@/lib/card-gen/local-store"; export type ServerPresetMeta = { id: string; name: string; config: GenerateConfig; imageName: string; hasImage: boolean; fontName: string | null; hasFont: boolean; createdAt: number; updatedAt: number; }; async function readError(res: Response): Promise { const body = (await res.json().catch(() => null)) as { error?: string } | null; return body?.error || `Request failed (${res.status})`; } export async function fetchServerPresetList(): Promise { const res = await fetch("/api/founders-card/presets", { cache: "no-store" }); if (!res.ok) throw new Error(await readError(res)); const body = (await res.json()) as { presets?: ServerPresetMeta[] }; return Array.isArray(body.presets) ? body.presets : []; } async function fileFromEndpoint( url: string, fallbackName: string, ): Promise { const res = await fetch(url, { cache: "no-store" }); if (!res.ok) return null; const blob = await res.blob(); if (blob.size === 0) return null; const name = /filename="([^"]+)"/i.exec(res.headers.get("content-disposition") ?? "")?.[1] ?? fallbackName; return new File([blob], name, { type: blob.type || "application/octet-stream", }); } export async function fetchServerPresets(): Promise { const list = await fetchServerPresetList(); const out: CardPreset[] = []; for (const meta of list) { const image = meta.hasImage ? await fileFromEndpoint( `/api/founders-card/presets/${meta.id}/image`, meta.imageName || "base.png", ) : null; const font = meta.hasFont ? await fileFromEndpoint( `/api/founders-card/presets/${meta.id}/font`, meta.fontName || "custom.ttf", ) : null; out.push({ id: meta.id, name: meta.name, config: meta.config, image, font, createdAt: meta.createdAt, updatedAt: meta.updatedAt, }); } return out; } export async function pushPresetToServer(input: { id?: string; name: string; config: GenerateConfig; image: File | null; font: File | null; }): Promise { const fd = new FormData(); fd.append("name", input.name); fd.append("config", JSON.stringify(input.config)); if (input.id) fd.append("id", input.id); if (input.image) fd.append("image", input.image); if (input.font) fd.append("font", input.font); if (!input.font) fd.append("clearFont", "1"); const res = await fetch("/api/founders-card/presets", { method: "POST", body: fd, }); if (!res.ok) throw new Error(await readError(res)); return (await res.json()) as ServerPresetMeta; } export async function deleteServerPreset(id: string): Promise { const res = await fetch(`/api/founders-card/presets/${id}`, { method: "DELETE", }); if (!res.ok && res.status !== 404) throw new Error(await readError(res)); } export async function cacheServerPresetsLocally( presets: CardPreset[], ): Promise { for (const preset of presets) { await savePreset({ id: preset.id, name: preset.name, config: preset.config, image: preset.image, font: preset.font, }); } }