umami
Some checks failed
Build & Deploy KLZ Cables / deploy (push) Failing after 13m20s

This commit is contained in:
2026-01-24 22:03:06 +01:00
parent 7e94feaf19
commit 72711c74ba
14 changed files with 3056 additions and 13 deletions

View File

@@ -5,22 +5,80 @@ import { MemoryCacheService } from './cache/memory-cache-service';
import { GlitchtipErrorReportingService } from './errors/glitchtip-error-reporting-service';
import { NoopErrorReportingService } from './errors/noop-error-reporting-service';
/**
* Singleton instance of AppServices.
*
* In Next.js, module singletons are per-process (server) and per-tab (client).
* This is sufficient for a small service layer and provides better performance
* than creating new instances on every request.
*
* @private
*/
let singleton: AppServices | undefined;
/**
* Get the application services singleton.
*
* This function creates and caches the application services, including:
* - Analytics service (Umami or no-op)
* - Error reporting service (GlitchTip/Sentry or no-op)
* - Cache service (in-memory)
*
* The services are configured based on environment variables:
* - `NEXT_PUBLIC_UMAMI_WEBSITE_ID` - Enables Umami analytics
* - `NEXT_PUBLIC_SENTRY_DSN` - Enables client-side error reporting
* - `SENTRY_DSN` - Enables server-side error reporting
*
* @returns {AppServices} The application services singleton
*
* @example
* ```typescript
* // Get services in a client component
* import { getAppServices } from '@/lib/services/create-services';
*
* const services = getAppServices();
* services.analytics.track('button_click', { button_id: 'cta' });
* ```
*
* @example
* ```typescript
* // Get services in a server component or API route
* import { getAppServices } from '@/lib/services/create-services';
*
* const services = getAppServices();
* await services.cache.set('key', 'value');
* ```
*
* @example
* ```typescript
* // Automatic service selection based on environment
* // If NEXT_PUBLIC_UMAMI_WEBSITE_ID is set:
* // services.analytics = UmamiAnalyticsService
* // If not set:
* // services.analytics = NoopAnalyticsService (safe no-op)
* ```
*
* @see {@link UmamiAnalyticsService} for analytics implementation
* @see {@link NoopAnalyticsService} for no-op fallback
* @see {@link GlitchtipErrorReportingService} for error reporting
* @see {@link MemoryCacheService} for caching
*/
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.
// Return cached instance if available
if (singleton) return singleton;
// Determine which services to enable based on environment variables
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);
// Create analytics service (Umami or no-op)
const analytics = umamiEnabled
? new UmamiAnalyticsService({ enabled: true })
: new NoopAnalyticsService();
// Enable GlitchTip/Sentry only when a DSN is present for the active runtime.
// Create error reporting service (GlitchTip/Sentry or no-op)
// Server-side and client-side have separate DSNs
const errors =
typeof window === 'undefined'
? sentryServerEnabled
@@ -35,6 +93,7 @@ export function getAppServices(): AppServices {
// Use [`getServerAppServices()`](lib/services/create-services.server.ts:1) on the server.
const cache = new MemoryCacheService();
// Create and cache the singleton
singleton = new AppServices(analytics, errors, cache);
return singleton;
}