@splitsoftware/splitio-commons 1.2.1-rc.0 → 1.2.1-rc.11
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/cjs/evaluator/Engine.js +6 -6
- package/cjs/evaluator/combiners/and.js +1 -1
- package/cjs/evaluator/combiners/ifelseif.js +2 -2
- package/cjs/evaluator/condition/engineUtils.js +2 -2
- package/cjs/evaluator/condition/index.js +4 -4
- package/cjs/evaluator/index.js +5 -5
- package/cjs/evaluator/matchers/cont_all.js +1 -1
- package/cjs/evaluator/matchers/cont_any.js +1 -1
- package/cjs/evaluator/matchers/cont_str.js +1 -1
- package/cjs/evaluator/matchers/dependency.js +1 -1
- package/cjs/evaluator/matchers/eq_set.js +1 -1
- package/cjs/evaluator/matchers/ew.js +3 -3
- package/cjs/evaluator/matchers/part_of.js +1 -1
- package/cjs/evaluator/matchers/segment.js +1 -1
- package/cjs/evaluator/matchers/sw.js +1 -1
- package/cjs/evaluator/matchers/whitelist.js +1 -1
- package/cjs/evaluator/matchersTransform/index.js +12 -12
- package/cjs/evaluator/parser/index.js +6 -6
- package/cjs/evaluator/treatments/index.js +1 -1
- package/cjs/evaluator/value/index.js +1 -1
- package/cjs/evaluator/value/sanitize.js +4 -4
- package/cjs/integrations/browser.js +3 -3
- package/cjs/integrations/ga/GaToSplit.js +14 -14
- package/cjs/integrations/ga/GoogleAnalyticsToSplit.js +5 -3
- package/cjs/integrations/ga/SplitToGa.js +1 -1
- package/cjs/integrations/ga/SplitToGoogleAnalytics.js +4 -2
- package/cjs/listeners/browser.js +15 -11
- package/cjs/listeners/node.js +1 -1
- package/cjs/logger/constants.js +9 -3
- package/cjs/logger/index.js +2 -2
- package/cjs/logger/messages/debug.js +4 -4
- package/cjs/logger/messages/error.js +5 -4
- package/cjs/logger/messages/info.js +8 -5
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/logger/sdkLogger.js +1 -1
- package/cjs/readiness/readinessManager.js +2 -2
- package/cjs/readiness/sdkReadinessManager.js +4 -4
- package/cjs/sdkClient/client.js +12 -11
- package/cjs/sdkClient/clientAttributesDecoration.js +4 -4
- package/cjs/sdkClient/clientCS.js +3 -3
- package/cjs/sdkClient/clientInputValidation.js +20 -22
- package/cjs/sdkClient/sdkClient.js +3 -6
- package/cjs/sdkClient/sdkClientMethod.js +1 -1
- package/cjs/sdkClient/sdkClientMethodCS.js +6 -10
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +7 -15
- package/cjs/sdkFactory/index.js +14 -12
- package/cjs/sdkFactory/userConsentProps.js +40 -0
- package/cjs/sdkManager/index.js +11 -11
- package/cjs/services/splitApi.js +3 -2
- package/cjs/services/splitHttpClient.js +2 -2
- package/cjs/storages/KeyBuilder.js +2 -6
- package/cjs/storages/KeyBuilderCS.js +13 -3
- package/cjs/storages/KeyBuilderSS.js +1 -1
- package/cjs/storages/findLatencyIndex.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +24 -4
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +12 -12
- package/cjs/storages/inLocalStorage/index.js +4 -4
- package/cjs/storages/inMemory/AttributesCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/ImpressionsCacheInMemory.js +15 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +1 -1
- package/cjs/storages/inMemory/InMemoryStorageCS.js +1 -1
- package/cjs/storages/inMemory/LatenciesCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +2 -2
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +5 -5
- package/cjs/storages/inRedis/LatenciesCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/RedisAdapter.js +24 -11
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +3 -3
- package/cjs/storages/inRedis/index.js +1 -1
- package/cjs/storages/pluggable/SegmentsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/SplitsCachePluggable.js +3 -3
- package/cjs/storages/pluggable/inMemoryWrapper.js +4 -4
- package/cjs/storages/pluggable/index.js +6 -6
- package/cjs/sync/offline/LocalhostFromFile.js +1 -1
- package/cjs/sync/offline/LocalhostFromObject.js +1 -1
- package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
- package/cjs/sync/offline/splitsParser/splitsParserFromFile.js +13 -13
- package/cjs/sync/offline/splitsParser/splitsParserFromSettings.js +3 -3
- package/cjs/sync/offline/syncManagerOffline.js +1 -1
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -2
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +2 -2
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +8 -7
- package/cjs/sync/polling/pollingManagerSS.js +5 -4
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +1 -1
- package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -3
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +2 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -2
- package/cjs/sync/streaming/AuthClient/index.js +3 -3
- package/cjs/sync/streaming/SSEClient/index.js +2 -1
- package/cjs/sync/streaming/SSEHandler/NotificationParser.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +3 -3
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +1 -1
- package/cjs/sync/streaming/mySegmentsV2utils.js +1 -1
- package/cjs/sync/streaming/pushManager.js +27 -19
- package/cjs/sync/submitters/eventsSyncTask.js +17 -5
- package/cjs/sync/submitters/impressionCountsSyncTask.js +1 -1
- package/cjs/sync/submitters/impressionsSyncTask.js +15 -3
- package/cjs/sync/submitters/metricsSyncTask.js +3 -3
- package/cjs/sync/submitters/submitterManager.js +6 -5
- package/cjs/sync/submitters/submitterSyncTask.js +1 -1
- package/cjs/sync/syncManagerOnline.js +14 -15
- package/cjs/trackers/eventTracker.js +11 -4
- package/cjs/trackers/impressionObserver/impressionObserverCS.js +1 -1
- package/cjs/trackers/impressionObserver/impressionObserverSS.js +1 -1
- package/cjs/trackers/impressionObserver/utils.js +8 -1
- package/cjs/trackers/impressionsTracker.js +9 -8
- package/cjs/utils/MinEvents.js +2 -1
- package/cjs/utils/consent.js +10 -0
- package/cjs/utils/constants/index.js +5 -1
- package/cjs/utils/inputValidation/apiKey.js +1 -1
- package/cjs/utils/inputValidation/attribute.js +4 -4
- package/cjs/utils/inputValidation/attributes.js +2 -2
- package/cjs/utils/inputValidation/event.js +1 -1
- package/cjs/utils/inputValidation/eventProperties.js +7 -5
- package/cjs/utils/inputValidation/eventValue.js +1 -1
- package/cjs/utils/inputValidation/key.js +6 -5
- package/cjs/utils/inputValidation/preloadedData.js +8 -8
- package/cjs/utils/inputValidation/split.js +1 -1
- package/cjs/utils/inputValidation/splits.js +2 -2
- package/cjs/utils/inputValidation/trafficType.js +1 -1
- package/cjs/utils/inputValidation/trafficTypeExistance.js +1 -1
- package/cjs/utils/jwt/index.js +1 -1
- package/cjs/utils/key/index.js +3 -3
- package/cjs/utils/lang/index.js +13 -16
- package/cjs/utils/lang/maps.js +16 -2
- package/cjs/utils/murmur3/common.js +1 -1
- package/cjs/utils/murmur3/murmur3.js +10 -10
- package/cjs/utils/murmur3/murmur3_128.js +1 -1
- package/cjs/utils/murmur3/murmur3_128_x86.js +37 -37
- package/cjs/utils/murmur3/murmur3_64.js +1 -1
- package/cjs/utils/settingsValidation/consent.js +16 -0
- package/cjs/utils/settingsValidation/impressionsMode.js +6 -6
- package/cjs/utils/settingsValidation/index.js +32 -14
- package/cjs/utils/settingsValidation/integrations/configurable.js +1 -1
- package/cjs/utils/settingsValidation/integrations/pluggable.js +1 -1
- package/cjs/utils/settingsValidation/localhost/builtin.js +2 -2
- package/cjs/utils/settingsValidation/logger/builtinLogger.js +3 -3
- package/cjs/utils/settingsValidation/logger/commons.js +1 -1
- package/cjs/utils/settingsValidation/logger/pluggableLogger.js +1 -1
- package/cjs/utils/settingsValidation/runtime.js +11 -0
- package/cjs/utils/settingsValidation/splitFilters.js +1 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/cjs/utils/timeTracker/index.js +3 -3
- package/esm/evaluator/matchers/ew.js +4 -4
- package/esm/integrations/ga/GoogleAnalyticsToSplit.js +4 -2
- package/esm/integrations/ga/SplitToGoogleAnalytics.js +4 -2
- package/esm/listeners/browser.js +14 -10
- package/esm/logger/constants.js +6 -2
- package/esm/logger/messages/debug.js +3 -3
- package/esm/logger/messages/error.js +4 -3
- package/esm/logger/messages/info.js +7 -4
- package/esm/sdkClient/client.js +3 -2
- package/esm/sdkClient/clientCS.js +1 -1
- package/esm/sdkClient/clientInputValidation.js +6 -8
- package/esm/sdkClient/sdkClient.js +1 -4
- package/esm/sdkClient/sdkClientMethodCS.js +1 -5
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +1 -9
- package/esm/sdkFactory/index.js +8 -6
- package/esm/sdkFactory/userConsentProps.js +36 -0
- package/esm/services/splitApi.js +2 -1
- package/esm/storages/KeyBuilder.js +2 -6
- package/esm/storages/KeyBuilderCS.js +11 -1
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +23 -3
- package/esm/storages/inLocalStorage/index.js +1 -1
- package/esm/storages/inMemory/ImpressionsCacheInMemory.js +15 -1
- package/esm/storages/inMemory/InMemoryStorage.js +1 -1
- package/esm/storages/inMemory/InMemoryStorageCS.js +1 -1
- package/esm/storages/inRedis/RedisAdapter.js +15 -2
- package/esm/storages/pluggable/index.js +2 -2
- package/esm/sync/offline/splitsParser/splitsParserFromFile.js +1 -1
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +2 -2
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +2 -2
- package/esm/sync/polling/pollingManagerCS.js +2 -1
- package/esm/sync/polling/pollingManagerSS.js +2 -1
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/streaming/SSEClient/index.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +1 -1
- package/esm/sync/streaming/pushManager.js +13 -5
- package/esm/sync/submitters/eventsSyncTask.js +18 -6
- package/esm/sync/submitters/impressionsSyncTask.js +13 -1
- package/esm/sync/submitters/submitterManager.js +2 -1
- package/esm/sync/syncManagerOnline.js +14 -15
- package/esm/trackers/eventTracker.js +8 -1
- package/esm/trackers/impressionObserver/utils.js +7 -1
- package/esm/trackers/impressionsTracker.js +6 -5
- package/esm/utils/consent.js +6 -0
- package/esm/utils/constants/index.js +4 -0
- package/esm/utils/inputValidation/attributes.js +1 -1
- package/esm/utils/inputValidation/eventProperties.js +4 -2
- package/esm/utils/inputValidation/key.js +2 -1
- package/esm/utils/lang/index.js +12 -15
- package/esm/utils/lang/maps.js +14 -1
- package/esm/utils/settingsValidation/consent.js +12 -0
- package/esm/utils/settingsValidation/impressionsMode.js +7 -7
- package/esm/utils/settingsValidation/index.js +28 -10
- package/esm/utils/settingsValidation/runtime.js +7 -0
- package/package.json +6 -6
- package/src/evaluator/matchers/ew.ts +4 -4
- package/src/evaluator/parser/index.ts +1 -1
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +2 -2
- package/src/integrations/ga/GoogleAnalyticsToSplit.ts +7 -4
- package/src/integrations/ga/SplitToGoogleAnalytics.ts +7 -4
- package/src/integrations/pluggable.ts +2 -2
- package/src/integrations/types.ts +5 -0
- package/src/listeners/browser.ts +13 -9
- package/src/logger/constants.ts +6 -2
- package/src/logger/messages/debug.ts +3 -3
- package/src/logger/messages/error.ts +4 -3
- package/src/logger/messages/info.ts +7 -4
- package/src/logger/types.ts +4 -0
- package/src/sdkClient/client.ts +3 -2
- package/src/sdkClient/clientCS.ts +1 -1
- package/src/sdkClient/clientInputValidation.ts +8 -7
- package/src/sdkClient/sdkClient.ts +2 -5
- package/src/sdkClient/sdkClientMethodCS.ts +1 -6
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +2 -11
- package/src/sdkFactory/index.ts +9 -7
- package/src/sdkFactory/types.ts +2 -1
- package/src/sdkFactory/userConsentProps.ts +42 -0
- package/src/storages/KeyBuilder.ts +2 -6
- package/src/storages/KeyBuilderCS.ts +13 -1
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +23 -3
- package/src/storages/inLocalStorage/index.ts +1 -1
- package/src/storages/inMemory/ImpressionsCacheInMemory.ts +22 -1
- package/src/storages/inMemory/InMemoryStorage.ts +1 -1
- package/src/storages/inMemory/InMemoryStorageCS.ts +1 -1
- package/src/storages/inRedis/RedisAdapter.ts +8 -2
- package/src/storages/pluggable/index.ts +2 -2
- package/src/storages/types.ts +6 -2
- package/src/sync/offline/splitsParser/splitsParserFromFile.ts +1 -1
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +2 -1
- package/src/sync/polling/fetchers/types.ts +1 -0
- package/src/sync/polling/pollingManagerCS.ts +3 -6
- package/src/sync/polling/pollingManagerSS.ts +3 -8
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +2 -1
- package/src/sync/polling/types.ts +0 -12
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -1
- package/src/sync/streaming/SSEClient/index.ts +2 -1
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +1 -1
- package/src/sync/streaming/pushManager.ts +19 -16
- package/src/sync/streaming/types.ts +5 -25
- package/src/sync/submitters/eventsSyncTask.ts +19 -6
- package/src/sync/submitters/impressionsSyncTask.ts +16 -1
- package/src/sync/submitters/submitterManager.ts +4 -8
- package/src/sync/syncManagerOnline.ts +20 -24
- package/src/sync/types.ts +4 -1
- package/src/trackers/eventTracker.ts +11 -3
- package/src/trackers/impressionObserver/utils.ts +8 -1
- package/src/trackers/impressionsTracker.ts +7 -8
- package/src/types.ts +22 -1
- package/src/utils/consent.ts +8 -0
- package/src/utils/constants/index.ts +5 -0
- package/src/utils/inputValidation/attributes.ts +1 -2
- package/src/utils/inputValidation/eventProperties.ts +4 -2
- package/src/utils/lang/index.ts +15 -18
- package/src/utils/lang/maps.ts +15 -1
- package/src/utils/settingsValidation/consent.ts +16 -0
- package/src/utils/settingsValidation/impressionsMode.ts +8 -8
- package/src/utils/settingsValidation/index.ts +29 -10
- package/src/utils/settingsValidation/runtime.ts +9 -0
- package/src/utils/settingsValidation/types.ts +12 -6
- package/types/evaluator/types.d.ts +2 -2
- package/types/evaluator/value/index.d.ts +1 -1
- package/types/evaluator/value/sanitize.d.ts +1 -1
- package/types/integrations/ga/GoogleAnalyticsToSplit.d.ts +2 -2
- package/types/integrations/ga/SplitToGoogleAnalytics.d.ts +2 -3
- package/types/integrations/types.d.ts +4 -0
- package/types/logger/constants.d.ts +6 -2
- package/types/logger/types.d.ts +4 -0
- package/types/sdkClient/clientAttributesDecoration.d.ts +1 -1
- package/types/sdkClient/clientInputValidation.d.ts +2 -3
- package/types/sdkFactory/types.d.ts +1 -1
- package/types/sdkFactory/userConsentProps.d.ts +6 -0
- package/types/storages/KeyBuilderCS.d.ts +2 -0
- package/types/storages/inMemory/ImpressionsCacheInMemory.d.ts +9 -0
- package/types/storages/inMemory/index.d.ts +10 -0
- package/types/storages/inRedis/RedisAdapter.d.ts +1 -1
- package/types/storages/parseSegments.d.ts +6 -0
- package/types/storages/types.d.ts +3 -1
- package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +1 -1
- package/types/sync/polling/fetchers/types.d.ts +1 -1
- package/types/sync/polling/pollingManagerCS.d.ts +2 -5
- package/types/sync/polling/pollingManagerSS.d.ts +2 -5
- package/types/sync/polling/types.d.ts +0 -11
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +1 -1
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -1
- package/types/sync/streaming/pushManager.d.ts +3 -7
- package/types/sync/streaming/pushManagerCS.d.ts +1 -12
- package/types/sync/streaming/pushManagerSS.d.ts +1 -11
- package/types/sync/streaming/types.d.ts +3 -23
- package/types/sync/submitters/submitterManager.d.ts +2 -4
- package/types/sync/syncManagerOnline.d.ts +3 -3
- package/types/sync/types.d.ts +3 -0
- package/types/trackers/eventTracker.d.ts +2 -2
- package/types/trackers/impressionObserver/utils.d.ts +4 -0
- package/types/trackers/impressionsTracker.d.ts +2 -3
- package/types/types.d.ts +22 -1
- package/types/utils/consent.d.ts +2 -0
- package/types/utils/constants/index.d.ts +3 -0
- package/types/utils/lang/index.d.ts +6 -5
- package/types/utils/lang/maps.d.ts +7 -0
- package/types/utils/settingsValidation/consent.d.ts +6 -0
- package/types/utils/settingsValidation/impressionsMode.d.ts +1 -1
- package/types/utils/settingsValidation/runtime/browser.d.ts +2 -0
- package/types/utils/settingsValidation/runtime/node.d.ts +2 -0
- package/types/utils/settingsValidation/runtime.d.ts +2 -0
- package/types/utils/settingsValidation/types.d.ts +12 -6
- package/types/utils/settingsValidation/userConsent.d.ts +5 -0
|
@@ -29,10 +29,10 @@ export function pluggableIntegrationsManagerFactory(
|
|
|
29
29
|
|
|
30
30
|
// Exception safe methods: each integration module is responsable for handling errors
|
|
31
31
|
return {
|
|
32
|
-
handleImpression
|
|
32
|
+
handleImpression(impressionData: SplitIO.ImpressionData) {
|
|
33
33
|
listeners.forEach(listener => listener.queue({ type: SPLIT_IMPRESSION, payload: impressionData }));
|
|
34
34
|
},
|
|
35
|
-
handleEvent
|
|
35
|
+
handleEvent(eventData: SplitIO.EventData) {
|
|
36
36
|
listeners.forEach(listener => listener.queue({ type: SPLIT_EVENT, payload: eventData }));
|
|
37
37
|
}
|
|
38
38
|
};
|
package/src/listeners/browser.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { OPTIMIZED, DEBUG } from '../utils/constants';
|
|
|
11
11
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
12
12
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
13
13
|
import { ISyncManager } from '../sync/types';
|
|
14
|
+
import { isConsentGranted } from '../utils/consent';
|
|
14
15
|
|
|
15
16
|
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
16
17
|
const UNLOAD_DOM_EVENT = 'unload';
|
|
@@ -65,15 +66,18 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
65
66
|
flushData() {
|
|
66
67
|
if (!this.syncManager) return; // In consumer mode there is not sync manager and data to flush
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
// Flush data if there is user consent
|
|
70
|
+
if (isConsentGranted(this.settings)) {
|
|
71
|
+
const eventsUrl = this.settings.urls.events;
|
|
72
|
+
const extraMetadata = {
|
|
73
|
+
// sim stands for Sync/Split Impressions Mode
|
|
74
|
+
sim: this.settings.sync.impressionsMode === OPTIMIZED ? OPTIMIZED : DEBUG
|
|
75
|
+
};
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
this._flushData(eventsUrl + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
|
|
78
|
+
this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
|
|
79
|
+
if (this.storage.impressionCounts) this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
|
|
80
|
+
}
|
|
77
81
|
|
|
78
82
|
// Close streaming connection
|
|
79
83
|
if (this.syncManager.pushManager) this.syncManager.pushManager.stop();
|
|
@@ -84,7 +88,7 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
84
88
|
if (!cache.isEmpty()) {
|
|
85
89
|
const dataPayload = fromCacheToPayload ? fromCacheToPayload(cache.state()) : cache.state();
|
|
86
90
|
if (!this._sendBeacon(url, dataPayload, extraMetadata)) {
|
|
87
|
-
postService(JSON.stringify(dataPayload)).catch(() => { }); // no-op just to catch a possible
|
|
91
|
+
postService(JSON.stringify(dataPayload)).catch(() => { }); // no-op just to catch a possible exception
|
|
88
92
|
}
|
|
89
93
|
cache.clear();
|
|
90
94
|
}
|
package/src/logger/constants.ts
CHANGED
|
@@ -61,13 +61,16 @@ export const STREAMING_RECONNECT = 111;
|
|
|
61
61
|
export const STREAMING_CONNECTING = 112;
|
|
62
62
|
export const STREAMING_DISABLED = 113;
|
|
63
63
|
export const STREAMING_DISCONNECTING = 114;
|
|
64
|
-
export const
|
|
64
|
+
export const SUBMITTERS_PUSH_FULL_QUEUE = 115;
|
|
65
65
|
export const SUBMITTERS_PUSH = 116;
|
|
66
66
|
export const SYNC_START_POLLING = 117;
|
|
67
67
|
export const SYNC_CONTINUE_POLLING = 118;
|
|
68
68
|
export const SYNC_STOP_POLLING = 119;
|
|
69
69
|
export const EVENTS_TRACKER_SUCCESS = 120;
|
|
70
70
|
export const IMPRESSIONS_TRACKER_SUCCESS = 121;
|
|
71
|
+
export const USER_CONSENT_UPDATED = 122;
|
|
72
|
+
export const USER_CONSENT_NOT_UPDATED = 123;
|
|
73
|
+
export const USER_CONSENT_INITIAL = 124;
|
|
71
74
|
|
|
72
75
|
export const ENGINE_VALUE_INVALID = 200;
|
|
73
76
|
export const ENGINE_VALUE_NO_ATTRIBUTES = 201;
|
|
@@ -115,10 +118,11 @@ export const ERROR_INVALID_KEY_OBJECT = 317;
|
|
|
115
118
|
export const ERROR_INVALID = 318;
|
|
116
119
|
export const ERROR_EMPTY = 319;
|
|
117
120
|
export const ERROR_EMPTY_ARRAY = 320;
|
|
118
|
-
export const
|
|
121
|
+
export const ERROR_INVALID_CONFIG_PARAM = 321;
|
|
119
122
|
export const ERROR_HTTP = 322;
|
|
120
123
|
export const ERROR_LOCALHOST_MODULE_REQUIRED = 323;
|
|
121
124
|
export const ERROR_STORAGE_INVALID = 324;
|
|
125
|
+
export const ERROR_NOT_BOOLEAN = 325;
|
|
122
126
|
|
|
123
127
|
// Log prefixes (a.k.a. tags or categories)
|
|
124
128
|
export const LOG_PREFIX_SETTINGS = 'settings';
|
|
@@ -31,9 +31,9 @@ export const codesDebug: [number, string][] = codesInfo.concat([
|
|
|
31
31
|
// SDK
|
|
32
32
|
[c.CLEANUP_REGISTERING, c.LOG_PREFIX_CLEANUP + 'Registering cleanup handler %s'],
|
|
33
33
|
[c.CLEANUP_DEREGISTERING, c.LOG_PREFIX_CLEANUP + 'Deregistering cleanup handler %s'],
|
|
34
|
-
[c.RETRIEVE_CLIENT_DEFAULT, '
|
|
35
|
-
[c.RETRIEVE_CLIENT_EXISTING, '
|
|
36
|
-
[c.RETRIEVE_MANAGER, '
|
|
34
|
+
[c.RETRIEVE_CLIENT_DEFAULT, 'Retrieving default SDK client.'],
|
|
35
|
+
[c.RETRIEVE_CLIENT_EXISTING, 'Retrieving existing SDK client.'],
|
|
36
|
+
[c.RETRIEVE_MANAGER, 'Retrieving manager instance.'],
|
|
37
37
|
// synchronizer
|
|
38
38
|
[c.SYNC_OFFLINE_DATA, c.LOG_PREFIX_SYNC_OFFLINE + 'Splits data: \n%s'],
|
|
39
39
|
[c.SYNC_SPLITS_FETCH, c.LOG_PREFIX_SYNC_SPLITS + 'Spin up split update using since = %s'],
|
|
@@ -5,7 +5,7 @@ export const codesError: [number, string][] = [
|
|
|
5
5
|
[c.ERROR_ENGINE_COMBINER_IFELSEIF, c.LOG_PREFIX_ENGINE_COMBINER + 'Invalid Split, no valid rules found'],
|
|
6
6
|
// SDK
|
|
7
7
|
[c.ERROR_LOGLEVEL_INVALID, 'logger: Invalid Log Level - No changes to the logs will be applied.'],
|
|
8
|
-
[c.ERROR_CLIENT_CANNOT_GET_READY, '
|
|
8
|
+
[c.ERROR_CLIENT_CANNOT_GET_READY, 'The SDK will not get ready. Reason: %s'],
|
|
9
9
|
[c.ERROR_IMPRESSIONS_TRACKER, c.LOG_PREFIX_IMPRESSIONS_TRACKER + 'Could not store impressions bulk with %s impression(s). Error: %s'],
|
|
10
10
|
[c.ERROR_IMPRESSIONS_LISTENER, c.LOG_PREFIX_IMPRESSIONS_TRACKER + 'Impression listener logImpression method threw: %s.'],
|
|
11
11
|
[c.ERROR_EVENTS_TRACKER, c.LOG_PREFIX_EVENTS_TRACKER + 'Failed to queue %s'],
|
|
@@ -13,7 +13,7 @@ export const codesError: [number, string][] = [
|
|
|
13
13
|
[c.ERROR_SYNC_OFFLINE_LOADING, c.LOG_PREFIX_SYNC_OFFLINE + 'There was an issue loading the mock Splits data, no changes will be applied to the current cache. %s'],
|
|
14
14
|
[c.ERROR_STREAMING_SSE, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to connect or error on streaming connection, with error message: %s'],
|
|
15
15
|
[c.ERROR_STREAMING_AUTH, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to authenticate for streaming. Error: %s.'],
|
|
16
|
-
[c.ERROR_HTTP, '
|
|
16
|
+
[c.ERROR_HTTP, 'Response status is not OK. Status: %s. URL: %s. Message: %s'],
|
|
17
17
|
// client status
|
|
18
18
|
[c.ERROR_CLIENT_LISTENER, 'A listener was added for %s on the SDK, which has already fired and won\'t be emitted again. The callback won\'t be executed.'],
|
|
19
19
|
[c.ERROR_CLIENT_DESTROYED, '%s: Client has already been destroyed - no calls possible.'],
|
|
@@ -28,8 +28,9 @@ export const codesError: [number, string][] = [
|
|
|
28
28
|
[c.ERROR_INVALID, '%s: you passed an invalid %s. It must be a non-empty string.'],
|
|
29
29
|
[c.ERROR_EMPTY, '%s: you passed an empty %s. It must be a non-empty string.'],
|
|
30
30
|
[c.ERROR_EMPTY_ARRAY, '%s: %s must be a non-empty array.'],
|
|
31
|
+
[c.ERROR_NOT_BOOLEAN, '%s: provided param must be a boolean value.'],
|
|
31
32
|
// initialization / settings validation
|
|
32
|
-
[c.
|
|
33
|
+
[c.ERROR_INVALID_CONFIG_PARAM, c.LOG_PREFIX_SETTINGS + ': you passed an invalid "%s" config param. It should be one of the following values: %s. Defaulting to "%s".'],
|
|
33
34
|
[c.ERROR_LOCALHOST_MODULE_REQUIRED, c.LOG_PREFIX_SETTINGS + ': an invalid value was received for "sync.localhostMode" config. A valid entity should be provided for localhost mode.'],
|
|
34
35
|
[c.ERROR_STORAGE_INVALID, c.LOG_PREFIX_SETTINGS+': The provided storage is invalid.%s Fallbacking into default MEMORY storage'],
|
|
35
36
|
];
|
|
@@ -10,17 +10,20 @@ export const codesInfo: [number, string][] = codesWarn.concat([
|
|
|
10
10
|
// SDK
|
|
11
11
|
[c.IMPRESSION, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Split: %s. Key: %s. Evaluation: %s. Label: %s'],
|
|
12
12
|
[c.IMPRESSION_QUEUEING, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Queueing corresponding impression.'],
|
|
13
|
-
[c.NEW_SHARED_CLIENT, '
|
|
14
|
-
[c.NEW_FACTORY, '
|
|
13
|
+
[c.NEW_SHARED_CLIENT, 'New shared client instance created.'],
|
|
14
|
+
[c.NEW_FACTORY, 'New Split SDK instance created.'],
|
|
15
15
|
[c.EVENTS_TRACKER_SUCCESS, c.LOG_PREFIX_EVENTS_TRACKER + 'Successfully queued %s'],
|
|
16
16
|
[c.IMPRESSIONS_TRACKER_SUCCESS, c.LOG_PREFIX_IMPRESSIONS_TRACKER + 'Successfully stored %s impression(s).'],
|
|
17
|
+
[c.USER_CONSENT_UPDATED, 'setUserConsent: consent status changed from %s to %s.'],
|
|
18
|
+
[c.USER_CONSENT_NOT_UPDATED, 'setUserConsent: call had no effect because it was the current consent status (%s).'],
|
|
19
|
+
[c.USER_CONSENT_INITIAL, 'Starting the SDK with %s user consent. No data will be sent.'],
|
|
17
20
|
|
|
18
21
|
// synchronizer
|
|
19
22
|
[c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'],
|
|
20
23
|
[c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'],
|
|
21
24
|
[c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'],
|
|
22
25
|
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying download of splits #%s. Reason: %s'],
|
|
23
|
-
[c.
|
|
26
|
+
[c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and reseting timer.'],
|
|
24
27
|
[c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s %s.'],
|
|
25
28
|
[c.STREAMING_REFRESH_TOKEN, c.LOG_PREFIX_SYNC_STREAMING + 'Refreshing streaming token in %s seconds, and connecting streaming in %s seconds.'],
|
|
26
29
|
[c.STREAMING_RECONNECT, c.LOG_PREFIX_SYNC_STREAMING + 'Attempting to reconnect streaming in %s seconds.'],
|
|
@@ -29,5 +32,5 @@ export const codesInfo: [number, string][] = codesWarn.concat([
|
|
|
29
32
|
[c.STREAMING_DISCONNECTING, c.LOG_PREFIX_SYNC_STREAMING + 'Disconnecting streaming.'],
|
|
30
33
|
[c.SYNC_START_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming not available. Starting polling.'],
|
|
31
34
|
[c.SYNC_CONTINUE_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming couldn\'t connect. Continue polling.'],
|
|
32
|
-
[c.SYNC_STOP_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming
|
|
35
|
+
[c.SYNC_STOP_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming connected. Syncing and stopping polling.'],
|
|
33
36
|
]);
|
package/src/logger/types.ts
CHANGED
|
@@ -9,11 +9,15 @@ export interface ILoggerOptions {
|
|
|
9
9
|
export interface ILogger {
|
|
10
10
|
setLogLevel(logLevel: LogLevel): void
|
|
11
11
|
|
|
12
|
+
debug(msg: any): void
|
|
12
13
|
debug(msg: string | number, args?: any[]): void
|
|
13
14
|
|
|
15
|
+
info(msg: any): void
|
|
14
16
|
info(msg: string | number, args?: any[]): void
|
|
15
17
|
|
|
18
|
+
warn(msg: any): void
|
|
16
19
|
warn(msg: string | number, args?: any[]): void
|
|
17
20
|
|
|
21
|
+
error(msg: any): void
|
|
18
22
|
error(msg: string | number, args?: any[]): void
|
|
19
23
|
}
|
package/src/sdkClient/client.ts
CHANGED
|
@@ -16,7 +16,8 @@ import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
|
|
|
16
16
|
*/
|
|
17
17
|
// @TODO missing time tracking to collect telemetry
|
|
18
18
|
export function clientFactory(params: IClientFactoryParams): SplitIO.IClient | SplitIO.IAsyncClient {
|
|
19
|
-
const { sdkReadinessManager: { readinessManager }, storage, settings
|
|
19
|
+
const { sdkReadinessManager: { readinessManager }, storage, settings, impressionsTracker, eventTracker } = params;
|
|
20
|
+
const { log, mode } = settings;
|
|
20
21
|
|
|
21
22
|
function getTreatment(key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, withConfig = false) {
|
|
22
23
|
const wrapUp = (evaluationResult: IEvaluationResult) => {
|
|
@@ -124,6 +125,6 @@ export function clientFactory(params: IClientFactoryParams): SplitIO.IClient | S
|
|
|
124
125
|
getTreatments,
|
|
125
126
|
getTreatmentsWithConfig,
|
|
126
127
|
track,
|
|
127
|
-
|
|
128
|
+
isClientSide: false
|
|
128
129
|
} as SplitIO.IClient | SplitIO.IAsyncClient;
|
|
129
130
|
}
|
|
@@ -25,6 +25,6 @@ export function clientCSDecorator(log: ILogger, client: SplitIO.IClient, key: Sp
|
|
|
25
25
|
// Key is bound to the `track` method. Same thing happens with trafficType but only if provided
|
|
26
26
|
track: trafficType ? clientCS.track.bind(clientCS, key, trafficType) : clientCS.track.bind(clientCS, key),
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
isClientSide: true
|
|
29
29
|
}) as SplitIO.ICsClient;
|
|
30
30
|
}
|
|
@@ -15,14 +15,17 @@ import { startsWith } from '../utils/lang';
|
|
|
15
15
|
import { CONTROL, CONTROL_WITH_CONFIG } from '../utils/constants';
|
|
16
16
|
import { IReadinessManager } from '../readiness/types';
|
|
17
17
|
import { MaybeThenable } from '../dtos/types';
|
|
18
|
-
import { SplitIO } from '../types';
|
|
19
|
-
import {
|
|
18
|
+
import { ISettings, SplitIO } from '../types';
|
|
19
|
+
import { isStorageSync } from '../trackers/impressionObserver/utils';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Decorator that validates the input before actually executing the client methods.
|
|
23
23
|
* We should "guard" the client here, while not polluting the "real" implementation of those methods.
|
|
24
24
|
*/
|
|
25
|
-
export function clientInputValidationDecorator<TClient extends SplitIO.IClient | SplitIO.IAsyncClient>(
|
|
25
|
+
export function clientInputValidationDecorator<TClient extends SplitIO.IClient | SplitIO.IAsyncClient>(settings: ISettings, client: TClient, readinessManager: IReadinessManager): TClient {
|
|
26
|
+
|
|
27
|
+
const log = settings.log;
|
|
28
|
+
const isSync = isStorageSync(settings);
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* Avoid repeating this validations code
|
|
@@ -47,8 +50,7 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
function wrapResult<T>(value: T): MaybeThenable<T> {
|
|
50
|
-
|
|
51
|
-
return Promise.resolve(value);
|
|
53
|
+
return isSync ? value : Promise.resolve(value);
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
function getTreatment(maybeKey: SplitIO.SplitKey, maybeSplit: string, maybeAttributes?: SplitIO.Attributes) {
|
|
@@ -108,8 +110,7 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
|
|
|
108
110
|
if (isOperational && key && tt && event && eventValue !== false && properties !== false) { // @ts-expect-error
|
|
109
111
|
return client.track(key, tt, event, eventValue, properties, size);
|
|
110
112
|
} else {
|
|
111
|
-
|
|
112
|
-
return Promise.resolve(false);
|
|
113
|
+
return isSync ? false : Promise.resolve(false);
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { IStatusInterface, SplitIO } from '../types';
|
|
3
|
-
import { CONSUMER_MODE, CONSUMER_PARTIAL_MODE } from '../utils/constants';
|
|
4
3
|
import { releaseApiKey } from '../utils/inputValidation/apiKey';
|
|
5
4
|
import { clientFactory } from './client';
|
|
6
5
|
import { clientInputValidationDecorator } from './clientInputValidation';
|
|
@@ -18,11 +17,9 @@ export function sdkClientFactory(params: ISdkClientFactoryParams): SplitIO.IClie
|
|
|
18
17
|
|
|
19
18
|
// Client API (getTreatment* & track methods)
|
|
20
19
|
clientInputValidationDecorator(
|
|
21
|
-
settings
|
|
20
|
+
settings,
|
|
22
21
|
clientFactory(params),
|
|
23
|
-
sdkReadinessManager.readinessManager
|
|
24
|
-
// storage is async if and only if mode is consumer or partial consumer
|
|
25
|
-
[CONSUMER_MODE, CONSUMER_PARTIAL_MODE].indexOf(settings.mode) === -1 ? true : false,
|
|
22
|
+
sdkReadinessManager.readinessManager
|
|
26
23
|
),
|
|
27
24
|
|
|
28
25
|
// Sdk destroy
|
|
@@ -23,15 +23,10 @@ const method = 'Client instantiation';
|
|
|
23
23
|
export function sdkClientMethodCSFactory(params: ISdkClientFactoryParams): (key?: SplitIO.SplitKey) => SplitIO.ICsClient {
|
|
24
24
|
const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params;
|
|
25
25
|
|
|
26
|
-
// Keeping similar behaviour as in the isomorphic JS SDK: if settings key is invalid,
|
|
27
|
-
// `false` value is used as binded key of the default client, but trafficType is ignored
|
|
28
|
-
// @TODO handle as a non-recoverable error
|
|
29
|
-
const validKey = validateKey(log, key, method);
|
|
30
|
-
|
|
31
26
|
const mainClientInstance = clientCSDecorator(
|
|
32
27
|
log,
|
|
33
28
|
sdkClientFactory(params) as SplitIO.IClient, // @ts-ignore
|
|
34
|
-
|
|
29
|
+
key
|
|
35
30
|
);
|
|
36
31
|
|
|
37
32
|
const parsedDefaultKey = keyParser(key);
|
|
@@ -25,20 +25,11 @@ const method = 'Client instantiation';
|
|
|
25
25
|
export function sdkClientMethodCSFactory(params: ISdkClientFactoryParams): (key?: SplitIO.SplitKey, trafficType?: string) => SplitIO.ICsClient {
|
|
26
26
|
const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, startup: { readyTimeout }, log } } = params;
|
|
27
27
|
|
|
28
|
-
// Keeping the behaviour as in the isomorphic JS SDK: if settings key or TT are invalid,
|
|
29
|
-
// `false` value is used as binded key/TT of the default client, which leads to several issues.
|
|
30
|
-
// @TODO update when supporting non-recoverable errors
|
|
31
|
-
const validKey = validateKey(log, key, method);
|
|
32
|
-
let validTrafficType;
|
|
33
|
-
if (trafficType !== undefined) {
|
|
34
|
-
validTrafficType = validateTrafficType(log, trafficType, method);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
28
|
const mainClientInstance = clientCSDecorator(
|
|
38
29
|
log,
|
|
39
30
|
sdkClientFactory(params) as SplitIO.IClient, // @ts-ignore
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
key,
|
|
32
|
+
trafficType
|
|
42
33
|
);
|
|
43
34
|
|
|
44
35
|
const parsedDefaultKey = keyParser(key);
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -12,14 +12,15 @@ import { createLoggerAPI } from '../logger/sdkLogger';
|
|
|
12
12
|
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
|
|
13
13
|
import { metadataBuilder } from '../storages/metadataBuilder';
|
|
14
14
|
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
15
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Modular SDK factory
|
|
18
19
|
*/
|
|
19
20
|
export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.ISDK | SplitIO.IAsyncSDK {
|
|
20
21
|
|
|
21
|
-
const { settings, platform, storageFactory, splitApiFactory,
|
|
22
|
-
syncManagerFactory, SignalListener, impressionsObserverFactory,
|
|
22
|
+
const { settings, platform, storageFactory, splitApiFactory, extraProps,
|
|
23
|
+
syncManagerFactory, SignalListener, impressionsObserverFactory,
|
|
23
24
|
integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory } = params;
|
|
24
25
|
const log = settings.log;
|
|
25
26
|
|
|
@@ -33,6 +34,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
33
34
|
|
|
34
35
|
// @TODO consider passing the settings object, so that each storage access only what it needs
|
|
35
36
|
const storageFactoryParams: IStorageFactoryParams = {
|
|
37
|
+
impressionsQueueSize: settings.scheduler.impressionsQueueSize,
|
|
36
38
|
eventsQueueSize: settings.scheduler.eventsQueueSize,
|
|
37
39
|
optimize: shouldBeOptimized(settings),
|
|
38
40
|
|
|
@@ -72,8 +74,8 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
72
74
|
|
|
73
75
|
// trackers
|
|
74
76
|
const observer = impressionsObserverFactory && impressionsObserverFactory();
|
|
75
|
-
const impressionsTracker = impressionsTrackerFactory(
|
|
76
|
-
const eventTracker = eventTrackerFactory(
|
|
77
|
+
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, integrationsManager, observer, storage.impressionCounts);
|
|
78
|
+
const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager);
|
|
77
79
|
|
|
78
80
|
// signal listener
|
|
79
81
|
const signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
|
@@ -87,12 +89,12 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
87
89
|
|
|
88
90
|
log.info(NEW_FACTORY);
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
return objectAssign({
|
|
91
94
|
// Split evaluation and event tracking engine
|
|
92
95
|
client: clientMethod,
|
|
93
96
|
|
|
94
97
|
// Manager API to explore available information
|
|
95
|
-
// @ts-ignore
|
|
96
98
|
manager() {
|
|
97
99
|
log.debug(RETRIEVE_MANAGER);
|
|
98
100
|
return managerInstance;
|
|
@@ -102,5 +104,5 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
102
104
|
Logger: createLoggerAPI(settings.log),
|
|
103
105
|
|
|
104
106
|
settings,
|
|
105
|
-
};
|
|
107
|
+
}, extraProps && extraProps(settings, syncManager));
|
|
106
108
|
}
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -64,10 +64,11 @@ export interface ISdkFactoryParams {
|
|
|
64
64
|
serviceApi: ISplitApi | undefined) => ISignalListener, // Used by BrowserSignalListener
|
|
65
65
|
|
|
66
66
|
// @TODO review impressionListener and integrations interfaces. What about handling impressionListener as an integration ?
|
|
67
|
-
impressionListener?: SplitIO.IImpressionListener,
|
|
68
67
|
integrationsManagerFactory?: (params: IIntegrationFactoryParams) => IIntegrationManager | undefined,
|
|
69
68
|
|
|
70
69
|
// Impression observer factory. If provided, will be used for impressions dedupe
|
|
71
70
|
impressionsObserverFactory?: () => IImpressionObserver
|
|
72
71
|
|
|
72
|
+
// Optional function to assign additional properties to the factory instance
|
|
73
|
+
extraProps?: (settings: ISettings, syncManager?: ISyncManager) => object
|
|
73
74
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ERROR_NOT_BOOLEAN, USER_CONSENT_UPDATED, USER_CONSENT_NOT_UPDATED, USER_CONSENT_INITIAL } from '../logger/constants';
|
|
2
|
+
import { ISyncManager } from '../sync/types';
|
|
3
|
+
import { ISettings } from '../types';
|
|
4
|
+
import { isConsentGranted } from '../utils/consent';
|
|
5
|
+
import { CONSENT_GRANTED, CONSENT_DECLINED } from '../utils/constants';
|
|
6
|
+
import { isBoolean } from '../utils/lang';
|
|
7
|
+
|
|
8
|
+
// Extend client-side factory instances with user consent getter/setter
|
|
9
|
+
export function userConsentProps(settings: ISettings, syncManager?: ISyncManager) {
|
|
10
|
+
|
|
11
|
+
const log = settings.log;
|
|
12
|
+
|
|
13
|
+
if (!isConsentGranted(settings)) log.info(USER_CONSENT_INITIAL, [settings.userConsent]);
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
setUserConsent(consent: unknown) {
|
|
17
|
+
// validate input param
|
|
18
|
+
if (!isBoolean(consent)) {
|
|
19
|
+
log.warn(ERROR_NOT_BOOLEAN, ['setUserConsent']);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const newConsentStatus = consent ? CONSENT_GRANTED : CONSENT_DECLINED;
|
|
24
|
+
|
|
25
|
+
if (settings.userConsent !== newConsentStatus) {
|
|
26
|
+
log.info(USER_CONSENT_UPDATED, [settings.userConsent, newConsentStatus]); // @ts-ignore, modify readonly prop
|
|
27
|
+
settings.userConsent = newConsentStatus;
|
|
28
|
+
|
|
29
|
+
if (consent) syncManager?.submitter?.start(); // resumes submitters if transitioning to GRANTED
|
|
30
|
+
else syncManager?.submitter?.stop(); // pauses submitters if transitioning to DECLINED
|
|
31
|
+
} else {
|
|
32
|
+
log.info(USER_CONSENT_NOT_UPDATED, [newConsentStatus]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return true;
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
getUserConsent() {
|
|
39
|
+
return settings.userConsent;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { startsWith } from '../utils/lang';
|
|
2
2
|
|
|
3
3
|
const everythingAtTheEnd = /[^.]+$/;
|
|
4
4
|
|
|
5
5
|
const DEFAULT_PREFIX = 'SPLITIO';
|
|
6
6
|
|
|
7
7
|
export function validatePrefix(prefix: unknown) {
|
|
8
|
-
return prefix
|
|
9
|
-
endsWith(prefix, '.' + DEFAULT_PREFIX) ?
|
|
10
|
-
prefix : // suffix already appended
|
|
11
|
-
prefix + '.' + DEFAULT_PREFIX : // append suffix
|
|
12
|
-
DEFAULT_PREFIX; // use default prefix if none is provided
|
|
8
|
+
return prefix ? prefix + '.SPLITIO' : 'SPLITIO';
|
|
13
9
|
}
|
|
14
10
|
|
|
15
11
|
export class KeyBuilder {
|
|
@@ -16,10 +16,22 @@ export class KeyBuilderCS extends KeyBuilder {
|
|
|
16
16
|
* @override
|
|
17
17
|
*/
|
|
18
18
|
buildSegmentNameKey(segmentName: string) {
|
|
19
|
-
return `${this.
|
|
19
|
+
return `${this.prefix}.${this.matchingKey}.segment.${segmentName}`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
extractSegmentName(builtSegmentKeyName: string) {
|
|
23
|
+
const prefix = `${this.prefix}.${this.matchingKey}.segment.`;
|
|
24
|
+
|
|
25
|
+
if (startsWith(builtSegmentKeyName, prefix))
|
|
26
|
+
return builtSegmentKeyName.substr(prefix.length);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// @BREAKING: The key used to start with the matching key instead of the prefix, this was changed on version 10.17.3
|
|
30
|
+
buildOldSegmentNameKey(segmentName: string) {
|
|
31
|
+
return `${this.matchingKey}.${this.prefix}.segment.${segmentName}`;
|
|
32
|
+
}
|
|
33
|
+
// @BREAKING: The key used to start with the matching key instead of the prefix, this was changed on version 10.17.3
|
|
34
|
+
extractOldSegmentKey(builtSegmentKeyName: string) {
|
|
23
35
|
const prefix = `${this.matchingKey}.${this.prefix}.segment.`;
|
|
24
36
|
|
|
25
37
|
if (startsWith(builtSegmentKeyName, prefix))
|
|
@@ -67,9 +67,29 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
67
67
|
|
|
68
68
|
// Scan current values from localStorage
|
|
69
69
|
const storedSegmentNames = Object.keys(localStorage).reduce((accum, key) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (
|
|
70
|
+
let segmentName = this.keys.extractSegmentName(key);
|
|
71
|
+
|
|
72
|
+
if (segmentName) {
|
|
73
|
+
accum.push(segmentName);
|
|
74
|
+
} else {
|
|
75
|
+
// @BREAKING: This is only to clean up "old" keys. Remove this whole else code block.
|
|
76
|
+
segmentName = this.keys.extractOldSegmentKey(key);
|
|
77
|
+
|
|
78
|
+
if (segmentName) { // this was an old segment key, let's clean up.
|
|
79
|
+
const newSegmentKey = this.keys.buildSegmentNameKey(segmentName);
|
|
80
|
+
try {
|
|
81
|
+
// If the new format key is not there, create it.
|
|
82
|
+
if (!localStorage.getItem(newSegmentKey) && names.indexOf(segmentName) > -1) {
|
|
83
|
+
localStorage.setItem(newSegmentKey, DEFINED);
|
|
84
|
+
// we are migrating a segment, let's track it.
|
|
85
|
+
accum.push(segmentName);
|
|
86
|
+
}
|
|
87
|
+
localStorage.removeItem(key); // we migrated the current key, let's delete it.
|
|
88
|
+
} catch (e) {
|
|
89
|
+
this.log.error(e);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
73
93
|
|
|
74
94
|
return accum;
|
|
75
95
|
}, [] as string[]);
|
|
@@ -40,7 +40,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
40
40
|
return {
|
|
41
41
|
splits: new SplitsCacheInLocal(log, keys, expirationTimestamp, params.splitFiltersValidation),
|
|
42
42
|
segments: new MySegmentsCacheInLocal(log, keys),
|
|
43
|
-
impressions: new ImpressionsCacheInMemory(),
|
|
43
|
+
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
44
44
|
impressionCounts: params.optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
45
45
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
46
46
|
|
|
@@ -3,13 +3,34 @@ import { ImpressionDTO } from '../../types';
|
|
|
3
3
|
|
|
4
4
|
export class ImpressionsCacheInMemory implements IImpressionsCacheSync {
|
|
5
5
|
|
|
6
|
-
private
|
|
6
|
+
private onFullQueue?: () => void;
|
|
7
|
+
private readonly maxQueue: number;
|
|
8
|
+
private queue: ImpressionDTO[];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param impressionsQueueSize number of queued impressions to call onFullQueueCb.
|
|
13
|
+
* Default value is 0, that means no maximum value, in case we want to avoid this being triggered.
|
|
14
|
+
*/
|
|
15
|
+
constructor(impressionsQueueSize: number = 0) {
|
|
16
|
+
this.maxQueue = impressionsQueueSize;
|
|
17
|
+
this.queue = [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
setOnFullQueueCb(cb: () => void) {
|
|
21
|
+
this.onFullQueue = cb;
|
|
22
|
+
}
|
|
7
23
|
|
|
8
24
|
/**
|
|
9
25
|
* Store impressions in sequential order
|
|
10
26
|
*/
|
|
11
27
|
track(data: ImpressionDTO[]) {
|
|
12
28
|
this.queue.push(...data);
|
|
29
|
+
|
|
30
|
+
// Check if the cache queue is full and we need to flush it.
|
|
31
|
+
if (this.maxQueue > 0 && this.queue.length >= this.maxQueue && this.onFullQueue) {
|
|
32
|
+
this.onFullQueue();
|
|
33
|
+
}
|
|
13
34
|
}
|
|
14
35
|
|
|
15
36
|
/**
|
|
@@ -16,7 +16,7 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
16
16
|
return {
|
|
17
17
|
splits: new SplitsCacheInMemory(),
|
|
18
18
|
segments: new SegmentsCacheInMemory(),
|
|
19
|
-
impressions: new ImpressionsCacheInMemory(),
|
|
19
|
+
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
20
20
|
impressionCounts: params.optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
21
21
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
22
22
|
|
|
@@ -16,7 +16,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
16
16
|
return {
|
|
17
17
|
splits: new SplitsCacheInMemory(),
|
|
18
18
|
segments: new MySegmentsCacheInMemory(),
|
|
19
|
-
impressions: new ImpressionsCacheInMemory(),
|
|
19
|
+
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
20
20
|
impressionCounts: params.optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
21
21
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
22
22
|
|
|
@@ -164,6 +164,12 @@ export class RedisAdapter extends ioredis {
|
|
|
164
164
|
} else { // If it IS the string URL, that'll be the first param for ioredis.
|
|
165
165
|
result.unshift(options.url);
|
|
166
166
|
}
|
|
167
|
+
if (options.connectionTimeout) {
|
|
168
|
+
merge(opts, { connectTimeout: options.connectionTimeout });
|
|
169
|
+
}
|
|
170
|
+
if (options.tls) {
|
|
171
|
+
merge(opts, { tls: options.tls });
|
|
172
|
+
}
|
|
167
173
|
|
|
168
174
|
return result;
|
|
169
175
|
}
|
|
@@ -171,9 +177,9 @@ export class RedisAdapter extends ioredis {
|
|
|
171
177
|
/**
|
|
172
178
|
* Parses the options into what we care about.
|
|
173
179
|
*/
|
|
174
|
-
static _defineOptions({ connectionTimeout, operationTimeout, url, host, port, db, pass }: Record<string, any>) {
|
|
180
|
+
static _defineOptions({ connectionTimeout, operationTimeout, url, host, port, db, pass, tls }: Record<string, any>) {
|
|
175
181
|
const parsedOptions = {
|
|
176
|
-
connectionTimeout, operationTimeout, url, host, port, db, pass
|
|
182
|
+
connectionTimeout, operationTimeout, url, host, port, db, pass, tls
|
|
177
183
|
};
|
|
178
184
|
|
|
179
185
|
return merge({}, DEFAULT_OPTIONS, parsedOptions);
|
|
@@ -63,7 +63,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
63
63
|
|
|
64
64
|
const prefix = validatePrefix(options.prefix);
|
|
65
65
|
|
|
66
|
-
function PluggableStorageFactory({ log, metadata, onReadyCb, mode, eventsQueueSize, optimize }: IStorageFactoryParams): IStorageAsync {
|
|
66
|
+
function PluggableStorageFactory({ log, metadata, onReadyCb, mode, eventsQueueSize, impressionsQueueSize, optimize }: IStorageFactoryParams): IStorageAsync {
|
|
67
67
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
68
68
|
const wrapper = wrapperAdapter(log, options.wrapper);
|
|
69
69
|
const isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
|
|
@@ -74,7 +74,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
74
74
|
return {
|
|
75
75
|
splits: new SplitsCachePluggable(log, keys, wrapper),
|
|
76
76
|
segments: new SegmentsCachePluggable(log, keys, wrapper),
|
|
77
|
-
impressions: isPartialConsumer ? new ImpressionsCacheInMemory() : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
77
|
+
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
78
78
|
impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
79
79
|
events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
|
|
80
80
|
// @TODO add telemetry cache when required
|