@splitsoftware/splitio 10.16.0 → 10.16.2-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.
- package/CHANGES.txt +9 -0
- package/CONTRIBUTORS-GUIDE.md +13 -12
- package/README.md +2 -1
- package/es/client/attributesDecoration.js +116 -0
- package/es/client/browser.js +2 -2
- package/es/engine/engine/murmur3/murmur3_128.js +1 -1
- package/es/engine/engine/murmur3/murmur3_128_x86.js +2 -3
- package/es/engine/evaluator/index.js +3 -4
- package/es/engine/matchers/index.js +20 -37
- package/es/engine/matchers/types.js +19 -72
- package/es/engine/transforms/matcherGroup.js +2 -2
- package/es/engine/transforms/matchers.js +2 -2
- package/es/engine/value/sanitize.js +12 -14
- package/es/impressions/hasher/hashImpression128.js +1 -1
- package/es/impressions/observer/observer.js +0 -1
- package/es/producer/updater/SplitChangesFromObject.js +3 -2
- package/es/storage/AttributesCache/InMemory.js +84 -0
- package/es/sync/PushManager/index.js +3 -11
- package/es/utils/inputValidation/attribute.js +22 -0
- package/es/utils/inputValidation/attributes.js +9 -0
- package/es/utils/logger/LoggerFactory.js +23 -16
- package/es/utils/settings/index.js +1 -1
- package/es/utils/settings/storage/browser.js +19 -4
- package/lib/client/attributesDecoration.js +128 -0
- package/lib/client/browser.js +5 -5
- package/lib/engine/engine/murmur3/murmur3_128.js +1 -1
- package/lib/engine/engine/murmur3/murmur3_128_x86.js +2 -3
- package/lib/engine/evaluator/index.js +3 -5
- package/lib/engine/matchers/index.js +21 -39
- package/lib/engine/matchers/types.js +23 -77
- package/lib/engine/transforms/matcherGroup.js +3 -3
- package/lib/engine/transforms/matchers.js +22 -22
- package/lib/engine/value/sanitize.js +11 -13
- package/lib/impressions/hasher/hashImpression128.js +2 -2
- package/lib/impressions/observer/observer.js +0 -1
- package/lib/producer/updater/SplitChangesFromObject.js +4 -2
- package/lib/storage/AttributesCache/InMemory.js +92 -0
- package/lib/sync/PushManager/index.js +3 -11
- package/lib/utils/inputValidation/attribute.js +32 -0
- package/lib/utils/inputValidation/attributes.js +12 -0
- package/lib/utils/logger/LoggerFactory.js +23 -17
- package/lib/utils/settings/index.js +1 -1
- package/lib/utils/settings/storage/browser.js +18 -3
- package/package.json +17 -17
- package/src/client/attributesDecoration.js +112 -0
- package/src/client/browser.js +2 -2
- package/src/engine/engine/murmur3/murmur3_128.js +1 -1
- package/src/engine/engine/murmur3/murmur3_128_x86.js +2 -3
- package/src/engine/evaluator/index.js +3 -4
- package/src/engine/matchers/index.js +22 -36
- package/src/engine/matchers/types.js +20 -55
- package/src/engine/transforms/matcherGroup.js +2 -5
- package/src/engine/transforms/matchers.js +2 -6
- package/src/engine/value/sanitize.js +12 -17
- package/src/impressions/hasher/hashImpression128.js +1 -1
- package/src/impressions/observer/observer.js +0 -2
- package/src/producer/updater/SplitChangesFromObject.js +2 -2
- package/src/storage/AttributesCache/InMemory.js +75 -0
- package/src/sync/PushManager/index.js +3 -10
- package/src/sync/constants.js +1 -1
- package/src/utils/inputValidation/attribute.js +22 -0
- package/src/utils/inputValidation/attributes.js +14 -0
- package/src/utils/logger/LoggerFactory.js +25 -16
- package/src/utils/settings/index.js +1 -1
- package/src/utils/settings/storage/browser.js +18 -3
- package/types/index.d.ts +1 -1
- package/types/splitio.d.ts +102 -27
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import ClientInputValidationLayer from './inputValidation';
|
|
2
|
+
import AttributesCacheInMemory from '../storage/AttributesCache/InMemory';
|
|
3
|
+
import { validateAttributesDeep } from '../utils/inputValidation/attributes';
|
|
4
|
+
import logFactory from '../utils/logger';
|
|
5
|
+
import objectAssign from 'object-assign';
|
|
6
|
+
const log = logFactory('splitio-client');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Add in memory attributes storage methods and combine them with any attribute received from the getTreatment/s call
|
|
10
|
+
*/
|
|
11
|
+
export default function ClientAttributesDecorationLayer(context, isKeyBinded, isTTBinded) {
|
|
12
|
+
|
|
13
|
+
const client = ClientInputValidationLayer(context, isKeyBinded, isTTBinded);
|
|
14
|
+
|
|
15
|
+
const attributeStorage = new AttributesCacheInMemory();
|
|
16
|
+
|
|
17
|
+
// Keep a reference to the original methods
|
|
18
|
+
const clientGetTreatment = client.getTreatment;
|
|
19
|
+
const clientGetTreatmentWithConfig = client.getTreatmentWithConfig;
|
|
20
|
+
const clientGetTreatments = client.getTreatments;
|
|
21
|
+
const clientGetTreatmentsWithConfig = client.getTreatmentsWithConfig;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Add an attribute to client's in memory attributes storage
|
|
25
|
+
*
|
|
26
|
+
* @param {string} attributeName Attrinute name
|
|
27
|
+
* @param {string, number, boolean, list} attributeValue Attribute value
|
|
28
|
+
* @returns {boolean} true if the attribute was stored and false otherways
|
|
29
|
+
*/
|
|
30
|
+
client.setAttribute = (attributeName, attributeValue) => {
|
|
31
|
+
const attribute = {};
|
|
32
|
+
attribute[attributeName] = attributeValue;
|
|
33
|
+
if (!validateAttributesDeep(attribute)) return false;
|
|
34
|
+
log.debug(`stored ${attributeValue} for attribute ${attributeName}`);
|
|
35
|
+
return attributeStorage.setAttribute(attributeName, attributeValue);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Returns the attribute with the given key
|
|
40
|
+
*
|
|
41
|
+
* @param {string} attributeName Attribute name
|
|
42
|
+
* @returns {Object} Attribute with the given key
|
|
43
|
+
*/
|
|
44
|
+
client.getAttribute = (attributeName) => {
|
|
45
|
+
log.debug(`retrieved attribute ${attributeName}`);
|
|
46
|
+
return attributeStorage.getAttribute(attributeName + '');
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Add to client's in memory attributes storage the attributes in 'attributes'
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} attributes Object with attributes to store
|
|
53
|
+
* @returns true if attributes were stored an false otherways
|
|
54
|
+
*/
|
|
55
|
+
client.setAttributes = (attributes) => {
|
|
56
|
+
if (!validateAttributesDeep(attributes)) return false;
|
|
57
|
+
return attributeStorage.setAttributes(attributes);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Return all the attributes stored in client's in memory attributes storage
|
|
62
|
+
*
|
|
63
|
+
* @returns {Object} returns all the stored attributes
|
|
64
|
+
*/
|
|
65
|
+
client.getAttributes = () => {
|
|
66
|
+
return attributeStorage.getAll();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Removes from client's in memory attributes storage the attribute with the given key
|
|
71
|
+
*
|
|
72
|
+
* @param {string} attributeName
|
|
73
|
+
* @returns {boolean} true if attribute was removed and false otherways
|
|
74
|
+
*/
|
|
75
|
+
client.removeAttribute = (attributeName) => {
|
|
76
|
+
log.debug(`removed attribute ${attributeName}`);
|
|
77
|
+
return attributeStorage.removeAttribute(attributeName + '');
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Remove all the stored attributes in the client's in memory attribute storage
|
|
82
|
+
*/
|
|
83
|
+
client.clearAttributes = () => {
|
|
84
|
+
return attributeStorage.clear();
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
client.getTreatment = (maybeKey, maybeSplit, maybeAttributes) => {
|
|
88
|
+
return clientGetTreatment(maybeKey, maybeSplit, combineAttributes(maybeAttributes));
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
client.getTreatmentWithConfig = (maybeKey, maybeSplit, maybeAttributes) => {
|
|
92
|
+
return clientGetTreatmentWithConfig(maybeKey, maybeSplit, combineAttributes(maybeAttributes));
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
client.getTreatments = (maybeKey, maybeSplits, maybeAttributes) => {
|
|
96
|
+
return clientGetTreatments(maybeKey, maybeSplits, combineAttributes(maybeAttributes));
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
client.getTreatmentsWithConfig = (maybeKey, maybeSplits, maybeAttributes) => {
|
|
100
|
+
return clientGetTreatmentsWithConfig(maybeKey, maybeSplits, combineAttributes(maybeAttributes));
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
function combineAttributes(maybeAttributes) {
|
|
104
|
+
const storedAttributes = attributeStorage.getAll();
|
|
105
|
+
if (Object.keys(storedAttributes).length > 0) {
|
|
106
|
+
return objectAssign({}, storedAttributes, maybeAttributes);
|
|
107
|
+
}
|
|
108
|
+
return maybeAttributes;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return client;
|
|
112
|
+
}
|
package/src/client/browser.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { get } from '../utils/lang';
|
|
2
|
-
import
|
|
2
|
+
import ClientAttributesDecorationLayer from './attributesDecoration';
|
|
3
3
|
import { LOCALHOST_MODE } from '../utils/constants';
|
|
4
4
|
import {
|
|
5
5
|
validateKey,
|
|
@@ -25,7 +25,7 @@ function BrowserClientFactory(context) {
|
|
|
25
25
|
trackBindings.push(tt);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const client =
|
|
28
|
+
const client = ClientAttributesDecorationLayer(context, true, trackBindings.length > 1);
|
|
29
29
|
client.isBrowserClient = true;
|
|
30
30
|
|
|
31
31
|
// In the browser land, we can bind the key and the traffic type (if provided)
|
|
@@ -265,7 +265,7 @@ function hash128x64(key /*: string */, seed /*: number */) /*: string */ {
|
|
|
265
265
|
|
|
266
266
|
/**
|
|
267
267
|
* x64 version of Murmur3 for 128bits.
|
|
268
|
-
*
|
|
268
|
+
*
|
|
269
269
|
* @param {string} str
|
|
270
270
|
*/
|
|
271
271
|
export function hash128(str /*: string */, seed /*: number */) /*: string */ {
|
|
@@ -179,10 +179,9 @@ function hash128x86(key /*: string */, seed /*: number */) /*: string */ {
|
|
|
179
179
|
|
|
180
180
|
/**
|
|
181
181
|
* x86 version of Murmur3 for 128bits.
|
|
182
|
-
*
|
|
182
|
+
* Used by hashImpression128 because in JS it is more efficient than the x64 version, no matter the underlying OS/CPU arch.
|
|
183
183
|
*
|
|
184
|
-
* @
|
|
185
|
-
* because it is more time efficient in JS, no matter the underlying CPU arch.
|
|
184
|
+
* @param {string} str
|
|
186
185
|
*/
|
|
187
186
|
export function hash128(str /*: string */, seed /*: number */) /*: string */ {
|
|
188
187
|
return hash128x86(UTF16ToUTF8(str), seed >>> 0);
|
|
@@ -17,7 +17,6 @@ limitations under the License.
|
|
|
17
17
|
import Engine from '../';
|
|
18
18
|
import thenable from '../../utils/promise/thenable';
|
|
19
19
|
import * as LabelsConstants from '../../utils/labels';
|
|
20
|
-
import { get } from '../../utils/lang';
|
|
21
20
|
import { CONTROL } from '../../utils/constants';
|
|
22
21
|
|
|
23
22
|
const treatmentException = {
|
|
@@ -103,17 +102,17 @@ function getEvaluation(
|
|
|
103
102
|
const split = Engine.parse(splitJSON, storage);
|
|
104
103
|
evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
105
104
|
|
|
106
|
-
// If the storage is async
|
|
105
|
+
// If the storage is async and the evaluated split uses segment, evaluation is thenable
|
|
107
106
|
if (thenable(evaluation)) {
|
|
108
107
|
return evaluation.then(result => {
|
|
109
108
|
result.changeNumber = split.getChangeNumber();
|
|
110
|
-
result.config =
|
|
109
|
+
result.config = splitJSON.configurations && splitJSON.configurations[result.treatment] || null;
|
|
111
110
|
|
|
112
111
|
return result;
|
|
113
112
|
});
|
|
114
113
|
} else {
|
|
115
114
|
evaluation.changeNumber = split.getChangeNumber(); // Always sync and optional
|
|
116
|
-
evaluation.config =
|
|
115
|
+
evaluation.config = splitJSON.configurations && splitJSON.configurations[evaluation.treatment] || null;
|
|
117
116
|
}
|
|
118
117
|
}
|
|
119
118
|
|
|
@@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
**/
|
|
16
|
-
import { types } from './types';
|
|
17
16
|
import allMatcher from './all';
|
|
18
17
|
import segmentMatcher from './segment';
|
|
19
18
|
import whitelistMatcher from './whitelist';
|
|
@@ -32,6 +31,27 @@ import dependencyMatcher from './dependency';
|
|
|
32
31
|
import booleanMatcher from './boolean';
|
|
33
32
|
import stringMatcher from './string';
|
|
34
33
|
|
|
34
|
+
const matchers = [
|
|
35
|
+
undefined, // UNDEFINED: 0,
|
|
36
|
+
allMatcher, // ALL_KEYS: 1,
|
|
37
|
+
segmentMatcher, // IN_SEGMENT: 2,
|
|
38
|
+
whitelistMatcher, // WHITELIST: 3,
|
|
39
|
+
eqMatcher, // EQUAL_TO: 4,
|
|
40
|
+
gteMatcher, // GREATER_THAN_OR_EQUAL_TO: 5,
|
|
41
|
+
lteMatcher, // LESS_THAN_OR_EQUAL_TO: 6,
|
|
42
|
+
betweenMatcher, // BETWEEN: 7,
|
|
43
|
+
equalToSetMatcher, // EQUAL_TO_SET: 8,
|
|
44
|
+
containsAnySetMatcher, // CONTAINS_ANY_OF_SET: 9,
|
|
45
|
+
containsAllSetMatcher, // CONTAINS_ALL_OF_SET: 10,
|
|
46
|
+
partOfSetMatcher, // PART_OF_SET: 11,
|
|
47
|
+
ewMatcher, // ENDS_WITH: 12,
|
|
48
|
+
swMatcher, // STARTS_WITH: 13,
|
|
49
|
+
containsStrMatcher, // CONTAINS_STRING: 14,
|
|
50
|
+
dependencyMatcher, // IN_SPLIT_TREATMENT: 15,
|
|
51
|
+
booleanMatcher, // EQUAL_TO_BOOLEAN: 16,
|
|
52
|
+
stringMatcher // MATCHES_STRING: 17
|
|
53
|
+
];
|
|
54
|
+
|
|
35
55
|
/**
|
|
36
56
|
* Matcher factory.
|
|
37
57
|
*/
|
|
@@ -43,41 +63,7 @@ function MatcherFactory(matcherDto, storage) {
|
|
|
43
63
|
|
|
44
64
|
let matcherFn;
|
|
45
65
|
|
|
46
|
-
if (type
|
|
47
|
-
matcherFn = allMatcher(value);
|
|
48
|
-
} else if (type === types.SEGMENT) {
|
|
49
|
-
matcherFn = segmentMatcher(value, storage);
|
|
50
|
-
} else if (type === types.WHITELIST) {
|
|
51
|
-
matcherFn = whitelistMatcher(value);
|
|
52
|
-
} else if (type === types.EQUAL_TO) {
|
|
53
|
-
matcherFn = eqMatcher(value);
|
|
54
|
-
} else if (type === types.GREATER_THAN_OR_EQUAL_TO) {
|
|
55
|
-
matcherFn = gteMatcher(value);
|
|
56
|
-
} else if (type === types.LESS_THAN_OR_EQUAL_TO) {
|
|
57
|
-
matcherFn = lteMatcher(value);
|
|
58
|
-
} else if (type === types.BETWEEN) {
|
|
59
|
-
matcherFn = betweenMatcher(value);
|
|
60
|
-
} else if (type === types.EQUAL_TO_SET) {
|
|
61
|
-
matcherFn = equalToSetMatcher(value);
|
|
62
|
-
} else if (type === types.CONTAINS_ANY_OF_SET) {
|
|
63
|
-
matcherFn = containsAnySetMatcher(value);
|
|
64
|
-
} else if (type === types.CONTAINS_ALL_OF_SET) {
|
|
65
|
-
matcherFn = containsAllSetMatcher(value);
|
|
66
|
-
} else if (type === types.PART_OF_SET) {
|
|
67
|
-
matcherFn = partOfSetMatcher(value);
|
|
68
|
-
} else if (type === types.STARTS_WITH) {
|
|
69
|
-
matcherFn = swMatcher(value);
|
|
70
|
-
} else if (type === types.ENDS_WITH) {
|
|
71
|
-
matcherFn = ewMatcher(value);
|
|
72
|
-
} else if (type === types.CONTAINS_STRING) {
|
|
73
|
-
matcherFn = containsStrMatcher(value);
|
|
74
|
-
} else if (type === types.IN_SPLIT_TREATMENT) {
|
|
75
|
-
matcherFn = dependencyMatcher(value, storage);
|
|
76
|
-
} else if (type === types.EQUAL_TO_BOOLEAN) {
|
|
77
|
-
matcherFn = booleanMatcher(value);
|
|
78
|
-
} else if (type === types.MATCHES_STRING) {
|
|
79
|
-
matcherFn = stringMatcher(value);
|
|
80
|
-
}
|
|
66
|
+
if (matchers[type]) matcherFn = matchers[type](value, storage); // There is no index-out-of-bound exception in JavaScript
|
|
81
67
|
|
|
82
68
|
return matcherFn;
|
|
83
69
|
}
|
|
@@ -15,28 +15,28 @@ limitations under the License.
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
// @WARNING Symbol is not correctly working in PhantomJS
|
|
18
|
-
export const
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export const matcherTypes = {
|
|
19
|
+
UNDEFINED: 0,
|
|
20
|
+
ALL_KEYS: 1,
|
|
21
|
+
IN_SEGMENT: 2,
|
|
21
22
|
WHITELIST: 3,
|
|
22
23
|
EQUAL_TO: 4,
|
|
23
24
|
GREATER_THAN_OR_EQUAL_TO: 5,
|
|
24
25
|
LESS_THAN_OR_EQUAL_TO: 6,
|
|
25
26
|
BETWEEN: 7,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
MATCHES_STRING: 18
|
|
27
|
+
EQUAL_TO_SET: 8,
|
|
28
|
+
CONTAINS_ANY_OF_SET: 9,
|
|
29
|
+
CONTAINS_ALL_OF_SET: 10,
|
|
30
|
+
PART_OF_SET: 11,
|
|
31
|
+
ENDS_WITH: 12,
|
|
32
|
+
STARTS_WITH: 13,
|
|
33
|
+
CONTAINS_STRING: 14,
|
|
34
|
+
IN_SPLIT_TREATMENT: 15,
|
|
35
|
+
EQUAL_TO_BOOLEAN: 16,
|
|
36
|
+
MATCHES_STRING: 17
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
export const
|
|
39
|
+
export const matcherDataTypes = {
|
|
40
40
|
BOOLEAN: 'BOOLEAN',
|
|
41
41
|
STRING: 'STRING',
|
|
42
42
|
NUMBER: 'NUMBER',
|
|
@@ -45,43 +45,8 @@ export const dataTypes = {
|
|
|
45
45
|
NOT_SPECIFIED: 'NOT_SPECIFIED'
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
export
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return types.SEGMENT;
|
|
54
|
-
case 'WHITELIST':
|
|
55
|
-
return types.WHITELIST;
|
|
56
|
-
case 'EQUAL_TO':
|
|
57
|
-
return types.EQUAL_TO;
|
|
58
|
-
case 'GREATER_THAN_OR_EQUAL_TO':
|
|
59
|
-
return types.GREATER_THAN_OR_EQUAL_TO;
|
|
60
|
-
case 'LESS_THAN_OR_EQUAL_TO':
|
|
61
|
-
return types.LESS_THAN_OR_EQUAL_TO;
|
|
62
|
-
case 'BETWEEN':
|
|
63
|
-
return types.BETWEEN;
|
|
64
|
-
case 'EQUAL_TO_SET':
|
|
65
|
-
return types.EQUAL_TO_SET;
|
|
66
|
-
case 'CONTAINS_ANY_OF_SET':
|
|
67
|
-
return types.CONTAINS_ANY_OF_SET;
|
|
68
|
-
case 'CONTAINS_ALL_OF_SET':
|
|
69
|
-
return types.CONTAINS_ALL_OF_SET;
|
|
70
|
-
case 'PART_OF_SET':
|
|
71
|
-
return types.PART_OF_SET;
|
|
72
|
-
case 'ENDS_WITH':
|
|
73
|
-
return types.ENDS_WITH;
|
|
74
|
-
case 'STARTS_WITH':
|
|
75
|
-
return types.STARTS_WITH;
|
|
76
|
-
case 'CONTAINS_STRING':
|
|
77
|
-
return types.CONTAINS_STRING;
|
|
78
|
-
case 'IN_SPLIT_TREATMENT':
|
|
79
|
-
return types.IN_SPLIT_TREATMENT;
|
|
80
|
-
case 'EQUAL_TO_BOOLEAN':
|
|
81
|
-
return types.EQUAL_TO_BOOLEAN;
|
|
82
|
-
case 'MATCHES_STRING':
|
|
83
|
-
return types.MATCHES_STRING;
|
|
84
|
-
default:
|
|
85
|
-
return types.UNDEFINED;
|
|
86
|
-
}
|
|
87
|
-
};
|
|
48
|
+
export function matcherTypesMapper(matcherType) {
|
|
49
|
+
const type = matcherTypes[matcherType];
|
|
50
|
+
if (type) return type;
|
|
51
|
+
else return matcherTypes.UNDEFINED;
|
|
52
|
+
}
|
|
@@ -13,10 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
**/
|
|
16
|
-
import {
|
|
17
|
-
types as matcherTypes,
|
|
18
|
-
mapper as matcherTypesMapper
|
|
19
|
-
} from '../matchers/types';
|
|
16
|
+
import { matcherTypes, matcherTypesMapper } from '../matchers/types';
|
|
20
17
|
import segmentTransform from './segment';
|
|
21
18
|
import whitelistTransform from './whitelist';
|
|
22
19
|
|
|
@@ -33,7 +30,7 @@ function transform(matcherGroup) {
|
|
|
33
30
|
let type = matcherTypesMapper(matcherType);
|
|
34
31
|
let value = undefined;
|
|
35
32
|
|
|
36
|
-
if (type === matcherTypes.
|
|
33
|
+
if (type === matcherTypes.IN_SEGMENT) {
|
|
37
34
|
value = segmentTransform(segmentObject);
|
|
38
35
|
} else if (type === matcherTypes.WHITELIST) {
|
|
39
36
|
value = whitelistTransform(whitelistObject);
|
|
@@ -15,11 +15,7 @@ limitations under the License.
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
import { findIndex } from '../../utils/lang';
|
|
18
|
-
import {
|
|
19
|
-
types as matcherTypes,
|
|
20
|
-
mapper as matcherTypesMapper,
|
|
21
|
-
dataTypes as matcherDataTypes
|
|
22
|
-
} from '../matchers/types';
|
|
18
|
+
import { matcherTypes, matcherTypesMapper, matcherDataTypes } from '../matchers/types';
|
|
23
19
|
import segmentTransform from './segment';
|
|
24
20
|
import whitelistTransform from './whitelist';
|
|
25
21
|
import setTransform from './set';
|
|
@@ -49,7 +45,7 @@ function transform(matchers) {
|
|
|
49
45
|
let dataType = matcherDataTypes.STRING;
|
|
50
46
|
let value = undefined;
|
|
51
47
|
|
|
52
|
-
if (type === matcherTypes.
|
|
48
|
+
if (type === matcherTypes.IN_SEGMENT) {
|
|
53
49
|
value = segmentTransform(segmentObject);
|
|
54
50
|
} else if (type === matcherTypes.WHITELIST) {
|
|
55
51
|
value = whitelistTransform(whitelistObject);
|
|
@@ -18,12 +18,7 @@ import logFactory from '../../utils/logger';
|
|
|
18
18
|
const log = logFactory('splitio-engine:sanitize');
|
|
19
19
|
import { isObject, uniq, toString, toNumber } from '../../utils/lang';
|
|
20
20
|
import { zeroSinceHH, zeroSinceSS } from '../convertions';
|
|
21
|
-
import {
|
|
22
|
-
types as matcherTypes,
|
|
23
|
-
dataTypes as matcherDataTypes
|
|
24
|
-
} from '../matchers/types';
|
|
25
|
-
const MATCHERS = matcherTypes;
|
|
26
|
-
const DATA_TYPES = matcherDataTypes;
|
|
21
|
+
import { matcherTypes, matcherDataTypes } from '../matchers/types';
|
|
27
22
|
|
|
28
23
|
function sanitizeNumber(val) {
|
|
29
24
|
const num = toNumber(val);
|
|
@@ -72,13 +67,13 @@ function dependencyProcessor(sanitizedValue, attributes) {
|
|
|
72
67
|
*/
|
|
73
68
|
function getProcessingFunction(matcherTypeID, dataType) {
|
|
74
69
|
switch (matcherTypeID) {
|
|
75
|
-
case
|
|
70
|
+
case matcherTypes.EQUAL_TO:
|
|
76
71
|
return dataType === 'DATETIME' ? zeroSinceHH : undefined;
|
|
77
|
-
case
|
|
78
|
-
case
|
|
79
|
-
case
|
|
72
|
+
case matcherTypes.GREATER_THAN_OR_EQUAL_TO:
|
|
73
|
+
case matcherTypes.LESS_THAN_OR_EQUAL_TO:
|
|
74
|
+
case matcherTypes.BETWEEN:
|
|
80
75
|
return dataType === 'DATETIME' ? zeroSinceSS : undefined;
|
|
81
|
-
case
|
|
76
|
+
case matcherTypes.IN_SPLIT_TREATMENT:
|
|
82
77
|
return dependencyProcessor;
|
|
83
78
|
default:
|
|
84
79
|
return undefined;
|
|
@@ -90,20 +85,20 @@ function sanitizeValue(matcherTypeID, value, dataType, attributes) {
|
|
|
90
85
|
let sanitizedValue;
|
|
91
86
|
|
|
92
87
|
switch (dataType) {
|
|
93
|
-
case
|
|
94
|
-
case
|
|
88
|
+
case matcherDataTypes.NUMBER:
|
|
89
|
+
case matcherDataTypes.DATETIME:
|
|
95
90
|
sanitizedValue = sanitizeNumber(value);
|
|
96
91
|
break;
|
|
97
|
-
case
|
|
92
|
+
case matcherDataTypes.STRING:
|
|
98
93
|
sanitizedValue = sanitizeString(value);
|
|
99
94
|
break;
|
|
100
|
-
case
|
|
95
|
+
case matcherDataTypes.SET:
|
|
101
96
|
sanitizedValue = sanitizeArray(value);
|
|
102
97
|
break;
|
|
103
|
-
case
|
|
98
|
+
case matcherDataTypes.BOOLEAN:
|
|
104
99
|
sanitizedValue = sanitizeBoolean(value);
|
|
105
100
|
break;
|
|
106
|
-
case
|
|
101
|
+
case matcherDataTypes.NOT_SPECIFIED:
|
|
107
102
|
sanitizedValue = value;
|
|
108
103
|
break;
|
|
109
104
|
default:
|
|
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
**/
|
|
16
|
+
import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
16
17
|
import { forOwn } from '../../utils/lang';
|
|
17
18
|
import logFactory from '../../utils/logger';
|
|
18
19
|
const log = logFactory('splitio-producer:offline');
|
|
@@ -59,7 +60,6 @@ function FromObjectUpdaterFactory(Fetcher, context) {
|
|
|
59
60
|
|
|
60
61
|
return Promise.all([
|
|
61
62
|
storage.splits.flush(), // required to sync removed splits from mock
|
|
62
|
-
storage.splits.setChangeNumber(Date.now()),
|
|
63
63
|
storage.splits.addSplits(splits)
|
|
64
64
|
]).then(() => {
|
|
65
65
|
readiness.splits.emit(readiness.splits.SDK_SPLITS_ARRIVED);
|
|
@@ -67,7 +67,7 @@ function FromObjectUpdaterFactory(Fetcher, context) {
|
|
|
67
67
|
if (startingUp) {
|
|
68
68
|
startingUp = false;
|
|
69
69
|
// Emits SDK_READY_FROM_CACHE
|
|
70
|
-
if (storage.
|
|
70
|
+
if (settings.storage.__originalType === STORAGE_LOCALSTORAGE) readiness.splits.emit(readiness.splits.SDK_SPLITS_CACHE_LOADED);
|
|
71
71
|
// Only emits SDK_SEGMENTS_ARRIVED the first time for SDK_READY
|
|
72
72
|
readiness.segments.emit(readiness.segments.SDK_SEGMENTS_ARRIVED);
|
|
73
73
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import objectAssign from 'object-assign';
|
|
2
|
+
|
|
3
|
+
class AttributesCacheInMemory {
|
|
4
|
+
|
|
5
|
+
constructor() {
|
|
6
|
+
this.attributesCache = {};
|
|
7
|
+
}
|
|
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
|
+
setAttribute(attributeName, attributeValue) {
|
|
17
|
+
this.attributesCache[attributeName] = attributeValue;
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves the value of a given attribute
|
|
23
|
+
*
|
|
24
|
+
* @param {string} attributeName attribute name
|
|
25
|
+
* @returns {Object?} stored attribute value
|
|
26
|
+
*/
|
|
27
|
+
getAttribute(attributeName) {
|
|
28
|
+
return this.attributesCache[attributeName];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create or update all the given attributes
|
|
33
|
+
*
|
|
34
|
+
* @param {[string, Object]} attributes attributes to create or update
|
|
35
|
+
* @returns {boolean} attributes were stored
|
|
36
|
+
*/
|
|
37
|
+
setAttributes(attributes) {
|
|
38
|
+
this.attributesCache = objectAssign(this.attributesCache, attributes);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Retrieve the full attributes map
|
|
44
|
+
*
|
|
45
|
+
* @returns {Map<string, Object>} stored attributes
|
|
46
|
+
*/
|
|
47
|
+
getAll() {
|
|
48
|
+
return this.attributesCache;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Removes a given attribute from the map
|
|
53
|
+
*
|
|
54
|
+
* @param {string} attributeName attribute to remove
|
|
55
|
+
* @returns {boolean} attribute removed
|
|
56
|
+
*/
|
|
57
|
+
removeAttribute(attributeName) {
|
|
58
|
+
if (Object.keys(this.attributesCache).indexOf(attributeName) >= 0) {
|
|
59
|
+
delete this.attributesCache[attributeName];
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Clears all attributes stored in the SDK
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
clear() {
|
|
70
|
+
this.attributesCache = {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default AttributesCacheInMemory;
|
|
@@ -247,19 +247,12 @@ export default function PushManagerFactory(context, clientContexts /* undefined
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
forOwn(clients, ({ hash64, worker }) => {
|
|
250
|
-
|
|
250
|
+
const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined;
|
|
251
|
+
if (add !== undefined) {
|
|
251
252
|
worker.put(parsedData.changeNumber, {
|
|
252
253
|
name: parsedData.segmentName,
|
|
253
|
-
add
|
|
254
|
+
add
|
|
254
255
|
});
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
if (removed.has(hash64.dec)) {
|
|
258
|
-
worker.put(parsedData.changeNumber, {
|
|
259
|
-
name: parsedData.segmentName,
|
|
260
|
-
add: false
|
|
261
|
-
});
|
|
262
|
-
return;
|
|
263
256
|
}
|
|
264
257
|
});
|
|
265
258
|
return;
|
package/src/sync/constants.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isString, numberIsFinite, isBoolean } from '../lang';
|
|
2
|
+
import logFactory from '../logger';
|
|
3
|
+
const log = logFactory('');
|
|
4
|
+
|
|
5
|
+
export function validateAttribute(attributeKey, attributeValue, method) {
|
|
6
|
+
if (!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
|
+
|
|
11
|
+
const isStringVal = isString(attributeValue);
|
|
12
|
+
const isFiniteVal = numberIsFinite(attributeValue);
|
|
13
|
+
const isBoolVal = isBoolean(attributeValue);
|
|
14
|
+
const isArrayVal = Array.isArray(attributeValue);
|
|
15
|
+
|
|
16
|
+
if (!(isStringVal || isFiniteVal || isBoolVal || isArrayVal)) { // If it's not of valid type.
|
|
17
|
+
log.warn(`${method}: you passed an invalid attribute value for ${attributeKey}. Acceptable types are: string, number, boolean and array of strings.`);
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isObject } from '../lang';
|
|
2
2
|
import logFactory from '../logger';
|
|
3
|
+
import { validateAttribute } from './attribute';
|
|
3
4
|
const log = logFactory('');
|
|
4
5
|
|
|
5
6
|
export function validateAttributes(maybeAttrs, method) {
|
|
@@ -10,3 +11,16 @@ export function validateAttributes(maybeAttrs, method) {
|
|
|
10
11
|
log.error(`${method}: attributes must be a plain object.`);
|
|
11
12
|
return false;
|
|
12
13
|
}
|
|
14
|
+
|
|
15
|
+
export function validateAttributesDeep(maybeAttributes, method) {
|
|
16
|
+
if (!validateAttributes(maybeAttributes, method)) return false;
|
|
17
|
+
|
|
18
|
+
let result = true;
|
|
19
|
+
Object.keys(maybeAttributes).forEach(attributeKey => {
|
|
20
|
+
if (!validateAttribute(attributeKey, maybeAttributes[attributeKey], method))
|
|
21
|
+
result = false;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return result;
|
|
25
|
+
|
|
26
|
+
}
|