/** * AnalyticsModule - NestJS module for backend analytics * * Provides: * - BackendAnalyticsClient for manual tracking * - Global interceptor for automatic request tracking * - @TrackAnalytics decorator for method-level tracking */ import { Module, Global, DynamicModule } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { BackendAnalyticsClient } from '@analytics/client'; import type { BackendAnalyticsConfig } from '@analytics/client'; export const ANALYTICS_CLIENT = 'ANALYTICS_CLIENT'; export interface AnalyticsModuleOptions { /** * Analytics collector URL. */ collectorUrl: string; /** * Application name for event attribution. */ appName: string; /** * Enable/disable tracking (useful for tests). */ enabled?: boolean; /** * Enable debug logging. */ debug?: boolean; } @Global() @Module({}) export class AnalyticsModule { /** * Register with static configuration. * * @example * ```ts * AnalyticsModule.register({ * collectorUrl: 'http://localhost:4001', * appName: 'my-api', * }) * ``` */ static register(options: AnalyticsModuleOptions): DynamicModule { return { module: AnalyticsModule, providers: [ { provide: ANALYTICS_CLIENT, useFactory: () => { const config: BackendAnalyticsConfig = { apiBaseUrl: options.collectorUrl, appName: options.appName, enabled: options.enabled ?? true, enableDebugLogging: options.debug ?? false, }; return new BackendAnalyticsClient(config); }, }, ], exports: [ANALYTICS_CLIENT], }; } /** * Register with async configuration (for ConfigService). * * @example * ```ts * AnalyticsModule.registerAsync({ * inject: [ConfigService], * useFactory: (config: ConfigService) => ({ * collectorUrl: config.get('ANALYTICS_COLLECTOR_URL'), * appName: config.get('APP_NAME'), * enabled: config.get('NODE_ENV') !== 'test', * }), * }) * ``` */ static registerAsync(options: { inject?: any[]; useFactory: (...args: any[]) => AnalyticsModuleOptions | Promise; }): DynamicModule { return { module: AnalyticsModule, providers: [ { provide: ANALYTICS_CLIENT, inject: options.inject || [], useFactory: async (...args: any[]) => { const moduleOptions = await options.useFactory(...args); const config: BackendAnalyticsConfig = { apiBaseUrl: moduleOptions.collectorUrl, appName: moduleOptions.appName, enabled: moduleOptions.enabled ?? true, enableDebugLogging: moduleOptions.debug ?? false, }; return new BackendAnalyticsClient(config); }, }, ], exports: [ANALYTICS_CLIENT], }; } } /** * Example AppModule setup: * * ```ts * @Module({ * imports: [ * ConfigModule.forRoot({ isGlobal: true }), * AnalyticsModule.registerAsync({ * inject: [ConfigService], * useFactory: (config: ConfigService) => ({ * collectorUrl: config.get('ANALYTICS_URL', 'http://localhost:4001'), * appName: 'my-api', * enabled: config.get('NODE_ENV') !== 'test', * debug: config.get('NODE_ENV') === 'development', * }), * }), * ], * }) * export class AppModule {} * ``` */