|
1 | 1 | # **Symflow: A Flexible Workflow Engine for Node.js** |
2 | 2 |
|
3 | 3 | [](https://github.com/vandetho/symflow/actions/workflows/ci.yaml) |
4 | | -[](https://www.npmjs.com/package/symflow) |
| 4 | +[](https://www.npmjs.com/package/symflow) |
5 | 5 | [](https://www.npmjs.com/package/symflow) |
6 | 6 | [](https://github.com/vandetho/symflow/stargazers) |
7 | 7 | [](https://github.com/vandetho/symflow/issues) |
| 8 | +[](https://www.npmjs.com/package/symflow) |
8 | 9 | [](LICENSE) |
9 | 10 |
|
10 | 11 | > 🔗 [View on npm »](https://www.npmjs.com/package/symflow) |
@@ -223,8 +224,101 @@ You can find a complete example of using **Symflow with Express.js** at: [Symflo |
223 | 224 | ### ✅ **Express.js API Support** |
224 | 225 | - Works **optionally** with Express.js **without modifying the core package**. |
225 | 226 |
|
| 227 | + |
| 228 | +--- |
| 229 | + |
| 230 | +## **📜 Event Handling in Symflow** |
| 231 | + |
| 232 | +Symflow allows you to **hook into various workflow events** using event listeners. |
| 233 | + |
| 234 | +### 📌 **Available Events** |
| 235 | +| Event Type | Description | |
| 236 | +|--------------|------------------------------------------------------| |
| 237 | +| `ANNOUNCE` | Fires **before** a transition begins. | |
| 238 | +| `GUARD` | **Prevents** transitions if conditions are not met. | |
| 239 | +| `LEAVE` | Fires **before leaving** a state. | |
| 240 | +| `ENTER` | Fires **before entering** a state. | |
| 241 | +| `TRANSITION` | Fires **during** a transition. | |
| 242 | +| `COMPLETED` | Fires **after** a transition successfully completes. | |
| 243 | +| `ENTERED` | Fires **after** a state is successfully entered. | |
| 244 | + |
| 245 | +## ✨ **Using Event Listeners** |
| 246 | +You can **register event listeners** to customize transition behavior. |
| 247 | + |
| 248 | +### 🛠 **Example: Blocking a Transition with `GUARD`** |
| 249 | +```typescript |
| 250 | +import { Symflow, WorkflowEventType } from "symflow"; |
| 251 | + |
| 252 | +// Define the workflow |
| 253 | +const workflowDefinition = { |
| 254 | + name: "order_workflow", |
| 255 | + stateField: "status", |
| 256 | + initialState: ["draft"], |
| 257 | + places: { draft: {}, pending: {}, confirmed: {} }, |
| 258 | + transitions: { approve: { from: ["draft"], to: ["pending"] } }, |
| 259 | + /* or */ |
| 260 | + events: { |
| 261 | + [WorkflowEventType.GUARD]: [ |
| 262 | + (event) => { |
| 263 | + if (event.entity.userRole !== "admin") { |
| 264 | + console.log("❌ Access Denied: Only admins can approve orders."); |
| 265 | + return false; |
| 266 | + } |
| 267 | + return true; |
| 268 | + }, |
| 269 | + ], |
| 270 | + }, |
| 271 | +}; |
| 272 | + |
| 273 | +// Create a workflow instance |
| 274 | +const workflow = new Symflow(workflowDefinition); |
| 275 | + |
| 276 | +// Register a Guard event to prevent unauthorized transitions |
| 277 | +workflow.on(WorkflowEventType.GUARD, (event) => { |
| 278 | + console.log(`Checking guard for transition "${event.transition}"`); |
| 279 | + if (event.entity.userRole !== "admin") { |
| 280 | + console.log("❌ Access Denied: Only admins can approve orders."); |
| 281 | + return false; // 🚫 Prevent transition |
| 282 | + } |
| 283 | + return true; |
| 284 | +}); |
| 285 | + |
| 286 | +// Sample order entity |
| 287 | +const order = { id: 1, status: ["draft"], userRole: "customer" }; |
| 288 | + |
| 289 | +// Attempt transition |
| 290 | +workflow.apply(order, "approve").catch((err) => console.log(err.message)); |
| 291 | + |
| 292 | +// Output: ❌ Access Denied: Only admins can approve orders. |
| 293 | +``` |
| 294 | +--- |
| 295 | +### 📜 **Metadata in Workflow Events** |
| 296 | + |
| 297 | +Metadata can be included in transitions and is accessible inside events. |
| 298 | +```typescript |
| 299 | +workflow.on(WorkflowEventType.COMPLETED, (event) => { |
| 300 | + console.log(`✅ Transition "${event.transition}" completed!`); |
| 301 | + console.log(`📌 Metadata:`, event.metadata); // ✅ Metadata is now accessible |
| 302 | +}); |
| 303 | +``` |
| 304 | + |
| 305 | +--- |
| 306 | + |
| 307 | +### ✅ **Example: Logging Transitions with `COMPLETED`** |
| 308 | +You can use the `COMPLETED` event to **log successful state changes**. |
| 309 | +```typescript |
| 310 | +workflow.on(WorkflowEventType.COMPLETED, (event) => { |
| 311 | + console.log(`✅ Order ${event.entity.id} successfully transitioned to ${event.toState}`); |
| 312 | +}); |
| 313 | +``` |
| 314 | +--- |
| 315 | +### 📡 **EventEmitter Integration** |
| 316 | +Symflow supports emitting events via Node.js `EventEmitter` for full flexibility and code-splitting. |
| 317 | +[event-emitter.md](doc/event-emitter.md) |
| 318 | + |
226 | 319 | --- |
227 | 320 |
|
| 321 | + |
228 | 322 | ## **📚 API Reference** |
229 | 323 | ### **`new Symflow(definition)`** |
230 | 324 | - **Defines a new workflow** that can be used globally. |
@@ -326,89 +420,5 @@ transitions: { |
326 | 420 | } |
327 | 421 | ``` |
328 | 422 |
|
329 | | ---- |
330 | | - |
331 | | -## **📜 Event Handling in Symflow** |
332 | | -Symflow allows you to **hook into various workflow events** using event listeners. |
333 | | -### 📌 **Available Events** |
334 | | -| Event Type | Description | |
335 | | -|--------------|------------------------------------------------------| |
336 | | -| `ANNOUNCE` | Fires **before** a transition begins. | |
337 | | -| `GUARD` | **Prevents** transitions if conditions are not met. | |
338 | | -| `LEAVE` | Fires **before leaving** a state. | |
339 | | -| `ENTER` | Fires **before entering** a state. | |
340 | | -| `TRANSITION` | Fires **during** a transition. | |
341 | | -| `COMPLETED` | Fires **after** a transition successfully completes. | |
342 | | -| `ENTERED` | Fires **after** a state is successfully entered. | |
343 | | - |
344 | | -## ✨ **Using Event Listeners** |
345 | | -You can **register event listeners** to customize transition behavior. |
346 | | - |
347 | | -### 🛠 **Example: Blocking a Transition with `GUARD`** |
348 | | -```typescript |
349 | | -import { Symflow, WorkflowEventType } from "symflow"; |
350 | | - |
351 | | -// Define the workflow |
352 | | -const workflowDefinition = { |
353 | | - name: "order_workflow", |
354 | | - stateField: "status", |
355 | | - initialState: ["draft"], |
356 | | - places: { draft: {}, pending: {}, confirmed: {} }, |
357 | | - transitions: { approve: { from: ["draft"], to: ["pending"] } } |
358 | | - /* or */ |
359 | | - events: { |
360 | | - [WorkflowEventType.GUARD]: [ |
361 | | - (event) => { |
362 | | - if (event.entity.userRole !== "admin") { |
363 | | - console.log("❌ Access Denied: Only admins can approve orders."); |
364 | | - return false; |
365 | | - } |
366 | | - return true; |
367 | | - }, |
368 | | - ], |
369 | | - }, |
370 | | -}; |
371 | | - |
372 | | -// Create a workflow instance |
373 | | -const workflow = new Symflow(workflowDefinition); |
374 | | - |
375 | | -// Register a Guard event to prevent unauthorized transitions |
376 | | -workflow.on(WorkflowEventType.GUARD, (event) => { |
377 | | - console.log(`Checking guard for transition "${event.transition}"`); |
378 | | - if (event.entity.userRole !== "admin") { |
379 | | - console.log("❌ Access Denied: Only admins can approve orders."); |
380 | | - return false; // 🚫 Prevent transition |
381 | | - } |
382 | | - return true; |
383 | | -}); |
384 | | - |
385 | | -// Sample order entity |
386 | | -const order = { id: 1, status: ["draft"], userRole: "customer" }; |
387 | | - |
388 | | -// Attempt transition |
389 | | -workflow.apply(order, "approve").catch((err) => console.log(err.message)); |
390 | | - |
391 | | -// Output: ❌ Access Denied: Only admins can approve orders. |
392 | | -``` |
393 | | ---- |
394 | | -### 📜 **Metadata in Workflow Events** |
395 | | - |
396 | | -Metadata can be included in transitions and is accessible inside events. |
397 | | -```typescript |
398 | | -workflow.on(WorkflowEventType.COMPLETED, (event) => { |
399 | | - console.log(`✅ Transition "${event.transition}" completed!`); |
400 | | - console.log(`📌 Metadata:`, event.metadata); // ✅ Metadata is now accessible |
401 | | -}); |
402 | | -``` |
403 | | - |
404 | | ---- |
405 | | - |
406 | | -### ✅ **Example: Logging Transitions with `COMPLETED`** |
407 | | -You can use the `COMPLETED` event to **log successful state changes**. |
408 | | -```typescript |
409 | | -workflow.on(WorkflowEventType.COMPLETED, (event) => { |
410 | | - console.log(`✅ Order ${event.entity.id} successfully transitioned to ${event.toState}`); |
411 | | -}); |
412 | | -``` |
413 | 423 |
|
414 | 424 |
|
0 commit comments