⚠️ 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.
- 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
npm install liteflowimport { 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();// 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
});const liteflow = new Liteflow({
client: 'pg',
connection: {
host: 'localhost',
port: 5432,
user: 'username',
password: 'password',
database: 'mydb'
}
});const liteflow = new Liteflow({
client: 'mysql2',
connection: {
host: 'localhost',
port: 3306,
user: 'username',
password: 'password',
database: 'mydb'
}
});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();Liteflow includes a powerful CLI tool for monitoring workflow statistics in real-time.
After installing the package, the CLI is available as liteflow:
npm install -g liteflow
# or use npx
npx liteflow stats --db ./path/to/database.dbDisplay general workflow statistics with various filtering and monitoring options:
# 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 --verboseList workflows with pagination, sorting and filtering:
# 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 userDedicated real-time monitoring command with change detection:
# 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 orderThe watch command provides:
- Real-time statistics with change indicators (+/- diffs)
- New workflow detection alerts
- Cycle counter for monitoring uptime
- All filter options supported
-d, --db <path>- Path to database file (default:./liteflow.db)-s, --status <status>- Filter by status (pending,completed,failed)-k, --key <key>- Filter by identifier key-v, --value <value>- Filter by identifier value-n, --name <pattern>- Filter by workflow name (partial match)--start-date <date>- Filter workflows started after this date (ISO 8601)--end-date <date>- Filter workflows started before this date (ISO 8601)--step <step-name>- Filter workflows containing this step--verbose- Show detailed information including workflows and steps-h, --help- Display help information
-w, --watch- Enable real-time monitoring-i, --interval <seconds>- Refresh interval for watch mode in seconds (default:2)
-p, --page <number>- Page number (default:1)--page-size <number>- Number of items per page (default:20)--order-by <field>- Order by field:started_at,ended_at(default:started_at)--order <direction>- Sort direction:asc,desc(default:desc)
-i, --interval <seconds>- Refresh interval in seconds (default:2)
The CLI displays:
- General Statistics: Total workflows, completed, pending, failed counts, and average steps per workflow
- Change Indicators (watch mode): Shows +/- diffs between refresh cycles
- Active Filters: Displays currently active filter parameters
- Workflow List (with
--verboseor filters): Detailed list of workflows with status, start time, and duration - Most Frequent Steps: Top 5 most frequently executed steps across all workflows
Creates a new Liteflow instance.
Parameters:
config: Database path (string) for SQLite, or configuration object for other databasesoptions.batchInsertDelay: Delay in milliseconds before flushing batch inserts (default: 100)
Example:
// 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 });Initializes the database schema. Must be called before using other methods.
Closes the database connection and flushes any pending batch inserts. Should be called when done using the instance.
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 }getStepsandgetStepsByIdentifier:[]getWorkflowStats:{ total: 0, completed: 0, pending: 0, avgSteps: 0 }getMostFrequentStepsandgetAverageStepDuration:[]attachIdentifier,deleteWorkflow,deleteAllWorkflows:false
Starts a new workflow and returns a WorkflowInstance object that provides convenient instance methods.
addSteps(workflowId: string | WorkflowInstance, steps: Array<{ step: string, data: any }>): Promise<void>
Adds multiple steps to a workflow in a single batch operation. More efficient than calling addStep multiple times.
Example:
await liteflow.addSteps(workflowId, [
{ step: 'step1', data: { value: 1 } },
{ step: 'step2', data: { value: 2 } },
{ step: 'step3', data: { value: 3 } }
]);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:
liteflow.addStep(workflowId, 'step1', { data: 'test' });
await liteflow.flushBatchInserts(); // Ensure step is persistedThe 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 workflowworkflow.addSteps(steps: Array<{ step: string, data: any }>): Add multiple steps in batch (Promise)workflow.complete(): Mark this workflow as completedworkflow.fail(reason?: string): Mark this workflow as failedworkflow.getSteps(): Get all steps for this workflow (Promise)workflow.delete(): Delete this workflow (Promise)
Adds a step to a workflow. Steps are queued and inserted in batches for performance. Accepts either a workflow ID string or a WorkflowInstance.
Marks a workflow as completed. Accepts either a workflow ID string or a WorkflowInstance.
Retrieves a workflow by its identifier.
Gets all steps for a workflow.
Gets all steps for workflows matching the given identifier key and value.
Returns workflow statistics.
attachIdentifier(existingKey: string, existingValue: string, newIdentifier: Identifier): Promise<boolean>
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.
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 statuspage?: 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 valuename?: 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:
// 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' }
});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.
Deletes all workflows and their steps. Returns true if the operation was successful, false if there was an error.
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;
}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:
// 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 } }
]);The main change is that all database methods are now asynchronous. Add await to all method calls:
// 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:
- All database methods return Promises (use
await) init()is now async- New
destroy()method for cleanup - New batch insert methods (
addSteps,flushBatchInserts) - Multi-database support (SQLite, PostgreSQL, MySQL)
git clone https://github.com/indatawetrust/liteflow.git
cd liteflow
npm installTests are powered by Vitest.
# Run tests once
npm test
# Run tests in watch mode
npm run test:watchnpm run benchmarkMIT