@splitsoftware/splitio-commons 2.4.2-rc.2 → 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/AbstractMySegmentsCacheSync.js +23 -31
  3. package/cjs/storages/AbstractSplitsCacheSync.js +2 -3
  4. package/cjs/storages/dataLoader.js +102 -43
  5. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  6. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +23 -20
  7. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  8. package/cjs/storages/inLocalStorage/index.js +13 -28
  9. package/cjs/storages/inLocalStorage/validateCache.js +23 -25
  10. package/cjs/storages/inMemory/InMemoryStorageCS.js +32 -14
  11. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  12. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -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/AbstractMySegmentsCacheSync.js +23 -31
  17. package/esm/storages/AbstractSplitsCacheSync.js +2 -3
  18. package/esm/storages/dataLoader.js +99 -41
  19. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  20. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +23 -20
  21. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  22. package/esm/storages/inLocalStorage/index.js +14 -29
  23. package/esm/storages/inLocalStorage/validateCache.js +23 -25
  24. package/esm/storages/inMemory/InMemoryStorageCS.js +32 -14
  25. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  26. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -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/AbstractMySegmentsCacheSync.ts +20 -26
  33. package/src/storages/AbstractSplitsCacheSync.ts +2 -3
  34. package/src/storages/dataLoader.ts +107 -49
  35. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +17 -18
  36. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +24 -22
  37. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +37 -34
  38. package/src/storages/inLocalStorage/index.ts +16 -33
  39. package/src/storages/inLocalStorage/validateCache.ts +23 -26
  40. package/src/storages/inMemory/InMemoryStorageCS.ts +37 -14
  41. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +4 -0
  42. package/src/storages/types.ts +6 -20
  43. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +2 -1
  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 -27
  49. package/cjs/storages/inLocalStorage/storageAdapter.js +0 -48
  50. package/esm/storages/inLocalStorage/storageAdapter.js +0 -44
  51. package/src/storages/inLocalStorage/storageAdapter.ts +0 -50
@@ -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; i < this.storage.length; 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,37 +5,34 @@ 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 {
29
- let updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
30
- updated = toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
31
27
  this.setChangeNumber(changeNumber);
32
- return updated;
28
+ const updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
29
+ return toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
33
30
  }
34
31
 
35
32
  private setChangeNumber(changeNumber: number) {
36
33
  try {
37
- this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
38
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
34
+ localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
35
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
39
36
  } catch (e) {
40
37
  this.log.error(LOG_PREFIX + e);
41
38
  }
@@ -43,19 +40,20 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
43
40
 
44
41
  private updateSegmentCount(diff: number) {
45
42
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
46
- const count = toNumber(this.storage.getItem(segmentsCountKey)) + diff;
47
- if (count > 0) this.storage.setItem(segmentsCountKey, count + '');
48
- 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);
49
47
  }
50
48
 
51
49
  private add(rbSegment: IRBSegment): boolean {
52
50
  try {
53
51
  const name = rbSegment.name;
54
52
  const rbSegmentKey = this.keys.buildRBSegmentKey(name);
55
- const rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
56
- const previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
53
+ const rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
54
+ const previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
57
55
 
58
- this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
56
+ localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
59
57
 
60
58
  let usesSegmentsDiff = 0;
61
59
  if (previous && usesSegments(previous)) usesSegmentsDiff--;
@@ -74,7 +72,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
74
72
  const rbSegment = this.get(name);
75
73
  if (!rbSegment) return false;
76
74
 
77
- this.storage.removeItem(this.keys.buildRBSegmentKey(name));
75
+ localStorage.removeItem(this.keys.buildRBSegmentKey(name));
78
76
 
79
77
  if (usesSegments(rbSegment)) this.updateSegmentCount(-1);
80
78
 
@@ -86,13 +84,13 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
86
84
  }
87
85
 
88
86
  private getNames(): string[] {
89
- const len = this.storage.length;
87
+ const len = localStorage.length;
90
88
  const accum = [];
91
89
 
92
90
  let cur = 0;
93
91
 
94
92
  while (cur < len) {
95
- const key = this.storage.key(cur);
93
+ const key = localStorage.key(cur);
96
94
 
97
95
  if (key != null && this.keys.isRBSegmentKey(key)) accum.push(this.keys.extractKey(key));
98
96
 
@@ -103,10 +101,14 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
103
101
  }
104
102
 
105
103
  get(name: string): IRBSegment | null {
106
- const item = this.storage.getItem(this.keys.buildRBSegmentKey(name));
104
+ const item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
107
105
  return item && JSON.parse(item);
108
106
  }
109
107
 
108
+ getAll(): IRBSegment[] {
109
+ return this.getNames().map(key => this.get(key)!);
110
+ }
111
+
110
112
  contains(names: Set<string>): boolean {
111
113
  const namesArray = setToArray(names);
112
114
  const namesInStorage = this.getNames();
@@ -115,7 +117,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
115
117
 
116
118
  getChangeNumber(): number {
117
119
  const n = -1;
118
- let value: string | number | null = this.storage.getItem(this.keys.buildRBSegmentsTillKey());
120
+ let value: string | number | null = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
119
121
 
120
122
  if (value !== null) {
121
123
  value = parseInt(value, 10);
@@ -127,7 +129,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
127
129
  }
128
130
 
129
131
  usesSegments(): boolean {
130
- const storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
132
+ const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
131
133
  const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
132
134
 
133
135
  return isFiniteNumber(splitsWithSegmentsCount) ?
@@ -6,28 +6,29 @@ import { ILogger } from '../../logger/types';
6
6
  import { LOG_PREFIX } from './constants';
7
7
  import { ISettings } from '../../types';
8
8
  import { setToArray } from '../../utils/lang/sets';
9
- import { StorageAdapter } from '../types';
10
9
 
10
+ /**
11
+ * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
12
+ */
11
13
  export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
12
14
 
13
15
  private readonly keys: KeyBuilderCS;
14
16
  private readonly log: ILogger;
15
17
  private readonly flagSetsFilter: string[];
16
18
  private hasSync?: boolean;
17
- private readonly storage: StorageAdapter;
18
19
 
19
- constructor(settings: ISettings, keys: KeyBuilderCS, storage: StorageAdapter) {
20
+ constructor(settings: ISettings, keys: KeyBuilderCS) {
20
21
  super();
21
22
  this.keys = keys;
22
23
  this.log = settings.log;
23
24
  this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
24
- this.storage = storage;
25
25
  }
26
26
 
27
27
  private _decrementCount(key: string) {
28
- const count = toNumber(this.storage.getItem(key)) - 1;
29
- if (count > 0) this.storage.setItem(key, count + '');
30
- else this.storage.removeItem(key);
28
+ const count = toNumber(localStorage.getItem(key)) - 1;
29
+ // @ts-expect-error
30
+ if (count > 0) localStorage.setItem(key, count);
31
+ else localStorage.removeItem(key);
31
32
  }
32
33
 
33
34
  private _decrementCounts(split: ISplit) {
@@ -47,11 +48,13 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
47
48
  private _incrementCounts(split: ISplit) {
48
49
  try {
49
50
  const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
50
- this.storage.setItem(ttKey, (toNumber(this.storage.getItem(ttKey)) + 1) + '');
51
+ // @ts-expect-error
52
+ localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
51
53
 
52
54
  if (usesSegments(split)) {
53
55
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
54
- this.storage.setItem(segmentsCountKey, (toNumber(this.storage.getItem(segmentsCountKey)) + 1) + '');
56
+ // @ts-expect-error
57
+ localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
55
58
  }
56
59
  } catch (e) {
57
60
  this.log.error(LOG_PREFIX + e);
@@ -65,15 +68,15 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
65
68
  */
66
69
  clear() {
67
70
  // collect item keys
68
- const len = this.storage.length;
71
+ const len = localStorage.length;
69
72
  const accum = [];
70
73
  for (let cur = 0; cur < len; cur++) {
71
- const key = this.storage.key(cur);
74
+ const key = localStorage.key(cur);
72
75
  if (key != null && this.keys.isSplitsCacheKey(key)) accum.push(key);
73
76
  }
74
77
  // remove items
75
78
  accum.forEach(key => {
76
- this.storage.removeItem(key);
79
+ localStorage.removeItem(key);
77
80
  });
78
81
 
79
82
  this.hasSync = false;
@@ -83,15 +86,15 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
83
86
  try {
84
87
  const name = split.name;
85
88
  const splitKey = this.keys.buildSplitKey(name);
86
- const splitFromStorage = this.storage.getItem(splitKey);
87
- const previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
89
+ const splitFromLocalStorage = localStorage.getItem(splitKey);
90
+ const previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
88
91
 
89
92
  if (previousSplit) {
90
93
  this._decrementCounts(previousSplit);
91
94
  this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
92
95
  }
93
96
 
94
- this.storage.setItem(splitKey, JSON.stringify(split));
97
+ localStorage.setItem(splitKey, JSON.stringify(split));
95
98
 
96
99
  this._incrementCounts(split);
97
100
  this.addToFlagSets(split);
@@ -108,7 +111,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
108
111
  const split = this.getSplit(name);
109
112
  if (!split) return false;
110
113
 
111
- this.storage.removeItem(this.keys.buildSplitKey(name));
114
+ localStorage.removeItem(this.keys.buildSplitKey(name));
112
115
 
113
116
  this._decrementCounts(split);
114
117
  this.removeFromFlagSets(split.name, split.sets);
@@ -121,15 +124,15 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
121
124
  }
122
125
 
123
126
  getSplit(name: string): ISplit | null {
124
- const item = this.storage.getItem(this.keys.buildSplitKey(name));
127
+ const item = localStorage.getItem(this.keys.buildSplitKey(name));
125
128
  return item && JSON.parse(item);
126
129
  }
127
130
 
128
131
  setChangeNumber(changeNumber: number): boolean {
129
132
  try {
130
- this.storage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
133
+ localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
131
134
  // update "last updated" timestamp with current time
132
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
135
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
133
136
  this.hasSync = true;
134
137
  return true;
135
138
  } catch (e) {
@@ -140,7 +143,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
140
143
 
141
144
  getChangeNumber(): number {
142
145
  const n = -1;
143
- let value: string | number | null = this.storage.getItem(this.keys.buildSplitsTillKey());
146
+ let value: string | number | null = localStorage.getItem(this.keys.buildSplitsTillKey());
144
147
 
145
148
  if (value !== null) {
146
149
  value = parseInt(value, 10);
@@ -152,13 +155,13 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
152
155
  }
153
156
 
154
157
  getSplitNames(): string[] {
155
- const len = this.storage.length;
158
+ const len = localStorage.length;
156
159
  const accum = [];
157
160
 
158
161
  let cur = 0;
159
162
 
160
163
  while (cur < len) {
161
- const key = this.storage.key(cur);
164
+ const key = localStorage.key(cur);
162
165
 
163
166
  if (key != null && this.keys.isSplitKey(key)) accum.push(this.keys.extractKey(key));
164
167
 
@@ -169,7 +172,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
169
172
  }
170
173
 
171
174
  trafficTypeExists(trafficType: string): boolean {
172
- const ttCount = toNumber(this.storage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
175
+ const ttCount = toNumber(localStorage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
173
176
  return isFiniteNumber(ttCount) && ttCount > 0;
174
177
  }
175
178
 
@@ -177,7 +180,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
177
180
  // If cache hasn't been synchronized with the cloud, assume we need them.
178
181
  if (!this.hasSync) return true;
179
182
 
180
- const storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
183
+ const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
181
184
  const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
182
185
 
183
186
  return isFiniteNumber(splitsWithSegmentsCount) ?
@@ -188,9 +191,9 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
188
191
  getNamesByFlagSets(flagSets: string[]): Set<string>[] {
189
192
  return flagSets.map(flagSet => {
190
193
  const flagSetKey = this.keys.buildFlagSetKey(flagSet);
191
- const flagSetFromStorage = this.storage.getItem(flagSetKey);
194
+ const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
192
195
 
193
- return new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
196
+ return new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
194
197
  });
195
198
  }
196
199
 
@@ -203,12 +206,12 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
203
206
 
204
207
  const flagSetKey = this.keys.buildFlagSetKey(featureFlagSet);
205
208
 
206
- const flagSetFromStorage = this.storage.getItem(flagSetKey);
209
+ const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
207
210
 
208
- const flagSetCache = new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
211
+ const flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
209
212
  flagSetCache.add(featureFlag.name);
210
213
 
211
- this.storage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
214
+ localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
212
215
  });
213
216
  }
214
217
 
@@ -223,19 +226,19 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
223
226
  private removeNames(flagSetName: string, featureFlagName: string) {
224
227
  const flagSetKey = this.keys.buildFlagSetKey(flagSetName);
225
228
 
226
- const flagSetFromStorage = this.storage.getItem(flagSetKey);
229
+ const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
227
230
 
228
- if (!flagSetFromStorage) return;
231
+ if (!flagSetFromLocalStorage) return;
229
232
 
230
- const flagSetCache = new Set(JSON.parse(flagSetFromStorage));
233
+ const flagSetCache = new Set(JSON.parse(flagSetFromLocalStorage));
231
234
  flagSetCache.delete(featureFlagName);
232
235
 
233
236
  if (flagSetCache.size === 0) {
234
- this.storage.removeItem(flagSetKey);
237
+ localStorage.removeItem(flagSetKey);
235
238
  return;
236
239
  }
237
240
 
238
- this.storage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
241
+ localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
239
242
  }
240
243
 
241
244
  }
@@ -1,10 +1,10 @@
1
1
  import { ImpressionsCacheInMemory } from '../inMemory/ImpressionsCacheInMemory';
2
2
  import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
3
3
  import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
4
- import { IStorageFactoryParams, IStorageSync, IStorageSyncFactory, StorageAdapter } from '../types';
4
+ import { IStorageFactoryParams, IStorageSync, IStorageSyncFactory } from '../types';
5
5
  import { validatePrefix } from '../KeyBuilder';
6
6
  import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
7
- import { isLocalStorageAvailable, isValidStorageWrapper, isWebStorage } from '../../utils/env/isLocalStorageAvailable';
7
+ import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
8
8
  import { SplitsCacheInLocal } from './SplitsCacheInLocal';
9
9
  import { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
10
10
  import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
@@ -15,24 +15,7 @@ import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/Telem
15
15
  import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
16
16
  import { getMatching } from '../../utils/key';
17
17
  import { validateCache } from './validateCache';
18
- import { ILogger } from '../../logger/types';
19
18
  import SplitIO from '../../../types/splitio';
20
- import { storageAdapter } from './storageAdapter';
21
-
22
- function validateStorage(log: ILogger, prefix: string, wrapper?: SplitIO.StorageWrapper): StorageAdapter | undefined {
23
- if (wrapper) {
24
- if (isValidStorageWrapper(wrapper)) {
25
- return isWebStorage(wrapper) ?
26
- wrapper as StorageAdapter: // localStorage and sessionStorage don't need adapter
27
- storageAdapter(log, prefix, wrapper);
28
- }
29
- log.warn(LOG_PREFIX + 'Invalid storage provided. Falling back to LocalStorage API');
30
- }
31
-
32
- if (isLocalStorageAvailable()) return localStorage;
33
-
34
- log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
35
- }
36
19
 
37
20
  /**
38
21
  * InLocal storage factory for standalone client-side SplitFactory
@@ -42,19 +25,21 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
42
25
  const prefix = validatePrefix(options.prefix);
43
26
 
44
27
  function InLocalStorageCSFactory(params: IStorageFactoryParams): IStorageSync {
45
- const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
46
28
 
47
- const storage = validateStorage(log, prefix, options.wrapper);
48
- if (!storage) return InMemoryStorageCSFactory(params);
29
+ // Fallback to InMemoryStorage if LocalStorage API is not available
30
+ if (!isLocalStorageAvailable()) {
31
+ params.settings.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
32
+ return InMemoryStorageCSFactory(params);
33
+ }
49
34
 
35
+ const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
50
36
  const matchingKey = getMatching(settings.core.key);
51
37
  const keys = new KeyBuilderCS(prefix, matchingKey);
52
38
 
53
- const splits = new SplitsCacheInLocal(settings, keys, storage);
54
- const rbSegments = new RBSegmentsCacheInLocal(settings, keys, storage);
55
- const segments = new MySegmentsCacheInLocal(log, keys, storage);
56
- const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey), storage);
57
- let validateCachePromise: Promise<boolean> | undefined;
39
+ const splits = new SplitsCacheInLocal(settings, keys);
40
+ const rbSegments = new RBSegmentsCacheInLocal(settings, keys);
41
+ const segments = new MySegmentsCacheInLocal(log, keys);
42
+ const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
58
43
 
59
44
  return {
60
45
  splits,
@@ -68,12 +53,10 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
68
53
  uniqueKeys: new UniqueKeysCacheInMemoryCS(),
69
54
 
70
55
  validateCache() {
71
- return validateCachePromise || (validateCachePromise = validateCache(options, storage, settings, keys, splits, rbSegments, segments, largeSegments));
56
+ return validateCache(options, settings, keys, splits, rbSegments, segments, largeSegments);
72
57
  },
73
58
 
74
- destroy() {
75
- return storage.save && storage.save();
76
- },
59
+ destroy() { },
77
60
 
78
61
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
79
62
  shared(matchingKey: string) {
@@ -81,8 +64,8 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
81
64
  return {
82
65
  splits: this.splits,
83
66
  rbSegments: this.rbSegments,
84
- segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey), storage),
85
- largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey), storage),
67
+ segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey)),
68
+ largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey)),
86
69
  impressions: this.impressions,
87
70
  impressionCounts: this.impressionCounts,
88
71
  events: this.events,
@@ -7,7 +7,6 @@ import type { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
7
7
  import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
8
8
  import { KeyBuilderCS } from '../KeyBuilderCS';
9
9
  import SplitIO from '../../../types/splitio';
10
- import { StorageAdapter } from '../types';
11
10
 
12
11
  const DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
13
12
  const MILLIS_IN_A_DAY = 86400000;
@@ -17,11 +16,11 @@ const MILLIS_IN_A_DAY = 86400000;
17
16
  *
18
17
  * @returns `true` if cache should be cleared, `false` otherwise
19
18
  */
20
- function validateExpiration(options: SplitIO.InLocalStorageOptions, storage: StorageAdapter, settings: ISettings, keys: KeyBuilderCS, currentTimestamp: number, isThereCache: boolean) {
19
+ function validateExpiration(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, currentTimestamp: number, isThereCache: boolean) {
21
20
  const { log } = settings;
22
21
 
23
22
  // Check expiration
24
- const lastUpdatedTimestamp = parseInt(storage.getItem(keys.buildLastUpdatedKey()) as string, 10);
23
+ const lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()) as string, 10);
25
24
  if (!isNaNNumber(lastUpdatedTimestamp)) {
26
25
  const cacheExpirationInDays = isFiniteNumber(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
27
26
  const expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
@@ -33,12 +32,12 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, storage: Sto
33
32
 
34
33
  // Check hash
35
34
  const storageHashKey = keys.buildHashKey();
36
- const storageHash = storage.getItem(storageHashKey);
35
+ const storageHash = localStorage.getItem(storageHashKey);
37
36
  const currentStorageHash = getStorageHash(settings);
38
37
 
39
38
  if (storageHash !== currentStorageHash) {
40
39
  try {
41
- storage.setItem(storageHashKey, currentStorageHash);
40
+ localStorage.setItem(storageHashKey, currentStorageHash);
42
41
  } catch (e) {
43
42
  log.error(LOG_PREFIX + e);
44
43
  }
@@ -51,7 +50,7 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, storage: Sto
51
50
 
52
51
  // Clear on init
53
52
  if (options.clearOnInit) {
54
- const lastClearTimestamp = parseInt(storage.getItem(keys.buildLastClear()) as string, 10);
53
+ const lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()) as string, 10);
55
54
 
56
55
  if (isNaNNumber(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
57
56
  log.info(LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
@@ -68,29 +67,27 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, storage: Sto
68
67
  *
69
68
  * @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
70
69
  */
71
- export function validateCache(options: SplitIO.InLocalStorageOptions, storage: StorageAdapter, settings: ISettings, keys: KeyBuilderCS, splits: SplitsCacheInLocal, rbSegments: RBSegmentsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): Promise<boolean> {
70
+ export function validateCache(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, splits: SplitsCacheInLocal, rbSegments: RBSegmentsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): boolean {
72
71
 
73
- return Promise.resolve(storage.load && storage.load()).then(() => {
74
- const currentTimestamp = Date.now();
75
- const isThereCache = splits.getChangeNumber() > -1;
72
+ const currentTimestamp = Date.now();
73
+ const isThereCache = splits.getChangeNumber() > -1;
76
74
 
77
- if (validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache)) {
78
- splits.clear();
79
- rbSegments.clear();
80
- segments.clear();
81
- largeSegments.clear();
75
+ if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
76
+ splits.clear();
77
+ rbSegments.clear();
78
+ segments.clear();
79
+ largeSegments.clear();
82
80
 
83
- // Update last clear timestamp
84
- try {
85
- storage.setItem(keys.buildLastClear(), currentTimestamp + '');
86
- } catch (e) {
87
- settings.log.error(LOG_PREFIX + e);
88
- }
89
-
90
- return false;
81
+ // Update last clear timestamp
82
+ try {
83
+ localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
84
+ } catch (e) {
85
+ settings.log.error(LOG_PREFIX + e);
91
86
  }
92
87
 
93
- // Check if ready from cache
94
- return isThereCache;
95
- });
88
+ return false;
89
+ }
90
+
91
+ // Check if ready from cache
92
+ return isThereCache;
96
93
  }