@eppo/js-client-sdk-common
Advanced tools
Comparing version 1.5.2 to 1.6.0
@@ -44,8 +44,8 @@ import { IAssignmentHooks } from '../assignment-hooks'; | ||
constructor(configurationStore: IConfigurationStore); | ||
getAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined): string | null; | ||
getStringAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined): string | null; | ||
getBoolAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined): boolean | null; | ||
getNumericAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, EppoValue>, assignmentHooks?: IAssignmentHooks | undefined): number | null; | ||
getJSONStringAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined): string | null; | ||
getParsedJSONAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined): object | null; | ||
getAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined, obfuscated?: boolean): string | null; | ||
getStringAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined, obfuscated?: boolean): string | null; | ||
getBoolAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined, obfuscated?: boolean): boolean | null; | ||
getNumericAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, EppoValue>, assignmentHooks?: IAssignmentHooks | undefined, obfuscated?: boolean): number | null; | ||
getJSONStringAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined, obfuscated?: boolean): string | null; | ||
getParsedJSONAssignment(subjectKey: string, flagKey: string, subjectAttributes?: Record<string, any>, assignmentHooks?: IAssignmentHooks | undefined, obfuscated?: boolean): object | null; | ||
private rethrowIfNotGraceful; | ||
@@ -52,0 +52,0 @@ private getAssignmentVariation; |
@@ -6,2 +6,3 @@ "use strict"; | ||
const eppo_value_1 = require("../eppo_value"); | ||
const obfuscation_1 = require("../obfuscation"); | ||
const rule_evaluator_1 = require("../rule_evaluator"); | ||
@@ -19,7 +20,6 @@ const shard_1 = require("../shard"); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
subjectAttributes = {}, assignmentHooks) { | ||
subjectAttributes = {}, assignmentHooks, obfuscated = false) { | ||
var _a; | ||
try { | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks) | ||
.stringValue) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated).stringValue) !== null && _a !== void 0 ? _a : null); | ||
} | ||
@@ -32,6 +32,6 @@ catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
subjectAttributes = {}, assignmentHooks) { | ||
subjectAttributes = {}, assignmentHooks, obfuscated = false) { | ||
var _a; | ||
try { | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, eppo_value_1.ValueType.StringType).stringValue) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated, eppo_value_1.ValueType.StringType).stringValue) !== null && _a !== void 0 ? _a : null); | ||
} | ||
@@ -44,6 +44,6 @@ catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
subjectAttributes = {}, assignmentHooks) { | ||
subjectAttributes = {}, assignmentHooks, obfuscated = false) { | ||
var _a; | ||
try { | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, eppo_value_1.ValueType.BoolType).boolValue) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated, eppo_value_1.ValueType.BoolType).boolValue) !== null && _a !== void 0 ? _a : null); | ||
} | ||
@@ -54,6 +54,6 @@ catch (error) { | ||
} | ||
getNumericAssignment(subjectKey, flagKey, subjectAttributes, assignmentHooks) { | ||
getNumericAssignment(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated = false) { | ||
var _a; | ||
try { | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, eppo_value_1.ValueType.NumericType).numericValue) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated, eppo_value_1.ValueType.NumericType).numericValue) !== null && _a !== void 0 ? _a : null); | ||
} | ||
@@ -66,6 +66,6 @@ catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
subjectAttributes = {}, assignmentHooks) { | ||
subjectAttributes = {}, assignmentHooks, obfuscated = false) { | ||
var _a; | ||
try { | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, eppo_value_1.ValueType.JSONType).stringValue) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated, eppo_value_1.ValueType.JSONType).stringValue) !== null && _a !== void 0 ? _a : null); | ||
} | ||
@@ -78,6 +78,6 @@ catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
subjectAttributes = {}, assignmentHooks) { | ||
subjectAttributes = {}, assignmentHooks, obfuscated = false) { | ||
var _a; | ||
try { | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, eppo_value_1.ValueType.JSONType).objectValue) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.getAssignmentVariation(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated, eppo_value_1.ValueType.JSONType).objectValue) !== null && _a !== void 0 ? _a : null); | ||
} | ||
@@ -97,4 +97,4 @@ catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
subjectAttributes = {}, assignmentHooks, valueType) { | ||
const { allocationKey, assignment } = this.getAssignmentInternal(subjectKey, flagKey, subjectAttributes, assignmentHooks, valueType); | ||
subjectAttributes = {}, assignmentHooks, obfuscated, valueType) { | ||
const { allocationKey, assignment } = this.getAssignmentInternal(subjectKey, flagKey, subjectAttributes, assignmentHooks, obfuscated, valueType); | ||
assignmentHooks === null || assignmentHooks === void 0 ? void 0 : assignmentHooks.onPostAssignment(flagKey, subjectKey, assignment, allocationKey); | ||
@@ -105,7 +105,7 @@ if (!assignment.isNullType() && allocationKey !== null) | ||
} | ||
getAssignmentInternal(subjectKey, flagKey, subjectAttributes = {}, assignmentHooks, expectedValueType) { | ||
getAssignmentInternal(subjectKey, flagKey, subjectAttributes = {}, assignmentHooks, obfuscated, expectedValueType) { | ||
(0, validation_1.validateNotBlank)(subjectKey, 'Invalid argument: subjectKey cannot be blank'); | ||
(0, validation_1.validateNotBlank)(flagKey, 'Invalid argument: flagKey cannot be blank'); | ||
const nullAssignment = { allocationKey: null, assignment: eppo_value_1.EppoValue.Null() }; | ||
const experimentConfig = this.configurationStore.get(flagKey); | ||
const experimentConfig = this.configurationStore.get(obfuscated ? (0, obfuscation_1.getMD5Hash)(flagKey) : flagKey); | ||
const allowListOverride = this.getSubjectVariationOverride(subjectKey, experimentConfig, expectedValueType); | ||
@@ -129,3 +129,3 @@ if (!allowListOverride.isNullType()) { | ||
// Attempt to match a rule from the list. | ||
const matchedRule = (0, rule_evaluator_1.findMatchingRule)(subjectAttributes || {}, experimentConfig.rules); | ||
const matchedRule = (0, rule_evaluator_1.findMatchingRule)(subjectAttributes || {}, experimentConfig.rules, obfuscated); | ||
if (!matchedRule) | ||
@@ -132,0 +132,0 @@ return nullAssignment; |
import { IRule } from './dto/rule-dto'; | ||
export declare function findMatchingRule(subjectAttributes: Record<string, any>, rules: IRule[]): IRule | null; | ||
export declare function findMatchingRule(subjectAttributes: Record<string, any>, rules: IRule[], obfuscated: boolean): IRule | null; | ||
//# sourceMappingURL=rule_evaluator.d.ts.map |
@@ -6,5 +6,6 @@ "use strict"; | ||
const rule_dto_1 = require("./dto/rule-dto"); | ||
function findMatchingRule(subjectAttributes, rules) { | ||
const obfuscation_1 = require("./obfuscation"); | ||
function findMatchingRule(subjectAttributes, rules, obfuscated) { | ||
for (const rule of rules) { | ||
if (matchesRule(subjectAttributes, rule)) { | ||
if (matchesRule(subjectAttributes, rule, obfuscated)) { | ||
return rule; | ||
@@ -16,8 +17,10 @@ } | ||
exports.findMatchingRule = findMatchingRule; | ||
function matchesRule(subjectAttributes, rule) { | ||
const conditionEvaluations = evaluateRuleConditions(subjectAttributes, rule.conditions); | ||
function matchesRule(subjectAttributes, rule, obfuscated) { | ||
const conditionEvaluations = evaluateRuleConditions(subjectAttributes, rule.conditions, obfuscated); | ||
return !conditionEvaluations.includes(false); | ||
} | ||
function evaluateRuleConditions(subjectAttributes, conditions) { | ||
return conditions.map((condition) => evaluateCondition(subjectAttributes, condition)); | ||
function evaluateRuleConditions(subjectAttributes, conditions, obfuscated) { | ||
return conditions.map((condition) => obfuscated | ||
? evaluateObfuscatedCondition(subjectAttributes, condition) | ||
: evaluateCondition(subjectAttributes, condition)); | ||
} | ||
@@ -39,5 +42,5 @@ function evaluateCondition(subjectAttributes, condition) { | ||
case rule_dto_1.OperatorType.ONE_OF: | ||
return isOneOf(value, condition.value); | ||
return isOneOf(value.toString().toLowerCase(), condition.value.map((value) => value.toLowerCase())); | ||
case rule_dto_1.OperatorType.NOT_ONE_OF: | ||
return isNotOneOf(value, condition.value); | ||
return isNotOneOf(value.toString().toLowerCase(), condition.value.map((value) => value.toLowerCase())); | ||
} | ||
@@ -47,10 +50,33 @@ } | ||
} | ||
function evaluateObfuscatedCondition(subjectAttributes, condition) { | ||
const hashedSubjectAttributes = Object.entries(subjectAttributes).reduce((accum, [key, val]) => (Object.assign({ [(0, obfuscation_1.getMD5Hash)(key)]: val }, accum)), {}); | ||
const value = hashedSubjectAttributes[condition.attribute]; | ||
if (value != null) { | ||
switch (condition.operator) { | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.GTE): | ||
return compareNumber(value, Number((0, obfuscation_1.decodeBase64)(condition.value)), (a, b) => a >= b); | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.GT): | ||
return compareNumber(value, Number((0, obfuscation_1.decodeBase64)(condition.value)), (a, b) => a > b); | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.LTE): | ||
return compareNumber(value, Number((0, obfuscation_1.decodeBase64)(condition.value)), (a, b) => a <= b); | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.LT): | ||
return compareNumber(value, Number((0, obfuscation_1.decodeBase64)(condition.value)), (a, b) => a < b); | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.MATCHES): | ||
return new RegExp((0, obfuscation_1.decodeBase64)(condition.value)).test(value); | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.ONE_OF): | ||
return isOneOf((0, obfuscation_1.getMD5Hash)(value.toString().toLowerCase()), condition.value); | ||
case (0, obfuscation_1.getMD5Hash)(rule_dto_1.OperatorType.NOT_ONE_OF): | ||
return isNotOneOf((0, obfuscation_1.getMD5Hash)(value.toString().toLowerCase()), condition.value); | ||
} | ||
} | ||
return false; | ||
} | ||
function isOneOf(attributeValue, conditionValue) { | ||
return getMatchingStringValues(attributeValue.toString(), conditionValue).length > 0; | ||
return getMatchingStringValues(attributeValue, conditionValue).length > 0; | ||
} | ||
function isNotOneOf(attributeValue, conditionValue) { | ||
return getMatchingStringValues(attributeValue.toString(), conditionValue).length === 0; | ||
return getMatchingStringValues(attributeValue, conditionValue).length === 0; | ||
} | ||
function getMatchingStringValues(attributeValue, conditionValues) { | ||
return conditionValues.filter((value) => value.toLowerCase() === attributeValue.toLowerCase()); | ||
return conditionValues.filter((value) => value === attributeValue); | ||
} | ||
@@ -57,0 +83,0 @@ function compareNumber(attributeValue, conditionValue, compareFn) { |
{ | ||
"name": "@eppo/js-client-sdk-common", | ||
"version": "1.5.2", | ||
"version": "1.6.0", | ||
"description": "Eppo SDK for client-side JavaScript applications (base for both web and react native)", | ||
@@ -24,3 +24,4 @@ "main": "dist/index.js", | ||
"test": "yarn test:unit", | ||
"test:unit": "NODE_ENV=test jest '.*\\.spec\\.ts'" | ||
"test:unit": "NODE_ENV=test jest '.*\\.spec\\.ts'", | ||
"obfuscate-mock-rac": "ts-node test/writeObfuscatedMockRac" | ||
}, | ||
@@ -56,2 +57,3 @@ "jsdelivr": "dist/eppo-sdk.js", | ||
"ts-loader": "^9.3.1", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.7.4", | ||
@@ -58,0 +60,0 @@ "webpack": "^5.73.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
166966
73
848
22