@splitsoftware/splitio-commons 2.12.0 → 3.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +19 -1
- 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 +73 -48
- 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 +15 -21
- 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 -10
- 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 +5 -4
- package/cjs/readiness/readinessManager.js +22 -22
- package/cjs/readiness/sdkReadinessManager.js +0 -16
- 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 +71 -0
- package/cjs/sdkClient/trackMethod.js +56 -0
- package/cjs/sdkFactory/index.js +13 -50
- package/cjs/sdkManager/index.js +5 -5
- package/cjs/services/authProvider.js +67 -0
- package/cjs/services/secureSplitHttpClient.js +39 -0
- package/cjs/services/splitApi.js +24 -14
- package/cjs/services/splitHttpClient.js +1 -1
- package/cjs/storages/AbstractDefinitionsCacheAsync.js +51 -0
- package/cjs/storages/AbstractDefinitionsCacheSync.js +76 -0
- package/cjs/storages/KeyBuilder.js +16 -16
- package/cjs/storages/KeyBuilderCS.js +17 -17
- package/cjs/storages/KeyBuilderSS.js +16 -16
- package/cjs/storages/getRolloutPlan.js +4 -4
- package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +194 -0
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -1
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +10 -10
- package/cjs/storages/inLocalStorage/index.js +6 -6
- package/cjs/storages/inLocalStorage/validateCache.js +3 -3
- package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +121 -0
- package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +4 -4
- package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -5
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +5 -5
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +5 -5
- package/cjs/storages/inRedis/DefinitionsCacheInRedis.js +243 -0
- 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/TelemetryCacheInRedis.js +7 -7
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +3 -3
- package/cjs/storages/inRedis/index.js +2 -2
- package/cjs/storages/pluggable/DefinitionsCachePluggable.js +212 -0
- 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/TelemetryCachePluggable.js +7 -7
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -2
- package/cjs/storages/pluggable/index.js +5 -5
- package/cjs/storages/pluggable/wrapperAdapter.js +1 -1
- package/cjs/storages/setRolloutPlan.js +6 -6
- package/cjs/storages/utils.js +6 -6
- package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +5 -5
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +24 -15
- package/cjs/sync/polling/pollingManagerCS.js +18 -18
- 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} +72 -64
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -3
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
- package/cjs/sync/streaming/SSEClient/index.js +2 -2
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +1 -1
- package/cjs/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +18 -18
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/constants.js +3 -3
- package/cjs/sync/streaming/parseUtils.js +12 -12
- package/cjs/sync/streaming/pushManager.js +14 -14
- package/cjs/sync/submitters/impressionsSubmitter.js +6 -6
- package/cjs/sync/submitters/submitter.js +1 -1
- package/cjs/sync/submitters/telemetrySubmitter.js +1 -2
- package/cjs/sync/syncManagerOnline.js +9 -6
- 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/Backoff.js +20 -0
- 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/lang/sets.js +4 -4
- package/cjs/utils/promise/timeout.js +1 -1
- package/cjs/utils/settingsValidation/splitFilters.js +4 -4
- package/cjs/utils/settingsValidation/url.js +6 -6
- 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 +72 -48
- 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 +12 -18
- 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 -9
- 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 +4 -3
- package/esm/readiness/readinessManager.js +23 -23
- package/esm/readiness/sdkReadinessManager.js +1 -17
- 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 +67 -0
- package/esm/sdkClient/trackMethod.js +52 -0
- package/esm/sdkFactory/index.js +14 -51
- package/esm/sdkManager/index.js +6 -6
- package/esm/services/authProvider.js +63 -0
- package/esm/services/secureSplitHttpClient.js +35 -0
- package/esm/services/splitApi.js +24 -14
- package/esm/services/splitHttpClient.js +1 -1
- package/esm/storages/AbstractDefinitionsCacheAsync.js +48 -0
- package/esm/storages/AbstractDefinitionsCacheSync.js +71 -0
- package/esm/storages/KeyBuilder.js +16 -16
- package/esm/storages/KeyBuilderCS.js +16 -16
- package/esm/storages/KeyBuilderSS.js +15 -15
- package/esm/storages/getRolloutPlan.js +4 -4
- package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +191 -0
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +7 -7
- package/esm/storages/inLocalStorage/index.js +6 -6
- package/esm/storages/inLocalStorage/validateCache.js +3 -3
- package/esm/storages/inMemory/DefinitionsCacheInMemory.js +118 -0
- package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/esm/storages/inMemory/InMemoryStorage.js +4 -4
- package/esm/storages/inMemory/InMemoryStorageCS.js +5 -5
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +2 -2
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +5 -5
- package/esm/storages/inRedis/DefinitionsCacheInRedis.js +240 -0
- 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/TelemetryCacheInRedis.js +7 -7
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -1
- package/esm/storages/inRedis/index.js +2 -2
- package/esm/storages/pluggable/DefinitionsCachePluggable.js +209 -0
- 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/TelemetryCachePluggable.js +7 -7
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -1
- package/esm/storages/pluggable/index.js +4 -4
- package/esm/storages/pluggable/wrapperAdapter.js +1 -1
- package/esm/storages/setRolloutPlan.js +6 -6
- package/esm/storages/utils.js +6 -6
- package/esm/sync/offline/splitsParser/parseCondition.js +1 -1
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +6 -6
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +25 -16
- package/esm/sync/polling/pollingManagerCS.js +15 -15
- package/esm/sync/polling/pollingManagerSS.js +13 -13
- package/esm/sync/polling/syncTasks/definitionsSyncTask.js +8 -0
- package/esm/sync/polling/updaters/definitionChangesUpdater.js +200 -0
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -3
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +7 -7
- package/esm/sync/streaming/SSEClient/index.js +2 -2
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +2 -2
- package/esm/sync/streaming/SSEHandler/index.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +17 -17
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
- package/esm/sync/streaming/constants.js +2 -2
- package/esm/sync/streaming/parseUtils.js +10 -10
- package/esm/sync/streaming/pushManager.js +16 -16
- package/esm/sync/submitters/impressionsSubmitter.js +6 -6
- package/esm/sync/submitters/submitter.js +1 -1
- package/esm/sync/submitters/telemetrySubmitter.js +1 -2
- package/esm/sync/syncManagerOnline.js +8 -5
- 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/Backoff.js +20 -0
- 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/lang/sets.js +4 -4
- package/esm/utils/promise/timeout.js +1 -1
- package/esm/utils/settingsValidation/splitFilters.js +4 -4
- package/esm/utils/settingsValidation/url.js +6 -6
- 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 +86 -51
- 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 +12 -18
- 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 -9
- 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 +4 -3
- package/src/readiness/readinessManager.ts +22 -22
- package/src/readiness/sdkReadinessManager.ts +1 -16
- package/src/readiness/types.ts +10 -16
- 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 +79 -0
- package/src/sdkClient/trackMethod.ts +59 -0
- package/src/sdkFactory/index.ts +15 -59
- package/src/sdkFactory/types.ts +19 -16
- package/src/sdkManager/index.ts +15 -15
- package/src/services/authProvider.ts +86 -0
- package/src/services/secureSplitHttpClient.ts +44 -0
- package/src/services/splitApi.ts +14 -2
- package/src/services/types.ts +7 -2
- package/src/storages/AbstractDefinitionsCacheAsync.ts +63 -0
- package/src/storages/AbstractDefinitionsCacheSync.ts +95 -0
- package/src/storages/KeyBuilder.ts +6 -6
- package/src/storages/KeyBuilderCS.ts +6 -6
- package/src/storages/KeyBuilderSS.ts +2 -2
- package/src/storages/getRolloutPlan.ts +3 -3
- package/src/storages/inLocalStorage/DefinitionsCacheInLocal.ts +234 -0
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +8 -8
- package/src/storages/inLocalStorage/index.ts +6 -6
- package/src/storages/inLocalStorage/validateCache.ts +4 -4
- package/src/storages/inMemory/DefinitionsCacheInMemory.ts +130 -0
- package/src/storages/inMemory/InMemoryStorage.ts +4 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +5 -5
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +3 -3
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +1 -1
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +5 -5
- package/src/storages/inRedis/{SplitsCacheInRedis.ts → DefinitionsCacheInRedis.ts} +69 -69
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +2 -2
- package/src/storages/inRedis/index.ts +2 -2
- package/src/storages/pluggable/DefinitionsCachePluggable.ts +230 -0
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +2 -2
- package/src/storages/pluggable/index.ts +2 -2
- package/src/storages/setRolloutPlan.ts +7 -7
- package/src/storages/types.ts +34 -29
- 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 +14 -14
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +58 -23
- package/src/sync/polling/fetchers/types.ts +5 -3
- package/src/sync/polling/pollingManagerCS.ts +16 -14
- package/src/sync/polling/pollingManagerSS.ts +15 -13
- package/src/sync/polling/syncTasks/{splitsSyncTask.ts → definitionsSyncTask.ts} +11 -12
- package/src/sync/polling/types.ts +3 -3
- package/src/sync/polling/updaters/definitionChangesUpdater.ts +239 -0
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +3 -3
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +7 -7
- package/src/sync/streaming/AuthClient/index.ts +2 -2
- package/src/sync/streaming/AuthClient/types.ts +14 -11
- package/src/sync/streaming/SSEClient/index.ts +2 -2
- package/src/sync/streaming/SSEClient/types.ts +2 -2
- package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +2 -2
- package/src/sync/streaming/SSEHandler/index.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.ts → DefinitionsUpdateWorker.ts} +21 -21
- package/src/sync/streaming/constants.ts +2 -2
- package/src/sync/streaming/parseUtils.ts +12 -12
- package/src/sync/streaming/pushManager.ts +18 -18
- package/src/sync/streaming/types.ts +2 -2
- package/src/sync/submitters/impressionsSubmitter.ts +9 -9
- package/src/sync/submitters/telemetrySubmitter.ts +1 -2
- package/src/sync/submitters/types.ts +3 -0
- package/src/sync/syncManagerOnline.ts +9 -5
- package/src/trackers/eventTracker.ts +7 -10
- package/src/trackers/impressionsTracker.ts +42 -26
- package/src/trackers/types.ts +3 -1
- package/src/utils/Backoff.ts +21 -0
- 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/inputValidation/trafficTypeExistence.ts +2 -2
- package/src/utils/jwt/types.ts +1 -1
- package/src/utils/labels/index.ts +2 -2
- package/src/utils/lang/sets.ts +4 -2
- package/src/utils/settingsValidation/splitFilters.ts +3 -3
- package/src/utils/settingsValidation/url.ts +1 -1
- package/types/splitio.d.ts +222 -11
- package/cjs/storages/AbstractSplitsCacheAsync.js +0 -51
- package/cjs/storages/AbstractSplitsCacheSync.js +0 -76
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -194
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -121
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +0 -243
- package/cjs/storages/pluggable/SplitsCachePluggable.js +0 -212
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +0 -13
- package/cjs/utils/inputValidation/splits.js +0 -25
- package/esm/storages/AbstractSplitsCacheAsync.js +0 -48
- package/esm/storages/AbstractSplitsCacheSync.js +0 -71
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -191
- package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -118
- package/esm/storages/inRedis/SplitsCacheInRedis.js +0 -240
- package/esm/storages/pluggable/SplitsCachePluggable.js +0 -209
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +0 -9
- package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -192
- package/esm/utils/inputValidation/splitExistence.js +0 -15
- package/esm/utils/inputValidation/splits.js +0 -21
- package/src/storages/AbstractSplitsCacheAsync.ts +0 -63
- package/src/storages/AbstractSplitsCacheSync.ts +0 -95
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +0 -234
- package/src/storages/inMemory/SplitsCacheInMemory.ts +0 -130
- package/src/storages/pluggable/SplitsCachePluggable.ts +0 -230
- package/src/sync/polling/updaters/splitChangesUpdater.ts +0 -230
- package/src/utils/inputValidation/split.ts +0 -27
- package/src/utils/inputValidation/splitExistence.ts +0 -19
- package/src/utils/inputValidation/splits.ts +0 -21
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { IDefinition, ISplitFiltersValidation } from '../../dtos/types';
|
|
2
|
+
import { AbstractDefinitionsCacheSync, usesSegments } from '../AbstractDefinitionsCacheSync';
|
|
3
|
+
import { isFiniteNumber } from '../../utils/lang';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default IDefinitionsCacheSync implementation that stores split definitions in memory.
|
|
7
|
+
*/
|
|
8
|
+
export class DefinitionsCacheInMemory extends AbstractDefinitionsCacheSync {
|
|
9
|
+
|
|
10
|
+
private setsFilter: string[];
|
|
11
|
+
private definitionsCache: Record<string, IDefinition> = {};
|
|
12
|
+
private ttCache: Record<string, number> = {};
|
|
13
|
+
private changeNumber: number = -1;
|
|
14
|
+
private segmentsCount: number = 0;
|
|
15
|
+
private setsCache: Record<string, Set<string>> = {};
|
|
16
|
+
|
|
17
|
+
constructor(splitFiltersValidation?: ISplitFiltersValidation) {
|
|
18
|
+
super();
|
|
19
|
+
this.setsFilter = splitFiltersValidation ? splitFiltersValidation.groupedFilters.bySet : [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
clear() {
|
|
23
|
+
this.definitionsCache = {};
|
|
24
|
+
this.ttCache = {};
|
|
25
|
+
this.changeNumber = -1;
|
|
26
|
+
this.segmentsCount = 0;
|
|
27
|
+
this.setsCache = {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
add(definition: IDefinition): boolean {
|
|
31
|
+
const name = definition.name;
|
|
32
|
+
const previousDefinition = this.get(name);
|
|
33
|
+
if (previousDefinition) { // We had this Split already
|
|
34
|
+
|
|
35
|
+
const previousTtName = previousDefinition.trafficTypeName;
|
|
36
|
+
this.ttCache[previousTtName]--;
|
|
37
|
+
if (!this.ttCache[previousTtName]) delete this.ttCache[previousTtName];
|
|
38
|
+
|
|
39
|
+
this.removeFromFlagSets(previousDefinition.name, previousDefinition.sets);
|
|
40
|
+
|
|
41
|
+
// Subtract from segments count for the previous version of this Split
|
|
42
|
+
if (usesSegments(previousDefinition)) this.segmentsCount--;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Store the Split.
|
|
46
|
+
this.definitionsCache[name] = definition;
|
|
47
|
+
// Update TT cache
|
|
48
|
+
const ttName = definition.trafficTypeName;
|
|
49
|
+
this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
|
|
50
|
+
this.addToFlagSets(definition);
|
|
51
|
+
|
|
52
|
+
// Add to segments count for the new version of the Split
|
|
53
|
+
if (usesSegments(definition)) this.segmentsCount++;
|
|
54
|
+
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
remove(name: string): boolean {
|
|
59
|
+
const definition = this.get(name);
|
|
60
|
+
if (!definition) return false;
|
|
61
|
+
|
|
62
|
+
// Delete the Split
|
|
63
|
+
delete this.definitionsCache[name];
|
|
64
|
+
|
|
65
|
+
const ttName = definition.trafficTypeName;
|
|
66
|
+
this.ttCache[ttName]--; // Update tt cache
|
|
67
|
+
if (!this.ttCache[ttName]) delete this.ttCache[ttName];
|
|
68
|
+
this.removeFromFlagSets(definition.name, definition.sets);
|
|
69
|
+
|
|
70
|
+
// Update the segments count.
|
|
71
|
+
if (usesSegments(definition)) this.segmentsCount--;
|
|
72
|
+
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get(name: string): IDefinition | null {
|
|
77
|
+
return this.definitionsCache[name] || null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setChangeNumber(changeNumber: number): boolean {
|
|
81
|
+
this.changeNumber = changeNumber;
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getChangeNumber(): number {
|
|
86
|
+
return this.changeNumber;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getNames(): string[] {
|
|
90
|
+
return Object.keys(this.definitionsCache);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
trafficTypeExists(trafficType: string): boolean {
|
|
94
|
+
return isFiniteNumber(this.ttCache[trafficType]) && this.ttCache[trafficType] > 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
usesSegments(): boolean {
|
|
98
|
+
return this.getChangeNumber() === -1 || this.segmentsCount > 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getNamesBySets(sets: string[]): Set<string>[] {
|
|
102
|
+
return sets.map(set => this.setsCache[set] || new Set());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private addToFlagSets(featureFlag: IDefinition) {
|
|
106
|
+
if (!featureFlag.sets) return;
|
|
107
|
+
featureFlag.sets.forEach(featureFlagSet => {
|
|
108
|
+
|
|
109
|
+
if (this.setsFilter.length > 0 && !this.setsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;
|
|
110
|
+
|
|
111
|
+
if (!this.setsCache[featureFlagSet]) this.setsCache[featureFlagSet] = new Set([]);
|
|
112
|
+
|
|
113
|
+
this.setsCache[featureFlagSet].add(featureFlag.name);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private removeFromFlagSets(featureFlagName: string, sets?: string[] | null) {
|
|
118
|
+
if (!sets) return;
|
|
119
|
+
sets.forEach(set => {
|
|
120
|
+
this.removeNames(set, featureFlagName);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private removeNames(setName: string, featureFlagName: string) {
|
|
125
|
+
if (!this.setsCache[setName]) return;
|
|
126
|
+
this.setsCache[setName].delete(featureFlagName);
|
|
127
|
+
if (this.setsCache[setName].size === 0) delete this.setsCache[setName];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DefinitionsCacheInMemory } from './DefinitionsCacheInMemory';
|
|
2
2
|
import { SegmentsCacheInMemory } from './SegmentsCacheInMemory';
|
|
3
3
|
import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
|
|
4
4
|
import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
@@ -17,18 +17,18 @@ import { RBSegmentsCacheInMemory } from './RBSegmentsCacheInMemory';
|
|
|
17
17
|
export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageSync {
|
|
18
18
|
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { __splitFiltersValidation } } } = params;
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const definitions = new DefinitionsCacheInMemory(__splitFiltersValidation);
|
|
21
21
|
const rbSegments = new RBSegmentsCacheInMemory();
|
|
22
22
|
const segments = new SegmentsCacheInMemory();
|
|
23
23
|
|
|
24
24
|
const storage = {
|
|
25
|
-
|
|
25
|
+
definitions,
|
|
26
26
|
rbSegments,
|
|
27
27
|
segments,
|
|
28
28
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
29
29
|
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
30
30
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
31
|
-
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(
|
|
31
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(definitions, segments) : undefined,
|
|
32
32
|
uniqueKeys: new UniqueKeysCacheInMemory(),
|
|
33
33
|
|
|
34
34
|
destroy() { }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DefinitionsCacheInMemory } from './DefinitionsCacheInMemory';
|
|
2
2
|
import { MySegmentsCacheInMemory } from './MySegmentsCacheInMemory';
|
|
3
3
|
import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
|
|
4
4
|
import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
@@ -17,20 +17,20 @@ import { RBSegmentsCacheInMemory } from './RBSegmentsCacheInMemory';
|
|
|
17
17
|
export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorageSync {
|
|
18
18
|
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize }, sync: { __splitFiltersValidation } } } = params;
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const definitions = new DefinitionsCacheInMemory(__splitFiltersValidation);
|
|
21
21
|
const rbSegments = new RBSegmentsCacheInMemory();
|
|
22
22
|
const segments = new MySegmentsCacheInMemory();
|
|
23
23
|
const largeSegments = new MySegmentsCacheInMemory();
|
|
24
24
|
|
|
25
25
|
const storage = {
|
|
26
|
-
|
|
26
|
+
definitions,
|
|
27
27
|
rbSegments,
|
|
28
28
|
segments,
|
|
29
29
|
largeSegments,
|
|
30
30
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
31
31
|
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
32
32
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
33
|
-
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(
|
|
33
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(definitions, segments) : undefined,
|
|
34
34
|
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
35
35
|
|
|
36
36
|
destroy() { },
|
|
@@ -38,7 +38,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
38
38
|
// When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
|
|
39
39
|
shared() {
|
|
40
40
|
return {
|
|
41
|
-
|
|
41
|
+
definitions: this.definitions,
|
|
42
42
|
rbSegments: this.rbSegments,
|
|
43
43
|
segments: new MySegmentsCacheInMemory(),
|
|
44
44
|
largeSegments: new MySegmentsCacheInMemory(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IRBSegment } from '../../dtos/types';
|
|
2
2
|
import { setToArray } from '../../utils/lang/sets';
|
|
3
|
-
import { usesSegments } from '../
|
|
3
|
+
import { usesSegments } from '../AbstractDefinitionsCacheSync';
|
|
4
4
|
import { IRBSegmentsCacheSync } from '../types';
|
|
5
5
|
|
|
6
6
|
export class RBSegmentsCacheInMemory implements IRBSegmentsCacheSync {
|
|
@@ -15,9 +15,9 @@ export class RBSegmentsCacheInMemory implements IRBSegmentsCacheSync {
|
|
|
15
15
|
this.segmentsCount = 0;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
update(toAdd: IRBSegment[], toRemove:
|
|
18
|
+
update(toAdd: IRBSegment[], toRemove: string[], changeNumber: number): boolean {
|
|
19
19
|
let updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
|
|
20
|
-
updated = toRemove.map(toRemove => this.remove(toRemove
|
|
20
|
+
updated = toRemove.map(toRemove => this.remove(toRemove)).some(result => result) || updated;
|
|
21
21
|
this.changeNumber = changeNumber;
|
|
22
22
|
return updated;
|
|
23
23
|
}
|
|
@@ -2,7 +2,7 @@ import { isIntegerNumber } from '../../utils/lang';
|
|
|
2
2
|
import { ISegmentsCacheSync } from '../types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Default
|
|
5
|
+
* Default IDefinitionsCacheSync implementation for server-side that stores segments definitions in memory.
|
|
6
6
|
*/
|
|
7
7
|
export class SegmentsCacheInMemory implements ISegmentsCacheSync {
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies,
|
|
|
2
2
|
import { DEDUPED, DROPPED, LOCALHOST_MODE, QUEUED } from '../../utils/constants';
|
|
3
3
|
import { checkIfServerSide } from '../../utils/key';
|
|
4
4
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
5
|
-
import { ISegmentsCacheSync,
|
|
5
|
+
import { ISegmentsCacheSync, IDefinitionsCacheSync, IStorageFactoryParams, ITelemetryCacheSync } from '../types';
|
|
6
6
|
|
|
7
7
|
const MAX_STREAMING_EVENTS = 20;
|
|
8
8
|
const MAX_TAGS = 10;
|
|
@@ -20,15 +20,15 @@ const ACCEPTANCE_RANGE = 0.001;
|
|
|
20
20
|
* Record telemetry if mode is not localhost.
|
|
21
21
|
* All factory instances track telemetry on server-side, and 0.1% on client-side.
|
|
22
22
|
*/
|
|
23
|
-
export function shouldRecordTelemetry({ settings }: IStorageFactoryParams) {
|
|
24
|
-
return settings.mode !== LOCALHOST_MODE && (checkIfServerSide(settings) || Math.random() <= ACCEPTANCE_RANGE);
|
|
23
|
+
export function shouldRecordTelemetry({ settings, disableTelemetry }: IStorageFactoryParams) {
|
|
24
|
+
return !disableTelemetry && settings.mode !== LOCALHOST_MODE && (checkIfServerSide(settings) || Math.random() <= ACCEPTANCE_RANGE);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export class TelemetryCacheInMemory implements ITelemetryCacheSync {
|
|
28
28
|
|
|
29
29
|
public name = 'telemetry stats';
|
|
30
30
|
|
|
31
|
-
constructor(private
|
|
31
|
+
constructor(private definitions?: IDefinitionsCacheSync, private segments?: ISegmentsCacheSync, private largeSegments?: ISegmentsCacheSync) { }
|
|
32
32
|
|
|
33
33
|
// isEmpty flag
|
|
34
34
|
private e = true;
|
|
@@ -51,7 +51,7 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
|
|
|
51
51
|
iQ: this.getImpressionStats(QUEUED),
|
|
52
52
|
iDe: this.getImpressionStats(DEDUPED),
|
|
53
53
|
iDr: this.getImpressionStats(DROPPED),
|
|
54
|
-
spC: this.
|
|
54
|
+
spC: this.definitions && this.definitions.getNames().length,
|
|
55
55
|
seC: this.segments && this.segments.getRegisteredSegments().length,
|
|
56
56
|
skC: this.segments && this.segments.getKeysCount(),
|
|
57
57
|
lsC: this.largeSegments && this.largeSegments.getRegisteredSegments().length,
|
|
@@ -2,8 +2,8 @@ import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
|
2
2
|
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
3
3
|
import { ILogger } from '../../logger/types';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { IDefinition, ISplitFiltersValidation } from '../../dtos/types';
|
|
6
|
+
import { AbstractDefinitionsCacheAsync } from '../AbstractDefinitionsCacheAsync';
|
|
7
7
|
import { returnDifference } from '../../utils/lang/sets';
|
|
8
8
|
import type { RedisAdapter } from './RedisAdapter';
|
|
9
9
|
|
|
@@ -18,23 +18,23 @@ function processPipelineAnswer(results: Array<[Error | null, unknown]> | null):
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* IDefinitionsCacheAsync implementation that stores definitions in Redis.
|
|
22
22
|
* Supported by Node.js
|
|
23
23
|
*/
|
|
24
|
-
export class
|
|
24
|
+
export class DefinitionsCacheInRedis extends AbstractDefinitionsCacheAsync {
|
|
25
25
|
|
|
26
26
|
private readonly log: ILogger;
|
|
27
27
|
private readonly redis: RedisAdapter;
|
|
28
28
|
private readonly keys: KeyBuilderSS;
|
|
29
29
|
private redisError?: Error;
|
|
30
|
-
private readonly
|
|
30
|
+
private readonly setsFilter: string[];
|
|
31
31
|
|
|
32
32
|
constructor(log: ILogger, keys: KeyBuilderSS, redis: RedisAdapter, splitFiltersValidation?: ISplitFiltersValidation) {
|
|
33
33
|
super();
|
|
34
34
|
this.log = log;
|
|
35
35
|
this.redis = redis;
|
|
36
36
|
this.keys = keys;
|
|
37
|
-
this.
|
|
37
|
+
this.setsFilter = splitFiltersValidation ? splitFiltersValidation.groupedFilters.bySet : [];
|
|
38
38
|
|
|
39
39
|
// There is no need to listen for redis 'error' event, because in that case ioredis calls will be rejected and handled by redis storage adapters.
|
|
40
40
|
// But it is done just to avoid getting the ioredis message `Unhandled error event`.
|
|
@@ -47,95 +47,95 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
private _decrementCounts(
|
|
51
|
-
const ttKey = this.keys.buildTrafficTypeKey(
|
|
50
|
+
private _decrementCounts(definition: IDefinition) {
|
|
51
|
+
const ttKey = this.keys.buildTrafficTypeKey(definition.trafficTypeName);
|
|
52
52
|
return this.redis.decr(ttKey).then((count: number) => {
|
|
53
53
|
if (count === 0) return this.redis.del(ttKey);
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
private _incrementCounts(
|
|
58
|
-
const ttKey = this.keys.buildTrafficTypeKey(
|
|
57
|
+
private _incrementCounts(definition: IDefinition) {
|
|
58
|
+
const ttKey = this.keys.buildTrafficTypeKey(definition.trafficTypeName);
|
|
59
59
|
return this.redis.incr(ttKey);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
private
|
|
63
|
-
const
|
|
62
|
+
private _updateSets(definitionName: string, setsOfRemovedDefinition?: string[] | null, setsOfAddedDefinition?: string[] | null) {
|
|
63
|
+
const removeFromSets = returnDifference(setsOfRemovedDefinition, setsOfAddedDefinition);
|
|
64
64
|
|
|
65
|
-
let
|
|
66
|
-
if (this.
|
|
67
|
-
|
|
68
|
-
return this.
|
|
65
|
+
let addToSets = returnDifference(setsOfAddedDefinition, setsOfRemovedDefinition);
|
|
66
|
+
if (this.setsFilter.length > 0) {
|
|
67
|
+
addToSets = addToSets.filter(set => {
|
|
68
|
+
return this.setsFilter.some(filterSet => filterSet === set);
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
const items = [
|
|
72
|
+
const items = [definitionName];
|
|
73
73
|
|
|
74
74
|
return Promise.all([
|
|
75
|
-
...
|
|
76
|
-
...
|
|
75
|
+
...removeFromSets.map(setName => this.redis.srem(this.keys.buildSetKey(setName), items)),
|
|
76
|
+
...addToSets.map(setName => this.redis.sadd(this.keys.buildSetKey(setName), items))
|
|
77
77
|
]);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
|
-
* Add a given
|
|
81
|
+
* Add a given definition.
|
|
82
82
|
* The returned promise is resolved when the operation success
|
|
83
83
|
* or rejected if it fails (e.g., redis operation fails)
|
|
84
84
|
*/
|
|
85
|
-
|
|
86
|
-
const name =
|
|
87
|
-
const
|
|
88
|
-
return this.redis.get(
|
|
85
|
+
add(definition: IDefinition): Promise<boolean> {
|
|
86
|
+
const name = definition.name;
|
|
87
|
+
const definitionKey = this.keys.buildDefinitionKey(name);
|
|
88
|
+
return this.redis.get(definitionKey).then((definitionFromStorage: string | null) => {
|
|
89
89
|
|
|
90
90
|
// handling parsing error
|
|
91
|
-
let
|
|
91
|
+
let parsedPreviousDefinition: IDefinition, stringifiedNewDefinition;
|
|
92
92
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
parsedPreviousDefinition = definitionFromStorage ? JSON.parse(definitionFromStorage) : undefined;
|
|
94
|
+
stringifiedNewDefinition = JSON.stringify(definition);
|
|
95
95
|
} catch (e) {
|
|
96
96
|
throw new Error('Error parsing feature flag definition: ' + e);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
return this.redis.set(
|
|
99
|
+
return this.redis.set(definitionKey, stringifiedNewDefinition).then(() => {
|
|
100
100
|
// avoid unnecessary increment/decrement operations
|
|
101
|
-
if (
|
|
101
|
+
if (parsedPreviousDefinition && parsedPreviousDefinition.trafficTypeName === definition.trafficTypeName) return;
|
|
102
102
|
|
|
103
103
|
// update traffic type counts
|
|
104
|
-
return this._incrementCounts(
|
|
105
|
-
if (
|
|
104
|
+
return this._incrementCounts(definition).then(() => {
|
|
105
|
+
if (parsedPreviousDefinition) return this._decrementCounts(parsedPreviousDefinition);
|
|
106
106
|
});
|
|
107
|
-
}).then(() => this.
|
|
107
|
+
}).then(() => this._updateSets(name, parsedPreviousDefinition && parsedPreviousDefinition.sets, definition.sets));
|
|
108
108
|
}).then(() => true);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
|
-
* Remove a given
|
|
113
|
-
* The returned promise is resolved when the operation success, with true or false indicating if the
|
|
112
|
+
* Remove a given definition.
|
|
113
|
+
* The returned promise is resolved when the operation success, with true or false indicating if the definition existed (and was removed) or not.
|
|
114
114
|
* or rejected if it fails (e.g., redis operation fails).
|
|
115
115
|
*/
|
|
116
|
-
|
|
117
|
-
return this.
|
|
118
|
-
if (
|
|
119
|
-
return this._decrementCounts(
|
|
116
|
+
remove(name: string) {
|
|
117
|
+
return this.get(name).then((definition) => {
|
|
118
|
+
if (definition) {
|
|
119
|
+
return this._decrementCounts(definition).then(() => this._updateSets(name, definition.sets));
|
|
120
120
|
}
|
|
121
121
|
}).then(() => {
|
|
122
|
-
return this.redis.del(this.keys.
|
|
122
|
+
return this.redis.del(this.keys.buildDefinitionKey(name)).then((status: number) => status === 1);
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* Get
|
|
127
|
+
* Get definition or null if it's not defined.
|
|
128
128
|
* Returned promise is rejected if redis operation fails.
|
|
129
129
|
*/
|
|
130
|
-
|
|
130
|
+
get(name: string): Promise<IDefinition | null> {
|
|
131
131
|
if (this.redisError) {
|
|
132
132
|
this.log.error(LOG_PREFIX + this.redisError);
|
|
133
133
|
|
|
134
134
|
return Promise.reject(this.redisError);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
return this.redis.get(this.keys.
|
|
138
|
-
.then((
|
|
137
|
+
return this.redis.get(this.keys.buildDefinitionKey(name))
|
|
138
|
+
.then((maybeDefinition: string | null) => maybeDefinition && JSON.parse(maybeDefinition));
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
/**
|
|
@@ -144,7 +144,7 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
144
144
|
* or rejected if it fails.
|
|
145
145
|
*/
|
|
146
146
|
setChangeNumber(changeNumber: number): Promise<boolean> {
|
|
147
|
-
return this.redis.set(this.keys.
|
|
147
|
+
return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(
|
|
148
148
|
(status: string | null) => status === 'OK'
|
|
149
149
|
);
|
|
150
150
|
}
|
|
@@ -155,7 +155,7 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
155
155
|
* The promise will never be rejected.
|
|
156
156
|
*/
|
|
157
157
|
getChangeNumber(): Promise<number> {
|
|
158
|
-
return this.redis.get(this.keys.
|
|
158
|
+
return this.redis.get(this.keys.buildDefinitionsTillKey()).then((value: string | null) => {
|
|
159
159
|
const i = parseInt(value as string, 10);
|
|
160
160
|
|
|
161
161
|
return isNaNNumber(i) ? -1 : i;
|
|
@@ -166,44 +166,44 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
|
-
* Get list of all
|
|
170
|
-
* The returned promise is resolved with the list of
|
|
169
|
+
* Get list of all definitions.
|
|
170
|
+
* The returned promise is resolved with the list of definitions,
|
|
171
171
|
* or rejected if redis operation fails.
|
|
172
172
|
*/
|
|
173
173
|
// @TODO we need to benchmark which is the maximun number of commands we could pipeline without kill redis performance.
|
|
174
|
-
getAll(): Promise<
|
|
175
|
-
return this.redis.keys(this.keys.
|
|
174
|
+
getAll(): Promise<IDefinition[]> {
|
|
175
|
+
return this.redis.keys(this.keys.searchPatternForDefinitionKeys())
|
|
176
176
|
.then((listOfKeys: string[]) => this.redis.pipeline(listOfKeys.map((k: string) => ['get', k])).exec())
|
|
177
177
|
.then(processPipelineAnswer)
|
|
178
|
-
.then((
|
|
179
|
-
return JSON.parse(
|
|
178
|
+
.then((definitions: string[]) => definitions.map((definition: string) => {
|
|
179
|
+
return JSON.parse(definition);
|
|
180
180
|
}));
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
|
-
* Get list of
|
|
185
|
-
* The returned promise is resolved with the list of
|
|
184
|
+
* Get list of definition names.
|
|
185
|
+
* The returned promise is resolved with the list of names,
|
|
186
186
|
* or rejected if redis operation fails.
|
|
187
187
|
*/
|
|
188
|
-
|
|
189
|
-
return this.redis.keys(this.keys.
|
|
188
|
+
getNames(): Promise<string[]> {
|
|
189
|
+
return this.redis.keys(this.keys.searchPatternForDefinitionKeys()).then(
|
|
190
190
|
(listOfKeys: string[]) => listOfKeys.map(this.keys.extractKey)
|
|
191
191
|
);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
/**
|
|
195
|
-
* Get list of
|
|
196
|
-
* The returned promise is resolved with the list of
|
|
195
|
+
* Get list of definition names related to a given list of set names.
|
|
196
|
+
* The returned promise is resolved with the list of names per set,
|
|
197
197
|
* or rejected if the pipelined redis operation fails (e.g., timeout).
|
|
198
198
|
*/
|
|
199
|
-
|
|
200
|
-
return this.redis.pipeline(
|
|
199
|
+
getNamesBySets(sets: string[]): Promise<Set<string>[]> {
|
|
200
|
+
return this.redis.pipeline(sets.map(set => ['smembers', this.keys.buildSetKey(set)])).exec()
|
|
201
201
|
.then((results: [Error | null, unknown][] | null) => results ? results.map(([e, value]: [Error | null, unknown], index: number) => {
|
|
202
202
|
if (e === null) return value as string;
|
|
203
203
|
|
|
204
|
-
this.log.error(LOG_PREFIX + `Could not read result from get members of
|
|
204
|
+
this.log.error(LOG_PREFIX + `Could not read result from get members of set ${sets[index]} due to an error: ${e}`);
|
|
205
205
|
}) : [])
|
|
206
|
-
.then((
|
|
206
|
+
.then((namesBySets: (string | undefined)[]) => namesBySets.map((namesBySet: string | undefined) => new Set(namesBySet)));
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
@@ -239,25 +239,25 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
|
-
* Fetches multiple
|
|
242
|
+
* Fetches multiple definitions.
|
|
243
243
|
* Returned promise is rejected if redis operation fails.
|
|
244
244
|
*/
|
|
245
|
-
|
|
245
|
+
getMany(names: string[]): Promise<Record<string, IDefinition | null>> {
|
|
246
246
|
if (this.redisError) {
|
|
247
247
|
this.log.error(LOG_PREFIX + this.redisError);
|
|
248
248
|
|
|
249
249
|
return Promise.reject(this.redisError);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
const keys = names.map(name => this.keys.
|
|
252
|
+
const keys = names.map(name => this.keys.buildDefinitionKey(name));
|
|
253
253
|
return this.redis.mget(...keys)
|
|
254
|
-
.then((
|
|
255
|
-
const
|
|
254
|
+
.then((stringifiedDefinitions: (string | null)[]) => {
|
|
255
|
+
const definitions: Record<string, IDefinition | null> = {};
|
|
256
256
|
names.forEach((name, idx) => {
|
|
257
|
-
const
|
|
258
|
-
|
|
257
|
+
const definition = stringifiedDefinitions[idx];
|
|
258
|
+
definitions[name] = definition && JSON.parse(definition);
|
|
259
259
|
});
|
|
260
|
-
return Promise.resolve(
|
|
260
|
+
return Promise.resolve(definitions);
|
|
261
261
|
})
|
|
262
262
|
.catch((e: unknown) => {
|
|
263
263
|
this.log.error(LOG_PREFIX + `Could not grab feature flags due to an error: ${e}.`);
|
|
@@ -37,7 +37,7 @@ export class RBSegmentsCacheInRedis implements IRBSegmentsCacheAsync {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
update(toAdd: IRBSegment[], toRemove:
|
|
40
|
+
update(toAdd: IRBSegment[], toRemove: string[], changeNumber: number): Promise<boolean> {
|
|
41
41
|
return Promise.all([
|
|
42
42
|
this.setChangeNumber(changeNumber),
|
|
43
43
|
Promise.all(toAdd.map(toAdd => {
|
|
@@ -46,7 +46,7 @@ export class RBSegmentsCacheInRedis implements IRBSegmentsCacheAsync {
|
|
|
46
46
|
return this.redis.set(key, stringifiedNewRBSegment).then(() => true);
|
|
47
47
|
})),
|
|
48
48
|
Promise.all(toRemove.map(toRemove => {
|
|
49
|
-
const key = this.keys.buildRBSegmentKey(toRemove
|
|
49
|
+
const key = this.keys.buildRBSegmentKey(toRemove);
|
|
50
50
|
return this.redis.del(key).then((status: number) => status === 1);
|
|
51
51
|
}))
|
|
52
52
|
]).then(([, added, removed]) => {
|
|
@@ -2,7 +2,7 @@ import type { RedisAdapter } from './RedisAdapter';
|
|
|
2
2
|
import { IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams } from '../types';
|
|
3
3
|
import { validatePrefix } from '../KeyBuilder';
|
|
4
4
|
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
5
|
-
import {
|
|
5
|
+
import { DefinitionsCacheInRedis } from './DefinitionsCacheInRedis';
|
|
6
6
|
import { SegmentsCacheInRedis } from './SegmentsCacheInRedis';
|
|
7
7
|
import { ImpressionsCacheInRedis } from './ImpressionsCacheInRedis';
|
|
8
8
|
import { EventsCacheInRedis } from './EventsCacheInRedis';
|
|
@@ -59,7 +59,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
return {
|
|
62
|
-
|
|
62
|
+
definitions: new DefinitionsCacheInRedis(log, keys, redisClient, settings.sync.__splitFiltersValidation),
|
|
63
63
|
rbSegments: new RBSegmentsCacheInRedis(log, keys, redisClient),
|
|
64
64
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
65
65
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|