@splitsoftware/splitio-commons 2.0.0-rc.0 → 2.0.0-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 (114) hide show
  1. package/CHANGES.txt +5 -1
  2. package/cjs/evaluator/Engine.js +1 -1
  3. package/cjs/evaluator/index.js +1 -1
  4. package/cjs/readiness/readinessManager.js +13 -2
  5. package/cjs/sdkClient/sdkClientMethodCS.js +0 -1
  6. package/cjs/sdkFactory/index.js +29 -9
  7. package/cjs/storages/{AbstractSegmentsCacheSync.js → AbstractMySegmentsCacheSync.js} +15 -17
  8. package/cjs/storages/dataLoader.js +99 -37
  9. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +5 -5
  10. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +3 -2
  11. package/cjs/storages/inLocalStorage/index.js +1 -1
  12. package/cjs/storages/inMemory/InMemoryStorageCS.js +18 -6
  13. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +5 -5
  14. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +13 -27
  15. package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -1
  16. package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +2 -1
  17. package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -1
  18. package/cjs/storages/inRedis/RedisAdapter.js +2 -1
  19. package/cjs/storages/inRedis/SegmentsCacheInRedis.js +13 -19
  20. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +2 -1
  21. package/cjs/storages/pluggable/SegmentsCachePluggable.js +11 -32
  22. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -1
  23. package/cjs/storages/pluggable/inMemoryWrapper.js +2 -1
  24. package/cjs/sync/offline/syncManagerOffline.js +18 -11
  25. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +12 -28
  26. package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -1
  27. package/cjs/sync/syncManagerOnline.js +20 -21
  28. package/cjs/trackers/eventTracker.js +12 -10
  29. package/cjs/trackers/impressionsTracker.js +16 -14
  30. package/cjs/trackers/uniqueKeysTracker.js +5 -3
  31. package/cjs/utils/lang/sets.js +12 -2
  32. package/esm/evaluator/Engine.js +1 -1
  33. package/esm/evaluator/index.js +2 -2
  34. package/esm/readiness/readinessManager.js +13 -2
  35. package/esm/sdkClient/sdkClientMethodCS.js +0 -1
  36. package/esm/sdkFactory/index.js +30 -10
  37. package/esm/storages/{AbstractSegmentsCacheSync.js → AbstractMySegmentsCacheSync.js} +14 -16
  38. package/esm/storages/dataLoader.js +96 -35
  39. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +5 -5
  40. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +3 -2
  41. package/esm/storages/inLocalStorage/index.js +1 -1
  42. package/esm/storages/inMemory/InMemoryStorageCS.js +18 -6
  43. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +5 -5
  44. package/esm/storages/inMemory/SegmentsCacheInMemory.js +13 -27
  45. package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -1
  46. package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +2 -1
  47. package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -1
  48. package/esm/storages/inRedis/RedisAdapter.js +2 -1
  49. package/esm/storages/inRedis/SegmentsCacheInRedis.js +13 -19
  50. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +2 -1
  51. package/esm/storages/pluggable/SegmentsCachePluggable.js +11 -32
  52. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +2 -1
  53. package/esm/storages/pluggable/inMemoryWrapper.js +2 -1
  54. package/esm/sync/offline/syncManagerOffline.js +18 -11
  55. package/esm/sync/polling/updaters/segmentChangesUpdater.js +12 -28
  56. package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -1
  57. package/esm/sync/syncManagerOnline.js +20 -21
  58. package/esm/trackers/eventTracker.js +12 -10
  59. package/esm/trackers/impressionsTracker.js +16 -14
  60. package/esm/trackers/uniqueKeysTracker.js +5 -3
  61. package/esm/utils/lang/sets.js +10 -1
  62. package/package.json +1 -1
  63. package/src/evaluator/Engine.ts +1 -1
  64. package/src/evaluator/index.ts +2 -2
  65. package/src/readiness/readinessManager.ts +12 -3
  66. package/src/readiness/types.ts +3 -0
  67. package/src/sdkClient/sdkClientMethodCS.ts +0 -2
  68. package/src/sdkFactory/index.ts +34 -12
  69. package/src/sdkFactory/types.ts +2 -0
  70. package/src/storages/{AbstractSegmentsCacheSync.ts → AbstractMySegmentsCacheSync.ts} +13 -28
  71. package/src/storages/dataLoader.ts +97 -38
  72. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +5 -5
  73. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +3 -2
  74. package/src/storages/inLocalStorage/index.ts +1 -1
  75. package/src/storages/inMemory/InMemoryStorageCS.ts +21 -6
  76. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +5 -5
  77. package/src/storages/inMemory/SegmentsCacheInMemory.ts +12 -26
  78. package/src/storages/inMemory/SplitsCacheInMemory.ts +0 -1
  79. package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +2 -1
  80. package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +2 -1
  81. package/src/storages/inRedis/RedisAdapter.ts +2 -1
  82. package/src/storages/inRedis/SegmentsCacheInRedis.ts +13 -22
  83. package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +2 -1
  84. package/src/storages/pluggable/SegmentsCachePluggable.ts +11 -35
  85. package/src/storages/pluggable/UniqueKeysCachePluggable.ts +2 -1
  86. package/src/storages/pluggable/inMemoryWrapper.ts +2 -1
  87. package/src/storages/types.ts +7 -11
  88. package/src/sync/offline/syncManagerOffline.ts +21 -13
  89. package/src/sync/polling/updaters/segmentChangesUpdater.ts +13 -29
  90. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -1
  91. package/src/sync/syncManagerOnline.ts +17 -17
  92. package/src/sync/types.ts +1 -1
  93. package/src/trackers/eventTracker.ts +11 -8
  94. package/src/trackers/impressionsTracker.ts +13 -10
  95. package/src/trackers/types.ts +1 -0
  96. package/src/trackers/uniqueKeysTracker.ts +6 -4
  97. package/src/types.ts +14 -13
  98. package/src/utils/lang/sets.ts +11 -1
  99. package/types/readiness/types.d.ts +3 -0
  100. package/types/sdkFactory/types.d.ts +1 -0
  101. package/types/storages/dataLoader.d.ts +17 -6
  102. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +5 -5
  103. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +5 -5
  104. package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +5 -7
  105. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +0 -1
  106. package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +6 -3
  107. package/types/storages/pluggable/SegmentsCachePluggable.d.ts +4 -16
  108. package/types/storages/types.d.ts +7 -10
  109. package/types/sync/types.d.ts +1 -1
  110. package/types/trackers/eventTracker.d.ts +1 -1
  111. package/types/trackers/impressionsTracker.d.ts +1 -1
  112. package/types/trackers/types.d.ts +1 -0
  113. package/types/types.d.ts +13 -13
  114. package/types/utils/lang/sets.d.ts +1 -0
@@ -6,7 +6,6 @@ var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
6
6
  var lang_1 = require("../../utils/lang");
7
7
  /**
8
8
  * Default ISplitsCacheSync implementation that stores split definitions in memory.
9
- * Supported by all JS runtimes.
10
9
  */
11
10
  var SplitsCacheInMemory = /** @class */ (function (_super) {
12
11
  (0, tslib_1.__extends)(SplitsCacheInMemory, _super);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UniqueKeysCacheInMemory = exports.fromUniqueKeysCollector = void 0;
4
4
  var constants_1 = require("../inRedis/constants");
5
+ var sets_1 = require("../../utils/lang/sets");
5
6
  /**
6
7
  * Converts `uniqueKeys` data from cache into request payload for SS.
7
8
  */
@@ -10,7 +11,7 @@ function fromUniqueKeysCollector(uniqueKeys) {
10
11
  var featureNames = Object.keys(uniqueKeys);
11
12
  for (var i = 0; i < featureNames.length; i++) {
12
13
  var featureName = featureNames[i];
13
- var userKeys = Array.from(uniqueKeys[featureName]);
14
+ var userKeys = (0, sets_1.setToArray)(uniqueKeys[featureName]);
14
15
  var uniqueKeysPayload = {
15
16
  f: featureName,
16
17
  ks: userKeys
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UniqueKeysCacheInMemoryCS = void 0;
4
4
  var constants_1 = require("../inRedis/constants");
5
+ var sets_1 = require("../../utils/lang/sets");
5
6
  var UniqueKeysCacheInMemoryCS = /** @class */ (function () {
6
7
  /**
7
8
  *
@@ -61,7 +62,7 @@ var UniqueKeysCacheInMemoryCS = /** @class */ (function () {
61
62
  var userKeys = Object.keys(uniqueKeys);
62
63
  for (var k = 0; k < userKeys.length; k++) {
63
64
  var userKey = userKeys[k];
64
- var featureNames = Array.from(uniqueKeys[userKey]);
65
+ var featureNames = (0, sets_1.setToArray)(uniqueKeys[userKey]);
65
66
  var uniqueKeysPayload = {
66
67
  k: userKey,
67
68
  fs: featureNames
@@ -6,6 +6,7 @@ var ioredis_1 = (0, tslib_1.__importDefault)(require("ioredis"));
6
6
  var lang_1 = require("../../utils/lang");
7
7
  var thenable_1 = require("../../utils/promise/thenable");
8
8
  var timeout_1 = require("../../utils/promise/timeout");
9
+ var sets_1 = require("../../utils/lang/sets");
9
10
  var LOG_PREFIX = 'storage:redis-adapter: ';
10
11
  // If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis.
11
12
  var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'expire', 'mget', 'lrange', 'ltrim', 'hset', 'hincrby', 'popNRaw'];
@@ -128,7 +129,7 @@ var RedisAdapter = /** @class */ (function (_super) {
128
129
  setTimeout(function deferredDisconnect() {
129
130
  if (instance._runningCommands.size > 0) {
130
131
  instance.log.info(LOG_PREFIX + ("Attempting to disconnect but there are " + instance._runningCommands.size + " commands still waiting for resolution. Defering disconnection until those finish."));
131
- Promise.all(Array.from(instance._runningCommands))
132
+ Promise.all((0, sets_1.setToArray)(instance._runningCommands))
132
133
  .then(function () {
133
134
  instance.log.debug(LOG_PREFIX + 'Pending commands finished successfully, disconnecting.');
134
135
  originalMethod.apply(instance, params);
@@ -9,30 +9,24 @@ var SegmentsCacheInRedis = /** @class */ (function () {
9
9
  this.redis = redis;
10
10
  this.keys = keys;
11
11
  }
12
- SegmentsCacheInRedis.prototype.addToSegment = function (name, segmentKeys) {
12
+ /**
13
+ * Update the given segment `name` with the lists of `addedKeys`, `removedKeys` and `changeNumber`.
14
+ * The returned promise is resolved if the operation success, with `true` if the segment was updated (i.e., some key was added or removed),
15
+ * or rejected if it fails (e.g., Redis operation fails).
16
+ */
17
+ SegmentsCacheInRedis.prototype.update = function (name, addedKeys, removedKeys, changeNumber) {
13
18
  var segmentKey = this.keys.buildSegmentNameKey(name);
14
- if (segmentKeys.length) {
15
- return this.redis.sadd(segmentKey, segmentKeys).then(function () { return true; });
16
- }
17
- else {
18
- return Promise.resolve(true);
19
- }
20
- };
21
- SegmentsCacheInRedis.prototype.removeFromSegment = function (name, segmentKeys) {
22
- var segmentKey = this.keys.buildSegmentNameKey(name);
23
- if (segmentKeys.length) {
24
- return this.redis.srem(segmentKey, segmentKeys).then(function () { return true; });
25
- }
26
- else {
27
- return Promise.resolve(true);
28
- }
19
+ return Promise.all([
20
+ addedKeys.length && this.redis.sadd(segmentKey, addedKeys),
21
+ removedKeys.length && this.redis.srem(segmentKey, removedKeys),
22
+ this.redis.set(this.keys.buildSegmentTillKey(name), changeNumber + '')
23
+ ]).then(function () {
24
+ return addedKeys.length > 0 || removedKeys.length > 0;
25
+ });
29
26
  };
30
27
  SegmentsCacheInRedis.prototype.isInSegment = function (name, key) {
31
28
  return this.redis.sismember(this.keys.buildSegmentNameKey(name), key).then(function (matches) { return matches !== 0; });
32
29
  };
33
- SegmentsCacheInRedis.prototype.setChangeNumber = function (name, changeNumber) {
34
- return this.redis.set(this.keys.buildSegmentTillKey(name), changeNumber + '').then(function (status) { return status === 'OK'; });
35
- };
36
30
  SegmentsCacheInRedis.prototype.getChangeNumber = function (name) {
37
31
  var _this = this;
38
32
  return this.redis.get(this.keys.buildSegmentTillKey(name)).then(function (value) {
@@ -5,6 +5,7 @@ var tslib_1 = require("tslib");
5
5
  var UniqueKeysCacheInMemory_1 = require("../inMemory/UniqueKeysCacheInMemory");
6
6
  var constants_1 = require("./constants");
7
7
  var constants_2 = require("./constants");
8
+ var sets_1 = require("../../utils/lang/sets");
8
9
  var UniqueKeysCacheInRedis = /** @class */ (function (_super) {
9
10
  (0, tslib_1.__extends)(UniqueKeysCacheInRedis, _super);
10
11
  function UniqueKeysCacheInRedis(log, key, redis, uniqueKeysQueueSize, refreshRate) {
@@ -24,7 +25,7 @@ var UniqueKeysCacheInRedis = /** @class */ (function (_super) {
24
25
  if (!featureNames.length)
25
26
  return Promise.resolve(false);
26
27
  var uniqueKeysArray = featureNames.map(function (featureName) {
27
- var featureKeys = Array.from(_this.uniqueKeysTracker[featureName]);
28
+ var featureKeys = (0, sets_1.setToArray)(_this.uniqueKeysTracker[featureName]);
28
29
  var uniqueKeysPayload = {
29
30
  f: featureName,
30
31
  ks: featureKeys
@@ -15,32 +15,19 @@ var SegmentsCachePluggable = /** @class */ (function () {
15
15
  this.wrapper = wrapper;
16
16
  }
17
17
  /**
18
- * Add a list of `segmentKeys` to the given segment `name`.
19
- * The returned promise is resolved when the operation success
20
- * or rejected if wrapper operation fails.
21
- */
22
- SegmentsCachePluggable.prototype.addToSegment = function (name, segmentKeys) {
23
- var segmentKey = this.keys.buildSegmentNameKey(name);
24
- if (segmentKeys.length) {
25
- return this.wrapper.addItems(segmentKey, segmentKeys);
26
- }
27
- else {
28
- return Promise.resolve();
29
- }
30
- };
31
- /**
32
- * Remove a list of `segmentKeys` from the given segment `name`.
33
- * The returned promise is resolved when the operation success
34
- * or rejected if wrapper operation fails.
18
+ * Update the given segment `name` with the lists of `addedKeys`, `removedKeys` and `changeNumber`.
19
+ * The returned promise is resolved if the operation success, with `true` if the segment was updated (i.e., some key was added or removed),
20
+ * or rejected if it fails (e.g., wrapper operation fails).
35
21
  */
36
- SegmentsCachePluggable.prototype.removeFromSegment = function (name, segmentKeys) {
22
+ SegmentsCachePluggable.prototype.update = function (name, addedKeys, removedKeys, changeNumber) {
37
23
  var segmentKey = this.keys.buildSegmentNameKey(name);
38
- if (segmentKeys.length) {
39
- return this.wrapper.removeItems(segmentKey, segmentKeys);
40
- }
41
- else {
42
- return Promise.resolve();
43
- }
24
+ return Promise.all([
25
+ addedKeys.length && this.wrapper.addItems(segmentKey, addedKeys),
26
+ removedKeys.length && this.wrapper.removeItems(segmentKey, removedKeys),
27
+ this.wrapper.set(this.keys.buildSegmentTillKey(name), changeNumber + '')
28
+ ]).then(function () {
29
+ return addedKeys.length > 0 || removedKeys.length > 0;
30
+ });
44
31
  };
45
32
  /**
46
33
  * Returns a promise that resolves with a boolean value indicating if `key` is part of `name` segment.
@@ -49,14 +36,6 @@ var SegmentsCachePluggable = /** @class */ (function () {
49
36
  SegmentsCachePluggable.prototype.isInSegment = function (name, key) {
50
37
  return this.wrapper.itemContains(this.keys.buildSegmentNameKey(name), key);
51
38
  };
52
- /**
53
- * Set till number for the given segment `name`.
54
- * The returned promise is resolved when the operation success,
55
- * or rejected if it fails (e.g., wrapper operation fails).
56
- */
57
- SegmentsCachePluggable.prototype.setChangeNumber = function (name, changeNumber) {
58
- return this.wrapper.set(this.keys.buildSegmentTillKey(name), changeNumber + '');
59
- };
60
39
  /**
61
40
  * Get till number or -1 if it's not defined.
62
41
  * The returned promise is resolved with the changeNumber or -1 if it doesn't exist or a wrapper operation fails.
@@ -5,6 +5,7 @@ var tslib_1 = require("tslib");
5
5
  var UniqueKeysCacheInMemory_1 = require("../inMemory/UniqueKeysCacheInMemory");
6
6
  var constants_1 = require("../inRedis/constants");
7
7
  var constants_2 = require("./constants");
8
+ var sets_1 = require("../../utils/lang/sets");
8
9
  var UniqueKeysCachePluggable = /** @class */ (function (_super) {
9
10
  (0, tslib_1.__extends)(UniqueKeysCachePluggable, _super);
10
11
  function UniqueKeysCachePluggable(log, key, wrapper, uniqueKeysQueueSize, refreshRate) {
@@ -24,7 +25,7 @@ var UniqueKeysCachePluggable = /** @class */ (function (_super) {
24
25
  if (!featureNames.length)
25
26
  return Promise.resolve(false);
26
27
  var uniqueKeysArray = featureNames.map(function (featureName) {
27
- var featureKeys = Array.from(_this.uniqueKeysTracker[featureName]);
28
+ var featureKeys = (0, sets_1.setToArray)(_this.uniqueKeysTracker[featureName]);
28
29
  var uniqueKeysPayload = {
29
30
  f: featureName,
30
31
  ks: featureKeys
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.inMemoryWrapperFactory = void 0;
4
4
  var lang_1 = require("../../utils/lang");
5
+ var sets_1 = require("../../utils/lang/sets");
5
6
  /**
6
7
  * Creates a IPluggableStorageWrapper implementation that stores items in memory.
7
8
  * The `_cache` property is the object were items are stored.
@@ -118,7 +119,7 @@ function inMemoryWrapperFactory(connDelay) {
118
119
  if (!set)
119
120
  return Promise.resolve([]);
120
121
  if (set instanceof Set)
121
- return Promise.resolve(Array.from(set));
122
+ return Promise.resolve((0, sets_1.setToArray)(set));
122
123
  return Promise.reject('key is not a set');
123
124
  },
124
125
  // always connects and disconnects
@@ -19,23 +19,30 @@ function syncManagerOfflineFactory(splitsParserFactory) {
19
19
  */
20
20
  return function (_a) {
21
21
  var settings = _a.settings, readiness = _a.readiness, storage = _a.storage;
22
- return (0, objectAssign_1.objectAssign)((0, fromObjectSyncTask_1.fromObjectSyncTaskFactory)(splitsParserFactory(), storage, readiness, settings), {
22
+ var mainSyncManager = (0, fromObjectSyncTask_1.fromObjectSyncTaskFactory)(splitsParserFactory(), storage, readiness, settings);
23
+ var mainStart = mainSyncManager.start;
24
+ var sharedStarts = [];
25
+ return (0, objectAssign_1.objectAssign)(mainSyncManager, {
26
+ start: function () {
27
+ mainStart();
28
+ sharedStarts.forEach(function (cb) { return cb(); });
29
+ sharedStarts.length = 0;
30
+ },
23
31
  // fake flush, that resolves immediately
24
32
  flush: flush,
25
33
  // [Only used for client-side]
26
34
  shared: function (matchingKey, readinessManager) {
35
+ // In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
36
+ // SDK_READY cannot be emitted directly because this will not update the readiness status
37
+ function emitSdkReady() {
38
+ readinessManager.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
39
+ }
40
+ if (mainSyncManager.isRunning())
41
+ setTimeout(emitSdkReady);
42
+ else
43
+ sharedStarts.push(emitSdkReady);
27
44
  return {
28
- start: function () {
29
- // In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
30
- // SDK_READY cannot be emitted directly because this will not update the readiness status
31
- setTimeout(function () {
32
- readinessManager.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
33
- }, 0);
34
- },
35
45
  stop: function () { },
36
- isRunning: function () {
37
- return true;
38
- },
39
46
  flush: flush,
40
47
  };
41
48
  }
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.segmentChangesUpdaterFactory = void 0;
4
- var lang_1 = require("../../../utils/lang");
5
4
  var constants_1 = require("../../../readiness/constants");
6
5
  var constants_2 = require("../../../logger/constants");
7
- var thenable_1 = require("../../../utils/promise/thenable");
8
6
  /**
9
7
  * Factory of SegmentChanges updater, a task that:
10
8
  * - fetches segment changes using `segmentChangesFetcher`
@@ -23,27 +21,16 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
23
21
  var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
24
22
  return sincePromise.then(function (since) {
25
23
  // if fetchOnlyNew flag, avoid processing already fetched segments
26
- if (fetchOnlyNew && since !== -1)
27
- return -1;
28
- return segmentChangesFetcher(since, segmentName, noCache, till).then(function (changes) {
29
- var changeNumber = -1;
30
- var results = [];
31
- changes.forEach(function (x) {
32
- if (x.added.length > 0)
33
- results.push(segments.addToSegment(segmentName, x.added));
34
- if (x.removed.length > 0)
35
- results.push(segments.removeFromSegment(segmentName, x.removed));
36
- if (x.added.length > 0 || x.removed.length > 0) {
37
- results.push(segments.setChangeNumber(segmentName, x.till));
38
- changeNumber = x.till;
39
- }
40
- log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processed " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
24
+ return fetchOnlyNew && since !== -1 ?
25
+ false :
26
+ segmentChangesFetcher(since, segmentName, noCache, till).then(function (changes) {
27
+ return Promise.all(changes.map(function (x) {
28
+ log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
29
+ return segments.update(segmentName, x.added, x.removed, x.till);
30
+ })).then(function (updates) {
31
+ return updates.some(function (update) { return update; });
32
+ });
41
33
  });
42
- // If at least one storage operation result is a promise, join all in a single promise.
43
- if (results.some(function (result) { return (0, thenable_1.thenable)(result); }))
44
- return Promise.all(results).then(function () { return changeNumber; });
45
- return changeNumber;
46
- });
47
34
  });
48
35
  }
49
36
  /**
@@ -62,14 +49,11 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
62
49
  // If not a segment name provided, read list of available segments names to be updated.
63
50
  var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
64
51
  return segmentsPromise.then(function (segmentNames) {
65
- // Async fetchers are collected here.
66
- var updaters = [];
67
- for (var index = 0; index < segmentNames.length; index++) {
68
- updaters.push(updateSegment(segmentNames[index], noCache, till, fetchOnlyNew));
69
- }
52
+ // Async fetchers
53
+ var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew); });
70
54
  return Promise.all(updaters).then(function (shouldUpdateFlags) {
71
55
  // if at least one segment fetch succeeded, mark segments ready
72
- if ((0, lang_1.findIndex)(shouldUpdateFlags, function (v) { return v !== -1; }) !== -1 || readyOnAlreadyExistentState) {
56
+ if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
73
57
  readyOnAlreadyExistentState = false;
74
58
  if (readiness)
75
59
  readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED);
@@ -6,6 +6,7 @@ var constants_1 = require("../../../readiness/constants");
6
6
  var constants_2 = require("../../../logger/constants");
7
7
  var lang_1 = require("../../../utils/lang");
8
8
  var constants_3 = require("../../../utils/constants");
9
+ var sets_1 = require("../../../utils/lang/sets");
9
10
  // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
10
11
  // Returns a promise that could be rejected.
11
12
  // @TODO review together with Segments and MySegments storage APIs
@@ -71,7 +72,7 @@ function computeSplitsMutation(entries, filters) {
71
72
  }
72
73
  return accum;
73
74
  }, { added: [], removed: [], segments: [] });
74
- computed.segments = Array.from(segments);
75
+ computed.segments = (0, sets_1.setToArray)(segments);
75
76
  return computed;
76
77
  }
77
78
  exports.computeSplitsMutation = computeSplitsMutation;
@@ -118,33 +118,32 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
118
118
  if (!pollingManager)
119
119
  return;
120
120
  var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
121
- return {
122
- isRunning: mySegmentsSyncTask.isRunning,
123
- start: function () {
124
- if (syncEnabled) {
125
- if (pushManager) {
126
- if (pollingManager.isRunning()) {
127
- // if doing polling, we must start the periodic fetch of data
128
- if (storage.splits.usesSegments())
129
- mySegmentsSyncTask.start();
130
- }
131
- else {
132
- // if not polling, we must execute the sync task for the initial fetch
133
- // of segments since `syncAll` was already executed when starting the main client
134
- mySegmentsSyncTask.execute();
135
- }
136
- pushManager.add(matchingKey, mySegmentsSyncTask);
137
- }
138
- else {
121
+ if (running) {
122
+ if (syncEnabled) {
123
+ if (pushManager) {
124
+ if (pollingManager.isRunning()) {
125
+ // if doing polling, we must start the periodic fetch of data
139
126
  if (storage.splits.usesSegments())
140
127
  mySegmentsSyncTask.start();
141
128
  }
129
+ else {
130
+ // if not polling, we must execute the sync task for the initial fetch
131
+ // of segments since `syncAll` was already executed when starting the main client
132
+ mySegmentsSyncTask.execute();
133
+ }
134
+ pushManager.add(matchingKey, mySegmentsSyncTask);
142
135
  }
143
136
  else {
144
- if (!readinessManager.isReady())
145
- mySegmentsSyncTask.execute();
137
+ if (storage.splits.usesSegments())
138
+ mySegmentsSyncTask.start();
146
139
  }
147
- },
140
+ }
141
+ else {
142
+ if (!readinessManager.isReady())
143
+ mySegmentsSyncTask.execute();
144
+ }
145
+ }
146
+ return {
148
147
  stop: function () {
149
148
  // check in case `client.destroy()` has been invoked more than once for the same client
150
149
  var mySegmentsSyncTask = pollingManager.get(matchingKey);
@@ -12,7 +12,7 @@ var mode_1 = require("../utils/settingsValidation/mode");
12
12
  * @param eventsCache cache to save events
13
13
  * @param integrationsManager optional event handler used for integrations
14
14
  */
15
- function eventTrackerFactory(settings, eventsCache, integrationsManager, telemetryCache) {
15
+ function eventTrackerFactory(settings, eventsCache, whenInit, integrationsManager, telemetryCache) {
16
16
  var log = settings.log, mode = settings.mode;
17
17
  var isAsync = (0, mode_1.isConsumerMode)(mode);
18
18
  function queueEventsCallback(eventData, tracked) {
@@ -22,15 +22,17 @@ function eventTrackerFactory(settings, eventsCache, integrationsManager, telemet
22
22
  if (tracked) {
23
23
  log.info(constants_1.EVENTS_TRACKER_SUCCESS, [msg]);
24
24
  if (integrationsManager) {
25
- // Wrap in a timeout because we don't want it to be blocking.
26
- setTimeout(function () {
27
- // copy of event, to avoid unexpected behaviour if modified by integrations
28
- var eventDataCopy = (0, objectAssign_1.objectAssign)({}, eventData);
29
- if (properties)
30
- eventDataCopy.properties = (0, objectAssign_1.objectAssign)({}, properties);
31
- // integrationsManager does not throw errors (they are internally handled by each integration module)
32
- integrationsManager.handleEvent(eventDataCopy);
33
- }, 0);
25
+ whenInit(function () {
26
+ // Wrap in a timeout because we don't want it to be blocking.
27
+ setTimeout(function () {
28
+ // copy of event, to avoid unexpected behaviour if modified by integrations
29
+ var eventDataCopy = (0, objectAssign_1.objectAssign)({}, eventData);
30
+ if (properties)
31
+ eventDataCopy.properties = (0, objectAssign_1.objectAssign)({}, properties);
32
+ // integrationsManager does not throw errors (they are internally handled by each integration module)
33
+ integrationsManager.handleEvent(eventDataCopy);
34
+ });
35
+ });
34
36
  }
35
37
  }
36
38
  else {
@@ -14,7 +14,7 @@ var constants_2 = require("../utils/constants");
14
14
  * @param integrationsManager optional integrations manager
15
15
  * @param strategy strategy for impressions tracking.
16
16
  */
17
- function impressionsTrackerFactory(settings, impressionsCache, strategy, integrationsManager, telemetryCache) {
17
+ function impressionsTrackerFactory(settings, impressionsCache, strategy, whenInit, integrationsManager, telemetryCache) {
18
18
  var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
19
19
  return {
20
20
  track: function (impressions, attributes) {
@@ -53,19 +53,21 @@ function impressionsTrackerFactory(settings, impressionsCache, strategy, integra
53
53
  hostname: hostname,
54
54
  sdkLanguageVersion: version
55
55
  };
56
- // Wrap in a timeout because we don't want it to be blocking.
57
- setTimeout(function () {
58
- // integrationsManager.handleImpression does not throw errors
59
- if (integrationsManager)
60
- integrationsManager.handleImpression(impressionData);
61
- try { // @ts-ignore. An exception on the listeners should not break the SDK.
62
- if (impressionListener)
63
- impressionListener.logImpression(impressionData);
64
- }
65
- catch (err) {
66
- log.error(constants_1.ERROR_IMPRESSIONS_LISTENER, [err]);
67
- }
68
- }, 0);
56
+ whenInit(function () {
57
+ // Wrap in a timeout because we don't want it to be blocking.
58
+ setTimeout(function () {
59
+ // integrationsManager.handleImpression does not throw errors
60
+ if (integrationsManager)
61
+ integrationsManager.handleImpression(impressionData);
62
+ try { // @ts-ignore. An exception on the listeners should not break the SDK.
63
+ if (impressionListener)
64
+ impressionListener.logImpression(impressionData);
65
+ }
66
+ catch (err) {
67
+ log.error(constants_1.ERROR_IMPRESSIONS_LISTENER, [err]);
68
+ }
69
+ });
70
+ });
69
71
  };
70
72
  for (var i = 0; i < impressionsToListenerCount; i++) {
71
73
  _loop_1(i);
@@ -19,9 +19,6 @@ var noopFilterAdapter = {
19
19
  function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
20
20
  if (filterAdapter === void 0) { filterAdapter = noopFilterAdapter; }
21
21
  var intervalId;
22
- if (filterAdapter.refreshRate) {
23
- intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
24
- }
25
22
  return {
26
23
  track: function (key, featureName) {
27
24
  if (!filterAdapter.add(key, featureName)) {
@@ -30,6 +27,11 @@ function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
30
27
  }
31
28
  uniqueKeysCache.track(key, featureName);
32
29
  },
30
+ start: function () {
31
+ if (filterAdapter.refreshRate) {
32
+ intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
33
+ }
34
+ },
33
35
  stop: function () {
34
36
  clearInterval(intervalId);
35
37
  }
@@ -1,8 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.returnDifference = exports.returnSetsUnion = void 0;
3
+ exports.returnDifference = exports.returnSetsUnion = exports.setToArray = void 0;
4
+ function setToArray(set) {
5
+ if (Array.from)
6
+ return Array.from(set);
7
+ var array = [];
8
+ set.forEach(function (value) {
9
+ array.push(value);
10
+ });
11
+ return array;
12
+ }
13
+ exports.setToArray = setToArray;
4
14
  function returnSetsUnion(set, set2) {
5
- return new Set(Array.from(set).concat(Array.from(set2)));
15
+ return new Set(setToArray(set).concat(setToArray(set2)));
6
16
  }
7
17
  exports.returnSetsUnion = returnSetsUnion;
8
18
  function returnDifference(list, list2) {
@@ -14,7 +14,7 @@ var Engine = /** @class */ (function () {
14
14
  function Engine(baseInfo, evaluator) {
15
15
  this.baseInfo = baseInfo;
16
16
  this.evaluator = evaluator;
17
- // in case we don't have a default treatment in the instanciation, use 'control'
17
+ // in case we don't have a default treatment in the instantiation, use 'control'
18
18
  if (typeof this.baseInfo.defaultTreatment !== 'string') {
19
19
  this.baseInfo.defaultTreatment = CONTROL;
20
20
  }
@@ -2,7 +2,7 @@ import { Engine } from './Engine';
2
2
  import { thenable } from '../utils/promise/thenable';
3
3
  import { EXCEPTION, SPLIT_NOT_FOUND } from '../utils/labels';
4
4
  import { CONTROL } from '../utils/constants';
5
- import { returnSetsUnion } from '../utils/lang/sets';
5
+ import { returnSetsUnion, setToArray } from '../utils/lang/sets';
6
6
  import { WARN_FLAGSET_WITHOUT_FLAGS } from '../logger/constants';
7
7
  var treatmentException = {
8
8
  treatment: CONTROL,
@@ -65,7 +65,7 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
65
65
  }
66
66
  }
67
67
  return featureFlags.size ?
68
- evaluateFeatures(log, key, Array.from(featureFlags), attributes, storage) :
68
+ evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
69
69
  {};
70
70
  }
71
71
  // get features by flag sets
@@ -4,6 +4,8 @@ function splitsEventEmitterFactory(EventEmitter) {
4
4
  var splitsEventEmitter = objectAssign(new EventEmitter(), {
5
5
  splitsArrived: false,
6
6
  splitsCacheLoaded: false,
7
+ initialized: false,
8
+ initCallbacks: []
7
9
  });
8
10
  // `isSplitKill` condition avoids an edge-case of wrongly emitting SDK_READY if:
9
11
  // - `/memberships` fetch and SPLIT_KILL occurs before `/splitChanges` fetch, and
@@ -43,7 +45,7 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
43
45
  // emit SDK_READY_TIMED_OUT
44
46
  var hasTimedout = false;
45
47
  function timeout() {
46
- if (hasTimedout)
48
+ if (hasTimedout || isReady)
47
49
  return;
48
50
  hasTimedout = true;
49
51
  syncLastUpdate();
@@ -51,7 +53,10 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
51
53
  }
52
54
  var readyTimeoutId;
53
55
  if (readyTimeout > 0) {
54
- readyTimeoutId = setTimeout(timeout, readyTimeout);
56
+ if (splits.initialized)
57
+ readyTimeoutId = setTimeout(timeout, readyTimeout);
58
+ else
59
+ splits.initCallbacks.push(function () { readyTimeoutId = setTimeout(timeout, readyTimeout); });
55
60
  }
56
61
  // emit SDK_READY and SDK_UPDATE
57
62
  var isReady = false;
@@ -113,6 +118,12 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
113
118
  // Called on 403 error (client-side SDK key on server-side), to set the SDK as destroyed for
114
119
  // tracking and evaluations, while keeping event listeners to emit SDK_READY_TIMED_OUT event
115
120
  setDestroyed: function () { isDestroyed = true; },
121
+ init: function () {
122
+ if (splits.initialized)
123
+ return;
124
+ splits.initialized = true;
125
+ splits.initCallbacks.forEach(function (cb) { return cb(); });
126
+ },
116
127
  destroy: function () {
117
128
  isDestroyed = true;
118
129
  syncLastUpdate();
@@ -52,7 +52,6 @@ export function sdkClientMethodCSFactory(params) {
52
52
  storage: sharedStorage || storage,
53
53
  syncManager: sharedSyncManager,
54
54
  }), true), validKey);
55
- sharedSyncManager && sharedSyncManager.start();
56
55
  log.info(NEW_SHARED_CLIENT);
57
56
  }
58
57
  else {