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 { RedisCacheService } from './cache/redis-cache-service'; import { GlitchtipErrorReportingService } from './errors/glitchtip-error-reporting-service'; import { NoopErrorReportingService } from './errors/noop-error-reporting-service'; let singleton: AppServices | undefined; export function getAppServices(): AppServices { // In Next.js, module singletons are per-process (server) and per-tab (client). // This is good enough for a small service layer. if (singleton) return singleton; const umamiEnabled = Boolean(process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID); const sentryClientEnabled = Boolean(process.env.NEXT_PUBLIC_SENTRY_DSN); const sentryServerEnabled = Boolean(process.env.SENTRY_DSN); const analytics = umamiEnabled ? new UmamiAnalyticsService({ enabled: true }) : new NoopAnalyticsService(); // Enable GlitchTip/Sentry only when a DSN is present for the active runtime. const errors = typeof window === 'undefined' ? sentryServerEnabled ? new GlitchtipErrorReportingService({ enabled: true }) : new NoopErrorReportingService() : sentryClientEnabled ? new GlitchtipErrorReportingService({ enabled: true }) : new NoopErrorReportingService(); const redisUrl = process.env.REDIS_URL; const cache = redisUrl ? new RedisCacheService({ url: redisUrl, keyPrefix: process.env.REDIS_KEY_PREFIX ?? 'klz:', }) : new MemoryCacheService(); singleton = new AppServices(analytics, errors, cache); return singleton; }