npm package: @omerrhamza/rule-engine
Description: A TypeScript rule engine library with JSON Schema Draft-07 compliance and JSONPath integration
Latest version: 0.1.6

# JSON Rule Engine

A 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.

## 🚀 Features

- **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

## 📦 Installation

```bash
npm install @omerrhamza/rule-engine
# or
yarn add @omerrhamza/rule-engine
# or
pnpm add @omerrhamza/rule-engine
# or
bun add @omerrhamza/rule-engine
```

## 🎯 Quick Start

```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}`);
console.log(`Execution time: ${result.executionTime}ms`);
```

### Simple Condition

```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
```

## 📚 Core Concepts

### Conditions

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<Condition | ConditionGroup>; // Can nest infinitely
}
```

### Evaluation Result

```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;
  }>;
}
```

### Operators

Built-in operator categories:

- **Comparison**: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`
- **String**: `contains`, `startsWith`, `endsWith`, `matches`
- **Array**: `arrayContains`, `arrayContainsAny`, `arrayContainsAll`, `arrayLength`, `arrayEmpty`, `arrayNotEmpty`
- **Existence**: `exists`, `notExists`, `empty`, `notEmpty`
- **Type**: `isString`, `isNumber`, `isBoolean`, `isArray`, `isObject`, `isNull`
- **DateTime**: `before`, `after`, `between`, `withinLast`, `olderThan`
- **Async**: `asyncWebhook`, `asyncCustom`

## 🔧 Advanced Features

### Custom Operators

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,
};
```

### Async Operators

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,
};
```

### Debug Mode

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);
```

### Schema Validation

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);
}
```

## ⚙️ Configuration

```typescript
const engine = new RuleEngine({
  debug: false, // Enable debug logging
  cacheJSONPath: true, // Cache JSONPath resolutions for performance
});
```

## 🧪 Development

```bash
# Type check
bun run tsc

# Lint
bun run lint

# Format
bun run format

# Lint & format (check and fix)
bun run check:fix

# Build
bun run build
bun run build:types
```