Overview
The StatefulRuleEngine extends the base RuleEngine with state tracking capabilities, enabling you to detect changes in data over time and trigger actions based on state transitions.
Perfect for monitoring systems, event-driven workflows, and reactive business logic.
Key Features
State Tracking Maintains previous states for comparison across evaluations
Event System Subscribe to rule state changes with event listeners
Change Detection Specialized operators for detecting value changes
History Management Optional storage of evaluation history
Creating a Stateful Engine
import { createRuleEngine , StatefulRuleEngine } from 'rule-engine-js' ;
const baseEngine = createRuleEngine ();
const statefulEngine = new StatefulRuleEngine ( baseEngine , {
triggerOnEveryChange: false , // Trigger only on false → true
storeHistory: true , // Keep evaluation history
maxHistorySize: 100 , // Limit history entries
});
Configuration Options
When false, triggers only on false → true transitions. When true, triggers on any state change.
Enable storage of evaluation history for analysis and debugging.
Maximum number of history entries to store per rule.
Event System
Subscribe to rule state changes:
Triggered Event
Changed Event
Evaluated Event
statefulEngine . on ( 'triggered' , ( event ) => {
console . log ( `Rule ${ event . ruleId } was triggered!` );
console . log ( 'Previous state:' , event . previousState );
console . log ( 'Current state:' , event . currentState );
console . log ( 'Context:' , event . context );
});
State Change Operators
changed - Detect Any Change
const rule = { changed: [ 'user.email' ] };
// First evaluation
statefulEngine . evaluate ( 'email-change' , rule , { user: { email: 'old@example.com' } });
// Second evaluation - triggers because email changed
statefulEngine . evaluate ( 'email-change' , rule , { user: { email: 'new@example.com' } });
changedBy - Detect Numeric Change
const rule = { changedBy: [ 'temperature' , 5 ] };
// First evaluation
statefulEngine . evaluate ( 'temp' , rule , { temperature: 20 });
// Triggers when temperature changes by 5 or more
statefulEngine . evaluate ( 'temp' , rule , { temperature: 26 }); // true
changedFrom - Detect Change from Value
const rule = { changedFrom: [ 'status' , 'pending' ] };
// Triggers when status changes from 'pending' to anything else
statefulEngine . evaluate ( 'status' , rule , { status: 'pending' });
statefulEngine . evaluate ( 'status' , rule , { status: 'approved' }); // triggers
changedTo - Detect Change to Value
const rule = { changedTo: [ 'status' , 'completed' ] };
// Triggers when status changes to 'completed'
statefulEngine . evaluate ( 'status' , rule , { status: 'processing' });
statefulEngine . evaluate ( 'status' , rule , { status: 'completed' }); // triggers
increased - Detect Numeric Increase
const rule = { increased: [ 'stock' ] };
// Triggers when stock quantity increases
statefulEngine . evaluate ( 'stock' , rule , { stock: 100 });
statefulEngine . evaluate ( 'stock' , rule , { stock: 150 }); // triggers
decreased - Detect Numeric Decrease
const rule = { decreased: [ 'balance' ] };
// Triggers when balance decreases
statefulEngine . evaluate ( 'balance' , rule , { balance: 1000 });
statefulEngine . evaluate ( 'balance' , rule , { balance: 800 }); // triggers
Real-World Example
// Order processing workflow
const orderRules = {
'payment-received' : { changedTo: [ 'order.paymentStatus' , 'paid' ] },
'inventory-low' : {
and: [
{ decreased: [ 'product.stock' ] },
{ lte: [ 'product.stock' , 10 ] }
]
},
'price-drop' : {
and: [
{ decreased: [ 'product.price' ] },
{ changedBy: [ 'product.price' , 5 ] }
]
},
};
// Event handlers
statefulEngine . on ( 'triggered' , ( event ) => {
switch ( event . ruleId ) {
case 'payment-received' :
processOrder ( event . context );
break ;
case 'inventory-low' :
reorderStock ( event . context . product );
break ;
case 'price-drop' :
notifyCustomers ( event . context . product );
break ;
}
});
// Evaluate all rules
const orderData = {
order: { paymentStatus: 'paid' },
product: { stock: 8 , price: 95 },
};
statefulEngine . evaluateBatch ( orderRules , orderData );
Methods
evaluate()
Evaluate a single rule with state tracking:
const result = statefulEngine . evaluate ( ruleId , rule , context );
evaluateBatch()
Evaluate multiple rules at once:
const results = statefulEngine . evaluateBatch ( rulesObject , context );
getRuleState()
Get current state of a specific rule:
const state = statefulEngine . getRuleState ( ruleId );
clearRuleState()
Clear state for a specific rule:
statefulEngine . clearRuleState ( ruleId );
getHistory()
Get evaluation history (if enabled):
const history = statefulEngine . getHistory ( ruleId );
Best Practices
Use Meaningful IDs Use descriptive rule IDs that indicate the rule’s purpose
Batch Evaluations Use evaluateBatch() for multiple related rules
Clean Up State Periodically clear state for inactive rules
Limit History Set appropriate maxHistorySize to manage memory
Next Steps