@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
99 lines (78 loc) • 4.47 kB
text/typescript
import { ISdkFactoryContext, ISdkFactoryContextSync, ISdkFactoryParams } from './types';
import { sdkReadinessManagerFactory } from '../readiness/sdkReadinessManager';
import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
import { eventTrackerFactory } from '../trackers/eventTracker';
import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
import SplitIO from '../../types/splitio';
import { createLoggerAPI } from '../logger/sdkLogger';
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
import { SDK_DEFINITIONS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_DEFINITIONS_CACHE_LOADED } from '../readiness/constants';
import { objectAssign } from '../utils/lang/objectAssign';
import { setRolloutPlan } from '../storages/setRolloutPlan';
import { IStorageSync } from '../storages/types';
import { getMatching } from '../utils/key';
import { FallbackTreatmentsCalculator } from '../evaluator/fallbackTreatmentsCalculator';
/**
* Modular SDK factory
*/
export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IAsyncSDK | SplitIO.IBrowserSDK | SplitIO.IBrowserAsyncSDK {
const { settings, platform, storageFactory, serviceApiFactory, extraProps, syncManagerFactory,
integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory, lazyInit } = params;
const { log, initialRolloutPlan, core: { key } } = settings;
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
const sdkReadinessManager = sdkReadinessManagerFactory(platform.EventEmitter, settings);
const readiness = sdkReadinessManager.readinessManager;
const storage = storageFactory({
settings,
onReadyCb(error) {
if (error) {
// If storage fails to connect, SDK_READY_TIMED_OUT event is emitted immediately. Review when timeout and non-recoverable errors are reworked
readiness.timeout();
return;
}
readiness.definitions.emit(SDK_DEFINITIONS_ARRIVED);
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
},
onReadyFromCacheCb() {
readiness.definitions.emit(SDK_DEFINITIONS_CACHE_LOADED);
}
});
const fallbackCalculator = FallbackTreatmentsCalculator(settings.fallbackTreatments);
if (initialRolloutPlan) {
setRolloutPlan(log, initialRolloutPlan, storage as IStorageSync, key && getMatching(key));
if ((storage as IStorageSync).definitions.getChangeNumber() > -1) readiness.definitions.emit(SDK_DEFINITIONS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
}
const clients: Record<string, SplitIO.IBasicClient & { init: () => void }> = {};
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
const impressionsTracker = impressionsTrackerFactory(params, storage, integrationsManager);
const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
// serviceApi is used by SyncManager and Browser signal listener
const serviceApi = serviceApiFactory && serviceApiFactory(settings, platform, telemetryTracker);
const ctx: ISdkFactoryContext = { clients, serviceApi, eventTracker, impressionsTracker, telemetryTracker, sdkReadinessManager, readiness, settings, storage, platform, fallbackCalculator };
ctx.syncManager = syncManagerFactory && syncManagerFactory(ctx as ISdkFactoryContextSync);
// SDK client and manager
const clientMethod = sdkClientMethodFactory(ctx);
const managerInstance = sdkManagerFactory(settings, storage.definitions, sdkReadinessManager);
function init() {
Object.keys(clients).map(key => clients[key].init());
}
log.info(NEW_FACTORY, [settings.version]);
// @ts-ignore
return objectAssign({
// Split evaluation and event tracking engine
client: clientMethod,
// Manager API to explore available information
manager() {
log.debug(RETRIEVE_MANAGER);
return managerInstance;
},
// Logger wrapper API
Logger: createLoggerAPI(log),
settings,
destroy() {
return Promise.all(Object.keys(clients).map(key => clients[key].destroy())).then(() => { });
}
}, extraProps && extraProps(ctx), lazyInit ? { init } : init());
}