@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
@@ -89,41 +89,36 @@ export function syncManagerOnlineFactory(
89
89
  start() {
90
90
  running = true;
91
91
 
92
- // @TODO once event, impression and telemetry storages support persistence, call when `validateCache` promise is resolved
93
- submitterManager.start(!isConsentGranted(settings));
94
-
95
- return Promise.resolve(storage.validateCache ? storage.validateCache() : false).then((isCacheLoaded) => {
96
- if (!running) return;
97
-
98
- if (startFirstTime) {
99
- // Emits SDK_READY_FROM_CACHE
100
- if (isCacheLoaded) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
92
+ if (startFirstTime) {
93
+ const isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
94
+ if (isCacheLoaded) Promise.resolve().then(() => { readiness.splits.emit(SDK_SPLITS_CACHE_LOADED); });
95
+ }
101
96
 
102
- }
97
+ // start syncing splits and segments
98
+ if (pollingManager) {
103
99
 
104
- // start syncing splits and segments
105
- if (pollingManager) {
106
-
107
- // If synchronization is disabled pushManager and pollingManager should not start
108
- if (syncEnabled) {
109
- if (pushManager) {
110
- // Doesn't call `syncAll` when the syncManager is resuming
111
- if (startFirstTime) {
112
- pollingManager.syncAll();
113
- }
114
- pushManager.start();
115
- } else {
116
- pollingManager.start();
117
- }
118
- } else {
100
+ // If synchronization is disabled pushManager and pollingManager should not start
101
+ if (syncEnabled) {
102
+ if (pushManager) {
103
+ // Doesn't call `syncAll` when the syncManager is resuming
119
104
  if (startFirstTime) {
120
105
  pollingManager.syncAll();
121
106
  }
107
+ pushManager.start();
108
+ } else {
109
+ pollingManager.start();
110
+ }
111
+ } else {
112
+ if (startFirstTime) {
113
+ pollingManager.syncAll();
122
114
  }
123
115
  }
116
+ }
117
+
118
+ // start periodic data recording (events, impressions, telemetry).
119
+ submitterManager.start(!isConsentGranted(settings));
124
120
 
125
- startFirstTime = false;
126
- });
121
+ startFirstTime = false;
127
122
  },
128
123
 
129
124
  /**
package/src/types.ts CHANGED
@@ -42,38 +42,3 @@ export interface IBasicClient extends SplitIO.IBasicClient {
42
42
  isClientSide?: boolean;
43
43
  key?: SplitIO.SplitKey;
44
44
  }
45
- /**
46
- * Defines the format of rollout plan data to preload the factory storage (cache).
47
- */
48
- export interface PreloadedData {
49
- /**
50
- * Timestamp of the last moment the data was synchronized with Split servers.
51
- * If this value is older than 10 days ago (expiration time policy), the data is not used to update the storage content.
52
- */
53
- // @TODO configurable expiration time policy?
54
- lastUpdated: number;
55
- /**
56
- * Change number of the preloaded data.
57
- * If this value is older than the current changeNumber at the storage, the data is not used to update the storage content.
58
- */
59
- since: number;
60
- /**
61
- * Map of feature flags to their stringified definitions.
62
- */
63
- splitsData: {
64
- [splitName: string]: string;
65
- };
66
- /**
67
- * Optional map of user keys to their list of segments.
68
- */
69
- mySegmentsData?: {
70
- [key: string]: string[];
71
- };
72
- /**
73
- * Optional map of segments to their stringified definitions.
74
- * This property is ignored if `mySegmentsData` was provided.
75
- */
76
- segmentsData?: {
77
- [segmentName: string]: string;
78
- };
79
- }
@@ -1,32 +1,11 @@
1
+ /* eslint-disable no-undef */
1
2
  export function isLocalStorageAvailable(): boolean {
2
- try {
3
- // eslint-disable-next-line no-undef
4
- return isValidStorageWrapper(localStorage);
5
- } catch (e) {
6
- return false;
7
- }
8
- }
9
-
10
- export function isValidStorageWrapper(wrapper: any): boolean {
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
  } catch (e) {
18
9
  return false;
19
10
  }
20
11
  }
21
-
22
- export function isWebStorage(wrapper: any): boolean {
23
- if (typeof wrapper.length === 'number') {
24
- try {
25
- wrapper.key(0);
26
- return true;
27
- } catch (e) {
28
- return false;
29
- }
30
- }
31
- return false;
32
- }
@@ -8,7 +8,7 @@ import { IStorageFactoryParams, IStorageSync } from '../../../storages/types';
8
8
 
9
9
  export function __InLocalStorageMockFactory(params: IStorageFactoryParams): IStorageSync {
10
10
  const result = InMemoryStorageCSFactory(params);
11
- result.validateCache = () => Promise.resolve(true); // to emit SDK_READY_FROM_CACHE
11
+ result.validateCache = () => true; // to emit SDK_READY_FROM_CACHE
12
12
  return result;
13
13
  }
14
14
  __InLocalStorageMockFactory.type = STORAGE_MEMORY;
@@ -350,6 +350,10 @@ interface IClientSideSyncSharedSettings extends IClientSideSharedSettings, ISync
350
350
  * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#localhost-mode}
351
351
  */
352
352
  features?: SplitIO.MockedFeaturesMap;
353
+ /**
354
+ * Data to initialize the SDK storage with. If provided and valid, the SDK will be ready from cache immediately.
355
+ */
356
+ preloadedData?: SplitIO.PreloadedData;
353
357
  /**
354
358
  * SDK Startup settings.
355
359
  */
@@ -458,36 +462,6 @@ interface IClientSideSyncSharedSettings extends IClientSideSharedSettings, ISync
458
462
  */
459
463
  declare namespace SplitIO {
460
464
 
461
- interface SyncStorageWrapper {
462
- /**
463
- * Returns the value associated with the given key, or null if the key does not exist.
464
- */
465
- getItem(key: string): string | null;
466
- /**
467
- * Sets the value for the given key, creating a new key/value pair if key does not exist.
468
- */
469
- setItem(key: string, value: string): void;
470
- /**
471
- * Removes the key/value pair for the given key, if the key exists.
472
- */
473
- removeItem(key: string): void;
474
- }
475
-
476
- interface AsyncStorageWrapper {
477
- /**
478
- * Returns a promise that resolves to the value associated with the given key, or null if the key does not exist.
479
- */
480
- getItem(key: string): Promise<string | null>;
481
- /**
482
- * Returns a promise that resolves when the value of the pair identified by key is set to value, creating a new key/value pair if key does not exist.
483
- */
484
- setItem(key: string, value: string): Promise<void>;
485
- /**
486
- * Returns a promise that resolves when the key/value pair for the given key is removed, if the key exists.
487
- */
488
- removeItem(key: string): Promise<void>;
489
- }
490
-
491
465
  /**
492
466
  * EventEmitter interface based on a subset of the Node.js EventEmitter methods.
493
467
  */
@@ -585,6 +559,7 @@ declare namespace SplitIO {
585
559
  eventsFirstPushWindow: number;
586
560
  };
587
561
  readonly storage: StorageSyncFactory | StorageAsyncFactory | StorageOptions;
562
+ readonly preloadedData?: SplitIO.PreloadedData;
588
563
  readonly urls: {
589
564
  events: string;
590
565
  sdk: string;
@@ -1002,12 +977,6 @@ declare namespace SplitIO {
1002
977
  * @defaultValue `false`
1003
978
  */
1004
979
  clearOnInit?: boolean;
1005
- /**
1006
- * Optional storage wrapper to persist rollout plan related data. If not provided, the SDK will use the default localStorage Web API.
1007
- *
1008
- * @defaultValue `window.localStorage`
1009
- */
1010
- wrapper?: SyncStorageWrapper | AsyncStorageWrapper;
1011
980
  }
1012
981
  /**
1013
982
  * Storage for asynchronous (consumer) SDK.
@@ -1057,6 +1026,40 @@ declare namespace SplitIO {
1057
1026
  prefix?: string;
1058
1027
  options?: Object;
1059
1028
  }
1029
+ /**
1030
+ * Defines the format of rollout plan data to preload the factory storage (cache).
1031
+ */
1032
+ type PreloadedData = {
1033
+ /**
1034
+ * Change number of feature flags.
1035
+ */
1036
+ since: number;
1037
+ /**
1038
+ * List of feature flags.
1039
+ */
1040
+ flags: Object[],
1041
+ /**
1042
+ * Change number of rule-based segments.
1043
+ */
1044
+ rbSince?: number,
1045
+ /**
1046
+ * List of rule-based segments.
1047
+ */
1048
+ rbSegments?: Object[],
1049
+ /**
1050
+ * Optional map of user keys to their memberships.
1051
+ */
1052
+ memberships?: {
1053
+ [key: string]: Object
1054
+ },
1055
+ /**
1056
+ * Optional map of segments to their list of keys.
1057
+ * This property is ignored if `memberships` is provided.
1058
+ */
1059
+ segments?: {
1060
+ [segmentName: string]: string[]
1061
+ },
1062
+ }
1060
1063
  /**
1061
1064
  * Impression listener interface. This is the interface that needs to be implemented
1062
1065
  * by the element you provide to the SDK as impression listener.
@@ -1348,12 +1351,6 @@ declare namespace SplitIO {
1348
1351
  * @defaultValue `false`
1349
1352
  */
1350
1353
  clearOnInit?: boolean;
1351
- /**
1352
- * Optional storage wrapper to persist rollout plan related data. If not provided, the SDK will use the default localStorage Web API.
1353
- *
1354
- * @defaultValue `window.localStorage`
1355
- */
1356
- wrapper?: SyncStorageWrapper | AsyncStorageWrapper;
1357
1354
  };
1358
1355
  }
1359
1356
  /**
@@ -1606,6 +1603,13 @@ declare namespace SplitIO {
1606
1603
  * @returns The manager instance.
1607
1604
  */
1608
1605
  manager(): IManager;
1606
+ /**
1607
+ * Returns the current snapshot of the SDK rollout plan in cache.
1608
+ *
1609
+ * @param keys - Optional list of keys to generate the rollout plan snapshot with the memberships of the given keys, rather than the complete segments data.
1610
+ * @returns The current snapshot of the SDK rollout plan.
1611
+ */
1612
+ getCache(keys?: SplitKey[]): PreloadedData,
1609
1613
  }
1610
1614
  /**
1611
1615
  * This represents the interface for the SDK instance for server-side with asynchronous storage.
@@ -1,54 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.storageAdapter = void 0;
4
- var constants_1 = require("./constants");
5
- function storageAdapter(log, prefix, wrapper) {
6
- var keys = [];
7
- var cache = {};
8
- var loadPromise;
9
- var savePromise = Promise.resolve();
10
- return {
11
- load: function () {
12
- return loadPromise || (loadPromise = Promise.resolve().then(function () {
13
- return wrapper.getItem(prefix);
14
- }).then(function (storedCache) {
15
- cache = JSON.parse(storedCache || '{}');
16
- keys = Object.keys(cache);
17
- }).catch(function (e) {
18
- log.error(constants_1.LOG_PREFIX + 'Rejected promise calling wrapper `getItem` method, with error: ' + e);
19
- }));
20
- },
21
- save: function () {
22
- return savePromise = savePromise.then(function () {
23
- return Promise.resolve(wrapper.setItem(prefix, JSON.stringify(cache)));
24
- }).catch(function (e) {
25
- log.error(constants_1.LOG_PREFIX + 'Rejected promise calling wrapper `setItem` method, with error: ' + e);
26
- });
27
- },
28
- whenSaved: function () {
29
- return savePromise;
30
- },
31
- get length() {
32
- return keys.length;
33
- },
34
- getItem: function (key) {
35
- return cache[key] || null;
36
- },
37
- key: function (index) {
38
- return keys[index] || null;
39
- },
40
- removeItem: function (key) {
41
- var index = keys.indexOf(key);
42
- if (index === -1)
43
- return;
44
- keys.splice(index, 1);
45
- delete cache[key];
46
- },
47
- setItem: function (key, value) {
48
- if (keys.indexOf(key) === -1)
49
- keys.push(key);
50
- cache[key] = value;
51
- }
52
- };
53
- }
54
- exports.storageAdapter = storageAdapter;
@@ -1,50 +0,0 @@
1
- import { LOG_PREFIX } from './constants';
2
- export function storageAdapter(log, prefix, wrapper) {
3
- var keys = [];
4
- var cache = {};
5
- var loadPromise;
6
- var savePromise = Promise.resolve();
7
- return {
8
- load: function () {
9
- return loadPromise || (loadPromise = Promise.resolve().then(function () {
10
- return wrapper.getItem(prefix);
11
- }).then(function (storedCache) {
12
- cache = JSON.parse(storedCache || '{}');
13
- keys = Object.keys(cache);
14
- }).catch(function (e) {
15
- log.error(LOG_PREFIX + 'Rejected promise calling wrapper `getItem` method, with error: ' + e);
16
- }));
17
- },
18
- save: function () {
19
- return savePromise = savePromise.then(function () {
20
- return Promise.resolve(wrapper.setItem(prefix, JSON.stringify(cache)));
21
- }).catch(function (e) {
22
- log.error(LOG_PREFIX + 'Rejected promise calling wrapper `setItem` method, with error: ' + e);
23
- });
24
- },
25
- whenSaved: function () {
26
- return savePromise;
27
- },
28
- get length() {
29
- return keys.length;
30
- },
31
- getItem: function (key) {
32
- return cache[key] || null;
33
- },
34
- key: function (index) {
35
- return keys[index] || null;
36
- },
37
- removeItem: function (key) {
38
- var index = keys.indexOf(key);
39
- if (index === -1)
40
- return;
41
- keys.splice(index, 1);
42
- delete cache[key];
43
- },
44
- setItem: function (key, value) {
45
- if (keys.indexOf(key) === -1)
46
- keys.push(key);
47
- cache[key] = value;
48
- }
49
- };
50
- }
@@ -1,62 +0,0 @@
1
- import { ILogger } from '../../logger/types';
2
- import SplitIO from '../../../types/splitio';
3
- import { LOG_PREFIX } from './constants';
4
- import { StorageAdapter } from '../types';
5
-
6
-
7
- export function storageAdapter(log: ILogger, prefix: string, wrapper: SplitIO.SyncStorageWrapper | SplitIO.AsyncStorageWrapper): Required<StorageAdapter> {
8
- let keys: string[] = [];
9
- let cache: Record<string, string> = {};
10
-
11
- let loadPromise: Promise<void> | undefined;
12
- let savePromise = Promise.resolve();
13
-
14
- return {
15
- load() {
16
- return loadPromise || (loadPromise = Promise.resolve().then(() => {
17
- return wrapper.getItem(prefix);
18
- }).then((storedCache) => {
19
- cache = JSON.parse(storedCache || '{}');
20
- keys = Object.keys(cache);
21
- }).catch((e) => {
22
- log.error(LOG_PREFIX + 'Rejected promise calling wrapper `getItem` method, with error: ' + e);
23
- }));
24
- },
25
-
26
- save() {
27
- return savePromise = savePromise.then(() => {
28
- return Promise.resolve(wrapper.setItem(prefix, JSON.stringify(cache)));
29
- }).catch((e) => {
30
- log.error(LOG_PREFIX + 'Rejected promise calling wrapper `setItem` method, with error: ' + e);
31
- });
32
- },
33
-
34
- whenSaved() {
35
- return savePromise;
36
- },
37
-
38
- get length() {
39
- return keys.length;
40
- },
41
-
42
- getItem(key: string) {
43
- return cache[key] || null;
44
- },
45
-
46
- key(index: number) {
47
- return keys[index] || null;
48
- },
49
-
50
- removeItem(key: string) {
51
- const index = keys.indexOf(key);
52
- if (index === -1) return;
53
- keys.splice(index, 1);
54
- delete cache[key];
55
- },
56
-
57
- setItem(key: string, value: string) {
58
- if (keys.indexOf(key) === -1) keys.push(key);
59
- cache[key] = value;
60
- }
61
- };
62
- }