@splitsoftware/splitio-commons 2.1.1-rc.1 → 2.1.1-rc.2
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 +5 -1
- package/cjs/readiness/readinessManager.js +6 -0
- package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
- package/cjs/storages/AbstractSplitsCacheSync.js +0 -7
- package/cjs/storages/KeyBuilderCS.js +3 -0
- package/cjs/storages/dataLoader.js +3 -2
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +11 -69
- package/cjs/storages/inLocalStorage/index.js +5 -3
- package/cjs/storages/inLocalStorage/validateCache.js +79 -0
- package/cjs/storages/pluggable/index.js +2 -1
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -12
- package/cjs/sync/syncManagerOnline.js +8 -3
- package/cjs/trackers/strategy/strategyDebug.js +2 -0
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/readiness/readinessManager.js +6 -0
- package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
- package/esm/storages/AbstractSplitsCacheSync.js +0 -7
- package/esm/storages/KeyBuilderCS.js +3 -0
- package/esm/storages/dataLoader.js +2 -1
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +11 -69
- package/esm/storages/inLocalStorage/index.js +5 -3
- package/esm/storages/inLocalStorage/validateCache.js +75 -0
- package/esm/storages/pluggable/index.js +2 -1
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -13
- package/esm/sync/syncManagerOnline.js +8 -3
- package/esm/trackers/strategy/strategyDebug.js +2 -0
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/readiness/readinessManager.ts +5 -0
- package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
- package/src/storages/AbstractSplitsCacheSync.ts +0 -8
- package/src/storages/KeyBuilderCS.ts +4 -0
- package/src/storages/dataLoader.ts +3 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +13 -78
- package/src/storages/inLocalStorage/index.ts +8 -8
- package/src/storages/inLocalStorage/validateCache.ts +91 -0
- package/src/storages/pluggable/index.ts +2 -1
- package/src/storages/types.ts +1 -4
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -13
- package/src/sync/syncManagerOnline.ts +9 -3
- package/src/trackers/strategy/strategyDebug.ts +2 -0
- package/src/utils/lang/index.ts +1 -1
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/splitio.d.ts +28 -1
- package/cjs/utils/constants/browser.js +0 -5
- package/esm/utils/constants/browser.js +0 -2
- package/src/utils/constants/browser.ts +0 -2
|
@@ -7,22 +7,19 @@ import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
|
|
|
7
7
|
import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
|
|
8
8
|
import { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
9
9
|
import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
10
|
-
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
|
|
11
10
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
12
11
|
import { LOG_PREFIX } from './constants';
|
|
13
12
|
import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
14
13
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
15
14
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
16
15
|
import { getMatching } from '../../utils/key';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
prefix?: string
|
|
20
|
-
}
|
|
16
|
+
import { validateCache } from './validateCache';
|
|
17
|
+
import SplitIO from '../../../types/splitio';
|
|
21
18
|
|
|
22
19
|
/**
|
|
23
20
|
* InLocal storage factory for standalone client-side SplitFactory
|
|
24
21
|
*/
|
|
25
|
-
export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyncFactory {
|
|
22
|
+
export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): IStorageSyncFactory {
|
|
26
23
|
|
|
27
24
|
const prefix = validatePrefix(options.prefix);
|
|
28
25
|
|
|
@@ -37,9 +34,8 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
37
34
|
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
38
35
|
const matchingKey = getMatching(settings.core.key);
|
|
39
36
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
40
|
-
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
41
37
|
|
|
42
|
-
const splits = new SplitsCacheInLocal(settings, keys
|
|
38
|
+
const splits = new SplitsCacheInLocal(settings, keys);
|
|
43
39
|
const segments = new MySegmentsCacheInLocal(log, keys);
|
|
44
40
|
const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
|
|
45
41
|
|
|
@@ -53,6 +49,10 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
53
49
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
54
50
|
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
55
51
|
|
|
52
|
+
validateCache() {
|
|
53
|
+
return validateCache(options, settings, keys, splits, segments, largeSegments);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
56
|
destroy() { },
|
|
57
57
|
|
|
58
58
|
// When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ISettings } from '../../types';
|
|
2
|
+
import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
3
|
+
import { getStorageHash } from '../KeyBuilder';
|
|
4
|
+
import { LOG_PREFIX } from './constants';
|
|
5
|
+
import type { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
6
|
+
import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
7
|
+
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
8
|
+
import SplitIO from '../../../types/splitio';
|
|
9
|
+
|
|
10
|
+
const DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
|
|
11
|
+
const MILLIS_IN_A_DAY = 86400000;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validates if cache should be cleared and sets the cache `hash` if needed.
|
|
15
|
+
*
|
|
16
|
+
* @returns `true` if cache should be cleared, `false` otherwise
|
|
17
|
+
*/
|
|
18
|
+
function validateExpiration(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, currentTimestamp: number, isThereCache: boolean) {
|
|
19
|
+
const { log } = settings;
|
|
20
|
+
|
|
21
|
+
// Check expiration
|
|
22
|
+
const lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()) as string, 10);
|
|
23
|
+
if (!isNaNNumber(lastUpdatedTimestamp)) {
|
|
24
|
+
const cacheExpirationInDays = isFiniteNumber(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
|
|
25
|
+
const expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
|
|
26
|
+
if (lastUpdatedTimestamp < expirationTimestamp) {
|
|
27
|
+
log.info(LOG_PREFIX + 'Cache expired more than ' + cacheExpirationInDays + ' days ago. Cleaning up cache');
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check hash
|
|
33
|
+
const storageHashKey = keys.buildHashKey();
|
|
34
|
+
const storageHash = localStorage.getItem(storageHashKey);
|
|
35
|
+
const currentStorageHash = getStorageHash(settings);
|
|
36
|
+
|
|
37
|
+
if (storageHash !== currentStorageHash) {
|
|
38
|
+
try {
|
|
39
|
+
localStorage.setItem(storageHashKey, currentStorageHash);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
log.error(LOG_PREFIX + e);
|
|
42
|
+
}
|
|
43
|
+
if (isThereCache) {
|
|
44
|
+
log.info(LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false; // No cache to clear
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Clear on init
|
|
51
|
+
if (options.clearOnInit) {
|
|
52
|
+
const lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()) as string, 10);
|
|
53
|
+
|
|
54
|
+
if (isNaNNumber(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
|
|
55
|
+
log.info(LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Clean cache if:
|
|
63
|
+
* - it has expired, i.e., its `lastUpdated` timestamp is older than the given `expirationTimestamp`
|
|
64
|
+
* - its hash has changed, i.e., the SDK key, flags filter criteria or flags spec version was modified
|
|
65
|
+
* - `clearOnInit` was set and cache was not cleared in the last 24 hours
|
|
66
|
+
*
|
|
67
|
+
* @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
|
|
68
|
+
*/
|
|
69
|
+
export function validateCache(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, splits: SplitsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): boolean {
|
|
70
|
+
|
|
71
|
+
const currentTimestamp = Date.now();
|
|
72
|
+
const isThereCache = splits.getChangeNumber() > -1;
|
|
73
|
+
|
|
74
|
+
if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
|
|
75
|
+
splits.clear();
|
|
76
|
+
segments.clear();
|
|
77
|
+
largeSegments.clear();
|
|
78
|
+
|
|
79
|
+
// Update last clear timestamp
|
|
80
|
+
try {
|
|
81
|
+
localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
|
|
82
|
+
} catch (e) {
|
|
83
|
+
settings.log.error(LOG_PREFIX + e);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check if ready from cache
|
|
90
|
+
return isThereCache;
|
|
91
|
+
}
|
|
@@ -88,7 +88,8 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
88
88
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
89
89
|
const connectPromise = wrapper.connect().then(() => {
|
|
90
90
|
if (isSynchronizer) {
|
|
91
|
-
//
|
|
91
|
+
// @TODO reuse InLocalStorage::validateCache logic
|
|
92
|
+
// In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
|
|
92
93
|
return wrapper.get(keys.buildHashKey()).then((hash) => {
|
|
93
94
|
const currentHash = getStorageHash(settings);
|
|
94
95
|
if (hash !== currentHash) {
|
package/src/storages/types.ts
CHANGED
|
@@ -189,8 +189,6 @@ export interface ISplitsCacheBase {
|
|
|
189
189
|
// only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === -1) or contains a FF using segments or large segments
|
|
190
190
|
usesSegments(): MaybeThenable<boolean>,
|
|
191
191
|
clear(): MaybeThenable<boolean | void>,
|
|
192
|
-
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
|
|
193
|
-
checkCache(): MaybeThenable<boolean>,
|
|
194
192
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean>,
|
|
195
193
|
getNamesByFlagSets(flagSets: string[]): MaybeThenable<Set<string>[]>
|
|
196
194
|
}
|
|
@@ -205,7 +203,6 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
|
205
203
|
trafficTypeExists(trafficType: string): boolean,
|
|
206
204
|
usesSegments(): boolean,
|
|
207
205
|
clear(): void,
|
|
208
|
-
checkCache(): boolean,
|
|
209
206
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
|
|
210
207
|
getNamesByFlagSets(flagSets: string[]): Set<string>[]
|
|
211
208
|
}
|
|
@@ -220,7 +217,6 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
|
220
217
|
trafficTypeExists(trafficType: string): Promise<boolean>,
|
|
221
218
|
usesSegments(): Promise<boolean>,
|
|
222
219
|
clear(): Promise<boolean | void>,
|
|
223
|
-
checkCache(): Promise<boolean>,
|
|
224
220
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
|
|
225
221
|
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]>
|
|
226
222
|
}
|
|
@@ -451,6 +447,7 @@ export interface IStorageSync extends IStorageBase<
|
|
|
451
447
|
IUniqueKeysCacheSync
|
|
452
448
|
> {
|
|
453
449
|
// Defined in client-side
|
|
450
|
+
validateCache?: () => boolean, // @TODO support async
|
|
454
451
|
largeSegments?: ISegmentsCacheSync,
|
|
455
452
|
}
|
|
456
453
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { forOwn } from '../../../utils/lang';
|
|
2
2
|
import { IReadinessManager } from '../../../readiness/types';
|
|
3
|
-
import {
|
|
3
|
+
import { IStorageSync } from '../../../storages/types';
|
|
4
4
|
import { ISplitsParser } from '../splitsParser/types';
|
|
5
5
|
import { ISplit, ISplitPartial } from '../../../dtos/types';
|
|
6
6
|
import { syncTaskFactory } from '../../syncTask';
|
|
@@ -15,7 +15,7 @@ import { SYNC_OFFLINE_DATA, ERROR_SYNC_OFFLINE_LOADING } from '../../../logger/c
|
|
|
15
15
|
*/
|
|
16
16
|
export function fromObjectUpdaterFactory(
|
|
17
17
|
splitsParser: ISplitsParser,
|
|
18
|
-
storage:
|
|
18
|
+
storage: Pick<IStorageSync, 'splits' | 'validateCache'>,
|
|
19
19
|
readiness: IReadinessManager,
|
|
20
20
|
settings: ISettings,
|
|
21
21
|
): () => Promise<boolean> {
|
|
@@ -59,9 +59,10 @@ export function fromObjectUpdaterFactory(
|
|
|
59
59
|
|
|
60
60
|
if (startingUp) {
|
|
61
61
|
startingUp = false;
|
|
62
|
-
|
|
62
|
+
const isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
|
|
63
|
+
Promise.resolve().then(() => {
|
|
63
64
|
// Emits SDK_READY_FROM_CACHE
|
|
64
|
-
if (
|
|
65
|
+
if (isCacheLoaded) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
65
66
|
// Emits SDK_READY
|
|
66
67
|
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
67
68
|
});
|
|
@@ -79,7 +80,7 @@ export function fromObjectUpdaterFactory(
|
|
|
79
80
|
*/
|
|
80
81
|
export function fromObjectSyncTaskFactory(
|
|
81
82
|
splitsParser: ISplitsParser,
|
|
82
|
-
storage:
|
|
83
|
+
storage: Pick<IStorageSync, 'splits' | 'validateCache'>,
|
|
83
84
|
readiness: IReadinessManager,
|
|
84
85
|
settings: ISettings
|
|
85
86
|
): ISyncTask<[], boolean> {
|
|
@@ -3,7 +3,7 @@ import { ISplitChangesFetcher } from '../fetchers/types';
|
|
|
3
3
|
import { ISplit, ISplitChangesResponse, ISplitFiltersValidation } from '../../../dtos/types';
|
|
4
4
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
5
5
|
import { timeout } from '../../../utils/promise/timeout';
|
|
6
|
-
import { SDK_SPLITS_ARRIVED
|
|
6
|
+
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
8
8
|
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
9
9
|
import { startsWith } from '../../../utils/lang';
|
|
@@ -143,7 +143,7 @@ export function splitChangesUpdaterFactory(
|
|
|
143
143
|
*/
|
|
144
144
|
function _splitChangesUpdater(since: number, retry = 0): Promise<boolean> {
|
|
145
145
|
log.debug(SYNC_SPLITS_FETCH, [since]);
|
|
146
|
-
|
|
146
|
+
return Promise.resolve(splitUpdateNotification ?
|
|
147
147
|
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
|
|
148
148
|
splitChangesFetcher(since, noCache, till, _promiseDecorator)
|
|
149
149
|
)
|
|
@@ -154,8 +154,6 @@ export function splitChangesUpdaterFactory(
|
|
|
154
154
|
|
|
155
155
|
log.debug(SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
|
|
156
156
|
|
|
157
|
-
// Write into storage
|
|
158
|
-
// @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
|
|
159
157
|
return Promise.all([
|
|
160
158
|
splits.update(mutation.added, mutation.removed, splitChanges.till),
|
|
161
159
|
segments.registerSegments(mutation.segments)
|
|
@@ -185,15 +183,6 @@ export function splitChangesUpdaterFactory(
|
|
|
185
183
|
}
|
|
186
184
|
return false;
|
|
187
185
|
});
|
|
188
|
-
|
|
189
|
-
// After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
|
|
190
|
-
// Wrapping in a promise since checkCache can be async.
|
|
191
|
-
if (splitsEventEmitter && startingUp) {
|
|
192
|
-
Promise.resolve(splits.checkCache()).then(isCacheReady => {
|
|
193
|
-
if (isCacheReady) splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED);
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
return fetcherPromise;
|
|
197
186
|
}
|
|
198
187
|
|
|
199
188
|
let sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
|
|
@@ -9,6 +9,7 @@ import { SYNC_START_POLLING, SYNC_CONTINUE_POLLING, SYNC_STOP_POLLING } from '..
|
|
|
9
9
|
import { isConsentGranted } from '../consent';
|
|
10
10
|
import { POLLING, STREAMING, SYNC_MODE_UPDATE } from '../utils/constants';
|
|
11
11
|
import { ISdkFactoryContextSync } from '../sdkFactory/types';
|
|
12
|
+
import { SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Online SyncManager factory.
|
|
@@ -28,7 +29,7 @@ export function syncManagerOnlineFactory(
|
|
|
28
29
|
*/
|
|
29
30
|
return function (params: ISdkFactoryContextSync): ISyncManagerCS {
|
|
30
31
|
|
|
31
|
-
const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled } },
|
|
32
|
+
const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled } }, telemetryTracker, storage, readiness } = params;
|
|
32
33
|
|
|
33
34
|
/** Polling Manager */
|
|
34
35
|
const pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
@@ -87,6 +88,11 @@ export function syncManagerOnlineFactory(
|
|
|
87
88
|
start() {
|
|
88
89
|
running = true;
|
|
89
90
|
|
|
91
|
+
if (startFirstTime) {
|
|
92
|
+
const isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
|
|
93
|
+
if (isCacheLoaded) Promise.resolve().then(() => { readiness.splits.emit(SDK_SPLITS_CACHE_LOADED); });
|
|
94
|
+
}
|
|
95
|
+
|
|
90
96
|
// start syncing splits and segments
|
|
91
97
|
if (pollingManager) {
|
|
92
98
|
|
|
@@ -96,7 +102,6 @@ export function syncManagerOnlineFactory(
|
|
|
96
102
|
// Doesn't call `syncAll` when the syncManager is resuming
|
|
97
103
|
if (startFirstTime) {
|
|
98
104
|
pollingManager.syncAll();
|
|
99
|
-
startFirstTime = false;
|
|
100
105
|
}
|
|
101
106
|
pushManager.start();
|
|
102
107
|
} else {
|
|
@@ -105,13 +110,14 @@ export function syncManagerOnlineFactory(
|
|
|
105
110
|
} else {
|
|
106
111
|
if (startFirstTime) {
|
|
107
112
|
pollingManager.syncAll();
|
|
108
|
-
startFirstTime = false;
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
// start periodic data recording (events, impressions, telemetry).
|
|
114
118
|
submitterManager.start(!isConsentGranted(settings));
|
|
119
|
+
|
|
120
|
+
startFirstTime = false;
|
|
115
121
|
},
|
|
116
122
|
|
|
117
123
|
/**
|
package/src/utils/lang/index.ts
CHANGED
|
@@ -120,7 +120,7 @@ export function isBoolean(val: any): boolean {
|
|
|
120
120
|
* Unlike `Number.isFinite`, it also tests Number object instances.
|
|
121
121
|
* Unlike global `isFinite`, it returns false if the value is not a number or Number object instance.
|
|
122
122
|
*/
|
|
123
|
-
export function isFiniteNumber(val: any):
|
|
123
|
+
export function isFiniteNumber(val: any): val is number {
|
|
124
124
|
if (val instanceof Number) val = val.valueOf();
|
|
125
125
|
return typeof val === 'number' ?
|
|
126
126
|
Number.isFinite ? Number.isFinite(val) : isFinite(val) :
|
|
@@ -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.
|
|
11
|
+
result.validateCache = () => true; // to emit SDK_READY_FROM_CACHE
|
|
12
12
|
return result;
|
|
13
13
|
}
|
|
14
14
|
__InLocalStorageMockFactory.type = STORAGE_MEMORY;
|
package/types/splitio.d.ts
CHANGED
|
@@ -782,6 +782,9 @@ declare namespace SplitIO {
|
|
|
782
782
|
* Evaluation options object for getTreatment methods.
|
|
783
783
|
*/
|
|
784
784
|
type EvaluationOptions = {
|
|
785
|
+
/**
|
|
786
|
+
* Optional properties to append to the generated impression object sent to Split backend.
|
|
787
|
+
*/
|
|
785
788
|
properties?: Properties;
|
|
786
789
|
}
|
|
787
790
|
/**
|
|
@@ -944,6 +947,18 @@ declare namespace SplitIO {
|
|
|
944
947
|
* @defaultValue `'SPLITIO'`
|
|
945
948
|
*/
|
|
946
949
|
prefix?: string;
|
|
950
|
+
/**
|
|
951
|
+
* Number of days before cached data expires if it was not updated. If cache expires, it is cleared on initialization.
|
|
952
|
+
*
|
|
953
|
+
* @defaultValue `10`
|
|
954
|
+
*/
|
|
955
|
+
expirationDays?: number;
|
|
956
|
+
/**
|
|
957
|
+
* Optional settings to clear the cache. If set to `true`, the SDK clears the cached data on initialization, unless the cache was cleared within the last 24 hours.
|
|
958
|
+
*
|
|
959
|
+
* @defaultValue `false`
|
|
960
|
+
*/
|
|
961
|
+
clearOnInit?: boolean;
|
|
947
962
|
}
|
|
948
963
|
/**
|
|
949
964
|
* Storage for asynchronous (consumer) SDK.
|
|
@@ -1267,11 +1282,23 @@ declare namespace SplitIO {
|
|
|
1267
1282
|
*/
|
|
1268
1283
|
type?: BrowserStorage;
|
|
1269
1284
|
/**
|
|
1270
|
-
* Optional prefix to prevent any kind of data collision between SDK versions.
|
|
1285
|
+
* Optional prefix to prevent any kind of data collision between SDK versions when using 'LOCALSTORAGE'.
|
|
1271
1286
|
*
|
|
1272
1287
|
* @defaultValue `'SPLITIO'`
|
|
1273
1288
|
*/
|
|
1274
1289
|
prefix?: string;
|
|
1290
|
+
/**
|
|
1291
|
+
* Optional settings for the 'LOCALSTORAGE' storage type. It specifies the number of days before cached data expires if it was not updated. If cache expires, it is cleared on initialization.
|
|
1292
|
+
*
|
|
1293
|
+
* @defaultValue `10`
|
|
1294
|
+
*/
|
|
1295
|
+
expirationDays?: number;
|
|
1296
|
+
/**
|
|
1297
|
+
* Optional settings for the 'LOCALSTORAGE' storage type. If set to `true`, the SDK clears the cached data on initialization, unless the cache was cleared within the last 24 hours.
|
|
1298
|
+
*
|
|
1299
|
+
* @defaultValue `false`
|
|
1300
|
+
*/
|
|
1301
|
+
clearOnInit?: boolean;
|
|
1275
1302
|
};
|
|
1276
1303
|
}
|
|
1277
1304
|
/**
|