@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 CHANGED
@@ -1,7 +1,7 @@
1
- 1.8.3 (June 28, 2023)
1
+ 1.8.3 (June 29, 2023)
2
2
  - Updated some transitive dependencies for vulnerability fixes.
3
- - Bugfix - The `destroy` method has been updated to immediately flag the SDK client as destroyed, to prevent access to the storage when `getTreatment` and `track` methods are called after the SDK is destroyed.
4
- - Bugfix - Fixed an issue with SDK_READY_TIMED_OUT event, that was not being emitted immediately when a connection error occurs using pluggable storage in consumer and partial consumer modes.
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(flagAsDestroyed) {
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
- function buildInstanceId(key) {
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
- var clientInstances = {};
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 (!clientInstances[instanceId]) {
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(true);
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
- clientInstances[instanceId] = (0, clientCS_1.clientCSDecorator)(log, (0, sdkClient_1.sdkClientFactory)((0, objectAssign_1.objectAssign)({}, params, {
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 clientInstances[instanceId];
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
- function buildInstanceId(key, trafficType) {
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(true);
50
+ sharedSdkReadiness_1.readinessManager.timeout();
54
51
  return;
55
52
  }
56
53
  // Emit SDK_READY in consumer mode for shared clients
@@ -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 (a non-recoverable error), SDK_READY_TIMED_OUT event is emitted and the SDK is flagged
35
- // as destroyed to ensure that any subsequent call to `getTreatment` or `track` will not access the storage
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(flagAsDestroyed) {
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
- function buildInstanceId(key) {
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
- var clientInstances = {};
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 (!clientInstances[instanceId]) {
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(true);
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
- clientInstances[instanceId] = clientCSDecorator(log, sdkClientFactory(objectAssign({}, params, {
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 clientInstances[instanceId];
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
- function buildInstanceId(key, trafficType) {
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(true);
47
+ sharedSdkReadiness_1.readinessManager.timeout();
51
48
  return;
52
49
  }
53
50
  // Emit SDK_READY in consumer mode for shared clients
@@ -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 (a non-recoverable error), SDK_READY_TIMED_OUT event is emitted and the SDK is flagged
32
- // as destroyed to ensure that any subsequent call to `getTreatment` or `track` will not access the storage
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.8.3-rc.2",
3
+ "version": "1.8.3-rc.4",
4
4
  "description": "Split Javascript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -1,4 +1,4 @@
1
- import { IEventsCacheBase } from '../storages/types';
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: { events: IEventsCacheBase }
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(flagAsDestroyed?: boolean) {
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: any;
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
@@ -54,7 +54,7 @@ export interface IReadinessManager {
54
54
  isDestroyed(): boolean,
55
55
  isOperational(): boolean,
56
56
 
57
- timeout(flagAsDestroyed?: boolean): void,
57
+ timeout(): void,
58
58
  destroy(): void,
59
59
 
60
60
  /** for client-side */
@@ -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
- const clientInstances: Record<string, SplitIO.ICsClient> = {};
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 (!clientInstances[instanceId]) {
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(true);
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
- clientInstances[instanceId] = clientCSDecorator(
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 clientInstances[instanceId];
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(true);
65
+ sharedSdkReadiness.readinessManager.timeout();
70
66
  return;
71
67
  }
72
68
  // Emit SDK_READY in consumer mode for shared clients
@@ -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 (a non-recoverable error), SDK_READY_TIMED_OUT event is emitted and the SDK is flagged
43
- // as destroyed to ensure that any subsequent call to `getTreatment` or `track` will not access the storage
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;
@@ -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 { IEventsCacheBase } from '../storages/types';
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(flagAsDestroyed?: boolean): void;
44
+ timeout(): void;
45
45
  destroy(): void;
46
46
  /** for client-side */
47
47
  shared(readyTimeout?: number): IReadinessManager;
@@ -0,0 +1,6 @@
1
+ import { SplitIO } from '../types';
2
+ export declare function buildInstanceId(key: SplitIO.SplitKey, trafficType?: string): string;
3
+ export declare function parseInstanceId(instanceId: string): {
4
+ key: SplitIO.SplitKey;
5
+ trafficType?: string;
6
+ };
@@ -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;