@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,63 @@
|
|
|
1
|
+
import { IDefinitionsCacheAsync } from './types';
|
|
2
|
+
import { IDefinition } from '../dtos/types';
|
|
3
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This class provides a skeletal implementation of the IDefinitionsCacheAsync interface
|
|
7
|
+
* to minimize the effort required to implement this interface.
|
|
8
|
+
*/
|
|
9
|
+
export abstract class AbstractDefinitionsCacheAsync implements IDefinitionsCacheAsync {
|
|
10
|
+
|
|
11
|
+
protected abstract add(definition: IDefinition): Promise<boolean>
|
|
12
|
+
protected abstract remove(name: string): Promise<boolean>
|
|
13
|
+
protected abstract setChangeNumber(changeNumber: number): Promise<boolean | void>
|
|
14
|
+
|
|
15
|
+
update(toAdd: IDefinition[], toRemove: string[], changeNumber: number): Promise<boolean> {
|
|
16
|
+
return Promise.all([
|
|
17
|
+
this.setChangeNumber(changeNumber),
|
|
18
|
+
Promise.all(toAdd.map(addedFF => this.add(addedFF))),
|
|
19
|
+
Promise.all(toRemove.map(removedFF => this.remove(removedFF)))
|
|
20
|
+
]).then(([, added, removed]) => {
|
|
21
|
+
return added.some(result => result) || removed.some(result => result);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
abstract get(name: string): Promise<IDefinition | null>
|
|
26
|
+
abstract getMany(names: string[]): Promise<Record<string, IDefinition | null>>
|
|
27
|
+
abstract getChangeNumber(): Promise<number>
|
|
28
|
+
abstract getAll(): Promise<IDefinition[]>
|
|
29
|
+
abstract getNames(): Promise<string[]>
|
|
30
|
+
abstract getNamesBySets(sets: string[]): Promise<Set<string>[]>
|
|
31
|
+
abstract trafficTypeExists(trafficType: string): Promise<boolean>
|
|
32
|
+
abstract clear(): Promise<boolean | void>
|
|
33
|
+
|
|
34
|
+
// @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
|
|
35
|
+
// noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
|
|
36
|
+
usesSegments(): Promise<boolean> {
|
|
37
|
+
return Promise.resolve(true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Kill `name` definition and set `defaultTreatment` and `changeNumber`.
|
|
42
|
+
* Used for SPLIT_KILL push notifications.
|
|
43
|
+
*
|
|
44
|
+
* @returns a promise that is resolved once the definition kill operation is performed. The fulfillment value is a boolean: `true` if the operation succeeded updating the definition or `false` if no definition is updated,
|
|
45
|
+
* for instance, if the `changeNumber` is old, or if the definition is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
46
|
+
* The promise will never be rejected.
|
|
47
|
+
*/
|
|
48
|
+
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean> {
|
|
49
|
+
return this.get(name).then(definition => {
|
|
50
|
+
|
|
51
|
+
if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
|
|
52
|
+
const newDefinition = objectAssign({}, definition);
|
|
53
|
+
newDefinition.killed = true;
|
|
54
|
+
newDefinition.defaultTreatment = defaultTreatment;
|
|
55
|
+
newDefinition.changeNumber = changeNumber;
|
|
56
|
+
|
|
57
|
+
return this.add(newDefinition);
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}).catch(() => false);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { IDefinitionsCacheSync, IStorageSync } from './types';
|
|
2
|
+
import { IRBSegment, IDefinition } from '../dtos/types';
|
|
3
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
4
|
+
import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This class provides a skeletal implementation of the IDefinitionsCacheSync interface
|
|
8
|
+
* to minimize the effort required to implement this interface.
|
|
9
|
+
*/
|
|
10
|
+
export abstract class AbstractDefinitionsCacheSync implements IDefinitionsCacheSync {
|
|
11
|
+
|
|
12
|
+
protected abstract add(definition: IDefinition): boolean
|
|
13
|
+
protected abstract remove(name: string): boolean
|
|
14
|
+
protected abstract setChangeNumber(changeNumber: number): boolean | void
|
|
15
|
+
|
|
16
|
+
update(toAdd: IDefinition[], toRemove: string[], changeNumber: number): boolean {
|
|
17
|
+
let updated = toAdd.map(addedFF => this.add(addedFF)).some(result => result);
|
|
18
|
+
updated = toRemove.map(removedFF => this.remove(removedFF)).some(result => result) || updated;
|
|
19
|
+
this.setChangeNumber(changeNumber);
|
|
20
|
+
return updated;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
abstract get(name: string): IDefinition | null
|
|
24
|
+
|
|
25
|
+
getMany(names: string[]): Record<string, IDefinition | null> {
|
|
26
|
+
const definitions: Record<string, IDefinition | null> = {};
|
|
27
|
+
names.forEach(name => {
|
|
28
|
+
definitions[name] = this.get(name);
|
|
29
|
+
});
|
|
30
|
+
return definitions;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
abstract getChangeNumber(): number
|
|
34
|
+
|
|
35
|
+
getAll(): IDefinition[] {
|
|
36
|
+
return this.getNames().map(key => this.get(key) as IDefinition);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
abstract getNames(): string[]
|
|
40
|
+
|
|
41
|
+
abstract trafficTypeExists(trafficType: string): boolean
|
|
42
|
+
|
|
43
|
+
abstract usesSegments(): boolean
|
|
44
|
+
|
|
45
|
+
abstract clear(): void
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Kill `name` definition and set `defaultTreatment` and `changeNumber`.
|
|
49
|
+
* Used for SPLIT_KILL push notifications.
|
|
50
|
+
*
|
|
51
|
+
* @returns `true` if the operation successed updating the definition, or `false` if no definition is updated,
|
|
52
|
+
* for instance, if the `changeNumber` is old, or if the definition is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
53
|
+
*/
|
|
54
|
+
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean {
|
|
55
|
+
const definition = this.get(name);
|
|
56
|
+
|
|
57
|
+
if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
|
|
58
|
+
const newDefinition = objectAssign({}, definition);
|
|
59
|
+
newDefinition.killed = true;
|
|
60
|
+
newDefinition.defaultTreatment = defaultTreatment;
|
|
61
|
+
newDefinition.changeNumber = changeNumber;
|
|
62
|
+
|
|
63
|
+
return this.add(newDefinition);
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
abstract getNamesBySets(sets: string[]): Set<string>[]
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Given a parsed definition, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
|
|
74
|
+
* This util is intended to simplify the implementation of `definitionsCache::usesSegments` method
|
|
75
|
+
*/
|
|
76
|
+
export function usesSegments(ruleEntity: IDefinition | IRBSegment) {
|
|
77
|
+
const conditions = ruleEntity.conditions || [];
|
|
78
|
+
for (let i = 0; i < conditions.length; i++) {
|
|
79
|
+
const matchers = conditions[i].matcherGroup.matchers;
|
|
80
|
+
|
|
81
|
+
for (let j = 0; j < matchers.length; j++) {
|
|
82
|
+
const matcher = matchers[j].matcherType;
|
|
83
|
+
if (matcher === IN_SEGMENT || matcher === IN_LARGE_SEGMENT) return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const excluded = (ruleEntity as IRBSegment).excluded;
|
|
88
|
+
if (excluded && excluded.segments && excluded.segments.length > 0) return true;
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function usesSegmentsSync(storage: Pick<IStorageSync, 'definitions' | 'rbSegments'>) {
|
|
94
|
+
return storage.definitions.usesSegments() || storage.rbSegments.usesSegments();
|
|
95
|
+
}
|
|
@@ -21,19 +21,19 @@ export class KeyBuilder {
|
|
|
21
21
|
return `${this.prefix}.trafficType.${trafficType}`;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
return `${this.prefix}.flagSet.${
|
|
24
|
+
buildSetKey(set: string) {
|
|
25
|
+
return `${this.prefix}.flagSet.${set}`;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
return `${this.prefix}.split.${
|
|
28
|
+
buildDefinitionKey(definitionName: string) {
|
|
29
|
+
return `${this.prefix}.split.${definitionName}`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
buildDefinitionsTillKey() {
|
|
33
33
|
return `${this.prefix}.splits.till`;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
buildDefinitionKeyPrefix() {
|
|
37
37
|
return `${this.prefix}.split.`;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -9,13 +9,13 @@ export interface MySegmentsKeyBuilder {
|
|
|
9
9
|
|
|
10
10
|
export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
11
11
|
|
|
12
|
-
protected readonly
|
|
12
|
+
protected readonly regexDefinitionsCacheKey: RegExp;
|
|
13
13
|
protected readonly matchingKey: string;
|
|
14
14
|
|
|
15
15
|
constructor(prefix: string, matchingKey: string) {
|
|
16
16
|
super(prefix);
|
|
17
17
|
this.matchingKey = matchingKey;
|
|
18
|
-
this.
|
|
18
|
+
this.regexDefinitionsCacheKey = new RegExp(`^${prefix}\\.(splits?|trafficType|flagSet)\\.`);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -35,15 +35,15 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
35
35
|
return `${this.prefix}.splits.lastUpdated`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
return this.
|
|
38
|
+
isDefinitionsCacheKey(key: string) {
|
|
39
|
+
return this.regexDefinitionsCacheKey.test(key);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
buildTillKey() {
|
|
43
43
|
return `${this.prefix}.${this.matchingKey}.segments.till`;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
isDefinitionKey(key: string) {
|
|
47
47
|
return startsWith(key, `${this.prefix}.split.`);
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
51
51
|
return startsWith(key, `${this.prefix}.rbsegment.`);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
buildDefinitionsWithSegmentCountKey() {
|
|
55
55
|
return `${this.prefix}.splits.usingSegments`;
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -49,8 +49,8 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
49
49
|
return `${this.prefix}.events`;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
return `${this.
|
|
52
|
+
searchPatternForDefinitionKeys() {
|
|
53
|
+
return `${this.buildDefinitionKeyPrefix()}*`;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
searchPatternForRBSegmentKeys() {
|
|
@@ -12,16 +12,16 @@ import { IMembershipsResponse, IMySegmentsResponse } from '../dtos/types';
|
|
|
12
12
|
export function getRolloutPlan(log: ILogger, storage: IStorageSync, options: SplitIO.RolloutPlanOptions = {}): RolloutPlan {
|
|
13
13
|
|
|
14
14
|
const { keys, exposeSegments } = options;
|
|
15
|
-
const {
|
|
15
|
+
const { definitions, segments, rbSegments } = storage;
|
|
16
16
|
|
|
17
17
|
log.debug(`storage: get feature flags${keys ? `, and memberships for keys: ${keys}` : ''}${exposeSegments ? ', and segments' : ''}`);
|
|
18
18
|
|
|
19
19
|
return {
|
|
20
20
|
splitChanges: {
|
|
21
21
|
ff: {
|
|
22
|
-
t:
|
|
22
|
+
t: definitions.getChangeNumber(),
|
|
23
23
|
s: -1,
|
|
24
|
-
d:
|
|
24
|
+
d: definitions.getAll(),
|
|
25
25
|
},
|
|
26
26
|
rbs: {
|
|
27
27
|
t: rbSegments.getChangeNumber(),
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { IDefinition } from '../../dtos/types';
|
|
2
|
+
import { AbstractDefinitionsCacheSync, usesSegments } from '../AbstractDefinitionsCacheSync';
|
|
3
|
+
import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
4
|
+
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
5
|
+
import { ILogger } from '../../logger/types';
|
|
6
|
+
import { LOG_PREFIX } from './constants';
|
|
7
|
+
import { ISettings } from '../../types';
|
|
8
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
9
|
+
import { StorageAdapter } from '../types';
|
|
10
|
+
|
|
11
|
+
export class DefinitionsCacheInLocal extends AbstractDefinitionsCacheSync {
|
|
12
|
+
|
|
13
|
+
private readonly keys: KeyBuilderCS;
|
|
14
|
+
private readonly log: ILogger;
|
|
15
|
+
private readonly setsFilter: string[];
|
|
16
|
+
private hasSync?: boolean;
|
|
17
|
+
private readonly storage: StorageAdapter;
|
|
18
|
+
|
|
19
|
+
constructor(settings: ISettings, keys: KeyBuilderCS, storage: StorageAdapter) {
|
|
20
|
+
super();
|
|
21
|
+
this.keys = keys;
|
|
22
|
+
this.log = settings.log;
|
|
23
|
+
this.setsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
|
|
24
|
+
this.storage = storage;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private _decrementCount(key: string) {
|
|
28
|
+
const count = toNumber(this.storage.getItem(key)) - 1;
|
|
29
|
+
if (count > 0) this.storage.setItem(key, count + '');
|
|
30
|
+
else this.storage.removeItem(key);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private _decrementCounts(definition: IDefinition) {
|
|
34
|
+
try {
|
|
35
|
+
const ttKey = this.keys.buildTrafficTypeKey(definition.trafficTypeName);
|
|
36
|
+
this._decrementCount(ttKey);
|
|
37
|
+
|
|
38
|
+
if (usesSegments(definition)) {
|
|
39
|
+
const segmentsCountKey = this.keys.buildDefinitionsWithSegmentCountKey();
|
|
40
|
+
this._decrementCount(segmentsCountKey);
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
this.log.error(LOG_PREFIX + e);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private _incrementCounts(definition: IDefinition) {
|
|
48
|
+
try {
|
|
49
|
+
const ttKey = this.keys.buildTrafficTypeKey(definition.trafficTypeName);
|
|
50
|
+
this.storage.setItem(ttKey, (toNumber(this.storage.getItem(ttKey)) + 1) + '');
|
|
51
|
+
|
|
52
|
+
if (usesSegments(definition)) {
|
|
53
|
+
const segmentsCountKey = this.keys.buildDefinitionsWithSegmentCountKey();
|
|
54
|
+
this.storage.setItem(segmentsCountKey, (toNumber(this.storage.getItem(segmentsCountKey)) + 1) + '');
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
this.log.error(LOG_PREFIX + e);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Removes all definitions related data from localStorage (splits, counters, changeNumber and lastUpdated).
|
|
64
|
+
* We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
|
|
65
|
+
*/
|
|
66
|
+
clear() {
|
|
67
|
+
// collect item keys
|
|
68
|
+
const len = this.storage.length;
|
|
69
|
+
const accum = [];
|
|
70
|
+
for (let cur = 0; cur < len; cur++) {
|
|
71
|
+
const key = this.storage.key(cur);
|
|
72
|
+
if (key != null && this.keys.isDefinitionsCacheKey(key)) accum.push(key);
|
|
73
|
+
}
|
|
74
|
+
// remove items
|
|
75
|
+
accum.forEach(key => {
|
|
76
|
+
this.storage.removeItem(key);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
this.hasSync = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
add(definition: IDefinition) {
|
|
83
|
+
const name = definition.name;
|
|
84
|
+
const definitionKey = this.keys.buildDefinitionKey(name);
|
|
85
|
+
const definitionFromStorage = this.storage.getItem(definitionKey);
|
|
86
|
+
const previousDefinition = definitionFromStorage ? JSON.parse(definitionFromStorage) : null;
|
|
87
|
+
|
|
88
|
+
if (previousDefinition) {
|
|
89
|
+
this._decrementCounts(previousDefinition);
|
|
90
|
+
this.removeFromSets(previousDefinition.name, previousDefinition.sets);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.storage.setItem(definitionKey, JSON.stringify(definition));
|
|
94
|
+
|
|
95
|
+
this._incrementCounts(definition);
|
|
96
|
+
this.addToSets(definition);
|
|
97
|
+
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
remove(name: string): boolean {
|
|
102
|
+
const definition = this.get(name);
|
|
103
|
+
if (!definition) return false;
|
|
104
|
+
|
|
105
|
+
this.storage.removeItem(this.keys.buildDefinitionKey(name));
|
|
106
|
+
|
|
107
|
+
this._decrementCounts(definition);
|
|
108
|
+
this.removeFromSets(definition.name, definition.sets);
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get(name: string): IDefinition | null {
|
|
114
|
+
const item = this.storage.getItem(this.keys.buildDefinitionKey(name));
|
|
115
|
+
return item && JSON.parse(item);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
setChangeNumber(changeNumber: number): boolean {
|
|
119
|
+
try {
|
|
120
|
+
this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
121
|
+
// update "last updated" timestamp with current time
|
|
122
|
+
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
123
|
+
this.hasSync = true;
|
|
124
|
+
return true;
|
|
125
|
+
} catch (e) {
|
|
126
|
+
this.log.error(LOG_PREFIX + e);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getChangeNumber(): number {
|
|
132
|
+
const n = -1;
|
|
133
|
+
let value: string | number | null = this.storage.getItem(this.keys.buildDefinitionsTillKey());
|
|
134
|
+
|
|
135
|
+
if (value !== null) {
|
|
136
|
+
value = parseInt(value, 10);
|
|
137
|
+
|
|
138
|
+
return isNaNNumber(value) ? n : value;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return n;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
getNames(): string[] {
|
|
145
|
+
const len = this.storage.length;
|
|
146
|
+
const accum = [];
|
|
147
|
+
|
|
148
|
+
let cur = 0;
|
|
149
|
+
|
|
150
|
+
while (cur < len) {
|
|
151
|
+
const key = this.storage.key(cur);
|
|
152
|
+
|
|
153
|
+
if (key != null && this.keys.isDefinitionKey(key)) accum.push(this.keys.extractKey(key));
|
|
154
|
+
|
|
155
|
+
cur++;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return accum;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
trafficTypeExists(trafficType: string): boolean {
|
|
162
|
+
const ttCount = toNumber(this.storage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
|
|
163
|
+
return isFiniteNumber(ttCount) && ttCount > 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
usesSegments() {
|
|
167
|
+
// If cache hasn't been synchronized with the cloud, assume we need them.
|
|
168
|
+
if (!this.hasSync) return true;
|
|
169
|
+
|
|
170
|
+
const storedCount = this.storage.getItem(this.keys.buildDefinitionsWithSegmentCountKey());
|
|
171
|
+
const definitionsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
|
|
172
|
+
|
|
173
|
+
return isFiniteNumber(definitionsWithSegmentsCount) ?
|
|
174
|
+
definitionsWithSegmentsCount > 0 :
|
|
175
|
+
true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
getNamesBySets(sets: string[]): Set<string>[] {
|
|
179
|
+
return sets.map(set => {
|
|
180
|
+
const setKey = this.keys.buildSetKey(set);
|
|
181
|
+
const setFromStorage = this.storage.getItem(setKey);
|
|
182
|
+
|
|
183
|
+
return new Set(setFromStorage ? JSON.parse(setFromStorage) : []);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private addToSets(definition: IDefinition) {
|
|
188
|
+
if (!definition.sets) return;
|
|
189
|
+
|
|
190
|
+
definition.sets.forEach(set => {
|
|
191
|
+
|
|
192
|
+
if (this.setsFilter.length > 0 && !this.setsFilter.some(filterSet => filterSet === set)) return;
|
|
193
|
+
|
|
194
|
+
const setKey = this.keys.buildSetKey(set);
|
|
195
|
+
|
|
196
|
+
const setFromStorage = this.storage.getItem(setKey);
|
|
197
|
+
|
|
198
|
+
const setCache = new Set(setFromStorage ? JSON.parse(setFromStorage) : []);
|
|
199
|
+
|
|
200
|
+
if (setCache.has(definition.name)) return;
|
|
201
|
+
|
|
202
|
+
setCache.add(definition.name);
|
|
203
|
+
|
|
204
|
+
this.storage.setItem(setKey, JSON.stringify(setToArray(setCache)));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private removeFromSets(definitionName: string, sets?: string[] | null) {
|
|
209
|
+
if (!sets) return;
|
|
210
|
+
|
|
211
|
+
sets.forEach(set => {
|
|
212
|
+
this.removeNames(set, definitionName);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private removeNames(setName: string, definitionName: string) {
|
|
217
|
+
const setKey = this.keys.buildSetKey(setName);
|
|
218
|
+
|
|
219
|
+
const setFromStorage = this.storage.getItem(setKey);
|
|
220
|
+
|
|
221
|
+
if (!setFromStorage) return;
|
|
222
|
+
|
|
223
|
+
const setCache = new Set(JSON.parse(setFromStorage));
|
|
224
|
+
setCache.delete(definitionName);
|
|
225
|
+
|
|
226
|
+
if (setCache.size === 0) {
|
|
227
|
+
this.storage.removeItem(setKey);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
this.storage.setItem(setKey, JSON.stringify(setToArray(setCache)));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
}
|
|
@@ -3,7 +3,7 @@ import { ILogger } from '../../logger/types';
|
|
|
3
3
|
import { ISettings } from '../../types';
|
|
4
4
|
import { isFiniteNumber, isNaNNumber, toNumber } from '../../utils/lang';
|
|
5
5
|
import { setToArray } from '../../utils/lang/sets';
|
|
6
|
-
import { usesSegments } from '../
|
|
6
|
+
import { usesSegments } from '../AbstractDefinitionsCacheSync';
|
|
7
7
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
8
8
|
import { IRBSegmentsCacheSync, StorageAdapter } from '../types';
|
|
9
9
|
import { LOG_PREFIX } from './constants';
|
|
@@ -25,9 +25,9 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
|
|
|
25
25
|
this.storage.removeItem(this.keys.buildRBSegmentsTillKey());
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
update(toAdd: IRBSegment[], toRemove:
|
|
28
|
+
update(toAdd: IRBSegment[], toRemove: string[], changeNumber: number): boolean {
|
|
29
29
|
let updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
|
|
30
|
-
updated = toRemove.map(toRemove => this.remove(toRemove
|
|
30
|
+
updated = toRemove.map(toRemove => this.remove(toRemove)).some(result => result) || updated;
|
|
31
31
|
this.setChangeNumber(changeNumber);
|
|
32
32
|
return updated;
|
|
33
33
|
}
|
|
@@ -42,7 +42,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
private updateSegmentCount(diff: number) {
|
|
45
|
-
const segmentsCountKey = this.keys.
|
|
45
|
+
const segmentsCountKey = this.keys.buildDefinitionsWithSegmentCountKey();
|
|
46
46
|
const count = toNumber(this.storage.getItem(segmentsCountKey)) + diff;
|
|
47
47
|
if (count > 0) this.storage.setItem(segmentsCountKey, count + '');
|
|
48
48
|
else this.storage.removeItem(segmentsCountKey);
|
|
@@ -121,11 +121,11 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
usesSegments(): boolean {
|
|
124
|
-
const storedCount = this.storage.getItem(this.keys.
|
|
125
|
-
const
|
|
124
|
+
const storedCount = this.storage.getItem(this.keys.buildDefinitionsWithSegmentCountKey());
|
|
125
|
+
const definitionsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
|
|
126
126
|
|
|
127
|
-
return isFiniteNumber(
|
|
128
|
-
|
|
127
|
+
return isFiniteNumber(definitionsWithSegmentsCount) ?
|
|
128
|
+
definitionsWithSegmentsCount > 0 :
|
|
129
129
|
true;
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -5,7 +5,7 @@ import { IStorageFactoryParams, IStorageSync, IStorageSyncFactory, StorageAdapte
|
|
|
5
5
|
import { validatePrefix } from '../KeyBuilder';
|
|
6
6
|
import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
|
|
7
7
|
import { isLocalStorageAvailable, isValidStorageWrapper, isWebStorage } from '../../utils/env/isLocalStorageAvailable';
|
|
8
|
-
import {
|
|
8
|
+
import { DefinitionsCacheInLocal } from './DefinitionsCacheInLocal';
|
|
9
9
|
import { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
|
|
10
10
|
import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
11
11
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
@@ -50,26 +50,26 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
50
50
|
const matchingKey = getMatching(settings.core.key);
|
|
51
51
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
52
52
|
|
|
53
|
-
const
|
|
53
|
+
const definitions = new DefinitionsCacheInLocal(settings, keys, storage);
|
|
54
54
|
const rbSegments = new RBSegmentsCacheInLocal(settings, keys, storage);
|
|
55
55
|
const segments = new MySegmentsCacheInLocal(log, keys, storage);
|
|
56
56
|
const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey), storage);
|
|
57
57
|
let validateCachePromise: Promise<SplitIO.SdkReadyMetadata> | undefined;
|
|
58
58
|
|
|
59
59
|
return {
|
|
60
|
-
|
|
60
|
+
definitions,
|
|
61
61
|
rbSegments,
|
|
62
62
|
segments,
|
|
63
63
|
largeSegments,
|
|
64
64
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
65
65
|
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
66
66
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
67
|
-
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(
|
|
67
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(definitions, segments) : undefined,
|
|
68
68
|
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
69
69
|
|
|
70
70
|
validateCache() {
|
|
71
71
|
if (!validateCachePromise) {
|
|
72
|
-
validateCachePromise = validateCache(options, storage, settings, keys,
|
|
72
|
+
validateCachePromise = validateCache(options, storage, settings, keys, definitions, rbSegments, segments, largeSegments);
|
|
73
73
|
}
|
|
74
74
|
return validateCachePromise;
|
|
75
75
|
},
|
|
@@ -86,7 +86,7 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
86
86
|
shared(matchingKey: string) {
|
|
87
87
|
|
|
88
88
|
return {
|
|
89
|
-
|
|
89
|
+
definitions: this.definitions,
|
|
90
90
|
rbSegments: this.rbSegments,
|
|
91
91
|
segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey), storage),
|
|
92
92
|
largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey), storage),
|
|
@@ -2,7 +2,7 @@ import { ISettings } from '../../types';
|
|
|
2
2
|
import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
3
3
|
import { getStorageHash } from '../KeyBuilder';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
|
-
import type {
|
|
5
|
+
import type { DefinitionsCacheInLocal } from './DefinitionsCacheInLocal';
|
|
6
6
|
import type { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
|
|
7
7
|
import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
8
8
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
@@ -68,11 +68,11 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, storage: Sto
|
|
|
68
68
|
*
|
|
69
69
|
* @returns Metadata object with `initialCacheLoad` (true if is fresh install, false if is ready from cache) and `lastUpdateTimestamp` (timestamp of last cache update or undefined)
|
|
70
70
|
*/
|
|
71
|
-
export function validateCache(options: SplitIO.InLocalStorageOptions, storage: StorageAdapter, settings: ISettings, keys: KeyBuilderCS,
|
|
71
|
+
export function validateCache(options: SplitIO.InLocalStorageOptions, storage: StorageAdapter, settings: ISettings, keys: KeyBuilderCS, definitions: DefinitionsCacheInLocal, rbSegments: RBSegmentsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): Promise<SplitIO.SdkReadyMetadata> {
|
|
72
72
|
|
|
73
73
|
return Promise.resolve(storage.load && storage.load()).then(() => {
|
|
74
74
|
const currentTimestamp = Date.now();
|
|
75
|
-
const isThereCache =
|
|
75
|
+
const isThereCache = definitions.getChangeNumber() > -1;
|
|
76
76
|
|
|
77
77
|
// Get lastUpdateTimestamp from storage
|
|
78
78
|
const lastUpdatedTimestampStr = storage.getItem(keys.buildLastUpdatedKey());
|
|
@@ -80,7 +80,7 @@ export function validateCache(options: SplitIO.InLocalStorageOptions, storage: S
|
|
|
80
80
|
const lastUpdateTimestamp = (!isNaNNumber(lastUpdatedTimestamp) && lastUpdatedTimestamp !== undefined) ? lastUpdatedTimestamp : undefined;
|
|
81
81
|
|
|
82
82
|
if (validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache)) {
|
|
83
|
-
|
|
83
|
+
definitions.clear();
|
|
84
84
|
rbSegments.clear();
|
|
85
85
|
segments.clear();
|
|
86
86
|
largeSegments.clear();
|