@splitsoftware/splitio-commons 2.4.2-rc.3 → 2.5.0-rc.1

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 (74) hide show
  1. package/CHANGES.txt +3 -11
  2. package/cjs/evaluator/convertions/index.js +9 -1
  3. package/cjs/evaluator/matchersTransform/index.js +2 -3
  4. package/cjs/sdkClient/sdkClientMethodCS.js +5 -1
  5. package/cjs/sdkFactory/index.js +8 -2
  6. package/cjs/storages/getRolloutPlan.js +69 -0
  7. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  8. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  9. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  10. package/cjs/storages/inLocalStorage/index.js +13 -31
  11. package/cjs/storages/inLocalStorage/validateCache.js +25 -30
  12. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  13. package/cjs/storages/setRolloutPlan.js +66 -0
  14. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  15. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  16. package/cjs/sync/polling/updaters/splitChangesUpdater.js +0 -2
  17. package/cjs/sync/syncManagerOnline.js +24 -28
  18. package/cjs/utils/env/isLocalStorageAvailable.js +5 -28
  19. package/cjs/utils/inputValidation/index.js +1 -3
  20. package/cjs/utils/settingsValidation/index.js +4 -0
  21. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  22. package/esm/evaluator/convertions/index.js +7 -0
  23. package/esm/evaluator/matchersTransform/index.js +3 -4
  24. package/esm/sdkClient/sdkClientMethodCS.js +5 -1
  25. package/esm/sdkFactory/index.js +8 -2
  26. package/esm/storages/getRolloutPlan.js +65 -0
  27. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  28. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  29. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  30. package/esm/storages/inLocalStorage/index.js +14 -32
  31. package/esm/storages/inLocalStorage/validateCache.js +25 -30
  32. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  33. package/esm/storages/setRolloutPlan.js +61 -0
  34. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  35. package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  36. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -2
  37. package/esm/sync/syncManagerOnline.js +24 -28
  38. package/esm/utils/env/isLocalStorageAvailable.js +3 -24
  39. package/esm/utils/inputValidation/index.js +0 -1
  40. package/esm/utils/settingsValidation/index.js +4 -0
  41. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  42. package/package.json +1 -1
  43. package/src/evaluator/convertions/index.ts +10 -0
  44. package/src/evaluator/matchersTransform/index.ts +3 -4
  45. package/src/sdkClient/sdkClientMethodCS.ts +7 -1
  46. package/src/sdkFactory/index.ts +12 -4
  47. package/src/storages/getRolloutPlan.ts +72 -0
  48. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +17 -18
  49. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -19
  50. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +37 -34
  51. package/src/storages/inLocalStorage/index.ts +16 -37
  52. package/src/storages/inLocalStorage/validateCache.ts +25 -31
  53. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +4 -0
  54. package/src/storages/setRolloutPlan.ts +71 -0
  55. package/src/storages/types.ts +25 -23
  56. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +2 -1
  57. package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -2
  58. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -3
  59. package/src/sync/syncManagerOnline.ts +22 -27
  60. package/src/types.ts +2 -35
  61. package/src/utils/env/isLocalStorageAvailable.ts +3 -24
  62. package/src/utils/inputValidation/index.ts +0 -1
  63. package/src/utils/settingsValidation/index.ts +4 -0
  64. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  65. package/types/splitio.d.ts +36 -44
  66. package/cjs/storages/dataLoader.js +0 -50
  67. package/cjs/storages/inLocalStorage/storageAdapter.js +0 -54
  68. package/cjs/utils/inputValidation/preloadedData.js +0 -59
  69. package/esm/storages/dataLoader.js +0 -46
  70. package/esm/storages/inLocalStorage/storageAdapter.js +0 -50
  71. package/esm/utils/inputValidation/preloadedData.js +0 -55
  72. package/src/storages/dataLoader.ts +0 -55
  73. package/src/storages/inLocalStorage/storageAdapter.ts +0 -62
  74. package/src/utils/inputValidation/preloadedData.ts +0 -57
@@ -17,20 +17,6 @@ var TelemetryCacheInMemory_1 = require("../inMemory/TelemetryCacheInMemory");
17
17
  var UniqueKeysCacheInMemoryCS_1 = require("../inMemory/UniqueKeysCacheInMemoryCS");
18
18
  var key_1 = require("../../utils/key");
19
19
  var validateCache_1 = require("./validateCache");
20
- var storageAdapter_1 = require("./storageAdapter");
21
- function validateStorage(log, prefix, wrapper) {
22
- if (wrapper) {
23
- if ((0, isLocalStorageAvailable_1.isValidStorageWrapper)(wrapper)) {
24
- return (0, isLocalStorageAvailable_1.isWebStorage)(wrapper) ?
25
- wrapper : // localStorage and sessionStorage don't need adapter
26
- (0, storageAdapter_1.storageAdapter)(log, prefix, wrapper);
27
- }
28
- log.warn(constants_1.LOG_PREFIX + 'Invalid storage provided. Falling back to LocalStorage API');
29
- }
30
- if ((0, isLocalStorageAvailable_1.isLocalStorageAvailable)())
31
- return localStorage;
32
- log.warn(constants_1.LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
33
- }
34
20
  /**
35
21
  * InLocal storage factory for standalone client-side SplitFactory
36
22
  */
@@ -38,17 +24,18 @@ function InLocalStorage(options) {
38
24
  if (options === void 0) { options = {}; }
39
25
  var prefix = (0, KeyBuilder_1.validatePrefix)(options.prefix);
40
26
  function InLocalStorageCSFactory(params) {
41
- var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
42
- var storage = validateStorage(log, prefix, options.wrapper);
43
- if (!storage)
27
+ // Fallback to InMemoryStorage if LocalStorage API is not available
28
+ if (!(0, isLocalStorageAvailable_1.isLocalStorageAvailable)()) {
29
+ params.settings.log.warn(constants_1.LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
44
30
  return (0, InMemoryStorageCS_1.InMemoryStorageCSFactory)(params);
31
+ }
32
+ var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
45
33
  var matchingKey = (0, key_1.getMatching)(settings.core.key);
46
34
  var keys = new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey);
47
- var splits = new SplitsCacheInLocal_1.SplitsCacheInLocal(settings, keys, storage);
48
- var rbSegments = new RBSegmentsCacheInLocal_1.RBSegmentsCacheInLocal(settings, keys, storage);
49
- var segments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, keys, storage);
50
- var largeSegments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey), storage);
51
- var validateCachePromise;
35
+ var splits = new SplitsCacheInLocal_1.SplitsCacheInLocal(settings, keys);
36
+ var rbSegments = new RBSegmentsCacheInLocal_1.RBSegmentsCacheInLocal(settings, keys);
37
+ var segments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, keys);
38
+ var largeSegments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey));
52
39
  return {
53
40
  splits: splits,
54
41
  rbSegments: rbSegments,
@@ -60,21 +47,16 @@ function InLocalStorage(options) {
60
47
  telemetry: (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) ? new TelemetryCacheInMemory_1.TelemetryCacheInMemory(splits, segments) : undefined,
61
48
  uniqueKeys: new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS(),
62
49
  validateCache: function () {
63
- return validateCachePromise || (validateCachePromise = (0, validateCache_1.validateCache)(options, storage, settings, keys, splits, rbSegments, segments, largeSegments));
64
- },
65
- save: function () {
66
- return storage.save && storage.save();
67
- },
68
- destroy: function () {
69
- return storage.whenSaved && storage.whenSaved();
50
+ return (0, validateCache_1.validateCache)(options, settings, keys, splits, rbSegments, segments, largeSegments);
70
51
  },
52
+ destroy: function () { },
71
53
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
72
54
  shared: function (matchingKey) {
73
55
  return {
74
56
  splits: this.splits,
75
57
  rbSegments: this.rbSegments,
76
- segments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey), storage),
77
- largeSegments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey), storage),
58
+ segments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey)),
59
+ largeSegments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey)),
78
60
  impressions: this.impressions,
79
61
  impressionCounts: this.impressionCounts,
80
62
  events: this.events,
@@ -11,10 +11,10 @@ var MILLIS_IN_A_DAY = 86400000;
11
11
  *
12
12
  * @returns `true` if cache should be cleared, `false` otherwise
13
13
  */
14
- function validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache) {
15
- var log = settings.log;
14
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
15
+ var log = settings.log, initialRolloutPlan = settings.initialRolloutPlan;
16
16
  // Check expiration
17
- var lastUpdatedTimestamp = parseInt(storage.getItem(keys.buildLastUpdatedKey()), 10);
17
+ var lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()), 10);
18
18
  if (!(0, lang_1.isNaNNumber)(lastUpdatedTimestamp)) {
19
19
  var cacheExpirationInDays = (0, lang_1.isFiniteNumber)(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
20
20
  var expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
@@ -25,16 +25,16 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
25
25
  }
26
26
  // Check hash
27
27
  var storageHashKey = keys.buildHashKey();
28
- var storageHash = storage.getItem(storageHashKey);
28
+ var storageHash = localStorage.getItem(storageHashKey);
29
29
  var currentStorageHash = (0, KeyBuilder_1.getStorageHash)(settings);
30
30
  if (storageHash !== currentStorageHash) {
31
31
  try {
32
- storage.setItem(storageHashKey, currentStorageHash);
32
+ localStorage.setItem(storageHashKey, currentStorageHash);
33
33
  }
34
34
  catch (e) {
35
35
  log.error(constants_1.LOG_PREFIX + e);
36
36
  }
37
- if (isThereCache) {
37
+ if (isThereCache && !initialRolloutPlan) {
38
38
  log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
39
39
  return true;
40
40
  }
@@ -42,7 +42,7 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
42
42
  }
43
43
  // Clear on init
44
44
  if (options.clearOnInit) {
45
- var lastClearTimestamp = parseInt(storage.getItem(keys.buildLastClear()), 10);
45
+ var lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()), 10);
46
46
  if ((0, lang_1.isNaNNumber)(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
47
47
  log.info(constants_1.LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
48
48
  return true;
@@ -57,29 +57,24 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
57
57
  *
58
58
  * @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
59
59
  */
60
- function validateCache(options, storage, settings, keys, splits, rbSegments, segments, largeSegments) {
61
- return Promise.resolve(storage.load && storage.load()).then(function () {
62
- var currentTimestamp = Date.now();
63
- var isThereCache = splits.getChangeNumber() > -1;
64
- if (validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache)) {
65
- splits.clear();
66
- rbSegments.clear();
67
- segments.clear();
68
- largeSegments.clear();
69
- // Update last clear timestamp
70
- try {
71
- storage.setItem(keys.buildLastClear(), currentTimestamp + '');
72
- }
73
- catch (e) {
74
- settings.log.error(constants_1.LOG_PREFIX + e);
75
- }
76
- // Persist clear
77
- if (storage.save)
78
- storage.save();
79
- return false;
60
+ function validateCache(options, settings, keys, splits, rbSegments, segments, largeSegments) {
61
+ var currentTimestamp = Date.now();
62
+ var isThereCache = splits.getChangeNumber() > -1;
63
+ if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
64
+ splits.clear();
65
+ rbSegments.clear();
66
+ segments.clear();
67
+ largeSegments.clear();
68
+ // Update last clear timestamp
69
+ try {
70
+ localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
71
+ }
72
+ catch (e) {
73
+ settings.log.error(constants_1.LOG_PREFIX + e);
80
74
  }
81
- // Check if ready from cache
82
- return isThereCache;
83
- });
75
+ return false;
76
+ }
77
+ // Check if ready from cache
78
+ return isThereCache;
84
79
  }
85
80
  exports.validateCache = validateCache;
@@ -45,6 +45,10 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
45
45
  RBSegmentsCacheInMemory.prototype.get = function (name) {
46
46
  return this.cache[name] || null;
47
47
  };
48
+ RBSegmentsCacheInMemory.prototype.getAll = function () {
49
+ var _this = this;
50
+ return this.getNames().map(function (key) { return _this.get(key); });
51
+ };
48
52
  RBSegmentsCacheInMemory.prototype.contains = function (names) {
49
53
  var namesArray = (0, sets_1.setToArray)(names);
50
54
  var namesInStorage = this.getNames();
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setRolloutPlan = exports.validateRolloutPlan = void 0;
4
+ var lang_1 = require("../utils/lang");
5
+ var mode_1 = require("../utils/settingsValidation/mode");
6
+ /**
7
+ * Validates if the given rollout plan is valid.
8
+ */
9
+ function validateRolloutPlan(log, settings) {
10
+ var mode = settings.mode, initialRolloutPlan = settings.initialRolloutPlan;
11
+ if ((0, mode_1.isConsumerMode)(mode)) {
12
+ log.warn('storage: initial rollout plan is ignored in consumer mode');
13
+ return;
14
+ }
15
+ if ((0, lang_1.isObject)(initialRolloutPlan) && (0, lang_1.isObject)(initialRolloutPlan.splitChanges))
16
+ return initialRolloutPlan;
17
+ log.error('storage: invalid rollout plan provided');
18
+ return;
19
+ }
20
+ exports.validateRolloutPlan = validateRolloutPlan;
21
+ /**
22
+ * Sets the given synchronous storage with the provided rollout plan snapshot.
23
+ * If `matchingKey` is provided, the storage is handled as a client-side storage (segments and largeSegments are instances of MySegmentsCache).
24
+ * Otherwise, the storage is handled as a server-side storage (segments is an instance of SegmentsCache).
25
+ */
26
+ function setRolloutPlan(log, rolloutPlan, storage, matchingKey) {
27
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
28
+ var _a = rolloutPlan.splitChanges, ff = _a.ff, rbs = _a.rbs;
29
+ log.debug("storage: set feature flags and segments" + (matchingKey ? " for key " + matchingKey : ''));
30
+ if (splits && ff) {
31
+ splits.clear();
32
+ splits.update(ff.d, [], ff.t);
33
+ }
34
+ if (rbSegments && rbs) {
35
+ rbSegments.clear();
36
+ rbSegments.update(rbs.d, [], rbs.t);
37
+ }
38
+ var segmentChanges = rolloutPlan.segmentChanges;
39
+ if (matchingKey) { // add memberships data (client-side)
40
+ var memberships = rolloutPlan.memberships && rolloutPlan.memberships[matchingKey];
41
+ if (!memberships && segmentChanges) {
42
+ memberships = {
43
+ ms: {
44
+ k: segmentChanges.filter(function (segment) {
45
+ return segment.added.indexOf(matchingKey) > -1;
46
+ }).map(function (segment) { return ({ n: segment.name }); })
47
+ }
48
+ };
49
+ }
50
+ if (memberships) {
51
+ if (memberships.ms)
52
+ segments.resetSegments(memberships.ms);
53
+ if (memberships.ls && largeSegments)
54
+ largeSegments.resetSegments(memberships.ls);
55
+ }
56
+ }
57
+ else { // add segments data (server-side)
58
+ if (segmentChanges) {
59
+ segments.clear();
60
+ segmentChanges.forEach(function (segment) {
61
+ segments.update(segment.name, segment.added, segment.removed, segment.till);
62
+ });
63
+ }
64
+ }
65
+ }
66
+ exports.setRolloutPlan = setRolloutPlan;
@@ -45,9 +45,10 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
45
45
  readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
46
46
  if (startingUp) {
47
47
  startingUp = false;
48
- Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
48
+ var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
49
+ Promise.resolve().then(function () {
49
50
  // Emits SDK_READY_FROM_CACHE
50
- if (isCacheLoaded)
51
+ if (isCacheLoaded_1)
51
52
  readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
52
53
  // Emits SDK_READY
53
54
  readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
@@ -34,8 +34,6 @@ function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEvent
34
34
  shouldNotifyUpdate = segments.resetSegments(segmentsData.ms || {});
35
35
  shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
36
36
  }
37
- if (storage.save)
38
- storage.save();
39
37
  // Notify update if required
40
38
  if ((0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
41
39
  readyOnAlreadyExistentState = false;
@@ -154,8 +154,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
154
154
  segments.registerSegments((0, sets_1.setToArray)(usedSegments))
155
155
  ]).then(function (_a) {
156
156
  var ffChanged = _a[0], rbsChanged = _a[1];
157
- if (storage.save)
158
- storage.save();
159
157
  if (splitsEventEmitter) {
160
158
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
161
159
  return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
@@ -69,39 +69,35 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
69
69
  */
70
70
  start: function () {
71
71
  running = true;
72
- // @TODO once event, impression and telemetry storages support persistence, call when `validateCache` promise is resolved
73
- submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
74
- return Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
75
- if (!running)
76
- return;
77
- if (startFirstTime) {
78
- // Emits SDK_READY_FROM_CACHE
79
- if (isCacheLoaded)
80
- readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED);
81
- }
82
- // start syncing splits and segments
83
- if (pollingManager) {
84
- // If synchronization is disabled pushManager and pollingManager should not start
85
- if (syncEnabled) {
86
- if (pushManager) {
87
- // Doesn't call `syncAll` when the syncManager is resuming
88
- if (startFirstTime) {
89
- pollingManager.syncAll();
90
- }
91
- pushManager.start();
92
- }
93
- else {
94
- pollingManager.start();
95
- }
96
- }
97
- else {
72
+ if (startFirstTime) {
73
+ var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
74
+ if (isCacheLoaded)
75
+ Promise.resolve().then(function () { readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED); });
76
+ }
77
+ // start syncing splits and segments
78
+ if (pollingManager) {
79
+ // If synchronization is disabled pushManager and pollingManager should not start
80
+ if (syncEnabled) {
81
+ if (pushManager) {
82
+ // Doesn't call `syncAll` when the syncManager is resuming
98
83
  if (startFirstTime) {
99
84
  pollingManager.syncAll();
100
85
  }
86
+ pushManager.start();
87
+ }
88
+ else {
89
+ pollingManager.start();
90
+ }
91
+ }
92
+ else {
93
+ if (startFirstTime) {
94
+ pollingManager.syncAll();
101
95
  }
102
96
  }
103
- startFirstTime = false;
104
- });
97
+ }
98
+ // start periodic data recording (events, impressions, telemetry).
99
+ submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
100
+ startFirstTime = false;
105
101
  },
106
102
  /**
107
103
  * Method used to stop/pause the syncManager.
@@ -1,39 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isWebStorage = exports.isValidStorageWrapper = exports.isLocalStorageAvailable = void 0;
3
+ exports.isLocalStorageAvailable = void 0;
4
+ /* eslint-disable no-undef */
4
5
  function isLocalStorageAvailable() {
5
- try {
6
- // eslint-disable-next-line no-undef
7
- return isValidStorageWrapper(localStorage);
8
- }
9
- catch (e) {
10
- return false;
11
- }
12
- }
13
- exports.isLocalStorageAvailable = isLocalStorageAvailable;
14
- function isValidStorageWrapper(wrapper) {
15
6
  var mod = '__SPLITSOFTWARE__';
16
7
  try {
17
- wrapper.setItem(mod, mod);
18
- wrapper.getItem(mod);
19
- wrapper.removeItem(mod);
8
+ localStorage.setItem(mod, mod);
9
+ localStorage.removeItem(mod);
20
10
  return true;
21
11
  }
22
12
  catch (e) {
23
13
  return false;
24
14
  }
25
15
  }
26
- exports.isValidStorageWrapper = isValidStorageWrapper;
27
- function isWebStorage(wrapper) {
28
- if (typeof wrapper.length === 'number') {
29
- try {
30
- wrapper.key(0);
31
- return true;
32
- }
33
- catch (e) {
34
- return false;
35
- }
36
- }
37
- return false;
38
- }
39
- exports.isWebStorage = isWebStorage;
16
+ exports.isLocalStorageAvailable = isLocalStorageAvailable;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateEvaluationOptions = exports.validatePreloadedData = exports.validateTrafficTypeExistence = exports.validateSplitExistence = exports.validateIfOperational = exports.validateIfNotDestroyed = exports.validateTrafficType = exports.validateSplits = exports.validateSplit = exports.validateKey = exports.validateEventProperties = exports.validateEventValue = exports.validateEvent = exports.validateAttributes = exports.releaseApiKey = exports.validateAndTrackApiKey = exports.validateApiKey = void 0;
3
+ exports.validateEvaluationOptions = exports.validateTrafficTypeExistence = exports.validateSplitExistence = exports.validateIfOperational = exports.validateIfNotDestroyed = exports.validateTrafficType = exports.validateSplits = exports.validateSplit = exports.validateKey = exports.validateEventProperties = exports.validateEventValue = exports.validateEvent = exports.validateAttributes = exports.releaseApiKey = exports.validateAndTrackApiKey = exports.validateApiKey = void 0;
4
4
  var apiKey_1 = require("./apiKey");
5
5
  Object.defineProperty(exports, "validateApiKey", { enumerable: true, get: function () { return apiKey_1.validateApiKey; } });
6
6
  Object.defineProperty(exports, "validateAndTrackApiKey", { enumerable: true, get: function () { return apiKey_1.validateAndTrackApiKey; } });
@@ -28,7 +28,5 @@ var splitExistence_1 = require("./splitExistence");
28
28
  Object.defineProperty(exports, "validateSplitExistence", { enumerable: true, get: function () { return splitExistence_1.validateSplitExistence; } });
29
29
  var trafficTypeExistence_1 = require("./trafficTypeExistence");
30
30
  Object.defineProperty(exports, "validateTrafficTypeExistence", { enumerable: true, get: function () { return trafficTypeExistence_1.validateTrafficTypeExistence; } });
31
- var preloadedData_1 = require("./preloadedData");
32
- Object.defineProperty(exports, "validatePreloadedData", { enumerable: true, get: function () { return preloadedData_1.validatePreloadedData; } });
33
31
  var eventProperties_2 = require("./eventProperties");
34
32
  Object.defineProperty(exports, "validateEvaluationOptions", { enumerable: true, get: function () { return eventProperties_2.validateEvaluationOptions; } });
@@ -8,6 +8,7 @@ var constants_1 = require("../constants");
8
8
  var impressionsMode_1 = require("./impressionsMode");
9
9
  var key_1 = require("../inputValidation/key");
10
10
  var constants_2 = require("../../logger/constants");
11
+ var setRolloutPlan_1 = require("../../storages/setRolloutPlan");
11
12
  // Exported for telemetry
12
13
  exports.base = {
13
14
  // Define which kind of object you want to retrieve from SplitFactory
@@ -131,6 +132,9 @@ function settingsValidation(config, validationParams) {
131
132
  // @ts-ignore, modify readonly prop
132
133
  if (storage)
133
134
  withDefaults.storage = storage(withDefaults);
135
+ // @ts-ignore, modify readonly prop
136
+ if (withDefaults.initialRolloutPlan)
137
+ withDefaults.initialRolloutPlan = (0, setRolloutPlan_1.validateRolloutPlan)(log, withDefaults);
134
138
  // Validate key and TT (for client-side)
135
139
  var maybeKey = withDefaults.core.key;
136
140
  if (validationParams.acceptKey) {
@@ -6,7 +6,7 @@ var constants_1 = require("../../../logger/constants");
6
6
  var constants_2 = require("../../../utils/constants");
7
7
  function __InLocalStorageMockFactory(params) {
8
8
  var result = (0, InMemoryStorageCS_1.InMemoryStorageCSFactory)(params);
9
- result.validateCache = function () { return Promise.resolve(true); }; // to emit SDK_READY_FROM_CACHE
9
+ result.validateCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
10
10
  return result;
11
11
  }
12
12
  exports.__InLocalStorageMockFactory = __InLocalStorageMockFactory;
@@ -4,3 +4,10 @@ export function zeroSinceHH(millisSinceEpoch) {
4
4
  export function zeroSinceSS(millisSinceEpoch) {
5
5
  return new Date(millisSinceEpoch).setUTCSeconds(0, 0);
6
6
  }
7
+ export function betweenDateTimeTransform(betweenMatcherData) {
8
+ return {
9
+ dataType: betweenMatcherData.dataType,
10
+ start: zeroSinceSS(betweenMatcherData.start),
11
+ end: zeroSinceSS(betweenMatcherData.end)
12
+ };
13
+ }
@@ -3,7 +3,7 @@ import { matcherTypes, matcherTypesMapper, matcherDataTypes } from '../matchers/
3
3
  import { segmentTransform } from './segment';
4
4
  import { whitelistTransform } from './whitelist';
5
5
  import { numericTransform } from './unaryNumeric';
6
- import { zeroSinceHH, zeroSinceSS } from '../convertions';
6
+ import { zeroSinceHH, zeroSinceSS, betweenDateTimeTransform } from '../convertions';
7
7
  /**
8
8
  * Flat the complex matcherGroup structure into something handy.
9
9
  */
@@ -14,7 +14,7 @@ export function matchersTransform(matchers) {
14
14
  var type = matcherTypesMapper(matcherType);
15
15
  // As default input data type we use string (even for ALL_KEYS)
16
16
  var dataType = matcherDataTypes.STRING;
17
- var value = undefined;
17
+ var value;
18
18
  if (type === matcherTypes.IN_SEGMENT) {
19
19
  value = segmentTransform(userDefinedSegmentMatcherData);
20
20
  }
@@ -42,8 +42,7 @@ export function matchersTransform(matchers) {
42
42
  value = betweenMatcherData;
43
43
  dataType = matcherDataTypes.NUMBER;
44
44
  if (value.dataType === 'DATETIME') {
45
- value.start = zeroSinceSS(value.start);
46
- value.end = zeroSinceSS(value.end);
45
+ value = betweenDateTimeTransform(value);
47
46
  dataType = matcherDataTypes.DATETIME;
48
47
  }
49
48
  }
@@ -6,12 +6,13 @@ import { objectAssign } from '../utils/lang/objectAssign';
6
6
  import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING, LOG_PREFIX_CLIENT_INSTANTIATION } from '../logger/constants';
7
7
  import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
8
8
  import { buildInstanceId } from './identity';
9
+ import { setRolloutPlan } from '../storages/setRolloutPlan';
9
10
  /**
10
11
  * Factory of client method for the client-side API variant where TT is ignored.
11
12
  * Therefore, clients don't have a bound TT for the track method.
12
13
  */
13
14
  export function sdkClientMethodCSFactory(params) {
14
- var clients = params.clients, storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, log = _a.log;
15
+ var clients = params.clients, storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, log = _a.log, initialRolloutPlan = _a.initialRolloutPlan;
15
16
  var mainClientInstance = clientCSDecorator(log, sdkClientFactory(params), key);
16
17
  var parsedDefaultKey = keyParser(key);
17
18
  var defaultInstanceId = buildInstanceId(parsedDefaultKey);
@@ -39,6 +40,9 @@ export function sdkClientMethodCSFactory(params) {
39
40
  // Emit SDK_READY in consumer mode for shared clients
40
41
  sharedSdkReadiness_1.readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED);
41
42
  });
43
+ if (sharedStorage && initialRolloutPlan) {
44
+ setRolloutPlan(log, initialRolloutPlan, { segments: sharedStorage.segments, largeSegments: sharedStorage.largeSegments }, matchingKey);
45
+ }
42
46
  // 3 possibilities:
43
47
  // - Standalone mode: both syncManager and sharedSyncManager are defined
44
48
  // - Consumer mode: both syncManager and sharedSyncManager are undefined
@@ -12,12 +12,14 @@ import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized
12
12
  import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
13
13
  import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
14
14
  import { DEBUG, OPTIMIZED } from '../utils/constants';
15
+ import { setRolloutPlan } from '../storages/setRolloutPlan';
16
+ import { getMatching } from '../utils/key';
15
17
  /**
16
18
  * Modular SDK factory
17
19
  */
18
20
  export function sdkFactory(params) {
19
21
  var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, splitApiFactory = params.splitApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, SignalListener = params.SignalListener, impressionsObserverFactory = params.impressionsObserverFactory, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, filterAdapterFactory = params.filterAdapterFactory, lazyInit = params.lazyInit;
20
- var log = settings.log, impressionsMode = settings.sync.impressionsMode;
22
+ var log = settings.log, impressionsMode = settings.sync.impressionsMode, initialRolloutPlan = settings.initialRolloutPlan, key = settings.core.key;
21
23
  // @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
22
24
  // On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
23
25
  // initialization
@@ -46,7 +48,11 @@ export function sdkFactory(params) {
46
48
  readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
47
49
  }
48
50
  });
49
- // @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
51
+ if (initialRolloutPlan) {
52
+ setRolloutPlan(log, initialRolloutPlan, storage, key && getMatching(key));
53
+ if (storage.splits.getChangeNumber() > -1)
54
+ readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
55
+ }
50
56
  var clients = {};
51
57
  var telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
52
58
  var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
@@ -0,0 +1,65 @@
1
+ import { setToArray } from '../utils/lang/sets';
2
+ import { getMatching } from '../utils/key';
3
+ /**
4
+ * Gets the rollout plan snapshot from the given synchronous storage.
5
+ */
6
+ export function getRolloutPlan(log, storage, options) {
7
+ if (options === void 0) { options = {}; }
8
+ var keys = options.keys, exposeSegments = options.exposeSegments;
9
+ var splits = storage.splits, segments = storage.segments, rbSegments = storage.rbSegments;
10
+ log.debug("storage: get feature flags" + (keys ? ", and memberships for keys " + keys : '') + (exposeSegments ? ', and segments' : ''));
11
+ return {
12
+ splitChanges: {
13
+ ff: {
14
+ t: splits.getChangeNumber(),
15
+ s: -1,
16
+ d: splits.getAll(),
17
+ },
18
+ rbs: {
19
+ t: rbSegments.getChangeNumber(),
20
+ s: -1,
21
+ d: rbSegments.getAll(),
22
+ }
23
+ },
24
+ segmentChanges: exposeSegments ? // @ts-ignore accessing private prop
25
+ Object.keys(segments.segmentCache).map(function (segmentName) { return ({
26
+ name: segmentName,
27
+ added: setToArray(segments.segmentCache[segmentName]),
28
+ removed: [],
29
+ since: -1,
30
+ till: segments.getChangeNumber(segmentName)
31
+ }); }) :
32
+ undefined,
33
+ memberships: keys ?
34
+ keys.reduce(function (prev, key) {
35
+ var matchingKey = getMatching(key);
36
+ if (storage.shared) { // Client-side segments
37
+ var sharedStorage = storage.shared(matchingKey);
38
+ prev[matchingKey] = {
39
+ ms: {
40
+ k: Object.keys(sharedStorage.segments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
41
+ },
42
+ ls: sharedStorage.largeSegments ? {
43
+ k: Object.keys(sharedStorage.largeSegments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
44
+ } : undefined
45
+ };
46
+ }
47
+ else { // Server-side segments
48
+ prev[matchingKey] = {
49
+ ms: {
50
+ k: Object.keys(storage.segments.segmentCache).reduce(function (prev, segmentName) {
51
+ return storage.segments.segmentCache[segmentName].has(matchingKey) ?
52
+ prev.concat({ n: segmentName }) :
53
+ prev;
54
+ }, [])
55
+ },
56
+ ls: {
57
+ k: []
58
+ }
59
+ };
60
+ }
61
+ return prev;
62
+ }, {}) :
63
+ undefined
64
+ };
65
+ }