B2B-88: add starter kit structure and elements

This commit is contained in:
devmc-ee
2025-06-08 16:18:30 +03:00
parent 657a36a298
commit e7b25600cb
1280 changed files with 77893 additions and 5688 deletions

View File

@@ -0,0 +1,94 @@
import { NullAnalyticsService } from './null-analytics-service';
import type {
AnalyticsManager,
AnalyticsService,
CreateAnalyticsManagerOptions,
} from './types';
export function createAnalyticsManager<T extends string, Config extends object>(
options: CreateAnalyticsManagerOptions<T, Config>,
): AnalyticsManager {
const activeServices = new Map<T, AnalyticsService>();
const getActiveServices = (): AnalyticsService[] => {
if (activeServices.size === 0) {
console.debug(
'No active analytics services. Using NullAnalyticsService.',
);
return [NullAnalyticsService];
}
return Array.from(activeServices.values());
};
const registerActiveServices = (
options: CreateAnalyticsManagerOptions<T, Config>,
) => {
Object.keys(options.providers).forEach((provider) => {
const providerKey = provider as keyof typeof options.providers;
const factory = options.providers[providerKey];
if (!factory) {
console.warn(
`Analytics provider '${provider}' not registered. Skipping initialization.`,
);
return;
}
const service = factory();
activeServices.set(provider as T, service);
void service.initialize();
});
};
registerActiveServices(options);
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<string, string>) => {
return Promise.all(
getActiveServices().map((service) => service.identify(userId, traits)),
);
},
trackPageView: (path: string) => {
return Promise.all(
getActiveServices().map((service) => service.trackPageView(path)),
);
},
trackEvent: (
eventName: string,
eventProperties?: Record<string, string | string[]>,
) => {
return Promise.all(
getActiveServices().map((service) =>
service.trackEvent(eventName, eventProperties),
),
);
},
};
}

View File

@@ -0,0 +1,9 @@
import { createAnalyticsManager } from './analytics-manager';
import { NullAnalyticsService } from './null-analytics-service';
import type { AnalyticsManager } from './types';
export const analytics: AnalyticsManager = createAnalyticsManager({
providers: {
null: () => NullAnalyticsService,
},
});

View File

@@ -0,0 +1,23 @@
import { AnalyticsService } from './types';
const noop = (event: string) => {
// do nothing - this is to prevent errors when the analytics service is not initialized
return async (...args: unknown[]) => {
console.debug(
`Noop analytics service called with event: ${event}`,
...args.filter(Boolean),
);
};
};
/**
* Null analytics service that does nothing. It is initialized with a noop function. This is useful for testing or when
* the user is calling analytics methods before the analytics service is initialized.
*/
export const NullAnalyticsService: AnalyticsService = {
initialize: noop('initialize'),
trackPageView: noop('trackPageView'),
trackEvent: noop('trackEvent'),
identify: noop('identify'),
};

View File

@@ -0,0 +1,41 @@
interface TrackEvent {
trackEvent(
eventName: string,
eventProperties?: Record<string, string | string[]>,
): Promise<unknown>;
}
interface TrackPageView {
trackPageView(path: string): Promise<unknown>;
}
interface Identify {
identify(userId: string, traits?: Record<string, string>): Promise<unknown>;
}
interface ProviderManager {
addProvider(provider: string, config: object): Promise<unknown>;
removeProvider(provider: string): void;
}
export interface AnalyticsService extends TrackPageView, TrackEvent, Identify {
initialize(): Promise<unknown>;
}
export type AnalyticsProviderFactory<Config extends object> = (
config?: Config,
) => AnalyticsService;
export interface CreateAnalyticsManagerOptions<
T extends string,
Config extends object,
> {
providers: Record<T, AnalyticsProviderFactory<Config>>;
}
export interface AnalyticsManager
extends TrackPageView,
TrackEvent,
Identify,
ProviderManager {}