@f-o-t/rules-engine 1.0.0 → 2.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.
package/dist/index.cjs CHANGED
@@ -37,7 +37,6 @@ __export(exports_src, {
37
37
  validateRule: () => validateRule,
38
38
  validateConditions: () => validateConditions,
39
39
  updateRule: () => updateRule,
40
- tap: () => tap,
41
40
  str: () => str,
42
41
  sortRules: () => sortRules,
43
42
  sortByUpdatedAt: () => sortByUpdatedAt,
@@ -55,16 +54,18 @@ __export(exports_src, {
55
54
  removeRuleSet: () => removeRuleSet,
56
55
  removeRule: () => removeRule,
57
56
  pruneOldVersions: () => pruneOldVersions,
58
- pipe: () => pipe,
57
+ parseVersioningConfig: () => parseVersioningConfig,
58
+ parseValidationConfig: () => parseValidationConfig,
59
59
  parseRule: () => parseRule,
60
+ parseCacheConfig: () => parseCacheConfig,
60
61
  or: () => or,
61
62
  num: () => num,
62
63
  mergeRuleSets: () => mergeRuleSets,
63
64
  measureTimeAsync: () => measureTimeAsync,
64
65
  measureTime: () => measureTime,
66
+ isConditionGroup: () => import_condition_evaluator7.isConditionGroup,
65
67
  importRules: () => importRules,
66
68
  importFromJson: () => importFromJson,
67
- identity: () => identity,
68
69
  hashRules: () => hashRules,
69
70
  hashContext: () => hashContext,
70
71
  hasErrors: () => hasErrors,
@@ -95,6 +96,11 @@ __export(exports_src, {
95
96
  getLatestVersion: () => getLatestVersion,
96
97
  getIndexStats: () => getIndexStats,
97
98
  getHistory: () => getHistory,
99
+ getDefaultVersioningConfig: () => getDefaultVersioningConfig,
100
+ getDefaultValidationConfig: () => getDefaultValidationConfig,
101
+ getDefaultLogLevel: () => getDefaultLogLevel,
102
+ getDefaultConflictResolution: () => getDefaultConflictResolution,
103
+ getDefaultCacheConfig: () => getDefaultCacheConfig,
98
104
  getConflictsByType: () => getConflictsByType,
99
105
  getConflictsBySeverity: () => getConflictsBySeverity,
100
106
  getAllVersions: () => getAllVersions,
@@ -123,7 +129,6 @@ __export(exports_src, {
123
129
  detectConflicts: () => detectConflicts,
124
130
  deserializeRuleSet: () => deserializeRuleSet,
125
131
  deserializeRule: () => deserializeRule,
126
- delay: () => delay,
127
132
  date: () => date,
128
133
  createVersionStore: () => createVersionStore,
129
134
  createRuleValidator: () => createRuleValidator,
@@ -135,7 +140,6 @@ __export(exports_src, {
135
140
  createEngine: () => createEngine,
136
141
  createCache: () => createCache,
137
142
  conditions: () => conditions,
138
- compose: () => compose,
139
143
  compareVersions: () => compareVersions,
140
144
  cloneState: () => cloneState,
141
145
  cloneRule: () => cloneRule,
@@ -154,23 +158,50 @@ __export(exports_src, {
154
158
  analyzeOperatorUsage: () => analyzeOperatorUsage,
155
159
  analyzeFieldUsage: () => analyzeFieldUsage,
156
160
  analyzeConsequenceUsage: () => analyzeConsequenceUsage,
157
- always: () => always,
158
161
  all: () => all,
159
162
  addVersion: () => addVersion,
160
163
  addRules: () => addRules,
161
164
  addRuleSet: () => addRuleSet,
162
165
  addRule: () => addRule,
166
+ VersioningConfigSchema: () => VersioningConfigSchema,
167
+ ValidationResultSchema: () => ValidationResultSchema,
168
+ ValidationOptionsSchema: () => ValidationOptionsSchema,
169
+ ValidationErrorSchema: () => ValidationErrorSchema,
170
+ ValidationConfigSchema: () => ValidationConfigSchema,
171
+ RuleStatsSchema: () => RuleStatsSchema,
163
172
  RuleSetSchema: () => RuleSetSchema,
164
173
  RuleSchema: () => RuleSchema,
165
- DEFAULT_VERSIONING_CONFIG: () => DEFAULT_VERSIONING_CONFIG,
166
- DEFAULT_VALIDATION_CONFIG: () => DEFAULT_VALIDATION_CONFIG,
167
- DEFAULT_ENGINE_CONFIG: () => DEFAULT_ENGINE_CONFIG,
168
- DEFAULT_CACHE_CONFIG: () => DEFAULT_CACHE_CONFIG
174
+ LogLevelSchema: () => LogLevelSchema,
175
+ EvaluateOptionsSchema: () => EvaluateOptionsSchema,
176
+ EvaluateConfigSchema: () => EvaluateConfigSchema,
177
+ EngineStatsSchema: () => EngineStatsSchema,
178
+ ConflictResolutionStrategySchema: () => ConflictResolutionStrategySchema,
179
+ ConditionGroupSchema: () => import_condition_evaluator7.ConditionGroup,
180
+ CacheStatsSchema: () => CacheStatsSchema,
181
+ CacheConfigSchema: () => CacheConfigSchema
169
182
  });
170
183
  module.exports = __toCommonJS(exports_src);
184
+ var import_condition_evaluator7 = require("@f-o-t/condition-evaluator");
171
185
 
172
186
  // src/analyzer/analysis.ts
187
+ var import_condition_evaluator2 = require("@f-o-t/condition-evaluator");
188
+
189
+ // src/utils/conditions.ts
173
190
  var import_condition_evaluator = require("@f-o-t/condition-evaluator");
191
+ var collectConditionFields = (condition) => {
192
+ const fields = new Set;
193
+ const traverse = (c) => {
194
+ if (import_condition_evaluator.isConditionGroup(c)) {
195
+ for (const child of c.conditions) {
196
+ traverse(child);
197
+ }
198
+ } else {
199
+ fields.add(c.field);
200
+ }
201
+ };
202
+ traverse(condition);
203
+ return fields;
204
+ };
174
205
  var countConditions = (condition) => {
175
206
  if (import_condition_evaluator.isConditionGroup(condition)) {
176
207
  return condition.conditions.reduce((sum, c) => sum + countConditions(c), 0);
@@ -185,30 +216,18 @@ var calculateMaxDepth = (condition, currentDepth = 1) => {
185
216
  }
186
217
  return currentDepth;
187
218
  };
188
- var countGroups = (condition) => {
219
+ var countConditionGroups = (condition) => {
189
220
  if (import_condition_evaluator.isConditionGroup(condition)) {
190
- return 1 + condition.conditions.reduce((sum, c) => sum + countGroups(c), 0);
221
+ return 1 + condition.conditions.reduce((sum, c) => sum + countConditionGroups(c), 0);
191
222
  }
192
223
  return 0;
193
224
  };
194
- var collectFields = (condition) => {
195
- const fields = new Set;
196
- const traverse = (c) => {
197
- if (import_condition_evaluator.isConditionGroup(c)) {
198
- for (const child of c.conditions) {
199
- traverse(child);
200
- }
201
- } else {
202
- fields.add(c.field);
203
- }
204
- };
205
- traverse(condition);
206
- return fields;
207
- };
225
+
226
+ // src/analyzer/analysis.ts
208
227
  var collectOperators = (condition) => {
209
228
  const operators = new Set;
210
229
  const traverse = (c) => {
211
- if (import_condition_evaluator.isConditionGroup(c)) {
230
+ if (import_condition_evaluator2.isConditionGroup(c)) {
212
231
  operators.add(c.operator);
213
232
  for (const child of c.conditions) {
214
233
  traverse(child);
@@ -226,8 +245,8 @@ var calculateComplexityScore = (totalConditions, maxDepth, groupCount, uniqueFie
226
245
  var analyzeRuleComplexity = (rule) => {
227
246
  const totalConditions = countConditions(rule.conditions);
228
247
  const maxDepth = calculateMaxDepth(rule.conditions);
229
- const groupCount = countGroups(rule.conditions);
230
- const uniqueFields = collectFields(rule.conditions).size;
248
+ const groupCount = countConditionGroups(rule.conditions);
249
+ const uniqueFields = collectConditionFields(rule.conditions).size;
231
250
  const uniqueOperators = collectOperators(rule.conditions).size;
232
251
  const consequenceCount = rule.consequences.length;
233
252
  const complexityScore = calculateComplexityScore(totalConditions, maxDepth, groupCount, uniqueFields);
@@ -264,7 +283,7 @@ var analyzeRuleSet = (rules) => {
264
283
  maxPriority = rule.priority;
265
284
  if (rule.enabled)
266
285
  enabledCount++;
267
- for (const field of collectFields(rule.conditions)) {
286
+ for (const field of collectConditionFields(rule.conditions)) {
268
287
  allFields.add(field);
269
288
  }
270
289
  for (const operator of collectOperators(rule.conditions)) {
@@ -308,7 +327,7 @@ var analyzeFieldUsage = (rules) => {
308
327
  const fieldMap = new Map;
309
328
  for (const rule of rules) {
310
329
  const traverse = (c) => {
311
- if (import_condition_evaluator.isConditionGroup(c)) {
330
+ if (import_condition_evaluator2.isConditionGroup(c)) {
312
331
  for (const child of c.conditions) {
313
332
  traverse(child);
314
333
  }
@@ -340,7 +359,7 @@ var analyzeOperatorUsage = (rules) => {
340
359
  const operatorMap = new Map;
341
360
  for (const rule of rules) {
342
361
  const traverse = (c) => {
343
- if (import_condition_evaluator.isConditionGroup(c)) {
362
+ if (import_condition_evaluator2.isConditionGroup(c)) {
344
363
  for (const child of c.conditions) {
345
364
  traverse(child);
346
365
  }
@@ -358,12 +377,15 @@ var analyzeOperatorUsage = (rules) => {
358
377
  };
359
378
  traverse(rule.conditions);
360
379
  }
361
- return [...operatorMap.entries()].map(([key, data]) => ({
362
- operator: key.split(":")[1],
363
- type: data.type,
364
- count: data.rules.length,
365
- rules: data.rules
366
- })).sort((a, b) => b.count - a.count);
380
+ return [...operatorMap.entries()].map(([key, data]) => {
381
+ const parts = key.split(":");
382
+ return {
383
+ operator: parts[1] ?? "",
384
+ type: data.type,
385
+ count: data.rules.length,
386
+ rules: data.rules
387
+ };
388
+ }).sort((a, b) => b.count - a.count);
367
389
  };
368
390
  var analyzeConsequenceUsage = (rules) => {
369
391
  const consequenceMap = new Map;
@@ -652,15 +674,8 @@ var createCache = (options) => {
652
674
  const evictOldest = () => {
653
675
  if (entries.size === 0)
654
676
  return;
655
- let oldestKey;
656
- let oldestTime = Number.POSITIVE_INFINITY;
657
- for (const [key, entry] of entries) {
658
- if (entry.createdAt < oldestTime) {
659
- oldestTime = entry.createdAt;
660
- oldestKey = key;
661
- }
662
- }
663
- if (oldestKey) {
677
+ const oldestKey = entries.keys().next().value;
678
+ if (oldestKey !== undefined) {
664
679
  const entry = entries.get(oldestKey);
665
680
  entries.delete(oldestKey);
666
681
  evictions++;
@@ -756,7 +771,7 @@ var createNoopCache = () => {
756
771
  };
757
772
  };
758
773
  // src/core/evaluate.ts
759
- var import_condition_evaluator2 = require("@f-o-t/condition-evaluator");
774
+ var import_condition_evaluator3 = require("@f-o-t/condition-evaluator");
760
775
 
761
776
  // src/utils/time.ts
762
777
  var measureTime = (fn) => {
@@ -785,9 +800,6 @@ var withTimeout = (promise, timeoutMs, errorMessage = "Operation timed out") =>
785
800
  });
786
801
  });
787
802
  };
788
- var delay = (ms) => {
789
- return new Promise((resolve) => setTimeout(resolve, ms));
790
- };
791
803
 
792
804
  // src/core/evaluate.ts
793
805
  var evaluateRule = (rule2, context, options = {}) => {
@@ -809,7 +821,7 @@ var evaluateRule = (rule2, context, options = {}) => {
809
821
  data: context.data,
810
822
  metadata: context.metadata
811
823
  };
812
- return import_condition_evaluator2.evaluateConditionGroup(rule2.conditions, evalContext);
824
+ return import_condition_evaluator3.evaluateConditionGroup(rule2.conditions, evalContext);
813
825
  } catch (error) {
814
826
  return {
815
827
  error,
@@ -1021,30 +1033,67 @@ var sortByUpdatedAt = (direction = "desc") => {
1021
1033
  return sortRules({ field: "updatedAt", direction });
1022
1034
  };
1023
1035
  // src/types/config.ts
1024
- var DEFAULT_CACHE_CONFIG = {
1025
- enabled: true,
1026
- ttl: 60000,
1027
- maxSize: 1000
1028
- };
1029
- var DEFAULT_VALIDATION_CONFIG = {
1030
- enabled: true,
1031
- strict: false
1032
- };
1033
- var DEFAULT_VERSIONING_CONFIG = {
1034
- enabled: false,
1035
- maxVersions: 10
1036
- };
1037
- var DEFAULT_ENGINE_CONFIG = {
1038
- conflictResolution: "priority",
1039
- cache: DEFAULT_CACHE_CONFIG,
1040
- validation: DEFAULT_VALIDATION_CONFIG,
1041
- versioning: DEFAULT_VERSIONING_CONFIG,
1042
- logLevel: "warn",
1043
- continueOnError: true,
1044
- slowRuleThresholdMs: 10
1045
- };
1036
+ var import_zod = require("zod");
1037
+ var LogLevelSchema = import_zod.z.enum([
1038
+ "none",
1039
+ "error",
1040
+ "warn",
1041
+ "info",
1042
+ "debug"
1043
+ ]);
1044
+ var CacheConfigSchema = import_zod.z.object({
1045
+ enabled: import_zod.z.boolean().default(true),
1046
+ ttl: import_zod.z.number().int().positive().default(60000),
1047
+ maxSize: import_zod.z.number().int().positive().default(1000)
1048
+ });
1049
+ var ValidationConfigSchema = import_zod.z.object({
1050
+ enabled: import_zod.z.boolean().default(true),
1051
+ strict: import_zod.z.boolean().default(false)
1052
+ });
1053
+ var VersioningConfigSchema = import_zod.z.object({
1054
+ enabled: import_zod.z.boolean().default(false),
1055
+ maxVersions: import_zod.z.number().int().positive().default(10)
1056
+ });
1057
+ var parseCacheConfig = (input) => CacheConfigSchema.parse(input ?? {});
1058
+ var parseValidationConfig = (input) => ValidationConfigSchema.parse(input ?? {});
1059
+ var parseVersioningConfig = (input) => VersioningConfigSchema.parse(input ?? {});
1060
+ var getDefaultCacheConfig = () => CacheConfigSchema.parse({});
1061
+ var getDefaultValidationConfig = () => ValidationConfigSchema.parse({});
1062
+ var getDefaultVersioningConfig = () => VersioningConfigSchema.parse({});
1063
+ var getDefaultLogLevel = () => "warn";
1064
+ var getDefaultConflictResolution = () => "priority";
1046
1065
 
1047
1066
  // src/types/state.ts
1067
+ var import_zod2 = require("zod");
1068
+ var RuleStatsSchema = import_zod2.z.object({
1069
+ evaluations: import_zod2.z.number().int().nonnegative(),
1070
+ matches: import_zod2.z.number().int().nonnegative(),
1071
+ errors: import_zod2.z.number().int().nonnegative(),
1072
+ totalTimeMs: import_zod2.z.number().nonnegative(),
1073
+ avgTimeMs: import_zod2.z.number().nonnegative(),
1074
+ lastEvaluated: import_zod2.z.date().optional()
1075
+ });
1076
+ var CacheStatsSchema = import_zod2.z.object({
1077
+ size: import_zod2.z.number().int().nonnegative(),
1078
+ maxSize: import_zod2.z.number().int().positive(),
1079
+ hits: import_zod2.z.number().int().nonnegative(),
1080
+ misses: import_zod2.z.number().int().nonnegative(),
1081
+ hitRate: import_zod2.z.number().min(0).max(1),
1082
+ evictions: import_zod2.z.number().int().nonnegative()
1083
+ });
1084
+ var EngineStatsSchema = import_zod2.z.object({
1085
+ totalRules: import_zod2.z.number().int().nonnegative(),
1086
+ enabledRules: import_zod2.z.number().int().nonnegative(),
1087
+ disabledRules: import_zod2.z.number().int().nonnegative(),
1088
+ totalRuleSets: import_zod2.z.number().int().nonnegative(),
1089
+ totalEvaluations: import_zod2.z.number().int().nonnegative(),
1090
+ totalMatches: import_zod2.z.number().int().nonnegative(),
1091
+ totalErrors: import_zod2.z.number().int().nonnegative(),
1092
+ avgEvaluationTimeMs: import_zod2.z.number().nonnegative(),
1093
+ cacheHits: import_zod2.z.number().int().nonnegative(),
1094
+ cacheMisses: import_zod2.z.number().int().nonnegative(),
1095
+ cacheHitRate: import_zod2.z.number().min(0).max(1)
1096
+ });
1048
1097
  var createInitialState = () => ({
1049
1098
  rules: new Map,
1050
1099
  ruleSets: new Map,
@@ -1101,82 +1150,73 @@ var generateId = () => {
1101
1150
  };
1102
1151
 
1103
1152
  // src/engine/hooks.ts
1104
- var executeBeforeEvaluation = async (hooks, context, rules) => {
1153
+ var toError = (error) => error instanceof Error ? error : new Error(String(error));
1154
+ var executeWithTimeout = async (hookName, hookFn, hooks, timeoutMs) => {
1155
+ try {
1156
+ const promise = Promise.resolve(hookFn());
1157
+ if (timeoutMs !== undefined && timeoutMs > 0) {
1158
+ await withTimeout(promise, timeoutMs, `Hook '${hookName}' timed out after ${timeoutMs}ms`);
1159
+ } else {
1160
+ await promise;
1161
+ }
1162
+ } catch (error) {
1163
+ hooks.onHookError?.(hookName, toError(error));
1164
+ }
1165
+ };
1166
+ var executeBeforeEvaluation = async (hooks, context, rules, timeoutMs) => {
1105
1167
  if (!hooks.beforeEvaluation)
1106
1168
  return;
1107
- try {
1108
- await hooks.beforeEvaluation(context, rules);
1109
- } catch {}
1169
+ await executeWithTimeout("beforeEvaluation", () => hooks.beforeEvaluation(context, rules), hooks, timeoutMs);
1110
1170
  };
1111
- var executeAfterEvaluation = async (hooks, result) => {
1171
+ var executeAfterEvaluation = async (hooks, result, timeoutMs) => {
1112
1172
  if (!hooks.afterEvaluation)
1113
1173
  return;
1114
- try {
1115
- await hooks.afterEvaluation(result);
1116
- } catch {}
1174
+ await executeWithTimeout("afterEvaluation", () => hooks.afterEvaluation(result), hooks, timeoutMs);
1117
1175
  };
1118
- var executeBeforeRuleEvaluation = async (hooks, rule2, context) => {
1176
+ var executeBeforeRuleEvaluation = async (hooks, rule2, context, timeoutMs) => {
1119
1177
  if (!hooks.beforeRuleEvaluation)
1120
1178
  return;
1121
- try {
1122
- await hooks.beforeRuleEvaluation(rule2, context);
1123
- } catch {}
1179
+ await executeWithTimeout("beforeRuleEvaluation", () => hooks.beforeRuleEvaluation(rule2, context), hooks, timeoutMs);
1124
1180
  };
1125
- var executeAfterRuleEvaluation = async (hooks, rule2, result) => {
1181
+ var executeAfterRuleEvaluation = async (hooks, rule2, result, timeoutMs) => {
1126
1182
  if (!hooks.afterRuleEvaluation)
1127
1183
  return;
1128
- try {
1129
- await hooks.afterRuleEvaluation(rule2, result);
1130
- } catch {}
1184
+ await executeWithTimeout("afterRuleEvaluation", () => hooks.afterRuleEvaluation(rule2, result), hooks, timeoutMs);
1131
1185
  };
1132
- var executeOnRuleMatch = async (hooks, rule2, context) => {
1186
+ var executeOnRuleMatch = async (hooks, rule2, context, timeoutMs) => {
1133
1187
  if (!hooks.onRuleMatch)
1134
1188
  return;
1135
- try {
1136
- await hooks.onRuleMatch(rule2, context);
1137
- } catch {}
1189
+ await executeWithTimeout("onRuleMatch", () => hooks.onRuleMatch(rule2, context), hooks, timeoutMs);
1138
1190
  };
1139
- var executeOnRuleSkip = async (hooks, rule2, reason) => {
1191
+ var executeOnRuleSkip = async (hooks, rule2, reason, timeoutMs) => {
1140
1192
  if (!hooks.onRuleSkip)
1141
1193
  return;
1142
- try {
1143
- await hooks.onRuleSkip(rule2, reason);
1144
- } catch {}
1194
+ await executeWithTimeout("onRuleSkip", () => hooks.onRuleSkip(rule2, reason), hooks, timeoutMs);
1145
1195
  };
1146
- var executeOnRuleError = async (hooks, rule2, error) => {
1196
+ var executeOnRuleError = async (hooks, rule2, ruleError, timeoutMs) => {
1147
1197
  if (!hooks.onRuleError)
1148
1198
  return;
1149
- try {
1150
- await hooks.onRuleError(rule2, error);
1151
- } catch {}
1199
+ await executeWithTimeout("onRuleError", () => hooks.onRuleError(rule2, ruleError), hooks, timeoutMs);
1152
1200
  };
1153
- var executeOnConsequenceCollected = async (hooks, rule2, consequence) => {
1201
+ var executeOnConsequenceCollected = async (hooks, rule2, consequence, timeoutMs) => {
1154
1202
  if (!hooks.onConsequenceCollected)
1155
1203
  return;
1156
- try {
1157
- await hooks.onConsequenceCollected(rule2, consequence);
1158
- } catch {}
1204
+ await executeWithTimeout("onConsequenceCollected", () => hooks.onConsequenceCollected(rule2, consequence), hooks, timeoutMs);
1159
1205
  };
1160
- var executeOnCacheHit = async (hooks, key, result) => {
1206
+ var executeOnCacheHit = async (hooks, key, result, timeoutMs) => {
1161
1207
  if (!hooks.onCacheHit)
1162
1208
  return;
1163
- try {
1164
- await hooks.onCacheHit(key, result);
1165
- } catch {}
1209
+ await executeWithTimeout("onCacheHit", () => hooks.onCacheHit(key, result), hooks, timeoutMs);
1166
1210
  };
1167
- var executeOnCacheMiss = async (hooks, key) => {
1211
+ var executeOnCacheMiss = async (hooks, key, timeoutMs) => {
1168
1212
  if (!hooks.onCacheMiss)
1169
1213
  return;
1170
- try {
1171
- await hooks.onCacheMiss(key);
1172
- } catch {}
1214
+ await executeWithTimeout("onCacheMiss", () => hooks.onCacheMiss(key), hooks, timeoutMs);
1173
1215
  };
1174
- var executeOnSlowRule = async (hooks, rule2, timeMs, threshold) => {
1216
+ var executeOnSlowRule = async (hooks, rule2, timeMs, threshold, timeoutMs) => {
1175
1217
  if (!hooks.onSlowRule)
1176
1218
  return;
1177
- try {
1178
- await hooks.onSlowRule(rule2, timeMs, threshold);
1179
- } catch {}
1219
+ await executeWithTimeout("onSlowRule", () => hooks.onSlowRule(rule2, timeMs, threshold), hooks, timeoutMs);
1180
1220
  };
1181
1221
 
1182
1222
  // src/engine/state.ts
@@ -1361,24 +1401,25 @@ var cloneState = (state) => {
1361
1401
  var resolveConfig = (config) => {
1362
1402
  return {
1363
1403
  consequences: config.consequences,
1364
- conflictResolution: config.conflictResolution ?? DEFAULT_ENGINE_CONFIG.conflictResolution,
1404
+ conflictResolution: config.conflictResolution ?? getDefaultConflictResolution(),
1365
1405
  cache: {
1366
- ...DEFAULT_CACHE_CONFIG,
1406
+ ...getDefaultCacheConfig(),
1367
1407
  ...config.cache
1368
1408
  },
1369
1409
  validation: {
1370
- ...DEFAULT_VALIDATION_CONFIG,
1410
+ ...getDefaultValidationConfig(),
1371
1411
  ...config.validation
1372
1412
  },
1373
1413
  versioning: {
1374
- ...DEFAULT_VERSIONING_CONFIG,
1414
+ ...getDefaultVersioningConfig(),
1375
1415
  ...config.versioning
1376
1416
  },
1377
1417
  hooks: config.hooks ?? {},
1378
- logLevel: config.logLevel ?? DEFAULT_ENGINE_CONFIG.logLevel,
1418
+ logLevel: config.logLevel ?? getDefaultLogLevel(),
1379
1419
  logger: config.logger ?? console,
1380
- continueOnError: config.continueOnError ?? DEFAULT_ENGINE_CONFIG.continueOnError,
1381
- slowRuleThresholdMs: config.slowRuleThresholdMs ?? DEFAULT_ENGINE_CONFIG.slowRuleThresholdMs
1420
+ continueOnError: config.continueOnError ?? true,
1421
+ slowRuleThresholdMs: config.slowRuleThresholdMs ?? 10,
1422
+ hookTimeoutMs: config.hookTimeoutMs
1382
1423
  };
1383
1424
  };
1384
1425
  var createEngine = (config = {}) => {
@@ -1410,12 +1451,6 @@ var createEngine = (config = {}) => {
1410
1451
  const ruleSetIds = new Set(ruleSetRules.map((r) => r.id));
1411
1452
  rulesToEvaluate = rulesToEvaluate.filter((r) => ruleSetIds.has(r.id));
1412
1453
  }
1413
- rulesToEvaluate = [
1414
- ...sortRules({
1415
- field: "priority",
1416
- direction: "desc"
1417
- })(rulesToEvaluate)
1418
- ];
1419
1454
  if (options.maxRules && options.maxRules > 0) {
1420
1455
  rulesToEvaluate = rulesToEvaluate.slice(0, options.maxRules);
1421
1456
  }
@@ -1424,15 +1459,15 @@ var createEngine = (config = {}) => {
1424
1459
  const cached = cache.get(cacheKey);
1425
1460
  if (cached) {
1426
1461
  cacheHits++;
1427
- await executeOnCacheHit(resolvedConfig.hooks, cacheKey, cached);
1462
+ await executeOnCacheHit(resolvedConfig.hooks, cacheKey, cached, resolvedConfig.hookTimeoutMs);
1428
1463
  return { ...cached, cacheHit: true };
1429
1464
  }
1430
1465
  }
1431
1466
  if (cacheKey) {
1432
1467
  cacheMisses++;
1433
- await executeOnCacheMiss(resolvedConfig.hooks, cacheKey);
1468
+ await executeOnCacheMiss(resolvedConfig.hooks, cacheKey, resolvedConfig.hookTimeoutMs);
1434
1469
  }
1435
- await executeBeforeEvaluation(resolvedConfig.hooks, context, rulesToEvaluate);
1470
+ await executeBeforeEvaluation(resolvedConfig.hooks, context, rulesToEvaluate, resolvedConfig.hookTimeoutMs);
1436
1471
  const { result: evaluationResult, durationMs } = measureTime(() => {
1437
1472
  const results = [];
1438
1473
  for (const rule2 of rulesToEvaluate) {
@@ -1449,29 +1484,29 @@ var createEngine = (config = {}) => {
1449
1484
  let rulesErrored = 0;
1450
1485
  const conflictResolution = options.conflictResolution ?? resolvedConfig.conflictResolution;
1451
1486
  for (const { rule: rule2, result } of evaluationResult) {
1452
- await executeBeforeRuleEvaluation(resolvedConfig.hooks, rule2, context);
1487
+ await executeBeforeRuleEvaluation(resolvedConfig.hooks, rule2, context, resolvedConfig.hookTimeoutMs);
1453
1488
  ruleResults.push(result);
1454
1489
  if (result.error) {
1455
1490
  rulesErrored++;
1456
- await executeOnRuleError(resolvedConfig.hooks, rule2, result.error);
1491
+ await executeOnRuleError(resolvedConfig.hooks, rule2, result.error, resolvedConfig.hookTimeoutMs);
1457
1492
  if (!resolvedConfig.continueOnError) {
1458
1493
  break;
1459
1494
  }
1460
1495
  }
1461
1496
  if (result.skipped) {
1462
- await executeOnRuleSkip(resolvedConfig.hooks, rule2, result.skipReason ?? "Unknown");
1497
+ await executeOnRuleSkip(resolvedConfig.hooks, rule2, result.skipReason ?? "Unknown", resolvedConfig.hookTimeoutMs);
1463
1498
  }
1464
1499
  if (result.evaluationTimeMs > resolvedConfig.slowRuleThresholdMs) {
1465
- await executeOnSlowRule(resolvedConfig.hooks, rule2, result.evaluationTimeMs, resolvedConfig.slowRuleThresholdMs);
1500
+ await executeOnSlowRule(resolvedConfig.hooks, rule2, result.evaluationTimeMs, resolvedConfig.slowRuleThresholdMs, resolvedConfig.hookTimeoutMs);
1466
1501
  }
1467
- await executeAfterRuleEvaluation(resolvedConfig.hooks, rule2, result);
1502
+ await executeAfterRuleEvaluation(resolvedConfig.hooks, rule2, result, resolvedConfig.hookTimeoutMs);
1468
1503
  if (result.matched) {
1469
1504
  matchedRules.push(rule2);
1470
1505
  for (const consequence of result.consequences) {
1471
1506
  consequences.push(consequence);
1472
- await executeOnConsequenceCollected(resolvedConfig.hooks, rule2, consequence);
1507
+ await executeOnConsequenceCollected(resolvedConfig.hooks, rule2, consequence, resolvedConfig.hookTimeoutMs);
1473
1508
  }
1474
- await executeOnRuleMatch(resolvedConfig.hooks, rule2, context);
1509
+ await executeOnRuleMatch(resolvedConfig.hooks, rule2, context, resolvedConfig.hookTimeoutMs);
1475
1510
  if (rule2.stopOnMatch) {
1476
1511
  stoppedEarly = true;
1477
1512
  stoppedByRuleId = rule2.id;
@@ -1505,7 +1540,7 @@ var createEngine = (config = {}) => {
1505
1540
  if (cacheKey) {
1506
1541
  cache.set(cacheKey, executionResult);
1507
1542
  }
1508
- await executeAfterEvaluation(resolvedConfig.hooks, executionResult);
1543
+ await executeAfterEvaluation(resolvedConfig.hooks, executionResult, resolvedConfig.hookTimeoutMs);
1509
1544
  return executionResult;
1510
1545
  };
1511
1546
  return {
@@ -1555,7 +1590,6 @@ var createEngine = (config = {}) => {
1555
1590
  }),
1556
1591
  getStats: () => {
1557
1592
  const enabledRules = Array.from(state.rules.values()).filter((r) => r.enabled).length;
1558
- const cacheStats = cache.getStats();
1559
1593
  return {
1560
1594
  totalRules: state.rules.size,
1561
1595
  enabledRules,
@@ -1573,27 +1607,12 @@ var createEngine = (config = {}) => {
1573
1607
  };
1574
1608
  };
1575
1609
  // src/optimizer/index-builder.ts
1576
- var import_condition_evaluator3 = require("@f-o-t/condition-evaluator");
1577
1610
  var DEFAULT_OPTIONS = {
1578
1611
  indexByField: true,
1579
1612
  indexByTag: true,
1580
1613
  indexByCategory: true,
1581
1614
  indexByPriority: true
1582
1615
  };
1583
- var collectFields2 = (condition) => {
1584
- const fields = new Set;
1585
- const traverse = (c) => {
1586
- if (import_condition_evaluator3.isConditionGroup(c)) {
1587
- for (const child of c.conditions) {
1588
- traverse(child);
1589
- }
1590
- } else {
1591
- fields.add(c.field);
1592
- }
1593
- };
1594
- traverse(condition);
1595
- return fields;
1596
- };
1597
1616
  var buildIndex = (rules, options = {}) => {
1598
1617
  const opts = { ...DEFAULT_OPTIONS, ...options };
1599
1618
  const byId = new Map;
@@ -1604,7 +1623,7 @@ var buildIndex = (rules, options = {}) => {
1604
1623
  for (const rule2 of rules) {
1605
1624
  byId.set(rule2.id, rule2);
1606
1625
  if (opts.indexByField) {
1607
- const fields = collectFields2(rule2.conditions);
1626
+ const fields = collectConditionFields(rule2.conditions);
1608
1627
  for (const field of fields) {
1609
1628
  const existing = byField.get(field) ?? [];
1610
1629
  existing.push(rule2);
@@ -1709,7 +1728,7 @@ var analyzeOptimizations = (rules) => {
1709
1728
  const suggestions = [];
1710
1729
  const fieldUsage = new Map;
1711
1730
  for (const rule2 of rules) {
1712
- const fields = collectFields2(rule2.conditions);
1731
+ const fields = collectConditionFields(rule2.conditions);
1713
1732
  for (const field of fields) {
1714
1733
  fieldUsage.set(field, (fieldUsage.get(field) ?? 0) + 1);
1715
1734
  }
@@ -1862,6 +1881,8 @@ var importRules = (data, options = {}) => {
1862
1881
  for (let i = 0;i < data.rules.length; i++) {
1863
1882
  try {
1864
1883
  const serialized = data.rules[i];
1884
+ if (!serialized)
1885
+ continue;
1865
1886
  const rule2 = deserializeRule(serialized, options);
1866
1887
  idMapping.set(serialized.id, rule2.id);
1867
1888
  rules.push(rule2);
@@ -1877,6 +1898,8 @@ var importRules = (data, options = {}) => {
1877
1898
  for (let i = 0;i < data.ruleSets.length; i++) {
1878
1899
  try {
1879
1900
  const serialized = data.ruleSets[i];
1901
+ if (!serialized)
1902
+ continue;
1880
1903
  const ruleSet = deserializeRuleSet(serialized, idMapping, options);
1881
1904
  ruleSets.push(ruleSet);
1882
1905
  } catch (error) {
@@ -1888,12 +1911,25 @@ var importRules = (data, options = {}) => {
1888
1911
  }
1889
1912
  }
1890
1913
  }
1914
+ const importedRuleIds = new Set(rules.map((r) => r.id));
1915
+ const orphanedReferences = [];
1916
+ for (const ruleSet of ruleSets) {
1917
+ const missingRuleIds = ruleSet.ruleIds.filter((id) => !importedRuleIds.has(id));
1918
+ if (missingRuleIds.length > 0) {
1919
+ orphanedReferences.push({
1920
+ ruleSetId: ruleSet.id,
1921
+ ruleSetName: ruleSet.name,
1922
+ missingRuleIds
1923
+ });
1924
+ }
1925
+ }
1891
1926
  return {
1892
1927
  success: errors.length === 0,
1893
1928
  rules,
1894
1929
  ruleSets,
1895
1930
  errors,
1896
- idMapping
1931
+ idMapping,
1932
+ orphanedReferences
1897
1933
  };
1898
1934
  };
1899
1935
  var importFromJson = (json, options = {}) => {
@@ -1912,7 +1948,8 @@ var importFromJson = (json, options = {}) => {
1912
1948
  message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`
1913
1949
  }
1914
1950
  ],
1915
- idMapping: new Map
1951
+ idMapping: new Map,
1952
+ orphanedReferences: []
1916
1953
  };
1917
1954
  }
1918
1955
  };
@@ -2049,8 +2086,8 @@ var whatIf = (originalRules, modifiedRules, context) => {
2049
2086
  const [ruleId, consequenceType] = key.split(":");
2050
2087
  consequenceChanges.push({
2051
2088
  type: "added",
2052
- consequenceType,
2053
- ruleId
2089
+ consequenceType: consequenceType ?? "",
2090
+ ruleId: ruleId ?? ""
2054
2091
  });
2055
2092
  }
2056
2093
  }
@@ -2059,8 +2096,8 @@ var whatIf = (originalRules, modifiedRules, context) => {
2059
2096
  const [ruleId, consequenceType] = key.split(":");
2060
2097
  consequenceChanges.push({
2061
2098
  type: "removed",
2062
- consequenceType,
2063
- ruleId
2099
+ consequenceType: consequenceType ?? "",
2100
+ ruleId: ruleId ?? ""
2064
2101
  });
2065
2102
  }
2066
2103
  }
@@ -2149,49 +2186,59 @@ var formatSimulationResult = (result) => {
2149
2186
  return lines.join(`
2150
2187
  `);
2151
2188
  };
2189
+ // src/types/evaluation.ts
2190
+ var import_zod3 = require("zod");
2191
+ var ConflictResolutionStrategySchema = import_zod3.z.enum([
2192
+ "priority",
2193
+ "first-match",
2194
+ "all",
2195
+ "most-specific"
2196
+ ]);
2197
+ var EvaluateOptionsSchema = import_zod3.z.object({
2198
+ conflictResolution: ConflictResolutionStrategySchema.optional(),
2199
+ maxRules: import_zod3.z.number().int().positive().optional(),
2200
+ timeout: import_zod3.z.number().int().positive().optional(),
2201
+ skipDisabled: import_zod3.z.boolean().optional(),
2202
+ tags: import_zod3.z.array(import_zod3.z.string()).optional(),
2203
+ category: import_zod3.z.string().optional(),
2204
+ ruleSetId: import_zod3.z.string().optional(),
2205
+ bypassCache: import_zod3.z.boolean().optional()
2206
+ });
2207
+ var EvaluateConfigSchema = import_zod3.z.object({
2208
+ conflictResolution: ConflictResolutionStrategySchema,
2209
+ continueOnError: import_zod3.z.boolean(),
2210
+ collectAllConsequences: import_zod3.z.boolean()
2211
+ });
2152
2212
  // src/types/rule.ts
2153
- var import_zod = require("zod");
2154
- var RuleSchema = import_zod.z.object({
2155
- id: import_zod.z.string().min(1),
2156
- name: import_zod.z.string().min(1),
2157
- description: import_zod.z.string().optional(),
2158
- conditions: import_zod.z.custom((val) => {
2213
+ var import_zod4 = require("zod");
2214
+ var RuleSchema = import_zod4.z.object({
2215
+ id: import_zod4.z.string().min(1),
2216
+ name: import_zod4.z.string().min(1),
2217
+ description: import_zod4.z.string().optional(),
2218
+ conditions: import_zod4.z.custom((val) => {
2159
2219
  return typeof val === "object" && val !== null && "id" in val && "operator" in val;
2160
2220
  }, "Invalid condition group"),
2161
- consequences: import_zod.z.array(import_zod.z.object({
2162
- type: import_zod.z.string(),
2163
- payload: import_zod.z.unknown()
2221
+ consequences: import_zod4.z.array(import_zod4.z.object({
2222
+ type: import_zod4.z.string(),
2223
+ payload: import_zod4.z.unknown()
2164
2224
  })),
2165
- priority: import_zod.z.number().int().default(0),
2166
- enabled: import_zod.z.boolean().default(true),
2167
- stopOnMatch: import_zod.z.boolean().default(false),
2168
- tags: import_zod.z.array(import_zod.z.string()).default([]),
2169
- category: import_zod.z.string().optional(),
2170
- metadata: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
2171
- createdAt: import_zod.z.date().default(() => new Date),
2172
- updatedAt: import_zod.z.date().default(() => new Date)
2225
+ priority: import_zod4.z.number().int().default(0),
2226
+ enabled: import_zod4.z.boolean().default(true),
2227
+ stopOnMatch: import_zod4.z.boolean().default(false),
2228
+ tags: import_zod4.z.array(import_zod4.z.string()).default([]),
2229
+ category: import_zod4.z.string().optional(),
2230
+ metadata: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional(),
2231
+ createdAt: import_zod4.z.date().default(() => new Date),
2232
+ updatedAt: import_zod4.z.date().default(() => new Date)
2173
2233
  });
2174
- var RuleSetSchema = import_zod.z.object({
2175
- id: import_zod.z.string().min(1),
2176
- name: import_zod.z.string().min(1),
2177
- description: import_zod.z.string().optional(),
2178
- ruleIds: import_zod.z.array(import_zod.z.string()),
2179
- enabled: import_zod.z.boolean().default(true),
2180
- metadata: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
2234
+ var RuleSetSchema = import_zod4.z.object({
2235
+ id: import_zod4.z.string().min(1),
2236
+ name: import_zod4.z.string().min(1),
2237
+ description: import_zod4.z.string().optional(),
2238
+ ruleIds: import_zod4.z.array(import_zod4.z.string()),
2239
+ enabled: import_zod4.z.boolean().default(true),
2240
+ metadata: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional()
2181
2241
  });
2182
- // src/utils/pipe.ts
2183
- function pipe(...fns) {
2184
- return (value) => fns.reduce((acc, fn) => fn(acc), value);
2185
- }
2186
- function compose(...fns) {
2187
- return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
2188
- }
2189
- var identity = (value) => value;
2190
- var always = (value) => () => value;
2191
- var tap = (fn) => (value) => {
2192
- fn(value);
2193
- return value;
2194
- };
2195
2242
  // src/validation/conflicts.ts
2196
2243
  var import_condition_evaluator4 = require("@f-o-t/condition-evaluator");
2197
2244
  var DEFAULT_OPTIONS2 = {
@@ -2201,11 +2248,11 @@ var DEFAULT_OPTIONS2 = {
2201
2248
  checkPriorityCollisions: true,
2202
2249
  checkUnreachableRules: true
2203
2250
  };
2204
- var collectConditionFields = (condition) => {
2251
+ var collectConditionFields2 = (condition) => {
2205
2252
  const fields = new Set;
2206
2253
  if (import_condition_evaluator4.isConditionGroup(condition)) {
2207
2254
  for (const child of condition.conditions) {
2208
- const childFields = collectConditionFields(child);
2255
+ const childFields = collectConditionFields2(child);
2209
2256
  for (const field of childFields) {
2210
2257
  fields.add(field);
2211
2258
  }
@@ -2240,8 +2287,8 @@ var getConditionOperatorValues = (condition, field) => {
2240
2287
  return results;
2241
2288
  };
2242
2289
  var areConditionsOverlapping = (conditions1, conditions2) => {
2243
- const fields1 = collectConditionFields(conditions1);
2244
- const fields2 = collectConditionFields(conditions2);
2290
+ const fields1 = collectConditionFields2(conditions1);
2291
+ const fields2 = collectConditionFields2(conditions2);
2245
2292
  const commonFields = new Set([...fields1].filter((f) => fields2.has(f)));
2246
2293
  if (commonFields.size === 0)
2247
2294
  return false;
@@ -2324,6 +2371,8 @@ var findOverlappingConditions = (rules) => {
2324
2371
  for (let j = i + 1;j < rules.length; j++) {
2325
2372
  const rule1 = rules[i];
2326
2373
  const rule2 = rules[j];
2374
+ if (!rule1 || !rule2)
2375
+ continue;
2327
2376
  const key = [rule1.id, rule2.id].sort().join(":");
2328
2377
  if (checked.has(key))
2329
2378
  continue;
@@ -2336,8 +2385,8 @@ var findOverlappingConditions = (rules) => {
2336
2385
  ruleIds: [rule1.id, rule2.id],
2337
2386
  rules: [rule1, rule2],
2338
2387
  details: {
2339
- rule1Fields: [...collectConditionFields(rule1.conditions)],
2340
- rule2Fields: [...collectConditionFields(rule2.conditions)]
2388
+ rule1Fields: [...collectConditionFields2(rule1.conditions)],
2389
+ rule2Fields: [...collectConditionFields2(rule2.conditions)]
2341
2390
  }
2342
2391
  });
2343
2392
  }
@@ -2360,6 +2409,8 @@ var findPriorityCollisions = (rules) => {
2360
2409
  for (let j = i + 1;j < rulesWithPriority.length; j++) {
2361
2410
  const r1 = rulesWithPriority[i];
2362
2411
  const r2 = rulesWithPriority[j];
2412
+ if (!r1 || !r2)
2413
+ continue;
2363
2414
  if (areConditionsOverlapping(r1.conditions, r2.conditions)) {
2364
2415
  overlappingPairs.add(r1.id);
2365
2416
  overlappingPairs.add(r2.id);
@@ -2386,10 +2437,14 @@ var findUnreachableRules = (rules) => {
2386
2437
  const sortedRules = [...rules].sort((a, b) => b.priority - a.priority);
2387
2438
  for (let i = 0;i < sortedRules.length; i++) {
2388
2439
  const rule2 = sortedRules[i];
2440
+ if (!rule2)
2441
+ continue;
2389
2442
  if (!rule2.enabled)
2390
2443
  continue;
2391
2444
  for (let j = 0;j < i; j++) {
2392
2445
  const higherPriorityRule = sortedRules[j];
2446
+ if (!higherPriorityRule)
2447
+ continue;
2393
2448
  if (!higherPriorityRule.enabled || !higherPriorityRule.stopOnMatch) {
2394
2449
  continue;
2395
2450
  }
@@ -2528,7 +2583,7 @@ var checkRuleIntegrity = (rule2, options) => {
2528
2583
  }
2529
2584
  }
2530
2585
  if (options.allowedTags) {
2531
- const invalidTags = rule2.tags.filter((t) => !options.allowedTags.includes(t));
2586
+ const invalidTags = rule2.tags.filter((t) => !options.allowedTags?.includes(t));
2532
2587
  if (invalidTags.length > 0) {
2533
2588
  issues.push(createIssue("INVALID_TAGS", `Rule "${rule2.name}" has invalid tags: ${invalidTags.join(", ")}`, "warning", {
2534
2589
  ruleId: rule2.id,
@@ -2701,11 +2756,22 @@ ${severity.toUpperCase()}S (${issues.length}):`);
2701
2756
  };
2702
2757
  // src/validation/schema.ts
2703
2758
  var import_condition_evaluator6 = require("@f-o-t/condition-evaluator");
2704
- var DEFAULT_OPTIONS4 = {
2705
- validateConditions: true,
2706
- validateConsequences: true,
2707
- strictMode: false
2708
- };
2759
+ var import_zod5 = require("zod");
2760
+ var ValidationErrorSchema = import_zod5.z.object({
2761
+ path: import_zod5.z.string(),
2762
+ message: import_zod5.z.string(),
2763
+ code: import_zod5.z.string()
2764
+ });
2765
+ var ValidationResultSchema = import_zod5.z.object({
2766
+ valid: import_zod5.z.boolean(),
2767
+ errors: import_zod5.z.array(ValidationErrorSchema)
2768
+ });
2769
+ var ValidationOptionsSchema = import_zod5.z.object({
2770
+ validateConditions: import_zod5.z.boolean().optional(),
2771
+ validateConsequences: import_zod5.z.boolean().optional(),
2772
+ strictMode: import_zod5.z.boolean().optional()
2773
+ });
2774
+ var DEFAULT_OPTIONS4 = ValidationOptionsSchema.parse({});
2709
2775
  var createError = (path, message, code) => ({
2710
2776
  path,
2711
2777
  message,
@@ -2717,7 +2783,7 @@ var validResult = () => ({
2717
2783
  });
2718
2784
  var invalidResult = (errors) => ({
2719
2785
  valid: false,
2720
- errors
2786
+ errors: [...errors]
2721
2787
  });
2722
2788
  var validateConditionStructure = (condition, path) => {
2723
2789
  const errors = [];
@@ -2758,6 +2824,8 @@ var validateConsequenceStructure = (consequences, consequenceSchemas, strictMode
2758
2824
  const errors = [];
2759
2825
  for (let i = 0;i < consequences.length; i++) {
2760
2826
  const consequence = consequences[i];
2827
+ if (!consequence)
2828
+ continue;
2761
2829
  const path = `consequences[${i}]`;
2762
2830
  if (!consequence.type || typeof consequence.type !== "string") {
2763
2831
  errors.push(createError(`${path}.type`, "Consequence must have a type", "MISSING_CONSEQUENCE_TYPE"));
@@ -2794,8 +2862,8 @@ var validateRule = (rule2, options = {}) => {
2794
2862
  const conditionErrors = validateConditionStructure(validRule.conditions, "conditions");
2795
2863
  errors.push(...conditionErrors);
2796
2864
  }
2797
- if (opts.validateConsequences) {
2798
- const consequenceErrors = validateConsequenceStructure(validRule.consequences, opts.consequenceSchemas, opts.strictMode);
2865
+ if (opts.validateConsequences || opts.strictMode) {
2866
+ const consequenceErrors = validateConsequenceStructure(validRule.consequences, opts.consequenceSchemas, opts.strictMode ?? false);
2799
2867
  errors.push(...consequenceErrors);
2800
2868
  }
2801
2869
  return errors.length > 0 ? invalidResult(errors) : validResult();