{"_id":"@c-a-f/workflow","_rev":"2-832b3b9b7d32f7f82ad86389fcb26c38","name":"@c-a-f/workflow","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.1":{"name":"@c-a-f/workflow","version":"1.0.1","keywords":["clean-architecture-frontend","clean-architecture","caf","workflow","state-machine","state-management","fsm","guards","actions","effects"],"author":{"name":"ali aslani","email":"aliaslani.mm@gmail.com"},"license":"MIT","_id":"@c-a-f/workflow@1.0.1","maintainers":[{"name":"ialiaslani","email":"aliaslani.mm@gmail.com"}],"homepage":"https://github.com/ialiaslani/caf#readme","bugs":{"url":"https://github.com/ialiaslani/caf/issues"},"dist":{"shasum":"f96a7291bf7a87232be0f29418ff50c0203b6214","tarball":"https://registry.npmjs.org/@c-a-f/workflow/-/workflow-1.0.1.tgz","fileCount":24,"integrity":"sha512-TjKeQTcura6fyWJz3wpb44FVr8Tih6A6ozCleqncguIAkOD19G2J2SgP3RSRlTbVxV6GpLypBRz1rLvhYEga0Q==","signatures":[{"sig":"MEYCIQC5a2h0XacIND9qXczLBlX2OzRoOMSicCk6EQYaPE4h6gIhAJS8FkwL+Lw944EYCpvqoOMogWe4HidGwe22gOvqr4Y2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51423},"main":"./.build/index.js","type":"module","types":"./.build/index.d.ts","module":"./.build/index.js","exports":{".":{"node":"./.build/index.js","types":"./.build/index.d.ts","import":"./.build/index.js","default":"./.build/index.js"},"./guards":{"node":"./.build/guards/index.js","types":"./.build/guards/index.d.ts","import":"./.build/guards/index.js","default":"./.build/guards/index.js"},"./actions":{"node":"./.build/actions/index.js","types":"./.build/actions/index.d.ts","import":"./.build/actions/index.js","default":"./.build/actions/index.js"},"./effects":{"node":"./.build/effects/index.js","types":"./.build/effects/index.d.ts","import":"./.build/effects/index.js","default":"./.build/effects/index.js"}},"gitHead":"ca2feba4757534a4a130717ea50c4df2e2ff01e6","scripts":{"test":"vitest run","build":"tsc --build","start":"tsc --watch","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"ialiaslani","email":"aliaslani.mm@gmail.com"},"repository":{"url":"git+https://github.com/ialiaslani/caf.git","type":"git"},"_npmVersion":"10.9.2","description":"Framework-agnostic workflow and state machine management for CAF. Built on top of Ploc for reactive state management. Includes guards, actions, and effects utilities.","directories":{},"_nodeVersion":"22.13.0","dependencies":{"@c-a-f/core":"1.0.3"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/workflow_1.0.1_1771671078273_0.016066412793058316","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@c-a-f/workflow","type":"module","version":"1.0.2","description":"Framework-agnostic workflow and state machine management for CAF. Built on top of Ploc for reactive state management. Includes guards, actions, and effects utilities.","keywords":["clean-architecture-frontend","clean-architecture","caf","workflow","state-machine","state-management","fsm","guards","actions","effects"],"author":{"name":"ali aslani","email":"aliaslani.mm@gmail.com"},"license":"MIT","homepage":"https://docs-caf.vercel.app/docs/packages/workflow","repository":{"type":"git","url":"git+https://github.com/ialiaslani/caf.git"},"main":"./.build/index.js","module":"./.build/index.js","types":"./.build/index.d.ts","exports":{".":{"types":"./.build/index.d.ts","import":"./.build/index.js","node":"./.build/index.js","default":"./.build/index.js"},"./guards":{"types":"./.build/guards/index.d.ts","import":"./.build/guards/index.js","node":"./.build/guards/index.js","default":"./.build/guards/index.js"},"./actions":{"types":"./.build/actions/index.d.ts","import":"./.build/actions/index.js","node":"./.build/actions/index.js","default":"./.build/actions/index.js"},"./effects":{"types":"./.build/effects/index.d.ts","import":"./.build/effects/index.js","node":"./.build/effects/index.js","default":"./.build/effects/index.js"}},"scripts":{"build":"tsc --build","start":"tsc --watch","prepublishOnly":"npm run build","test":"vitest run","test:watch":"vitest"},"dependencies":{"@c-a-f/core":"1.0.3"},"devDependencies":{"vitest":"^2.1.0"},"_id":"@c-a-f/workflow@1.0.2","gitHead":"c754b6d68b1a5b1196bb202e70c962ea7c3de87e","bugs":{"url":"https://github.com/ialiaslani/caf/issues"},"_nodeVersion":"22.13.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-PZCJAOSg4UCx9jJTJ7SvHYt+2LsBVOl3XPO2afU/tjs6qB99+7JP6puEtY2h7bc8r9aiys19wRWOblGvOjs8SA==","shasum":"886c138fa05423979b05b19f29226f48e1a9227f","tarball":"https://registry.npmjs.org/@c-a-f/workflow/-/workflow-1.0.2.tgz","fileCount":24,"unpackedSize":51655,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDBfAaW2v0Mmi7MJTojJWzivwUjvB3CSugMQd59zf29gQIhAPtC0pidZYiFMmVatKHumIRZyopKUgeuQJ6n3xKreZGW"}]},"_npmUser":{"name":"ialiaslani","email":"aliaslani.mm@gmail.com"},"directories":{},"maintainers":[{"name":"ialiaslani","email":"aliaslani.mm@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/workflow_1.0.2_1771680104836_0.7186170235403639"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-21T10:51:18.122Z","modified":"2026-02-21T13:21:45.109Z","1.0.1":"2026-02-21T10:51:18.429Z","1.0.2":"2026-02-21T13:21:44.985Z"},"bugs":{"url":"https://github.com/ialiaslani/caf/issues"},"author":{"name":"ali aslani","email":"aliaslani.mm@gmail.com"},"license":"MIT","homepage":"https://docs-caf.vercel.app/docs/packages/workflow","keywords":["clean-architecture-frontend","clean-architecture","caf","workflow","state-machine","state-management","fsm","guards","actions","effects"],"repository":{"type":"git","url":"git+https://github.com/ialiaslani/caf.git"},"description":"Framework-agnostic workflow and state machine management for CAF. Built on top of Ploc for reactive state management. Includes guards, actions, and effects utilities.","maintainers":[{"name":"ialiaslani","email":"aliaslani.mm@gmail.com"}],"readme":"# @c-a-f/workflow\r\n\r\nFramework-agnostic workflow and state machine management for CAF. Built on top of Ploc for reactive state management.\r\n\r\n**Documentation:** [@c-a-f/workflow docs](https://docs-caf.vercel.app/docs/packages/workflow)\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @c-a-f/workflow\r\n```\r\n\r\n## Usage\r\n\r\n### Core Interfaces\r\n\r\nThe package provides framework-agnostic interfaces for managing workflows and state machines:\r\n\r\n```typescript\r\nimport {\r\n  IWorkflow,\r\n  WorkflowDefinition,\r\n  WorkflowStateSnapshot,\r\n  WorkflowManager,\r\n} from '@c-a-f/workflow';\r\n\r\n// Define workflow\r\nconst orderWorkflow: WorkflowDefinition = {\r\n  id: 'order',\r\n  initialState: 'pending',\r\n  states: {\r\n    pending: {\r\n      id: 'pending',\r\n      label: 'Pending',\r\n      transitions: {\r\n        approve: {\r\n          target: 'approved',\r\n          guard: (context) => context.userRole === 'admin',\r\n        },\r\n        cancel: {\r\n          target: 'cancelled',\r\n        },\r\n      },\r\n    },\r\n    approved: {\r\n      id: 'approved',\r\n      label: 'Approved',\r\n      transitions: {\r\n        ship: {\r\n          target: 'shipped',\r\n        },\r\n      },\r\n    },\r\n    shipped: {\r\n      id: 'shipped',\r\n      label: 'Shipped',\r\n      transitions: {},\r\n    },\r\n    cancelled: {\r\n      id: 'cancelled',\r\n      label: 'Cancelled',\r\n      transitions: {},\r\n    },\r\n  },\r\n};\r\n\r\n// Create workflow manager (built on Ploc for reactive state)\r\nconst workflow = new WorkflowManager(orderWorkflow, { userRole: 'admin' });\r\n\r\n// Subscribe to state changes\r\nworkflow.subscribe((snapshot) => {\r\n  console.log('Current state:', snapshot.currentState);\r\n});\r\n\r\n// Dispatch events to trigger transitions\r\nawait workflow.dispatch('approve');\r\nawait workflow.dispatch('ship');\r\n\r\n// Check if transition is available\r\nif (workflow.canTransition('approve')) {\r\n  await workflow.dispatch('approve');\r\n}\r\n\r\n// Update workflow context\r\nworkflow.updateContext({ orderId: '12345' });\r\n\r\n// Reset workflow to initial state\r\nawait workflow.reset();\r\n```\r\n\r\n## Workflow Definition\r\n\r\nA workflow is defined by a `WorkflowDefinition` object:\r\n\r\n```typescript\r\ninterface WorkflowDefinition {\r\n  id: string;                    // Unique workflow identifier\r\n  initialState: WorkflowStateId; // Initial state ID\r\n  states: Record<WorkflowStateId, WorkflowState>; // All states\r\n}\r\n```\r\n\r\nEach state can have:\r\n- **Transitions**: Available state transitions triggered by events\r\n- **Guards**: Functions that determine if a transition is allowed\r\n- **Actions**: Functions executed during transitions or state entry/exit\r\n\r\n## Workflow Manager\r\n\r\n`WorkflowManager` extends `Ploc` from `@c-a-f/core`, providing reactive state management:\r\n\r\n```typescript\r\nimport { WorkflowManager } from '@c-a-f/workflow';\r\nimport { WorkflowDefinition } from '@c-a-f/workflow';\r\n\r\nconst workflow = new WorkflowManager(definition, initialContext);\r\n\r\n// Subscribe to state changes (reactive)\r\nworkflow.subscribe((snapshot) => {\r\n  console.log('State changed:', snapshot.currentState);\r\n});\r\n\r\n// Dispatch events\r\nawait workflow.dispatch('eventName', payload);\r\n\r\n// Check transitions\r\nconst canTransition = workflow.canTransition('eventName');\r\n\r\n// Update context\r\nworkflow.updateContext({ key: 'value' });\r\n\r\n// Reset workflow\r\nawait workflow.reset();\r\n```\r\n\r\n## Example: Order Processing Workflow\r\n\r\n```typescript\r\nimport { WorkflowManager, WorkflowDefinition } from '@c-a-f/workflow';\r\n\r\nconst orderWorkflow: WorkflowDefinition = {\r\n  id: 'order-processing',\r\n  initialState: 'created',\r\n  states: {\r\n    created: {\r\n      id: 'created',\r\n      label: 'Order Created',\r\n      transitions: {\r\n        pay: {\r\n          target: 'paid',\r\n          action: async (context) => {\r\n            console.log('Processing payment...', context);\r\n          },\r\n        },\r\n        cancel: {\r\n          target: 'cancelled',\r\n        },\r\n      },\r\n      onEnter: async (context) => {\r\n        console.log('Order created:', context.orderId);\r\n      },\r\n    },\r\n    paid: {\r\n      id: 'paid',\r\n      label: 'Paid',\r\n      transitions: {\r\n        ship: {\r\n          target: 'shipped',\r\n          guard: async (context) => {\r\n            return context.paymentConfirmed === true;\r\n          },\r\n        },\r\n        refund: {\r\n          target: 'refunded',\r\n        },\r\n      },\r\n      onEnter: async (context) => {\r\n        console.log('Payment received for order:', context.orderId);\r\n      },\r\n    },\r\n    shipped: {\r\n      id: 'shipped',\r\n      label: 'Shipped',\r\n      transitions: {\r\n        deliver: {\r\n          target: 'delivered',\r\n        },\r\n      },\r\n    },\r\n    delivered: {\r\n      id: 'delivered',\r\n      label: 'Delivered',\r\n      transitions: {},\r\n    },\r\n    cancelled: {\r\n      id: 'cancelled',\r\n      label: 'Cancelled',\r\n      transitions: {},\r\n    },\r\n    refunded: {\r\n      id: 'refunded',\r\n      label: 'Refunded',\r\n      transitions: {},\r\n    },\r\n  },\r\n};\r\n\r\n// Create workflow instance\r\nconst workflow = new WorkflowManager(orderWorkflow, {\r\n  orderId: '12345',\r\n  paymentConfirmed: false,\r\n});\r\n\r\n// Subscribe to state changes\r\nworkflow.subscribe((snapshot) => {\r\n  console.log(`Order ${snapshot.context.orderId} is now ${snapshot.currentState}`);\r\n  if (snapshot.isFinal) {\r\n    console.log('Workflow completed!');\r\n  }\r\n});\r\n\r\n// Process order\r\nawait workflow.dispatch('pay');\r\nworkflow.updateContext({ paymentConfirmed: true });\r\nawait workflow.dispatch('ship');\r\nawait workflow.dispatch('deliver');\r\n```\r\n\r\n## Usage in Use Cases and Plocs\r\n\r\n```typescript\r\nimport { UseCase, RequestResult, pulse } from '@c-a-f/core';\r\nimport { WorkflowManager, WorkflowDefinition } from '@c-a-f/workflow';\r\n\r\nclass ProcessOrder implements UseCase<[{ orderId: string }], void> {\r\n  constructor(private workflow: WorkflowManager) {}\r\n\r\n  async execute(args: { orderId: string }): Promise<RequestResult<void>> {\r\n    try {\r\n      // Update workflow context\r\n      this.workflow.updateContext({ orderId: args.orderId });\r\n\r\n      // Process workflow steps\r\n      await this.workflow.dispatch('pay');\r\n      this.workflow.updateContext({ paymentConfirmed: true });\r\n      await this.workflow.dispatch('ship');\r\n\r\n      return {\r\n        loading: pulse(false),\r\n        data: pulse(undefined!),\r\n        error: pulse(null! as Error),\r\n      };\r\n    } catch (error) {\r\n      return {\r\n        loading: pulse(false),\r\n        data: pulse(undefined!),\r\n        error: pulse(error as Error),\r\n      };\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n## Guard Combinators\r\n\r\nUse guard combinators to create complex guard conditions:\r\n\r\n```typescript\r\nimport { WorkflowDefinition } from '@c-a-f/workflow';\r\nimport { and, or, not, equals, exists } from '@c-a-f/workflow/guards';\r\n\r\nconst orderWorkflow: WorkflowDefinition = {\r\n  id: 'order',\r\n  initialState: 'pending',\r\n  states: {\r\n    pending: {\r\n      id: 'pending',\r\n      transitions: {\r\n        approve: {\r\n          target: 'approved',\r\n          // Complex guard: user must be admin AND (order amount > 1000 OR isVip)\r\n          guard: and(\r\n            (ctx) => ctx.userRole === 'admin',\r\n            or(\r\n              (ctx) => ctx.orderAmount > 1000,\r\n              (ctx) => ctx.isVip === true\r\n            )\r\n          ),\r\n        },\r\n        cancel: {\r\n          target: 'cancelled',\r\n          // Simple guard: check if cancellation allowed\r\n          guard: equals('canCancel', true),\r\n        },\r\n      },\r\n    },\r\n    approved: {\r\n      id: 'approved',\r\n      transitions: {\r\n        ship: {\r\n          target: 'shipped',\r\n          // Guard: payment must be confirmed\r\n          guard: exists('paymentConfirmed'),\r\n        },\r\n      },\r\n    },\r\n    shipped: {\r\n      id: 'shipped',\r\n      transitions: {},\r\n    },\r\n    cancelled: {\r\n      id: 'cancelled',\r\n      transitions: {},\r\n    },\r\n  },\r\n};\r\n```\r\n\r\n### Available Guard Combinators\r\n\r\n- `and(...guards)` — All guards must pass\r\n- `or(...guards)` — At least one guard must pass\r\n- `not(guard)` — Negate a guard\r\n- `always()` — Always returns true\r\n- `never()` — Always returns false\r\n- `equals(property, value)` — Check if context property equals value\r\n- `exists(property)` — Check if context property exists\r\n- `matches(property, predicate)` — Check if context property matches predicate\r\n\r\n## Action Helpers\r\n\r\nUse action helpers to create and compose workflow actions:\r\n\r\n```typescript\r\nimport { WorkflowDefinition } from '@c-a-f/workflow';\r\nimport { log, updateContext, callService, sequence, parallel, conditional, retry } from '@c-a-f/workflow/actions';\r\n\r\nconst orderWorkflow: WorkflowDefinition = {\r\n  id: 'order',\r\n  initialState: 'pending',\r\n  states: {\r\n    pending: {\r\n      id: 'pending',\r\n      transitions: {\r\n        approve: {\r\n          target: 'approved',\r\n          // Sequence of actions\r\n          action: sequence(\r\n            log('Approving order...'),\r\n            updateContext({ status: 'approved', approvedAt: new Date() }),\r\n            callService(async (ctx) => {\r\n              await orderService.approve(ctx.orderId);\r\n            })\r\n          ),\r\n        },\r\n      },\r\n      onEnter: log((ctx) => `Order ${ctx.orderId} is pending`),\r\n    },\r\n    approved: {\r\n      id: 'approved',\r\n      transitions: {\r\n        ship: {\r\n          target: 'shipped',\r\n          // Parallel actions\r\n          action: parallel(\r\n            callService(async (ctx) => {\r\n              await shippingService.createShipment(ctx.orderId);\r\n            }),\r\n            callService(async (ctx) => {\r\n              await notificationService.sendShippingNotification(ctx.orderId);\r\n            })\r\n          ),\r\n        },\r\n      },\r\n      onEnter: sequence(\r\n        log('Order approved'),\r\n        conditional(\r\n          (ctx) => ctx.isVip === true,\r\n          callService(async (ctx) => {\r\n            await vipService.sendVipNotification(ctx.orderId);\r\n          })\r\n        )\r\n      ),\r\n    },\r\n    shipped: {\r\n      id: 'shipped',\r\n      transitions: {},\r\n      onEnter: retry(\r\n        callService(async (ctx) => {\r\n          await deliveryService.scheduleDelivery(ctx.orderId);\r\n        }),\r\n        3, // max attempts\r\n        1000 // delay between attempts\r\n      ),\r\n    },\r\n  },\r\n};\r\n```\r\n\r\n### Available Action Helpers\r\n\r\n- `log(message)` — Log a message\r\n- `updateContext(updates)` — Update workflow context\r\n- `callService(serviceFn)` — Call an async service function\r\n- `sequence(...actions)` — Execute actions in sequence\r\n- `parallel(...actions)` — Execute actions in parallel\r\n- `conditional(condition, trueAction, falseAction?)` — Conditionally execute action\r\n- `retry(action, maxAttempts, delay)` — Retry action on failure\r\n- `timeout(action, ms)` — Timeout action after duration\r\n\r\n## Workflow Effects\r\n\r\nUse effects to reactively respond to workflow state changes:\r\n\r\n```typescript\r\nimport { WorkflowManager, WorkflowDefinition } from '@c-a-f/workflow';\r\nimport { createEffect, onStateEnter, onStateExit, onTransition, onFinalState, createEffects } from '@c-a-f/workflow/effects';\r\nimport { notificationService, auditService, analyticsService, shippingService, reviewService } from './services';\r\n\r\nconst workflow = new WorkflowManager(orderWorkflow, { orderId: '12345' });\r\n\r\n// Effect: Run when entering 'approved' state\r\nconst unsubscribe1 = createEffect(workflow, onStateEnter('approved', async (snapshot) => {\r\n  await notificationService.sendApprovalNotification(snapshot.context.orderId);\r\n  console.log('Order approved:', snapshot.context.orderId);\r\n}));\r\n\r\n// Effect: Run when exiting 'pending' state\r\nconst unsubscribe2 = createEffect(workflow, onStateExit('pending', async (snapshot) => {\r\n  console.log('Order is no longer pending');\r\n}));\r\n\r\n// Effect: Run on any transition\r\nconst unsubscribe3 = createEffect(workflow, onTransition(async (from, to, snapshot) => {\r\n  await auditService.logTransition(snapshot.context.orderId, from, to);\r\n  console.log(`Order ${snapshot.context.orderId} transitioned from ${from} to ${to}`);\r\n}));\r\n\r\n// Effect: Run when workflow reaches final state\r\nconst unsubscribe4 = createEffect(workflow, onFinalState(async (snapshot) => {\r\n  await analyticsService.trackCompletion(snapshot.context.orderId);\r\n  console.log('Order workflow completed');\r\n}));\r\n\r\n// Create multiple effects at once\r\nconst unsubscribeAll = createEffects(\r\n  workflow,\r\n  onStateEnter('shipped', async (snapshot) => {\r\n    await shippingService.sendTrackingInfo(snapshot.context.orderId);\r\n  }),\r\n  onStateEnter('delivered', async (snapshot) => {\r\n    await reviewService.requestReview(snapshot.context.orderId);\r\n  })\r\n);\r\n\r\n// Cleanup: unsubscribe all effects\r\n// unsubscribeAll();\r\n```\r\n\r\n### Available Effect Functions\r\n\r\n- `onStateEnter(stateId, handler)` — Run when entering a specific state\r\n- `onStateExit(stateId, handler)` — Run when exiting a specific state\r\n- `onTransition(handler)` — Run on any state transition\r\n- `onFinalState(handler)` — Run when workflow reaches final state\r\n- `onStateChange(handler)` — Run on every state change\r\n- `createEffect(workflow, effectFactory)` — Create and register an effect\r\n- `createEffects(workflow, ...effectFactories)` — Create multiple effects at once\r\n\r\n## Custom Workflow Implementation\r\n\r\nYou can implement `IWorkflow` interface for custom workflow logic:\r\n\r\n```typescript\r\nimport { IWorkflow, WorkflowStateSnapshot, WorkflowDefinition } from '@c-a-f/workflow';\r\n\r\nclass CustomWorkflow implements IWorkflow {\r\n  private currentState: string = 'initial';\r\n  private context: Record<string, unknown> = {};\r\n  private definition: WorkflowDefinition;\r\n\r\n  constructor(definition: WorkflowDefinition) {\r\n    this.definition = definition;\r\n    this.currentState = definition.initialState;\r\n  }\r\n\r\n  getState(): WorkflowStateSnapshot {\r\n    return {\r\n      currentState: this.currentState,\r\n      context: this.context,\r\n      isFinal: this.isFinalState(),\r\n    };\r\n  }\r\n\r\n  async dispatch(event: string): Promise<boolean> {\r\n    // Custom transition logic\r\n    return true;\r\n  }\r\n\r\n  canTransition(event: string): boolean {\r\n    // Check if transition is allowed\r\n    return true;\r\n  }\r\n\r\n  async reset(): Promise<void> {\r\n    this.currentState = this.definition.initialState;\r\n    this.context = {};\r\n  }\r\n\r\n  updateContext(context: Record<string, unknown>): void {\r\n    this.context = { ...this.context, ...context };\r\n  }\r\n\r\n  getDefinition(): WorkflowDefinition {\r\n    return this.definition;\r\n  }\r\n\r\n  private isFinalState(): boolean {\r\n    // Check if current state is final\r\n    return false;\r\n  }\r\n}\r\n```\r\n\r\n## Exports\r\n\r\n- `IWorkflow` — Interface for workflow/state machine implementations\r\n- `WorkflowDefinition` — Interface for workflow definitions\r\n- `WorkflowState` — Interface for workflow state definitions\r\n- `WorkflowTransition` — Interface for workflow transition definitions\r\n- `WorkflowStateSnapshot` — Interface for workflow state snapshots\r\n- `WorkflowManager` — Class for managing workflows (built on Ploc)\r\n- `WorkflowStateId` — Type for state identifiers\r\n- `WorkflowEventId` — Type for event identifiers\r\n- `WorkflowContext` — Type for workflow context/data\r\n- `WorkflowGuard` — Type for guard functions\r\n- `WorkflowAction` — Type for action handlers\r\n- Guard combinators: `and`, `or`, `not`, `always`, `never`, `equals`, `exists`, `matches` (from `@c-a-f/workflow/guards`)\r\n- Action helpers: `log`, `updateContext`, `callService`, `sequence`, `parallel`, `conditional`, `retry`, `timeout` (from `@c-a-f/workflow/actions`)\r\n- Effect functions: `onStateEnter`, `onStateExit`, `onTransition`, `onFinalState`, `onStateChange`, `createEffect`, `createEffects` (from `@c-a-f/workflow/effects`)\r\n\r\n## Testing\r\n\r\nThe workflow package includes comprehensive test coverage. You can test your workflows using standard testing frameworks:\r\n\r\n```typescript\r\nimport { describe, it, expect } from 'vitest';\r\nimport { WorkflowManager, WorkflowDefinition } from '@c-a-f/workflow';\r\n\r\ndescribe('Order Workflow', () => {\r\n  let workflow: WorkflowManager;\r\n  let definition: WorkflowDefinition;\r\n\r\n  beforeEach(() => {\r\n    definition = {\r\n      id: 'order',\r\n      initialState: 'pending',\r\n      states: {\r\n        pending: {\r\n          id: 'pending',\r\n          transitions: {\r\n            approve: { target: 'approved' },\r\n            cancel: { target: 'cancelled' },\r\n          },\r\n        },\r\n        approved: {\r\n          id: 'approved',\r\n          transitions: {\r\n            ship: { target: 'shipped' },\r\n          },\r\n        },\r\n        shipped: {\r\n          id: 'shipped',\r\n          transitions: {},\r\n        },\r\n        cancelled: {\r\n          id: 'cancelled',\r\n          transitions: {},\r\n        },\r\n      },\r\n    };\r\n    workflow = new WorkflowManager(definition);\r\n  });\r\n\r\n  it('should transition from pending to approved', async () => {\r\n    const result = await workflow.dispatch('approve');\r\n    expect(result).toBe(true);\r\n    expect(workflow.getState().currentState).toBe('approved');\r\n  });\r\n\r\n  it('should not allow invalid transitions', async () => {\r\n    const result = await workflow.dispatch('ship'); // Not available from pending\r\n    expect(result).toBe(false);\r\n    expect(workflow.getState().currentState).toBe('pending');\r\n  });\r\n\r\n  it('should check if transition is available', () => {\r\n    expect(workflow.canTransition('approve')).toBe(true);\r\n    expect(workflow.canTransition('ship')).toBe(false);\r\n  });\r\n\r\n  it('should notify subscribers on state change', async () => {\r\n    const states: string[] = [];\r\n    const listener = (snapshot: WorkflowStateSnapshot) => {\r\n      states.push(snapshot.currentState);\r\n    };\r\n\r\n    workflow.subscribe(listener);\r\n    await workflow.dispatch('approve');\r\n    await workflow.dispatch('ship');\r\n\r\n    expect(states).toContain('approved');\r\n    expect(states).toContain('shipped');\r\n\r\n    workflow.unsubscribe(listener);\r\n  });\r\n});\r\n```\r\n\r\n### Testing Guards\r\n\r\n```typescript\r\nimport { and, equals } from '@c-a-f/workflow/guards';\r\n\r\nit('should respect guard conditions', async () => {\r\n  const definition: WorkflowDefinition = {\r\n    id: 'order',\r\n    initialState: 'pending',\r\n    states: {\r\n      pending: {\r\n        id: 'pending',\r\n        transitions: {\r\n          approve: {\r\n            target: 'approved',\r\n            guard: equals('userRole', 'admin'),\r\n          },\r\n        },\r\n      },\r\n      approved: {\r\n        id: 'approved',\r\n        transitions: {},\r\n      },\r\n    },\r\n  };\r\n\r\n  const workflow = new WorkflowManager(definition, { userRole: 'user' });\r\n  const result = await workflow.dispatch('approve');\r\n  \r\n  expect(result).toBe(false); // Guard should prevent transition\r\n  expect(workflow.getState().currentState).toBe('pending');\r\n});\r\n```\r\n\r\n### Testing Effects\r\n\r\n```typescript\r\nimport { createEffect, onStateEnter } from '@c-a-f/workflow/effects';\r\n\r\nit('should trigger effects on state changes', async () => {\r\n  const handler = vi.fn();\r\n  const effect = onStateEnter('approved', handler);\r\n\r\n  createEffect(workflow, effect);\r\n  await workflow.dispatch('approve');\r\n\r\n  expect(handler).toHaveBeenCalledTimes(1);\r\n  expect(handler).toHaveBeenCalledWith(\r\n    expect.objectContaining({ currentState: 'approved' })\r\n  );\r\n});\r\n```\r\n\r\n## Dependencies\r\n\r\n- `@c-a-f/core` — Core primitives (Ploc)\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md"}