const fs = require("node:fs"); const path = require("node:path"); const { randomUUID } = require("node:crypto"); const EMPTY_DATABASE = { fileRecords: [], functionConfigs: [], panelInbox: [], identificationFiles: [], identificationFeedback: [], volumeConfigRequests: [], volumeConfigs: [], panelNotifications: [], userInfo: [], companies: [], productionLines: [], licenses: [] }; class JsonStore { constructor(dataDirectory) { this.dataDirectory = dataDirectory; this.filesDirectory = path.join(dataDirectory, "files"); this.modelsDirectory = path.join(dataDirectory, "models"); this.databasePath = path.join(dataDirectory, "database.json"); this.writeQueue = Promise.resolve(); } async initialize() { await fs.promises.mkdir(this.filesDirectory, { recursive: true }); try { await fs.promises.access(this.databasePath); } catch { await this.writeDatabase(structuredClone(EMPTY_DATABASE)); } } async read() { const content = await fs.promises.readFile(this.databasePath, "utf8"); return { ...structuredClone(EMPTY_DATABASE), ...JSON.parse(content) }; } async update(mutator) { const operation = this.writeQueue.then(async () => { const database = await this.read(); const result = await mutator(database); await this.writeDatabase(database); return result; }); this.writeQueue = operation.catch(() => undefined); return operation; } async writeDatabase(database) { await fs.promises.mkdir(this.dataDirectory, { recursive: true }); const temporaryPath = `${this.databasePath}.${process.pid}.tmp`; await fs.promises.writeFile( temporaryPath, `${JSON.stringify(database, null, 2)}\n`, "utf8" ); await fs.promises.rename(temporaryPath, this.databasePath); } createId(prefix) { return `${prefix}_${randomUUID()}`; } resolveStoredFile(fileID) { if (typeof fileID !== "string") return null; const isModel = fileID.startsWith("model://"); if (!isModel && !fileID.startsWith("local://")) return null; const rootDirectory = isModel ? this.modelsDirectory : this.filesDirectory; const relativePath = fileID.slice(isModel ? "model://".length : "local://".length).replace(/\\/g, "/"); const absolutePath = path.resolve(rootDirectory, relativePath); const relativeToRoot = path.relative(rootDirectory, absolutePath); if (relativeToRoot.startsWith("..") || path.isAbsolute(relativeToRoot)) return null; return absolutePath; } } module.exports = { EMPTY_DATABASE, JsonStore };