Spaces:
Running
Running
| ; | |
| 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; | |
| } | |