@open-mercato/core 0.6.5-develop.4516.1.88e6ab71a9 → 0.6.5-develop.4534.1.b459babe6d

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.
Files changed (102) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/step_instance/index.js +2 -0
  3. package/dist/generated/entities/step_instance/index.js.map +2 -2
  4. package/dist/generated/entities/user_task/index.js +2 -0
  5. package/dist/generated/entities/user_task/index.js.map +2 -2
  6. package/dist/generated/entities/workflow_branch_instance/index.js +39 -0
  7. package/dist/generated/entities/workflow_branch_instance/index.js.map +7 -0
  8. package/dist/generated/entities/workflow_event/index.js +2 -0
  9. package/dist/generated/entities/workflow_event/index.js.map +2 -2
  10. package/dist/generated/entities/workflow_instance/index.js +2 -0
  11. package/dist/generated/entities/workflow_instance/index.js.map +2 -2
  12. package/dist/generated/entities.ids.generated.js +1 -0
  13. package/dist/generated/entities.ids.generated.js.map +2 -2
  14. package/dist/generated/entity-fields-registry.js +24 -0
  15. package/dist/generated/entity-fields-registry.js.map +2 -2
  16. package/dist/modules/progress/api/jobs/[id]/route.js +7 -1
  17. package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
  18. package/dist/modules/shipping_carriers/api/cancel/route.js +2 -2
  19. package/dist/modules/shipping_carriers/api/cancel/route.js.map +2 -2
  20. package/dist/modules/shipping_carriers/lib/status-sync.js +8 -1
  21. package/dist/modules/shipping_carriers/lib/status-sync.js.map +2 -2
  22. package/dist/modules/workflows/components/NodeEditDialog.js +3 -1
  23. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  24. package/dist/modules/workflows/components/WorkflowGraphImpl.js +4 -2
  25. package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
  26. package/dist/modules/workflows/components/nodes/ParallelForkNode.js +49 -0
  27. package/dist/modules/workflows/components/nodes/ParallelForkNode.js.map +7 -0
  28. package/dist/modules/workflows/components/nodes/ParallelJoinNode.js +49 -0
  29. package/dist/modules/workflows/components/nodes/ParallelJoinNode.js.map +7 -0
  30. package/dist/modules/workflows/components/nodes/index.js +4 -0
  31. package/dist/modules/workflows/components/nodes/index.js.map +2 -2
  32. package/dist/modules/workflows/data/entities.js +81 -0
  33. package/dist/modules/workflows/data/entities.js.map +2 -2
  34. package/dist/modules/workflows/data/validators.js +146 -1
  35. package/dist/modules/workflows/data/validators.js.map +2 -2
  36. package/dist/modules/workflows/events.js +7 -1
  37. package/dist/modules/workflows/events.js.map +2 -2
  38. package/dist/modules/workflows/lib/activity-executor.js +4 -2
  39. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  40. package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
  41. package/dist/modules/workflows/lib/event-logger.js +2 -0
  42. package/dist/modules/workflows/lib/event-logger.js.map +2 -2
  43. package/dist/modules/workflows/lib/execution-token.js +98 -0
  44. package/dist/modules/workflows/lib/execution-token.js.map +7 -0
  45. package/dist/modules/workflows/lib/node-type-icons.js +14 -5
  46. package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
  47. package/dist/modules/workflows/lib/parallel-handler.js +364 -0
  48. package/dist/modules/workflows/lib/parallel-handler.js.map +7 -0
  49. package/dist/modules/workflows/lib/signal-handler.js +63 -1
  50. package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
  51. package/dist/modules/workflows/lib/step-handler.js +74 -30
  52. package/dist/modules/workflows/lib/step-handler.js.map +2 -2
  53. package/dist/modules/workflows/lib/task-handler.js +26 -0
  54. package/dist/modules/workflows/lib/task-handler.js.map +2 -2
  55. package/dist/modules/workflows/lib/timer-handler.js +26 -1
  56. package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
  57. package/dist/modules/workflows/lib/transition-handler.js +33 -21
  58. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  59. package/dist/modules/workflows/lib/workflow-executor.js +39 -1
  60. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  61. package/dist/modules/workflows/migrations/Migration20260602120000.js +24 -0
  62. package/dist/modules/workflows/migrations/Migration20260602120000.js.map +7 -0
  63. package/dist/modules/workflows/workers/workflow-activities.worker.js +8 -4
  64. package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
  65. package/generated/entities/step_instance/index.ts +1 -0
  66. package/generated/entities/user_task/index.ts +1 -0
  67. package/generated/entities/workflow_branch_instance/index.ts +18 -0
  68. package/generated/entities/workflow_event/index.ts +1 -0
  69. package/generated/entities/workflow_instance/index.ts +1 -0
  70. package/generated/entities.ids.generated.ts +1 -0
  71. package/generated/entity-fields-registry.ts +24 -0
  72. package/package.json +7 -7
  73. package/src/modules/progress/api/jobs/[id]/route.ts +7 -0
  74. package/src/modules/shipping_carriers/api/cancel/route.ts +2 -2
  75. package/src/modules/shipping_carriers/lib/status-sync.ts +19 -0
  76. package/src/modules/workflows/components/NodeEditDialog.tsx +2 -0
  77. package/src/modules/workflows/components/WorkflowGraphImpl.tsx +3 -1
  78. package/src/modules/workflows/components/nodes/ParallelForkNode.tsx +66 -0
  79. package/src/modules/workflows/components/nodes/ParallelJoinNode.tsx +66 -0
  80. package/src/modules/workflows/components/nodes/index.ts +6 -0
  81. package/src/modules/workflows/data/entities.ts +109 -0
  82. package/src/modules/workflows/data/validators.ts +223 -0
  83. package/src/modules/workflows/events.ts +7 -0
  84. package/src/modules/workflows/i18n/de.json +12 -0
  85. package/src/modules/workflows/i18n/en.json +12 -0
  86. package/src/modules/workflows/i18n/es.json +12 -0
  87. package/src/modules/workflows/i18n/pl.json +12 -0
  88. package/src/modules/workflows/lib/activity-executor.ts +8 -2
  89. package/src/modules/workflows/lib/activity-queue-types.ts +3 -0
  90. package/src/modules/workflows/lib/event-logger.ts +3 -0
  91. package/src/modules/workflows/lib/execution-token.ts +166 -0
  92. package/src/modules/workflows/lib/node-type-icons.ts +11 -2
  93. package/src/modules/workflows/lib/parallel-handler.ts +575 -0
  94. package/src/modules/workflows/lib/signal-handler.ts +72 -1
  95. package/src/modules/workflows/lib/step-handler.ts +94 -34
  96. package/src/modules/workflows/lib/task-handler.ts +32 -0
  97. package/src/modules/workflows/lib/timer-handler.ts +30 -1
  98. package/src/modules/workflows/lib/transition-handler.ts +56 -24
  99. package/src/modules/workflows/lib/workflow-executor.ts +53 -1
  100. package/src/modules/workflows/migrations/.snapshot-open-mercato.json +263 -0
  101. package/src/modules/workflows/migrations/Migration20260602120000.ts +25 -0
  102. package/src/modules/workflows/workers/workflow-activities.worker.ts +9 -4
@@ -14,7 +14,7 @@ class StepExecutionError extends Error {
14
14
  this.name = "StepExecutionError";
15
15
  }
16
16
  }
17
- async function enterStep(em, instance, stepId, context) {
17
+ async function enterStep(em, instance, stepId, context, branch) {
18
18
  const definition = await em.findOne(WorkflowDefinition, {
19
19
  id: instance.definitionId
20
20
  });
@@ -36,6 +36,7 @@ async function enterStep(em, instance, stepId, context) {
36
36
  const now = /* @__PURE__ */ new Date();
37
37
  const stepInstance = em.create(StepInstance, {
38
38
  workflowInstanceId: instance.id,
39
+ branchInstanceId: branch ? branch.id : null,
39
40
  stepId: stepDef.stepId,
40
41
  stepName: stepDef.stepName,
41
42
  stepType: stepDef.stepType,
@@ -52,6 +53,7 @@ async function enterStep(em, instance, stepId, context) {
52
53
  await logStepEvent(em, {
53
54
  workflowInstanceId: instance.id,
54
55
  stepInstanceId: stepInstance.id,
56
+ ...branch ? { branchInstanceId: branch.id } : {},
55
57
  eventType: "STEP_ENTERED",
56
58
  eventData: {
57
59
  stepId: stepDef.stepId,
@@ -90,9 +92,9 @@ async function exitStep(em, stepInstance, outputData) {
90
92
  organizationId: stepInstance.organizationId
91
93
  });
92
94
  }
93
- async function executeStep(em, instance, stepId, context, container) {
95
+ async function executeStep(em, instance, stepId, context, container, branch) {
94
96
  try {
95
- const stepInstance = await enterStep(em, instance, stepId, context);
97
+ const stepInstance = await enterStep(em, instance, stepId, context, branch);
96
98
  const definition = await em.findOne(WorkflowDefinition, {
97
99
  id: instance.definitionId
98
100
  });
@@ -117,7 +119,8 @@ async function executeStep(em, instance, stepId, context, container) {
117
119
  stepInstance,
118
120
  stepDef,
119
121
  context,
120
- container
122
+ container,
123
+ branch
121
124
  );
122
125
  if (result.status === "COMPLETED") {
123
126
  await exitStep(em, stepInstance, result.outputData);
@@ -158,7 +161,7 @@ async function executeStep(em, instance, stepId, context, container) {
158
161
  };
159
162
  }
160
163
  }
161
- async function executeStepByType(em, instance, stepInstance, stepDef, context, container) {
164
+ async function executeStepByType(em, instance, stepInstance, stepDef, context, container, branch) {
162
165
  const stepType = stepDef.stepType;
163
166
  switch (stepType) {
164
167
  case "START":
@@ -166,9 +169,9 @@ async function executeStepByType(em, instance, stepInstance, stepDef, context, c
166
169
  case "END":
167
170
  return handleEndStep(stepDef, context);
168
171
  case "AUTOMATED":
169
- return await handleAutomatedStep(em, instance, stepInstance, stepDef, context, container);
172
+ return await handleAutomatedStep(em, instance, stepInstance, stepDef, context, container, branch);
170
173
  case "USER_TASK":
171
- return await handleUserTaskStep(em, instance, stepInstance, stepDef, context);
174
+ return await handleUserTaskStep(em, instance, stepInstance, stepDef, context, branch);
172
175
  case "SUB_WORKFLOW":
173
176
  if (!container) {
174
177
  throw new StepExecutionError(
@@ -179,16 +182,31 @@ async function executeStepByType(em, instance, stepInstance, stepDef, context, c
179
182
  }
180
183
  return await handleSubWorkflowStep(em, container, instance, stepInstance, stepDef, context);
181
184
  case "WAIT_FOR_SIGNAL":
182
- return await handleWaitForSignalStep(em, instance, stepInstance, stepDef, context);
185
+ return await handleWaitForSignalStep(em, instance, stepInstance, stepDef, context, branch);
183
186
  case "WAIT_FOR_TIMER":
184
- return await handleWaitForTimerStep(em, instance, stepInstance, stepDef, context);
185
- case "PARALLEL_FORK":
187
+ return await handleWaitForTimerStep(em, instance, stepInstance, stepDef, context, branch);
188
+ case "PARALLEL_FORK": {
189
+ if (branch) {
190
+ throw new StepExecutionError(
191
+ "Nested PARALLEL_FORK is not supported",
192
+ "NESTED_FORK_NOT_SUPPORTED",
193
+ { stepType, stepId: stepDef.stepId }
194
+ );
195
+ }
196
+ const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId });
197
+ if (!definition) {
198
+ throw new StepExecutionError(
199
+ `Workflow definition not found: ${instance.definitionId}`,
200
+ "DEFINITION_NOT_FOUND",
201
+ { definitionId: instance.definitionId }
202
+ );
203
+ }
204
+ const { openFork } = await import("./parallel-handler.js");
205
+ await openFork(em, instance, definition, stepDef);
206
+ return { status: "WAITING", waitReason: "FORK", outputData: { stepType: "PARALLEL_FORK", forkStepId: stepDef.stepId } };
207
+ }
186
208
  case "PARALLEL_JOIN":
187
- throw new StepExecutionError(
188
- `Step type not yet implemented: ${stepType}`,
189
- "STEP_TYPE_NOT_IMPLEMENTED",
190
- { stepType }
191
- );
209
+ return { status: "COMPLETED", outputData: { stepType: "PARALLEL_JOIN", timestamp: (/* @__PURE__ */ new Date()).toISOString() } };
192
210
  default:
193
211
  throw new StepExecutionError(
194
212
  `Unknown step type: ${stepType}`,
@@ -216,7 +234,7 @@ function handleEndStep(stepDef, context) {
216
234
  }
217
235
  };
218
236
  }
219
- async function handleAutomatedStep(em, instance, stepInstance, stepDef, context, container) {
237
+ async function handleAutomatedStep(em, instance, stepInstance, stepDef, context, container, branch) {
220
238
  const activities = stepDef.activities || [];
221
239
  if (activities.length === 0) {
222
240
  return {
@@ -238,9 +256,15 @@ async function handleAutomatedStep(em, instance, stepInstance, stepDef, context,
238
256
  });
239
257
  const pendingActivities = results.filter((r) => r.async && !r.success);
240
258
  if (pendingActivities.length > 0) {
241
- instance.status = "WAITING_FOR_ACTIVITIES";
242
- instance.pausedAt = /* @__PURE__ */ new Date();
243
- instance.updatedAt = /* @__PURE__ */ new Date();
259
+ const now = /* @__PURE__ */ new Date();
260
+ if (branch) {
261
+ branch.status = "WAITING_FOR_ACTIVITIES";
262
+ branch.updatedAt = now;
263
+ } else {
264
+ instance.status = "WAITING_FOR_ACTIVITIES";
265
+ instance.pausedAt = now;
266
+ instance.updatedAt = now;
267
+ }
244
268
  await em.flush();
245
269
  return {
246
270
  status: "WAITING",
@@ -293,7 +317,7 @@ async function handleAutomatedStep(em, instance, stepInstance, stepDef, context,
293
317
  };
294
318
  }
295
319
  }
296
- async function handleUserTaskStep(em, instance, stepInstance, stepDef, context) {
320
+ async function handleUserTaskStep(em, instance, stepInstance, stepDef, context, branch) {
297
321
  const userTaskConfig = stepDef.userTaskConfig || {};
298
322
  let assignedTo = userTaskConfig.assignedTo || null;
299
323
  let assignedToRoles = userTaskConfig.assignedToRoles || null;
@@ -305,6 +329,7 @@ async function handleUserTaskStep(em, instance, stepInstance, stepDef, context)
305
329
  const userTask = em.create(UserTask, {
306
330
  workflowInstanceId: instance.id,
307
331
  stepInstanceId: stepInstance.id,
332
+ branchInstanceId: branch ? branch.id : null,
308
333
  taskName: stepDef.stepName,
309
334
  description: stepDef.description || null,
310
335
  status: "PENDING",
@@ -322,6 +347,7 @@ async function handleUserTaskStep(em, instance, stepInstance, stepDef, context)
322
347
  await logStepEvent(em, {
323
348
  workflowInstanceId: instance.id,
324
349
  stepInstanceId: stepInstance.id,
350
+ ...branch ? { branchInstanceId: branch.id } : {},
325
351
  eventType: "USER_TASK_CREATED",
326
352
  eventData: {
327
353
  userTaskId: userTask.id,
@@ -332,8 +358,13 @@ async function handleUserTaskStep(em, instance, stepInstance, stepDef, context)
332
358
  tenantId: instance.tenantId,
333
359
  organizationId: instance.organizationId
334
360
  });
335
- instance.status = "PAUSED";
336
- instance.updatedAt = now;
361
+ if (branch) {
362
+ branch.status = "PAUSED";
363
+ branch.updatedAt = now;
364
+ } else {
365
+ instance.status = "PAUSED";
366
+ instance.updatedAt = now;
367
+ }
337
368
  await em.flush();
338
369
  return {
339
370
  status: "WAITING",
@@ -448,7 +479,7 @@ async function handleSubWorkflowStep(em, container, instance, stepInstance, step
448
479
  };
449
480
  }
450
481
  }
451
- async function handleWaitForSignalStep(em, instance, stepInstance, stepDef, context) {
482
+ async function handleWaitForSignalStep(em, instance, stepInstance, stepDef, context, branch) {
452
483
  const signalConfig = stepDef.signalConfig || {};
453
484
  const signalName = signalConfig.signalName || stepDef.stepId;
454
485
  const timeout = signalConfig.timeout ? parseDuration(signalConfig.timeout) : null;
@@ -456,6 +487,7 @@ async function handleWaitForSignalStep(em, instance, stepInstance, stepDef, cont
456
487
  await logStepEvent(em, {
457
488
  workflowInstanceId: instance.id,
458
489
  stepInstanceId: stepInstance.id,
490
+ ...branch ? { branchInstanceId: branch.id } : {},
459
491
  eventType: "SIGNAL_AWAITING",
460
492
  eventData: {
461
493
  signalName,
@@ -466,9 +498,14 @@ async function handleWaitForSignalStep(em, instance, stepInstance, stepDef, cont
466
498
  tenantId: instance.tenantId,
467
499
  organizationId: instance.organizationId
468
500
  });
469
- instance.status = "PAUSED";
470
- instance.pausedAt = now;
471
- instance.updatedAt = now;
501
+ if (branch) {
502
+ branch.status = "PAUSED";
503
+ branch.updatedAt = now;
504
+ } else {
505
+ instance.status = "PAUSED";
506
+ instance.pausedAt = now;
507
+ instance.updatedAt = now;
508
+ }
472
509
  await em.flush();
473
510
  return {
474
511
  status: "WAITING",
@@ -480,7 +517,7 @@ async function handleWaitForSignalStep(em, instance, stepInstance, stepDef, cont
480
517
  }
481
518
  };
482
519
  }
483
- async function handleWaitForTimerStep(em, instance, stepInstance, stepDef, context) {
520
+ async function handleWaitForTimerStep(em, instance, stepInstance, stepDef, context, branch) {
484
521
  const timerConfig = stepDef.config || stepDef.timerConfig || {};
485
522
  const duration = timerConfig.duration;
486
523
  const until = timerConfig.until;
@@ -524,6 +561,7 @@ async function handleWaitForTimerStep(em, instance, stepInstance, stepDef, conte
524
561
  const jobId = await enqueueTimerJob({
525
562
  workflowInstanceId: instance.id,
526
563
  stepInstanceId: stepInstance.id,
564
+ branchInstanceId: branch ? branch.id : void 0,
527
565
  tenantId: instance.tenantId,
528
566
  organizationId: instance.organizationId,
529
567
  userId: context.userId,
@@ -533,6 +571,7 @@ async function handleWaitForTimerStep(em, instance, stepInstance, stepDef, conte
533
571
  await logWorkflowEvent(em, {
534
572
  workflowInstanceId: instance.id,
535
573
  stepInstanceId: stepInstance.id,
574
+ ...branch ? { branchInstanceId: branch.id } : {},
536
575
  eventType: "TIMER_AWAITING",
537
576
  eventData: {
538
577
  fireAt: fireAt.toISOString(),
@@ -544,9 +583,14 @@ async function handleWaitForTimerStep(em, instance, stepInstance, stepDef, conte
544
583
  tenantId: instance.tenantId,
545
584
  organizationId: instance.organizationId
546
585
  });
547
- instance.status = "PAUSED";
548
- instance.pausedAt = now;
549
- instance.updatedAt = now;
586
+ if (branch) {
587
+ branch.status = "PAUSED";
588
+ branch.updatedAt = now;
589
+ } else {
590
+ instance.status = "PAUSED";
591
+ instance.pausedAt = now;
592
+ instance.updatedAt = now;
593
+ }
550
594
  await em.flush();
551
595
  return {
552
596
  status: "WAITING",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/step-handler.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module - Step Handler Service\n *\n * Handles individual workflow step execution:\n * - Creating step instances when entering a step\n * - Executing step logic based on step type (START, END, AUTOMATED, USER_TASK)\n * - Completing step instances when exiting\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport {\n WorkflowInstance,\n WorkflowDefinition,\n StepInstance,\n UserTask,\n WorkflowEvent,\n type StepInstanceStatus,\n type WorkflowStepType,\n} from '../data/entities'\nimport { parseDuration } from './duration'\nimport { logWorkflowEvent } from './event-logger'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StepExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface StepExecutionResult {\n status: 'COMPLETED' | 'WAITING' | 'FAILED'\n outputData?: any\n nextSteps?: string[] // For parallel forks (Phase 7)\n waitReason?: 'USER_TASK' | 'SIGNAL' | 'TIMER'\n error?: string\n}\n\nexport class StepExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'StepExecutionError'\n }\n}\n\n// ============================================================================\n// Main Step Execution Functions\n// ============================================================================\n\n/**\n * Enter a workflow step - create step instance and mark as ACTIVE\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to enter\n * @param context - Execution context\n * @returns Created step instance\n */\nexport async function enterStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext\n): Promise<StepInstance> {\n // Load workflow definition to get step details\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find step in definition\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found in workflow definition: ${stepId}`,\n 'STEP_NOT_FOUND',\n { workflowId: definition.workflowId, stepId }\n )\n }\n\n const now = new Date()\n\n // Create step instance\n const stepInstance = em.create(StepInstance, {\n workflowInstanceId: instance.id,\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n status: 'ACTIVE',\n inputData: context.triggerData || null,\n enteredAt: now,\n retryCount: 0,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(stepInstance).flush()\n\n // Log STEP_ENTERED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return stepInstance\n}\n\n/**\n * Exit a workflow step - mark as completed and record timing\n *\n * @param em - Entity manager\n * @param stepInstance - Step instance to exit\n * @param outputData - Optional output data from step execution\n */\nexport async function exitStep(\n em: EntityManager,\n stepInstance: StepInstance,\n outputData?: any\n): Promise<void> {\n const now = new Date()\n\n // Calculate execution time if we have enteredAt\n let executionTimeMs: number | null = null\n if (stepInstance.enteredAt) {\n executionTimeMs = now.getTime() - stepInstance.enteredAt.getTime()\n }\n\n // Update step instance\n stepInstance.status = 'COMPLETED'\n stepInstance.outputData = outputData || null\n stepInstance.exitedAt = now\n stepInstance.executionTimeMs = executionTimeMs\n stepInstance.updatedAt = now\n\n await em.flush()\n\n // Log STEP_EXITED event\n await logStepEvent(em, {\n workflowInstanceId: stepInstance.workflowInstanceId,\n stepInstanceId: stepInstance.id,\n eventType: 'STEP_EXITED',\n eventData: {\n stepId: stepInstance.stepId,\n status: 'COMPLETED',\n executionTimeMs,\n hasOutput: !!outputData,\n },\n tenantId: stepInstance.tenantId,\n organizationId: stepInstance.organizationId,\n })\n}\n\n/**\n * Execute a workflow step based on its type\n *\n * Main entry point for step execution. Handles:\n * - START: Immediate completion\n * - END: Workflow completion\n * - AUTOMATED: Activity execution (MVP: immediate completion)\n * - USER_TASK: Create user task and wait\n * - SUB_WORKFLOW: Invoke child workflow\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to execute\n * @param context - Execution context\n * @param container - DI container (required for SUB_WORKFLOW steps)\n * @returns Execution result with status and output\n */\nexport async function executeStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n container?: any\n): Promise<StepExecutionResult> {\n try {\n // Enter the step (create step instance)\n const stepInstance = await enterStep(em, instance, stepId, context)\n\n // Load workflow definition to get step configuration\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found: ${stepId}`,\n 'STEP_NOT_FOUND',\n { stepId }\n )\n }\n\n // Execute based on step type\n const result = await executeStepByType(\n em,\n instance,\n stepInstance,\n stepDef,\n context,\n container\n )\n\n // If step completed, exit it\n if (result.status === 'COMPLETED') {\n await exitStep(em, stepInstance, result.outputData)\n }\n\n return result\n } catch (error) {\n // Handle step execution errors\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n // Try to mark step as failed if we have a step instance\n try {\n const failedStepInstance = await em.findOne(StepInstance, {\n workflowInstanceId: instance.id,\n stepId,\n status: 'ACTIVE',\n })\n\n if (failedStepInstance) {\n failedStepInstance.status = 'FAILED'\n failedStepInstance.errorData = {\n error: errorMessage,\n details: error instanceof StepExecutionError ? error.details : undefined,\n }\n failedStepInstance.exitedAt = new Date()\n failedStepInstance.updatedAt = new Date()\n await em.flush()\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: failedStepInstance.id,\n eventType: 'STEP_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n // Swallow update errors to preserve original error\n console.error('Failed to update step instance with error:', updateError)\n }\n\n return {\n status: 'FAILED',\n error: errorMessage,\n }\n }\n}\n\n// ============================================================================\n// Step Type Handlers\n// ============================================================================\n\n/**\n * Execute step based on its type\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepInstance - Step instance\n * @param stepDef - Step definition from workflow\n * @param context - Execution context\n * @returns Execution result\n */\nasync function executeStepByType(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any\n): Promise<StepExecutionResult> {\n const stepType: WorkflowStepType = stepDef.stepType\n\n switch (stepType) {\n case 'START':\n return handleStartStep(stepDef, context)\n\n case 'END':\n return handleEndStep(stepDef, context)\n\n case 'AUTOMATED':\n return await handleAutomatedStep(em, instance, stepInstance, stepDef, context, container)\n\n case 'USER_TASK':\n return await handleUserTaskStep(em, instance, stepInstance, stepDef, context)\n\n case 'SUB_WORKFLOW':\n if (!container) {\n throw new StepExecutionError(\n 'Container required for SUB_WORKFLOW execution',\n 'CONTAINER_REQUIRED',\n { stepType }\n )\n }\n return await handleSubWorkflowStep(em, container, instance, stepInstance, stepDef, context)\n\n case 'WAIT_FOR_SIGNAL':\n return await handleWaitForSignalStep(em, instance, stepInstance, stepDef, context)\n\n case 'WAIT_FOR_TIMER':\n return await handleWaitForTimerStep(em, instance, stepInstance, stepDef, context)\n\n case 'PARALLEL_FORK':\n case 'PARALLEL_JOIN':\n // These will be implemented in later phases\n throw new StepExecutionError(\n `Step type not yet implemented: ${stepType}`,\n 'STEP_TYPE_NOT_IMPLEMENTED',\n { stepType }\n )\n\n default:\n throw new StepExecutionError(\n `Unknown step type: ${stepType}`,\n 'UNKNOWN_STEP_TYPE',\n { stepType }\n )\n }\n}\n\n/**\n * Handle START step - no-op, immediately complete\n */\nfunction handleStartStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'START',\n timestamp: new Date().toISOString(),\n },\n }\n}\n\n/**\n * Handle END step - mark as complete\n */\nfunction handleEndStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'END',\n timestamp: new Date().toISOString(),\n finalContext: context.workflowContext,\n },\n }\n}\n\n/**\n * Handle AUTOMATED step - execute activities\n *\n * Executes activities defined in step configuration.\n * Supports both sync and async activities.\n */\nasync function handleAutomatedStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any\n): Promise<StepExecutionResult> {\n // Extract activities from step definition\n const activities = stepDef.activities || []\n\n if (activities.length === 0) {\n // No activities defined - immediate completion (legacy behavior)\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n },\n }\n }\n\n // Import activity executor\n const { executeActivities } = await import('./activity-executor')\n\n try {\n // Execute activities with proper context\n const results = await executeActivities(em, container, activities, {\n workflowInstance: instance,\n workflowContext: context.workflowContext,\n stepContext: { stepId: stepDef.stepId, stepName: stepDef.stepName },\n stepInstanceId: stepInstance.id,\n userId: context.userId,\n })\n\n // Check if there are pending async activities\n const pendingActivities = results.filter(r => r.async && !r.success)\n if (pendingActivities.length > 0) {\n // Workflow should pause and wait for async activities\n instance.status = 'WAITING_FOR_ACTIVITIES'\n instance.pausedAt = new Date()\n instance.updatedAt = new Date()\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL', // Reuse SIGNAL wait reason (will be resumed by activity completion)\n outputData: {\n pendingActivities: pendingActivities.map(r => ({\n activityId: r.activityId,\n activityName: r.activityName,\n jobId: r.jobId,\n })),\n },\n }\n }\n\n // Check for failures in sync activities\n const failures = results.filter(r => !r.success && !r.async)\n if (failures.length > 0) {\n const errorMessages = failures.map(f => `${f.activityName || f.activityId}: ${f.error}`).join('; ')\n return {\n status: 'FAILED',\n error: `${failures.length} activity(ies) failed: ${errorMessages}`,\n outputData: {\n failures: failures.map(f => ({\n activityId: f.activityId,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n },\n }\n }\n\n // All activities completed successfully\n const activityOutputs = results.reduce((acc, r) => {\n if (r.output) {\n acc[r.activityId] = r.output\n }\n return acc\n }, {} as Record<string, any>)\n\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n activityResults: activityOutputs,\n activityCount: results.length,\n },\n }\n } catch (error: any) {\n return {\n status: 'FAILED',\n error: `Activity execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle USER_TASK step - create user task and enter waiting state\n *\n * Creates a UserTask entity and returns WAITING status.\n * The workflow will pause until the task is completed by a user.\n */\nasync function handleUserTaskStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const userTaskConfig = stepDef.userTaskConfig || {}\n\n // Handle assignedTo - if it's an array, treat it as roles\n let assignedTo = userTaskConfig.assignedTo || null\n let assignedToRoles = userTaskConfig.assignedToRoles || null\n\n if (Array.isArray(assignedTo)) {\n assignedToRoles = assignedTo\n assignedTo = null\n }\n\n // Create user task\n const now = new Date()\n const userTask = em.create(UserTask, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n taskName: stepDef.stepName,\n description: stepDef.description || null,\n status: 'PENDING',\n formSchema: userTaskConfig.formSchema || null,\n formData: null,\n assignedTo: assignedTo,\n assignedToRoles: assignedToRoles,\n dueDate: userTaskConfig.slaDuration ? calculateDueDate(userTaskConfig.slaDuration) : null,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(userTask).flush()\n\n // Log USER_TASK_CREATED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'USER_TASK_CREATED',\n eventData: {\n userTaskId: userTask.id,\n taskName: userTask.taskName,\n assignedTo: userTask.assignedTo,\n assignedToRoles: userTask.assignedToRoles,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause workflow execution - workflow waits for user task completion\n instance.status = 'PAUSED'\n instance.updatedAt = now\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'USER_TASK',\n outputData: {\n userTaskId: userTask.id,\n },\n }\n}\n\n/**\n * Handle SUB_WORKFLOW step - invoke another workflow and wait for completion\n *\n * Creates a child workflow instance with mapped input data,\n * executes it synchronously, and returns mapped output data.\n */\nasync function handleSubWorkflowStep(\n em: EntityManager,\n container: any,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const { subWorkflowId, inputMapping, outputMapping, version } = stepDef.config || {}\n\n if (!subWorkflowId) {\n return {\n status: 'FAILED',\n error: 'Sub-workflow ID not specified in step configuration'\n }\n }\n\n // Map input data from parent context to child context\n const childContext = mapInputData(instance.context, inputMapping || {})\n\n // Import workflow executor functions\n const { startWorkflow, executeWorkflow } = await import('./workflow-executor')\n\n try {\n // Start child workflow with parent metadata\n const childInstance = await startWorkflow(em, {\n workflowId: subWorkflowId,\n version,\n initialContext: childContext,\n correlationKey: instance.correlationKey || undefined,\n metadata: {\n ...instance.metadata,\n labels: {\n ...instance.metadata?.labels,\n parentInstanceId: instance.id,\n parentStepId: stepDef.stepId,\n parentStepInstanceId: stepInstance.id,\n },\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Log sub-workflow invocation event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_STARTED',\n eventData: {\n childInstanceId: childInstance.id,\n subWorkflowId,\n version,\n inputData: childContext,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Execute child workflow synchronously\n const result = await executeWorkflow(em, container, childInstance.id, {\n userId: context.userId,\n })\n\n // Handle child workflow result\n if (result.status === 'COMPLETED') {\n // Map output data from child context to parent context\n const outputData = mapOutputData(result.context, outputMapping || {})\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_COMPLETED',\n eventData: {\n childInstanceId: childInstance.id,\n outputData,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'COMPLETED',\n outputData,\n }\n } else if (result.status === 'FAILED') {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n childInstanceId: childInstance.id,\n error: result.errors?.join(', '),\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow failed: ${result.errors?.join(', ')}`,\n }\n } else {\n // WAITING, PAUSED, etc. - For synchronous execution, treat as error\n return {\n status: 'FAILED',\n error: `Sub-workflow ended in unexpected state: ${result.status}`,\n }\n }\n } catch (error: any) {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n subWorkflowId,\n error: error.message,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle WAIT_FOR_SIGNAL step - pause workflow until signal received\n *\n * Creates a waiting state and pauses the workflow until an external signal\n * with the matching signal name is received. The signal payload will be merged\n * into the workflow context when received.\n */\nasync function handleWaitForSignalStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const signalConfig = stepDef.signalConfig || {}\n const signalName = signalConfig.signalName || stepDef.stepId\n const timeout = signalConfig.timeout ? parseDuration(signalConfig.timeout) : null\n\n const now = new Date()\n\n // Log signal awaiting event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SIGNAL_AWAITING',\n eventData: {\n signalName,\n timeout,\n description: stepDef.description,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause workflow execution\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n await em.flush()\n\n // Return WAITING status to halt executor\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL',\n outputData: {\n signalName,\n timeout,\n awaitingSince: now,\n },\n }\n}\n\n/**\n * Handle WAIT_FOR_TIMER step - pause workflow until a timer fires.\n *\n * Reads `duration` (relative, e.g. \"PT5M\") or `until` (ISO 8601 datetime) from\n * `stepDef.config` (preferred \u2014 matches StepsEditor) or `stepDef.timerConfig`.\n * Enqueues a delayed timer job on the workflow-activities queue; when the job\n * is processed by the activity worker, it calls `timerHandler.fireTimer` to\n * resume the workflow.\n */\nasync function handleWaitForTimerStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const timerConfig = stepDef.config || stepDef.timerConfig || {}\n const duration: string | undefined = timerConfig.duration\n const until: string | undefined = timerConfig.until\n\n if (!duration && !until) {\n throw new StepExecutionError(\n 'WAIT_FOR_TIMER requires either \"duration\" (e.g., \"PT5M\") or \"until\" (ISO 8601 datetime)',\n 'TIMER_CONFIG_MISSING',\n { stepId: stepDef.stepId }\n )\n }\n\n let fireAtMs: number\n if (until) {\n const targetDate = new Date(until)\n if (isNaN(targetDate.getTime())) {\n throw new StepExecutionError(\n `WAIT_FOR_TIMER invalid \"until\" datetime: ${until}`,\n 'TIMER_CONFIG_INVALID',\n { until }\n )\n }\n fireAtMs = targetDate.getTime()\n } else {\n fireAtMs = Date.now() + parseDuration(duration as string)\n }\n\n const delayMs = fireAtMs - Date.now()\n const fireAt = new Date(fireAtMs)\n\n // Immediate-fire path: skip the queue round-trip if the timer is in the past\n if (delayMs <= 0) {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'WAIT_FOR_TIMER',\n timerFiredImmediately: true,\n fireAt,\n duration,\n until,\n },\n }\n }\n\n const now = new Date()\n\n // Enqueue delayed timer job via the shared activity queue.\n // Imported here to avoid a top-level cycle between step-handler and activity-executor.\n const { enqueueTimerJob } = await import('./activity-executor')\n const jobId = await enqueueTimerJob({\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n userId: context.userId,\n fireAt: fireAt.toISOString(),\n delayMs,\n })\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'TIMER_AWAITING',\n eventData: {\n fireAt: fireAt.toISOString(),\n duration: duration || null,\n until: until || null,\n jobId,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'TIMER',\n outputData: {\n fireAt,\n duration,\n until,\n jobId,\n },\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n// parseDuration is imported from ./duration\n\n/**\n * Log step-related event to event sourcing table\n */\nasync function logStepEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Calculate due date from ISO 8601 duration string\n *\n * @param duration - ISO 8601 duration (e.g., \"P1D\" for 1 day)\n * @returns Due date\n */\nfunction calculateDueDate(duration: string): Date {\n // Simple implementation for MVP\n // Supports: P1D (1 day), P1H (1 hour), P1W (1 week)\n const now = new Date()\n\n const daysMatch = duration.match(/P(\\d+)D/)\n if (daysMatch) {\n const days = parseInt(daysMatch[1], 10)\n return new Date(now.getTime() + days * 24 * 60 * 60 * 1000)\n }\n\n const hoursMatch = duration.match(/PT(\\d+)H/)\n if (hoursMatch) {\n const hours = parseInt(hoursMatch[1], 10)\n return new Date(now.getTime() + hours * 60 * 60 * 1000)\n }\n\n const weeksMatch = duration.match(/P(\\d+)W/)\n if (weeksMatch) {\n const weeks = parseInt(weeksMatch[1], 10)\n return new Date(now.getTime() + weeks * 7 * 24 * 60 * 60 * 1000)\n }\n\n // Default: 1 day\n return new Date(now.getTime() + 24 * 60 * 60 * 1000)\n}\n\n/**\n * Get nested value from object using dot notation\n *\n * @param obj - Source object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @returns Value at path or undefined\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj)\n}\n\n/**\n * Set nested value in object using dot notation\n *\n * @param obj - Target object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @param value - Value to set\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.')\n const lastKey = keys.pop()!\n const target = keys.reduce((current, key) => {\n if (!(key in current)) current[key] = {}\n return current[key]\n }, obj)\n target[lastKey] = value\n}\n\n/**\n * Map data from source context using mapping configuration\n *\n * @param sourceContext - Source data object\n * @param mapping - Mapping configuration (targetKey -> sourcePath)\n * @returns Mapped data object\n */\nfunction mapInputData(\n sourceContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n const value = getNestedValue(sourceContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire context\n return Object.keys(result).length > 0 ? result : sourceContext\n}\n\n/**\n * Map output data from child context back to parent\n *\n * @param childContext - Child workflow context\n * @param mapping - Mapping configuration (targetKey -> sourcePath)\n * @returns Mapped output data\n */\nfunction mapOutputData(\n childContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n const value = getNestedValue(childContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire child context\n return Object.keys(result).length > 0 ? result : childContext\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module - Step Handler Service\n *\n * Handles individual workflow step execution:\n * - Creating step instances when entering a step\n * - Executing step logic based on step type (START, END, AUTOMATED, USER_TASK)\n * - Completing step instances when exiting\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport {\n WorkflowInstance,\n WorkflowBranchInstance,\n WorkflowDefinition,\n StepInstance,\n UserTask,\n WorkflowEvent,\n type StepInstanceStatus,\n type WorkflowStepType,\n} from '../data/entities'\nimport { parseDuration } from './duration'\nimport { logWorkflowEvent } from './event-logger'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StepExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface StepExecutionResult {\n status: 'COMPLETED' | 'WAITING' | 'FAILED'\n outputData?: any\n nextSteps?: string[] // For parallel forks (Phase 7)\n waitReason?: 'USER_TASK' | 'SIGNAL' | 'TIMER' | 'FORK'\n error?: string\n}\n\nexport class StepExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'StepExecutionError'\n }\n}\n\n// ============================================================================\n// Main Step Execution Functions\n// ============================================================================\n\n/**\n * Enter a workflow step - create step instance and mark as ACTIVE\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to enter\n * @param context - Execution context\n * @returns Created step instance\n */\nexport async function enterStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepInstance> {\n // Load workflow definition to get step details\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find step in definition\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found in workflow definition: ${stepId}`,\n 'STEP_NOT_FOUND',\n { workflowId: definition.workflowId, stepId }\n )\n }\n\n const now = new Date()\n\n // Create step instance\n const stepInstance = em.create(StepInstance, {\n workflowInstanceId: instance.id,\n branchInstanceId: branch ? branch.id : null,\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n status: 'ACTIVE',\n inputData: context.triggerData || null,\n enteredAt: now,\n retryCount: 0,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(stepInstance).flush()\n\n // Log STEP_ENTERED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: stepDef.stepId,\n stepName: stepDef.stepName,\n stepType: stepDef.stepType,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return stepInstance\n}\n\n/**\n * Exit a workflow step - mark as completed and record timing\n *\n * @param em - Entity manager\n * @param stepInstance - Step instance to exit\n * @param outputData - Optional output data from step execution\n */\nexport async function exitStep(\n em: EntityManager,\n stepInstance: StepInstance,\n outputData?: any\n): Promise<void> {\n const now = new Date()\n\n // Calculate execution time if we have enteredAt\n let executionTimeMs: number | null = null\n if (stepInstance.enteredAt) {\n executionTimeMs = now.getTime() - stepInstance.enteredAt.getTime()\n }\n\n // Update step instance\n stepInstance.status = 'COMPLETED'\n stepInstance.outputData = outputData || null\n stepInstance.exitedAt = now\n stepInstance.executionTimeMs = executionTimeMs\n stepInstance.updatedAt = now\n\n await em.flush()\n\n // Log STEP_EXITED event\n await logStepEvent(em, {\n workflowInstanceId: stepInstance.workflowInstanceId,\n stepInstanceId: stepInstance.id,\n eventType: 'STEP_EXITED',\n eventData: {\n stepId: stepInstance.stepId,\n status: 'COMPLETED',\n executionTimeMs,\n hasOutput: !!outputData,\n },\n tenantId: stepInstance.tenantId,\n organizationId: stepInstance.organizationId,\n })\n}\n\n/**\n * Execute a workflow step based on its type\n *\n * Main entry point for step execution. Handles:\n * - START: Immediate completion\n * - END: Workflow completion\n * - AUTOMATED: Activity execution (MVP: immediate completion)\n * - USER_TASK: Create user task and wait\n * - SUB_WORKFLOW: Invoke child workflow\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepId - Step ID to execute\n * @param context - Execution context\n * @param container - DI container (required for SUB_WORKFLOW steps)\n * @returns Execution result with status and output\n */\nexport async function executeStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepId: string,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n try {\n // Enter the step (create step instance)\n const stepInstance = await enterStep(em, instance, stepId, context, branch)\n\n // Load workflow definition to get step configuration\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const stepDef = definition.definition.steps.find((s: any) => s.stepId === stepId)\n if (!stepDef) {\n throw new StepExecutionError(\n `Step not found: ${stepId}`,\n 'STEP_NOT_FOUND',\n { stepId }\n )\n }\n\n // Execute based on step type\n const result = await executeStepByType(\n em,\n instance,\n stepInstance,\n stepDef,\n context,\n container,\n branch\n )\n\n // If step completed, exit it\n if (result.status === 'COMPLETED') {\n await exitStep(em, stepInstance, result.outputData)\n }\n\n return result\n } catch (error) {\n // Handle step execution errors\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n // Try to mark step as failed if we have a step instance\n try {\n const failedStepInstance = await em.findOne(StepInstance, {\n workflowInstanceId: instance.id,\n stepId,\n status: 'ACTIVE',\n })\n\n if (failedStepInstance) {\n failedStepInstance.status = 'FAILED'\n failedStepInstance.errorData = {\n error: errorMessage,\n details: error instanceof StepExecutionError ? error.details : undefined,\n }\n failedStepInstance.exitedAt = new Date()\n failedStepInstance.updatedAt = new Date()\n await em.flush()\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: failedStepInstance.id,\n eventType: 'STEP_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n // Swallow update errors to preserve original error\n console.error('Failed to update step instance with error:', updateError)\n }\n\n return {\n status: 'FAILED',\n error: errorMessage,\n }\n }\n}\n\n// ============================================================================\n// Step Type Handlers\n// ============================================================================\n\n/**\n * Execute step based on its type\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param stepInstance - Step instance\n * @param stepDef - Step definition from workflow\n * @param context - Execution context\n * @returns Execution result\n */\nasync function executeStepByType(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const stepType: WorkflowStepType = stepDef.stepType\n\n switch (stepType) {\n case 'START':\n return handleStartStep(stepDef, context)\n\n case 'END':\n return handleEndStep(stepDef, context)\n\n case 'AUTOMATED':\n return await handleAutomatedStep(em, instance, stepInstance, stepDef, context, container, branch)\n\n case 'USER_TASK':\n return await handleUserTaskStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'SUB_WORKFLOW':\n if (!container) {\n throw new StepExecutionError(\n 'Container required for SUB_WORKFLOW execution',\n 'CONTAINER_REQUIRED',\n { stepType }\n )\n }\n return await handleSubWorkflowStep(em, container, instance, stepInstance, stepDef, context)\n\n case 'WAIT_FOR_SIGNAL':\n return await handleWaitForSignalStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'WAIT_FOR_TIMER':\n return await handleWaitForTimerStep(em, instance, stepInstance, stepDef, context, branch)\n\n case 'PARALLEL_FORK': {\n // Entering a fork opens branch tokens and parks the root token in the\n // FORKED state; the interleaved loop in the executor drives the branches.\n if (branch) {\n // Nested forks are rejected by definition validation; fail closed.\n throw new StepExecutionError(\n 'Nested PARALLEL_FORK is not supported',\n 'NESTED_FORK_NOT_SUPPORTED',\n { stepType, stepId: stepDef.stepId }\n )\n }\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n if (!definition) {\n throw new StepExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n const { openFork } = await import('./parallel-handler')\n await openFork(em, instance, definition, stepDef)\n return { status: 'WAITING', waitReason: 'FORK', outputData: { stepType: 'PARALLEL_FORK', forkStepId: stepDef.stepId } }\n }\n\n case 'PARALLEL_JOIN':\n // The join is a synchronization point handled by the parallel loop\n // (branches are marked COMPLETED on arrival; the loop fires the join).\n // Executing the step itself is a no-op.\n return { status: 'COMPLETED', outputData: { stepType: 'PARALLEL_JOIN', timestamp: new Date().toISOString() } }\n\n default:\n throw new StepExecutionError(\n `Unknown step type: ${stepType}`,\n 'UNKNOWN_STEP_TYPE',\n { stepType }\n )\n }\n}\n\n/**\n * Handle START step - no-op, immediately complete\n */\nfunction handleStartStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'START',\n timestamp: new Date().toISOString(),\n },\n }\n}\n\n/**\n * Handle END step - mark as complete\n */\nfunction handleEndStep(\n stepDef: any,\n context: StepExecutionContext\n): StepExecutionResult {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'END',\n timestamp: new Date().toISOString(),\n finalContext: context.workflowContext,\n },\n }\n}\n\n/**\n * Handle AUTOMATED step - execute activities\n *\n * Executes activities defined in step configuration.\n * Supports both sync and async activities.\n */\nasync function handleAutomatedStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n container?: any,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n // Extract activities from step definition\n const activities = stepDef.activities || []\n\n if (activities.length === 0) {\n // No activities defined - immediate completion (legacy behavior)\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n },\n }\n }\n\n // Import activity executor\n const { executeActivities } = await import('./activity-executor')\n\n try {\n // Execute activities with proper context\n const results = await executeActivities(em, container, activities, {\n workflowInstance: instance,\n workflowContext: context.workflowContext,\n stepContext: { stepId: stepDef.stepId, stepName: stepDef.stepName },\n stepInstanceId: stepInstance.id,\n userId: context.userId,\n })\n\n // Check if there are pending async activities\n const pendingActivities = results.filter(r => r.async && !r.success)\n if (pendingActivities.length > 0) {\n // Workflow should pause and wait for async activities\n const now = new Date()\n if (branch) {\n branch.status = 'WAITING_FOR_ACTIVITIES'\n branch.updatedAt = now\n } else {\n instance.status = 'WAITING_FOR_ACTIVITIES'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL', // Reuse SIGNAL wait reason (will be resumed by activity completion)\n outputData: {\n pendingActivities: pendingActivities.map(r => ({\n activityId: r.activityId,\n activityName: r.activityName,\n jobId: r.jobId,\n })),\n },\n }\n }\n\n // Check for failures in sync activities\n const failures = results.filter(r => !r.success && !r.async)\n if (failures.length > 0) {\n const errorMessages = failures.map(f => `${f.activityName || f.activityId}: ${f.error}`).join('; ')\n return {\n status: 'FAILED',\n error: `${failures.length} activity(ies) failed: ${errorMessages}`,\n outputData: {\n failures: failures.map(f => ({\n activityId: f.activityId,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n },\n }\n }\n\n // All activities completed successfully\n const activityOutputs = results.reduce((acc, r) => {\n if (r.output) {\n acc[r.activityId] = r.output\n }\n return acc\n }, {} as Record<string, any>)\n\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'AUTOMATED',\n timestamp: new Date().toISOString(),\n activityResults: activityOutputs,\n activityCount: results.length,\n },\n }\n } catch (error: any) {\n return {\n status: 'FAILED',\n error: `Activity execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle USER_TASK step - create user task and enter waiting state\n *\n * Creates a UserTask entity and returns WAITING status.\n * The workflow will pause until the task is completed by a user.\n */\nasync function handleUserTaskStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const userTaskConfig = stepDef.userTaskConfig || {}\n\n // Handle assignedTo - if it's an array, treat it as roles\n let assignedTo = userTaskConfig.assignedTo || null\n let assignedToRoles = userTaskConfig.assignedToRoles || null\n\n if (Array.isArray(assignedTo)) {\n assignedToRoles = assignedTo\n assignedTo = null\n }\n\n // Create user task\n const now = new Date()\n const userTask = em.create(UserTask, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n branchInstanceId: branch ? branch.id : null,\n taskName: stepDef.stepName,\n description: stepDef.description || null,\n status: 'PENDING',\n formSchema: userTaskConfig.formSchema || null,\n formData: null,\n assignedTo: assignedTo,\n assignedToRoles: assignedToRoles,\n dueDate: userTaskConfig.slaDuration ? calculateDueDate(userTaskConfig.slaDuration) : null,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(userTask).flush()\n\n // Log USER_TASK_CREATED event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'USER_TASK_CREATED',\n eventData: {\n userTaskId: userTask.id,\n taskName: userTask.taskName,\n assignedTo: userTask.assignedTo,\n assignedToRoles: userTask.assignedToRoles,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause execution - waits for user task completion. For a branch, only the\n // branch pauses; sibling branches keep running.\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'USER_TASK',\n outputData: {\n userTaskId: userTask.id,\n },\n }\n}\n\n/**\n * Handle SUB_WORKFLOW step - invoke another workflow and wait for completion\n *\n * Creates a child workflow instance with mapped input data,\n * executes it synchronously, and returns mapped output data.\n */\nasync function handleSubWorkflowStep(\n em: EntityManager,\n container: any,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext\n): Promise<StepExecutionResult> {\n const { subWorkflowId, inputMapping, outputMapping, version } = stepDef.config || {}\n\n if (!subWorkflowId) {\n return {\n status: 'FAILED',\n error: 'Sub-workflow ID not specified in step configuration'\n }\n }\n\n // Map input data from parent context to child context\n const childContext = mapInputData(instance.context, inputMapping || {})\n\n // Import workflow executor functions\n const { startWorkflow, executeWorkflow } = await import('./workflow-executor')\n\n try {\n // Start child workflow with parent metadata\n const childInstance = await startWorkflow(em, {\n workflowId: subWorkflowId,\n version,\n initialContext: childContext,\n correlationKey: instance.correlationKey || undefined,\n metadata: {\n ...instance.metadata,\n labels: {\n ...instance.metadata?.labels,\n parentInstanceId: instance.id,\n parentStepId: stepDef.stepId,\n parentStepInstanceId: stepInstance.id,\n },\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Log sub-workflow invocation event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_STARTED',\n eventData: {\n childInstanceId: childInstance.id,\n subWorkflowId,\n version,\n inputData: childContext,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Execute child workflow synchronously\n const result = await executeWorkflow(em, container, childInstance.id, {\n userId: context.userId,\n })\n\n // Handle child workflow result\n if (result.status === 'COMPLETED') {\n // Map output data from child context to parent context\n const outputData = mapOutputData(result.context, outputMapping || {})\n\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_COMPLETED',\n eventData: {\n childInstanceId: childInstance.id,\n outputData,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'COMPLETED',\n outputData,\n }\n } else if (result.status === 'FAILED') {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n childInstanceId: childInstance.id,\n error: result.errors?.join(', '),\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow failed: ${result.errors?.join(', ')}`,\n }\n } else {\n // WAITING, PAUSED, etc. - For synchronous execution, treat as error\n return {\n status: 'FAILED',\n error: `Sub-workflow ended in unexpected state: ${result.status}`,\n }\n }\n } catch (error: any) {\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n eventType: 'SUB_WORKFLOW_FAILED',\n eventData: {\n subWorkflowId,\n error: error.message,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n status: 'FAILED',\n error: `Sub-workflow execution failed: ${error.message}`,\n }\n }\n}\n\n/**\n * Handle WAIT_FOR_SIGNAL step - pause workflow until signal received\n *\n * Creates a waiting state and pauses the workflow until an external signal\n * with the matching signal name is received. The signal payload will be merged\n * into the workflow context when received.\n */\nasync function handleWaitForSignalStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const signalConfig = stepDef.signalConfig || {}\n const signalName = signalConfig.signalName || stepDef.stepId\n const timeout = signalConfig.timeout ? parseDuration(signalConfig.timeout) : null\n\n const now = new Date()\n\n // Log signal awaiting event\n await logStepEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'SIGNAL_AWAITING',\n eventData: {\n signalName,\n timeout,\n description: stepDef.description,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Pause execution (branch-scoped when running inside a parallel branch)\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n // Return WAITING status to halt executor\n return {\n status: 'WAITING',\n waitReason: 'SIGNAL',\n outputData: {\n signalName,\n timeout,\n awaitingSince: now,\n },\n }\n}\n\n/**\n * Handle WAIT_FOR_TIMER step - pause workflow until a timer fires.\n *\n * Reads `duration` (relative, e.g. \"PT5M\") or `until` (ISO 8601 datetime) from\n * `stepDef.config` (preferred \u2014 matches StepsEditor) or `stepDef.timerConfig`.\n * Enqueues a delayed timer job on the workflow-activities queue; when the job\n * is processed by the activity worker, it calls `timerHandler.fireTimer` to\n * resume the workflow.\n */\nasync function handleWaitForTimerStep(\n em: EntityManager,\n instance: WorkflowInstance,\n stepInstance: StepInstance,\n stepDef: any,\n context: StepExecutionContext,\n branch?: WorkflowBranchInstance | null\n): Promise<StepExecutionResult> {\n const timerConfig = stepDef.config || stepDef.timerConfig || {}\n const duration: string | undefined = timerConfig.duration\n const until: string | undefined = timerConfig.until\n\n if (!duration && !until) {\n throw new StepExecutionError(\n 'WAIT_FOR_TIMER requires either \"duration\" (e.g., \"PT5M\") or \"until\" (ISO 8601 datetime)',\n 'TIMER_CONFIG_MISSING',\n { stepId: stepDef.stepId }\n )\n }\n\n let fireAtMs: number\n if (until) {\n const targetDate = new Date(until)\n if (isNaN(targetDate.getTime())) {\n throw new StepExecutionError(\n `WAIT_FOR_TIMER invalid \"until\" datetime: ${until}`,\n 'TIMER_CONFIG_INVALID',\n { until }\n )\n }\n fireAtMs = targetDate.getTime()\n } else {\n fireAtMs = Date.now() + parseDuration(duration as string)\n }\n\n const delayMs = fireAtMs - Date.now()\n const fireAt = new Date(fireAtMs)\n\n // Immediate-fire path: skip the queue round-trip if the timer is in the past\n if (delayMs <= 0) {\n return {\n status: 'COMPLETED',\n outputData: {\n stepType: 'WAIT_FOR_TIMER',\n timerFiredImmediately: true,\n fireAt,\n duration,\n until,\n },\n }\n }\n\n const now = new Date()\n\n // Enqueue delayed timer job via the shared activity queue.\n // Imported here to avoid a top-level cycle between step-handler and activity-executor.\n const { enqueueTimerJob } = await import('./activity-executor')\n const jobId = await enqueueTimerJob({\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n branchInstanceId: branch ? branch.id : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n userId: context.userId,\n fireAt: fireAt.toISOString(),\n delayMs,\n })\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: stepInstance.id,\n ...(branch ? { branchInstanceId: branch.id } : {}),\n eventType: 'TIMER_AWAITING',\n eventData: {\n fireAt: fireAt.toISOString(),\n duration: duration || null,\n until: until || null,\n jobId,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (branch) {\n branch.status = 'PAUSED'\n branch.updatedAt = now\n } else {\n instance.status = 'PAUSED'\n instance.pausedAt = now\n instance.updatedAt = now\n }\n await em.flush()\n\n return {\n status: 'WAITING',\n waitReason: 'TIMER',\n outputData: {\n fireAt,\n duration,\n until,\n jobId,\n },\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n// parseDuration is imported from ./duration\n\n/**\n * Log step-related event to event sourcing table\n */\nasync function logStepEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Calculate due date from ISO 8601 duration string\n *\n * @param duration - ISO 8601 duration (e.g., \"P1D\" for 1 day)\n * @returns Due date\n */\nfunction calculateDueDate(duration: string): Date {\n // Simple implementation for MVP\n // Supports: P1D (1 day), P1H (1 hour), P1W (1 week)\n const now = new Date()\n\n const daysMatch = duration.match(/P(\\d+)D/)\n if (daysMatch) {\n const days = parseInt(daysMatch[1], 10)\n return new Date(now.getTime() + days * 24 * 60 * 60 * 1000)\n }\n\n const hoursMatch = duration.match(/PT(\\d+)H/)\n if (hoursMatch) {\n const hours = parseInt(hoursMatch[1], 10)\n return new Date(now.getTime() + hours * 60 * 60 * 1000)\n }\n\n const weeksMatch = duration.match(/P(\\d+)W/)\n if (weeksMatch) {\n const weeks = parseInt(weeksMatch[1], 10)\n return new Date(now.getTime() + weeks * 7 * 24 * 60 * 60 * 1000)\n }\n\n // Default: 1 day\n return new Date(now.getTime() + 24 * 60 * 60 * 1000)\n}\n\n/**\n * Get nested value from object using dot notation\n *\n * @param obj - Source object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @returns Value at path or undefined\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj)\n}\n\n/**\n * Set nested value in object using dot notation\n *\n * @param obj - Target object\n * @param path - Dot-notation path (e.g., \"user.email\")\n * @param value - Value to set\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.')\n const lastKey = keys.pop()!\n const target = keys.reduce((current, key) => {\n if (!(key in current)) current[key] = {}\n return current[key]\n }, obj)\n target[lastKey] = value\n}\n\n/**\n * Map data from source context using mapping configuration\n *\n * @param sourceContext - Source data object\n * @param mapping - Mapping configuration (targetKey -> sourcePath)\n * @returns Mapped data object\n */\nfunction mapInputData(\n sourceContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n const value = getNestedValue(sourceContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire context\n return Object.keys(result).length > 0 ? result : sourceContext\n}\n\n/**\n * Map output data from child context back to parent\n *\n * @param childContext - Child workflow context\n * @param mapping - Mapping configuration (targetKey -> sourcePath)\n * @returns Mapped output data\n */\nfunction mapOutputData(\n childContext: Record<string, any>,\n mapping: Record<string, string>\n): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [targetKey, sourcePath] of Object.entries(mapping)) {\n const value = getNestedValue(childContext, sourcePath)\n if (value !== undefined) {\n setNestedValue(result, targetKey, value)\n }\n }\n\n // If no mapping provided, pass entire child context\n return Object.keys(result).length > 0 ? result : childContext\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -56,6 +56,32 @@ async function completeUserTask(em, container, options) {
56
56
  { workflowInstanceId: task.workflowInstanceId }
57
57
  );
58
58
  }
59
+ if (task.branchInstanceId) {
60
+ await logWorkflowEvent(em, {
61
+ workflowInstanceId: instance.id,
62
+ stepInstanceId: task.stepInstanceId,
63
+ branchInstanceId: task.branchInstanceId,
64
+ eventType: "USER_TASK_COMPLETED",
65
+ eventData: { taskId: task.id, taskName: task.taskName, completedBy: userId, formData },
66
+ userId,
67
+ tenantId: instance.tenantId,
68
+ organizationId: instance.organizationId
69
+ });
70
+ const { resumeBranch } = await import("./parallel-handler.js");
71
+ const resumed = await resumeBranch(em, {
72
+ instanceId: instance.id,
73
+ branchInstanceId: task.branchInstanceId,
74
+ tenantId: instance.tenantId,
75
+ organizationId: instance.organizationId,
76
+ contextMerge: formData,
77
+ exitStepInstanceId: task.stepInstanceId,
78
+ exitOutput: { userTaskId: task.id, formData }
79
+ });
80
+ if (resumed) {
81
+ await executeWorkflow(em, container, instance.id, { userId });
82
+ }
83
+ return;
84
+ }
59
85
  instance.context = {
60
86
  ...instance.context,
61
87
  ...formData
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/task-handler.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module - User Task Handler Service\n *\n * Handles user task lifecycle operations:\n * - Completing user tasks\n * - Claiming tasks from role queues\n * - Reassigning tasks\n * - Escalating overdue tasks\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n UserTask,\n WorkflowInstance,\n WorkflowEvent,\n StepInstance,\n WorkflowDefinition,\n} from '../data/entities'\nimport { executeWorkflow } from './workflow-executor'\nimport * as stepHandler from './step-handler'\nimport * as transitionHandler from './transition-handler'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface CompleteUserTaskOptions {\n taskId: string\n formData: Record<string, any>\n userId: string\n comments?: string\n}\n\nexport class UserTaskError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'UserTaskError'\n }\n}\n\n// ============================================================================\n// User Task Completion\n// ============================================================================\n\n/**\n * Complete a user task and resume workflow execution\n *\n * This function:\n * 1. Validates the task exists and can be completed\n * 2. Updates the task with form data and completion info\n * 3. Merges form data into workflow context\n * 4. Logs completion event\n * 5. Resumes workflow execution\n *\n * @param em - Entity manager\n * @param container - DI container for workflow execution\n * @param options - Task completion options\n * @throws UserTaskError if task not found or validation fails\n */\nexport async function completeUserTask(\n em: EntityManager,\n container: AwilixContainer,\n options: CompleteUserTaskOptions\n): Promise<void> {\n const { taskId, formData, userId, comments } = options\n\n // Fetch task\n const task = await em.findOne(UserTask, {\n id: taskId,\n status: { $in: ['PENDING', 'IN_PROGRESS'] },\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already completed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n // Validate form data against schema (simple validation for MVP)\n // In Phase 7, we'll add comprehensive JSON Schema validation\n if (task.formSchema) {\n try {\n validateFormData(formData, task.formSchema)\n } catch (error) {\n throw new UserTaskError(\n error instanceof Error ? error.message : 'Form validation failed',\n 'FORM_VALIDATION_FAILED',\n { taskId, formSchema: task.formSchema, formData }\n )\n }\n }\n\n // Update task\n const now = new Date()\n task.status = 'COMPLETED'\n task.formData = formData\n task.completedBy = userId\n task.completedAt = now\n task.comments = comments || null\n task.updatedAt = now\n\n await em.flush()\n\n // Fetch workflow instance\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (!instance) {\n throw new UserTaskError(\n 'Workflow instance not found',\n 'INSTANCE_NOT_FOUND',\n { workflowInstanceId: task.workflowInstanceId }\n )\n }\n\n // Merge form data into workflow context\n instance.context = {\n ...instance.context,\n ...formData,\n }\n instance.updatedAt = now\n\n // Log USER_TASK_COMPLETED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n completedBy: userId,\n formData,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Mark the step instance as completed\n const stepInstance = await em.findOne(StepInstance, {\n id: task.stepInstanceId,\n status: 'ACTIVE',\n })\n\n if (stepInstance) {\n await stepHandler.exitStep(em, stepInstance, { userTaskId: task.id, formData })\n }\n\n // Find the next automatic transition from the current step\n const currentStepId = instance.currentStepId\n\n // Load workflow definition to find transitions\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new UserTaskError(\n 'Workflow definition not found',\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find automatic transitions from current step\n const autoTransitions = (definition.definition.transitions || []).filter(\n (t: any) => t.fromStepId === currentStepId && t.trigger === 'auto'\n )\n\n if (autoTransitions.length === 0) {\n // No automatic transitions, workflow stays paused at current step\n return\n }\n\n // Find valid transitions using transition handler\n const transitionContext = {\n workflowContext: instance.context,\n userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n em,\n instance,\n currentStepId,\n transitionContext\n )\n\n const firstValidTransition = validTransitions.find(t => t.isValid)\n\n if (!firstValidTransition || !firstValidTransition.transition) {\n // Resume workflow execution anyway, maybe conditions will be met later\n instance.status = 'RUNNING'\n await em.flush()\n return\n }\n\n // Execute the transition to move to next step\n\n const transitionResult = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n currentStepId,\n firstValidTransition.transition.toStepId,\n transitionContext\n )\n\n if (!transitionResult.success) {\n console.error(`[TaskHandler] Transition failed:`, transitionResult.error)\n // Don't throw, just leave workflow in current state\n return\n }\n\n // Now continue workflow execution from the new step\n await executeWorkflow(em, container, instance.id, { userId })\n}\n\n/**\n * Claim a user task from a role queue\n *\n * Allows a user to claim a task that's assigned to their role(s).\n * Prevents race conditions by checking task status.\n *\n * @param em - Entity manager\n * @param taskId - Task ID to claim\n * @param userId - User claiming the task\n * @throws UserTaskError if task cannot be claimed\n */\nexport async function claimUserTask(\n em: EntityManager,\n taskId: string,\n userId: string\n): Promise<void> {\n const task = await em.findOne(UserTask, {\n id: taskId,\n status: 'PENDING',\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n if (task.assignedTo) {\n throw new UserTaskError(\n 'Task is already assigned to a specific user',\n 'TASK_ALREADY_ASSIGNED',\n { taskId, assignedTo: task.assignedTo }\n )\n }\n\n if (!task.assignedToRoles || task.assignedToRoles.length === 0) {\n throw new UserTaskError(\n 'Task is not assigned to any roles',\n 'TASK_NOT_ROLE_ASSIGNED',\n { taskId }\n )\n }\n\n // Update task\n const now = new Date()\n task.claimedBy = userId\n task.claimedAt = now\n task.status = 'IN_PROGRESS'\n task.updatedAt = now\n\n await em.flush()\n\n // Log event\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (instance) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_STARTED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n claimedBy: userId,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log workflow event to event sourcing table\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Validate form data against JSON schema (basic validation for MVP)\n *\n * In Phase 7, we'll implement comprehensive JSON Schema validation.\n * For MVP, we do basic type checking.\n *\n * @param formData - User-provided form data\n * @param formSchema - JSON schema defining expected structure\n * @throws Error if validation fails\n */\nfunction validateFormData(\n formData: Record<string, any>,\n formSchema: any\n): void {\n // For MVP: Basic validation - just check required fields exist\n if (!formSchema || !formSchema.properties) {\n return // No schema to validate against\n }\n\n const requiredFields = formSchema.required || []\n\n for (const field of requiredFields) {\n if (!(field in formData) || formData[field] === null || formData[field] === undefined) {\n throw new Error(`Required field missing: ${field}`)\n }\n }\n\n // Additional type validation can be added in Phase 7\n // For now, this basic validation is sufficient\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module - User Task Handler Service\n *\n * Handles user task lifecycle operations:\n * - Completing user tasks\n * - Claiming tasks from role queues\n * - Reassigning tasks\n * - Escalating overdue tasks\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n UserTask,\n WorkflowInstance,\n WorkflowEvent,\n StepInstance,\n WorkflowDefinition,\n} from '../data/entities'\nimport { executeWorkflow } from './workflow-executor'\nimport * as stepHandler from './step-handler'\nimport * as transitionHandler from './transition-handler'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface CompleteUserTaskOptions {\n taskId: string\n formData: Record<string, any>\n userId: string\n comments?: string\n}\n\nexport class UserTaskError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'UserTaskError'\n }\n}\n\n// ============================================================================\n// User Task Completion\n// ============================================================================\n\n/**\n * Complete a user task and resume workflow execution\n *\n * This function:\n * 1. Validates the task exists and can be completed\n * 2. Updates the task with form data and completion info\n * 3. Merges form data into workflow context\n * 4. Logs completion event\n * 5. Resumes workflow execution\n *\n * @param em - Entity manager\n * @param container - DI container for workflow execution\n * @param options - Task completion options\n * @throws UserTaskError if task not found or validation fails\n */\nexport async function completeUserTask(\n em: EntityManager,\n container: AwilixContainer,\n options: CompleteUserTaskOptions\n): Promise<void> {\n const { taskId, formData, userId, comments } = options\n\n // Fetch task\n const task = await em.findOne(UserTask, {\n id: taskId,\n status: { $in: ['PENDING', 'IN_PROGRESS'] },\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already completed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n // Validate form data against schema (simple validation for MVP)\n // In Phase 7, we'll add comprehensive JSON Schema validation\n if (task.formSchema) {\n try {\n validateFormData(formData, task.formSchema)\n } catch (error) {\n throw new UserTaskError(\n error instanceof Error ? error.message : 'Form validation failed',\n 'FORM_VALIDATION_FAILED',\n { taskId, formSchema: task.formSchema, formData }\n )\n }\n }\n\n // Update task\n const now = new Date()\n task.status = 'COMPLETED'\n task.formData = formData\n task.completedBy = userId\n task.completedAt = now\n task.comments = comments || null\n task.updatedAt = now\n\n await em.flush()\n\n // Fetch workflow instance\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (!instance) {\n throw new UserTaskError(\n 'Workflow instance not found',\n 'INSTANCE_NOT_FOUND',\n { workflowInstanceId: task.workflowInstanceId }\n )\n }\n\n // Branch-scoped completion: when the task belongs to a parallel branch,\n // merge form data into the branch namespace and resume just that branch.\n if (task.branchInstanceId) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n branchInstanceId: task.branchInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: { taskId: task.id, taskName: task.taskName, completedBy: userId, formData },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { resumeBranch } = await import('./parallel-handler')\n const resumed = await resumeBranch(em, {\n instanceId: instance.id,\n branchInstanceId: task.branchInstanceId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n contextMerge: formData,\n exitStepInstanceId: task.stepInstanceId,\n exitOutput: { userTaskId: task.id, formData },\n })\n\n if (resumed) {\n await executeWorkflow(em, container, instance.id, { userId })\n }\n return\n }\n\n // Merge form data into workflow context\n instance.context = {\n ...instance.context,\n ...formData,\n }\n instance.updatedAt = now\n\n // Log USER_TASK_COMPLETED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n completedBy: userId,\n formData,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Mark the step instance as completed\n const stepInstance = await em.findOne(StepInstance, {\n id: task.stepInstanceId,\n status: 'ACTIVE',\n })\n\n if (stepInstance) {\n await stepHandler.exitStep(em, stepInstance, { userTaskId: task.id, formData })\n }\n\n // Find the next automatic transition from the current step\n const currentStepId = instance.currentStepId\n\n // Load workflow definition to find transitions\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new UserTaskError(\n 'Workflow definition not found',\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find automatic transitions from current step\n const autoTransitions = (definition.definition.transitions || []).filter(\n (t: any) => t.fromStepId === currentStepId && t.trigger === 'auto'\n )\n\n if (autoTransitions.length === 0) {\n // No automatic transitions, workflow stays paused at current step\n return\n }\n\n // Find valid transitions using transition handler\n const transitionContext = {\n workflowContext: instance.context,\n userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n em,\n instance,\n currentStepId,\n transitionContext\n )\n\n const firstValidTransition = validTransitions.find(t => t.isValid)\n\n if (!firstValidTransition || !firstValidTransition.transition) {\n // Resume workflow execution anyway, maybe conditions will be met later\n instance.status = 'RUNNING'\n await em.flush()\n return\n }\n\n // Execute the transition to move to next step\n\n const transitionResult = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n currentStepId,\n firstValidTransition.transition.toStepId,\n transitionContext\n )\n\n if (!transitionResult.success) {\n console.error(`[TaskHandler] Transition failed:`, transitionResult.error)\n // Don't throw, just leave workflow in current state\n return\n }\n\n // Now continue workflow execution from the new step\n await executeWorkflow(em, container, instance.id, { userId })\n}\n\n/**\n * Claim a user task from a role queue\n *\n * Allows a user to claim a task that's assigned to their role(s).\n * Prevents race conditions by checking task status.\n *\n * @param em - Entity manager\n * @param taskId - Task ID to claim\n * @param userId - User claiming the task\n * @throws UserTaskError if task cannot be claimed\n */\nexport async function claimUserTask(\n em: EntityManager,\n taskId: string,\n userId: string\n): Promise<void> {\n const task = await em.findOne(UserTask, {\n id: taskId,\n status: 'PENDING',\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n if (task.assignedTo) {\n throw new UserTaskError(\n 'Task is already assigned to a specific user',\n 'TASK_ALREADY_ASSIGNED',\n { taskId, assignedTo: task.assignedTo }\n )\n }\n\n if (!task.assignedToRoles || task.assignedToRoles.length === 0) {\n throw new UserTaskError(\n 'Task is not assigned to any roles',\n 'TASK_NOT_ROLE_ASSIGNED',\n { taskId }\n )\n }\n\n // Update task\n const now = new Date()\n task.claimedBy = userId\n task.claimedAt = now\n task.status = 'IN_PROGRESS'\n task.updatedAt = now\n\n await em.flush()\n\n // Log event\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (instance) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_STARTED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n claimedBy: userId,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log workflow event to event sourcing table\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string | null\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Validate form data against JSON schema (basic validation for MVP)\n *\n * In Phase 7, we'll implement comprehensive JSON Schema validation.\n * For MVP, we do basic type checking.\n *\n * @param formData - User-provided form data\n * @param formSchema - JSON schema defining expected structure\n * @throws Error if validation fails\n */\nfunction validateFormData(\n formData: Record<string, any>,\n formSchema: any\n): void {\n // For MVP: Basic validation - just check required fields exist\n if (!formSchema || !formSchema.properties) {\n return // No schema to validate against\n }\n\n const requiredFields = formSchema.required || []\n\n for (const field of requiredFields) {\n if (!(field in formData) || formData[field] === null || formData[field] === undefined) {\n throw new Error(`Required field missing: ${field}`)\n }\n }\n\n // Additional type validation can be added in Phase 7\n // For now, this basic validation is sufficient\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -9,11 +9,36 @@ class TimerError extends Error {
9
9
  }
10
10
  }
11
11
  async function fireTimer(em, container, options) {
12
- const { instanceId, stepInstanceId, userId, tenantId, organizationId } = options;
12
+ const { instanceId, stepInstanceId, branchInstanceId, userId, tenantId, organizationId } = options;
13
13
  const eventLogger = container.resolve("eventLogger");
14
14
  const stepHandler = container.resolve("stepHandler");
15
15
  const transitionHandler = container.resolve("transitionHandler");
16
16
  const workflowExecutor = container.resolve("workflowExecutor");
17
+ if (branchInstanceId) {
18
+ await eventLogger.logWorkflowEvent(em, {
19
+ workflowInstanceId: instanceId,
20
+ stepInstanceId,
21
+ branchInstanceId,
22
+ eventType: "TIMER_FIRED",
23
+ eventData: { firedAt: (/* @__PURE__ */ new Date()).toISOString(), branch: true },
24
+ userId,
25
+ tenantId,
26
+ organizationId
27
+ });
28
+ const { resumeBranch } = await import("./parallel-handler.js");
29
+ const resumed = await resumeBranch(em, {
30
+ instanceId,
31
+ branchInstanceId,
32
+ tenantId,
33
+ organizationId,
34
+ exitStepInstanceId: stepInstanceId,
35
+ exitOutput: { firedAt: (/* @__PURE__ */ new Date()).toISOString() }
36
+ });
37
+ if (resumed) {
38
+ await workflowExecutor.executeWorkflow(em, container, instanceId, { userId });
39
+ }
40
+ return;
41
+ }
17
42
  const instance = await findOneWithDecryption(
18
43
  em,
19
44
  WorkflowInstance,