import * as plugins from './plugins.js'; import * as interfaces from '../dist_ts_interfaces/index.js'; // Create main app state instance export const appState = new plugins.domtools.plugins.smartstate.Smartstate(); // Define state interfaces export interface ILoginState { identity: interfaces.data.IIdentity | null; isLoggedIn: boolean; } export interface IStatsState { serverStats: interfaces.data.IServerStats | null; emailStats: interfaces.data.IEmailStats | null; dnsStats: interfaces.data.IDnsStats | null; securityMetrics: interfaces.data.ISecurityMetrics | null; lastUpdated: number; isLoading: boolean; error: string | null; } export interface IConfigState { config: any | null; isLoading: boolean; error: string | null; } export interface IUiState { activeView: string; sidebarCollapsed: boolean; autoRefresh: boolean; refreshInterval: number; // milliseconds theme: 'light' | 'dark'; } export interface ILogState { recentLogs: interfaces.data.ILogEntry[]; isStreaming: boolean; filters: { level?: string[]; category?: string[]; }; } // Create state parts with appropriate persistence export const loginStatePart = await appState.getStatePart( 'login', { identity: null, isLoggedIn: false, }, 'persistent' // Login state persists across sessions ); export const statsStatePart = await appState.getStatePart( 'stats', { serverStats: null, emailStats: null, dnsStats: null, securityMetrics: null, lastUpdated: 0, isLoading: false, error: null, }, 'soft' // Stats are cached but not persisted ); export const configStatePart = await appState.getStatePart( 'config', { config: null, isLoading: false, error: null, }, 'soft' ); export const uiStatePart = await appState.getStatePart( 'ui', { activeView: 'dashboard', sidebarCollapsed: false, autoRefresh: true, refreshInterval: 30000, // 30 seconds theme: 'light', }, 'persistent' // UI preferences persist ); export const logStatePart = await appState.getStatePart( 'logs', { recentLogs: [], isStreaming: false, filters: {}, }, 'soft' ); // Actions for state management interface IActionContext { identity: interfaces.data.IIdentity | null; } const getActionContext = (): IActionContext => { return { identity: loginStatePart.getState().identity, }; }; // Login Action export const loginAction = loginStatePart.createAction<{ username: string; password: string; }>(async (statePartArg, dataArg) => { const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_AdminLoginWithUsernameAndPassword >('/typedrequest', 'adminLoginWithUsernameAndPassword'); try { const response = await typedRequest.fire({ username: dataArg.username, password: dataArg.password, }); if (response.identity) { return { identity: response.identity, isLoggedIn: true, }; } return statePartArg.getState(); } catch (error) { console.error('Login failed:', error); return statePartArg.getState(); } }); // Logout Action export const logoutAction = loginStatePart.createAction(async (statePartArg) => { const context = getActionContext(); if (!context.identity) return statePartArg.getState(); const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_AdminLogout >('/typedrequest', 'adminLogout'); try { await typedRequest.fire({ identity: context.identity, }); } catch (error) { console.error('Logout error:', error); } // Clear login state regardless return { identity: null, isLoggedIn: false, }; }); // Fetch All Stats Action export const fetchAllStatsAction = statsStatePart.createAction(async (statePartArg) => { const context = getActionContext(); const currentState = statePartArg.getState(); try { // Fetch server stats const serverStatsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetServerStatistics >('/typedrequest', 'getServerStatistics'); const serverStatsResponse = await serverStatsRequest.fire({ identity: context.identity, includeHistory: false, }); // Fetch email stats const emailStatsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetEmailStatistics >('/typedrequest', 'getEmailStatistics'); const emailStatsResponse = await emailStatsRequest.fire({ identity: context.identity, }); // Fetch DNS stats const dnsStatsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetDnsStatistics >('/typedrequest', 'getDnsStatistics'); const dnsStatsResponse = await dnsStatsRequest.fire({ identity: context.identity, }); // Fetch security metrics const securityRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetSecurityMetrics >('/typedrequest', 'getSecurityMetrics'); const securityResponse = await securityRequest.fire({ identity: context.identity, }); // Update state with all stats return { serverStats: serverStatsResponse.stats, emailStats: emailStatsResponse.stats, dnsStats: dnsStatsResponse.stats, securityMetrics: securityResponse.metrics, lastUpdated: Date.now(), isLoading: false, error: null, }; } catch (error) { return { ...currentState, isLoading: false, error: error.message || 'Failed to fetch statistics', }; } }); // Fetch Configuration Action export const fetchConfigurationAction = configStatePart.createAction(async (statePartArg) => { const context = getActionContext(); const currentState = statePartArg.getState(); try { const configRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetConfiguration >('/typedrequest', 'getConfiguration'); const response = await configRequest.fire({ identity: context.identity, }); return { config: response.config, isLoading: false, error: null, }; } catch (error) { return { ...currentState, isLoading: false, error: error.message || 'Failed to fetch configuration', }; } }); // Update Configuration Action export const updateConfigurationAction = configStatePart.createAction<{ section: string; config: any; }>(async (statePartArg, dataArg) => { const context = getActionContext(); if (!context.identity) { throw new Error('Must be logged in to update configuration'); } const updateRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_UpdateConfiguration >('/typedrequest', 'updateConfiguration'); const response = await updateRequest.fire({ identity: context.identity, section: dataArg.section, config: dataArg.config, }); if (response.updated) { // Refresh configuration await configStatePart.dispatchAction(fetchConfigurationAction, null); return statePartArg.getState(); } return statePartArg.getState(); }); // Fetch Recent Logs Action export const fetchRecentLogsAction = logStatePart.createAction<{ limit?: number; level?: 'debug' | 'info' | 'warn' | 'error'; category?: 'smtp' | 'dns' | 'security' | 'system' | 'email'; }>(async (statePartArg, dataArg) => { const context = getActionContext(); const logsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetRecentLogs >('/typedrequest', 'getRecentLogs'); const response = await logsRequest.fire({ identity: context.identity, limit: dataArg.limit || 100, level: dataArg.level, category: dataArg.category, }); return { ...statePartArg.getState(), recentLogs: response.logs, }; }); // Toggle Auto Refresh Action export const toggleAutoRefreshAction = uiStatePart.createAction(async (statePartArg) => { const currentState = statePartArg.getState(); return { ...currentState, autoRefresh: !currentState.autoRefresh, }; }); // Set Active View Action export const setActiveViewAction = uiStatePart.createAction(async (statePartArg, viewName) => { const currentState = statePartArg.getState(); return { ...currentState, activeView: viewName, }; }); // Initialize auto-refresh let refreshInterval: NodeJS.Timeout | null = null; // Initialize auto-refresh when UI state is ready (() => { const startAutoRefresh = () => { const uiState = uiStatePart.getState(); if (uiState.autoRefresh && loginStatePart.getState().isLoggedIn) { refreshInterval = setInterval(() => { statsStatePart.dispatchAction(fetchAllStatsAction, null); }, uiState.refreshInterval); } }; const stopAutoRefresh = () => { if (refreshInterval) { clearInterval(refreshInterval); refreshInterval = null; } }; // Watch for changes uiStatePart.state.subscribe(() => { stopAutoRefresh(); startAutoRefresh(); }); loginStatePart.state.subscribe(() => { stopAutoRefresh(); startAutoRefresh(); }); // Initial start startAutoRefresh(); })();