Skip to content

setnev/workflow-engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

workflow-engine

A minimal rules engine (~500 lines) that executes actions based on events. Built with TypeScript — no database, fully in-memory.

Demonstrates data modeling, abstraction, extensibility, and thinking in systems.

Install

npm install

Run example

npm run example

Run tests

npm test

Typecheck

npm run typecheck

Concepts

Concept Description
Event Something that happened: { type, properties }
Condition A predicate on event properties: { field, op, value }
ConditionGroup Conditions combined with AND or OR logic
Rule Wires event type(s) → conditions → actions
Action A side effect to run: { type, params }
ActionHandler A function registered for an action type

Supported operators

Operator Description
eq Strict equality
neq Strict inequality
gt Greater than (numeric)
gte Greater than or equal (numeric)
lt Less than (numeric)
lte Less than or equal (numeric)
contains String substring or array element check
in Value is member of a provided array
exists Field is defined and not null

Usage

import { WorkflowEngine, registerBuiltinActions } from './src/index.js';

const engine = new WorkflowEngine();
registerBuiltinActions(engine);

engine.addRule({
  name: 'welcome-trial',
  when: 'new_customer',
  conditionGroup: {
    logic: 'AND',
    conditions: [
      { field: 'plan', op: 'eq', value: 'trial' },
    ],
  },
  actions: [
    { type: 'log', params: { message: 'New trial customer!' } },
    { type: 'send_email', params: { to: 'user@example.com', subject: 'Welcome!' } },
  ],
});

const results = await engine.emit({
  type: 'new_customer',
  properties: { plan: 'trial' },
});

// [{ ruleName: 'welcome-trial', actionType: 'log', status: 'success' }, ...]
console.log(results);

Custom actions

engine.registerAction('slack_notify', async (params, event) => {
  await fetch(params.webhookUrl as string, {
    method: 'POST',
    body: JSON.stringify({ text: params.message }),
  });
});

Multi-event rules

A single rule can match multiple event types:

engine.addRule({
  name: 'premium-welcome',
  when: ['new_customer', 'upgrade'],   // fires on either event
  conditionGroup: {
    logic: 'AND',
    conditions: [{ field: 'plan', op: 'eq', value: 'premium' }],
  },
  actions: [{ type: 'log', params: { message: 'Premium user!' } }],
});

Project structure

src/
  types.ts       Core interfaces and types
  evaluator.ts   Pure condition evaluation (eq, gte, contains, etc.)
  engine.ts      WorkflowEngine class — orchestrates rule matching and action dispatch
  actions.ts     Built-in action handlers (log, send_email)
  index.ts       Public API exports
examples/
  onboarding.ts  Runnable demo with 4 scenarios
tests/
  engine.test.ts 30 unit tests covering all operators and engine behaviour

About

A minimal rules engine that executes actions based on events. Built with TypeScript.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors