@omega-flow/engine 0.1.0

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.
@@ -0,0 +1,997 @@
1
+ import { Edge, Event, Node, Workflow, WorkflowHistoryItem, WorkflowStatus, Context } from '@omega-flow/types';
2
+
3
+ /**
4
+ * Represents a connection (edge) between two nodes in a workflow graph.
5
+ *
6
+ * EdgeModel wraps the underlying Edge definition and provides methods
7
+ * to access source and target node information, as well as handle identifiers
8
+ * for connecting specific input/output ports on nodes.
9
+ */
10
+ declare class EdgeModel {
11
+ /** The underlying edge definition from the workflow */
12
+ edge: Edge;
13
+ /**
14
+ * Creates a new EdgeModel instance.
15
+ * @param edge - The edge definition from the workflow
16
+ * @throws Error if edge is missing, has no id, or lacks source/target
17
+ */
18
+ constructor(edge: Edge);
19
+ /**
20
+ * Gets the unique identifier of this edge.
21
+ * @returns The edge's ID as a string
22
+ */
23
+ getId(): string;
24
+ /**
25
+ * Gets the ID of the source (origin) node.
26
+ * @returns The source node's ID as a string
27
+ */
28
+ getSourceNodeId(): string;
29
+ /**
30
+ * Gets the source handle identifier (output port).
31
+ * Handles allow nodes to have multiple outputs (e.g., "true"/"false" for conditions).
32
+ * @returns The source handle name, or "_" if not specified
33
+ */
34
+ getSourceHandle(): string;
35
+ /**
36
+ * Gets the ID of the target (destination) node.
37
+ * @returns The target node's ID as a string
38
+ */
39
+ getTargetNodeId(): string;
40
+ /**
41
+ * Gets the target handle identifier (input port).
42
+ * @returns The target handle name, or "_" if not specified
43
+ */
44
+ getTargetHandle(): string;
45
+ }
46
+
47
+ /**
48
+ * Represents a connection from a source node to a target node via an edge.
49
+ *
50
+ * Connections are stored on the source node and define which target node
51
+ * is reachable through a specific edge. This structure enables nodes to
52
+ * look up their outgoing connections and determine the next node in the workflow.
53
+ */
54
+ type Connection = {
55
+ /** The destination node that this connection leads to */
56
+ targetNode: NodeModel;
57
+ /** The edge that defines this connection, including handle information */
58
+ edge: EdgeModel;
59
+ };
60
+
61
+ /**
62
+ * Minimal interface for WorkflowManager used by schedulers.
63
+ * This forward declaration avoids circular dependency issues.
64
+ */
65
+ interface IWorkflowManager {
66
+ /**
67
+ * Process an event through the workflow system.
68
+ * @param event - The event to process
69
+ */
70
+ processEvent(event: Event): Promise<void>;
71
+ }
72
+ /**
73
+ * Interface for scheduling future workflow events
74
+ * Used for timeouts, delays, and other time-based workflow events
75
+ */
76
+ interface WorkflowScheduler {
77
+ /**
78
+ * Schedule an event to be delivered after a delay
79
+ * When the delay expires, the event will be passed to the workflow manager
80
+ * @param event - The event to schedule
81
+ * @param delayMs - Delay in milliseconds before the event is delivered
82
+ * @returns Promise resolving to a schedule ID that can be used to cancel the schedule
83
+ */
84
+ schedule(event: Event, delayMs: number): Promise<string>;
85
+ /**
86
+ * Cancel a scheduled event
87
+ * @param scheduleId - The ID of the schedule to cancel
88
+ * @returns Promise resolving to true if canceled, false if not found
89
+ */
90
+ cancel(scheduleId: string): Promise<boolean>;
91
+ }
92
+
93
+ interface NodeServices {
94
+ scheduler?: WorkflowScheduler;
95
+ }
96
+
97
+ /**
98
+ * Base class for all workflow node types.
99
+ *
100
+ * NodeModel represents a single step in a workflow graph. Each node can accept events,
101
+ * process them, and determine which node should be executed next. Subclasses must
102
+ * implement the `acceptEvent` and `nextNode` methods to define their specific behavior.
103
+ *
104
+ * When a workflow is on a node, that node is waiting for events (not yet processed).
105
+ * Processing happens when an event is accepted by the node.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * class MyCustomNode extends NodeModel {
110
+ * async acceptEvent(event: Event): Promise<boolean> {
111
+ * // Return true if event is accepted and processing is complete
112
+ * return event.type === 'my-event';
113
+ * }
114
+ *
115
+ * async nextNode(event: Event): Promise<NodeModel | null> {
116
+ * return this.getTargetNodeFromSourceHandle('output');
117
+ * }
118
+ * }
119
+ * ```
120
+ */
121
+ declare class NodeModel {
122
+ /**
123
+ * Factory method to create a new NodeModel instance.
124
+ * Subclasses should override this method to perform type validation.
125
+ * @param node - The node definition from the workflow
126
+ * @returns A new NodeModel instance
127
+ */
128
+ static create(node: Node): NodeModel;
129
+ /** The underlying node definition from the workflow */
130
+ node: Node;
131
+ /** List of outgoing connections to other nodes */
132
+ connections: Connection[];
133
+ /** Internal state that persists across event processing. Use setState/getState to access. */
134
+ state: any;
135
+ /** Services available to nodes (scheduler, etc.) */
136
+ services: NodeServices;
137
+ /**
138
+ * Creates a new NodeModel instance.
139
+ * @param node - The node definition from the workflow
140
+ * @throws Error if node is missing or doesn't have an id
141
+ */
142
+ constructor(node: Node);
143
+ /**
144
+ * Gets the unique identifier of this node.
145
+ * @returns The node's ID as a string
146
+ */
147
+ getId(): string;
148
+ /**
149
+ * Gets the data payload associated with this node.
150
+ * This typically contains node-specific configuration like parameters.
151
+ * @returns The node's data object, or an empty object if not defined
152
+ */
153
+ getData(): any;
154
+ /**
155
+ * Checks if this node is equal to another node by comparing IDs.
156
+ * @param node - The node to compare against (can be null)
157
+ * @returns True if the nodes have the same ID, false otherwise
158
+ */
159
+ equals(node: NodeModel | null): boolean;
160
+ /**
161
+ * Gets the current internal state of the node.
162
+ * State is used to share data between `acceptEvent` and `nextNode` methods.
163
+ * @returns The current state object
164
+ */
165
+ getState(): any;
166
+ /**
167
+ * Replaces the entire internal state of the node.
168
+ * @param state - The new state object
169
+ */
170
+ setState(state: any): void;
171
+ /**
172
+ * Merges changes into the existing state (shallow merge).
173
+ * @param changes - Object containing state properties to update
174
+ */
175
+ updateState(changes: any): void;
176
+ /**
177
+ * Connects this node to a target node via an edge.
178
+ * This node becomes the source node of the connection.
179
+ * @param targetNode - The node to connect to
180
+ * @param edge - The edge defining the connection
181
+ * @throws Error if attempting to connect node to itself
182
+ * @throws Error if connection already exists with the same source handle
183
+ */
184
+ connect(targetNode: NodeModel, edge: EdgeModel): void;
185
+ /**
186
+ * Returns all outgoing connections from this node.
187
+ * @returns Array of Connection objects containing targetNode and edge
188
+ */
189
+ getConnections(): Connection[];
190
+ /**
191
+ * Returns all source handle identifiers (output labels) for this node.
192
+ * Source handles define the different output paths from this node.
193
+ * @returns Array of source handle strings
194
+ */
195
+ getSourceHandles(): string[];
196
+ /**
197
+ * Finds the target node connected to a specific source handle.
198
+ * @param sourceHandle - The source handle (output) identifier to look up
199
+ * @returns The connected NodeModel, or null if no connection exists for the handle
200
+ */
201
+ getTargetNodeFromSourceHandle(sourceHandle: string): NodeModel | null;
202
+ /**
203
+ * Returns the target node connected to the first source handle, or null
204
+ * if this node has no outgoing connections.
205
+ *
206
+ * Most pass-through nodes (single output) implement `nextNode` as
207
+ * `return this.getDefaultNext();`. Use it instead of repeating the
208
+ * `getSourceHandles()[0]` lookup by hand.
209
+ */
210
+ getDefaultNext(): NodeModel | null;
211
+ /**
212
+ * Accepts and processes an incoming event.
213
+ *
214
+ * This method must be overridden by subclasses to define how the node
215
+ * handles events. The method can be called multiple times for the same
216
+ * logical operation (e.g., start wait, then complete wait).
217
+ *
218
+ * @param event - The event to process
219
+ * @returns Promise resolving to true if event is accepted and processing is complete,
220
+ * false if the node is still waiting or doesn't accept the event
221
+ * @throws Error if not implemented by subclass
222
+ */
223
+ acceptEvent(_event: Event): Promise<boolean>;
224
+ /**
225
+ * Determines the next node to execute after processing an event.
226
+ *
227
+ * This method must be overridden by subclasses. It is called after
228
+ * `acceptEvent` returns true to determine where the workflow should go next.
229
+ *
230
+ * @param event - The event that was processed
231
+ * @returns Promise resolving to the next NodeModel to execute,
232
+ * or null if the workflow should end
233
+ * @throws Error if not implemented by subclass
234
+ */
235
+ nextNode(_event: Event): Promise<NodeModel | null>;
236
+ }
237
+
238
+ /**
239
+ * Core workflow execution engine that manages the lifecycle of a single workflow instance.
240
+ *
241
+ * WorkflowModel takes a workflow definition (graph of nodes and edges) and executes it
242
+ * by processing events and moving through nodes. It maintains execution state including
243
+ * the current node, history, and node-specific state.
244
+ *
245
+ * Workflow execution follows this model:
246
+ * 1. Workflow starts in `idle` status
247
+ * 2. After `start()` is called, status becomes `waiting`
248
+ * 3. When an event arrives via `acceptEvent()`:
249
+ * - If current node accepts the event, status becomes `processing`
250
+ * - After determining next node, status becomes `transforming`
251
+ * - Once moved to next node, status returns to `waiting`
252
+ * - Process repeats recursively until node doesn't accept the event
253
+ * 4. When workflow reaches an exit node, status becomes `completed`
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const workflow = new WorkflowModel(workflowDef, nodeModels);
258
+ * workflow.start();
259
+ * await workflow.acceptEvent({ type: 'trigger', time: Date.now(), data: {} });
260
+ * const context = workflow.getContext(); // Save for later resumption
261
+ * ```
262
+ */
263
+ declare class WorkflowModel {
264
+ #private;
265
+ /** The workflow definition containing metadata, flow (nodes/edges), and options */
266
+ workflow: Workflow;
267
+ /** Array of instantiated node models for this workflow */
268
+ nodes: NodeModel[];
269
+ /** Array of edge models connecting the nodes */
270
+ edges: EdgeModel[];
271
+ /** The node currently waiting for events (null before start or after completion) */
272
+ currentNode: NodeModel | null;
273
+ /** Execution history recording workflow transitions */
274
+ history: WorkflowHistoryItem[];
275
+ /** Current execution status of the workflow */
276
+ status: WorkflowStatus;
277
+ /** Unique identifier for this workflow instance */
278
+ instanceId: string;
279
+ /** Unix timestamp (ms) when this workflow instance was started */
280
+ startedAt: number;
281
+ /**
282
+ * Creates a new WorkflowModel instance from a workflow definition.
283
+ * @param workflow - The workflow definition to execute
284
+ * @param nodeModels - Map of node type names to their NodeModel classes
285
+ * @throws Error if workflow is invalid or missing required nodes
286
+ */
287
+ constructor(workflow: Workflow, nodeModels: Record<string, typeof NodeModel>, services?: NodeServices);
288
+ /**
289
+ * Restores workflow state from a previously saved context.
290
+ * Use this to resume a workflow that was interrupted or to restore from persistence.
291
+ * After calling setContext, you must call start() to begin processing events.
292
+ * @param context - The context to restore from
293
+ * @throws Error if workflow is already running
294
+ * @throws Error if context is invalid or doesn't match this workflow
295
+ * @throws Error if the current node in context doesn't exist in the workflow
296
+ */
297
+ setContext(context: Context): void;
298
+ /**
299
+ * Exports the current workflow state as a Context object.
300
+ * The context contains all information needed to restore the workflow later.
301
+ * @returns A Context object containing workflow state
302
+ */
303
+ getContext(): Context;
304
+ /**
305
+ * Gets the current execution status of the workflow.
306
+ * @returns The current WorkflowStatus
307
+ */
308
+ getStatus(): WorkflowStatus;
309
+ /**
310
+ * Starts or resumes the workflow execution.
311
+ * If no context was set, starts from the beginning at the start node.
312
+ * If a context was set via setContext(), resumes from the saved position.
313
+ * @throws Error if workflow is already running or completed
314
+ * @throws Error if workflow has no start node
315
+ */
316
+ start(): void;
317
+ /**
318
+ * Processes an incoming event through the workflow.
319
+ *
320
+ * This is the main event processing method. It passes the event to the current node
321
+ * and handles workflow transitions. The method recursively processes the event through
322
+ * subsequent nodes until a node doesn't accept the event or the workflow completes.
323
+ *
324
+ * @param event - The event to process
325
+ * @throws Error if workflow is not in waiting status
326
+ * @throws Error if event is invalid
327
+ * @throws Error if current node is not set
328
+ */
329
+ acceptEvent(event: Event): Promise<void>;
330
+ /**
331
+ * Gets the current node that is waiting for events.
332
+ * @returns The current NodeModel
333
+ * @throws Error if workflow is not running (still idle)
334
+ */
335
+ getCurrentNode(): NodeModel | null;
336
+ /**
337
+ * Finds the start node of the workflow.
338
+ * The start node is the node with no incoming edges.
339
+ * @returns The start NodeModel, or null if not found
340
+ */
341
+ getStartNode(): NodeModel | null;
342
+ /**
343
+ * Finds a node by its ID.
344
+ * @param nodeId - The ID of the node to find (can be null)
345
+ * @returns The NodeModel if found, or null if not found or nodeId is null
346
+ */
347
+ getNode(nodeId: string | null): NodeModel | null;
348
+ }
349
+
350
+ /**
351
+ * Node that performs an action and immediately proceeds to the next node.
352
+ *
353
+ * ActionModel accepts all events unconditionally and moves to the next node.
354
+ * It represents a step in the workflow that performs some operation (defined
355
+ * in the node's data) and continues without waiting.
356
+ *
357
+ * This node type is useful for:
358
+ * - Sending notifications
359
+ * - Updating external systems
360
+ * - Logging or recording events
361
+ * - Any non-blocking operation
362
+ *
363
+ * @example
364
+ * ```json
365
+ * {
366
+ * "id": "action-1",
367
+ * "type": "Action",
368
+ * "data": {
369
+ * "action": "sendEmail",
370
+ * "params": { "to": "user@example.com" }
371
+ * }
372
+ * }
373
+ * ```
374
+ */
375
+ declare class ActionModel extends NodeModel {
376
+ /**
377
+ * Creates a new ActionModel instance.
378
+ * @param node - The node definition from the workflow
379
+ */
380
+ constructor(node: Node);
381
+ /**
382
+ * Factory method to create an ActionModel with type validation.
383
+ * @param node - The node definition from the workflow
384
+ * @returns A new ActionModel instance
385
+ * @throws Error if node type is not "Action"
386
+ */
387
+ static create(node: Node): ActionModel;
388
+ /**
389
+ * Accepts all events immediately.
390
+ * Actions don't filter events - they execute whenever reached.
391
+ * @param _event - The event being processed (unused)
392
+ * @returns Always returns true (event accepted)
393
+ */
394
+ acceptEvent(_event: Event): Promise<boolean>;
395
+ /**
396
+ * Returns the next node connected to this action's output.
397
+ * @param _event - The event being processed (unused)
398
+ * @returns The next NodeModel, or null if no connection exists
399
+ */
400
+ nextNode(_event: Event): Promise<NodeModel | null>;
401
+ }
402
+
403
+ /**
404
+ * Node that evaluates conditions and routes to different paths based on the result.
405
+ *
406
+ * The conditions are configured in the node's data.conditions field using the
407
+ * shared `Conditions` format: top-level OR between groups, each group is AND
408
+ * (`all`) or OR (`any`) of leaf rules. The same shape is produced by the
409
+ * editor's visual condition builder, so no conversion is needed at runtime.
410
+ *
411
+ * @example
412
+ * ```json
413
+ * {
414
+ * "id": "condition-1",
415
+ * "type": "Condition",
416
+ * "data": {
417
+ * "conditions": {
418
+ * "groups": [
419
+ * {
420
+ * "operator": "all",
421
+ * "conditions": [
422
+ * { "fact": "amount", "operator": "greaterThan", "value": 100 }
423
+ * ]
424
+ * }
425
+ * ]
426
+ * }
427
+ * }
428
+ * }
429
+ * ```
430
+ */
431
+ declare class ConditionModel extends NodeModel {
432
+ constructor(node: Node);
433
+ /**
434
+ * Factory method to create a ConditionModel with type validation.
435
+ */
436
+ static create(node: Node): ConditionModel;
437
+ /**
438
+ * Evaluates the condition against the event data using the built-in
439
+ * evaluator. The result is stored in state for use by nextNode().
440
+ */
441
+ acceptEvent(event: Event): Promise<boolean>;
442
+ /**
443
+ * Routes to "true" handle if condition passed, "false" handle otherwise.
444
+ */
445
+ nextNode(_event: Event): Promise<NodeModel | null>;
446
+ }
447
+
448
+ /**
449
+ * Node that terminates the workflow execution.
450
+ *
451
+ * ExitModel accepts all events and returns null from nextNode(), which signals
452
+ * to the WorkflowModel that the workflow should be marked as completed.
453
+ * Every workflow should have at least one exit node to properly terminate.
454
+ *
455
+ * @example
456
+ * ```json
457
+ * {
458
+ * "id": "exit-1",
459
+ * "type": "Exit",
460
+ * "data": {}
461
+ * }
462
+ * ```
463
+ */
464
+ declare class ExitModel extends NodeModel {
465
+ /**
466
+ * Creates a new ExitModel instance.
467
+ * @param node - The node definition from the workflow
468
+ */
469
+ constructor(node: Node);
470
+ /**
471
+ * Factory method to create an ExitModel with type validation.
472
+ * @param node - The node definition from the workflow
473
+ * @returns A new ExitModel instance
474
+ * @throws Error if node type is not "Exit"
475
+ */
476
+ static create(node: Node): ExitModel;
477
+ /**
478
+ * Accepts all events immediately.
479
+ * Exit nodes don't filter events - they terminate whenever reached.
480
+ * @param _event - The event being processed (unused)
481
+ * @returns Always returns true (event accepted)
482
+ */
483
+ acceptEvent(_event: Event): Promise<boolean>;
484
+ /**
485
+ * Always returns null to signal workflow termination.
486
+ * @param _event - The event being processed (unused)
487
+ * @returns Always null, signaling workflow completion
488
+ */
489
+ nextNode(_event: Event): Promise<NodeModel | null>;
490
+ }
491
+
492
+ /**
493
+ * Node that waits for a specific event type before proceeding.
494
+ *
495
+ * TriggerModel acts as a start node or checkpoint in a workflow that only
496
+ * accepts events matching the configured event type. This allows workflows
497
+ * to be triggered by specific events from external systems.
498
+ *
499
+ * The trigger event type is configured in the node's data.params.event field.
500
+ *
501
+ * @example
502
+ * ```json
503
+ * {
504
+ * "id": "trigger-1",
505
+ * "type": "Trigger",
506
+ * "data": {
507
+ * "params": { "event": "order_placed" }
508
+ * }
509
+ * }
510
+ * ```
511
+ */
512
+ declare class TriggerModel extends NodeModel {
513
+ /**
514
+ * Creates a new TriggerModel instance.
515
+ * @param node - The node definition from the workflow
516
+ */
517
+ constructor(node: Node);
518
+ /**
519
+ * Factory method to create a TriggerModel with type validation.
520
+ * @param node - The node definition from the workflow
521
+ * @returns A new TriggerModel instance
522
+ * @throws Error if node type is not "Trigger"
523
+ */
524
+ static create(node: Node): TriggerModel;
525
+ /**
526
+ * Accepts events that match the configured trigger event type.
527
+ * @param event - The event being processed
528
+ * @returns True if event.type matches the configured params.event, false otherwise
529
+ */
530
+ acceptEvent(event: Event): Promise<boolean>;
531
+ /**
532
+ * Returns the next node connected to this trigger's output.
533
+ * @param _event - The event being processed (unused)
534
+ * @returns The next NodeModel, or null if no connection exists
535
+ */
536
+ nextNode(_event: Event): Promise<NodeModel | null>;
537
+ }
538
+
539
+ /**
540
+ * Node that pauses workflow execution for a specified duration.
541
+ *
542
+ * WaitModel implements a time-based delay in the workflow. On the first event,
543
+ * it starts waiting and returns false (not accepted). Subsequent events check
544
+ * if the wait duration has elapsed. Once complete, the node accepts the event
545
+ * and proceeds to the next node.
546
+ *
547
+ * The wait duration is configured in the node's data.params.duration field
548
+ * (in milliseconds).
549
+ *
550
+ * State tracking:
551
+ * - `waitStartsAt`: Timestamp when waiting began
552
+ * - `waitEndsAt`: Timestamp when waiting completed
553
+ *
554
+ * @example
555
+ * ```json
556
+ * {
557
+ * "id": "wait-1",
558
+ * "type": "Wait",
559
+ * "data": {
560
+ * "params": { "duration": 60000 }
561
+ * }
562
+ * }
563
+ * ```
564
+ */
565
+ declare class WaitModel extends NodeModel {
566
+ /**
567
+ * Creates a new WaitModel instance.
568
+ * @param node - The node definition from the workflow
569
+ */
570
+ constructor(node: Node);
571
+ /**
572
+ * Factory method to create a WaitModel with type validation.
573
+ * @param node - The node definition from the workflow
574
+ * @returns A new WaitModel instance
575
+ * @throws Error if node type is not "Wait"
576
+ */
577
+ static create(node: Node): WaitModel;
578
+ /**
579
+ * Checks if the node is currently in a waiting state.
580
+ * @returns True if waiting has been started but not completed
581
+ */
582
+ isWaiting(): boolean;
583
+ /**
584
+ * Starts the waiting period by recording the start time and scheduling a timeout event.
585
+ * @param time - The timestamp when waiting begins (usually event.time)
586
+ * @param eventData - Optional event data to include in the scheduled timeout (for routing)
587
+ */
588
+ startWaiting(time: number, eventData?: any): Promise<void>;
589
+ /**
590
+ * Stops the waiting period by recording the end time.
591
+ * @param time - The timestamp when waiting ends
592
+ */
593
+ stopWaiting(time: number): void;
594
+ /**
595
+ * Checks if the configured wait duration has elapsed.
596
+ * @param currentTime - The current timestamp to check against
597
+ * @returns True if waiting and the duration has passed, false otherwise
598
+ */
599
+ isWaitComplete(currentTime: number): boolean;
600
+ /**
601
+ * Processes events during the waiting period.
602
+ * - First event: Starts waiting and returns false
603
+ * - Subsequent events: Checks if wait is complete
604
+ * - If complete: Stops waiting and returns true
605
+ * - If not complete: Returns false (still waiting)
606
+ * @param event - The event being processed
607
+ * @returns True if wait is complete and event is accepted, false if still waiting
608
+ */
609
+ acceptEvent(event: Event): Promise<boolean>;
610
+ /**
611
+ * Returns the next node connected to this wait node's output.
612
+ * @param _event - The event being processed (unused)
613
+ * @returns The next NodeModel, or null if no connection exists
614
+ */
615
+ nextNode(_event: Event): Promise<NodeModel | null>;
616
+ }
617
+
618
+ /**
619
+ * Node that waits for either a specific event or a timeout, whichever comes first.
620
+ *
621
+ * TriggerOrTimeoutModel extends WaitModel to add event-based triggering.
622
+ * It will proceed when either:
623
+ * 1. A matching event arrives (configured in params.event) — routes via the `trigger` source handle
624
+ * 2. The timeout duration elapses (configured in params.duration) — routes via the `timeout` source handle
625
+ *
626
+ * This is useful for scenarios like:
627
+ * - "Wait for payment confirmation or timeout after 24 hours"
628
+ * - "Wait for user action or proceed automatically after delay"
629
+ *
630
+ * @example
631
+ * ```json
632
+ * {
633
+ * "id": "trigger-or-timeout-1",
634
+ * "type": "TriggerOrTimeout",
635
+ * "data": {
636
+ * "params": {
637
+ * "event": "payment_received",
638
+ * "duration": 86400000
639
+ * }
640
+ * }
641
+ * }
642
+ * ```
643
+ */
644
+ declare class TriggerOrTimeoutModel extends WaitModel {
645
+ /**
646
+ * Creates a new TriggerOrTimeoutModel instance.
647
+ * @param node - The node definition from the workflow
648
+ */
649
+ constructor(node: Node);
650
+ /**
651
+ * Factory method to create a TriggerOrTimeoutModel with type validation.
652
+ * @param node - The node definition from the workflow
653
+ * @returns A new TriggerOrTimeoutModel instance
654
+ * @throws Error if node type is not "TriggerOrTimeout"
655
+ */
656
+ static create(node: Node): TriggerOrTimeoutModel;
657
+ /**
658
+ * Processes events, accepting either a matching trigger event or timeout completion.
659
+ * - If event type matches params.event: Records `resolvedBy: "trigger"` and accepts
660
+ * - If already waiting and timeout elapsed: Records `resolvedBy: "timeout"` and accepts
661
+ * - If not waiting: Starts waiting and returns false
662
+ * @param event - The event being processed
663
+ * @returns True if event matches trigger or timeout completed, false if still waiting
664
+ */
665
+ acceptEvent(event: Event): Promise<boolean>;
666
+ /**
667
+ * Routes execution to the `trigger` source handle if the matching event
668
+ * resolved the wait, or the `timeout` source handle if the duration elapsed.
669
+ * @param _event - The event being processed (unused)
670
+ * @returns The next NodeModel, or null if no connection exists for the resolved handle
671
+ */
672
+ nextNode(_event: Event): Promise<NodeModel | null>;
673
+ }
674
+
675
+ declare const _default: {
676
+ Action: typeof ActionModel;
677
+ Condition: typeof ConditionModel;
678
+ Exit: typeof ExitModel;
679
+ Trigger: typeof TriggerModel;
680
+ Wait: typeof WaitModel;
681
+ TriggerOrTimeout: typeof TriggerOrTimeoutModel;
682
+ };
683
+
684
+ /**
685
+ * Interface for workflow storage backend
686
+ * Responsible for loading workflow definitions
687
+ */
688
+ interface WorkflowStore {
689
+ /**
690
+ * Retrieve a workflow definition by its ID
691
+ * @param domain - The domain identifier
692
+ * @param workflowId - The unique identifier of the workflow
693
+ * @returns Promise resolving to the workflow definition, or null if not found
694
+ */
695
+ getWorkflow(domain: string, workflowId: string): Promise<Workflow | null>;
696
+ /**
697
+ * Get all workflow definitions in the store
698
+ * @returns Promise resolving to an array of all workflows
699
+ */
700
+ getAllWorkflows(domain: string): Promise<Workflow[]>;
701
+ }
702
+
703
+ /**
704
+ * Interface for workflow context storage backend
705
+ * Responsible for persisting and retrieving workflow execution state for each subject
706
+ */
707
+ interface WorkflowMemory {
708
+ /**
709
+ * Retrieve all workflow contexts for a specific subject in a domain
710
+ * Supports multiple concurrent instances of the same workflow for a subject
711
+ * @param domain - The domain identifier (tenant, organization, etc.)
712
+ * @param workflowId - The unique identifier of the workflow
713
+ * @param subjectId - The unique identifier of the subject (user, order, device, etc.)
714
+ * @returns Promise resolving to an array of contexts (empty if none found)
715
+ */
716
+ getContexts(domain: string, workflowId: string, subjectId: string): Promise<Context[]>;
717
+ /**
718
+ * Save workflow context for a specific subject in a domain
719
+ * @param domain - The domain identifier (tenant, organization, etc.)
720
+ * @param workflowId - The unique identifier of the workflow
721
+ * @param subjectId - The unique identifier of the subject
722
+ * @param context - The context to save (identified by context.instanceId)
723
+ */
724
+ saveContext(domain: string, workflowId: string, subjectId: string, context: Context): Promise<void>;
725
+ /**
726
+ * Delete workflow context for a specific subject and instance in a domain
727
+ * @param domain - The domain identifier (tenant, organization, etc.)
728
+ * @param workflowId - The unique identifier of the workflow
729
+ * @param subjectId - The unique identifier of the subject
730
+ * @param instanceId - The unique identifier of the workflow instance
731
+ */
732
+ deleteContext(domain: string, workflowId: string, subjectId: string, instanceId: string): Promise<void>;
733
+ }
734
+
735
+ /**
736
+ * Constructor type for a NodeModel subclass.
737
+ * Re-exported from `@omega-flow/engine` as `NodeModelClass`.
738
+ */
739
+ type NodeModelClass = typeof NodeModel;
740
+ /**
741
+ * Map of node type names to their NodeModel classes.
742
+ * Re-exported from `@omega-flow/engine` as `NodeModelRegistry`.
743
+ */
744
+ type NodeModelRegistry = Record<string, NodeModelClass>;
745
+ /**
746
+ * Configuration options for WorkflowManager.
747
+ */
748
+ interface WorkflowManagerConfig {
749
+ /** Storage backend for workflow definitions */
750
+ workflowStore: WorkflowStore;
751
+ /** Storage backend for workflow execution contexts */
752
+ workflowMemory: WorkflowMemory;
753
+ /** Scheduler for time-based workflow events */
754
+ workflowScheduler: WorkflowScheduler;
755
+ /** Map of node type names to their NodeModel classes */
756
+ nodeModels: NodeModelRegistry;
757
+ /**
758
+ * Function to extract domain and subject ID from an event.
759
+ * The domain allows multi-tenant workflow isolation.
760
+ * The subject ID identifies which entity (user, order, etc.) the workflow is for.
761
+ * @param event - The incoming event
762
+ * @returns Tuple of [domain, subjectId]
763
+ */
764
+ eventExtractor: (event: Event) => [string, string];
765
+ }
766
+ /**
767
+ * Orchestrates multiple workflows across multiple subjects and domains.
768
+ *
769
+ * WorkflowManager is the top-level coordinator that:
770
+ * - Routes incoming events to the appropriate workflow instances
771
+ * - Manages workflow lifecycle (start, resume, complete)
772
+ * - Handles state persistence via WorkflowMemory
773
+ * - Enforces workflow frequency rules (one_time, every_rematch)
774
+ *
775
+ * Each combination of (domain, workflowId, subjectId) can have multiple
776
+ * workflow instances depending on the frequency configuration.
777
+ *
778
+ * @example
779
+ * ```typescript
780
+ * const manager = new WorkflowManager({
781
+ * workflowStore: new InMemoryWorkflowStore([...]),
782
+ * workflowMemory: new InMemoryWorkflowMemory(),
783
+ * workflowScheduler: new InMemoryWorkflowScheduler(),
784
+ * nodeModels: { Trigger: TriggerModel, Action: ActionModel, Exit: ExitModel },
785
+ * eventExtractor: (event) => [event.data.domain, event.data.userId],
786
+ * });
787
+ *
788
+ * await manager.processEvent({ type: 'user_signup', time: Date.now(), data: {...} });
789
+ * ```
790
+ */
791
+ declare class WorkflowManager {
792
+ /** Storage backend for workflow definitions */
793
+ private workflowStore;
794
+ /** Storage backend for workflow execution contexts */
795
+ private workflowMemory;
796
+ /** Scheduler for time-based workflow events */
797
+ private workflowScheduler;
798
+ /** Map of node type names to their NodeModel classes */
799
+ private nodeModels;
800
+ /** Function to extract domain and subject ID from events */
801
+ private eventExtractor;
802
+ /**
803
+ * Creates a new WorkflowManager instance.
804
+ * @param config - Configuration options including storage backends and node models
805
+ */
806
+ constructor(config: WorkflowManagerConfig);
807
+ /**
808
+ * Process an event by routing it to appropriate workflow instances
809
+ * @param event - The event to process
810
+ */
811
+ processEvent(event: Event): Promise<void>;
812
+ /**
813
+ * Process a specific workflow definition for an event
814
+ * @param workflowDef - The workflow definition
815
+ * @param event - The event to process
816
+ * @param domain - The domain identifier
817
+ * @param subjectId - The subject ID extracted from the event
818
+ */
819
+ private processWorkflowForEvent;
820
+ /**
821
+ * Check if a new workflow instance can be started based on frequency option
822
+ * @param workflowDef - The workflow definition
823
+ * @param activeContexts - Currently active workflow instances
824
+ * @param completedContexts - Completed workflow instances
825
+ * @returns true if a new instance can be started
826
+ */
827
+ private canStartNewInstance;
828
+ /**
829
+ * Try to start a new workflow instance for a subject
830
+ * Only saves context if the workflow actually started (start node accepted the event)
831
+ * @param workflowDef - The workflow definition
832
+ * @param event - The triggering event
833
+ * @param domain - The domain identifier
834
+ * @param subjectId - The subject ID
835
+ */
836
+ private tryStartNewWorkflowInstance;
837
+ /**
838
+ * Resume an existing workflow instance and process an event
839
+ * @param workflowDef - The workflow definition
840
+ * @param context - The existing context
841
+ * @param event - The event to process
842
+ * @param domain - The domain identifier
843
+ * @param subjectId - The subject ID
844
+ */
845
+ private resumeWorkflowInstance;
846
+ /**
847
+ * Get the workflow scheduler instance
848
+ * Useful for nodes that need to schedule future events
849
+ * @returns The workflow scheduler
850
+ */
851
+ getScheduler(): WorkflowScheduler;
852
+ }
853
+
854
+ /**
855
+ * In-memory implementation of WorkflowStore.
856
+ *
857
+ * Stores workflow definitions in memory using a nested Map structure.
858
+ * Useful for testing, development, and single-instance deployments.
859
+ *
860
+ * Storage structure: domain -> workflowId -> Workflow
861
+ */
862
+ declare class InMemoryWorkflowStore implements WorkflowStore {
863
+ /** Nested map storing workflows by domain and workflow ID */
864
+ private workflows;
865
+ /**
866
+ * Creates a new InMemoryWorkflowStore.
867
+ * @param workflows - Optional array of workflows to initialize the store with
868
+ */
869
+ constructor(workflows?: Array<{
870
+ domain: string;
871
+ workflow: Workflow;
872
+ }>);
873
+ /**
874
+ * Retrieve a workflow definition by its ID
875
+ * @param domain - The domain identifier
876
+ * @param workflowId - The unique identifier of the workflow
877
+ * @returns Promise resolving to the workflow definition, or null if not found
878
+ */
879
+ getWorkflow(domain: string, workflowId: string): Promise<Workflow | null>;
880
+ /**
881
+ * Add or update a workflow definition in the store
882
+ * @param domain - The domain identifier
883
+ * @param workflow - The workflow definition to add or update
884
+ */
885
+ setWorkflow(domain: string, workflow: Workflow): Promise<void>;
886
+ /**
887
+ * Remove a workflow definition from the store
888
+ * @param domain - The domain identifier
889
+ * @param workflowId - The unique identifier of the workflow to remove
890
+ */
891
+ deleteWorkflow(domain: string, workflowId: string): Promise<void>;
892
+ /**
893
+ * Get all workflow definitions in the store for a specific domain
894
+ * @param domain - The domain identifier
895
+ * @returns Promise resolving to an array of all workflows in the domain
896
+ */
897
+ getAllWorkflows(domain: string): Promise<Workflow[]>;
898
+ }
899
+
900
+ /**
901
+ * In-memory implementation of WorkflowMemory.
902
+ *
903
+ * Stores workflow execution contexts in memory using a nested Map structure.
904
+ * Useful for testing, development, and single-instance deployments.
905
+ *
906
+ * Storage structure: domain -> workflowId -> subjectId -> instanceId -> Context
907
+ */
908
+ declare class InMemoryWorkflowMemory implements WorkflowMemory {
909
+ /** Nested map storing contexts by domain, workflow, subject, and instance */
910
+ private contexts;
911
+ /**
912
+ * Creates a new InMemoryWorkflowMemory with empty storage.
913
+ */
914
+ constructor();
915
+ /**
916
+ * Retrieve all workflow contexts for a specific subject in a domain
917
+ * @param domain - The domain identifier
918
+ * @param workflowId - The unique identifier of the workflow
919
+ * @param subjectId - The unique identifier of the subject
920
+ * @returns Promise resolving to an array of contexts
921
+ */
922
+ getContexts(domain: string, workflowId: string, subjectId: string): Promise<Context[]>;
923
+ /**
924
+ * Save workflow context for a specific subject in a domain
925
+ * @param domain - The domain identifier
926
+ * @param workflowId - The unique identifier of the workflow
927
+ * @param subjectId - The unique identifier of the subject
928
+ * @param context - The context to save (identified by context.instanceId)
929
+ */
930
+ saveContext(domain: string, workflowId: string, subjectId: string, context: Context): Promise<void>;
931
+ /**
932
+ * Delete workflow context for a specific subject and instance in a domain
933
+ * @param domain - The domain identifier
934
+ * @param workflowId - The unique identifier of the workflow
935
+ * @param subjectId - The unique identifier of the subject
936
+ * @param instanceId - The unique identifier of the workflow instance
937
+ */
938
+ deleteContext(domain: string, workflowId: string, subjectId: string, instanceId: string): Promise<void>;
939
+ /**
940
+ * Clear all contexts from memory
941
+ */
942
+ clear(): Promise<void>;
943
+ }
944
+
945
+ /**
946
+ * In-memory implementation of WorkflowScheduler using setTimeout.
947
+ *
948
+ * Stores scheduled events in memory with their timeout handles.
949
+ * When a timeout fires, the event is delivered to the workflow manager.
950
+ * Useful for testing, development, and single-instance deployments.
951
+ *
952
+ * Note: Requires setWorkflowManager() to be called before scheduling events.
953
+ */
954
+ declare class InMemoryWorkflowScheduler implements WorkflowScheduler {
955
+ /** Map of schedule IDs to their setTimeout handles */
956
+ private schedules;
957
+ /** Counter for generating unique schedule IDs */
958
+ private scheduleIdCounter;
959
+ /** Reference to the workflow manager for event delivery */
960
+ private workflowManager;
961
+ /**
962
+ * Creates a new InMemoryWorkflowScheduler.
963
+ * Call setWorkflowManager() before scheduling any events.
964
+ */
965
+ constructor();
966
+ /**
967
+ * Set the workflow manager reference
968
+ * The scheduler will call processEvent on the manager when scheduled events are due
969
+ * @param manager - The workflow manager instance
970
+ */
971
+ setWorkflowManager(manager: IWorkflowManager): void;
972
+ /**
973
+ * Schedule an event to be delivered after a delay
974
+ * When the delay expires, the event will be passed to the workflow manager
975
+ * @param event - The event to schedule
976
+ * @param delayMs - Delay in milliseconds before the event is delivered
977
+ * @returns Promise resolving to a schedule ID that can be used to cancel
978
+ */
979
+ schedule(event: Event, delayMs: number): Promise<string>;
980
+ /**
981
+ * Cancel a scheduled event
982
+ * @param scheduleId - The ID of the schedule to cancel
983
+ * @returns Promise resolving to true if canceled, false if not found
984
+ */
985
+ cancel(scheduleId: string): Promise<boolean>;
986
+ /**
987
+ * Get the number of currently scheduled events
988
+ * @returns The count of active schedules
989
+ */
990
+ getScheduleCount(): number;
991
+ /**
992
+ * Cancel all scheduled events
993
+ */
994
+ cancelAll(): Promise<void>;
995
+ }
996
+
997
+ export { type Connection, InMemoryWorkflowMemory, InMemoryWorkflowScheduler, InMemoryWorkflowStore, NodeModel, type NodeModelClass, type NodeModelRegistry, type NodeServices, WorkflowManager, type WorkflowManagerConfig, type WorkflowMemory, WorkflowModel, type WorkflowScheduler, type WorkflowStore, _default as defaultNodeModels };