@splitsoftware/splitio-commons 3.1.0 → 3.1.1-rc.1

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.
Files changed (35) hide show
  1. package/CHANGES.txt +4 -0
  2. package/cjs/evaluator/condition/index.js +1 -1
  3. package/cjs/evaluator/index.js +26 -46
  4. package/cjs/listeners/browser.js +2 -2
  5. package/cjs/sdkClient/client.js +18 -17
  6. package/cjs/services/authProvider.js +1 -1
  7. package/cjs/storages/utils.js +1 -0
  8. package/cjs/sync/submitters/impressionsSubmitter.js +5 -4
  9. package/esm/evaluator/condition/index.js +1 -1
  10. package/esm/evaluator/index.js +26 -46
  11. package/esm/listeners/browser.js +2 -2
  12. package/esm/sdkClient/client.js +18 -17
  13. package/esm/services/authProvider.js +1 -1
  14. package/esm/storages/utils.js +1 -0
  15. package/esm/sync/submitters/impressionsSubmitter.js +5 -4
  16. package/package.json +1 -1
  17. package/src/dtos/types.ts +7 -0
  18. package/src/evaluator/Engine.ts +3 -3
  19. package/src/evaluator/condition/index.ts +2 -2
  20. package/src/evaluator/index.ts +33 -79
  21. package/src/evaluator/types.ts +3 -6
  22. package/src/listeners/browser.ts +2 -2
  23. package/src/sdkClient/client.ts +24 -25
  24. package/src/sdkFactory/types.ts +0 -4
  25. package/src/services/authProvider.ts +1 -1
  26. package/src/storages/utils.ts +1 -0
  27. package/src/sync/submitters/impressionsSubmitter.ts +6 -6
  28. package/src/sync/submitters/types.ts +2 -1
  29. package/types/splitio.d.ts +1 -171
  30. package/cjs/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +0 -70
  31. package/cjs/evaluator/fallbackConfigsCalculator/index.js +0 -25
  32. package/esm/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +0 -64
  33. package/esm/evaluator/fallbackConfigsCalculator/index.js +0 -21
  34. package/src/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.ts +0 -76
  35. package/src/evaluator/fallbackConfigsCalculator/index.ts +0 -24
@@ -4,7 +4,7 @@ import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
4
4
  /**
5
5
  * Converts `impressions` data from cache into request payload.
6
6
  */
7
- export function fromImpressionsCollector(sendLabels, entityType, data) {
7
+ export function fromImpressionsCollector(sendLabels, data) {
8
8
  var groupedByFeature = groupBy(data, 'feature');
9
9
  var dto = [];
10
10
  forOwn(groupedByFeature, function (value, name) {
@@ -20,7 +20,8 @@ export function fromImpressionsCollector(sendLabels, entityType, data) {
20
20
  b: entry.bucketingKey,
21
21
  pt: entry.pt,
22
22
  properties: entry.properties,
23
- et: entityType, // Definition type
23
+ // @ts-expect-error - entityType is not yet public. @TODO: add to SplitIO.ImpressionDTO type
24
+ et: entry.entityType, // Definition type
24
25
  };
25
26
  })
26
27
  });
@@ -31,9 +32,9 @@ export function fromImpressionsCollector(sendLabels, entityType, data) {
31
32
  * Submitter that periodically posts impressions data
32
33
  */
33
34
  export function impressionsSubmitterFactory(params) {
34
- var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.serviceApi.postTestImpressionsBulk, impressions = params.storage.impressions, entityType = params.entityType;
35
+ var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.serviceApi.postTestImpressionsBulk, impressions = params.storage.impressions;
35
36
  // retry impressions only once.
36
- var syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled, entityType), 1);
37
+ var syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
37
38
  // register impressions submitter to be executed when impressions cache is full
38
39
  impressions.setOnFullQueueCb(function () {
39
40
  if (syncTask.isRunning()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "3.1.0",
3
+ "version": "3.1.1-rc.1",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
package/src/dtos/types.ts CHANGED
@@ -215,6 +215,9 @@ export interface IRBSegment extends TargetingEntity {
215
215
  } | null
216
216
  }
217
217
 
218
+ export type ConfigType = 'standard' | 'ai';
219
+ export type ConfigSubtype = 'llm_call';
220
+
218
221
  export interface IDefinition extends TargetingEntity {
219
222
  trafficTypeName: string;
220
223
  sets?: string[] | null;
@@ -231,6 +234,10 @@ export interface IDefinition extends TargetingEntity {
231
234
  configurations?: {
232
235
  [treatmentName: string]: string | SplitIO.JsonObject
233
236
  } | null;
237
+ /** Definition classification. Absent means a feature flag. */
238
+ type?: ConfigType;
239
+ /** Only meaningful when `type === 'AI'`. */
240
+ subtype?: ConfigSubtype;
234
241
  }
235
242
 
236
243
  /** Interface of the parsed JSON response of `/splitChanges` */
@@ -7,12 +7,12 @@ import { CONTROL } from '../utils/constants';
7
7
  import { IDefinition, MaybeThenable } from '../dtos/types';
8
8
  import SplitIO from '../../types/splitio';
9
9
  import { IStorageAsync, IStorageSync } from '../storages/types';
10
- import { IEvaluation, IEvaluationResult, IDefinitionEvaluator } from './types';
10
+ import { IEvaluation, IDefinitionEvaluator } from './types';
11
11
  import { ILogger } from '../logger/types';
12
12
  import { ENGINE_DEFAULT } from '../logger/constants';
13
13
  import { prerequisitesMatcherContext } from './matchers/prerequisites';
14
14
 
15
- function evaluationResult(result: IEvaluation | undefined, defaultTreatment: string): IEvaluationResult {
15
+ function evaluationResult(result: IEvaluation | undefined, defaultTreatment: string): IEvaluation {
16
16
  return {
17
17
  treatment: get(result, 'treatment', defaultTreatment),
18
18
  label: get(result, 'label', NO_CONDITION_MATCH)
@@ -29,7 +29,7 @@ export function engineParser(log: ILogger, split: IDefinition, storage: IStorage
29
29
 
30
30
  return {
31
31
 
32
- getTreatment(key: SplitIO.SplitKey, attributes: SplitIO.Attributes | undefined, splitEvaluator: IDefinitionEvaluator): MaybeThenable<IEvaluationResult> {
32
+ getTreatment(key: SplitIO.SplitKey, attributes: SplitIO.Attributes | undefined, splitEvaluator: IDefinitionEvaluator): MaybeThenable<IEvaluation> {
33
33
 
34
34
  const parsedKey = keyParser(key);
35
35
 
@@ -29,9 +29,9 @@ export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.S
29
29
  // Whitelisting has more priority than traffic allocation, so we don't apply this filtering to those conditions.
30
30
  if (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation!, key.bucketingKey, trafficAllocationSeed!)) {
31
31
  return {
32
- treatment: undefined, // treatment value is assigned later
32
+ // treatment value is assigned later, at Engine's evaluationResult
33
33
  label: NOT_IN_SPLIT
34
- };
34
+ } as IEvaluation;
35
35
  }
36
36
 
37
37
  // matcherEvaluator could be Async, this relays on matchers return value, so we need
@@ -4,11 +4,12 @@ import { EXCEPTION, NO_CONDITION_MATCH, DEFINITION_NOT_FOUND } from '../utils/la
4
4
  import { CONTROL } from '../utils/constants';
5
5
  import { IDefinition, MaybeThenable } from '../dtos/types';
6
6
  import { IStorageAsync, IStorageSync } from '../storages/types';
7
- import { IEvaluationResult } from './types';
7
+ import { IEvaluation } from './types';
8
8
  import SplitIO from '../../types/splitio';
9
9
  import { ILogger } from '../logger/types';
10
10
  import { returnSetsUnion, setToArray } from '../utils/lang/sets';
11
11
  import { WARN_FLAGSET_WITHOUT_FLAGS } from '../logger/constants';
12
+ import { objectAssign } from '../utils/lang/objectAssign';
12
13
 
13
14
  const EVALUATION_EXCEPTION = {
14
15
  treatment: CONTROL,
@@ -23,7 +24,7 @@ const EVALUATION_DEFINITION_NOT_FOUND = {
23
24
  };
24
25
 
25
26
  function treatmentsException(definitionNames: string[]) {
26
- const evaluations: Record<string, IEvaluationResult> = {};
27
+ const evaluations: Record<string, IEvaluation> = {};
27
28
  definitionNames.forEach(definitionName => {
28
29
  evaluations[definitionName] = EVALUATION_EXCEPTION;
29
30
  });
@@ -36,8 +37,7 @@ export function evaluateFeature(
36
37
  definitionName: string,
37
38
  attributes: SplitIO.Attributes | undefined,
38
39
  storage: IStorageSync | IStorageAsync,
39
- options?: SplitIO.EvaluationOptions
40
- ): MaybeThenable<IEvaluationResult> {
40
+ ): MaybeThenable<IEvaluation> {
41
41
  let definition;
42
42
 
43
43
  try {
@@ -47,29 +47,14 @@ export function evaluateFeature(
47
47
  return EVALUATION_EXCEPTION;
48
48
  }
49
49
 
50
- if (thenable(definition)) {
51
- return definition.then((definition) => getEvaluation(
52
- log,
53
- key,
54
- definition,
55
- attributes,
56
- storage,
57
- options,
58
- )).catch(
59
- // Exception on async storage. For example, when the storage is redis or
60
- // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
61
- () => EVALUATION_EXCEPTION
62
- );
63
- }
64
-
65
- return getEvaluation(
66
- log,
67
- key,
68
- definition,
69
- attributes,
70
- storage,
71
- options,
72
- );
50
+ return thenable(definition) ?
51
+ definition.then((definition) => getEvaluation(log, key, definition, attributes, storage))
52
+ .catch(
53
+ // Exception on async storage. For example, when the storage is redis or
54
+ // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
55
+ () => EVALUATION_EXCEPTION
56
+ ) :
57
+ getEvaluation(log, key, definition, attributes, storage);
73
58
  }
74
59
 
75
60
  export function evaluateFeatures(
@@ -78,8 +63,7 @@ export function evaluateFeatures(
78
63
  definitionNames: string[],
79
64
  attributes: SplitIO.Attributes | undefined,
80
65
  storage: IStorageSync | IStorageAsync,
81
- options?: SplitIO.EvaluationOptions,
82
- ): MaybeThenable<Record<string, IEvaluationResult>> {
66
+ ): MaybeThenable<Record<string, IEvaluation>> {
83
67
  let definitions;
84
68
 
85
69
  try {
@@ -90,13 +74,13 @@ export function evaluateFeatures(
90
74
  }
91
75
 
92
76
  return thenable(definitions) ?
93
- definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage, options))
94
- .catch(() => {
77
+ definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage))
78
+ .catch(
95
79
  // Exception on async storage. For example, when the storage is redis or
96
80
  // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
97
- return treatmentsException(definitionNames);
98
- }) :
99
- getEvaluations(log, key, definitionNames, definitions, attributes, storage, options);
81
+ () => treatmentsException(definitionNames)
82
+ ) :
83
+ getEvaluations(log, key, definitionNames, definitions, attributes, storage);
100
84
  }
101
85
 
102
86
  export function evaluateFeaturesByFlagSets(
@@ -106,8 +90,7 @@ export function evaluateFeaturesByFlagSets(
106
90
  attributes: SplitIO.Attributes | undefined,
107
91
  storage: IStorageSync | IStorageAsync,
108
92
  method: string,
109
- options?: SplitIO.EvaluationOptions,
110
- ): MaybeThenable<Record<string, IEvaluationResult>> {
93
+ ): MaybeThenable<Record<string, IEvaluation>> {
111
94
  let storedFlagNames: MaybeThenable<Set<string>[]>;
112
95
 
113
96
  function evaluate(featureFlagsByFlagSets: Set<string>[]) {
@@ -122,7 +105,7 @@ export function evaluateFeaturesByFlagSets(
122
105
  }
123
106
 
124
107
  return featureFlags.size ?
125
- evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage, options) :
108
+ evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
126
109
  {};
127
110
  }
128
111
 
@@ -137,9 +120,7 @@ export function evaluateFeaturesByFlagSets(
137
120
  // evaluate related features
138
121
  return thenable(storedFlagNames) ?
139
122
  storedFlagNames.then((storedFlagNames) => evaluate(storedFlagNames))
140
- .catch(() => {
141
- return {};
142
- }) :
123
+ .catch(() => ({})) :
143
124
  evaluate(storedFlagNames);
144
125
  }
145
126
 
@@ -149,31 +130,15 @@ function getEvaluation(
149
130
  definition: IDefinition | null,
150
131
  attributes: SplitIO.Attributes | undefined,
151
132
  storage: IStorageSync | IStorageAsync,
152
- options?: SplitIO.EvaluationOptions,
153
- ): MaybeThenable<IEvaluationResult> {
133
+ ): MaybeThenable<IEvaluation> {
154
134
 
155
135
  if (definition) {
156
136
  const split = engineParser(log, definition, storage);
157
137
  const evaluation = split.getTreatment(key, attributes, evaluateFeature);
158
138
 
159
- // If the storage is async and the evaluated definition uses segments or dependencies, evaluation is thenable
160
- if (thenable(evaluation)) {
161
- return evaluation.then(result => {
162
- result.changeNumber = definition.changeNumber;
163
- result.config = definition.configurations && definition.configurations[result.treatment] || null;
164
- // @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
165
- result.impressionsDisabled = options?.impressionsDisabled || definition.impressionsDisabled;
166
-
167
- return result;
168
- });
169
- } else {
170
- evaluation.changeNumber = definition.changeNumber;
171
- evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
172
- // @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
173
- evaluation.impressionsDisabled = options?.impressionsDisabled || definition.impressionsDisabled;
174
- }
175
-
176
- return evaluation;
139
+ return thenable(evaluation) ?
140
+ evaluation.then(result => objectAssign(result, { definition })) :
141
+ objectAssign(evaluation, { definition });
177
142
  }
178
143
 
179
144
  return EVALUATION_DEFINITION_NOT_FOUND;
@@ -186,26 +151,16 @@ function getEvaluations(
186
151
  definitions: Record<string, IDefinition | null>,
187
152
  attributes: SplitIO.Attributes | undefined,
188
153
  storage: IStorageSync | IStorageAsync,
189
- options?: SplitIO.EvaluationOptions,
190
- ): MaybeThenable<Record<string, IEvaluationResult>> {
191
- const result: Record<string, IEvaluationResult> = {};
154
+ ): MaybeThenable<Record<string, IEvaluation>> {
155
+ const result: Record<string, IEvaluation> = {};
192
156
  const thenables: Promise<void>[] = [];
193
157
  definitionNames.forEach(definitionName => {
194
- const evaluation = getEvaluation(
195
- log,
196
- key,
197
- definitions[definitionName],
198
- attributes,
199
- storage,
200
- options
201
- );
202
- if (thenable(evaluation)) {
158
+ const evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
159
+ thenable(evaluation) ?
203
160
  thenables.push(evaluation.then(res => {
204
161
  result[definitionName] = res;
205
- }));
206
- } else {
162
+ })) :
207
163
  result[definitionName] = evaluation;
208
- }
209
164
  });
210
165
 
211
166
  return thenables.length > 0 ? Promise.all(thenables).then(() => result) : result;
@@ -214,7 +169,7 @@ function getEvaluations(
214
169
  export function evaluateDefaultTreatment(
215
170
  definitionName: string,
216
171
  storage: IStorageSync | IStorageAsync,
217
- ): MaybeThenable<IEvaluationResult> {
172
+ ): MaybeThenable<IEvaluation> {
218
173
  let definition;
219
174
 
220
175
  try {
@@ -230,13 +185,12 @@ export function evaluateDefaultTreatment(
230
185
 
231
186
  function getDefaultTreatment(
232
187
  definition: IDefinition | null,
233
- ): MaybeThenable<IEvaluationResult> {
188
+ ): MaybeThenable<IEvaluation> {
234
189
  if (definition) {
235
190
  return {
236
191
  treatment: definition.defaultTreatment,
237
192
  label: NO_CONDITION_MATCH, // "default rule"
238
- config: definition.configurations && definition.configurations[definition.defaultTreatment] || null,
239
- changeNumber: definition.changeNumber
193
+ definition,
240
194
  };
241
195
  }
242
196
 
@@ -1,4 +1,4 @@
1
- import { IBetweenMatcherData, IBetweenStringMatcherData, IDependencyMatcherData, MaybeThenable } from '../dtos/types';
1
+ import { IBetweenMatcherData, IBetweenStringMatcherData, IDefinition, IDependencyMatcherData, MaybeThenable } from '../dtos/types';
2
2
  import { IStorageAsync, IStorageSync } from '../storages/types';
3
3
  import SplitIO from '../../types/splitio';
4
4
  import { ILogger } from '../logger/types';
@@ -19,14 +19,11 @@ export interface IMatcherDto {
19
19
  }
20
20
 
21
21
  export interface IEvaluation {
22
- treatment?: string,
22
+ treatment: string,
23
23
  label: string,
24
- changeNumber?: number,
25
- config?: string | null | SplitIO.JsonObject
24
+ definition?: IDefinition
26
25
  }
27
26
 
28
- export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }
29
-
30
27
  export type IDefinitionEvaluator = (log: ILogger, key: SplitIO.SplitKey, definitionName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
31
28
 
32
29
  export type IEvaluator = (key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => MaybeThenable<IEvaluation | boolean | undefined>
@@ -28,14 +28,14 @@ export class BrowserSignalListener implements ISignalListener {
28
28
  private serviceApi: IServiceApi;
29
29
  private fromImpressionsCollector: (data: SplitIO.ImpressionDTO[]) => ImpressionsPayload;
30
30
 
31
- constructor({ syncManager, settings, storage, serviceApi, entityType }: ISdkFactoryContextSync) {
31
+ constructor({ syncManager, settings, storage, serviceApi }: ISdkFactoryContextSync) {
32
32
  this.syncManager = syncManager;
33
33
  this.settings = settings;
34
34
  this.storage = storage;
35
35
  this.serviceApi = serviceApi;
36
36
  this.flushData = this.flushData.bind(this);
37
37
  this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
38
- this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled, entityType);
38
+ this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
39
39
  }
40
40
 
41
41
  /**
@@ -4,7 +4,7 @@ import { getMatching, getBucketing } from '../utils/key';
4
4
  import { validateDefinitionExistence } from '../utils/inputValidation/definitionExistence';
5
5
  import { SDK_NOT_READY } from '../utils/labels';
6
6
  import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, TREATMENTS_BY_FLAGSETS, TREATMENTS_BY_FLAGSET, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENT_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS } from '../utils/constants';
7
- import { IEvaluationResult } from '../evaluator/types';
7
+ import { IEvaluation } from '../evaluator/types';
8
8
  import SplitIO from '../../types/splitio';
9
9
  import { IMPRESSION_QUEUEING } from '../logger/constants';
10
10
  import { ISdkFactoryContext } from '../sdkFactory/types';
@@ -16,17 +16,17 @@ import { trackMethodFactory } from './trackMethod';
16
16
  const treatmentNotReady = { treatment: CONTROL, label: SDK_NOT_READY };
17
17
 
18
18
  function treatmentsNotReady(featureFlagNames: string[]) {
19
- const evaluations: Record<string, IEvaluationResult> = {};
19
+ const evaluations: Record<string, IEvaluation> = {};
20
20
  featureFlagNames.forEach(featureFlagName => {
21
21
  evaluations[featureFlagName] = treatmentNotReady;
22
22
  });
23
23
  return evaluations;
24
24
  }
25
25
 
26
- export function stringify(options?: SplitIO.EvaluationOptions) {
27
- if (options && options.properties) {
26
+ export function stringify(properties?: SplitIO.Properties) {
27
+ if (properties) {
28
28
  try {
29
- return JSON.stringify(options.properties);
29
+ return JSON.stringify(properties);
30
30
  } catch { /* JSON.stringify should never throw with validated options, but handling just in case */ }
31
31
  }
32
32
  }
@@ -42,9 +42,9 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
42
42
  function getTreatment(key: SplitIO.SplitKey, featureFlagName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENT) {
43
43
  const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
44
44
 
45
- const wrapUp = (evaluationResult: IEvaluationResult) => {
45
+ const wrapUp = (evaluationResult: IEvaluation) => {
46
46
  const queue: ImpressionDecorated[] = [];
47
- const treatment = processEvaluation(evaluationResult, featureFlagName, key, stringify(options), withConfig, methodName, queue);
47
+ const treatment = processEvaluation(evaluationResult, featureFlagName, key, withConfig, methodName, queue, options);
48
48
  impressionsTracker.track(queue, attributes);
49
49
 
50
50
  stopTelemetryTracker(queue[0] && queue[0].imp.label);
@@ -52,7 +52,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
52
52
  };
53
53
 
54
54
  const evaluation = readinessManager.isReadyFromCache() ?
55
- evaluateFeature(log, key, featureFlagName, attributes, storage, options) :
55
+ evaluateFeature(log, key, featureFlagName, attributes, storage) :
56
56
  isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
57
57
  Promise.resolve(treatmentNotReady) :
58
58
  treatmentNotReady;
@@ -67,12 +67,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
67
67
  function getTreatments(key: SplitIO.SplitKey, featureFlagNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENTS) {
68
68
  const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
69
69
 
70
- const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
70
+ const wrapUp = (evaluationResults: Record<string, IEvaluation>) => {
71
71
  const queue: ImpressionDecorated[] = [];
72
72
  const treatments: SplitIO.Treatments | SplitIO.TreatmentsWithConfig = {};
73
- const properties = stringify(options);
74
73
  Object.keys(evaluationResults).forEach(featureFlagName => {
75
- treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
74
+ treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
76
75
  });
77
76
  impressionsTracker.track(queue, attributes);
78
77
 
@@ -81,7 +80,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
81
80
  };
82
81
 
83
82
  const evaluations = readinessManager.isReadyFromCache() ?
84
- evaluateFeatures(log, key, featureFlagNames, attributes, storage, options) :
83
+ evaluateFeatures(log, key, featureFlagNames, attributes, storage) :
85
84
  isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
86
85
  Promise.resolve(treatmentsNotReady(featureFlagNames)) :
87
86
  treatmentsNotReady(featureFlagNames);
@@ -96,12 +95,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
96
95
  function getTreatmentsByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, method: Method = TREATMENTS_BY_FLAGSETS, methodName = GET_TREATMENTS_BY_FLAG_SETS) {
97
96
  const stopTelemetryTracker = telemetryTracker.trackEval(method);
98
97
 
99
- const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
98
+ const wrapUp = (evaluationResults: Record<string, IEvaluation>) => {
100
99
  const queue: ImpressionDecorated[] = [];
101
100
  const treatments: SplitIO.Treatments | SplitIO.TreatmentsWithConfig = {};
102
- const properties = stringify(options);
103
101
  Object.keys(evaluationResults).forEach(featureFlagName => {
104
- treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
102
+ treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
105
103
  });
106
104
  impressionsTracker.track(queue, attributes);
107
105
 
@@ -110,7 +108,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
110
108
  };
111
109
 
112
110
  const evaluations = readinessManager.isReadyFromCache() ?
113
- evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName, options) :
111
+ evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName) :
114
112
  isAsync ?
115
113
  Promise.resolve({}) :
116
114
  {};
@@ -132,19 +130,20 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
132
130
 
133
131
  // Internal function
134
132
  function processEvaluation(
135
- evaluation: IEvaluationResult,
133
+ evaluation: IEvaluation,
136
134
  featureFlagName: string,
137
135
  key: SplitIO.SplitKey,
138
- properties: string | undefined,
139
136
  withConfig: boolean,
140
137
  invokingMethodName: string,
141
- queue: ImpressionDecorated[]
138
+ queue: ImpressionDecorated[],
139
+ options: SplitIO.EvaluationOptions = {}
142
140
  ): SplitIO.Treatment | SplitIO.TreatmentWithConfig {
143
141
  const matchingKey = getMatching(key);
144
142
  const bucketingKey = getBucketing(key);
145
143
 
146
- const { changeNumber, impressionsDisabled } = evaluation;
147
- let { treatment, label, config = null } = evaluation;
144
+ const { definition } = evaluation;
145
+ let { treatment, label } = evaluation;
146
+ let config = definition?.configurations?.[treatment] || null;
148
147
 
149
148
  if (treatment === CONTROL) {
150
149
  const fallbackTreatment = fallbackCalculator(featureFlagName, label);
@@ -163,10 +162,10 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
163
162
  time: Date.now(),
164
163
  bucketingKey,
165
164
  label,
166
- changeNumber: changeNumber as number,
167
- properties
168
- },
169
- disabled: impressionsDisabled
165
+ changeNumber: definition!.changeNumber,
166
+ properties: stringify(options.properties)
167
+ }, // @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
168
+ disabled: options.impressionsDisabled || definition!.impressionsDisabled
170
169
  });
171
170
  }
172
171
 
@@ -43,9 +43,6 @@ export interface IPlatform {
43
43
  SignalListener?: new (params: ISdkFactoryContext) => ISignalListener, // Used by BrowserSignalListener
44
44
  }
45
45
 
46
- // Definition type
47
- export type EntityType = 'config' | 'flag';
48
-
49
46
  export interface ISdkFactoryContext {
50
47
  platform: IPlatform,
51
48
  sdkReadinessManager: ISdkReadinessManager,
@@ -59,7 +56,6 @@ export interface ISdkFactoryContext {
59
56
  syncManager?: ISyncManager,
60
57
  clients: Record<string, SplitIO.IBasicClient>,
61
58
  fallbackCalculator: IFallbackCalculator,
62
- entityType?: EntityType
63
59
  }
64
60
 
65
61
  export interface ISdkFactoryContextSync extends ISdkFactoryContext {
@@ -28,7 +28,7 @@ export function authProviderFactory(settings: ISettings, splitHttpClient: ISplit
28
28
  const { urls, log } = settings;
29
29
 
30
30
  function fetchAuth() {
31
- let url = `${urls.auth}/api/v3/auth?capabilities=config`;
31
+ let url = `${urls.auth}/api/v3/auth?capabilities=config,aiconfig`;
32
32
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN), false, true);
33
33
  }
34
34
 
@@ -31,6 +31,7 @@ export function impressionsToJSON(impressions: SplitIO.ImpressionDTO[], metadata
31
31
  m: impression.time,
32
32
  pt: impression.pt,
33
33
  properties: impression.properties
34
+ // @TODO set entityType
34
35
  }
35
36
  };
36
37
 
@@ -3,12 +3,12 @@ import SplitIO from '../../../types/splitio';
3
3
  import { submitterFactory } from './submitter';
4
4
  import { ImpressionsPayload } from './types';
5
5
  import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
6
- import { EntityType, ISdkFactoryContextSync } from '../../sdkFactory/types';
6
+ import { ISdkFactoryContextSync } from '../../sdkFactory/types';
7
7
 
8
8
  /**
9
9
  * Converts `impressions` data from cache into request payload.
10
10
  */
11
- export function fromImpressionsCollector(sendLabels: boolean, entityType: EntityType | undefined, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
11
+ export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
12
12
  let groupedByFeature = groupBy(data, 'feature');
13
13
  let dto: ImpressionsPayload = [];
14
14
 
@@ -25,7 +25,8 @@ export function fromImpressionsCollector(sendLabels: boolean, entityType: Entity
25
25
  b: entry.bucketingKey, // Bucketing Key
26
26
  pt: entry.pt, // Previous time
27
27
  properties: entry.properties, // Properties
28
- et: entityType, // Definition type
28
+ // @ts-expect-error - entityType is not yet public. @TODO: add to SplitIO.ImpressionDTO type
29
+ et: entry.entityType, // Definition type
29
30
  };
30
31
  })
31
32
  });
@@ -42,12 +43,11 @@ export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) {
42
43
  const {
43
44
  settings: { log, scheduler: { impressionsRefreshRate }, core: { labelsEnabled } },
44
45
  serviceApi: { postTestImpressionsBulk },
45
- storage: { impressions },
46
- entityType
46
+ storage: { impressions }
47
47
  } = params;
48
48
 
49
49
  // retry impressions only once.
50
- const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled, entityType), 1);
50
+ const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
51
51
 
52
52
  // register impressions submitter to be executed when impressions cache is full
53
53
  impressions.setOnFullQueueCb(() => {
@@ -2,7 +2,8 @@
2
2
  import { IMetadata } from '../../dtos/types';
3
3
  import SplitIO from '../../../types/splitio';
4
4
  import { ISyncTask } from '../types';
5
- import { EntityType } from '../../sdkFactory/types';
5
+
6
+ type EntityType = 'config' | 'flag' | 'ai-config';
6
7
 
7
8
  type ImpressionPayload = {
8
9
  /** Matching Key */