@onlineapps/conn-orch-orchestrator 1.0.25 → 1.0.27
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 +102 -2
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.27",
|
|
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",
|
|
@@ -155,6 +155,21 @@ class WorkflowOrchestrator {
|
|
|
155
155
|
completed_at: new Date().toISOString()
|
|
156
156
|
};
|
|
157
157
|
|
|
158
|
+
// === STRUCTURED LOG: Context update ===
|
|
159
|
+
console.log(`[WorkflowOrchestrator:CONTEXT_UPDATE] ${JSON.stringify({
|
|
160
|
+
layer: 'orchestrator',
|
|
161
|
+
workflow_id: workflow_id,
|
|
162
|
+
step_id: stepId,
|
|
163
|
+
stored_output: {
|
|
164
|
+
_descriptor: result?._descriptor,
|
|
165
|
+
type: result?.type,
|
|
166
|
+
storage_ref: result?.storage_ref,
|
|
167
|
+
outputKeys: result && typeof result === 'object' ? Object.keys(result) : null
|
|
168
|
+
},
|
|
169
|
+
timestamp: new Date().toISOString()
|
|
170
|
+
})}`);
|
|
171
|
+
|
|
172
|
+
|
|
158
173
|
const updatedContext = {
|
|
159
174
|
...enrichedContext,
|
|
160
175
|
steps: existingSteps // Object keyed by step_id
|
|
@@ -280,9 +295,34 @@ class WorkflowOrchestrator {
|
|
|
280
295
|
* @returns {Promise<Object>} API call result
|
|
281
296
|
*/
|
|
282
297
|
async _executeTaskStep(step, context) {
|
|
298
|
+
// FAIL-FAST: Verify context exists
|
|
299
|
+
if (!context) {
|
|
300
|
+
const error = new Error(`Context is missing for step ${step.step_id}`);
|
|
301
|
+
this.logger.error('[WorkflowOrchestrator] [FAIL-FAST] Missing context', { step_id: step.step_id });
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
|
|
283
305
|
// Debug: log context keys and api_input
|
|
284
306
|
console.log(`[WorkflowOrchestrator] [RESOLVE] Step ${step.step_id} - context keys:`, Object.keys(context || {}));
|
|
285
|
-
|
|
307
|
+
|
|
308
|
+
// FAIL-FAST: Log api_input state (but don't fail if missing - it might not be needed)
|
|
309
|
+
if (context.api_input === undefined) {
|
|
310
|
+
console.warn(`[WorkflowOrchestrator] [WARNING] Step ${step.step_id} - context.api_input is undefined - template references like {{api_input.field}} will fail`);
|
|
311
|
+
} else if (context.api_input === null) {
|
|
312
|
+
console.warn(`[WorkflowOrchestrator] [WARNING] Step ${step.step_id} - context.api_input is null - template references like {{api_input.field}} will fail`);
|
|
313
|
+
} else if (typeof context.api_input !== 'object' || Array.isArray(context.api_input)) {
|
|
314
|
+
const error = new Error(`Invalid api_input type for step ${step.step_id}: expected object, got ${typeof context.api_input}`);
|
|
315
|
+
console.error(`[WorkflowOrchestrator] [FAIL-FAST] Invalid api_input type:`, {
|
|
316
|
+
step_id: step.step_id,
|
|
317
|
+
api_input_type: typeof context.api_input,
|
|
318
|
+
api_input_value: context.api_input,
|
|
319
|
+
is_array: Array.isArray(context.api_input)
|
|
320
|
+
});
|
|
321
|
+
throw error;
|
|
322
|
+
} else {
|
|
323
|
+
console.log(`[WorkflowOrchestrator] [RESOLVE] Step ${step.step_id} - context.api_input:`, JSON.stringify(context.api_input));
|
|
324
|
+
}
|
|
325
|
+
|
|
286
326
|
console.log(`[WorkflowOrchestrator] [RESOLVE] Step ${step.step_id} - context.steps keys:`,
|
|
287
327
|
context.steps ? Object.keys(context.steps) : 'NO STEPS');
|
|
288
328
|
|
|
@@ -291,6 +331,18 @@ class WorkflowOrchestrator {
|
|
|
291
331
|
const resolvedInput = this._resolveInputReferences(step.input, context);
|
|
292
332
|
console.log(`[WorkflowOrchestrator] [RESOLVE] Step ${step.step_id} input AFTER:`, JSON.stringify(resolvedInput));
|
|
293
333
|
|
|
334
|
+
// FAIL-FAST: Check if template references were resolved
|
|
335
|
+
const inputStr = JSON.stringify(resolvedInput);
|
|
336
|
+
if (inputStr.includes('{{api_input.') || inputStr.includes('${api_input.')) {
|
|
337
|
+
console.error(`[WorkflowOrchestrator] [FAIL-FAST] Unresolved api_input template in step ${step.step_id}:`, {
|
|
338
|
+
step_id: step.step_id,
|
|
339
|
+
resolved_input: resolvedInput,
|
|
340
|
+
context_api_input: context.api_input,
|
|
341
|
+
context_keys: Object.keys(context)
|
|
342
|
+
});
|
|
343
|
+
throw new Error(`Template reference to api_input not resolved in step ${step.step_id} - check that api_input is in context`);
|
|
344
|
+
}
|
|
345
|
+
|
|
294
346
|
// Use API mapper to call the service with resolved input
|
|
295
347
|
const result = await this.apiMapper.callOperation(
|
|
296
348
|
step.operation,
|
|
@@ -298,6 +350,21 @@ class WorkflowOrchestrator {
|
|
|
298
350
|
context
|
|
299
351
|
);
|
|
300
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
|
+
|
|
301
368
|
this.logger.info(`Task step executed`, {
|
|
302
369
|
step: step.step_id,
|
|
303
370
|
service: step.service,
|
|
@@ -378,6 +445,12 @@ class WorkflowOrchestrator {
|
|
|
378
445
|
* @returns {*} Resolved value or undefined
|
|
379
446
|
*/
|
|
380
447
|
_getValueFromPath(path, context) {
|
|
448
|
+
// FAIL-FAST: Verify context exists
|
|
449
|
+
if (!context) {
|
|
450
|
+
console.error('[WorkflowOrchestrator] [FAIL-FAST] _getValueFromPath called with null/undefined context', { path });
|
|
451
|
+
throw new Error(`Cannot resolve path '${path}': context is null or undefined`);
|
|
452
|
+
}
|
|
453
|
+
|
|
381
454
|
// V2: steps is an object keyed by step_id, not an array
|
|
382
455
|
// Support both formats for backward compatibility during migration:
|
|
383
456
|
// - steps.step_id.output.field (V2, preferred)
|
|
@@ -402,9 +475,36 @@ class WorkflowOrchestrator {
|
|
|
402
475
|
|
|
403
476
|
const parts = normalized.split('.');
|
|
404
477
|
|
|
478
|
+
// FAIL-FAST: Log api_input access attempts
|
|
479
|
+
if (normalized.startsWith('api_input.')) {
|
|
480
|
+
console.log(`[WorkflowOrchestrator] [GET_VALUE] Resolving api_input path: ${path} -> ${normalized}`);
|
|
481
|
+
console.log(`[WorkflowOrchestrator] [GET_VALUE] context.api_input exists:`, context.api_input !== undefined);
|
|
482
|
+
console.log(`[WorkflowOrchestrator] [GET_VALUE] context.api_input type:`, typeof context.api_input);
|
|
483
|
+
if (context.api_input) {
|
|
484
|
+
console.log(`[WorkflowOrchestrator] [GET_VALUE] context.api_input keys:`, Object.keys(context.api_input));
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
405
488
|
let current = context;
|
|
406
489
|
for (const part of parts) {
|
|
407
|
-
if (current === undefined || current === null)
|
|
490
|
+
if (current === undefined || current === null) {
|
|
491
|
+
// FAIL-FAST: Log failed resolution for api_input
|
|
492
|
+
if (normalized.startsWith('api_input.')) {
|
|
493
|
+
console.error(`[WorkflowOrchestrator] [FAIL-FAST] Failed to resolve api_input path: ${path}`, {
|
|
494
|
+
path,
|
|
495
|
+
normalized,
|
|
496
|
+
parts,
|
|
497
|
+
failed_at_part: part,
|
|
498
|
+
current_type: typeof current,
|
|
499
|
+
context_keys: Object.keys(context),
|
|
500
|
+
context_has_api_input: 'api_input' in context,
|
|
501
|
+
api_input_type: typeof context.api_input,
|
|
502
|
+
api_input_keys: context.api_input ? Object.keys(context.api_input) : null
|
|
503
|
+
});
|
|
504
|
+
throw new Error(`Failed to resolve api_input path '${path}': '${part}' is undefined in context`);
|
|
505
|
+
}
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
408
508
|
|
|
409
509
|
// Special handling for steps: if accessing by numeric index and steps is object,
|
|
410
510
|
// try to find step by index in cookbook (fallback for legacy)
|