Files
teatea-pension/modules/core/server/store.ts

64 lines
1.7 KiB
TypeScript

import { promises as fs } from "node:fs";
import path from "node:path";
import type { AppData } from "@/modules/core/types";
const DATA_DIR = process.env.TEATEA_DATA_DIR ?? path.join(process.cwd(), ".data");
const DATA_FILE = path.join(DATA_DIR, "teatea.json");
function createEmptyData(): AppData {
return {
accounts: [],
sessions: [],
elders: [],
auditLogs: [],
};
}
function normalizeData(data: Partial<AppData>): AppData {
return {
accounts: Array.isArray(data.accounts) ? data.accounts : [],
sessions: Array.isArray(data.sessions) ? data.sessions : [],
elders: Array.isArray(data.elders) ? data.elders : [],
auditLogs: Array.isArray(data.auditLogs) ? data.auditLogs : [],
};
}
function isMissingFileError(error: unknown): boolean {
return (
typeof error === "object" &&
error !== null &&
"code" in error &&
(error as { code?: unknown }).code === "ENOENT"
);
}
export async function readData(): Promise<AppData> {
try {
const raw = await fs.readFile(DATA_FILE, "utf8");
const parsed = JSON.parse(raw) as Partial<AppData>;
return normalizeData(parsed);
} catch (error) {
if (isMissingFileError(error)) {
return createEmptyData();
}
throw error;
}
}
export async function writeData(data: AppData): Promise<void> {
await fs.mkdir(DATA_DIR, { recursive: true });
const temporaryFile = `${DATA_FILE}.tmp`;
await fs.writeFile(temporaryFile, JSON.stringify(data, null, 2), "utf8");
await fs.rename(temporaryFile, DATA_FILE);
}
export async function updateData<T>(mutator: (data: AppData) => T): Promise<T> {
const data = await readData();
const result = mutator(data);
await writeData(data);
return result;
}