@open-mercato/core 0.6.6-develop.6543.1.49fadb4c31 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/api_keys/api/keys/route.js +9 -23
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/cli.js +1 -2
- package/dist/modules/api_keys/cli.js.map +2 -2
- package/dist/modules/attachments/api/file/[id]/route.js +7 -9
- package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +7 -9
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +17 -21
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +2 -6
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/cli.js +2 -3
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +0 -22
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection-table.js +2 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -7
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +7 -11
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
- package/dist/modules/dashboards/api/roles/widgets/route.js +3 -22
- package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +3 -22
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/cli.js +3 -4
- package/dist/modules/dashboards/cli.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetAssignmentScope.js +1 -9
- package/dist/modules/dashboards/lib/widgetAssignmentScope.js.map +2 -2
- package/dist/modules/dictionaries/commands/entries.js +14 -7
- package/dist/modules/dictionaries/commands/entries.js.map +2 -2
- package/dist/modules/dictionaries/commands/entry-operations.js +16 -7
- package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +3 -9
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/fields/dictionary.js +41 -56
- package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +3 -10
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -5
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js +0 -1
- package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +49 -49
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js +0 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js.map +2 -2
- package/dist/modules/entities/cli.js +1 -2
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/query_index/api/status.js +8 -2
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +0 -44
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +27 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +2 -6
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +0 -1
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +0 -9
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +0 -44
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +38 -59
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/lib/shipments/snapshots.js +1 -27
- package/dist/modules/sales/lib/shipments/snapshots.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -1
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +1 -1
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/find-definition.js +18 -2
- package/dist/modules/workflows/lib/find-definition.js.map +2 -2
- package/dist/modules/workflows/lib/signal-handler.js +3 -2
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +4 -8
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +3 -5
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/timer-handler.js +2 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +5 -13
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +11 -9
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260715120000.js +68 -0
- package/dist/modules/workflows/migrations/Migration20260715120000.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260716120000.js +24 -0
- package/dist/modules/workflows/migrations/Migration20260716120000.js.map +7 -0
- package/dist/modules/workflows/workflows.js +2 -0
- package/dist/modules/workflows/workflows.js.map +2 -2
- package/package.json +8 -9
- package/src/modules/api_keys/api/keys/route.ts +9 -27
- package/src/modules/api_keys/cli.ts +3 -2
- package/src/modules/attachments/api/file/[id]/route.ts +7 -11
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +7 -11
- package/src/modules/attachments/api/route.ts +21 -26
- package/src/modules/auth/api/users/route.ts +2 -11
- package/src/modules/auth/cli.ts +2 -3
- package/src/modules/configs/i18n/de.json +1 -5
- package/src/modules/configs/i18n/en.json +1 -5
- package/src/modules/configs/i18n/es.json +1 -5
- package/src/modules/configs/i18n/pl.json +1 -5
- package/src/modules/configs/lib/upgrade-actions.ts +0 -24
- package/src/modules/customer_accounts/AGENTS.md +6 -8
- package/src/modules/customer_accounts/widgets/injection-table.ts +2 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -11
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +7 -13
- package/src/modules/dashboards/api/roles/widgets/route.ts +3 -22
- package/src/modules/dashboards/api/users/widgets/route.ts +3 -22
- package/src/modules/dashboards/cli.ts +9 -4
- package/src/modules/dashboards/lib/widgetAssignmentScope.ts +0 -18
- package/src/modules/dictionaries/commands/entries.ts +16 -7
- package/src/modules/dictionaries/commands/entry-operations.ts +18 -8
- package/src/modules/dictionaries/commands/factory.ts +2 -8
- package/src/modules/dictionaries/fields/dictionary.tsx +32 -55
- package/src/modules/dictionaries/i18n/de.json +0 -2
- package/src/modules/dictionaries/i18n/en.json +0 -2
- package/src/modules/dictionaries/i18n/es.json +0 -2
- package/src/modules/dictionaries/i18n/pl.json +0 -2
- package/src/modules/directory/utils/organizationScope.ts +2 -36
- package/src/modules/entities/api/records.ts +7 -5
- package/src/modules/entities/backend/entities/system/[entityId]/page.meta.ts +0 -1
- package/src/modules/entities/backend/entities/user/[entityId]/page.meta.ts +0 -1
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +49 -51
- package/src/modules/entities/cli.ts +1 -2
- package/src/modules/entities/i18n/de.json +0 -34
- package/src/modules/entities/i18n/en.json +0 -34
- package/src/modules/entities/i18n/es.json +0 -34
- package/src/modules/entities/i18n/pl.json +0 -34
- package/src/modules/query_index/api/status.ts +8 -2
- package/src/modules/sales/commands/documents.ts +0 -65
- package/src/modules/sales/commands/returns.ts +32 -2
- package/src/modules/sales/components/documents/AddressesSection.tsx +2 -6
- package/src/modules/sales/components/documents/ItemsSection.tsx +0 -5
- package/src/modules/sales/components/documents/LineItemDialog.tsx +0 -10
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +0 -46
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +40 -65
- package/src/modules/sales/i18n/de.json +0 -4
- package/src/modules/sales/i18n/en.json +0 -4
- package/src/modules/sales/i18n/es.json +0 -4
- package/src/modules/sales/i18n/pl.json +0 -4
- package/src/modules/sales/lib/shipments/snapshots.ts +0 -30
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +12 -1
- package/src/modules/workflows/lib/activity-executor.ts +22 -2
- package/src/modules/workflows/lib/find-definition.ts +53 -1
- package/src/modules/workflows/lib/signal-handler.ts +5 -4
- package/src/modules/workflows/lib/step-handler.ts +4 -8
- package/src/modules/workflows/lib/task-handler.ts +2 -4
- package/src/modules/workflows/lib/timer-handler.ts +3 -2
- package/src/modules/workflows/lib/transition-handler.ts +5 -13
- package/src/modules/workflows/lib/workflow-executor.ts +11 -8
- package/src/modules/workflows/migrations/Migration20260715120000.ts +114 -0
- package/src/modules/workflows/migrations/Migration20260716120000.ts +57 -0
- package/src/modules/workflows/workflows.ts +2 -0
- package/dist/modules/attachments/lib/reconcileOrganization.js +0 -110
- package/dist/modules/attachments/lib/reconcileOrganization.js.map +0 -7
- package/dist/modules/attachments/lib/requestScope.js +0 -10
- package/dist/modules/attachments/lib/requestScope.js.map +0 -7
- package/dist/modules/customers/components/detail/useDealsAccess.js +0 -16
- package/dist/modules/customers/components/detail/useDealsAccess.js.map +0 -7
- package/src/modules/attachments/lib/reconcileOrganization.ts +0 -188
- package/src/modules/attachments/lib/requestScope.ts +0 -27
- package/src/modules/customers/components/detail/useDealsAccess.ts +0 -19
|
@@ -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'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\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 logger.error('Error finding valid transitions', { err: 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 logger.error('Error evaluating pre-conditions', { err: 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 logger.error('Error evaluating post-conditions', { err: 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 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 { findDefinitionForInstance } from './find-definition'\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'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\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 findDefinitionForInstance(em, instance)\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 findDefinitionForInstance(em, instance)\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 logger.error('Error finding valid transitions', { err: 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 findDefinitionForInstance(em, instance)\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 logger.error('Error evaluating pre-conditions', { err: 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 findDefinitionForInstance(em, instance)\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 logger.error('Error evaluating post-conditions', { err: 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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",
|
|
6
6
|
"names": ["isRequired"]
|
|
7
7
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { LockMode } from "@mikro-orm/core";
|
|
2
2
|
import {
|
|
3
|
-
WorkflowDefinition,
|
|
4
3
|
WorkflowInstance,
|
|
5
4
|
WorkflowEvent
|
|
6
5
|
} from "../data/entities.js";
|
|
7
6
|
import { compensateWorkflow } from "./compensation-handler.js";
|
|
8
|
-
import { findWorkflowDefinition } from "./find-definition.js";
|
|
7
|
+
import { findWorkflowDefinition, findDefinitionForInstance } from "./find-definition.js";
|
|
9
8
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
10
9
|
const logger = createLogger("workflows");
|
|
11
10
|
class WorkflowExecutionError extends Error {
|
|
@@ -155,9 +154,7 @@ async function executeWorkflow(em, container, instanceId, context) {
|
|
|
155
154
|
{ instanceId, status: instance.status }
|
|
156
155
|
);
|
|
157
156
|
}
|
|
158
|
-
const definition = await trx
|
|
159
|
-
id: instance.definitionId
|
|
160
|
-
});
|
|
157
|
+
const definition = await findDefinitionForInstance(trx, instance);
|
|
161
158
|
if (!definition) {
|
|
162
159
|
throw new WorkflowExecutionError(
|
|
163
160
|
`Workflow definition not found: ${instance.definitionId}`,
|
|
@@ -426,7 +423,7 @@ async function completeWorkflow(em, container, instanceId, status, result) {
|
|
|
426
423
|
);
|
|
427
424
|
}
|
|
428
425
|
if (status === "FAILED") {
|
|
429
|
-
const definition = await em
|
|
426
|
+
const definition = await findDefinitionForInstance(em, instance);
|
|
430
427
|
if (definition && checkIfCompensationNeeded(definition)) {
|
|
431
428
|
try {
|
|
432
429
|
if (result?.error) {
|
|
@@ -582,9 +579,14 @@ async function resumeWorkflowAfterActivities(em, container, instanceId, branchIn
|
|
|
582
579
|
toStepId: pendingTransition.toStepId,
|
|
583
580
|
fromStepId: instance.currentStepId
|
|
584
581
|
});
|
|
585
|
-
const definition = await trx
|
|
586
|
-
|
|
587
|
-
|
|
582
|
+
const definition = await findDefinitionForInstance(trx, instance);
|
|
583
|
+
if (!definition) {
|
|
584
|
+
throw new WorkflowExecutionError(
|
|
585
|
+
`Workflow definition not found: ${instance.definitionId}`,
|
|
586
|
+
"DEFINITION_NOT_FOUND",
|
|
587
|
+
{ definitionId: instance.definitionId }
|
|
588
|
+
);
|
|
589
|
+
}
|
|
588
590
|
const step = definition.definition.steps.find((s) => s.stepId === pendingTransition.toStepId);
|
|
589
591
|
instance.currentStepId = pendingTransition.toStepId;
|
|
590
592
|
instance.status = "RUNNING";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/workflows/lib/workflow-executor.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Workflows Module - Workflow Executor Service\n *\n * Main orchestrator for workflow execution. Handles workflow lifecycle:\n * - Starting workflow instances from definitions\n * - Executing workflow steps and transitions\n * - Completing workflows with final status\n * - Triggering compensation on failure\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager, LockMode } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n WorkflowDefinition,\n WorkflowInstance,\n WorkflowEvent,\n type WorkflowInstanceStatus,\n} from '../data/entities'\nimport { compensateWorkflow } from './compensation-handler'\nimport { findWorkflowDefinition } from './find-definition'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StartWorkflowOptions {\n workflowId: string\n version?: number // Default to latest enabled version\n initialContext?: Record<string, any>\n correlationKey?: string\n metadata?: {\n entityType?: string\n entityId?: string\n initiatedBy?: string\n labels?: Record<string, string>\n }\n tenantId: string\n organizationId: string\n}\n\nexport interface ExecutionContext {\n userId?: string\n dryRun?: boolean\n timeout?: number\n}\n\nexport interface ExecutionResult {\n status: WorkflowInstanceStatus\n currentStep: string\n context: Record<string, any>\n events: WorkflowEventSummary[]\n errors?: string[]\n executionTime: number\n}\n\nexport interface WorkflowEventSummary {\n eventType: string\n occurredAt: Date\n data?: any\n}\n\nexport class WorkflowExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'WorkflowExecutionError'\n }\n}\n\n// ============================================================================\n// Main Orchestration Functions\n// ============================================================================\n\n/**\n * Start a new workflow instance from a definition\n *\n * @param em - Entity manager for database operations\n * @param options - Workflow start options\n * @returns Created workflow instance\n * @throws WorkflowExecutionError if definition not found or validation fails\n */\nexport async function startWorkflow(\n em: EntityManager,\n options: StartWorkflowOptions\n): Promise<WorkflowInstance> {\n const {\n workflowId,\n version,\n initialContext = {},\n correlationKey,\n metadata,\n tenantId,\n organizationId,\n } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${workflowId}${version ? ` v${version}` : ''}`,\n 'DEFINITION_NOT_FOUND',\n { workflowId, version }\n )\n }\n\n if (!definition.enabled) {\n throw new WorkflowExecutionError(\n `Workflow definition is disabled: ${workflowId}`,\n 'DEFINITION_DISABLED',\n { workflowId, version: definition.version }\n )\n }\n\n // Validate definition has required steps\n const { steps, transitions } = definition.definition\n if (!steps || steps.length < 2) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least START and END steps',\n 'INVALID_DEFINITION',\n { workflowId, stepsCount: steps?.length || 0 }\n )\n }\n\n if (!transitions || transitions.length < 1) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least one transition',\n 'INVALID_DEFINITION',\n { workflowId, transitionsCount: transitions?.length || 0 }\n )\n }\n\n // Find START step\n const startStep = steps.find((s: any) => s.stepType === 'START')\n if (!startStep) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have a START step',\n 'INVALID_DEFINITION',\n { workflowId }\n )\n }\n\n // Validate START step pre-conditions if defined\n if (startStep.preConditions && startStep.preConditions.length > 0) {\n const { validateWorkflowStart } = await import('./start-validator')\n\n const validationResult = await validateWorkflowStart(em, {\n workflowId,\n version: definition.version,\n context: initialContext,\n tenantId,\n organizationId,\n })\n\n if (!validationResult.canStart) {\n throw new WorkflowExecutionError(\n `Workflow start pre-conditions failed: ${validationResult.errors.map(e => e.message).join('; ')}`,\n 'START_PRE_CONDITIONS_FAILED',\n {\n workflowId,\n errors: validationResult.errors,\n validatedRules: validationResult.validatedRules,\n }\n )\n }\n }\n\n // Create workflow instance\n const now = new Date()\n const instance = em.create(WorkflowInstance, {\n definitionId: definition.id,\n workflowId: definition.workflowId,\n version: definition.version,\n status: 'RUNNING',\n currentStepId: startStep.stepId,\n context: initialContext,\n correlationKey,\n metadata,\n startedAt: now,\n retryCount: 0,\n tenantId,\n organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(instance).flush()\n\n // Log WORKFLOW_STARTED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'WORKFLOW_STARTED',\n eventData: {\n workflowId: instance.workflowId,\n version: instance.version,\n startStepId: startStep.stepId,\n initialContext,\n metadata,\n },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n\n return instance\n}\n\n/**\n * Execute a workflow instance\n *\n * Main execution loop that processes steps and transitions until:\n * - Workflow completes (reaches END step)\n * - Workflow waits (USER_TASK, SIGNAL, TIMER)\n * - Workflow fails (error occurs)\n * - Timeout is reached\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution and other services)\n * @param instanceId - Workflow instance ID\n * @param context - Execution context (userId, dryRun, timeout)\n * @returns Execution result with status and events\n */\nexport async function executeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n context?: ExecutionContext\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(\n callback: (trx: EntityManager) => Promise<TResult>,\n ) => Promise<TResult>\n }\n\n const runExecution = async (trx: EntityManager): Promise<ExecutionResult> => {\n const events: WorkflowEventSummary[] = []\n const errors: string[] = []\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status === 'COMPLETED') {\n return {\n status: 'COMPLETED',\n currentStep: instance.currentStepId,\n context: instance.context,\n events: [],\n executionTime: 0,\n }\n }\n\n if (instance.status === 'CANCELLED') {\n throw new WorkflowExecutionError(\n 'Cannot execute cancelled workflow',\n 'WORKFLOW_CANCELLED',\n { instanceId, status: instance.status }\n )\n }\n\n const definition = await trx.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const maxIterations = 100\n let iterations = 0\n\n while (iterations < maxIterations) {\n iterations++\n\n const currentInstance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: iterations > 1 })\n if (!currentInstance) {\n throw new WorkflowExecutionError(\n 'Instance not found during execution',\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Parallel execution: while the instance is FORKED, drive the branches.\n if (currentInstance.status === 'FORKED') {\n const { advanceBranches } = await import('./parallel-handler')\n const branchResult = await advanceBranches(trx, container, currentInstance, definition, {\n userId: context?.userId,\n })\n\n if (branchResult.outcome === 'joined') {\n // Instance resumed at the post-join step; continue single-token.\n continue\n }\n\n if (branchResult.outcome === 'failed') {\n errors.push(branchResult.error || 'Parallel branch failed')\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: branchResult.error || 'Parallel branch failed',\n })\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n // 'waiting' \u2014 all branches paused for external resume (task/signal/timer/async).\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const currentStep = definition.definition.steps.find(\n (s: any) => s.stepId === currentInstance.currentStepId\n )\n\n if (currentStep?.stepType === 'END') {\n await completeWorkflow(trx, container, instanceId, 'COMPLETED')\n events.push({\n eventType: 'WORKFLOW_COMPLETED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'COMPLETED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (\n currentStep?.stepType === 'USER_TASK' ||\n currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||\n currentStep?.stepType === 'WAIT_FOR_TIMER'\n ) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitions = definition.definition.transitions.filter(\n (t: any) =>\n t.fromStepId === currentInstance.currentStepId &&\n t.trigger === 'auto'\n )\n\n if (transitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitionHandler = await import('./transition-handler')\n const evalContext: any = {\n workflowContext: currentInstance.context,\n userId: context?.userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n trx,\n currentInstance,\n currentInstance.currentStepId!,\n evalContext\n )\n\n const validAutoTransitions = validTransitions.filter(\n (vt) => vt.isValid && vt.transition?.trigger === 'auto'\n )\n\n if (validAutoTransitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const selectedTransition = validAutoTransitions[0].transition\n\n try {\n const transitionResult = await transitionHandler.executeTransition(\n trx,\n container,\n currentInstance,\n selectedTransition.fromStepId,\n selectedTransition.toStepId,\n evalContext\n )\n\n if (!transitionResult.success) {\n const rejectionMessage = transitionResult.error || 'Transition failed'\n logger.error('Transition rejected', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: rejectionMessage,\n })\n errors.push(rejectionMessage)\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: rejectionMessage,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n events.push({\n eventType: 'TRANSITION_EXECUTED',\n occurredAt: new Date(),\n data: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n transitionId: selectedTransition.transitionId,\n },\n })\n\n if (transitionResult.pausedForActivities) {\n await logWorkflowEvent(trx, {\n workflowInstanceId: currentInstance.id,\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n eventData: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n pausedAtTransition: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n },\n },\n tenantId: currentInstance.tenantId,\n organizationId: currentInstance.organizationId,\n })\n\n events.push({\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n occurredAt: new Date(),\n data: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n },\n })\n\n return {\n status: 'WAITING_FOR_ACTIVITIES',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n await trx.flush()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Transition execution failed', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: error,\n })\n errors.push(errorMessage)\n\n events.push({\n eventType: 'TRANSITION_FAILED',\n occurredAt: new Date(),\n data: {\n transitionId: selectedTransition.transitionId,\n error: errorMessage,\n },\n })\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: errorMessage,\n details: error instanceof WorkflowExecutionError ? error.details : undefined,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n errors.push('Maximum execution iterations reached - possible infinite loop')\n return {\n status: 'RUNNING',\n currentStep: instance.currentStepId,\n context: instance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Execution failed', { instanceId, err: error })\n errors.push(errorMessage)\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: true })\n if (instance && instance.status === 'RUNNING') {\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n logger.error('Failed to update instance with error state', { instanceId, err: updateError })\n }\n\n throw error\n }\n }\n\n return typeof transactionalEm.transactional === 'function'\n ? transactionalEm.transactional((trx) => runExecution(trx))\n : runExecution(em)\n}\n\n/**\n * Complete a workflow instance with final status\n *\n * @param em - Entity manager\n * @param container\n * @param instanceId - Workflow instance ID\n * @param status - Final status (COMPLETED, FAILED, CANCELLED)\n * @param result - Optional result data\n */\nexport async function completeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED',\n result?: any\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)\n if (status === 'FAILED') {\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n\n if (definition && checkIfCompensationNeeded(definition)) {\n try {\n\n // Set error message before compensation\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n await em.flush()\n }\n\n const compensationResult = await compensateWorkflow(\n em,\n container,\n instance,\n definition,\n {\n continueOnError: true // Best-effort compensation\n }\n )\n\n logger.info('Compensation finished', {\n status: compensationResult.status,\n compensatedActivities: compensationResult.compensatedActivities,\n totalActivities: compensationResult.totalActivities,\n })\n\n // Note: instance status already updated by compensateWorkflow\n // It will be COMPENSATED or remain FAILED\n return\n } catch (error: any) {\n logger.error('Compensation failed with exception', { err: error })\n // Continue to mark workflow as failed\n }\n }\n }\n\n // Original completion logic (no compensation needed or status is COMPLETED/CANCELLED)\n const now = new Date()\n instance.status = status\n instance.updatedAt = now\n\n switch (status) {\n case 'COMPLETED':\n instance.completedAt = now\n if (result) {\n instance.context = { ...instance.context, __result: result }\n }\n break\n\n case 'FAILED':\n instance.completedAt = now\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n }\n break\n\n case 'CANCELLED':\n instance.cancelledAt = now\n break\n }\n\n await em.flush()\n\n // Log completion event\n const eventType =\n status === 'COMPLETED'\n ? 'WORKFLOW_COMPLETED'\n : status === 'FAILED'\n ? 'WORKFLOW_FAILED'\n : 'WORKFLOW_CANCELLED'\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instanceId,\n eventType,\n eventData: result || {},\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Resume workflow after async activities complete\n *\n * Called by the activity worker after all async activities finish execution.\n * Checks if all activities are done, merges outputs into context, and resumes execution.\n *\n * @param em - Entity manager\n * @param container - DI container\n * @param instanceId - Workflow instance ID\n */\nexport async function resumeWorkflowAfterActivities(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n branchInstanceId?: string | null\n): Promise<void> {\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n\n // Branch-scoped async resume: the instance is FORKED and the branch (not the\n // instance) is WAITING_FOR_ACTIVITIES. Resume just that branch, then let the\n // interleaved loop continue. Missing branchInstanceId \u2192 legacy instance path.\n if (branchInstanceId) {\n const { resumeBranchAfterActivities } = await import('./parallel-handler')\n const branchResume = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => resumeBranchAfterActivities(trx, container, instanceId, branchInstanceId))\n : await resumeBranchAfterActivities(em, container, instanceId, branchInstanceId)\n if (branchResume.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n return\n }\n\n const runResume = async (trx: EntityManager): Promise<{ continueExecution: boolean }> => {\n const instance = await trx.findOne(WorkflowInstance, {\n id: instanceId,\n status: 'WAITING_FOR_ACTIVITIES',\n }, { lockMode: LockMode.PESSIMISTIC_WRITE })\n\n if (!instance) {\n throw new Error('Workflow instance not waiting for activities')\n }\n\n const pendingJobIds = (instance.context._pendingAsyncActivities as any[]) || []\n\n const completedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n const failedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n const totalProcessed = completedActivities + failedActivities\n\n if (totalProcessed < pendingJobIds.length) {\n throw new Error('Activities still pending')\n }\n\n if (failedActivities > 0) {\n const failedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n instance.status = 'FAILED'\n instance.errorMessage = `${failedActivities} async activities failed`\n instance.errorDetails = {\n failedActivities: failedEvents.map(e => ({\n activityId: e.eventData.activityId,\n error: e.eventData.error,\n jobId: e.eventData.jobId,\n })),\n }\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: {\n reason: 'Async activities failed',\n failedActivities: instance.errorDetails.failedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: false }\n }\n\n const completedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n for (const event of completedEvents) {\n if (event.eventData.output) {\n instance.context = {\n ...instance.context,\n [`${event.eventData.activityId}_result`]: event.eventData.output,\n }\n }\n }\n\n delete instance.context._pendingAsyncActivities\n\n const pendingTransition = instance.pendingTransition\n\n if (!pendingTransition) {\n logger.warn('No pending transition found during resume')\n instance.status = 'RUNNING'\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'All async activities completed',\n completedActivities: completedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: true }\n }\n\n logger.debug('Completing pending transition', {\n toStepId: pendingTransition.toStepId,\n fromStepId: instance.currentStepId,\n })\n\n const definition = await trx.findOneOrFail(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)\n\n instance.currentStepId = pendingTransition.toStepId\n instance.status = 'RUNNING'\n instance.pendingTransition = null\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: pendingTransition.toStepId,\n stepName: step?.stepName,\n stepType: step?.stepType,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'Async activities completed, resuming pending transition',\n completedActivities: completedActivities,\n completedTransitionTo: pendingTransition.toStepId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { executeStep } = await import('./step-handler')\n await executeStep(\n trx,\n instance,\n pendingTransition.toStepId,\n {\n workflowContext: instance.context || {},\n userId: undefined,\n },\n container\n )\n\n return { continueExecution: true }\n }\n\n const resumeResult = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => runResume(trx))\n : await runResume(em)\n\n if (resumeResult.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n}\n\n/**\n * Check if workflow definition has any compensatable activities\n */\nfunction checkIfCompensationNeeded(definition: WorkflowDefinition): boolean {\n // Check if any activities have compensation defined\n for (const transition of definition.definition.transitions) {\n if (transition.activities) {\n for (const activity of transition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n }\n\n // Check root-level activities (legacy)\n if (definition.definition.activities) {\n for (const activity of definition.definition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get workflow instance by ID\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @returns Workflow instance or null if not found\n */\nexport async function getWorkflowInstance(\n em: EntityManager,\n instanceId: string\n): Promise<WorkflowInstance | null> {\n return em.findOne(WorkflowInstance, { id: instanceId })\n}\n\nasync function getWorkflowInstanceForExecution(\n em: EntityManager,\n instanceId: string,\n options?: { refresh?: boolean }\n): Promise<WorkflowInstance | null> {\n return em.findOne(\n WorkflowInstance,\n { id: instanceId },\n {\n lockMode: LockMode.PESSIMISTIC_WRITE,\n ...(options?.refresh ? { refresh: true } : {}),\n }\n )\n}\n\n/**\n * Update workflow context with new data\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @param updates - Context updates (merged with existing context)\n */\nexport async function updateWorkflowContext(\n em: EntityManager,\n instanceId: string,\n updates: Record<string, any>\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n}\n\n// findWorkflowDefinition is imported from ./find-definition\n\n/**\n * Log workflow event to event sourcing table\n *\n * @param em - Entity manager\n * @param event - Event data\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId?: string\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 - Workflow Executor Service\n *\n * Main orchestrator for workflow execution. Handles workflow lifecycle:\n * - Starting workflow instances from definitions\n * - Executing workflow steps and transitions\n * - Completing workflows with final status\n * - Triggering compensation on failure\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager, LockMode } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n WorkflowDefinition,\n WorkflowInstance,\n WorkflowEvent,\n type WorkflowInstanceStatus,\n} from '../data/entities'\nimport { compensateWorkflow } from './compensation-handler'\nimport { findWorkflowDefinition, findDefinitionForInstance } from './find-definition'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StartWorkflowOptions {\n workflowId: string\n version?: number // Default to latest enabled version\n initialContext?: Record<string, any>\n correlationKey?: string\n metadata?: {\n entityType?: string\n entityId?: string\n initiatedBy?: string\n labels?: Record<string, string>\n }\n tenantId: string\n organizationId: string\n}\n\nexport interface ExecutionContext {\n userId?: string\n dryRun?: boolean\n timeout?: number\n}\n\nexport interface ExecutionResult {\n status: WorkflowInstanceStatus\n currentStep: string\n context: Record<string, any>\n events: WorkflowEventSummary[]\n errors?: string[]\n executionTime: number\n}\n\nexport interface WorkflowEventSummary {\n eventType: string\n occurredAt: Date\n data?: any\n}\n\nexport class WorkflowExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'WorkflowExecutionError'\n }\n}\n\n// ============================================================================\n// Main Orchestration Functions\n// ============================================================================\n\n/**\n * Start a new workflow instance from a definition\n *\n * @param em - Entity manager for database operations\n * @param options - Workflow start options\n * @returns Created workflow instance\n * @throws WorkflowExecutionError if definition not found or validation fails\n */\nexport async function startWorkflow(\n em: EntityManager,\n options: StartWorkflowOptions\n): Promise<WorkflowInstance> {\n const {\n workflowId,\n version,\n initialContext = {},\n correlationKey,\n metadata,\n tenantId,\n organizationId,\n } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${workflowId}${version ? ` v${version}` : ''}`,\n 'DEFINITION_NOT_FOUND',\n { workflowId, version }\n )\n }\n\n if (!definition.enabled) {\n throw new WorkflowExecutionError(\n `Workflow definition is disabled: ${workflowId}`,\n 'DEFINITION_DISABLED',\n { workflowId, version: definition.version }\n )\n }\n\n // Validate definition has required steps\n const { steps, transitions } = definition.definition\n if (!steps || steps.length < 2) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least START and END steps',\n 'INVALID_DEFINITION',\n { workflowId, stepsCount: steps?.length || 0 }\n )\n }\n\n if (!transitions || transitions.length < 1) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least one transition',\n 'INVALID_DEFINITION',\n { workflowId, transitionsCount: transitions?.length || 0 }\n )\n }\n\n // Find START step\n const startStep = steps.find((s: any) => s.stepType === 'START')\n if (!startStep) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have a START step',\n 'INVALID_DEFINITION',\n { workflowId }\n )\n }\n\n // Validate START step pre-conditions if defined\n if (startStep.preConditions && startStep.preConditions.length > 0) {\n const { validateWorkflowStart } = await import('./start-validator')\n\n const validationResult = await validateWorkflowStart(em, {\n workflowId,\n version: definition.version,\n context: initialContext,\n tenantId,\n organizationId,\n })\n\n if (!validationResult.canStart) {\n throw new WorkflowExecutionError(\n `Workflow start pre-conditions failed: ${validationResult.errors.map(e => e.message).join('; ')}`,\n 'START_PRE_CONDITIONS_FAILED',\n {\n workflowId,\n errors: validationResult.errors,\n validatedRules: validationResult.validatedRules,\n }\n )\n }\n }\n\n // Create workflow instance\n const now = new Date()\n const instance = em.create(WorkflowInstance, {\n definitionId: definition.id,\n workflowId: definition.workflowId,\n version: definition.version,\n status: 'RUNNING',\n currentStepId: startStep.stepId,\n context: initialContext,\n correlationKey,\n metadata,\n startedAt: now,\n retryCount: 0,\n tenantId,\n organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(instance).flush()\n\n // Log WORKFLOW_STARTED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'WORKFLOW_STARTED',\n eventData: {\n workflowId: instance.workflowId,\n version: instance.version,\n startStepId: startStep.stepId,\n initialContext,\n metadata,\n },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n\n return instance\n}\n\n/**\n * Execute a workflow instance\n *\n * Main execution loop that processes steps and transitions until:\n * - Workflow completes (reaches END step)\n * - Workflow waits (USER_TASK, SIGNAL, TIMER)\n * - Workflow fails (error occurs)\n * - Timeout is reached\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution and other services)\n * @param instanceId - Workflow instance ID\n * @param context - Execution context (userId, dryRun, timeout)\n * @returns Execution result with status and events\n */\nexport async function executeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n context?: ExecutionContext\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(\n callback: (trx: EntityManager) => Promise<TResult>,\n ) => Promise<TResult>\n }\n\n const runExecution = async (trx: EntityManager): Promise<ExecutionResult> => {\n const events: WorkflowEventSummary[] = []\n const errors: string[] = []\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status === 'COMPLETED') {\n return {\n status: 'COMPLETED',\n currentStep: instance.currentStepId,\n context: instance.context,\n events: [],\n executionTime: 0,\n }\n }\n\n if (instance.status === 'CANCELLED') {\n throw new WorkflowExecutionError(\n 'Cannot execute cancelled workflow',\n 'WORKFLOW_CANCELLED',\n { instanceId, status: instance.status }\n )\n }\n\n const definition = await findDefinitionForInstance(trx, instance)\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const maxIterations = 100\n let iterations = 0\n\n while (iterations < maxIterations) {\n iterations++\n\n const currentInstance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: iterations > 1 })\n if (!currentInstance) {\n throw new WorkflowExecutionError(\n 'Instance not found during execution',\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Parallel execution: while the instance is FORKED, drive the branches.\n if (currentInstance.status === 'FORKED') {\n const { advanceBranches } = await import('./parallel-handler')\n const branchResult = await advanceBranches(trx, container, currentInstance, definition, {\n userId: context?.userId,\n })\n\n if (branchResult.outcome === 'joined') {\n // Instance resumed at the post-join step; continue single-token.\n continue\n }\n\n if (branchResult.outcome === 'failed') {\n errors.push(branchResult.error || 'Parallel branch failed')\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: branchResult.error || 'Parallel branch failed',\n })\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n // 'waiting' \u2014 all branches paused for external resume (task/signal/timer/async).\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const currentStep = definition.definition.steps.find(\n (s: any) => s.stepId === currentInstance.currentStepId\n )\n\n if (currentStep?.stepType === 'END') {\n await completeWorkflow(trx, container, instanceId, 'COMPLETED')\n events.push({\n eventType: 'WORKFLOW_COMPLETED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'COMPLETED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (\n currentStep?.stepType === 'USER_TASK' ||\n currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||\n currentStep?.stepType === 'WAIT_FOR_TIMER'\n ) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitions = definition.definition.transitions.filter(\n (t: any) =>\n t.fromStepId === currentInstance.currentStepId &&\n t.trigger === 'auto'\n )\n\n if (transitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitionHandler = await import('./transition-handler')\n const evalContext: any = {\n workflowContext: currentInstance.context,\n userId: context?.userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n trx,\n currentInstance,\n currentInstance.currentStepId!,\n evalContext\n )\n\n const validAutoTransitions = validTransitions.filter(\n (vt) => vt.isValid && vt.transition?.trigger === 'auto'\n )\n\n if (validAutoTransitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const selectedTransition = validAutoTransitions[0].transition\n\n try {\n const transitionResult = await transitionHandler.executeTransition(\n trx,\n container,\n currentInstance,\n selectedTransition.fromStepId,\n selectedTransition.toStepId,\n evalContext\n )\n\n if (!transitionResult.success) {\n const rejectionMessage = transitionResult.error || 'Transition failed'\n logger.error('Transition rejected', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: rejectionMessage,\n })\n errors.push(rejectionMessage)\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: rejectionMessage,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n events.push({\n eventType: 'TRANSITION_EXECUTED',\n occurredAt: new Date(),\n data: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n transitionId: selectedTransition.transitionId,\n },\n })\n\n if (transitionResult.pausedForActivities) {\n await logWorkflowEvent(trx, {\n workflowInstanceId: currentInstance.id,\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n eventData: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n pausedAtTransition: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n },\n },\n tenantId: currentInstance.tenantId,\n organizationId: currentInstance.organizationId,\n })\n\n events.push({\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n occurredAt: new Date(),\n data: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n },\n })\n\n return {\n status: 'WAITING_FOR_ACTIVITIES',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n await trx.flush()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Transition execution failed', {\n instanceId: currentInstance.id,\n workflowId: currentInstance.workflowId,\n fromStepId: currentInstance.currentStepId,\n toStepId: selectedTransition.toStepId,\n err: error,\n })\n errors.push(errorMessage)\n\n events.push({\n eventType: 'TRANSITION_FAILED',\n occurredAt: new Date(),\n data: {\n transitionId: selectedTransition.transitionId,\n error: errorMessage,\n },\n })\n\n await completeWorkflow(trx, container, instanceId, 'FAILED', {\n error: errorMessage,\n details: error instanceof WorkflowExecutionError ? error.details : undefined,\n })\n events.push({\n eventType: 'WORKFLOW_FAILED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n errors.push('Maximum execution iterations reached - possible infinite loop')\n return {\n status: 'RUNNING',\n currentStep: instance.currentStepId,\n context: instance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error('Execution failed', { instanceId, err: error })\n errors.push(errorMessage)\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: true })\n if (instance && instance.status === 'RUNNING') {\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n logger.error('Failed to update instance with error state', { instanceId, err: updateError })\n }\n\n throw error\n }\n }\n\n return typeof transactionalEm.transactional === 'function'\n ? transactionalEm.transactional((trx) => runExecution(trx))\n : runExecution(em)\n}\n\n/**\n * Complete a workflow instance with final status\n *\n * @param em - Entity manager\n * @param container\n * @param instanceId - Workflow instance ID\n * @param status - Final status (COMPLETED, FAILED, CANCELLED)\n * @param result - Optional result data\n */\nexport async function completeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED',\n result?: any\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)\n if (status === 'FAILED') {\n const definition = await findDefinitionForInstance(em, instance)\n\n if (definition && checkIfCompensationNeeded(definition)) {\n try {\n\n // Set error message before compensation\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n await em.flush()\n }\n\n const compensationResult = await compensateWorkflow(\n em,\n container,\n instance,\n definition,\n {\n continueOnError: true // Best-effort compensation\n }\n )\n\n logger.info('Compensation finished', {\n status: compensationResult.status,\n compensatedActivities: compensationResult.compensatedActivities,\n totalActivities: compensationResult.totalActivities,\n })\n\n // Note: instance status already updated by compensateWorkflow\n // It will be COMPENSATED or remain FAILED\n return\n } catch (error: any) {\n logger.error('Compensation failed with exception', { err: error })\n // Continue to mark workflow as failed\n }\n }\n }\n\n // Original completion logic (no compensation needed or status is COMPLETED/CANCELLED)\n const now = new Date()\n instance.status = status\n instance.updatedAt = now\n\n switch (status) {\n case 'COMPLETED':\n instance.completedAt = now\n if (result) {\n instance.context = { ...instance.context, __result: result }\n }\n break\n\n case 'FAILED':\n instance.completedAt = now\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n }\n break\n\n case 'CANCELLED':\n instance.cancelledAt = now\n break\n }\n\n await em.flush()\n\n // Log completion event\n const eventType =\n status === 'COMPLETED'\n ? 'WORKFLOW_COMPLETED'\n : status === 'FAILED'\n ? 'WORKFLOW_FAILED'\n : 'WORKFLOW_CANCELLED'\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instanceId,\n eventType,\n eventData: result || {},\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Resume workflow after async activities complete\n *\n * Called by the activity worker after all async activities finish execution.\n * Checks if all activities are done, merges outputs into context, and resumes execution.\n *\n * @param em - Entity manager\n * @param container - DI container\n * @param instanceId - Workflow instance ID\n */\nexport async function resumeWorkflowAfterActivities(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n branchInstanceId?: string | null\n): Promise<void> {\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n\n // Branch-scoped async resume: the instance is FORKED and the branch (not the\n // instance) is WAITING_FOR_ACTIVITIES. Resume just that branch, then let the\n // interleaved loop continue. Missing branchInstanceId \u2192 legacy instance path.\n if (branchInstanceId) {\n const { resumeBranchAfterActivities } = await import('./parallel-handler')\n const branchResume = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => resumeBranchAfterActivities(trx, container, instanceId, branchInstanceId))\n : await resumeBranchAfterActivities(em, container, instanceId, branchInstanceId)\n if (branchResume.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n return\n }\n\n const runResume = async (trx: EntityManager): Promise<{ continueExecution: boolean }> => {\n const instance = await trx.findOne(WorkflowInstance, {\n id: instanceId,\n status: 'WAITING_FOR_ACTIVITIES',\n }, { lockMode: LockMode.PESSIMISTIC_WRITE })\n\n if (!instance) {\n throw new Error('Workflow instance not waiting for activities')\n }\n\n const pendingJobIds = (instance.context._pendingAsyncActivities as any[]) || []\n\n const completedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n const failedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n const totalProcessed = completedActivities + failedActivities\n\n if (totalProcessed < pendingJobIds.length) {\n throw new Error('Activities still pending')\n }\n\n if (failedActivities > 0) {\n const failedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n instance.status = 'FAILED'\n instance.errorMessage = `${failedActivities} async activities failed`\n instance.errorDetails = {\n failedActivities: failedEvents.map(e => ({\n activityId: e.eventData.activityId,\n error: e.eventData.error,\n jobId: e.eventData.jobId,\n })),\n }\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: {\n reason: 'Async activities failed',\n failedActivities: instance.errorDetails.failedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: false }\n }\n\n const completedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n for (const event of completedEvents) {\n if (event.eventData.output) {\n instance.context = {\n ...instance.context,\n [`${event.eventData.activityId}_result`]: event.eventData.output,\n }\n }\n }\n\n delete instance.context._pendingAsyncActivities\n\n const pendingTransition = instance.pendingTransition\n\n if (!pendingTransition) {\n logger.warn('No pending transition found during resume')\n instance.status = 'RUNNING'\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'All async activities completed',\n completedActivities: completedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: true }\n }\n\n logger.debug('Completing pending transition', {\n toStepId: pendingTransition.toStepId,\n fromStepId: instance.currentStepId,\n })\n\n const definition = await findDefinitionForInstance(trx, instance)\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)\n\n instance.currentStepId = pendingTransition.toStepId\n instance.status = 'RUNNING'\n instance.pendingTransition = null\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: pendingTransition.toStepId,\n stepName: step?.stepName,\n stepType: step?.stepType,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'Async activities completed, resuming pending transition',\n completedActivities: completedActivities,\n completedTransitionTo: pendingTransition.toStepId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { executeStep } = await import('./step-handler')\n await executeStep(\n trx,\n instance,\n pendingTransition.toStepId,\n {\n workflowContext: instance.context || {},\n userId: undefined,\n },\n container\n )\n\n return { continueExecution: true }\n }\n\n const resumeResult = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => runResume(trx))\n : await runResume(em)\n\n if (resumeResult.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n}\n\n/**\n * Check if workflow definition has any compensatable activities\n */\nfunction checkIfCompensationNeeded(definition: WorkflowDefinition): boolean {\n // Check if any activities have compensation defined\n for (const transition of definition.definition.transitions) {\n if (transition.activities) {\n for (const activity of transition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n }\n\n // Check root-level activities (legacy)\n if (definition.definition.activities) {\n for (const activity of definition.definition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get workflow instance by ID\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @returns Workflow instance or null if not found\n */\nexport async function getWorkflowInstance(\n em: EntityManager,\n instanceId: string\n): Promise<WorkflowInstance | null> {\n return em.findOne(WorkflowInstance, { id: instanceId })\n}\n\nasync function getWorkflowInstanceForExecution(\n em: EntityManager,\n instanceId: string,\n options?: { refresh?: boolean }\n): Promise<WorkflowInstance | null> {\n return em.findOne(\n WorkflowInstance,\n { id: instanceId },\n {\n lockMode: LockMode.PESSIMISTIC_WRITE,\n ...(options?.refresh ? { refresh: true } : {}),\n }\n )\n}\n\n/**\n * Update workflow context with new data\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @param updates - Context updates (merged with existing context)\n */\nexport async function updateWorkflowContext(\n em: EntityManager,\n instanceId: string,\n updates: Record<string, any>\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n}\n\n// findWorkflowDefinition is imported from ./find-definition\n\n/**\n * Log workflow event to event sourcing table\n *\n * @param em - Entity manager\n * @param event - Event data\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId?: string\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": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
const LEGACY_WORKFLOW_ID = "workflows.checkout-demo";
|
|
3
|
+
const LEGACY_WORKFLOW_NAME = "Checkout with Payment Webhook";
|
|
4
|
+
const LEGACY_ACTIVITY_ID = "reserve_inventory";
|
|
5
|
+
const LEGACY_ACTIVITY_URL = "{{env.INVENTORY_SERVICE_URL}}/api/inventory/reserve";
|
|
6
|
+
const TRANSITIONS_REPLACED_BY_CODE_DEFINITION = [
|
|
7
|
+
"cart_to_customer_info",
|
|
8
|
+
"customer_info_to_payment",
|
|
9
|
+
"confirmation_to_order"
|
|
10
|
+
];
|
|
11
|
+
function legacyCheckoutPredicate() {
|
|
12
|
+
return `
|
|
13
|
+
"wf"."workflow_id" = '${LEGACY_WORKFLOW_ID}'
|
|
14
|
+
and "wf"."workflow_name" = '${LEGACY_WORKFLOW_NAME}'
|
|
15
|
+
and "wf"."version" = 1
|
|
16
|
+
and exists (
|
|
17
|
+
select 1
|
|
18
|
+
from jsonb_array_elements(coalesce("wf"."definition"->'transitions', '[]'::jsonb)) as "transition"("value")
|
|
19
|
+
cross join lateral jsonb_array_elements(coalesce("transition"."value"->'activities', '[]'::jsonb)) as "activity"("value")
|
|
20
|
+
where "activity"."value"->>'activityId' = '${LEGACY_ACTIVITY_ID}'
|
|
21
|
+
and "activity"."value"->>'activityType' = 'CALL_WEBHOOK'
|
|
22
|
+
and "activity"."value"#>>'{config,url}' = '${LEGACY_ACTIVITY_URL}'
|
|
23
|
+
)
|
|
24
|
+
`.trim();
|
|
25
|
+
}
|
|
26
|
+
function buildLegacyCheckoutRepairSql() {
|
|
27
|
+
const strippedTransitionList = TRANSITIONS_REPLACED_BY_CODE_DEFINITION.map((id) => `'${id}'`).join(", ");
|
|
28
|
+
return `
|
|
29
|
+
update "workflow_definitions" as "wf"
|
|
30
|
+
set "definition" = jsonb_set(
|
|
31
|
+
"wf"."definition",
|
|
32
|
+
'{transitions}',
|
|
33
|
+
coalesce(
|
|
34
|
+
(
|
|
35
|
+
select jsonb_agg(
|
|
36
|
+
case
|
|
37
|
+
when "transition"."value"->>'transitionId' in (${strippedTransitionList})
|
|
38
|
+
then "transition"."value" - 'activities'
|
|
39
|
+
else "transition"."value"
|
|
40
|
+
end
|
|
41
|
+
order by "transition"."ordinality"
|
|
42
|
+
)
|
|
43
|
+
from jsonb_array_elements(
|
|
44
|
+
coalesce("wf"."definition"->'transitions', '[]'::jsonb)
|
|
45
|
+
) with ordinality as "transition"("value", "ordinality")
|
|
46
|
+
),
|
|
47
|
+
'[]'::jsonb
|
|
48
|
+
)
|
|
49
|
+
),
|
|
50
|
+
"updated_at" = current_timestamp
|
|
51
|
+
where "wf"."code_workflow_id" is null
|
|
52
|
+
and "wf"."deleted_at" is null
|
|
53
|
+
and ${legacyCheckoutPredicate()};
|
|
54
|
+
`.trim();
|
|
55
|
+
}
|
|
56
|
+
class Migration20260715120000 extends Migration {
|
|
57
|
+
async up() {
|
|
58
|
+
this.addSql(buildLegacyCheckoutRepairSql());
|
|
59
|
+
}
|
|
60
|
+
async down() {
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
Migration20260715120000,
|
|
65
|
+
buildLegacyCheckoutRepairSql,
|
|
66
|
+
legacyCheckoutPredicate
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=Migration20260715120000.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/workflows/migrations/Migration20260715120000.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations'\n\nconst LEGACY_WORKFLOW_ID = 'workflows.checkout-demo'\nconst LEGACY_WORKFLOW_NAME = 'Checkout with Payment Webhook'\nconst LEGACY_ACTIVITY_ID = 'reserve_inventory'\nconst LEGACY_ACTIVITY_URL = '{{env.INVENTORY_SERVICE_URL}}/api/inventory/reserve'\nconst TRANSITIONS_REPLACED_BY_CODE_DEFINITION = [\n 'cart_to_customer_info',\n 'customer_info_to_payment',\n 'confirmation_to_order',\n] as const\n\n/**\n * SQL fragment (for the UPDATE `where` clause) that matches ONLY the exact\n * legacy checkout seed: workflow id, name, version, and the presence of the\n * obsolete `reserve_inventory` `CALL_WEBHOOK` activity with its exact env-based\n * URL. The match is intentionally strict so the repair never touches a row that\n * is not the known-broken seed. A tenant whose persisted row diverges from this\n * fingerprint (renamed, re-versioned, or a different webhook URL) is left\n * untouched \u2014 the trade-off is safety over coverage for an unknown variant.\n */\nexport function legacyCheckoutPredicate(): string {\n return `\n \"wf\".\"workflow_id\" = '${LEGACY_WORKFLOW_ID}'\n and \"wf\".\"workflow_name\" = '${LEGACY_WORKFLOW_NAME}'\n and \"wf\".\"version\" = 1\n and exists (\n select 1\n from jsonb_array_elements(coalesce(\"wf\".\"definition\"->'transitions', '[]'::jsonb)) as \"transition\"(\"value\")\n cross join lateral jsonb_array_elements(coalesce(\"transition\".\"value\"->'activities', '[]'::jsonb)) as \"activity\"(\"value\")\n where \"activity\".\"value\"->>'activityId' = '${LEGACY_ACTIVITY_ID}'\n and \"activity\".\"value\"->>'activityType' = 'CALL_WEBHOOK'\n and \"activity\".\"value\"#>>'{config,url}' = '${LEGACY_ACTIVITY_URL}'\n )\n `.trim()\n}\n\n/**\n * The exact UPDATE the migration runs. Exported so the DB-level regression test\n * (`__integration__/TC-WF-031`) executes the identical SQL against Postgres,\n * making the jsonb transformation itself \u2014 not just its rendered string \u2014\n * the thing under test.\n *\n * It rebuilds the `transitions` array in original order, dropping the\n * `activities` key from exactly the three transitions the maintained code\n * definition made side-effect-free. All other keys (e.g. `preConditions`) and\n * all other transitions \u2014 including `confirmation_to_end`, whose remaining\n * activities are internal (`CALL_API`/`SEND_EMAIL`/`EMIT_EVENT`) and never trip\n * the outbound URL guard \u2014 are preserved verbatim.\n */\nexport function buildLegacyCheckoutRepairSql(): string {\n const strippedTransitionList = TRANSITIONS_REPLACED_BY_CODE_DEFINITION\n .map((id) => `'${id}'`)\n .join(', ')\n return `\n update \"workflow_definitions\" as \"wf\"\n set \"definition\" = jsonb_set(\n \"wf\".\"definition\",\n '{transitions}',\n coalesce(\n (\n select jsonb_agg(\n case\n when \"transition\".\"value\"->>'transitionId' in (${strippedTransitionList})\n then \"transition\".\"value\" - 'activities'\n else \"transition\".\"value\"\n end\n order by \"transition\".\"ordinality\"\n )\n from jsonb_array_elements(\n coalesce(\"wf\".\"definition\"->'transitions', '[]'::jsonb)\n ) with ordinality as \"transition\"(\"value\", \"ordinality\")\n ),\n '[]'::jsonb\n )\n ),\n \"updated_at\" = current_timestamp\n where \"wf\".\"code_workflow_id\" is null\n and \"wf\".\"deleted_at\" is null\n and ${legacyCheckoutPredicate()};\n `.trim()\n}\n\n/**\n * Repairs the former seeded checkout demo after it was renamed to the same ID\n * as the code-defined workflow. The DB-first lookup shadows the current code\n * definition, including its obsolete external inventory webhook.\n *\n * The persisted row must remain active because historical and in-flight\n * workflow instances reference it by definition_id \u2014 a random UUID the\n * code-registry fallback in find-definition.ts deliberately never substitutes.\n * The migration removes the activity arrays from the three transitions that\n * the maintained code definition intentionally made side-effect-free,\n * preserving the row and all instance references while keeping the demo\n * self-contained. (Fresh installs never had this row; they execute the virtual\n * code definition directly via findDefinitionForInstance.)\n *\n * `confirmation_to_end` is deliberately NOT rebuilt: unlike the three stripped\n * transitions it still holds activities in the maintained code definition, and\n * its legacy-only extra (`emit_order_completed`, an internal `EMIT_EVENT`) is\n * harmless \u2014 it emits no external request, so leaving it costs nothing and\n * avoids fragile per-activity surgery that could re-introduce a failure.\n */\nexport class Migration20260715120000 extends Migration {\n override async up(): Promise<void> {\n this.addSql(buildLegacyCheckoutRepairSql())\n }\n\n override async down(): Promise<void> {\n // Forward-only data repair. The removed demo-only activity payloads cannot\n // be reconstructed safely, and restoring obsolete external webhooks would\n // re-open issue #4179.\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAE1B,MAAM,qBAAqB;AAC3B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,0CAA0C;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AACF;AAWO,SAAS,0BAAkC;AAChD,SAAO;AAAA,4BACmB,kBAAkB;AAAA,kCACZ,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAMH,kBAAkB;AAAA;AAAA,qDAEhB,mBAAmB;AAAA;AAAA,IAEpE,KAAK;AACT;AAeO,SAAS,+BAAuC;AACrD,QAAM,yBAAyB,wCAC5B,IAAI,CAAC,OAAO,IAAI,EAAE,GAAG,EACrB,KAAK,IAAI;AACZ,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mEAS0D,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAgB7E,wBAAwB,CAAC;AAAA,IACjC,KAAK;AACT;AAsBO,MAAM,gCAAgC,UAAU;AAAA,EACrD,MAAe,KAAoB;AACjC,SAAK,OAAO,6BAA6B,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAe,OAAsB;AAAA,EAIrC;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
const CODE_WORKFLOW_ID = "workflows.checkout-demo";
|
|
3
|
+
function buildRetireSeededCheckoutDemoSql() {
|
|
4
|
+
return `
|
|
5
|
+
update "workflow_definitions" as "wf"
|
|
6
|
+
set "deleted_at" = current_timestamp,
|
|
7
|
+
"updated_at" = current_timestamp
|
|
8
|
+
where "wf"."workflow_id" = '${CODE_WORKFLOW_ID}'
|
|
9
|
+
and "wf"."code_workflow_id" is null
|
|
10
|
+
and "wf"."deleted_at" is null;
|
|
11
|
+
`.trim();
|
|
12
|
+
}
|
|
13
|
+
class Migration20260716120000 extends Migration {
|
|
14
|
+
async up() {
|
|
15
|
+
this.addSql(buildRetireSeededCheckoutDemoSql());
|
|
16
|
+
}
|
|
17
|
+
async down() {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
Migration20260716120000,
|
|
22
|
+
buildRetireSeededCheckoutDemoSql
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=Migration20260716120000.js.map
|