@onlineapps/conn-orch-orchestrator 1.0.26 → 1.0.28
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 +2 -2
- package/src/WorkflowOrchestrator.js +64 -20
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.28",
|
|
4
4
|
"description": "Workflow orchestration connector for OA Drive - handles message routing and workflow execution",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@onlineapps/conn-infra-mq": "^1.1.0",
|
|
25
25
|
"@onlineapps/conn-orch-registry": "^1.1.4",
|
|
26
26
|
"@onlineapps/conn-orch-cookbook": "^2.0.0",
|
|
27
|
-
"@onlineapps/conn-orch-api-mapper": "^1.0.
|
|
27
|
+
"@onlineapps/conn-orch-api-mapper": "^1.0.8"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"jest": "^29.5.0",
|
|
@@ -89,10 +89,10 @@ class WorkflowOrchestrator {
|
|
|
89
89
|
delivery: context?.delivery || cookbookDef?.delivery || { handler: 'none' }
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
// Find current step (V2: step_id
|
|
93
|
-
const step = cookbookDef.steps
|
|
92
|
+
// Find current step (V2: steps is an object keyed by step_id)
|
|
93
|
+
const step = cookbookDef.steps[current_step];
|
|
94
94
|
if (!step) {
|
|
95
|
-
throw new Error(`Step not found: ${current_step}. Available steps: ${cookbookDef.steps
|
|
95
|
+
throw new Error(`Step not found: ${current_step}. Available steps: ${Object.keys(cookbookDef.steps).join(', ')}`);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
// Get step_id (V2)
|
|
@@ -131,19 +131,16 @@ class WorkflowOrchestrator {
|
|
|
131
131
|
|
|
132
132
|
// Update context with result - steps as OBJECT (V2 format, keyed by step_id)
|
|
133
133
|
// Each step preserves its definition (step_id, type, service, operation, input) and adds output
|
|
134
|
-
const
|
|
135
|
-
const stepDefinition = cookbookDef.steps[currentIndex];
|
|
134
|
+
const stepDefinition = cookbookDef.steps[current_step];
|
|
136
135
|
|
|
137
136
|
// Initialize steps object from cookbook if not present
|
|
138
|
-
// V2: steps is an object keyed by step_id
|
|
137
|
+
// V2: steps is an object keyed by step_id
|
|
139
138
|
let existingSteps = enrichedContext.steps || {};
|
|
140
139
|
|
|
141
140
|
// Initialize from cookbook if empty
|
|
142
141
|
if (Object.keys(existingSteps).length === 0) {
|
|
143
|
-
cookbookDef.steps.forEach(s => {
|
|
144
|
-
|
|
145
|
-
existingSteps[s.step_id] = { ...s };
|
|
146
|
-
}
|
|
142
|
+
Object.entries(cookbookDef.steps).forEach(([key, s]) => {
|
|
143
|
+
existingSteps[key] = { ...s };
|
|
147
144
|
});
|
|
148
145
|
}
|
|
149
146
|
|
|
@@ -155,11 +152,32 @@ class WorkflowOrchestrator {
|
|
|
155
152
|
completed_at: new Date().toISOString()
|
|
156
153
|
};
|
|
157
154
|
|
|
155
|
+
// === STRUCTURED LOG: Context update ===
|
|
156
|
+
console.log(`[WorkflowOrchestrator:CONTEXT_UPDATE] ${JSON.stringify({
|
|
157
|
+
layer: 'orchestrator',
|
|
158
|
+
workflow_id: workflow_id,
|
|
159
|
+
step_id: stepId,
|
|
160
|
+
stored_output: {
|
|
161
|
+
_descriptor: result?._descriptor,
|
|
162
|
+
type: result?.type,
|
|
163
|
+
storage_ref: result?.storage_ref,
|
|
164
|
+
outputKeys: result && typeof result === 'object' ? Object.keys(result) : null
|
|
165
|
+
},
|
|
166
|
+
timestamp: new Date().toISOString()
|
|
167
|
+
})}`);
|
|
168
|
+
|
|
169
|
+
|
|
158
170
|
const updatedContext = {
|
|
159
171
|
...enrichedContext,
|
|
160
172
|
steps: existingSteps // Object keyed by step_id
|
|
161
173
|
};
|
|
162
174
|
|
|
175
|
+
// V2: Get step order from object keys (JavaScript preserves insertion order for string keys)
|
|
176
|
+
const stepKeys = Object.keys(cookbookDef.steps);
|
|
177
|
+
const currentIndex = stepKeys.indexOf(current_step);
|
|
178
|
+
const nextStepKey = stepKeys[currentIndex + 1];
|
|
179
|
+
const nextStep = nextStepKey ? cookbookDef.steps[nextStepKey] : null;
|
|
180
|
+
|
|
163
181
|
// Publish workflow.progress AFTER execution (so we have step output)
|
|
164
182
|
const { publishToMonitoringWorkflow } = require('@onlineapps/mq-client-core').monitoring;
|
|
165
183
|
try {
|
|
@@ -186,9 +204,6 @@ class WorkflowOrchestrator {
|
|
|
186
204
|
});
|
|
187
205
|
}
|
|
188
206
|
|
|
189
|
-
// Find next step (currentIndex already defined above)
|
|
190
|
-
const nextStep = cookbookDef.steps[currentIndex + 1];
|
|
191
|
-
|
|
192
207
|
if (nextStep) {
|
|
193
208
|
// Route to next step
|
|
194
209
|
const nextStepId = nextStep.step_id;
|
|
@@ -335,6 +350,21 @@ class WorkflowOrchestrator {
|
|
|
335
350
|
context
|
|
336
351
|
);
|
|
337
352
|
|
|
353
|
+
// === STRUCTURED LOG: Step result ===
|
|
354
|
+
console.log(`[WorkflowOrchestrator:STEP_RESULT] ${JSON.stringify({
|
|
355
|
+
layer: 'orchestrator',
|
|
356
|
+
step_id: step.step_id,
|
|
357
|
+
service: step.service,
|
|
358
|
+
operation: step.operation,
|
|
359
|
+
result: {
|
|
360
|
+
_descriptor: result?._descriptor,
|
|
361
|
+
type: result?.type,
|
|
362
|
+
storage_ref: result?.storage_ref,
|
|
363
|
+
resultKeys: result && typeof result === 'object' ? Object.keys(result) : null
|
|
364
|
+
},
|
|
365
|
+
timestamp: new Date().toISOString()
|
|
366
|
+
})}`);
|
|
367
|
+
|
|
338
368
|
this.logger.info(`Task step executed`, {
|
|
339
369
|
step: step.step_id,
|
|
340
370
|
service: step.service,
|
|
@@ -722,22 +752,36 @@ class WorkflowOrchestrator {
|
|
|
722
752
|
throw new Error(`FAIL-FAST: Invalid version format '${version}'. Must be 2.x.x (e.g., 2.0.0)`);
|
|
723
753
|
}
|
|
724
754
|
|
|
725
|
-
// Check steps
|
|
726
|
-
if (!cookbook.steps ||
|
|
755
|
+
// Check steps - V2 FORMAT: steps MUST be an OBJECT (keyed by step_id), NOT an array!
|
|
756
|
+
if (!cookbook.steps || typeof cookbook.steps !== 'object') {
|
|
757
|
+
throw new Error('FAIL-FAST: Cookbook must have steps object');
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// V1 format (array) is BANNED!
|
|
761
|
+
if (Array.isArray(cookbook.steps)) {
|
|
762
|
+
throw new Error('FAIL-FAST: V1 FORMAT BANNED! Cookbook steps must be an OBJECT (keyed by step_id), NOT an array!');
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const stepKeys = Object.keys(cookbook.steps);
|
|
766
|
+
if (stepKeys.length === 0) {
|
|
727
767
|
throw new Error('FAIL-FAST: Cookbook must have at least one step');
|
|
728
768
|
}
|
|
729
769
|
|
|
730
770
|
// Validate each step has step_id (V2) not id (V1)
|
|
731
771
|
const invalidSteps = [];
|
|
732
|
-
|
|
772
|
+
stepKeys.forEach((stepKey) => {
|
|
773
|
+
const step = cookbook.steps[stepKey];
|
|
733
774
|
if (step.id && !step.step_id) {
|
|
734
|
-
invalidSteps.push(`Step ${
|
|
775
|
+
invalidSteps.push(`Step '${stepKey}': has 'id' (V1) but missing 'step_id' (V2)`);
|
|
735
776
|
}
|
|
736
777
|
if (!step.step_id) {
|
|
737
|
-
invalidSteps.push(`Step ${
|
|
778
|
+
invalidSteps.push(`Step '${stepKey}': missing required 'step_id'`);
|
|
779
|
+
}
|
|
780
|
+
if (step.step_id !== stepKey) {
|
|
781
|
+
invalidSteps.push(`Step '${stepKey}': step_id '${step.step_id}' does not match key '${stepKey}'`);
|
|
738
782
|
}
|
|
739
783
|
if (!step.type) {
|
|
740
|
-
invalidSteps.push(`Step ${
|
|
784
|
+
invalidSteps.push(`Step '${stepKey}': missing required 'type'`);
|
|
741
785
|
}
|
|
742
786
|
});
|
|
743
787
|
|
|
@@ -747,7 +791,7 @@ class WorkflowOrchestrator {
|
|
|
747
791
|
|
|
748
792
|
this.logger.info('[WorkflowOrchestrator] V2 format validation passed', {
|
|
749
793
|
version: cookbook.version,
|
|
750
|
-
steps: cookbook.steps
|
|
794
|
+
steps: Object.keys(cookbook.steps)
|
|
751
795
|
});
|
|
752
796
|
}
|
|
753
797
|
}
|