flowcraft 1.0.0-beta.21 → 1.0.0-beta.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,16 +39,27 @@ npm install flowcraft
39
39
  Create and run a simple workflow in a few lines of code.
40
40
 
41
41
  ```typescript
42
- import { Flow, mapNode } from 'flowcraft' // Use mapNode for simple functions
42
+ import { contextKey, Flow, Node, TypedContext } from 'flowcraft'
43
43
 
44
- // Create a node from a simple function that takes params and returns a value.
45
- const greetNode = mapNode(() => 'Hello, World!')
46
- // Functional helpers make common tasks easy.
47
- .tap(console.log)
44
+ // 1. Define a type-safe key for our data
45
+ const MESSAGE = contextKey<string>('message')
48
46
 
47
+ // 2. Create nodes using the fluent API
48
+ const greetNode = new Node()
49
+ .exec(async ({ params }) => `Hello, ${params.name}!`)
50
+ .toContext(MESSAGE) // Stores the result in the context
51
+
52
+ const farewellNode = new Node()
53
+ .exec(async ({ ctx }) => `${await ctx.get(MESSAGE)} Goodbye!`)
54
+ .tap(console.log) // Prints the final message
55
+
56
+ // 3. Chain the nodes and create a flow
57
+ greetNode.next(farewellNode)
49
58
  const flow = new Flow(greetNode)
50
- // Run using the default InMemoryExecutor.
51
- await flow.run()
59
+
60
+ // 4. Run the flow with a context and params
61
+ await flow.withParams({ name: 'World' }).run(new TypedContext())
62
+ // Output: "Hello, World! Goodbye!"
52
63
  ```
53
64
 
54
65
  ## Learn by Example
@@ -171,12 +182,13 @@ graph TD
171
182
 
172
183
  The `Node` is the fundamental building block of a workflow. It represents a single unit of work and is fully generic, allowing you to define types for its lifecycle results and its static parameters.
173
184
 
174
- The class signature is: `Node<PrepRes, ExecRes, PostRes, TParams>`
185
+ The class signature is: `Node<PrepRes, ExecRes, PostRes, TParams, TContext>`
175
186
 
176
187
  - `PrepRes`: The type of data returned by the `prep` phase.
177
188
  - `ExecRes`: The type of data returned by the `exec` phase.
178
189
  - `PostRes`: The type of the "action" returned by the `post` phase.
179
190
  - `TParams`: The type of the static parameters object for the node, accessible via `.withParams()`.
191
+ - `TContext`: The type of the `Context` object.
180
192
 
181
193
  **Example: A Type-Safe GreetNode**
182
194
 
@@ -192,7 +204,7 @@ interface GreetParams {
192
204
  // 2. Define the node with the TParams generic.
193
205
  class GreetNode extends Node<void, string, any, GreetParams> {
194
206
  // 3. The 'exec' method can safely access typed parameters.
195
- async exec({ params }: NodeArgs<GreetParams>): Promise<string> {
207
+ async exec({ params }: NodeArgs<void, void, GreetParams>): Promise<string> {
196
208
  let message = `${params.greeting}, World!`
197
209
  if (params.loudly) {
198
210
  message = message.toUpperCase()
@@ -252,8 +264,8 @@ const COUNTER = contextKey<number>('counter')
252
264
  class IncrementCounterNode extends PreNode {
253
265
  // You only need to implement the 'prep' method for context mutations.
254
266
  async prep({ ctx }: NodeArgs): Promise<void> {
255
- const current = ctx.get(COUNTER) ?? 0
256
- ctx.set(COUNTER, current + 1)
267
+ const current = (await ctx.get(COUNTER)) ?? 0
268
+ await ctx.set(COUNTER, current + 1)
257
269
  }
258
270
  }
259
271
  ```
@@ -270,7 +282,7 @@ type UserAction = 'grant_access' | 'deny_access'
270
282
  class CheckAdminNode extends PostNode<UserAction> {
271
283
  // You only need to implement the 'post' method for branching logic.
272
284
  async post({ ctx }: NodeArgs): Promise<UserAction> {
273
- const role = ctx.get(USER_ROLE)
285
+ const role = await ctx.get(USER_ROLE)
274
286
  return role === 'admin' ? 'grant_access' : 'deny_access'
275
287
  }
276
288
  }
@@ -283,7 +295,7 @@ checkAdmin.next(new GuestPageNode(), 'deny_access')
283
295
 
284
296
  ### Flow
285
297
 
286
- A `Flow` is a special type of `Node` that orchestrates a sequence of other nodes. It is also generic (`Flow<PrepRes, ExecRes, TParams>`) and can be configured with its own parameters and middleware. It contains the logic for traversing its own graph of operations, making it a powerful, self-contained unit of work.
298
+ A `Flow` is a special type of `Node` that orchestrates a sequence of other nodes. It is also generic (`Flow<PrepRes, ExecRes, TParams, TContext>`) and can be configured with its own parameters and middleware. It contains the logic for traversing its own graph of operations, making it a powerful, self-contained unit of work.
287
299
 
288
300
  ### Executor
289
301
 
@@ -295,7 +307,7 @@ A `Flow` can be configured with middleware functions that wrap the execution of
295
307
 
296
308
  ### Context
297
309
 
298
- The `Context` is a shared, type-safe `Map`-like object passed through every node in a flow. It acts as a shared memory space, allowing nodes to pass data and share state.
310
+ The `Context` is a shared, type-safe `Map`-like object passed through every node in a flow. It acts as a shared memory space, allowing nodes to pass data and share state. All its methods are asynchronous.
299
311
 
300
312
  ### Actions & Branching
301
313
 
@@ -322,8 +334,8 @@ To simplify the creation of common and complex patterns, the framework provides
322
334
 
323
335
  ### Core Classes
324
336
 
325
- - `Node`: The base class for a unit of work: `Node<PrepRes, ExecRes, PostRes, TParams>`. It has built-in retry logic and a fluent API (`.map`, `.filter`, etc.).
326
- - `Flow`: Orchestrates a sequence of nodes: `Flow<PrepRes, ExecRes, TParams>`. Supports middleware via `.use()`.
337
+ - `Node`: The base class for a unit of work: `Node<PrepRes, ExecRes, PostRes, TParams, TContext>`. It has built-in retry logic and a fluent API (`.map`, `.filter`, etc.).
338
+ - `Flow`: Orchestrates a sequence of nodes: `Flow<PrepRes, ExecRes, TParams, TContext>`. Supports middleware via `.use()`.
327
339
  - `InMemoryExecutor`: The default `IExecutor` implementation for running flows in-memory.
328
340
  - `TypedContext`: The standard `Map`-based implementation for the `Context` interface.
329
341
  - `ConsoleLogger`, `NullLogger`: Pre-built logger implementations.
@@ -343,9 +355,8 @@ A collection of functions for creating nodes and pipelines in a more functional
343
355
  ### Builder Classes
344
356
 
345
357
  - `SequenceFlow`: A `Flow` that creates a linear flow from a sequence of nodes.
346
- - `BatchFlow`: A `Flow` that processes a collection of items sequentially.
347
- - `ParallelBatchFlow`: A `Flow` that processes a collection of items in parallel.
348
- - `GraphBuilder`: Constructs a `Flow` from a declarative graph definition. Its `.build()` method returns a `BuildResult` object containing:
358
+ - **`BatchFlow` / `ParallelBatchFlow`**: Process a collection of items sequentially or concurrently.
359
+ - **`GraphBuilder`**: Constructs a `Flow` from a declarative graph definition. Its `.build()` method returns a `BuildResult` object containing:
349
360
  - `flow`: The executable `Flow` instance.
350
361
  - `nodeMap`: A `Map` of all instantiated nodes, keyed by their ID.
351
362
  - `predecessorCountMap`: A `Map` of node IDs to their total number of incoming connections.