import { mkdirSync, readFileSync, writeFileSync } from 'node:fs' export interface RolePanel { channelID: string /** unicode emoji, or `name:id` for custom emoji */ emoji: string guildID: string /** users known to have the reaction, kept in step with role grants */ reactors: Set roleID: string } type StoredPanel = Omit & { reactors?: string[] } const DATA_DIR = new URL('../data/', import.meta.url) const FILE = new URL('role-panels.json', DATA_DIR) function load(): Map { let raw: string try { raw = readFileSync(FILE, 'utf8') } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return new Map() throw error } return new Map( Object.entries(JSON.parse(raw) as Record).map(([messageID, panel]) => [ messageID, // files written before reactors were tracked { ...panel, reactors: new Set(panel.reactors ?? []) } ]) ) } function save(): void { mkdirSync(DATA_DIR, { recursive: true }) const json = JSON.stringify( Object.fromEntries(panels), (_, value: unknown) => (value instanceof Set ? [...value] : value), 2 ) writeFileSync(FILE, json) } /** Panel registry, keyed by panel message ID. */ export const panels = load() export function setPanel(messageID: string, panel: RolePanel): void { panels.set(messageID, panel) save() } export function deletePanel(messageID: string): boolean { if (!panels.delete(messageID)) return false save() return true } export function setReactor(panel: RolePanel, userID: string, reacted: boolean): void { if (reacted) panel.reactors.add(userID) else panel.reactors.delete(userID) save() }