// autocomplete.ts let _usermapCache: Record | null = null; function getUsermapCache(): Record { if (!_usermapCache) { try { _usermapCache = JSON.parse(fs.readFileSync(Paths.data("usermap.json"), "utf8")); } catch { _usermapCache = {}; } } return _usermapCache!; } // interactions.ts const chars = JSON.parse( fs.readFileSync(path.join(__dirname, "../../data/characters.json"), "utf8") ); // subcommands/switch.ts function findSharedChar(userKey: string, charName: string): { ownerKey: string; char: any } | null { try { const chars = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8")); for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) { if (ownerKey === userKey) continue; const char = data.characters?.find( (c: any) => c.name.toLowerCase() === charName.toLowerCase() && c.sharedWith?.includes(userKey) ); if (char) return { ownerKey, char }; } } catch {} return null; } // subcommands.admin.ts (userMap) if (sub === "map") { const target = interaction.options.getUser("user", true); const userKey = interaction.options.getString("userkey", true); // Check if userKey exists in characters.json const fs = require("fs"); const path = require("path"); const chars = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../data/characters.json"), "utf8")); if (!chars[userKey]) { return void replyAndDelete(interaction, `❌ No characters found for userKey **${userKey}**. Make sure it exists in characters.json first.`, true); } // Check if this Discord ID is already mapped const existing = getUsermapEntryById(target.id, target.username); const entry = existing ?? { file: userKey, aliases: [target.globalName ?? target.username] }; entry.file = userKey; setUsermapEntry(target.id, entry); return void replyAndDelete(interaction, `✅ Mapped **${target.username}** (${target.id}) → **${userKey}**`, true); } const raw = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../data/usermap.json"), "utf8")); // subcommands/char (looks a lot like the previous one, maybe extract?) function findSharedChar(userKey: string, charName: string): { ownerKey: string; charName: string } | null { try { const chars = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8")); for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) { if (ownerKey === userKey) continue; const char = data.characters?.find( (c: any) => c.name.toLowerCase() === charName.toLowerCase() && c.sharedWith?.includes(userKey) ); if (char) return { ownerKey, charName: char.name }; } } catch {} return null; } // subcommands/share.ts function loadRawChars(): any { return JSON.parse(fs.readFileSync(CHARS_PATH, "utf8")); } // subcommands/poll/seed.ts usermap = JSON.parse(fs.readFileSync(path.join(__dirname, "../../../data/usermap.json"), "utf8")); // attendance.ts function load(): void { try { _data = JSON.parse(fs.readFileSync(Paths.data("attendance.json"), "utf8")); } catch { _data = {}; } } function save(): void { fs.writeFileSync(Paths.data("attendance.json"), JSON.stringify(_data, null, 2)); } // borrow.ts let _prefs: Record = {}; function loadPrefs(): void { try { _prefs = JSON.parse(fs.readFileSync(PREFS_PATH, "utf8")); } catch { _prefs = {}; } } function savePrefs(): void { try { fs.writeFileSync(PREFS_PATH, JSON.stringify(_prefs, null, 2)); } catch (err) { console.error("Failed to save sessionPreferences.json:", err); } } // systems/charSelect.ts const sharedChars: Character[] = []; try { const chars = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8")); for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) { if (ownerKey === userKey) continue; for (const c of data.characters ?? []) { if (c.sharedWith?.includes(userKey)) sharedChars.push(c); } } } catch {} // systems/config.ts let _cfg: BotConfig = {}; export function loadConfig(): void { try { _cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8")); } catch { _cfg = {}; } } export function saveConfig(): void { try { fs.writeFileSync(CONFIG_PATH, JSON.stringify(_cfg, null, 2)); } catch (err) { console.error("Failed to save config.json:", err); } } // systems/emojis.ts function loadEmojiMap(): Record { if (_map) return _map; _map = {}; const dir = Paths.emojis(); if (!fs.existsSync(dir)) { // Fallback to legacy messages/emojis.json try { _map = JSON.parse(fs.readFileSync(Paths.messages("emojis.json"), "utf8")); console.warn("[emojis] data/emojis/ not found, using legacy messages/emojis.json"); } catch {} return _map!; } for (const file of fs.readdirSync(dir)) { if (!file.endsWith(".json")) continue; try { const data = JSON.parse(fs.readFileSync(Paths.emojis(file), "utf8")); Object.assign(_map!, data); } catch (err) { console.error(`[emojis] Failed to load ${file}:`, err); } } return _map!; } // systems/history.ts export function loadResult(date: string, slot: number): TGResult | null { try { return JSON.parse(fs.readFileSync(historyPath(historyKey(date, slot)), "utf8")); } catch { return null; } } export function saveResult(result: TGResult): void { if (!fs.existsSync(HISTORY_DIR)) fs.mkdirSync(HISTORY_DIR, { recursive: true }); const key = historyKey(result.date, result.slot); fs.writeFileSync(historyPath(key), JSON.stringify(result, null, 2)); } export function listRecentResults(limit = 10): TGResult[] { if (!fs.existsSync(HISTORY_DIR)) return []; return fs.readdirSync(HISTORY_DIR) .filter((f) => f.endsWith(".json")) .sort() .reverse() .slice(0, limit) .map((f) => { try { return JSON.parse(fs.readFileSync(path.join(HISTORY_DIR, f), "utf8")) as TGResult; } catch { return null; } }) .filter(Boolean) as TGResult[]; } // systems.impersonate.ts const usermap = JSON.parse(fs.readFileSync(Paths.data("usermap.json"), "utf-8")); // systems/messages.ts export function loadMessages(): void { try { MESSAGES.global = JSON.parse(fs.readFileSync(path.join(MESSAGES_DIR, "global.json"), "utf8")); } catch (err) { console.error("Failed to load global.json:", err); } try { MESSAGES.userMap = JSON.parse(fs.readFileSync(USERMAP_PATH, "utf8")); } catch { MESSAGES.userMap = {}; } const usersDir = path.join(MESSAGES_DIR, "users"); MESSAGES.users = {}; if (fs.existsSync(usersDir)) { for (const file of fs.readdirSync(usersDir)) { if (!file.endsWith(".json")) continue; const key = path.basename(file, ".json"); try { MESSAGES.users[key] = JSON.parse(fs.readFileSync(path.join(usersDir, file), "utf8")); } catch (err) { console.error(`Failed to load user message file ${file}:`, err); } } } console.log(`Messages loaded — ${Object.keys(MESSAGES.users).length} user file(s).`); } export function setUsermapEntry(discordId: string, entry: UsermapEntry): void { MESSAGES.userMap[discordId] = entry; // Persist to disk const USERMAP_PATH = path.join(__dirname, "../../data/usermap.json"); try { const raw = JSON.parse(fs.readFileSync(USERMAP_PATH, "utf8")); raw[discordId] = entry; fs.writeFileSync(USERMAP_PATH, JSON.stringify(raw, null, 2)); } catch (err) { console.error("Failed to save usermap.json:", err); } } export function removeUsermapEntry(discordId: string): void { delete MESSAGES.userMap[discordId]; const USERMAP_PATH = path.join(__dirname, "../../data/usermap.json"); try { const raw = JSON.parse(fs.readFileSync(USERMAP_PATH, "utf8")); delete raw[discordId]; fs.writeFileSync(USERMAP_PATH, JSON.stringify(raw, null, 2)); } catch (err) { console.error("Failed to save usermap.json:", err); } } // systems/pollPersistence.ts export namespace persist { export function save(polls: Map): void { try { fs.writeFileSync(PERSIST_PATH, JSON.stringify(serialize(polls), null, 2), "utf8"); } catch (err) { console.error("[pollPersistence] Failed to save poll state:", err); } } export function load(): Map | null { try { if (!fs.existsSync(PERSIST_PATH)) return null; const raw = fs.readFileSync(PERSIST_PATH, "utf8"); const data = JSON.parse(raw) as SerializedPollState[]; const polls = deserialize(data); console.log(`[pollPersistence] Restored ${polls.size} poll(s) from disk.`); return polls; } catch (err) { console.error("[pollPersistence] Failed to load poll state:", err); return null; } } export function clear(): void { try { if (fs.existsSync(PERSIST_PATH)) fs.unlinkSync(PERSIST_PATH); } catch (err) { console.error("[pollPersistence] Failed to clear poll state:", err); } } } // systems/score.ts function getHistoryPath(historyKey: HistoryKey): string { return Paths.data("tg-history", `${historyKey}.json`); } function loadHistory(historyKey: HistoryKey): { scores: TGScore[] } { try { return JSON.parse(fs.readFileSync(getHistoryPath(historyKey), "utf8")); } catch { return { scores: [] }; } } function saveHistory(historyKey: HistoryKey, data: { scores: TGScore[] }): void { fs.writeFileSync(getHistoryPath(historyKey), JSON.stringify(data, null, 2)); } // systems/registry.ts function loadUsermap(): Record { if (!_cache) { try { _cache = JSON.parse(fs.readFileSync(Paths.data("usermap.json"), "utf8")); } catch { _cache = {}; } } return _cache!; }