@basementscripts/flow
v1.0.8
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
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.
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?: BoonFn
validate?: VoidFn
inputMapper?: (context: any) => any,
outputMapper?: (result: any, context: any) => void | Promise<void>
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) => { /* ... */ },
next: ['a', 'b'] // Both 'a' and 'b' will run in parallel
},
{
id: 'a', module: async (ctx) => { /* ... */ }, next: ''
},
{
id: 'b', module: async (ctx) => { /* ... */ }, next: ''
}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
interface Node {
id: string
module: Function | { execute: Function }
next?: string | string[] | ((context: any) => string | string[])
retries?: number
retryDelayMs?: number
onStart?: (context: any) => void | Promise<void>
onSuccess?: (context: any) => void | Promise<void>
onFail?: (error: Error, 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
