@splitsoftware/splitio-commons 1.17.1-rc.4 → 1.17.1-rc.5
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 +28 -29
- package/LICENSE +1 -1
- package/README.md +4 -3
- package/cjs/consent/sdkUserConsent.js +4 -2
- package/cjs/evaluator/matchers/index.js +1 -3
- package/cjs/evaluator/matchers/matcherTypes.js +0 -1
- package/cjs/evaluator/matchers/segment.js +0 -6
- package/cjs/evaluator/matchersTransform/index.js +1 -4
- package/cjs/evaluator/matchersTransform/segment.js +1 -3
- package/cjs/logger/constants.js +2 -2
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +8 -18
- package/cjs/readiness/sdkReadinessManager.js +6 -5
- package/cjs/sdkClient/sdkClient.js +5 -5
- package/cjs/sdkClient/sdkClientMethod.js +1 -3
- package/cjs/sdkClient/sdkClientMethodCS.js +15 -9
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +15 -9
- package/cjs/sdkFactory/index.js +10 -32
- package/cjs/services/decorateHeaders.js +6 -1
- package/cjs/services/splitApi.js +5 -5
- package/cjs/services/splitHttpClient.js +5 -2
- package/cjs/storages/AbstractSegmentsCacheSync.js +33 -0
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -2
- package/cjs/storages/KeyBuilderCS.js +5 -23
- package/cjs/storages/dataLoader.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
- package/cjs/storages/inLocalStorage/index.js +2 -6
- package/cjs/storages/inMemory/InMemoryStorageCS.js +1 -6
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +28 -14
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +9 -8
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +21 -15
- package/cjs/storages/inRedis/index.js +11 -5
- package/cjs/storages/pluggable/SegmentsCachePluggable.js +34 -13
- package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
- package/cjs/sync/offline/syncManagerOffline.js +11 -18
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -15
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +28 -12
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/cjs/sync/streaming/AuthClient/index.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +5 -3
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +48 -107
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
- package/cjs/sync/streaming/constants.js +3 -3
- package/cjs/sync/streaming/parseUtils.js +9 -14
- package/cjs/sync/streaming/pushManager.js +67 -69
- package/cjs/sync/syncManagerOnline.js +21 -20
- package/cjs/sync/syncTask.js +2 -2
- package/cjs/trackers/eventTracker.js +10 -12
- package/cjs/trackers/impressionsTracker.js +14 -16
- package/cjs/trackers/uniqueKeysTracker.js +3 -5
- package/cjs/utils/constants/index.js +4 -5
- package/cjs/utils/settingsValidation/index.js +1 -2
- package/esm/consent/sdkUserConsent.js +4 -2
- package/esm/evaluator/matchers/index.js +1 -3
- package/esm/evaluator/matchers/matcherTypes.js +0 -1
- package/esm/evaluator/matchers/segment.js +0 -6
- package/esm/evaluator/matchersTransform/index.js +1 -4
- package/esm/evaluator/matchersTransform/segment.js +1 -3
- package/esm/logger/constants.js +1 -1
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +8 -18
- package/esm/readiness/sdkReadinessManager.js +6 -5
- package/esm/sdkClient/sdkClient.js +5 -5
- package/esm/sdkClient/sdkClientMethod.js +1 -3
- package/esm/sdkClient/sdkClientMethodCS.js +13 -7
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +13 -7
- package/esm/sdkFactory/index.js +10 -32
- package/esm/services/decorateHeaders.js +4 -0
- package/esm/services/splitApi.js +6 -6
- package/esm/services/splitHttpClient.js +6 -3
- package/esm/storages/AbstractSegmentsCacheSync.js +30 -0
- package/esm/storages/AbstractSplitsCacheSync.js +2 -3
- package/esm/storages/KeyBuilderCS.js +4 -21
- package/esm/storages/dataLoader.js +1 -1
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
- package/esm/storages/inLocalStorage/index.js +3 -7
- package/esm/storages/inMemory/InMemoryStorageCS.js +1 -6
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +28 -14
- package/esm/storages/inMemory/SplitsCacheInMemory.js +9 -8
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
- package/esm/storages/inRedis/SegmentsCacheInRedis.js +21 -15
- package/esm/storages/inRedis/index.js +11 -5
- package/esm/storages/pluggable/SegmentsCachePluggable.js +34 -13
- package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
- package/esm/sync/offline/syncManagerOffline.js +11 -18
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +21 -15
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +28 -12
- package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/esm/sync/streaming/AuthClient/index.js +1 -1
- package/esm/sync/streaming/SSEHandler/index.js +6 -4
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +49 -108
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
- package/esm/sync/streaming/constants.js +2 -2
- package/esm/sync/streaming/parseUtils.js +8 -12
- package/esm/sync/streaming/pushManager.js +70 -72
- package/esm/sync/syncManagerOnline.js +21 -20
- package/esm/sync/syncTask.js +2 -2
- package/esm/trackers/eventTracker.js +10 -12
- package/esm/trackers/impressionsTracker.js +14 -16
- package/esm/trackers/uniqueKeysTracker.js +3 -5
- package/esm/utils/constants/index.js +2 -3
- package/esm/utils/settingsValidation/index.js +1 -2
- package/package.json +1 -1
- package/src/consent/sdkUserConsent.ts +3 -2
- package/src/dtos/types.ts +7 -21
- package/src/evaluator/matchers/index.ts +0 -2
- package/src/evaluator/matchers/matcherTypes.ts +0 -1
- package/src/evaluator/matchers/segment.ts +0 -7
- package/src/evaluator/matchersTransform/index.ts +1 -4
- package/src/evaluator/matchersTransform/segment.ts +3 -5
- package/src/logger/constants.ts +1 -1
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +8 -19
- package/src/readiness/sdkReadinessManager.ts +7 -7
- package/src/readiness/types.ts +2 -5
- package/src/sdkClient/sdkClient.ts +5 -5
- package/src/sdkClient/sdkClientMethod.ts +1 -4
- package/src/sdkClient/sdkClientMethodCS.ts +15 -7
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +15 -7
- package/src/sdkFactory/index.ts +12 -35
- package/src/sdkFactory/types.ts +1 -4
- package/src/services/decorateHeaders.ts +5 -0
- package/src/services/splitApi.ts +7 -7
- package/src/services/splitHttpClient.ts +7 -4
- package/src/services/types.ts +2 -2
- package/src/storages/AbstractSegmentsCacheSync.ts +68 -0
- package/src/storages/AbstractSplitsCacheSync.ts +3 -4
- package/src/storages/KeyBuilderCS.ts +5 -34
- package/src/storages/dataLoader.ts +1 -1
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +63 -33
- package/src/storages/inLocalStorage/index.ts +4 -8
- package/src/storages/inMemory/InMemoryStorageCS.ts +1 -6
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +47 -13
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +27 -13
- package/src/storages/inMemory/SplitsCacheInMemory.ts +9 -7
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
- package/src/storages/inRedis/SegmentsCacheInRedis.ts +24 -15
- package/src/storages/inRedis/index.ts +12 -6
- package/src/storages/pluggable/SegmentsCachePluggable.ts +37 -13
- package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
- package/src/storages/types.ts +17 -15
- package/src/sync/offline/syncManagerOffline.ts +13 -21
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +10 -8
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
- package/src/sync/polling/fetchers/types.ts +2 -3
- package/src/sync/polling/pollingManagerCS.ts +4 -4
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +5 -4
- package/src/sync/polling/types.ts +6 -7
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +22 -19
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +29 -13
- package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
- package/src/sync/streaming/AuthClient/index.ts +1 -1
- package/src/sync/streaming/SSEClient/index.ts +6 -4
- package/src/sync/streaming/SSEHandler/index.ts +8 -5
- package/src/sync/streaming/SSEHandler/types.ts +15 -15
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +49 -116
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +4 -4
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
- package/src/sync/streaming/constants.ts +2 -2
- package/src/sync/streaming/parseUtils.ts +11 -19
- package/src/sync/streaming/pushManager.ts +72 -73
- package/src/sync/streaming/types.ts +10 -10
- package/src/sync/submitters/types.ts +5 -8
- package/src/sync/syncManagerOnline.ts +17 -17
- package/src/sync/syncTask.ts +2 -2
- package/src/sync/types.ts +1 -1
- package/src/trackers/eventTracker.ts +8 -11
- package/src/trackers/impressionsTracker.ts +10 -13
- package/src/trackers/types.ts +0 -1
- package/src/trackers/uniqueKeysTracker.ts +4 -6
- package/src/types.ts +1 -7
- package/src/utils/constants/index.ts +2 -3
- package/src/utils/settingsValidation/index.ts +2 -3
- package/src/utils/settingsValidation/types.ts +1 -1
- package/types/dtos/types.d.ts +7 -18
- package/types/evaluator/matchersTransform/segment.d.ts +2 -2
- package/types/logger/constants.d.ts +1 -1
- package/types/readiness/readinessManager.d.ts +2 -2
- package/types/readiness/sdkReadinessManager.d.ts +3 -2
- package/types/readiness/types.d.ts +2 -5
- package/types/sdkClient/sdkClientMethod.d.ts +1 -1
- package/types/sdkFactory/types.d.ts +1 -3
- package/types/services/decorateHeaders.d.ts +1 -0
- package/types/services/splitApi.d.ts +1 -1
- package/types/services/splitHttpClient.d.ts +1 -1
- package/types/services/types.d.ts +2 -2
- package/types/storages/AbstractSegmentsCacheSync.d.ts +11 -9
- package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
- package/types/storages/KeyBuilderCS.d.ts +2 -9
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +18 -8
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +13 -7
- package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +8 -6
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -1
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
- package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +4 -7
- package/types/storages/inRedis/index.d.ts +1 -1
- package/types/storages/pluggable/SegmentsCachePluggable.d.ts +17 -5
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
- package/types/storages/types.d.ts +15 -11
- package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
- package/types/sync/polling/fetchers/types.d.ts +2 -2
- package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
- package/types/sync/polling/types.d.ts +4 -7
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -4
- package/types/sync/streaming/SSEHandler/types.d.ts +14 -16
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -4
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
- package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
- package/types/sync/streaming/constants.d.ts +2 -2
- package/types/sync/streaming/parseUtils.d.ts +5 -4
- package/types/sync/streaming/types.d.ts +8 -8
- package/types/sync/submitters/types.d.ts +4 -7
- package/types/sync/types.d.ts +1 -1
- package/types/trackers/eventTracker.d.ts +1 -1
- package/types/trackers/impressionsTracker.d.ts +1 -1
- package/types/trackers/types.d.ts +0 -1
- package/types/types.d.ts +1 -7
- package/types/utils/constants/index.d.ts +2 -3
- package/types/utils/settingsValidation/types.d.ts +1 -1
- package/cjs/evaluator/matchers/large_segment.js +0 -16
- package/cjs/sdkClient/identity.js +0 -7
- package/cjs/storages/AbstractMySegmentsCacheSync.js +0 -60
- package/esm/evaluator/matchers/large_segment.js +0 -12
- package/esm/sdkClient/identity.js +0 -3
- package/esm/storages/AbstractMySegmentsCacheSync.js +0 -57
- package/src/evaluator/matchers/large_segment.ts +0 -18
- package/src/sdkClient/identity.ts +0 -5
- package/src/storages/AbstractMySegmentsCacheSync.ts +0 -94
- package/types/evaluator/matchers/large_segment.d.ts +0 -5
- 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/sdkClient/identity.d.ts +0 -2
- package/types/storages/AbstractMySegmentsCacheSync.d.ts +0 -39
- 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/redis/RedisMock.d.ts +0 -4
- package/types/utils/settingsValidation/logger/globalLogLevel.d.ts +0 -8
- /package/types/utils/{semVer.d.ts → Semver.d.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
|
-
import { IEventEmitter
|
|
2
|
+
import { IEventEmitter } from '../types';
|
|
3
3
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
|
|
4
4
|
import { IReadinessEventEmitter, IReadinessManager, ISegmentsEventEmitter, ISplitsEventEmitter } from './types';
|
|
5
5
|
|
|
@@ -7,12 +7,10 @@ function splitsEventEmitterFactory(EventEmitter: new () => IEventEmitter): ISpli
|
|
|
7
7
|
const splitsEventEmitter = objectAssign(new EventEmitter(), {
|
|
8
8
|
splitsArrived: false,
|
|
9
9
|
splitsCacheLoaded: false,
|
|
10
|
-
initialized: false,
|
|
11
|
-
initCallbacks: []
|
|
12
10
|
});
|
|
13
11
|
|
|
14
12
|
// `isSplitKill` condition avoids an edge-case of wrongly emitting SDK_READY if:
|
|
15
|
-
// - `/
|
|
13
|
+
// - `/mySegments` fetch and SPLIT_KILL occurs before `/splitChanges` fetch, and
|
|
16
14
|
// - storage has cached splits (for which case `splitsStorage.killLocally` can return true)
|
|
17
15
|
splitsEventEmitter.on(SDK_SPLITS_ARRIVED, (isSplitKill: boolean) => { if (!isSplitKill) splitsEventEmitter.splitsArrived = true; });
|
|
18
16
|
splitsEventEmitter.once(SDK_SPLITS_CACHE_LOADED, () => { splitsEventEmitter.splitsCacheLoaded = true; });
|
|
@@ -35,11 +33,9 @@ function segmentsEventEmitterFactory(EventEmitter: new () => IEventEmitter): ISe
|
|
|
35
33
|
*/
|
|
36
34
|
export function readinessManagerFactory(
|
|
37
35
|
EventEmitter: new () => IEventEmitter,
|
|
38
|
-
|
|
36
|
+
readyTimeout = 0,
|
|
39
37
|
splits: ISplitsEventEmitter = splitsEventEmitterFactory(EventEmitter)): IReadinessManager {
|
|
40
38
|
|
|
41
|
-
const readyTimeout = settings.startup.readyTimeout;
|
|
42
|
-
|
|
43
39
|
const segments: ISegmentsEventEmitter = segmentsEventEmitterFactory(EventEmitter);
|
|
44
40
|
const gate: IReadinessEventEmitter = new EventEmitter();
|
|
45
41
|
|
|
@@ -58,8 +54,8 @@ export function readinessManagerFactory(
|
|
|
58
54
|
// emit SDK_READY_TIMED_OUT
|
|
59
55
|
let hasTimedout = false;
|
|
60
56
|
|
|
61
|
-
function timeout() {
|
|
62
|
-
if (hasTimedout
|
|
57
|
+
function timeout() {
|
|
58
|
+
if (hasTimedout) return;
|
|
63
59
|
hasTimedout = true;
|
|
64
60
|
syncLastUpdate();
|
|
65
61
|
gate.emit(SDK_READY_TIMED_OUT, 'Split SDK emitted SDK_READY_TIMED_OUT event.');
|
|
@@ -67,8 +63,7 @@ export function readinessManagerFactory(
|
|
|
67
63
|
|
|
68
64
|
let readyTimeoutId: ReturnType<typeof setTimeout>;
|
|
69
65
|
if (readyTimeout > 0) {
|
|
70
|
-
|
|
71
|
-
else splits.initCallbacks.push(() => { readyTimeoutId = setTimeout(timeout, readyTimeout); });
|
|
66
|
+
readyTimeoutId = setTimeout(timeout, readyTimeout);
|
|
72
67
|
}
|
|
73
68
|
|
|
74
69
|
// emit SDK_READY and SDK_UPDATE
|
|
@@ -123,9 +118,9 @@ export function readinessManagerFactory(
|
|
|
123
118
|
segments,
|
|
124
119
|
gate,
|
|
125
120
|
|
|
126
|
-
shared() {
|
|
121
|
+
shared(readyTimeout = 0) {
|
|
127
122
|
refCount++;
|
|
128
|
-
return readinessManagerFactory(EventEmitter,
|
|
123
|
+
return readinessManagerFactory(EventEmitter, readyTimeout, splits);
|
|
129
124
|
},
|
|
130
125
|
|
|
131
126
|
// @TODO review/remove next methods when non-recoverable errors are reworked
|
|
@@ -135,12 +130,6 @@ export function readinessManagerFactory(
|
|
|
135
130
|
// tracking and evaluations, while keeping event listeners to emit SDK_READY_TIMED_OUT event
|
|
136
131
|
setDestroyed() { isDestroyed = true; },
|
|
137
132
|
|
|
138
|
-
init() {
|
|
139
|
-
if (splits.initialized) return;
|
|
140
|
-
splits.initialized = true;
|
|
141
|
-
splits.initCallbacks.forEach(cb => cb());
|
|
142
|
-
},
|
|
143
|
-
|
|
144
133
|
destroy() {
|
|
145
134
|
isDestroyed = true;
|
|
146
135
|
syncLastUpdate();
|
|
@@ -2,8 +2,9 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
2
2
|
import { promiseWrapper } from '../utils/promise/wrapper';
|
|
3
3
|
import { readinessManagerFactory } from './readinessManager';
|
|
4
4
|
import { ISdkReadinessManager } from './types';
|
|
5
|
-
import { IEventEmitter
|
|
5
|
+
import { IEventEmitter } from '../types';
|
|
6
6
|
import { SDK_READY, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE } from './constants';
|
|
7
|
+
import { ILogger } from '../logger/types';
|
|
7
8
|
import { ERROR_CLIENT_LISTENER, CLIENT_READY_FROM_CACHE, CLIENT_READY, CLIENT_NO_LISTENER } from '../logger/constants';
|
|
8
9
|
|
|
9
10
|
const NEW_LISTENER_EVENT = 'newListener';
|
|
@@ -17,11 +18,10 @@ const REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
17
18
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
18
19
|
*/
|
|
19
20
|
export function sdkReadinessManagerFactory(
|
|
21
|
+
log: ILogger,
|
|
20
22
|
EventEmitter: new () => IEventEmitter,
|
|
21
|
-
|
|
22
|
-
readinessManager = readinessManagerFactory(EventEmitter,
|
|
23
|
-
|
|
24
|
-
const log = settings.log;
|
|
23
|
+
readyTimeout = 0,
|
|
24
|
+
readinessManager = readinessManagerFactory(EventEmitter, readyTimeout)): ISdkReadinessManager {
|
|
25
25
|
|
|
26
26
|
/** Ready callback warning */
|
|
27
27
|
let internalReadyCbCount = 0;
|
|
@@ -72,8 +72,8 @@ export function sdkReadinessManagerFactory(
|
|
|
72
72
|
return {
|
|
73
73
|
readinessManager,
|
|
74
74
|
|
|
75
|
-
shared() {
|
|
76
|
-
return sdkReadinessManagerFactory(EventEmitter,
|
|
75
|
+
shared(readyTimeout = 0) {
|
|
76
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
77
77
|
},
|
|
78
78
|
|
|
79
79
|
incInternalReadyCbCount() {
|
package/src/readiness/types.ts
CHANGED
|
@@ -12,8 +12,6 @@ export interface ISplitsEventEmitter extends IEventEmitter {
|
|
|
12
12
|
once(event: ISplitsEvent, listener: (...args: any[]) => void): this;
|
|
13
13
|
splitsArrived: boolean
|
|
14
14
|
splitsCacheLoaded: boolean
|
|
15
|
-
initialized: boolean,
|
|
16
|
-
initCallbacks: (() => void)[]
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
/** Segments data emitter */
|
|
@@ -61,10 +59,9 @@ export interface IReadinessManager {
|
|
|
61
59
|
timeout(): void,
|
|
62
60
|
setDestroyed(): void,
|
|
63
61
|
destroy(): void,
|
|
64
|
-
init(): void,
|
|
65
62
|
|
|
66
63
|
/** for client-side */
|
|
67
|
-
shared(): IReadinessManager,
|
|
64
|
+
shared(readyTimeout?: number): IReadinessManager,
|
|
68
65
|
}
|
|
69
66
|
|
|
70
67
|
/** SDK readiness manager */
|
|
@@ -80,5 +77,5 @@ export interface ISdkReadinessManager {
|
|
|
80
77
|
incInternalReadyCbCount(): void
|
|
81
78
|
|
|
82
79
|
/** for client-side */
|
|
83
|
-
shared(): ISdkReadinessManager
|
|
80
|
+
shared(readyTimeout?: number): ISdkReadinessManager
|
|
84
81
|
}
|
|
@@ -66,11 +66,11 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
|
|
|
66
66
|
syncManager && syncManager.stop();
|
|
67
67
|
|
|
68
68
|
return __flush().then(() => {
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
// Cleanup event listeners
|
|
70
|
+
signalListener && signalListener.stop();
|
|
71
|
+
|
|
72
|
+
// @TODO stop only if last client is destroyed
|
|
73
|
+
if (uniqueKeysTracker) uniqueKeysTracker.stop();
|
|
74
74
|
|
|
75
75
|
// Cleanup storage
|
|
76
76
|
return storage.destroy();
|
|
@@ -4,15 +4,12 @@ import { RETRIEVE_CLIENT_DEFAULT } from '../logger/constants';
|
|
|
4
4
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Factory of client method for server-side SDKs
|
|
7
|
+
* Factory of client method for server-side SDKs (ISDK and IAsyncSDK)
|
|
8
8
|
*/
|
|
9
9
|
export function sdkClientMethodFactory(params: ISdkFactoryContext): () => SplitIO.IClient | SplitIO.IAsyncClient {
|
|
10
10
|
const log = params.settings.log;
|
|
11
11
|
const clientInstance = sdkClientFactory(params);
|
|
12
12
|
|
|
13
|
-
// Only one client in server-side without bound key
|
|
14
|
-
params.clients[''] = clientInstance;
|
|
15
|
-
|
|
16
13
|
return function client() {
|
|
17
14
|
if (arguments.length > 0) {
|
|
18
15
|
throw new Error('Shared Client not supported by the storage mechanism. Create isolated instances instead.');
|
|
@@ -8,14 +8,18 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
8
8
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING, LOG_PREFIX_CLIENT_INSTANTIATION } from '../logger/constants';
|
|
9
9
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
10
10
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
function buildInstanceId(key: SplitIO.SplitKey) {
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
return `${key.matchingKey ? key.matchingKey : key}-${key.bucketingKey ? key.bucketingKey : key}-`;
|
|
15
|
+
}
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* Factory of client method for the client-side API variant where TT is ignored.
|
|
15
19
|
* Therefore, clients don't have a bound TT for the track method.
|
|
16
20
|
*/
|
|
17
21
|
export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey) => SplitIO.ICsClient {
|
|
18
|
-
const {
|
|
22
|
+
const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params;
|
|
19
23
|
|
|
20
24
|
const mainClientInstance = clientCSDecorator(
|
|
21
25
|
log,
|
|
@@ -27,7 +31,8 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
27
31
|
const defaultInstanceId = buildInstanceId(parsedDefaultKey);
|
|
28
32
|
|
|
29
33
|
// Cache instances created per factory.
|
|
30
|
-
|
|
34
|
+
const clientInstances: Record<string, SplitIO.ICsClient> = {};
|
|
35
|
+
clientInstances[defaultInstanceId] = mainClientInstance;
|
|
31
36
|
|
|
32
37
|
return function client(key?: SplitIO.SplitKey) {
|
|
33
38
|
if (key === undefined) {
|
|
@@ -43,10 +48,10 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
43
48
|
|
|
44
49
|
const instanceId = buildInstanceId(validKey);
|
|
45
50
|
|
|
46
|
-
if (!
|
|
51
|
+
if (!clientInstances[instanceId]) {
|
|
47
52
|
const matchingKey = getMatching(validKey);
|
|
48
53
|
|
|
49
|
-
const sharedSdkReadiness = sdkReadinessManager.shared();
|
|
54
|
+
const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout);
|
|
50
55
|
const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => {
|
|
51
56
|
if (err) {
|
|
52
57
|
sharedSdkReadiness.readinessManager.timeout();
|
|
@@ -65,21 +70,24 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
65
70
|
|
|
66
71
|
// As shared clients reuse all the storage information, we don't need to check here if we
|
|
67
72
|
// will use offline or online mode. We should stick with the original decision.
|
|
68
|
-
|
|
73
|
+
clientInstances[instanceId] = clientCSDecorator(
|
|
69
74
|
log,
|
|
70
75
|
sdkClientFactory(objectAssign({}, params, {
|
|
71
76
|
sdkReadinessManager: sharedSdkReadiness,
|
|
72
77
|
storage: sharedStorage || storage,
|
|
73
78
|
syncManager: sharedSyncManager,
|
|
79
|
+
signalListener: undefined, // only the main client "destroy" method stops the signal listener
|
|
74
80
|
}), true) as SplitIO.IClient,
|
|
75
81
|
validKey
|
|
76
82
|
);
|
|
77
83
|
|
|
84
|
+
sharedSyncManager && sharedSyncManager.start();
|
|
85
|
+
|
|
78
86
|
log.info(NEW_SHARED_CLIENT);
|
|
79
87
|
} else {
|
|
80
88
|
log.debug(RETRIEVE_CLIENT_EXISTING);
|
|
81
89
|
}
|
|
82
90
|
|
|
83
|
-
return
|
|
91
|
+
return clientInstances[instanceId];
|
|
84
92
|
};
|
|
85
93
|
}
|
|
@@ -9,7 +9,11 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
9
9
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING, LOG_PREFIX_CLIENT_INSTANTIATION } from '../logger/constants';
|
|
10
10
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
11
11
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
function buildInstanceId(key: SplitIO.SplitKey, trafficType?: string) {
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
return `${key.matchingKey ? key.matchingKey : key}-${key.bucketingKey ? key.bucketingKey : key}-${trafficType !== undefined ? trafficType : ''}`;
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
/**
|
|
15
19
|
* Factory of client method for the client-side (browser) variant of the Isomorphic JS SDK,
|
|
@@ -17,7 +21,7 @@ import { buildInstanceId } from './identity';
|
|
|
17
21
|
* (default client) or the client method (shared clients).
|
|
18
22
|
*/
|
|
19
23
|
export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey, trafficType?: string) => SplitIO.ICsClient {
|
|
20
|
-
const {
|
|
24
|
+
const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, startup: { readyTimeout }, log } } = params;
|
|
21
25
|
|
|
22
26
|
const mainClientInstance = clientCSDecorator(
|
|
23
27
|
log,
|
|
@@ -30,7 +34,8 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
30
34
|
const defaultInstanceId = buildInstanceId(parsedDefaultKey, trafficType);
|
|
31
35
|
|
|
32
36
|
// Cache instances created per factory.
|
|
33
|
-
|
|
37
|
+
const clientInstances: Record<string, SplitIO.ICsClient> = {};
|
|
38
|
+
clientInstances[defaultInstanceId] = mainClientInstance;
|
|
34
39
|
|
|
35
40
|
return function client(key?: SplitIO.SplitKey, trafficType?: string) {
|
|
36
41
|
if (key === undefined) {
|
|
@@ -53,10 +58,10 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
53
58
|
}
|
|
54
59
|
const instanceId = buildInstanceId(validKey, validTrafficType);
|
|
55
60
|
|
|
56
|
-
if (!
|
|
61
|
+
if (!clientInstances[instanceId]) {
|
|
57
62
|
const matchingKey = getMatching(validKey);
|
|
58
63
|
|
|
59
|
-
const sharedSdkReadiness = sdkReadinessManager.shared();
|
|
64
|
+
const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout);
|
|
60
65
|
const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => {
|
|
61
66
|
if (err) {
|
|
62
67
|
sharedSdkReadiness.readinessManager.timeout();
|
|
@@ -75,22 +80,25 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
75
80
|
|
|
76
81
|
// As shared clients reuse all the storage information, we don't need to check here if we
|
|
77
82
|
// will use offline or online mode. We should stick with the original decision.
|
|
78
|
-
|
|
83
|
+
clientInstances[instanceId] = clientCSDecorator(
|
|
79
84
|
log,
|
|
80
85
|
sdkClientFactory(objectAssign({}, params, {
|
|
81
86
|
sdkReadinessManager: sharedSdkReadiness,
|
|
82
87
|
storage: sharedStorage || storage,
|
|
83
88
|
syncManager: sharedSyncManager,
|
|
89
|
+
signalListener: undefined, // only the main client "destroy" method stops the signal listener
|
|
84
90
|
}), true) as SplitIO.IClient,
|
|
85
91
|
validKey,
|
|
86
92
|
validTrafficType
|
|
87
93
|
);
|
|
88
94
|
|
|
95
|
+
sharedSyncManager && sharedSyncManager.start();
|
|
96
|
+
|
|
89
97
|
log.info(NEW_SHARED_CLIENT);
|
|
90
98
|
} else {
|
|
91
99
|
log.debug(RETRIEVE_CLIENT_EXISTING);
|
|
92
100
|
}
|
|
93
101
|
|
|
94
|
-
return
|
|
102
|
+
return clientInstances[instanceId];
|
|
95
103
|
};
|
|
96
104
|
}
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { sdkReadinessManagerFactory } from '../readiness/sdkReadinessManager';
|
|
|
3
3
|
import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
|
|
4
4
|
import { eventTrackerFactory } from '../trackers/eventTracker';
|
|
5
5
|
import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
|
|
6
|
-
import {
|
|
6
|
+
import { 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';
|
|
@@ -23,22 +23,16 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
23
23
|
const { settings, platform, storageFactory, splitApiFactory, extraProps,
|
|
24
24
|
syncManagerFactory, SignalListener, impressionsObserverFactory,
|
|
25
25
|
integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory,
|
|
26
|
-
filterAdapterFactory
|
|
26
|
+
filterAdapterFactory } = params;
|
|
27
27
|
const { log, sync: { impressionsMode } } = settings;
|
|
28
28
|
|
|
29
29
|
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
|
|
30
30
|
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
const initCallbacks: (() => void)[] = [];
|
|
32
|
+
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
33
|
+
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
if (hasInit) cb();
|
|
38
|
-
else initCallbacks.push(cb);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const sdkReadinessManager = sdkReadinessManagerFactory(platform.EventEmitter, settings);
|
|
35
|
+
const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
|
|
42
36
|
const readiness = sdkReadinessManager.readinessManager;
|
|
43
37
|
|
|
44
38
|
const storage = storageFactory({
|
|
@@ -54,7 +48,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
54
48
|
},
|
|
55
49
|
});
|
|
56
50
|
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
57
|
-
|
|
51
|
+
|
|
58
52
|
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
59
53
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
|
|
60
54
|
|
|
@@ -73,13 +67,13 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
73
67
|
strategy = strategyDebugFactory(observer);
|
|
74
68
|
}
|
|
75
69
|
|
|
76
|
-
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy,
|
|
77
|
-
const eventTracker = eventTrackerFactory(settings, storage.events,
|
|
70
|
+
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, integrationsManager, storage.telemetry);
|
|
71
|
+
const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
|
|
78
72
|
|
|
79
73
|
// splitApi is used by SyncManager and Browser signal listener
|
|
80
74
|
const splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
81
75
|
|
|
82
|
-
const ctx: ISdkFactoryContext = {
|
|
76
|
+
const ctx: ISdkFactoryContext = { splitApi, eventTracker, impressionsTracker, telemetryTracker, uniqueKeysTracker, sdkReadinessManager, readiness, settings, storage, platform };
|
|
83
77
|
|
|
84
78
|
const syncManager = syncManagerFactory && syncManagerFactory(ctx as ISdkFactoryContextSync);
|
|
85
79
|
ctx.syncManager = syncManager;
|
|
@@ -91,21 +85,8 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
91
85
|
const clientMethod = sdkClientMethodFactory(ctx);
|
|
92
86
|
const managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
|
|
93
87
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (hasInit) return;
|
|
97
|
-
hasInit = true;
|
|
98
|
-
|
|
99
|
-
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
100
|
-
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
101
|
-
readiness.init();
|
|
102
|
-
uniqueKeysTracker && uniqueKeysTracker.start();
|
|
103
|
-
syncManager && syncManager.start();
|
|
104
|
-
signalListener && signalListener.start();
|
|
105
|
-
|
|
106
|
-
initCallbacks.forEach((cb) => cb());
|
|
107
|
-
initCallbacks.length = 0;
|
|
108
|
-
}
|
|
88
|
+
syncManager && syncManager.start();
|
|
89
|
+
signalListener && signalListener.start();
|
|
109
90
|
|
|
110
91
|
log.info(NEW_FACTORY);
|
|
111
92
|
|
|
@@ -124,9 +105,5 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
124
105
|
Logger: createLoggerAPI(log),
|
|
125
106
|
|
|
126
107
|
settings,
|
|
127
|
-
|
|
128
|
-
destroy() {
|
|
129
|
-
return Promise.all(Object.keys(clients).map(key => clients[key].destroy())).then(() => { });
|
|
130
|
-
}
|
|
131
|
-
}, extraProps && extraProps(ctx), lazyInit ? { init } : init());
|
|
108
|
+
}, extraProps && extraProps(ctx));
|
|
132
109
|
}
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { IStorageAsync, IStorageSync, IStorageFactoryParams } from '../storages/
|
|
|
8
8
|
import { ISyncManager } from '../sync/types';
|
|
9
9
|
import { IImpressionObserver } from '../trackers/impressionObserver/types';
|
|
10
10
|
import { IImpressionsTracker, IEventTracker, ITelemetryTracker, IFilterAdapter, IUniqueKeysTracker } from '../trackers/types';
|
|
11
|
-
import { SplitIO, ISettings, IEventEmitter
|
|
11
|
+
import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Environment related dependencies.
|
|
@@ -49,7 +49,6 @@ export interface ISdkFactoryContext {
|
|
|
49
49
|
signalListener?: ISignalListener
|
|
50
50
|
splitApi?: ISplitApi
|
|
51
51
|
syncManager?: ISyncManager,
|
|
52
|
-
clients: Record<string, IBasicClient>,
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
export interface ISdkFactoryContextSync extends ISdkFactoryContext {
|
|
@@ -68,8 +67,6 @@ export interface ISdkFactoryContextAsync extends ISdkFactoryContext {
|
|
|
68
67
|
* Object parameter with the modules required to create an SDK factory instance
|
|
69
68
|
*/
|
|
70
69
|
export interface ISdkFactoryParams {
|
|
71
|
-
// If true, the `sdkFactory` is pure (no side effects), and the SDK instance includes a `init` method to run initialization side effects
|
|
72
|
-
lazyInit?: boolean,
|
|
73
70
|
|
|
74
71
|
// The settings must be already validated
|
|
75
72
|
settings: ISettings,
|
|
@@ -31,3 +31,8 @@ export function decorateHeaders(settings: ISettings, headers: Record<string, str
|
|
|
31
31
|
}
|
|
32
32
|
return headers;
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
export function removeNonISO88591(input: string) {
|
|
36
|
+
// eslint-disable-next-line no-control-regex
|
|
37
|
+
return input.replace(/[^\x00-\xFF]/g, '');
|
|
38
|
+
}
|
package/src/services/splitApi.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
|
|
|
4
4
|
import { ISplitApi } from './types';
|
|
5
5
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
6
6
|
import { ITelemetryTracker } from '../trackers/types';
|
|
7
|
-
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT,
|
|
7
|
+
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
|
|
8
8
|
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
|
|
9
9
|
|
|
10
10
|
const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
@@ -22,7 +22,7 @@ function userKeyToQueryParam(userKey: string) {
|
|
|
22
22
|
*/
|
|
23
23
|
export function splitApiFactory(
|
|
24
24
|
settings: ISettings,
|
|
25
|
-
platform:
|
|
25
|
+
platform: IPlatform,
|
|
26
26
|
telemetryTracker: ITelemetryTracker
|
|
27
27
|
): ISplitApi {
|
|
28
28
|
|
|
@@ -67,15 +67,15 @@ export function splitApiFactory(
|
|
|
67
67
|
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
fetchMySegments(userMatchingKey: string, noCache?: boolean) {
|
|
71
71
|
/**
|
|
72
72
|
* URI encoding of user keys in order to:
|
|
73
|
-
* - avoid 400 responses (due to URI malformed). E.g.: '/api/
|
|
74
|
-
* - avoid 404 responses. E.g.: '/api/
|
|
73
|
+
* - avoid 400 responses (due to URI malformed). E.g.: '/api/mySegments/%'
|
|
74
|
+
* - avoid 404 responses. E.g.: '/api/mySegments/foo/bar'
|
|
75
75
|
* - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
|
|
76
76
|
*/
|
|
77
|
-
const url = `${urls.sdk}/
|
|
78
|
-
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(
|
|
77
|
+
const url = `${urls.sdk}/mySegments/${encodeURIComponent(userMatchingKey)}`;
|
|
78
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_SEGMENT));
|
|
79
79
|
},
|
|
80
80
|
|
|
81
81
|
/**
|
|
@@ -3,8 +3,10 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
3
3
|
import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants';
|
|
4
4
|
import { ISettings } from '../types';
|
|
5
5
|
import { IPlatform } from '../sdkFactory/types';
|
|
6
|
-
import { decorateHeaders } from './decorateHeaders';
|
|
6
|
+
import { decorateHeaders, removeNonISO88591 } from './decorateHeaders';
|
|
7
|
+
import { timeout } from '../utils/promise/timeout';
|
|
7
8
|
|
|
9
|
+
const PENDING_FETCH_ERROR_TIMEOUT = 100;
|
|
8
10
|
const messageNoFetch = 'Global fetch API is not available.';
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -13,7 +15,7 @@ const messageNoFetch = 'Global fetch API is not available.';
|
|
|
13
15
|
* @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
|
|
14
16
|
* @param platform object containing environment-specific dependencies
|
|
15
17
|
*/
|
|
16
|
-
export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }:
|
|
18
|
+
export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }: IPlatform): ISplitHttpClient {
|
|
17
19
|
|
|
18
20
|
const { log, core: { authorizationKey }, version, runtime: { ip, hostname } } = settings;
|
|
19
21
|
const options = getOptions && getOptions(settings);
|
|
@@ -30,7 +32,7 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
|
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
if (ip) commonHeaders['SplitSDKMachineIP'] = ip;
|
|
33
|
-
if (hostname) commonHeaders['SplitSDKMachineName'] = hostname;
|
|
35
|
+
if (hostname) commonHeaders['SplitSDKMachineName'] = removeNonISO88591(hostname);
|
|
34
36
|
|
|
35
37
|
return function httpClient(url: string, reqOpts: IRequestOptions = {}, latencyTracker: (error?: NetworkError) => void = () => { }, logErrorsAsInfo: boolean = false): Promise<IResponse> {
|
|
36
38
|
|
|
@@ -45,7 +47,8 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
|
|
|
45
47
|
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
|
|
46
48
|
.then(response => {
|
|
47
49
|
if (!response.ok) {
|
|
48
|
-
|
|
50
|
+
// `text()` promise might not settle in some fetch implementations and cases (e.g. no content)
|
|
51
|
+
return timeout(PENDING_FETCH_ERROR_TIMEOUT, response.text()).then(message => Promise.reject({ response, message }), () => Promise.reject({ response }));
|
|
49
52
|
}
|
|
50
53
|
latencyTracker();
|
|
51
54
|
return response;
|
package/src/services/types.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type IFetchSplitChanges = (since: number, noCache?: boolean, till?: numbe
|
|
|
39
39
|
|
|
40
40
|
export type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean, till?: number) => Promise<IResponse>
|
|
41
41
|
|
|
42
|
-
export type
|
|
42
|
+
export type IFetchMySegments = (userMatchingKey: string, noCache?: boolean) => Promise<IResponse>
|
|
43
43
|
|
|
44
44
|
export type IPostEventsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>
|
|
45
45
|
|
|
@@ -61,7 +61,7 @@ export interface ISplitApi {
|
|
|
61
61
|
fetchAuth: IFetchAuth
|
|
62
62
|
fetchSplitChanges: IFetchSplitChanges
|
|
63
63
|
fetchSegmentChanges: IFetchSegmentChanges
|
|
64
|
-
|
|
64
|
+
fetchMySegments: IFetchMySegments
|
|
65
65
|
postEventsBulk: IPostEventsBulk
|
|
66
66
|
postUniqueKeysBulkCs: IPostUniqueKeysBulkCs
|
|
67
67
|
postUniqueKeysBulkSs: IPostUniqueKeysBulkSs
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/* eslint-disable no-unused-vars */
|
|
3
|
+
import { ISegmentsCacheSync } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This class provides a skeletal implementation of the ISegmentsCacheSync interface
|
|
7
|
+
* to minimize the effort required to implement this interface.
|
|
8
|
+
*/
|
|
9
|
+
export abstract class AbstractSegmentsCacheSync implements ISegmentsCacheSync {
|
|
10
|
+
/**
|
|
11
|
+
* For server-side synchronizer: add `segmentKeys` list of keys to `name` segment.
|
|
12
|
+
* For client-side synchronizer: add `name` segment to the cache. `segmentKeys` is undefined.
|
|
13
|
+
*/
|
|
14
|
+
abstract addToSegment(name: string, segmentKeys?: string[]): boolean
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* For server-side synchronizer: remove `segmentKeys` list of keys from `name` segment.
|
|
18
|
+
* For client-side synchronizer: remove `name` segment from the cache. `segmentKeys` is undefined.
|
|
19
|
+
*/
|
|
20
|
+
abstract removeFromSegment(name: string, segmentKeys?: string[]): boolean
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* For server-side synchronizer: check if `key` is in `name` segment.
|
|
24
|
+
* For client-side synchronizer: check if `name` segment is in the cache. `key` is undefined.
|
|
25
|
+
*/
|
|
26
|
+
abstract isInSegment(name: string, key?: string): boolean
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* clear the cache.
|
|
30
|
+
*/
|
|
31
|
+
abstract clear(): void
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* For server-side synchronizer: add the given list of segments to the cache, with an empty list of keys. The segments that already exist are not modified.
|
|
35
|
+
* For client-side synchronizer: the method is not used.
|
|
36
|
+
*/
|
|
37
|
+
registerSegments(names: string[]): boolean { return false; }
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* For server-side synchronizer: get the list of segments to fetch changes.
|
|
41
|
+
* Also used for the `seC` (segment count) telemetry stat.
|
|
42
|
+
*/
|
|
43
|
+
abstract getRegisteredSegments(): string[]
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Only used for the `skC`(segment keys count) telemetry stat: 1 for client-side, and total count of keys in server-side.
|
|
47
|
+
* @TODO for client-side it should be the number of clients, but it requires a refactor of MySegments caches to simplify the code.
|
|
48
|
+
*/
|
|
49
|
+
abstract getKeysCount(): number
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* For server-side synchronizer: set the change number of `name` segment.
|
|
53
|
+
* For client-side synchronizer: the method is not used.
|
|
54
|
+
*/
|
|
55
|
+
setChangeNumber(name: string, changeNumber: number): boolean { return true; }
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* For server-side synchronizer: get the change number of `name` segment.
|
|
59
|
+
* For client-side synchronizer: the method is not used.
|
|
60
|
+
*/
|
|
61
|
+
getChangeNumber(name: string): number | undefined { return -1; }
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* For server-side synchronizer: the method is not used.
|
|
65
|
+
* For client-side synchronizer: reset the cache with the given list of segments.
|
|
66
|
+
*/
|
|
67
|
+
resetSegments(names: string[]): boolean { return true; }
|
|
68
|
+
}
|
|
@@ -2,7 +2,7 @@ import { ISplitsCacheSync } from './types';
|
|
|
2
2
|
import { ISplit } from '../dtos/types';
|
|
3
3
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
4
4
|
import { ISet } from '../utils/lang/sets';
|
|
5
|
-
import { IN_SEGMENT
|
|
5
|
+
import { IN_SEGMENT } from '../utils/constants';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* This class provides a skeletal implementation of the ISplitsCacheSync interface
|
|
@@ -32,7 +32,7 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
32
32
|
return splits;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
abstract setChangeNumber(changeNumber: number): boolean
|
|
35
|
+
abstract setChangeNumber(changeNumber: number): boolean
|
|
36
36
|
|
|
37
37
|
abstract getChangeNumber(): number
|
|
38
38
|
|
|
@@ -94,8 +94,7 @@ export function usesSegments(split: ISplit) {
|
|
|
94
94
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
95
95
|
|
|
96
96
|
for (let j = 0; j < matchers.length; j++) {
|
|
97
|
-
|
|
98
|
-
if (matcher === IN_SEGMENT || matcher === IN_LARGE_SEGMENT) return true;
|
|
97
|
+
if (matchers[j].matcherType === IN_SEGMENT) return true;
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
|