@splitsoftware/splitio-commons 1.17.1 → 1.17.2-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.
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +16 -77
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +24 -22
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +17 -78
- package/esm/sync/polling/updaters/splitChangesUpdater.js +24 -22
- package/package.json +1 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +47 -71
- package/src/sync/polling/updaters/splitChangesUpdater.ts +25 -23
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +0 -4
|
@@ -88,54 +88,28 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
88
88
|
this.hasSync = false;
|
|
89
89
|
};
|
|
90
90
|
SplitsCacheInLocal.prototype.addSplit = function (name, split) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.addToFlagSets(split);
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
catch (e) {
|
|
104
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
91
|
+
var splitKey = this.keys.buildSplitKey(name);
|
|
92
|
+
var splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
93
|
+
var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
94
|
+
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
95
|
+
this._incrementCounts(split);
|
|
96
|
+
this._decrementCounts(previousSplit);
|
|
97
|
+
// if (previousSplit) this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
98
|
+
// this.addToFlagSets(split);
|
|
99
|
+
return true;
|
|
107
100
|
};
|
|
108
101
|
SplitsCacheInLocal.prototype.removeSplit = function (name) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
this.removeFromFlagSets(split.name, split.sets);
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
catch (e) {
|
|
118
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
102
|
+
var split = this.getSplit(name);
|
|
103
|
+
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
104
|
+
this._decrementCounts(split);
|
|
105
|
+
// if (split) this.removeFromFlagSets(split.name, split.sets);
|
|
106
|
+
return true;
|
|
121
107
|
};
|
|
122
108
|
SplitsCacheInLocal.prototype.getSplit = function (name) {
|
|
123
109
|
var item = localStorage.getItem(this.keys.buildSplitKey(name));
|
|
124
110
|
return item && JSON.parse(item);
|
|
125
111
|
};
|
|
126
112
|
SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
127
|
-
// when using a new split query, we must update it at the store
|
|
128
|
-
if (this.updateNewFilter) {
|
|
129
|
-
this.log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
130
|
-
var storageHashKey = this.keys.buildHashKey();
|
|
131
|
-
try {
|
|
132
|
-
localStorage.setItem(storageHashKey, this.storageHash);
|
|
133
|
-
}
|
|
134
|
-
catch (e) {
|
|
135
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
136
|
-
}
|
|
137
|
-
this.updateNewFilter = false;
|
|
138
|
-
}
|
|
139
113
|
try {
|
|
140
114
|
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
|
|
141
115
|
// update "last updated" timestamp with current time
|
|
@@ -213,11 +187,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
213
187
|
var storageHash = localStorage.getItem(storageHashKey);
|
|
214
188
|
if (storageHash !== this.storageHash) {
|
|
215
189
|
try {
|
|
216
|
-
// mark cache to update the new query filter on first successful splits fetch
|
|
217
|
-
this.updateNewFilter = true;
|
|
218
190
|
// if there is cache, clear it
|
|
219
191
|
if (this.checkCache())
|
|
220
192
|
this.clear();
|
|
193
|
+
this.log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
194
|
+
localStorage.setItem(storageHashKey, this.storageHash);
|
|
221
195
|
}
|
|
222
196
|
catch (e) {
|
|
223
197
|
this.log.error(constants_1.LOG_PREFIX + e);
|
|
@@ -233,41 +207,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
233
207
|
return new sets_1._Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
234
208
|
});
|
|
235
209
|
};
|
|
236
|
-
SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
|
|
237
|
-
var _this = this;
|
|
238
|
-
if (!featureFlag.sets)
|
|
239
|
-
return;
|
|
240
|
-
featureFlag.sets.forEach(function (featureFlagSet) {
|
|
241
|
-
if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
|
|
242
|
-
return;
|
|
243
|
-
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
|
|
244
|
-
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
245
|
-
var flagSetCache = new sets_1._Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
246
|
-
flagSetCache.add(featureFlag.name);
|
|
247
|
-
localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
|
|
248
|
-
});
|
|
249
|
-
};
|
|
250
|
-
SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
|
|
251
|
-
var _this = this;
|
|
252
|
-
if (!flagSets)
|
|
253
|
-
return;
|
|
254
|
-
flagSets.forEach(function (flagSet) {
|
|
255
|
-
_this.removeNames(flagSet, featureFlagName);
|
|
256
|
-
});
|
|
257
|
-
};
|
|
258
|
-
SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
|
|
259
|
-
var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
|
|
260
|
-
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
261
|
-
if (!flagSetFromLocalStorage)
|
|
262
|
-
return;
|
|
263
|
-
var flagSetCache = new sets_1._Set(JSON.parse(flagSetFromLocalStorage));
|
|
264
|
-
flagSetCache.delete(featureFlagName);
|
|
265
|
-
if (flagSetCache.size === 0) {
|
|
266
|
-
localStorage.removeItem(flagSetKey);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
|
|
270
|
-
};
|
|
271
210
|
return SplitsCacheInLocal;
|
|
272
211
|
}(AbstractSplitsCacheSync_1.AbstractSplitsCacheSync));
|
|
273
212
|
exports.SplitsCacheInLocal = SplitsCacheInLocal;
|
|
@@ -102,7 +102,7 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
|
|
|
102
102
|
}
|
|
103
103
|
/** Returns true if at least one split was updated */
|
|
104
104
|
function isThereUpdate(flagsChange) {
|
|
105
|
-
var added = flagsChange[
|
|
105
|
+
var added = flagsChange[0], removed = flagsChange[1];
|
|
106
106
|
// There is at least one added or modified feature flag
|
|
107
107
|
if (added && added.some(function (update) { return update; }))
|
|
108
108
|
return true;
|
|
@@ -130,36 +130,38 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
|
|
|
130
130
|
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
|
|
131
131
|
splitChangesFetcher(since, noCache, till, _promiseDecorator))
|
|
132
132
|
.then(function (splitChanges) {
|
|
133
|
-
startingUp = false;
|
|
134
133
|
var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
|
|
135
134
|
log.debug(constants_2.SYNC_SPLITS_NEW, [mutation.added.length]);
|
|
136
135
|
log.debug(constants_2.SYNC_SPLITS_REMOVED, [mutation.removed.length]);
|
|
137
136
|
log.debug(constants_2.SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
|
|
138
137
|
// Write into storage
|
|
139
|
-
//
|
|
140
|
-
return Promise.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
138
|
+
// Wrap into a promise to handle LOCALSTORAGE exceptions and REDIS rejected promises uniformly
|
|
139
|
+
return Promise.resolve().then(function () {
|
|
140
|
+
return Promise.all([
|
|
141
|
+
splits.addSplits(mutation.added),
|
|
142
|
+
splits.removeSplits(mutation.removed),
|
|
143
|
+
segments.registerSegments(mutation.segments)
|
|
144
|
+
]).then(function (flagsChange) {
|
|
145
|
+
splits.setChangeNumber(splitChanges.till);
|
|
146
|
+
startingUp = false;
|
|
147
|
+
if (splitsEventEmitter) {
|
|
148
|
+
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
149
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
|
|
150
|
+
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
151
|
+
.then(function (emitSplitsArrivedEvent) {
|
|
152
|
+
// emit SDK events
|
|
153
|
+
if (emitSplitsArrivedEvent)
|
|
154
|
+
splitsEventEmitter.emit(constants_1.SDK_SPLITS_ARRIVED);
|
|
155
|
+
return true;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
159
160
|
});
|
|
160
161
|
})
|
|
161
162
|
.catch(function (error) {
|
|
162
163
|
log.warn(constants_2.SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
164
|
+
console.log('startingUp', startingUp, 'retriesOnFailureBeforeReady', retriesOnFailureBeforeReady, 'retry', retry);
|
|
163
165
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
164
166
|
retry += 1;
|
|
165
167
|
log.info(constants_2.SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
|
@@ -2,7 +2,7 @@ import { __extends } from "tslib";
|
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
|
-
import { _Set
|
|
5
|
+
import { _Set } from '../../utils/lang/sets';
|
|
6
6
|
import { getStorageHash } from '../KeyBuilder';
|
|
7
7
|
/**
|
|
8
8
|
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
|
|
@@ -85,54 +85,28 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
85
85
|
this.hasSync = false;
|
|
86
86
|
};
|
|
87
87
|
SplitsCacheInLocal.prototype.addSplit = function (name, split) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.addToFlagSets(split);
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
catch (e) {
|
|
101
|
-
this.log.error(LOG_PREFIX + e);
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
88
|
+
var splitKey = this.keys.buildSplitKey(name);
|
|
89
|
+
var splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
90
|
+
var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
91
|
+
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
92
|
+
this._incrementCounts(split);
|
|
93
|
+
this._decrementCounts(previousSplit);
|
|
94
|
+
// if (previousSplit) this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
95
|
+
// this.addToFlagSets(split);
|
|
96
|
+
return true;
|
|
104
97
|
};
|
|
105
98
|
SplitsCacheInLocal.prototype.removeSplit = function (name) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.removeFromFlagSets(split.name, split.sets);
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
this.log.error(LOG_PREFIX + e);
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
99
|
+
var split = this.getSplit(name);
|
|
100
|
+
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
101
|
+
this._decrementCounts(split);
|
|
102
|
+
// if (split) this.removeFromFlagSets(split.name, split.sets);
|
|
103
|
+
return true;
|
|
118
104
|
};
|
|
119
105
|
SplitsCacheInLocal.prototype.getSplit = function (name) {
|
|
120
106
|
var item = localStorage.getItem(this.keys.buildSplitKey(name));
|
|
121
107
|
return item && JSON.parse(item);
|
|
122
108
|
};
|
|
123
109
|
SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
124
|
-
// when using a new split query, we must update it at the store
|
|
125
|
-
if (this.updateNewFilter) {
|
|
126
|
-
this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
127
|
-
var storageHashKey = this.keys.buildHashKey();
|
|
128
|
-
try {
|
|
129
|
-
localStorage.setItem(storageHashKey, this.storageHash);
|
|
130
|
-
}
|
|
131
|
-
catch (e) {
|
|
132
|
-
this.log.error(LOG_PREFIX + e);
|
|
133
|
-
}
|
|
134
|
-
this.updateNewFilter = false;
|
|
135
|
-
}
|
|
136
110
|
try {
|
|
137
111
|
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
|
|
138
112
|
// update "last updated" timestamp with current time
|
|
@@ -210,11 +184,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
210
184
|
var storageHash = localStorage.getItem(storageHashKey);
|
|
211
185
|
if (storageHash !== this.storageHash) {
|
|
212
186
|
try {
|
|
213
|
-
// mark cache to update the new query filter on first successful splits fetch
|
|
214
|
-
this.updateNewFilter = true;
|
|
215
187
|
// if there is cache, clear it
|
|
216
188
|
if (this.checkCache())
|
|
217
189
|
this.clear();
|
|
190
|
+
this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
191
|
+
localStorage.setItem(storageHashKey, this.storageHash);
|
|
218
192
|
}
|
|
219
193
|
catch (e) {
|
|
220
194
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -230,41 +204,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
230
204
|
return new _Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
231
205
|
});
|
|
232
206
|
};
|
|
233
|
-
SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
|
|
234
|
-
var _this = this;
|
|
235
|
-
if (!featureFlag.sets)
|
|
236
|
-
return;
|
|
237
|
-
featureFlag.sets.forEach(function (featureFlagSet) {
|
|
238
|
-
if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
|
|
239
|
-
return;
|
|
240
|
-
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
|
|
241
|
-
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
242
|
-
var flagSetCache = new _Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
243
|
-
flagSetCache.add(featureFlag.name);
|
|
244
|
-
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
245
|
-
});
|
|
246
|
-
};
|
|
247
|
-
SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
|
|
248
|
-
var _this = this;
|
|
249
|
-
if (!flagSets)
|
|
250
|
-
return;
|
|
251
|
-
flagSets.forEach(function (flagSet) {
|
|
252
|
-
_this.removeNames(flagSet, featureFlagName);
|
|
253
|
-
});
|
|
254
|
-
};
|
|
255
|
-
SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
|
|
256
|
-
var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
|
|
257
|
-
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
258
|
-
if (!flagSetFromLocalStorage)
|
|
259
|
-
return;
|
|
260
|
-
var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
261
|
-
flagSetCache.delete(featureFlagName);
|
|
262
|
-
if (flagSetCache.size === 0) {
|
|
263
|
-
localStorage.removeItem(flagSetKey);
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
267
|
-
};
|
|
268
207
|
return SplitsCacheInLocal;
|
|
269
208
|
}(AbstractSplitsCacheSync));
|
|
270
209
|
export { SplitsCacheInLocal };
|
|
@@ -97,7 +97,7 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
97
97
|
}
|
|
98
98
|
/** Returns true if at least one split was updated */
|
|
99
99
|
function isThereUpdate(flagsChange) {
|
|
100
|
-
var added = flagsChange[
|
|
100
|
+
var added = flagsChange[0], removed = flagsChange[1];
|
|
101
101
|
// There is at least one added or modified feature flag
|
|
102
102
|
if (added && added.some(function (update) { return update; }))
|
|
103
103
|
return true;
|
|
@@ -125,36 +125,38 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
125
125
|
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
|
|
126
126
|
splitChangesFetcher(since, noCache, till, _promiseDecorator))
|
|
127
127
|
.then(function (splitChanges) {
|
|
128
|
-
startingUp = false;
|
|
129
128
|
var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
|
|
130
129
|
log.debug(SYNC_SPLITS_NEW, [mutation.added.length]);
|
|
131
130
|
log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]);
|
|
132
131
|
log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
|
|
133
132
|
// Write into storage
|
|
134
|
-
//
|
|
135
|
-
return Promise.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
133
|
+
// Wrap into a promise to handle LOCALSTORAGE exceptions and REDIS rejected promises uniformly
|
|
134
|
+
return Promise.resolve().then(function () {
|
|
135
|
+
return Promise.all([
|
|
136
|
+
splits.addSplits(mutation.added),
|
|
137
|
+
splits.removeSplits(mutation.removed),
|
|
138
|
+
segments.registerSegments(mutation.segments)
|
|
139
|
+
]).then(function (flagsChange) {
|
|
140
|
+
splits.setChangeNumber(splitChanges.till);
|
|
141
|
+
startingUp = false;
|
|
142
|
+
if (splitsEventEmitter) {
|
|
143
|
+
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
144
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
|
|
145
|
+
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
146
|
+
.then(function (emitSplitsArrivedEvent) {
|
|
147
|
+
// emit SDK events
|
|
148
|
+
if (emitSplitsArrivedEvent)
|
|
149
|
+
splitsEventEmitter.emit(SDK_SPLITS_ARRIVED);
|
|
150
|
+
return true;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
});
|
|
154
155
|
});
|
|
155
156
|
})
|
|
156
157
|
.catch(function (error) {
|
|
157
158
|
log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
159
|
+
console.log('startingUp', startingUp, 'retriesOnFailureBeforeReady', retriesOnFailureBeforeReady, 'retry', retry);
|
|
158
160
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
159
161
|
retry += 1;
|
|
160
162
|
log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
|
4
4
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
5
5
|
import { ILogger } from '../../logger/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
|
-
import { ISet, _Set
|
|
7
|
+
import { ISet, _Set } from '../../utils/lang/sets';
|
|
8
8
|
import { ISettings } from '../../types';
|
|
9
9
|
import { getStorageHash } from '../KeyBuilder';
|
|
10
10
|
|
|
@@ -18,7 +18,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
18
18
|
private readonly storageHash: string;
|
|
19
19
|
private readonly flagSetsFilter: string[];
|
|
20
20
|
private hasSync?: boolean;
|
|
21
|
-
private updateNewFilter?: boolean;
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
23
|
* @param {KeyBuilderCS} keys
|
|
@@ -102,39 +101,29 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
addSplit(name: string, split: ISplit) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
104
|
+
const splitKey = this.keys.buildSplitKey(name);
|
|
105
|
+
const splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
106
|
+
const previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
109
107
|
|
|
110
|
-
|
|
108
|
+
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
111
109
|
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
this._incrementCounts(split);
|
|
111
|
+
this._decrementCounts(previousSplit);
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
// if (previousSplit) this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
114
|
+
// this.addToFlagSets(split);
|
|
117
115
|
|
|
118
|
-
|
|
119
|
-
} catch (e) {
|
|
120
|
-
this.log.error(LOG_PREFIX + e);
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
116
|
+
return true;
|
|
123
117
|
}
|
|
124
118
|
|
|
125
119
|
removeSplit(name: string): boolean {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
120
|
+
const split = this.getSplit(name);
|
|
121
|
+
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
129
122
|
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
this._decrementCounts(split);
|
|
124
|
+
// if (split) this.removeFromFlagSets(split.name, split.sets);
|
|
132
125
|
|
|
133
|
-
|
|
134
|
-
} catch (e) {
|
|
135
|
-
this.log.error(LOG_PREFIX + e);
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
126
|
+
return true;
|
|
138
127
|
}
|
|
139
128
|
|
|
140
129
|
getSplit(name: string) {
|
|
@@ -143,19 +132,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
143
132
|
}
|
|
144
133
|
|
|
145
134
|
setChangeNumber(changeNumber: number): boolean {
|
|
146
|
-
|
|
147
|
-
// when using a new split query, we must update it at the store
|
|
148
|
-
if (this.updateNewFilter) {
|
|
149
|
-
this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
150
|
-
const storageHashKey = this.keys.buildHashKey();
|
|
151
|
-
try {
|
|
152
|
-
localStorage.setItem(storageHashKey, this.storageHash);
|
|
153
|
-
} catch (e) {
|
|
154
|
-
this.log.error(LOG_PREFIX + e);
|
|
155
|
-
}
|
|
156
|
-
this.updateNewFilter = false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
135
|
try {
|
|
160
136
|
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
|
|
161
137
|
// update "last updated" timestamp with current time
|
|
@@ -246,12 +222,12 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
246
222
|
|
|
247
223
|
if (storageHash !== this.storageHash) {
|
|
248
224
|
try {
|
|
249
|
-
// mark cache to update the new query filter on first successful splits fetch
|
|
250
|
-
this.updateNewFilter = true;
|
|
251
|
-
|
|
252
225
|
// if there is cache, clear it
|
|
253
226
|
if (this.checkCache()) this.clear();
|
|
254
227
|
|
|
228
|
+
this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
229
|
+
localStorage.setItem(storageHashKey, this.storageHash);
|
|
230
|
+
|
|
255
231
|
} catch (e) {
|
|
256
232
|
this.log.error(LOG_PREFIX + e);
|
|
257
233
|
}
|
|
@@ -268,48 +244,48 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
268
244
|
});
|
|
269
245
|
}
|
|
270
246
|
|
|
271
|
-
private addToFlagSets(featureFlag: ISplit) {
|
|
272
|
-
|
|
247
|
+
// private addToFlagSets(featureFlag: ISplit) {
|
|
248
|
+
// if (!featureFlag.sets) return;
|
|
273
249
|
|
|
274
|
-
|
|
250
|
+
// featureFlag.sets.forEach(featureFlagSet => {
|
|
275
251
|
|
|
276
|
-
|
|
252
|
+
// if (this.flagSetsFilter.length > 0 && !this.flagSetsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;
|
|
277
253
|
|
|
278
|
-
|
|
254
|
+
// const flagSetKey = this.keys.buildFlagSetKey(featureFlagSet);
|
|
279
255
|
|
|
280
|
-
|
|
256
|
+
// const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
281
257
|
|
|
282
|
-
|
|
283
|
-
|
|
258
|
+
// const flagSetCache = new _Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
259
|
+
// flagSetCache.add(featureFlag.name);
|
|
284
260
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
261
|
+
// localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
262
|
+
// });
|
|
263
|
+
// }
|
|
288
264
|
|
|
289
|
-
private removeFromFlagSets(featureFlagName: string, flagSets?: string[]) {
|
|
290
|
-
|
|
265
|
+
// private removeFromFlagSets(featureFlagName: string, flagSets?: string[]) {
|
|
266
|
+
// if (!flagSets) return;
|
|
291
267
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
268
|
+
// flagSets.forEach(flagSet => {
|
|
269
|
+
// this.removeNames(flagSet, featureFlagName);
|
|
270
|
+
// });
|
|
271
|
+
// }
|
|
296
272
|
|
|
297
|
-
private removeNames(flagSetName: string, featureFlagName: string) {
|
|
298
|
-
|
|
273
|
+
// private removeNames(flagSetName: string, featureFlagName: string) {
|
|
274
|
+
// const flagSetKey = this.keys.buildFlagSetKey(flagSetName);
|
|
299
275
|
|
|
300
|
-
|
|
276
|
+
// const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
301
277
|
|
|
302
|
-
|
|
278
|
+
// if (!flagSetFromLocalStorage) return;
|
|
303
279
|
|
|
304
|
-
|
|
305
|
-
|
|
280
|
+
// const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
281
|
+
// flagSetCache.delete(featureFlagName);
|
|
306
282
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
283
|
+
// if (flagSetCache.size === 0) {
|
|
284
|
+
// localStorage.removeItem(flagSetKey);
|
|
285
|
+
// return;
|
|
286
|
+
// }
|
|
311
287
|
|
|
312
|
-
|
|
313
|
-
}
|
|
288
|
+
// localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
289
|
+
// }
|
|
314
290
|
|
|
315
291
|
}
|
|
@@ -129,8 +129,8 @@ export function splitChangesUpdaterFactory(
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/** Returns true if at least one split was updated */
|
|
132
|
-
function isThereUpdate(flagsChange: [
|
|
133
|
-
const [
|
|
132
|
+
function isThereUpdate(flagsChange: [void | boolean[], void | boolean[], boolean | void] | [any, any, any]) {
|
|
133
|
+
const [added, removed] = flagsChange;
|
|
134
134
|
// There is at least one added or modified feature flag
|
|
135
135
|
if (added && added.some((update: boolean) => update)) return true;
|
|
136
136
|
// There is at least one removed feature flag
|
|
@@ -158,8 +158,6 @@ export function splitChangesUpdaterFactory(
|
|
|
158
158
|
splitChangesFetcher(since, noCache, till, _promiseDecorator)
|
|
159
159
|
)
|
|
160
160
|
.then((splitChanges: ISplitChangesResponse) => {
|
|
161
|
-
startingUp = false;
|
|
162
|
-
|
|
163
161
|
const mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
|
|
164
162
|
|
|
165
163
|
log.debug(SYNC_SPLITS_NEW, [mutation.added.length]);
|
|
@@ -167,29 +165,33 @@ export function splitChangesUpdaterFactory(
|
|
|
167
165
|
log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
|
|
168
166
|
|
|
169
167
|
// Write into storage
|
|
170
|
-
//
|
|
171
|
-
return Promise.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
168
|
+
// Wrap into a promise to handle LOCALSTORAGE exceptions and REDIS rejected promises uniformly
|
|
169
|
+
return Promise.resolve().then(() => {
|
|
170
|
+
return Promise.all([
|
|
171
|
+
splits.addSplits(mutation.added),
|
|
172
|
+
splits.removeSplits(mutation.removed),
|
|
173
|
+
segments.registerSegments(mutation.segments)
|
|
174
|
+
]).then((flagsChange) => {
|
|
175
|
+
splits.setChangeNumber(splitChanges.till);
|
|
176
|
+
startingUp = false;
|
|
177
|
+
|
|
178
|
+
if (splitsEventEmitter) {
|
|
179
|
+
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
180
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
|
|
181
|
+
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
182
|
+
.then(emitSplitsArrivedEvent => {
|
|
183
|
+
// emit SDK events
|
|
184
|
+
if (emitSplitsArrivedEvent) splitsEventEmitter.emit(SDK_SPLITS_ARRIVED);
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
});
|
|
189
190
|
});
|
|
190
191
|
})
|
|
191
192
|
.catch(error => {
|
|
192
193
|
log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
194
|
+
console.log('startingUp', startingUp, 'retriesOnFailureBeforeReady', retriesOnFailureBeforeReady, 'retry', retry);
|
|
193
195
|
|
|
194
196
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
195
197
|
retry += 1;
|
|
@@ -12,7 +12,6 @@ export declare class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
12
12
|
private readonly storageHash;
|
|
13
13
|
private readonly flagSetsFilter;
|
|
14
14
|
private hasSync?;
|
|
15
|
-
private updateNewFilter?;
|
|
16
15
|
/**
|
|
17
16
|
* @param {KeyBuilderCS} keys
|
|
18
17
|
* @param {number | undefined} expirationTimestamp
|
|
@@ -49,7 +48,4 @@ export declare class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
49
48
|
private _checkExpiration;
|
|
50
49
|
private _checkFilterQuery;
|
|
51
50
|
getNamesByFlagSets(flagSets: string[]): ISet<string>[];
|
|
52
|
-
private addToFlagSets;
|
|
53
|
-
private removeFromFlagSets;
|
|
54
|
-
private removeNames;
|
|
55
51
|
}
|