A TypeScript rule engine library with JSON Schema Draft-07 compliance and JSONPath integration
npm install @omerrhamza/rule-engineA pure, flexible, type-safe condition evaluation engine for complex conditional logic on dynamic JSON data. Built with TypeScript, designed for escalation policies, alert routing, and complex decision-making systems.
- Type-Safe: Full TypeScript support with comprehensive type definitions
- Flexible Conditions: Support for nested AND/OR logic with unlimited depth
- JSONPath Support: Access any field in your JSON data using JSONPath expressions
- Extensible: Runtime operator registration - add custom operators on the fly
- Async Operations: Built-in support for async operators (API calls, DB queries)
- Debug Mode: Detailed logging and execution traces
- Schema Validation: Validate conditions and data against JSON Schema
- Performance: JSONPath caching and optimized evaluation
- Zero Config: Works out of the box with sensible defaults
- Universal: Works in both frontend and backend
``bash`
npm install @omerrhamza/rule-engineor
yarn add @omerrhamza/rule-engineor
pnpm add @omerrhamza/rule-engineor
bun add @omerrhamza/rule-engine
`typescript
import { RuleEngine } from "rule-engine";
import type { Condition, ConditionGroup } from "rule-engine";
// Your data
const alert = {
severity: "HIGH",
host: "production-database-01",
status: "PROBLEM",
tags: ["database", "production"],
};
// Define a condition
const criticalDbCondition: ConditionGroup = {
operator: "AND",
conditions: [
{ field: "$.severity", operator: "in", value: ["HIGH", "DISASTER"] },
{ field: "$.host", operator: "contains", value: "database" },
{ field: "$.status", operator: "eq", value: "PROBLEM" },
],
};
// Create engine and evaluate
const engine = new RuleEngine();
const result = await engine.evaluate(criticalDbCondition, alert);
console.log(Matched: ${result.matched});Execution time: ${result.executionTime}ms
console.log();`
`typescript
// Single condition
const condition: Condition = {
field: "$.severity",
operator: "eq",
value: "HIGH",
};
const result = await engine.evaluate(condition, data);
console.log(result.matched); // true or false
`
Two types of conditions:
1. Single Condition
`typescript`
interface Condition {
field: string; // JSONPath expression (e.g., "$.user.age")
operator: string; // Operator name (e.g., "eq", "gt")
value: unknown; // Value to compare against
}
2. Condition Group
`typescript`
interface ConditionGroup {
operator: "AND" | "OR";
conditions: Array
}
`typescript`
interface EvaluationResult {
matched: boolean; // Did the condition match?
executionTime: number; // Execution time in milliseconds
trace?: Array<{
// Debug trace (if debug mode enabled)
path: string;
operator: string;
result: boolean;
}>;
}
Built-in operator categories:
- Comparison: eq, neq, gt, gte, lt, lte, in, notIncontains
- String: , startsWith, endsWith, matchesarrayContains
- Array: , arrayContainsAny, arrayContainsAll, arrayLength, arrayEmpty, arrayNotEmptyexists
- Existence: , notExists, empty, notEmptyisString
- Type: , isNumber, isBoolean, isArray, isObject, isNullbefore
- DateTime: , after, between, withinLast, olderThanasyncWebhook
- Async: , asyncCustom
Register your own operators:
`typescript
engine.getRegistry().register("divisibleBy", {
execute: (fieldValue, compareValue) => {
return (
typeof fieldValue === "number" &&
typeof compareValue === "number" &&
fieldValue % compareValue === 0
);
},
metadata: {
name: "Divisible By",
description: "Check if number is divisible by another",
category: "custom",
},
});
// Use it
const condition: Condition = {
field: "$.value",
operator: "divisibleBy",
value: 5,
};
`
Handle async operations like API calls or database queries:
`typescript
engine.getRegistry().register("userExists", {
execute: async (userId) => {
const user = await database.findUser(userId);
return user !== null;
},
metadata: {
name: "User Exists",
description: "Check if user exists in database",
category: "async",
},
});
const condition: Condition = {
field: "$.userId",
operator: "userExists",
value: null,
};
`
Enable detailed logging:
`typescript
const engine = new RuleEngine({ debug: true });
const result = await engine.evaluate(condition, data);
// Access debug logs
const logger = engine.getLogger();
const logs = logger.getLogs();
console.log(logs);
`
Validate conditions and check fields against your provider schema:
`typescript
import { SchemaValidator } from "rule-engine";
const validator = new SchemaValidator();
// Validate condition structure
const validation = validator.validateConditionGroup(condition);
if (!validation.valid) {
console.error("Invalid condition:", validation.errors);
}
`
`typescript`
const engine = new RuleEngine({
debug: false, // Enable debug logging
cacheJSONPath: true, // Cache JSONPath resolutions for performance
});
`bashType check
bun run tsc