@splitsoftware/splitio-commons 1.6.2-rc.8 → 1.7.0
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/CHANGES.txt +4 -1
- package/cjs/evaluator/index.js +5 -5
- package/cjs/listeners/browser.js +9 -11
- package/cjs/sdkClient/client.js +19 -7
- package/cjs/sdkFactory/index.js +7 -25
- package/cjs/services/splitApi.js +4 -4
- package/cjs/storages/AbstractSplitsCacheAsync.js +1 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
- package/cjs/storages/KeyBuilderSS.js +9 -9
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -1
- package/cjs/storages/inLocalStorage/index.js +15 -11
- package/cjs/storages/inMemory/InMemoryStorage.js +11 -8
- package/cjs/storages/inMemory/InMemoryStorageCS.js +11 -8
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +65 -37
- package/cjs/storages/inMemory/{uniqueKeysCacheInMemory.js → UniqueKeysCacheInMemory.js} +24 -25
- package/cjs/storages/inMemory/{uniqueKeysCacheInMemoryCS.js → UniqueKeysCacheInMemoryCS.js} +10 -12
- package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +37 -2
- package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +2 -19
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +100 -0
- package/cjs/storages/inRedis/{uniqueKeysCacheInRedis.js → UniqueKeysCacheInRedis.js} +16 -4
- package/cjs/storages/inRedis/index.js +6 -4
- package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +81 -0
- package/cjs/storages/pluggable/ImpressionsCachePluggable.js +2 -19
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +126 -0
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +61 -0
- package/cjs/storages/pluggable/inMemoryWrapper.js +8 -6
- package/cjs/storages/pluggable/index.js +51 -18
- package/cjs/storages/utils.js +73 -0
- package/cjs/sync/submitters/submitterManager.js +1 -1
- package/cjs/sync/submitters/telemetrySubmitter.js +4 -37
- package/cjs/sync/submitters/uniqueKeysSubmitter.js +4 -3
- package/cjs/trackers/impressionObserver/utils.js +1 -17
- package/cjs/trackers/uniqueKeysTracker.js +1 -1
- package/cjs/utils/lang/maps.js +15 -7
- package/cjs/utils/redis/RedisMock.js +31 -0
- package/cjs/utils/settingsValidation/index.js +7 -4
- package/esm/evaluator/index.js +5 -5
- package/esm/listeners/browser.js +9 -11
- package/esm/sdkClient/client.js +19 -7
- package/esm/sdkFactory/index.js +7 -25
- package/esm/services/splitApi.js +4 -4
- package/esm/storages/AbstractSplitsCacheAsync.js +1 -1
- package/esm/storages/AbstractSplitsCacheSync.js +1 -1
- package/esm/storages/KeyBuilderSS.js +8 -8
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -1
- package/esm/storages/inLocalStorage/index.js +16 -12
- package/esm/storages/inMemory/InMemoryStorage.js +13 -10
- package/esm/storages/inMemory/InMemoryStorageCS.js +12 -9
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +64 -37
- package/esm/storages/inMemory/{uniqueKeysCacheInMemory.js → UniqueKeysCacheInMemory.js} +22 -24
- package/esm/storages/inMemory/{uniqueKeysCacheInMemoryCS.js → UniqueKeysCacheInMemoryCS.js} +10 -12
- package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +37 -2
- package/esm/storages/inRedis/ImpressionsCacheInRedis.js +2 -19
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +100 -0
- package/esm/storages/inRedis/{uniqueKeysCacheInRedis.js → UniqueKeysCacheInRedis.js} +15 -3
- package/esm/storages/inRedis/index.js +5 -3
- package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +78 -0
- package/esm/storages/pluggable/ImpressionsCachePluggable.js +2 -19
- package/esm/storages/pluggable/TelemetryCachePluggable.js +126 -0
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +58 -0
- package/esm/storages/pluggable/inMemoryWrapper.js +8 -6
- package/esm/storages/pluggable/index.js +52 -19
- package/esm/storages/utils.js +65 -0
- package/esm/sync/submitters/submitterManager.js +1 -1
- package/esm/sync/submitters/telemetrySubmitter.js +4 -36
- package/esm/sync/submitters/uniqueKeysSubmitter.js +4 -3
- package/esm/trackers/impressionObserver/utils.js +1 -15
- package/esm/trackers/uniqueKeysTracker.js +1 -1
- package/esm/utils/lang/maps.js +15 -7
- package/esm/utils/redis/RedisMock.js +28 -0
- package/esm/utils/settingsValidation/index.js +7 -4
- package/package.json +2 -2
- package/src/consent/sdkUserConsent.ts +1 -1
- package/src/evaluator/index.ts +6 -6
- package/src/listeners/browser.ts +9 -13
- package/src/logger/.DS_Store +0 -0
- package/src/sdkClient/client.ts +21 -8
- package/src/sdkClient/sdkClient.ts +1 -1
- package/src/sdkFactory/index.ts +10 -33
- package/src/sdkFactory/types.ts +2 -2
- package/src/services/splitApi.ts +6 -6
- package/src/services/types.ts +2 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +1 -1
- package/src/storages/AbstractSplitsCacheSync.ts +1 -1
- package/src/storages/KeyBuilderSS.ts +13 -11
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +0 -1
- package/src/storages/inLocalStorage/index.ts +17 -12
- package/src/storages/inMemory/AttributesCacheInMemory.ts +7 -7
- package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +2 -2
- package/src/storages/inMemory/InMemoryStorage.ts +14 -10
- package/src/storages/inMemory/InMemoryStorageCS.ts +13 -10
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +72 -35
- package/src/storages/inMemory/{uniqueKeysCacheInMemory.ts → UniqueKeysCacheInMemory.ts} +26 -28
- package/src/storages/inMemory/{uniqueKeysCacheInMemoryCS.ts → UniqueKeysCacheInMemoryCS.ts} +15 -17
- package/src/storages/inRedis/EventsCacheInRedis.ts +1 -1
- package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +51 -8
- package/src/storages/inRedis/ImpressionsCacheInRedis.ts +2 -22
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +122 -1
- package/src/storages/inRedis/{uniqueKeysCacheInRedis.ts → UniqueKeysCacheInRedis.ts} +25 -12
- package/src/storages/inRedis/index.ts +6 -3
- package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +92 -0
- package/src/storages/pluggable/ImpressionsCachePluggable.ts +3 -23
- package/src/storages/pluggable/TelemetryCachePluggable.ts +147 -1
- package/src/storages/pluggable/UniqueKeysCachePluggable.ts +67 -0
- package/src/storages/pluggable/inMemoryWrapper.ts +6 -6
- package/src/storages/pluggable/index.ts +56 -20
- package/src/storages/types.ts +53 -70
- package/src/storages/utils.ts +78 -0
- package/src/sync/submitters/submitter.ts +2 -2
- package/src/sync/submitters/submitterManager.ts +1 -1
- package/src/sync/submitters/telemetrySubmitter.ts +9 -39
- package/src/sync/submitters/types.ts +33 -17
- package/src/sync/submitters/uniqueKeysSubmitter.ts +6 -5
- package/src/trackers/impressionObserver/utils.ts +1 -16
- package/src/trackers/impressionsTracker.ts +2 -2
- package/src/trackers/strategy/strategyDebug.ts +4 -4
- package/src/trackers/strategy/strategyNone.ts +9 -9
- package/src/trackers/strategy/strategyOptimized.ts +9 -9
- package/src/trackers/uniqueKeysTracker.ts +6 -6
- package/src/types.ts +0 -2
- package/src/utils/lang/maps.ts +20 -8
- package/src/utils/redis/RedisMock.ts +33 -0
- package/src/utils/settingsValidation/index.ts +5 -5
- package/types/services/types.d.ts +2 -2
- package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
- package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
- package/types/storages/KeyBuilderSS.d.ts +5 -2
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +0 -1
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +23 -9
- package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +9 -9
- package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +2 -4
- package/types/storages/inRedis/EventsCacheInRedis.d.ts +1 -1
- package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +3 -1
- package/types/storages/inRedis/ImpressionsCacheInRedis.d.ts +0 -1
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +16 -1
- package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +8 -2
- package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +16 -0
- package/types/storages/pluggable/ImpressionsCachePluggable.d.ts +1 -2
- package/types/storages/pluggable/TelemetryCachePluggable.d.ts +17 -1
- package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +20 -0
- package/types/storages/types.d.ts +42 -49
- package/types/storages/utils.d.ts +8 -0
- package/types/sync/submitters/submitter.d.ts +2 -2
- package/types/sync/submitters/telemetrySubmitter.d.ts +2 -10
- package/types/sync/submitters/types.d.ts +27 -18
- package/types/trackers/impressionObserver/utils.d.ts +0 -8
- package/types/trackers/strategy/strategyNone.d.ts +2 -2
- package/types/trackers/strategy/strategyOptimized.d.ts +2 -2
- package/types/trackers/uniqueKeysTracker.d.ts +1 -1
- package/types/types.d.ts +0 -2
- package/types/utils/lang/maps.d.ts +6 -2
- package/types/utils/redis/RedisMock.d.ts +4 -0
- package/types/utils/settingsValidation/index.d.ts +0 -1
- package/cjs/storages/metadataBuilder.js +0 -12
- package/esm/storages/metadataBuilder.js +0 -8
- package/src/storages/metadataBuilder.ts +0 -11
- package/types/sdkClient/types.d.ts +0 -18
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
- package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
- package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
- package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +0 -5
- package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
- package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
- package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
- package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
- package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +0 -5
- package/types/sync/syncTaskComposite.d.ts +0 -5
- package/types/trackers/filter/bloomFilter.d.ts +0 -10
- package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
- package/types/trackers/filter/types.d.ts +0 -5
- package/types/utils/timeTracker/index.d.ts +0 -70
package/esm/utils/lang/maps.js
CHANGED
|
@@ -37,13 +37,6 @@ var MapPoly = /** @class */ (function () {
|
|
|
37
37
|
this.__mapKeysData__.length = 0;
|
|
38
38
|
this.__mapValuesData__.length = 0;
|
|
39
39
|
};
|
|
40
|
-
MapPoly.prototype.set = function (key, value) {
|
|
41
|
-
var index = this.__mapKeysData__.indexOf(key);
|
|
42
|
-
if (index === -1)
|
|
43
|
-
index = this.__mapKeysData__.push(key) - 1;
|
|
44
|
-
this.__mapValuesData__[index] = value;
|
|
45
|
-
return this;
|
|
46
|
-
};
|
|
47
40
|
MapPoly.prototype.delete = function (key) {
|
|
48
41
|
var index = this.__mapKeysData__.indexOf(key);
|
|
49
42
|
if (index === -1)
|
|
@@ -52,12 +45,27 @@ var MapPoly = /** @class */ (function () {
|
|
|
52
45
|
this.__mapValuesData__.splice(index, 1);
|
|
53
46
|
return true;
|
|
54
47
|
};
|
|
48
|
+
MapPoly.prototype.forEach = function (callbackfn, thisArg) {
|
|
49
|
+
for (var i = 0; i < this.__mapKeysData__.length; i++) {
|
|
50
|
+
callbackfn.call(thisArg, this.__mapValuesData__[i], this.__mapKeysData__[i], this);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
55
53
|
MapPoly.prototype.get = function (key) {
|
|
56
54
|
var index = this.__mapKeysData__.indexOf(key);
|
|
57
55
|
if (index === -1)
|
|
58
56
|
return;
|
|
59
57
|
return this.__mapValuesData__[index];
|
|
60
58
|
};
|
|
59
|
+
MapPoly.prototype.has = function (key) {
|
|
60
|
+
return this.__mapKeysData__.indexOf(key) !== -1;
|
|
61
|
+
};
|
|
62
|
+
MapPoly.prototype.set = function (key, value) {
|
|
63
|
+
var index = this.__mapKeysData__.indexOf(key);
|
|
64
|
+
if (index === -1)
|
|
65
|
+
index = this.__mapKeysData__.push(key) - 1;
|
|
66
|
+
this.__mapValuesData__[index] = value;
|
|
67
|
+
return this;
|
|
68
|
+
};
|
|
61
69
|
Object.defineProperty(MapPoly.prototype, "size", {
|
|
62
70
|
get: function () {
|
|
63
71
|
return this.__mapKeysData__.length;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
function identityFunction(data) {
|
|
3
|
+
return data;
|
|
4
|
+
}
|
|
5
|
+
function asyncFunction(data) {
|
|
6
|
+
return Promise.resolve(data);
|
|
7
|
+
}
|
|
8
|
+
var IDENTITY_METHODS = [];
|
|
9
|
+
var ASYNC_METHODS = ['rpush', 'hincrby'];
|
|
10
|
+
var PIPELINE_METHODS = ['rpush', 'hincrby'];
|
|
11
|
+
var RedisMock = /** @class */ (function () {
|
|
12
|
+
function RedisMock() {
|
|
13
|
+
var _this = this;
|
|
14
|
+
this.pipelineMethods = { exec: jest.fn(asyncFunction) };
|
|
15
|
+
IDENTITY_METHODS.forEach(function (method) {
|
|
16
|
+
_this[method] = jest.fn(identityFunction);
|
|
17
|
+
});
|
|
18
|
+
ASYNC_METHODS.forEach(function (method) {
|
|
19
|
+
_this[method] = jest.fn(asyncFunction);
|
|
20
|
+
});
|
|
21
|
+
PIPELINE_METHODS.forEach(function (method) {
|
|
22
|
+
_this.pipelineMethods[method] = _this[method];
|
|
23
|
+
});
|
|
24
|
+
this.pipeline = jest.fn(function () { return _this.pipelineMethods; });
|
|
25
|
+
}
|
|
26
|
+
return RedisMock;
|
|
27
|
+
}());
|
|
28
|
+
export { RedisMock };
|
|
@@ -31,8 +31,6 @@ export var base = {
|
|
|
31
31
|
telemetryRefreshRate: 3600,
|
|
32
32
|
// publish evaluations each 300 sec (default value for OPTIMIZED impressions mode)
|
|
33
33
|
impressionsRefreshRate: 300,
|
|
34
|
-
// publish unique Keys each 900 sec (15 min)
|
|
35
|
-
uniqueKeysRefreshRate: 900,
|
|
36
34
|
// fetch offline changes each 15 sec
|
|
37
35
|
offlineRefreshRate: 15,
|
|
38
36
|
// publish events every 60 seconds after the first flush
|
|
@@ -111,7 +109,6 @@ export function settingsValidation(config, validationParams) {
|
|
|
111
109
|
scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate);
|
|
112
110
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
113
111
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
114
|
-
scheduler.uniqueKeysRefreshRate = fromSecondsToMillis(scheduler.uniqueKeysRefreshRate);
|
|
115
112
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
116
113
|
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
117
114
|
if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG)
|
|
@@ -132,8 +129,8 @@ export function settingsValidation(config, validationParams) {
|
|
|
132
129
|
if (storage)
|
|
133
130
|
withDefaults.storage = storage(withDefaults);
|
|
134
131
|
// Validate key and TT (for client-side)
|
|
132
|
+
var maybeKey = withDefaults.core.key;
|
|
135
133
|
if (validationParams.acceptKey) {
|
|
136
|
-
var maybeKey = withDefaults.core.key;
|
|
137
134
|
// Although `key` is required in client-side, it can be omitted in LOCALHOST mode. In that case, the value `localhost_key` is used.
|
|
138
135
|
if (withDefaults.mode === LOCALHOST_MODE && maybeKey === undefined) {
|
|
139
136
|
withDefaults.core.key = 'localhost_key';
|
|
@@ -151,6 +148,12 @@ export function settingsValidation(config, validationParams) {
|
|
|
151
148
|
}
|
|
152
149
|
}
|
|
153
150
|
}
|
|
151
|
+
else {
|
|
152
|
+
// On server-side, key is undefined and used to distinguish from client-side
|
|
153
|
+
if (maybeKey !== undefined)
|
|
154
|
+
log.warn('Provided `key` is ignored in server-side SDK.'); // @ts-ignore
|
|
155
|
+
withDefaults.core.key = undefined;
|
|
156
|
+
}
|
|
154
157
|
// Current ip/hostname information
|
|
155
158
|
// @ts-ignore, modify readonly prop
|
|
156
159
|
withDefaults.runtime = runtime(withDefaults);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@splitsoftware/splitio-commons",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Split Javascript SDK common components",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"build:cjs": "rimraf cjs && tsc -m CommonJS --outDir cjs",
|
|
25
25
|
"test": "jest",
|
|
26
26
|
"test:coverage": "jest --coverage",
|
|
27
|
+
"all": "npm run check && npm run build && npm run test",
|
|
27
28
|
"publish:rc": "npm run check && npm run test && npm run build && npm publish --tag rc",
|
|
28
29
|
"publish:stable": "npm run check && npm run test && npm run build && npm publish"
|
|
29
30
|
},
|
|
@@ -70,7 +71,6 @@
|
|
|
70
71
|
"ioredis": "^4.28.0",
|
|
71
72
|
"jest": "^27.2.3",
|
|
72
73
|
"jest-localstorage-mock": "^2.4.3",
|
|
73
|
-
"js-yaml": "^3.13.1",
|
|
74
74
|
"lodash": "^4.17.21",
|
|
75
75
|
"node-fetch": "^2.6.7",
|
|
76
76
|
"redis-server": "1.2.2",
|
|
@@ -40,7 +40,7 @@ export function createUserConsentAPI(params: ISdkFactoryContext) {
|
|
|
40
40
|
|
|
41
41
|
// @ts-ignore, clear method is present in storage for standalone and partial consumer mode
|
|
42
42
|
if (events.clear) events.clear(); // @ts-ignore
|
|
43
|
-
if (impressions.clear) impressions.clear()
|
|
43
|
+
if (impressions.clear) impressions.clear(); // @ts-ignore
|
|
44
44
|
if (impressionCounts && impressionCounts.clear) impressionCounts.clear();
|
|
45
45
|
}
|
|
46
46
|
} else {
|
package/src/evaluator/index.ts
CHANGED
|
@@ -29,19 +29,19 @@ export function evaluateFeature(
|
|
|
29
29
|
attributes: SplitIO.Attributes | undefined,
|
|
30
30
|
storage: IStorageSync | IStorageAsync,
|
|
31
31
|
): MaybeThenable<IEvaluationResult> {
|
|
32
|
-
let
|
|
32
|
+
let parsedSplit;
|
|
33
33
|
|
|
34
34
|
try {
|
|
35
|
-
|
|
35
|
+
parsedSplit = storage.splits.getSplit(splitName);
|
|
36
36
|
} catch (e) {
|
|
37
37
|
// Exception on sync `getSplit` storage. Not possible ATM with InMemory and InLocal storages.
|
|
38
38
|
return treatmentException;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if (thenable(
|
|
42
|
-
return
|
|
41
|
+
if (thenable(parsedSplit)) {
|
|
42
|
+
return parsedSplit.then((split) => getEvaluation(
|
|
43
43
|
log,
|
|
44
|
-
|
|
44
|
+
split,
|
|
45
45
|
key,
|
|
46
46
|
attributes,
|
|
47
47
|
storage,
|
|
@@ -54,7 +54,7 @@ export function evaluateFeature(
|
|
|
54
54
|
|
|
55
55
|
return getEvaluation(
|
|
56
56
|
log,
|
|
57
|
-
|
|
57
|
+
parsedSplit,
|
|
58
58
|
key,
|
|
59
59
|
attributes,
|
|
60
60
|
storage,
|
package/src/listeners/browser.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-undef */
|
|
2
2
|
// @TODO eventually migrate to JS-Browser-SDK package.
|
|
3
3
|
import { ISignalListener } from './types';
|
|
4
|
-
import {
|
|
4
|
+
import { IRecorderCacheSync, IStorageSync } from '../storages/types';
|
|
5
5
|
import { fromImpressionsCollector } from '../sync/submitters/impressionsSubmitter';
|
|
6
6
|
import { fromImpressionCountsCollector } from '../sync/submitters/impressionCountsSubmitter';
|
|
7
7
|
import { IResponse, ISplitApi } from '../services/types';
|
|
@@ -12,7 +12,6 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
12
12
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
13
13
|
import { ISyncManager } from '../sync/types';
|
|
14
14
|
import { isConsentGranted } from '../consent';
|
|
15
|
-
import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';
|
|
16
15
|
|
|
17
16
|
const VISIBILITYCHANGE_EVENT = 'visibilitychange';
|
|
18
17
|
const PAGEHIDE_EVENT = 'pagehide';
|
|
@@ -84,27 +83,25 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
84
83
|
*/
|
|
85
84
|
flushData() {
|
|
86
85
|
if (!this.syncManager) return; // In consumer mode there is not sync manager and data to flush
|
|
86
|
+
const { events, telemetry } = this.settings.urls;
|
|
87
87
|
|
|
88
88
|
// Flush impressions & events data if there is user consent
|
|
89
89
|
if (isConsentGranted(this.settings)) {
|
|
90
|
-
const eventsUrl = this.settings.urls.events;
|
|
91
90
|
const sim = this.settings.sync.impressionsMode;
|
|
92
91
|
const extraMetadata = {
|
|
93
92
|
// sim stands for Sync/Split Impressions Mode
|
|
94
93
|
sim: sim === OPTIMIZED ? OPTIMIZED : sim === DEBUG ? DEBUG : NONE
|
|
95
94
|
};
|
|
96
95
|
|
|
97
|
-
this._flushData(
|
|
98
|
-
this._flushData(
|
|
99
|
-
if (this.storage.impressionCounts) this._flushData(
|
|
96
|
+
this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
|
|
97
|
+
this._flushData(events + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
|
|
98
|
+
if (this.storage.impressionCounts) this._flushData(events + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
if (this.storage.uniqueKeys) this._flushData(telemetry + '/v1/keys/cs/beacon', this.storage.uniqueKeys, this.serviceApi.postUniqueKeysBulkCs);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
// Flush telemetry data
|
|
103
|
-
if (this.storage.telemetry)
|
|
104
|
-
const telemetryUrl = this.settings.urls.telemetry;
|
|
105
|
-
const telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
106
|
-
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
107
|
-
}
|
|
104
|
+
if (this.storage.telemetry) this._flushData(telemetry + '/v1/metrics/usage/beacon', this.storage.telemetry, this.serviceApi.postMetricsUsage);
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
flushDataIfHidden() {
|
|
@@ -112,14 +109,13 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
112
109
|
if (document.visibilityState === 'hidden') this.flushData(); // On a 'visibilitychange' event, flush data if state is hidden
|
|
113
110
|
}
|
|
114
111
|
|
|
115
|
-
private _flushData<T>(url: string, cache:
|
|
112
|
+
private _flushData<T>(url: string, cache: IRecorderCacheSync<T>, postService: (body: string) => Promise<IResponse>, fromCacheToPayload?: (cacheData: T) => any, extraMetadata?: {}) {
|
|
116
113
|
// if there is data in cache, send it to backend
|
|
117
114
|
if (!cache.isEmpty()) {
|
|
118
115
|
const dataPayload = fromCacheToPayload ? fromCacheToPayload(cache.pop()) : cache.pop();
|
|
119
116
|
if (!this._sendBeacon(url, dataPayload, extraMetadata)) {
|
|
120
117
|
postService(JSON.stringify(dataPayload)).catch(() => { }); // no-op just to catch a possible exception
|
|
121
118
|
}
|
|
122
|
-
cache.clear();
|
|
123
119
|
}
|
|
124
120
|
}
|
|
125
121
|
|
|
Binary file
|
package/src/sdkClient/client.ts
CHANGED
|
@@ -9,6 +9,17 @@ import { IEvaluationResult } from '../evaluator/types';
|
|
|
9
9
|
import { SplitIO, ImpressionDTO } from '../types';
|
|
10
10
|
import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
|
|
11
11
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
12
|
+
import { isStorageSync } from '../trackers/impressionObserver/utils';
|
|
13
|
+
|
|
14
|
+
const treatmentNotReady = { treatment: CONTROL, label: SDK_NOT_READY };
|
|
15
|
+
|
|
16
|
+
function treatmentsNotReady(splitNames: string[]) {
|
|
17
|
+
const evaluations: Record<string, IEvaluationResult> = {};
|
|
18
|
+
splitNames.forEach(splitName => {
|
|
19
|
+
evaluations[splitName] = treatmentNotReady;
|
|
20
|
+
});
|
|
21
|
+
return evaluations;
|
|
22
|
+
}
|
|
12
23
|
|
|
13
24
|
/**
|
|
14
25
|
* Creator of base client with getTreatments and track methods.
|
|
@@ -29,7 +40,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
29
40
|
return treatment;
|
|
30
41
|
};
|
|
31
42
|
|
|
32
|
-
const evaluation =
|
|
43
|
+
const evaluation = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
|
|
44
|
+
evaluateFeature(log, key, splitName, attributes, storage) :
|
|
45
|
+
isStorageSync(settings) ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
46
|
+
treatmentNotReady :
|
|
47
|
+
Promise.resolve(treatmentNotReady); // Promisify if async
|
|
33
48
|
|
|
34
49
|
return thenable(evaluation) ? evaluation.then((res) => wrapUp(res)) : wrapUp(evaluation);
|
|
35
50
|
}
|
|
@@ -53,7 +68,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
53
68
|
return treatments;
|
|
54
69
|
};
|
|
55
70
|
|
|
56
|
-
const evaluations =
|
|
71
|
+
const evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
|
|
72
|
+
evaluateFeatures(log, key, splitNames, attributes, storage) :
|
|
73
|
+
isStorageSync(settings) ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
74
|
+
treatmentsNotReady(splitNames) :
|
|
75
|
+
Promise.resolve(treatmentsNotReady(splitNames)); // Promisify if async
|
|
57
76
|
|
|
58
77
|
return thenable(evaluations) ? evaluations.then((res) => wrapUp(res)) : wrapUp(evaluations);
|
|
59
78
|
}
|
|
@@ -72,15 +91,9 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
72
91
|
invokingMethodName: string,
|
|
73
92
|
queue: ImpressionDTO[]
|
|
74
93
|
): SplitIO.Treatment | SplitIO.TreatmentWithConfig {
|
|
75
|
-
const isSdkReady = readinessManager.isReady() || readinessManager.isReadyFromCache();
|
|
76
94
|
const matchingKey = getMatching(key);
|
|
77
95
|
const bucketingKey = getBucketing(key);
|
|
78
96
|
|
|
79
|
-
// If the SDK was not ready, treatment may be incorrect due to having Splits but not segments data.
|
|
80
|
-
if (!isSdkReady) {
|
|
81
|
-
evaluation = { treatment: CONTROL, label: SDK_NOT_READY };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
97
|
const { treatment, label, changeNumber, config = null } = evaluation;
|
|
85
98
|
log.info(IMPRESSION, [splitName, matchingKey, treatment, label]);
|
|
86
99
|
|
|
@@ -39,7 +39,7 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
|
|
|
39
39
|
|
|
40
40
|
// Release the API Key if it is the main client
|
|
41
41
|
if (!isSharedClient) releaseApiKey(settings.core.authorizationKey);
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
if (uniqueKeysTracker) uniqueKeysTracker.stop();
|
|
44
44
|
|
|
45
45
|
// Cleanup storage
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -3,14 +3,10 @@ import { sdkReadinessManagerFactory } from '../readiness/sdkReadinessManager';
|
|
|
3
3
|
import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
|
|
4
4
|
import { eventTrackerFactory } from '../trackers/eventTracker';
|
|
5
5
|
import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
|
|
6
|
-
import { IStorageFactoryParams } from '../storages/types';
|
|
7
6
|
import { SplitIO } from '../types';
|
|
8
|
-
import { getMatching } from '../utils/key';
|
|
9
|
-
import { shouldBeOptimized } from '../trackers/impressionObserver/utils';
|
|
10
7
|
import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
|
|
11
8
|
import { createLoggerAPI } from '../logger/sdkLogger';
|
|
12
9
|
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
|
|
13
|
-
import { metadataBuilder } from '../storages/metadataBuilder';
|
|
14
10
|
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
15
11
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
16
12
|
import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
|
|
@@ -28,7 +24,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
28
24
|
syncManagerFactory, SignalListener, impressionsObserverFactory,
|
|
29
25
|
integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory,
|
|
30
26
|
filterAdapterFactory } = params;
|
|
31
|
-
const log = settings
|
|
27
|
+
const { log, sync: { impressionsMode } } = settings;
|
|
32
28
|
|
|
33
29
|
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid API Key, etc.
|
|
34
30
|
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
|
|
@@ -39,50 +35,31 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
39
35
|
const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
|
|
40
36
|
const readiness = sdkReadinessManager.readinessManager;
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
impressionsQueueSize: settings.scheduler.impressionsQueueSize,
|
|
45
|
-
eventsQueueSize: settings.scheduler.eventsQueueSize,
|
|
46
|
-
uniqueKeysCacheSize: settings.scheduler.uniqueKeysCacheSize,
|
|
47
|
-
optimize: shouldBeOptimized(settings),
|
|
48
|
-
|
|
49
|
-
// ATM, only used by InLocalStorage
|
|
50
|
-
matchingKey: getMatching(settings.core.key),
|
|
51
|
-
splitFiltersValidation: settings.sync.__splitFiltersValidation,
|
|
52
|
-
|
|
53
|
-
// ATM, only used by PluggableStorage
|
|
54
|
-
mode: settings.mode,
|
|
55
|
-
impressionsMode: settings.sync.impressionsMode,
|
|
56
|
-
|
|
57
|
-
// Callback used to emit SDK_READY in consumer mode, where `syncManagerFactory` is undefined,
|
|
58
|
-
// or partial consumer mode, where it only has submitters, and therefore it doesn't emit readiness events.
|
|
38
|
+
const storage = storageFactory({
|
|
39
|
+
settings,
|
|
59
40
|
onReadyCb: (error) => {
|
|
60
41
|
if (error) return; // Don't emit SDK_READY if storage failed to connect. Error message is logged by wrapperAdapter
|
|
61
42
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
62
43
|
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
63
44
|
},
|
|
64
|
-
|
|
65
|
-
log
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const storage = storageFactory(storageFactoryParams);
|
|
45
|
+
});
|
|
69
46
|
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
70
47
|
|
|
71
48
|
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
72
49
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
|
|
73
50
|
|
|
74
51
|
const observer = impressionsObserverFactory();
|
|
75
|
-
const uniqueKeysTracker =
|
|
52
|
+
const uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys!, filterAdapterFactory && filterAdapterFactory()) : undefined;
|
|
76
53
|
|
|
77
54
|
let strategy;
|
|
78
|
-
switch (
|
|
79
|
-
case OPTIMIZED:
|
|
55
|
+
switch (impressionsMode) {
|
|
56
|
+
case OPTIMIZED:
|
|
80
57
|
strategy = strategyOptimizedFactory(observer, storage.impressionCounts!);
|
|
81
58
|
break;
|
|
82
|
-
case NONE:
|
|
59
|
+
case NONE:
|
|
83
60
|
strategy = strategyNoneFactory(storage.impressionCounts!, uniqueKeysTracker!);
|
|
84
61
|
break;
|
|
85
|
-
default:
|
|
62
|
+
default:
|
|
86
63
|
strategy = strategyDebugFactory(observer);
|
|
87
64
|
}
|
|
88
65
|
|
|
@@ -121,7 +98,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
121
98
|
},
|
|
122
99
|
|
|
123
100
|
// Logger wrapper API
|
|
124
|
-
Logger: createLoggerAPI(
|
|
101
|
+
Logger: createLoggerAPI(log),
|
|
125
102
|
|
|
126
103
|
settings,
|
|
127
104
|
}, extraProps && extraProps(ctx));
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -97,9 +97,9 @@ export interface ISdkFactoryParams {
|
|
|
97
97
|
// It Allows to distinguish SDK clients with the client-side API (`ICsSDK`) or server-side API (`ISDK` or `IAsyncSDK`).
|
|
98
98
|
sdkClientMethodFactory: (params: ISdkFactoryContext) => ({ (): SplitIO.ICsClient; (key: SplitIO.SplitKey, trafficType?: string | undefined): SplitIO.ICsClient; } | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient))
|
|
99
99
|
|
|
100
|
-
// Impression observer factory.
|
|
100
|
+
// Impression observer factory.
|
|
101
101
|
impressionsObserverFactory: () => IImpressionObserver
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
filterAdapterFactory?: () => IFilterAdapter
|
|
104
104
|
|
|
105
105
|
// Optional signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed.
|
package/src/services/splitApi.ts
CHANGED
|
@@ -106,7 +106,7 @@ export function splitApiFactory(
|
|
|
106
106
|
const url = `${urls.events}/testImpressions/count`;
|
|
107
107
|
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(IMPRESSIONS_COUNT));
|
|
108
108
|
},
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
/**
|
|
111
111
|
* Post unique keys for client side.
|
|
112
112
|
*
|
|
@@ -117,7 +117,7 @@ export function splitApiFactory(
|
|
|
117
117
|
const url = `${urls.telemetry}/v1/keys/cs`;
|
|
118
118
|
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY));
|
|
119
119
|
},
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
/**
|
|
122
122
|
* Post unique keys for server side.
|
|
123
123
|
*
|
|
@@ -129,14 +129,14 @@ export function splitApiFactory(
|
|
|
129
129
|
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY));
|
|
130
130
|
},
|
|
131
131
|
|
|
132
|
-
postMetricsConfig(body: string) {
|
|
132
|
+
postMetricsConfig(body: string, headers?: Record<string, string>) {
|
|
133
133
|
const url = `${urls.telemetry}/v1/metrics/config`;
|
|
134
|
-
return splitHttpClient(url, { method: 'POST', body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
134
|
+
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
135
135
|
},
|
|
136
136
|
|
|
137
|
-
postMetricsUsage(body: string) {
|
|
137
|
+
postMetricsUsage(body: string, headers?: Record<string, string>) {
|
|
138
138
|
const url = `${urls.telemetry}/v1/metrics/usage`;
|
|
139
|
-
return splitHttpClient(url, { method: 'POST', body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
139
|
+
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
140
140
|
}
|
|
141
141
|
};
|
|
142
142
|
}
|
package/src/services/types.ts
CHANGED
|
@@ -51,9 +51,9 @@ export type IPostTestImpressionsBulk = (body: string, headers?: Record<string, s
|
|
|
51
51
|
|
|
52
52
|
export type IPostTestImpressionsCount = (body: string, headers?: Record<string, string>) => Promise<IResponse>
|
|
53
53
|
|
|
54
|
-
export type IPostMetricsConfig = (body: string) => Promise<IResponse>
|
|
54
|
+
export type IPostMetricsConfig = (body: string, headers?: Record<string, string>) => Promise<IResponse>
|
|
55
55
|
|
|
56
|
-
export type IPostMetricsUsage = (body: string) => Promise<IResponse>
|
|
56
|
+
export type IPostMetricsUsage = (body: string, headers?: Record<string, string>) => Promise<IResponse>
|
|
57
57
|
|
|
58
58
|
export interface ISplitApi {
|
|
59
59
|
getSdkAPIHealthCheck: IHealthCheckAPI
|
|
@@ -41,7 +41,7 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
|
|
|
41
41
|
* @param {string} name
|
|
42
42
|
* @param {string} defaultTreatment
|
|
43
43
|
* @param {number} changeNumber
|
|
44
|
-
* @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the
|
|
44
|
+
* @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the operation successed updating the split or `false` if no split is updated,
|
|
45
45
|
* for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
46
46
|
* The promise will never be rejected.
|
|
47
47
|
*/
|
|
@@ -61,7 +61,7 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
61
61
|
* @param {string} name
|
|
62
62
|
* @param {string} defaultTreatment
|
|
63
63
|
* @param {number} changeNumber
|
|
64
|
-
* @returns {
|
|
64
|
+
* @returns {boolean} `true` if the operation successed updating the split, or `false` if no split is updated,
|
|
65
65
|
* for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
66
66
|
*/
|
|
67
67
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean {
|
|
@@ -2,7 +2,7 @@ import { KeyBuilder } from './KeyBuilder';
|
|
|
2
2
|
import { IMetadata } from '../dtos/types';
|
|
3
3
|
import { Method } from '../sync/submitters/types';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
export const METHOD_NAMES: Record<Method, string> = {
|
|
6
6
|
t: 'treatment',
|
|
7
7
|
ts: 'treatments',
|
|
8
8
|
tc: 'treatmentWithConfig',
|
|
@@ -12,11 +12,17 @@ const methodNames: Record<Method, string> = {
|
|
|
12
12
|
|
|
13
13
|
export class KeyBuilderSS extends KeyBuilder {
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
latencyPrefix: string;
|
|
16
|
+
exceptionPrefix: string;
|
|
17
|
+
initPrefix: string;
|
|
18
|
+
private versionablePrefix: string;
|
|
16
19
|
|
|
17
20
|
constructor(prefix: string, metadata: IMetadata) {
|
|
18
21
|
super(prefix);
|
|
19
|
-
this.
|
|
22
|
+
this.latencyPrefix = `${this.prefix}.telemetry.latencies`;
|
|
23
|
+
this.exceptionPrefix = `${this.prefix}.telemetry.exceptions`;
|
|
24
|
+
this.initPrefix = `${this.prefix}.telemetry.init`;
|
|
25
|
+
this.versionablePrefix = `${metadata.s}/${metadata.n}/${metadata.i}`;
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
buildRegisteredSegmentsKey() {
|
|
@@ -30,7 +36,7 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
30
36
|
buildImpressionsCountKey() {
|
|
31
37
|
return `${this.prefix}.impressions.count`;
|
|
32
38
|
}
|
|
33
|
-
|
|
39
|
+
|
|
34
40
|
buildUniqueKeysKey() {
|
|
35
41
|
return `${this.prefix}.uniquekeys`;
|
|
36
42
|
}
|
|
@@ -46,19 +52,15 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
46
52
|
/* Telemetry keys */
|
|
47
53
|
|
|
48
54
|
buildLatencyKey(method: Method, bucket: number) {
|
|
49
|
-
return `${this.
|
|
55
|
+
return `${this.latencyPrefix}::${this.versionablePrefix}/${METHOD_NAMES[method]}/${bucket}`;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
buildExceptionKey(method: Method) {
|
|
53
|
-
return `${this.
|
|
59
|
+
return `${this.exceptionPrefix}::${this.versionablePrefix}/${METHOD_NAMES[method]}`;
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
buildInitKey() {
|
|
57
|
-
return `${this.
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private buildVersionablePrefix() {
|
|
61
|
-
return `${this.metadata.s}/${this.metadata.n}/${this.metadata.i}`;
|
|
63
|
+
return `${this.initPrefix}::${this.versionablePrefix}`;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
}
|
|
@@ -229,7 +229,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
231
|
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
232
|
-
* Clean operation (clear) also updates `lastUpdated` timestamp with current time.
|
|
233
232
|
*
|
|
234
233
|
* @param {number | undefined} expirationTimestamp if the value is not a number, data will not be cleaned
|
|
235
234
|
*/
|
|
@@ -12,9 +12,10 @@ import { SplitsCacheInMemory } from '../inMemory/SplitsCacheInMemory';
|
|
|
12
12
|
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
|
|
13
13
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
14
14
|
import { LOG_PREFIX } from './constants';
|
|
15
|
-
import {
|
|
15
|
+
import { DEBUG, NONE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
16
16
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
17
|
-
import { UniqueKeysCacheInMemoryCS } from '../inMemory/
|
|
17
|
+
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
18
|
+
import { getMatching } from '../../utils/key';
|
|
18
19
|
|
|
19
20
|
export interface InLocalStorageOptions {
|
|
20
21
|
prefix?: string
|
|
@@ -31,22 +32,26 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
31
32
|
|
|
32
33
|
// Fallback to InMemoryStorage if LocalStorage API is not available
|
|
33
34
|
if (!isLocalStorageAvailable()) {
|
|
34
|
-
params.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
|
|
35
|
+
params.settings.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
|
|
35
36
|
return InMemoryStorageCSFactory(params);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
const log = params
|
|
39
|
-
const
|
|
39
|
+
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
|
|
40
|
+
const matchingKey = getMatching(settings.core.key);
|
|
41
|
+
const keys = new KeyBuilderCS(prefix, matchingKey as string);
|
|
40
42
|
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
41
43
|
|
|
44
|
+
const splits = new SplitsCacheInLocal(log, keys, expirationTimestamp, __splitFiltersValidation);
|
|
45
|
+
const segments = new MySegmentsCacheInLocal(log, keys);
|
|
46
|
+
|
|
42
47
|
return {
|
|
43
|
-
splits
|
|
44
|
-
segments
|
|
45
|
-
impressions: new ImpressionsCacheInMemory(
|
|
46
|
-
impressionCounts:
|
|
47
|
-
events: new EventsCacheInMemory(
|
|
48
|
-
telemetry:
|
|
49
|
-
uniqueKeys:
|
|
48
|
+
splits,
|
|
49
|
+
segments,
|
|
50
|
+
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
51
|
+
impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
|
|
52
|
+
events: new EventsCacheInMemory(eventsQueueSize),
|
|
53
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
54
|
+
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
50
55
|
|
|
51
56
|
destroy() {
|
|
52
57
|
this.splits = new SplitsCacheInMemory();
|