import { AppServices } from './app-services'; import { NoopAnalyticsService } from './analytics/noop-analytics-service'; import { UmamiAnalyticsService } from './analytics/umami-analytics-service'; import { MemoryCacheService } from './cache/memory-cache-service'; import { GlitchtipErrorReportingService } from './errors/glitchtip-error-reporting-service'; import { NoopErrorReportingService } from './errors/noop-error-reporting-service'; import { GotifyNotificationService, NoopNotificationService, } from './notifications/gotify-notification-service'; import { PinoLoggerService } from './logging/pino-logger-service'; import { config, getMaskedConfig } from '../config'; declare global { var __appServices: AppServices | undefined; } // Add a local cache to prevent re-looking up globalThis frequently let serverSingleton: AppServices | undefined; export function getServerAppServices(): AppServices { if (serverSingleton) return serverSingleton; if (globalThis.__appServices) { serverSingleton = globalThis.__appServices; return serverSingleton; } // Create logger first to log initialization const logger = new PinoLoggerService('server'); logger.info('Initializing server application services', { environment: getMaskedConfig(), timestamp: new Date().toISOString(), }); logger.info('Service configuration', { umamiEnabled: config.analytics.umami.enabled, sentryEnabled: config.errors.glitchtip.enabled, mailEnabled: Boolean(config.mail.host && config.mail.user), gotifyEnabled: config.notifications.gotify.enabled, }); const analytics = config.analytics.umami.enabled ? new UmamiAnalyticsService({ enabled: true }, logger) : new NoopAnalyticsService(); if (config.analytics.umami.enabled) { logger.info('Umami analytics service initialized'); } else { logger.info('Noop analytics service initialized (analytics disabled)'); } const notifications = config.notifications.gotify.enabled ? new GotifyNotificationService({ url: config.notifications.gotify.url!, token: config.notifications.gotify.token!, enabled: true, }) : new NoopNotificationService(); if (config.notifications.gotify.enabled) { logger.info('Gotify notification service initialized'); } else { logger.info('Noop notification service initialized (notifications disabled)'); } const errors = config.errors.glitchtip.enabled ? new GlitchtipErrorReportingService( { enabled: true, dsn: config.errors.glitchtip.dsn, tracesSampleRate: 1.0, // Server-side we usually want higher visibility }, logger, notifications, ) : new NoopErrorReportingService(); if (config.errors.glitchtip.enabled) { logger.info('GlitchTip error reporting service initialized', { dsnPresent: Boolean(config.errors.glitchtip.dsn), }); } else { logger.info('Noop error reporting service initialized (error reporting disabled)'); } const cache = new MemoryCacheService(); logger.info('Memory cache service initialized'); logger.info('Pino logger service initialized', { name: 'server', level: config.logging.level, }); globalThis.__appServices = new AppServices(analytics, errors, cache, logger, notifications); logger.info('All application services initialized successfully'); return globalThis.__appServices; }