@splitsoftware/splitio-commons 1.17.1-rc.2 → 1.17.1-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/cjs/readiness/readinessManager.js +7 -5
  2. package/cjs/sdkClient/sdkClientMethodCS.js +7 -4
  3. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +7 -4
  4. package/cjs/sdkFactory/index.js +30 -9
  5. package/cjs/storages/dataLoader.js +10 -11
  6. package/cjs/storages/inLocalStorage/index.js +5 -3
  7. package/cjs/storages/inRedis/RedisAdapter.js +1 -1
  8. package/cjs/storages/pluggable/index.js +37 -32
  9. package/cjs/trackers/eventTracker.js +11 -9
  10. package/cjs/trackers/impressionsTracker.js +15 -13
  11. package/cjs/trackers/uniqueKeysTracker.js +5 -3
  12. package/esm/readiness/readinessManager.js +7 -5
  13. package/esm/sdkClient/sdkClientMethodCS.js +7 -4
  14. package/esm/sdkClient/sdkClientMethodCSWithTT.js +7 -4
  15. package/esm/sdkFactory/index.js +30 -9
  16. package/esm/storages/dataLoader.js +10 -11
  17. package/esm/storages/inLocalStorage/index.js +5 -3
  18. package/esm/storages/inRedis/RedisAdapter.js +1 -1
  19. package/esm/storages/pluggable/index.js +37 -32
  20. package/esm/trackers/eventTracker.js +11 -9
  21. package/esm/trackers/impressionsTracker.js +15 -13
  22. package/esm/trackers/uniqueKeysTracker.js +5 -3
  23. package/package.json +1 -1
  24. package/src/readiness/readinessManager.ts +9 -7
  25. package/src/readiness/types.ts +1 -0
  26. package/src/sdkClient/sdkClientMethodCS.ts +5 -2
  27. package/src/sdkClient/sdkClientMethodCSWithTT.ts +5 -2
  28. package/src/sdkFactory/index.ts +32 -10
  29. package/src/sdkFactory/types.ts +3 -0
  30. package/src/storages/dataLoader.ts +12 -13
  31. package/src/storages/inLocalStorage/index.ts +6 -4
  32. package/src/storages/inRedis/RedisAdapter.ts +1 -1
  33. package/src/storages/pluggable/index.ts +38 -33
  34. package/src/storages/types.ts +1 -0
  35. package/src/trackers/eventTracker.ts +10 -7
  36. package/src/trackers/impressionsTracker.ts +12 -9
  37. package/src/trackers/types.ts +1 -0
  38. package/src/trackers/uniqueKeysTracker.ts +6 -4
  39. package/types/readiness/types.d.ts +1 -0
  40. package/types/sdkFactory/types.d.ts +2 -0
  41. package/types/storages/dataLoader.d.ts +2 -2
  42. package/types/storages/types.d.ts +1 -0
  43. package/types/trackers/eventTracker.d.ts +1 -1
  44. package/types/trackers/impressionsTracker.d.ts +1 -1
  45. package/types/trackers/types.d.ts +1 -0
@@ -1,4 +1,4 @@
1
- import { IPluggableStorageWrapper, IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams, ITelemetryCacheAsync } from '../types';
1
+ import { IPluggableStorageWrapper, IStorageAsyncFactory, IStorageFactoryParams, ITelemetryCacheAsync } from '../types';
2
2
 
3
3
  import { KeyBuilderSS } from '../KeyBuilderSS';
4
4
  import { SplitsCachePluggable } from './SplitsCachePluggable';
@@ -62,11 +62,12 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
62
62
 
63
63
  const prefix = validatePrefix(options.prefix);
64
64
 
65
- function PluggableStorageFactory(params: IStorageFactoryParams): IStorageAsync {
65
+ function PluggableStorageFactory(params: IStorageFactoryParams) {
66
66
  const { onReadyCb, settings, settings: { log, mode, sync: { impressionsMode }, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
67
67
  const metadata = metadataBuilder(settings);
68
68
  const keys = new KeyBuilderSS(prefix, metadata);
69
69
  const wrapper = wrapperAdapter(log, options.wrapper);
70
+ let connectPromise: Promise<void>;
70
71
 
71
72
  const isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
72
73
  const isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
@@ -89,35 +90,6 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
89
90
  new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
90
91
  undefined;
91
92
 
92
- // Connects to wrapper and emits SDK_READY event on main client
93
- const connectPromise = wrapper.connect().then(() => {
94
- if (isSyncronizer) {
95
- // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
96
- return wrapper.get(keys.buildHashKey()).then((hash) => {
97
- const currentHash = getStorageHash(settings);
98
- if (hash !== currentHash) {
99
- log.info(LOG_PREFIX + 'Storage HASH has changed (SDK key, flags filter criteria or flags spec version was modified). Clearing cache');
100
- return wrapper.getKeysByPrefix(`${keys.prefix}.`).then(storageKeys => {
101
- return Promise.all(storageKeys.map(storageKey => wrapper.del(storageKey)));
102
- }).then(() => wrapper.set(keys.buildHashKey(), currentHash));
103
- }
104
- }).then(() => {
105
- onReadyCb();
106
- });
107
- } else {
108
- // Start periodic flush of async storages if not running synchronizer (producer mode)
109
- if (impressionCountsCache && (impressionCountsCache as ImpressionCountsCachePluggable).start) (impressionCountsCache as ImpressionCountsCachePluggable).start();
110
- if (uniqueKeysCache && (uniqueKeysCache as UniqueKeysCachePluggable).start) (uniqueKeysCache as UniqueKeysCachePluggable).start();
111
- if (telemetry && (telemetry as ITelemetryCacheAsync).recordConfig) (telemetry as ITelemetryCacheAsync).recordConfig();
112
-
113
- onReadyCb();
114
- }
115
- }).catch((e) => {
116
- e = e || new Error('Error connecting wrapper');
117
- onReadyCb(e);
118
- return e; // Propagate error for shared clients
119
- });
120
-
121
93
  return {
122
94
  splits: new SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
123
95
  segments: new SegmentsCachePluggable(log, keys, wrapper),
@@ -127,6 +99,39 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
127
99
  telemetry,
128
100
  uniqueKeys: uniqueKeysCache,
129
101
 
102
+ init() {
103
+ if (connectPromise) return connectPromise;
104
+
105
+ // Connects to wrapper and emits SDK_READY event on main client
106
+ return connectPromise = wrapper.connect().then(() => {
107
+ if (isSyncronizer) {
108
+ // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
109
+ return wrapper.get(keys.buildHashKey()).then((hash) => {
110
+ const currentHash = getStorageHash(settings);
111
+ if (hash !== currentHash) {
112
+ log.info(LOG_PREFIX + 'Storage HASH has changed (SDK key, flags filter criteria or flags spec version was modified). Clearing cache');
113
+ return wrapper.getKeysByPrefix(`${keys.prefix}.`).then(storageKeys => {
114
+ return Promise.all(storageKeys.map(storageKey => wrapper.del(storageKey)));
115
+ }).then(() => wrapper.set(keys.buildHashKey(), currentHash));
116
+ }
117
+ }).then(() => {
118
+ onReadyCb();
119
+ });
120
+ } else {
121
+ // Start periodic flush of async storages if not running synchronizer (producer mode)
122
+ if (impressionCountsCache && (impressionCountsCache as ImpressionCountsCachePluggable).start) (impressionCountsCache as ImpressionCountsCachePluggable).start();
123
+ if (uniqueKeysCache && (uniqueKeysCache as UniqueKeysCachePluggable).start) (uniqueKeysCache as UniqueKeysCachePluggable).start();
124
+ if (telemetry && (telemetry as ITelemetryCacheAsync).recordConfig) (telemetry as ITelemetryCacheAsync).recordConfig();
125
+
126
+ onReadyCb();
127
+ }
128
+ }).catch((e) => {
129
+ e = e || new Error('Error connecting wrapper');
130
+ onReadyCb(e);
131
+ return e; // Propagate error for shared clients
132
+ });
133
+ },
134
+
130
135
  // Stop periodic flush and disconnect the underlying storage
131
136
  destroy() {
132
137
  return Promise.all(isSyncronizer ? [] : [
@@ -136,8 +141,8 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
136
141
  },
137
142
 
138
143
  // emits SDK_READY event on shared clients and returns a reference to the storage
139
- shared(_, onReadyCb) {
140
- connectPromise.then(onReadyCb);
144
+ shared(_: string, onReadyCb: (error?: any) => void) {
145
+ this.init().then(onReadyCb);
141
146
 
142
147
  return {
143
148
  ...this,
@@ -462,6 +462,7 @@ export interface IStorageBase<
462
462
  events: TEventsCache,
463
463
  telemetry?: TTelemetryCache,
464
464
  uniqueKeys?: TUniqueKeysCache,
465
+ init?: () => void | Promise<void>,
465
466
  destroy(): void | Promise<void>,
466
467
  shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this
467
468
  }
@@ -16,6 +16,7 @@ import { isConsumerMode } from '../utils/settingsValidation/mode';
16
16
  export function eventTrackerFactory(
17
17
  settings: ISettings,
18
18
  eventsCache: IEventsCacheBase,
19
+ whenInit: (cb: () => void) => void,
19
20
  integrationsManager?: IEventsHandler,
20
21
  telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync
21
22
  ): IEventTracker {
@@ -32,13 +33,15 @@ export function eventTrackerFactory(
32
33
  log.info(EVENTS_TRACKER_SUCCESS, [msg]);
33
34
  if (integrationsManager) {
34
35
  // Wrap in a timeout because we don't want it to be blocking.
35
- setTimeout(function () {
36
- // copy of event, to avoid unexpected behaviour if modified by integrations
37
- const eventDataCopy = objectAssign({}, eventData);
38
- if (properties) eventDataCopy.properties = objectAssign({}, properties);
39
- // integrationsManager does not throw errors (they are internally handled by each integration module)
40
- integrationsManager.handleEvent(eventDataCopy);
41
- }, 0);
36
+ whenInit(() => {
37
+ setTimeout(() => {
38
+ // copy of event, to avoid unexpected behaviour if modified by integrations
39
+ const eventDataCopy = objectAssign({}, eventData);
40
+ if (properties) eventDataCopy.properties = objectAssign({}, properties);
41
+ // integrationsManager does not throw errors (they are internally handled by each integration module)
42
+ integrationsManager.handleEvent(eventDataCopy);
43
+ });
44
+ });
42
45
  }
43
46
  } else {
44
47
  log.error(ERROR_EVENTS_TRACKER, [msg]);
@@ -19,6 +19,7 @@ export function impressionsTrackerFactory(
19
19
  settings: ISettings,
20
20
  impressionsCache: IImpressionsCacheBase,
21
21
  strategy: IStrategy,
22
+ whenInit: (cb: () => void) => void,
22
23
  integrationsManager?: IImpressionsHandler,
23
24
  telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync,
24
25
  ): IImpressionsTracker {
@@ -67,16 +68,18 @@ export function impressionsTrackerFactory(
67
68
  };
68
69
 
69
70
  // Wrap in a timeout because we don't want it to be blocking.
70
- setTimeout(function () {
71
- // integrationsManager.handleImpression does not throw errors
72
- if (integrationsManager) integrationsManager.handleImpression(impressionData);
71
+ whenInit(() => {
72
+ setTimeout(() => {
73
+ // integrationsManager.handleImpression does not throw errors
74
+ if (integrationsManager) integrationsManager.handleImpression(impressionData);
73
75
 
74
- try { // @ts-ignore. An exception on the listeners should not break the SDK.
75
- if (impressionListener) impressionListener.logImpression(impressionData);
76
- } catch (err) {
77
- log.error(ERROR_IMPRESSIONS_LISTENER, [err]);
78
- }
79
- }, 0);
76
+ try { // @ts-ignore. An exception on the listeners should not break the SDK.
77
+ if (impressionListener) impressionListener.logImpression(impressionData);
78
+ } catch (err) {
79
+ log.error(ERROR_IMPRESSIONS_LISTENER, [err]);
80
+ }
81
+ });
82
+ });
80
83
  }
81
84
  }
82
85
  }
@@ -65,6 +65,7 @@ export interface IImpressionSenderAdapter {
65
65
 
66
66
  /** Unique keys tracker */
67
67
  export interface IUniqueKeysTracker {
68
+ start(): void;
68
69
  stop(): void;
69
70
  track(key: string, featureName: string): void;
70
71
  }
@@ -25,10 +25,6 @@ export function uniqueKeysTrackerFactory(
25
25
  ): IUniqueKeysTracker {
26
26
  let intervalId: any;
27
27
 
28
- if (filterAdapter.refreshRate) {
29
- intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
30
- }
31
-
32
28
  return {
33
29
 
34
30
  track(key: string, featureName: string): void {
@@ -39,6 +35,12 @@ export function uniqueKeysTrackerFactory(
39
35
  uniqueKeysCache.track(key, featureName);
40
36
  },
41
37
 
38
+ start(): void {
39
+ if (filterAdapter.refreshRate) {
40
+ intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
41
+ }
42
+ },
43
+
42
44
  stop(): void {
43
45
  clearInterval(intervalId);
44
46
  }
@@ -46,6 +46,7 @@ export interface IReadinessManager {
46
46
  timeout(): void;
47
47
  setDestroyed(): void;
48
48
  destroy(): void;
49
+ init(): void;
49
50
  /** for client-side */
50
51
  shared(): IReadinessManager;
51
52
  }
@@ -48,6 +48,7 @@ export interface ISdkFactoryContext {
48
48
  splitApi?: ISplitApi;
49
49
  syncManager?: ISyncManager;
50
50
  clients: Record<string, IBasicClient>;
51
+ whenInit(cb: () => void): void;
51
52
  }
52
53
  export interface ISdkFactoryContextSync extends ISdkFactoryContext {
53
54
  storage: IStorageSync;
@@ -63,6 +64,7 @@ export interface ISdkFactoryContextAsync extends ISdkFactoryContext {
63
64
  * Object parameter with the modules required to create an SDK factory instance
64
65
  */
65
66
  export interface ISdkFactoryParams {
67
+ isPure?: boolean;
66
68
  settings: ISettings;
67
69
  platform: IPlatform;
68
70
  storageFactory: (params: IStorageFactoryParams) => IStorageSync | IStorageAsync;
@@ -17,5 +17,5 @@ export declare function loadData(preloadedData: SplitIO.PreloadedData, storage:
17
17
  splits?: ISplitsCacheSync;
18
18
  segments: ISegmentsCacheSync;
19
19
  largeSegments?: ISegmentsCacheSync;
20
- }, userKey?: string): void;
21
- export declare function getSnapshot(storage: IStorageSync, userKeys?: string[]): SplitIO.PreloadedData;
20
+ }, matchingKey?: string): void;
21
+ export declare function getSnapshot(storage: IStorageSync, userKeys?: SplitIO.SplitKey[]): SplitIO.PreloadedData;
@@ -382,6 +382,7 @@ export interface IStorageBase<TSplitsCache extends ISplitsCacheBase, TSegmentsCa
382
382
  events: TEventsCache;
383
383
  telemetry?: TTelemetryCache;
384
384
  uniqueKeys?: TUniqueKeysCache;
385
+ init?: () => void | Promise<void>;
385
386
  destroy(): void | Promise<void>;
386
387
  shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this;
387
388
  }
@@ -7,4 +7,4 @@ import { ISettings } from '../types';
7
7
  * @param eventsCache cache to save events
8
8
  * @param integrationsManager optional event handler used for integrations
9
9
  */
10
- export declare function eventTrackerFactory(settings: ISettings, eventsCache: IEventsCacheBase, integrationsManager?: IEventsHandler, telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync): IEventTracker;
10
+ export declare function eventTrackerFactory(settings: ISettings, eventsCache: IEventsCacheBase, whenInit: (cb: () => void) => void, integrationsManager?: IEventsHandler, telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync): IEventTracker;
@@ -10,4 +10,4 @@ import { ISettings } from '../types';
10
10
  * @param integrationsManager optional integrations manager
11
11
  * @param strategy strategy for impressions tracking.
12
12
  */
13
- export declare function impressionsTrackerFactory(settings: ISettings, impressionsCache: IImpressionsCacheBase, strategy: IStrategy, integrationsManager?: IImpressionsHandler, telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync): IImpressionsTracker;
13
+ export declare function impressionsTrackerFactory(settings: ISettings, impressionsCache: IImpressionsCacheBase, strategy: IStrategy, whenInit: (cb: () => void) => void, integrationsManager?: IImpressionsHandler, telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync): IImpressionsTracker;
@@ -54,6 +54,7 @@ export interface IImpressionSenderAdapter {
54
54
  }
55
55
  /** Unique keys tracker */
56
56
  export interface IUniqueKeysTracker {
57
+ start(): void;
57
58
  stop(): void;
58
59
  track(key: string, featureName: string): void;
59
60
  }