import os from "node:os"; import path from "node:path"; import fs from "fs-extra"; import type { TNamespaceStat, TSmartCacheEntry } from "./smart-cache.types"; const CACHE_DIRECTORY = path.join(os.homedir(), ".simplemdg", "cache"); type TNamespaceFile = Record>; function namespaceFilePath(namespace: string): string { return path.join(CACHE_DIRECTORY, `${namespace}.json`); } export function getCacheDirectory(): string { return CACHE_DIRECTORY; } async function readNamespaceFile(namespace: string): Promise { const filePath = namespaceFilePath(namespace); if (!(await fs.pathExists(filePath))) { return {}; } const parsed = await fs.readJson(filePath).catch(() => ({})) as TNamespaceFile; return parsed && typeof parsed === "object" ? parsed : {}; } async function writeNamespaceFile(namespace: string, file: TNamespaceFile): Promise { await fs.ensureDir(CACHE_DIRECTORY); await fs.writeJson(namespaceFilePath(namespace), file, { spaces: 2 }); } export async function readEntry(namespace: string, key: string): Promise | undefined> { const file = await readNamespaceFile(namespace); return file[key] as TSmartCacheEntry | undefined; } export async function readAllEntries(namespace: string): Promise>> { return await readNamespaceFile(namespace) as Record>; } export async function writeEntry(namespace: string, key: string, entry: TSmartCacheEntry): Promise { const file = await readNamespaceFile(namespace); file[key] = entry as TSmartCacheEntry; await writeNamespaceFile(namespace, file); } export async function removeEntry(namespace: string, key: string): Promise { const file = await readNamespaceFile(namespace); if (!(key in file)) { return false; } delete file[key]; await writeNamespaceFile(namespace, file); return true; } export async function clearNamespace(namespace: string): Promise { await fs.remove(namespaceFilePath(namespace)).catch(() => undefined); } export async function statNamespace(namespace: string): Promise { const filePath = namespaceFilePath(namespace); if (!(await fs.pathExists(filePath))) { return { namespace, count: 0, exists: false }; } const file = await readNamespaceFile(namespace); const entries = Object.values(file); let lastUpdatedAt: string | undefined; for (const entry of entries) { if (!lastUpdatedAt || entry.updatedAt > lastUpdatedAt) { lastUpdatedAt = entry.updatedAt; } } return { namespace, count: entries.length, lastUpdatedAt, exists: true }; }