@splitsoftware/splitio-commons 2.11.1-rc.2 → 3.0.0-rc.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 +15 -2
- package/cjs/evaluator/condition/engineUtils.js +2 -2
- package/cjs/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +70 -0
- package/cjs/evaluator/fallbackConfigsCalculator/index.js +25 -0
- package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
- package/cjs/evaluator/fallbackTreatmentsCalculator/index.js +21 -32
- package/cjs/evaluator/index.js +67 -42
- package/cjs/evaluator/matchers/whitelist.js +1 -1
- package/cjs/integrations/pluggable.js +1 -1
- package/cjs/listeners/browser.js +4 -3
- package/cjs/listeners/node.js +4 -4
- package/cjs/logger/constants.js +14 -20
- package/cjs/logger/index.js +1 -1
- package/cjs/logger/messages/debug.js +6 -7
- package/cjs/logger/messages/error.js +4 -4
- package/cjs/logger/messages/info.js +2 -4
- package/cjs/logger/messages/warn.js +9 -9
- package/cjs/platform/browser.js +15 -0
- package/cjs/platform/getEventSource/browser.js +8 -0
- package/cjs/platform/getEventSource/eventsource.js +480 -0
- package/cjs/platform/getEventSource/node.js +26 -0
- package/cjs/platform/getFetch/browser.js +9 -0
- package/cjs/platform/getFetch/node.js +27 -0
- package/cjs/platform/getOptions/node.js +25 -0
- package/cjs/platform/node.js +17 -0
- package/cjs/readiness/constants.js +2 -1
- package/cjs/sdkClient/client.js +9 -35
- package/cjs/sdkClient/clientAttributesDecoration.js +3 -3
- package/cjs/sdkClient/clientInputValidation.js +38 -81
- package/cjs/sdkClient/identity.js +1 -1
- package/cjs/sdkClient/sdkClient.js +4 -49
- package/cjs/sdkClient/sdkLifecycle.js +70 -0
- package/cjs/sdkClient/trackMethod.js +56 -0
- package/cjs/sdkFactory/index.js +8 -45
- package/cjs/sdkManager/index.js +3 -3
- package/cjs/services/splitApi.js +18 -13
- package/cjs/services/splitHttpClient.js +1 -1
- package/cjs/storages/AbstractSplitsCacheAsync.js +1 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
- package/cjs/storages/KeyBuilder.js +12 -12
- package/cjs/storages/KeyBuilderCS.js +13 -13
- package/cjs/storages/KeyBuilderSS.js +15 -15
- package/cjs/storages/getRolloutPlan.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -1
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +1 -1
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -1
- package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +2 -2
- package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +5 -5
- package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/RedisAdapter.js +8 -8
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -6
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +7 -7
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +3 -3
- package/cjs/storages/pluggable/EventsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +6 -6
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/SplitsCachePluggable.js +4 -4
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +7 -7
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -2
- package/cjs/storages/pluggable/index.js +3 -3
- package/cjs/storages/pluggable/wrapperAdapter.js +1 -1
- package/cjs/storages/setRolloutPlan.js +1 -1
- package/cjs/storages/utils.js +6 -6
- package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +23 -14
- package/cjs/sync/polling/pollingManagerCS.js +11 -11
- package/cjs/sync/polling/pollingManagerSS.js +13 -13
- package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +12 -0
- package/cjs/sync/polling/updaters/{splitChangesUpdater.js → definitionChangesUpdater.js} +67 -59
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +1 -1
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
- package/cjs/sync/streaming/SSEClient/index.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +4 -4
- package/cjs/sync/streaming/parseUtils.js +12 -12
- package/cjs/sync/streaming/pushManager.js +2 -2
- package/cjs/sync/submitters/impressionsSubmitter.js +6 -6
- package/cjs/sync/submitters/submitter.js +1 -1
- package/cjs/sync/syncManagerOnline.js +5 -2
- package/cjs/trackers/eventTracker.js +10 -12
- package/cjs/trackers/impressionObserver/buildKey.js +1 -1
- package/cjs/trackers/impressionsTracker.js +37 -20
- package/cjs/trackers/uniqueKeysTracker.js +1 -1
- package/cjs/utils/EventEmitter.js +391 -0
- package/cjs/utils/filter/bloomFilter.js +37 -0
- package/cjs/utils/inputValidation/apiKey.js +1 -1
- package/cjs/utils/inputValidation/attribute.js +2 -2
- package/cjs/utils/inputValidation/{split.js → definition.js} +10 -10
- package/cjs/utils/inputValidation/{splitExistence.js → definitionExistence.js} +6 -6
- package/cjs/utils/inputValidation/definitions.js +25 -0
- package/cjs/utils/inputValidation/eventProperties.js +1 -1
- package/cjs/utils/inputValidation/index.js +7 -7
- package/cjs/utils/inputValidation/isOperational.js +4 -4
- package/cjs/utils/inputValidation/target.js +22 -0
- package/cjs/utils/labels/index.js +3 -3
- package/cjs/utils/lang/index.js +1 -1
- package/cjs/utils/promise/timeout.js +1 -1
- package/cjs/utils/settingsValidation/splitFilters.js +4 -4
- package/cjs/utils/settingsValidation/url.js +5 -5
- package/esm/evaluator/condition/engineUtils.js +2 -2
- package/esm/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +64 -0
- package/esm/evaluator/fallbackConfigsCalculator/index.js +21 -0
- package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
- package/esm/evaluator/fallbackTreatmentsCalculator/index.js +21 -33
- package/esm/evaluator/index.js +66 -42
- package/esm/evaluator/matchers/whitelist.js +1 -1
- package/esm/integrations/pluggable.js +1 -1
- package/esm/listeners/browser.js +4 -3
- package/esm/listeners/node.js +4 -4
- package/esm/logger/constants.js +11 -17
- package/esm/logger/index.js +1 -1
- package/esm/logger/messages/debug.js +5 -6
- package/esm/logger/messages/error.js +3 -3
- package/esm/logger/messages/info.js +1 -3
- package/esm/logger/messages/warn.js +8 -8
- package/esm/platform/browser.js +12 -0
- package/esm/platform/getEventSource/browser.js +4 -0
- package/esm/platform/getEventSource/eventsource.js +480 -0
- package/esm/platform/getEventSource/node.js +20 -0
- package/esm/platform/getFetch/browser.js +5 -0
- package/esm/platform/getFetch/node.js +22 -0
- package/esm/platform/getOptions/node.js +20 -0
- package/esm/platform/node.js +14 -0
- package/esm/readiness/constants.js +1 -0
- package/esm/sdkClient/client.js +10 -37
- package/esm/sdkClient/clientAttributesDecoration.js +3 -3
- package/esm/sdkClient/clientInputValidation.js +40 -83
- package/esm/sdkClient/identity.js +1 -1
- package/esm/sdkClient/sdkClient.js +4 -49
- package/esm/sdkClient/sdkLifecycle.js +66 -0
- package/esm/sdkClient/trackMethod.js +52 -0
- package/esm/sdkFactory/index.js +8 -45
- package/esm/sdkManager/index.js +4 -4
- package/esm/services/splitApi.js +18 -13
- package/esm/services/splitHttpClient.js +1 -1
- package/esm/storages/AbstractSplitsCacheAsync.js +1 -1
- package/esm/storages/AbstractSplitsCacheSync.js +1 -1
- package/esm/storages/KeyBuilder.js +12 -12
- package/esm/storages/KeyBuilderCS.js +12 -12
- package/esm/storages/KeyBuilderSS.js +14 -14
- package/esm/storages/getRolloutPlan.js +1 -1
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +1 -1
- package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +1 -1
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +2 -2
- package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +4 -4
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/RedisAdapter.js +7 -7
- package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -4
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +7 -7
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -1
- package/esm/storages/pluggable/EventsCachePluggable.js +1 -1
- package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +5 -5
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -2
- package/esm/storages/pluggable/TelemetryCachePluggable.js +7 -7
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -1
- package/esm/storages/pluggable/index.js +2 -2
- package/esm/storages/pluggable/wrapperAdapter.js +1 -1
- package/esm/storages/setRolloutPlan.js +1 -1
- package/esm/storages/utils.js +6 -6
- package/esm/sync/offline/splitsParser/parseCondition.js +1 -1
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +24 -15
- package/esm/sync/polling/pollingManagerCS.js +11 -11
- package/esm/sync/polling/pollingManagerSS.js +13 -13
- package/esm/sync/polling/syncTasks/definitionsSyncTask.js +8 -0
- package/esm/sync/polling/updaters/{splitChangesUpdater.js → definitionChangesUpdater.js} +67 -59
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +7 -7
- package/esm/sync/streaming/SSEClient/index.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +4 -4
- package/esm/sync/streaming/parseUtils.js +10 -10
- package/esm/sync/streaming/pushManager.js +3 -3
- package/esm/sync/submitters/impressionsSubmitter.js +6 -6
- package/esm/sync/submitters/submitter.js +1 -1
- package/esm/sync/syncManagerOnline.js +5 -2
- package/esm/trackers/eventTracker.js +10 -12
- package/esm/trackers/impressionObserver/buildKey.js +1 -1
- package/esm/trackers/impressionsTracker.js +38 -21
- package/esm/trackers/uniqueKeysTracker.js +1 -1
- package/esm/utils/EventEmitter.js +387 -0
- package/esm/utils/filter/bloomFilter.js +33 -0
- package/esm/utils/inputValidation/apiKey.js +1 -1
- package/esm/utils/inputValidation/attribute.js +2 -2
- package/esm/utils/inputValidation/{split.js → definition.js} +8 -8
- package/esm/utils/inputValidation/definitionExistence.js +15 -0
- package/esm/utils/inputValidation/definitions.js +21 -0
- package/esm/utils/inputValidation/index.js +3 -3
- package/esm/utils/inputValidation/isOperational.js +4 -4
- package/esm/utils/inputValidation/target.js +18 -0
- package/esm/utils/labels/index.js +2 -2
- package/esm/utils/promise/timeout.js +1 -1
- package/esm/utils/settingsValidation/splitFilters.js +4 -4
- package/esm/utils/settingsValidation/url.js +5 -5
- package/package.json +15 -6
- package/src/dtos/types.ts +65 -70
- package/src/evaluator/Engine.ts +4 -4
- package/src/evaluator/combiners/and.ts +3 -3
- package/src/evaluator/combiners/ifelseif.ts +2 -2
- package/src/evaluator/condition/engineUtils.ts +2 -2
- package/src/evaluator/condition/index.ts +3 -3
- package/src/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.ts +76 -0
- package/src/evaluator/fallbackConfigsCalculator/index.ts +24 -0
- package/src/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.ts +5 -7
- package/src/evaluator/fallbackTreatmentsCalculator/index.ts +27 -41
- package/src/evaluator/index.ts +80 -45
- package/src/evaluator/matchers/dependency.ts +2 -2
- package/src/evaluator/matchers/matcherTypes.ts +2 -2
- package/src/evaluator/matchers/prerequisites.ts +4 -4
- package/src/evaluator/matchers/rbsegment.ts +2 -2
- package/src/evaluator/matchers/whitelist.ts +2 -2
- package/src/evaluator/matchersTransform/index.ts +2 -2
- package/src/evaluator/matchersTransform/whitelist.ts +2 -2
- package/src/evaluator/parser/index.ts +4 -4
- package/src/evaluator/treatments/index.ts +2 -2
- package/src/evaluator/types.ts +6 -6
- package/src/evaluator/value/index.ts +1 -1
- package/src/integrations/pluggable.ts +1 -1
- package/src/listeners/browser.ts +11 -8
- package/src/listeners/node.ts +2 -5
- package/src/logger/constants.ts +11 -17
- package/src/logger/messages/debug.ts +5 -6
- package/src/logger/messages/error.ts +3 -3
- package/src/logger/messages/info.ts +1 -3
- package/src/logger/messages/warn.ts +8 -8
- package/src/platform/browser.ts +14 -0
- package/src/platform/getEventSource/browser.ts +4 -0
- package/src/platform/getEventSource/eventsource.js +519 -0
- package/src/platform/getEventSource/node.ts +23 -0
- package/src/platform/getFetch/browser.ts +5 -0
- package/src/platform/getFetch/node.ts +27 -0
- package/src/platform/getOptions/node.ts +24 -0
- package/src/platform/node.ts +16 -0
- package/src/readiness/constants.ts +1 -0
- package/src/sdkClient/client.ts +11 -41
- package/src/sdkClient/clientInputValidation.ts +44 -84
- package/src/sdkClient/sdkClient.ts +5 -54
- package/src/sdkClient/sdkLifecycle.ts +78 -0
- package/src/sdkClient/trackMethod.ts +59 -0
- package/src/sdkFactory/index.ts +10 -54
- package/src/sdkFactory/types.ts +19 -16
- package/src/sdkManager/index.ts +9 -9
- package/src/services/splitApi.ts +6 -0
- package/src/services/types.ts +3 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +7 -7
- package/src/storages/AbstractSplitsCacheSync.ts +10 -10
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +2 -2
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +6 -6
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +2 -2
- package/src/storages/inMemory/SplitsCacheInMemory.ts +5 -5
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +2 -2
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +2 -2
- package/src/storages/inRedis/SplitsCacheInRedis.ts +9 -9
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +2 -2
- package/src/storages/pluggable/SplitsCachePluggable.ts +9 -9
- package/src/storages/types.ts +21 -16
- package/src/sync/offline/splitsParser/parseCondition.ts +2 -2
- package/src/sync/offline/splitsParser/splitsParserFromSettings.ts +3 -3
- package/src/sync/offline/splitsParser/types.ts +6 -3
- package/src/sync/offline/syncManagerOffline.ts +2 -2
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -6
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +57 -22
- package/src/sync/polling/fetchers/types.ts +5 -3
- package/src/sync/polling/pollingManagerCS.ts +12 -10
- package/src/sync/polling/pollingManagerSS.ts +15 -13
- package/src/sync/polling/syncTasks/{splitsSyncTask.ts → definitionsSyncTask.ts} +10 -11
- package/src/sync/polling/types.ts +3 -3
- package/src/sync/polling/updaters/{splitChangesUpdater.ts → definitionChangesUpdater.ts} +77 -68
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +7 -7
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +6 -6
- package/src/sync/streaming/parseUtils.ts +12 -12
- package/src/sync/streaming/pushManager.ts +3 -3
- package/src/sync/submitters/impressionsSubmitter.ts +9 -9
- package/src/sync/submitters/types.ts +3 -0
- package/src/sync/syncManagerOnline.ts +6 -2
- package/src/trackers/eventTracker.ts +7 -10
- package/src/trackers/impressionsTracker.ts +42 -26
- package/src/trackers/types.ts +3 -1
- package/src/utils/EventEmitter.js +444 -0
- package/src/utils/filter/bloomFilter.ts +38 -0
- package/src/utils/inputValidation/definition.ts +27 -0
- package/src/utils/inputValidation/definitionExistence.ts +19 -0
- package/src/utils/inputValidation/definitions.ts +21 -0
- package/src/utils/inputValidation/index.ts +3 -3
- package/src/utils/inputValidation/isOperational.ts +4 -4
- package/src/utils/inputValidation/target.ts +21 -0
- package/src/utils/labels/index.ts +2 -2
- package/src/utils/settingsValidation/splitFilters.ts +3 -3
- package/types/splitio.d.ts +202 -9
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +0 -13
- package/cjs/utils/inputValidation/splits.js +0 -25
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +0 -9
- package/esm/utils/inputValidation/splitExistence.js +0 -15
- package/esm/utils/inputValidation/splits.js +0 -21
- package/src/utils/inputValidation/split.ts +0 -27
- package/src/utils/inputValidation/splitExistence.ts +0 -19
- package/src/utils/inputValidation/splits.ts +0 -21
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { ISegmentsCacheBase, IStorageBase } from '../../../storages/types';
|
|
2
|
-
import {
|
|
3
|
-
import { IRBSegment,
|
|
2
|
+
import { IDefinitionChangesFetcher } from '../fetchers/types';
|
|
3
|
+
import { IRBSegment, IDefinition, IDefinitionChangesResponse, ISplitFiltersValidation, MaybeThenable } from '../../../dtos/types';
|
|
4
4
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
5
5
|
import { timeout } from '../../../utils/promise/timeout';
|
|
6
|
-
import { SDK_SPLITS_ARRIVED, FLAGS_UPDATE, SEGMENTS_UPDATE } from '../../../readiness/constants';
|
|
6
|
+
import { SDK_SPLITS_ARRIVED, FLAGS_UPDATE, SEGMENTS_UPDATE, CONFIGS_UPDATE } from '../../../readiness/constants';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
8
|
-
import {
|
|
8
|
+
import { SYNC_FETCH, SYNC_UPDATE, SYNC_FETCH_FAILS, SYNC_FETCH_RETRY } from '../../../logger/constants';
|
|
9
9
|
import { startsWith } from '../../../utils/lang';
|
|
10
10
|
import { IN_RULE_BASED_SEGMENT, IN_SEGMENT, RULE_BASED_SEGMENT, STANDARD_SEGMENT } from '../../../utils/constants';
|
|
11
11
|
import { setToArray } from '../../../utils/lang/sets';
|
|
12
12
|
import { SPLIT_UPDATE } from '../../streaming/constants';
|
|
13
13
|
import { SdkUpdateMetadata } from '../../../../types/splitio';
|
|
14
|
+
import { ISplit } from '../fetchers/splitChangesFetcher';
|
|
14
15
|
|
|
15
16
|
export type InstantUpdate = { payload: ISplit | IRBSegment, changeNumber: number, type: string };
|
|
16
|
-
type
|
|
17
|
+
type DefinitionChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
|
|
17
18
|
|
|
18
19
|
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
19
20
|
// Returns a promise that could be rejected.
|
|
@@ -30,8 +31,8 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
|
|
|
30
31
|
* Collect segments from a raw FF or RBS definition.
|
|
31
32
|
* Exported for testing purposes.
|
|
32
33
|
*/
|
|
33
|
-
export function parseSegments(ruleEntity:
|
|
34
|
-
const { conditions
|
|
34
|
+
export function parseSegments(ruleEntity: IDefinition | IRBSegment, matcherType: typeof IN_SEGMENT | typeof IN_RULE_BASED_SEGMENT = IN_SEGMENT): Set<string> {
|
|
35
|
+
const { conditions, excluded } = ruleEntity as IRBSegment;
|
|
35
36
|
|
|
36
37
|
const segments = new Set<string>();
|
|
37
38
|
if (excluded && excluded.segments) {
|
|
@@ -42,146 +43,154 @@ export function parseSegments(ruleEntity: ISplit | IRBSegment, matcherType: type
|
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
if (conditions) {
|
|
47
|
+
for (let i = 0; i < conditions.length; i++) {
|
|
48
|
+
const matchers = conditions[i].matcherGroup.matchers;
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
matchers.forEach(matcher => {
|
|
51
|
+
if (matcher.matcherType === matcherType) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
return segments;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
interface
|
|
59
|
+
interface IDefinitionMutations<T extends IDefinition | IRBSegment> {
|
|
57
60
|
added: T[],
|
|
58
|
-
removed:
|
|
61
|
+
removed: string[],
|
|
59
62
|
names: string[]
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
/**
|
|
63
|
-
* If there are defined filters and one
|
|
66
|
+
* If there are defined filters and one definition doesn't match with them, its status is changed to 'ARCHIVE' to avoid storing it
|
|
64
67
|
* If there is `bySet` filter, `byName` and `byPrefix` filters are ignored
|
|
65
68
|
*
|
|
66
|
-
* @param
|
|
69
|
+
* @param definition - definition to be evaluated
|
|
67
70
|
* @param filters - splitFiltersValidation bySet | byName
|
|
68
71
|
*/
|
|
69
|
-
function matchFilters(
|
|
72
|
+
function matchFilters(definition: IDefinition, filters: ISplitFiltersValidation) {
|
|
70
73
|
const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter } = filters.groupedFilters;
|
|
71
|
-
if (setsFilter.length > 0) return
|
|
74
|
+
if (setsFilter.length > 0) return definition.sets && definition.sets.some((definitionSet: string) => setsFilter.indexOf(definitionSet) > -1);
|
|
72
75
|
|
|
73
76
|
const namesFilterConfigured = namesFilter.length > 0;
|
|
74
77
|
const prefixFilterConfigured = prefixFilter.length > 0;
|
|
75
78
|
|
|
76
79
|
if (!namesFilterConfigured && !prefixFilterConfigured) return true;
|
|
77
80
|
|
|
78
|
-
const matchNames = namesFilterConfigured && namesFilter.indexOf(
|
|
79
|
-
const matchPrefix = prefixFilterConfigured && prefixFilter.some(prefix => startsWith(
|
|
81
|
+
const matchNames = namesFilterConfigured && namesFilter.indexOf(definition.name) > -1;
|
|
82
|
+
const matchPrefix = prefixFilterConfigured && prefixFilter.some(prefix => startsWith(definition.name, prefix));
|
|
80
83
|
return matchNames || matchPrefix;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
84
|
-
* Given the list of
|
|
85
|
-
* i.e., an object with added
|
|
87
|
+
* Given the list of definitions from /splitChanges or /configs endpoint, it returns the mutations,
|
|
88
|
+
* i.e., an object with added definitions, removed definitions, and used segments.
|
|
86
89
|
* Exported for testing purposes.
|
|
87
90
|
*/
|
|
88
|
-
export function computeMutation<T extends
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity as ISplit, filters))) {
|
|
91
|
+
export function computeMutation<T extends IDefinition | IRBSegment>(update: { updated: T[], removed: string[] }, segments: Set<string>, filters?: ISplitFiltersValidation): IDefinitionMutations<T> {
|
|
92
|
+
return update.updated.reduce((accum, ruleEntity) => {
|
|
93
|
+
if (!filters || matchFilters(ruleEntity as IDefinition, filters)) {
|
|
92
94
|
accum.added.push(ruleEntity);
|
|
93
95
|
|
|
94
96
|
parseSegments(ruleEntity).forEach((segmentName: string) => {
|
|
95
97
|
segments.add(segmentName);
|
|
96
98
|
});
|
|
97
99
|
} else {
|
|
98
|
-
accum.removed.push(ruleEntity);
|
|
100
|
+
accum.removed.push(ruleEntity.name);
|
|
99
101
|
}
|
|
100
102
|
accum.names.push(ruleEntity.name);
|
|
101
|
-
|
|
102
103
|
return accum;
|
|
103
|
-
}, { added: [], removed:
|
|
104
|
+
}, { added: [], removed: update.removed, names: update.removed.slice() } as IDefinitionMutations<T>);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function convertInstantUpdateToDefinitionChanges(instantUpdate: InstantUpdate) {
|
|
108
|
+
const { payload, changeNumber } = instantUpdate;
|
|
109
|
+
return payload.status === 'ARCHIVED' ?
|
|
110
|
+
{ till: changeNumber, updated: [], removed: [payload.name] } :
|
|
111
|
+
{ till: changeNumber, updated: [payload], removed: [] };
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
/**
|
|
107
|
-
*
|
|
108
|
-
* - fetches
|
|
109
|
-
* - updates
|
|
110
|
-
* - uses `
|
|
115
|
+
* Factory of DefinitionChanges updater, a task that:
|
|
116
|
+
* - fetches definition changes using `definitionChangesFetcher`
|
|
117
|
+
* - updates definitions storage
|
|
118
|
+
* - uses `definitionsEventEmitter` to emit events related to definition data updates
|
|
111
119
|
*
|
|
112
120
|
* @param log - Logger instance
|
|
113
|
-
* @param
|
|
114
|
-
* @param
|
|
121
|
+
* @param definitionChangesFetcher - Fetcher of `/splitChanges` or `/configs`
|
|
122
|
+
* @param definitions - Definitions storage, with sync or async methods
|
|
115
123
|
* @param segments - Segments storage, with sync or async methods
|
|
116
|
-
* @param
|
|
124
|
+
* @param definitionsEventEmitter - Optional readiness manager. Not required for synchronizer or producer mode.
|
|
117
125
|
* @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
118
|
-
* @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
126
|
+
* @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` or `/configs` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
119
127
|
*/
|
|
120
|
-
export function
|
|
128
|
+
export function definitionChangesUpdaterFactory(
|
|
121
129
|
log: ILogger,
|
|
122
|
-
|
|
130
|
+
definitionChangesFetcher: IDefinitionChangesFetcher,
|
|
123
131
|
storage: Pick<IStorageBase, 'splits' | 'rbSegments' | 'segments' | 'save'>,
|
|
124
132
|
splitFiltersValidation: ISplitFiltersValidation,
|
|
125
133
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
126
134
|
requestTimeoutBeforeReady = 0,
|
|
127
135
|
retriesOnFailureBeforeReady = 0,
|
|
128
136
|
isClientSide?: boolean
|
|
129
|
-
):
|
|
137
|
+
): DefinitionChangesUpdater {
|
|
130
138
|
const { splits, rbSegments, segments } = storage;
|
|
131
139
|
|
|
132
140
|
let startingUp = true;
|
|
133
141
|
|
|
134
|
-
/** timeout decorator for `
|
|
142
|
+
/** timeout decorator for `definitionChangesFetcher` promise */
|
|
135
143
|
function _promiseDecorator<T>(promise: Promise<T>) {
|
|
136
144
|
if (startingUp && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise);
|
|
137
145
|
return promise;
|
|
138
146
|
}
|
|
139
147
|
|
|
140
148
|
/**
|
|
141
|
-
*
|
|
149
|
+
* DefinitionChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch definitions or synchronize them with the storage.
|
|
142
150
|
* Returned promise will not be rejected.
|
|
143
151
|
*
|
|
144
152
|
* @param noCache - true to revalidate data to fetch
|
|
145
153
|
* @param till - query param to bypass CDN requests
|
|
146
154
|
*/
|
|
147
|
-
return function
|
|
155
|
+
return function definitionChangesUpdater(noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) {
|
|
148
156
|
|
|
149
157
|
/**
|
|
150
|
-
* @param since - current changeNumber at
|
|
158
|
+
* @param since - current changeNumber at definitionsCache
|
|
151
159
|
* @param retry - current number of retry attempts
|
|
152
160
|
*/
|
|
153
|
-
function
|
|
161
|
+
function _definitionChangesUpdater(sinces: [number, number], retry = 0): Promise<boolean> {
|
|
154
162
|
const [since, rbSince] = sinces;
|
|
155
|
-
log.debug(
|
|
163
|
+
log.debug(SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
|
|
164
|
+
|
|
156
165
|
return Promise.resolve(
|
|
157
166
|
instantUpdate ?
|
|
158
167
|
instantUpdate.type === SPLIT_UPDATE ?
|
|
159
|
-
// IFFU edge case: a change to
|
|
168
|
+
// IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
160
169
|
Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, IN_RULE_BASED_SEGMENT))).then((contains) => {
|
|
161
170
|
return contains ?
|
|
162
|
-
{
|
|
163
|
-
|
|
171
|
+
{ d: convertInstantUpdateToDefinitionChanges(instantUpdate) as IDefinitionChangesResponse['d'] } :
|
|
172
|
+
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
164
173
|
}) :
|
|
165
|
-
{ rbs:
|
|
166
|
-
|
|
174
|
+
{ rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) as IDefinitionChangesResponse['rbs'] } :
|
|
175
|
+
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
|
|
167
176
|
)
|
|
168
|
-
.then((
|
|
177
|
+
.then((definitionChanges: IDefinitionChangesResponse) => {
|
|
169
178
|
const usedSegments = new Set<string>();
|
|
170
179
|
|
|
171
|
-
let
|
|
180
|
+
let updatedDefinitions: string[] = [];
|
|
172
181
|
let ffUpdate: MaybeThenable<boolean> = false;
|
|
173
|
-
if (
|
|
174
|
-
const { added, removed, names } = computeMutation(
|
|
175
|
-
|
|
176
|
-
log.debug(
|
|
177
|
-
ffUpdate = splits.update(added, removed,
|
|
182
|
+
if (definitionChanges.d) {
|
|
183
|
+
const { added, removed, names } = computeMutation(definitionChanges.d, usedSegments, splitFiltersValidation);
|
|
184
|
+
updatedDefinitions = names;
|
|
185
|
+
log.debug(SYNC_UPDATE, [definitionChangesFetcher.type, added.length, removed.length]);
|
|
186
|
+
ffUpdate = splits.update(added, removed, definitionChanges.d.till);
|
|
178
187
|
}
|
|
179
188
|
|
|
180
189
|
let rbsUpdate: MaybeThenable<boolean> = false;
|
|
181
|
-
if (
|
|
182
|
-
const { added, removed } = computeMutation(
|
|
183
|
-
log.debug(
|
|
184
|
-
rbsUpdate = rbSegments.update(added, removed,
|
|
190
|
+
if (definitionChanges.rbs) {
|
|
191
|
+
const { added, removed } = computeMutation(definitionChanges.rbs, usedSegments);
|
|
192
|
+
log.debug(SYNC_UPDATE, ['rule-based segments', added.length, removed.length]);
|
|
193
|
+
rbsUpdate = rbSegments.update(added, removed, definitionChanges.rbs.till);
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
return Promise.all([ffUpdate, rbsUpdate,
|
|
@@ -200,8 +209,8 @@ export function splitChangesUpdaterFactory(
|
|
|
200
209
|
// emit SDK events
|
|
201
210
|
if (emitSplitsArrivedEvent) {
|
|
202
211
|
const metadata: SdkUpdateMetadata = {
|
|
203
|
-
type:
|
|
204
|
-
names:
|
|
212
|
+
type: updatedDefinitions.length > 0 ? definitionChangesFetcher.type === 'configs' ? CONFIGS_UPDATE : FLAGS_UPDATE : SEGMENTS_UPDATE,
|
|
213
|
+
names: updatedDefinitions.length > 0 ? updatedDefinitions : []
|
|
205
214
|
};
|
|
206
215
|
splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, metadata);
|
|
207
216
|
}
|
|
@@ -214,17 +223,17 @@ export function splitChangesUpdaterFactory(
|
|
|
214
223
|
.catch(error => {
|
|
215
224
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
216
225
|
retry += 1;
|
|
217
|
-
log.warn(
|
|
218
|
-
return
|
|
226
|
+
log.warn(SYNC_FETCH_RETRY, [definitionChangesFetcher.type, retry, error]);
|
|
227
|
+
return _definitionChangesUpdater(sinces, retry);
|
|
219
228
|
} else {
|
|
220
229
|
startingUp = false;
|
|
221
|
-
log.warn(
|
|
230
|
+
log.warn(SYNC_FETCH_FAILS, [definitionChangesFetcher.type, error]);
|
|
222
231
|
}
|
|
223
232
|
return false;
|
|
224
233
|
});
|
|
225
234
|
}
|
|
226
235
|
|
|
227
236
|
// `getChangeNumber` never rejects or throws error
|
|
228
|
-
return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(
|
|
237
|
+
return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(_definitionChangesUpdater);
|
|
229
238
|
};
|
|
230
239
|
}
|
|
@@ -4,7 +4,7 @@ import { ISegmentsEventEmitter } from '../../../readiness/types';
|
|
|
4
4
|
import { timeout } from '../../../utils/promise/timeout';
|
|
5
5
|
import { SDK_SEGMENTS_ARRIVED, SEGMENTS_UPDATE } from '../../../readiness/constants';
|
|
6
6
|
import { ILogger } from '../../../logger/types';
|
|
7
|
-
import {
|
|
7
|
+
import { SYNC_FETCH_RETRY } from '../../../logger/constants';
|
|
8
8
|
import { MySegmentsData } from '../types';
|
|
9
9
|
import { IMembershipsResponse } from '../../../dtos/types';
|
|
10
10
|
import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
|
|
@@ -76,7 +76,7 @@ export function mySegmentsUpdaterFactory(
|
|
|
76
76
|
return updaterPromise.catch(error => {
|
|
77
77
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
78
78
|
retry += 1;
|
|
79
|
-
log.warn(
|
|
79
|
+
log.warn(SYNC_FETCH_RETRY, ['memberships', retry, error]);
|
|
80
80
|
return _mySegmentsUpdater(retry); // no need to forward `segmentList` and `noCache` params
|
|
81
81
|
} else {
|
|
82
82
|
startingUp = false;
|
|
@@ -3,7 +3,7 @@ import { ISegmentsCacheBase } from '../../../storages/types';
|
|
|
3
3
|
import { IReadinessManager } from '../../../readiness/types';
|
|
4
4
|
import { SDK_SEGMENTS_ARRIVED, SEGMENTS_UPDATE } from '../../../readiness/constants';
|
|
5
5
|
import { ILogger } from '../../../logger/types';
|
|
6
|
-
import { LOG_PREFIX_INSTANTIATION,
|
|
6
|
+
import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC } from '../../../logger/constants';
|
|
7
7
|
import { timeout } from '../../../utils/promise/timeout';
|
|
8
8
|
import { SdkUpdateMetadata } from '../../../../types/splitio';
|
|
9
9
|
|
|
@@ -38,7 +38,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean, retries?: number): Promise<boolean> {
|
|
41
|
-
log.debug(`${
|
|
41
|
+
log.debug(`${LOG_PREFIX_SYNC}Processing segment ${segmentName}`);
|
|
42
42
|
const sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
|
|
43
43
|
|
|
44
44
|
return sincePromise.then(since => {
|
|
@@ -47,14 +47,14 @@ export function segmentChangesUpdaterFactory(
|
|
|
47
47
|
false :
|
|
48
48
|
segmentChangesFetcher(since || -1, segmentName, noCache, till, _promiseDecorator).then((changes) => {
|
|
49
49
|
return Promise.all(changes.map(x => {
|
|
50
|
-
log.debug(`${
|
|
50
|
+
log.debug(`${LOG_PREFIX_SYNC}Processing ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
|
|
51
51
|
return segments.update(segmentName, x.added, x.removed, x.till);
|
|
52
52
|
})).then((updates) => {
|
|
53
53
|
return updates.some(update => update);
|
|
54
54
|
});
|
|
55
55
|
}).catch(error => {
|
|
56
56
|
if (retries) {
|
|
57
|
-
log.warn(`${
|
|
57
|
+
log.warn(`${LOG_PREFIX_SYNC}Retrying fetch of segment ${segmentName} (attempt #${retries}). Reason: ${error}`);
|
|
58
58
|
return updateSegment(segmentName, noCache, till, fetchOnlyNew, retries - 1);
|
|
59
59
|
}
|
|
60
60
|
throw error;
|
|
@@ -73,7 +73,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
73
73
|
* @param till - till target for the provided segmentName, for CDN bypass.
|
|
74
74
|
*/
|
|
75
75
|
return function segmentChangesUpdater(fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number) {
|
|
76
|
-
log.debug(`${
|
|
76
|
+
log.debug(`${LOG_PREFIX_SYNC}Started segments update`);
|
|
77
77
|
|
|
78
78
|
// If not a segment name provided, read list of available segments names to be updated.
|
|
79
79
|
let segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
|
|
@@ -102,9 +102,9 @@ export function segmentChangesUpdaterFactory(
|
|
|
102
102
|
// If the operation is forbidden, it may be due to permissions. Destroy the SDK instance.
|
|
103
103
|
// @TODO although factory status is destroyed, synchronization is not stopped
|
|
104
104
|
if (readiness) readiness.setDestroyed();
|
|
105
|
-
log.error(`${LOG_PREFIX_INSTANTIATION}: you passed a client-side type authorizationKey, please grab an SDK Key from
|
|
105
|
+
log.error(`${LOG_PREFIX_INSTANTIATION}: you passed a client-side type authorizationKey, please grab an SDK Key from Harness UI that is of type server-side.`);
|
|
106
106
|
} else {
|
|
107
|
-
log.warn(`${
|
|
107
|
+
log.warn(`${LOG_PREFIX_SYNC}Error while doing fetch of segments. ${error}`);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
return false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IRBSegment,
|
|
1
|
+
import { IRBSegment, IDefinition } from '../../../dtos/types';
|
|
2
2
|
import { STREAMING_PARSING_SPLIT_UPDATE } from '../../../logger/constants';
|
|
3
3
|
import { ILogger } from '../../../logger/types';
|
|
4
4
|
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
@@ -7,8 +7,8 @@ import { IRBSegmentsCacheSync, ISplitsCacheSync, IStorageSync } from '../../../s
|
|
|
7
7
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
8
8
|
import { Backoff } from '../../../utils/Backoff';
|
|
9
9
|
import { SPLITS } from '../../../utils/constants';
|
|
10
|
-
import { ISegmentsSyncTask,
|
|
11
|
-
import { InstantUpdate } from '../../polling/updaters/
|
|
10
|
+
import { ISegmentsSyncTask, IDefinitionsSyncTask } from '../../polling/types';
|
|
11
|
+
import { InstantUpdate } from '../../polling/updaters/definitionChangesUpdater';
|
|
12
12
|
import { RB_SEGMENT_UPDATE } from '../constants';
|
|
13
13
|
import { parseFFUpdatePayload } from '../parseUtils';
|
|
14
14
|
import { ISplitKillData, ISplitUpdateData } from '../SSEHandler/types';
|
|
@@ -18,7 +18,7 @@ import { IUpdateWorker } from './types';
|
|
|
18
18
|
/**
|
|
19
19
|
* SplitsUpdateWorker factory
|
|
20
20
|
*/
|
|
21
|
-
export function SplitsUpdateWorker(log: ILogger, storage: IStorageSync,
|
|
21
|
+
export function SplitsUpdateWorker(log: ILogger, storage: IStorageSync, definitionsSyncTask: IDefinitionsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker<[updateData: ISplitUpdateData]> & { killSplit(event: ISplitKillData): void } {
|
|
22
22
|
|
|
23
23
|
const ff = SplitsUpdateWorker(storage.splits);
|
|
24
24
|
const rbs = SplitsUpdateWorker(storage.rbSegments);
|
|
@@ -36,7 +36,7 @@ export function SplitsUpdateWorker(log: ILogger, storage: IStorageSync, splitsSy
|
|
|
36
36
|
if (maxChangeNumber > cache.getChangeNumber()) {
|
|
37
37
|
handleNewEvent = false;
|
|
38
38
|
// fetch splits revalidating data if cached
|
|
39
|
-
|
|
39
|
+
definitionsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, instantUpdate).then(() => {
|
|
40
40
|
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
41
41
|
if (handleNewEvent) {
|
|
42
42
|
__handleSplitUpdateCall();
|
|
@@ -79,7 +79,7 @@ export function SplitsUpdateWorker(log: ILogger, storage: IStorageSync, splitsSy
|
|
|
79
79
|
*
|
|
80
80
|
* @param changeNumber - change number of the notification
|
|
81
81
|
*/
|
|
82
|
-
put({ changeNumber, pcn, type }: ISplitUpdateData, payload?:
|
|
82
|
+
put({ changeNumber, pcn, type }: ISplitUpdateData, payload?: IDefinition | IRBSegment) {
|
|
83
83
|
const currentChangeNumber = cache.getChangeNumber();
|
|
84
84
|
|
|
85
85
|
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { algorithms } from '../../utils/decompress';
|
|
2
2
|
import { decodeFromBase64 } from '../../utils/base64';
|
|
3
3
|
import { hash } from '../../utils/murmur3/murmur3';
|
|
4
|
-
import { Compression, IMembershipMSUpdateData
|
|
5
|
-
import { IRBSegment,
|
|
4
|
+
import { Compression, IMembershipMSUpdateData } from './SSEHandler/types';
|
|
5
|
+
import { IRBSegment, IDefinition } from '../../dtos/types';
|
|
6
6
|
|
|
7
7
|
const GZIP = 1;
|
|
8
8
|
const ZLIB = 2;
|
|
@@ -35,20 +35,20 @@ function decompress(data: string, compression: Compression) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Decode, decompress and parse the provided 'data' into
|
|
38
|
+
* Decode, decompress and parse the provided 'data' into an object of type T
|
|
39
39
|
*
|
|
40
40
|
* @param data - base64 encoded string
|
|
41
41
|
* @param compression - 1 GZIP, 2 ZLIB
|
|
42
42
|
* @param avoidPrecisionLoss - true as default, set it as false if dont need to avoid precission loss
|
|
43
|
-
* @returns
|
|
43
|
+
* @returns parsed object
|
|
44
44
|
* @throws if data string cannot be decoded, decompressed or parsed
|
|
45
45
|
*/
|
|
46
|
-
export function
|
|
47
|
-
const
|
|
48
|
-
let
|
|
49
|
-
// replace numbers to strings, to avoid losing precision
|
|
50
|
-
if (avoidPrecisionLoss)
|
|
51
|
-
return JSON.parse(
|
|
46
|
+
export function parseCompressedData<T>(data: string, compression: Compression, avoidPrecisionLoss = true): T {
|
|
47
|
+
const binData = decompress(data, compression);
|
|
48
|
+
let str = Uint8ArrayToString(binData);
|
|
49
|
+
// replace numbers to strings, to avoid losing precision (e.g., 64-bit IDs in KeyList)
|
|
50
|
+
if (avoidPrecisionLoss) str = str.replace(/\d+/g, '"$&"');
|
|
51
|
+
return JSON.parse(str) as T;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -82,9 +82,9 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
|
|
|
82
82
|
/**
|
|
83
83
|
* Parse feature flags notifications for instant feature flag updates
|
|
84
84
|
*/
|
|
85
|
-
export function parseFFUpdatePayload(compression: Compression, data: string):
|
|
85
|
+
export function parseFFUpdatePayload(compression: Compression, data: string): IDefinition | IRBSegment | undefined {
|
|
86
86
|
return compression > 0 ?
|
|
87
|
-
|
|
87
|
+
parseCompressedData<IDefinition | IRBSegment>(data, compression, false) :
|
|
88
88
|
JSON.parse(decodeFromBase64(data));
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -14,7 +14,7 @@ import { checkIfServerSide, getMatching } from '../../utils/key';
|
|
|
14
14
|
import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, RB_SEGMENT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
|
|
15
15
|
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE } from '../../logger/constants';
|
|
16
16
|
import { IMembershipMSUpdateData, IMembershipLSUpdateData, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
|
-
import { getDelay, isInBitmap, parseBitmap,
|
|
17
|
+
import { getDelay, isInBitmap, parseBitmap, parseCompressedData } from './parseUtils';
|
|
18
18
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
19
19
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
20
20
|
import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
@@ -56,7 +56,7 @@ export function pushManagerFactory(
|
|
|
56
56
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
57
57
|
const segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask as ISegmentsSyncTask, storage.segments);
|
|
58
58
|
// For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
|
|
59
|
-
const splitsUpdateWorker = SplitsUpdateWorker(log, storage, pollingManager.
|
|
59
|
+
const splitsUpdateWorker = SplitsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
|
|
60
60
|
|
|
61
61
|
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
62
62
|
const userKeyHashes: Record<string, string> = {};
|
|
@@ -243,7 +243,7 @@ export function pushManagerFactory(
|
|
|
243
243
|
case UpdateStrategy.KeyList: {
|
|
244
244
|
let keyList: KeyList, added: Set<string>, removed: Set<string>;
|
|
245
245
|
try {
|
|
246
|
-
keyList =
|
|
246
|
+
keyList = parseCompressedData<KeyList>(parsedData.d!, parsedData.c!);
|
|
247
247
|
added = new Set(keyList.a);
|
|
248
248
|
removed = new Set(keyList.r);
|
|
249
249
|
} catch (e) {
|
|
@@ -3,20 +3,20 @@ import SplitIO from '../../../types/splitio';
|
|
|
3
3
|
import { submitterFactory } from './submitter';
|
|
4
4
|
import { ImpressionsPayload } from './types';
|
|
5
5
|
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
6
|
-
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
6
|
+
import { EntityType, ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Converts `impressions` data from cache into request payload.
|
|
10
10
|
*/
|
|
11
|
-
export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
|
|
11
|
+
export function fromImpressionsCollector(sendLabels: boolean, entityType: EntityType | undefined, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
|
|
12
12
|
let groupedByFeature = groupBy(data, 'feature');
|
|
13
13
|
let dto: ImpressionsPayload = [];
|
|
14
14
|
|
|
15
15
|
forOwn(groupedByFeature, (value, name) => {
|
|
16
16
|
dto.push({
|
|
17
|
-
f: name, //
|
|
17
|
+
f: name, // Definition type
|
|
18
18
|
i: value.map(entry => { // Key Impressions
|
|
19
|
-
|
|
19
|
+
return {
|
|
20
20
|
k: entry.keyName, // Key
|
|
21
21
|
t: entry.treatment, // Treatment
|
|
22
22
|
m: entry.time, // Timestamp
|
|
@@ -24,10 +24,9 @@ export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.Impr
|
|
|
24
24
|
r: sendLabels ? entry.label : undefined, // Rule
|
|
25
25
|
b: entry.bucketingKey, // Bucketing Key
|
|
26
26
|
pt: entry.pt, // Previous time
|
|
27
|
-
properties: entry.properties // Properties
|
|
27
|
+
properties: entry.properties, // Properties
|
|
28
|
+
et: entityType, // Definition type
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
-
return keyImpression;
|
|
31
30
|
})
|
|
32
31
|
});
|
|
33
32
|
});
|
|
@@ -43,11 +42,12 @@ export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) {
|
|
|
43
42
|
const {
|
|
44
43
|
settings: { log, scheduler: { impressionsRefreshRate }, core: { labelsEnabled } },
|
|
45
44
|
splitApi: { postTestImpressionsBulk },
|
|
46
|
-
storage: { impressions }
|
|
45
|
+
storage: { impressions },
|
|
46
|
+
entityType
|
|
47
47
|
} = params;
|
|
48
48
|
|
|
49
49
|
// retry impressions only once.
|
|
50
|
-
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
|
|
50
|
+
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled, entityType), 1);
|
|
51
51
|
|
|
52
52
|
// register impressions submitter to be executed when impressions cache is full
|
|
53
53
|
impressions.setOnFullQueueCb(() => {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { IMetadata } from '../../dtos/types';
|
|
3
3
|
import SplitIO from '../../../types/splitio';
|
|
4
4
|
import { ISyncTask } from '../types';
|
|
5
|
+
import { EntityType } from '../../sdkFactory/types';
|
|
5
6
|
|
|
6
7
|
type ImpressionPayload = {
|
|
7
8
|
/** Matching Key */
|
|
@@ -20,6 +21,8 @@ type ImpressionPayload = {
|
|
|
20
21
|
pt?: number;
|
|
21
22
|
/** Stringified JSON object with properties */
|
|
22
23
|
properties?: string;
|
|
24
|
+
/** Definition type */
|
|
25
|
+
et?: EntityType,
|
|
23
26
|
};
|
|
24
27
|
|
|
25
28
|
export type ImpressionsPayload = {
|
|
@@ -11,6 +11,8 @@ import { POLLING, STREAMING, SYNC_MODE_UPDATE } from '../utils/constants';
|
|
|
11
11
|
import { ISdkFactoryContextSync } from '../sdkFactory/types';
|
|
12
12
|
import { SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
|
|
13
13
|
import { usesSegmentsSync } from '../storages/AbstractSplitsCacheSync';
|
|
14
|
+
import { splitChangesFetcherFactory } from './polling/fetchers/splitChangesFetcher';
|
|
15
|
+
import { IDefinitionChangesFetcher } from './polling/fetchers/types';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Online SyncManager factory.
|
|
@@ -19,10 +21,12 @@ import { usesSegmentsSync } from '../storages/AbstractSplitsCacheSync';
|
|
|
19
21
|
* @param pollingManagerFactory - allows to specialize the SyncManager for server-side or client-side API by passing
|
|
20
22
|
* `pollingManagerSSFactory` or `pollingManagerCSFactory` respectively.
|
|
21
23
|
* @param pushManagerFactory - optional to build a SyncManager with or without streaming support
|
|
24
|
+
* @param definitionChangesFetcherFactory - optional to replace the default split changes fetcher
|
|
22
25
|
*/
|
|
23
26
|
export function syncManagerOnlineFactory(
|
|
24
|
-
pollingManagerFactory?: (params: ISdkFactoryContextSync) => IPollingManager,
|
|
27
|
+
pollingManagerFactory?: (params: ISdkFactoryContextSync, definitionChangesFetcher: IDefinitionChangesFetcher) => IPollingManager,
|
|
25
28
|
pushManagerFactory?: (params: ISdkFactoryContextSync, pollingManager: IPollingManager) => IPushManager | undefined,
|
|
29
|
+
definitionChangesFetcherFactory = splitChangesFetcherFactory
|
|
26
30
|
): (params: ISdkFactoryContextSync) => ISyncManagerCS {
|
|
27
31
|
|
|
28
32
|
/**
|
|
@@ -33,7 +37,7 @@ export function syncManagerOnlineFactory(
|
|
|
33
37
|
const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled } }, telemetryTracker, storage, readiness } = params;
|
|
34
38
|
|
|
35
39
|
/** Polling Manager */
|
|
36
|
-
const pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
40
|
+
const pollingManager = pollingManagerFactory && pollingManagerFactory(params, definitionChangesFetcherFactory(params));
|
|
37
41
|
|
|
38
42
|
/** Push Manager */
|
|
39
43
|
const pushManager = syncEnabled && streamingEnabled && pollingManager && pushManagerFactory ?
|
|
@@ -17,7 +17,6 @@ import { isConsumerMode } from '../utils/settingsValidation/mode';
|
|
|
17
17
|
export function eventTrackerFactory(
|
|
18
18
|
settings: ISettings,
|
|
19
19
|
eventsCache: IEventsCacheBase,
|
|
20
|
-
whenInit: (cb: () => void) => void,
|
|
21
20
|
integrationsManager?: IEventsHandler,
|
|
22
21
|
telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync
|
|
23
22
|
): IEventTracker {
|
|
@@ -33,15 +32,13 @@ export function eventTrackerFactory(
|
|
|
33
32
|
if (tracked) {
|
|
34
33
|
log.info(EVENTS_TRACKER_SUCCESS, [msg]);
|
|
35
34
|
if (integrationsManager) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
integrationsManager.handleEvent(eventDataCopy);
|
|
44
|
-
});
|
|
35
|
+
// Wrap in a timeout because we don't want it to be blocking.
|
|
36
|
+
setTimeout(() => {
|
|
37
|
+
// copy of event, to avoid unexpected behavior if modified by integrations
|
|
38
|
+
const eventDataCopy = objectAssign({}, eventData);
|
|
39
|
+
if (properties) eventDataCopy.properties = objectAssign({}, properties);
|
|
40
|
+
// integrationsManager does not throw errors (they are internally handled by each integration module)
|
|
41
|
+
integrationsManager.handleEvent(eventDataCopy);
|
|
45
42
|
});
|
|
46
43
|
}
|
|
47
44
|
} else {
|