@splitsoftware/splitio-commons 2.0.0-rc.2 → 2.0.0-rc.3
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 +1 -3
- package/cjs/logger/constants.js +1 -2
- package/cjs/logger/messages/error.js +0 -1
- package/cjs/sdkFactory/index.js +1 -3
- package/cjs/storages/dataLoader.js +37 -99
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -16
- package/cjs/sync/offline/LocalhostFromObject.js +3 -8
- package/cjs/utils/settingsValidation/index.js +1 -4
- package/esm/logger/constants.js +0 -1
- package/esm/logger/messages/error.js +0 -1
- package/esm/sdkFactory/index.js +2 -4
- package/esm/storages/dataLoader.js +35 -96
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -16
- package/esm/sync/offline/LocalhostFromObject.js +2 -6
- package/esm/utils/settingsValidation/index.js +1 -4
- package/package.json +1 -1
- package/src/logger/constants.ts +0 -1
- package/src/logger/messages/error.ts +0 -1
- package/src/sdkFactory/index.ts +3 -6
- package/src/storages/dataLoader.ts +38 -97
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -19
- package/src/storages/types.ts +2 -4
- package/src/sync/offline/LocalhostFromObject.ts +2 -8
- package/src/types.ts +14 -26
- package/src/utils/settingsValidation/index.ts +1 -4
- package/src/utils/settingsValidation/types.ts +0 -2
- package/types/logger/constants.d.ts +0 -1
- package/types/storages/dataLoader.d.ts +6 -17
- package/types/storages/types.d.ts +1 -4
- package/types/sync/offline/LocalhostFromObject.d.ts +1 -2
- package/types/types.d.ts +13 -23
- package/types/utils/settingsValidation/index.d.ts +0 -1
- package/types/utils/settingsValidation/types.d.ts +0 -2
- package/cjs/utils/settingsValidation/localhost/builtin.js +0 -18
- package/cjs/utils/settingsValidation/localhost/pluggable.js +0 -22
- package/esm/utils/settingsValidation/localhost/builtin.js +0 -14
- package/esm/utils/settingsValidation/localhost/pluggable.js +0 -18
- package/src/utils/settingsValidation/localhost/builtin.ts +0 -16
- package/src/utils/settingsValidation/localhost/pluggable.ts +0 -22
- package/types/evaluator/matchers/sember_inlist.d.ts +0 -3
- package/types/evaluator/matchersTransform/set.d.ts +0 -5
- package/types/evaluator/matchersTransform/string.d.ts +0 -7
- package/types/integrations/browser.d.ts +0 -12
- package/types/integrations/ga/GaToSplit.d.ts +0 -40
- package/types/integrations/ga/GoogleAnalyticsToSplit.d.ts +0 -3
- package/types/integrations/ga/SplitToGa.d.ts +0 -34
- package/types/integrations/ga/SplitToGoogleAnalytics.d.ts +0 -3
- package/types/integrations/ga/types.d.ts +0 -148
- package/types/sdkClient/sdkClientMethodCSWithTT.d.ts +0 -8
- package/types/storages/AbstractSegmentsCacheSync.d.ts +0 -54
- package/types/storages/AbstractSplitsCache.d.ts +0 -46
- package/types/sync/streaming/mySegmentsV2utils.d.ts +0 -27
- package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +0 -9
- package/types/sync/streaming/pushManager_Spec1_3.d.ts +0 -9
- package/types/trackers/impressionObserver/utils.d.ts +0 -5
- package/types/utils/inputValidation/sdkKey.d.ts +0 -7
- package/types/utils/inputValidation/splitExistance.d.ts +0 -7
- package/types/utils/inputValidation/trafficTypeExistance.d.ts +0 -9
- package/types/utils/lang/maps.d.ts +0 -59
- package/types/utils/redis/RedisMock.d.ts +0 -4
- package/types/utils/settingsValidation/localhost/builtin.d.ts +0 -16
- package/types/utils/settingsValidation/localhost/pluggable.d.ts +0 -16
- package/types/utils/settingsValidation/logger/globalLogLevel.d.ts +0 -8
- /package/types/utils/{semVer.d.ts → Semver.d.ts} +0 -0
package/src/sdkFactory/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { IBasicClient, SplitIO } from '../types';
|
|
|
7
7
|
import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
|
|
8
8
|
import { createLoggerAPI } from '../logger/sdkLogger';
|
|
9
9
|
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
|
|
10
|
-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED
|
|
10
|
+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
11
11
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
12
12
|
import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
|
|
13
13
|
import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
|
|
@@ -43,7 +43,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
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,11 +52,8 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
52
52
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
53
53
|
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
54
54
|
},
|
|
55
|
-
onReadyFromCacheCb() {
|
|
56
|
-
readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
57
|
-
}
|
|
58
55
|
});
|
|
59
|
-
|
|
56
|
+
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
60
57
|
const clients: Record<string, IBasicClient> = {};
|
|
61
58
|
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
62
59
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
|
|
@@ -1,114 +1,55 @@
|
|
|
1
1
|
import { SplitIO } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { getMatching } from '../utils/key';
|
|
5
|
-
import { IMembershipsResponse, IMySegmentsResponse } from '../dtos/types';
|
|
2
|
+
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
3
|
+
import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
|
-
*
|
|
9
|
-
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
6
|
+
* Factory of client-side storage loader
|
|
10
7
|
*
|
|
11
|
-
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
14
|
-
*
|
|
15
|
-
* @TODO extend to load largeSegments
|
|
16
|
-
* @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.
|
|
17
|
-
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
18
|
-
* @TODO unit tests
|
|
8
|
+
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
9
|
+
* and extended with a `mySegmentsData` property.
|
|
10
|
+
* @returns function to preload the storage
|
|
19
11
|
*/
|
|
20
|
-
export function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
export function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
|
|
16
|
+
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
17
|
+
*
|
|
18
|
+
* @param storage object containing `splits` and `segments` cache (client-side variant)
|
|
19
|
+
* @param userId user key string of the provided MySegmentsCache
|
|
20
|
+
*
|
|
21
|
+
* @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
|
|
22
|
+
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
23
|
+
*/
|
|
24
|
+
return function loadData(storage: { splits: ISplitsCacheSync, segments: ISegmentsCacheSync }, userId: string) {
|
|
25
|
+
// Do not load data if current preloadedData is empty
|
|
26
|
+
if (Object.keys(preloadedData).length === 0) return;
|
|
27
|
+
|
|
28
|
+
const { lastUpdated = -1, segmentsData = {}, since = -1, splitsData = {} } = preloadedData;
|
|
25
29
|
|
|
26
|
-
if (storage.splits) {
|
|
27
30
|
const storedSince = storage.splits.getChangeNumber();
|
|
31
|
+
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
28
32
|
|
|
29
|
-
// Do not load data if current data is more recent
|
|
30
|
-
if
|
|
33
|
+
// Do not load data if current localStorage data is more recent,
|
|
34
|
+
// or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
35
|
+
if (storedSince > since || lastUpdated < expirationTimestamp) return;
|
|
31
36
|
|
|
32
37
|
// cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
|
|
33
38
|
storage.splits.clear();
|
|
34
39
|
storage.splits.setChangeNumber(since);
|
|
35
40
|
|
|
36
41
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
37
|
-
storage.splits.addSplits(splitsData.map(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return segmentKeys.indexOf(matchingKey) > -1;
|
|
48
|
-
}).map(segmentName => ({ n: segmentName }))
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
if (membershipsData) {
|
|
53
|
-
if (membershipsData.ms) storage.segments.resetSegments(membershipsData.ms);
|
|
54
|
-
if (membershipsData.ls && storage.largeSegments) storage.largeSegments.resetSegments(membershipsData.ls);
|
|
42
|
+
storage.splits.addSplits(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])));
|
|
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
|
+
});
|
|
55
52
|
}
|
|
56
|
-
|
|
57
|
-
} else { // add segments data (server-side)
|
|
58
|
-
Object.keys(segmentsData).forEach(segmentName => {
|
|
59
|
-
const segmentKeys = segmentsData[segmentName];
|
|
60
|
-
storage.segments.update(segmentName, segmentKeys, [], -1);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function getSnapshot(storage: IStorageSync, userKeys?: SplitIO.SplitKey[]): SplitIO.PreloadedData {
|
|
66
|
-
return {
|
|
67
|
-
// lastUpdated: Date.now(),
|
|
68
|
-
since: storage.splits.getChangeNumber(),
|
|
69
|
-
splitsData: storage.splits.getAll(),
|
|
70
|
-
segmentsData: userKeys ?
|
|
71
|
-
undefined : // @ts-ignore accessing private prop
|
|
72
|
-
Object.keys(storage.segments.segmentCache).reduce((prev, cur) => { // @ts-ignore accessing private prop
|
|
73
|
-
prev[cur] = setToArray(storage.segments.segmentCache[cur] as Set<string>);
|
|
74
|
-
return prev;
|
|
75
|
-
}, {}),
|
|
76
|
-
membershipsData: userKeys ?
|
|
77
|
-
userKeys.reduce<Record<string, IMembershipsResponse>>((prev, userKey) => {
|
|
78
|
-
if (storage.shared) {
|
|
79
|
-
// Client-side segments
|
|
80
|
-
// @ts-ignore accessing private prop
|
|
81
|
-
const sharedStorage = storage.shared(userKey);
|
|
82
|
-
prev[getMatching(userKey)] = {
|
|
83
|
-
ms: {
|
|
84
|
-
// @ts-ignore accessing private prop
|
|
85
|
-
k: Object.keys(sharedStorage.segments.segmentCache).map(segmentName => ({ n: segmentName })),
|
|
86
|
-
// cn: sharedStorage.segments.getChangeNumber()
|
|
87
|
-
},
|
|
88
|
-
ls: sharedStorage.largeSegments ? {
|
|
89
|
-
// @ts-ignore accessing private prop
|
|
90
|
-
k: Object.keys(sharedStorage.largeSegments.segmentCache).map(segmentName => ({ n: segmentName })),
|
|
91
|
-
// cn: sharedStorage.largeSegments.getChangeNumber()
|
|
92
|
-
} : undefined
|
|
93
|
-
};
|
|
94
|
-
} else {
|
|
95
|
-
prev[getMatching(userKey)] = {
|
|
96
|
-
ms: {
|
|
97
|
-
// Server-side segments
|
|
98
|
-
// @ts-ignore accessing private prop
|
|
99
|
-
k: Object.keys(storage.segments.segmentCache).reduce<IMySegmentsResponse['k']>((prev, segmentName) => { // @ts-ignore accessing private prop
|
|
100
|
-
return storage.segments.segmentCache[segmentName].has(userKey) ?
|
|
101
|
-
prev!.concat({ n: segmentName }) :
|
|
102
|
-
prev;
|
|
103
|
-
}, [])
|
|
104
|
-
},
|
|
105
|
-
ls: {
|
|
106
|
-
k: []
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
return prev;
|
|
111
|
-
}, {}) :
|
|
112
|
-
undefined
|
|
53
|
+
storage.segments.resetSegments({ k: mySegmentsData.map(s => ({ n: s })) });
|
|
113
54
|
};
|
|
114
55
|
}
|
|
@@ -7,8 +7,6 @@ import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
|
7
7
|
import { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
9
|
import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
10
|
-
import { getMatching } from '../../utils/key';
|
|
11
|
-
import { loadData } from '../dataLoader';
|
|
12
10
|
|
|
13
11
|
/**
|
|
14
12
|
* InMemory storage factory for standalone client-side SplitFactory
|
|
@@ -16,7 +14,7 @@ import { loadData } from '../dataLoader';
|
|
|
16
14
|
* @param params parameters required by EventsCacheSync
|
|
17
15
|
*/
|
|
18
16
|
export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorageSync {
|
|
19
|
-
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation }
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
|
|
20
18
|
|
|
21
19
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
22
20
|
const segments = new MySegmentsCacheInMemory();
|
|
@@ -44,18 +42,11 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
44
42
|
},
|
|
45
43
|
|
|
46
44
|
// When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
|
|
47
|
-
shared(
|
|
48
|
-
const segments = new MySegmentsCacheInMemory();
|
|
49
|
-
const largeSegments = new MySegmentsCacheInMemory();
|
|
50
|
-
|
|
51
|
-
if (preloadedData) {
|
|
52
|
-
loadData(preloadedData, { segments, largeSegments }, matchingKey);
|
|
53
|
-
}
|
|
54
|
-
|
|
45
|
+
shared() {
|
|
55
46
|
return {
|
|
56
47
|
splits: this.splits,
|
|
57
|
-
segments,
|
|
58
|
-
largeSegments,
|
|
48
|
+
segments: new MySegmentsCacheInMemory(),
|
|
49
|
+
largeSegments: new MySegmentsCacheInMemory(),
|
|
59
50
|
impressions: this.impressions,
|
|
60
51
|
impressionCounts: this.impressionCounts,
|
|
61
52
|
events: this.events,
|
|
@@ -81,12 +72,6 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
81
72
|
if (storage.uniqueKeys) storage.uniqueKeys.track = noopTrack;
|
|
82
73
|
}
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
if (preloadedData) {
|
|
86
|
-
loadData(preloadedData, storage, getMatching(params.settings.core.key));
|
|
87
|
-
if (splits.getChangeNumber() > -1) onReadyFromCacheCb();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
75
|
return storage;
|
|
91
76
|
}
|
|
92
77
|
|
package/src/storages/types.ts
CHANGED
|
@@ -488,6 +488,8 @@ export interface IStorageAsync extends IStorageBase<
|
|
|
488
488
|
|
|
489
489
|
/** StorageFactory */
|
|
490
490
|
|
|
491
|
+
export type DataLoader = (storage: IStorageSync, matchingKey: string) => void
|
|
492
|
+
|
|
491
493
|
export interface IStorageFactoryParams {
|
|
492
494
|
settings: ISettings,
|
|
493
495
|
/**
|
|
@@ -495,10 +497,6 @@ export interface IStorageFactoryParams {
|
|
|
495
497
|
* It is meant for emitting SDK_READY event in consumer mode, and waiting before using the storage in the synchronizer.
|
|
496
498
|
*/
|
|
497
499
|
onReadyCb: (error?: any) => void,
|
|
498
|
-
/**
|
|
499
|
-
* It is meant for emitting SDK_READY_FROM_CACHE event in standalone mode with preloaded data
|
|
500
|
-
*/
|
|
501
|
-
onReadyFromCacheCb: () => void,
|
|
502
500
|
}
|
|
503
501
|
|
|
504
502
|
export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE';
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { splitsParserFromSettingsFactory } from './splitsParser/splitsParserFromSettings';
|
|
2
2
|
import { syncManagerOfflineFactory } from './syncManagerOffline';
|
|
3
|
-
import { SplitIO } from '../../types';
|
|
4
3
|
|
|
5
|
-
// Singleton instance of the factory function for offline SyncManager from object
|
|
4
|
+
// Singleton instance of the factory function for offline SyncManager from object
|
|
6
5
|
// SDK instances instantiate their SyncManagers with the same factory
|
|
7
|
-
const
|
|
8
|
-
localhostFromObject.type = 'LocalhostFromObject';
|
|
9
|
-
|
|
10
|
-
export function LocalhostFromObject(): SplitIO.LocalhostFactory {
|
|
11
|
-
return localhostFromObject;
|
|
12
|
-
}
|
|
6
|
+
export const localhostFromObjectFactory = syncManagerOfflineFactory(splitsParserFromSettingsFactory);
|
package/src/types.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable no-use-before-define */
|
|
2
|
+
import { ISplitFiltersValidation } from './dtos/types';
|
|
2
3
|
import { IIntegration, IIntegrationFactoryParams } from './integrations/types';
|
|
3
4
|
import { ILogger } from './logger/types';
|
|
4
|
-
import { ISdkFactoryContext } from './sdkFactory/types';
|
|
5
|
-
/* eslint-disable no-use-before-define */
|
|
6
|
-
|
|
7
5
|
import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory } from './storages/types';
|
|
8
|
-
import { ISyncManagerCS } from './sync/types';
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* Reduced version of NodeJS.EventEmitter interface with the minimal methods used by the SDK
|
|
@@ -97,7 +94,6 @@ export interface ISettings {
|
|
|
97
94
|
eventsFirstPushWindow: number
|
|
98
95
|
},
|
|
99
96
|
readonly storage: IStorageSyncFactory | IStorageAsyncFactory,
|
|
100
|
-
readonly preloadedData?: SplitIO.PreloadedData,
|
|
101
97
|
readonly integrations: Array<{
|
|
102
98
|
readonly type: string,
|
|
103
99
|
(params: IIntegrationFactoryParams): IIntegration | void
|
|
@@ -117,7 +113,6 @@ export interface ISettings {
|
|
|
117
113
|
splitFilters: SplitIO.SplitFilter[],
|
|
118
114
|
impressionsMode: SplitIO.ImpressionsMode,
|
|
119
115
|
__splitFiltersValidation: ISplitFiltersValidation,
|
|
120
|
-
localhostMode?: SplitIO.LocalhostFactory,
|
|
121
116
|
enabled: boolean,
|
|
122
117
|
flagSpecVersion: string,
|
|
123
118
|
requestOptions?: {
|
|
@@ -667,13 +662,6 @@ export namespace SplitIO {
|
|
|
667
662
|
* @typedef {Promise<SplitNames>} SplitNamesAsync
|
|
668
663
|
*/
|
|
669
664
|
export type SplitNamesAsync = Promise<SplitNames>;
|
|
670
|
-
/**
|
|
671
|
-
* Localhost mode factory.
|
|
672
|
-
*/
|
|
673
|
-
export type LocalhostFactory = {
|
|
674
|
-
type: 'LocalhostFromObject' | 'LocalhostFromFile'
|
|
675
|
-
(params: ISdkFactoryContext): ISyncManagerCS
|
|
676
|
-
}
|
|
677
665
|
/**
|
|
678
666
|
* Impression listener interface. This is the interface that needs to be implemented
|
|
679
667
|
* by the element you provide to the SDK as impression listener.
|
|
@@ -771,31 +759,31 @@ export namespace SplitIO {
|
|
|
771
759
|
* If this value is older than 10 days ago (expiration time policy), the data is not used to update the storage content.
|
|
772
760
|
* @TODO configurable expiration time policy?
|
|
773
761
|
*/
|
|
774
|
-
|
|
762
|
+
lastUpdated: number,
|
|
775
763
|
/**
|
|
776
764
|
* Change number of the preloaded data.
|
|
777
765
|
* If this value is older than the current changeNumber at the storage, the data is not used to update the storage content.
|
|
778
766
|
*/
|
|
779
767
|
since: number,
|
|
780
768
|
/**
|
|
781
|
-
*
|
|
782
|
-
* @TODO rename to flags
|
|
769
|
+
* Map of feature flags to their stringified definitions.
|
|
783
770
|
*/
|
|
784
|
-
splitsData:
|
|
771
|
+
splitsData: {
|
|
772
|
+
[splitName: string]: string
|
|
773
|
+
},
|
|
785
774
|
/**
|
|
786
|
-
* Optional map of user keys to their
|
|
787
|
-
* @TODO
|
|
775
|
+
* Optional map of user keys to their list of segments.
|
|
776
|
+
* @TODO remove when releasing first version
|
|
788
777
|
*/
|
|
789
|
-
|
|
790
|
-
[key: string]:
|
|
778
|
+
mySegmentsData?: {
|
|
779
|
+
[key: string]: string[]
|
|
791
780
|
},
|
|
792
781
|
/**
|
|
793
|
-
* Optional map of segments to their
|
|
794
|
-
* This property is ignored if `
|
|
795
|
-
* @TODO rename to segments
|
|
782
|
+
* Optional map of segments to their stringified definitions.
|
|
783
|
+
* This property is ignored if `mySegmentsData` was provided.
|
|
796
784
|
*/
|
|
797
785
|
segmentsData?: {
|
|
798
|
-
[segmentName: string]: string
|
|
786
|
+
[segmentName: string]: string
|
|
799
787
|
},
|
|
800
788
|
}
|
|
801
789
|
/**
|
|
@@ -80,7 +80,6 @@ export const base = {
|
|
|
80
80
|
splitFilters: undefined,
|
|
81
81
|
// impressions collection mode
|
|
82
82
|
impressionsMode: OPTIMIZED,
|
|
83
|
-
localhostMode: undefined,
|
|
84
83
|
enabled: true,
|
|
85
84
|
flagSpecVersion: FLAG_SPEC_VERSION
|
|
86
85
|
},
|
|
@@ -102,7 +101,7 @@ function fromSecondsToMillis(n: number) {
|
|
|
102
101
|
*/
|
|
103
102
|
export function settingsValidation(config: unknown, validationParams: ISettingsValidationParams) {
|
|
104
103
|
|
|
105
|
-
const { defaults, runtime, storage, integrations, logger,
|
|
104
|
+
const { defaults, runtime, storage, integrations, logger, consent, flagSpec } = validationParams;
|
|
106
105
|
|
|
107
106
|
// creates a settings object merging base, defaults and config objects.
|
|
108
107
|
const withDefaults = merge({}, base, defaults, config) as ISettings;
|
|
@@ -180,8 +179,6 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
180
179
|
// @ts-ignore, modify readonly prop
|
|
181
180
|
if (integrations) withDefaults.integrations = integrations(withDefaults);
|
|
182
181
|
|
|
183
|
-
if (localhost) sync.localhostMode = localhost(withDefaults);
|
|
184
|
-
|
|
185
182
|
// validate push options
|
|
186
183
|
if (withDefaults.streamingEnabled !== false) { // @ts-ignore, modify readonly prop
|
|
187
184
|
withDefaults.streamingEnabled = true;
|
|
@@ -20,8 +20,6 @@ export interface ISettingsValidationParams {
|
|
|
20
20
|
integrations?: (settings: ISettings) => ISettings['integrations'],
|
|
21
21
|
/** Logger validator (`settings.debug`) */
|
|
22
22
|
logger: (settings: ISettings) => ISettings['log'],
|
|
23
|
-
/** Localhost mode validator (`settings.sync.localhostMode`) */
|
|
24
|
-
localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'],
|
|
25
23
|
/** User consent validator (`settings.userConsent`) */
|
|
26
24
|
consent?: (settings: ISettings) => ISettings['userConsent'],
|
|
27
25
|
/** Flag spec version validation. Configurable by the JS Synchronizer but not by the SDKs */
|
|
@@ -106,7 +106,6 @@ export declare const ERROR_EMPTY = 319;
|
|
|
106
106
|
export declare const ERROR_EMPTY_ARRAY = 320;
|
|
107
107
|
export declare const ERROR_INVALID_CONFIG_PARAM = 321;
|
|
108
108
|
export declare const ERROR_HTTP = 322;
|
|
109
|
-
export declare const ERROR_LOCALHOST_MODULE_REQUIRED = 323;
|
|
110
109
|
export declare const ERROR_STORAGE_INVALID = 324;
|
|
111
110
|
export declare const ERROR_NOT_BOOLEAN = 325;
|
|
112
111
|
export declare const ERROR_MIN_CONFIG_PARAM = 326;
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import { SplitIO } from '../types';
|
|
2
|
-
import {
|
|
2
|
+
import { DataLoader } from './types';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
4
|
+
* Factory of client-side storage loader
|
|
6
5
|
*
|
|
7
|
-
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
8
|
-
*
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
* @TODO extend to load largeSegments
|
|
12
|
-
* @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.
|
|
13
|
-
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
14
|
-
* @TODO unit tests
|
|
6
|
+
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
7
|
+
* and extended with a `mySegmentsData` property.
|
|
8
|
+
* @returns function to preload the storage
|
|
15
9
|
*/
|
|
16
|
-
export declare function
|
|
17
|
-
splits?: ISplitsCacheSync;
|
|
18
|
-
segments: ISegmentsCacheSync;
|
|
19
|
-
largeSegments?: ISegmentsCacheSync;
|
|
20
|
-
}, matchingKey?: string): void;
|
|
21
|
-
export declare function getSnapshot(storage: IStorageSync, userKeys?: SplitIO.SplitKey[]): SplitIO.PreloadedData;
|
|
10
|
+
export declare function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader;
|
|
@@ -387,6 +387,7 @@ export interface IStorageSync extends IStorageBase<ISplitsCacheSync, ISegmentsCa
|
|
|
387
387
|
export interface IStorageAsync extends IStorageBase<ISplitsCacheAsync, ISegmentsCacheAsync, IImpressionsCacheAsync | IImpressionsCacheSync, IImpressionCountsCacheBase, IEventsCacheAsync | IEventsCacheSync, ITelemetryCacheAsync | ITelemetryCacheSync, IUniqueKeysCacheBase> {
|
|
388
388
|
}
|
|
389
389
|
/** StorageFactory */
|
|
390
|
+
export declare type DataLoader = (storage: IStorageSync, matchingKey: string) => void;
|
|
390
391
|
export interface IStorageFactoryParams {
|
|
391
392
|
settings: ISettings;
|
|
392
393
|
/**
|
|
@@ -394,10 +395,6 @@ export interface IStorageFactoryParams {
|
|
|
394
395
|
* It is meant for emitting SDK_READY event in consumer mode, and waiting before using the storage in the synchronizer.
|
|
395
396
|
*/
|
|
396
397
|
onReadyCb: (error?: any) => void;
|
|
397
|
-
/**
|
|
398
|
-
* It is meant for emitting SDK_READY_FROM_CACHE event in standalone mode with preloaded data
|
|
399
|
-
*/
|
|
400
|
-
onReadyFromCacheCb: () => void;
|
|
401
398
|
}
|
|
402
399
|
export declare type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE';
|
|
403
400
|
export declare type IStorageSyncFactory = {
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function LocalhostFromObject(): SplitIO.LocalhostFactory;
|
|
1
|
+
export declare const localhostFromObjectFactory: (params: import("../../sdkFactory/types").ISdkFactoryContextSync) => import("../types").ISyncManagerCS;
|
package/types/types.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ISplitFiltersValidation } from './dtos/types';
|
|
2
2
|
import { IIntegration, IIntegrationFactoryParams } from './integrations/types';
|
|
3
3
|
import { ILogger } from './logger/types';
|
|
4
|
-
import { ISdkFactoryContext } from './sdkFactory/types';
|
|
5
4
|
import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory } from './storages/types';
|
|
6
|
-
import { ISyncManagerCS } from './sync/types';
|
|
7
5
|
/**
|
|
8
6
|
* Reduced version of NodeJS.EventEmitter interface with the minimal methods used by the SDK
|
|
9
7
|
* @see {@link https://nodejs.org/api/events.html}
|
|
@@ -91,7 +89,6 @@ export interface ISettings {
|
|
|
91
89
|
eventsFirstPushWindow: number;
|
|
92
90
|
};
|
|
93
91
|
readonly storage: IStorageSyncFactory | IStorageAsyncFactory;
|
|
94
|
-
readonly preloadedData?: SplitIO.PreloadedData;
|
|
95
92
|
readonly integrations: Array<{
|
|
96
93
|
readonly type: string;
|
|
97
94
|
(params: IIntegrationFactoryParams): IIntegration | void;
|
|
@@ -111,7 +108,6 @@ export interface ISettings {
|
|
|
111
108
|
splitFilters: SplitIO.SplitFilter[];
|
|
112
109
|
impressionsMode: SplitIO.ImpressionsMode;
|
|
113
110
|
__splitFiltersValidation: ISplitFiltersValidation;
|
|
114
|
-
localhostMode?: SplitIO.LocalhostFactory;
|
|
115
111
|
enabled: boolean;
|
|
116
112
|
flagSpecVersion: string;
|
|
117
113
|
requestOptions?: {
|
|
@@ -660,13 +656,6 @@ export declare namespace SplitIO {
|
|
|
660
656
|
* @typedef {Promise<SplitNames>} SplitNamesAsync
|
|
661
657
|
*/
|
|
662
658
|
type SplitNamesAsync = Promise<SplitNames>;
|
|
663
|
-
/**
|
|
664
|
-
* Localhost mode factory.
|
|
665
|
-
*/
|
|
666
|
-
type LocalhostFactory = {
|
|
667
|
-
type: 'LocalhostFromObject' | 'LocalhostFromFile';
|
|
668
|
-
(params: ISdkFactoryContext): ISyncManagerCS;
|
|
669
|
-
};
|
|
670
659
|
/**
|
|
671
660
|
* Impression listener interface. This is the interface that needs to be implemented
|
|
672
661
|
* by the element you provide to the SDK as impression listener.
|
|
@@ -770,30 +759,31 @@ export declare namespace SplitIO {
|
|
|
770
759
|
* If this value is older than 10 days ago (expiration time policy), the data is not used to update the storage content.
|
|
771
760
|
* @TODO configurable expiration time policy?
|
|
772
761
|
*/
|
|
762
|
+
lastUpdated: number;
|
|
773
763
|
/**
|
|
774
764
|
* Change number of the preloaded data.
|
|
775
765
|
* If this value is older than the current changeNumber at the storage, the data is not used to update the storage content.
|
|
776
766
|
*/
|
|
777
767
|
since: number;
|
|
778
768
|
/**
|
|
779
|
-
*
|
|
780
|
-
* @TODO rename to flags
|
|
769
|
+
* Map of feature flags to their stringified definitions.
|
|
781
770
|
*/
|
|
782
|
-
splitsData:
|
|
771
|
+
splitsData: {
|
|
772
|
+
[splitName: string]: string;
|
|
773
|
+
};
|
|
783
774
|
/**
|
|
784
|
-
* Optional map of user keys to their
|
|
785
|
-
* @TODO
|
|
775
|
+
* Optional map of user keys to their list of segments.
|
|
776
|
+
* @TODO remove when releasing first version
|
|
786
777
|
*/
|
|
787
|
-
|
|
788
|
-
[key: string]:
|
|
778
|
+
mySegmentsData?: {
|
|
779
|
+
[key: string]: string[];
|
|
789
780
|
};
|
|
790
781
|
/**
|
|
791
|
-
* Optional map of segments to their
|
|
792
|
-
* This property is ignored if `
|
|
793
|
-
* @TODO rename to segments
|
|
782
|
+
* Optional map of segments to their stringified definitions.
|
|
783
|
+
* This property is ignored if `mySegmentsData` was provided.
|
|
794
784
|
*/
|
|
795
785
|
segmentsData?: {
|
|
796
|
-
[segmentName: string]: string
|
|
786
|
+
[segmentName: string]: string;
|
|
797
787
|
};
|
|
798
788
|
}
|
|
799
789
|
/**
|
|
@@ -23,8 +23,6 @@ export interface ISettingsValidationParams {
|
|
|
23
23
|
integrations?: (settings: ISettings) => ISettings['integrations'];
|
|
24
24
|
/** Logger validator (`settings.debug`) */
|
|
25
25
|
logger: (settings: ISettings) => ISettings['log'];
|
|
26
|
-
/** Localhost mode validator (`settings.sync.localhostMode`) */
|
|
27
|
-
localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'];
|
|
28
26
|
/** User consent validator (`settings.userConsent`) */
|
|
29
27
|
consent?: (settings: ISettings) => ISettings['userConsent'];
|
|
30
28
|
/** Flag spec version validation. Configurable by the JS Synchronizer but not by the SDKs */
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateLocalhostWithDefault = void 0;
|
|
4
|
-
var LocalhostFromObject_1 = require("../../../sync/offline/LocalhostFromObject");
|
|
5
|
-
var pluggable_1 = require("./pluggable");
|
|
6
|
-
/**
|
|
7
|
-
* This function validates `settings.sync.localhostMode` object
|
|
8
|
-
*
|
|
9
|
-
* @param {any} settings config object provided by the user to initialize the sdk
|
|
10
|
-
*
|
|
11
|
-
* @returns {Object} provided localhost mode module at `settings.sync.localhostMode` if valid, or a default LocalhostFromObject instance if not provided or invalid
|
|
12
|
-
*/
|
|
13
|
-
function validateLocalhostWithDefault(settings) {
|
|
14
|
-
if (!settings.sync.localhostMode)
|
|
15
|
-
return (0, LocalhostFromObject_1.LocalhostFromObject)();
|
|
16
|
-
return (0, pluggable_1.validateLocalhost)(settings) || (0, LocalhostFromObject_1.LocalhostFromObject)();
|
|
17
|
-
}
|
|
18
|
-
exports.validateLocalhostWithDefault = validateLocalhostWithDefault;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateLocalhost = void 0;
|
|
4
|
-
var constants_1 = require("../../../logger/constants");
|
|
5
|
-
var constants_2 = require("../../constants");
|
|
6
|
-
/**
|
|
7
|
-
* This function validates `settings.sync.localhostMode` object
|
|
8
|
-
*
|
|
9
|
-
* @param {any} settings config object provided by the user to initialize the sdk
|
|
10
|
-
*
|
|
11
|
-
* @returns {Object | undefined} provided localhost mode module at `settings.sync.localhostMode`, or undefined if it is not provided or invalid
|
|
12
|
-
*/
|
|
13
|
-
function validateLocalhost(settings) {
|
|
14
|
-
var localhostMode = settings.sync.localhostMode;
|
|
15
|
-
// localhostMode.type is used for internal validation. Not considered part of the public API, and might be updated eventually.
|
|
16
|
-
if (settings.mode === constants_2.LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== 'LocalhostFromObject')) {
|
|
17
|
-
settings.log.error(constants_1.ERROR_LOCALHOST_MODULE_REQUIRED);
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
return localhostMode;
|
|
21
|
-
}
|
|
22
|
-
exports.validateLocalhost = validateLocalhost;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { LocalhostFromObject } from '../../../sync/offline/LocalhostFromObject';
|
|
2
|
-
import { validateLocalhost } from './pluggable';
|
|
3
|
-
/**
|
|
4
|
-
* This function validates `settings.sync.localhostMode` object
|
|
5
|
-
*
|
|
6
|
-
* @param {any} settings config object provided by the user to initialize the sdk
|
|
7
|
-
*
|
|
8
|
-
* @returns {Object} provided localhost mode module at `settings.sync.localhostMode` if valid, or a default LocalhostFromObject instance if not provided or invalid
|
|
9
|
-
*/
|
|
10
|
-
export function validateLocalhostWithDefault(settings) {
|
|
11
|
-
if (!settings.sync.localhostMode)
|
|
12
|
-
return LocalhostFromObject();
|
|
13
|
-
return validateLocalhost(settings) || LocalhostFromObject();
|
|
14
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ERROR_LOCALHOST_MODULE_REQUIRED } from '../../../logger/constants';
|
|
2
|
-
import { LOCALHOST_MODE } from '../../constants';
|
|
3
|
-
/**
|
|
4
|
-
* This function validates `settings.sync.localhostMode` object
|
|
5
|
-
*
|
|
6
|
-
* @param {any} settings config object provided by the user to initialize the sdk
|
|
7
|
-
*
|
|
8
|
-
* @returns {Object | undefined} provided localhost mode module at `settings.sync.localhostMode`, or undefined if it is not provided or invalid
|
|
9
|
-
*/
|
|
10
|
-
export function validateLocalhost(settings) {
|
|
11
|
-
var localhostMode = settings.sync.localhostMode;
|
|
12
|
-
// localhostMode.type is used for internal validation. Not considered part of the public API, and might be updated eventually.
|
|
13
|
-
if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== 'LocalhostFromObject')) {
|
|
14
|
-
settings.log.error(ERROR_LOCALHOST_MODULE_REQUIRED);
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
return localhostMode;
|
|
18
|
-
}
|