@allternit/workflow-engine 0.1.0 → 0.1.1
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 +1 -1
- package/dist/engine/workflow-engine.d.ts.map +1 -1
- package/dist/engine/workflow-engine.js +32 -6
- package/dist/engine/workflow-engine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/package.json +4 -16
- package/src/engine/workflow-engine.ts +35 -6
- package/src/index.ts +1 -1
- package/src/types.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/engine/workflow-engine.d.ts.bak +0 -39
- package/dist/engine/workflow-engine.js.bak +0 -532
- package/dist/index.d.ts.bak +0 -38
- package/dist/index.js.bak +0 -41
- package/dist/scheduler/index.d.ts.bak +0 -53
- package/dist/scheduler/index.js.bak +0 -135
- package/dist/types.d.ts.bak +0 -402
- package/dist/types.js.bak +0 -7
- package/dist/visualizer/index.d.ts.bak +0 -81
- package/dist/visualizer/index.js.bak +0 -277
- package/src/__tests__/visualizer.test.ts.bak +0 -110
- package/src/__tests__/workflow-engine.test.ts.bak +0 -239
- package/src/engine/workflow-engine.test.ts.bak +0 -852
- package/src/engine/workflow-engine.ts.bak +0 -651
- package/src/index.ts.bak +0 -89
- package/src/scheduler/index.ts.bak +0 -204
- package/src/scheduler/scheduler.test.ts.bak +0 -521
- package/src/types.ts.bak +0 -449
- package/src/visualizer/index.ts.bak +0 -409
- package/src/visualizer/visualizer.test.ts.bak +0 -844
- package/vitest.config.ts.bak +0 -9
|
@@ -1,532 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Engine
|
|
3
|
-
*
|
|
4
|
-
* Core engine for executing workflows with DAG support.
|
|
5
|
-
*/
|
|
6
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
7
|
-
/**
|
|
8
|
-
* Create workflow engine
|
|
9
|
-
*/
|
|
10
|
-
export function createWorkflowEngine(config = {}) {
|
|
11
|
-
const workflows = new Map();
|
|
12
|
-
const executions = new Map();
|
|
13
|
-
const nodeTypes = new Map();
|
|
14
|
-
const activeExecutions = new Set();
|
|
15
|
-
const { maxConcurrentExecutions = 10, defaultTimeout = 300000, // 5 minutes
|
|
16
|
-
enableHistory = true, hooks = {}, } = config;
|
|
17
|
-
/**
|
|
18
|
-
* Register built-in node types
|
|
19
|
-
*/
|
|
20
|
-
function registerBuiltInNodeTypes() {
|
|
21
|
-
// Input nodes
|
|
22
|
-
registerNodeType({
|
|
23
|
-
type: 'trigger:manual',
|
|
24
|
-
category: 'input',
|
|
25
|
-
displayName: 'Manual Trigger',
|
|
26
|
-
description: 'Triggered manually or via API',
|
|
27
|
-
outputs: [{ name: 'data', type: 'any' }],
|
|
28
|
-
executor: async (_, __, inputs) => inputs,
|
|
29
|
-
});
|
|
30
|
-
registerNodeType({
|
|
31
|
-
type: 'trigger:schedule',
|
|
32
|
-
category: 'input',
|
|
33
|
-
displayName: 'Schedule Trigger',
|
|
34
|
-
description: 'Triggered on a schedule',
|
|
35
|
-
outputs: [{ name: 'timestamp', type: 'string' }],
|
|
36
|
-
executor: async (_, __, inputs) => inputs,
|
|
37
|
-
});
|
|
38
|
-
registerNodeType({
|
|
39
|
-
type: 'trigger:webhook',
|
|
40
|
-
category: 'input',
|
|
41
|
-
displayName: 'Webhook Trigger',
|
|
42
|
-
description: 'Triggered by HTTP webhook',
|
|
43
|
-
outputs: [{ name: 'body', type: 'any' }, { name: 'headers', type: 'object' }],
|
|
44
|
-
executor: async (_, __, inputs) => inputs,
|
|
45
|
-
});
|
|
46
|
-
// Transform nodes
|
|
47
|
-
registerNodeType({
|
|
48
|
-
type: 'transform:map',
|
|
49
|
-
category: 'transform',
|
|
50
|
-
displayName: 'Map',
|
|
51
|
-
description: 'Transform data using expression',
|
|
52
|
-
inputs: [{ name: 'data', type: 'any', required: true }],
|
|
53
|
-
outputs: [{ name: 'result', type: 'any' }],
|
|
54
|
-
configSchema: [
|
|
55
|
-
{ name: 'expression', type: 'string', required: true, description: 'JavaScript expression' },
|
|
56
|
-
],
|
|
57
|
-
executor: async (node, context, inputs) => {
|
|
58
|
-
const expression = node.config?.expression;
|
|
59
|
-
if (!expression)
|
|
60
|
-
throw new Error('Expression required');
|
|
61
|
-
// Simple expression evaluation
|
|
62
|
-
const data = inputs.data;
|
|
63
|
-
const result = new Function('data', 'context', `return ${expression}`)(data, context);
|
|
64
|
-
return { result };
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
registerNodeType({
|
|
68
|
-
type: 'transform:filter',
|
|
69
|
-
category: 'transform',
|
|
70
|
-
displayName: 'Filter',
|
|
71
|
-
description: 'Filter array items',
|
|
72
|
-
inputs: [{ name: 'array', type: 'array', required: true }],
|
|
73
|
-
outputs: [{ name: 'filtered', type: 'array' }],
|
|
74
|
-
configSchema: [
|
|
75
|
-
{ name: 'condition', type: 'string', required: true, description: 'Filter condition (item, index) => boolean' },
|
|
76
|
-
],
|
|
77
|
-
executor: async (node, _, inputs) => {
|
|
78
|
-
const array = inputs.array;
|
|
79
|
-
const condition = node.config?.condition;
|
|
80
|
-
if (!condition)
|
|
81
|
-
return { filtered: array };
|
|
82
|
-
const filterFn = new Function('item', 'index', `return ${condition}`);
|
|
83
|
-
const filtered = array.filter((item, index) => filterFn(item, index));
|
|
84
|
-
return { filtered };
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
// Condition nodes
|
|
88
|
-
registerNodeType({
|
|
89
|
-
type: 'condition:if',
|
|
90
|
-
category: 'condition',
|
|
91
|
-
displayName: 'If Condition',
|
|
92
|
-
description: 'Branch based on condition',
|
|
93
|
-
inputs: [{ name: 'data', type: 'any' }],
|
|
94
|
-
outputs: [
|
|
95
|
-
{ name: 'true', type: 'any' },
|
|
96
|
-
{ name: 'false', type: 'any' },
|
|
97
|
-
],
|
|
98
|
-
configSchema: [
|
|
99
|
-
{ name: 'condition', type: 'string', required: true, description: 'Boolean expression' },
|
|
100
|
-
],
|
|
101
|
-
executor: async (node, context, inputs) => {
|
|
102
|
-
const condition = node.config?.condition;
|
|
103
|
-
if (!condition)
|
|
104
|
-
throw new Error('Condition required');
|
|
105
|
-
const result = new Function('data', 'context', `return ${condition}`)(inputs.data, context);
|
|
106
|
-
return result ? { true: inputs.data } : { false: inputs.data };
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
// Loop nodes
|
|
110
|
-
registerNodeType({
|
|
111
|
-
type: 'loop:for-each',
|
|
112
|
-
category: 'loop',
|
|
113
|
-
displayName: 'For Each',
|
|
114
|
-
description: 'Iterate over array items',
|
|
115
|
-
inputs: [{ name: 'array', type: 'array', required: true }],
|
|
116
|
-
outputs: [{ name: 'results', type: 'array' }],
|
|
117
|
-
configSchema: [
|
|
118
|
-
{ name: 'parallel', type: 'boolean', default: false, description: 'Execute in parallel' },
|
|
119
|
-
{ name: 'maxConcurrency', type: 'number', default: 5, description: 'Max parallel executions' },
|
|
120
|
-
],
|
|
121
|
-
executor: async (node, context, inputs) => {
|
|
122
|
-
// For-each logic handled by scheduler
|
|
123
|
-
return { items: inputs.array };
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
// Delay nodes
|
|
127
|
-
registerNodeType({
|
|
128
|
-
type: 'delay:wait',
|
|
129
|
-
category: 'delay',
|
|
130
|
-
displayName: 'Wait',
|
|
131
|
-
description: 'Pause execution',
|
|
132
|
-
inputs: [{ name: 'data', type: 'any' }],
|
|
133
|
-
outputs: [{ name: 'data', type: 'any' }],
|
|
134
|
-
configSchema: [
|
|
135
|
-
{ name: 'delay', type: 'number', required: true, description: 'Delay in milliseconds' },
|
|
136
|
-
],
|
|
137
|
-
executor: async (node, _, inputs) => {
|
|
138
|
-
const delay = node.config?.delay || 1000;
|
|
139
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
140
|
-
return { data: inputs.data };
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
// HTTP nodes
|
|
144
|
-
registerNodeType({
|
|
145
|
-
type: 'http:request',
|
|
146
|
-
category: 'http',
|
|
147
|
-
displayName: 'HTTP Request',
|
|
148
|
-
description: 'Make HTTP request',
|
|
149
|
-
inputs: [
|
|
150
|
-
{ name: 'url', type: 'string', required: true },
|
|
151
|
-
{ name: 'body', type: 'any' },
|
|
152
|
-
],
|
|
153
|
-
outputs: [
|
|
154
|
-
{ name: 'response', type: 'object' },
|
|
155
|
-
{ name: 'status', type: 'number' },
|
|
156
|
-
],
|
|
157
|
-
configSchema: [
|
|
158
|
-
{ name: 'method', type: 'string', default: 'GET', description: 'HTTP method' },
|
|
159
|
-
{ name: 'headers', type: 'object', description: 'Request headers' },
|
|
160
|
-
{ name: 'timeout', type: 'number', default: 30000, description: 'Timeout in ms' },
|
|
161
|
-
],
|
|
162
|
-
executor: async (node, _, inputs) => {
|
|
163
|
-
const method = node.config?.method || 'GET';
|
|
164
|
-
const url = inputs.url;
|
|
165
|
-
const headers = node.config?.headers || {};
|
|
166
|
-
const timeout = node.config?.timeout || 30000;
|
|
167
|
-
const controller = new AbortController();
|
|
168
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
169
|
-
try {
|
|
170
|
-
const response = await fetch(url, {
|
|
171
|
-
method,
|
|
172
|
-
headers,
|
|
173
|
-
body: inputs.body ? JSON.stringify(inputs.body) : undefined,
|
|
174
|
-
signal: controller.signal,
|
|
175
|
-
});
|
|
176
|
-
clearTimeout(timeoutId);
|
|
177
|
-
const data = await response.json().catch(() => null);
|
|
178
|
-
const responseHeaders = {};
|
|
179
|
-
response.headers.forEach((value, key) => {
|
|
180
|
-
responseHeaders[key] = value;
|
|
181
|
-
});
|
|
182
|
-
return {
|
|
183
|
-
response: data,
|
|
184
|
-
status: response.status,
|
|
185
|
-
headers: responseHeaders,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
catch (error) {
|
|
189
|
-
clearTimeout(timeoutId);
|
|
190
|
-
throw error;
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
// Output nodes
|
|
195
|
-
registerNodeType({
|
|
196
|
-
type: 'output:result',
|
|
197
|
-
category: 'output',
|
|
198
|
-
displayName: 'Set Result',
|
|
199
|
-
description: 'Set workflow output',
|
|
200
|
-
inputs: [{ name: 'data', type: 'any' }],
|
|
201
|
-
executor: async (_, __, inputs) => inputs,
|
|
202
|
-
});
|
|
203
|
-
registerNodeType({
|
|
204
|
-
type: 'output:log',
|
|
205
|
-
category: 'output',
|
|
206
|
-
displayName: 'Log',
|
|
207
|
-
description: 'Log message to console',
|
|
208
|
-
inputs: [{ name: 'message', type: 'any' }],
|
|
209
|
-
configSchema: [
|
|
210
|
-
{ name: 'level', type: 'string', default: 'info', description: 'Log level' },
|
|
211
|
-
],
|
|
212
|
-
executor: async (node, _, inputs) => {
|
|
213
|
-
const level = node.config?.level || 'info';
|
|
214
|
-
console[level]?.('Workflow log:', inputs.message);
|
|
215
|
-
return { message: inputs.message };
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Register workflow
|
|
221
|
-
*/
|
|
222
|
-
function registerWorkflow(workflow) {
|
|
223
|
-
workflows.set(workflow.id, workflow);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Get workflow
|
|
227
|
-
*/
|
|
228
|
-
function getWorkflow(id) {
|
|
229
|
-
return workflows.get(id);
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* List workflows
|
|
233
|
-
*/
|
|
234
|
-
function listWorkflows() {
|
|
235
|
-
return Array.from(workflows.values());
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Delete workflow
|
|
239
|
-
*/
|
|
240
|
-
function deleteWorkflow(id) {
|
|
241
|
-
return workflows.delete(id);
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Execute workflow
|
|
245
|
-
*/
|
|
246
|
-
async function execute(workflowId, inputs = {}) {
|
|
247
|
-
const workflow = workflows.get(workflowId);
|
|
248
|
-
if (!workflow) {
|
|
249
|
-
throw new Error(`Workflow not found: ${workflowId}`);
|
|
250
|
-
}
|
|
251
|
-
// Check concurrent execution limit
|
|
252
|
-
if (activeExecutions.size >= maxConcurrentExecutions) {
|
|
253
|
-
throw new Error('Max concurrent executions reached');
|
|
254
|
-
}
|
|
255
|
-
const executionId = uuidv4();
|
|
256
|
-
// Build DAG
|
|
257
|
-
const dag = buildDAG(workflow);
|
|
258
|
-
// Initialize execution
|
|
259
|
-
const execution = {
|
|
260
|
-
id: executionId,
|
|
261
|
-
workflowId,
|
|
262
|
-
status: 'pending',
|
|
263
|
-
inputs,
|
|
264
|
-
context: {
|
|
265
|
-
variables: { ...inputs },
|
|
266
|
-
state: {
|
|
267
|
-
activeNodes: [],
|
|
268
|
-
completedNodes: [],
|
|
269
|
-
failedNodes: [],
|
|
270
|
-
nodeResults: {},
|
|
271
|
-
executionPath: [],
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
nodeExecutions: [],
|
|
275
|
-
startedAt: new Date().toISOString(),
|
|
276
|
-
};
|
|
277
|
-
executions.set(executionId, execution);
|
|
278
|
-
activeExecutions.add(executionId);
|
|
279
|
-
// Trigger before execute hook
|
|
280
|
-
await hooks.beforeExecute?.(execution);
|
|
281
|
-
// Start execution
|
|
282
|
-
execution.status = 'running';
|
|
283
|
-
try {
|
|
284
|
-
// Execute starting nodes (no incoming connections)
|
|
285
|
-
const startNodes = dag.nodes.filter(n => !dag.connections.some(c => c.target === n.id));
|
|
286
|
-
await Promise.all(startNodes.map(node => executeNode(node, execution, dag)));
|
|
287
|
-
execution.status = 'completed';
|
|
288
|
-
execution.completedAt = new Date().toISOString();
|
|
289
|
-
// Collect outputs
|
|
290
|
-
const outputNodes = workflow.nodes.filter(n => n.type === 'output:result');
|
|
291
|
-
execution.outputs = {};
|
|
292
|
-
for (const node of outputNodes) {
|
|
293
|
-
const result = execution.context?.state.nodeResults[node.id];
|
|
294
|
-
if (result) {
|
|
295
|
-
Object.assign(execution.outputs, result);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
execution.status = 'failed';
|
|
301
|
-
execution.error = {
|
|
302
|
-
code: 'EXECUTION_ERROR',
|
|
303
|
-
message: error instanceof Error ? error.message : String(error),
|
|
304
|
-
};
|
|
305
|
-
await hooks.onError?.(execution.error, execution.context);
|
|
306
|
-
}
|
|
307
|
-
finally {
|
|
308
|
-
activeExecutions.delete(executionId);
|
|
309
|
-
await hooks.afterExecute?.(execution);
|
|
310
|
-
}
|
|
311
|
-
return execution;
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Build DAG from workflow
|
|
315
|
-
*/
|
|
316
|
-
function buildDAG(workflow) {
|
|
317
|
-
return {
|
|
318
|
-
nodes: workflow.nodes,
|
|
319
|
-
connections: workflow.connections,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Execute a node
|
|
324
|
-
*/
|
|
325
|
-
async function executeNode(node, execution, dag) {
|
|
326
|
-
if (!execution.context)
|
|
327
|
-
return;
|
|
328
|
-
const nodeType = nodeTypes.get(node.type);
|
|
329
|
-
if (!nodeType) {
|
|
330
|
-
throw new Error(`Unknown node type: ${node.type}`);
|
|
331
|
-
}
|
|
332
|
-
// Check if already executed
|
|
333
|
-
if (execution.context.state.completedNodes.includes(node.id)) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
// Check dependencies
|
|
337
|
-
const incomingConnections = dag.connections.filter(c => c.target === node.id);
|
|
338
|
-
const dependenciesMet = incomingConnections.every(c => execution.context.state.completedNodes.includes(c.source) ||
|
|
339
|
-
execution.context.state.nodeResults[c.source] !== undefined);
|
|
340
|
-
if (!dependenciesMet) {
|
|
341
|
-
return; // Will be executed when dependencies complete
|
|
342
|
-
}
|
|
343
|
-
// Mark as active
|
|
344
|
-
execution.context.state.activeNodes.push(node.id);
|
|
345
|
-
execution.context.state.executionPath.push(node.id);
|
|
346
|
-
// Prepare inputs
|
|
347
|
-
const inputs = {};
|
|
348
|
-
// Get inputs from connections
|
|
349
|
-
incomingConnections.forEach(conn => {
|
|
350
|
-
const sourceResult = execution.context.state.nodeResults[conn.source];
|
|
351
|
-
if (sourceResult) {
|
|
352
|
-
const portName = conn.sourcePort || 'data';
|
|
353
|
-
inputs[portName] = sourceResult;
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
// Apply input mappings
|
|
357
|
-
node.inputs?.forEach(mapping => {
|
|
358
|
-
const value = evaluateMapping(mapping.source, execution.context);
|
|
359
|
-
if (value !== undefined || mapping.default !== undefined) {
|
|
360
|
-
inputs[mapping.target] = value ?? mapping.default;
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
// Create node execution
|
|
364
|
-
const nodeExecution = {
|
|
365
|
-
nodeId: node.id,
|
|
366
|
-
status: 'running',
|
|
367
|
-
inputs,
|
|
368
|
-
startedAt: new Date().toISOString(),
|
|
369
|
-
};
|
|
370
|
-
execution.nodeExecutions = execution.nodeExecutions || [];
|
|
371
|
-
execution.nodeExecutions.push(nodeExecution);
|
|
372
|
-
// Trigger before node execute hook
|
|
373
|
-
await hooks.beforeNodeExecute?.(node, execution.context);
|
|
374
|
-
try {
|
|
375
|
-
// Execute node
|
|
376
|
-
const executor = nodeType.executor;
|
|
377
|
-
if (!executor) {
|
|
378
|
-
throw new Error(`No executor for node type: ${node.type}`);
|
|
379
|
-
}
|
|
380
|
-
const result = await executor(node, execution.context, inputs);
|
|
381
|
-
// Store result
|
|
382
|
-
execution.context.state.nodeResults[node.id] = result;
|
|
383
|
-
execution.context.state.completedNodes.push(node.id);
|
|
384
|
-
// Update node execution
|
|
385
|
-
nodeExecution.status = 'completed';
|
|
386
|
-
nodeExecution.outputs = result;
|
|
387
|
-
nodeExecution.completedAt = new Date().toISOString();
|
|
388
|
-
// Trigger after node execute hook
|
|
389
|
-
await hooks.afterNodeExecute?.(node, execution.context, result);
|
|
390
|
-
// Execute next nodes
|
|
391
|
-
const outgoingConnections = dag.connections.filter(c => c.source === node.id);
|
|
392
|
-
for (const conn of outgoingConnections) {
|
|
393
|
-
// Check condition
|
|
394
|
-
if (conn.condition) {
|
|
395
|
-
const conditionMet = evaluateCondition(conn.condition, result, execution.context);
|
|
396
|
-
if (!conditionMet)
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
const nextNode = dag.nodes.find(n => n.id === conn.target);
|
|
400
|
-
if (nextNode) {
|
|
401
|
-
await executeNode(nextNode, execution, dag);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
catch (error) {
|
|
406
|
-
nodeExecution.status = 'failed';
|
|
407
|
-
nodeExecution.error = {
|
|
408
|
-
code: 'NODE_EXECUTION_ERROR',
|
|
409
|
-
message: error instanceof Error ? error.message : String(error),
|
|
410
|
-
nodeId: node.id,
|
|
411
|
-
};
|
|
412
|
-
execution.context.state.failedNodes.push(node.id);
|
|
413
|
-
throw error;
|
|
414
|
-
}
|
|
415
|
-
finally {
|
|
416
|
-
// Remove from active
|
|
417
|
-
execution.context.state.activeNodes = execution.context.state.activeNodes.filter(id => id !== node.id);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* Evaluate mapping expression
|
|
422
|
-
*/
|
|
423
|
-
function evaluateMapping(expression, context) {
|
|
424
|
-
try {
|
|
425
|
-
// Simple variable substitution
|
|
426
|
-
if (expression.startsWith('${') && expression.endsWith('}')) {
|
|
427
|
-
const path = expression.slice(2, -1);
|
|
428
|
-
return getValueByPath(context.variables, path);
|
|
429
|
-
}
|
|
430
|
-
return expression;
|
|
431
|
-
}
|
|
432
|
-
catch {
|
|
433
|
-
return undefined;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Evaluate condition
|
|
438
|
-
*/
|
|
439
|
-
function evaluateCondition(condition, result, context) {
|
|
440
|
-
try {
|
|
441
|
-
return new Function('result', 'context', `return ${condition}`)(result, context);
|
|
442
|
-
}
|
|
443
|
-
catch {
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Get value by path
|
|
449
|
-
*/
|
|
450
|
-
function getValueByPath(obj, path) {
|
|
451
|
-
return path.split('.').reduce((acc, key) => {
|
|
452
|
-
if (acc && typeof acc === 'object') {
|
|
453
|
-
return acc[key];
|
|
454
|
-
}
|
|
455
|
-
return undefined;
|
|
456
|
-
}, obj);
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Get execution
|
|
460
|
-
*/
|
|
461
|
-
function getExecution(executionId) {
|
|
462
|
-
return executions.get(executionId);
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Cancel execution
|
|
466
|
-
*/
|
|
467
|
-
function cancelExecution(executionId) {
|
|
468
|
-
const execution = executions.get(executionId);
|
|
469
|
-
if (execution && execution.status === 'running') {
|
|
470
|
-
execution.status = 'cancelled';
|
|
471
|
-
execution.completedAt = new Date().toISOString();
|
|
472
|
-
activeExecutions.delete(executionId);
|
|
473
|
-
return true;
|
|
474
|
-
}
|
|
475
|
-
return false;
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Pause execution
|
|
479
|
-
*/
|
|
480
|
-
function pauseExecution(executionId) {
|
|
481
|
-
const execution = executions.get(executionId);
|
|
482
|
-
if (execution && execution.status === 'running') {
|
|
483
|
-
execution.status = 'paused';
|
|
484
|
-
return true;
|
|
485
|
-
}
|
|
486
|
-
return false;
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* Resume execution
|
|
490
|
-
*/
|
|
491
|
-
function resumeExecution(executionId) {
|
|
492
|
-
const execution = executions.get(executionId);
|
|
493
|
-
if (execution && execution.status === 'paused') {
|
|
494
|
-
execution.status = 'running';
|
|
495
|
-
// TODO: Resume execution logic
|
|
496
|
-
return true;
|
|
497
|
-
}
|
|
498
|
-
return false;
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Register node type
|
|
502
|
-
*/
|
|
503
|
-
function registerNodeType(nodeType) {
|
|
504
|
-
nodeTypes.set(nodeType.type, nodeType);
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Get node type
|
|
508
|
-
*/
|
|
509
|
-
function getNodeType(type) {
|
|
510
|
-
return nodeTypes.get(type);
|
|
511
|
-
}
|
|
512
|
-
// Initialize
|
|
513
|
-
registerBuiltInNodeTypes();
|
|
514
|
-
return {
|
|
515
|
-
registerWorkflow,
|
|
516
|
-
getWorkflow,
|
|
517
|
-
listWorkflows,
|
|
518
|
-
deleteWorkflow,
|
|
519
|
-
execute,
|
|
520
|
-
getExecution,
|
|
521
|
-
cancelExecution,
|
|
522
|
-
pauseExecution,
|
|
523
|
-
resumeExecution,
|
|
524
|
-
registerNodeType,
|
|
525
|
-
getNodeType,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* Global workflow engine instance
|
|
530
|
-
*/
|
|
531
|
-
export const globalWorkflowEngine = createWorkflowEngine();
|
|
532
|
-
//# sourceMappingURL=workflow-engine.js.map
|
package/dist/index.d.ts.bak
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A2R Workflow Engine
|
|
3
|
-
*
|
|
4
|
-
* Visual workflow orchestration with DAG support.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```typescript
|
|
8
|
-
* import { createWorkflowEngine, createVisualizer } from '@allternit/workflow-engine';
|
|
9
|
-
*
|
|
10
|
-
* const engine = createWorkflowEngine();
|
|
11
|
-
*
|
|
12
|
-
* // Register workflow
|
|
13
|
-
* engine.registerWorkflow({
|
|
14
|
-
* id: 'my-workflow',
|
|
15
|
-
* name: 'My Workflow',
|
|
16
|
-
* version: '1.0.0',
|
|
17
|
-
* nodes: [
|
|
18
|
-
* { id: 'trigger', type: 'trigger:manual', name: 'Start' },
|
|
19
|
-
* { id: 'http', type: 'http:request', name: 'Fetch Data', config: { method: 'GET' } },
|
|
20
|
-
* { id: 'output', type: 'output:result', name: 'Return Result' },
|
|
21
|
-
* ],
|
|
22
|
-
* connections: [
|
|
23
|
-
* { id: 'c1', source: 'trigger', target: 'http' },
|
|
24
|
-
* { id: 'c2', source: 'http', target: 'output' },
|
|
25
|
-
* ],
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* // Execute workflow
|
|
29
|
-
* const execution = await engine.execute('my-workflow', { url: 'https://api.example.com' });
|
|
30
|
-
* console.log(execution.status); // 'completed'
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export type { Workflow, WorkflowNode, Connection, WorkflowExecution, ExecutionContext, ExecutionState, NodeExecution, ExecutionStatus, ExecutionError, ParameterSchema, Variable, InputMapping, OutputMapping, Trigger, ErrorHandlingConfig, NodeType, NodeCategory, PortDefinition, WorkflowEngineConfig, WorkflowHooks, Position, } from './types';
|
|
34
|
-
export { createWorkflowEngine, globalWorkflowEngine, type WorkflowEngine, } from './engine/workflow-engine';
|
|
35
|
-
export { createScheduler, globalScheduler, type Scheduler, type SchedulerConfig, type Task, type SchedulerStatus, } from './scheduler';
|
|
36
|
-
export { createVisualizer, globalVisualizer, type WorkflowVisualizer, type VisualizerConfig, type VisualLayout, type VisualNode, type VisualConnection, type Bounds, } from './visualizer';
|
|
37
|
-
export declare const VERSION = "0.1.0";
|
|
38
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js.bak
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A2R Workflow Engine
|
|
3
|
-
*
|
|
4
|
-
* Visual workflow orchestration with DAG support.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```typescript
|
|
8
|
-
* import { createWorkflowEngine, createVisualizer } from '@allternit/workflow-engine';
|
|
9
|
-
*
|
|
10
|
-
* const engine = createWorkflowEngine();
|
|
11
|
-
*
|
|
12
|
-
* // Register workflow
|
|
13
|
-
* engine.registerWorkflow({
|
|
14
|
-
* id: 'my-workflow',
|
|
15
|
-
* name: 'My Workflow',
|
|
16
|
-
* version: '1.0.0',
|
|
17
|
-
* nodes: [
|
|
18
|
-
* { id: 'trigger', type: 'trigger:manual', name: 'Start' },
|
|
19
|
-
* { id: 'http', type: 'http:request', name: 'Fetch Data', config: { method: 'GET' } },
|
|
20
|
-
* { id: 'output', type: 'output:result', name: 'Return Result' },
|
|
21
|
-
* ],
|
|
22
|
-
* connections: [
|
|
23
|
-
* { id: 'c1', source: 'trigger', target: 'http' },
|
|
24
|
-
* { id: 'c2', source: 'http', target: 'output' },
|
|
25
|
-
* ],
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* // Execute workflow
|
|
29
|
-
* const execution = await engine.execute('my-workflow', { url: 'https://api.example.com' });
|
|
30
|
-
* console.log(execution.status); // 'completed'
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
// Engine
|
|
34
|
-
export { createWorkflowEngine, globalWorkflowEngine, } from './engine/workflow-engine';
|
|
35
|
-
// Scheduler
|
|
36
|
-
export { createScheduler, globalScheduler, } from './scheduler';
|
|
37
|
-
// Visualizer
|
|
38
|
-
export { createVisualizer, globalVisualizer, } from './visualizer';
|
|
39
|
-
// Version
|
|
40
|
-
export const VERSION = '0.1.0';
|
|
41
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Scheduler
|
|
3
|
-
*
|
|
4
|
-
* Handles parallel execution, queuing, and resource management.
|
|
5
|
-
*/
|
|
6
|
-
import type { WorkflowExecution, WorkflowNode } from '../types';
|
|
7
|
-
export interface SchedulerConfig {
|
|
8
|
-
/** Max concurrent tasks */
|
|
9
|
-
maxConcurrency?: number;
|
|
10
|
-
/** Queue size limit */
|
|
11
|
-
queueLimit?: number;
|
|
12
|
-
/** Default task timeout (ms) */
|
|
13
|
-
defaultTimeout?: number;
|
|
14
|
-
/** Enable task prioritization */
|
|
15
|
-
enablePriority?: boolean;
|
|
16
|
-
}
|
|
17
|
-
export interface Task {
|
|
18
|
-
id: string;
|
|
19
|
-
node: WorkflowNode;
|
|
20
|
-
execution: WorkflowExecution;
|
|
21
|
-
priority?: number;
|
|
22
|
-
timeout?: number;
|
|
23
|
-
}
|
|
24
|
-
export interface Scheduler {
|
|
25
|
-
/** Submit task for execution */
|
|
26
|
-
submit(task: Task): Promise<unknown>;
|
|
27
|
-
/** Submit multiple tasks (parallel) */
|
|
28
|
-
submitAll(tasks: Task[]): Promise<unknown[]>;
|
|
29
|
-
/** Cancel task */
|
|
30
|
-
cancel(taskId: string): boolean;
|
|
31
|
-
/** Get queue status */
|
|
32
|
-
getStatus(): SchedulerStatus;
|
|
33
|
-
/** Pause scheduler */
|
|
34
|
-
pause(): void;
|
|
35
|
-
/** Resume scheduler */
|
|
36
|
-
resume(): void;
|
|
37
|
-
}
|
|
38
|
-
export interface SchedulerStatus {
|
|
39
|
-
running: number;
|
|
40
|
-
queued: number;
|
|
41
|
-
completed: number;
|
|
42
|
-
failed: number;
|
|
43
|
-
isPaused: boolean;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Create workflow scheduler
|
|
47
|
-
*/
|
|
48
|
-
export declare function createScheduler(config?: SchedulerConfig): Scheduler;
|
|
49
|
-
/**
|
|
50
|
-
* Global scheduler instance
|
|
51
|
-
*/
|
|
52
|
-
export declare const globalScheduler: Scheduler;
|
|
53
|
-
//# sourceMappingURL=index.d.ts.map
|