Skip to content
6 changes: 2 additions & 4 deletions src/evaluator/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ export function engineParser(log: ILogger, split: ISplit, storage: IStorageSync

return {

getTreatment(key: SplitIO.SplitKey, attributes: SplitIO.Attributes | undefined, splitEvaluator: ISplitEvaluator): MaybeThenable<IEvaluationResult> {

const parsedKey = keyParser(key);
getTreatment(key: SplitIO.SplitKey | undefined, attributes: SplitIO.Attributes | undefined, splitEvaluator: ISplitEvaluator): MaybeThenable<IEvaluationResult> {

function evaluate(prerequisitesMet: boolean) {
if (!prerequisitesMet) {
Expand All @@ -42,7 +40,7 @@ export function engineParser(log: ILogger, split: ISplit, storage: IStorageSync
};
}

const evaluation = evaluator(parsedKey, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator) as MaybeThenable<IEvaluation>;
const evaluation = evaluator(key ? keyParser(key) : undefined, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator) as MaybeThenable<IEvaluation>;

return thenable(evaluation) ?
evaluation.then(result => evaluationResult(result, defaultTreatment)) :
Expand Down
2 changes: 1 addition & 1 deletion src/evaluator/combiners/ifelseif.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function ifElseIfCombinerContext(log: ILogger, predicates: IEvaluator[]):
return undefined;
}

function ifElseIfCombiner(key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
function ifElseIfCombiner(key?: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
// In Async environments we are going to have async predicates. There is none way to know
// before hand so we need to evaluate all the predicates, verify for thenables, and finally,
// define how to return the treatment (wrap result into a Promise or not).
Expand Down
4 changes: 2 additions & 2 deletions src/evaluator/condition/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ function match(log: ILogger, matchingResult: boolean, bucketingKey: string | und
// Condition factory
export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.SplitKeyObject, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<boolean>, treatments?: { getTreatmentFor: (x: number) => string }, label?: string, conditionType?: 'ROLLOUT' | 'WHITELIST'): IEvaluator {

return function conditionEvaluator(key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
return function conditionEvaluator(key?: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {

// Whitelisting has more priority than traffic allocation, so we don't apply this filtering to those conditions.
if (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation!, key.bucketingKey, trafficAllocationSeed!)) {
if (!key || (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation!, key.bucketingKey, trafficAllocationSeed!))) {
return {
treatment: undefined, // treatment value is assigned later
label: NOT_IN_SPLIT
Expand Down
5 changes: 3 additions & 2 deletions src/evaluator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ function treatmentsException(splitNames: string[]) {
return evaluations;
}

// @TODO: test cases with no key
export function evaluateFeature(
log: ILogger,
key: SplitIO.SplitKey,
key: SplitIO.SplitKey | undefined,
splitName: string,
attributes: SplitIO.Attributes | undefined,
storage: IStorageSync | IStorageAsync,
Expand Down Expand Up @@ -139,7 +140,7 @@ export function evaluateFeaturesByFlagSets(

function getEvaluation(
log: ILogger,
key: SplitIO.SplitKey,
key: SplitIO.SplitKey | undefined,
splitJSON: ISplit | null,
attributes: SplitIO.Attributes | undefined,
storage: IStorageSync | IStorageAsync,
Expand Down
2 changes: 1 addition & 1 deletion src/evaluator/matchers/prerequisites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { IDependencyMatcherValue, ISplitEvaluator } from '../types';

export function prerequisitesMatcherContext(prerequisites: ISplit['prerequisites'], storage: IStorageSync | IStorageAsync, log: ILogger) {

return function prerequisitesMatcher({ key, attributes }: IDependencyMatcherValue, splitEvaluator: ISplitEvaluator): MaybeThenable<boolean> {
return function prerequisitesMatcher({ key, attributes }: Partial<IDependencyMatcherValue>, splitEvaluator: ISplitEvaluator): MaybeThenable<boolean> {

prerequisites = prerequisites == null ? [] : prerequisites;

Expand Down
4 changes: 2 additions & 2 deletions src/evaluator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export interface IEvaluation {

export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }

export type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
export type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey | undefined, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>

export type IEvaluator = (key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<IEvaluation | boolean | undefined>
export type IEvaluator = (key?: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<IEvaluation | boolean | undefined>

export type IMatcher = (value: string | number | boolean | string[] | IDependencyMatcherValue, splitEvaluator?: ISplitEvaluator) => MaybeThenable<boolean>
13 changes: 7 additions & 6 deletions src/sdkClient/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
const { log, mode } = settings;
const isAsync = isConsumerMode(mode);

function getTreatment(key: SplitIO.SplitKey, featureFlagName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENT) {
function getTreatment(key: SplitIO.SplitKey | undefined, featureFlagName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENT) {
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);

const wrapUp = (evaluationResult: IEvaluationResult) => {
Expand Down Expand Up @@ -134,15 +134,12 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
function processEvaluation(
evaluation: IEvaluationResult,
featureFlagName: string,
key: SplitIO.SplitKey,
key: SplitIO.SplitKey | undefined,
properties: string | undefined,
withConfig: boolean,
invokingMethodName: string,
queue: ImpressionDecorated[]
): SplitIO.Treatment | SplitIO.TreatmentWithConfig {
const matchingKey = getMatching(key);
const bucketingKey = getBucketing(key);

const { changeNumber, impressionsDisabled } = evaluation;
let { treatment, label, config = null } = evaluation;

Expand All @@ -153,7 +150,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
config = fallbackTreatment.config;
}

if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
// If no target/key, no impression is tracked
if (key && validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
const matchingKey = getMatching(key);
const bucketingKey = getBucketing(key);

log.info(IMPRESSION_QUEUEING, [featureFlagName, matchingKey, treatment, label]);
queue.push({
imp: {
Expand Down