"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.REACTION_EMOJIS = void 0; exports.addPost = addPost; exports.listPostsByAuthor = listPostsByAuthor; exports.listFeed = listFeed; exports.getPost = getPost; exports.softDeletePost = softDeletePost; exports.editPost = editPost; exports.addComment = addComment; exports.toggleReaction = toggleReaction; exports.deleteComment = deleteComment; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const secureStore_1 = require("./secureStore"); exports.REACTION_EMOJIS = ["like", "love", "haha", "wow", "sad", "angry"]; const LOCAL_DIR = path_1.default.join(__dirname, "../../local-db"); const DATA_DIR = path_1.default.join(LOCAL_DIR, "posts"); const FILE = path_1.default.join(DATA_DIR, "posts.enc"); const LEGACY = path_1.default.join(LOCAL_DIR, "posts.json"); const RING_LIMIT = 5000; const FLUSH_MS = 5000; let buffer = []; let loaded = false; let dirty = false; let secure = null; function getSecure() { if (!secure) { fs_1.default.mkdirSync(LOCAL_DIR, { recursive: true }); secure = new secureStore_1.SecureStore(LOCAL_DIR); } return secure; } function persistNow() { try { fs_1.default.mkdirSync(DATA_DIR, { recursive: true }); getSecure().encryptToFile(JSON.stringify(buffer.slice(-RING_LIMIT)), FILE); } catch (e) { console.warn("[postsStore] persist failed:", e?.message); } } function ensureLoaded() { if (loaded) return; loaded = true; try { fs_1.default.mkdirSync(DATA_DIR, { recursive: true }); // One-time migration from legacy posts.json if (fs_1.default.existsSync(LEGACY) && !fs_1.default.existsSync(FILE)) { try { const arr = JSON.parse(fs_1.default.readFileSync(LEGACY, "utf-8")); if (Array.isArray(arr)) buffer = arr.slice(-RING_LIMIT); persistNow(); fs_1.default.unlinkSync(LEGACY); console.log(`[postsStore] migrated posts.json → posts/posts.enc (${buffer.length} posts)`); return; } catch (e) { console.warn("[postsStore] migration failed:", e?.message); } } if (fs_1.default.existsSync(FILE)) { const json = getSecure().decryptFromFile(FILE); const arr = JSON.parse(json); if (Array.isArray(arr)) buffer = arr.slice(-RING_LIMIT); } } catch (e) { console.warn("[postsStore] load failed:", e?.message); } } // Eagerly migrate / load at module startup so the posts/ dir exists before // the first addPost or listFeed call. ensureLoaded(); function persistSoon() { dirty = true; } setInterval(() => { if (!dirty) return; dirty = false; persistNow(); }, FLUSH_MS).unref?.(); function addPost(p) { ensureLoaded(); buffer.push(p); if (buffer.length > RING_LIMIT) buffer = buffer.slice(-RING_LIMIT); persistSoon(); } function listPostsByAuthor(author, limit = 50) { ensureLoaded(); return buffer.filter(p => p.author === author && !p.deleted).slice(-limit).reverse(); } function listFeed(limit = 60) { ensureLoaded(); return buffer.filter(p => !p.deleted).slice(-limit).reverse(); } function getPost(id) { ensureLoaded(); return buffer.find(p => p.id === id); } function softDeletePost(id) { ensureLoaded(); const p = buffer.find(x => x.id === id); if (!p || p.deleted) return false; p.deleted = true; p.text = ""; persistSoon(); return true; } function editPost(id, newText) { ensureLoaded(); const p = buffer.find(x => x.id === id); if (!p || p.deleted) return false; p.text = String(newText).slice(0, 500); persistSoon(); return true; } function addComment(postId, c) { ensureLoaded(); const p = buffer.find(x => x.id === postId); if (!p || p.deleted) return false; p.comments.push(c); if (p.comments.length > 500) p.comments = p.comments.slice(-500); persistSoon(); return true; } function toggleReaction(postId, emoji, username) { ensureLoaded(); const p = buffer.find(x => x.id === postId); if (!p || p.deleted) return null; if (!p.reactions) p.reactions = {}; let prev = null; for (const k of Object.keys(p.reactions)) { const arr = p.reactions[k]; const i = arr.indexOf(username); if (i >= 0) { prev = k; arr.splice(i, 1); if (arr.length === 0) delete p.reactions[k]; } } if (prev !== emoji) { if (!p.reactions[emoji]) p.reactions[emoji] = []; p.reactions[emoji].push(username); } persistSoon(); const mine = prev === emoji ? null : emoji; return { reactions: p.reactions, mine }; } function deleteComment(postId, commentId) { ensureLoaded(); const p = buffer.find(x => x.id === postId); if (!p) return false; const c = p.comments.find(x => x.id === commentId); if (!c || c.deleted) return false; c.deleted = true; c.text = ""; persistSoon(); return true; }