const chokidar = require('chokidar'); const path = require('path'); const contentService = require('./content'); const pluginManager = require('./plugin-manager'); const { loadSiteConfig } = require('../config'); class WatcherService { constructor() { this.watcher = null; this.debounceTimer = null; } start(contentDir, app) { console.log(`[Watcher] Starting filesystem watcher on ${contentDir}`); this.watcher = chokidar.watch(contentDir, { ignored: [ /(^|[\/\\])\../, // dotfiles /(^|[\/\\])data([\/\\]|$)/, // ignore entire data/ directory (site.db, journals, etc.) /\.db(-journal|-wal|-shm)?$/, // sqlite database files /node_modules/ ], persistent: true, ignoreInitial: true, awaitWriteFinish: { stabilityThreshold: 300, pollInterval: 100 } }); const triggerReload = (event, filePath) => { const relative = path.relative(contentDir, filePath); console.log(`[Watcher] Detected ${event} on ${relative}`); clearTimeout(this.debounceTimer); this.debounceTimer = setTimeout(() => { try { const freshConfig = loadSiteConfig(); pluginManager.loadPlugins(contentDir, app, freshConfig); contentService.reload(); console.log(`[Watcher] Hot reload finished successfully.`); } catch (err) { console.error(`[Watcher] Error during hot reload:`, err); } }, 250); }; this.watcher.on('add', (p) => triggerReload('add', p)); this.watcher.on('change', (p) => triggerReload('change', p)); this.watcher.on('unlink', (p) => triggerReload('unlink', p)); } close() { if (this.watcher) { this.watcher.close(); } } } module.exports = new WatcherService();