import fs from 'node:fs'; import path from 'node:path'; import { DEFAULT_PROMPT_TEMPLATE } from './bugs.js'; const DEFAULT_STATE = () => ({ persons: [], absences: [], holidays: [], assignments: {}, requests: [], bugs: [], exported: {}, settings: { meetingTime: '09:30', durationMinutes: 15, bundesland: 'BY', calendarDisplayName: 'Morning Meeting', inviteAttendees: false, historyWindowDays: 60, holidaysSeeded: false, bugPromptTemplate: DEFAULT_PROMPT_TEMPLATE, targetCalendarHref: '', targetCalendarName: '', absenceCalendarHref: '', absenceCalendarName: '', }, }); /** Bildtyp anhand der ersten Bytes erkennen. */ export function imageMime(buffer) { if (!buffer || buffer.length < 12) return null; if (buffer[0] === 0xff && buffer[1] === 0xd8) return 'image/jpeg'; if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) return 'image/png'; if (buffer.subarray(0, 4).toString('ascii') === 'RIFF' && buffer.subarray(8, 12).toString('ascii') === 'WEBP') return 'image/webp'; if (buffer.subarray(0, 4).toString('ascii') === 'GIF8') return 'image/gif'; return null; } /** Einfacher JSON-Speicher mit atomarem Schreiben. Fotos liegen daneben im Ordner photos/. */ export function createStore(dataDir) { const file = path.join(dataDir, 'rotatory.json'); const photoDir = path.join(dataDir, 'photos'); const bugDir = path.join(dataDir, 'bugs'); fs.mkdirSync(photoDir, { recursive: true }); fs.mkdirSync(bugDir, { recursive: true }); let state = DEFAULT_STATE(); if (fs.existsSync(file)) { const loaded = JSON.parse(fs.readFileSync(file, 'utf8')); state = { ...state, ...loaded, settings: { ...state.settings, ...(loaded.settings || {}) } }; } function save() { const tmp = file + '.tmp'; fs.writeFileSync(tmp, JSON.stringify(state, null, 2)); fs.renameSync(tmp, file); } const photoPath = (id) => path.join(photoDir, `${id}.jpg`); return { get state() { return state; }, save, photoPath, hasPhoto: (id) => fs.existsSync(photoPath(id)), readPhoto: (id) => (fs.existsSync(photoPath(id)) ? fs.readFileSync(photoPath(id)) : null), savePhoto: (id, buffer) => fs.writeFileSync(photoPath(id), buffer), deletePhoto: (id) => { try { fs.unlinkSync(photoPath(id)); } catch {} }, saveBug: (id, buffer) => fs.writeFileSync(path.join(bugDir, `${id}.png`), buffer), readBug: (id) => (fs.existsSync(path.join(bugDir, `${id}.png`)) ? fs.readFileSync(path.join(bugDir, `${id}.png`)) : null), deleteBug: (id) => { try { fs.unlinkSync(path.join(bugDir, `${id}.png`)); } catch {} }, }; }