@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/conn-orch-orchestrator",
3
- "version": "1.0.26",
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.6"
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 only)
93
- const step = cookbookDef.steps.find(s => s.step_id === current_step);
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.map(s => s.step_id).join(', ')}`);
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 currentIndex = cookbookDef.steps.findIndex(s => s.step_id === current_step);
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, not an array
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
- if (s.step_id) {
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 || !Array.isArray(cookbook.steps) || cookbook.steps.length === 0) {
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
- cookbook.steps.forEach((step, index) => {
772
+ stepKeys.forEach((stepKey) => {
773
+ const step = cookbook.steps[stepKey];
733
774
  if (step.id && !step.step_id) {
734
- invalidSteps.push(`Step ${index}: has 'id' (V1) but missing 'step_id' (V2)`);
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 ${index}: missing required 'step_id'`);
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 ${index} (${step.step_id || 'unknown'}): missing required 'type'`);
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.map(s => s.step_id)
794
+ steps: Object.keys(cookbook.steps)
751
795
  });
752
796
  }
753
797
  }