@splitsoftware/splitio-commons 2.4.2-rc.3 → 2.5.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGES.txt +2 -10
  2. package/cjs/storages/dataLoader.js +102 -43
  3. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  4. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  5. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  6. package/cjs/storages/inLocalStorage/index.js +13 -31
  7. package/cjs/storages/inLocalStorage/validateCache.js +23 -28
  8. package/cjs/storages/inMemory/InMemoryStorageCS.js +32 -14
  9. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  10. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  11. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  12. package/cjs/sync/polling/updaters/splitChangesUpdater.js +0 -2
  13. package/cjs/sync/syncManagerOnline.js +24 -28
  14. package/cjs/utils/env/isLocalStorageAvailable.js +5 -28
  15. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  16. package/esm/storages/dataLoader.js +99 -41
  17. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  18. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  19. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  20. package/esm/storages/inLocalStorage/index.js +14 -32
  21. package/esm/storages/inLocalStorage/validateCache.js +23 -28
  22. package/esm/storages/inMemory/InMemoryStorageCS.js +32 -14
  23. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  24. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  25. package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  26. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -2
  27. package/esm/sync/syncManagerOnline.js +24 -28
  28. package/esm/utils/env/isLocalStorageAvailable.js +3 -24
  29. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  30. package/package.json +1 -1
  31. package/src/sdkFactory/index.ts +3 -2
  32. package/src/storages/dataLoader.ts +107 -49
  33. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +17 -18
  34. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -19
  35. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +37 -34
  36. package/src/storages/inLocalStorage/index.ts +16 -37
  37. package/src/storages/inLocalStorage/validateCache.ts +23 -29
  38. package/src/storages/inMemory/InMemoryStorageCS.ts +37 -14
  39. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +4 -0
  40. package/src/storages/types.ts +6 -22
  41. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +2 -1
  42. package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -2
  43. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -3
  44. package/src/sync/syncManagerOnline.ts +22 -27
  45. package/src/types.ts +0 -35
  46. package/src/utils/env/isLocalStorageAvailable.ts +3 -24
  47. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  48. package/types/splitio.d.ts +46 -42
  49. package/cjs/storages/inLocalStorage/storageAdapter.js +0 -54
  50. package/esm/storages/inLocalStorage/storageAdapter.js +0 -50
  51. package/src/storages/inLocalStorage/storageAdapter.ts +0 -62
@@ -66,39 +66,35 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
66
66
  */
67
67
  start: function () {
68
68
  running = true;
69
- // @TODO once event, impression and telemetry storages support persistence, call when `validateCache` promise is resolved
70
- submitterManager.start(!isConsentGranted(settings));
71
- return Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
72
- if (!running)
73
- return;
74
- if (startFirstTime) {
75
- // Emits SDK_READY_FROM_CACHE
76
- if (isCacheLoaded)
77
- readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
78
- }
79
- // start syncing splits and segments
80
- if (pollingManager) {
81
- // If synchronization is disabled pushManager and pollingManager should not start
82
- if (syncEnabled) {
83
- if (pushManager) {
84
- // Doesn't call `syncAll` when the syncManager is resuming
85
- if (startFirstTime) {
86
- pollingManager.syncAll();
87
- }
88
- pushManager.start();
89
- }
90
- else {
91
- pollingManager.start();
92
- }
93
- }
94
- else {
69
+ if (startFirstTime) {
70
+ var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
71
+ if (isCacheLoaded)
72
+ Promise.resolve().then(function () { readiness.splits.emit(SDK_SPLITS_CACHE_LOADED); });
73
+ }
74
+ // start syncing splits and segments
75
+ if (pollingManager) {
76
+ // If synchronization is disabled pushManager and pollingManager should not start
77
+ if (syncEnabled) {
78
+ if (pushManager) {
79
+ // Doesn't call `syncAll` when the syncManager is resuming
95
80
  if (startFirstTime) {
96
81
  pollingManager.syncAll();
97
82
  }
83
+ pushManager.start();
84
+ }
85
+ else {
86
+ pollingManager.start();
87
+ }
88
+ }
89
+ else {
90
+ if (startFirstTime) {
91
+ pollingManager.syncAll();
98
92
  }
99
93
  }
100
- startFirstTime = false;
101
- });
94
+ }
95
+ // start periodic data recording (events, impressions, telemetry).
96
+ submitterManager.start(!isConsentGranted(settings));
97
+ startFirstTime = false;
102
98
  },
103
99
  /**
104
100
  * Method used to stop/pause the syncManager.
@@ -1,33 +1,12 @@
1
+ /* eslint-disable no-undef */
1
2
  export function isLocalStorageAvailable() {
2
- try {
3
- // eslint-disable-next-line no-undef
4
- return isValidStorageWrapper(localStorage);
5
- }
6
- catch (e) {
7
- return false;
8
- }
9
- }
10
- export function isValidStorageWrapper(wrapper) {
11
3
  var mod = '__SPLITSOFTWARE__';
12
4
  try {
13
- wrapper.setItem(mod, mod);
14
- wrapper.getItem(mod);
15
- wrapper.removeItem(mod);
5
+ localStorage.setItem(mod, mod);
6
+ localStorage.removeItem(mod);
16
7
  return true;
17
8
  }
18
9
  catch (e) {
19
10
  return false;
20
11
  }
21
12
  }
22
- export function isWebStorage(wrapper) {
23
- if (typeof wrapper.length === 'number') {
24
- try {
25
- wrapper.key(0);
26
- return true;
27
- }
28
- catch (e) {
29
- return false;
30
- }
31
- }
32
- return false;
33
- }
@@ -3,7 +3,7 @@ import { ERROR_STORAGE_INVALID } from '../../../logger/constants';
3
3
  import { LOCALHOST_MODE, STANDALONE_MODE, STORAGE_PLUGGABLE, STORAGE_LOCALSTORAGE, STORAGE_MEMORY } from '../../../utils/constants';
4
4
  export function __InLocalStorageMockFactory(params) {
5
5
  var result = InMemoryStorageCSFactory(params);
6
- result.validateCache = function () { return Promise.resolve(true); }; // to emit SDK_READY_FROM_CACHE
6
+ result.validateCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
7
7
  return result;
8
8
  }
9
9
  __InLocalStorageMockFactory.type = STORAGE_MEMORY;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.4.2-rc.3",
3
+ "version": "2.5.0-rc.0",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -43,7 +43,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
43
43
 
44
44
  const storage = storageFactory({
45
45
  settings,
46
- onReadyCb: (error) => {
46
+ onReadyCb(error) {
47
47
  if (error) {
48
48
  // If storage fails to connect, SDK_READY_TIMED_OUT event is emitted immediately. Review when timeout and non-recoverable errors are reworked
49
49
  readiness.timeout();
@@ -52,10 +52,11 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
52
52
  readiness.splits.emit(SDK_SPLITS_ARRIVED);
53
53
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
54
54
  },
55
- onReadyFromCacheCb: () => {
55
+ onReadyFromCacheCb() {
56
56
  readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
57
57
  }
58
58
  });
59
+
59
60
  // @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
60
61
  const clients: Record<string, SplitIO.IBasicClient> = {};
61
62
  const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
@@ -1,55 +1,113 @@
1
- import { PreloadedData } from '../types';
2
- import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
3
-
4
- // This value might be eventually set via a config parameter
5
- const DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
1
+ import SplitIO from '../../types/splitio';
2
+ import { IRBSegmentsCacheSync, ISegmentsCacheSync, ISplitsCacheSync, IStorageSync } from './types';
3
+ import { setToArray } from '../utils/lang/sets';
4
+ import { getMatching } from '../utils/key';
5
+ import { IMembershipsResponse, IMySegmentsResponse, IRBSegment, ISplit } from '../dtos/types';
6
+ import { ILogger } from '../logger/types';
6
7
 
7
8
  /**
8
- * Factory of client-side storage loader
9
- *
10
- * @param preloadedData - validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
11
- * and extended with a `mySegmentsData` property.
12
- * @returns function to preload the storage
9
+ * Sets the given synchronous storage with the provided preloaded data snapshot.
10
+ * If `matchingKey` is provided, the storage is handled as a client-side storage (segments and largeSegments are instances of MySegmentsCache).
11
+ * Otherwise, the storage is handled as a server-side storage (segments is an instance of SegmentsCache).
13
12
  */
14
- export function dataLoaderFactory(preloadedData: PreloadedData): DataLoader {
15
-
16
- /**
17
- * Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
18
- * (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
19
- *
20
- * @param storage - object containing `splits` and `segments` cache (client-side variant)
21
- * @param userId - user key string of the provided MySegmentsCache
22
- */
23
- // @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
24
- // @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.
25
- return function loadData(storage: { splits: ISplitsCacheSync, segments: ISegmentsCacheSync }, userId: string) {
26
- // Do not load data if current preloadedData is empty
27
- if (Object.keys(preloadedData).length === 0) return;
28
-
29
- const { lastUpdated = -1, segmentsData = {}, since = -1, splitsData = {} } = preloadedData;
30
-
31
- const storedSince = storage.splits.getChangeNumber();
32
- const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
33
-
34
- // Do not load data if current localStorage data is more recent,
35
- // or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
36
- if (storedSince > since || lastUpdated < expirationTimestamp) return;
37
-
38
- // cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
39
- storage.splits.clear();
40
-
41
- // splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
42
- storage.splits.update(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])), [], since);
43
-
44
- // add mySegments data
45
- let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
46
- if (!mySegmentsData) {
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
48
- mySegmentsData = Object.keys(segmentsData).filter(segmentName => {
49
- const userIds = JSON.parse(segmentsData[segmentName]).added;
50
- return Array.isArray(userIds) && userIds.indexOf(userId) > -1;
51
- });
13
+ export function setCache(log: ILogger, preloadedData: SplitIO.PreloadedData, storage: { splits?: ISplitsCacheSync, rbSegments?: IRBSegmentsCacheSync, segments: ISegmentsCacheSync, largeSegments?: ISegmentsCacheSync }, matchingKey?: string) {
14
+ // Do not load data if current preloadedData is empty
15
+ if (Object.keys(preloadedData).length === 0) return;
16
+
17
+ const { splits, rbSegments, segments, largeSegments } = storage;
18
+
19
+ log.debug(`set cache${matchingKey ? ` for key ${matchingKey}` : ''}`);
20
+
21
+ if (splits) {
22
+ splits.clear();
23
+ splits.update(preloadedData.flags as ISplit[] || [], [], preloadedData.since || -1);
24
+ }
25
+
26
+ if (rbSegments) {
27
+ rbSegments.clear();
28
+ rbSegments.update(preloadedData.rbSegments as IRBSegment[] || [], [], preloadedData.rbSince || -1);
29
+ }
30
+
31
+ const segmentsData = preloadedData.segments || {};
32
+ if (matchingKey) { // add memberships data (client-side)
33
+ let memberships = preloadedData.memberships && preloadedData.memberships[matchingKey];
34
+ if (!memberships && segmentsData) {
35
+ memberships = {
36
+ ms: {
37
+ k: Object.keys(segmentsData).filter(segmentName => {
38
+ const segmentKeys = segmentsData[segmentName];
39
+ return segmentKeys.indexOf(matchingKey) > -1;
40
+ }).map(segmentName => ({ n: segmentName }))
41
+ }
42
+ };
43
+ }
44
+
45
+ if (memberships) {
46
+ if ((memberships as IMembershipsResponse).ms) segments.resetSegments((memberships as IMembershipsResponse).ms!);
47
+ if ((memberships as IMembershipsResponse).ls && largeSegments) largeSegments.resetSegments((memberships as IMembershipsResponse).ls!);
52
48
  }
53
- storage.segments.resetSegments({ k: mySegmentsData.map(s => ({ n: s })) });
49
+ } else { // add segments data (server-side)
50
+ Object.keys(segmentsData).forEach(segmentName => {
51
+ const segmentKeys = segmentsData[segmentName];
52
+ segments.update(segmentName, segmentKeys, [], -1);
53
+ });
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Gets the preloaded data snapshot from the given synchronous storage.
59
+ * If `keys` are provided, the memberships for those keys is returned, to protect segments data.
60
+ * Otherwise, the segments data is returned.
61
+ */
62
+ export function getCache(log: ILogger, storage: IStorageSync, keys?: SplitIO.SplitKey[]): SplitIO.PreloadedData {
63
+
64
+ log.debug(`get cache${keys ? ` for keys ${keys}` : ''}`);
65
+
66
+ return {
67
+ since: storage.splits.getChangeNumber(),
68
+ flags: storage.splits.getAll(),
69
+ rbSince: storage.rbSegments.getChangeNumber(),
70
+ rbSegments: storage.rbSegments.getAll(),
71
+ segments: keys ?
72
+ undefined : // @ts-ignore accessing private prop
73
+ Object.keys(storage.segments.segmentCache).reduce((prev, cur) => { // @ts-ignore accessing private prop
74
+ prev[cur] = setToArray(storage.segments.segmentCache[cur] as Set<string>);
75
+ return prev;
76
+ }, {}),
77
+ memberships: keys ?
78
+ keys.reduce<Record<string, IMembershipsResponse>>((prev, key) => {
79
+ if (storage.shared) {
80
+ // Client-side segments
81
+ // @ts-ignore accessing private prop
82
+ const sharedStorage = storage.shared(key);
83
+ prev[getMatching(key)] = {
84
+ ms: {
85
+ // @ts-ignore accessing private prop
86
+ k: Object.keys(sharedStorage.segments.segmentCache).map(segmentName => ({ n: segmentName })),
87
+ },
88
+ ls: sharedStorage.largeSegments ? {
89
+ // @ts-ignore accessing private prop
90
+ k: Object.keys(sharedStorage.largeSegments.segmentCache).map(segmentName => ({ n: segmentName })),
91
+ } : undefined
92
+ };
93
+ } else {
94
+ prev[getMatching(key)] = {
95
+ ms: {
96
+ // Server-side segments
97
+ // @ts-ignore accessing private prop
98
+ k: Object.keys(storage.segments.segmentCache).reduce<IMySegmentsResponse['k']>((prev, segmentName) => { // @ts-ignore accessing private prop
99
+ return storage.segments.segmentCache[segmentName].has(key) ?
100
+ prev!.concat({ n: segmentName }) :
101
+ prev;
102
+ }, [])
103
+ },
104
+ ls: {
105
+ k: []
106
+ }
107
+ };
108
+ }
109
+ return prev;
110
+ }, {}) :
111
+ undefined
54
112
  };
55
113
  }
@@ -3,19 +3,16 @@ import { isNaNNumber } from '../../utils/lang';
3
3
  import { AbstractMySegmentsCacheSync } from '../AbstractMySegmentsCacheSync';
4
4
  import type { MySegmentsKeyBuilder } from '../KeyBuilderCS';
5
5
  import { LOG_PREFIX, DEFINED } from './constants';
6
- import { StorageAdapter } from '../types';
7
6
 
8
7
  export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
9
8
 
10
9
  private readonly keys: MySegmentsKeyBuilder;
11
10
  private readonly log: ILogger;
12
- private readonly storage: StorageAdapter;
13
11
 
14
- constructor(log: ILogger, keys: MySegmentsKeyBuilder, storage: StorageAdapter) {
12
+ constructor(log: ILogger, keys: MySegmentsKeyBuilder) {
15
13
  super();
16
14
  this.log = log;
17
15
  this.keys = keys;
18
- this.storage = storage;
19
16
  // There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
20
17
  }
21
18
 
@@ -23,8 +20,8 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
23
20
  const segmentKey = this.keys.buildSegmentNameKey(name);
24
21
 
25
22
  try {
26
- if (this.storage.getItem(segmentKey) === DEFINED) return false;
27
- this.storage.setItem(segmentKey, DEFINED);
23
+ if (localStorage.getItem(segmentKey) === DEFINED) return false;
24
+ localStorage.setItem(segmentKey, DEFINED);
28
25
  return true;
29
26
  } catch (e) {
30
27
  this.log.error(LOG_PREFIX + e);
@@ -36,8 +33,8 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
36
33
  const segmentKey = this.keys.buildSegmentNameKey(name);
37
34
 
38
35
  try {
39
- if (this.storage.getItem(segmentKey) !== DEFINED) return false;
40
- this.storage.removeItem(segmentKey);
36
+ if (localStorage.getItem(segmentKey) !== DEFINED) return false;
37
+ localStorage.removeItem(segmentKey);
41
38
  return true;
42
39
  } catch (e) {
43
40
  this.log.error(LOG_PREFIX + e);
@@ -46,16 +43,18 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
46
43
  }
47
44
 
48
45
  isInSegment(name: string): boolean {
49
- return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
46
+ return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
50
47
  }
51
48
 
52
49
  getRegisteredSegments(): string[] {
53
- const registeredSegments: string[] = [];
54
- for (let i = 0, len = this.storage.length; i < len; i++) {
55
- const segmentName = this.keys.extractSegmentName(this.storage.key(i)!);
56
- if (segmentName) registeredSegments.push(segmentName);
57
- }
58
- return registeredSegments;
50
+ // Scan current values from localStorage
51
+ return Object.keys(localStorage).reduce((accum, key) => {
52
+ let segmentName = this.keys.extractSegmentName(key);
53
+
54
+ if (segmentName) accum.push(segmentName);
55
+
56
+ return accum;
57
+ }, [] as string[]);
59
58
  }
60
59
 
61
60
  getKeysCount() {
@@ -64,8 +63,8 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
64
63
 
65
64
  protected setChangeNumber(changeNumber?: number) {
66
65
  try {
67
- if (changeNumber) this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
68
- else this.storage.removeItem(this.keys.buildTillKey());
66
+ if (changeNumber) localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
67
+ else localStorage.removeItem(this.keys.buildTillKey());
69
68
  } catch (e) {
70
69
  this.log.error(e);
71
70
  }
@@ -73,7 +72,7 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
73
72
 
74
73
  getChangeNumber() {
75
74
  const n = -1;
76
- let value: string | number | null = this.storage.getItem(this.keys.buildTillKey());
75
+ let value: string | number | null = localStorage.getItem(this.keys.buildTillKey());
77
76
 
78
77
  if (value !== null) {
79
78
  value = parseInt(value, 10);
@@ -5,24 +5,22 @@ import { isFiniteNumber, isNaNNumber, toNumber } from '../../utils/lang';
5
5
  import { setToArray } from '../../utils/lang/sets';
6
6
  import { usesSegments } from '../AbstractSplitsCacheSync';
7
7
  import { KeyBuilderCS } from '../KeyBuilderCS';
8
- import { IRBSegmentsCacheSync, StorageAdapter } from '../types';
8
+ import { IRBSegmentsCacheSync } from '../types';
9
9
  import { LOG_PREFIX } from './constants';
10
10
 
11
11
  export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
12
12
 
13
13
  private readonly keys: KeyBuilderCS;
14
14
  private readonly log: ILogger;
15
- private readonly storage: StorageAdapter;
16
15
 
17
- constructor(settings: ISettings, keys: KeyBuilderCS, storage: StorageAdapter) {
16
+ constructor(settings: ISettings, keys: KeyBuilderCS) {
18
17
  this.keys = keys;
19
18
  this.log = settings.log;
20
- this.storage = storage;
21
19
  }
22
20
 
23
21
  clear() {
24
22
  this.getNames().forEach(name => this.remove(name));
25
- this.storage.removeItem(this.keys.buildRBSegmentsTillKey());
23
+ localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
26
24
  }
27
25
 
28
26
  update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
@@ -33,8 +31,8 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
33
31
 
34
32
  private setChangeNumber(changeNumber: number) {
35
33
  try {
36
- this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
37
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
34
+ localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
35
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
38
36
  } catch (e) {
39
37
  this.log.error(LOG_PREFIX + e);
40
38
  }
@@ -42,19 +40,20 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
42
40
 
43
41
  private updateSegmentCount(diff: number) {
44
42
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
45
- const count = toNumber(this.storage.getItem(segmentsCountKey)) + diff;
46
- if (count > 0) this.storage.setItem(segmentsCountKey, count + '');
47
- else this.storage.removeItem(segmentsCountKey);
43
+ const count = toNumber(localStorage.getItem(segmentsCountKey)) + diff;
44
+ // @ts-expect-error
45
+ if (count > 0) localStorage.setItem(segmentsCountKey, count);
46
+ else localStorage.removeItem(segmentsCountKey);
48
47
  }
49
48
 
50
49
  private add(rbSegment: IRBSegment): boolean {
51
50
  try {
52
51
  const name = rbSegment.name;
53
52
  const rbSegmentKey = this.keys.buildRBSegmentKey(name);
54
- const rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
55
- const previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
53
+ const rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
54
+ const previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
56
55
 
57
- this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
56
+ localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
58
57
 
59
58
  let usesSegmentsDiff = 0;
60
59
  if (previous && usesSegments(previous)) usesSegmentsDiff--;
@@ -73,7 +72,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
73
72
  const rbSegment = this.get(name);
74
73
  if (!rbSegment) return false;
75
74
 
76
- this.storage.removeItem(this.keys.buildRBSegmentKey(name));
75
+ localStorage.removeItem(this.keys.buildRBSegmentKey(name));
77
76
 
78
77
  if (usesSegments(rbSegment)) this.updateSegmentCount(-1);
79
78
 
@@ -85,13 +84,13 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
85
84
  }
86
85
 
87
86
  private getNames(): string[] {
88
- const len = this.storage.length;
87
+ const len = localStorage.length;
89
88
  const accum = [];
90
89
 
91
90
  let cur = 0;
92
91
 
93
92
  while (cur < len) {
94
- const key = this.storage.key(cur);
93
+ const key = localStorage.key(cur);
95
94
 
96
95
  if (key != null && this.keys.isRBSegmentKey(key)) accum.push(this.keys.extractKey(key));
97
96
 
@@ -102,10 +101,14 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
102
101
  }
103
102
 
104
103
  get(name: string): IRBSegment | null {
105
- const item = this.storage.getItem(this.keys.buildRBSegmentKey(name));
104
+ const item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
106
105
  return item && JSON.parse(item);
107
106
  }
108
107
 
108
+ getAll(): IRBSegment[] {
109
+ return this.getNames().map(key => this.get(key)!);
110
+ }
111
+
109
112
  contains(names: Set<string>): boolean {
110
113
  const namesArray = setToArray(names);
111
114
  const namesInStorage = this.getNames();
@@ -114,7 +117,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
114
117
 
115
118
  getChangeNumber(): number {
116
119
  const n = -1;
117
- let value: string | number | null = this.storage.getItem(this.keys.buildRBSegmentsTillKey());
120
+ let value: string | number | null = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
118
121
 
119
122
  if (value !== null) {
120
123
  value = parseInt(value, 10);
@@ -126,7 +129,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
126
129
  }
127
130
 
128
131
  usesSegments(): boolean {
129
- const storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
132
+ const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
130
133
  const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
131
134
 
132
135
  return isFiniteNumber(splitsWithSegmentsCount) ?