@splitsoftware/splitio-commons 1.17.1-rc.3 → 1.17.1-rc.5
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 +28 -28
- package/LICENSE +1 -1
- package/README.md +4 -3
- package/cjs/consent/sdkUserConsent.js +4 -2
- package/cjs/evaluator/matchers/index.js +1 -3
- package/cjs/evaluator/matchers/matcherTypes.js +0 -1
- package/cjs/evaluator/matchers/segment.js +0 -6
- package/cjs/evaluator/matchersTransform/index.js +1 -4
- package/cjs/evaluator/matchersTransform/segment.js +1 -3
- package/cjs/logger/constants.js +2 -2
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +11 -12
- package/cjs/readiness/sdkReadinessManager.js +6 -5
- package/cjs/sdkClient/sdkClient.js +5 -5
- package/cjs/sdkClient/sdkClientMethod.js +1 -3
- package/cjs/sdkClient/sdkClientMethodCS.js +17 -15
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +17 -15
- package/cjs/sdkFactory/index.js +11 -38
- package/cjs/services/decorateHeaders.js +6 -1
- package/cjs/services/splitApi.js +5 -5
- package/cjs/services/splitHttpClient.js +5 -2
- package/cjs/storages/AbstractSegmentsCacheSync.js +12 -41
- package/cjs/storages/AbstractSplitsCacheAsync.js +7 -0
- package/cjs/storages/AbstractSplitsCacheSync.js +8 -2
- package/cjs/storages/KeyBuilderCS.js +5 -23
- package/cjs/storages/dataLoader.js +33 -65
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +52 -29
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +9 -1
- package/cjs/storages/inLocalStorage/index.js +3 -12
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -20
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +40 -9
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +8 -8
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
- package/cjs/storages/inRedis/RedisAdapter.js +1 -1
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +2 -2
- package/cjs/storages/inRedis/index.js +11 -5
- package/cjs/storages/pluggable/SegmentsCachePluggable.js +2 -2
- package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
- package/cjs/storages/pluggable/index.js +32 -37
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +7 -2
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/pollingManagerSS.js +3 -3
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -15
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +2 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +11 -2
- package/cjs/sync/streaming/AuthClient/index.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +5 -3
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +48 -107
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
- package/cjs/sync/streaming/constants.js +3 -3
- package/cjs/sync/streaming/parseUtils.js +9 -14
- package/cjs/sync/streaming/pushManager.js +67 -69
- package/cjs/sync/syncTask.js +2 -2
- package/cjs/trackers/eventTracker.js +9 -11
- package/cjs/trackers/impressionsTracker.js +13 -15
- package/cjs/trackers/uniqueKeysTracker.js +3 -5
- package/cjs/utils/constants/index.js +4 -5
- package/cjs/utils/settingsValidation/index.js +1 -2
- package/cjs/utils/settingsValidation/storage/storageCS.js +12 -1
- package/esm/consent/sdkUserConsent.js +4 -2
- package/esm/evaluator/matchers/index.js +1 -3
- package/esm/evaluator/matchers/matcherTypes.js +0 -1
- package/esm/evaluator/matchers/segment.js +0 -6
- package/esm/evaluator/matchersTransform/index.js +1 -4
- package/esm/evaluator/matchersTransform/segment.js +1 -3
- package/esm/logger/constants.js +1 -1
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +11 -12
- package/esm/readiness/sdkReadinessManager.js +6 -5
- package/esm/sdkClient/sdkClient.js +5 -5
- package/esm/sdkClient/sdkClientMethod.js +1 -3
- package/esm/sdkClient/sdkClientMethodCS.js +15 -13
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +15 -13
- package/esm/sdkFactory/index.js +12 -39
- package/esm/services/decorateHeaders.js +4 -0
- package/esm/services/splitApi.js +6 -6
- package/esm/services/splitHttpClient.js +6 -3
- package/esm/storages/AbstractSegmentsCacheSync.js +12 -41
- package/esm/storages/AbstractSplitsCacheAsync.js +7 -0
- package/esm/storages/AbstractSplitsCacheSync.js +9 -3
- package/esm/storages/KeyBuilderCS.js +4 -21
- package/esm/storages/dataLoader.js +31 -62
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +52 -29
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +9 -1
- package/esm/storages/inLocalStorage/index.js +5 -14
- package/esm/storages/inMemory/InMemoryStorageCS.js +3 -20
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +40 -9
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
- package/esm/storages/inMemory/SplitsCacheInMemory.js +8 -8
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
- package/esm/storages/inRedis/RedisAdapter.js +1 -1
- package/esm/storages/inRedis/SegmentsCacheInRedis.js +2 -2
- package/esm/storages/inRedis/index.js +11 -5
- package/esm/storages/pluggable/SegmentsCachePluggable.js +2 -2
- package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
- package/esm/storages/pluggable/index.js +32 -37
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +8 -3
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/pollingManagerSS.js +3 -3
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +21 -15
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +2 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +12 -3
- package/esm/sync/streaming/AuthClient/index.js +1 -1
- package/esm/sync/streaming/SSEHandler/index.js +6 -4
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +49 -108
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
- package/esm/sync/streaming/constants.js +2 -2
- package/esm/sync/streaming/parseUtils.js +8 -12
- package/esm/sync/streaming/pushManager.js +70 -72
- package/esm/sync/syncTask.js +2 -2
- package/esm/trackers/eventTracker.js +9 -11
- package/esm/trackers/impressionsTracker.js +13 -15
- package/esm/trackers/uniqueKeysTracker.js +3 -5
- package/esm/utils/constants/index.js +2 -3
- package/esm/utils/settingsValidation/index.js +1 -2
- package/esm/utils/settingsValidation/storage/storageCS.js +10 -0
- package/package.json +1 -1
- package/src/consent/sdkUserConsent.ts +3 -2
- package/src/dtos/types.ts +7 -21
- package/src/evaluator/matchers/index.ts +0 -2
- package/src/evaluator/matchers/matcherTypes.ts +0 -1
- package/src/evaluator/matchers/segment.ts +0 -7
- package/src/evaluator/matchersTransform/index.ts +1 -4
- package/src/evaluator/matchersTransform/segment.ts +3 -5
- package/src/logger/constants.ts +1 -1
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +12 -16
- package/src/readiness/sdkReadinessManager.ts +7 -7
- package/src/readiness/types.ts +2 -3
- package/src/sdkClient/sdkClient.ts +5 -5
- package/src/sdkClient/sdkClientMethod.ts +1 -4
- package/src/sdkClient/sdkClientMethodCS.ts +14 -11
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +14 -11
- package/src/sdkFactory/index.ts +13 -42
- package/src/sdkFactory/types.ts +1 -5
- package/src/services/decorateHeaders.ts +5 -0
- package/src/services/splitApi.ts +7 -7
- package/src/services/splitHttpClient.ts +7 -4
- package/src/services/types.ts +2 -2
- package/src/storages/AbstractSegmentsCacheSync.ts +12 -53
- package/src/storages/AbstractSplitsCacheAsync.ts +8 -0
- package/src/storages/AbstractSplitsCacheSync.ts +11 -4
- package/src/storages/KeyBuilderCS.ts +5 -34
- package/src/storages/dataLoader.ts +33 -63
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +59 -29
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +10 -1
- package/src/storages/inLocalStorage/index.ts +6 -16
- package/src/storages/inMemory/InMemoryStorageCS.ts +3 -23
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +44 -10
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +1 -1
- package/src/storages/inMemory/SplitsCacheInMemory.ts +8 -7
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
- package/src/storages/inRedis/RedisAdapter.ts +1 -1
- package/src/storages/inRedis/SegmentsCacheInRedis.ts +2 -2
- package/src/storages/inRedis/index.ts +12 -6
- package/src/storages/pluggable/SegmentsCachePluggable.ts +2 -2
- package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
- package/src/storages/pluggable/index.ts +33 -38
- package/src/storages/types.ts +15 -15
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +7 -3
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +10 -8
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
- package/src/sync/polling/fetchers/types.ts +2 -3
- package/src/sync/polling/pollingManagerCS.ts +4 -4
- package/src/sync/polling/pollingManagerSS.ts +2 -3
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +5 -4
- package/src/sync/polling/types.ts +6 -7
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +22 -19
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -2
- package/src/sync/polling/updaters/splitChangesUpdater.ts +12 -4
- package/src/sync/streaming/AuthClient/index.ts +1 -1
- package/src/sync/streaming/SSEClient/index.ts +6 -4
- package/src/sync/streaming/SSEHandler/index.ts +8 -5
- package/src/sync/streaming/SSEHandler/types.ts +15 -15
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +49 -116
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +4 -4
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
- package/src/sync/streaming/constants.ts +2 -2
- package/src/sync/streaming/parseUtils.ts +11 -19
- package/src/sync/streaming/pushManager.ts +72 -73
- package/src/sync/streaming/types.ts +10 -10
- package/src/sync/submitters/types.ts +5 -8
- package/src/sync/syncTask.ts +2 -2
- package/src/trackers/eventTracker.ts +7 -10
- package/src/trackers/impressionsTracker.ts +9 -12
- package/src/trackers/types.ts +0 -1
- package/src/trackers/uniqueKeysTracker.ts +4 -6
- package/src/types.ts +9 -16
- package/src/utils/constants/index.ts +2 -3
- package/src/utils/settingsValidation/index.ts +2 -3
- package/src/utils/settingsValidation/storage/storageCS.ts +13 -0
- package/src/utils/settingsValidation/types.ts +1 -1
- package/types/dtos/types.d.ts +7 -18
- package/types/evaluator/matchersTransform/segment.d.ts +2 -2
- package/types/logger/constants.d.ts +1 -1
- package/types/readiness/readinessManager.d.ts +2 -2
- package/types/readiness/sdkReadinessManager.d.ts +3 -2
- package/types/readiness/types.d.ts +2 -3
- package/types/sdkClient/sdkClientMethod.d.ts +1 -1
- package/types/sdkFactory/types.d.ts +1 -4
- package/types/services/decorateHeaders.d.ts +1 -0
- package/types/services/splitApi.d.ts +1 -1
- package/types/services/splitHttpClient.d.ts +1 -1
- package/types/services/types.d.ts +2 -2
- package/types/storages/AbstractSegmentsCacheSync.d.ts +11 -9
- package/types/storages/AbstractSplitsCacheAsync.d.ts +5 -0
- package/types/storages/AbstractSplitsCacheSync.d.ts +6 -1
- package/types/storages/KeyBuilderCS.d.ts +2 -9
- package/types/storages/dataLoader.d.ts +6 -17
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +14 -4
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +6 -0
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +9 -3
- package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +1 -1
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -1
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
- package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +1 -1
- package/types/storages/inRedis/index.d.ts +1 -1
- package/types/storages/pluggable/SegmentsCachePluggable.d.ts +1 -1
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
- package/types/storages/types.d.ts +11 -11
- package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
- package/types/sync/polling/fetchers/types.d.ts +2 -2
- package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
- package/types/sync/polling/types.d.ts +4 -7
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -4
- package/types/sync/streaming/SSEHandler/types.d.ts +14 -16
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -4
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
- package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
- package/types/sync/streaming/constants.d.ts +2 -2
- package/types/sync/streaming/parseUtils.d.ts +5 -4
- package/types/sync/streaming/types.d.ts +8 -8
- package/types/sync/submitters/types.d.ts +4 -7
- package/types/trackers/eventTracker.d.ts +1 -1
- package/types/trackers/impressionsTracker.d.ts +1 -1
- package/types/trackers/types.d.ts +0 -1
- package/types/types.d.ts +9 -15
- package/types/utils/constants/index.d.ts +2 -3
- package/types/utils/settingsValidation/storage/storageCS.d.ts +5 -0
- package/types/utils/settingsValidation/types.d.ts +1 -1
- package/cjs/evaluator/matchers/large_segment.js +0 -16
- package/cjs/sdkClient/identity.js +0 -7
- package/esm/evaluator/matchers/large_segment.js +0 -12
- package/esm/sdkClient/identity.js +0 -3
- package/src/evaluator/matchers/large_segment.ts +0 -18
- package/src/sdkClient/identity.ts +0 -5
- package/types/evaluator/matchers/large_segment.d.ts +0 -5
- package/types/evaluator/matchers/sember_inlist.d.ts +0 -3
- package/types/evaluator/matchersTransform/set.d.ts +0 -5
- package/types/evaluator/matchersTransform/string.d.ts +0 -7
- package/types/sdkClient/identity.d.ts +0 -2
- package/types/storages/AbstractMySegmentsCacheSync.d.ts +0 -39
- package/types/storages/AbstractSplitsCache.d.ts +0 -46
- package/types/sync/streaming/mySegmentsV2utils.d.ts +0 -27
- package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +0 -9
- package/types/sync/streaming/pushManager_Spec1_3.d.ts +0 -9
- package/types/trackers/impressionObserver/utils.d.ts +0 -5
- package/types/utils/inputValidation/sdkKey.d.ts +0 -7
- package/types/utils/inputValidation/splitExistance.d.ts +0 -7
- package/types/utils/inputValidation/trafficTypeExistance.d.ts +0 -9
- package/types/utils/redis/RedisMock.d.ts +0 -4
- package/types/utils/settingsValidation/logger/globalLogLevel.d.ts +0 -8
- /package/types/utils/{semVer.d.ts → Semver.d.ts} +0 -0
package/src/services/splitApi.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
|
|
|
4
4
|
import { ISplitApi } from './types';
|
|
5
5
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
6
6
|
import { ITelemetryTracker } from '../trackers/types';
|
|
7
|
-
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT,
|
|
7
|
+
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
|
|
8
8
|
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
|
|
9
9
|
|
|
10
10
|
const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
@@ -22,7 +22,7 @@ function userKeyToQueryParam(userKey: string) {
|
|
|
22
22
|
*/
|
|
23
23
|
export function splitApiFactory(
|
|
24
24
|
settings: ISettings,
|
|
25
|
-
platform:
|
|
25
|
+
platform: IPlatform,
|
|
26
26
|
telemetryTracker: ITelemetryTracker
|
|
27
27
|
): ISplitApi {
|
|
28
28
|
|
|
@@ -67,15 +67,15 @@ export function splitApiFactory(
|
|
|
67
67
|
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
fetchMySegments(userMatchingKey: string, noCache?: boolean) {
|
|
71
71
|
/**
|
|
72
72
|
* URI encoding of user keys in order to:
|
|
73
|
-
* - avoid 400 responses (due to URI malformed). E.g.: '/api/
|
|
74
|
-
* - avoid 404 responses. E.g.: '/api/
|
|
73
|
+
* - avoid 400 responses (due to URI malformed). E.g.: '/api/mySegments/%'
|
|
74
|
+
* - avoid 404 responses. E.g.: '/api/mySegments/foo/bar'
|
|
75
75
|
* - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
|
|
76
76
|
*/
|
|
77
|
-
const url = `${urls.sdk}/
|
|
78
|
-
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(
|
|
77
|
+
const url = `${urls.sdk}/mySegments/${encodeURIComponent(userMatchingKey)}`;
|
|
78
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_SEGMENT));
|
|
79
79
|
},
|
|
80
80
|
|
|
81
81
|
/**
|
|
@@ -3,8 +3,10 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
3
3
|
import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants';
|
|
4
4
|
import { ISettings } from '../types';
|
|
5
5
|
import { IPlatform } from '../sdkFactory/types';
|
|
6
|
-
import { decorateHeaders } from './decorateHeaders';
|
|
6
|
+
import { decorateHeaders, removeNonISO88591 } from './decorateHeaders';
|
|
7
|
+
import { timeout } from '../utils/promise/timeout';
|
|
7
8
|
|
|
9
|
+
const PENDING_FETCH_ERROR_TIMEOUT = 100;
|
|
8
10
|
const messageNoFetch = 'Global fetch API is not available.';
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -13,7 +15,7 @@ const messageNoFetch = 'Global fetch API is not available.';
|
|
|
13
15
|
* @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
|
|
14
16
|
* @param platform object containing environment-specific dependencies
|
|
15
17
|
*/
|
|
16
|
-
export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }:
|
|
18
|
+
export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }: IPlatform): ISplitHttpClient {
|
|
17
19
|
|
|
18
20
|
const { log, core: { authorizationKey }, version, runtime: { ip, hostname } } = settings;
|
|
19
21
|
const options = getOptions && getOptions(settings);
|
|
@@ -30,7 +32,7 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
|
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
if (ip) commonHeaders['SplitSDKMachineIP'] = ip;
|
|
33
|
-
if (hostname) commonHeaders['SplitSDKMachineName'] = hostname;
|
|
35
|
+
if (hostname) commonHeaders['SplitSDKMachineName'] = removeNonISO88591(hostname);
|
|
34
36
|
|
|
35
37
|
return function httpClient(url: string, reqOpts: IRequestOptions = {}, latencyTracker: (error?: NetworkError) => void = () => { }, logErrorsAsInfo: boolean = false): Promise<IResponse> {
|
|
36
38
|
|
|
@@ -45,7 +47,8 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
|
|
|
45
47
|
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
|
|
46
48
|
.then(response => {
|
|
47
49
|
if (!response.ok) {
|
|
48
|
-
|
|
50
|
+
// `text()` promise might not settle in some fetch implementations and cases (e.g. no content)
|
|
51
|
+
return timeout(PENDING_FETCH_ERROR_TIMEOUT, response.text()).then(message => Promise.reject({ response, message }), () => Promise.reject({ response }));
|
|
49
52
|
}
|
|
50
53
|
latencyTracker();
|
|
51
54
|
return response;
|
package/src/services/types.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type IFetchSplitChanges = (since: number, noCache?: boolean, till?: numbe
|
|
|
39
39
|
|
|
40
40
|
export type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean, till?: number) => Promise<IResponse>
|
|
41
41
|
|
|
42
|
-
export type
|
|
42
|
+
export type IFetchMySegments = (userMatchingKey: string, noCache?: boolean) => Promise<IResponse>
|
|
43
43
|
|
|
44
44
|
export type IPostEventsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>
|
|
45
45
|
|
|
@@ -61,7 +61,7 @@ export interface ISplitApi {
|
|
|
61
61
|
fetchAuth: IFetchAuth
|
|
62
62
|
fetchSplitChanges: IFetchSplitChanges
|
|
63
63
|
fetchSegmentChanges: IFetchSegmentChanges
|
|
64
|
-
|
|
64
|
+
fetchMySegments: IFetchMySegments
|
|
65
65
|
postEventsBulk: IPostEventsBulk
|
|
66
66
|
postUniqueKeysBulkCs: IPostUniqueKeysBulkCs
|
|
67
67
|
postUniqueKeysBulkSs: IPostUniqueKeysBulkSs
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
/* eslint-disable no-unused-vars */
|
|
3
|
-
import { IMySegmentsResponse } from '../dtos/types';
|
|
4
|
-
import { MySegmentsData } from '../sync/polling/types';
|
|
5
3
|
import { ISegmentsCacheSync } from './types';
|
|
6
4
|
|
|
7
5
|
/**
|
|
@@ -30,9 +28,7 @@ export abstract class AbstractSegmentsCacheSync implements ISegmentsCacheSync {
|
|
|
30
28
|
/**
|
|
31
29
|
* clear the cache.
|
|
32
30
|
*/
|
|
33
|
-
clear()
|
|
34
|
-
this.resetSegments({});
|
|
35
|
-
}
|
|
31
|
+
abstract clear(): void
|
|
36
32
|
|
|
37
33
|
/**
|
|
38
34
|
* For server-side synchronizer: add the given list of segments to the cache, with an empty list of keys. The segments that already exist are not modified.
|
|
@@ -53,57 +49,20 @@ export abstract class AbstractSegmentsCacheSync implements ISegmentsCacheSync {
|
|
|
53
49
|
abstract getKeysCount(): number
|
|
54
50
|
|
|
55
51
|
/**
|
|
56
|
-
* For server-side synchronizer: change number of `name` segment.
|
|
57
|
-
* For client-side synchronizer:
|
|
52
|
+
* For server-side synchronizer: set the change number of `name` segment.
|
|
53
|
+
* For client-side synchronizer: the method is not used.
|
|
58
54
|
*/
|
|
59
|
-
|
|
60
|
-
abstract getChangeNumber(name: string): number
|
|
55
|
+
setChangeNumber(name: string, changeNumber: number): boolean { return true; }
|
|
61
56
|
|
|
62
57
|
/**
|
|
63
|
-
* For server-side synchronizer: the
|
|
64
|
-
* For client-side synchronizer:
|
|
58
|
+
* For server-side synchronizer: get the change number of `name` segment.
|
|
59
|
+
* For client-side synchronizer: the method is not used.
|
|
65
60
|
*/
|
|
66
|
-
|
|
67
|
-
this.setChangeNumber(undefined, segmentsData.cn);
|
|
68
|
-
|
|
69
|
-
const { added, removed } = segmentsData as MySegmentsData;
|
|
70
|
-
|
|
71
|
-
if (added && removed) {
|
|
72
|
-
let isDiff = false;
|
|
73
|
-
|
|
74
|
-
added.forEach(segment => {
|
|
75
|
-
isDiff = this.addToSegment(segment) || isDiff;
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
removed.forEach(segment => {
|
|
79
|
-
isDiff = this.removeFromSegment(segment) || isDiff;
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return isDiff;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const names = ((segmentsData as IMySegmentsResponse).k || []).map(s => s.n).sort();
|
|
86
|
-
const storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
61
|
+
getChangeNumber(name: string): number | undefined { return -1; }
|
|
87
62
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index]) index++;
|
|
94
|
-
|
|
95
|
-
// Quick path => no changes
|
|
96
|
-
if (index === names.length && index === storedSegmentKeys.length) return false;
|
|
97
|
-
|
|
98
|
-
// Slowest path => add and/or remove segments
|
|
99
|
-
for (let removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
100
|
-
this.removeFromSegment(storedSegmentKeys[removeIndex]);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
for (let addIndex = index; addIndex < names.length; addIndex++) {
|
|
104
|
-
this.addToSegment(names[addIndex]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
63
|
+
/**
|
|
64
|
+
* For server-side synchronizer: the method is not used.
|
|
65
|
+
* For client-side synchronizer: reset the cache with the given list of segments.
|
|
66
|
+
*/
|
|
67
|
+
resetSegments(names: string[]): boolean { return true; }
|
|
109
68
|
}
|
|
@@ -28,6 +28,14 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
|
|
|
28
28
|
return Promise.resolve(true);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Check if the splits information is already stored in cache.
|
|
33
|
+
* Noop, just keeping the interface. This is used by client-side implementations only.
|
|
34
|
+
*/
|
|
35
|
+
checkCache(): Promise<boolean> {
|
|
36
|
+
return Promise.resolve(false);
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
/**
|
|
32
40
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
33
41
|
* Used for SPLIT_KILL push notifications.
|
|
@@ -2,7 +2,7 @@ import { ISplitsCacheSync } from './types';
|
|
|
2
2
|
import { ISplit } from '../dtos/types';
|
|
3
3
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
4
4
|
import { ISet } from '../utils/lang/sets';
|
|
5
|
-
import { IN_SEGMENT
|
|
5
|
+
import { IN_SEGMENT } from '../utils/constants';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* This class provides a skeletal implementation of the ISplitsCacheSync interface
|
|
@@ -32,7 +32,7 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
32
32
|
return splits;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
abstract setChangeNumber(changeNumber: number): boolean
|
|
35
|
+
abstract setChangeNumber(changeNumber: number): boolean
|
|
36
36
|
|
|
37
37
|
abstract getChangeNumber(): number
|
|
38
38
|
|
|
@@ -48,6 +48,14 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
48
48
|
|
|
49
49
|
abstract clear(): void
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Check if the splits information is already stored in cache. This data can be preloaded.
|
|
53
|
+
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
|
|
54
|
+
*/
|
|
55
|
+
checkCache(): boolean {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
/**
|
|
52
60
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
53
61
|
* Used for SPLIT_KILL push notifications.
|
|
@@ -86,8 +94,7 @@ export function usesSegments(split: ISplit) {
|
|
|
86
94
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
87
95
|
|
|
88
96
|
for (let j = 0; j < matchers.length; j++) {
|
|
89
|
-
|
|
90
|
-
if (matcher === IN_SEGMENT || matcher === IN_LARGE_SEGMENT) return true;
|
|
97
|
+
if (matchers[j].matcherType === IN_SEGMENT) return true;
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
100
|
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { startsWith } from '../utils/lang';
|
|
2
2
|
import { KeyBuilder } from './KeyBuilder';
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
buildSegmentNameKey(segmentName: string): string;
|
|
6
|
-
extractSegmentName(builtSegmentKeyName: string): string | undefined;
|
|
7
|
-
extractOldSegmentKey(builtSegmentKeyName: string): string | undefined;
|
|
8
|
-
buildTillKey(): string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
4
|
+
export class KeyBuilderCS extends KeyBuilder {
|
|
12
5
|
|
|
13
6
|
protected readonly regexSplitsCacheKey: RegExp;
|
|
14
7
|
protected readonly matchingKey: string;
|
|
@@ -33,6 +26,10 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
33
26
|
return builtSegmentKeyName.substr(prefix.length);
|
|
34
27
|
}
|
|
35
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
|
+
}
|
|
36
33
|
// @BREAKING: The key used to start with the matching key instead of the prefix, this was changed on version 10.17.3
|
|
37
34
|
extractOldSegmentKey(builtSegmentKeyName: string) {
|
|
38
35
|
const prefix = `${this.matchingKey}.${this.prefix}.segment.`;
|
|
@@ -48,30 +45,4 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
48
45
|
isSplitsCacheKey(key: string) {
|
|
49
46
|
return this.regexSplitsCacheKey.test(key);
|
|
50
47
|
}
|
|
51
|
-
|
|
52
|
-
buildTillKey() {
|
|
53
|
-
return `${this.prefix}.${this.matchingKey}.segments.till`;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string): MySegmentsKeyBuilder {
|
|
58
|
-
return {
|
|
59
|
-
buildSegmentNameKey(segmentName: string) {
|
|
60
|
-
return `${prefix}.${matchingKey}.largeSegment.${segmentName}`;
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
extractSegmentName(builtSegmentKeyName: string) {
|
|
64
|
-
const p = `${prefix}.${matchingKey}.largeSegment.`;
|
|
65
|
-
|
|
66
|
-
if (startsWith(builtSegmentKeyName, p)) return builtSegmentKeyName.substr(p.length);
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
extractOldSegmentKey() {
|
|
70
|
-
return undefined;
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
buildTillKey() {
|
|
74
|
-
return `${prefix}.${matchingKey}.largeSegments.till`;
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
48
|
}
|
|
@@ -1,85 +1,55 @@
|
|
|
1
1
|
import { SplitIO } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { getMatching } from '../utils/key';
|
|
2
|
+
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
3
|
+
import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
8
|
-
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
6
|
+
* Factory of client-side storage loader
|
|
9
7
|
*
|
|
10
|
-
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
11
|
-
*
|
|
12
|
-
* @
|
|
13
|
-
*
|
|
14
|
-
* @TODO extend to load largeSegments
|
|
15
|
-
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
16
|
-
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
17
|
-
* @TODO unit tests
|
|
8
|
+
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
9
|
+
* and extended with a `mySegmentsData` property.
|
|
10
|
+
* @returns function to preload the storage
|
|
18
11
|
*/
|
|
19
|
-
export function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
export function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
|
|
16
|
+
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
17
|
+
*
|
|
18
|
+
* @param storage object containing `splits` and `segments` cache (client-side variant)
|
|
19
|
+
* @param userId user key string of the provided MySegmentsCache
|
|
20
|
+
*
|
|
21
|
+
* @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
|
|
22
|
+
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
23
|
+
*/
|
|
24
|
+
return function loadData(storage: { splits: ISplitsCacheSync, segments: ISegmentsCacheSync }, userId: string) {
|
|
25
|
+
// Do not load data if current preloadedData is empty
|
|
26
|
+
if (Object.keys(preloadedData).length === 0) return;
|
|
27
|
+
|
|
28
|
+
const { lastUpdated = -1, segmentsData = {}, since = -1, splitsData = {} } = preloadedData;
|
|
24
29
|
|
|
25
|
-
if (storage.splits) {
|
|
26
30
|
const storedSince = storage.splits.getChangeNumber();
|
|
31
|
+
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
27
32
|
|
|
28
|
-
// Do not load data if current data is more recent
|
|
29
|
-
if
|
|
33
|
+
// Do not load data if current localStorage data is more recent,
|
|
34
|
+
// or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
35
|
+
if (storedSince > since || lastUpdated < expirationTimestamp) return;
|
|
30
36
|
|
|
31
37
|
// cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
|
|
32
38
|
storage.splits.clear();
|
|
33
39
|
storage.splits.setChangeNumber(since);
|
|
34
40
|
|
|
35
41
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
36
|
-
storage.splits.addSplits(splitsData.map(
|
|
37
|
-
}
|
|
42
|
+
storage.splits.addSplits(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])));
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[
|
|
44
|
+
// add mySegments data
|
|
45
|
+
let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
|
|
41
46
|
if (!mySegmentsData) {
|
|
42
47
|
// segmentsData in an object where the property is the segment name and the pertaining value is a stringified object that contains the `added` array of userIds
|
|
43
48
|
mySegmentsData = Object.keys(segmentsData).filter(segmentName => {
|
|
44
|
-
const
|
|
45
|
-
return
|
|
49
|
+
const userIds = JSON.parse(segmentsData[segmentName]).added;
|
|
50
|
+
return Array.isArray(userIds) && userIds.indexOf(userId) > -1;
|
|
46
51
|
});
|
|
47
52
|
}
|
|
48
|
-
storage.segments.resetSegments(
|
|
49
|
-
} else { // add segments data (server-side)
|
|
50
|
-
Object.keys(segmentsData).filter(segmentName => {
|
|
51
|
-
const matchingKeys = segmentsData[segmentName];
|
|
52
|
-
storage.segments.addToSegment(segmentName, matchingKeys);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function getSnapshot(storage: IStorageSync, userKeys?: SplitIO.SplitKey[]): SplitIO.PreloadedData {
|
|
58
|
-
return {
|
|
59
|
-
// lastUpdated: Date.now(),
|
|
60
|
-
since: storage.splits.getChangeNumber(),
|
|
61
|
-
splitsData: storage.splits.getAll(),
|
|
62
|
-
segmentsData: userKeys ?
|
|
63
|
-
undefined : // @ts-ignore accessing private prop
|
|
64
|
-
Object.keys(storage.segments.segmentCache).reduce((prev, cur) => { // @ts-ignore accessing private prop
|
|
65
|
-
prev[cur] = setToArray(storage.segments.segmentCache[cur] as ISet<string>);
|
|
66
|
-
return prev;
|
|
67
|
-
}, {}),
|
|
68
|
-
mySegmentsData: userKeys ?
|
|
69
|
-
userKeys.reduce<Record<string, string[]>>((prev, userKey) => {
|
|
70
|
-
prev[getMatching(userKey)] = storage.shared ?
|
|
71
|
-
// Client-side segments
|
|
72
|
-
// @ts-ignore accessing private prop
|
|
73
|
-
Object.keys(storage.shared(userKey).segments.segmentCache) :
|
|
74
|
-
// Server-side segments
|
|
75
|
-
// @ts-ignore accessing private prop
|
|
76
|
-
Object.keys(storage.segments.segmentCache).reduce<string[]>((prev, segmentName) => { // @ts-ignore accessing private prop
|
|
77
|
-
return storage.segments.segmentCache[segmentName].has(userKey) ?
|
|
78
|
-
prev.concat(segmentName) :
|
|
79
|
-
prev;
|
|
80
|
-
}, []);
|
|
81
|
-
return prev;
|
|
82
|
-
}, {}) :
|
|
83
|
-
undefined
|
|
53
|
+
storage.segments.resetSegments(mySegmentsData);
|
|
84
54
|
};
|
|
85
55
|
}
|
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
import { ILogger } from '../../logger/types';
|
|
2
|
-
import { isNaNNumber } from '../../utils/lang';
|
|
3
2
|
import { AbstractSegmentsCacheSync } from '../AbstractSegmentsCacheSync';
|
|
4
|
-
import
|
|
3
|
+
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
5
4
|
import { LOG_PREFIX, DEFINED } from './constants';
|
|
6
5
|
|
|
7
6
|
export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
8
7
|
|
|
9
|
-
private readonly keys:
|
|
8
|
+
private readonly keys: KeyBuilderCS;
|
|
10
9
|
private readonly log: ILogger;
|
|
11
10
|
|
|
12
|
-
constructor(log: ILogger, keys:
|
|
11
|
+
constructor(log: ILogger, keys: KeyBuilderCS) {
|
|
13
12
|
super();
|
|
14
13
|
this.log = log;
|
|
15
14
|
this.keys = keys;
|
|
16
15
|
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
|
|
17
16
|
}
|
|
18
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Removes list of segments from localStorage
|
|
20
|
+
* @NOTE this method is not being used at the moment.
|
|
21
|
+
*/
|
|
22
|
+
clear() {
|
|
23
|
+
this.log.info(LOG_PREFIX + 'Flushing MySegments data from localStorage');
|
|
24
|
+
|
|
25
|
+
// We cannot simply call `localStorage.clear()` since that implies removing user items from the storage
|
|
26
|
+
// We could optimize next sentence, since it implies iterating over all localStorage items
|
|
27
|
+
this.resetSegments([]);
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
addToSegment(name: string): boolean {
|
|
20
31
|
const segmentKey = this.keys.buildSegmentNameKey(name);
|
|
21
32
|
|
|
22
33
|
try {
|
|
23
|
-
if (localStorage.getItem(segmentKey) === DEFINED) return false;
|
|
24
34
|
localStorage.setItem(segmentKey, DEFINED);
|
|
25
35
|
return true;
|
|
26
36
|
} catch (e) {
|
|
@@ -33,7 +43,6 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
33
43
|
const segmentKey = this.keys.buildSegmentNameKey(name);
|
|
34
44
|
|
|
35
45
|
try {
|
|
36
|
-
if (localStorage.getItem(segmentKey) !== DEFINED) return false;
|
|
37
46
|
localStorage.removeItem(segmentKey);
|
|
38
47
|
return true;
|
|
39
48
|
} catch (e) {
|
|
@@ -46,22 +55,31 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
46
55
|
return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Reset (update) the cached list of segments with the given list, removing and adding segments if necessary.
|
|
60
|
+
*
|
|
61
|
+
* @param {string[]} segmentNames list of segment names
|
|
62
|
+
* @returns boolean indicating if the cache was updated (i.e., given list was different from the cached one)
|
|
63
|
+
*/
|
|
64
|
+
resetSegments(names: string[]): boolean {
|
|
65
|
+
let isDiff = false;
|
|
66
|
+
let index;
|
|
67
|
+
|
|
50
68
|
// Scan current values from localStorage
|
|
51
|
-
|
|
69
|
+
const storedSegmentNames = Object.keys(localStorage).reduce((accum, key) => {
|
|
52
70
|
let segmentName = this.keys.extractSegmentName(key);
|
|
53
71
|
|
|
54
72
|
if (segmentName) {
|
|
55
73
|
accum.push(segmentName);
|
|
56
74
|
} else {
|
|
57
|
-
// @TODO @BREAKING: This is only to clean up "old" keys. Remove this whole else code block
|
|
75
|
+
// @TODO @BREAKING: This is only to clean up "old" keys. Remove this whole else code block and reuse `getRegisteredSegments` method.
|
|
58
76
|
segmentName = this.keys.extractOldSegmentKey(key);
|
|
59
77
|
|
|
60
78
|
if (segmentName) { // this was an old segment key, let's clean up.
|
|
61
79
|
const newSegmentKey = this.keys.buildSegmentNameKey(segmentName);
|
|
62
80
|
try {
|
|
63
81
|
// If the new format key is not there, create it.
|
|
64
|
-
if (!localStorage.getItem(newSegmentKey)) {
|
|
82
|
+
if (!localStorage.getItem(newSegmentKey) && names.indexOf(segmentName) > -1) {
|
|
65
83
|
localStorage.setItem(newSegmentKey, DEFINED);
|
|
66
84
|
// we are migrating a segment, let's track it.
|
|
67
85
|
accum.push(segmentName);
|
|
@@ -75,32 +93,44 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
75
93
|
|
|
76
94
|
return accum;
|
|
77
95
|
}, [] as string[]);
|
|
78
|
-
}
|
|
79
96
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
// Extreme fast => everything is empty
|
|
98
|
+
if (names.length === 0 && storedSegmentNames.length === names.length)
|
|
99
|
+
return isDiff;
|
|
83
100
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
else localStorage.removeItem(this.keys.buildTillKey());
|
|
88
|
-
} catch (e) {
|
|
89
|
-
this.log.error(e);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
101
|
+
// Quick path
|
|
102
|
+
if (storedSegmentNames.length !== names.length) {
|
|
103
|
+
isDiff = true;
|
|
92
104
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
storedSegmentNames.forEach(name => this.removeFromSegment(name));
|
|
106
|
+
names.forEach(name => this.addToSegment(name));
|
|
107
|
+
} else {
|
|
108
|
+
// Slowest path => we need to find at least 1 difference because
|
|
109
|
+
for (index = 0; index < names.length && storedSegmentNames.indexOf(names[index]) !== -1; index++) {
|
|
110
|
+
// TODO: why empty statement?
|
|
111
|
+
}
|
|
96
112
|
|
|
97
|
-
|
|
98
|
-
|
|
113
|
+
if (index < names.length) {
|
|
114
|
+
isDiff = true;
|
|
99
115
|
|
|
100
|
-
|
|
116
|
+
storedSegmentNames.forEach(name => this.removeFromSegment(name));
|
|
117
|
+
names.forEach(name => this.addToSegment(name));
|
|
118
|
+
}
|
|
101
119
|
}
|
|
102
120
|
|
|
103
|
-
return
|
|
121
|
+
return isDiff;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getRegisteredSegments(): string[] {
|
|
125
|
+
return Object.keys(localStorage).reduce<string[]>((accum, key) => {
|
|
126
|
+
const segmentName = this.keys.extractSegmentName(key);
|
|
127
|
+
if (segmentName) accum.push(segmentName);
|
|
128
|
+
return accum;
|
|
129
|
+
}, []);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getKeysCount() {
|
|
133
|
+
return 1;
|
|
104
134
|
}
|
|
105
135
|
|
|
106
136
|
}
|
|
@@ -217,6 +217,15 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Check if the splits information is already stored in browser LocalStorage.
|
|
222
|
+
* In this function we could add more code to check if the data is valid.
|
|
223
|
+
* @override
|
|
224
|
+
*/
|
|
225
|
+
checkCache(): boolean {
|
|
226
|
+
return this.getChangeNumber() > -1;
|
|
227
|
+
}
|
|
228
|
+
|
|
220
229
|
/**
|
|
221
230
|
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
222
231
|
*
|
|
@@ -241,7 +250,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
241
250
|
this.updateNewFilter = true;
|
|
242
251
|
|
|
243
252
|
// if there is cache, clear it
|
|
244
|
-
if (this.
|
|
253
|
+
if (this.checkCache()) this.clear();
|
|
245
254
|
|
|
246
255
|
} catch (e) {
|
|
247
256
|
this.log.error(LOG_PREFIX + e);
|