@kenji71089/evaluation 0.0.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 (209) hide show
  1. package/.release-please-manifest.json +3 -0
  2. package/README.md +9 -0
  3. package/eslint.config.mjs +27 -0
  4. package/lib/clauseEvaluator.d.ts +22 -0
  5. package/lib/clauseEvaluator.js +299 -0
  6. package/lib/clauseEvaluator.mjs +214 -0
  7. package/lib/dependencyEvaluator.d.ts +6 -0
  8. package/lib/dependencyEvaluator.js +46 -0
  9. package/lib/dependencyEvaluator.mjs +19 -0
  10. package/lib/errors.d.ts +9 -0
  11. package/lib/errors.js +15 -0
  12. package/lib/errors.mjs +12 -0
  13. package/lib/evaluation.d.ts +25 -0
  14. package/lib/evaluation.js +503 -0
  15. package/lib/evaluation.mjs +328 -0
  16. package/lib/google/api/annotations_pb.d.ts +8 -0
  17. package/lib/google/api/annotations_pb.js +40 -0
  18. package/lib/google/api/annotations_pb.mjs +54 -0
  19. package/lib/google/api/annotations_pb_service.d.ts +3 -0
  20. package/lib/google/api/annotations_pb_service.js +3 -0
  21. package/lib/google/api/annotations_pb_service.mjs +3 -0
  22. package/lib/google/api/http_pb.d.ts +132 -0
  23. package/lib/google/api/http_pb.js +860 -0
  24. package/lib/google/api/http_pb.mjs +982 -0
  25. package/lib/google/api/http_pb_service.d.ts +3 -0
  26. package/lib/google/api/http_pb_service.js +3 -0
  27. package/lib/google/api/http_pb_service.mjs +3 -0
  28. package/lib/google/rpc/code_pb.d.ts +26 -0
  29. package/lib/google/rpc/code_pb.js +44 -0
  30. package/lib/google/rpc/code_pb.mjs +48 -0
  31. package/lib/google/rpc/code_pb_service.d.ts +3 -0
  32. package/lib/google/rpc/code_pb_service.js +3 -0
  33. package/lib/google/rpc/code_pb_service.mjs +3 -0
  34. package/lib/google/rpc/error_details_pb.d.ts +322 -0
  35. package/lib/google/rpc/error_details_pb.js +2220 -0
  36. package/lib/google/rpc/error_details_pb.mjs +2499 -0
  37. package/lib/google/rpc/error_details_pb_service.d.ts +3 -0
  38. package/lib/google/rpc/error_details_pb_service.js +3 -0
  39. package/lib/google/rpc/error_details_pb_service.mjs +3 -0
  40. package/lib/google/rpc/status_pb.d.ts +36 -0
  41. package/lib/google/rpc/status_pb.js +235 -0
  42. package/lib/google/rpc/status_pb.mjs +268 -0
  43. package/lib/google/rpc/status_pb_service.d.ts +3 -0
  44. package/lib/google/rpc/status_pb_service.js +3 -0
  45. package/lib/google/rpc/status_pb_service.mjs +3 -0
  46. package/lib/index.d.ts +20 -0
  47. package/lib/index.js +199 -0
  48. package/lib/index.mjs +46 -0
  49. package/lib/modelFactory.d.ts +64 -0
  50. package/lib/modelFactory.js +206 -0
  51. package/lib/modelFactory.mjs +176 -0
  52. package/lib/proto/event/client/event_pb.d.ts +761 -0
  53. package/lib/proto/event/client/event_pb.js +5195 -0
  54. package/lib/proto/event/client/event_pb.mjs +5865 -0
  55. package/lib/proto/event/client/event_pb_service.d.ts +3 -0
  56. package/lib/proto/event/client/event_pb_service.js +3 -0
  57. package/lib/proto/event/client/event_pb_service.mjs +3 -0
  58. package/lib/proto/event/domain/event_pb.d.ts +4518 -0
  59. package/lib/proto/event/domain/event_pb.js +10834 -0
  60. package/lib/proto/event/domain/event_pb.mjs +33315 -0
  61. package/lib/proto/event/domain/event_pb_service.d.ts +3 -0
  62. package/lib/proto/event/domain/event_pb_service.js +3 -0
  63. package/lib/proto/event/domain/event_pb_service.mjs +3 -0
  64. package/lib/proto/event/domain/localized_message_pb.d.ts +29 -0
  65. package/lib/proto/event/domain/localized_message_pb.js +183 -0
  66. package/lib/proto/event/domain/localized_message_pb.mjs +206 -0
  67. package/lib/proto/event/domain/localized_message_pb_service.d.ts +3 -0
  68. package/lib/proto/event/domain/localized_message_pb_service.js +3 -0
  69. package/lib/proto/event/domain/localized_message_pb_service.mjs +3 -0
  70. package/lib/proto/event/service/feature_pb.d.ts +44 -0
  71. package/lib/proto/event/service/feature_pb.js +277 -0
  72. package/lib/proto/event/service/feature_pb.mjs +319 -0
  73. package/lib/proto/event/service/feature_pb_service.d.ts +3 -0
  74. package/lib/proto/event/service/feature_pb_service.js +3 -0
  75. package/lib/proto/event/service/feature_pb_service.mjs +3 -0
  76. package/lib/proto/event/service/segment_pb.d.ts +51 -0
  77. package/lib/proto/event/service/segment_pb.js +324 -0
  78. package/lib/proto/event/service/segment_pb.mjs +375 -0
  79. package/lib/proto/event/service/segment_pb_service.d.ts +3 -0
  80. package/lib/proto/event/service/segment_pb_service.js +3 -0
  81. package/lib/proto/event/service/segment_pb_service.mjs +3 -0
  82. package/lib/proto/event/service/user_pb.d.ts +49 -0
  83. package/lib/proto/event/service/user_pb.js +315 -0
  84. package/lib/proto/event/service/user_pb.mjs +362 -0
  85. package/lib/proto/event/service/user_pb_service.d.ts +3 -0
  86. package/lib/proto/event/service/user_pb_service.js +3 -0
  87. package/lib/proto/event/service/user_pb_service.mjs +3 -0
  88. package/lib/proto/feature/clause_pb.d.ts +57 -0
  89. package/lib/proto/feature/clause_pb.js +277 -0
  90. package/lib/proto/feature/clause_pb.mjs +312 -0
  91. package/lib/proto/feature/clause_pb_service.d.ts +3 -0
  92. package/lib/proto/feature/clause_pb_service.js +3 -0
  93. package/lib/proto/feature/clause_pb_service.mjs +3 -0
  94. package/lib/proto/feature/command_pb.d.ts +1213 -0
  95. package/lib/proto/feature/command_pb.js +8260 -0
  96. package/lib/proto/feature/command_pb.mjs +9275 -0
  97. package/lib/proto/feature/command_pb_service.d.ts +3 -0
  98. package/lib/proto/feature/command_pb_service.js +3 -0
  99. package/lib/proto/feature/command_pb_service.mjs +3 -0
  100. package/lib/proto/feature/evaluation_pb.d.ts +111 -0
  101. package/lib/proto/feature/evaluation_pb.js +685 -0
  102. package/lib/proto/feature/evaluation_pb.mjs +793 -0
  103. package/lib/proto/feature/evaluation_pb_service.d.ts +3 -0
  104. package/lib/proto/feature/evaluation_pb_service.js +3 -0
  105. package/lib/proto/feature/evaluation_pb_service.mjs +3 -0
  106. package/lib/proto/feature/feature_last_used_info_pb.d.ts +45 -0
  107. package/lib/proto/feature/feature_last_used_info_pb.js +283 -0
  108. package/lib/proto/feature/feature_last_used_info_pb.mjs +326 -0
  109. package/lib/proto/feature/feature_last_used_info_pb_service.d.ts +3 -0
  110. package/lib/proto/feature/feature_last_used_info_pb_service.js +3 -0
  111. package/lib/proto/feature/feature_last_used_info_pb_service.mjs +3 -0
  112. package/lib/proto/feature/feature_pb.d.ts +192 -0
  113. package/lib/proto/feature/feature_pb.js +1210 -0
  114. package/lib/proto/feature/feature_pb.mjs +1413 -0
  115. package/lib/proto/feature/feature_pb_service.d.ts +3 -0
  116. package/lib/proto/feature/feature_pb_service.js +3 -0
  117. package/lib/proto/feature/feature_pb_service.mjs +3 -0
  118. package/lib/proto/feature/flag_trigger_pb.d.ts +84 -0
  119. package/lib/proto/feature/flag_trigger_pb.js +452 -0
  120. package/lib/proto/feature/flag_trigger_pb.mjs +525 -0
  121. package/lib/proto/feature/flag_trigger_pb_service.d.ts +3 -0
  122. package/lib/proto/feature/flag_trigger_pb_service.js +3 -0
  123. package/lib/proto/feature/flag_trigger_pb_service.mjs +3 -0
  124. package/lib/proto/feature/prerequisite_pb.d.ts +29 -0
  125. package/lib/proto/feature/prerequisite_pb.js +183 -0
  126. package/lib/proto/feature/prerequisite_pb.mjs +206 -0
  127. package/lib/proto/feature/prerequisite_pb_service.d.ts +3 -0
  128. package/lib/proto/feature/prerequisite_pb_service.js +3 -0
  129. package/lib/proto/feature/prerequisite_pb_service.mjs +3 -0
  130. package/lib/proto/feature/reason_pb.d.ts +40 -0
  131. package/lib/proto/feature/reason_pb.js +196 -0
  132. package/lib/proto/feature/reason_pb.mjs +219 -0
  133. package/lib/proto/feature/reason_pb_service.d.ts +3 -0
  134. package/lib/proto/feature/reason_pb_service.js +3 -0
  135. package/lib/proto/feature/reason_pb_service.mjs +3 -0
  136. package/lib/proto/feature/rule_pb.d.ts +39 -0
  137. package/lib/proto/feature/rule_pb.js +254 -0
  138. package/lib/proto/feature/rule_pb.mjs +291 -0
  139. package/lib/proto/feature/rule_pb_service.d.ts +3 -0
  140. package/lib/proto/feature/rule_pb_service.js +3 -0
  141. package/lib/proto/feature/rule_pb_service.mjs +3 -0
  142. package/lib/proto/feature/segment_pb.d.ts +161 -0
  143. package/lib/proto/feature/segment_pb.js +974 -0
  144. package/lib/proto/feature/segment_pb.mjs +1127 -0
  145. package/lib/proto/feature/segment_pb_service.d.ts +3 -0
  146. package/lib/proto/feature/segment_pb_service.js +3 -0
  147. package/lib/proto/feature/segment_pb_service.mjs +3 -0
  148. package/lib/proto/feature/service_pb.d.ts +2158 -0
  149. package/lib/proto/feature/service_pb.js +5363 -0
  150. package/lib/proto/feature/service_pb.mjs +16348 -0
  151. package/lib/proto/feature/service_pb_service.d.ts +747 -0
  152. package/lib/proto/feature/service_pb_service.js +1424 -0
  153. package/lib/proto/feature/service_pb_service.mjs +1501 -0
  154. package/lib/proto/feature/strategy_pb.d.ts +110 -0
  155. package/lib/proto/feature/strategy_pb.js +712 -0
  156. package/lib/proto/feature/strategy_pb.mjs +803 -0
  157. package/lib/proto/feature/strategy_pb_service.d.ts +3 -0
  158. package/lib/proto/feature/strategy_pb_service.js +3 -0
  159. package/lib/proto/feature/strategy_pb_service.mjs +3 -0
  160. package/lib/proto/feature/target_pb.d.ts +31 -0
  161. package/lib/proto/feature/target_pb.js +207 -0
  162. package/lib/proto/feature/target_pb.mjs +232 -0
  163. package/lib/proto/feature/target_pb_service.d.ts +3 -0
  164. package/lib/proto/feature/target_pb_service.js +3 -0
  165. package/lib/proto/feature/target_pb_service.mjs +3 -0
  166. package/lib/proto/feature/variation_pb.d.ts +37 -0
  167. package/lib/proto/feature/variation_pb.js +233 -0
  168. package/lib/proto/feature/variation_pb.mjs +266 -0
  169. package/lib/proto/feature/variation_pb_service.d.ts +3 -0
  170. package/lib/proto/feature/variation_pb_service.js +3 -0
  171. package/lib/proto/feature/variation_pb_service.mjs +3 -0
  172. package/lib/proto/gateway/service_pb.d.ts +772 -0
  173. package/lib/proto/gateway/service_pb.js +5249 -0
  174. package/lib/proto/gateway/service_pb.mjs +6001 -0
  175. package/lib/proto/gateway/service_pb_service.d.ts +253 -0
  176. package/lib/proto/gateway/service_pb_service.js +436 -0
  177. package/lib/proto/gateway/service_pb_service.mjs +461 -0
  178. package/lib/proto/user/user_pb.d.ts +58 -0
  179. package/lib/proto/user/user_pb.js +410 -0
  180. package/lib/proto/user/user_pb.mjs +460 -0
  181. package/lib/proto/user/user_pb_service.d.ts +3 -0
  182. package/lib/proto/user/user_pb_service.js +3 -0
  183. package/lib/proto/user/user_pb_service.mjs +3 -0
  184. package/lib/protoc-gen-openapiv2/options/annotations_pb.d.ts +16 -0
  185. package/lib/protoc-gen-openapiv2/options/annotations_pb.js +100 -0
  186. package/lib/protoc-gen-openapiv2/options/annotations_pb.mjs +158 -0
  187. package/lib/protoc-gen-openapiv2/options/annotations_pb_service.d.ts +3 -0
  188. package/lib/protoc-gen-openapiv2/options/annotations_pb_service.js +3 -0
  189. package/lib/protoc-gen-openapiv2/options/annotations_pb_service.mjs +3 -0
  190. package/lib/protoc-gen-openapiv2/options/openapiv2_pb.d.ts +834 -0
  191. package/lib/protoc-gen-openapiv2/options/openapiv2_pb.js +5456 -0
  192. package/lib/protoc-gen-openapiv2/options/openapiv2_pb.mjs +6256 -0
  193. package/lib/protoc-gen-openapiv2/options/openapiv2_pb_service.d.ts +3 -0
  194. package/lib/protoc-gen-openapiv2/options/openapiv2_pb_service.js +3 -0
  195. package/lib/protoc-gen-openapiv2/options/openapiv2_pb_service.mjs +3 -0
  196. package/lib/ruleEvaluator.d.ts +13 -0
  197. package/lib/ruleEvaluator.js +80 -0
  198. package/lib/ruleEvaluator.mjs +41 -0
  199. package/lib/segmentEvaluator.d.ts +7 -0
  200. package/lib/segmentEvaluator.js +74 -0
  201. package/lib/segmentEvaluator.mjs +34 -0
  202. package/lib/strategyEvaluator.d.ts +10 -0
  203. package/lib/strategyEvaluator.js +135 -0
  204. package/lib/strategyEvaluator.mjs +83 -0
  205. package/lib/userEvaluation.d.ts +8 -0
  206. package/lib/userEvaluation.js +70 -0
  207. package/lib/userEvaluation.mjs +60 -0
  208. package/package.json +46 -0
  209. package/release-please-config.json +22 -0
@@ -0,0 +1,328 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Evaluator = void 0;
4
+ exports.EvaluationID = EvaluationID;
5
+ const errors_1 = require("./errors");
6
+ const clause_pb_1 = require("./proto/feature/clause_pb");
7
+ const evaluation_pb_1 = require("./proto/feature/evaluation_pb");
8
+ const reason_pb_1 = require("./proto/feature/reason_pb");
9
+ const variation_pb_1 = require("./proto/feature/variation_pb");
10
+ const ruleEvaluator_1 = require("./ruleEvaluator");
11
+ const strategyEvaluator_1 = require("./strategyEvaluator");
12
+ const userEvaluation_1 = require("./userEvaluation");
13
+ const modelFactory_1 = require("./modelFactory");
14
+ const SECONDS_TO_RE_EVALUATE_ALL = 30 * 24 * 60 * 60; // 30 days
15
+ const SECONDS_FOR_ADJUSTMENT = 10; // 10 seconds
16
+ function EvaluationID(featureID, featureVersion, userID) {
17
+ return `${featureID}:${featureVersion}:${userID}`;
18
+ }
19
+ class Evaluator {
20
+ ruleEvaluator;
21
+ strategyEvaluator;
22
+ constructor() {
23
+ this.ruleEvaluator = new ruleEvaluator_1.RuleEvaluator();
24
+ this.strategyEvaluator = new strategyEvaluator_1.StrategyEvaluator();
25
+ }
26
+ async evaluateFeatures(features, user, mapSegmentUsers, targetTag) {
27
+ return this.evaluate(features, user, mapSegmentUsers, false, targetTag);
28
+ }
29
+ // GetPrerequisiteDownwards gets the features specified as prerequisite by the targetFeatures.
30
+ getPrerequisiteDownwards(targetFeatures, allFeatures) {
31
+ const allFeaturesMap = new Map();
32
+ for (const feature of allFeatures) {
33
+ allFeaturesMap.set(feature.getId(), feature);
34
+ }
35
+ const dependedOnTargets = getFeaturesDependedOnTargets(targetFeatures, allFeaturesMap);
36
+ return Object.values(dependedOnTargets);
37
+ }
38
+ evaluateFeaturesByEvaluatedAt(features, user, mapSegmentUsers, prevUEID, evaluatedAt, userAttributesUpdated, targetTag) {
39
+ if (prevUEID === '') {
40
+ return this.evaluate(features, user, mapSegmentUsers, true, targetTag);
41
+ }
42
+ const now = Math.floor(Date.now() / 1000);
43
+ if (evaluatedAt < now - SECONDS_TO_RE_EVALUATE_ALL) {
44
+ return this.evaluate(features, user, mapSegmentUsers, true, targetTag);
45
+ }
46
+ const adjustedEvalAt = evaluatedAt - SECONDS_FOR_ADJUSTMENT;
47
+ const updatedFeatures = features.filter((feature) => feature.getUpdatedAt() > adjustedEvalAt ||
48
+ (userAttributesUpdated && feature.getRulesList().length > 0));
49
+ // If the UserEvaluationsID has changed, but both User Attributes and Feature Flags have not been updated,
50
+ // it is considered unusual and a force update should be performed.
51
+ if (updatedFeatures.length === 0) {
52
+ return this.evaluate(features, user, mapSegmentUsers, true, targetTag);
53
+ }
54
+ const evalTargets = this.getEvalFeatures(updatedFeatures, features);
55
+ return this.evaluate(evalTargets, user, mapSegmentUsers, false, targetTag);
56
+ }
57
+ evaluate(features, user, mapSegmentUsers, forceUpdate, targetTag) {
58
+ const flagVariations = {};
59
+ // fs need to be sorted in order from upstream to downstream.
60
+ const sortedFeatures = topologicalSort(features);
61
+ const evaluations = [];
62
+ const archivedIDs = [];
63
+ for (const feature of sortedFeatures) {
64
+ if (feature.getArchived()) {
65
+ // To keep response size small, the feature flags archived long time ago are excluded.
66
+ if (!this.isArchivedBeforeLastThirtyDays(feature)) {
67
+ archivedIDs.push(feature.getId());
68
+ }
69
+ continue;
70
+ }
71
+ const segmentUsers = this.listSegmentIDs(feature).flatMap((id) => mapSegmentUsers.get(id) || []);
72
+ const [reason, variation] = this.assignUser(feature, user, segmentUsers, flagVariations);
73
+ // VariationId is used to check if prerequisite flag's result is what user expects it to be.
74
+ flagVariations[feature.getId()] = variation.getId();
75
+ // When the tag is set in the request,
76
+ // it will return only the evaluations of flags that match the tag configured on the dashboard.
77
+ // When empty, it will return all the evaluations of the flags in the environment.
78
+ if (targetTag !== '' && !this.tagExist(feature.getTagsList(), targetTag)) {
79
+ continue;
80
+ }
81
+ const evaluationID = EvaluationID(feature.getId(), feature.getVersion(), user.getId());
82
+ const evaluation = new evaluation_pb_1.Evaluation();
83
+ evaluation.setId(evaluationID);
84
+ evaluation.setFeatureId(feature.getId());
85
+ evaluation.setFeatureVersion(feature.getVersion());
86
+ evaluation.setUserId(user.getId());
87
+ evaluation.setVariationId(variation.getId());
88
+ evaluation.setVariationName(variation.getName());
89
+ evaluation.setVariationValue(variation.getValue());
90
+ // Deprecated
91
+ // FIXME: Remove the Variation when is no longer being used.
92
+ // For security reasons, we should remove the variation description.
93
+ // We copy the variation object to avoid race conditions when removing
94
+ // the description directly from the `variation`
95
+ const copyVariation = new variation_pb_1.Variation();
96
+ copyVariation.setId(variation.getId());
97
+ copyVariation.setName(variation.getName());
98
+ copyVariation.setValue(variation.getValue());
99
+ evaluation.setVariation(copyVariation);
100
+ evaluation.setReason(reason);
101
+ evaluations.push(evaluation);
102
+ }
103
+ const id = (0, userEvaluation_1.UserEvaluationsID)(user.getId(), arrayToRecord(user.getDataMap().toArray()), features);
104
+ const userEvaluations = (0, userEvaluation_1.NewUserEvaluations)(id, evaluations, archivedIDs, forceUpdate);
105
+ return userEvaluations;
106
+ }
107
+ tagExist(tags, target) {
108
+ return tags.includes(target);
109
+ }
110
+ /*
111
+ IsArchivedBeforeLastThirtyDays returns a bool value
112
+ indicating whether the feature flag was archived within the last thirty days.
113
+ */
114
+ isArchivedBeforeLastThirtyDays(feature) {
115
+ if (!feature.getArchived()) {
116
+ return false;
117
+ }
118
+ const now = Math.floor(Date.now() / 1000);
119
+ return feature.getUpdatedAt() < now - SECONDS_TO_RE_EVALUATE_ALL;
120
+ }
121
+ listSegmentIDs(feature) {
122
+ const mapIDs = new Set();
123
+ for (const rule of feature.getRulesList()) {
124
+ for (const clause of rule.getClausesList()) {
125
+ if (clause.getOperator() === clause_pb_1.Clause.Operator.SEGMENT) {
126
+ clause.getValuesList().forEach((value) => mapIDs.add(value));
127
+ }
128
+ }
129
+ }
130
+ return Array.from(mapIDs);
131
+ }
132
+ assignUser(feature, user, segmentUsers, flagVariations) {
133
+ for (const pf of feature.getPrerequisitesList()) {
134
+ const variationId = flagVariations[pf.getFeatureId()];
135
+ if (!variationId) {
136
+ throw errors_1.EVALUATOR_ERRORS.PrerequisiteVariationNotFound;
137
+ }
138
+ if (pf.getVariationId() !== variationId) {
139
+ if (feature.getOffVariation() !== '') {
140
+ const variation = this.findVariation(feature.getOffVariation(), feature.getVariationsList());
141
+ const reason = (0, modelFactory_1.createReason)('', reason_pb_1.Reason.Type.PREREQUISITE);
142
+ return [reason, variation];
143
+ }
144
+ }
145
+ }
146
+ // It doesn't assign the user in case of the feature is disabled and OffVariation is not set
147
+ if (!feature.getEnabled() && feature.getOffVariation() !== '') {
148
+ const variation = this.findVariation(feature.getOffVariation(), feature.getVariationsList());
149
+ const reason = (0, modelFactory_1.createReason)('', reason_pb_1.Reason.Type.OFF_VARIATION);
150
+ return [reason, variation];
151
+ }
152
+ // evaluate from top to bottom, return if one rule matches
153
+ // evaluate targeting rules
154
+ for (const target of feature.getTargetsList()) {
155
+ if (target.getUsersList().includes(user.getId())) {
156
+ const variation = this.findVariation(target.getVariation(), feature.getVariationsList());
157
+ const reason = (0, modelFactory_1.createReason)('', reason_pb_1.Reason.Type.TARGET);
158
+ return [reason, variation];
159
+ }
160
+ }
161
+ // evaluate ruleset
162
+ const rule = this.ruleEvaluator.evaluate(feature.getRulesList(), user, segmentUsers, flagVariations);
163
+ if (rule) {
164
+ const strategy = rule.getStrategy();
165
+ if (strategy == undefined) {
166
+ throw errors_1.EVALUATOR_ERRORS.StrategyNotFound;
167
+ }
168
+ const variation = this.strategyEvaluator.evaluate(strategy, user.getId(), feature.getVariationsList(), feature.getId(), feature.getSamplingSeed());
169
+ const reason = (0, modelFactory_1.createReason)(rule.getId(), reason_pb_1.Reason.Type.RULE);
170
+ return [reason, variation];
171
+ }
172
+ // use default strategy
173
+ const defaultStrategy = feature.getDefaultStrategy();
174
+ if (defaultStrategy == undefined) {
175
+ throw errors_1.EVALUATOR_ERRORS.DefaultStrategyNotFound;
176
+ }
177
+ const variation = this.strategyEvaluator.evaluate(defaultStrategy, user.getId(), feature.getVariationsList(), feature.getId(), feature.getSamplingSeed());
178
+ const reason = (0, modelFactory_1.createReason)('', reason_pb_1.Reason.Type.DEFAULT);
179
+ return [reason, variation];
180
+ }
181
+ getEvalFeatures(targetFeatures, allFeatures) {
182
+ const allFeaturesMap = new Map();
183
+ for (const feature of allFeatures) {
184
+ allFeaturesMap.set(feature.getId(), feature);
185
+ }
186
+ const evals1 = getFeaturesDependedOnTargets(targetFeatures, allFeaturesMap);
187
+ const evals2 = getFeaturesDependsOnTargets(targetFeatures, allFeaturesMap);
188
+ const mergedEvals = { ...evals1, ...evals2 };
189
+ return Object.values(mergedEvals);
190
+ }
191
+ findVariation(v, variations) {
192
+ const variation = variations.find((variation) => variation.getId() === v);
193
+ if (!variation) {
194
+ throw errors_1.EVALUATOR_ERRORS.VariationNotFound;
195
+ }
196
+ return variation;
197
+ }
198
+ }
199
+ exports.Evaluator = Evaluator;
200
+ var Mark;
201
+ (function (Mark) {
202
+ Mark[Mark["Unvisited"] = 0] = "Unvisited";
203
+ Mark[Mark["Temporary"] = 1] = "Temporary";
204
+ Mark[Mark["Permanently"] = 2] = "Permanently";
205
+ })(Mark || (Mark = {}));
206
+ // FeatureIDsDependsOn returns the ids of the features that this feature depends on.
207
+ function featureIDsDependsOn(feature) {
208
+ const ids = [];
209
+ // Iterate over prerequisites and add their FeatureId
210
+ feature.getPrerequisitesList().forEach((p) => {
211
+ ids.push(p.getFeatureId());
212
+ });
213
+ // Iterate over rules and collect ids from clauses where the operator is FEATURE_FLAG
214
+ feature.getRulesList().forEach((rule) => {
215
+ rule.getClausesList().forEach((clause) => {
216
+ if (clause.getOperator() === clause_pb_1.Clause.Operator.FEATURE_FLAG) {
217
+ ids.push(clause.getAttribute());
218
+ }
219
+ });
220
+ });
221
+ return ids;
222
+ }
223
+ // Error types
224
+ class ErrCycleExists extends Error {
225
+ constructor() {
226
+ super('Cycle exists in the graph');
227
+ }
228
+ }
229
+ class ErrFeatureNotFound extends Error {
230
+ constructor() {
231
+ super('Feature not found');
232
+ }
233
+ }
234
+ // Topological sort function
235
+ function topologicalSort(features) {
236
+ const marks = {};
237
+ const mapFeatures = {};
238
+ features.forEach((f) => {
239
+ marks[f.getId()] = Mark.Unvisited;
240
+ mapFeatures[f.getId()] = f;
241
+ });
242
+ const sortedFeatures = [];
243
+ const sort = (f) => {
244
+ const fId = f.getId();
245
+ if (marks[fId] === Mark.Permanently)
246
+ return;
247
+ if (marks[fId] === Mark.Temporary) {
248
+ throw new ErrCycleExists();
249
+ }
250
+ marks[fId] = Mark.Temporary;
251
+ const dependentFeatureIds = featureIDsDependsOn(f);
252
+ for (const fid of dependentFeatureIds) {
253
+ const pf = mapFeatures[fid];
254
+ if (!pf) {
255
+ throw new ErrFeatureNotFound();
256
+ }
257
+ sort(pf);
258
+ }
259
+ marks[fId] = Mark.Permanently;
260
+ sortedFeatures.push(f);
261
+ };
262
+ // Process each feature
263
+ for (const f of features) {
264
+ if (marks[f.getId()] === Mark.Unvisited) {
265
+ sort(f);
266
+ }
267
+ }
268
+ return sortedFeatures;
269
+ }
270
+ // getFeaturesDependedOnTargets returns the features that are depended on the target features.
271
+ // targetFeatures are included in the result.
272
+ function getFeaturesDependedOnTargets(targets, all) {
273
+ const evals = {};
274
+ const dfs = (f) => {
275
+ // If the feature is already in the evals map, skip
276
+ if (evals[f.getId()])
277
+ return;
278
+ // Add feature to evals
279
+ evals[f.getId()] = f;
280
+ // Get dependent features recursively
281
+ const featureDependencies = featureIDsDependsOn(f);
282
+ featureDependencies.forEach((fid) => {
283
+ const target = all.get(fid);
284
+ if (target !== undefined) {
285
+ dfs(target);
286
+ }
287
+ });
288
+ };
289
+ // Start DFS for each target feature
290
+ targets.forEach((f) => dfs(f));
291
+ return evals;
292
+ }
293
+ // getFeaturesDependsOnTargets returns the features that depend on the target features.
294
+ // targetFeatures are included in the result.
295
+ function getFeaturesDependsOnTargets(targets, all) {
296
+ const evals = {};
297
+ // Mark target features in the evals map initially
298
+ targets.forEach((f) => {
299
+ evals[f.getId()] = f;
300
+ });
301
+ // Depth-first search to determine if a feature depends on a target feature
302
+ const dfs = (f) => {
303
+ if (evals[f.getId()]) {
304
+ return true;
305
+ }
306
+ const featureDependencies = featureIDsDependsOn(f);
307
+ for (const fid of featureDependencies) {
308
+ const dependentFeature = all.get(fid);
309
+ if (dependentFeature && dfs(dependentFeature)) {
310
+ // If the feature depends on one of the target features, add it to evals
311
+ evals[f.getId()] = f;
312
+ return true;
313
+ }
314
+ }
315
+ return false;
316
+ };
317
+ // Apply DFS for all features, except target features
318
+ all.forEach((f) => {
319
+ dfs(f);
320
+ });
321
+ return evals;
322
+ }
323
+ function arrayToRecord(arr) {
324
+ return arr.reduce((acc, [key, value]) => {
325
+ acc[key] = value;
326
+ return acc;
327
+ }, {});
328
+ }
@@ -0,0 +1,8 @@
1
+ // package: google.api
2
+ // file: google/api/annotations.proto
3
+
4
+ import * as jspb from 'google-protobuf';
5
+ import * as google_api_http_pb from '../../google/api/http_pb';
6
+
7
+ export const http: jspb.ExtensionFieldInfo<google_api_http_pb.HttpRule>;
8
+
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ // source: google/api/annotations.proto
4
+ /**
5
+ * @fileoverview
6
+ * @enhanceable
7
+ * @suppress {missingRequire} reports error on implicit type usages.
8
+ * @suppress {messageConventions} JS Compiler reports an error if a variable or
9
+ * field starts with 'MSG_' and isn't a translatable message.
10
+ * @public
11
+ */
12
+ // GENERATED CODE -- DO NOT EDIT!
13
+
14
+ // @ts-nocheck
15
+
16
+ var jspb = require('google-protobuf');
17
+ var goog = jspb;
18
+ var global = typeof globalThis !== 'undefined' && globalThis || typeof window !== 'undefined' && window || typeof global !== 'undefined' && global || typeof self !== 'undefined' && self || function () {
19
+ return this;
20
+ }.call(null) || Function('return this')();
21
+ var google_api_http_pb = require('../../google/api/http_pb.js');
22
+ goog.object.extend(proto, google_api_http_pb);
23
+ var google_protobuf_descriptor_pb = require('google-protobuf/google/protobuf/descriptor_pb.js');
24
+ goog.object.extend(proto, google_protobuf_descriptor_pb);
25
+ goog.exportSymbol('proto.google.api.http', null, global);
26
+
27
+ /**
28
+ * A tuple of {field number, class constructor} for the extension
29
+ * field named `http`.
30
+ * @type {!jspb.ExtensionFieldInfo<!proto.google.api.HttpRule>}
31
+ */
32
+ proto.google.api.http = new jspb.ExtensionFieldInfo(72295728, {
33
+ http: 0
34
+ }, google_api_http_pb.HttpRule, /** @type {?function((boolean|undefined),!jspb.Message=): !Object} */
35
+ google_api_http_pb.HttpRule.toObject, 0);
36
+ google_protobuf_descriptor_pb.MethodOptions.extensionsBinary[72295728] = new jspb.ExtensionFieldBinaryInfo(proto.google.api.http, jspb.BinaryReader.prototype.readMessage, jspb.BinaryWriter.prototype.writeMessage, google_api_http_pb.HttpRule.serializeBinaryToWriter, google_api_http_pb.HttpRule.deserializeBinaryFromReader, false);
37
+ // This registers the extension field with the extended class, so that
38
+ // toObject() will function correctly.
39
+ google_protobuf_descriptor_pb.MethodOptions.extensions[72295728] = proto.google.api.http;
40
+ goog.object.extend(exports, proto.google.api);
@@ -0,0 +1,54 @@
1
+ // source: google/api/annotations.proto
2
+ /**
3
+ * @fileoverview
4
+ * @enhanceable
5
+ * @suppress {missingRequire} reports error on implicit type usages.
6
+ * @suppress {messageConventions} JS Compiler reports an error if a variable or
7
+ * field starts with 'MSG_' and isn't a translatable message.
8
+ * @public
9
+ */
10
+ // GENERATED CODE -- DO NOT EDIT!
11
+
12
+ // @ts-nocheck
13
+
14
+ var jspb = require('google-protobuf');
15
+ var goog = jspb;
16
+ var global =
17
+ (typeof globalThis !== 'undefined' && globalThis) ||
18
+ (typeof window !== 'undefined' && window) ||
19
+ (typeof global !== 'undefined' && global) ||
20
+ (typeof self !== 'undefined' && self) ||
21
+ (function () { return this; }).call(null) ||
22
+ Function('return this')();
23
+
24
+ var google_api_http_pb = require('../../google/api/http_pb.js');
25
+ goog.object.extend(proto, google_api_http_pb);
26
+ var google_protobuf_descriptor_pb = require('google-protobuf/google/protobuf/descriptor_pb.js');
27
+ goog.object.extend(proto, google_protobuf_descriptor_pb);
28
+ goog.exportSymbol('proto.google.api.http', null, global);
29
+
30
+ /**
31
+ * A tuple of {field number, class constructor} for the extension
32
+ * field named `http`.
33
+ * @type {!jspb.ExtensionFieldInfo<!proto.google.api.HttpRule>}
34
+ */
35
+ proto.google.api.http = new jspb.ExtensionFieldInfo(
36
+ 72295728,
37
+ {http: 0},
38
+ google_api_http_pb.HttpRule,
39
+ /** @type {?function((boolean|undefined),!jspb.Message=): !Object} */ (
40
+ google_api_http_pb.HttpRule.toObject),
41
+ 0);
42
+
43
+ google_protobuf_descriptor_pb.MethodOptions.extensionsBinary[72295728] = new jspb.ExtensionFieldBinaryInfo(
44
+ proto.google.api.http,
45
+ jspb.BinaryReader.prototype.readMessage,
46
+ jspb.BinaryWriter.prototype.writeMessage,
47
+ google_api_http_pb.HttpRule.serializeBinaryToWriter,
48
+ google_api_http_pb.HttpRule.deserializeBinaryFromReader,
49
+ false);
50
+ // This registers the extension field with the extended class, so that
51
+ // toObject() will function correctly.
52
+ google_protobuf_descriptor_pb.MethodOptions.extensions[72295728] = proto.google.api.http;
53
+
54
+ goog.object.extend(exports, proto.google.api);
@@ -0,0 +1,3 @@
1
+ // package: google.api
2
+ // file: google/api/annotations.proto
3
+
@@ -0,0 +1,3 @@
1
+ // package: google.api
2
+ // file: google/api/annotations.proto
3
+ "use strict";
@@ -0,0 +1,3 @@
1
+ // package: google.api
2
+ // file: google/api/annotations.proto
3
+
@@ -0,0 +1,132 @@
1
+ // package: google.api
2
+ // file: google/api/http.proto
3
+
4
+ import * as jspb from 'google-protobuf';
5
+
6
+ export class Http extends jspb.Message {
7
+ clearRulesList(): void;
8
+ getRulesList(): Array<HttpRule>;
9
+ setRulesList(value: Array<HttpRule>): void;
10
+ addRules(value?: HttpRule, index?: number): HttpRule;
11
+
12
+ getFullyDecodeReservedExpansion(): boolean;
13
+ setFullyDecodeReservedExpansion(value: boolean): void;
14
+
15
+ serializeBinary(): Uint8Array;
16
+ toObject(includeInstance?: boolean): Http.AsObject;
17
+ static toObject(includeInstance: boolean, msg: Http): Http.AsObject;
18
+ static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
19
+ static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
20
+ static serializeBinaryToWriter(message: Http, writer: jspb.BinaryWriter): void;
21
+ static deserializeBinary(bytes: Uint8Array): Http;
22
+ static deserializeBinaryFromReader(message: Http, reader: jspb.BinaryReader): Http;
23
+ }
24
+
25
+ export namespace Http {
26
+ export type AsObject = {
27
+ rulesList: Array<HttpRule.AsObject>,
28
+ fullyDecodeReservedExpansion: boolean,
29
+ }
30
+ }
31
+
32
+ export class HttpRule extends jspb.Message {
33
+ getSelector(): string;
34
+ setSelector(value: string): void;
35
+
36
+ hasGet(): boolean;
37
+ clearGet(): void;
38
+ getGet(): string;
39
+ setGet(value: string): void;
40
+
41
+ hasPut(): boolean;
42
+ clearPut(): void;
43
+ getPut(): string;
44
+ setPut(value: string): void;
45
+
46
+ hasPost(): boolean;
47
+ clearPost(): void;
48
+ getPost(): string;
49
+ setPost(value: string): void;
50
+
51
+ hasDelete(): boolean;
52
+ clearDelete(): void;
53
+ getDelete(): string;
54
+ setDelete(value: string): void;
55
+
56
+ hasPatch(): boolean;
57
+ clearPatch(): void;
58
+ getPatch(): string;
59
+ setPatch(value: string): void;
60
+
61
+ hasCustom(): boolean;
62
+ clearCustom(): void;
63
+ getCustom(): CustomHttpPattern | undefined;
64
+ setCustom(value?: CustomHttpPattern): void;
65
+
66
+ getBody(): string;
67
+ setBody(value: string): void;
68
+
69
+ clearAdditionalBindingsList(): void;
70
+ getAdditionalBindingsList(): Array<HttpRule>;
71
+ setAdditionalBindingsList(value: Array<HttpRule>): void;
72
+ addAdditionalBindings(value?: HttpRule, index?: number): HttpRule;
73
+
74
+ getPatternCase(): HttpRule.PatternCase;
75
+ serializeBinary(): Uint8Array;
76
+ toObject(includeInstance?: boolean): HttpRule.AsObject;
77
+ static toObject(includeInstance: boolean, msg: HttpRule): HttpRule.AsObject;
78
+ static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
79
+ static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
80
+ static serializeBinaryToWriter(message: HttpRule, writer: jspb.BinaryWriter): void;
81
+ static deserializeBinary(bytes: Uint8Array): HttpRule;
82
+ static deserializeBinaryFromReader(message: HttpRule, reader: jspb.BinaryReader): HttpRule;
83
+ }
84
+
85
+ export namespace HttpRule {
86
+ export type AsObject = {
87
+ selector: string,
88
+ get: string,
89
+ put: string,
90
+ post: string,
91
+ pb_delete: string,
92
+ patch: string,
93
+ custom?: CustomHttpPattern.AsObject,
94
+ body: string,
95
+ additionalBindingsList: Array<HttpRule.AsObject>,
96
+ }
97
+
98
+ export enum PatternCase {
99
+ PATTERN_NOT_SET = 0,
100
+ GET = 2,
101
+ PUT = 3,
102
+ POST = 4,
103
+ DELETE = 5,
104
+ PATCH = 6,
105
+ CUSTOM = 8,
106
+ }
107
+ }
108
+
109
+ export class CustomHttpPattern extends jspb.Message {
110
+ getKind(): string;
111
+ setKind(value: string): void;
112
+
113
+ getPath(): string;
114
+ setPath(value: string): void;
115
+
116
+ serializeBinary(): Uint8Array;
117
+ toObject(includeInstance?: boolean): CustomHttpPattern.AsObject;
118
+ static toObject(includeInstance: boolean, msg: CustomHttpPattern): CustomHttpPattern.AsObject;
119
+ static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
120
+ static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
121
+ static serializeBinaryToWriter(message: CustomHttpPattern, writer: jspb.BinaryWriter): void;
122
+ static deserializeBinary(bytes: Uint8Array): CustomHttpPattern;
123
+ static deserializeBinaryFromReader(message: CustomHttpPattern, reader: jspb.BinaryReader): CustomHttpPattern;
124
+ }
125
+
126
+ export namespace CustomHttpPattern {
127
+ export type AsObject = {
128
+ kind: string,
129
+ path: string,
130
+ }
131
+ }
132
+