@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
184 lines (183 loc) • 10.4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.clientFactory = void 0;
var evaluator_1 = require("../evaluator");
var thenable_1 = require("../utils/promise/thenable");
var key_1 = require("../utils/key");
var splitExistence_1 = require("../utils/inputValidation/splitExistence");
var trafficTypeExistence_1 = require("../utils/inputValidation/trafficTypeExistence");
var labels_1 = require("../utils/labels");
var constants_1 = require("../utils/constants");
var constants_2 = require("../logger/constants");
var mode_1 = require("../utils/settingsValidation/mode");
var treatmentNotReady = { treatment: constants_1.CONTROL, label: labels_1.SDK_NOT_READY };
function treatmentsNotReady(featureFlagNames) {
var evaluations = {};
featureFlagNames.forEach(function (featureFlagName) {
evaluations[featureFlagName] = treatmentNotReady;
});
return evaluations;
}
function stringify(options) {
if (options && options.properties) {
try {
return JSON.stringify(options.properties);
}
catch ( /* JSON.stringify should never throw with validated options, but handling just in case */_a) { /* JSON.stringify should never throw with validated options, but handling just in case */ }
}
}
/**
* Creator of base client with getTreatments and track methods.
*/
function clientFactory(params) {
var readinessManager = params.sdkReadinessManager.readinessManager, storage = params.storage, settings = params.settings, impressionsTracker = params.impressionsTracker, eventTracker = params.eventTracker, telemetryTracker = params.telemetryTracker;
var log = settings.log, mode = settings.mode;
var isAsync = (0, mode_1.isConsumerMode)(mode);
function getTreatment(key, featureFlagName, attributes, options, withConfig, methodName) {
if (withConfig === void 0) { withConfig = false; }
if (methodName === void 0) { methodName = constants_1.GET_TREATMENT; }
var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? constants_1.TREATMENT_WITH_CONFIG : constants_1.TREATMENT);
var wrapUp = function (evaluationResult) {
var queue = [];
var treatment = processEvaluation(evaluationResult, featureFlagName, key, stringify(options), withConfig, methodName, queue);
impressionsTracker.track(queue, attributes);
stopTelemetryTracker(queue[0] && queue[0].imp.label);
return treatment;
};
var evaluation = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
(0, evaluator_1.evaluateFeature)(log, key, featureFlagName, attributes, storage) :
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
Promise.resolve(treatmentNotReady) :
treatmentNotReady;
return (0, thenable_1.thenable)(evaluation) ? evaluation.then(function (res) { return wrapUp(res); }) : wrapUp(evaluation);
}
function getTreatmentWithConfig(key, featureFlagName, attributes, options) {
return getTreatment(key, featureFlagName, attributes, options, true, constants_1.GET_TREATMENT_WITH_CONFIG);
}
function getTreatments(key, featureFlagNames, attributes, options, withConfig, methodName) {
if (withConfig === void 0) { withConfig = false; }
if (methodName === void 0) { methodName = constants_1.GET_TREATMENTS; }
var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? constants_1.TREATMENTS_WITH_CONFIG : constants_1.TREATMENTS);
var wrapUp = function (evaluationResults) {
var queue = [];
var treatments = {};
var properties = stringify(options);
Object.keys(evaluationResults).forEach(function (featureFlagName) {
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
});
impressionsTracker.track(queue, attributes);
stopTelemetryTracker(queue[0] && queue[0].imp.label);
return treatments;
};
var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
(0, evaluator_1.evaluateFeatures)(log, key, featureFlagNames, attributes, storage) :
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
Promise.resolve(treatmentsNotReady(featureFlagNames)) :
treatmentsNotReady(featureFlagNames);
return (0, thenable_1.thenable)(evaluations) ? evaluations.then(function (res) { return wrapUp(res); }) : wrapUp(evaluations);
}
function getTreatmentsWithConfig(key, featureFlagNames, attributes, options) {
return getTreatments(key, featureFlagNames, attributes, options, true, constants_1.GET_TREATMENTS_WITH_CONFIG);
}
function getTreatmentsByFlagSets(key, flagSetNames, attributes, options, withConfig, method, methodName) {
if (withConfig === void 0) { withConfig = false; }
if (method === void 0) { method = constants_1.TREATMENTS_BY_FLAGSETS; }
if (methodName === void 0) { methodName = constants_1.GET_TREATMENTS_BY_FLAG_SETS; }
var stopTelemetryTracker = telemetryTracker.trackEval(method);
var wrapUp = function (evaluationResults) {
var queue = [];
var treatments = {};
var properties = stringify(options);
Object.keys(evaluationResults).forEach(function (featureFlagName) {
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
});
impressionsTracker.track(queue, attributes);
stopTelemetryTracker(queue[0] && queue[0].imp.label);
return treatments;
};
var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
(0, evaluator_1.evaluateFeaturesByFlagSets)(log, key, flagSetNames, attributes, storage, methodName) :
isAsync ?
Promise.resolve({}) :
{};
return (0, thenable_1.thenable)(evaluations) ? evaluations.then(function (res) { return wrapUp(res); }) : wrapUp(evaluations);
}
function getTreatmentsWithConfigByFlagSets(key, flagSetNames, attributes, options) {
return getTreatmentsByFlagSets(key, flagSetNames, attributes, options, true, constants_1.TREATMENTS_WITH_CONFIG_BY_FLAGSETS, constants_1.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
}
function getTreatmentsByFlagSet(key, flagSetName, attributes, options) {
return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, false, constants_1.TREATMENTS_BY_FLAGSET, constants_1.GET_TREATMENTS_BY_FLAG_SET);
}
function getTreatmentsWithConfigByFlagSet(key, flagSetName, attributes, options) {
return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, true, constants_1.TREATMENTS_WITH_CONFIG_BY_FLAGSET, constants_1.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
}
// Internal function
function processEvaluation(evaluation, featureFlagName, key, properties, withConfig, invokingMethodName, queue) {
var matchingKey = (0, key_1.getMatching)(key);
var bucketingKey = (0, key_1.getBucketing)(key);
var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a, impressionsDisabled = evaluation.impressionsDisabled;
log.info(constants_2.IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
if ((0, splitExistence_1.validateSplitExistence)(log, readinessManager, featureFlagName, label, invokingMethodName)) {
log.info(constants_2.IMPRESSION_QUEUEING);
queue.push({
imp: {
feature: featureFlagName,
keyName: matchingKey,
treatment: treatment,
time: Date.now(),
bucketingKey: bucketingKey,
label: label,
changeNumber: changeNumber,
properties: properties
},
disabled: impressionsDisabled
});
}
if (withConfig) {
return {
treatment: treatment,
config: config
};
}
return treatment;
}
function track(key, trafficTypeName, eventTypeId, value, properties, size) {
if (size === void 0) { size = 1024; }
var stopTelemetryTracker = telemetryTracker.trackEval(constants_1.TRACK);
var matchingKey = (0, key_1.getMatching)(key);
var timestamp = Date.now();
var eventData = {
eventTypeId: eventTypeId,
trafficTypeName: trafficTypeName,
value: value,
timestamp: timestamp,
key: matchingKey,
properties: properties
};
// This may be async but we only warn, we don't actually care if it is valid or not in terms of queueing the event.
(0, trafficTypeExistence_1.validateTrafficTypeExistence)(log, readinessManager, storage.splits, mode, trafficTypeName, constants_1.TRACK_FN_LABEL);
var result = eventTracker.track(eventData, size);
if ((0, thenable_1.thenable)(result)) {
return result.then(function (result) {
stopTelemetryTracker();
return result;
});
}
else {
stopTelemetryTracker();
return result;
}
}
return {
getTreatment: getTreatment,
getTreatmentWithConfig: getTreatmentWithConfig,
getTreatments: getTreatments,
getTreatmentsWithConfig: getTreatmentsWithConfig,
getTreatmentsByFlagSets: getTreatmentsByFlagSets,
getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
getTreatmentsByFlagSet: getTreatmentsByFlagSet,
getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
track: track,
};
}
exports.clientFactory = clientFactory;
;