@splitsoftware/splitio-commons 1.4.1 → 1.4.2-rc.2

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 (54) hide show
  1. package/CHANGES.txt +5 -0
  2. package/cjs/consent/sdkUserConsent.js +3 -3
  3. package/cjs/listeners/browser.js +7 -6
  4. package/cjs/sdkFactory/index.js +20 -2
  5. package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
  6. package/cjs/storages/dataLoader.js +23 -15
  7. package/cjs/storages/inMemory/InMemoryStorage.js +15 -1
  8. package/cjs/storages/inMemory/InMemoryStorageCS.js +12 -0
  9. package/cjs/sync/submitters/submitterManager.js +28 -4
  10. package/cjs/sync/syncManagerOnline.js +40 -29
  11. package/cjs/sync/syncTask.js +15 -10
  12. package/cjs/trackers/impressionObserver/impressionObserverCS.js +1 -1
  13. package/cjs/utils/settingsValidation/index.js +13 -1
  14. package/esm/consent/sdkUserConsent.js +3 -3
  15. package/esm/listeners/browser.js +7 -6
  16. package/esm/sdkFactory/index.js +21 -3
  17. package/esm/storages/AbstractSplitsCacheSync.js +1 -1
  18. package/esm/storages/dataLoader.js +21 -13
  19. package/esm/storages/inMemory/InMemoryStorage.js +15 -1
  20. package/esm/storages/inMemory/InMemoryStorageCS.js +12 -0
  21. package/esm/sync/submitters/submitterManager.js +28 -4
  22. package/esm/sync/syncManagerOnline.js +40 -29
  23. package/esm/sync/syncTask.js +15 -10
  24. package/esm/trackers/impressionObserver/impressionObserverCS.js +1 -1
  25. package/esm/utils/settingsValidation/index.js +13 -1
  26. package/package.json +1 -1
  27. package/src/consent/sdkUserConsent.ts +4 -3
  28. package/src/listeners/browser.ts +8 -6
  29. package/src/sdkClient/clientAttributesDecoration.ts +9 -9
  30. package/src/sdkFactory/index.ts +23 -4
  31. package/src/storages/AbstractSplitsCacheSync.ts +1 -1
  32. package/src/storages/dataLoader.ts +20 -13
  33. package/src/storages/inMemory/InMemoryStorage.ts +16 -1
  34. package/src/storages/inMemory/InMemoryStorageCS.ts +13 -0
  35. package/src/sync/submitters/submitterManager.ts +30 -4
  36. package/src/sync/submitters/types.ts +7 -0
  37. package/src/sync/syncManagerOnline.ts +35 -23
  38. package/src/sync/syncTask.ts +17 -11
  39. package/src/sync/types.ts +2 -1
  40. package/src/trackers/impressionObserver/impressionObserverCS.ts +1 -1
  41. package/src/types.ts +11 -3
  42. package/src/utils/settingsValidation/index.ts +15 -1
  43. package/types/integrations/ga/autoRequire.d.ts +4 -0
  44. package/types/storages/dataLoader.d.ts +2 -2
  45. package/types/sync/submitters/submitterManager.d.ts +2 -1
  46. package/types/sync/submitters/types.d.ts +6 -0
  47. package/types/sync/syncTask.d.ts +2 -2
  48. package/types/sync/types.d.ts +2 -1
  49. package/types/trackers/impressionObserver/impressionObserverCS.d.ts +2 -2
  50. package/types/types.d.ts +10 -2
  51. package/types/utils/settingsValidation/index.d.ts +1 -0
  52. package/cjs/sync/syncTaskComposite.js +0 -26
  53. package/esm/sync/syncTaskComposite.js +0 -22
  54. package/src/sync/syncTaskComposite.ts +0 -26
@@ -6,6 +6,8 @@ import { IStorageFactoryParams, IStorageSync } from '../types';
6
6
  import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
7
7
  import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
8
8
  import { TelemetryCacheInMemory } from './TelemetryCacheInMemory';
9
+ import { SplitIO } from '../../types';
10
+ import { setToArray, ISet } from '../../utils/lang/sets';
9
11
 
10
12
  /**
11
13
  * InMemory storage factory for standalone server-side SplitFactory
@@ -29,7 +31,20 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
29
31
  this.impressions.clear();
30
32
  this.impressionCounts && this.impressionCounts.clear();
31
33
  this.events.clear();
32
- }
34
+ },
35
+
36
+ // @ts-ignore, private method, for POC
37
+ getSnapshot(): SplitIO.PreloadedData {
38
+ return {
39
+ lastUpdated: Date.now(), // @ts-ignore accessing private prop
40
+ since: this.splits.changeNumber, // @ts-ignore accessing private prop
41
+ splitsData: this.splits.splitsCache, // @ts-ignore accessing private prop
42
+ segmentsData: Object.keys(this.segments.segmentCache).reduce((prev, cur) => { // @ts-ignore accessing private prop
43
+ prev[cur] = setToArray(this.segments.segmentCache[cur] as ISet<string>);
44
+ return prev;
45
+ }, {})
46
+ };
47
+ },
33
48
  };
34
49
  }
35
50
 
@@ -6,6 +6,7 @@ import { IStorageSync, IStorageFactoryParams } from '../types';
6
6
  import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
7
7
  import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
8
8
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
9
+ import { SplitIO } from '../../types';
9
10
 
10
11
  /**
11
12
  * InMemory storage factory for standalone client-side SplitFactory
@@ -31,6 +32,18 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
31
32
  this.events.clear();
32
33
  },
33
34
 
35
+ // @ts-ignore, private method, for POC
36
+ getSnapshot(): SplitIO.PreloadedData {
37
+ return {
38
+ lastUpdated: Date.now(), // @ts-ignore accessing private prop
39
+ since: this.splits.changeNumber, // @ts-ignore accessing private prop
40
+ splitsData: this.splits.splitsCache,
41
+ mySegmentsData: { // @ts-ignore accessing private prop
42
+ [params.matchingKey as string]: Object.keys(this.segments.segmentCache)
43
+ }
44
+ };
45
+ },
46
+
34
47
  // When using shared instanciation with MEMORY we reuse everything but segments (they are unique per key)
35
48
  shared() {
36
49
  return {
@@ -1,11 +1,11 @@
1
- import { syncTaskComposite } from '../syncTaskComposite';
2
1
  import { eventsSubmitterFactory } from './eventsSubmitter';
3
2
  import { impressionsSubmitterFactory } from './impressionsSubmitter';
4
3
  import { impressionCountsSubmitterFactory } from './impressionCountsSubmitter';
5
4
  import { telemetrySubmitterFactory } from './telemetrySubmitter';
6
5
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
6
+ import { ISubmitterManager } from './types';
7
7
 
8
- export function submitterManagerFactory(params: ISdkFactoryContextSync) {
8
+ export function submitterManagerFactory(params: ISdkFactoryContextSync): ISubmitterManager {
9
9
 
10
10
  const submitters = [
11
11
  impressionsSubmitterFactory(params),
@@ -15,7 +15,33 @@ export function submitterManagerFactory(params: ISdkFactoryContextSync) {
15
15
  const impressionCountsSubmitter = impressionCountsSubmitterFactory(params);
16
16
  if (impressionCountsSubmitter) submitters.push(impressionCountsSubmitter);
17
17
  const telemetrySubmitter = telemetrySubmitterFactory(params);
18
- if (telemetrySubmitter) submitters.push(telemetrySubmitter);
19
18
 
20
- return syncTaskComposite(submitters);
19
+ return {
20
+ // `onlyTelemetry` true if SDK is created with userConsent not GRANTED
21
+ start(onlyTelemetry?: boolean) {
22
+ if (!onlyTelemetry) submitters.forEach(submitter => submitter.start());
23
+ if (telemetrySubmitter) telemetrySubmitter.start();
24
+ },
25
+
26
+ // `allExceptTelemetry` true if userConsent is changed to DECLINED
27
+ stop(allExceptTelemetry?: boolean) {
28
+ submitters.forEach(submitter => submitter.stop());
29
+ if (!allExceptTelemetry && telemetrySubmitter) telemetrySubmitter.stop();
30
+ },
31
+
32
+ isRunning() {
33
+ return submitters.some(submitter => submitter.isRunning());
34
+ },
35
+
36
+ // Flush data. Called with `onlyTelemetry` true if SDK is destroyed with userConsent not GRANTED
37
+ execute(onlyTelemetry?: boolean) {
38
+ const promises = onlyTelemetry ? [] : submitters.map(submitter => submitter.execute());
39
+ if (telemetrySubmitter) promises.push(telemetrySubmitter.execute());
40
+ return Promise.all(promises);
41
+ },
42
+
43
+ isExecuting() {
44
+ return submitters.some(submitter => submitter.isExecuting());
45
+ }
46
+ };
21
47
  }
@@ -1,5 +1,6 @@
1
1
  import { IMetadata } from '../../dtos/types';
2
2
  import { SplitIO } from '../../types';
3
+ import { ISyncTask } from '../types';
3
4
 
4
5
  export type ImpressionsPayload = {
5
6
  /** Split name */
@@ -191,3 +192,9 @@ export type TelemetryConfigStatsPayload = TelemetryConfigStats & {
191
192
  i?: Array<string>, // integrations
192
193
  uC: number, // userConsent
193
194
  }
195
+
196
+ export interface ISubmitterManager extends ISyncTask {
197
+ start(onlyTelemetry?: boolean): void,
198
+ stop(allExceptTelemetry?: boolean): void,
199
+ execute(onlyTelemetry?: boolean): Promise<any>
200
+ }
@@ -28,19 +28,19 @@ export function syncManagerOnlineFactory(
28
28
  */
29
29
  return function (params: ISdkFactoryContextSync): ISyncManagerCS {
30
30
 
31
- const { settings, settings: { log, streamingEnabled }, telemetryTracker } = params;
31
+ const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled, onlySubmitters } }, telemetryTracker } = params;
32
32
 
33
33
  /** Polling Manager */
34
- const pollingManager = pollingManagerFactory && pollingManagerFactory(params);
34
+ const pollingManager = onlySubmitters ? undefined : pollingManagerFactory && pollingManagerFactory(params);
35
35
 
36
36
  /** Push Manager */
37
- const pushManager = streamingEnabled && pollingManager && pushManagerFactory ?
37
+ const pushManager = syncEnabled && streamingEnabled && pollingManager && pushManagerFactory ?
38
38
  pushManagerFactory(params, pollingManager) :
39
39
  undefined;
40
40
 
41
41
  /** Submitter Manager */
42
42
  // It is not inyected as push and polling managers, because at the moment it is required
43
- const submitter = submitterManagerFactory(params);
43
+ const submitterManager = submitterManagerFactory(params);
44
44
 
45
45
  /** Sync Manager logic */
46
46
 
@@ -79,7 +79,7 @@ export function syncManagerOnlineFactory(
79
79
  // E.g.: user consent, app state changes (Page hide, Foreground/Background, Online/Offline).
80
80
  pollingManager,
81
81
  pushManager,
82
- submitter,
82
+ submitterManager,
83
83
 
84
84
  /**
85
85
  * Method used to start the syncManager for the first time, or resume it after being stopped.
@@ -89,20 +89,29 @@ export function syncManagerOnlineFactory(
89
89
 
90
90
  // start syncing splits and segments
91
91
  if (pollingManager) {
92
- if (pushManager) {
93
- // Doesn't call `syncAll` when the syncManager is resuming
92
+
93
+ // If synchronization is disabled pushManager and pollingManager should not start
94
+ if (syncEnabled) {
95
+ if (pushManager) {
96
+ // Doesn't call `syncAll` when the syncManager is resuming
97
+ if (startFirstTime) {
98
+ pollingManager.syncAll();
99
+ startFirstTime = false;
100
+ }
101
+ pushManager.start();
102
+ } else {
103
+ pollingManager.start();
104
+ }
105
+ } else {
94
106
  if (startFirstTime) {
95
107
  pollingManager.syncAll();
96
108
  startFirstTime = false;
97
109
  }
98
- pushManager.start();
99
- } else {
100
- pollingManager.start();
101
110
  }
102
111
  }
103
112
 
104
113
  // start periodic data recording (events, impressions, telemetry).
105
- if (isConsentGranted(settings)) submitter.start();
114
+ submitterManager.start(!isConsentGranted(settings));
106
115
  },
107
116
 
108
117
  /**
@@ -116,7 +125,7 @@ export function syncManagerOnlineFactory(
116
125
  if (pollingManager && pollingManager.isRunning()) pollingManager.stop();
117
126
 
118
127
  // stop periodic data recording (events, impressions, telemetry).
119
- submitter.stop();
128
+ submitterManager.stop();
120
129
  },
121
130
 
122
131
  isRunning() {
@@ -124,8 +133,7 @@ export function syncManagerOnlineFactory(
124
133
  },
125
134
 
126
135
  flush() {
127
- if (isConsentGranted(settings)) return submitter.execute();
128
- else return Promise.resolve();
136
+ return submitterManager.execute(!isConsentGranted(settings));
129
137
  },
130
138
 
131
139
  // [Only used for client-side]
@@ -138,18 +146,22 @@ export function syncManagerOnlineFactory(
138
146
  return {
139
147
  isRunning: mySegmentsSyncTask.isRunning,
140
148
  start() {
141
- if (pushManager) {
142
- if (pollingManager!.isRunning()) {
143
- // if doing polling, we must start the periodic fetch of data
144
- if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
149
+ if (syncEnabled) {
150
+ if (pushManager) {
151
+ if (pollingManager!.isRunning()) {
152
+ // if doing polling, we must start the periodic fetch of data
153
+ if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
154
+ } else {
155
+ // if not polling, we must execute the sync task for the initial fetch
156
+ // of segments since `syncAll` was already executed when starting the main client
157
+ mySegmentsSyncTask.execute();
158
+ }
159
+ pushManager.add(matchingKey, mySegmentsSyncTask);
145
160
  } else {
146
- // if not polling, we must execute the sync task for the initial fetch
147
- // of segments since `syncAll` was already executed when starting the main client
148
- mySegmentsSyncTask.execute();
161
+ if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
149
162
  }
150
- pushManager.add(matchingKey, mySegmentsSyncTask);
151
163
  } else {
152
- if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
164
+ if (!readinessManager.isReady()) mySegmentsSyncTask.execute();
153
165
  }
154
166
  },
155
167
  stop() {
@@ -4,8 +4,8 @@ import { ISyncTask } from './types';
4
4
 
5
5
  /**
6
6
  * Creates a syncTask that handles the periodic execution of a given task ("start" and "stop" methods).
7
- * The task can be executed once calling the "execute" method.
8
- * NOTE: Multiple calls to "execute" are not queued. Use "isExecuting" method to handle synchronization.
7
+ * The task can be also executed by calling the "execute" method. Multiple execute calls are chained to run secuentially and avoid race conditions.
8
+ * For example, submitters executed on SDK destroy or full queue, while periodic execution is pending.
9
9
  *
10
10
  * @param log Logger instance.
11
11
  * @param task Task to execute that returns a promise that NEVER REJECTS. Otherwise, periodic execution can result in Unhandled Promise Rejections.
@@ -15,8 +15,8 @@ import { ISyncTask } from './types';
15
15
  */
16
16
  export function syncTaskFactory<Input extends any[], Output = any>(log: ILogger, task: (...args: Input) => Promise<Output>, period: number, taskName = 'task'): ISyncTask<Input, Output> {
17
17
 
18
- // Flag that indicates if the task is being executed
19
- let executing = false;
18
+ // Task promise while it is pending. Undefined once the promise is resolved
19
+ let pendingTask: Promise<Output> | undefined;
20
20
  // flag that indicates if the task periodic execution has been started/stopped.
21
21
  let running = false;
22
22
  // Auxiliar counter used to avoid race condition when calling `start` & `stop` intermittently
@@ -26,14 +26,21 @@ export function syncTaskFactory<Input extends any[], Output = any>(log: ILogger,
26
26
  // Id of the periodic call timeout
27
27
  let timeoutID: any;
28
28
 
29
- function execute(...args: Input) {
30
- executing = true;
29
+ function execute(...args: Input): Promise<Output> {
30
+ // If task is executing, chain the new execution
31
+ if (pendingTask) {
32
+ return pendingTask.then(() => {
33
+ return execute(...args);
34
+ });
35
+ }
36
+
37
+ // Execute task
31
38
  log.debug(SYNC_TASK_EXECUTE, [taskName]);
32
- return task(...args).then(result => {
33
- executing = false;
39
+ pendingTask = task(...args).then(result => {
40
+ pendingTask = undefined;
34
41
  return result;
35
42
  });
36
- // No need to handle promise rejection because it is a pre-condition that provided task never rejects.
43
+ return pendingTask;
37
44
  }
38
45
 
39
46
  function periodicExecute(currentRunningId: number) {
@@ -46,11 +53,10 @@ export function syncTaskFactory<Input extends any[], Output = any>(log: ILogger,
46
53
  }
47
54
 
48
55
  return {
49
- // @TODO check if we need to queued `execute` calls, to avoid possible race conditions on submitters and updaters with streaming.
50
56
  execute,
51
57
 
52
58
  isExecuting() {
53
- return executing;
59
+ return pendingTask !== undefined;
54
60
  },
55
61
 
56
62
  start(...args: Input) {
package/src/sync/types.ts CHANGED
@@ -2,6 +2,7 @@ import { IReadinessManager } from '../readiness/types';
2
2
  import { IStorageSync } from '../storages/types';
3
3
  import { IPollingManager } from './polling/types';
4
4
  import { IPushManager } from './streaming/types';
5
+ import { ISubmitterManager } from './submitters/types';
5
6
 
6
7
  export interface ITask<Input extends any[] = []> {
7
8
  /**
@@ -39,7 +40,7 @@ export interface ISyncManager extends ITask {
39
40
  flush(): Promise<any>,
40
41
  pushManager?: IPushManager,
41
42
  pollingManager?: IPollingManager,
42
- submitter?: ISyncTask
43
+ submitterManager?: ISubmitterManager
43
44
  }
44
45
 
45
46
  export interface ISyncManagerCS extends ISyncManager {
@@ -4,7 +4,7 @@ import { buildKey } from './buildKey';
4
4
  import { ImpressionDTO } from '../../types';
5
5
 
6
6
  export function hashImpression32(impression: ImpressionDTO) {
7
- return hash(buildKey(impression));
7
+ return hash(buildKey(impression)).toString();
8
8
  }
9
9
 
10
10
  const LAST_SEEN_CACHE_SIZE = 500; // cache up to 500 impression hashes
package/src/types.ts CHANGED
@@ -4,7 +4,7 @@ import { ILogger } from './logger/types';
4
4
  import { ISdkFactoryContext } from './sdkFactory/types';
5
5
  /* eslint-disable no-use-before-define */
6
6
 
7
- import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory } from './storages/types';
7
+ import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory, DataLoader } from './storages/types';
8
8
  import { ISyncManagerCS } from './sync/types';
9
9
 
10
10
  /**
@@ -98,6 +98,7 @@ export interface ISettings {
98
98
  eventsFirstPushWindow: number
99
99
  },
100
100
  readonly storage: IStorageSyncFactory | IStorageAsyncFactory,
101
+ readonly dataLoader?: DataLoader,
101
102
  readonly integrations: Array<{
102
103
  readonly type: string,
103
104
  (params: IIntegrationFactoryParams): IIntegration | void
@@ -117,7 +118,9 @@ export interface ISettings {
117
118
  splitFilters: SplitIO.SplitFilter[],
118
119
  impressionsMode: SplitIO.ImpressionsMode,
119
120
  __splitFiltersValidation: ISplitFiltersValidation,
120
- localhostMode?: SplitIO.LocalhostFactory
121
+ localhostMode?: SplitIO.LocalhostFactory,
122
+ enabled: boolean,
123
+ onlySubmitters: boolean
121
124
  },
122
125
  readonly runtime: {
123
126
  ip: string | false
@@ -214,6 +217,11 @@ interface ISharedSettings {
214
217
  * @default 'OPTIMIZED'
215
218
  */
216
219
  impressionsMode?: SplitIO.ImpressionsMode,
220
+ /**
221
+ * Enables synchronization.
222
+ * @property {boolean} enabled
223
+ */
224
+ enabled: boolean
217
225
  }
218
226
  }
219
227
  /**
@@ -746,7 +754,7 @@ export namespace SplitIO {
746
754
  * This property is ignored if `mySegmentsData` was provided.
747
755
  */
748
756
  segmentsData?: {
749
- [segmentName: string]: string
757
+ [segmentName: string]: string[]
750
758
  },
751
759
  }
752
760
  /**
@@ -83,7 +83,8 @@ export const base = {
83
83
  splitFilters: undefined,
84
84
  // impressions collection mode
85
85
  impressionsMode: OPTIMIZED,
86
- localhostMode: undefined
86
+ localhostMode: undefined,
87
+ enabled: true
87
88
  },
88
89
 
89
90
  // Logger
@@ -146,6 +147,9 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
146
147
  // ensure a valid SDK mode
147
148
  // @ts-ignore, modify readonly prop
148
149
  withDefaults.mode = mode(withDefaults.core.authorizationKey, withDefaults.mode);
150
+ if (withDefaults.sync.onlySubmitters && withDefaults.mode === STANDALONE_MODE && !withDefaults.dataLoader) {
151
+ throw new Error('To use `onlySubmitters` param in standalone mode, DataLoader is required to preload data into the storage');
152
+ }
149
153
 
150
154
  // ensure a valid Storage based on mode defined.
151
155
  // @ts-ignore, modify readonly prop
@@ -191,6 +195,16 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
191
195
  scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase);
192
196
  }
193
197
 
198
+ // validate sync enabled
199
+ if (withDefaults.sync.enabled !== false) {
200
+ withDefaults.sync.enabled = true;
201
+ }
202
+
203
+ // validate sync onlySubmitters
204
+ if (withDefaults.sync.onlySubmitters !== true) {
205
+ withDefaults.sync.onlySubmitters = false;
206
+ }
207
+
194
208
  // validate the `splitFilters` settings and parse splits query
195
209
  const splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
196
210
  withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Auto-require script to use with GaToSplit integration
3
+ */
4
+ export declare function autoRequire(): void;
@@ -1,10 +1,10 @@
1
1
  import { SplitIO } from '../types';
2
2
  import { DataLoader } from './types';
3
3
  /**
4
- * Factory of client-side storage loader
4
+ * Factory of storage loader
5
5
  *
6
6
  * @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
7
7
  * and extended with a `mySegmentsData` property.
8
8
  * @returns function to preload the storage
9
9
  */
10
- export declare function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader;
10
+ export declare function DataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader;
@@ -1,2 +1,3 @@
1
1
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
2
- export declare function submitterManagerFactory(params: ISdkFactoryContextSync): import("../types").ISyncTask<[], any>;
2
+ import { ISubmitterManager } from './types';
3
+ export declare function submitterManagerFactory(params: ISdkFactoryContextSync): ISubmitterManager;
@@ -1,5 +1,6 @@
1
1
  import { IMetadata } from '../../dtos/types';
2
2
  import { SplitIO } from '../../types';
3
+ import { ISyncTask } from '../types';
3
4
  export declare type ImpressionsPayload = {
4
5
  /** Split name */
5
6
  f: string;
@@ -169,3 +170,8 @@ export declare type TelemetryConfigStatsPayload = TelemetryConfigStats & {
169
170
  i?: Array<string>;
170
171
  uC: number;
171
172
  };
173
+ export interface ISubmitterManager extends ISyncTask {
174
+ start(onlyTelemetry?: boolean): void;
175
+ stop(allExceptTelemetry?: boolean): void;
176
+ execute(onlyTelemetry?: boolean): Promise<any>;
177
+ }
@@ -2,8 +2,8 @@ import { ILogger } from '../logger/types';
2
2
  import { ISyncTask } from './types';
3
3
  /**
4
4
  * Creates a syncTask that handles the periodic execution of a given task ("start" and "stop" methods).
5
- * The task can be executed once calling the "execute" method.
6
- * NOTE: Multiple calls to "execute" are not queued. Use "isExecuting" method to handle synchronization.
5
+ * The task can be also executed by calling the "execute" method. Multiple execute calls are chained to run secuentially and avoid race conditions.
6
+ * For example, submitters executed on SDK destroy or full queue, while periodic execution is pending.
7
7
  *
8
8
  * @param log Logger instance.
9
9
  * @param task Task to execute that returns a promise that NEVER REJECTS. Otherwise, periodic execution can result in Unhandled Promise Rejections.
@@ -2,6 +2,7 @@ import { IReadinessManager } from '../readiness/types';
2
2
  import { IStorageSync } from '../storages/types';
3
3
  import { IPollingManager } from './polling/types';
4
4
  import { IPushManager } from './streaming/types';
5
+ import { ISubmitterManager } from './submitters/types';
5
6
  export interface ITask<Input extends any[] = []> {
6
7
  /**
7
8
  * Start periodic execution of the task
@@ -35,7 +36,7 @@ export interface ISyncManager extends ITask {
35
36
  flush(): Promise<any>;
36
37
  pushManager?: IPushManager;
37
38
  pollingManager?: IPollingManager;
38
- submitter?: ISyncTask;
39
+ submitterManager?: ISubmitterManager;
39
40
  }
40
41
  export interface ISyncManagerCS extends ISyncManager {
41
42
  shared(matchingKey: string, readinessManager: IReadinessManager, storage: IStorageSync): ISyncManager | undefined;
@@ -1,4 +1,4 @@
1
1
  import { ImpressionObserver } from './ImpressionObserver';
2
2
  import { ImpressionDTO } from '../../types';
3
- export declare function hashImpression32(impression: ImpressionDTO): number;
4
- export declare function impressionObserverCSFactory(): ImpressionObserver<number>;
3
+ export declare function hashImpression32(impression: ImpressionDTO): string;
4
+ export declare function impressionObserverCSFactory(): ImpressionObserver<string>;
package/types/types.d.ts CHANGED
@@ -2,7 +2,7 @@ import { ISplitFiltersValidation } from './dtos/types';
2
2
  import { IIntegration, IIntegrationFactoryParams } from './integrations/types';
3
3
  import { ILogger } from './logger/types';
4
4
  import { ISdkFactoryContext } from './sdkFactory/types';
5
- import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory } from './storages/types';
5
+ import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory, DataLoader } from './storages/types';
6
6
  import { ISyncManagerCS } from './sync/types';
7
7
  /**
8
8
  * Reduced version of NodeJS.EventEmitter interface with the minimal methods used by the SDK
@@ -92,6 +92,7 @@ export interface ISettings {
92
92
  eventsFirstPushWindow: number;
93
93
  };
94
94
  readonly storage: IStorageSyncFactory | IStorageAsyncFactory;
95
+ readonly dataLoader?: DataLoader;
95
96
  readonly integrations: Array<{
96
97
  readonly type: string;
97
98
  (params: IIntegrationFactoryParams): IIntegration | void;
@@ -112,6 +113,8 @@ export interface ISettings {
112
113
  impressionsMode: SplitIO.ImpressionsMode;
113
114
  __splitFiltersValidation: ISplitFiltersValidation;
114
115
  localhostMode?: SplitIO.LocalhostFactory;
116
+ enabled: boolean;
117
+ onlySubmitters: boolean;
115
118
  };
116
119
  readonly runtime: {
117
120
  ip: string | false;
@@ -208,6 +211,11 @@ interface ISharedSettings {
208
211
  * @default 'OPTIMIZED'
209
212
  */
210
213
  impressionsMode?: SplitIO.ImpressionsMode;
214
+ /**
215
+ * Enables synchronization.
216
+ * @property {boolean} enabled
217
+ */
218
+ enabled: boolean;
211
219
  };
212
220
  }
213
221
  /**
@@ -743,7 +751,7 @@ export declare namespace SplitIO {
743
751
  * This property is ignored if `mySegmentsData` was provided.
744
752
  */
745
753
  segmentsData?: {
746
- [segmentName: string]: string;
754
+ [segmentName: string]: string[];
747
755
  };
748
756
  }
749
757
  /**
@@ -37,6 +37,7 @@ export declare const base: {
37
37
  splitFilters: undefined;
38
38
  impressionsMode: string;
39
39
  localhostMode: undefined;
40
+ enabled: boolean;
40
41
  };
41
42
  log: undefined;
42
43
  };
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.syncTaskComposite = void 0;
4
- /**
5
- * Composite Sync Task: group of sync tasks that are treated as a single one.
6
- */
7
- function syncTaskComposite(syncTasks) {
8
- return {
9
- start: function () {
10
- syncTasks.forEach(function (syncTask) { return syncTask.start(); });
11
- },
12
- stop: function () {
13
- syncTasks.forEach(function (syncTask) { return syncTask.stop(); });
14
- },
15
- isRunning: function () {
16
- return syncTasks.some(function (syncTask) { return syncTask.isRunning(); });
17
- },
18
- execute: function () {
19
- return Promise.all(syncTasks.map(function (syncTask) { return syncTask.execute(); }));
20
- },
21
- isExecuting: function () {
22
- return syncTasks.some(function (syncTask) { return syncTask.isExecuting(); });
23
- }
24
- };
25
- }
26
- exports.syncTaskComposite = syncTaskComposite;
@@ -1,22 +0,0 @@
1
- /**
2
- * Composite Sync Task: group of sync tasks that are treated as a single one.
3
- */
4
- export function syncTaskComposite(syncTasks) {
5
- return {
6
- start: function () {
7
- syncTasks.forEach(function (syncTask) { return syncTask.start(); });
8
- },
9
- stop: function () {
10
- syncTasks.forEach(function (syncTask) { return syncTask.stop(); });
11
- },
12
- isRunning: function () {
13
- return syncTasks.some(function (syncTask) { return syncTask.isRunning(); });
14
- },
15
- execute: function () {
16
- return Promise.all(syncTasks.map(function (syncTask) { return syncTask.execute(); }));
17
- },
18
- isExecuting: function () {
19
- return syncTasks.some(function (syncTask) { return syncTask.isExecuting(); });
20
- }
21
- };
22
- }
@@ -1,26 +0,0 @@
1
- import { ISyncTask } from './types';
2
-
3
- /**
4
- * Composite Sync Task: group of sync tasks that are treated as a single one.
5
- */
6
- export function syncTaskComposite(syncTasks: ISyncTask[]): ISyncTask {
7
-
8
- return {
9
- start() {
10
- syncTasks.forEach(syncTask => syncTask.start());
11
- },
12
- stop() {
13
- syncTasks.forEach(syncTask => syncTask.stop());
14
- },
15
- isRunning() {
16
- return syncTasks.some(syncTask => syncTask.isRunning());
17
- },
18
- execute() {
19
- return Promise.all(syncTasks.map(syncTask => syncTask.execute()));
20
- },
21
- isExecuting() {
22
- return syncTasks.some(syncTask => syncTask.isExecuting());
23
- }
24
- };
25
-
26
- }