diff --git a/packages/analytics/src/analytics-manager.ts b/packages/analytics/src/analytics-manager.ts index c33ea2093..92d8d912c 100644 --- a/packages/analytics/src/analytics-manager.ts +++ b/packages/analytics/src/analytics-manager.ts @@ -5,69 +5,69 @@ import type { CreateAnalyticsManagerOptions, } from './types'; -/** - * Creates an analytics manager that can be used to track page views and events. The manager is initialized with a - * default provider and can be switched to a different provider at any time. The manager will use a NullAnalyticsService - * if the provider is not registered. - * @param options - */ export function createAnalyticsManager( options: CreateAnalyticsManagerOptions, ): AnalyticsManager { - let activeService: AnalyticsService = NullAnalyticsService; + const activeServices = new Map(); - const getActiveService = (): AnalyticsService => { - if (activeService === NullAnalyticsService) { + const getActiveServices = (): AnalyticsService[] => { + if (activeServices.size === 0) { console.debug( - 'Analytics service not initialized. Using NullAnalyticsService.', - ); - } - - return activeService; - }; - - const initialize = (provider: T, config: Config) => { - const factory = options.providers[provider]; - - if (!factory) { - console.warn( - `Analytics provider '${provider}' not registered. Using NullAnalyticsService.`, + 'No active analytics services. Using NullAnalyticsService.', ); - activeService = NullAnalyticsService; - return; + return [NullAnalyticsService]; } - activeService = factory(config); - activeService.initialize(); + return Array.from(activeServices.values()); }; - // Initialize with the default provider - initialize(options.defaultProvider, {} as Config); - return { + addProvider: ( + provider: T, + config: Config, + ) => { + const factory = options.providers[provider]; + + if (!factory) { + console.warn( + `Analytics provider '${provider}' not registered. Skipping initialization.`, + ); + + return Promise.resolve(); + } + + const service = factory(config); + activeServices.set(provider, service); + + return service.initialize(); + }, + + removeProvider: (provider: T) => { + activeServices.delete(provider); + }, + identify: (userId: string, traits?: Record) => { - return getActiveService().identify(userId, traits); + return Promise.all( + getActiveServices().map((service) => service.identify(userId, traits)), + ); }, - /** - * Track a page view with the given URL. - * @param url - */ trackPageView: (url: string) => { - return getActiveService().trackPageView(url); + return Promise.all( + getActiveServices().map((service) => service.trackPageView(url)), + ); }, - /** - * Track an event with the given name and properties. - * @param eventName - * @param eventProperties - */ trackEvent: ( eventName: string, eventProperties?: Record, ) => { - return getActiveService().trackEvent(eventName, eventProperties); + return Promise.all( + getActiveServices().map((service) => + service.trackEvent(eventName, eventProperties), + ), + ); }, }; } diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index 74a47eda6..ed4f93d9d 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -3,7 +3,6 @@ import { NullAnalyticsService } from './null-analytics-service'; import type { AnalyticsManager } from './types'; export const analytics: AnalyticsManager = createAnalyticsManager({ - defaultProvider: 'null', providers: { null: () => NullAnalyticsService, }, diff --git a/packages/analytics/src/null-analytics-service.ts b/packages/analytics/src/null-analytics-service.ts index 7ee7b0eed..a52466105 100644 --- a/packages/analytics/src/null-analytics-service.ts +++ b/packages/analytics/src/null-analytics-service.ts @@ -3,7 +3,8 @@ import { AnalyticsService } from './types'; const noop = (event: string) => { // do nothing - this is to prevent errors when the analytics service is not initialized - return (...args: unknown[]) => { + // eslint-disable-next-line @typescript-eslint/require-await + return async (...args: unknown[]) => { console.debug( `Noop analytics service called with event: ${event}`, ...args.filter(Boolean), diff --git a/packages/analytics/src/types.ts b/packages/analytics/src/types.ts index 194b9fb4f..b2aa1a496 100644 --- a/packages/analytics/src/types.ts +++ b/packages/analytics/src/types.ts @@ -2,19 +2,25 @@ interface TrackEvent { trackEvent( eventName: string, eventProperties?: Record, - ): void; + ): Promise; } interface TrackPageView { - trackPageView(url: string): void; + trackPageView(url: string): Promise; } interface Identify { - identify(userId: string, traits?: Record): void; + identify(userId: string, traits?: Record): Promise; +} + +interface ProviderManager { + addProvider(provider: string, config: object): Promise; + + removeProvider(provider: string): void; } export interface AnalyticsService extends TrackPageView, TrackEvent, Identify { - initialize(): void; + initialize(): Promise; } export type AnalyticsProviderFactory = ( @@ -25,8 +31,11 @@ export interface CreateAnalyticsManagerOptions< T extends string, Config extends object, > { - defaultProvider: T; providers: Record>; } -export interface AnalyticsManager extends TrackPageView, TrackEvent, Identify {} +export interface AnalyticsManager + extends TrackPageView, + TrackEvent, + Identify, + ProviderManager {}