@splitsoftware/splitio-commons 1.1.0 → 1.1.1-rc.0

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.
Files changed (75) hide show
  1. package/CHANGES.txt +3 -0
  2. package/cjs/sdkClient/clientAttributesDecoration.js +108 -0
  3. package/cjs/sdkClient/clientCS.js +9 -7
  4. package/cjs/sdkClient/sdkClientMethodCS.js +2 -2
  5. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +2 -2
  6. package/cjs/storages/inMemory/AttributesCacheInMemory.js +70 -0
  7. package/cjs/utils/inputValidation/attribute.js +20 -0
  8. package/cjs/utils/inputValidation/attributes.js +13 -1
  9. package/esm/sdkClient/clientAttributesDecoration.js +104 -0
  10. package/esm/sdkClient/clientCS.js +9 -7
  11. package/esm/sdkClient/sdkClientMethodCS.js +2 -2
  12. package/esm/sdkClient/sdkClientMethodCSWithTT.js +2 -2
  13. package/esm/storages/inMemory/AttributesCacheInMemory.js +67 -0
  14. package/esm/utils/inputValidation/attribute.js +16 -0
  15. package/esm/utils/inputValidation/attributes.js +11 -0
  16. package/package.json +1 -1
  17. package/src/sdkClient/clientAttributesDecoration.ts +122 -0
  18. package/src/sdkClient/clientCS.ts +12 -7
  19. package/src/sdkClient/sdkClientMethodCS.ts +2 -0
  20. package/src/sdkClient/sdkClientMethodCSWithTT.ts +2 -0
  21. package/src/storages/inMemory/AttributesCacheInMemory.ts +73 -0
  22. package/src/types.ts +39 -0
  23. package/src/utils/inputValidation/attribute.ts +21 -0
  24. package/src/utils/inputValidation/attributes.ts +14 -0
  25. package/types/logger/browser/{debugLogger.d.ts → DebugLogger.d.ts} +0 -0
  26. package/types/logger/browser/{errorLogger.d.ts → ErrorLogger.d.ts} +0 -0
  27. package/types/logger/browser/{infoLogger.d.ts → InfoLogger.d.ts} +0 -0
  28. package/types/logger/browser/{warnLogger.d.ts → WarnLogger.d.ts} +0 -0
  29. package/types/sdkClient/clientAttributesDecoration.d.ts +51 -0
  30. package/types/sdkClient/clientCS.d.ts +2 -1
  31. package/types/storages/inMemory/AttributesCacheInMemory.d.ts +43 -0
  32. package/types/types.d.ts +39 -0
  33. package/types/utils/inputValidation/attribute.d.ts +2 -0
  34. package/types/utils/inputValidation/attributes.d.ts +1 -0
  35. package/src/logger/.DS_Store +0 -0
  36. package/types/integrations/ga/GaToSplitPlugin.d.ts +0 -3
  37. package/types/integrations/ga/SplitToGaPlugin.d.ts +0 -4
  38. package/types/logger/codes.d.ts +0 -2
  39. package/types/logger/codesConstants.d.ts +0 -117
  40. package/types/logger/codesConstantsBrowser.d.ts +0 -2
  41. package/types/logger/codesConstantsNode.d.ts +0 -14
  42. package/types/logger/codesDebug.d.ts +0 -1
  43. package/types/logger/codesDebugBrowser.d.ts +0 -1
  44. package/types/logger/codesDebugNode.d.ts +0 -1
  45. package/types/logger/codesError.d.ts +0 -1
  46. package/types/logger/codesErrorNode.d.ts +0 -1
  47. package/types/logger/codesInfo.d.ts +0 -1
  48. package/types/logger/codesWarn.d.ts +0 -1
  49. package/types/logger/codesWarnNode.d.ts +0 -1
  50. package/types/logger/debugLogger.d.ts +0 -2
  51. package/types/logger/errorLogger.d.ts +0 -2
  52. package/types/logger/infoLogger.d.ts +0 -2
  53. package/types/logger/messages/debugBrowser.d.ts +0 -1
  54. package/types/logger/messages/debugNode.d.ts +0 -1
  55. package/types/logger/messages/errorNode.d.ts +0 -1
  56. package/types/logger/messages/warnNode.d.ts +0 -1
  57. package/types/logger/noopLogger.d.ts +0 -2
  58. package/types/logger/warnLogger.d.ts +0 -2
  59. package/types/sdkManager/sdkManagerMethod.d.ts +0 -6
  60. package/types/storages/getRegisteredSegments.d.ts +0 -10
  61. package/types/sync/polling/syncTasks/splitsSyncTask.copy.d.ts +0 -35
  62. package/types/sync/polling/syncTasks/splitsSyncTask.morelikeoriginal.d.ts +0 -35
  63. package/types/sync/streaming/AuthClient/indexV1.d.ts +0 -12
  64. package/types/sync/streaming/AuthClient/indexV2.d.ts +0 -8
  65. package/types/sync/streaming/pushManagerCS.d.ts +0 -12
  66. package/types/sync/streaming/pushManagerNoUsers.d.ts +0 -13
  67. package/types/sync/streaming/pushManagerSS.d.ts +0 -11
  68. package/types/sync/syncManagerFromFile.d.ts +0 -2
  69. package/types/sync/syncManagerFromObject.d.ts +0 -2
  70. package/types/sync/syncManagerOffline.d.ts +0 -9
  71. package/types/utils/lang/errors.d.ts +0 -10
  72. package/types/utils/murmur3/commons.d.ts +0 -12
  73. package/types/utils/settingsValidation/buildMetadata.d.ts +0 -3
  74. package/types/utils/settingsValidation/localhost/index.d.ts +0 -9
  75. package/types/utils/settingsValidation/logger.d.ts +0 -11
package/CHANGES.txt CHANGED
@@ -1,3 +1,6 @@
1
+ 1.1.1 (XXX)
2
+ - Added support to SDK clients on browser to optionally bind attributes to the client, keeping these loaded within the SDK along with the user ID, for easier usage when requesting flag.
3
+
1
4
  1.1.0 (January 11, 2022)
2
5
  - Added support for the SDK to run in "consumer" and "partial consumer" modes, with a pluggable implementation of it's internal storage, enabling
3
6
  customers to implement this caching with any storage technology of choice and connect it to the SDK instance to be used instead of its default in-memory storage.
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientAttributesDecoration = void 0;
4
+ var AttributesCacheInMemory_1 = require("../storages/inMemory/AttributesCacheInMemory");
5
+ var attributes_1 = require("../utils/inputValidation/attributes");
6
+ var objectAssign_1 = require("../utils/lang/objectAssign");
7
+ /**
8
+ * Add in memory attributes storage methods and combine them with any attribute received from the getTreatment/s call
9
+ */
10
+ function clientAttributesDecoration(log, client) {
11
+ var attributeStorage = new AttributesCacheInMemory_1.AttributesCacheInMemory();
12
+ // Keep a reference to the original methods
13
+ var clientGetTreatment = client.getTreatment;
14
+ var clientGetTreatmentWithConfig = client.getTreatmentWithConfig;
15
+ var clientGetTreatments = client.getTreatments;
16
+ var clientGetTreatmentsWithConfig = client.getTreatmentsWithConfig;
17
+ var clientTrack = client.track;
18
+ function getTreatment(maybeKey, maybeSplit, maybeAttributes) {
19
+ return clientGetTreatment(maybeKey, maybeSplit, combineAttributes(maybeAttributes));
20
+ }
21
+ function getTreatmentWithConfig(maybeKey, maybeSplit, maybeAttributes) {
22
+ return clientGetTreatmentWithConfig(maybeKey, maybeSplit, combineAttributes(maybeAttributes));
23
+ }
24
+ function getTreatments(maybeKey, maybeSplits, maybeAttributes) {
25
+ return clientGetTreatments(maybeKey, maybeSplits, combineAttributes(maybeAttributes));
26
+ }
27
+ function getTreatmentsWithConfig(maybeKey, maybeSplits, maybeAttributes) {
28
+ return clientGetTreatmentsWithConfig(maybeKey, maybeSplits, combineAttributes(maybeAttributes));
29
+ }
30
+ function track(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties) {
31
+ return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
32
+ }
33
+ function combineAttributes(maybeAttributes) {
34
+ var storedAttributes = attributeStorage.getAll();
35
+ if (Object.keys(storedAttributes).length > 0) {
36
+ return objectAssign_1.objectAssign({}, storedAttributes, maybeAttributes);
37
+ }
38
+ return maybeAttributes;
39
+ }
40
+ return objectAssign_1.objectAssign(client, {
41
+ getTreatment: getTreatment,
42
+ getTreatmentWithConfig: getTreatmentWithConfig,
43
+ getTreatments: getTreatments,
44
+ getTreatmentsWithConfig: getTreatmentsWithConfig,
45
+ track: track,
46
+ /**
47
+ * Add an attribute to client's in memory attributes storage
48
+ *
49
+ * @param {string} attributeName Attrinute name
50
+ * @param {string, number, boolean, list} attributeValue Attribute value
51
+ * @returns {boolean} true if the attribute was stored and false otherways
52
+ */
53
+ setAttribute: function (attributeName, attributeValue) {
54
+ var attribute = {};
55
+ attribute[attributeName] = attributeValue;
56
+ if (!attributes_1.validateAttributesDeep(log, attribute, 'setAttribute'))
57
+ return false;
58
+ log.debug("stored " + attributeValue + " for attribute " + attributeName);
59
+ return attributeStorage.setAttribute(attributeName, attributeValue);
60
+ },
61
+ /**
62
+ * Returns the attribute with the given key
63
+ *
64
+ * @param {string} attributeName Attribute name
65
+ * @returns {Object} Attribute with the given key
66
+ */
67
+ getAttribute: function (attributeName) {
68
+ log.debug("retrieved attribute " + attributeName);
69
+ return attributeStorage.getAttribute(attributeName + '');
70
+ },
71
+ /**
72
+ * Add to client's in memory attributes storage the attributes in 'attributes'
73
+ *
74
+ * @param {Object} attributes Object with attributes to store
75
+ * @returns true if attributes were stored an false otherways
76
+ */
77
+ setAttributes: function (attributes) {
78
+ if (!attributes_1.validateAttributesDeep(log, attributes, 'setAttributes'))
79
+ return false;
80
+ return attributeStorage.setAttributes(attributes);
81
+ },
82
+ /**
83
+ * Return all the attributes stored in client's in memory attributes storage
84
+ *
85
+ * @returns {Object} returns all the stored attributes
86
+ */
87
+ getAttributes: function () {
88
+ return attributeStorage.getAll();
89
+ },
90
+ /**
91
+ * Removes from client's in memory attributes storage the attribute with the given key
92
+ *
93
+ * @param {string} attributeName
94
+ * @returns {boolean} true if attribute was removed and false otherways
95
+ */
96
+ removeAttribute: function (attributeName) {
97
+ log.debug("removed attribute " + attributeName);
98
+ return attributeStorage.removeAttribute(attributeName + '');
99
+ },
100
+ /**
101
+ * Remove all the stored attributes in the client's in memory attribute storage
102
+ */
103
+ clearAttributes: function () {
104
+ return attributeStorage.clear();
105
+ }
106
+ });
107
+ }
108
+ exports.clientAttributesDecoration = clientAttributesDecoration;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.clientCSDecorator = void 0;
4
4
  var objectAssign_1 = require("../utils/lang/objectAssign");
5
+ var clientAttributesDecoration_1 = require("./clientAttributesDecoration");
5
6
  /**
6
7
  * Decorator that binds a key and (optionally) a traffic type to client methods
7
8
  *
@@ -9,15 +10,16 @@ var objectAssign_1 = require("../utils/lang/objectAssign");
9
10
  * @param key validated split key
10
11
  * @param trafficType validated traffic type
11
12
  */
12
- function clientCSDecorator(client, key, trafficType) {
13
- return objectAssign_1.objectAssign(client, {
13
+ function clientCSDecorator(log, client, key, trafficType) {
14
+ var clientCS = clientAttributesDecoration_1.clientAttributesDecoration(log, client);
15
+ return objectAssign_1.objectAssign(clientCS, {
14
16
  // In the client-side API, we bind a key to the client `getTreatment*` methods
15
- getTreatment: client.getTreatment.bind(client, key),
16
- getTreatmentWithConfig: client.getTreatmentWithConfig.bind(client, key),
17
- getTreatments: client.getTreatments.bind(client, key),
18
- getTreatmentsWithConfig: client.getTreatmentsWithConfig.bind(client, key),
17
+ getTreatment: clientCS.getTreatment.bind(clientCS, key),
18
+ getTreatmentWithConfig: clientCS.getTreatmentWithConfig.bind(clientCS, key),
19
+ getTreatments: clientCS.getTreatments.bind(clientCS, key),
20
+ getTreatmentsWithConfig: clientCS.getTreatmentsWithConfig.bind(clientCS, key),
19
21
  // Key is bound to the `track` method. Same thing happens with trafficType but only if provided
20
- track: trafficType ? client.track.bind(client, key, trafficType) : client.track.bind(client, key)
22
+ track: trafficType ? clientCS.track.bind(clientCS, key, trafficType) : clientCS.track.bind(clientCS, key)
21
23
  });
22
24
  }
23
25
  exports.clientCSDecorator = clientCSDecorator;
@@ -23,7 +23,7 @@ function sdkClientMethodCSFactory(params) {
23
23
  // `false` value is used as binded key of the default client, but trafficType is ignored
24
24
  // @TODO handle as a non-recoverable error
25
25
  var validKey = key_1.validateKey(log, key, method);
26
- var mainClientInstance = clientCS_1.clientCSDecorator(sdkClient_1.sdkClientFactory(params), // @ts-ignore
26
+ var mainClientInstance = clientCS_1.clientCSDecorator(log, sdkClient_1.sdkClientFactory(params), // @ts-ignore
27
27
  validKey);
28
28
  var parsedDefaultKey = key_2.keyParser(key);
29
29
  var defaultInstanceId = buildInstanceId(parsedDefaultKey);
@@ -58,7 +58,7 @@ function sdkClientMethodCSFactory(params) {
58
58
  var sharedSyncManager = syncManager && sharedStorage && syncManager.shared(matchingKey, sharedSdkReadiness_1.readinessManager, sharedStorage);
59
59
  // As shared clients reuse all the storage information, we don't need to check here if we
60
60
  // will use offline or online mode. We should stick with the original decision.
61
- clientInstances[instanceId] = clientCS_1.clientCSDecorator(sdkClient_1.sdkClientFactory(objectAssign_1.objectAssign({}, params, {
61
+ clientInstances[instanceId] = clientCS_1.clientCSDecorator(log, sdkClient_1.sdkClientFactory(objectAssign_1.objectAssign({}, params, {
62
62
  sdkReadinessManager: sharedSdkReadiness_1,
63
63
  storage: sharedStorage || storage,
64
64
  syncManager: sharedSyncManager,
@@ -29,7 +29,7 @@ function sdkClientMethodCSFactory(params) {
29
29
  if (trafficType !== undefined) {
30
30
  validTrafficType = trafficType_1.validateTrafficType(log, trafficType, method);
31
31
  }
32
- var mainClientInstance = clientCS_1.clientCSDecorator(sdkClient_1.sdkClientFactory(params), // @ts-ignore
32
+ var mainClientInstance = clientCS_1.clientCSDecorator(log, sdkClient_1.sdkClientFactory(params), // @ts-ignore
33
33
  validKey, validTrafficType);
34
34
  var parsedDefaultKey = key_2.keyParser(key);
35
35
  var defaultInstanceId = buildInstanceId(parsedDefaultKey, trafficType);
@@ -71,7 +71,7 @@ function sdkClientMethodCSFactory(params) {
71
71
  var sharedSyncManager = syncManager && sharedStorage && syncManager.shared(matchingKey, sharedSdkReadiness_1.readinessManager, sharedStorage);
72
72
  // As shared clients reuse all the storage information, we don't need to check here if we
73
73
  // will use offline or online mode. We should stick with the original decision.
74
- clientInstances[instanceId] = clientCS_1.clientCSDecorator(sdkClient_1.sdkClientFactory(objectAssign_1.objectAssign({}, params, {
74
+ clientInstances[instanceId] = clientCS_1.clientCSDecorator(log, sdkClient_1.sdkClientFactory(objectAssign_1.objectAssign({}, params, {
75
75
  sdkReadinessManager: sharedSdkReadiness_1,
76
76
  storage: sharedStorage || storage,
77
77
  syncManager: sharedSyncManager,
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AttributesCacheInMemory = void 0;
4
+ var objectAssign_1 = require("../../utils/lang/objectAssign");
5
+ var AttributesCacheInMemory = /** @class */ (function () {
6
+ function AttributesCacheInMemory() {
7
+ this.attributesCache = {};
8
+ }
9
+ /**
10
+ * Create or update the value for the given attribute
11
+ *
12
+ * @param {string} attributeName attribute name
13
+ * @param {Object} attributeValue attribute value
14
+ * @returns {boolean} the attribute was stored
15
+ */
16
+ AttributesCacheInMemory.prototype.setAttribute = function (attributeName, attributeValue) {
17
+ this.attributesCache[attributeName] = attributeValue;
18
+ return true;
19
+ };
20
+ /**
21
+ * Retrieves the value of a given attribute
22
+ *
23
+ * @param {string} attributeName attribute name
24
+ * @returns {Object?} stored attribute value
25
+ */
26
+ AttributesCacheInMemory.prototype.getAttribute = function (attributeName) {
27
+ return this.attributesCache[attributeName];
28
+ };
29
+ /**
30
+ * Create or update all the given attributes
31
+ *
32
+ * @param {[string, Object]} attributes attributes to create or update
33
+ * @returns {boolean} attributes were stored
34
+ */
35
+ AttributesCacheInMemory.prototype.setAttributes = function (attributes) {
36
+ this.attributesCache = objectAssign_1.objectAssign(this.attributesCache, attributes);
37
+ return true;
38
+ };
39
+ /**
40
+ * Retrieve the full attributes map
41
+ *
42
+ * @returns {Map<string, Object>} stored attributes
43
+ */
44
+ AttributesCacheInMemory.prototype.getAll = function () {
45
+ return this.attributesCache;
46
+ };
47
+ /**
48
+ * Removes a given attribute from the map
49
+ *
50
+ * @param {string} attributeName attribute to remove
51
+ * @returns {boolean} attribute removed
52
+ */
53
+ AttributesCacheInMemory.prototype.removeAttribute = function (attributeName) {
54
+ if (Object.keys(this.attributesCache).indexOf(attributeName) >= 0) {
55
+ delete this.attributesCache[attributeName];
56
+ return true;
57
+ }
58
+ return false;
59
+ };
60
+ /**
61
+ * Clears all attributes stored in the SDK
62
+ *
63
+ */
64
+ AttributesCacheInMemory.prototype.clear = function () {
65
+ this.attributesCache = {};
66
+ return true;
67
+ };
68
+ return AttributesCacheInMemory;
69
+ }());
70
+ exports.AttributesCacheInMemory = AttributesCacheInMemory;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAttribute = void 0;
4
+ var lang_1 = require("../../utils/lang");
5
+ function validateAttribute(log, attributeKey, attributeValue, method) {
6
+ if (!lang_1.isString(attributeKey) || attributeKey.length === 0) {
7
+ log.warn(method + ": you passed an invalid attribute name, attribute name must be a non-empty string.");
8
+ return false;
9
+ }
10
+ var isStringVal = lang_1.isString(attributeValue);
11
+ var isFiniteVal = lang_1.isFiniteNumber(attributeValue);
12
+ var isBoolVal = lang_1.isBoolean(attributeValue);
13
+ var isArrayVal = Array.isArray(attributeValue);
14
+ if (!(isStringVal || isFiniteVal || isBoolVal || isArrayVal)) { // If it's not of valid type.
15
+ log.warn(method + ": you passed an invalid attribute value for " + attributeKey + ". Acceptable types are: string, number, boolean and array of strings.");
16
+ return false;
17
+ }
18
+ return true;
19
+ }
20
+ exports.validateAttribute = validateAttribute;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateAttributes = void 0;
3
+ exports.validateAttributesDeep = exports.validateAttributes = void 0;
4
4
  var lang_1 = require("../lang");
5
+ var attribute_1 = require("./attribute");
5
6
  var constants_1 = require("../../logger/constants");
6
7
  function validateAttributes(log, maybeAttrs, method) {
7
8
  // Attributes are optional
@@ -11,3 +12,14 @@ function validateAttributes(log, maybeAttrs, method) {
11
12
  return false;
12
13
  }
13
14
  exports.validateAttributes = validateAttributes;
15
+ function validateAttributesDeep(log, maybeAttributes, method) {
16
+ if (!validateAttributes(log, maybeAttributes, method))
17
+ return false;
18
+ var result = true;
19
+ Object.keys(maybeAttributes).forEach(function (attributeKey) {
20
+ if (!attribute_1.validateAttribute(log, attributeKey, maybeAttributes[attributeKey], method))
21
+ result = false;
22
+ });
23
+ return result;
24
+ }
25
+ exports.validateAttributesDeep = validateAttributesDeep;
@@ -0,0 +1,104 @@
1
+ import { AttributesCacheInMemory } from '../storages/inMemory/AttributesCacheInMemory';
2
+ import { validateAttributesDeep } from '../utils/inputValidation/attributes';
3
+ import { objectAssign } from '../utils/lang/objectAssign';
4
+ /**
5
+ * Add in memory attributes storage methods and combine them with any attribute received from the getTreatment/s call
6
+ */
7
+ export function clientAttributesDecoration(log, client) {
8
+ var attributeStorage = new AttributesCacheInMemory();
9
+ // Keep a reference to the original methods
10
+ var clientGetTreatment = client.getTreatment;
11
+ var clientGetTreatmentWithConfig = client.getTreatmentWithConfig;
12
+ var clientGetTreatments = client.getTreatments;
13
+ var clientGetTreatmentsWithConfig = client.getTreatmentsWithConfig;
14
+ var clientTrack = client.track;
15
+ function getTreatment(maybeKey, maybeSplit, maybeAttributes) {
16
+ return clientGetTreatment(maybeKey, maybeSplit, combineAttributes(maybeAttributes));
17
+ }
18
+ function getTreatmentWithConfig(maybeKey, maybeSplit, maybeAttributes) {
19
+ return clientGetTreatmentWithConfig(maybeKey, maybeSplit, combineAttributes(maybeAttributes));
20
+ }
21
+ function getTreatments(maybeKey, maybeSplits, maybeAttributes) {
22
+ return clientGetTreatments(maybeKey, maybeSplits, combineAttributes(maybeAttributes));
23
+ }
24
+ function getTreatmentsWithConfig(maybeKey, maybeSplits, maybeAttributes) {
25
+ return clientGetTreatmentsWithConfig(maybeKey, maybeSplits, combineAttributes(maybeAttributes));
26
+ }
27
+ function track(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties) {
28
+ return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
29
+ }
30
+ function combineAttributes(maybeAttributes) {
31
+ var storedAttributes = attributeStorage.getAll();
32
+ if (Object.keys(storedAttributes).length > 0) {
33
+ return objectAssign({}, storedAttributes, maybeAttributes);
34
+ }
35
+ return maybeAttributes;
36
+ }
37
+ return objectAssign(client, {
38
+ getTreatment: getTreatment,
39
+ getTreatmentWithConfig: getTreatmentWithConfig,
40
+ getTreatments: getTreatments,
41
+ getTreatmentsWithConfig: getTreatmentsWithConfig,
42
+ track: track,
43
+ /**
44
+ * Add an attribute to client's in memory attributes storage
45
+ *
46
+ * @param {string} attributeName Attrinute name
47
+ * @param {string, number, boolean, list} attributeValue Attribute value
48
+ * @returns {boolean} true if the attribute was stored and false otherways
49
+ */
50
+ setAttribute: function (attributeName, attributeValue) {
51
+ var attribute = {};
52
+ attribute[attributeName] = attributeValue;
53
+ if (!validateAttributesDeep(log, attribute, 'setAttribute'))
54
+ return false;
55
+ log.debug("stored " + attributeValue + " for attribute " + attributeName);
56
+ return attributeStorage.setAttribute(attributeName, attributeValue);
57
+ },
58
+ /**
59
+ * Returns the attribute with the given key
60
+ *
61
+ * @param {string} attributeName Attribute name
62
+ * @returns {Object} Attribute with the given key
63
+ */
64
+ getAttribute: function (attributeName) {
65
+ log.debug("retrieved attribute " + attributeName);
66
+ return attributeStorage.getAttribute(attributeName + '');
67
+ },
68
+ /**
69
+ * Add to client's in memory attributes storage the attributes in 'attributes'
70
+ *
71
+ * @param {Object} attributes Object with attributes to store
72
+ * @returns true if attributes were stored an false otherways
73
+ */
74
+ setAttributes: function (attributes) {
75
+ if (!validateAttributesDeep(log, attributes, 'setAttributes'))
76
+ return false;
77
+ return attributeStorage.setAttributes(attributes);
78
+ },
79
+ /**
80
+ * Return all the attributes stored in client's in memory attributes storage
81
+ *
82
+ * @returns {Object} returns all the stored attributes
83
+ */
84
+ getAttributes: function () {
85
+ return attributeStorage.getAll();
86
+ },
87
+ /**
88
+ * Removes from client's in memory attributes storage the attribute with the given key
89
+ *
90
+ * @param {string} attributeName
91
+ * @returns {boolean} true if attribute was removed and false otherways
92
+ */
93
+ removeAttribute: function (attributeName) {
94
+ log.debug("removed attribute " + attributeName);
95
+ return attributeStorage.removeAttribute(attributeName + '');
96
+ },
97
+ /**
98
+ * Remove all the stored attributes in the client's in memory attribute storage
99
+ */
100
+ clearAttributes: function () {
101
+ return attributeStorage.clear();
102
+ }
103
+ });
104
+ }
@@ -1,4 +1,5 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
+ import { clientAttributesDecoration } from './clientAttributesDecoration';
2
3
  /**
3
4
  * Decorator that binds a key and (optionally) a traffic type to client methods
4
5
  *
@@ -6,14 +7,15 @@ import { objectAssign } from '../utils/lang/objectAssign';
6
7
  * @param key validated split key
7
8
  * @param trafficType validated traffic type
8
9
  */
9
- export function clientCSDecorator(client, key, trafficType) {
10
- return objectAssign(client, {
10
+ export function clientCSDecorator(log, client, key, trafficType) {
11
+ var clientCS = clientAttributesDecoration(log, client);
12
+ return objectAssign(clientCS, {
11
13
  // In the client-side API, we bind a key to the client `getTreatment*` methods
12
- getTreatment: client.getTreatment.bind(client, key),
13
- getTreatmentWithConfig: client.getTreatmentWithConfig.bind(client, key),
14
- getTreatments: client.getTreatments.bind(client, key),
15
- getTreatmentsWithConfig: client.getTreatmentsWithConfig.bind(client, key),
14
+ getTreatment: clientCS.getTreatment.bind(clientCS, key),
15
+ getTreatmentWithConfig: clientCS.getTreatmentWithConfig.bind(clientCS, key),
16
+ getTreatments: clientCS.getTreatments.bind(clientCS, key),
17
+ getTreatmentsWithConfig: clientCS.getTreatmentsWithConfig.bind(clientCS, key),
16
18
  // Key is bound to the `track` method. Same thing happens with trafficType but only if provided
17
- track: trafficType ? client.track.bind(client, key, trafficType) : client.track.bind(client, key)
19
+ track: trafficType ? clientCS.track.bind(clientCS, key, trafficType) : clientCS.track.bind(clientCS, key)
18
20
  });
19
21
  }
@@ -20,7 +20,7 @@ export function sdkClientMethodCSFactory(params) {
20
20
  // `false` value is used as binded key of the default client, but trafficType is ignored
21
21
  // @TODO handle as a non-recoverable error
22
22
  var validKey = validateKey(log, key, method);
23
- var mainClientInstance = clientCSDecorator(sdkClientFactory(params), // @ts-ignore
23
+ var mainClientInstance = clientCSDecorator(log, sdkClientFactory(params), // @ts-ignore
24
24
  validKey);
25
25
  var parsedDefaultKey = keyParser(key);
26
26
  var defaultInstanceId = buildInstanceId(parsedDefaultKey);
@@ -55,7 +55,7 @@ export function sdkClientMethodCSFactory(params) {
55
55
  var sharedSyncManager = syncManager && sharedStorage && syncManager.shared(matchingKey, sharedSdkReadiness_1.readinessManager, sharedStorage);
56
56
  // As shared clients reuse all the storage information, we don't need to check here if we
57
57
  // will use offline or online mode. We should stick with the original decision.
58
- clientInstances[instanceId] = clientCSDecorator(sdkClientFactory(objectAssign({}, params, {
58
+ clientInstances[instanceId] = clientCSDecorator(log, sdkClientFactory(objectAssign({}, params, {
59
59
  sdkReadinessManager: sharedSdkReadiness_1,
60
60
  storage: sharedStorage || storage,
61
61
  syncManager: sharedSyncManager,
@@ -26,7 +26,7 @@ export function sdkClientMethodCSFactory(params) {
26
26
  if (trafficType !== undefined) {
27
27
  validTrafficType = validateTrafficType(log, trafficType, method);
28
28
  }
29
- var mainClientInstance = clientCSDecorator(sdkClientFactory(params), // @ts-ignore
29
+ var mainClientInstance = clientCSDecorator(log, sdkClientFactory(params), // @ts-ignore
30
30
  validKey, validTrafficType);
31
31
  var parsedDefaultKey = keyParser(key);
32
32
  var defaultInstanceId = buildInstanceId(parsedDefaultKey, trafficType);
@@ -68,7 +68,7 @@ export function sdkClientMethodCSFactory(params) {
68
68
  var sharedSyncManager = syncManager && sharedStorage && syncManager.shared(matchingKey, sharedSdkReadiness_1.readinessManager, sharedStorage);
69
69
  // As shared clients reuse all the storage information, we don't need to check here if we
70
70
  // will use offline or online mode. We should stick with the original decision.
71
- clientInstances[instanceId] = clientCSDecorator(sdkClientFactory(objectAssign({}, params, {
71
+ clientInstances[instanceId] = clientCSDecorator(log, sdkClientFactory(objectAssign({}, params, {
72
72
  sdkReadinessManager: sharedSdkReadiness_1,
73
73
  storage: sharedStorage || storage,
74
74
  syncManager: sharedSyncManager,
@@ -0,0 +1,67 @@
1
+ import { objectAssign } from '../../utils/lang/objectAssign';
2
+ var AttributesCacheInMemory = /** @class */ (function () {
3
+ function AttributesCacheInMemory() {
4
+ this.attributesCache = {};
5
+ }
6
+ /**
7
+ * Create or update the value for the given attribute
8
+ *
9
+ * @param {string} attributeName attribute name
10
+ * @param {Object} attributeValue attribute value
11
+ * @returns {boolean} the attribute was stored
12
+ */
13
+ AttributesCacheInMemory.prototype.setAttribute = function (attributeName, attributeValue) {
14
+ this.attributesCache[attributeName] = attributeValue;
15
+ return true;
16
+ };
17
+ /**
18
+ * Retrieves the value of a given attribute
19
+ *
20
+ * @param {string} attributeName attribute name
21
+ * @returns {Object?} stored attribute value
22
+ */
23
+ AttributesCacheInMemory.prototype.getAttribute = function (attributeName) {
24
+ return this.attributesCache[attributeName];
25
+ };
26
+ /**
27
+ * Create or update all the given attributes
28
+ *
29
+ * @param {[string, Object]} attributes attributes to create or update
30
+ * @returns {boolean} attributes were stored
31
+ */
32
+ AttributesCacheInMemory.prototype.setAttributes = function (attributes) {
33
+ this.attributesCache = objectAssign(this.attributesCache, attributes);
34
+ return true;
35
+ };
36
+ /**
37
+ * Retrieve the full attributes map
38
+ *
39
+ * @returns {Map<string, Object>} stored attributes
40
+ */
41
+ AttributesCacheInMemory.prototype.getAll = function () {
42
+ return this.attributesCache;
43
+ };
44
+ /**
45
+ * Removes a given attribute from the map
46
+ *
47
+ * @param {string} attributeName attribute to remove
48
+ * @returns {boolean} attribute removed
49
+ */
50
+ AttributesCacheInMemory.prototype.removeAttribute = function (attributeName) {
51
+ if (Object.keys(this.attributesCache).indexOf(attributeName) >= 0) {
52
+ delete this.attributesCache[attributeName];
53
+ return true;
54
+ }
55
+ return false;
56
+ };
57
+ /**
58
+ * Clears all attributes stored in the SDK
59
+ *
60
+ */
61
+ AttributesCacheInMemory.prototype.clear = function () {
62
+ this.attributesCache = {};
63
+ return true;
64
+ };
65
+ return AttributesCacheInMemory;
66
+ }());
67
+ export { AttributesCacheInMemory };
@@ -0,0 +1,16 @@
1
+ import { isString, isFiniteNumber, isBoolean } from '../../utils/lang';
2
+ export function validateAttribute(log, attributeKey, attributeValue, method) {
3
+ if (!isString(attributeKey) || attributeKey.length === 0) {
4
+ log.warn(method + ": you passed an invalid attribute name, attribute name must be a non-empty string.");
5
+ return false;
6
+ }
7
+ var isStringVal = isString(attributeValue);
8
+ var isFiniteVal = isFiniteNumber(attributeValue);
9
+ var isBoolVal = isBoolean(attributeValue);
10
+ var isArrayVal = Array.isArray(attributeValue);
11
+ if (!(isStringVal || isFiniteVal || isBoolVal || isArrayVal)) { // If it's not of valid type.
12
+ log.warn(method + ": you passed an invalid attribute value for " + attributeKey + ". Acceptable types are: string, number, boolean and array of strings.");
13
+ return false;
14
+ }
15
+ return true;
16
+ }
@@ -1,4 +1,5 @@
1
1
  import { isObject } from '../lang';
2
+ import { validateAttribute } from './attribute';
2
3
  import { ERROR_NOT_PLAIN_OBJECT } from '../../logger/constants';
3
4
  export function validateAttributes(log, maybeAttrs, method) {
4
5
  // Attributes are optional
@@ -7,3 +8,13 @@ export function validateAttributes(log, maybeAttrs, method) {
7
8
  log.error(ERROR_NOT_PLAIN_OBJECT, [method, 'attributes']);
8
9
  return false;
9
10
  }
11
+ export function validateAttributesDeep(log, maybeAttributes, method) {
12
+ if (!validateAttributes(log, maybeAttributes, method))
13
+ return false;
14
+ var result = true;
15
+ Object.keys(maybeAttributes).forEach(function (attributeKey) {
16
+ if (!validateAttribute(log, attributeKey, maybeAttributes[attributeKey], method))
17
+ result = false;
18
+ });
19
+ return result;
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.1.0",
3
+ "version": "1.1.1-rc.0",
4
4
  "description": "Split Javascript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",