@splitsoftware/splitio-commons 2.1.1-rc.0 → 2.1.1-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +7 -0
- package/README.md +0 -1
- package/cjs/evaluator/combiners/and.js +6 -2
- package/cjs/evaluator/combiners/ifelseif.js +6 -6
- package/cjs/evaluator/condition/index.js +5 -6
- package/cjs/evaluator/index.js +7 -7
- package/cjs/evaluator/matchers/index.js +1 -3
- package/cjs/evaluator/matchers/matcherTypes.js +0 -1
- package/cjs/evaluator/matchersTransform/index.js +0 -4
- package/cjs/evaluator/parser/index.js +2 -2
- package/cjs/evaluator/value/sanitize.js +0 -1
- package/cjs/logger/constants.js +3 -4
- package/cjs/logger/messages/debug.js +2 -3
- package/cjs/logger/messages/error.js +1 -1
- package/cjs/logger/messages/warn.js +2 -2
- package/cjs/readiness/readinessManager.js +6 -0
- package/cjs/sdkClient/client.js +29 -19
- package/cjs/sdkClient/clientAttributesDecoration.js +19 -25
- package/cjs/sdkClient/clientInputValidation.js +28 -26
- package/cjs/services/splitApi.js +2 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
- package/cjs/storages/AbstractSplitsCacheSync.js +2 -12
- package/cjs/storages/KeyBuilder.js +0 -9
- package/cjs/storages/KeyBuilderCS.js +4 -4
- package/cjs/storages/KeyBuilderSS.js +0 -3
- package/cjs/storages/dataLoader.js +3 -2
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +23 -76
- package/cjs/storages/inLocalStorage/index.js +5 -7
- package/cjs/storages/inLocalStorage/validateCache.js +79 -0
- package/cjs/storages/inMemory/InMemoryStorage.js +0 -3
- package/cjs/storages/inMemory/InMemoryStorageCS.js +0 -4
- package/cjs/storages/inRedis/index.js +0 -2
- package/cjs/storages/pluggable/index.js +2 -3
- package/cjs/storages/utils.js +1 -0
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/cjs/sync/polling/pollingManagerCS.js +7 -7
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +33 -60
- package/cjs/sync/streaming/SSEHandler/index.js +0 -1
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +77 -106
- package/cjs/sync/streaming/constants.js +1 -2
- package/cjs/sync/streaming/pushManager.js +16 -3
- package/cjs/sync/submitters/impressionsSubmitter.js +3 -2
- package/cjs/sync/syncManagerOnline.js +10 -5
- package/cjs/trackers/strategy/strategyDebug.js +2 -0
- package/cjs/trackers/strategy/strategyOptimized.js +3 -0
- package/cjs/utils/constants/index.js +2 -3
- package/cjs/utils/inputValidation/eventProperties.js +12 -1
- package/cjs/utils/inputValidation/index.js +3 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/evaluator/combiners/and.js +6 -2
- package/esm/evaluator/combiners/ifelseif.js +7 -7
- package/esm/evaluator/condition/index.js +5 -6
- package/esm/evaluator/index.js +7 -7
- package/esm/evaluator/matchers/index.js +1 -3
- package/esm/evaluator/matchers/matcherTypes.js +0 -1
- package/esm/evaluator/matchersTransform/index.js +0 -4
- package/esm/evaluator/parser/index.js +2 -2
- package/esm/evaluator/value/sanitize.js +0 -1
- package/esm/logger/constants.js +0 -1
- package/esm/logger/messages/debug.js +2 -3
- package/esm/logger/messages/error.js +1 -1
- package/esm/logger/messages/warn.js +2 -2
- package/esm/readiness/readinessManager.js +6 -0
- package/esm/sdkClient/client.js +29 -19
- package/esm/sdkClient/clientAttributesDecoration.js +19 -25
- package/esm/sdkClient/clientInputValidation.js +29 -27
- package/esm/services/splitApi.js +2 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
- package/esm/storages/AbstractSplitsCacheSync.js +2 -12
- package/esm/storages/KeyBuilder.js +0 -9
- package/esm/storages/KeyBuilderCS.js +4 -4
- package/esm/storages/KeyBuilderSS.js +0 -3
- package/esm/storages/dataLoader.js +2 -1
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +23 -76
- package/esm/storages/inLocalStorage/index.js +5 -7
- package/esm/storages/inLocalStorage/validateCache.js +75 -0
- package/esm/storages/inMemory/InMemoryStorage.js +0 -3
- package/esm/storages/inMemory/InMemoryStorageCS.js +0 -4
- package/esm/storages/inRedis/index.js +0 -2
- package/esm/storages/pluggable/index.js +2 -3
- package/esm/storages/utils.js +1 -0
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/esm/sync/polling/pollingManagerCS.js +7 -7
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +34 -61
- package/esm/sync/streaming/SSEHandler/index.js +1 -2
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +73 -102
- package/esm/sync/streaming/constants.js +0 -1
- package/esm/sync/streaming/pushManager.js +19 -6
- package/esm/sync/submitters/impressionsSubmitter.js +3 -2
- package/esm/sync/syncManagerOnline.js +10 -5
- package/esm/trackers/strategy/strategyDebug.js +2 -0
- package/esm/trackers/strategy/strategyOptimized.js +3 -0
- package/esm/utils/constants/index.js +1 -2
- package/esm/utils/inputValidation/eventProperties.js +10 -0
- package/esm/utils/inputValidation/index.js +1 -0
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +8 -32
- package/src/evaluator/Engine.ts +1 -1
- package/src/evaluator/combiners/and.ts +4 -5
- package/src/evaluator/combiners/ifelseif.ts +9 -7
- package/src/evaluator/condition/engineUtils.ts +1 -1
- package/src/evaluator/condition/index.ts +12 -12
- package/src/evaluator/index.ts +7 -7
- package/src/evaluator/matchers/index.ts +1 -3
- package/src/evaluator/matchers/matcherTypes.ts +0 -1
- package/src/evaluator/matchersTransform/index.ts +0 -3
- package/src/evaluator/parser/index.ts +3 -3
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +4 -5
- package/src/logger/constants.ts +0 -1
- package/src/logger/messages/debug.ts +2 -3
- package/src/logger/messages/error.ts +1 -1
- package/src/logger/messages/warn.ts +2 -2
- package/src/readiness/readinessManager.ts +5 -0
- package/src/sdkClient/client.ts +31 -21
- package/src/sdkClient/clientAttributesDecoration.ts +20 -27
- package/src/sdkClient/clientInputValidation.ts +30 -27
- package/src/sdkManager/index.ts +1 -1
- package/src/services/splitApi.ts +2 -2
- package/src/services/types.ts +1 -1
- package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
- package/src/storages/AbstractSplitsCacheSync.ts +3 -14
- package/src/storages/KeyBuilder.ts +0 -12
- package/src/storages/KeyBuilderCS.ts +5 -5
- package/src/storages/KeyBuilderSS.ts +0 -4
- package/src/storages/dataLoader.ts +3 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +26 -87
- package/src/storages/inLocalStorage/index.ts +8 -12
- package/src/storages/inLocalStorage/validateCache.ts +91 -0
- package/src/storages/inMemory/InMemoryStorage.ts +0 -3
- package/src/storages/inMemory/InMemoryStorageCS.ts +0 -4
- package/src/storages/inRedis/index.ts +0 -2
- package/src/storages/pluggable/index.ts +2 -3
- package/src/storages/types.ts +2 -37
- package/src/storages/utils.ts +1 -0
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +1 -2
- package/src/sync/polling/fetchers/types.ts +0 -1
- package/src/sync/polling/pollingManagerCS.ts +7 -7
- package/src/sync/polling/types.ts +2 -2
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +43 -71
- package/src/sync/streaming/SSEHandler/index.ts +1 -2
- package/src/sync/streaming/SSEHandler/types.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +68 -98
- package/src/sync/streaming/constants.ts +0 -1
- package/src/sync/streaming/parseUtils.ts +2 -2
- package/src/sync/streaming/pushManager.ts +18 -6
- package/src/sync/streaming/types.ts +2 -3
- package/src/sync/submitters/impressionsSubmitter.ts +3 -2
- package/src/sync/submitters/types.ts +23 -33
- package/src/sync/syncManagerOnline.ts +11 -5
- package/src/trackers/strategy/strategyDebug.ts +2 -0
- package/src/trackers/strategy/strategyOptimized.ts +3 -0
- package/src/utils/constants/index.ts +1 -2
- package/src/utils/inputValidation/eventProperties.ts +10 -0
- package/src/utils/inputValidation/index.ts +1 -0
- package/src/utils/lang/index.ts +2 -2
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/splitio.d.ts +128 -36
- package/cjs/evaluator/matchers/rbsegment.js +0 -43
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +0 -117
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +0 -61
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +0 -64
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +0 -64
- package/cjs/utils/constants/browser.js +0 -5
- package/esm/evaluator/matchers/rbsegment.js +0 -39
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +0 -114
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +0 -58
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +0 -61
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +0 -61
- package/esm/utils/constants/browser.js +0 -2
- package/src/evaluator/matchers/rbsegment.ts +0 -61
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +0 -136
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +0 -68
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +0 -79
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +0 -76
- package/src/utils/constants/browser.ts +0 -2
|
@@ -20,50 +20,44 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
|
|
|
20
20
|
const clientGetTreatmentsWithConfigByFlagSets = client.getTreatmentsWithConfigByFlagSets;
|
|
21
21
|
const clientGetTreatmentsByFlagSet = client.getTreatmentsByFlagSet;
|
|
22
22
|
const clientGetTreatmentsWithConfigByFlagSet = client.getTreatmentsWithConfigByFlagSet;
|
|
23
|
-
const clientTrack = client.track;
|
|
24
23
|
|
|
25
|
-
function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
|
|
26
|
-
return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
|
|
24
|
+
function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
25
|
+
return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes), maybeOptions);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
|
|
30
|
-
return clientGetTreatmentWithConfig(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
|
|
28
|
+
function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
29
|
+
return clientGetTreatmentWithConfig(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes), maybeOptions);
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
34
|
-
return clientGetTreatments(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
|
|
32
|
+
function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
33
|
+
return clientGetTreatments(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes), maybeOptions);
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
38
|
-
return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
|
|
36
|
+
function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
37
|
+
return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes), maybeOptions);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
42
|
-
return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
|
|
40
|
+
function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
41
|
+
return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes), maybeOptions);
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
46
|
-
return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
|
|
44
|
+
function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
45
|
+
return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes), maybeOptions);
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
|
|
50
|
-
return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
|
|
48
|
+
function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
49
|
+
return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes), maybeOptions);
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
|
|
54
|
-
return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
|
|
52
|
+
function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
53
|
+
return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes), maybeOptions);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
function
|
|
58
|
-
return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function combineAttributes(maybeAttributes: SplitIO.Attributes | undefined): SplitIO.Attributes | undefined{
|
|
56
|
+
function combineAttributes(maybeAttributes: SplitIO.Attributes | undefined): SplitIO.Attributes | undefined {
|
|
62
57
|
const storedAttributes = attributeStorage.getAll();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return maybeAttributes;
|
|
58
|
+
return Object.keys(storedAttributes).length > 0 ?
|
|
59
|
+
objectAssign({}, storedAttributes, maybeAttributes) :
|
|
60
|
+
maybeAttributes;
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
return objectAssign(client, {
|
|
@@ -75,7 +69,6 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
|
|
|
75
69
|
getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
|
|
76
70
|
getTreatmentsByFlagSet: getTreatmentsByFlagSet,
|
|
77
71
|
getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
|
|
78
|
-
track: track,
|
|
79
72
|
|
|
80
73
|
/**
|
|
81
74
|
* Add an attribute to client's in memory attributes storage
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
validateSplits,
|
|
10
10
|
validateTrafficType,
|
|
11
11
|
validateIfNotDestroyed,
|
|
12
|
-
validateIfOperational
|
|
12
|
+
validateIfOperational,
|
|
13
|
+
validateEvaluationOptions
|
|
13
14
|
} from '../utils/inputValidation';
|
|
14
15
|
import { startsWith } from '../utils/lang';
|
|
15
16
|
import { CONTROL, CONTROL_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENT_WITH_CONFIG, TRACK_FN_LABEL } from '../utils/constants';
|
|
@@ -32,7 +33,7 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
32
33
|
/**
|
|
33
34
|
* Avoid repeating this validations code
|
|
34
35
|
*/
|
|
35
|
-
function validateEvaluationParams(maybeKey: SplitIO.SplitKey, maybeNameOrNames: string | string[], maybeAttributes
|
|
36
|
+
function validateEvaluationParams(methodName: string, maybeKey: SplitIO.SplitKey, maybeNameOrNames: string | string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
36
37
|
const key = validateKey(log, maybeKey, methodName);
|
|
37
38
|
|
|
38
39
|
const nameOrNames = methodName.indexOf('ByFlagSet') > -1 ?
|
|
@@ -43,6 +44,7 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
43
44
|
|
|
44
45
|
const attributes = validateAttributes(log, maybeAttributes, methodName);
|
|
45
46
|
const isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
|
|
47
|
+
const options = validateEvaluationOptions(log, maybeOptions, methodName);
|
|
46
48
|
|
|
47
49
|
validateIfOperational(log, readinessManager, methodName, nameOrNames);
|
|
48
50
|
|
|
@@ -52,7 +54,8 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
52
54
|
valid,
|
|
53
55
|
key,
|
|
54
56
|
nameOrNames,
|
|
55
|
-
attributes
|
|
57
|
+
attributes,
|
|
58
|
+
options
|
|
56
59
|
};
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -60,31 +63,31 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
60
63
|
return isAsync ? Promise.resolve(value) : value;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
|
|
64
|
-
const params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes,
|
|
66
|
+
function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
67
|
+
const params = validateEvaluationParams(GET_TREATMENT, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
|
|
65
68
|
|
|
66
69
|
if (params.valid) {
|
|
67
|
-
return client.getTreatment(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined);
|
|
70
|
+
return client.getTreatment(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
68
71
|
} else {
|
|
69
72
|
return wrapResult(CONTROL);
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
|
|
74
|
-
const params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes,
|
|
76
|
+
function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
77
|
+
const params = validateEvaluationParams(GET_TREATMENT_WITH_CONFIG, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
|
|
75
78
|
|
|
76
79
|
if (params.valid) {
|
|
77
|
-
return client.getTreatmentWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined);
|
|
80
|
+
return client.getTreatmentWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
78
81
|
} else {
|
|
79
82
|
return wrapResult(objectAssign({}, CONTROL_WITH_CONFIG));
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
84
|
-
const params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes,
|
|
86
|
+
function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
87
|
+
const params = validateEvaluationParams(GET_TREATMENTS, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
|
|
85
88
|
|
|
86
89
|
if (params.valid) {
|
|
87
|
-
return client.getTreatments(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
|
|
90
|
+
return client.getTreatments(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
88
91
|
} else {
|
|
89
92
|
const res: SplitIO.Treatments = {};
|
|
90
93
|
if (params.nameOrNames) (params.nameOrNames as string[]).forEach((split: string) => res[split] = CONTROL);
|
|
@@ -93,11 +96,11 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
97
|
-
const params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes,
|
|
99
|
+
function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
100
|
+
const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
|
|
98
101
|
|
|
99
102
|
if (params.valid) {
|
|
100
|
-
return client.getTreatmentsWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
|
|
103
|
+
return client.getTreatmentsWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
101
104
|
} else {
|
|
102
105
|
const res: SplitIO.TreatmentsWithConfig = {};
|
|
103
106
|
if (params.nameOrNames) (params.nameOrNames as string[]).forEach(split => res[split] = objectAssign({}, CONTROL_WITH_CONFIG));
|
|
@@ -106,41 +109,41 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
|
|
109
|
-
function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
110
|
-
const params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes,
|
|
112
|
+
function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
113
|
+
const params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
|
|
111
114
|
|
|
112
115
|
if (params.valid) {
|
|
113
|
-
return client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
|
|
116
|
+
return client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
114
117
|
} else {
|
|
115
118
|
return wrapResult({});
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
|
|
119
|
-
function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
|
|
120
|
-
const params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes,
|
|
122
|
+
function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
123
|
+
const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
|
|
121
124
|
|
|
122
125
|
if (params.valid) {
|
|
123
|
-
return client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined);
|
|
126
|
+
return client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
124
127
|
} else {
|
|
125
128
|
return wrapResult({});
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
|
|
130
|
-
const params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes,
|
|
132
|
+
function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
133
|
+
const params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
|
|
131
134
|
|
|
132
135
|
if (params.valid) {
|
|
133
|
-
return client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined);
|
|
136
|
+
return client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
134
137
|
} else {
|
|
135
138
|
return wrapResult({});
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
|
|
139
|
-
function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
|
|
140
|
-
const params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes,
|
|
142
|
+
function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
|
|
143
|
+
const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
|
|
141
144
|
|
|
142
145
|
if (params.valid) {
|
|
143
|
-
return client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined);
|
|
146
|
+
return client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options);
|
|
144
147
|
} else {
|
|
145
148
|
return wrapResult({});
|
|
146
149
|
}
|
package/src/sdkManager/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ function collectTreatments(splitObject: ISplit) {
|
|
|
17
17
|
// Localstorage mode could fall into a no rollout conditions state. Take the first condition in that case.
|
|
18
18
|
if (!allTreatmentsCondition) allTreatmentsCondition = conditions[0];
|
|
19
19
|
// Then extract the treatments from the partitions
|
|
20
|
-
return allTreatmentsCondition ? allTreatmentsCondition.partitions
|
|
20
|
+
return allTreatmentsCondition ? allTreatmentsCondition.partitions.map(v => v.treatment) : [];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function objectToView(splitObject: ISplit | null): SplitIO.SplitView | null {
|
package/src/services/splitApi.ts
CHANGED
|
@@ -53,8 +53,8 @@ export function splitApiFactory(
|
|
|
53
53
|
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN));
|
|
54
54
|
},
|
|
55
55
|
|
|
56
|
-
fetchSplitChanges(since: number, noCache?: boolean, till?: number
|
|
57
|
-
const url = `${urls.sdk}/splitChanges?s=${flagSpecVersion}&since=${since}${
|
|
56
|
+
fetchSplitChanges(since: number, noCache?: boolean, till?: number) {
|
|
57
|
+
const url = `${urls.sdk}/splitChanges?s=${flagSpecVersion}&since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
|
|
58
58
|
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
|
|
59
59
|
.catch((err) => {
|
|
60
60
|
if (err.statusCode === 414) settings.log.error(ERROR_TOO_MANY_SETS);
|
package/src/services/types.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type ISplitHttpClient = (url: string, options?: IRequestOptions, latencyT
|
|
|
35
35
|
|
|
36
36
|
export type IFetchAuth = (userKeys?: string[]) => Promise<IResponse>
|
|
37
37
|
|
|
38
|
-
export type IFetchSplitChanges = (since: number, noCache?: boolean, till?: number
|
|
38
|
+
export type IFetchSplitChanges = (since: number, noCache?: boolean, till?: number) => Promise<IResponse>
|
|
39
39
|
|
|
40
40
|
export type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean, till?: number) => Promise<IResponse>
|
|
41
41
|
|
|
@@ -37,14 +37,6 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
|
|
|
37
37
|
return Promise.resolve(true);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
* Check if the splits information is already stored in cache.
|
|
42
|
-
* Noop, just keeping the interface. This is used by client-side implementations only.
|
|
43
|
-
*/
|
|
44
|
-
checkCache(): Promise<boolean> {
|
|
45
|
-
return Promise.resolve(false);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
40
|
/**
|
|
49
41
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
50
42
|
* Used for SPLIT_KILL push notifications.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ISplitsCacheSync } from './types';
|
|
2
|
-
import {
|
|
2
|
+
import { ISplit } from '../dtos/types';
|
|
3
3
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
4
4
|
import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
|
|
5
5
|
|
|
@@ -43,14 +43,6 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
43
43
|
|
|
44
44
|
abstract clear(): void
|
|
45
45
|
|
|
46
|
-
/**
|
|
47
|
-
* Check if the splits information is already stored in cache. This data can be preloaded.
|
|
48
|
-
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
|
|
49
|
-
*/
|
|
50
|
-
checkCache(): boolean {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
46
|
/**
|
|
55
47
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
56
48
|
* Used for SPLIT_KILL push notifications.
|
|
@@ -80,8 +72,8 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
80
72
|
* Given a parsed split, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
|
|
81
73
|
* This util is intended to simplify the implementation of `splitsCache::usesSegments` method
|
|
82
74
|
*/
|
|
83
|
-
export function usesSegments(
|
|
84
|
-
const conditions =
|
|
75
|
+
export function usesSegments(split: ISplit) {
|
|
76
|
+
const conditions = split.conditions || [];
|
|
85
77
|
for (let i = 0; i < conditions.length; i++) {
|
|
86
78
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
87
79
|
|
|
@@ -91,8 +83,5 @@ export function usesSegments(ruleEntity: ISplit | IRBSegment) {
|
|
|
91
83
|
}
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
const excluded = (ruleEntity as IRBSegment).excluded;
|
|
95
|
-
if (excluded && excluded.segments && excluded.segments.length > 0) return true;
|
|
96
|
-
|
|
97
86
|
return false;
|
|
98
87
|
}
|
|
@@ -37,18 +37,6 @@ export class KeyBuilder {
|
|
|
37
37
|
return `${this.prefix}.split.`;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
buildRBSegmentKey(rbsegmentName: string) {
|
|
41
|
-
return `${this.prefix}.rbsegment.${rbsegmentName}`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
buildRBSegmentsTillKey() {
|
|
45
|
-
return `${this.prefix}.rbsegments.till`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
buildRBSegmentKeyPrefix() {
|
|
49
|
-
return `${this.prefix}.rbsegment.`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
40
|
buildSegmentNameKey(segmentName: string) {
|
|
53
41
|
return `${this.prefix}.segment.${segmentName}`;
|
|
54
42
|
}
|
|
@@ -15,7 +15,7 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
15
15
|
constructor(prefix: string, matchingKey: string) {
|
|
16
16
|
super(prefix);
|
|
17
17
|
this.matchingKey = matchingKey;
|
|
18
|
-
this.regexSplitsCacheKey = new RegExp(`^${prefix}\\.(splits?|trafficType|flagSet
|
|
18
|
+
this.regexSplitsCacheKey = new RegExp(`^${prefix}\\.(splits?|trafficType|flagSet)\\.`);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -47,13 +47,13 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
47
47
|
return startsWith(key, `${this.prefix}.split.`);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
isRBSegmentKey(key: string) {
|
|
51
|
-
return startsWith(key, `${this.prefix}.rbsegment.`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
50
|
buildSplitsWithSegmentCountKey() {
|
|
55
51
|
return `${this.prefix}.splits.usingSegments`;
|
|
56
52
|
}
|
|
53
|
+
|
|
54
|
+
buildLastClear() {
|
|
55
|
+
return `${this.prefix}.lastClear`;
|
|
56
|
+
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string): MySegmentsKeyBuilder {
|
|
@@ -53,10 +53,6 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
53
53
|
return `${this.buildSplitKeyPrefix()}*`;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
searchPatternForRBSegmentKeys() {
|
|
57
|
-
return `${this.buildRBSegmentKeyPrefix()}*`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
56
|
/* Telemetry keys */
|
|
61
57
|
|
|
62
58
|
buildLatencyKey(method: Method, bucket: number) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { PreloadedData } from '../types';
|
|
2
|
-
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
3
2
|
import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
|
|
4
3
|
|
|
4
|
+
// This value might be eventually set via a config parameter
|
|
5
|
+
const DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Factory of client-side storage loader
|
|
7
9
|
*
|
|
@@ -5,7 +5,6 @@ import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
|
5
5
|
import { ILogger } from '../../logger/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
7
|
import { ISettings } from '../../types';
|
|
8
|
-
import { getStorageHash } from '../KeyBuilder';
|
|
9
8
|
import { setToArray } from '../../utils/lang/sets';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -15,21 +14,14 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
15
14
|
|
|
16
15
|
private readonly keys: KeyBuilderCS;
|
|
17
16
|
private readonly log: ILogger;
|
|
18
|
-
private readonly storageHash: string;
|
|
19
17
|
private readonly flagSetsFilter: string[];
|
|
20
18
|
private hasSync?: boolean;
|
|
21
|
-
private updateNewFilter?: boolean;
|
|
22
19
|
|
|
23
|
-
constructor(settings: ISettings, keys: KeyBuilderCS
|
|
20
|
+
constructor(settings: ISettings, keys: KeyBuilderCS) {
|
|
24
21
|
super();
|
|
25
22
|
this.keys = keys;
|
|
26
23
|
this.log = settings.log;
|
|
27
|
-
this.storageHash = getStorageHash(settings);
|
|
28
24
|
this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
|
|
29
|
-
|
|
30
|
-
this._checkExpiration(expirationTimestamp);
|
|
31
|
-
|
|
32
|
-
this._checkFilterQuery();
|
|
33
25
|
}
|
|
34
26
|
|
|
35
27
|
private _decrementCount(key: string) {
|
|
@@ -39,16 +31,14 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
39
31
|
else localStorage.removeItem(key);
|
|
40
32
|
}
|
|
41
33
|
|
|
42
|
-
private _decrementCounts(split: ISplit
|
|
34
|
+
private _decrementCounts(split: ISplit) {
|
|
43
35
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
this._decrementCount(ttKey);
|
|
36
|
+
const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
|
|
37
|
+
this._decrementCount(ttKey);
|
|
47
38
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
39
|
+
if (usesSegments(split)) {
|
|
40
|
+
const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
41
|
+
this._decrementCount(segmentsCountKey);
|
|
52
42
|
}
|
|
53
43
|
} catch (e) {
|
|
54
44
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -57,14 +47,16 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
57
47
|
|
|
58
48
|
private _incrementCounts(split: ISplit) {
|
|
59
49
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
|
|
63
|
-
|
|
64
|
-
if (usesSegments(split)) {
|
|
65
|
-
const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
50
|
+
if (split) {
|
|
51
|
+
const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
|
|
66
52
|
// @ts-expect-error
|
|
67
|
-
localStorage.setItem(
|
|
53
|
+
localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
|
|
54
|
+
|
|
55
|
+
if (usesSegments(split)) {
|
|
56
|
+
const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
57
|
+
// @ts-expect-error
|
|
58
|
+
localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
|
|
59
|
+
}
|
|
68
60
|
}
|
|
69
61
|
} catch (e) {
|
|
70
62
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -77,8 +69,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
77
69
|
* We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
|
|
78
70
|
*/
|
|
79
71
|
clear() {
|
|
80
|
-
this.log.info(LOG_PREFIX + 'Flushing Splits data from localStorage');
|
|
81
|
-
|
|
82
72
|
// collect item keys
|
|
83
73
|
const len = localStorage.length;
|
|
84
74
|
const accum = [];
|
|
@@ -101,12 +91,14 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
101
91
|
const splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
102
92
|
const previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
103
93
|
|
|
94
|
+
if (previousSplit) {
|
|
95
|
+
this._decrementCounts(previousSplit);
|
|
96
|
+
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
97
|
+
}
|
|
98
|
+
|
|
104
99
|
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
105
100
|
|
|
106
101
|
this._incrementCounts(split);
|
|
107
|
-
this._decrementCounts(previousSplit);
|
|
108
|
-
|
|
109
|
-
if (previousSplit) this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
110
102
|
this.addToFlagSets(split);
|
|
111
103
|
|
|
112
104
|
return true;
|
|
@@ -124,7 +116,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
124
116
|
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
125
117
|
|
|
126
118
|
this._decrementCounts(split);
|
|
127
|
-
|
|
119
|
+
this.removeFromFlagSets(split.name, split.sets);
|
|
128
120
|
|
|
129
121
|
return true;
|
|
130
122
|
} catch (e) {
|
|
@@ -139,19 +131,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
139
131
|
}
|
|
140
132
|
|
|
141
133
|
setChangeNumber(changeNumber: number): boolean {
|
|
142
|
-
|
|
143
|
-
// when using a new split query, we must update it at the store
|
|
144
|
-
if (this.updateNewFilter) {
|
|
145
|
-
this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
146
|
-
const storageHashKey = this.keys.buildHashKey();
|
|
147
|
-
try {
|
|
148
|
-
localStorage.setItem(storageHashKey, this.storageHash);
|
|
149
|
-
} catch (e) {
|
|
150
|
-
this.log.error(LOG_PREFIX + e);
|
|
151
|
-
}
|
|
152
|
-
this.updateNewFilter = false;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
134
|
try {
|
|
156
135
|
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
|
|
157
136
|
// update "last updated" timestamp with current time
|
|
@@ -206,51 +185,11 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
206
185
|
const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
|
|
207
186
|
const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
|
|
208
187
|
|
|
209
|
-
|
|
210
|
-
splitsWithSegmentsCount > 0
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Check if the splits information is already stored in browser LocalStorage.
|
|
216
|
-
* In this function we could add more code to check if the data is valid.
|
|
217
|
-
* @override
|
|
218
|
-
*/
|
|
219
|
-
checkCache(): boolean {
|
|
220
|
-
return this.getChangeNumber() > -1;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
225
|
-
*
|
|
226
|
-
* @param expirationTimestamp - if the value is not a number, data will not be cleaned
|
|
227
|
-
*/
|
|
228
|
-
private _checkExpiration(expirationTimestamp?: number) {
|
|
229
|
-
let value: string | number | null = localStorage.getItem(this.keys.buildLastUpdatedKey());
|
|
230
|
-
if (value !== null) {
|
|
231
|
-
value = parseInt(value, 10);
|
|
232
|
-
if (!isNaNNumber(value) && expirationTimestamp && value < expirationTimestamp) this.clear();
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// @TODO eventually remove `_checkFilterQuery`. Cache should be cleared at the storage level, reusing same logic than PluggableStorage
|
|
237
|
-
private _checkFilterQuery() {
|
|
238
|
-
const storageHashKey = this.keys.buildHashKey();
|
|
239
|
-
const storageHash = localStorage.getItem(storageHashKey);
|
|
240
|
-
|
|
241
|
-
if (storageHash !== this.storageHash) {
|
|
242
|
-
try {
|
|
243
|
-
// mark cache to update the new query filter on first successful splits fetch
|
|
244
|
-
this.updateNewFilter = true;
|
|
245
|
-
|
|
246
|
-
// if there is cache, clear it
|
|
247
|
-
if (this.checkCache()) this.clear();
|
|
248
|
-
|
|
249
|
-
} catch (e) {
|
|
250
|
-
this.log.error(LOG_PREFIX + e);
|
|
251
|
-
}
|
|
188
|
+
if (isFiniteNumber(splitsWithSegmentsCount)) {
|
|
189
|
+
return splitsWithSegmentsCount > 0;
|
|
190
|
+
} else {
|
|
191
|
+
return true;
|
|
252
192
|
}
|
|
253
|
-
// if the filter didn't change, nothing is done
|
|
254
193
|
}
|
|
255
194
|
|
|
256
195
|
getNamesByFlagSets(flagSets: string[]): Set<string>[] {
|
|
@@ -7,23 +7,19 @@ import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
|
|
|
7
7
|
import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
|
|
8
8
|
import { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
9
9
|
import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
10
|
-
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
|
|
11
10
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
12
11
|
import { LOG_PREFIX } from './constants';
|
|
13
12
|
import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
14
13
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
15
14
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
16
15
|
import { getMatching } from '../../utils/key';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
export interface InLocalStorageOptions {
|
|
20
|
-
prefix?: string
|
|
21
|
-
}
|
|
16
|
+
import { validateCache } from './validateCache';
|
|
17
|
+
import SplitIO from '../../../types/splitio';
|
|
22
18
|
|
|
23
19
|
/**
|
|
24
20
|
* InLocal storage factory for standalone client-side SplitFactory
|
|
25
21
|
*/
|
|
26
|
-
export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyncFactory {
|
|
22
|
+
export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): IStorageSyncFactory {
|
|
27
23
|
|
|
28
24
|
const prefix = validatePrefix(options.prefix);
|
|
29
25
|
|
|
@@ -38,16 +34,13 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
38
34
|
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
39
35
|
const matchingKey = getMatching(settings.core.key);
|
|
40
36
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
41
|
-
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
42
37
|
|
|
43
|
-
const splits = new SplitsCacheInLocal(settings, keys
|
|
44
|
-
const rbSegments = new RBSegmentsCacheInLocal(settings, keys);
|
|
38
|
+
const splits = new SplitsCacheInLocal(settings, keys);
|
|
45
39
|
const segments = new MySegmentsCacheInLocal(log, keys);
|
|
46
40
|
const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
|
|
47
41
|
|
|
48
42
|
return {
|
|
49
43
|
splits,
|
|
50
|
-
rbSegments,
|
|
51
44
|
segments,
|
|
52
45
|
largeSegments,
|
|
53
46
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
@@ -56,6 +49,10 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
56
49
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
57
50
|
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
58
51
|
|
|
52
|
+
validateCache() {
|
|
53
|
+
return validateCache(options, settings, keys, splits, segments, largeSegments);
|
|
54
|
+
},
|
|
55
|
+
|
|
59
56
|
destroy() { },
|
|
60
57
|
|
|
61
58
|
// When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
|
|
@@ -63,7 +60,6 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
63
60
|
|
|
64
61
|
return {
|
|
65
62
|
splits: this.splits,
|
|
66
|
-
rbSegments: this.rbSegments,
|
|
67
63
|
segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey)),
|
|
68
64
|
largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey)),
|
|
69
65
|
impressions: this.impressions,
|