@f-o-t/rules-engine 3.0.0 → 3.0.5

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 (105) hide show
  1. package/dist/analyzer/analysis.d.ts +72 -0
  2. package/dist/analyzer/analysis.d.ts.map +1 -0
  3. package/dist/builder/conditions.d.ts +29 -0
  4. package/dist/builder/conditions.d.ts.map +1 -0
  5. package/dist/builder/rule.d.ts +40 -0
  6. package/dist/builder/rule.d.ts.map +1 -0
  7. package/dist/cache/cache.d.ts +21 -0
  8. package/dist/cache/cache.d.ts.map +1 -0
  9. package/dist/cache/noop.d.ts +3 -0
  10. package/dist/cache/noop.d.ts.map +1 -0
  11. package/dist/core/evaluate.d.ts +21 -0
  12. package/dist/core/evaluate.d.ts.map +1 -0
  13. package/dist/core/filter.d.ts +8 -0
  14. package/dist/core/filter.d.ts.map +1 -0
  15. package/dist/core/group.d.ts +10 -0
  16. package/dist/core/group.d.ts.map +1 -0
  17. package/dist/core/sort.d.ts +14 -0
  18. package/dist/core/sort.d.ts.map +1 -0
  19. package/dist/engine/engine.d.ts +27 -0
  20. package/dist/engine/engine.d.ts.map +1 -0
  21. package/dist/engine/hooks.d.ts +16 -0
  22. package/dist/engine/hooks.d.ts.map +1 -0
  23. package/dist/engine/state.d.ts +19 -0
  24. package/dist/engine/state.d.ts.map +1 -0
  25. package/dist/index.d.ts +33 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +3083 -0
  28. package/dist/index.js.map +37 -0
  29. package/dist/optimizer/index-builder.d.ts +48 -0
  30. package/dist/optimizer/index-builder.d.ts.map +1 -0
  31. package/dist/serialization/serializer.d.ts +79 -0
  32. package/dist/serialization/serializer.d.ts.map +1 -0
  33. package/dist/simulation/simulator.d.ts +65 -0
  34. package/dist/simulation/simulator.d.ts.map +1 -0
  35. package/dist/types/config.d.ts +87 -0
  36. package/dist/types/config.d.ts.map +1 -0
  37. package/dist/types/consequence.d.ts +21 -0
  38. package/dist/types/consequence.d.ts.map +1 -0
  39. package/dist/types/evaluation.d.ts +70 -0
  40. package/dist/types/evaluation.d.ts.map +1 -0
  41. package/dist/types/rule.d.ts +114 -0
  42. package/dist/types/rule.d.ts.map +1 -0
  43. package/dist/types/state.d.ts +65 -0
  44. package/dist/types/state.d.ts.map +1 -0
  45. package/dist/utils/conditions.d.ts +24 -0
  46. package/dist/utils/conditions.d.ts.map +1 -0
  47. package/dist/utils/hash.d.ts +3 -0
  48. package/dist/utils/hash.d.ts.map +1 -0
  49. package/dist/utils/id.d.ts +2 -0
  50. package/dist/utils/id.d.ts.map +1 -0
  51. package/dist/utils/time.d.ts +8 -0
  52. package/dist/utils/time.d.ts.map +1 -0
  53. package/dist/validation/conflicts.d.ts +25 -0
  54. package/dist/validation/conflicts.d.ts.map +1 -0
  55. package/dist/validation/integrity.d.ts +38 -0
  56. package/dist/validation/integrity.d.ts.map +1 -0
  57. package/dist/validation/schema.d.ts +69 -0
  58. package/dist/validation/schema.d.ts.map +1 -0
  59. package/dist/versioning/version-store.d.ts +50 -0
  60. package/dist/versioning/version-store.d.ts.map +1 -0
  61. package/package.json +35 -31
  62. package/CHANGELOG.md +0 -168
  63. package/__tests__/builder.test.ts +0 -363
  64. package/__tests__/cache.test.ts +0 -130
  65. package/__tests__/config.test.ts +0 -35
  66. package/__tests__/engine.test.ts +0 -1213
  67. package/__tests__/evaluate.test.ts +0 -339
  68. package/__tests__/exports.test.ts +0 -30
  69. package/__tests__/filter-sort.test.ts +0 -303
  70. package/__tests__/integration.test.ts +0 -419
  71. package/__tests__/money-integration.test.ts +0 -149
  72. package/__tests__/validation.test.ts +0 -862
  73. package/biome.json +0 -39
  74. package/docs/MIGRATION-v3.md +0 -118
  75. package/fot.config.ts +0 -5
  76. package/src/analyzer/analysis.ts +0 -401
  77. package/src/builder/conditions.ts +0 -321
  78. package/src/builder/rule.ts +0 -192
  79. package/src/cache/cache.ts +0 -135
  80. package/src/cache/noop.ts +0 -20
  81. package/src/core/evaluate.ts +0 -185
  82. package/src/core/filter.ts +0 -85
  83. package/src/core/group.ts +0 -103
  84. package/src/core/sort.ts +0 -90
  85. package/src/engine/engine.ts +0 -462
  86. package/src/engine/hooks.ts +0 -235
  87. package/src/engine/state.ts +0 -322
  88. package/src/index.ts +0 -303
  89. package/src/optimizer/index-builder.ts +0 -381
  90. package/src/serialization/serializer.ts +0 -408
  91. package/src/simulation/simulator.ts +0 -359
  92. package/src/types/config.ts +0 -184
  93. package/src/types/consequence.ts +0 -38
  94. package/src/types/evaluation.ts +0 -87
  95. package/src/types/rule.ts +0 -112
  96. package/src/types/state.ts +0 -116
  97. package/src/utils/conditions.ts +0 -108
  98. package/src/utils/hash.ts +0 -30
  99. package/src/utils/id.ts +0 -6
  100. package/src/utils/time.ts +0 -42
  101. package/src/validation/conflicts.ts +0 -440
  102. package/src/validation/integrity.ts +0 -473
  103. package/src/validation/schema.ts +0 -386
  104. package/src/versioning/version-store.ts +0 -337
  105. package/tsconfig.json +0 -29
@@ -1,462 +0,0 @@
1
- import { type Cache, createCache } from "../cache/cache";
2
- import { createNoopCache } from "../cache/noop";
3
- import { evaluateRule } from "../core/evaluate";
4
- import { createEvaluator } from "@f-o-t/condition-evaluator";
5
- import {
6
- type EngineConfig,
7
- getDefaultCacheConfig,
8
- getDefaultConflictResolution,
9
- getDefaultLogLevel,
10
- getDefaultValidationConfig,
11
- getDefaultVersioningConfig,
12
- type ResolvedEngineConfig,
13
- } from "../types/config";
14
- import type {
15
- AggregatedConsequence,
16
- ConsequenceDefinitions,
17
- DefaultConsequences,
18
- } from "../types/consequence";
19
- import type {
20
- EngineExecutionResult,
21
- EvaluateOptions,
22
- EvaluationContext,
23
- } from "../types/evaluation";
24
- import type {
25
- Rule,
26
- RuleFilters,
27
- RuleInput,
28
- RuleSet,
29
- RuleSetInput,
30
- } from "../types/rule";
31
- import type {
32
- CacheStats,
33
- EngineState,
34
- EngineStats,
35
- MutableEngineState,
36
- } from "../types/state";
37
- import { createInitialState } from "../types/state";
38
- import { hashContext, hashRules } from "../utils/hash";
39
- import { generateId } from "../utils/id";
40
- import { measureTime } from "../utils/time";
41
- import {
42
- executeAfterEvaluation,
43
- executeAfterRuleEvaluation,
44
- executeBeforeEvaluation,
45
- executeBeforeRuleEvaluation,
46
- executeOnCacheHit,
47
- executeOnCacheMiss,
48
- executeOnConsequenceCollected,
49
- executeOnRuleError,
50
- executeOnRuleMatch,
51
- executeOnRuleSkip,
52
- executeOnSlowRule,
53
- } from "./hooks";
54
- import {
55
- addRule,
56
- addRuleSet,
57
- addRules,
58
- clearRules,
59
- disableRule,
60
- enableRule,
61
- getRule,
62
- getRuleSet,
63
- getRuleSets,
64
- getRules,
65
- getRulesInSet,
66
- removeRule,
67
- removeRuleSet,
68
- updateRule,
69
- } from "./state";
70
-
71
- export type Engine<
72
- TContext = unknown,
73
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
74
- > = {
75
- readonly addRule: (
76
- input: RuleInput<TContext, TConsequences>,
77
- ) => Rule<TContext, TConsequences>;
78
- readonly addRules: (
79
- inputs: RuleInput<TContext, TConsequences>[],
80
- ) => Rule<TContext, TConsequences>[];
81
- readonly removeRule: (ruleId: string) => boolean;
82
- readonly updateRule: (
83
- ruleId: string,
84
- updates: Partial<RuleInput<TContext, TConsequences>>,
85
- ) => Rule<TContext, TConsequences> | undefined;
86
- readonly getRule: (
87
- ruleId: string,
88
- ) => Rule<TContext, TConsequences> | undefined;
89
- readonly getRules: (
90
- filters?: RuleFilters,
91
- ) => ReadonlyArray<Rule<TContext, TConsequences>>;
92
- readonly enableRule: (ruleId: string) => boolean;
93
- readonly disableRule: (ruleId: string) => boolean;
94
- readonly clearRules: () => void;
95
-
96
- readonly addRuleSet: (input: RuleSetInput) => RuleSet;
97
- readonly getRuleSet: (ruleSetId: string) => RuleSet | undefined;
98
- readonly getRuleSets: () => ReadonlyArray<RuleSet>;
99
- readonly removeRuleSet: (ruleSetId: string) => boolean;
100
-
101
- readonly evaluate: (
102
- context: TContext,
103
- options?: EvaluateOptions,
104
- ) => Promise<EngineExecutionResult<TContext, TConsequences>>;
105
-
106
- readonly clearCache: () => void;
107
- readonly getCacheStats: () => CacheStats;
108
-
109
- readonly getState: () => Readonly<EngineState<TContext, TConsequences>>;
110
- readonly getStats: () => EngineStats;
111
- };
112
-
113
- const resolveConfig = <
114
- TContext = unknown,
115
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
116
- >(
117
- config: EngineConfig<TContext, TConsequences>,
118
- ): ResolvedEngineConfig<TContext, TConsequences> => {
119
- // Validate evaluator config
120
- if (!config.evaluator && !config.operators) {
121
- throw new Error(
122
- "Engine requires either 'evaluator' or 'operators' config. " +
123
- "Pass { evaluator: createEvaluator() } for built-in operators only, " +
124
- "or { operators: customOperators } to use custom operators."
125
- );
126
- }
127
-
128
- // Create evaluator from config
129
- const evaluator = config.evaluator
130
- ? config.evaluator
131
- : createEvaluator({ operators: config.operators });
132
-
133
- return {
134
- consequences: config.consequences,
135
- conflictResolution:
136
- config.conflictResolution ?? getDefaultConflictResolution(),
137
- cache: {
138
- ...getDefaultCacheConfig(),
139
- ...config.cache,
140
- },
141
- validation: {
142
- ...getDefaultValidationConfig(),
143
- ...config.validation,
144
- },
145
- versioning: {
146
- ...getDefaultVersioningConfig(),
147
- ...config.versioning,
148
- },
149
- hooks: config.hooks ?? {},
150
- logLevel: config.logLevel ?? getDefaultLogLevel(),
151
- logger: config.logger ?? console,
152
- continueOnError: config.continueOnError ?? true,
153
- slowRuleThresholdMs: config.slowRuleThresholdMs ?? 10,
154
- hookTimeoutMs: config.hookTimeoutMs,
155
- evaluator, // Add to resolved config
156
- };
157
- };
158
-
159
- export const createEngine = <
160
- TContext = unknown,
161
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
162
- >(
163
- config: EngineConfig<TContext, TConsequences> = {},
164
- ): Engine<TContext, TConsequences> => {
165
- const resolvedConfig = resolveConfig(config);
166
- const state: MutableEngineState<TContext, TConsequences> =
167
- createInitialState();
168
-
169
- const cache: Cache<EngineExecutionResult<TContext, TConsequences>> =
170
- resolvedConfig.cache.enabled
171
- ? createCache({
172
- ttl: resolvedConfig.cache.ttl,
173
- maxSize: resolvedConfig.cache.maxSize,
174
- })
175
- : createNoopCache();
176
-
177
- let totalEvaluations = 0;
178
- let totalMatches = 0;
179
- let totalErrors = 0;
180
- let cacheHits = 0;
181
- let cacheMisses = 0;
182
- let totalEvaluationTime = 0;
183
-
184
- const evaluate = async (
185
- contextData: TContext,
186
- options: EvaluateOptions = {},
187
- ): Promise<EngineExecutionResult<TContext, TConsequences>> => {
188
- const context: EvaluationContext<TContext> = {
189
- data: contextData,
190
- timestamp: new Date(),
191
- correlationId: generateId(),
192
- };
193
-
194
- let rulesToEvaluate = getRules(state, {
195
- enabled: options.skipDisabled !== false ? true : undefined,
196
- tags: options.tags,
197
- category: options.category,
198
- });
199
-
200
- if (options.ruleSetId) {
201
- const ruleSetRules = getRulesInSet(state, options.ruleSetId);
202
- const ruleSetIds = new Set(ruleSetRules.map((r) => r.id));
203
- rulesToEvaluate = rulesToEvaluate.filter((r) => ruleSetIds.has(r.id));
204
- }
205
-
206
- // Rules are already sorted by priority via state.ruleOrder (sorted on add/update)
207
-
208
- if (options.maxRules && options.maxRules > 0) {
209
- rulesToEvaluate = rulesToEvaluate.slice(0, options.maxRules);
210
- }
211
-
212
- const cacheKey = !options.bypassCache
213
- ? `${hashContext(contextData)}:${hashRules(rulesToEvaluate.map((r) => r.id))}`
214
- : null;
215
-
216
- if (cacheKey && cache.has(cacheKey)) {
217
- const cached = cache.get(cacheKey);
218
- if (cached) {
219
- cacheHits++;
220
- await executeOnCacheHit(
221
- resolvedConfig.hooks,
222
- cacheKey,
223
- cached,
224
- resolvedConfig.hookTimeoutMs,
225
- );
226
- return { ...cached, cacheHit: true };
227
- }
228
- }
229
-
230
- if (cacheKey) {
231
- cacheMisses++;
232
- await executeOnCacheMiss(
233
- resolvedConfig.hooks,
234
- cacheKey,
235
- resolvedConfig.hookTimeoutMs,
236
- );
237
- }
238
-
239
- await executeBeforeEvaluation(
240
- resolvedConfig.hooks,
241
- context,
242
- rulesToEvaluate,
243
- resolvedConfig.hookTimeoutMs,
244
- );
245
-
246
- const { result: evaluationResult, durationMs } = measureTime(() => {
247
- const results: Array<{
248
- rule: Rule<TContext, TConsequences>;
249
- result: ReturnType<typeof evaluateRule<TContext, TConsequences>>;
250
- }> = [];
251
-
252
- for (const rule of rulesToEvaluate) {
253
- const result = evaluateRule(rule, context, resolvedConfig.evaluator, { skipDisabled: true });
254
- results.push({ rule, result });
255
- }
256
-
257
- return results;
258
- });
259
-
260
- const ruleResults: ReturnType<
261
- typeof evaluateRule<TContext, TConsequences>
262
- >[] = [];
263
- const matchedRules: Rule<TContext, TConsequences>[] = [];
264
- const consequences: AggregatedConsequence<TConsequences>[] = [];
265
- let stoppedEarly = false;
266
- let stoppedByRuleId: string | undefined;
267
- let rulesErrored = 0;
268
-
269
- const conflictResolution =
270
- options.conflictResolution ?? resolvedConfig.conflictResolution;
271
-
272
- for (const { rule, result } of evaluationResult) {
273
- await executeBeforeRuleEvaluation(
274
- resolvedConfig.hooks,
275
- rule,
276
- context,
277
- resolvedConfig.hookTimeoutMs,
278
- );
279
-
280
- ruleResults.push(result);
281
-
282
- if (result.error) {
283
- rulesErrored++;
284
- await executeOnRuleError(
285
- resolvedConfig.hooks,
286
- rule,
287
- result.error,
288
- resolvedConfig.hookTimeoutMs,
289
- );
290
- if (!resolvedConfig.continueOnError) {
291
- break;
292
- }
293
- }
294
-
295
- if (result.skipped) {
296
- await executeOnRuleSkip(
297
- resolvedConfig.hooks,
298
- rule,
299
- result.skipReason ?? "Unknown",
300
- resolvedConfig.hookTimeoutMs,
301
- );
302
- }
303
-
304
- if (result.evaluationTimeMs > resolvedConfig.slowRuleThresholdMs) {
305
- await executeOnSlowRule(
306
- resolvedConfig.hooks,
307
- rule,
308
- result.evaluationTimeMs,
309
- resolvedConfig.slowRuleThresholdMs,
310
- resolvedConfig.hookTimeoutMs,
311
- );
312
- }
313
-
314
- await executeAfterRuleEvaluation(
315
- resolvedConfig.hooks,
316
- rule,
317
- result,
318
- resolvedConfig.hookTimeoutMs,
319
- );
320
-
321
- if (result.matched) {
322
- matchedRules.push(rule);
323
-
324
- for (const consequence of result.consequences) {
325
- consequences.push(consequence);
326
- await executeOnConsequenceCollected(
327
- resolvedConfig.hooks,
328
- rule,
329
- consequence,
330
- resolvedConfig.hookTimeoutMs,
331
- );
332
- }
333
-
334
- await executeOnRuleMatch(
335
- resolvedConfig.hooks,
336
- rule,
337
- context,
338
- resolvedConfig.hookTimeoutMs,
339
- );
340
-
341
- if (rule.stopOnMatch) {
342
- stoppedEarly = true;
343
- stoppedByRuleId = rule.id;
344
- break;
345
- }
346
-
347
- if (conflictResolution === "first-match") {
348
- stoppedEarly = true;
349
- stoppedByRuleId = rule.id;
350
- break;
351
- }
352
- }
353
- }
354
-
355
- totalEvaluations++;
356
- totalMatches += matchedRules.length;
357
- totalErrors += rulesErrored;
358
- totalEvaluationTime += durationMs;
359
-
360
- const executionResult: EngineExecutionResult<TContext, TConsequences> = {
361
- context,
362
- results: ruleResults,
363
- matchedRules,
364
- consequences,
365
- totalRulesEvaluated: ruleResults.length,
366
- totalRulesMatched: matchedRules.length,
367
- totalRulesSkipped: ruleResults.filter((r) => r.skipped).length,
368
- totalRulesErrored: rulesErrored,
369
- executionTimeMs: durationMs,
370
- stoppedEarly,
371
- stoppedByRuleId,
372
- cacheHit: false,
373
- };
374
-
375
- if (cacheKey) {
376
- cache.set(cacheKey, executionResult);
377
- }
378
-
379
- await executeAfterEvaluation(
380
- resolvedConfig.hooks,
381
- executionResult,
382
- resolvedConfig.hookTimeoutMs,
383
- );
384
-
385
- return executionResult;
386
- };
387
-
388
- return {
389
- addRule: (input) => addRule(state, input),
390
- addRules: (inputs) => addRules(state, inputs),
391
- removeRule: (ruleId) => {
392
- const result = removeRule(state, ruleId);
393
- if (result) cache.clear();
394
- return result;
395
- },
396
- updateRule: (ruleId, updates) => {
397
- const result = updateRule(state, ruleId, updates);
398
- if (result) cache.clear();
399
- return result;
400
- },
401
- getRule: (ruleId) => getRule(state, ruleId),
402
- getRules: (filters) => getRules(state, filters),
403
- enableRule: (ruleId) => {
404
- const result = enableRule(state, ruleId);
405
- if (result) cache.clear();
406
- return result;
407
- },
408
- disableRule: (ruleId) => {
409
- const result = disableRule(state, ruleId);
410
- if (result) cache.clear();
411
- return result;
412
- },
413
- clearRules: () => {
414
- clearRules(state);
415
- cache.clear();
416
- },
417
-
418
- addRuleSet: (input) => addRuleSet(state, input),
419
- getRuleSet: (ruleSetId) => getRuleSet(state, ruleSetId),
420
- getRuleSets: () => getRuleSets(state),
421
- removeRuleSet: (ruleSetId) => removeRuleSet(state, ruleSetId),
422
-
423
- evaluate,
424
-
425
- clearCache: () => cache.clear(),
426
- getCacheStats: () => cache.getStats(),
427
-
428
- getState: () => ({
429
- rules: state.rules as ReadonlyMap<
430
- string,
431
- Rule<TContext, TConsequences>
432
- >,
433
- ruleSets: state.ruleSets as ReadonlyMap<string, RuleSet>,
434
- ruleOrder: state.ruleOrder,
435
- }),
436
-
437
- getStats: () => {
438
- const enabledRules = Array.from(state.rules.values()).filter(
439
- (r) => r.enabled,
440
- ).length;
441
- return {
442
- totalRules: state.rules.size,
443
- enabledRules,
444
- disabledRules: state.rules.size - enabledRules,
445
- totalRuleSets: state.ruleSets.size,
446
- totalEvaluations,
447
- totalMatches,
448
- totalErrors,
449
- avgEvaluationTimeMs:
450
- totalEvaluations > 0
451
- ? totalEvaluationTime / totalEvaluations
452
- : 0,
453
- cacheHits,
454
- cacheMisses,
455
- cacheHitRate:
456
- cacheHits + cacheMisses > 0
457
- ? cacheHits / (cacheHits + cacheMisses)
458
- : 0,
459
- };
460
- },
461
- };
462
- };
@@ -1,235 +0,0 @@
1
- import type { EngineHooks } from "../types/config";
2
- import type {
3
- AggregatedConsequence,
4
- ConsequenceDefinitions,
5
- DefaultConsequences,
6
- } from "../types/consequence";
7
- import type {
8
- EngineExecutionResult,
9
- EvaluationContext,
10
- RuleEvaluationResult,
11
- } from "../types/evaluation";
12
- import type { Rule } from "../types/rule";
13
- import { withTimeout } from "../utils/time";
14
-
15
- const toError = (error: unknown): Error =>
16
- error instanceof Error ? error : new Error(String(error));
17
-
18
- const executeWithTimeout = async (
19
- hookName: string,
20
- hookFn: () => void | Promise<void>,
21
- hooks: EngineHooks<unknown, ConsequenceDefinitions>,
22
- timeoutMs?: number,
23
- ): Promise<void> => {
24
- try {
25
- const promise = Promise.resolve(hookFn());
26
- if (timeoutMs !== undefined && timeoutMs > 0) {
27
- await withTimeout(
28
- promise,
29
- timeoutMs,
30
- `Hook '${hookName}' timed out after ${timeoutMs}ms`,
31
- );
32
- } else {
33
- await promise;
34
- }
35
- } catch (error) {
36
- hooks.onHookError?.(hookName, toError(error));
37
- }
38
- };
39
-
40
- export const executeBeforeEvaluation = async <
41
- TContext = unknown,
42
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
43
- >(
44
- hooks: EngineHooks<TContext, TConsequences>,
45
- context: EvaluationContext<TContext>,
46
- rules: ReadonlyArray<Rule<TContext, TConsequences>>,
47
- timeoutMs?: number,
48
- ): Promise<void> => {
49
- if (!hooks.beforeEvaluation) return;
50
- await executeWithTimeout(
51
- "beforeEvaluation",
52
- () => hooks.beforeEvaluation?.(context, rules),
53
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
54
- timeoutMs,
55
- );
56
- };
57
-
58
- export const executeAfterEvaluation = async <
59
- TContext = unknown,
60
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
61
- >(
62
- hooks: EngineHooks<TContext, TConsequences>,
63
- result: EngineExecutionResult<TContext, TConsequences>,
64
- timeoutMs?: number,
65
- ): Promise<void> => {
66
- if (!hooks.afterEvaluation) return;
67
- await executeWithTimeout(
68
- "afterEvaluation",
69
- () => hooks.afterEvaluation?.(result),
70
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
71
- timeoutMs,
72
- );
73
- };
74
-
75
- export const executeBeforeRuleEvaluation = async <
76
- TContext = unknown,
77
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
78
- >(
79
- hooks: EngineHooks<TContext, TConsequences>,
80
- rule: Rule<TContext, TConsequences>,
81
- context: EvaluationContext<TContext>,
82
- timeoutMs?: number,
83
- ): Promise<void> => {
84
- if (!hooks.beforeRuleEvaluation) return;
85
- await executeWithTimeout(
86
- "beforeRuleEvaluation",
87
- () => hooks.beforeRuleEvaluation?.(rule, context),
88
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
89
- timeoutMs,
90
- );
91
- };
92
-
93
- export const executeAfterRuleEvaluation = async <
94
- TContext = unknown,
95
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
96
- >(
97
- hooks: EngineHooks<TContext, TConsequences>,
98
- rule: Rule<TContext, TConsequences>,
99
- result: RuleEvaluationResult<TContext, TConsequences>,
100
- timeoutMs?: number,
101
- ): Promise<void> => {
102
- if (!hooks.afterRuleEvaluation) return;
103
- await executeWithTimeout(
104
- "afterRuleEvaluation",
105
- () => hooks.afterRuleEvaluation?.(rule, result),
106
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
107
- timeoutMs,
108
- );
109
- };
110
-
111
- export const executeOnRuleMatch = async <
112
- TContext = unknown,
113
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
114
- >(
115
- hooks: EngineHooks<TContext, TConsequences>,
116
- rule: Rule<TContext, TConsequences>,
117
- context: EvaluationContext<TContext>,
118
- timeoutMs?: number,
119
- ): Promise<void> => {
120
- if (!hooks.onRuleMatch) return;
121
- await executeWithTimeout(
122
- "onRuleMatch",
123
- () => hooks.onRuleMatch?.(rule, context),
124
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
125
- timeoutMs,
126
- );
127
- };
128
-
129
- export const executeOnRuleSkip = async <
130
- TContext = unknown,
131
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
132
- >(
133
- hooks: EngineHooks<TContext, TConsequences>,
134
- rule: Rule<TContext, TConsequences>,
135
- reason: string,
136
- timeoutMs?: number,
137
- ): Promise<void> => {
138
- if (!hooks.onRuleSkip) return;
139
- await executeWithTimeout(
140
- "onRuleSkip",
141
- () => hooks.onRuleSkip?.(rule, reason),
142
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
143
- timeoutMs,
144
- );
145
- };
146
-
147
- export const executeOnRuleError = async <
148
- TContext = unknown,
149
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
150
- >(
151
- hooks: EngineHooks<TContext, TConsequences>,
152
- rule: Rule<TContext, TConsequences>,
153
- ruleError: Error,
154
- timeoutMs?: number,
155
- ): Promise<void> => {
156
- if (!hooks.onRuleError) return;
157
- await executeWithTimeout(
158
- "onRuleError",
159
- () => hooks.onRuleError?.(rule, ruleError),
160
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
161
- timeoutMs,
162
- );
163
- };
164
-
165
- export const executeOnConsequenceCollected = async <
166
- TContext = unknown,
167
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
168
- >(
169
- hooks: EngineHooks<TContext, TConsequences>,
170
- rule: Rule<TContext, TConsequences>,
171
- consequence: AggregatedConsequence<TConsequences>,
172
- timeoutMs?: number,
173
- ): Promise<void> => {
174
- if (!hooks.onConsequenceCollected) return;
175
- await executeWithTimeout(
176
- "onConsequenceCollected",
177
- () => hooks.onConsequenceCollected?.(rule, consequence),
178
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
179
- timeoutMs,
180
- );
181
- };
182
-
183
- export const executeOnCacheHit = async <
184
- TContext = unknown,
185
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
186
- >(
187
- hooks: EngineHooks<TContext, TConsequences>,
188
- key: string,
189
- result: EngineExecutionResult<TContext, TConsequences>,
190
- timeoutMs?: number,
191
- ): Promise<void> => {
192
- if (!hooks.onCacheHit) return;
193
- await executeWithTimeout(
194
- "onCacheHit",
195
- () => hooks.onCacheHit?.(key, result),
196
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
197
- timeoutMs,
198
- );
199
- };
200
-
201
- export const executeOnCacheMiss = async <
202
- TContext = unknown,
203
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
204
- >(
205
- hooks: EngineHooks<TContext, TConsequences>,
206
- key: string,
207
- timeoutMs?: number,
208
- ): Promise<void> => {
209
- if (!hooks.onCacheMiss) return;
210
- await executeWithTimeout(
211
- "onCacheMiss",
212
- () => hooks.onCacheMiss?.(key),
213
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
214
- timeoutMs,
215
- );
216
- };
217
-
218
- export const executeOnSlowRule = async <
219
- TContext = unknown,
220
- TConsequences extends ConsequenceDefinitions = DefaultConsequences,
221
- >(
222
- hooks: EngineHooks<TContext, TConsequences>,
223
- rule: Rule<TContext, TConsequences>,
224
- timeMs: number,
225
- threshold: number,
226
- timeoutMs?: number,
227
- ): Promise<void> => {
228
- if (!hooks.onSlowRule) return;
229
- await executeWithTimeout(
230
- "onSlowRule",
231
- () => hooks.onSlowRule?.(rule, timeMs, threshold),
232
- hooks as EngineHooks<unknown, ConsequenceDefinitions>,
233
- timeoutMs,
234
- );
235
- };