https://github.com/litepacks/liteflow
https://github.com/litepacks/liteflow
experimental nodejs sqlite3 workflow-engine workflow-tracking
Last synced: 4 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/litepacks/liteflow
- Owner: litepacks
- Created: 2025-04-26T07:43:57.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-02-15T20:04:55.000Z (4 months ago)
- Last Synced: 2026-02-16T00:57:32.276Z (4 months ago)
- Topics: experimental, nodejs, sqlite3, workflow-engine, workflow-tracking
- Language: TypeScript
- Homepage:
- Size: 858 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Liteflow
> ⚠️ **Experimental Package**: This package is currently under development and should not be used in production. The API may change.
A lightweight workflow tracker for Node.js applications with multi-database support.
## Features
- Simple workflow management
- Step tracking
- Identifier-based workflow lookup
- Workflow statistics
- **CLI tool for real-time statistics monitoring**
- **Advanced filtering** (name, status, date range, step, identifier)
- **Multi-database support** (SQLite, PostgreSQL, MySQL)
- **Batch insert architecture** for high-performance writes
- TypeScript support
- Async/await API
- Bulk operations support
- Performance optimizations
- Centralized error handling
- Graceful error recovery
## Installation
```bash
npm install liteflow
```
## Quick Start
```typescript
import { Liteflow } from 'liteflow';
// Initialize with a database path (SQLite)
const liteflow = new Liteflow('path/to/database.db');
await liteflow.init();
// Start a new workflow - returns a WorkflowInstance
const workflow = liteflow.startWorkflow('test-workflow', [
{ key: 'test', value: '123' }
]);
// Add steps to the workflow
workflow.addStep('step1', { data: 'test1' });
workflow.addStep('step2', { data: 'test2' });
// Flush batch inserts (optional - done automatically)
await liteflow.flushBatchInserts();
// Mark workflow as complete
workflow.complete();
// Get workflow steps
const steps = await workflow.getSteps();
// Clean up when done
await liteflow.destroy();
```
## Database Configuration
### SQLite (Default)
```typescript
// Simple path (backward compatible)
const liteflow = new Liteflow('./database.db');
// Or with config object
const liteflow = new Liteflow({
client: 'sqlite3',
connection: {
filename: './database.db'
},
useNullAsDefault: true
});
```
### PostgreSQL
```typescript
const liteflow = new Liteflow({
client: 'pg',
connection: {
host: 'localhost',
port: 5432,
user: 'username',
password: 'password',
database: 'mydb'
}
});
```
### MySQL
```typescript
const liteflow = new Liteflow({
client: 'mysql2',
connection: {
host: 'localhost',
port: 3306,
user: 'username',
password: 'password',
database: 'mydb'
}
});
```
## Usage
```typescript
import { Liteflow } from 'liteflow';
// Initialize with a database path
const liteflow = new Liteflow('path/to/database.db');
await liteflow.init();
// Start a new workflow - returns a WorkflowInstance
const workflow = liteflow.startWorkflow('test-workflow', [
{ key: 'test', value: '123' }
]);
// Use the workflow instance methods directly
workflow.addStep('step1', { data: 'test1' });
workflow.addStep('step2', { data: 'test2' });
workflow.complete();
// Or use the traditional API (still supported)
const workflowId = workflow.id; // Get the workflow ID
liteflow.addStep(workflowId, 'step1', { data: 'test1' });
liteflow.addStep(workflowId, 'step2', { data: 'test2' });
liteflow.completeWorkflow(workflowId);
// Batch insert multiple steps (more efficient)
await liteflow.addSteps(workflowId, [
{ step: 'step3', data: { value: 3 } },
{ step: 'step4', data: { value: 4 } },
{ step: 'step5', data: { value: 5 } }
]);
// Manual flush of pending batch inserts
await liteflow.flushBatchInserts();
// Get workflow by identifier
const foundWorkflow = await liteflow.getWorkflowByIdentifier('test', '123');
// Get workflow steps
const steps = await workflow.getSteps(); // Using instance method
// or
const stepsById = await liteflow.getSteps(workflowId); // Using traditional method
// Get steps by identifier
const stepsByIdentifier = await liteflow.getStepsByIdentifier('test', '123');
// Get workflow statistics
const stats = await liteflow.getWorkflowStats();
// Get workflows with pagination and filtering
const workflows = await liteflow.getWorkflows({
status: 'completed',
page: 1,
pageSize: 10,
orderBy: 'started_at',
order: 'desc'
});
// Advanced filtering
const filtered = await liteflow.getWorkflows({
name: 'user-registration', // Filter by name (partial match)
status: 'completed', // Filter by status
startDate: '2026-01-01', // Filter by start date
endDate: '2026-12-31', // Filter by end date
step: 'validate-email', // Filter by step name
identifier: { key: 'userId', value: '1001' } // Filter by identifier
});
// Delete a workflow
const deleted = await workflow.delete(); // Using instance method
// or
const deletedById = await liteflow.deleteWorkflow(workflowId); // Using traditional method
if (deleted) {
console.log('Workflow deleted successfully');
}
// Delete all workflows
const allDeleted = await liteflow.deleteAllWorkflows();
if (allDeleted) {
console.log('All workflows deleted successfully');
}
// Attach additional identifiers
await liteflow.attachIdentifier('test', '123', { key: 'test2', value: '456' });
// Get most frequent steps
const frequentSteps = await liteflow.getMostFrequentSteps(5);
// Get average step duration
const stepDurations = await liteflow.getAverageStepDuration();
// Clean up database connection
await liteflow.destroy();
```
## CLI Usage
Liteflow includes a powerful CLI tool for monitoring workflow statistics in real-time.
### Installation
After installing the package, the CLI is available as `liteflow`:
```bash
npm install -g liteflow
# or use npx
npx liteflow stats --db ./path/to/database.db
```
### Commands
#### `stats` - Display Workflow Statistics
Display general workflow statistics with various filtering and monitoring options:
```bash
# Basic usage - show statistics
liteflow stats --db ./liteflow.db
# Show verbose output with workflow details
liteflow stats --db ./liteflow.db --verbose
# Filter by workflow status
liteflow stats --db ./liteflow.db --status pending
liteflow stats --db ./liteflow.db --status completed
liteflow stats --db ./liteflow.db --status failed
# Filter by identifier
liteflow stats --db ./liteflow.db --key userId --value 1001
# Filter by workflow name (partial match)
liteflow stats --db ./liteflow.db --name user-registration
# Filter by step name
liteflow stats --db ./liteflow.db --step validate-email
# Filter by date range
liteflow stats --db ./liteflow.db --start-date 2026-01-01 --end-date 2026-12-31
# Combine multiple filters
liteflow stats --db ./liteflow.db --name user --status completed --step validate-email
# Real-time monitoring (refreshes every 2 seconds)
liteflow stats --db ./liteflow.db --watch
# Real-time monitoring with custom interval (5 seconds)
liteflow stats --db ./liteflow.db --watch --interval 5
# Combine filters with real-time monitoring
liteflow stats --db ./liteflow.db --status pending --watch --verbose
```
#### `list` - List Workflows
List workflows with pagination, sorting and filtering:
```bash
# List all workflows
liteflow list --db ./liteflow.db
# List with pagination
liteflow list --db ./liteflow.db --page 1 --page-size 20
# List with sorting
liteflow list --db ./liteflow.db --order-by started_at --order asc
# List with filters
liteflow list --db ./liteflow.db --status completed --name user
```
#### `watch` - Real-Time Monitoring
Dedicated real-time monitoring command with change detection:
```bash
# Start monitoring
liteflow watch --db ./liteflow.db
# Monitor with custom interval
liteflow watch --db ./liteflow.db --interval 5
# Monitor with filters
liteflow watch --db ./liteflow.db --status pending --name order
```
The watch command provides:
- Real-time statistics with change indicators (+/- diffs)
- New workflow detection alerts
- Cycle counter for monitoring uptime
- All filter options supported
### CLI Options
#### Common Options (all commands)
- `-d, --db ` - Path to database file (default: `./liteflow.db`)
- `-s, --status ` - Filter by status (`pending`, `completed`, `failed`)
- `-k, --key ` - Filter by identifier key
- `-v, --value ` - Filter by identifier value
- `-n, --name ` - Filter by workflow name (partial match)
- `--start-date ` - Filter workflows started after this date (ISO 8601)
- `--end-date ` - Filter workflows started before this date (ISO 8601)
- `--step ` - Filter workflows containing this step
- `--verbose` - Show detailed information including workflows and steps
- `-h, --help` - Display help information
#### Stats Options
- `-w, --watch` - Enable real-time monitoring
- `-i, --interval ` - Refresh interval for watch mode in seconds (default: `2`)
#### List Options
- `-p, --page ` - Page number (default: `1`)
- `--page-size ` - Number of items per page (default: `20`)
- `--order-by ` - Order by field: `started_at`, `ended_at` (default: `started_at`)
- `--order ` - Sort direction: `asc`, `desc` (default: `desc`)
#### Watch Options
- `-i, --interval ` - Refresh interval in seconds (default: `2`)
### CLI Output
The CLI displays:
1. **General Statistics**: Total workflows, completed, pending, failed counts, and average steps per workflow
2. **Change Indicators** (watch mode): Shows +/- diffs between refresh cycles
3. **Active Filters**: Displays currently active filter parameters
4. **Workflow List** (with `--verbose` or filters): Detailed list of workflows with status, start time, and duration
5. **Most Frequent Steps**: Top 5 most frequently executed steps across all workflows
## API Reference
### `Liteflow(config: string | LiteflowConfig, options?: { batchInsertDelay?: number })`
Creates a new Liteflow instance.
**Parameters:**
- `config`: Database path (string) for SQLite, or configuration object for other databases
- `options.batchInsertDelay`: Delay in milliseconds before flushing batch inserts (default: 100)
**Example:**
```typescript
// SQLite with string path
const liteflow = new Liteflow('./database.db');
// PostgreSQL with config
const liteflow = new Liteflow({
client: 'pg',
connection: {
host: 'localhost',
database: 'mydb',
user: 'user',
password: 'pass'
}
});
// Custom batch delay
const liteflow = new Liteflow('./database.db', { batchInsertDelay: 200 });
```
### `init(): Promise`
Initializes the database schema. Must be called before using other methods.
### `destroy(): Promise`
Closes the database connection and flushes any pending batch inserts. Should be called when done using the instance.
### Error Handling
Liteflow implements a centralized error handling mechanism through the `wrap` function. This ensures that:
- All database operations are wrapped in try-catch blocks
- Errors are logged to the console
- Operations return fallback values instead of throwing errors
- System stability is maintained even when errors occur
Fallback values for different operations:
- `getWorkflows`: `{ workflows: [], total: 0, page: 1, pageSize: 10, totalPages: 0 }`
- `getSteps` and `getStepsByIdentifier`: `[]`
- `getWorkflowStats`: `{ total: 0, completed: 0, pending: 0, avgSteps: 0 }`
- `getMostFrequentSteps` and `getAverageStepDuration`: `[]`
- `attachIdentifier`, `deleteWorkflow`, `deleteAllWorkflows`: `false`
### `startWorkflow(name: string, identifiers: Identifier[]): WorkflowInstance`
Starts a new workflow and returns a WorkflowInstance object that provides convenient instance methods.
### Batch Insert Methods
### `addSteps(workflowId: string | WorkflowInstance, steps: Array<{ step: string, data: any }>): Promise`
Adds multiple steps to a workflow in a single batch operation. More efficient than calling `addStep` multiple times.
**Example:**
```typescript
await liteflow.addSteps(workflowId, [
{ step: 'step1', data: { value: 1 } },
{ step: 'step2', data: { value: 2 } },
{ step: 'step3', data: { value: 3 } }
]);
```
### `flushBatchInserts(): Promise`
Manually flushes any pending batch inserts to the database. Normally happens automatically after the configured delay, but can be called to ensure immediate persistence.
**Example:**
```typescript
liteflow.addStep(workflowId, 'step1', { data: 'test' });
await liteflow.flushBatchInserts(); // Ensure step is persisted
```
### WorkflowInstance Methods
The `WorkflowInstance` returned by `startWorkflow` provides the following methods:
- `workflow.id`: Get the workflow ID (string)
- `workflow.addStep(step: string, data: any)`: Add a step to this workflow
- `workflow.addSteps(steps: Array<{ step: string, data: any }>)`: Add multiple steps in batch (Promise)
- `workflow.complete()`: Mark this workflow as completed
- `workflow.fail(reason?: string)`: Mark this workflow as failed
- `workflow.getSteps()`: Get all steps for this workflow (Promise)
- `workflow.delete()`: Delete this workflow (Promise)
### `addStep(workflowId: string | WorkflowInstance, step: string, data: any): void`
Adds a step to a workflow. Steps are queued and inserted in batches for performance. Accepts either a workflow ID string or a WorkflowInstance.
### `completeWorkflow(workflowId: string | WorkflowInstance): void`
Marks a workflow as completed. Accepts either a workflow ID string or a WorkflowInstance.
### `getWorkflowByIdentifier(key: string, value: string): Promise`
Retrieves a workflow by its identifier.
### `getSteps(workflowId: string): Promise`
Gets all steps for a workflow.
### `getStepsByIdentifier(key: string, value: string): Promise`
Gets all steps for workflows matching the given identifier key and value.
### `getWorkflowStats(): Promise`
Returns workflow statistics.
### `attachIdentifier(existingKey: string, existingValue: string, newIdentifier: Identifier): Promise`
Attaches a new identifier to an existing workflow. Returns true if successful, false if the workflow doesn't exist or if the identifier already exists.
### `getMostFrequentSteps(limit?: number): Promise<{ step: string, count: number }[]>`
Returns the most frequent steps across all workflows, limited by the specified number.
### `getAverageStepDuration(): Promise<{ workflow_id: string, total_duration: number, step_count: number }[]>`
Returns average step duration for workflows.
### `getWorkflows(options?: GetWorkflowsOptions): Promise<{ workflows: Workflow[], total: number, page: number, pageSize: number, totalPages: number }>`
Retrieves workflows with pagination, filtering and sorting options.
Options:
- `status?: 'pending' | 'completed' | 'failed'` - Filter by workflow status
- `page?: number` - Page number (default: 1)
- `pageSize?: number` - Items per page (default: 10)
- `orderBy?: 'started_at' | 'ended_at'` - Field to sort by (default: 'started_at')
- `order?: 'asc' | 'desc'` - Sort order (default: 'desc')
- `identifier?: { key: string, value: string }` - Filter by identifier key and value
- `name?: string` - Filter by workflow name (partial match / LIKE)
- `startDate?: string` - Filter workflows started after this date (ISO 8601)
- `endDate?: string` - Filter workflows started before this date (ISO 8601)
- `step?: string` - Filter workflows that contain this step name
All filters are combined with AND logic when multiple are provided.
**Example:**
```typescript
// Basic pagination
const result = await liteflow.getWorkflows({ page: 1, pageSize: 10 });
// Filter by status
const completed = await liteflow.getWorkflows({ status: 'completed' });
// Advanced filtering
const filtered = await liteflow.getWorkflows({
name: 'user',
status: 'completed',
step: 'validate-email',
startDate: '2026-01-01',
endDate: '2026-12-31',
identifier: { key: 'userId', value: '1001' }
});
```
### `deleteWorkflow(workflowId: string): Promise`
Deletes a workflow and all its steps. Returns true if the workflow was deleted successfully, false if the workflow doesn't exist or if there was an error.
### `deleteAllWorkflows(): Promise`
Deletes all workflows and their steps. Returns true if the operation was successful, false if there was an error.
## Types
```typescript
interface LiteflowConfig {
client: 'sqlite3' | 'pg' | 'mysql' | 'mysql2';
connection: string | {
host?: string;
port?: number;
user?: string;
password?: string;
database?: string;
filename?: string;
};
useNullAsDefault?: boolean;
}
interface Identifier {
key: string;
value: string;
}
interface Workflow {
id: string;
name: string;
identifiers: string;
status: 'pending' | 'completed' | 'failed';
started_at: string;
ended_at?: string;
}
interface WorkflowStep {
id: string;
workflow_id: string;
step: string;
data: string;
created_at: string;
}
interface WorkflowStats {
total: number;
completed: number;
pending: number;
avgSteps: number;
}
interface GetWorkflowsOptions {
status?: 'pending' | 'completed' | 'failed';
page?: number;
pageSize?: number;
orderBy?: 'started_at' | 'ended_at';
order?: 'asc' | 'desc';
identifier?: {
key: string;
value: string;
};
name?: string;
startDate?: string;
endDate?: string;
step?: string;
}
```
## Performance
### Batch Insert Architecture
Liteflow uses an automatic batch insert system for workflow steps:
- **Automatic Batching**: Steps added with `addStep()` are queued and inserted in batches
- **Configurable Delay**: Default 100ms delay before flushing (configurable via constructor)
- **Manual Control**: Use `flushBatchInserts()` for immediate persistence
- **Explicit Batching**: Use `addSteps()` for bulk operations
**Performance Benefits:**
- Reduces database round trips
- Improves throughput for high-volume workflows
- Maintains ACID guarantees
**Example:**
```typescript
// Automatic batching (100ms delay)
workflow.addStep('step1', { data: 1 });
workflow.addStep('step2', { data: 2 });
// Steps will be inserted together after 100ms
// Manual flush for immediate persistence
await liteflow.flushBatchInserts();
// Explicit batch insert
await liteflow.addSteps(workflowId, [
{ step: 'step1', data: { value: 1 } },
{ step: 'step2', data: { value: 2 } }
]);
```
## Migration Guide
### Upgrading from 1.0.x to 2.0.x
The main change is that all database methods are now asynchronous. Add `await` to all method calls:
```typescript
// Before (1.0.x)
const liteflow = new Liteflow('./database.db');
liteflow.init();
const steps = liteflow.getSteps(workflowId);
const stats = liteflow.getWorkflowStats();
// After (2.0.x)
const liteflow = new Liteflow('./database.db');
await liteflow.init();
const steps = await liteflow.getSteps(workflowId);
const stats = await liteflow.getWorkflowStats();
// Don't forget to clean up
await liteflow.destroy();
```
**Key Changes:**
1. All database methods return Promises (use `await`)
2. `init()` is now async
3. New `destroy()` method for cleanup
4. New batch insert methods (`addSteps`, `flushBatchInserts`)
5. Multi-database support (SQLite, PostgreSQL, MySQL)
## Development
### Setup
```bash
git clone https://github.com/indatawetrust/liteflow.git
cd liteflow
npm install
```
### Testing
Tests are powered by [Vitest](https://vitest.dev/).
```bash
# Run tests once
npm test
# Run tests in watch mode
npm run test:watch
```
### Benchmarking
```bash
npm run benchmark
```
## License
MIT