feat: add full-stack API persistence and RBAC
This commit is contained in:
63
modules/core/server/store.ts
Normal file
63
modules/core/server/store.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user