@allternit/workflow-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.
Files changed (49) hide show
  1. package/README.md +227 -0
  2. package/dist/engine/workflow-engine.d.ts +39 -0
  3. package/dist/engine/workflow-engine.d.ts.bak +39 -0
  4. package/dist/engine/workflow-engine.d.ts.map +1 -0
  5. package/dist/engine/workflow-engine.js +532 -0
  6. package/dist/engine/workflow-engine.js.bak +532 -0
  7. package/dist/engine/workflow-engine.js.map +1 -0
  8. package/dist/index.d.ts +38 -0
  9. package/dist/index.d.ts.bak +38 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +41 -0
  12. package/dist/index.js.bak +41 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/scheduler/index.d.ts +53 -0
  15. package/dist/scheduler/index.d.ts.bak +53 -0
  16. package/dist/scheduler/index.d.ts.map +1 -0
  17. package/dist/scheduler/index.js +135 -0
  18. package/dist/scheduler/index.js.bak +135 -0
  19. package/dist/scheduler/index.js.map +1 -0
  20. package/dist/types.d.ts +402 -0
  21. package/dist/types.d.ts.bak +402 -0
  22. package/dist/types.d.ts.map +1 -0
  23. package/dist/types.js +7 -0
  24. package/dist/types.js.bak +7 -0
  25. package/dist/types.js.map +1 -0
  26. package/dist/visualizer/index.d.ts +81 -0
  27. package/dist/visualizer/index.d.ts.bak +81 -0
  28. package/dist/visualizer/index.d.ts.map +1 -0
  29. package/dist/visualizer/index.js +277 -0
  30. package/dist/visualizer/index.js.bak +277 -0
  31. package/dist/visualizer/index.js.map +1 -0
  32. package/package.json +57 -0
  33. package/src/__tests__/visualizer.test.ts.bak +110 -0
  34. package/src/__tests__/workflow-engine.test.ts.bak +239 -0
  35. package/src/engine/workflow-engine.test.ts.bak +852 -0
  36. package/src/engine/workflow-engine.ts +651 -0
  37. package/src/engine/workflow-engine.ts.bak +651 -0
  38. package/src/index.ts +89 -0
  39. package/src/index.ts.bak +89 -0
  40. package/src/scheduler/index.ts +204 -0
  41. package/src/scheduler/index.ts.bak +204 -0
  42. package/src/scheduler/scheduler.test.ts.bak +521 -0
  43. package/src/types.ts +449 -0
  44. package/src/types.ts.bak +449 -0
  45. package/src/visualizer/index.ts +409 -0
  46. package/src/visualizer/index.ts.bak +409 -0
  47. package/src/visualizer/visualizer.test.ts.bak +844 -0
  48. package/tsconfig.json +22 -0
  49. package/vitest.config.ts.bak +9 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Workflow Visualizer Tests
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { createVisualizer } from '../visualizer';
7
+ import type { Workflow } from '../types';
8
+
9
+ describe('WorkflowVisualizer', () => {
10
+ const sampleWorkflow: Workflow = {
11
+ id: 'test-workflow',
12
+ name: 'Test Workflow',
13
+ version: '1.0.0',
14
+ nodes: [
15
+ { id: 'trigger', type: 'trigger:manual', name: 'Start', position: { x: 100, y: 100 } },
16
+ { id: 'http', type: 'http:request', name: 'HTTP Request', position: { x: 100, y: 200 } },
17
+ { id: 'condition', type: 'condition:if', name: 'Check', position: { x: 100, y: 300 } },
18
+ { id: 'output1', type: 'output:result', name: 'Success', position: { x: 50, y: 400 } },
19
+ { id: 'output2', type: 'output:result', name: 'Error', position: { x: 150, y: 400 } },
20
+ ],
21
+ connections: [
22
+ { id: 'c1', source: 'trigger', target: 'http' },
23
+ { id: 'c2', source: 'http', target: 'condition' },
24
+ { id: 'c3', source: 'condition', target: 'output1' },
25
+ { id: 'c4', source: 'condition', target: 'output2' },
26
+ ],
27
+ };
28
+
29
+ describe('layout', () => {
30
+ it('should generate visual layout', () => {
31
+ const visualizer = createVisualizer({ autoLayout: false });
32
+ const layout = visualizer.layout(sampleWorkflow);
33
+
34
+ expect(layout.nodes).toHaveLength(5);
35
+ expect(layout.connections).toHaveLength(4);
36
+ expect(layout.bounds).toBeDefined();
37
+ });
38
+
39
+ it('should position nodes correctly', () => {
40
+ const visualizer = createVisualizer({ autoLayout: false });
41
+ const layout = visualizer.layout(sampleWorkflow);
42
+
43
+ const triggerNode = layout.nodes.find(n => n.id === 'trigger');
44
+ expect(triggerNode?.x).toBe(100);
45
+ expect(triggerNode?.y).toBe(100);
46
+ });
47
+ });
48
+
49
+ describe('auto layout', () => {
50
+ it('should auto-layout nodes in layers', () => {
51
+ const visualizer = createVisualizer({ autoLayout: true });
52
+ const positions = visualizer.autoLayout(sampleWorkflow.nodes, sampleWorkflow.connections);
53
+
54
+ expect(Object.keys(positions)).toHaveLength(5);
55
+
56
+ // Check that all nodes have positions
57
+ sampleWorkflow.nodes.forEach(node => {
58
+ expect(positions[node.id]).toBeDefined();
59
+ expect(positions[node.id].x).toBeGreaterThanOrEqual(0);
60
+ expect(positions[node.id].y).toBeGreaterThanOrEqual(0);
61
+ });
62
+ });
63
+ });
64
+
65
+ describe('export formats', () => {
66
+ it('should export to SVG', () => {
67
+ const visualizer = createVisualizer();
68
+ const svg = visualizer.toSVG(sampleWorkflow);
69
+
70
+ expect(svg).toContain('<svg');
71
+ expect(svg).toContain('</svg>');
72
+ expect(svg).toContain('Start');
73
+ expect(svg).toContain('HTTP Request');
74
+ });
75
+
76
+ it('should export to Mermaid', () => {
77
+ const visualizer = createVisualizer();
78
+ const mermaid = visualizer.toMermaid(sampleWorkflow);
79
+
80
+ expect(mermaid).toContain('graph TD');
81
+ expect(mermaid).toContain('trigger');
82
+ expect(mermaid).toContain('http');
83
+ expect(mermaid).toContain('-->');
84
+ });
85
+
86
+ it('should export to DOT', () => {
87
+ const visualizer = createVisualizer();
88
+ const dot = visualizer.toDOT(sampleWorkflow);
89
+
90
+ expect(dot).toContain('digraph Workflow');
91
+ expect(dot).toContain('trigger');
92
+ expect(dot).toContain('->');
93
+ });
94
+ });
95
+
96
+ describe('node colors', () => {
97
+ it('should assign colors by node type', () => {
98
+ const visualizer = createVisualizer();
99
+ const layout = visualizer.layout(sampleWorkflow);
100
+
101
+ const triggerNode = layout.nodes.find(n => n.id === 'trigger');
102
+ const httpNode = layout.nodes.find(n => n.id === 'http');
103
+ const conditionNode = layout.nodes.find(n => n.id === 'condition');
104
+
105
+ expect(triggerNode?.color).toBe('#3b82f6'); // Blue for triggers
106
+ expect(httpNode?.color).toBe('#ec4899'); // Pink for HTTP
107
+ expect(conditionNode?.color).toBe('#f59e0b'); // Orange for conditions
108
+ });
109
+ });
110
+ });
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Workflow Engine Tests
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach } from 'vitest';
6
+ import { createWorkflowEngine } from '../engine/workflow-engine';
7
+ import type { Workflow } from '../types';
8
+
9
+ describe('WorkflowEngine', () => {
10
+ let engine: ReturnType<typeof createWorkflowEngine>;
11
+
12
+ beforeEach(() => {
13
+ engine = createWorkflowEngine();
14
+ });
15
+
16
+ describe('workflow management', () => {
17
+ it('should register and retrieve workflow', () => {
18
+ const workflow: Workflow = {
19
+ id: 'test-workflow',
20
+ name: 'Test Workflow',
21
+ version: '1.0.0',
22
+ nodes: [],
23
+ connections: [],
24
+ };
25
+
26
+ engine.registerWorkflow(workflow);
27
+ const retrieved = engine.getWorkflow('test-workflow');
28
+
29
+ expect(retrieved).toEqual(workflow);
30
+ });
31
+
32
+ it('should list all workflows', () => {
33
+ const workflow1: Workflow = {
34
+ id: 'workflow-1',
35
+ name: 'Workflow 1',
36
+ version: '1.0.0',
37
+ nodes: [],
38
+ connections: [],
39
+ };
40
+
41
+ const workflow2: Workflow = {
42
+ id: 'workflow-2',
43
+ name: 'Workflow 2',
44
+ version: '1.0.0',
45
+ nodes: [],
46
+ connections: [],
47
+ };
48
+
49
+ engine.registerWorkflow(workflow1);
50
+ engine.registerWorkflow(workflow2);
51
+
52
+ const workflows = engine.listWorkflows();
53
+ expect(workflows).toHaveLength(2);
54
+ });
55
+
56
+ it('should delete workflow', () => {
57
+ const workflow: Workflow = {
58
+ id: 'test-workflow',
59
+ name: 'Test Workflow',
60
+ version: '1.0.0',
61
+ nodes: [],
62
+ connections: [],
63
+ };
64
+
65
+ engine.registerWorkflow(workflow);
66
+ expect(engine.getWorkflow('test-workflow')).toBeDefined();
67
+
68
+ engine.deleteWorkflow('test-workflow');
69
+ expect(engine.getWorkflow('test-workflow')).toBeUndefined();
70
+ });
71
+ });
72
+
73
+ describe('workflow execution', () => {
74
+ it('should execute simple workflow', async () => {
75
+ const workflow: Workflow = {
76
+ id: 'simple-workflow',
77
+ name: 'Simple Workflow',
78
+ version: '1.0.0',
79
+ nodes: [
80
+ {
81
+ id: 'trigger',
82
+ type: 'trigger:manual',
83
+ name: 'Start',
84
+ },
85
+ {
86
+ id: 'output',
87
+ type: 'output:result',
88
+ name: 'End',
89
+ },
90
+ ],
91
+ connections: [
92
+ { id: 'c1', source: 'trigger', target: 'output' },
93
+ ],
94
+ };
95
+
96
+ engine.registerWorkflow(workflow);
97
+ const execution = await engine.execute('simple-workflow');
98
+
99
+ expect(execution.status).toBe('completed');
100
+ expect(execution.workflowId).toBe('simple-workflow');
101
+ });
102
+
103
+ it('should throw error for non-existent workflow', async () => {
104
+ await expect(engine.execute('non-existent')).rejects.toThrow('Workflow not found');
105
+ });
106
+
107
+ it('should track execution state', async () => {
108
+ const workflow: Workflow = {
109
+ id: 'tracking-workflow',
110
+ name: 'Tracking Workflow',
111
+ version: '1.0.0',
112
+ nodes: [
113
+ { id: 'trigger', type: 'trigger:manual', name: 'Start' },
114
+ { id: 'log', type: 'output:log', name: 'Log' },
115
+ { id: 'output', type: 'output:result', name: 'End' },
116
+ ],
117
+ connections: [
118
+ { id: 'c1', source: 'trigger', target: 'log' },
119
+ { id: 'c2', source: 'log', target: 'output' },
120
+ ],
121
+ };
122
+
123
+ engine.registerWorkflow(workflow);
124
+ const execution = await engine.execute('tracking-workflow');
125
+
126
+ expect(execution.context?.state.completedNodes).toContain('trigger');
127
+ expect(execution.context?.state.completedNodes).toContain('log');
128
+ expect(execution.context?.state.completedNodes).toContain('output');
129
+ expect(execution.context?.state.executionPath).toHaveLength(3);
130
+ });
131
+ });
132
+
133
+ describe('node types', () => {
134
+ it('should get built-in node types', () => {
135
+ const triggerType = engine.getNodeType('trigger:manual');
136
+ expect(triggerType).toBeDefined();
137
+ expect(triggerType?.displayName).toBe('Manual Trigger');
138
+ });
139
+
140
+ it('should register custom node type', () => {
141
+ engine.registerNodeType({
142
+ type: 'custom:action',
143
+ category: 'custom',
144
+ displayName: 'Custom Action',
145
+ executor: async () => ({ result: 'custom' }),
146
+ });
147
+
148
+ const customType = engine.getNodeType('custom:action');
149
+ expect(customType).toBeDefined();
150
+ expect(customType?.displayName).toBe('Custom Action');
151
+ });
152
+ });
153
+
154
+ describe('execution control', () => {
155
+ it('should get execution by id', async () => {
156
+ const workflow: Workflow = {
157
+ id: 'test-workflow',
158
+ name: 'Test Workflow',
159
+ version: '1.0.0',
160
+ nodes: [
161
+ { id: 'trigger', type: 'trigger:manual', name: 'Start' },
162
+ { id: 'output', type: 'output:result', name: 'End' },
163
+ ],
164
+ connections: [{ id: 'c1', source: 'trigger', target: 'output' }],
165
+ };
166
+
167
+ engine.registerWorkflow(workflow);
168
+ const execution = await engine.execute('test-workflow');
169
+
170
+ const retrieved = engine.getExecution(execution.id);
171
+ expect(retrieved).toEqual(execution);
172
+ });
173
+ });
174
+ });
175
+
176
+ describe('WorkflowEngine with conditions', () => {
177
+ it('should execute conditional workflow', async () => {
178
+ const engine = createWorkflowEngine();
179
+
180
+ const workflow: Workflow = {
181
+ id: 'conditional-workflow',
182
+ name: 'Conditional Workflow',
183
+ version: '1.0.0',
184
+ nodes: [
185
+ { id: 'trigger', type: 'trigger:manual', name: 'Start' },
186
+ {
187
+ id: 'condition',
188
+ type: 'condition:if',
189
+ name: 'Check Value',
190
+ config: { condition: 'data.value > 10' },
191
+ },
192
+ { id: 'high', type: 'output:result', name: 'High Value' },
193
+ { id: 'low', type: 'output:result', name: 'Low Value' },
194
+ ],
195
+ connections: [
196
+ { id: 'c1', source: 'trigger', target: 'condition' },
197
+ { id: 'c2', source: 'condition', target: 'high', condition: 'result.true' },
198
+ { id: 'c3', source: 'condition', target: 'low', condition: 'result.false' },
199
+ ],
200
+ };
201
+
202
+ engine.registerWorkflow(workflow);
203
+ const execution = await engine.execute('conditional-workflow', { value: 15 });
204
+
205
+ expect(execution.status).toBe('completed');
206
+ });
207
+ });
208
+
209
+ describe('WorkflowEngine with transforms', () => {
210
+ it('should execute transform node', async () => {
211
+ const engine = createWorkflowEngine();
212
+
213
+ const workflow: Workflow = {
214
+ id: 'transform-workflow',
215
+ name: 'Transform Workflow',
216
+ version: '1.0.0',
217
+ nodes: [
218
+ { id: 'trigger', type: 'trigger:manual', name: 'Start' },
219
+ {
220
+ id: 'transform',
221
+ type: 'transform:map',
222
+ name: 'Double Value',
223
+ config: { expression: 'data.value * 2' },
224
+ inputs: [{ target: 'data', source: '${value}' }],
225
+ },
226
+ { id: 'output', type: 'output:result', name: 'Result' },
227
+ ],
228
+ connections: [
229
+ { id: 'c1', source: 'trigger', target: 'transform' },
230
+ { id: 'c2', source: 'transform', target: 'output' },
231
+ ],
232
+ };
233
+
234
+ engine.registerWorkflow(workflow);
235
+ const execution = await engine.execute('transform-workflow', { value: 5 });
236
+
237
+ expect(execution.status).toBe('completed');
238
+ });
239
+ });