@splitsoftware/splitio-commons 1.8.3-rc.2 → 1.8.3-rc.4
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 +3 -3
- package/cjs/readiness/readinessManager.js +2 -4
- package/cjs/sdkClient/identity.js +14 -0
- package/cjs/sdkClient/sdkClientMethodCS.js +9 -13
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +4 -7
- package/cjs/sdkFactory/index.js +5 -5
- package/esm/readiness/readinessManager.js +2 -4
- package/esm/sdkClient/identity.js +9 -0
- package/esm/sdkClient/sdkClientMethodCS.js +7 -11
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +2 -5
- package/esm/sdkFactory/index.js +5 -5
- package/package.json +1 -1
- package/src/integrations/types.ts +3 -2
- package/src/readiness/readinessManager.ts +4 -5
- package/src/readiness/types.ts +1 -1
- package/src/sdkClient/identity.ts +12 -0
- package/src/sdkClient/sdkClientMethodCS.ts +7 -12
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +2 -6
- package/src/sdkFactory/index.ts +5 -6
- package/src/sdkFactory/types.ts +1 -4
- package/types/integrations/types.d.ts +3 -4
- package/types/readiness/types.d.ts +1 -1
- package/types/sdkClient/identity.d.ts +6 -0
- package/types/sdkFactory/types.d.ts +1 -4
package/CHANGES.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
1.8.3 (June
|
|
1
|
+
1.8.3 (June 29, 2023)
|
|
2
2
|
- Updated some transitive dependencies for vulnerability fixes.
|
|
3
|
-
-
|
|
4
|
-
- Bugfix -
|
|
3
|
+
- Updated SDK_READY_TIMED_OUT event to be emitted immediately when a connection error occurs using pluggable storage (i.e., when the wrapper `connect` promise is rejected) in consumer and partial consumer modes.
|
|
4
|
+
- Bugfix - The `destroy` method has been updated to immediately flag the SDK client as destroyed, to prevent unexpected behaviours when `getTreatment` and `track` methods are called synchronously after `destroy` method is called.
|
|
5
5
|
|
|
6
6
|
1.8.2 (May 15, 2023)
|
|
7
7
|
- Updated terminology on the SDKs codebase to be more aligned with current standard without causing a breaking change. The core change is the term split for feature flag on things like logs and IntelliSense comments.
|
|
@@ -31,7 +31,6 @@ function readinessManagerFactory(EventEmitter, readyTimeout, splits) {
|
|
|
31
31
|
if (splits === void 0) { splits = splitsEventEmitterFactory(EventEmitter); }
|
|
32
32
|
var segments = segmentsEventEmitterFactory(EventEmitter);
|
|
33
33
|
var gate = new EventEmitter();
|
|
34
|
-
var isDestroyed = false;
|
|
35
34
|
// emit SDK_READY_FROM_CACHE
|
|
36
35
|
var isReadyFromCache = false;
|
|
37
36
|
if (splits.splitsCacheLoaded)
|
|
@@ -40,9 +39,7 @@ function readinessManagerFactory(EventEmitter, readyTimeout, splits) {
|
|
|
40
39
|
splits.once(constants_1.SDK_SPLITS_CACHE_LOADED, checkIsReadyFromCache);
|
|
41
40
|
// emit SDK_READY_TIMED_OUT
|
|
42
41
|
var hasTimedout = false;
|
|
43
|
-
function timeout(
|
|
44
|
-
if (flagAsDestroyed)
|
|
45
|
-
isDestroyed = true;
|
|
42
|
+
function timeout() {
|
|
46
43
|
if (hasTimedout)
|
|
47
44
|
return;
|
|
48
45
|
hasTimedout = true;
|
|
@@ -56,6 +53,7 @@ function readinessManagerFactory(EventEmitter, readyTimeout, splits) {
|
|
|
56
53
|
var isReady = false;
|
|
57
54
|
splits.on(constants_1.SDK_SPLITS_ARRIVED, checkIsReadyOrUpdate);
|
|
58
55
|
segments.on(constants_1.SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate);
|
|
56
|
+
var isDestroyed = false;
|
|
59
57
|
function checkIsReadyFromCache() {
|
|
60
58
|
isReadyFromCache = true;
|
|
61
59
|
// Don't emit SDK_READY_FROM_CACHE if SDK_READY has been emitted
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseInstanceId = exports.buildInstanceId = void 0;
|
|
4
|
+
function buildInstanceId(key, trafficType) {
|
|
5
|
+
return (key.matchingKey ? key.matchingKey : key) + "-" + (key.bucketingKey ? key.bucketingKey : key) + "-" + (trafficType ? trafficType : '');
|
|
6
|
+
}
|
|
7
|
+
exports.buildInstanceId = buildInstanceId;
|
|
8
|
+
function parseInstanceId(instanceId) {
|
|
9
|
+
var _a = instanceId.split('-'), matchingKey = _a[0], bucketingKey = _a[1], trafficType = _a[2];
|
|
10
|
+
return matchingKey === bucketingKey ?
|
|
11
|
+
{ key: matchingKey, trafficType: trafficType } :
|
|
12
|
+
{ key: { matchingKey: matchingKey, bucketingKey: bucketingKey }, trafficType: trafficType };
|
|
13
|
+
}
|
|
14
|
+
exports.parseInstanceId = parseInstanceId;
|
|
@@ -8,23 +8,19 @@ var sdkClient_1 = require("./sdkClient");
|
|
|
8
8
|
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
9
9
|
var constants_1 = require("../logger/constants");
|
|
10
10
|
var constants_2 = require("../readiness/constants");
|
|
11
|
-
|
|
12
|
-
// @ts-ignore
|
|
13
|
-
return (key.matchingKey ? key.matchingKey : key) + "-" + (key.bucketingKey ? key.bucketingKey : key) + "-";
|
|
14
|
-
}
|
|
11
|
+
var identity_1 = require("./identity");
|
|
15
12
|
var method = 'Client instantiation';
|
|
16
13
|
/**
|
|
17
14
|
* Factory of client method for the client-side API variant where TT is ignored and thus
|
|
18
15
|
* clients don't have a binded TT for the track method.
|
|
19
16
|
*/
|
|
20
17
|
function sdkClientMethodCSFactory(params) {
|
|
21
|
-
var storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, readyTimeout = _a.startup.readyTimeout, log = _a.log;
|
|
18
|
+
var clients = params.clients, storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, readyTimeout = _a.startup.readyTimeout, log = _a.log;
|
|
22
19
|
var mainClientInstance = (0, clientCS_1.clientCSDecorator)(log, (0, sdkClient_1.sdkClientFactory)(params), key);
|
|
23
20
|
var parsedDefaultKey = (0, key_2.keyParser)(key);
|
|
24
|
-
var defaultInstanceId = buildInstanceId(parsedDefaultKey);
|
|
21
|
+
var defaultInstanceId = (0, identity_1.buildInstanceId)(parsedDefaultKey);
|
|
25
22
|
// Cache instances created per factory.
|
|
26
|
-
|
|
27
|
-
clientInstances[defaultInstanceId] = mainClientInstance;
|
|
23
|
+
clients[defaultInstanceId] = mainClientInstance;
|
|
28
24
|
return function client(key) {
|
|
29
25
|
if (key === undefined) {
|
|
30
26
|
log.debug(constants_1.RETRIEVE_CLIENT_DEFAULT);
|
|
@@ -35,13 +31,13 @@ function sdkClientMethodCSFactory(params) {
|
|
|
35
31
|
if (validKey === false) {
|
|
36
32
|
throw new Error('Shared Client needs a valid key.');
|
|
37
33
|
}
|
|
38
|
-
var instanceId = buildInstanceId(validKey);
|
|
39
|
-
if (!
|
|
34
|
+
var instanceId = (0, identity_1.buildInstanceId)(validKey);
|
|
35
|
+
if (!clients[instanceId]) {
|
|
40
36
|
var matchingKey = (0, key_2.getMatching)(validKey);
|
|
41
37
|
var sharedSdkReadiness_1 = sdkReadinessManager.shared(readyTimeout);
|
|
42
38
|
var sharedStorage = storage.shared && storage.shared(matchingKey, function (err) {
|
|
43
39
|
if (err) {
|
|
44
|
-
sharedSdkReadiness_1.readinessManager.timeout(
|
|
40
|
+
sharedSdkReadiness_1.readinessManager.timeout();
|
|
45
41
|
return;
|
|
46
42
|
}
|
|
47
43
|
// Emit SDK_READY in consumer mode for shared clients
|
|
@@ -55,7 +51,7 @@ function sdkClientMethodCSFactory(params) {
|
|
|
55
51
|
var sharedSyncManager = syncManager && sharedStorage && syncManager.shared(matchingKey, sharedSdkReadiness_1.readinessManager, sharedStorage);
|
|
56
52
|
// As shared clients reuse all the storage information, we don't need to check here if we
|
|
57
53
|
// will use offline or online mode. We should stick with the original decision.
|
|
58
|
-
|
|
54
|
+
clients[instanceId] = (0, clientCS_1.clientCSDecorator)(log, (0, sdkClient_1.sdkClientFactory)((0, objectAssign_1.objectAssign)({}, params, {
|
|
59
55
|
sdkReadinessManager: sharedSdkReadiness_1,
|
|
60
56
|
storage: sharedStorage || storage,
|
|
61
57
|
syncManager: sharedSyncManager,
|
|
@@ -67,7 +63,7 @@ function sdkClientMethodCSFactory(params) {
|
|
|
67
63
|
else {
|
|
68
64
|
log.debug(constants_1.RETRIEVE_CLIENT_EXISTING);
|
|
69
65
|
}
|
|
70
|
-
return
|
|
66
|
+
return clients[instanceId];
|
|
71
67
|
};
|
|
72
68
|
}
|
|
73
69
|
exports.sdkClientMethodCSFactory = sdkClientMethodCSFactory;
|
|
@@ -9,10 +9,7 @@ var sdkClient_1 = require("./sdkClient");
|
|
|
9
9
|
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
10
10
|
var constants_1 = require("../logger/constants");
|
|
11
11
|
var constants_2 = require("../readiness/constants");
|
|
12
|
-
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
return (key.matchingKey ? key.matchingKey : key) + "-" + (key.bucketingKey ? key.bucketingKey : key) + "-" + (trafficType !== undefined ? trafficType : '');
|
|
15
|
-
}
|
|
12
|
+
var identity_1 = require("./identity");
|
|
16
13
|
var method = 'Client instantiation';
|
|
17
14
|
/**
|
|
18
15
|
* Factory of client method for the client-side (browser) variant of the Isomorphic JS SDK,
|
|
@@ -23,7 +20,7 @@ function sdkClientMethodCSFactory(params) {
|
|
|
23
20
|
var storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, _b = _a.core, key = _b.key, trafficType = _b.trafficType, readyTimeout = _a.startup.readyTimeout, log = _a.log;
|
|
24
21
|
var mainClientInstance = (0, clientCS_1.clientCSDecorator)(log, (0, sdkClient_1.sdkClientFactory)(params), key, trafficType);
|
|
25
22
|
var parsedDefaultKey = (0, key_2.keyParser)(key);
|
|
26
|
-
var defaultInstanceId = buildInstanceId(parsedDefaultKey, trafficType);
|
|
23
|
+
var defaultInstanceId = (0, identity_1.buildInstanceId)(parsedDefaultKey, trafficType);
|
|
27
24
|
// Cache instances created per factory.
|
|
28
25
|
var clientInstances = {};
|
|
29
26
|
clientInstances[defaultInstanceId] = mainClientInstance;
|
|
@@ -44,13 +41,13 @@ function sdkClientMethodCSFactory(params) {
|
|
|
44
41
|
throw new Error('Shared Client needs a valid traffic type or no traffic type at all.');
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
|
-
var instanceId = buildInstanceId(validKey, validTrafficType);
|
|
44
|
+
var instanceId = (0, identity_1.buildInstanceId)(validKey, validTrafficType);
|
|
48
45
|
if (!clientInstances[instanceId]) {
|
|
49
46
|
var matchingKey = (0, key_2.getMatching)(validKey);
|
|
50
47
|
var sharedSdkReadiness_1 = sdkReadinessManager.shared(readyTimeout);
|
|
51
48
|
var sharedStorage = storage.shared && storage.shared(matchingKey, function (err) {
|
|
52
49
|
if (err) {
|
|
53
|
-
sharedSdkReadiness_1.readinessManager.timeout(
|
|
50
|
+
sharedSdkReadiness_1.readinessManager.timeout();
|
|
54
51
|
return;
|
|
55
52
|
}
|
|
56
53
|
// Emit SDK_READY in consumer mode for shared clients
|
package/cjs/sdkFactory/index.js
CHANGED
|
@@ -31,9 +31,8 @@ function sdkFactory(params) {
|
|
|
31
31
|
settings: settings,
|
|
32
32
|
onReadyCb: function (error) {
|
|
33
33
|
if (error) {
|
|
34
|
-
// If storage fails to connect
|
|
35
|
-
|
|
36
|
-
readiness.timeout(true);
|
|
34
|
+
// If storage fails to connect, SDK_READY_TIMED_OUT event is emitted immediately. Review when timeout and non-recoverable errors are reworked
|
|
35
|
+
readiness.timeout();
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
39
38
|
readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
|
|
@@ -41,8 +40,9 @@ function sdkFactory(params) {
|
|
|
41
40
|
},
|
|
42
41
|
});
|
|
43
42
|
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
43
|
+
var clients = {};
|
|
44
44
|
var telemetryTracker = (0, telemetryTracker_1.telemetryTrackerFactory)(storage.telemetry, platform.now);
|
|
45
|
-
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
|
|
45
|
+
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker, clients: clients });
|
|
46
46
|
var observer = impressionsObserverFactory();
|
|
47
47
|
var uniqueKeysTracker = impressionsMode === constants_3.NONE ? (0, uniqueKeysTracker_1.uniqueKeysTrackerFactory)(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory()) : undefined;
|
|
48
48
|
var strategy;
|
|
@@ -60,7 +60,7 @@ function sdkFactory(params) {
|
|
|
60
60
|
var eventTracker = (0, eventTracker_1.eventTrackerFactory)(settings, storage.events, integrationsManager, storage.telemetry);
|
|
61
61
|
// splitApi is used by SyncManager and Browser signal listener
|
|
62
62
|
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
63
|
-
var ctx = { splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
63
|
+
var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
64
64
|
var syncManager = syncManagerFactory && syncManagerFactory(ctx);
|
|
65
65
|
ctx.syncManager = syncManager;
|
|
66
66
|
var signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
|
@@ -28,7 +28,6 @@ export function readinessManagerFactory(EventEmitter, readyTimeout, splits) {
|
|
|
28
28
|
if (splits === void 0) { splits = splitsEventEmitterFactory(EventEmitter); }
|
|
29
29
|
var segments = segmentsEventEmitterFactory(EventEmitter);
|
|
30
30
|
var gate = new EventEmitter();
|
|
31
|
-
var isDestroyed = false;
|
|
32
31
|
// emit SDK_READY_FROM_CACHE
|
|
33
32
|
var isReadyFromCache = false;
|
|
34
33
|
if (splits.splitsCacheLoaded)
|
|
@@ -37,9 +36,7 @@ export function readinessManagerFactory(EventEmitter, readyTimeout, splits) {
|
|
|
37
36
|
splits.once(SDK_SPLITS_CACHE_LOADED, checkIsReadyFromCache);
|
|
38
37
|
// emit SDK_READY_TIMED_OUT
|
|
39
38
|
var hasTimedout = false;
|
|
40
|
-
function timeout(
|
|
41
|
-
if (flagAsDestroyed)
|
|
42
|
-
isDestroyed = true;
|
|
39
|
+
function timeout() {
|
|
43
40
|
if (hasTimedout)
|
|
44
41
|
return;
|
|
45
42
|
hasTimedout = true;
|
|
@@ -53,6 +50,7 @@ export function readinessManagerFactory(EventEmitter, readyTimeout, splits) {
|
|
|
53
50
|
var isReady = false;
|
|
54
51
|
splits.on(SDK_SPLITS_ARRIVED, checkIsReadyOrUpdate);
|
|
55
52
|
segments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate);
|
|
53
|
+
var isDestroyed = false;
|
|
56
54
|
function checkIsReadyFromCache() {
|
|
57
55
|
isReadyFromCache = true;
|
|
58
56
|
// Don't emit SDK_READY_FROM_CACHE if SDK_READY has been emitted
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function buildInstanceId(key, trafficType) {
|
|
2
|
+
return (key.matchingKey ? key.matchingKey : key) + "-" + (key.bucketingKey ? key.bucketingKey : key) + "-" + (trafficType ? trafficType : '');
|
|
3
|
+
}
|
|
4
|
+
export function parseInstanceId(instanceId) {
|
|
5
|
+
var _a = instanceId.split('-'), matchingKey = _a[0], bucketingKey = _a[1], trafficType = _a[2];
|
|
6
|
+
return matchingKey === bucketingKey ?
|
|
7
|
+
{ key: matchingKey, trafficType: trafficType } :
|
|
8
|
+
{ key: { matchingKey: matchingKey, bucketingKey: bucketingKey }, trafficType: trafficType };
|
|
9
|
+
}
|
|
@@ -5,23 +5,19 @@ import { sdkClientFactory } from './sdkClient';
|
|
|
5
5
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
6
6
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING } from '../logger/constants';
|
|
7
7
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
8
|
-
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
return (key.matchingKey ? key.matchingKey : key) + "-" + (key.bucketingKey ? key.bucketingKey : key) + "-";
|
|
11
|
-
}
|
|
8
|
+
import { buildInstanceId } from './identity';
|
|
12
9
|
var method = 'Client instantiation';
|
|
13
10
|
/**
|
|
14
11
|
* Factory of client method for the client-side API variant where TT is ignored and thus
|
|
15
12
|
* clients don't have a binded TT for the track method.
|
|
16
13
|
*/
|
|
17
14
|
export function sdkClientMethodCSFactory(params) {
|
|
18
|
-
var storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, readyTimeout = _a.startup.readyTimeout, log = _a.log;
|
|
15
|
+
var clients = params.clients, storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, readyTimeout = _a.startup.readyTimeout, log = _a.log;
|
|
19
16
|
var mainClientInstance = clientCSDecorator(log, sdkClientFactory(params), key);
|
|
20
17
|
var parsedDefaultKey = keyParser(key);
|
|
21
18
|
var defaultInstanceId = buildInstanceId(parsedDefaultKey);
|
|
22
19
|
// Cache instances created per factory.
|
|
23
|
-
|
|
24
|
-
clientInstances[defaultInstanceId] = mainClientInstance;
|
|
20
|
+
clients[defaultInstanceId] = mainClientInstance;
|
|
25
21
|
return function client(key) {
|
|
26
22
|
if (key === undefined) {
|
|
27
23
|
log.debug(RETRIEVE_CLIENT_DEFAULT);
|
|
@@ -33,12 +29,12 @@ export function sdkClientMethodCSFactory(params) {
|
|
|
33
29
|
throw new Error('Shared Client needs a valid key.');
|
|
34
30
|
}
|
|
35
31
|
var instanceId = buildInstanceId(validKey);
|
|
36
|
-
if (!
|
|
32
|
+
if (!clients[instanceId]) {
|
|
37
33
|
var matchingKey = getMatching(validKey);
|
|
38
34
|
var sharedSdkReadiness_1 = sdkReadinessManager.shared(readyTimeout);
|
|
39
35
|
var sharedStorage = storage.shared && storage.shared(matchingKey, function (err) {
|
|
40
36
|
if (err) {
|
|
41
|
-
sharedSdkReadiness_1.readinessManager.timeout(
|
|
37
|
+
sharedSdkReadiness_1.readinessManager.timeout();
|
|
42
38
|
return;
|
|
43
39
|
}
|
|
44
40
|
// Emit SDK_READY in consumer mode for shared clients
|
|
@@ -52,7 +48,7 @@ export function sdkClientMethodCSFactory(params) {
|
|
|
52
48
|
var sharedSyncManager = syncManager && sharedStorage && syncManager.shared(matchingKey, sharedSdkReadiness_1.readinessManager, sharedStorage);
|
|
53
49
|
// As shared clients reuse all the storage information, we don't need to check here if we
|
|
54
50
|
// will use offline or online mode. We should stick with the original decision.
|
|
55
|
-
|
|
51
|
+
clients[instanceId] = clientCSDecorator(log, sdkClientFactory(objectAssign({}, params, {
|
|
56
52
|
sdkReadinessManager: sharedSdkReadiness_1,
|
|
57
53
|
storage: sharedStorage || storage,
|
|
58
54
|
syncManager: sharedSyncManager,
|
|
@@ -64,6 +60,6 @@ export function sdkClientMethodCSFactory(params) {
|
|
|
64
60
|
else {
|
|
65
61
|
log.debug(RETRIEVE_CLIENT_EXISTING);
|
|
66
62
|
}
|
|
67
|
-
return
|
|
63
|
+
return clients[instanceId];
|
|
68
64
|
};
|
|
69
65
|
}
|
|
@@ -6,10 +6,7 @@ import { sdkClientFactory } from './sdkClient';
|
|
|
6
6
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
7
7
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING } from '../logger/constants';
|
|
8
8
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
9
|
-
|
|
10
|
-
// @ts-ignore
|
|
11
|
-
return (key.matchingKey ? key.matchingKey : key) + "-" + (key.bucketingKey ? key.bucketingKey : key) + "-" + (trafficType !== undefined ? trafficType : '');
|
|
12
|
-
}
|
|
9
|
+
import { buildInstanceId } from './identity';
|
|
13
10
|
var method = 'Client instantiation';
|
|
14
11
|
/**
|
|
15
12
|
* Factory of client method for the client-side (browser) variant of the Isomorphic JS SDK,
|
|
@@ -47,7 +44,7 @@ export function sdkClientMethodCSFactory(params) {
|
|
|
47
44
|
var sharedSdkReadiness_1 = sdkReadinessManager.shared(readyTimeout);
|
|
48
45
|
var sharedStorage = storage.shared && storage.shared(matchingKey, function (err) {
|
|
49
46
|
if (err) {
|
|
50
|
-
sharedSdkReadiness_1.readinessManager.timeout(
|
|
47
|
+
sharedSdkReadiness_1.readinessManager.timeout();
|
|
51
48
|
return;
|
|
52
49
|
}
|
|
53
50
|
// Emit SDK_READY in consumer mode for shared clients
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -28,9 +28,8 @@ export function sdkFactory(params) {
|
|
|
28
28
|
settings: settings,
|
|
29
29
|
onReadyCb: function (error) {
|
|
30
30
|
if (error) {
|
|
31
|
-
// If storage fails to connect
|
|
32
|
-
|
|
33
|
-
readiness.timeout(true);
|
|
31
|
+
// If storage fails to connect, SDK_READY_TIMED_OUT event is emitted immediately. Review when timeout and non-recoverable errors are reworked
|
|
32
|
+
readiness.timeout();
|
|
34
33
|
return;
|
|
35
34
|
}
|
|
36
35
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
@@ -38,8 +37,9 @@ export function sdkFactory(params) {
|
|
|
38
37
|
},
|
|
39
38
|
});
|
|
40
39
|
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
40
|
+
var clients = {};
|
|
41
41
|
var telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
42
|
-
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
|
|
42
|
+
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker, clients: clients });
|
|
43
43
|
var observer = impressionsObserverFactory();
|
|
44
44
|
var uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory()) : undefined;
|
|
45
45
|
var strategy;
|
|
@@ -57,7 +57,7 @@ export function sdkFactory(params) {
|
|
|
57
57
|
var eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
|
|
58
58
|
// splitApi is used by SyncManager and Browser signal listener
|
|
59
59
|
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
60
|
-
var ctx = { splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
60
|
+
var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
61
61
|
var syncManager = syncManagerFactory && syncManagerFactory(ctx);
|
|
62
62
|
ctx.syncManager = syncManager;
|
|
63
63
|
var signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IStorageSync, IStorageAsync } from '../storages/types';
|
|
2
2
|
import { IEventsHandler, IImpressionsHandler, ITelemetryTracker } from '../trackers/types';
|
|
3
3
|
import { ISettings, SplitIO } from '../types';
|
|
4
4
|
|
|
@@ -9,9 +9,10 @@ export interface IIntegration {
|
|
|
9
9
|
export type IIntegrationManager = IEventsHandler & IImpressionsHandler;
|
|
10
10
|
|
|
11
11
|
export interface IIntegrationFactoryParams {
|
|
12
|
-
storage:
|
|
12
|
+
storage: IStorageSync | IStorageAsync,
|
|
13
13
|
settings: ISettings
|
|
14
14
|
telemetryTracker: ITelemetryTracker
|
|
15
|
+
clients: Record<string, SplitIO.ICsClient>,
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export type IntegrationFactory = {
|
|
@@ -39,8 +39,6 @@ export function readinessManagerFactory(
|
|
|
39
39
|
const segments: ISegmentsEventEmitter = segmentsEventEmitterFactory(EventEmitter);
|
|
40
40
|
const gate: IReadinessEventEmitter = new EventEmitter();
|
|
41
41
|
|
|
42
|
-
let isDestroyed = false;
|
|
43
|
-
|
|
44
42
|
// emit SDK_READY_FROM_CACHE
|
|
45
43
|
let isReadyFromCache = false;
|
|
46
44
|
if (splits.splitsCacheLoaded) isReadyFromCache = true; // ready from cache, but doesn't emit SDK_READY_FROM_CACHE
|
|
@@ -49,14 +47,13 @@ export function readinessManagerFactory(
|
|
|
49
47
|
// emit SDK_READY_TIMED_OUT
|
|
50
48
|
let hasTimedout = false;
|
|
51
49
|
|
|
52
|
-
function timeout(
|
|
53
|
-
if (flagAsDestroyed) isDestroyed = true;
|
|
50
|
+
function timeout() {
|
|
54
51
|
if (hasTimedout) return;
|
|
55
52
|
hasTimedout = true;
|
|
56
53
|
gate.emit(SDK_READY_TIMED_OUT, 'Split SDK emitted SDK_READY_TIMED_OUT event.');
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
let readyTimeoutId:
|
|
56
|
+
let readyTimeoutId: ReturnType<typeof setTimeout>;
|
|
60
57
|
if (readyTimeout > 0) {
|
|
61
58
|
readyTimeoutId = setTimeout(timeout, readyTimeout);
|
|
62
59
|
}
|
|
@@ -66,6 +63,8 @@ export function readinessManagerFactory(
|
|
|
66
63
|
splits.on(SDK_SPLITS_ARRIVED, checkIsReadyOrUpdate);
|
|
67
64
|
segments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate);
|
|
68
65
|
|
|
66
|
+
let isDestroyed = false;
|
|
67
|
+
|
|
69
68
|
function checkIsReadyFromCache() {
|
|
70
69
|
isReadyFromCache = true;
|
|
71
70
|
// Don't emit SDK_READY_FROM_CACHE if SDK_READY has been emitted
|
package/src/readiness/types.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SplitIO } from '../types';
|
|
2
|
+
|
|
3
|
+
export function buildInstanceId(key: SplitIO.SplitKey, trafficType?: string) { // @ts-ignore
|
|
4
|
+
return `${key.matchingKey ? key.matchingKey : key}-${key.bucketingKey ? key.bucketingKey : key}-${trafficType ? trafficType : ''}`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function parseInstanceId(instanceId: string): { key: SplitIO.SplitKey, trafficType?: string } {
|
|
8
|
+
const [matchingKey, bucketingKey, trafficType] = instanceId.split('-');
|
|
9
|
+
return matchingKey === bucketingKey ?
|
|
10
|
+
{ key: matchingKey, trafficType } :
|
|
11
|
+
{ key: { matchingKey, bucketingKey }, trafficType };
|
|
12
|
+
}
|
|
@@ -8,11 +8,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
8
8
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING } from '../logger/constants';
|
|
9
9
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
10
10
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
11
|
-
|
|
12
|
-
function buildInstanceId(key: SplitIO.SplitKey) {
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
return `${key.matchingKey ? key.matchingKey : key}-${key.bucketingKey ? key.bucketingKey : key}-`;
|
|
15
|
-
}
|
|
11
|
+
import { buildInstanceId } from './identity';
|
|
16
12
|
|
|
17
13
|
const method = 'Client instantiation';
|
|
18
14
|
|
|
@@ -21,7 +17,7 @@ const method = 'Client instantiation';
|
|
|
21
17
|
* clients don't have a binded TT for the track method.
|
|
22
18
|
*/
|
|
23
19
|
export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey) => SplitIO.ICsClient {
|
|
24
|
-
const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params;
|
|
20
|
+
const { clients, storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params;
|
|
25
21
|
|
|
26
22
|
const mainClientInstance = clientCSDecorator(
|
|
27
23
|
log,
|
|
@@ -33,8 +29,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
33
29
|
const defaultInstanceId = buildInstanceId(parsedDefaultKey);
|
|
34
30
|
|
|
35
31
|
// Cache instances created per factory.
|
|
36
|
-
|
|
37
|
-
clientInstances[defaultInstanceId] = mainClientInstance;
|
|
32
|
+
clients[defaultInstanceId] = mainClientInstance;
|
|
38
33
|
|
|
39
34
|
return function client(key?: SplitIO.SplitKey) {
|
|
40
35
|
if (key === undefined) {
|
|
@@ -50,13 +45,13 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
50
45
|
|
|
51
46
|
const instanceId = buildInstanceId(validKey);
|
|
52
47
|
|
|
53
|
-
if (!
|
|
48
|
+
if (!clients[instanceId]) {
|
|
54
49
|
const matchingKey = getMatching(validKey);
|
|
55
50
|
|
|
56
51
|
const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout);
|
|
57
52
|
const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => {
|
|
58
53
|
if (err) {
|
|
59
|
-
sharedSdkReadiness.readinessManager.timeout(
|
|
54
|
+
sharedSdkReadiness.readinessManager.timeout();
|
|
60
55
|
return;
|
|
61
56
|
}
|
|
62
57
|
// Emit SDK_READY in consumer mode for shared clients
|
|
@@ -72,7 +67,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
72
67
|
|
|
73
68
|
// As shared clients reuse all the storage information, we don't need to check here if we
|
|
74
69
|
// will use offline or online mode. We should stick with the original decision.
|
|
75
|
-
|
|
70
|
+
clients[instanceId] = clientCSDecorator(
|
|
76
71
|
log,
|
|
77
72
|
sdkClientFactory(objectAssign({}, params, {
|
|
78
73
|
sdkReadinessManager: sharedSdkReadiness,
|
|
@@ -90,6 +85,6 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
90
85
|
log.debug(RETRIEVE_CLIENT_EXISTING);
|
|
91
86
|
}
|
|
92
87
|
|
|
93
|
-
return
|
|
88
|
+
return clients[instanceId];
|
|
94
89
|
};
|
|
95
90
|
}
|
|
@@ -9,11 +9,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
9
9
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING } from '../logger/constants';
|
|
10
10
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
11
11
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
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
|
-
}
|
|
12
|
+
import { buildInstanceId } from './identity';
|
|
17
13
|
|
|
18
14
|
const method = 'Client instantiation';
|
|
19
15
|
|
|
@@ -66,7 +62,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl
|
|
|
66
62
|
const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout);
|
|
67
63
|
const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => {
|
|
68
64
|
if (err) {
|
|
69
|
-
sharedSdkReadiness.readinessManager.timeout(
|
|
65
|
+
sharedSdkReadiness.readinessManager.timeout();
|
|
70
66
|
return;
|
|
71
67
|
}
|
|
72
68
|
// Emit SDK_READY in consumer mode for shared clients
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -39,9 +39,8 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
39
39
|
settings,
|
|
40
40
|
onReadyCb: (error) => {
|
|
41
41
|
if (error) {
|
|
42
|
-
// If storage fails to connect
|
|
43
|
-
|
|
44
|
-
readiness.timeout(true);
|
|
42
|
+
// If storage fails to connect, SDK_READY_TIMED_OUT event is emitted immediately. Review when timeout and non-recoverable errors are reworked
|
|
43
|
+
readiness.timeout();
|
|
45
44
|
return;
|
|
46
45
|
}
|
|
47
46
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
@@ -49,9 +48,9 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
49
48
|
},
|
|
50
49
|
});
|
|
51
50
|
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
52
|
-
|
|
51
|
+
const clients: Record<string, SplitIO.ICsClient> = {};
|
|
53
52
|
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
54
|
-
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
|
|
53
|
+
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker, clients });
|
|
55
54
|
|
|
56
55
|
const observer = impressionsObserverFactory();
|
|
57
56
|
const uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys!, filterAdapterFactory && filterAdapterFactory()) : undefined;
|
|
@@ -74,7 +73,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
74
73
|
// splitApi is used by SyncManager and Browser signal listener
|
|
75
74
|
const splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
76
75
|
|
|
77
|
-
const ctx: ISdkFactoryContext = { splitApi, eventTracker, impressionsTracker, telemetryTracker, uniqueKeysTracker, sdkReadinessManager, readiness, settings, storage, platform };
|
|
76
|
+
const ctx: ISdkFactoryContext = { clients, splitApi, eventTracker, impressionsTracker, telemetryTracker, uniqueKeysTracker, sdkReadinessManager, readiness, settings, storage, platform };
|
|
78
77
|
|
|
79
78
|
const syncManager = syncManagerFactory && syncManagerFactory(ctx as ISdkFactoryContextSync);
|
|
80
79
|
ctx.syncManager = syncManager;
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -35,15 +35,12 @@ export interface IPlatform {
|
|
|
35
35
|
now?: () => number
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export interface ISdkFactoryContext {
|
|
38
|
+
export interface ISdkFactoryContext extends IIntegrationFactoryParams {
|
|
39
39
|
platform: IPlatform,
|
|
40
40
|
sdkReadinessManager: ISdkReadinessManager,
|
|
41
41
|
readiness: IReadinessManager,
|
|
42
|
-
settings: ISettings
|
|
43
42
|
impressionsTracker: IImpressionsTracker,
|
|
44
43
|
eventTracker: IEventTracker,
|
|
45
|
-
telemetryTracker: ITelemetryTracker,
|
|
46
|
-
storage: IStorageSync | IStorageAsync,
|
|
47
44
|
uniqueKeysTracker?: IUniqueKeysTracker,
|
|
48
45
|
signalListener?: ISignalListener
|
|
49
46
|
splitApi?: ISplitApi
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IStorageSync, IStorageAsync } from '../storages/types';
|
|
2
2
|
import { IEventsHandler, IImpressionsHandler, ITelemetryTracker } from '../trackers/types';
|
|
3
3
|
import { ISettings, SplitIO } from '../types';
|
|
4
4
|
export interface IIntegration {
|
|
@@ -6,11 +6,10 @@ export interface IIntegration {
|
|
|
6
6
|
}
|
|
7
7
|
export declare type IIntegrationManager = IEventsHandler & IImpressionsHandler;
|
|
8
8
|
export interface IIntegrationFactoryParams {
|
|
9
|
-
storage:
|
|
10
|
-
events: IEventsCacheBase;
|
|
11
|
-
};
|
|
9
|
+
storage: IStorageSync | IStorageAsync;
|
|
12
10
|
settings: ISettings;
|
|
13
11
|
telemetryTracker: ITelemetryTracker;
|
|
12
|
+
clients: Record<string, SplitIO.ICsClient>;
|
|
14
13
|
}
|
|
15
14
|
export declare type IntegrationFactory = {
|
|
16
15
|
readonly type: string;
|
|
@@ -41,7 +41,7 @@ export interface IReadinessManager {
|
|
|
41
41
|
hasTimedout(): boolean;
|
|
42
42
|
isDestroyed(): boolean;
|
|
43
43
|
isOperational(): boolean;
|
|
44
|
-
timeout(
|
|
44
|
+
timeout(): void;
|
|
45
45
|
destroy(): void;
|
|
46
46
|
/** for client-side */
|
|
47
47
|
shared(readyTimeout?: number): IReadinessManager;
|
|
@@ -33,15 +33,12 @@ export interface IPlatform {
|
|
|
33
33
|
*/
|
|
34
34
|
now?: () => number;
|
|
35
35
|
}
|
|
36
|
-
export interface ISdkFactoryContext {
|
|
36
|
+
export interface ISdkFactoryContext extends IIntegrationFactoryParams {
|
|
37
37
|
platform: IPlatform;
|
|
38
38
|
sdkReadinessManager: ISdkReadinessManager;
|
|
39
39
|
readiness: IReadinessManager;
|
|
40
|
-
settings: ISettings;
|
|
41
40
|
impressionsTracker: IImpressionsTracker;
|
|
42
41
|
eventTracker: IEventTracker;
|
|
43
|
-
telemetryTracker: ITelemetryTracker;
|
|
44
|
-
storage: IStorageSync | IStorageAsync;
|
|
45
42
|
uniqueKeysTracker?: IUniqueKeysTracker;
|
|
46
43
|
signalListener?: ISignalListener;
|
|
47
44
|
splitApi?: ISplitApi;
|