@statsig/on-device-eval-core 3.26.0 → 3.28.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statsig/on-device-eval-core",
3
- "version": "3.26.0",
3
+ "version": "3.28.0",
4
4
  "license": "ISC",
5
5
  "homepage": "https://github.com/statsig-io/js-client-monorepo",
6
6
  "repository": {
@@ -9,8 +9,8 @@
9
9
  "directory": "packages/on-device-eval-core"
10
10
  },
11
11
  "dependencies": {
12
- "@statsig/client-core": "3.26.0",
13
- "@statsig/sha256": "3.26.0"
12
+ "@statsig/client-core": "3.28.0",
13
+ "@statsig/sha256": "3.28.0"
14
14
  },
15
15
  "type": "commonjs",
16
16
  "main": "./src/index.js",
@@ -1,4 +1,5 @@
1
- import { DynamicConfigEvaluation, EvaluationDetails, GateEvaluation, LayerEvaluation, ParamStoreConfig, StatsigUserInternal } from '@statsig/client-core';
1
+ import { DynamicConfigEvaluation, EvaluationDetails, GateEvaluation, LayerEvaluation, ParamStoreConfig, Spec, StatsigUserInternal } from '@statsig/client-core';
2
+ import { EvaluationResult } from './EvaluationResult';
2
3
  import { SpecStore } from './SpecStore';
3
4
  type DetailedEvaluation<T> = {
4
5
  evaluation: T | null;
@@ -15,9 +16,9 @@ export declare class Evaluator {
15
16
  config: ParamStoreConfig | null;
16
17
  details: EvaluationDetails;
17
18
  };
19
+ evaluateSpec(spec: Spec, user: StatsigUserInternal): EvaluationResult;
18
20
  private _getSpecAndDetails;
19
21
  private _getEvaluationDetails;
20
- private _evaluateSpec;
21
22
  private _evaluateRule;
22
23
  private _evaluateCondition;
23
24
  private _evaluateDelegate;
package/src/Evaluator.js CHANGED
@@ -15,7 +15,7 @@ class Evaluator {
15
15
  if (!spec) {
16
16
  return { evaluation: null, details };
17
17
  }
18
- const result = this._evaluateSpec(spec, user);
18
+ const result = this.evaluateSpec(spec, user);
19
19
  const evaluation = (0, EvaluationResult_1.resultToGateEval)(spec, result);
20
20
  this._handleUnsupportedEvaluation(result, details);
21
21
  return { evaluation, details };
@@ -25,7 +25,7 @@ class Evaluator {
25
25
  if (!spec) {
26
26
  return { evaluation: null, details };
27
27
  }
28
- const result = this._evaluateSpec(spec, user);
28
+ const result = this.evaluateSpec(spec, user);
29
29
  const evaluation = (0, EvaluationResult_1.resultToConfigEval)(spec, result);
30
30
  this._handleUnsupportedEvaluation(result, details);
31
31
  return { evaluation, details };
@@ -36,7 +36,7 @@ class Evaluator {
36
36
  if (!spec) {
37
37
  return { evaluation: null, details };
38
38
  }
39
- const result = this._evaluateSpec(spec, user);
39
+ const result = this.evaluateSpec(spec, user);
40
40
  const experimentName = (_a = result === null || result === void 0 ? void 0 : result.allocated_experiment_name) !== null && _a !== void 0 ? _a : '';
41
41
  const experimentSpec = this._store.getSpecAndSourceInfo('config', experimentName).spec;
42
42
  const evaluation = (0, EvaluationResult_1.resultToLayerEval)(spec, experimentSpec, result);
@@ -57,23 +57,7 @@ class Evaluator {
57
57
  details,
58
58
  };
59
59
  }
60
- _getSpecAndDetails(kind, name) {
61
- const specAndSourceInfo = this._store.getSpecAndSourceInfo(kind, name);
62
- const details = this._getEvaluationDetails(specAndSourceInfo);
63
- return { details, spec: specAndSourceInfo.spec };
64
- }
65
- _getEvaluationDetails(info) {
66
- const { source, lcut, receivedAt } = info;
67
- if (source === 'Uninitialized' || source === 'NoValues') {
68
- return { reason: source };
69
- }
70
- const subreason = ('spec' in info ? info.spec : info.paramStoreConfig) == null
71
- ? 'Unrecognized'
72
- : 'Recognized';
73
- const reason = `${source}:${subreason}`;
74
- return { reason, lcut, receivedAt };
75
- }
76
- _evaluateSpec(spec, user) {
60
+ evaluateSpec(spec, user) {
77
61
  const defaultValue = _isRecord(spec.defaultValue)
78
62
  ? spec.defaultValue
79
63
  : undefined;
@@ -84,12 +68,20 @@ class Evaluator {
84
68
  });
85
69
  }
86
70
  const exposures = [];
71
+ const seen = {};
87
72
  for (const rule of spec.rules) {
88
73
  const result = this._evaluateRule(rule, user);
89
74
  if (result.unsupported) {
90
75
  return result;
91
76
  }
92
- exposures.push(...result.secondary_exposures);
77
+ for (const exposure of result.secondary_exposures) {
78
+ const key = `${exposure.gate}|${exposure.gateValue}|${exposure.ruleID}`;
79
+ if (seen[key]) {
80
+ continue;
81
+ }
82
+ seen[key] = true;
83
+ exposures.push(exposure);
84
+ }
93
85
  if (!result.bool_value) {
94
86
  continue;
95
87
  }
@@ -115,6 +107,22 @@ class Evaluator {
115
107
  rule_id: 'default',
116
108
  });
117
109
  }
110
+ _getSpecAndDetails(kind, name) {
111
+ const specAndSourceInfo = this._store.getSpecAndSourceInfo(kind, name);
112
+ const details = this._getEvaluationDetails(specAndSourceInfo);
113
+ return { details, spec: specAndSourceInfo.spec };
114
+ }
115
+ _getEvaluationDetails(info) {
116
+ const { source, lcut, receivedAt } = info;
117
+ if (source === 'Uninitialized' || source === 'NoValues') {
118
+ return { reason: source };
119
+ }
120
+ const subreason = ('spec' in info ? info.spec : info.paramStoreConfig) == null
121
+ ? 'Unrecognized'
122
+ : 'Recognized';
123
+ const reason = `${source}:${subreason}`;
124
+ return { reason, lcut, receivedAt };
125
+ }
118
126
  _evaluateRule(rule, user) {
119
127
  const exposures = [];
120
128
  let pass = true;
@@ -268,25 +276,37 @@ class Evaluator {
268
276
  if (!spec) {
269
277
  return null;
270
278
  }
271
- const result = this._evaluateSpec(spec, user);
272
- return (0, EvaluationResult_1.makeEvalResult)(Object.assign(Object.assign({}, result), { allocated_experiment_name: configDelegate, explicit_parameters: spec.explicitParameters, secondary_exposures: exposures.concat(result.secondary_exposures), undelegated_secondary_exposures: exposures }));
279
+ const result = this.evaluateSpec(spec, user);
280
+ const seen = {};
281
+ const mergedExposures = [];
282
+ for (const exposure of exposures.concat(result.secondary_exposures)) {
283
+ const key = `${exposure.gate}|${exposure.gateValue}|${exposure.ruleID}`;
284
+ if (seen[key]) {
285
+ continue;
286
+ }
287
+ seen[key] = true;
288
+ mergedExposures.push(exposure);
289
+ }
290
+ return (0, EvaluationResult_1.makeEvalResult)(Object.assign(Object.assign({}, result), { allocated_experiment_name: configDelegate, explicit_parameters: spec.explicitParameters, secondary_exposures: mergedExposures, undelegated_secondary_exposures: exposures }));
273
291
  }
274
292
  _evaluateNestedGate(name, user) {
275
293
  const exposures = [];
276
294
  let pass = false;
277
295
  const { spec } = this._store.getSpecAndSourceInfo('gate', name);
278
296
  if (spec) {
279
- const result = this._evaluateSpec(spec, user);
297
+ const result = this.evaluateSpec(spec, user);
280
298
  if (result.unsupported) {
281
299
  return result;
282
300
  }
283
301
  pass = result.bool_value;
284
302
  exposures.push(...result.secondary_exposures);
285
- exposures.push({
286
- gate: name,
287
- gateValue: String(pass),
288
- ruleID: result.rule_id,
289
- });
303
+ if (!name.startsWith('segment:')) {
304
+ exposures.push({
305
+ gate: name,
306
+ gateValue: String(pass),
307
+ ruleID: result.rule_id,
308
+ });
309
+ }
290
310
  }
291
311
  return (0, EvaluationResult_1.makeEvalResult)({
292
312
  bool_value: pass,
@@ -27,4 +27,6 @@ export declare class SpecStore {
27
27
  getSpecAndSourceInfo(kind: SpecKind, name: string): SpecAndSourceInfo;
28
28
  getParamStoreAndSourceInfo(name: string): ParamStoreAndSourceInfo;
29
29
  private _getSpecs;
30
+ getAllSpecs(kind: SpecKind): Spec[];
31
+ getLastUpdateTime(): number;
30
32
  }
package/src/SpecStore.js CHANGED
@@ -86,5 +86,12 @@ class SpecStore {
86
86
  return (_c = this._values) === null || _c === void 0 ? void 0 : _c.layer_configs;
87
87
  }
88
88
  }
89
+ getAllSpecs(kind) {
90
+ const specs = this._getSpecs(kind);
91
+ return specs || [];
92
+ }
93
+ getLastUpdateTime() {
94
+ return this._lcut;
95
+ }
89
96
  }
90
97
  exports.SpecStore = SpecStore;
package/src/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './Evaluator';
2
+ export * from './EvaluationResult';
2
3
  export * from './SpecStore';
package/src/index.js CHANGED
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./Evaluator"), exports);
18
+ __exportStar(require("./EvaluationResult"), exports);
18
19
  __exportStar(require("./SpecStore"), exports);