@open-mercato/core 0.4.2-canary-d0a025141f → 0.4.2-canary-3efa759f5c

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 (158) 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/__tests__/instances.route.test.ts +2 -5
  78. package/src/modules/workflows/api/instances/route.ts +7 -21
  79. package/src/modules/workflows/api/tasks/route.ts +1 -7
  80. package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
  81. package/src/modules/workflows/backend/definitions/[id]/page.tsx +0 -9
  82. package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
  83. package/src/modules/workflows/backend/definitions/create/page.tsx +0 -9
  84. package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
  85. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +3 -21
  86. package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
  87. package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
  88. package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
  89. package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
  90. package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
  91. package/src/modules/workflows/backend/tasks/page.tsx +6 -5
  92. package/src/modules/workflows/cli.ts +0 -111
  93. package/src/modules/workflows/data/entities.ts +0 -124
  94. package/src/modules/workflows/data/validators.ts +0 -138
  95. package/src/modules/workflows/examples/checkout-demo-definition.json +5 -1
  96. package/src/modules/workflows/i18n/en.json +0 -71
  97. package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +36 -43
  98. package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +90 -170
  99. package/src/modules/workflows/lib/activity-executor.ts +16 -129
  100. package/src/modules/workflows/lib/graph-utils.ts +2 -117
  101. package/src/modules/workflows/lib/seeds.ts +8 -34
  102. package/src/modules/workflows/lib/start-validator.ts +28 -38
  103. package/src/modules/workflows/lib/transition-handler.ts +55 -208
  104. package/dist/generated/entities/workflow_event_trigger/index.js +0 -33
  105. package/dist/generated/entities/workflow_event_trigger/index.js.map +0 -7
  106. package/dist/modules/auth/events.js +0 -30
  107. package/dist/modules/auth/events.js.map +0 -7
  108. package/dist/modules/business_rules/api/execute/[ruleId]/route.js +0 -145
  109. package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +0 -7
  110. package/dist/modules/catalog/events.js +0 -34
  111. package/dist/modules/catalog/events.js.map +0 -7
  112. package/dist/modules/customers/events.js +0 -49
  113. package/dist/modules/customers/events.js.map +0 -7
  114. package/dist/modules/directory/events.js +0 -23
  115. package/dist/modules/directory/events.js.map +0 -7
  116. package/dist/modules/sales/events.js +0 -63
  117. package/dist/modules/sales/events.js.map +0 -7
  118. package/dist/modules/sales/lib/frontend/documentDataEvents.js +0 -25
  119. package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +0 -7
  120. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +0 -481
  121. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +0 -7
  122. package/dist/modules/workflows/components/EventTriggersEditor.js +0 -553
  123. package/dist/modules/workflows/components/EventTriggersEditor.js.map +0 -7
  124. package/dist/modules/workflows/events.js +0 -38
  125. package/dist/modules/workflows/events.js.map +0 -7
  126. package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
  127. package/dist/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  128. package/dist/modules/workflows/lib/event-trigger-service.js +0 -308
  129. package/dist/modules/workflows/lib/event-trigger-service.js.map +0 -7
  130. package/dist/modules/workflows/migrations/Migration20260123143500.js +0 -36
  131. package/dist/modules/workflows/migrations/Migration20260123143500.js.map +0 -7
  132. package/dist/modules/workflows/subscribers/event-trigger.js +0 -78
  133. package/dist/modules/workflows/subscribers/event-trigger.js.map +0 -7
  134. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +0 -323
  135. package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +0 -7
  136. package/dist/modules/workflows/widgets/injection/order-approval/widget.js +0 -17
  137. package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +0 -7
  138. package/dist/modules/workflows/widgets/injection-table.js +0 -19
  139. package/dist/modules/workflows/widgets/injection-table.js.map +0 -7
  140. package/generated/entities/workflow_event_trigger/index.ts +0 -15
  141. package/src/modules/auth/events.ts +0 -39
  142. package/src/modules/business_rules/api/execute/[ruleId]/route.ts +0 -163
  143. package/src/modules/catalog/events.ts +0 -45
  144. package/src/modules/customers/events.ts +0 -63
  145. package/src/modules/directory/events.ts +0 -31
  146. package/src/modules/sales/events.ts +0 -82
  147. package/src/modules/sales/lib/frontend/documentDataEvents.ts +0 -28
  148. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +0 -581
  149. package/src/modules/workflows/components/EventTriggersEditor.tsx +0 -664
  150. package/src/modules/workflows/events.ts +0 -49
  151. package/src/modules/workflows/examples/order-approval-definition.json +0 -257
  152. package/src/modules/workflows/examples/order-approval-guard-rules.json +0 -32
  153. package/src/modules/workflows/lib/event-trigger-service.ts +0 -557
  154. package/src/modules/workflows/migrations/Migration20260123143500.ts +0 -38
  155. package/src/modules/workflows/subscribers/event-trigger.ts +0 -109
  156. package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +0 -446
  157. package/src/modules/workflows/widgets/injection/order-approval/widget.ts +0 -16
  158. package/src/modules/workflows/widgets/injection-table.ts +0 -21
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/seeds.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { WorkflowDefinition, type WorkflowDefinitionData } from '../data/entities'\nimport { BusinessRule, type RuleType } from '@open-mercato/core/modules/business_rules/data/entities'\nimport checkoutDemoDefinition from '../examples/checkout-demo-definition.json'\nimport guardRulesExample from '../examples/guard-rules-example.json'\nimport salesPipelineDefinition from '../examples/sales-pipeline-definition.json'\nimport simpleApprovalDefinition from '../examples/simple-approval-definition.json'\nimport orderApprovalDefinition from '../examples/order-approval-definition.json'\nimport orderApprovalGuardRules from '../examples/order-approval-guard-rules.json'\n\nexport type WorkflowSeedScope = { tenantId: string; organizationId: string }\n\ntype WorkflowSeedDefinition = {\n workflowId: string\n workflowName: string\n description?: string | null\n version?: number\n definition: WorkflowDefinitionData\n metadata?: Record<string, unknown> | null\n enabled?: boolean\n effectiveFrom?: string | null\n effectiveTo?: string | null\n createdBy?: string | null\n updatedBy?: string | null\n}\n\ntype GuardRuleSeed = {\n ruleId: string\n ruleName: string\n ruleType: RuleType\n entityType: string\n conditionExpression: unknown\n eventType?: string | null\n ruleCategory?: string | null\n description?: string | null\n successActions?: unknown\n failureActions?: unknown\n enabled?: boolean\n priority?: number\n version?: number\n effectiveFrom?: string | null\n effectiveTo?: string | null\n createdBy?: string | null\n updatedBy?: string | null\n tagsJson?: string[]\n labelsJson?: Record<string, string>\n}\n\nconst embeddedSeeds: Record<string, unknown> = {\n 'checkout-demo-definition.json': checkoutDemoDefinition,\n 'guard-rules-example.json': guardRulesExample,\n 'sales-pipeline-definition.json': salesPipelineDefinition,\n 'simple-approval-definition.json': simpleApprovalDefinition,\n 'order-approval-definition.json': orderApprovalDefinition,\n 'order-approval-guard-rules.json': orderApprovalGuardRules,\n}\n\nfunction readExampleJson<T>(fileName: string): T {\n const embedded = embeddedSeeds[fileName]\n if (embedded) {\n return embedded as T\n }\n const candidates = [\n path.join(__dirname, '..', 'examples', fileName),\n path.join(process.cwd(), 'packages', 'core', 'src', 'modules', 'workflows', 'examples', fileName),\n path.join(process.cwd(), 'src', 'modules', 'workflows', 'examples', fileName),\n ]\n const filePath = candidates.find((candidate) => fs.existsSync(candidate))\n if (!filePath) {\n throw new Error(`Missing workflow seed file: ${fileName}`)\n }\n return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T\n}\n\nfunction requireString(value: unknown, label: string): string {\n if (typeof value === 'string' && value.trim().length > 0) return value\n throw new Error(`Invalid ${label} in workflow seed data.`)\n}\n\nasync function seedWorkflowDefinition(\n em: EntityManager,\n scope: WorkflowSeedScope,\n fileName: string,\n): Promise<boolean> {\n const seed = readExampleJson<WorkflowSeedDefinition>(fileName)\n const workflowId = requireString(seed.workflowId, 'workflowId')\n\n const existing = await em.findOne(WorkflowDefinition, {\n workflowId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n\n if (existing) {\n // Check if the definition needs to be updated by comparing steps and transitions\n const seedStepCount = seed.definition.steps.length\n const existingStepCount = existing.definition.steps.length\n const seedTransitionCount = seed.definition.transitions.length\n const existingTransitionCount = existing.definition.transitions.length\n\n // Check for preConditions on transitions\n const seedHasTransitionPreConditions = seed.definition.transitions.some(\n (t: any) => t.preConditions && t.preConditions.length > 0\n )\n const existingHasTransitionPreConditions = existing.definition.transitions.some(\n (t: any) => t.preConditions && t.preConditions.length > 0\n )\n\n // Check for preConditions on START step\n const seedStartStep = seed.definition.steps.find((s: any) => s.stepType === 'START')\n const existingStartStep = existing.definition.steps.find((s: any) => s.stepType === 'START')\n const seedHasStartPreConditions = seedStartStep?.preConditions && seedStartStep.preConditions.length > 0\n const existingHasStartPreConditions = existingStartStep?.preConditions && existingStartStep.preConditions.length > 0\n\n // Update if structure has changed\n const needsUpdate =\n seedStepCount !== existingStepCount ||\n seedTransitionCount !== existingTransitionCount ||\n (seedHasStartPreConditions && !existingHasStartPreConditions) ||\n (seedHasTransitionPreConditions && !existingHasTransitionPreConditions)\n\n if (needsUpdate) {\n console.log(`[seed] Updating workflow ${workflowId} (steps: ${existingStepCount}\u2192${seedStepCount}, transitions: ${existingTransitionCount}\u2192${seedTransitionCount})`)\n existing.definition = seed.definition\n await em.flush()\n return true\n }\n\n return false\n }\n\n const workflow = em.create(WorkflowDefinition, {\n ...seed,\n workflowId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n em.persist(workflow)\n await em.flush()\n return true\n}\n\nasync function seedGuardRules(\n em: EntityManager,\n scope: WorkflowSeedScope,\n fileName: string,\n): Promise<{ seeded: number; skipped: number; updated: number }> {\n const seeds = readExampleJson<GuardRuleSeed[]>(fileName)\n if (!Array.isArray(seeds)) {\n throw new Error('Invalid guard rules seed data.')\n }\n\n let seeded = 0\n let skipped = 0\n let updated = 0\n for (const rule of seeds) {\n const ruleId = requireString(rule.ruleId, 'ruleId')\n const existing = await em.findOne(BusinessRule, {\n ruleId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n if (existing) {\n // Check if entityType or eventType needs updating\n const needsUpdate = existing.entityType !== rule.entityType || existing.eventType !== rule.eventType\n if (needsUpdate) {\n console.log(`[seed] Updating business rule ${ruleId}: entityType=${rule.entityType}, eventType=${rule.eventType}`)\n existing.entityType = rule.entityType\n existing.eventType = rule.eventType ?? null\n updated += 1\n } else {\n skipped += 1\n }\n continue\n }\n const entry = em.create(BusinessRule, {\n ...rule,\n ruleId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n em.persist(entry)\n seeded += 1\n }\n if (seeded > 0 || updated > 0) {\n await em.flush()\n }\n return { seeded, skipped, updated }\n}\n\nexport async function seedExampleWorkflows(em: EntityManager, scope: WorkflowSeedScope): Promise<void> {\n await seedWorkflowDefinition(em, scope, 'checkout-demo-definition.json')\n await seedGuardRules(em, scope, 'guard-rules-example.json')\n await seedWorkflowDefinition(em, scope, 'sales-pipeline-definition.json')\n await seedWorkflowDefinition(em, scope, 'simple-approval-definition.json')\n // Seed order approval guard rules before the workflow definition\n await seedGuardRules(em, scope, 'order-approval-guard-rules.json')\n await seedWorkflowDefinition(em, scope, 'order-approval-definition.json')\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { WorkflowDefinition, type WorkflowDefinitionData } from '../data/entities'\nimport { BusinessRule, type RuleType } from '@open-mercato/core/modules/business_rules/data/entities'\nimport checkoutDemoDefinition from '../examples/checkout-demo-definition.json'\nimport guardRulesExample from '../examples/guard-rules-example.json'\nimport salesPipelineDefinition from '../examples/sales-pipeline-definition.json'\nimport simpleApprovalDefinition from '../examples/simple-approval-definition.json'\n\nexport type WorkflowSeedScope = { tenantId: string; organizationId: string }\n\ntype WorkflowSeedDefinition = {\n workflowId: string\n workflowName: string\n description?: string | null\n version?: number\n definition: WorkflowDefinitionData\n metadata?: Record<string, unknown> | null\n enabled?: boolean\n effectiveFrom?: string | null\n effectiveTo?: string | null\n createdBy?: string | null\n updatedBy?: string | null\n}\n\ntype GuardRuleSeed = {\n ruleId: string\n ruleName: string\n ruleType: RuleType\n entityType: string\n conditionExpression: unknown\n eventType?: string | null\n ruleCategory?: string | null\n description?: string | null\n successActions?: unknown\n failureActions?: unknown\n enabled?: boolean\n priority?: number\n version?: number\n effectiveFrom?: string | null\n effectiveTo?: string | null\n createdBy?: string | null\n updatedBy?: string | null\n tagsJson?: string[]\n labelsJson?: Record<string, string>\n}\n\nconst embeddedSeeds: Record<string, unknown> = {\n 'checkout-demo-definition.json': checkoutDemoDefinition,\n 'guard-rules-example.json': guardRulesExample,\n 'sales-pipeline-definition.json': salesPipelineDefinition,\n 'simple-approval-definition.json': simpleApprovalDefinition,\n}\n\nfunction readExampleJson<T>(fileName: string): T {\n const embedded = embeddedSeeds[fileName]\n if (embedded) {\n return embedded as T\n }\n const candidates = [\n path.join(__dirname, '..', 'examples', fileName),\n path.join(process.cwd(), 'packages', 'core', 'src', 'modules', 'workflows', 'examples', fileName),\n path.join(process.cwd(), 'src', 'modules', 'workflows', 'examples', fileName),\n ]\n const filePath = candidates.find((candidate) => fs.existsSync(candidate))\n if (!filePath) {\n throw new Error(`Missing workflow seed file: ${fileName}`)\n }\n return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T\n}\n\nfunction requireString(value: unknown, label: string): string {\n if (typeof value === 'string' && value.trim().length > 0) return value\n throw new Error(`Invalid ${label} in workflow seed data.`)\n}\n\nasync function seedWorkflowDefinition(\n em: EntityManager,\n scope: WorkflowSeedScope,\n fileName: string,\n): Promise<boolean> {\n const seed = readExampleJson<WorkflowSeedDefinition>(fileName)\n const workflowId = requireString(seed.workflowId, 'workflowId')\n\n const existing = await em.findOne(WorkflowDefinition, {\n workflowId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n\n if (existing) {\n // Check if the definition needs to be updated (e.g., missing preConditions on START step)\n const seedStartStep = seed.definition.steps.find((s: any) => s.stepType === 'START')\n const existingStartStep = existing.definition.steps.find((s: any) => s.stepType === 'START')\n\n const seedHasPreConditions = seedStartStep?.preConditions && seedStartStep.preConditions.length > 0\n const existingHasPreConditions = existingStartStep?.preConditions && existingStartStep.preConditions.length > 0\n\n // Update if seed has preConditions but existing doesn't\n if (seedHasPreConditions && !existingHasPreConditions) {\n console.log(`[seed] Updating workflow ${workflowId} with preConditions`)\n existing.definition = seed.definition\n await em.flush()\n return true\n }\n\n return false\n }\n\n const workflow = em.create(WorkflowDefinition, {\n ...seed,\n workflowId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n em.persist(workflow)\n await em.flush()\n return true\n}\n\nasync function seedGuardRules(\n em: EntityManager,\n scope: WorkflowSeedScope,\n fileName: string,\n): Promise<{ seeded: number; skipped: number; updated: number }> {\n const seeds = readExampleJson<GuardRuleSeed[]>(fileName)\n if (!Array.isArray(seeds)) {\n throw new Error('Invalid guard rules seed data.')\n }\n\n let seeded = 0\n let skipped = 0\n let updated = 0\n for (const rule of seeds) {\n const ruleId = requireString(rule.ruleId, 'ruleId')\n const existing = await em.findOne(BusinessRule, {\n ruleId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n if (existing) {\n // Check if entityType or eventType needs updating\n const needsUpdate = existing.entityType !== rule.entityType || existing.eventType !== rule.eventType\n if (needsUpdate) {\n console.log(`[seed] Updating business rule ${ruleId}: entityType=${rule.entityType}, eventType=${rule.eventType}`)\n existing.entityType = rule.entityType\n existing.eventType = rule.eventType ?? null\n updated += 1\n } else {\n skipped += 1\n }\n continue\n }\n const entry = em.create(BusinessRule, {\n ...rule,\n ruleId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n em.persist(entry)\n seeded += 1\n }\n if (seeded > 0 || updated > 0) {\n await em.flush()\n }\n return { seeded, skipped, updated }\n}\n\nexport async function seedExampleWorkflows(em: EntityManager, scope: WorkflowSeedScope): Promise<void> {\n await seedWorkflowDefinition(em, scope, 'checkout-demo-definition.json')\n await seedGuardRules(em, scope, 'guard-rules-example.json')\n await seedWorkflowDefinition(em, scope, 'sales-pipeline-definition.json')\n await seedWorkflowDefinition(em, scope, 'simple-approval-definition.json')\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -58,60 +58,50 @@ async function validateWorkflowStart(em, options) {
58
58
  const errors = [];
59
59
  const validatedRules = [];
60
60
  for (const condition of preConditions) {
61
- const result = await ruleEngine.executeRuleByRuleId(em, {
62
- ruleId: condition.ruleId,
63
- // String identifier like "workflow_checkout_inventory_available"
61
+ const ruleContext = {
62
+ entityType: `workflow:${workflowId}:start`,
63
+ entityId: "pre_start_validation",
64
+ eventType: "validate_start",
64
65
  data: {
65
66
  workflowId,
66
67
  workflowContext: context
67
68
  },
68
69
  tenantId,
69
70
  organizationId,
70
- entityType: `workflow:${workflowId}:start`,
71
- entityId: "pre_start_validation",
72
- eventType: "validate_start",
73
71
  dryRun: true
74
72
  // Don't log execution during validation
73
+ };
74
+ const rules = await ruleEngine.findApplicableRules(em, {
75
+ entityType: ruleContext.entityType,
76
+ eventType: ruleContext.eventType,
77
+ tenantId,
78
+ organizationId,
79
+ ruleType: "GUARD"
75
80
  });
76
- validatedRules.push({
77
- ruleId: condition.ruleId,
78
- passed: result.conditionResult,
79
- executionTime: result.executionTime
80
- });
81
- if (result.error === "Rule not found") {
81
+ const rule = rules.find((r) => r.ruleId === condition.ruleId);
82
+ if (!rule) {
82
83
  if (condition.required) {
83
84
  errors.push({
84
85
  ruleId: condition.ruleId,
85
- message: getLocalizedMessage(condition, null, locale, `Business rule not found: ${condition.ruleId}`),
86
+ message: getLocalizedMessage(condition, null, locale, `Business rule '${condition.ruleId}' not found`),
86
87
  code: "RULE_NOT_FOUND"
87
88
  });
89
+ validatedRules.push({ ruleId: condition.ruleId, passed: false });
88
90
  }
89
91
  continue;
90
92
  }
91
- if (result.error === "Rule is disabled") {
92
- if (condition.required) {
93
- errors.push({
94
- ruleId: condition.ruleId,
95
- message: getLocalizedMessage(condition, null, locale, `Business rule is disabled: ${result.ruleName}`),
96
- code: "RULE_DISABLED"
97
- });
98
- }
99
- continue;
100
- }
101
- if (result.error && condition.required) {
102
- errors.push({
103
- ruleId: condition.ruleId,
104
- message: getLocalizedMessage(condition, null, locale, `Rule error: ${result.error}`),
105
- code: "RULE_ERROR"
106
- });
107
- continue;
108
- }
93
+ const result = await ruleEngine.executeSingleRule(em, rule, ruleContext);
94
+ validatedRules.push({
95
+ ruleId: condition.ruleId,
96
+ passed: result.conditionResult,
97
+ executionTime: result.executionTime
98
+ });
109
99
  if (!result.conditionResult && condition.required) {
110
100
  const message = getLocalizedMessage(
111
101
  condition,
112
- null,
102
+ rule,
113
103
  locale,
114
- `Pre-condition '${result.ruleName || condition.ruleId}' failed`
104
+ `Pre-condition '${rule.ruleName || condition.ruleId}' failed`
115
105
  );
116
106
  errors.push({
117
107
  ruleId: condition.ruleId,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/workflows/lib/start-validator.ts"],
4
- "sourcesContent": ["/**\n * Workflows Module - Start Validator Service\n *\n * Validates pre-conditions on START step before workflow instance creation.\n * This enables guard rules that determine whether a workflow can be started\n * based on the initial context provided.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport { WorkflowDefinition } from '../data/entities'\nimport * as ruleEngine from '../../business_rules/lib/rule-engine'\nimport type { StartPreCondition } from '../data/validators'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface ValidateStartOptions {\n workflowId: string\n version?: number\n context: Record<string, any>\n locale?: string\n tenantId: string\n organizationId: string\n}\n\nexport interface ValidationError {\n ruleId: string\n message: string\n code: string\n}\n\nexport interface ValidatedRule {\n ruleId: string\n passed: boolean\n executionTime?: number\n}\n\nexport interface ValidateStartResult {\n canStart: boolean\n errors: ValidationError[]\n validatedRules: ValidatedRule[]\n}\n\n// ============================================================================\n// Main Validation Function\n// ============================================================================\n\n/**\n * Validate if a workflow can be started with the given context\n *\n * @param em - Entity manager for database operations\n * @param options - Validation options including workflowId, context, and scope\n * @returns Validation result with canStart flag, errors, and validated rules\n */\nexport async function validateWorkflowStart(\n em: EntityManager,\n options: ValidateStartOptions\n): Promise<ValidateStartResult> {\n const { workflowId, version, context, locale = 'en', tenantId, organizationId } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n return {\n canStart: false,\n errors: [{\n ruleId: '_DEFINITION_NOT_FOUND',\n message: `Workflow definition not found: ${workflowId}`,\n code: 'DEFINITION_NOT_FOUND',\n }],\n validatedRules: [],\n }\n }\n\n if (!definition.enabled) {\n return {\n canStart: false,\n errors: [{\n ruleId: '_DEFINITION_DISABLED',\n message: `Workflow is disabled: ${workflowId}`,\n code: 'DEFINITION_DISABLED',\n }],\n validatedRules: [],\n }\n }\n\n // Find START step and get pre-conditions\n const startStep = definition.definition.steps.find(\n (s: any) => s.stepType === 'START'\n )\n\n if (!startStep) {\n return {\n canStart: false,\n errors: [{\n ruleId: '_NO_START_STEP',\n message: 'Workflow has no START step',\n code: 'INVALID_DEFINITION',\n }],\n validatedRules: [],\n }\n }\n\n const preConditions: StartPreCondition[] = startStep.preConditions || []\n\n console.log('[start-validator] START step:', JSON.stringify(startStep, null, 2))\n console.log('[start-validator] preConditions:', preConditions.length, JSON.stringify(preConditions))\n\n // If no pre-conditions, workflow can start\n if (preConditions.length === 0) {\n console.log('[start-validator] No pre-conditions defined, allowing start')\n return {\n canStart: true,\n errors: [],\n validatedRules: [],\n }\n }\n\n // Evaluate each pre-condition using rule engine\n const errors: ValidationError[] = []\n const validatedRules: ValidatedRule[] = []\n\n for (const condition of preConditions) {\n // Execute rule directly by string rule_id\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier like \"workflow_checkout_inventory_available\"\n data: {\n workflowId,\n workflowContext: context,\n },\n tenantId,\n organizationId,\n entityType: `workflow:${workflowId}:start`,\n entityId: 'pre_start_validation',\n eventType: 'validate_start',\n dryRun: true, // Don't log execution during validation\n })\n\n validatedRules.push({\n ruleId: condition.ruleId,\n passed: result.conditionResult,\n executionTime: result.executionTime,\n })\n\n // Handle rule not found\n if (result.error === 'Rule not found') {\n if (condition.required) {\n errors.push({\n ruleId: condition.ruleId,\n message: getLocalizedMessage(condition, null, locale, `Business rule not found: ${condition.ruleId}`),\n code: 'RULE_NOT_FOUND',\n })\n }\n continue\n }\n\n // Handle disabled rule\n if (result.error === 'Rule is disabled') {\n if (condition.required) {\n errors.push({\n ruleId: condition.ruleId,\n message: getLocalizedMessage(condition, null, locale, `Business rule is disabled: ${result.ruleName}`),\n code: 'RULE_DISABLED',\n })\n }\n continue\n }\n\n // Handle other errors (not yet effective, expired, etc.)\n if (result.error && condition.required) {\n errors.push({\n ruleId: condition.ruleId,\n message: getLocalizedMessage(condition, null, locale, `Rule error: ${result.error}`),\n code: 'RULE_ERROR',\n })\n continue\n }\n\n // Handle condition failure\n if (!result.conditionResult && condition.required) {\n // Get localized message from condition or use default with rule name\n const message = getLocalizedMessage(\n condition,\n null,\n locale,\n `Pre-condition '${result.ruleName || condition.ruleId}' failed`\n )\n errors.push({\n ruleId: condition.ruleId,\n message,\n code: 'PRE_CONDITION_FAILED',\n })\n }\n }\n\n return {\n canStart: errors.length === 0,\n errors,\n validatedRules,\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get localized message with fallback chain\n *\n * Priority:\n * 1. condition.validationMessage[locale]\n * 2. condition.validationMessage['en']\n * 3. rule.failureActions[BLOCK_TRANSITION].config.message\n * 4. rule.description\n * 5. defaultMessage\n */\nfunction getLocalizedMessage(\n condition: StartPreCondition,\n rule: any | null,\n locale: string,\n defaultMessage: string\n): string {\n // Priority 1: Localized message in condition definition (requested locale)\n if (condition.validationMessage?.[locale]) {\n return condition.validationMessage[locale]\n }\n\n // Priority 2: English fallback in condition\n if (condition.validationMessage?.['en']) {\n return condition.validationMessage['en']\n }\n\n if (rule) {\n // Priority 3: Message from rule's failureActions\n if (rule.failureActions && Array.isArray(rule.failureActions)) {\n const blockAction = rule.failureActions.find(\n (a: any) => a.type === 'BLOCK_TRANSITION'\n )\n if (blockAction?.config?.message) {\n return blockAction.config.message\n }\n }\n\n // Priority 4: Rule description\n if (rule.description) {\n return rule.description\n }\n }\n\n // Priority 5: Default message\n return defaultMessage\n}\n\n/**\n * Find workflow definition by ID and optional version\n */\nasync function findWorkflowDefinition(\n em: EntityManager,\n options: {\n workflowId: string\n version?: number\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowDefinition | null> {\n const { workflowId, version, tenantId, organizationId } = options\n\n const where: any = {\n workflowId,\n tenantId,\n organizationId,\n deletedAt: null,\n }\n\n if (version !== undefined) {\n where.version = version\n }\n\n // If no version specified, get latest enabled version\n if (version === undefined) {\n where.enabled = true\n return em.findOne(WorkflowDefinition, where, {\n orderBy: { version: 'DESC' },\n })\n }\n\n return em.findOne(WorkflowDefinition, where)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Workflows Module - Start Validator Service\n *\n * Validates pre-conditions on START step before workflow instance creation.\n * This enables guard rules that determine whether a workflow can be started\n * based on the initial context provided.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport { WorkflowDefinition } from '../data/entities'\nimport * as ruleEngine from '../../business_rules/lib/rule-engine'\nimport type { StartPreCondition } from '../data/validators'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface ValidateStartOptions {\n workflowId: string\n version?: number\n context: Record<string, any>\n locale?: string\n tenantId: string\n organizationId: string\n}\n\nexport interface ValidationError {\n ruleId: string\n message: string\n code: string\n}\n\nexport interface ValidatedRule {\n ruleId: string\n passed: boolean\n executionTime?: number\n}\n\nexport interface ValidateStartResult {\n canStart: boolean\n errors: ValidationError[]\n validatedRules: ValidatedRule[]\n}\n\n// ============================================================================\n// Main Validation Function\n// ============================================================================\n\n/**\n * Validate if a workflow can be started with the given context\n *\n * @param em - Entity manager for database operations\n * @param options - Validation options including workflowId, context, and scope\n * @returns Validation result with canStart flag, errors, and validated rules\n */\nexport async function validateWorkflowStart(\n em: EntityManager,\n options: ValidateStartOptions\n): Promise<ValidateStartResult> {\n const { workflowId, version, context, locale = 'en', tenantId, organizationId } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n return {\n canStart: false,\n errors: [{\n ruleId: '_DEFINITION_NOT_FOUND',\n message: `Workflow definition not found: ${workflowId}`,\n code: 'DEFINITION_NOT_FOUND',\n }],\n validatedRules: [],\n }\n }\n\n if (!definition.enabled) {\n return {\n canStart: false,\n errors: [{\n ruleId: '_DEFINITION_DISABLED',\n message: `Workflow is disabled: ${workflowId}`,\n code: 'DEFINITION_DISABLED',\n }],\n validatedRules: [],\n }\n }\n\n // Find START step and get pre-conditions\n const startStep = definition.definition.steps.find(\n (s: any) => s.stepType === 'START'\n )\n\n if (!startStep) {\n return {\n canStart: false,\n errors: [{\n ruleId: '_NO_START_STEP',\n message: 'Workflow has no START step',\n code: 'INVALID_DEFINITION',\n }],\n validatedRules: [],\n }\n }\n\n const preConditions: StartPreCondition[] = startStep.preConditions || []\n\n console.log('[start-validator] START step:', JSON.stringify(startStep, null, 2))\n console.log('[start-validator] preConditions:', preConditions.length, JSON.stringify(preConditions))\n\n // If no pre-conditions, workflow can start\n if (preConditions.length === 0) {\n console.log('[start-validator] No pre-conditions defined, allowing start')\n return {\n canStart: true,\n errors: [],\n validatedRules: [],\n }\n }\n\n // Evaluate each pre-condition using rule engine\n const errors: ValidationError[] = []\n const validatedRules: ValidatedRule[] = []\n\n for (const condition of preConditions) {\n const ruleContext: ruleEngine.RuleEngineContext = {\n entityType: `workflow:${workflowId}:start`,\n entityId: 'pre_start_validation',\n eventType: 'validate_start',\n data: {\n workflowId,\n workflowContext: context,\n },\n tenantId,\n organizationId,\n dryRun: true, // Don't log execution during validation\n }\n\n // Find applicable rules for this context\n const rules = await ruleEngine.findApplicableRules(em, {\n entityType: ruleContext.entityType,\n eventType: ruleContext.eventType,\n tenantId,\n organizationId,\n ruleType: 'GUARD',\n })\n\n const rule = rules.find(r => r.ruleId === condition.ruleId)\n\n if (!rule) {\n // Rule not found - if required, this is an error\n if (condition.required) {\n errors.push({\n ruleId: condition.ruleId,\n message: getLocalizedMessage(condition, null, locale, `Business rule '${condition.ruleId}' not found`),\n code: 'RULE_NOT_FOUND',\n })\n validatedRules.push({ ruleId: condition.ruleId, passed: false })\n }\n continue\n }\n\n // Execute the single rule\n const result = await ruleEngine.executeSingleRule(em, rule, ruleContext)\n\n validatedRules.push({\n ruleId: condition.ruleId,\n passed: result.conditionResult,\n executionTime: result.executionTime,\n })\n\n if (!result.conditionResult && condition.required) {\n // Get localized message from condition, rule failure actions, or default\n const message = getLocalizedMessage(\n condition,\n rule,\n locale,\n `Pre-condition '${rule.ruleName || condition.ruleId}' failed`\n )\n errors.push({\n ruleId: condition.ruleId,\n message,\n code: 'PRE_CONDITION_FAILED',\n })\n }\n }\n\n return {\n canStart: errors.length === 0,\n errors,\n validatedRules,\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get localized message with fallback chain\n *\n * Priority:\n * 1. condition.validationMessage[locale]\n * 2. condition.validationMessage['en']\n * 3. rule.failureActions[BLOCK_TRANSITION].config.message\n * 4. rule.description\n * 5. defaultMessage\n */\nfunction getLocalizedMessage(\n condition: StartPreCondition,\n rule: any | null,\n locale: string,\n defaultMessage: string\n): string {\n // Priority 1: Localized message in condition definition (requested locale)\n if (condition.validationMessage?.[locale]) {\n return condition.validationMessage[locale]\n }\n\n // Priority 2: English fallback in condition\n if (condition.validationMessage?.['en']) {\n return condition.validationMessage['en']\n }\n\n if (rule) {\n // Priority 3: Message from rule's failureActions\n if (rule.failureActions && Array.isArray(rule.failureActions)) {\n const blockAction = rule.failureActions.find(\n (a: any) => a.type === 'BLOCK_TRANSITION'\n )\n if (blockAction?.config?.message) {\n return blockAction.config.message\n }\n }\n\n // Priority 4: Rule description\n if (rule.description) {\n return rule.description\n }\n }\n\n // Priority 5: Default message\n return defaultMessage\n}\n\n/**\n * Find workflow definition by ID and optional version\n */\nasync function findWorkflowDefinition(\n em: EntityManager,\n options: {\n workflowId: string\n version?: number\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowDefinition | null> {\n const { workflowId, version, tenantId, organizationId } = options\n\n const where: any = {\n workflowId,\n tenantId,\n organizationId,\n deletedAt: null,\n }\n\n if (version !== undefined) {\n where.version = version\n }\n\n // If no version specified, get latest enabled version\n if (version === undefined) {\n where.enabled = true\n return em.findOne(WorkflowDefinition, where, {\n orderBy: { version: 'DESC' },\n })\n }\n\n return em.findOne(WorkflowDefinition, where)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -99,43 +99,19 @@ async function findValidTransitions(em, instance, fromStepId, context) {
99
99
  if (!definition) {
100
100
  return [];
101
101
  }
102
- const transitions = (definition.definition.transitions || []).filter((t) => t.fromStepId === fromStepId).sort((a, b) => (b.priority || 0) - (a.priority || 0));
102
+ const transitions = (definition.definition.transitions || []).filter(
103
+ (t) => t.fromStepId === fromStepId
104
+ );
103
105
  const results = [];
104
106
  for (const transition of transitions) {
105
- const conditionResult = await evaluateTransition(
107
+ const result = await evaluateTransition(
106
108
  em,
107
109
  instance,
108
110
  fromStepId,
109
111
  transition.toStepId,
110
112
  context
111
113
  );
112
- if (!conditionResult.isValid) {
113
- results.push(conditionResult);
114
- continue;
115
- }
116
- const preConditions = transition.preConditions || [];
117
- if (preConditions.length > 0) {
118
- const preConditionsResult = await evaluatePreConditions(
119
- em,
120
- instance,
121
- transition,
122
- context
123
- );
124
- if (!preConditionsResult.allowed) {
125
- const failedRules = preConditionsResult.executedRules.filter((r) => !r.conditionResult).map((r) => r.rule.ruleId || r.rule.ruleName);
126
- results.push({
127
- isValid: false,
128
- transition,
129
- reason: `Pre-conditions failed: ${failedRules.join(", ")}`,
130
- failedConditions: failedRules
131
- });
132
- continue;
133
- }
134
- }
135
- results.push({
136
- ...conditionResult,
137
- transition
138
- });
114
+ results.push(result);
139
115
  }
140
116
  return results;
141
117
  } catch (error) {
@@ -439,74 +415,28 @@ async function evaluatePreConditions(em, instance, transition, context) {
439
415
  totalExecutionTime: 0
440
416
  };
441
417
  }
442
- const preConditions = transition.preConditions || [];
443
- if (preConditions.length === 0) {
444
- return {
445
- allowed: true,
446
- executedRules: [],
447
- totalExecutionTime: 0
448
- };
449
- }
450
- const startTime = Date.now();
451
- const executedRules = [];
452
- const errors = [];
453
- let allowed = true;
454
- for (const condition of preConditions) {
455
- const result = await ruleEngine.executeRuleByRuleId(em, {
456
- ruleId: condition.ruleId,
457
- // String identifier
458
- data: {
459
- workflowInstanceId: instance.id,
460
- workflowId: definition.workflowId,
461
- fromStepId: transition.fromStepId,
462
- toStepId: transition.toStepId,
463
- workflowContext: {
464
- ...instance.context,
465
- ...context.workflowContext
466
- },
467
- triggerData: context.triggerData
468
- },
469
- user: context.userId ? { id: context.userId } : void 0,
470
- tenantId: instance.tenantId,
471
- organizationId: instance.organizationId,
472
- executedBy: context.userId,
473
- entityType: `workflow:${definition.workflowId}:transition`,
474
- entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
475
- eventType: "pre_transition"
476
- });
477
- const ruleResult = {
478
- rule: {
479
- ruleId: result.ruleId,
480
- ruleName: result.ruleName,
481
- ruleType: "GUARD"
418
+ const ruleContext = {
419
+ entityType: `workflow:${definition.workflowId}:transition`,
420
+ entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
421
+ eventType: "pre_transition",
422
+ data: {
423
+ workflowInstanceId: instance.id,
424
+ workflowId: definition.workflowId,
425
+ fromStepId: transition.fromStepId,
426
+ toStepId: transition.toStepId,
427
+ workflowContext: {
428
+ ...instance.context,
429
+ ...context.workflowContext
482
430
  },
483
- conditionResult: result.conditionResult,
484
- actionsExecuted: result.actionsExecuted,
485
- executionTime: result.executionTime,
486
- error: result.error,
487
- logId: result.logId
488
- };
489
- executedRules.push(ruleResult);
490
- if (result.error) {
491
- const isRequired2 = condition.required !== false;
492
- if (isRequired2) {
493
- allowed = false;
494
- errors.push(`Rule '${result.ruleId}': ${result.error}`);
495
- }
496
- continue;
497
- }
498
- const isRequired = condition.required !== false;
499
- if (isRequired && !result.conditionResult) {
500
- allowed = false;
501
- errors.push(`Pre-condition '${result.ruleName || result.ruleId}' failed`);
502
- }
503
- }
504
- return {
505
- allowed,
506
- executedRules,
507
- totalExecutionTime: Date.now() - startTime,
508
- errors: errors.length > 0 ? errors : void 0
431
+ triggerData: context.triggerData
432
+ },
433
+ user: context.userId ? { id: context.userId } : void 0,
434
+ tenantId: instance.tenantId,
435
+ organizationId: instance.organizationId,
436
+ executedBy: context.userId
509
437
  };
438
+ const result = await ruleEngine.executeRules(em, ruleContext);
439
+ return result;
510
440
  } catch (error) {
511
441
  console.error("Error evaluating pre-conditions:", error);
512
442
  return {
@@ -529,70 +459,28 @@ async function evaluatePostConditions(em, instance, transition, context) {
529
459
  totalExecutionTime: 0
530
460
  };
531
461
  }
532
- const postConditions = transition.postConditions || [];
533
- if (postConditions.length === 0) {
534
- return {
535
- allowed: true,
536
- executedRules: [],
537
- totalExecutionTime: 0
538
- };
539
- }
540
- const startTime = Date.now();
541
- const executedRules = [];
542
- const errors = [];
543
- let allowed = true;
544
- for (const condition of postConditions) {
545
- const result = await ruleEngine.executeRuleByRuleId(em, {
546
- ruleId: condition.ruleId,
547
- // String identifier
548
- data: {
549
- workflowInstanceId: instance.id,
550
- workflowId: definition.workflowId,
551
- fromStepId: transition.fromStepId,
552
- toStepId: transition.toStepId,
553
- workflowContext: {
554
- ...instance.context,
555
- ...context.workflowContext
556
- },
557
- triggerData: context.triggerData
558
- },
559
- user: context.userId ? { id: context.userId } : void 0,
560
- tenantId: instance.tenantId,
561
- organizationId: instance.organizationId,
562
- executedBy: context.userId,
563
- entityType: `workflow:${definition.workflowId}:transition`,
564
- entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
565
- eventType: "post_transition"
566
- });
567
- const ruleResult = {
568
- rule: {
569
- ruleId: result.ruleId,
570
- ruleName: result.ruleName,
571
- ruleType: "GUARD"
462
+ const ruleContext = {
463
+ entityType: `workflow:${definition.workflowId}:transition`,
464
+ entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,
465
+ eventType: "post_transition",
466
+ data: {
467
+ workflowInstanceId: instance.id,
468
+ workflowId: definition.workflowId,
469
+ fromStepId: transition.fromStepId,
470
+ toStepId: transition.toStepId,
471
+ workflowContext: {
472
+ ...instance.context,
473
+ ...context.workflowContext
572
474
  },
573
- conditionResult: result.conditionResult,
574
- actionsExecuted: result.actionsExecuted,
575
- executionTime: result.executionTime,
576
- error: result.error,
577
- logId: result.logId
578
- };
579
- executedRules.push(ruleResult);
580
- if (result.error) {
581
- errors.push(`Rule '${result.ruleId}': ${result.error}`);
582
- allowed = false;
583
- continue;
584
- }
585
- if (!result.conditionResult) {
586
- allowed = false;
587
- errors.push(`Post-condition '${result.ruleName || result.ruleId}' failed`);
588
- }
589
- }
590
- return {
591
- allowed,
592
- executedRules,
593
- totalExecutionTime: Date.now() - startTime,
594
- errors: errors.length > 0 ? errors : void 0
475
+ triggerData: context.triggerData
476
+ },
477
+ user: context.userId ? { id: context.userId } : void 0,
478
+ tenantId: instance.tenantId,
479
+ organizationId: instance.organizationId,
480
+ executedBy: context.userId
595
481
  };
482
+ const result = await ruleEngine.executeRules(em, ruleContext);
483
+ return result;
596
484
  } catch (error) {
597
485
  console.error("Error evaluating post-conditions:", error);
598
486
  return {