@basementscripts/flow
v1.0.10
Published
Flow Functions
Keywords
Readme
Flow Master
A robust, extensible flow engine for orchestrating complex, dynamic workflows in TypeScript/JavaScript.
Table of Contents
Overview
Flow Master allows you to define a series of nodes (steps) that can be executed in sequence, in parallel, or conditionally, with full support for retries, hooks, and context passing. Each node can be a function or an object with an execute method. Flows can branch, run in parallel, and handle errors gracefully.
API Reference
Flow
import Flow, { type FlowConfig } from './Flow'Constructor
const flow = new Flow(config: FlowConfig)config: The flow configuration object (see Types & Interfaces).
Methods
run(startNodeId: string, context?: Record<string, any>): Promise<void>- Starts the flow at the given node, passing an optional context object.
static execute(config: FlowConfig, startNodeId: string, context?: Record<string, any>): Promise<Flow>- Creates a flow instance with stored execution state; call
.promise()later to run.
- Creates a flow instance with stored execution state; call
promise(): Promise<void>- Runs the stored flow created by
Flow.execute.
- Runs the stored flow created by
static auto(context: Record<string, any>, ...modules: any[]): Promise<void>- Convenience helper that wires modules into a simple linear flow and runs them in order.
flowModule
import { flowModule } from './flowModule'Wraps a function or object for use as a flow node, with optional input/output mapping.
Signature
flowModule({
id?: string
fn: AnyFn | { execute: AnyFn }
if?: BoolFn
skip?: BoolFn
validate?: VoidFn
inputMapper?: (context: any) => any
outputMapper?: (result: any, context: any) => void | Promise<void> | any
errorHandler?: (error: any) => void | Promise<void>
suppressErrors?: boolean
}): (context: any) => Promise<void>Node Hooks
onStart(context)— called before the node runsonSuccess(context)— called after successful executiononFail(error, context)— called on error (before retry or fail)
Config-level Error Handling
onError(error, node, context)— called for unhandled errors at the flow level
Examples
Branching Flow
const flow = new Flow({
nodes: [
{
id: 'start',
module: (ctx) => {
ctx.score = Math.random()
console.log('Started')
},
next: (ctx) => (ctx.score > 0.5 ? 'success' : 'failure'),
onStart: (ctx) => console.log('Starting node "start"...'),
onSuccess: (ctx) => console.log('Node "start" succeeded with score', ctx.score),
onFail: (err, ctx) => console.error('Node "start" failed:', err)
},
{
id: 'success',
module: (ctx) => console.log('✅ Passed with score:', ctx.score)
},
{
id: 'failure',
module: (ctx) => {
throw new Error('🚫 Failed path taken')
},
retries: 2,
retryDelayMs: 300,
onFail: (err, ctx) => console.warn('Retrying "failure"...', err.message)
}
],
onError: (err, node, ctx) => {
console.error(`Unhandled error in node "${node.id}":`, err)
}
})
flow.run('start')Wrapping Async Modules
const wrappedFetchUser = flowModule({
fn: fetchUserProfile,
inputMapper: (ctx) => ({ userId: ctx.session.userId }),
outputMapper: (result, ctx) => ({
userProfile: result
})
})Advanced Usage
Parallel Nodes
{
id: 'start',
module: (ctx) => { /* ... */ },
// Both 'a' and 'b' will run in parallel, then 'after-parallel' will run once both complete.
next: ['a', 'b'],
done: 'after-parallel'
},
{
id: 'a',
module: async (ctx) => { /* ... */ },
next: ''
},
{
id: 'b',
module: async (ctx) => { /* ... */ },
next: ''
},
{
id: 'after-parallel',
module: (ctx) => { /* runs after a & b */ }
}Dynamic Next
next: (ctx) => (ctx.shouldContinue ? 'nextStep' : 'end')Config-level onError
const flow = new Flow({
nodes: [
/* ... */
],
onError: (err, node, ctx) => {
// Custom error handling
}
})Types & Interfaces
FlowConfig
interface FlowConfig {
nodes: Node[]
onError?: (error: Error, node: Node, context: any) => void
}Node
type NextFn =
| string
| string[]
| null
| ((context: any) => string | string[] | null)
type DoneFn = string | ((context: any) => string)
interface Node {
id: string
module:
| ((context: any) => any | Promise<any>)
| { execute: (context: any) => any | Promise<any> }
type?: 'sync' | 'async' | 'parallel'
next?: NextFn
/**
* When next is an array (parallel), run this node after all parallel branches complete.
*/
done?: DoneFn
retries?: number
retryDelayMs?: number
/**
* Event name to listen on; when emitted, flow runs with event payload (id, data).
*/
listen?: string
/**
* Optional event name associated with this node.
*/
event?: string
// Hooks
onStart?: (context: any) => void | Promise<void>
onSuccess?: (context: any) => void | Promise<void>
onFail?: (error: Error | null, context: any) => void | Promise<void>
}Testing
- All logic is covered by Jest tests in
Flow.test.ts. - To run tests:
yarn jest api/src/lib/Flow/Flow.test.ts --no-watch - Add new tests for any new features or edge cases.
Contributing
- Fork and clone the repo.
- Add or update features in
Flow.ts,flowModule.ts, or types. - Add/extend tests in
Flow.test.ts. - Update this README with new usage or API changes.
- Run tests and ensure all pass before submitting a PR.
License
MIT
