@onlineapps/conn-orch-orchestrator 1.0.33 → 1.0.39
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/package.json +5 -5
- package/src/WorkflowOrchestrator.js +60 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-orchestrator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"description": "Workflow orchestration connector for OA Drive - handles message routing and workflow execution",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@onlineapps/conn-base-monitoring": "^1.0.0",
|
|
24
|
-
"@onlineapps/conn-infra-mq": "
|
|
25
|
-
"@onlineapps/conn-orch-
|
|
24
|
+
"@onlineapps/conn-infra-mq": "1.1.53",
|
|
25
|
+
"@onlineapps/conn-orch-api-mapper": "^1.0.0",
|
|
26
26
|
"@onlineapps/conn-orch-cookbook": "^2.0.0",
|
|
27
|
-
"@onlineapps/conn-orch-
|
|
27
|
+
"@onlineapps/conn-orch-registry": "^1.1.4"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"jest": "^29.5.0",
|
|
31
30
|
"eslint": "^8.30.0",
|
|
31
|
+
"jest": "^29.5.0",
|
|
32
32
|
"jsdoc-to-markdown": "^8.0.0"
|
|
33
33
|
},
|
|
34
34
|
"jest": {
|
|
@@ -61,6 +61,25 @@ class WorkflowOrchestrator {
|
|
|
61
61
|
return step?.step_id || step?.id;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Get steps as array (supports both V1 array and V2 object formats)
|
|
66
|
+
* V2 FORMAT: steps is an object keyed by step_id
|
|
67
|
+
* V1 FORMAT (deprecated): steps is an array
|
|
68
|
+
* @private
|
|
69
|
+
* @param {Object} cookbookDef - Cookbook definition
|
|
70
|
+
* @returns {Array} Array of step objects
|
|
71
|
+
*/
|
|
72
|
+
_getStepsArray(cookbookDef) {
|
|
73
|
+
if (!cookbookDef?.steps) return [];
|
|
74
|
+
if (Array.isArray(cookbookDef.steps)) {
|
|
75
|
+
// V1 format (deprecated) - steps is already an array
|
|
76
|
+
this.logger.warn('Using deprecated V1 cookbook format (steps as array). Please migrate to V2 (steps as object).');
|
|
77
|
+
return cookbookDef.steps;
|
|
78
|
+
}
|
|
79
|
+
// V2 format - steps is an object keyed by step_id
|
|
80
|
+
return Object.values(cookbookDef.steps);
|
|
81
|
+
}
|
|
82
|
+
|
|
64
83
|
/**
|
|
65
84
|
* Process a workflow message
|
|
66
85
|
* @async
|
|
@@ -97,7 +116,9 @@ class WorkflowOrchestrator {
|
|
|
97
116
|
};
|
|
98
117
|
|
|
99
118
|
// Find current step (supports both V1 'id' and V2 'step_id')
|
|
100
|
-
|
|
119
|
+
// V2 FORMAT: steps is an object keyed by step_id
|
|
120
|
+
const stepsArray = this._getStepsArray(cookbookDef);
|
|
121
|
+
const step = stepsArray.find(s => this._getStepId(s) === current_step);
|
|
101
122
|
if (!step) {
|
|
102
123
|
throw new Error(`Step not found: ${current_step}`);
|
|
103
124
|
}
|
|
@@ -135,13 +156,14 @@ class WorkflowOrchestrator {
|
|
|
135
156
|
|
|
136
157
|
// Update context with result - steps as ARRAY (consistent with cookbook.steps)
|
|
137
158
|
// Each step preserves its definition (id/step_id, type, service, operation, input) and adds output
|
|
138
|
-
|
|
139
|
-
const
|
|
159
|
+
// stepsArray is already defined above via _getStepsArray()
|
|
160
|
+
const currentIndex = stepsArray.findIndex(s => this._getStepId(s) === current_step);
|
|
161
|
+
const stepDefinition = stepsArray[currentIndex];
|
|
140
162
|
|
|
141
163
|
// Initialize steps array from cookbook if not present
|
|
142
164
|
const existingSteps = Array.isArray(enrichedContext.steps)
|
|
143
165
|
? [...enrichedContext.steps]
|
|
144
|
-
:
|
|
166
|
+
: stepsArray.map(s => ({ ...s })); // Deep copy of step definitions
|
|
145
167
|
|
|
146
168
|
// Update the current step with output (preserve id, type, service, operation, input)
|
|
147
169
|
existingSteps[currentIndex] = {
|
|
@@ -182,8 +204,8 @@ class WorkflowOrchestrator {
|
|
|
182
204
|
});
|
|
183
205
|
}
|
|
184
206
|
|
|
185
|
-
// Find next step (currentIndex already defined above)
|
|
186
|
-
const nextStep =
|
|
207
|
+
// Find next step (currentIndex and stepsArray already defined above)
|
|
208
|
+
const nextStep = stepsArray[currentIndex + 1];
|
|
187
209
|
|
|
188
210
|
if (nextStep) {
|
|
189
211
|
// Route to next step
|
|
@@ -304,7 +326,7 @@ class WorkflowOrchestrator {
|
|
|
304
326
|
|
|
305
327
|
/**
|
|
306
328
|
* Resolve variable references in input object
|
|
307
|
-
* Supports
|
|
329
|
+
* Supports {{steps.step_id.output.field}}, {{api_input.field}}, {{context.field}}
|
|
308
330
|
* @private
|
|
309
331
|
* @param {Object} input - Input object with potential references
|
|
310
332
|
* @param {Object} context - Current context with steps, api_input, etc
|
|
@@ -314,11 +336,24 @@ class WorkflowOrchestrator {
|
|
|
314
336
|
if (!input) return input;
|
|
315
337
|
|
|
316
338
|
const resolveValue = (value) => {
|
|
317
|
-
if (typeof value === 'string' && value.includes('
|
|
318
|
-
//
|
|
319
|
-
|
|
339
|
+
if (typeof value === 'string' && value.includes('{{')) {
|
|
340
|
+
// Check if the ENTIRE string is a single template reference
|
|
341
|
+
// e.g. "{{steps.greeting.output}}" should return the object directly
|
|
342
|
+
const singleRefMatch = value.match(/^\{\{([^}]+)\}\}$/);
|
|
343
|
+
if (singleRefMatch) {
|
|
344
|
+
// Entire value is a single reference - return the resolved value directly (preserves objects)
|
|
345
|
+
const resolved = this._getValueFromPath(singleRefMatch[1].trim(), context);
|
|
346
|
+
return resolved !== undefined ? resolved : value;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Multiple references or mixed with text - use string replacement
|
|
350
|
+
// e.g. "Hello {{name}}, your order {{orderId}}" becomes "Hello John, your order 123"
|
|
351
|
+
return value.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
|
|
320
352
|
const resolved = this._getValueFromPath(path.trim(), context);
|
|
321
|
-
|
|
353
|
+
if (resolved === undefined) return match;
|
|
354
|
+
// For string concatenation, convert objects to JSON string
|
|
355
|
+
if (typeof resolved === 'object') return JSON.stringify(resolved);
|
|
356
|
+
return String(resolved);
|
|
322
357
|
});
|
|
323
358
|
}
|
|
324
359
|
if (Array.isArray(value)) {
|
|
@@ -338,7 +373,7 @@ class WorkflowOrchestrator {
|
|
|
338
373
|
/**
|
|
339
374
|
* Get value from dot/bracket notation path
|
|
340
375
|
* @private
|
|
341
|
-
* @param {string} path - Path like "steps
|
|
376
|
+
* @param {string} path - Path like "steps.greeting.output.message" or "api_input.name"
|
|
342
377
|
* @param {Object} context - Context object
|
|
343
378
|
* @returns {*} Resolved value or undefined
|
|
344
379
|
*/
|
|
@@ -356,9 +391,20 @@ class WorkflowOrchestrator {
|
|
|
356
391
|
const parts = normalized.split('.');
|
|
357
392
|
|
|
358
393
|
let current = context;
|
|
359
|
-
for (
|
|
394
|
+
for (let i = 0; i < parts.length; i++) {
|
|
395
|
+
const part = parts[i];
|
|
360
396
|
if (current === undefined || current === null) return undefined;
|
|
361
|
-
|
|
397
|
+
|
|
398
|
+
// Special handling for 'steps' array - lookup by step id
|
|
399
|
+
// context.steps is an array of {id/step_id: "step_id", output: {...}}
|
|
400
|
+
// Path like "steps.greeting.output" should find step with id="greeting"
|
|
401
|
+
if (parts[i - 1] === 'steps' && Array.isArray(context.steps)) {
|
|
402
|
+
// 'part' is the step_id, find the step in the array (support both 'id' and 'step_id')
|
|
403
|
+
const step = context.steps.find(s => s.id === part || s.step_id === part);
|
|
404
|
+
current = step;
|
|
405
|
+
} else {
|
|
406
|
+
current = current[part];
|
|
407
|
+
}
|
|
362
408
|
}
|
|
363
409
|
return current;
|
|
364
410
|
}
|