@open-mercato/core 0.6.6-develop.6336.1.38e0a4c455 → 0.6.6-develop.6337.1.bd66ae541e

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/workflows/components/fields/MappingArrayEditor.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport { useState } from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { ChevronDown, Plus, Trash2 } from 'lucide-react'\nimport type { CrudCustomFieldRenderProps } from '@open-mercato/ui/backend/CrudForm'\n\n/**\n * Mapping definition structure for SubWorkflow input/output\n */\nexport interface Mapping {\n key: string\n value: string\n}\n\ninterface MappingArrayEditorProps extends CrudCustomFieldRenderProps {\n value: Mapping[]\n label?: string\n description?: string\n}\n\n/**\n * MappingArrayEditor - Custom field component for managing SubWorkflow input/output mappings\n *\n * Provides an interface to add, edit, and remove key-value pair mappings.\n * Values support template expressions like {{context.foo}} for dynamic data binding.\n *\n * Used by NodeEditDialog (SubWorkflow type only)\n */\nexport function MappingArrayEditor({\n id,\n value = [],\n error,\n setValue,\n disabled,\n label: labelProp,\n description: descriptionProp,\n}: MappingArrayEditorProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const label = labelProp ?? t('workflows.fieldEditors.mappings.label')\n const description = descriptionProp ?? t('workflows.fieldEditors.mappings.description')\n const [expandedIndices, setExpandedIndices] = useState<Set<number>>(new Set())\n\n const mappings = Array.isArray(value) ? value : []\n\n const toggleExpanded = (index: number) => {\n const newExpanded = new Set(expandedIndices)\n if (newExpanded.has(index)) {\n newExpanded.delete(index)\n } else {\n newExpanded.add(index)\n }\n setExpandedIndices(newExpanded)\n }\n\n const addMapping = () => {\n const newMapping: Mapping = {\n key: `key_${Date.now()}`,\n value: '',\n }\n const newMappings = [...mappings, newMapping]\n setValue(newMappings)\n\n // Auto-expand the newly added mapping\n const newExpanded = new Set(expandedIndices)\n newExpanded.add(mappings.length)\n setExpandedIndices(newExpanded)\n }\n\n const removeMapping = async (index: number) => {\n const confirmed = await confirm({\n title: t('workflows.fieldEditors.mappings.removeMapping'),\n text: t('workflows.fieldEditors.mappings.confirmRemove'),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n const newMappings = mappings.filter((_, i) => i !== index)\n setValue(newMappings)\n\n // Remove from expanded set\n const newExpanded = new Set(expandedIndices)\n newExpanded.delete(index)\n setExpandedIndices(newExpanded)\n }\n\n const updateMapping = (index: number, field: keyof Mapping, fieldValue: string) => {\n const updated = [...mappings]\n updated[index] = { ...updated[index], [field]: fieldValue }\n setValue(updated)\n }\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <Label className=\"text-sm font-semibold\">{label} ({mappings.length})</Label>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {description}\n </p>\n {error && <p className=\"text-xs text-red-600 mt-1\">{error}</p>}\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={addMapping}\n disabled={disabled}\n className=\"w-full sm:w-auto\"\n >\n <Plus className=\"size-3 mr-1\" />\n {t('workflows.fieldEditors.mappings.addMapping')}\n </Button>\n </div>\n\n {mappings.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-muted-foreground bg-muted rounded-lg border\">\n {t('workflows.fieldEditors.mappings.emptyState')}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {mappings.map((mapping, index) => {\n const isExpanded = expandedIndices.has(index)\n return (\n <div key={index} className=\"border border-gray-200 rounded-lg bg-gray-50\">\n {/* Collapsed Header */}\n <button\n type=\"button\"\n onClick={() => toggleExpanded(index)}\n disabled={disabled}\n className=\"w-full px-4 py-3 text-left flex items-center justify-between hover:bg-gray-100 transition-colors rounded-t-lg disabled:opacity-50\"\n >\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-semibold text-gray-900\">\n {mapping.key || `Mapping ${index + 1}`}\n </span>\n </div>\n <p className=\"text-xs text-gray-600 mt-1 font-mono truncate\">\n {mapping.value ? (\n <>\n <span className=\"text-gray-400\">=</span> {mapping.value}\n </>\n ) : (\n <span className=\"text-gray-400 italic\">{t('workflows.common.noValueSet')}</span>\n )}\n </p>\n </div>\n <ChevronDown\n className={`w-5 h-5 text-gray-400 transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n />\n </button>\n\n {/* Expanded Content */}\n {isExpanded && (\n <div className=\"px-4 pb-4 space-y-3 border-t border-gray-200 bg-white\">\n {/* Key Field */}\n <div className=\"pt-3\">\n <Label htmlFor={`${id}-${index}-key`} className=\"text-xs font-medium mb-1\">\n {t('workflows.fieldEditors.mappings.key')} *\n </Label>\n <Input\n id={`${id}-${index}-key`}\n type=\"text\"\n value={mapping.key}\n onChange={(e) => updateMapping(index, 'key', e.target.value)}\n placeholder={t('workflows.fieldEditors.mappings.keyPlaceholder')}\n className=\"text-xs\"\n disabled={disabled}\n />\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {t('workflows.fieldEditors.mappings.keyHint')}\n </p>\n </div>\n\n {/* Value Field */}\n <div>\n <Label htmlFor={`${id}-${index}-value`} className=\"text-xs font-medium mb-1\">\n {t('workflows.fieldEditors.mappings.value')} *\n </Label>\n <Input\n id={`${id}-${index}-value`}\n type=\"text\"\n value={mapping.value}\n onChange={(e) => updateMapping(index, 'value', e.target.value)}\n placeholder={t('workflows.fieldEditors.mappings.valuePlaceholder')}\n className=\"text-xs font-mono\"\n disabled={disabled}\n />\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {t('workflows.fieldEditors.mappings.valueHint')}\n </p>\n </div>\n\n {/* Delete Button */}\n <div className=\"border-t border-gray-200 pt-3\">\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => removeMapping(index)}\n disabled={disabled}\n >\n <Trash2 className=\"size-4 mr-1\" />\n {t('workflows.fieldEditors.mappings.removeMapping')}\n </Button>\n </div>\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport { useState } from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { ChevronDown, Plus, Trash2 } from 'lucide-react'\nimport type { CrudCustomFieldRenderProps } from '@open-mercato/ui/backend/CrudForm'\n\n/**\n * Mapping definition structure for SubWorkflow input/output\n */\nexport interface Mapping {\n key: string\n value: string\n}\n\ninterface MappingArrayEditorProps extends CrudCustomFieldRenderProps {\n value: Mapping[]\n label?: string\n description?: string\n}\n\n/**\n * MappingArrayEditor - Custom field component for managing SubWorkflow input/output mappings\n *\n * Provides an interface to add, edit, and remove key-value pair mappings.\n * Each value is a plain dot-path into the source context (e.g. `order.id` or\n * `items.0.sku`), NOT a {{ }} template \u2014 the SUB_WORKFLOW mapping resolver walks\n * the path directly and ignores template expressions. For an inputMapping the\n * key is the child context key and the value is the parent path; for an\n * outputMapping the key is the parent context key and the value is the child path.\n *\n * Used by NodeEditDialog (SubWorkflow type only)\n */\nexport function MappingArrayEditor({\n id,\n value = [],\n error,\n setValue,\n disabled,\n label: labelProp,\n description: descriptionProp,\n}: MappingArrayEditorProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const label = labelProp ?? t('workflows.fieldEditors.mappings.label')\n const description = descriptionProp ?? t('workflows.fieldEditors.mappings.description')\n const [expandedIndices, setExpandedIndices] = useState<Set<number>>(new Set())\n\n const mappings = Array.isArray(value) ? value : []\n\n const toggleExpanded = (index: number) => {\n const newExpanded = new Set(expandedIndices)\n if (newExpanded.has(index)) {\n newExpanded.delete(index)\n } else {\n newExpanded.add(index)\n }\n setExpandedIndices(newExpanded)\n }\n\n const addMapping = () => {\n const newMapping: Mapping = {\n key: `key_${Date.now()}`,\n value: '',\n }\n const newMappings = [...mappings, newMapping]\n setValue(newMappings)\n\n // Auto-expand the newly added mapping\n const newExpanded = new Set(expandedIndices)\n newExpanded.add(mappings.length)\n setExpandedIndices(newExpanded)\n }\n\n const removeMapping = async (index: number) => {\n const confirmed = await confirm({\n title: t('workflows.fieldEditors.mappings.removeMapping'),\n text: t('workflows.fieldEditors.mappings.confirmRemove'),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n const newMappings = mappings.filter((_, i) => i !== index)\n setValue(newMappings)\n\n // Remove from expanded set\n const newExpanded = new Set(expandedIndices)\n newExpanded.delete(index)\n setExpandedIndices(newExpanded)\n }\n\n const updateMapping = (index: number, field: keyof Mapping, fieldValue: string) => {\n const updated = [...mappings]\n updated[index] = { ...updated[index], [field]: fieldValue }\n setValue(updated)\n }\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <Label className=\"text-sm font-semibold\">{label} ({mappings.length})</Label>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {description}\n </p>\n {error && <p className=\"text-xs text-red-600 mt-1\">{error}</p>}\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={addMapping}\n disabled={disabled}\n className=\"w-full sm:w-auto\"\n >\n <Plus className=\"size-3 mr-1\" />\n {t('workflows.fieldEditors.mappings.addMapping')}\n </Button>\n </div>\n\n {mappings.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-muted-foreground bg-muted rounded-lg border\">\n {t('workflows.fieldEditors.mappings.emptyState')}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {mappings.map((mapping, index) => {\n const isExpanded = expandedIndices.has(index)\n return (\n <div key={index} className=\"border border-gray-200 rounded-lg bg-gray-50\">\n {/* Collapsed Header */}\n <button\n type=\"button\"\n onClick={() => toggleExpanded(index)}\n disabled={disabled}\n className=\"w-full px-4 py-3 text-left flex items-center justify-between hover:bg-gray-100 transition-colors rounded-t-lg disabled:opacity-50\"\n >\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-semibold text-gray-900\">\n {mapping.key || `Mapping ${index + 1}`}\n </span>\n </div>\n <p className=\"text-xs text-gray-600 mt-1 font-mono truncate\">\n {mapping.value ? (\n <>\n <span className=\"text-gray-400\">=</span> {mapping.value}\n </>\n ) : (\n <span className=\"text-gray-400 italic\">{t('workflows.common.noValueSet')}</span>\n )}\n </p>\n </div>\n <ChevronDown\n className={`w-5 h-5 text-gray-400 transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n />\n </button>\n\n {/* Expanded Content */}\n {isExpanded && (\n <div className=\"px-4 pb-4 space-y-3 border-t border-gray-200 bg-white\">\n {/* Key Field */}\n <div className=\"pt-3\">\n <Label htmlFor={`${id}-${index}-key`} className=\"text-xs font-medium mb-1\">\n {t('workflows.fieldEditors.mappings.key')} *\n </Label>\n <Input\n id={`${id}-${index}-key`}\n type=\"text\"\n value={mapping.key}\n onChange={(e) => updateMapping(index, 'key', e.target.value)}\n placeholder={t('workflows.fieldEditors.mappings.keyPlaceholder')}\n className=\"text-xs\"\n disabled={disabled}\n />\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {t('workflows.fieldEditors.mappings.keyHint')}\n </p>\n </div>\n\n {/* Value Field */}\n <div>\n <Label htmlFor={`${id}-${index}-value`} className=\"text-xs font-medium mb-1\">\n {t('workflows.fieldEditors.mappings.value')} *\n </Label>\n <Input\n id={`${id}-${index}-value`}\n type=\"text\"\n value={mapping.value}\n onChange={(e) => updateMapping(index, 'value', e.target.value)}\n placeholder={t('workflows.fieldEditors.mappings.valuePlaceholder')}\n className=\"text-xs font-mono\"\n disabled={disabled}\n />\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {t('workflows.fieldEditors.mappings.valueHint')}\n </p>\n </div>\n\n {/* Delete Button */}\n <div className=\"border-t border-gray-200 pt-3\">\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => removeMapping(index)}\n disabled={disabled}\n >\n <Trash2 className=\"size-4 mr-1\" />\n {t('workflows.fieldEditors.mappings.removeMapping')}\n </Button>\n </div>\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -642,9 +642,17 @@ function setNestedValue(obj, path, value) {
642
642
  }, obj);
643
643
  target[lastKey] = value;
644
644
  }
645
+ function warnOnTemplateMapping(sourcePath, direction) {
646
+ if (/\{\{.*\}\}/.test(sourcePath)) {
647
+ console.warn(
648
+ `[workflows] SUB_WORKFLOW ${direction} mapping value "${sourcePath}" looks like a {{ }} template, but mapping values are plain dot-paths into the source context (e.g. "order.id"). This entry will not resolve and is being ignored.`
649
+ );
650
+ }
651
+ }
645
652
  function mapInputData(sourceContext, mapping) {
646
653
  const result = {};
647
654
  for (const [targetKey, sourcePath] of Object.entries(mapping)) {
655
+ warnOnTemplateMapping(sourcePath, "input");
648
656
  const value = getNestedValue(sourceContext, sourcePath);
649
657
  if (value !== void 0) {
650
658
  setNestedValue(result, targetKey, value);
@@ -655,6 +663,7 @@ function mapInputData(sourceContext, mapping) {
655
663
  function mapOutputData(childContext, mapping) {
656
664
  const result = {};
657
665
  for (const [targetKey, sourcePath] of Object.entries(mapping)) {
666
+ warnOnTemplateMapping(sourcePath, "output");
658
667
  const value = getNestedValue(childContext, sourcePath);
659
668
  if (value !== void 0) {
660
669
  setNestedValue(result, targetKey, value);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/step-handler.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module - Step Handler Service\n *\n * Handles individual workflow step execution:\n * - Creating step instances when entering a step\n * - Executing step logic based on step type (START, END, AUTOMATED, USER_TASK)\n * - Completing step instances when exiting\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport {\n WorkflowInstance,\n WorkflowBranchInstance,\n WorkflowDefinition,\n StepInstance,\n UserTask,\n WorkflowEvent,\n type StepInstanceStatus,\n type WorkflowStepType,\n} from '../data/entities'\nimport { parseDuration } from './duration'\nimport { logWorkflowEvent } from './event-logger'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StepExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface StepExecutionResult {\n status: 'COMPLETED' | 'WAITING' | 'FAILED'\n outputData?: any\n nextSteps?: string[] // For parallel forks (Phase 7)\n waitReason?: 'USER_TASK' | 'SIGNAL' | 'TIMER' | 'FORK'\n error?: string\n}\n\nexport class StepExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'StepExecutionError'\n }\n}\n\n// ============================================================================\n// Main Step Execution Functions\n// ============================================================================\n\n/**\n * Enter a workflow step - create step instance and mark as ACTIVE\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to enter\n * @param context - Execution context\n * @returns Created step instance\n */\nexport async function enterStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepInstance> {\n // Load workflow definition to get step details\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find step in definition\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found in workflow definition: ${stepId}`,\n 'STEP_NOT_FOUND',\n { workflowId: definition.workflowId, stepId }\n )\n }\n\n const now = new Date()\n\n // Create step instance\n const stepInstance = em.create(StepInstance, {\n workflowInstanceId: instance.id,\n branchInstanceId: branch ? branch.id : null,\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n status: 'ACTIVE',\n inputData: context.triggerData || null,\n enteredAt: now,\n retryCount: 0,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(stepInstance).flush()\n\n // Log STEP_ENTERED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return stepInstance\n}\n\n/**\n * Exit a workflow step - mark as completed and record timing\n *\n * @param em - Entity manager\n * @param stepInstance - Step instance to exit\n * @param outputData - Optional output data from step execution\n */\nexport async function exitStep(\n em: EntityManager,\n stepInstance: StepInstance,\n outputData?: any\n): Promise<void> {\n const now = new Date()\n\n // Calculate execution time if we have enteredAt\n let executionTimeMs: number | null = null\n if (stepInstance.enteredAt) {\n executionTimeMs = now.getTime() - stepInstance.enteredAt.getTime()\n }\n\n // Update step instance\n stepInstance.status = 'COMPLETED'\n stepInstance.outputData = outputData || null\n stepInstance.exitedAt = now\n stepInstance.executionTimeMs = executionTimeMs\n stepInstance.updatedAt = now\n\n await em.flush()\n\n // Log STEP_EXITED event\n await logStepEvent(em, {\n workflowInstanceId: stepInstance.workflowInstanceId,\n stepInstanceId: stepInstance.id,\n eventType: 'STEP_EXITED',\n eventData: {\n stepId: stepInstance.stepId,\n status: 'COMPLETED',\n executionTimeMs,\n hasOutput: !!outputData,\n },\n tenantId: stepInstance.tenantId,\n organizationId: stepInstance.organizationId,\n })\n}\n\n/**\n * Execute a workflow step based on its type\n *\n * Main entry point for step execution. Handles:\n * - START: Immediate completion\n * - END: Workflow completion\n * - AUTOMATED: Activity execution (MVP: immediate completion)\n * - USER_TASK: Create user task and wait\n * - SUB_WORKFLOW: Invoke child workflow\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to execute\n * @param context - Execution context\n * @param container - DI container (required for SUB_WORKFLOW steps)\n * @returns Execution result with status and output\n */\nexport async function executeStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n try {\n // Enter the step (create step instance)\n const stepInstance = await enterStep(em, instance, stepId, context, branch)\n\n // Load workflow definition to get step configuration\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found: ${stepId}`,\n 'STEP_NOT_FOUND',\n { stepId }\n )\n }\n\n // Execute based on step type\n const result = await executeStepByType(\n em,\n instance,\n stepInstance,\n stepDef,\n context,\n container,\n branch\n )\n\n // If step completed, exit it\n if (result.status === 'COMPLETED') {\n await exitStep(em, stepInstance, result.outputData)\n }\n\n return result\n } catch (error) {\n // Handle step execution errors\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n // Try to mark step as failed if we have a step instance\n try {\n const failedStepInstance = await em.findOne(StepInstance, {\n workflowInstanceId: instance.id,\n stepId,\n status: 'ACTIVE',\n })\n\n if (failedStepInstance) {\n failedStepInstance.status = 'FAILED'\n failedStepInstance.errorData = {\n error: errorMessage,\n details: error instanceof StepExecutionError ? error.details : undefined,\n }\n failedStepInstance.exitedAt = new Date()\n failedStepInstance.updatedAt = new Date()\n await em.flush()\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: failedStepInstance.id,\n eventType: 'STEP_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n // Swallow update errors to preserve original error\n console.error('Failed to update step instance with error:', updateError)\n }\n\n return {\n status: 'FAILED',\n error: errorMessage,\n }\n }\n}\n\n// ============================================================================\n// Step Type Handlers\n// ============================================================================\n\n/**\n * Execute step based on its type\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepInstance - Step instance\n * @param stepDef - Step definition from workflow\n * @param context - Execution context\n * @returns Execution result\n */\nasync function executeStepByType(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const stepType: WorkflowStepType = stepDef.stepType\n\n switch (stepType) {\n case 'START':\n return handleStartStep(stepDef, context)\n\n case 'END':\n return handleEndStep(stepDef, context)\n\n case 'AUTOMATED':\n return await handleAutomatedStep(em, instance, stepInstance, stepDef, context, container, branch)\n\n case 'USER_TASK':\n return await handleUserTaskStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'SUB_WORKFLOW':\n if (!container) {\n throw new StepExecutionError(\n 'Container required for SUB_WORKFLOW execution',\n 'CONTAINER_REQUIRED',\n { stepType }\n )\n }\n return await handleSubWorkflowStep(em, container, instance, stepInstance, stepDef, context)\n\n case 'WAIT_FOR_SIGNAL':\n return await handleWaitForSignalStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'WAIT_FOR_TIMER':\n return await handleWaitForTimerStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'PARALLEL_FORK': {\n // Entering a fork opens branch tokens and parks the root token in the\n // FORKED state; the interleaved loop in the executor drives the branches.\n if (branch) {\n // Nested forks are rejected by definition validation; fail closed.\n throw new StepExecutionError(\n 'Nested PARALLEL_FORK is not supported',\n 'NESTED_FORK_NOT_SUPPORTED',\n { stepType, stepId: stepDef.stepId }\n )\n }\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n const { openFork } = await import('./parallel-handler')\n await openFork(em, instance, definition, stepDef)\n return { status: 'WAITING', waitReason: 'FORK', outputData: { stepType: 'PARALLEL_FORK', forkStepId: stepDef.stepId } }\n }\n\n case 'PARALLEL_JOIN':\n // The join is a synchronization point handled by the parallel loop\n // (branches are marked COMPLETED on arrival; the loop fires the join).\n // Executing the step itself is a no-op.\n return { status: 'COMPLETED', outputData: { stepType: 'PARALLEL_JOIN', timestamp: new Date().toISOString() } }\n\n default:\n throw new StepExecutionError(\n `Unknown step type: ${stepType}`,\n 'UNKNOWN_STEP_TYPE',\n { stepType }\n )\n }\n}\n\n/**\n * Handle START step - no-op, immediately complete\n */\nfunction handleStartStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'START',\n timestamp: new Date().toISOString(),\n },\n }\n}\n\n/**\n * Handle END step - mark as complete\n */\nfunction handleEndStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'END',\n timestamp: new Date().toISOString(),\n finalContext: context.workflowContext,\n },\n }\n}\n\n/**\n * Handle AUTOMATED step - execute activities\n *\n * Executes activities defined in step configuration.\n * Supports both sync and async activities.\n */\nasync function handleAutomatedStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n // Extract activities from step definition\n const activities = stepDef.activities || []\n\n if (activities.length === 0) {\n // No activities defined - immediate completion (legacy behavior)\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n },\n }\n }\n\n // Import activity executor\n const { executeActivities } = await import('./activity-executor')\n\n try {\n // Execute activities with proper context\n const results = await executeActivities(em, container, activities, {\n workflowInstance: instance,\n workflowContext: context.workflowContext,\n stepContext: { stepId: stepDef.stepId, stepName: stepDef.stepName },\n stepInstanceId: stepInstance.id,\n userId: context.userId,\n })\n\n // Check if there are pending async activities\n const pendingActivities = results.filter(r => r.async && !r.success)\n if (pendingActivities.length > 0) {\n // Workflow should pause and wait for async activities\n const now = new Date()\n if (branch) {\n branch.status = 'WAITING_FOR_ACTIVITIES'\n branch.updatedAt = now\n } else {\n instance.status = 'WAITING_FOR_ACTIVITIES'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL', // Reuse SIGNAL wait reason (will be resumed by activity completion)\n outputData: {\n pendingActivities: pendingActivities.map(r => ({\n activityId: r.activityId,\n activityName: r.activityName,\n jobId: r.jobId,\n })),\n },\n }\n }\n\n // Check for failures in sync activities\n const failures = results.filter(r => !r.success && !r.async)\n if (failures.length > 0) {\n const errorMessages = failures.map(f => `${f.activityName || f.activityId}: ${f.error}`).join('; ')\n return {\n status: 'FAILED',\n error: `${failures.length} activity(ies) failed: ${errorMessages}`,\n outputData: {\n failures: failures.map(f => ({\n activityId: f.activityId,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n },\n }\n }\n\n // All activities completed successfully\n const activityOutputs = results.reduce((acc, r) => {\n if (r.output) {\n acc[r.activityId] = r.output\n }\n return acc\n }, {} as Record<string, any>)\n\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n activityResults: activityOutputs,\n activityCount: results.length,\n },\n }\n } catch (error: any) {\n return {\n status: 'FAILED',\n error: `Activity execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle USER_TASK step - create user task and enter waiting state\n *\n * Creates a UserTask entity and returns WAITING status.\n * The workflow will pause until the task is completed by a user.\n */\nasync function handleUserTaskStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const userTaskConfig = stepDef.userTaskConfig || {}\n\n // Handle assignedTo - if it's an array, treat it as roles\n let assignedTo = userTaskConfig.assignedTo || null\n let assignedToRoles = userTaskConfig.assignedToRoles || null\n\n if (Array.isArray(assignedTo)) {\n assignedToRoles = assignedTo\n assignedTo = null\n }\n\n // Create user task\n const now = new Date()\n const userTask = em.create(UserTask, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n branchInstanceId: branch ? branch.id : null,\n taskName: stepDef.stepName,\n description: stepDef.description || null,\n status: 'PENDING',\n formSchema: userTaskConfig.formSchema || null,\n formData: null,\n assignedTo: assignedTo,\n assignedToRoles: assignedToRoles,\n dueDate: userTaskConfig.slaDuration ? calculateDueDate(userTaskConfig.slaDuration) : null,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(userTask).flush()\n\n // Log USER_TASK_CREATED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'USER_TASK_CREATED',\n eventData: {\n userTaskId: userTask.id,\n taskName: userTask.taskName,\n assignedTo: userTask.assignedTo,\n assignedToRoles: userTask.assignedToRoles,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause execution - waits for user task completion. For a branch, only the\n // branch pauses; sibling branches keep running.\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'USER_TASK',\n outputData: {\n userTaskId: userTask.id,\n },\n }\n}\n\n/**\n * Handle SUB_WORKFLOW step - invoke another workflow and wait for completion\n *\n * Creates a child workflow instance with mapped input data,\n * executes it synchronously, and returns mapped output data.\n */\nasync function handleSubWorkflowStep(\n em: EntityManager,\n container: any,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const { subWorkflowId, inputMapping, outputMapping, version } = stepDef.config || {}\n\n if (!subWorkflowId) {\n return {\n status: 'FAILED',\n error: 'Sub-workflow ID not specified in step configuration'\n }\n }\n\n // Map input data from parent context to child context\n const childContext = mapInputData(instance.context, inputMapping || {})\n\n // Import workflow executor functions\n const { startWorkflow, executeWorkflow } = await import('./workflow-executor')\n\n try {\n // Start child workflow with parent metadata\n const childInstance = await startWorkflow(em, {\n workflowId: subWorkflowId,\n version,\n initialContext: childContext,\n correlationKey: instance.correlationKey || undefined,\n metadata: {\n ...instance.metadata,\n labels: {\n ...instance.metadata?.labels,\n parentInstanceId: instance.id,\n parentStepId: stepDef.stepId,\n parentStepInstanceId: stepInstance.id,\n },\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Log sub-workflow invocation event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_STARTED',\n eventData: {\n childInstanceId: childInstance.id,\n subWorkflowId,\n version,\n inputData: childContext,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Execute child workflow synchronously\n const result = await executeWorkflow(em, container, childInstance.id, {\n userId: context.userId,\n })\n\n // Handle child workflow result\n if (result.status === 'COMPLETED') {\n // Map output data from child context to parent context\n const outputData = mapOutputData(result.context, outputMapping || {})\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_COMPLETED',\n eventData: {\n childInstanceId: childInstance.id,\n outputData,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'COMPLETED',\n outputData,\n }\n } else if (result.status === 'FAILED') {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n childInstanceId: childInstance.id,\n error: result.errors?.join(', '),\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow failed: ${result.errors?.join(', ')}`,\n }\n } else {\n // WAITING, PAUSED, etc. - For synchronous execution, treat as error\n return {\n status: 'FAILED',\n error: `Sub-workflow ended in unexpected state: ${result.status}`,\n }\n }\n } catch (error: any) {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n subWorkflowId,\n error: error.message,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle WAIT_FOR_SIGNAL step - pause workflow until signal received\n *\n * Creates a waiting state and pauses the workflow until an external signal\n * with the matching signal name is received. The signal payload will be merged\n * into the workflow context when received.\n */\nasync function handleWaitForSignalStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const signalConfig = stepDef.signalConfig || {}\n const signalName = signalConfig.signalName || stepDef.stepId\n const timeout = signalConfig.timeout ? parseDuration(signalConfig.timeout) : null\n\n const now = new Date()\n\n // Log signal awaiting event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'SIGNAL_AWAITING',\n eventData: {\n signalName,\n timeout,\n description: stepDef.description,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause execution (branch-scoped when running inside a parallel branch)\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n // Return WAITING status to halt executor\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL',\n outputData: {\n signalName,\n timeout,\n awaitingSince: now,\n },\n }\n}\n\n/**\n * Handle WAIT_FOR_TIMER step - pause workflow until a timer fires.\n *\n * Reads `duration` (relative, e.g. \"PT5M\") or `until` (ISO 8601 datetime) from\n * `stepDef.config` (preferred \u2014 matches StepsEditor) or `stepDef.timerConfig`.\n * Enqueues a delayed timer job on the workflow-activities queue; when the job\n * is processed by the activity worker, it calls `timerHandler.fireTimer` to\n * resume the workflow.\n */\nasync function handleWaitForTimerStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const timerConfig = stepDef.config || stepDef.timerConfig || {}\n const duration: string | undefined = timerConfig.duration\n const until: string | undefined = timerConfig.until\n\n if (!duration && !until) {\n throw new StepExecutionError(\n 'WAIT_FOR_TIMER requires either \"duration\" (e.g., \"PT5M\") or \"until\" (ISO 8601 datetime)',\n 'TIMER_CONFIG_MISSING',\n { stepId: stepDef.stepId }\n )\n }\n\n let fireAtMs: number\n if (until) {\n const targetDate = new Date(until)\n if (isNaN(targetDate.getTime())) {\n throw new StepExecutionError(\n `WAIT_FOR_TIMER invalid \"until\" datetime: ${until}`,\n 'TIMER_CONFIG_INVALID',\n { until }\n )\n }\n fireAtMs = targetDate.getTime()\n } else {\n fireAtMs = Date.now() + parseDuration(duration as string)\n }\n\n const delayMs = fireAtMs - Date.now()\n const fireAt = new Date(fireAtMs)\n\n // Immediate-fire path: skip the queue round-trip if the timer is in the past\n if (delayMs <= 0) {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'WAIT_FOR_TIMER',\n timerFiredImmediately: true,\n fireAt,\n duration,\n until,\n },\n }\n }\n\n const now = new Date()\n\n // Enqueue delayed timer job via the shared activity queue.\n // Imported here to avoid a top-level cycle between step-handler and activity-executor.\n const { enqueueTimerJob } = await import('./activity-executor')\n const jobId = await enqueueTimerJob({\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n branchInstanceId: branch ? branch.id : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n userId: context.userId,\n fireAt: fireAt.toISOString(),\n delayMs,\n })\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'TIMER_AWAITING',\n eventData: {\n fireAt: fireAt.toISOString(),\n duration: duration || null,\n until: until || null,\n jobId,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'TIMER',\n outputData: {\n fireAt,\n duration,\n until,\n jobId,\n },\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n// parseDuration is imported from ./duration\n\n/**\n * Log step-related event to event sourcing table\n */\nasync function logStepEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Calculate due date from ISO 8601 duration string\n *\n * @param duration - ISO 8601 duration (e.g., \"P1D\" for 1 day)\n * @returns Due date\n */\nfunction calculateDueDate(duration: string): Date {\n // Simple implementation for MVP\n // Supports: P1D (1 day), P1H (1 hour), P1W (1 week)\n const now = new Date()\n\n const daysMatch = duration.match(/P(\\d+)D/)\n if (daysMatch) {\n const days = parseInt(daysMatch[1], 10)\n return new Date(now.getTime() + days * 24 * 60 * 60 * 1000)\n }\n\n const hoursMatch = duration.match(/PT(\\d+)H/)\n if (hoursMatch) {\n const hours = parseInt(hoursMatch[1], 10)\n return new Date(now.getTime() + hours * 60 * 60 * 1000)\n }\n\n const weeksMatch = duration.match(/P(\\d+)W/)\n if (weeksMatch) {\n const weeks = parseInt(weeksMatch[1], 10)\n return new Date(now.getTime() + weeks * 7 * 24 * 60 * 60 * 1000)\n }\n\n // Default: 1 day\n return new Date(now.getTime() + 24 * 60 * 60 * 1000)\n}\n\n/**\n * Get nested value from object using dot notation\n *\n * @param obj - Source object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @returns Value at path or undefined\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj)\n}\n\n/**\n * Set nested value in object using dot notation\n *\n * @param obj - Target object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @param value - Value to set\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.')\n const lastKey = keys.pop()!\n const target = keys.reduce((current, key) => {\n if (!(key in current)) current[key] = {}\n return current[key]\n }, obj)\n target[lastKey] = value\n}\n\n/**\n * Map data from source context using mapping configuration\n *\n * @param sourceContext - Source data object\n * @param mapping - Mapping configuration (targetKey -> sourcePath)\n * @returns Mapped data object\n */\nfunction mapInputData(\n sourceContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n const value = getNestedValue(sourceContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire context\n return Object.keys(result).length > 0 ? result : sourceContext\n}\n\n/**\n * Map output data from child context back to parent\n *\n * @param childContext - Child workflow context\n * @param mapping - Mapping configuration (targetKey -> sourcePath)\n * @returns Mapped output data\n */\nfunction mapOutputData(\n childContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n const value = getNestedValue(childContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire child context\n return Object.keys(result).length > 0 ? result : childContext\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module - Step Handler Service\n *\n * Handles individual workflow step execution:\n * - Creating step instances when entering a step\n * - Executing step logic based on step type (START, END, AUTOMATED, USER_TASK)\n * - Completing step instances when exiting\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport {\n WorkflowInstance,\n WorkflowBranchInstance,\n WorkflowDefinition,\n StepInstance,\n UserTask,\n WorkflowEvent,\n type StepInstanceStatus,\n type WorkflowStepType,\n} from '../data/entities'\nimport { parseDuration } from './duration'\nimport { logWorkflowEvent } from './event-logger'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StepExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface StepExecutionResult {\n status: 'COMPLETED' | 'WAITING' | 'FAILED'\n outputData?: any\n nextSteps?: string[] // For parallel forks (Phase 7)\n waitReason?: 'USER_TASK' | 'SIGNAL' | 'TIMER' | 'FORK'\n error?: string\n}\n\nexport class StepExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'StepExecutionError'\n }\n}\n\n// ============================================================================\n// Main Step Execution Functions\n// ============================================================================\n\n/**\n * Enter a workflow step - create step instance and mark as ACTIVE\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to enter\n * @param context - Execution context\n * @returns Created step instance\n */\nexport async function enterStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepInstance> {\n // Load workflow definition to get step details\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find step in definition\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found in workflow definition: ${stepId}`,\n 'STEP_NOT_FOUND',\n { workflowId: definition.workflowId, stepId }\n )\n }\n\n const now = new Date()\n\n // Create step instance\n const stepInstance = em.create(StepInstance, {\n workflowInstanceId: instance.id,\n branchInstanceId: branch ? branch.id : null,\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n status: 'ACTIVE',\n inputData: context.triggerData || null,\n enteredAt: now,\n retryCount: 0,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(stepInstance).flush()\n\n // Log STEP_ENTERED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return stepInstance\n}\n\n/**\n * Exit a workflow step - mark as completed and record timing\n *\n * @param em - Entity manager\n * @param stepInstance - Step instance to exit\n * @param outputData - Optional output data from step execution\n */\nexport async function exitStep(\n em: EntityManager,\n stepInstance: StepInstance,\n outputData?: any\n): Promise<void> {\n const now = new Date()\n\n // Calculate execution time if we have enteredAt\n let executionTimeMs: number | null = null\n if (stepInstance.enteredAt) {\n executionTimeMs = now.getTime() - stepInstance.enteredAt.getTime()\n }\n\n // Update step instance\n stepInstance.status = 'COMPLETED'\n stepInstance.outputData = outputData || null\n stepInstance.exitedAt = now\n stepInstance.executionTimeMs = executionTimeMs\n stepInstance.updatedAt = now\n\n await em.flush()\n\n // Log STEP_EXITED event\n await logStepEvent(em, {\n workflowInstanceId: stepInstance.workflowInstanceId,\n stepInstanceId: stepInstance.id,\n eventType: 'STEP_EXITED',\n eventData: {\n stepId: stepInstance.stepId,\n status: 'COMPLETED',\n executionTimeMs,\n hasOutput: !!outputData,\n },\n tenantId: stepInstance.tenantId,\n organizationId: stepInstance.organizationId,\n })\n}\n\n/**\n * Execute a workflow step based on its type\n *\n * Main entry point for step execution. Handles:\n * - START: Immediate completion\n * - END: Workflow completion\n * - AUTOMATED: Activity execution (MVP: immediate completion)\n * - USER_TASK: Create user task and wait\n * - SUB_WORKFLOW: Invoke child workflow\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to execute\n * @param context - Execution context\n * @param container - DI container (required for SUB_WORKFLOW steps)\n * @returns Execution result with status and output\n */\nexport async function executeStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n try {\n // Enter the step (create step instance)\n const stepInstance = await enterStep(em, instance, stepId, context, branch)\n\n // Load workflow definition to get step configuration\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found: ${stepId}`,\n 'STEP_NOT_FOUND',\n { stepId }\n )\n }\n\n // Execute based on step type\n const result = await executeStepByType(\n em,\n instance,\n stepInstance,\n stepDef,\n context,\n container,\n branch\n )\n\n // If step completed, exit it\n if (result.status === 'COMPLETED') {\n await exitStep(em, stepInstance, result.outputData)\n }\n\n return result\n } catch (error) {\n // Handle step execution errors\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n // Try to mark step as failed if we have a step instance\n try {\n const failedStepInstance = await em.findOne(StepInstance, {\n workflowInstanceId: instance.id,\n stepId,\n status: 'ACTIVE',\n })\n\n if (failedStepInstance) {\n failedStepInstance.status = 'FAILED'\n failedStepInstance.errorData = {\n error: errorMessage,\n details: error instanceof StepExecutionError ? error.details : undefined,\n }\n failedStepInstance.exitedAt = new Date()\n failedStepInstance.updatedAt = new Date()\n await em.flush()\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: failedStepInstance.id,\n eventType: 'STEP_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n // Swallow update errors to preserve original error\n console.error('Failed to update step instance with error:', updateError)\n }\n\n return {\n status: 'FAILED',\n error: errorMessage,\n }\n }\n}\n\n// ============================================================================\n// Step Type Handlers\n// ============================================================================\n\n/**\n * Execute step based on its type\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepInstance - Step instance\n * @param stepDef - Step definition from workflow\n * @param context - Execution context\n * @returns Execution result\n */\nasync function executeStepByType(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const stepType: WorkflowStepType = stepDef.stepType\n\n switch (stepType) {\n case 'START':\n return handleStartStep(stepDef, context)\n\n case 'END':\n return handleEndStep(stepDef, context)\n\n case 'AUTOMATED':\n return await handleAutomatedStep(em, instance, stepInstance, stepDef, context, container, branch)\n\n case 'USER_TASK':\n return await handleUserTaskStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'SUB_WORKFLOW':\n if (!container) {\n throw new StepExecutionError(\n 'Container required for SUB_WORKFLOW execution',\n 'CONTAINER_REQUIRED',\n { stepType }\n )\n }\n return await handleSubWorkflowStep(em, container, instance, stepInstance, stepDef, context)\n\n case 'WAIT_FOR_SIGNAL':\n return await handleWaitForSignalStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'WAIT_FOR_TIMER':\n return await handleWaitForTimerStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'PARALLEL_FORK': {\n // Entering a fork opens branch tokens and parks the root token in the\n // FORKED state; the interleaved loop in the executor drives the branches.\n if (branch) {\n // Nested forks are rejected by definition validation; fail closed.\n throw new StepExecutionError(\n 'Nested PARALLEL_FORK is not supported',\n 'NESTED_FORK_NOT_SUPPORTED',\n { stepType, stepId: stepDef.stepId }\n )\n }\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n const { openFork } = await import('./parallel-handler')\n await openFork(em, instance, definition, stepDef)\n return { status: 'WAITING', waitReason: 'FORK', outputData: { stepType: 'PARALLEL_FORK', forkStepId: stepDef.stepId } }\n }\n\n case 'PARALLEL_JOIN':\n // The join is a synchronization point handled by the parallel loop\n // (branches are marked COMPLETED on arrival; the loop fires the join).\n // Executing the step itself is a no-op.\n return { status: 'COMPLETED', outputData: { stepType: 'PARALLEL_JOIN', timestamp: new Date().toISOString() } }\n\n default:\n throw new StepExecutionError(\n `Unknown step type: ${stepType}`,\n 'UNKNOWN_STEP_TYPE',\n { stepType }\n )\n }\n}\n\n/**\n * Handle START step - no-op, immediately complete\n */\nfunction handleStartStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'START',\n timestamp: new Date().toISOString(),\n },\n }\n}\n\n/**\n * Handle END step - mark as complete\n */\nfunction handleEndStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'END',\n timestamp: new Date().toISOString(),\n finalContext: context.workflowContext,\n },\n }\n}\n\n/**\n * Handle AUTOMATED step - execute activities\n *\n * Executes activities defined in step configuration.\n * Supports both sync and async activities.\n */\nasync function handleAutomatedStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n // Extract activities from step definition\n const activities = stepDef.activities || []\n\n if (activities.length === 0) {\n // No activities defined - immediate completion (legacy behavior)\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n },\n }\n }\n\n // Import activity executor\n const { executeActivities } = await import('./activity-executor')\n\n try {\n // Execute activities with proper context\n const results = await executeActivities(em, container, activities, {\n workflowInstance: instance,\n workflowContext: context.workflowContext,\n stepContext: { stepId: stepDef.stepId, stepName: stepDef.stepName },\n stepInstanceId: stepInstance.id,\n userId: context.userId,\n })\n\n // Check if there are pending async activities\n const pendingActivities = results.filter(r => r.async && !r.success)\n if (pendingActivities.length > 0) {\n // Workflow should pause and wait for async activities\n const now = new Date()\n if (branch) {\n branch.status = 'WAITING_FOR_ACTIVITIES'\n branch.updatedAt = now\n } else {\n instance.status = 'WAITING_FOR_ACTIVITIES'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL', // Reuse SIGNAL wait reason (will be resumed by activity completion)\n outputData: {\n pendingActivities: pendingActivities.map(r => ({\n activityId: r.activityId,\n activityName: r.activityName,\n jobId: r.jobId,\n })),\n },\n }\n }\n\n // Check for failures in sync activities\n const failures = results.filter(r => !r.success && !r.async)\n if (failures.length > 0) {\n const errorMessages = failures.map(f => `${f.activityName || f.activityId}: ${f.error}`).join('; ')\n return {\n status: 'FAILED',\n error: `${failures.length} activity(ies) failed: ${errorMessages}`,\n outputData: {\n failures: failures.map(f => ({\n activityId: f.activityId,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n },\n }\n }\n\n // All activities completed successfully\n const activityOutputs = results.reduce((acc, r) => {\n if (r.output) {\n acc[r.activityId] = r.output\n }\n return acc\n }, {} as Record<string, any>)\n\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n activityResults: activityOutputs,\n activityCount: results.length,\n },\n }\n } catch (error: any) {\n return {\n status: 'FAILED',\n error: `Activity execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle USER_TASK step - create user task and enter waiting state\n *\n * Creates a UserTask entity and returns WAITING status.\n * The workflow will pause until the task is completed by a user.\n */\nasync function handleUserTaskStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const userTaskConfig = stepDef.userTaskConfig || {}\n\n // Handle assignedTo - if it's an array, treat it as roles\n let assignedTo = userTaskConfig.assignedTo || null\n let assignedToRoles = userTaskConfig.assignedToRoles || null\n\n if (Array.isArray(assignedTo)) {\n assignedToRoles = assignedTo\n assignedTo = null\n }\n\n // Create user task\n const now = new Date()\n const userTask = em.create(UserTask, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n branchInstanceId: branch ? branch.id : null,\n taskName: stepDef.stepName,\n description: stepDef.description || null,\n status: 'PENDING',\n formSchema: userTaskConfig.formSchema || null,\n formData: null,\n assignedTo: assignedTo,\n assignedToRoles: assignedToRoles,\n dueDate: userTaskConfig.slaDuration ? calculateDueDate(userTaskConfig.slaDuration) : null,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(userTask).flush()\n\n // Log USER_TASK_CREATED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'USER_TASK_CREATED',\n eventData: {\n userTaskId: userTask.id,\n taskName: userTask.taskName,\n assignedTo: userTask.assignedTo,\n assignedToRoles: userTask.assignedToRoles,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause execution - waits for user task completion. For a branch, only the\n // branch pauses; sibling branches keep running.\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'USER_TASK',\n outputData: {\n userTaskId: userTask.id,\n },\n }\n}\n\n/**\n * Handle SUB_WORKFLOW step - invoke another workflow and wait for completion\n *\n * Creates a child workflow instance with mapped input data,\n * executes it synchronously, and returns mapped output data.\n */\nasync function handleSubWorkflowStep(\n em: EntityManager,\n container: any,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const { subWorkflowId, inputMapping, outputMapping, version } = stepDef.config || {}\n\n if (!subWorkflowId) {\n return {\n status: 'FAILED',\n error: 'Sub-workflow ID not specified in step configuration'\n }\n }\n\n // Map input data from parent context to child context\n const childContext = mapInputData(instance.context, inputMapping || {})\n\n // Import workflow executor functions\n const { startWorkflow, executeWorkflow } = await import('./workflow-executor')\n\n try {\n // Start child workflow with parent metadata\n const childInstance = await startWorkflow(em, {\n workflowId: subWorkflowId,\n version,\n initialContext: childContext,\n correlationKey: instance.correlationKey || undefined,\n metadata: {\n ...instance.metadata,\n labels: {\n ...instance.metadata?.labels,\n parentInstanceId: instance.id,\n parentStepId: stepDef.stepId,\n parentStepInstanceId: stepInstance.id,\n },\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Log sub-workflow invocation event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_STARTED',\n eventData: {\n childInstanceId: childInstance.id,\n subWorkflowId,\n version,\n inputData: childContext,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Execute child workflow synchronously\n const result = await executeWorkflow(em, container, childInstance.id, {\n userId: context.userId,\n })\n\n // Handle child workflow result\n if (result.status === 'COMPLETED') {\n // Map output data from child context to parent context\n const outputData = mapOutputData(result.context, outputMapping || {})\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_COMPLETED',\n eventData: {\n childInstanceId: childInstance.id,\n outputData,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'COMPLETED',\n outputData,\n }\n } else if (result.status === 'FAILED') {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n childInstanceId: childInstance.id,\n error: result.errors?.join(', '),\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow failed: ${result.errors?.join(', ')}`,\n }\n } else {\n // WAITING, PAUSED, etc. - For synchronous execution, treat as error\n return {\n status: 'FAILED',\n error: `Sub-workflow ended in unexpected state: ${result.status}`,\n }\n }\n } catch (error: any) {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n subWorkflowId,\n error: error.message,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle WAIT_FOR_SIGNAL step - pause workflow until signal received\n *\n * Creates a waiting state and pauses the workflow until an external signal\n * with the matching signal name is received. The signal payload will be merged\n * into the workflow context when received.\n */\nasync function handleWaitForSignalStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const signalConfig = stepDef.signalConfig || {}\n const signalName = signalConfig.signalName || stepDef.stepId\n const timeout = signalConfig.timeout ? parseDuration(signalConfig.timeout) : null\n\n const now = new Date()\n\n // Log signal awaiting event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'SIGNAL_AWAITING',\n eventData: {\n signalName,\n timeout,\n description: stepDef.description,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause execution (branch-scoped when running inside a parallel branch)\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n // Return WAITING status to halt executor\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL',\n outputData: {\n signalName,\n timeout,\n awaitingSince: now,\n },\n }\n}\n\n/**\n * Handle WAIT_FOR_TIMER step - pause workflow until a timer fires.\n *\n * Reads `duration` (relative, e.g. \"PT5M\") or `until` (ISO 8601 datetime) from\n * `stepDef.config` (preferred \u2014 matches StepsEditor) or `stepDef.timerConfig`.\n * Enqueues a delayed timer job on the workflow-activities queue; when the job\n * is processed by the activity worker, it calls `timerHandler.fireTimer` to\n * resume the workflow.\n */\nasync function handleWaitForTimerStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const timerConfig = stepDef.config || stepDef.timerConfig || {}\n const duration: string | undefined = timerConfig.duration\n const until: string | undefined = timerConfig.until\n\n if (!duration && !until) {\n throw new StepExecutionError(\n 'WAIT_FOR_TIMER requires either \"duration\" (e.g., \"PT5M\") or \"until\" (ISO 8601 datetime)',\n 'TIMER_CONFIG_MISSING',\n { stepId: stepDef.stepId }\n )\n }\n\n let fireAtMs: number\n if (until) {\n const targetDate = new Date(until)\n if (isNaN(targetDate.getTime())) {\n throw new StepExecutionError(\n `WAIT_FOR_TIMER invalid \"until\" datetime: ${until}`,\n 'TIMER_CONFIG_INVALID',\n { until }\n )\n }\n fireAtMs = targetDate.getTime()\n } else {\n fireAtMs = Date.now() + parseDuration(duration as string)\n }\n\n const delayMs = fireAtMs - Date.now()\n const fireAt = new Date(fireAtMs)\n\n // Immediate-fire path: skip the queue round-trip if the timer is in the past\n if (delayMs <= 0) {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'WAIT_FOR_TIMER',\n timerFiredImmediately: true,\n fireAt,\n duration,\n until,\n },\n }\n }\n\n const now = new Date()\n\n // Enqueue delayed timer job via the shared activity queue.\n // Imported here to avoid a top-level cycle between step-handler and activity-executor.\n const { enqueueTimerJob } = await import('./activity-executor')\n const jobId = await enqueueTimerJob({\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n branchInstanceId: branch ? branch.id : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n userId: context.userId,\n fireAt: fireAt.toISOString(),\n delayMs,\n })\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'TIMER_AWAITING',\n eventData: {\n fireAt: fireAt.toISOString(),\n duration: duration || null,\n until: until || null,\n jobId,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'TIMER',\n outputData: {\n fireAt,\n duration,\n until,\n jobId,\n },\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n// parseDuration is imported from ./duration\n\n/**\n * Log step-related event to event sourcing table\n */\nasync function logStepEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Calculate due date from ISO 8601 duration string\n *\n * @param duration - ISO 8601 duration (e.g., \"P1D\" for 1 day)\n * @returns Due date\n */\nfunction calculateDueDate(duration: string): Date {\n // Simple implementation for MVP\n // Supports: P1D (1 day), P1H (1 hour), P1W (1 week)\n const now = new Date()\n\n const daysMatch = duration.match(/P(\\d+)D/)\n if (daysMatch) {\n const days = parseInt(daysMatch[1], 10)\n return new Date(now.getTime() + days * 24 * 60 * 60 * 1000)\n }\n\n const hoursMatch = duration.match(/PT(\\d+)H/)\n if (hoursMatch) {\n const hours = parseInt(hoursMatch[1], 10)\n return new Date(now.getTime() + hours * 60 * 60 * 1000)\n }\n\n const weeksMatch = duration.match(/P(\\d+)W/)\n if (weeksMatch) {\n const weeks = parseInt(weeksMatch[1], 10)\n return new Date(now.getTime() + weeks * 7 * 24 * 60 * 60 * 1000)\n }\n\n // Default: 1 day\n return new Date(now.getTime() + 24 * 60 * 60 * 1000)\n}\n\n/**\n * Get nested value from object using dot notation\n *\n * @param obj - Source object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @returns Value at path or undefined\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj)\n}\n\n/**\n * Set nested value in object using dot notation\n *\n * @param obj - Target object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @param value - Value to set\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.')\n const lastKey = keys.pop()!\n const target = keys.reduce((current, key) => {\n if (!(key in current)) current[key] = {}\n return current[key]\n }, obj)\n target[lastKey] = value\n}\n\n/**\n * Warn (dev-time) when a SUB_WORKFLOW mapping value is written as a `{{ }}`\n * template. Mapping values are plain dot-paths into the source context \u2014 the\n * `{{ }}` form only works for activity config interpolation \u2014 so such entries\n * never resolve and are silently dropped. Surfacing a warning makes legacy\n * misconfigurations debuggable instead of invisible.\n */\nfunction warnOnTemplateMapping(sourcePath: string, direction: 'input' | 'output'): void {\n if (/\\{\\{.*\\}\\}/.test(sourcePath)) {\n console.warn(\n `[workflows] SUB_WORKFLOW ${direction} mapping value \"${sourcePath}\" looks like a {{ }} template, ` +\n 'but mapping values are plain dot-paths into the source context (e.g. \"order.id\"). ' +\n 'This entry will not resolve and is being ignored.'\n )\n }\n}\n\n/**\n * Map data from source context using mapping configuration\n *\n * @param sourceContext - Source data object\n * @param mapping - Mapping configuration (targetKey -> sourcePath, plain dot-path)\n * @returns Mapped data object\n */\nfunction mapInputData(\n sourceContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n warnOnTemplateMapping(sourcePath, 'input')\n const value = getNestedValue(sourceContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire context\n return Object.keys(result).length > 0 ? result : sourceContext\n}\n\n/**\n * Map output data from child context back to parent\n *\n * @param childContext - Child workflow context\n * @param mapping - Mapping configuration (targetKey -> sourcePath, plain dot-path)\n * @returns Mapped output data\n */\nfunction mapOutputData(\n childContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n warnOnTemplateMapping(sourcePath, 'output')\n const value = getNestedValue(childContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire child context\n return Object.keys(result).length > 0 ? result : childContext\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -335,6 +335,13 @@ async function executeTransitionForToken(em, container, token, fromStepId, toSte
335
335
  container,
336
336
  branch
337
337
  );
338
+ if (stepExecutionResult.status === "COMPLETED" && stepExecutionResult.outputData && typeof stepExecutionResult.outputData === "object") {
339
+ const completedStepType = await getStepType(em, instance, toStepId);
340
+ if (completedStepType === "SUB_WORKFLOW") {
341
+ mergeTokenContext(token, stepExecutionResult.outputData);
342
+ touchToken(token, /* @__PURE__ */ new Date());
343
+ }
344
+ }
338
345
  await em.flush();
339
346
  if (stepExecutionResult.status === "FAILED") {
340
347
  return {
@@ -623,6 +630,11 @@ async function evaluatePostConditions(em, instance, transition, context, eventBu
623
630
  };
624
631
  }
625
632
  }
633
+ async function getStepType(em, instance, stepId) {
634
+ const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId });
635
+ const stepDef = definition?.definition.steps.find((step) => step.stepId === stepId);
636
+ return stepDef?.stepType;
637
+ }
626
638
  async function logTransitionEvent(em, event) {
627
639
  const workflowEvent = em.create(WorkflowEvent, {
628
640
  ...event,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/transition-handler.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module - Transition Handler Service\n *\n * Handles workflow transitions between steps:\n * - Evaluating if a transition is valid (checking conditions)\n * - Executing transitions (moving from one step to another)\n * - Integrating with business rules engine for pre/post conditions\n * - Executing activities on transition\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport type { EventBus } from '@open-mercato/events'\nimport {\n WorkflowInstance,\n WorkflowDefinition,\n WorkflowEvent,\n} from '../data/entities'\nimport * as ruleEvaluator from '../../business_rules/lib/rule-evaluator'\nimport * as ruleEngine from '../../business_rules/lib/rule-engine'\nimport * as activityExecutor from './activity-executor'\nimport type { ActivityDefinition } from './activity-executor'\nimport * as stepHandler from './step-handler'\nimport {\n type ExecutionToken,\n rootToken,\n tokenBranchInstanceId,\n tokenReadContext,\n setTokenCurrentStepId,\n applyTokenContextWrites,\n mergeTokenContext,\n setTokenWaitingForActivities,\n setTokenPendingTransition,\n touchToken,\n} from './execution-token'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface TransitionEvaluationContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionEvaluationResult {\n isValid: boolean\n transition?: any\n reason?: string\n failedConditions?: string[]\n evaluationTime?: number\n}\n\nexport interface TransitionExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionExecutionResult {\n success: boolean\n nextStepId?: string\n pausedForActivities?: boolean\n conditionsEvaluated?: {\n preConditions: boolean\n postConditions: boolean\n }\n activitiesExecuted?: activityExecutor.ActivityExecutionResult[]\n error?: string\n}\n\nexport class TransitionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'TransitionError'\n }\n}\n\n// ============================================================================\n// Main Transition Functions\n// ============================================================================\n\n/**\n * Evaluate if a transition from current step to target step is valid\n *\n * Checks:\n * - Transition exists in workflow definition\n * - Pre-conditions pass (if any business rules defined)\n * - Transition condition evaluates to true (if specified)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID (optional - will auto-select if not provided)\n * @param context - Evaluation context\n * @returns Evaluation result with validity and reason\n */\nexport async function evaluateTransition(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string | undefined,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n const startTime = Date.now()\n\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n isValid: false,\n reason: `Workflow definition not found: ${instance.definitionId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Find transition\n const transitions = definition.definition.transitions || []\n let transition: any\n\n if (toStepId) {\n // Find specific transition\n transition = transitions.find(\n (t: any) => t.fromStepId === fromStepId && t.toStepId === toStepId\n )\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No transition found from ${fromStepId} to ${toStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n } else {\n // Auto-select first valid transition\n const availableTransitions = transitions.filter(\n (t: any) => t.fromStepId === fromStepId\n )\n\n if (availableTransitions.length === 0) {\n return {\n isValid: false,\n reason: `No transitions available from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Evaluate each transition to find first valid one\n for (const t of availableTransitions) {\n const result = await evaluateTransitionConditions(\n em,\n instance,\n t,\n context\n )\n\n if (result.isValid) {\n transition = t\n break\n }\n }\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No valid transitions found from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n }\n\n // Evaluate transition conditions (inline condition + business rules pre-conditions)\n const conditionResult = await evaluateTransitionConditions(\n em,\n instance,\n transition,\n context\n )\n\n return {\n ...conditionResult,\n transition,\n evaluationTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Transition evaluation error: ${errorMessage}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n}\n\n/**\n * Find all valid transitions from current step\n *\n * This function evaluates both inline conditions AND preConditions (business rules)\n * to determine which transitions are truly valid. This is important for decision\n * branching where multiple transitions exist with different preConditions.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param context - Evaluation context\n * @returns Array of evaluation results for all transitions, sorted by priority (desc)\n */\nexport async function findValidTransitions(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult[]> {\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return []\n }\n\n // Find all transitions from current step, sorted by priority (highest first)\n const transitions = (definition.definition.transitions || [])\n .filter((t: any) => t.fromStepId === fromStepId)\n .sort((a: any, b: any) => (b.priority || 0) - (a.priority || 0))\n\n // Evaluate each transition including preConditions\n const results: TransitionEvaluationResult[] = []\n\n for (const transition of transitions) {\n // First check inline condition\n const conditionResult = await evaluateTransition(\n em,\n instance,\n fromStepId,\n transition.toStepId,\n context\n )\n\n if (!conditionResult.isValid) {\n results.push(conditionResult)\n continue\n }\n\n // Also evaluate preConditions if they exist\n const preConditions = transition.preConditions || []\n if (preConditions.length > 0) {\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context as TransitionExecutionContext,\n null\n )\n\n if (!preConditionsResult.allowed) {\n // Transition is invalid due to preConditions\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => r.rule.ruleId || r.rule.ruleName)\n\n results.push({\n isValid: false,\n transition,\n reason: `Pre-conditions failed: ${failedRules.join(', ')}`,\n failedConditions: failedRules,\n })\n continue\n }\n }\n\n // Transition is valid (both condition and preConditions passed)\n results.push({\n ...conditionResult,\n transition,\n })\n }\n\n return results\n } catch (error) {\n console.error('Error finding valid transitions:', error)\n return []\n }\n}\n\n/**\n * Execute a transition from one step to another\n *\n * This is the main entry point for transition execution. It:\n * 1. Validates the transition\n * 2. Evaluates pre-conditions\n * 3. Executes activities (if any)\n * 4. Updates workflow instance state (atomically with activity outputs)\n * 5. Evaluates post-conditions\n * 6. Logs transition event\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution)\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID\n * @param context - Execution context\n * @returns Execution result\n */\nexport async function executeTransition(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string,\n context: TransitionExecutionContext\n): Promise<TransitionExecutionResult> {\n // Public DI signature preserved: the root token adapts the instance, so the\n // single-token path is behaviourally unchanged.\n return executeTransitionForToken(em, container, rootToken(instance), fromStepId, toStepId, context)\n}\n\n/**\n * Token-aware transition execution. The root token wraps a WorkflowInstance\n * (legacy single-token path); a branch token wraps a WorkflowBranchInstance so\n * a parallel branch advances independently with its own context namespace,\n * status and pending transition.\n */\nexport async function executeTransitionForToken(\n em: EntityManager,\n container: AwilixContainer,\n token: ExecutionToken,\n fromStepId: string,\n toStepId: string,\n context: TransitionExecutionContext\n): Promise<TransitionExecutionResult> {\n const instance = token.instance\n const branch = token.kind === 'branch' ? token.branch : null\n const branchInstanceId = tokenBranchInstanceId(token)\n try {\n let eventBus: Pick<EventBus, 'emitEvent'> | null = null\n try {\n eventBus = container.resolve('eventBus') as EventBus\n } catch {\n eventBus = null\n }\n\n // First, evaluate if transition is valid\n const evaluation = await evaluateTransition(\n em,\n instance,\n fromStepId,\n toStepId,\n context\n )\n\n if (!evaluation.isValid) {\n return {\n success: false,\n error: evaluation.reason || 'Transition validation failed',\n }\n }\n\n const transition = evaluation.transition!\n\n // Evaluate pre-conditions (business rules)\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!preConditionsResult.allowed) {\n // Build detailed failure information\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => ({\n ruleId: r.rule.ruleId,\n ruleName: r.rule.ruleName,\n error: r.error,\n }))\n\n const failedRulesDetails = failedRules.length > 0\n ? failedRules.map(r => `${r.ruleId}: ${r.error || 'condition failed'}`).join('; ')\n : preConditionsResult.errors?.join(', ') || 'Unknown pre-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_REJECTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Pre-conditions failed',\n failedRules: failedRulesDetails,\n failedRulesDetail: failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Pre-conditions failed: ${failedRulesDetails}`,\n conditionsEvaluated: {\n preConditions: false,\n postConditions: false,\n },\n }\n }\n\n // Execute activities (if any)\n let activityOutputs: Record<string, any> = {}\n const activityResults: activityExecutor.ActivityExecutionResult[] = []\n\n if (transition.activities && transition.activities.length > 0) {\n const activityContext: activityExecutor.ActivityContext = {\n workflowInstance: instance,\n workflowContext: {\n ...tokenReadContext(token),\n ...context.workflowContext,\n },\n branchInstanceId,\n userId: context.userId,\n }\n\n // Execute all activities\n const results = await activityExecutor.executeActivities(\n em,\n container,\n transition.activities as ActivityDefinition[],\n activityContext\n )\n\n activityResults.push(...results)\n\n // Check for failures\n const failedActivities = results.filter(r => !r.success)\n\n if (failedActivities.length > 0) {\n const continueOnFailure = transition.continueOnActivityFailure ?? false\n\n // Log activity failures\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ACTIVITY_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n failedActivities: failedActivities.map(f => ({\n activityType: f.activityType,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n continueOnFailure,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (!continueOnFailure) {\n return {\n success: false,\n error: `Activities failed: ${failedActivities.map(f => f.error).join(', ')}`,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false,\n },\n }\n }\n }\n\n // Collect activity outputs for context update\n results.forEach(result => {\n if (result.success && result.output) {\n const key = result.activityName || result.activityType\n activityOutputs[key] = result.output\n }\n })\n }\n\n // Check if any activities are async - if so, pause before executing step\n const hasAsyncActivities = activityResults.some(r => r.async)\n\n if (hasAsyncActivities) {\n const pendingJobIds = activityResults\n .filter(a => a.async && a.jobId)\n .map(a => ({ activityId: a.activityId, jobId: a.jobId }))\n\n // Store pending transition state (per-token: branch or instance)\n setTokenPendingTransition(token, {\n toStepId,\n activityResults,\n timestamp: new Date(),\n })\n\n // Store activity outputs + pending-activity tracking in the token's own\n // context scope (instance.context for root, branch namespace for a branch)\n applyTokenContextWrites(token, context.workflowContext, activityOutputs)\n mergeTokenContext(token, { _pendingAsyncActivities: pendingJobIds })\n\n // Set status to waiting (branch-scoped when running inside a branch)\n setTokenWaitingForActivities(token)\n touchToken(token, new Date())\n await em.flush()\n\n // Log event\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n branchInstanceId,\n eventType: 'TRANSITION_PAUSED_FOR_ACTIVITIES',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId,\n pendingActivities: pendingJobIds,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Return WITHOUT executing step\n return {\n success: true,\n pausedForActivities: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false, // Not evaluated yet\n },\n activitiesExecuted: activityResults,\n }\n }\n\n // Advance the token cursor and update context atomically (instance for the\n // root token; branch cursor + namespace for a branch token).\n setTokenCurrentStepId(token, toStepId)\n applyTokenContextWrites(token, context.workflowContext, activityOutputs)\n touchToken(token, new Date())\n\n await em.flush()\n\n // Execute the new step (this will create USER_TASK, handle END steps, etc.)\n const stepExecutionResult = await stepHandler.executeStep(\n em,\n instance,\n toStepId,\n {\n workflowContext: tokenReadContext(token),\n userId: context.userId,\n triggerData: context.triggerData,\n },\n container,\n branch\n )\n\n // Flush to database after step execution completes to make state visible to UI\n await em.flush()\n\n // Handle step execution failure\n if (stepExecutionResult.status === 'FAILED') {\n return {\n success: false,\n error: stepExecutionResult.error || 'Step execution failed',\n }\n }\n\n // Evaluate post-conditions (business rules)\n const postConditionsResult = await evaluatePostConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!postConditionsResult.allowed) {\n const failedRules = postConditionsResult.errors?.join(', ') || 'Unknown post-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_POST_CONDITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Post-conditions failed',\n failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Note: We don't roll back the transition on post-condition failure\n // Post-conditions are warnings, not blockers\n }\n\n // Log successful transition\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_EXECUTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n transitionName: transition.transitionName,\n preConditionsPassed: true,\n postConditionsPassed: postConditionsResult.allowed,\n activitiesExecuted: activityResults.length,\n activitiesSucceeded: activityResults.filter(r => r.success).length,\n activitiesFailed: activityResults.filter(r => !r.success).length,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: postConditionsResult.allowed,\n },\n activitiesExecuted: activityResults,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n error: errorMessage,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Transition execution failed: ${errorMessage}`,\n }\n }\n}\n\n// ============================================================================\n// Condition Evaluation\n// ============================================================================\n\n/**\n * Evaluate transition conditions (inline condition expression)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Evaluation context\n * @returns Evaluation result\n */\nasync function evaluateTransitionConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n try {\n // If no condition specified, transition is always valid\n if (!transition.condition) {\n return {\n isValid: true,\n }\n }\n\n // Build data context for rule evaluation\n const data = {\n ...instance.context,\n ...context.workflowContext,\n triggerData: context.triggerData,\n }\n\n // Build evaluation context\n const evalContext: ruleEvaluator.RuleEvaluationContext = {\n entityType: 'workflow:transition',\n entityId: instance.id,\n user: context.userId ? { id: context.userId } : undefined,\n }\n\n // Evaluate condition using expression evaluator\n const result = await ruleEvaluator.evaluateConditions(\n transition.condition,\n data,\n evalContext\n )\n\n return {\n isValid: result,\n reason: result ? undefined : 'Transition condition evaluated to false',\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Condition evaluation error: ${errorMessage}`,\n }\n }\n}\n\n/**\n * Evaluate pre-conditions using business rules engine\n *\n * Pre-conditions are GUARD rules that must pass before transition can execute.\n * If any GUARD rule fails, the transition is blocked.\n *\n * If the transition defines specific preConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, falls back to\n * discovery-based execution via executeRules.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePreConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific preConditions defined\n const preConditions = transition.preConditions || []\n\n // If no pre-conditions defined, allow transition\n if (preConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each pre-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of preConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'pre_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n // We don't have the full BusinessRule entity, but we can create a partial result\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n // Rule not found, disabled, or other errors\n const isRequired = condition.required !== false // Default to required\n if (isRequired) {\n allowed = false\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n }\n continue\n }\n\n // If required and condition failed, block transition\n const isRequired = condition.required !== false // Default to required\n if (isRequired && !result.conditionResult) {\n allowed = false\n errors.push(`Pre-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating pre-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n/**\n * Evaluate post-conditions using business rules engine\n *\n * Post-conditions are GUARD rules that should pass after transition executes.\n * Unlike pre-conditions, post-condition failures are logged but don't block the transition.\n *\n * If the transition defines specific postConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, returns allowed: true.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePostConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific postConditions defined\n const postConditions = transition.postConditions || []\n\n // If no post-conditions defined, allow\n if (postConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each post-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of postConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'post_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n // Post-conditions don't block, but track the failure\n allowed = false\n continue\n }\n\n // Track condition failures (post-conditions are warnings, not blockers)\n if (!result.conditionResult) {\n allowed = false\n errors.push(`Post-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating post-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log transition-related event to event sourcing table\n */\nasync function logTransitionEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module - Transition Handler Service\n *\n * Handles workflow transitions between steps:\n * - Evaluating if a transition is valid (checking conditions)\n * - Executing transitions (moving from one step to another)\n * - Integrating with business rules engine for pre/post conditions\n * - Executing activities on transition\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport type { EventBus } from '@open-mercato/events'\nimport {\n WorkflowInstance,\n WorkflowDefinition,\n WorkflowEvent,\n} from '../data/entities'\nimport * as ruleEvaluator from '../../business_rules/lib/rule-evaluator'\nimport * as ruleEngine from '../../business_rules/lib/rule-engine'\nimport * as activityExecutor from './activity-executor'\nimport type { ActivityDefinition } from './activity-executor'\nimport * as stepHandler from './step-handler'\nimport {\n type ExecutionToken,\n rootToken,\n tokenBranchInstanceId,\n tokenReadContext,\n setTokenCurrentStepId,\n applyTokenContextWrites,\n mergeTokenContext,\n setTokenWaitingForActivities,\n setTokenPendingTransition,\n touchToken,\n} from './execution-token'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface TransitionEvaluationContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionEvaluationResult {\n isValid: boolean\n transition?: any\n reason?: string\n failedConditions?: string[]\n evaluationTime?: number\n}\n\nexport interface TransitionExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionExecutionResult {\n success: boolean\n nextStepId?: string\n pausedForActivities?: boolean\n conditionsEvaluated?: {\n preConditions: boolean\n postConditions: boolean\n }\n activitiesExecuted?: activityExecutor.ActivityExecutionResult[]\n error?: string\n}\n\nexport class TransitionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'TransitionError'\n }\n}\n\n// ============================================================================\n// Main Transition Functions\n// ============================================================================\n\n/**\n * Evaluate if a transition from current step to target step is valid\n *\n * Checks:\n * - Transition exists in workflow definition\n * - Pre-conditions pass (if any business rules defined)\n * - Transition condition evaluates to true (if specified)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID (optional - will auto-select if not provided)\n * @param context - Evaluation context\n * @returns Evaluation result with validity and reason\n */\nexport async function evaluateTransition(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string | undefined,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n const startTime = Date.now()\n\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n isValid: false,\n reason: `Workflow definition not found: ${instance.definitionId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Find transition\n const transitions = definition.definition.transitions || []\n let transition: any\n\n if (toStepId) {\n // Find specific transition\n transition = transitions.find(\n (t: any) => t.fromStepId === fromStepId && t.toStepId === toStepId\n )\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No transition found from ${fromStepId} to ${toStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n } else {\n // Auto-select first valid transition\n const availableTransitions = transitions.filter(\n (t: any) => t.fromStepId === fromStepId\n )\n\n if (availableTransitions.length === 0) {\n return {\n isValid: false,\n reason: `No transitions available from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Evaluate each transition to find first valid one\n for (const t of availableTransitions) {\n const result = await evaluateTransitionConditions(\n em,\n instance,\n t,\n context\n )\n\n if (result.isValid) {\n transition = t\n break\n }\n }\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No valid transitions found from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n }\n\n // Evaluate transition conditions (inline condition + business rules pre-conditions)\n const conditionResult = await evaluateTransitionConditions(\n em,\n instance,\n transition,\n context\n )\n\n return {\n ...conditionResult,\n transition,\n evaluationTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Transition evaluation error: ${errorMessage}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n}\n\n/**\n * Find all valid transitions from current step\n *\n * This function evaluates both inline conditions AND preConditions (business rules)\n * to determine which transitions are truly valid. This is important for decision\n * branching where multiple transitions exist with different preConditions.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param context - Evaluation context\n * @returns Array of evaluation results for all transitions, sorted by priority (desc)\n */\nexport async function findValidTransitions(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult[]> {\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return []\n }\n\n // Find all transitions from current step, sorted by priority (highest first)\n const transitions = (definition.definition.transitions || [])\n .filter((t: any) => t.fromStepId === fromStepId)\n .sort((a: any, b: any) => (b.priority || 0) - (a.priority || 0))\n\n // Evaluate each transition including preConditions\n const results: TransitionEvaluationResult[] = []\n\n for (const transition of transitions) {\n // First check inline condition\n const conditionResult = await evaluateTransition(\n em,\n instance,\n fromStepId,\n transition.toStepId,\n context\n )\n\n if (!conditionResult.isValid) {\n results.push(conditionResult)\n continue\n }\n\n // Also evaluate preConditions if they exist\n const preConditions = transition.preConditions || []\n if (preConditions.length > 0) {\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context as TransitionExecutionContext,\n null\n )\n\n if (!preConditionsResult.allowed) {\n // Transition is invalid due to preConditions\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => r.rule.ruleId || r.rule.ruleName)\n\n results.push({\n isValid: false,\n transition,\n reason: `Pre-conditions failed: ${failedRules.join(', ')}`,\n failedConditions: failedRules,\n })\n continue\n }\n }\n\n // Transition is valid (both condition and preConditions passed)\n results.push({\n ...conditionResult,\n transition,\n })\n }\n\n return results\n } catch (error) {\n console.error('Error finding valid transitions:', error)\n return []\n }\n}\n\n/**\n * Execute a transition from one step to another\n *\n * This is the main entry point for transition execution. It:\n * 1. Validates the transition\n * 2. Evaluates pre-conditions\n * 3. Executes activities (if any)\n * 4. Updates workflow instance state (atomically with activity outputs)\n * 5. Evaluates post-conditions\n * 6. Logs transition event\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution)\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID\n * @param context - Execution context\n * @returns Execution result\n */\nexport async function executeTransition(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string,\n context: TransitionExecutionContext\n): Promise<TransitionExecutionResult> {\n // Public DI signature preserved: the root token adapts the instance, so the\n // single-token path is behaviourally unchanged.\n return executeTransitionForToken(em, container, rootToken(instance), fromStepId, toStepId, context)\n}\n\n/**\n * Token-aware transition execution. The root token wraps a WorkflowInstance\n * (legacy single-token path); a branch token wraps a WorkflowBranchInstance so\n * a parallel branch advances independently with its own context namespace,\n * status and pending transition.\n */\nexport async function executeTransitionForToken(\n em: EntityManager,\n container: AwilixContainer,\n token: ExecutionToken,\n fromStepId: string,\n toStepId: string,\n context: TransitionExecutionContext\n): Promise<TransitionExecutionResult> {\n const instance = token.instance\n const branch = token.kind === 'branch' ? token.branch : null\n const branchInstanceId = tokenBranchInstanceId(token)\n try {\n let eventBus: Pick<EventBus, 'emitEvent'> | null = null\n try {\n eventBus = container.resolve('eventBus') as EventBus\n } catch {\n eventBus = null\n }\n\n // First, evaluate if transition is valid\n const evaluation = await evaluateTransition(\n em,\n instance,\n fromStepId,\n toStepId,\n context\n )\n\n if (!evaluation.isValid) {\n return {\n success: false,\n error: evaluation.reason || 'Transition validation failed',\n }\n }\n\n const transition = evaluation.transition!\n\n // Evaluate pre-conditions (business rules)\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!preConditionsResult.allowed) {\n // Build detailed failure information\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => ({\n ruleId: r.rule.ruleId,\n ruleName: r.rule.ruleName,\n error: r.error,\n }))\n\n const failedRulesDetails = failedRules.length > 0\n ? failedRules.map(r => `${r.ruleId}: ${r.error || 'condition failed'}`).join('; ')\n : preConditionsResult.errors?.join(', ') || 'Unknown pre-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_REJECTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Pre-conditions failed',\n failedRules: failedRulesDetails,\n failedRulesDetail: failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Pre-conditions failed: ${failedRulesDetails}`,\n conditionsEvaluated: {\n preConditions: false,\n postConditions: false,\n },\n }\n }\n\n // Execute activities (if any)\n let activityOutputs: Record<string, any> = {}\n const activityResults: activityExecutor.ActivityExecutionResult[] = []\n\n if (transition.activities && transition.activities.length > 0) {\n const activityContext: activityExecutor.ActivityContext = {\n workflowInstance: instance,\n workflowContext: {\n ...tokenReadContext(token),\n ...context.workflowContext,\n },\n branchInstanceId,\n userId: context.userId,\n }\n\n // Execute all activities\n const results = await activityExecutor.executeActivities(\n em,\n container,\n transition.activities as ActivityDefinition[],\n activityContext\n )\n\n activityResults.push(...results)\n\n // Check for failures\n const failedActivities = results.filter(r => !r.success)\n\n if (failedActivities.length > 0) {\n const continueOnFailure = transition.continueOnActivityFailure ?? false\n\n // Log activity failures\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ACTIVITY_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n failedActivities: failedActivities.map(f => ({\n activityType: f.activityType,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n continueOnFailure,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (!continueOnFailure) {\n return {\n success: false,\n error: `Activities failed: ${failedActivities.map(f => f.error).join(', ')}`,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false,\n },\n }\n }\n }\n\n // Collect activity outputs for context update\n results.forEach(result => {\n if (result.success && result.output) {\n const key = result.activityName || result.activityType\n activityOutputs[key] = result.output\n }\n })\n }\n\n // Check if any activities are async - if so, pause before executing step\n const hasAsyncActivities = activityResults.some(r => r.async)\n\n if (hasAsyncActivities) {\n const pendingJobIds = activityResults\n .filter(a => a.async && a.jobId)\n .map(a => ({ activityId: a.activityId, jobId: a.jobId }))\n\n // Store pending transition state (per-token: branch or instance)\n setTokenPendingTransition(token, {\n toStepId,\n activityResults,\n timestamp: new Date(),\n })\n\n // Store activity outputs + pending-activity tracking in the token's own\n // context scope (instance.context for root, branch namespace for a branch)\n applyTokenContextWrites(token, context.workflowContext, activityOutputs)\n mergeTokenContext(token, { _pendingAsyncActivities: pendingJobIds })\n\n // Set status to waiting (branch-scoped when running inside a branch)\n setTokenWaitingForActivities(token)\n touchToken(token, new Date())\n await em.flush()\n\n // Log event\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n branchInstanceId,\n eventType: 'TRANSITION_PAUSED_FOR_ACTIVITIES',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId,\n pendingActivities: pendingJobIds,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Return WITHOUT executing step\n return {\n success: true,\n pausedForActivities: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false, // Not evaluated yet\n },\n activitiesExecuted: activityResults,\n }\n }\n\n // Advance the token cursor and update context atomically (instance for the\n // root token; branch cursor + namespace for a branch token).\n setTokenCurrentStepId(token, toStepId)\n applyTokenContextWrites(token, context.workflowContext, activityOutputs)\n touchToken(token, new Date())\n\n await em.flush()\n\n // Execute the new step (this will create USER_TASK, handle END steps, etc.)\n const stepExecutionResult = await stepHandler.executeStep(\n em,\n instance,\n toStepId,\n {\n workflowContext: tokenReadContext(token),\n userId: context.userId,\n triggerData: context.triggerData,\n },\n container,\n branch\n )\n\n // Promote a SUB_WORKFLOW step's mapped output into the running context so\n // subsequent steps (or sibling sub-workflows) can read it. Unlike activity\n // outputs \u2014 already merged above via applyTokenContextWrites \u2014 a sub-workflow\n // returns its outputMapping result through StepExecutionResult.outputData and\n // would otherwise be dropped on the floor. Other step types return diagnostic\n // outputData (stepType/timestamp/finalContext) that must NOT leak into the\n // context, so gate strictly on the SUB_WORKFLOW step type.\n if (\n stepExecutionResult.status === 'COMPLETED' &&\n stepExecutionResult.outputData &&\n typeof stepExecutionResult.outputData === 'object'\n ) {\n const completedStepType = await getStepType(em, instance, toStepId)\n if (completedStepType === 'SUB_WORKFLOW') {\n mergeTokenContext(token, stepExecutionResult.outputData as Record<string, any>)\n touchToken(token, new Date())\n }\n }\n\n // Flush to database after step execution completes to make state visible to UI\n await em.flush()\n\n // Handle step execution failure\n if (stepExecutionResult.status === 'FAILED') {\n return {\n success: false,\n error: stepExecutionResult.error || 'Step execution failed',\n }\n }\n\n // Evaluate post-conditions (business rules)\n const postConditionsResult = await evaluatePostConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!postConditionsResult.allowed) {\n const failedRules = postConditionsResult.errors?.join(', ') || 'Unknown post-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_POST_CONDITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Post-conditions failed',\n failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Note: We don't roll back the transition on post-condition failure\n // Post-conditions are warnings, not blockers\n }\n\n // Log successful transition\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_EXECUTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n transitionName: transition.transitionName,\n preConditionsPassed: true,\n postConditionsPassed: postConditionsResult.allowed,\n activitiesExecuted: activityResults.length,\n activitiesSucceeded: activityResults.filter(r => r.success).length,\n activitiesFailed: activityResults.filter(r => !r.success).length,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: postConditionsResult.allowed,\n },\n activitiesExecuted: activityResults,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n error: errorMessage,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Transition execution failed: ${errorMessage}`,\n }\n }\n}\n\n// ============================================================================\n// Condition Evaluation\n// ============================================================================\n\n/**\n * Evaluate transition conditions (inline condition expression)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Evaluation context\n * @returns Evaluation result\n */\nasync function evaluateTransitionConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n try {\n // If no condition specified, transition is always valid\n if (!transition.condition) {\n return {\n isValid: true,\n }\n }\n\n // Build data context for rule evaluation\n const data = {\n ...instance.context,\n ...context.workflowContext,\n triggerData: context.triggerData,\n }\n\n // Build evaluation context\n const evalContext: ruleEvaluator.RuleEvaluationContext = {\n entityType: 'workflow:transition',\n entityId: instance.id,\n user: context.userId ? { id: context.userId } : undefined,\n }\n\n // Evaluate condition using expression evaluator\n const result = await ruleEvaluator.evaluateConditions(\n transition.condition,\n data,\n evalContext\n )\n\n return {\n isValid: result,\n reason: result ? undefined : 'Transition condition evaluated to false',\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Condition evaluation error: ${errorMessage}`,\n }\n }\n}\n\n/**\n * Evaluate pre-conditions using business rules engine\n *\n * Pre-conditions are GUARD rules that must pass before transition can execute.\n * If any GUARD rule fails, the transition is blocked.\n *\n * If the transition defines specific preConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, falls back to\n * discovery-based execution via executeRules.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePreConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific preConditions defined\n const preConditions = transition.preConditions || []\n\n // If no pre-conditions defined, allow transition\n if (preConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each pre-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of preConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'pre_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n // We don't have the full BusinessRule entity, but we can create a partial result\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n // Rule not found, disabled, or other errors\n const isRequired = condition.required !== false // Default to required\n if (isRequired) {\n allowed = false\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n }\n continue\n }\n\n // If required and condition failed, block transition\n const isRequired = condition.required !== false // Default to required\n if (isRequired && !result.conditionResult) {\n allowed = false\n errors.push(`Pre-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating pre-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n/**\n * Evaluate post-conditions using business rules engine\n *\n * Post-conditions are GUARD rules that should pass after transition executes.\n * Unlike pre-conditions, post-condition failures are logged but don't block the transition.\n *\n * If the transition defines specific postConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, returns allowed: true.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePostConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific postConditions defined\n const postConditions = transition.postConditions || []\n\n // If no post-conditions defined, allow\n if (postConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each post-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of postConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'post_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n // Post-conditions don't block, but track the failure\n allowed = false\n continue\n }\n\n // Track condition failures (post-conditions are warnings, not blockers)\n if (!result.conditionResult) {\n allowed = false\n errors.push(`Post-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating post-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Resolve a step's declared type from the workflow definition.\n *\n * Used to decide whether a completed step's outputData should be promoted into\n * the running context \u2014 only SUB_WORKFLOW steps return mapped output meant for\n * downstream steps. The definition is already in the identity map from earlier\n * evaluation, so this findOne is a cheap lookup rather than a fresh DB round-trip.\n */\nasync function getStepType(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string\n): Promise<string | undefined> {\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n const stepDef = definition?.definition.steps.find((step: any) => step.stepId === stepId)\n return stepDef?.stepType\n}\n\n/**\n * Log transition-related event to event sourcing table\n */\nasync function logTransitionEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["isRequired"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6336.1.38e0a4c455",
3
+ "version": "0.6.6-develop.6337.1.bd66ae541e",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -246,16 +246,16 @@
246
246
  "zod": "^4.4.3"
247
247
  },
248
248
  "peerDependencies": {
249
- "@open-mercato/ai-assistant": "0.6.6-develop.6336.1.38e0a4c455",
250
- "@open-mercato/shared": "0.6.6-develop.6336.1.38e0a4c455",
251
- "@open-mercato/ui": "0.6.6-develop.6336.1.38e0a4c455",
249
+ "@open-mercato/ai-assistant": "0.6.6-develop.6337.1.bd66ae541e",
250
+ "@open-mercato/shared": "0.6.6-develop.6337.1.bd66ae541e",
251
+ "@open-mercato/ui": "0.6.6-develop.6337.1.bd66ae541e",
252
252
  "react": "^19.0.0",
253
253
  "react-dom": "^19.0.0"
254
254
  },
255
255
  "devDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.6-develop.6336.1.38e0a4c455",
257
- "@open-mercato/shared": "0.6.6-develop.6336.1.38e0a4c455",
258
- "@open-mercato/ui": "0.6.6-develop.6336.1.38e0a4c455",
256
+ "@open-mercato/ai-assistant": "0.6.6-develop.6337.1.bd66ae541e",
257
+ "@open-mercato/shared": "0.6.6-develop.6337.1.bd66ae541e",
258
+ "@open-mercato/ui": "0.6.6-develop.6337.1.bd66ae541e",
259
259
  "@testing-library/dom": "^10.4.1",
260
260
  "@testing-library/jest-dom": "^6.9.1",
261
261
  "@testing-library/react": "^16.3.1",
@@ -27,7 +27,11 @@ interface MappingArrayEditorProps extends CrudCustomFieldRenderProps {
27
27
  * MappingArrayEditor - Custom field component for managing SubWorkflow input/output mappings
28
28
  *
29
29
  * Provides an interface to add, edit, and remove key-value pair mappings.
30
- * Values support template expressions like {{context.foo}} for dynamic data binding.
30
+ * Each value is a plain dot-path into the source context (e.g. `order.id` or
31
+ * `items.0.sku`), NOT a {{ }} template — the SUB_WORKFLOW mapping resolver walks
32
+ * the path directly and ignores template expressions. For an inputMapping the
33
+ * key is the child context key and the value is the parent path; for an
34
+ * outputMapping the key is the parent context key and the value is the child path.
31
35
  *
32
36
  * Used by NodeEditDialog (SubWorkflow type only)
33
37
  */
@@ -591,8 +591,8 @@
591
591
  "workflows.fieldEditors.mappings.label": "Zuordnungen",
592
592
  "workflows.fieldEditors.mappings.removeMapping": "Zuordnung entfernen",
593
593
  "workflows.fieldEditors.mappings.value": "Wert",
594
- "workflows.fieldEditors.mappings.valueHint": "Verwenden Sie Template-Ausdrücke wie {{context.foo}} für dynamische Werte",
595
- "workflows.fieldEditors.mappings.valuePlaceholder": "{{context.fieldName}} oder statischer Wert",
594
+ "workflows.fieldEditors.mappings.valueHint": "Ein Punktpfad in den Quellkontext, z. B. order.id oder items.0.sku (keine {{ }}-Vorlage)",
595
+ "workflows.fieldEditors.mappings.valuePlaceholder": "order.id",
596
596
  "workflows.fieldEditors.preConditions.addRule": "Regel hinzufügen",
597
597
  "workflows.fieldEditors.preConditions.confirmRemove": "Möchten Sie diese Vorbedingung wirklich entfernen?",
598
598
  "workflows.fieldEditors.preConditions.description": "Geschäftsregeln, die erfüllt sein müssen, bevor der Workflow gestartet werden kann",
@@ -591,8 +591,8 @@
591
591
  "workflows.fieldEditors.mappings.label": "Mappings",
592
592
  "workflows.fieldEditors.mappings.removeMapping": "Remove Mapping",
593
593
  "workflows.fieldEditors.mappings.value": "Value",
594
- "workflows.fieldEditors.mappings.valueHint": "Use template expressions like {{context.foo}} for dynamic values",
595
- "workflows.fieldEditors.mappings.valuePlaceholder": "{{context.fieldName}} or static value",
594
+ "workflows.fieldEditors.mappings.valueHint": "A dot-path into the source context, e.g. order.id or items.0.sku (not a {{ }} template)",
595
+ "workflows.fieldEditors.mappings.valuePlaceholder": "order.id",
596
596
  "workflows.fieldEditors.preConditions.addRule": "Add Rule",
597
597
  "workflows.fieldEditors.preConditions.confirmRemove": "Are you sure you want to remove this pre-condition?",
598
598
  "workflows.fieldEditors.preConditions.description": "Business rules that must pass before the workflow can start",
@@ -591,8 +591,8 @@
591
591
  "workflows.fieldEditors.mappings.label": "Mapeos",
592
592
  "workflows.fieldEditors.mappings.removeMapping": "Eliminar mapeo",
593
593
  "workflows.fieldEditors.mappings.value": "Valor",
594
- "workflows.fieldEditors.mappings.valueHint": "Usa expresiones de plantilla como {{context.foo}} para valores dinamicos",
595
- "workflows.fieldEditors.mappings.valuePlaceholder": "{{context.fieldName}} o valor estatico",
594
+ "workflows.fieldEditors.mappings.valueHint": "Una ruta con puntos en el contexto de origen, p. ej. order.id o items.0.sku (no una plantilla {{ }})",
595
+ "workflows.fieldEditors.mappings.valuePlaceholder": "order.id",
596
596
  "workflows.fieldEditors.preConditions.addRule": "Agregar regla",
597
597
  "workflows.fieldEditors.preConditions.confirmRemove": "¿Seguro que quieres eliminar esta precondicion?",
598
598
  "workflows.fieldEditors.preConditions.description": "Reglas de negocio que deben cumplirse antes de que el flujo de trabajo pueda iniciarse",
@@ -591,8 +591,8 @@
591
591
  "workflows.fieldEditors.mappings.label": "Mapowania",
592
592
  "workflows.fieldEditors.mappings.removeMapping": "Usuń Mapowanie",
593
593
  "workflows.fieldEditors.mappings.value": "Wartość",
594
- "workflows.fieldEditors.mappings.valueHint": "Użyj wyrażeń szablonowych, takich jak {{context.foo}}, dla wartości dynamicznych",
595
- "workflows.fieldEditors.mappings.valuePlaceholder": "{{context.fieldName}} lub wartość statyczna",
594
+ "workflows.fieldEditors.mappings.valueHint": "Ścieżka z kropkami do kontekstu źródłowego, np. order.id lub items.0.sku (nie szablon {{ }})",
595
+ "workflows.fieldEditors.mappings.valuePlaceholder": "order.id",
596
596
  "workflows.fieldEditors.preConditions.addRule": "Dodaj Regułę",
597
597
  "workflows.fieldEditors.preConditions.confirmRemove": "Czy na pewno chcesz usunąć ten warunek wstępny?",
598
598
  "workflows.fieldEditors.preConditions.description": "Reguły biznesowe, które muszą być spełnione, zanim przepływ będzie mógł zostać uruchomiony",
@@ -1018,11 +1018,28 @@ function setNestedValue(obj: any, path: string, value: any): void {
1018
1018
  target[lastKey] = value
1019
1019
  }
1020
1020
 
1021
+ /**
1022
+ * Warn (dev-time) when a SUB_WORKFLOW mapping value is written as a `{{ }}`
1023
+ * template. Mapping values are plain dot-paths into the source context — the
1024
+ * `{{ }}` form only works for activity config interpolation — so such entries
1025
+ * never resolve and are silently dropped. Surfacing a warning makes legacy
1026
+ * misconfigurations debuggable instead of invisible.
1027
+ */
1028
+ function warnOnTemplateMapping(sourcePath: string, direction: 'input' | 'output'): void {
1029
+ if (/\{\{.*\}\}/.test(sourcePath)) {
1030
+ console.warn(
1031
+ `[workflows] SUB_WORKFLOW ${direction} mapping value "${sourcePath}" looks like a {{ }} template, ` +
1032
+ 'but mapping values are plain dot-paths into the source context (e.g. "order.id"). ' +
1033
+ 'This entry will not resolve and is being ignored.'
1034
+ )
1035
+ }
1036
+ }
1037
+
1021
1038
  /**
1022
1039
  * Map data from source context using mapping configuration
1023
1040
  *
1024
1041
  * @param sourceContext - Source data object
1025
- * @param mapping - Mapping configuration (targetKey -> sourcePath)
1042
+ * @param mapping - Mapping configuration (targetKey -> sourcePath, plain dot-path)
1026
1043
  * @returns Mapped data object
1027
1044
  */
1028
1045
  function mapInputData(
@@ -1032,6 +1049,7 @@ function mapInputData(
1032
1049
  const result: Record<string, any> = {}
1033
1050
 
1034
1051
  for (const [targetKey, sourcePath] of Object.entries(mapping)) {
1052
+ warnOnTemplateMapping(sourcePath, 'input')
1035
1053
  const value = getNestedValue(sourceContext, sourcePath)
1036
1054
  if (value !== undefined) {
1037
1055
  setNestedValue(result, targetKey, value)
@@ -1046,7 +1064,7 @@ function mapInputData(
1046
1064
  * Map output data from child context back to parent
1047
1065
  *
1048
1066
  * @param childContext - Child workflow context
1049
- * @param mapping - Mapping configuration (targetKey -> sourcePath)
1067
+ * @param mapping - Mapping configuration (targetKey -> sourcePath, plain dot-path)
1050
1068
  * @returns Mapped output data
1051
1069
  */
1052
1070
  function mapOutputData(
@@ -1056,6 +1074,7 @@ function mapOutputData(
1056
1074
  const result: Record<string, any> = {}
1057
1075
 
1058
1076
  for (const [targetKey, sourcePath] of Object.entries(mapping)) {
1077
+ warnOnTemplateMapping(sourcePath, 'output')
1059
1078
  const value = getNestedValue(childContext, sourcePath)
1060
1079
  if (value !== undefined) {
1061
1080
  setNestedValue(result, targetKey, value)
@@ -569,6 +569,25 @@ export async function executeTransitionForToken(
569
569
  branch
570
570
  )
571
571
 
572
+ // Promote a SUB_WORKFLOW step's mapped output into the running context so
573
+ // subsequent steps (or sibling sub-workflows) can read it. Unlike activity
574
+ // outputs — already merged above via applyTokenContextWrites — a sub-workflow
575
+ // returns its outputMapping result through StepExecutionResult.outputData and
576
+ // would otherwise be dropped on the floor. Other step types return diagnostic
577
+ // outputData (stepType/timestamp/finalContext) that must NOT leak into the
578
+ // context, so gate strictly on the SUB_WORKFLOW step type.
579
+ if (
580
+ stepExecutionResult.status === 'COMPLETED' &&
581
+ stepExecutionResult.outputData &&
582
+ typeof stepExecutionResult.outputData === 'object'
583
+ ) {
584
+ const completedStepType = await getStepType(em, instance, toStepId)
585
+ if (completedStepType === 'SUB_WORKFLOW') {
586
+ mergeTokenContext(token, stepExecutionResult.outputData as Record<string, any>)
587
+ touchToken(token, new Date())
588
+ }
589
+ }
590
+
572
591
  // Flush to database after step execution completes to make state visible to UI
573
592
  await em.flush()
574
593
 
@@ -982,6 +1001,24 @@ async function evaluatePostConditions(
982
1001
  // Helper Functions
983
1002
  // ============================================================================
984
1003
 
1004
+ /**
1005
+ * Resolve a step's declared type from the workflow definition.
1006
+ *
1007
+ * Used to decide whether a completed step's outputData should be promoted into
1008
+ * the running context — only SUB_WORKFLOW steps return mapped output meant for
1009
+ * downstream steps. The definition is already in the identity map from earlier
1010
+ * evaluation, so this findOne is a cheap lookup rather than a fresh DB round-trip.
1011
+ */
1012
+ async function getStepType(
1013
+ em: EntityManager,
1014
+ instance: WorkflowInstance,
1015
+ stepId: string
1016
+ ): Promise<string | undefined> {
1017
+ const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })
1018
+ const stepDef = definition?.definition.steps.find((step: any) => step.stepId === stepId)
1019
+ return stepDef?.stepType
1020
+ }
1021
+
985
1022
  /**
986
1023
  * Log transition-related event to event sourcing table
987
1024
  */