@open-mercato/core 0.4.2-canary-ec4978dbb3 → 0.4.2-canary-9074fd41ce

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 (155) hide show
  1. package/dist/generated/entities.ids.generated.js +0 -1
  2. package/dist/generated/entities.ids.generated.js.map +2 -2
  3. package/dist/generated/entity-fields-registry.js +0 -2
  4. package/dist/generated/entity-fields-registry.js.map +2 -2
  5. package/dist/modules/business_rules/data/validators.js +0 -34
  6. package/dist/modules/business_rules/data/validators.js.map +2 -2
  7. package/dist/modules/business_rules/index.js +1 -21
  8. package/dist/modules/business_rules/index.js.map +2 -2
  9. package/dist/modules/business_rules/lib/rule-engine.js +1 -182
  10. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  11. package/dist/modules/sales/acl.js +0 -1
  12. package/dist/modules/sales/acl.js.map +2 -2
  13. package/dist/modules/sales/backend/sales/documents/[id]/page.js +0 -12
  14. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  15. package/dist/modules/sales/commands/documents.js +0 -62
  16. package/dist/modules/sales/commands/documents.js.map +2 -2
  17. package/dist/modules/sales/lib/dictionaries.js +0 -3
  18. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  19. package/dist/modules/workflows/acl.js +0 -2
  20. package/dist/modules/workflows/acl.js.map +2 -2
  21. package/dist/modules/workflows/api/instances/route.js +6 -18
  22. package/dist/modules/workflows/api/instances/route.js.map +2 -2
  23. package/dist/modules/workflows/api/tasks/route.js +1 -6
  24. package/dist/modules/workflows/api/tasks/route.js.map +2 -2
  25. package/dist/modules/workflows/backend/definitions/[id]/page.js +1 -9
  26. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  27. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
  28. package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
  29. package/dist/modules/workflows/backend/definitions/create/page.js +15 -24
  30. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  31. package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
  32. package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
  33. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +132 -150
  34. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  35. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
  36. package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
  37. package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
  38. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  39. package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
  40. package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
  41. package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
  42. package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
  43. package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
  44. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  45. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
  46. package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
  47. package/dist/modules/workflows/backend/tasks/page.js +6 -5
  48. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  49. package/dist/modules/workflows/cli.js +3 -81
  50. package/dist/modules/workflows/cli.js.map +3 -3
  51. package/dist/modules/workflows/data/entities.js +1 -64
  52. package/dist/modules/workflows/data/entities.js.map +2 -2
  53. package/dist/modules/workflows/data/validators.js +0 -115
  54. package/dist/modules/workflows/data/validators.js.map +2 -2
  55. package/dist/modules/workflows/examples/checkout-demo-definition.json +5 -1
  56. package/dist/modules/workflows/lib/activity-executor.js +13 -75
  57. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  58. package/dist/modules/workflows/lib/graph-utils.js +2 -71
  59. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  60. package/dist/modules/workflows/lib/seeds.js +5 -22
  61. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  62. package/dist/modules/workflows/lib/start-validator.js +23 -33
  63. package/dist/modules/workflows/lib/start-validator.js.map +2 -2
  64. package/dist/modules/workflows/lib/transition-handler.js +45 -157
  65. package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
  66. package/generated/entities.ids.generated.ts +0 -1
  67. package/generated/entity-fields-registry.ts +0 -2
  68. package/package.json +2 -2
  69. package/src/modules/business_rules/data/validators.ts +0 -40
  70. package/src/modules/business_rules/index.ts +0 -25
  71. package/src/modules/business_rules/lib/rule-engine.ts +1 -281
  72. package/src/modules/sales/acl.ts +0 -1
  73. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +0 -16
  74. package/src/modules/sales/commands/documents.ts +1 -74
  75. package/src/modules/sales/lib/dictionaries.ts +0 -3
  76. package/src/modules/workflows/acl.ts +0 -2
  77. package/src/modules/workflows/api/instances/route.ts +7 -21
  78. package/src/modules/workflows/api/tasks/route.ts +1 -7
  79. package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
  80. package/src/modules/workflows/backend/definitions/[id]/page.tsx +0 -9
  81. package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
  82. package/src/modules/workflows/backend/definitions/create/page.tsx +0 -9
  83. package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
  84. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +3 -21
  85. package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
  86. package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
  87. package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
  88. package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
  89. package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
  90. package/src/modules/workflows/backend/tasks/page.tsx +6 -5
  91. package/src/modules/workflows/cli.ts +0 -111
  92. package/src/modules/workflows/data/entities.ts +0 -124
  93. package/src/modules/workflows/data/validators.ts +0 -138
  94. package/src/modules/workflows/examples/checkout-demo-definition.json +5 -1
  95. package/src/modules/workflows/i18n/en.json +0 -71
  96. package/src/modules/workflows/lib/activity-executor.ts +16 -129
  97. package/src/modules/workflows/lib/graph-utils.ts +2 -117
  98. package/src/modules/workflows/lib/seeds.ts +8 -34
  99. package/src/modules/workflows/lib/start-validator.ts +28 -38
  100. package/src/modules/workflows/lib/transition-handler.ts +55 -208
  101. package/dist/generated/entities/workflow_event_trigger/index.js +0 -33
  102. package/dist/generated/entities/workflow_event_trigger/index.js.map +0 -7
  103. package/dist/modules/auth/events.js +0 -30
  104. package/dist/modules/auth/events.js.map +0 -7
  105. package/dist/modules/business_rules/api/execute/[ruleId]/route.js +0 -145
  106. package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +0 -7
  107. package/dist/modules/catalog/events.js +0 -34
  108. package/dist/modules/catalog/events.js.map +0 -7
  109. package/dist/modules/customers/events.js +0 -49
  110. package/dist/modules/customers/events.js.map +0 -7
  111. package/dist/modules/directory/events.js +0 -23
  112. package/dist/modules/directory/events.js.map +0 -7
  113. package/dist/modules/sales/events.js +0 -63
  114. package/dist/modules/sales/events.js.map +0 -7
  115. package/dist/modules/sales/lib/frontend/documentDataEvents.js +0 -25
  116. package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +0 -7
  117. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +0 -481
  118. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +0 -7
  119. package/dist/modules/workflows/components/EventTriggersEditor.js +0 -553
  120. package/dist/modules/workflows/components/EventTriggersEditor.js.map +0 -7
  121. package/dist/modules/workflows/events.js +0 -38
  122. package/dist/modules/workflows/events.js.map +0 -7
  123. package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
  124. package/dist/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  125. package/dist/modules/workflows/lib/event-trigger-service.js +0 -308
  126. package/dist/modules/workflows/lib/event-trigger-service.js.map +0 -7
  127. package/dist/modules/workflows/migrations/Migration20260123143500.js +0 -36
  128. package/dist/modules/workflows/migrations/Migration20260123143500.js.map +0 -7
  129. package/dist/modules/workflows/subscribers/event-trigger.js +0 -78
  130. package/dist/modules/workflows/subscribers/event-trigger.js.map +0 -7
  131. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +0 -323
  132. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +0 -7
  133. package/dist/modules/workflows/widgets/injection/order-approval/widget.js +0 -17
  134. package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +0 -7
  135. package/dist/modules/workflows/widgets/injection-table.js +0 -19
  136. package/dist/modules/workflows/widgets/injection-table.js.map +0 -7
  137. package/generated/entities/workflow_event_trigger/index.ts +0 -15
  138. package/src/modules/auth/events.ts +0 -39
  139. package/src/modules/business_rules/api/execute/[ruleId]/route.ts +0 -163
  140. package/src/modules/catalog/events.ts +0 -45
  141. package/src/modules/customers/events.ts +0 -63
  142. package/src/modules/directory/events.ts +0 -31
  143. package/src/modules/sales/events.ts +0 -82
  144. package/src/modules/sales/lib/frontend/documentDataEvents.ts +0 -28
  145. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +0 -581
  146. package/src/modules/workflows/components/EventTriggersEditor.tsx +0 -664
  147. package/src/modules/workflows/events.ts +0 -49
  148. package/src/modules/workflows/examples/order-approval-definition.json +0 -257
  149. package/src/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  150. package/src/modules/workflows/lib/event-trigger-service.ts +0 -557
  151. package/src/modules/workflows/migrations/Migration20260123143500.ts +0 -38
  152. package/src/modules/workflows/subscribers/event-trigger.ts +0 -109
  153. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +0 -446
  154. package/src/modules/workflows/widgets/injection/order-approval/widget.ts +0 -16
  155. package/src/modules/workflows/widgets/injection-table.ts +0 -21
@@ -205,20 +205,12 @@ export function definitionToGraph(
205
205
  definition: WorkflowDefinition['definition'],
206
206
  options: DefinitionToGraphOptions = {}
207
207
  ): { nodes: Node[]; edges: Edge[] } {
208
- const { autoLayout = true, layoutSpacing = { vertical: 200, horizontal: 300 } } = options
209
-
210
- // Build step map for quick lookup
211
- const stepMap = new Map(definition.steps.map(step => [step.stepId, step]))
212
-
213
- // Calculate smart layout positions if autoLayout is enabled
214
- const positions = autoLayout
215
- ? calculateSmartLayout(definition.steps, definition.transitions, layoutSpacing)
216
- : null
208
+ const { autoLayout = true, layoutSpacing = { vertical: 250, horizontal: 100 } } = options
217
209
 
218
210
  // Convert steps to nodes
219
211
  const nodes: Node[] = definition.steps.map((step, index) => {
220
212
  // Determine position
221
- let position = positions?.get(step.stepId) || { x: 250, y: 50 + index * layoutSpacing.vertical }
213
+ let position = { x: 250, y: 50 + index * layoutSpacing.vertical }
222
214
 
223
215
  // Use stored position if available and not auto-layouting
224
216
  if (!autoLayout && (step as any)._editorPosition) {
@@ -334,113 +326,6 @@ export function definitionToGraph(
334
326
  return { nodes, edges }
335
327
  }
336
328
 
337
- /**
338
- * Calculate smart layout positions for workflow nodes
339
- * Uses a layered/hierarchical layout algorithm that:
340
- * 1. Assigns levels (ranks) to nodes based on graph topology
341
- * 2. Spreads sibling nodes horizontally at the same level
342
- * 3. Centers merge points below their incoming nodes
343
- */
344
- function calculateSmartLayout(
345
- steps: any[],
346
- transitions: any[],
347
- spacing: { vertical: number; horizontal: number }
348
- ): Map<string, { x: number; y: number }> {
349
- const positions = new Map<string, { x: number; y: number }>()
350
-
351
- if (steps.length === 0) return positions
352
-
353
- // Build adjacency lists
354
- const outgoing = new Map<string, string[]>() // node -> children
355
- const incoming = new Map<string, string[]>() // node -> parents
356
-
357
- for (const step of steps) {
358
- outgoing.set(step.stepId, [])
359
- incoming.set(step.stepId, [])
360
- }
361
-
362
- for (const t of transitions) {
363
- const children = outgoing.get(t.fromStepId) || []
364
- children.push(t.toStepId)
365
- outgoing.set(t.fromStepId, children)
366
-
367
- const parents = incoming.get(t.toStepId) || []
368
- parents.push(t.fromStepId)
369
- incoming.set(t.toStepId, parents)
370
- }
371
-
372
- // Find start node(s) - nodes with no incoming edges
373
- const startNodes = steps.filter(s => (incoming.get(s.stepId) || []).length === 0)
374
- if (startNodes.length === 0) {
375
- // Fallback: use first step as start
376
- startNodes.push(steps[0])
377
- }
378
-
379
- // Assign levels using BFS (longest path from start)
380
- const levels = new Map<string, number>()
381
- const queue: Array<{ id: string; level: number }> = []
382
-
383
- for (const start of startNodes) {
384
- queue.push({ id: start.stepId, level: 0 })
385
- }
386
-
387
- while (queue.length > 0) {
388
- const { id, level } = queue.shift()!
389
- const currentLevel = levels.get(id)
390
-
391
- // Take the maximum level (longest path)
392
- if (currentLevel === undefined || level > currentLevel) {
393
- levels.set(id, level)
394
- }
395
-
396
- const children = outgoing.get(id) || []
397
- for (const child of children) {
398
- queue.push({ id: child, level: level + 1 })
399
- }
400
- }
401
-
402
- // Group nodes by level
403
- const nodesByLevel = new Map<number, string[]>()
404
- for (const [nodeId, level] of levels) {
405
- const nodesAtLevel = nodesByLevel.get(level) || []
406
- nodesAtLevel.push(nodeId)
407
- nodesByLevel.set(level, nodesAtLevel)
408
- }
409
-
410
- // Calculate positions
411
- const centerX = 400 // Center line for the graph
412
- const startY = 50
413
-
414
- for (const [level, nodeIds] of nodesByLevel) {
415
- const count = nodeIds.length
416
- const y = startY + level * spacing.vertical
417
-
418
- if (count === 1) {
419
- // Single node at this level - center it
420
- positions.set(nodeIds[0], { x: centerX, y })
421
- } else {
422
- // Multiple nodes at this level - spread them horizontally
423
- const totalWidth = (count - 1) * spacing.horizontal
424
- const startX = centerX - totalWidth / 2
425
-
426
- // Sort nodes by their parent's position for consistent ordering
427
- nodeIds.sort((a, b) => {
428
- const parentsA = incoming.get(a) || []
429
- const parentsB = incoming.get(b) || []
430
- const parentPosA = parentsA.length > 0 ? (positions.get(parentsA[0])?.x || 0) : 0
431
- const parentPosB = parentsB.length > 0 ? (positions.get(parentsB[0])?.x || 0) : 0
432
- return parentPosA - parentPosB
433
- })
434
-
435
- nodeIds.forEach((nodeId, idx) => {
436
- positions.set(nodeId, { x: startX + idx * spacing.horizontal, y })
437
- })
438
- }
439
- }
440
-
441
- return positions
442
- }
443
-
444
329
  /**
445
330
  * Map node type to step type (for graph → definition)
446
331
  */
@@ -7,8 +7,6 @@ import checkoutDemoDefinition from '../examples/checkout-demo-definition.json'
7
7
  import guardRulesExample from '../examples/guard-rules-example.json'
8
8
  import salesPipelineDefinition from '../examples/sales-pipeline-definition.json'
9
9
  import simpleApprovalDefinition from '../examples/simple-approval-definition.json'
10
- import orderApprovalDefinition from '../examples/order-approval-definition.json'
11
- import orderApprovalGuardRules from '../examples/order-approval-guard-rules.json'
12
10
 
13
11
  export type WorkflowSeedScope = { tenantId: string; organizationId: string }
14
12
 
@@ -53,8 +51,6 @@ const embeddedSeeds: Record<string, unknown> = {
53
51
  'guard-rules-example.json': guardRulesExample,
54
52
  'sales-pipeline-definition.json': salesPipelineDefinition,
55
53
  'simple-approval-definition.json': simpleApprovalDefinition,
56
- 'order-approval-definition.json': orderApprovalDefinition,
57
- 'order-approval-guard-rules.json': orderApprovalGuardRules,
58
54
  }
59
55
 
60
56
  function readExampleJson<T>(fileName: string): T {
@@ -94,35 +90,16 @@ async function seedWorkflowDefinition(
94
90
  })
95
91
 
96
92
  if (existing) {
97
- // Check if the definition needs to be updated by comparing steps and transitions
98
- const seedStepCount = seed.definition.steps.length
99
- const existingStepCount = existing.definition.steps.length
100
- const seedTransitionCount = seed.definition.transitions.length
101
- const existingTransitionCount = existing.definition.transitions.length
102
-
103
- // Check for preConditions on transitions
104
- const seedHasTransitionPreConditions = seed.definition.transitions.some(
105
- (t: any) => t.preConditions && t.preConditions.length > 0
106
- )
107
- const existingHasTransitionPreConditions = existing.definition.transitions.some(
108
- (t: any) => t.preConditions && t.preConditions.length > 0
109
- )
110
-
111
- // Check for preConditions on START step
93
+ // Check if the definition needs to be updated (e.g., missing preConditions on START step)
112
94
  const seedStartStep = seed.definition.steps.find((s: any) => s.stepType === 'START')
113
95
  const existingStartStep = existing.definition.steps.find((s: any) => s.stepType === 'START')
114
- const seedHasStartPreConditions = seedStartStep?.preConditions && seedStartStep.preConditions.length > 0
115
- const existingHasStartPreConditions = existingStartStep?.preConditions && existingStartStep.preConditions.length > 0
116
-
117
- // Update if structure has changed
118
- const needsUpdate =
119
- seedStepCount !== existingStepCount ||
120
- seedTransitionCount !== existingTransitionCount ||
121
- (seedHasStartPreConditions && !existingHasStartPreConditions) ||
122
- (seedHasTransitionPreConditions && !existingHasTransitionPreConditions)
123
-
124
- if (needsUpdate) {
125
- console.log(`[seed] Updating workflow ${workflowId} (steps: ${existingStepCount}→${seedStepCount}, transitions: ${existingTransitionCount}→${seedTransitionCount})`)
96
+
97
+ const seedHasPreConditions = seedStartStep?.preConditions && seedStartStep.preConditions.length > 0
98
+ const existingHasPreConditions = existingStartStep?.preConditions && existingStartStep.preConditions.length > 0
99
+
100
+ // Update if seed has preConditions but existing doesn't
101
+ if (seedHasPreConditions && !existingHasPreConditions) {
102
+ console.log(`[seed] Updating workflow ${workflowId} with preConditions`)
126
103
  existing.definition = seed.definition
127
104
  await em.flush()
128
105
  return true
@@ -195,7 +172,4 @@ export async function seedExampleWorkflows(em: EntityManager, scope: WorkflowSee
195
172
  await seedGuardRules(em, scope, 'guard-rules-example.json')
196
173
  await seedWorkflowDefinition(em, scope, 'sales-pipeline-definition.json')
197
174
  await seedWorkflowDefinition(em, scope, 'simple-approval-definition.json')
198
- // Seed order approval guard rules before the workflow definition
199
- await seedGuardRules(em, scope, 'order-approval-guard-rules.json')
200
- await seedWorkflowDefinition(em, scope, 'order-approval-definition.json')
201
175
  }
@@ -128,69 +128,59 @@ export async function validateWorkflowStart(
128
128
  const validatedRules: ValidatedRule[] = []
129
129
 
130
130
  for (const condition of preConditions) {
131
- // Execute rule directly by string rule_id
132
- const result = await ruleEngine.executeRuleByRuleId(em, {
133
- ruleId: condition.ruleId, // String identifier like "workflow_checkout_inventory_available"
131
+ const ruleContext: ruleEngine.RuleEngineContext = {
132
+ entityType: `workflow:${workflowId}:start`,
133
+ entityId: 'pre_start_validation',
134
+ eventType: 'validate_start',
134
135
  data: {
135
136
  workflowId,
136
137
  workflowContext: context,
137
138
  },
138
139
  tenantId,
139
140
  organizationId,
140
- entityType: `workflow:${workflowId}:start`,
141
- entityId: 'pre_start_validation',
142
- eventType: 'validate_start',
143
141
  dryRun: true, // Don't log execution during validation
144
- })
142
+ }
145
143
 
146
- validatedRules.push({
147
- ruleId: condition.ruleId,
148
- passed: result.conditionResult,
149
- executionTime: result.executionTime,
144
+ // Find applicable rules for this context
145
+ const rules = await ruleEngine.findApplicableRules(em, {
146
+ entityType: ruleContext.entityType,
147
+ eventType: ruleContext.eventType,
148
+ tenantId,
149
+ organizationId,
150
+ ruleType: 'GUARD',
150
151
  })
151
152
 
152
- // Handle rule not found
153
- if (result.error === 'Rule not found') {
153
+ const rule = rules.find(r => r.ruleId === condition.ruleId)
154
+
155
+ if (!rule) {
156
+ // Rule not found - if required, this is an error
154
157
  if (condition.required) {
155
158
  errors.push({
156
159
  ruleId: condition.ruleId,
157
- message: getLocalizedMessage(condition, null, locale, `Business rule not found: ${condition.ruleId}`),
160
+ message: getLocalizedMessage(condition, null, locale, `Business rule '${condition.ruleId}' not found`),
158
161
  code: 'RULE_NOT_FOUND',
159
162
  })
163
+ validatedRules.push({ ruleId: condition.ruleId, passed: false })
160
164
  }
161
165
  continue
162
166
  }
163
167
 
164
- // Handle disabled rule
165
- if (result.error === 'Rule is disabled') {
166
- if (condition.required) {
167
- errors.push({
168
- ruleId: condition.ruleId,
169
- message: getLocalizedMessage(condition, null, locale, `Business rule is disabled: ${result.ruleName}`),
170
- code: 'RULE_DISABLED',
171
- })
172
- }
173
- continue
174
- }
168
+ // Execute the single rule
169
+ const result = await ruleEngine.executeSingleRule(em, rule, ruleContext)
175
170
 
176
- // Handle other errors (not yet effective, expired, etc.)
177
- if (result.error && condition.required) {
178
- errors.push({
179
- ruleId: condition.ruleId,
180
- message: getLocalizedMessage(condition, null, locale, `Rule error: ${result.error}`),
181
- code: 'RULE_ERROR',
182
- })
183
- continue
184
- }
171
+ validatedRules.push({
172
+ ruleId: condition.ruleId,
173
+ passed: result.conditionResult,
174
+ executionTime: result.executionTime,
175
+ })
185
176
 
186
- // Handle condition failure
187
177
  if (!result.conditionResult && condition.required) {
188
- // Get localized message from condition or use default with rule name
178
+ // Get localized message from condition, rule failure actions, or default
189
179
  const message = getLocalizedMessage(
190
180
  condition,
191
- null,
181
+ rule,
192
182
  locale,
193
- `Pre-condition '${result.ruleName || condition.ruleId}' failed`
183
+ `Pre-condition '${rule.ruleName || condition.ruleId}' failed`
194
184
  )
195
185
  errors.push({
196
186
  ruleId: condition.ruleId,
@@ -19,6 +19,7 @@ import {
19
19
  } from '../data/entities'
20
20
  import * as ruleEvaluator from '../../business_rules/lib/rule-evaluator'
21
21
  import * as ruleEngine from '../../business_rules/lib/rule-engine'
22
+ import type { RuleEngineContext } from '../../business_rules/lib/rule-engine'
22
23
  import * as activityExecutor from './activity-executor'
23
24
  import type { ActivityDefinition } from './activity-executor'
24
25
  import * as stepHandler from './step-handler'
@@ -193,15 +194,11 @@ export async function evaluateTransition(
193
194
  /**
194
195
  * Find all valid transitions from current step
195
196
  *
196
- * This function evaluates both inline conditions AND preConditions (business rules)
197
- * to determine which transitions are truly valid. This is important for decision
198
- * branching where multiple transitions exist with different preConditions.
199
- *
200
197
  * @param em - Entity manager
201
198
  * @param instance - Workflow instance
202
199
  * @param fromStepId - Current step ID
203
200
  * @param context - Evaluation context
204
- * @returns Array of evaluation results for all transitions, sorted by priority (desc)
201
+ * @returns Array of evaluation results for all transitions
205
202
  */
206
203
  export async function findValidTransitions(
207
204
  em: EntityManager,
@@ -219,17 +216,16 @@ export async function findValidTransitions(
219
216
  return []
220
217
  }
221
218
 
222
- // Find all transitions from current step, sorted by priority (highest first)
223
- const transitions = (definition.definition.transitions || [])
224
- .filter((t: any) => t.fromStepId === fromStepId)
225
- .sort((a: any, b: any) => (b.priority || 0) - (a.priority || 0))
219
+ // Find all transitions from current step
220
+ const transitions = (definition.definition.transitions || []).filter(
221
+ (t: any) => t.fromStepId === fromStepId
222
+ )
226
223
 
227
- // Evaluate each transition including preConditions
224
+ // Evaluate each transition
228
225
  const results: TransitionEvaluationResult[] = []
229
226
 
230
227
  for (const transition of transitions) {
231
- // First check inline condition
232
- const conditionResult = await evaluateTransition(
228
+ const result = await evaluateTransition(
233
229
  em,
234
230
  instance,
235
231
  fromStepId,
@@ -237,42 +233,7 @@ export async function findValidTransitions(
237
233
  context
238
234
  )
239
235
 
240
- if (!conditionResult.isValid) {
241
- results.push(conditionResult)
242
- continue
243
- }
244
-
245
- // Also evaluate preConditions if they exist
246
- const preConditions = transition.preConditions || []
247
- if (preConditions.length > 0) {
248
- const preConditionsResult = await evaluatePreConditions(
249
- em,
250
- instance,
251
- transition,
252
- context as TransitionExecutionContext
253
- )
254
-
255
- if (!preConditionsResult.allowed) {
256
- // Transition is invalid due to preConditions
257
- const failedRules = preConditionsResult.executedRules
258
- .filter((r) => !r.conditionResult)
259
- .map((r) => r.rule.ruleId || r.rule.ruleName)
260
-
261
- results.push({
262
- isValid: false,
263
- transition,
264
- reason: `Pre-conditions failed: ${failedRules.join(', ')}`,
265
- failedConditions: failedRules,
266
- })
267
- continue
268
- }
269
- }
270
-
271
- // Transition is valid (both condition and preConditions passed)
272
- results.push({
273
- ...conditionResult,
274
- transition,
275
- })
236
+ results.push(result)
276
237
  }
277
238
 
278
239
  return results
@@ -688,10 +649,6 @@ async function evaluateTransitionConditions(
688
649
  * Pre-conditions are GUARD rules that must pass before transition can execute.
689
650
  * If any GUARD rule fails, the transition is blocked.
690
651
  *
691
- * If the transition defines specific preConditions with ruleIds, those are
692
- * executed directly via executeRuleByRuleId. Otherwise, falls back to
693
- * discovery-based execution via executeRules.
694
- *
695
652
  * @param em - Entity manager
696
653
  * @param instance - Workflow instance
697
654
  * @param transition - Transition definition
@@ -718,88 +675,32 @@ async function evaluatePreConditions(
718
675
  }
719
676
  }
720
677
 
721
- // Check if transition has specific preConditions defined
722
- const preConditions = transition.preConditions || []
723
-
724
- // If no pre-conditions defined, allow transition
725
- if (preConditions.length === 0) {
726
- return {
727
- allowed: true,
728
- executedRules: [],
729
- totalExecutionTime: 0,
730
- }
731
- }
732
-
733
- // Execute each pre-condition rule directly by ruleId
734
- const startTime = Date.now()
735
- const executedRules: ruleEngine.RuleExecutionResult[] = []
736
- const errors: string[] = []
737
- let allowed = true
738
-
739
- for (const condition of preConditions) {
740
- const result = await ruleEngine.executeRuleByRuleId(em, {
741
- ruleId: condition.ruleId, // String identifier
742
- data: {
743
- workflowInstanceId: instance.id,
744
- workflowId: definition.workflowId,
745
- fromStepId: transition.fromStepId,
746
- toStepId: transition.toStepId,
747
- workflowContext: {
748
- ...instance.context,
749
- ...context.workflowContext,
750
- },
751
- triggerData: context.triggerData,
678
+ // Build rule engine context
679
+ const ruleContext: RuleEngineContext = {
680
+ entityType: `workflow:${definition.workflowId}:transition`,
681
+ entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
682
+ eventType: 'pre_transition',
683
+ data: {
684
+ workflowInstanceId: instance.id,
685
+ workflowId: definition.workflowId,
686
+ fromStepId: transition.fromStepId,
687
+ toStepId: transition.toStepId,
688
+ workflowContext: {
689
+ ...instance.context,
690
+ ...context.workflowContext,
752
691
  },
753
- user: context.userId ? { id: context.userId } : undefined,
754
- tenantId: instance.tenantId,
755
- organizationId: instance.organizationId,
756
- executedBy: context.userId,
757
- entityType: `workflow:${definition.workflowId}:transition`,
758
- entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
759
- eventType: 'pre_transition',
760
- })
761
-
762
- // Create a compatible RuleExecutionResult for tracking
763
- // We don't have the full BusinessRule entity, but we can create a partial result
764
- const ruleResult: ruleEngine.RuleExecutionResult = {
765
- rule: {
766
- ruleId: result.ruleId,
767
- ruleName: result.ruleName,
768
- ruleType: 'GUARD',
769
- } as any,
770
- conditionResult: result.conditionResult,
771
- actionsExecuted: result.actionsExecuted,
772
- executionTime: result.executionTime,
773
- error: result.error,
774
- logId: result.logId,
775
- }
776
- executedRules.push(ruleResult)
777
-
778
- // Handle rule errors
779
- if (result.error) {
780
- // Rule not found, disabled, or other errors
781
- const isRequired = condition.required !== false // Default to required
782
- if (isRequired) {
783
- allowed = false
784
- errors.push(`Rule '${result.ruleId}': ${result.error}`)
785
- }
786
- continue
787
- }
788
-
789
- // If required and condition failed, block transition
790
- const isRequired = condition.required !== false // Default to required
791
- if (isRequired && !result.conditionResult) {
792
- allowed = false
793
- errors.push(`Pre-condition '${result.ruleName || result.ruleId}' failed`)
794
- }
692
+ triggerData: context.triggerData,
693
+ },
694
+ user: context.userId ? { id: context.userId } : undefined,
695
+ tenantId: instance.tenantId,
696
+ organizationId: instance.organizationId,
697
+ executedBy: context.userId,
795
698
  }
796
699
 
797
- return {
798
- allowed,
799
- executedRules,
800
- totalExecutionTime: Date.now() - startTime,
801
- errors: errors.length > 0 ? errors : undefined,
802
- }
700
+ // Execute rules - only GUARD rules will affect the 'allowed' status
701
+ const result = await ruleEngine.executeRules(em, ruleContext)
702
+
703
+ return result
803
704
  } catch (error) {
804
705
  console.error('Error evaluating pre-conditions:', error)
805
706
  return {
@@ -817,9 +718,6 @@ async function evaluatePreConditions(
817
718
  * Post-conditions are GUARD rules that should pass after transition executes.
818
719
  * Unlike pre-conditions, post-condition failures are logged but don't block the transition.
819
720
  *
820
- * If the transition defines specific postConditions with ruleIds, those are
821
- * executed directly via executeRuleByRuleId. Otherwise, returns allowed: true.
822
- *
823
721
  * @param em - Entity manager
824
722
  * @param instance - Workflow instance
825
723
  * @param transition - Transition definition
@@ -846,83 +744,32 @@ async function evaluatePostConditions(
846
744
  }
847
745
  }
848
746
 
849
- // Check if transition has specific postConditions defined
850
- const postConditions = transition.postConditions || []
851
-
852
- // If no post-conditions defined, allow
853
- if (postConditions.length === 0) {
854
- return {
855
- allowed: true,
856
- executedRules: [],
857
- totalExecutionTime: 0,
858
- }
859
- }
860
-
861
- // Execute each post-condition rule directly by ruleId
862
- const startTime = Date.now()
863
- const executedRules: ruleEngine.RuleExecutionResult[] = []
864
- const errors: string[] = []
865
- let allowed = true
866
-
867
- for (const condition of postConditions) {
868
- const result = await ruleEngine.executeRuleByRuleId(em, {
869
- ruleId: condition.ruleId, // String identifier
870
- data: {
871
- workflowInstanceId: instance.id,
872
- workflowId: definition.workflowId,
873
- fromStepId: transition.fromStepId,
874
- toStepId: transition.toStepId,
875
- workflowContext: {
876
- ...instance.context,
877
- ...context.workflowContext,
878
- },
879
- triggerData: context.triggerData,
747
+ // Build rule engine context
748
+ const ruleContext: RuleEngineContext = {
749
+ entityType: `workflow:${definition.workflowId}:transition`,
750
+ entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
751
+ eventType: 'post_transition',
752
+ data: {
753
+ workflowInstanceId: instance.id,
754
+ workflowId: definition.workflowId,
755
+ fromStepId: transition.fromStepId,
756
+ toStepId: transition.toStepId,
757
+ workflowContext: {
758
+ ...instance.context,
759
+ ...context.workflowContext,
880
760
  },
881
- user: context.userId ? { id: context.userId } : undefined,
882
- tenantId: instance.tenantId,
883
- organizationId: instance.organizationId,
884
- executedBy: context.userId,
885
- entityType: `workflow:${definition.workflowId}:transition`,
886
- entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
887
- eventType: 'post_transition',
888
- })
889
-
890
- // Create a compatible RuleExecutionResult for tracking
891
- const ruleResult: ruleEngine.RuleExecutionResult = {
892
- rule: {
893
- ruleId: result.ruleId,
894
- ruleName: result.ruleName,
895
- ruleType: 'GUARD',
896
- } as any,
897
- conditionResult: result.conditionResult,
898
- actionsExecuted: result.actionsExecuted,
899
- executionTime: result.executionTime,
900
- error: result.error,
901
- logId: result.logId,
902
- }
903
- executedRules.push(ruleResult)
904
-
905
- // Handle rule errors
906
- if (result.error) {
907
- errors.push(`Rule '${result.ruleId}': ${result.error}`)
908
- // Post-conditions don't block, but track the failure
909
- allowed = false
910
- continue
911
- }
912
-
913
- // Track condition failures (post-conditions are warnings, not blockers)
914
- if (!result.conditionResult) {
915
- allowed = false
916
- errors.push(`Post-condition '${result.ruleName || result.ruleId}' failed`)
917
- }
761
+ triggerData: context.triggerData,
762
+ },
763
+ user: context.userId ? { id: context.userId } : undefined,
764
+ tenantId: instance.tenantId,
765
+ organizationId: instance.organizationId,
766
+ executedBy: context.userId,
918
767
  }
919
768
 
920
- return {
921
- allowed,
922
- executedRules,
923
- totalExecutionTime: Date.now() - startTime,
924
- errors: errors.length > 0 ? errors : undefined,
925
- }
769
+ // Execute rules
770
+ const result = await ruleEngine.executeRules(em, ruleContext)
771
+
772
+ return result
926
773
  } catch (error) {
927
774
  console.error('Error evaluating post-conditions:', error)
928
775
  return {
@@ -1,33 +0,0 @@
1
- const id = "id";
2
- const name = "name";
3
- const description = "description";
4
- const workflow_definition_id = "workflow_definition_id";
5
- const event_pattern = "event_pattern";
6
- const config = "config";
7
- const enabled = "enabled";
8
- const priority = "priority";
9
- const tenant_id = "tenant_id";
10
- const organization_id = "organization_id";
11
- const created_by = "created_by";
12
- const updated_by = "updated_by";
13
- const created_at = "created_at";
14
- const updated_at = "updated_at";
15
- const deleted_at = "deleted_at";
16
- export {
17
- config,
18
- created_at,
19
- created_by,
20
- deleted_at,
21
- description,
22
- enabled,
23
- event_pattern,
24
- id,
25
- name,
26
- organization_id,
27
- priority,
28
- tenant_id,
29
- updated_at,
30
- updated_by,
31
- workflow_definition_id
32
- };
33
- //# sourceMappingURL=index.js.map