-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using features property with consumer mode produces a type error #108
Comments
Hi @dereksdev , The So you cannot use it with modes In summary:
|
Thank you @EmilianoSanchez. This helps me understand the intent better. The So in order to test in consumer mode, do we need to create a mock |
Hi @dereksdev ,
If you are using just JavaScript, yes, you can pass the
We are going to take a look to it during January. At the moment there is not official support for localhost mode in consumer modes, but I can share with you a code snippet you can try on your side, based on the implementation of a storage wrapper in memory. However, keep in mind that this might not be the final solution for sure. // index.js
import { SplitFactory, PluggableStorage } from '@splitsoftware/splitio-browserjs';
import { inMemoryWrapperFactory } from './inMemoryWrapper.js';
const inMemoryWrapper = inMemoryWrapperFactory({
// `features` format as explained here: https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK#localhost-mode
features: {
'feature_1': 'on',
}
});
const factory = SplitFactory({
core: {
authorizationKey: 'anything-except-localhost',
key: 'user_x'
},
mode: 'consumer',
storage: PluggableStorage({
wrapper: inMemoryWrapper
})
});
const client = factory.client();
client.ready().then(async () => {
console.log(await client.getTreatment('feature_1')); // on
console.log(inMemoryWrapper._cache);
}); // inMemoryWrapper.js
/**
* Creates a IPluggableStorageWrapper implementation that stores items in memory.
* The `_cache` property is the object were items are stored.
* Intended for testing purposes.
*/
export function inMemoryWrapperFactory({ features, prefix } = {}) {
let _cache = {};
const wrapper = {
_cache,
get(key) {
return Promise.resolve(key in _cache ? _cache[key] : null);
},
set(key, value) {
const result = key in _cache;
_cache[key] = value;
return Promise.resolve(result);
},
getAndSet(key, value) {
const result = key in _cache ? _cache[key] : null;
_cache[key] = value;
return Promise.resolve(result);
},
del(key) {
const result = key in _cache;
delete _cache[key];
return Promise.resolve(result);
},
getKeysByPrefix(prefix) {
return Promise.resolve(Object.keys(_cache).filter(key => key.startsWith(prefix)));
},
incr(key, increment = 1) {
if (key in _cache) {
const count = parseInt(_cache[key]) + increment;
if (isNaN(count)) return Promise.reject('Given key is not a number');
_cache[key] = count + '';
return Promise.resolve(count);
} else {
_cache[key] = '' + increment;
return Promise.resolve(1);
}
},
decr(key, decrement = 1) {
if (key in _cache) {
const count = parseInt(_cache[key]) - decrement;
if (isNaN(count)) return Promise.reject('Given key is not a number');
_cache[key] = count + '';
return Promise.resolve(count);
} else {
_cache[key] = '-' + decrement;
return Promise.resolve(-1);
}
},
getMany(keys) {
return Promise.resolve(keys.map(key => _cache[key] ? _cache[key] : null));
},
pushItems(key, items) {
if (!(key in _cache)) _cache[key] = [];
const list = _cache[key];
if (Array.isArray(list)) {
list.push(...items);
return Promise.resolve();
}
return Promise.reject('key is not a list');
},
popItems(key, count) {
const list = _cache[key];
return Promise.resolve(Array.isArray(list) ? list.splice(0, count) : []);
},
getItemsCount(key) {
const list = _cache[key];
return Promise.resolve(Array.isArray(list) ? list.length : 0);
},
itemContains(key, item) {
const set = _cache[key];
if (!set) return Promise.resolve(false);
if (set instanceof Set) return Promise.resolve(set.has(item));
return Promise.reject('key is not a set');
},
addItems(key, items) {
if (!(key in _cache)) _cache[key] = new Set();
const set = _cache[key];
if (set instanceof Set) {
items.forEach(item => set.add(item));
return Promise.resolve();
}
return Promise.reject('key is not a set');
},
removeItems(key, items) {
if (!(key in _cache)) _cache[key] = new Set();
const set = _cache[key];
if (set instanceof Set) {
items.forEach(item => set.delete(item));
return Promise.resolve();
}
return Promise.reject('key is not a set');
},
getItems(key) {
const set = _cache[key];
if (!set) return Promise.resolve([]);
if (set instanceof Set) return Promise.resolve(setToArray(set));
return Promise.reject('key is not a set');
},
// always connects and disconnects
connect() { return Promise.resolve(); },
disconnect() { return Promise.resolve(); },
};
// Add features to wrapper
if (features) {
function parseCondition(data) {
const treatment = data.treatment;
if (data.keys) {
return {
conditionType: 'WHITELIST',
matcherGroup: {
combiner: 'AND',
matchers: [
{
keySelector: null,
matcherType: 'WHITELIST',
negate: false,
whitelistMatcherData: {
whitelist: typeof data.keys === 'string' ? [data.keys] : data.keys
}
}
]
},
partitions: [
{
treatment: treatment,
size: 100
}
],
label: `whitelisted ${treatment}`
};
} else {
return {
conditionType: 'ROLLOUT',
matcherGroup: {
combiner: 'AND',
matchers: [
{
keySelector: null,
matcherType: 'ALL_KEYS',
negate: false
}
]
},
partitions: [
{
treatment: treatment,
size: 100
}
],
label: 'default rule'
};
}
}
function splitsParserFromFeatures(features) {
const splitObjects = {};
Object.entries(features).forEach(([splitName, data]) => {
let treatment = data;
let config = null;
if (data !== null && typeof data === 'object') {
treatment = data.treatment;
config = data.config || config;
}
const configurations = {};
if (config !== null) configurations[treatment] = config;
splitObjects[splitName] = {
name: splitName,
trafficTypeName: 'localhost',
conditions: [parseCondition({ treatment: treatment })],
configurations,
status: 'ACTIVE',
killed: false,
trafficAllocation: 100,
defaultTreatment: 'control',
};
});
return splitObjects;
};
const featureFlags = splitsParserFromFeatures(features);
prefix = prefix ? prefix + '.SPLITIO' : 'SPLITIO';
Object.entries(featureFlags).forEach(([featureFlagName, featureFlag]) => {
const featureFlagKey = `${prefix}.split.${featureFlagName}`;
wrapper.set(featureFlagKey, JSON.stringify(featureFlag))
});
}
return wrapper;
} |
Using the features property in "consumer" or "consumer_partial" mode produces the following type error.
Example:
The text was updated successfully, but these errors were encountered: