@open-mercato/core 0.5.1-develop.2691.d8a0934b37 → 0.5.1-develop.2694.732417c5ec
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/api_keys/data/entities.js +1 -1
- package/dist/modules/api_keys/data/entities.js.map +1 -1
- package/dist/modules/api_keys/services/apiKeyService.js +5 -5
- package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +1 -1
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/library/route.js +7 -9
- package/dist/modules/attachments/api/library/route.js.map +2 -2
- package/dist/modules/attachments/api/partitions/route.js +3 -3
- package/dist/modules/attachments/api/partitions/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +6 -5
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/api/transfer/route.js +1 -1
- package/dist/modules/attachments/api/transfer/route.js.map +2 -2
- package/dist/modules/attachments/data/entities.js +2 -1
- package/dist/modules/attachments/data/entities.js.map +2 -2
- package/dist/modules/attachments/lib/ocrQueue.js +1 -1
- package/dist/modules/attachments/lib/ocrQueue.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
- package/dist/modules/audit_logs/data/entities.js +1 -1
- package/dist/modules/audit_logs/data/entities.js.map +1 -1
- package/dist/modules/audit_logs/services/actionLogService.js +77 -70
- package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +1 -1
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +2 -2
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/resend-invite/route.js +1 -1
- package/dist/modules/auth/api/users/resend-invite/route.js.map +2 -2
- package/dist/modules/auth/cli.js +12 -6
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +1 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/entities.js +1 -1
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +3 -3
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/services/authService.js +2 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +3 -3
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/[id]/members/route.js +7 -4
- package/dist/modules/business_rules/api/sets/[id]/members/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +3 -3
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/cli.js +1 -1
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/data/entities.js +2 -9
- package/dist/modules/business_rules/data/entities.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +1 -1
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/api/option-schemas/route.js +0 -1
- package/dist/modules/catalog/api/option-schemas/route.js.map +2 -2
- package/dist/modules/catalog/data/entities.js +2 -11
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/configs/data/entities.js +2 -1
- package/dist/modules/configs/data/entities.js.map +2 -2
- package/dist/modules/currencies/commands/fetch-configs.js +3 -3
- package/dist/modules/currencies/commands/fetch-configs.js.map +2 -2
- package/dist/modules/currencies/data/entities.js +1 -1
- package/dist/modules/currencies/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +1 -1
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/customer_accounts/data/entities.js +1 -1
- package/dist/modules/customer_accounts/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js +1 -1
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerSessionService.js +1 -1
- package/dist/modules/customer_accounts/services/customerSessionService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerTokenService.js +12 -7
- package/dist/modules/customer_accounts/services/customerTokenService.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +19 -17
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +7 -6
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +28 -42
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/utils.js +29 -24
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/cli.js +45 -40
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/dictionaries.js +1 -1
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/tags.js +1 -1
- package/dist/modules/customers/commands/tags.js.map +2 -2
- package/dist/modules/customers/data/entities.js +2 -12
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/lib/interactionProjection.js +18 -15
- package/dist/modules/customers/lib/interactionProjection.js.map +2 -2
- package/dist/modules/customers/lib/personCompanyLinkTable.js +6 -8
- package/dist/modules/customers/lib/personCompanyLinkTable.js.map +2 -2
- package/dist/modules/dashboards/api/roles/widgets/route.js +1 -1
- package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +1 -1
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/data/entities.js +1 -1
- package/dist/modules/dashboards/data/entities.js.map +1 -1
- package/dist/modules/data_sync/api/mappings/route.js +1 -1
- package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
- package/dist/modules/data_sync/data/entities.js +2 -1
- package/dist/modules/data_sync/data/entities.js.map +2 -2
- package/dist/modules/data_sync/lib/id-mapping.js +1 -1
- package/dist/modules/data_sync/lib/id-mapping.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +1 -1
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +1 -1
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/data/entities.js +2 -9
- package/dist/modules/dictionaries/data/entities.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +4 -4
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/directory/data/entities.js +2 -1
- package/dist/modules/directory/data/entities.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +2 -2
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/encryption.js +2 -2
- package/dist/modules/entities/api/encryption.js.map +2 -2
- package/dist/modules/entities/api/relations/options.js +2 -2
- package/dist/modules/entities/api/relations/options.js.map +2 -2
- package/dist/modules/entities/cli.js +4 -4
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/data/entities.js +1 -1
- package/dist/modules/entities/data/entities.js.map +2 -2
- package/dist/modules/entities/lib/field-definitions.js +2 -2
- package/dist/modules/entities/lib/field-definitions.js.map +2 -2
- package/dist/modules/entities/lib/register.js +1 -1
- package/dist/modules/entities/lib/register.js.map +2 -2
- package/dist/modules/feature_toggles/data/entities.js +2 -9
- package/dist/modules/feature_toggles/data/entities.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js +3 -6
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/data/entities.js +2 -8
- package/dist/modules/inbox_ops/data/entities.js.map +2 -2
- package/dist/modules/inbox_ops/lib/messagesIntegration.js +6 -6
- package/dist/modules/inbox_ops/lib/messagesIntegration.js.map +2 -2
- package/dist/modules/integrations/data/entities.js +2 -1
- package/dist/modules/integrations/data/entities.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-service.js +1 -1
- package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
- package/dist/modules/integrations/lib/log-service.js +1 -1
- package/dist/modules/integrations/lib/log-service.js.map +2 -2
- package/dist/modules/integrations/lib/state-service.js +1 -1
- package/dist/modules/integrations/lib/state-service.js.map +2 -2
- package/dist/modules/messages/api/route.js +90 -93
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/api/unread-count/route.js +8 -7
- package/dist/modules/messages/api/unread-count/route.js.map +2 -2
- package/dist/modules/messages/commands/confirmations.js +1 -1
- package/dist/modules/messages/commands/confirmations.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +3 -3
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/data/entities.js +2 -1
- package/dist/modules/messages/data/entities.js.map +2 -2
- package/dist/modules/messages/lib/email-sender.js +1 -1
- package/dist/modules/messages/lib/email-sender.js.map +2 -2
- package/dist/modules/messages/lib/searchLookup.js +8 -8
- package/dist/modules/messages/lib/searchLookup.js.map +2 -2
- package/dist/modules/messages/lib/tokenConsumption.js +9 -4
- package/dist/modules/messages/lib/tokenConsumption.js.map +2 -2
- package/dist/modules/notifications/data/entities.js +2 -1
- package/dist/modules/notifications/data/entities.js.map +2 -2
- package/dist/modules/notifications/lib/notificationRecipients.js +15 -5
- package/dist/modules/notifications/lib/notificationRecipients.js.map +2 -2
- package/dist/modules/notifications/lib/notificationService.js +39 -34
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/notifications/workers/create-notification.worker.js +14 -13
- package/dist/modules/notifications/workers/create-notification.worker.js.map +2 -2
- package/dist/modules/payment_gateways/api/transactions/route.js +2 -2
- package/dist/modules/payment_gateways/api/transactions/route.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +2 -1
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +1 -1
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-utils.js +2 -2
- package/dist/modules/payment_gateways/lib/webhook-utils.js.map +2 -2
- package/dist/modules/perspectives/data/entities.js +1 -1
- package/dist/modules/perspectives/data/entities.js.map +2 -2
- package/dist/modules/planner/data/entities.js +1 -1
- package/dist/modules/planner/data/entities.js.map +2 -2
- package/dist/modules/progress/data/entities.js +2 -1
- package/dist/modules/progress/data/entities.js.map +2 -2
- package/dist/modules/progress/lib/progressServiceImpl.js +1 -1
- package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
- package/dist/modules/query_index/api/status.js +66 -57
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/query_index/cli.js +39 -24
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/data/entities.js +1 -1
- package/dist/modules/query_index/data/entities.js.map +2 -2
- package/dist/modules/query_index/di.js +25 -13
- package/dist/modules/query_index/di.js.map +2 -2
- package/dist/modules/query_index/lib/batch.js +31 -33
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +63 -50
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +592 -588
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +74 -47
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/jobs.js +37 -24
- package/dist/modules/query_index/lib/jobs.js.map +2 -2
- package/dist/modules/query_index/lib/purge.js +19 -11
- package/dist/modules/query_index/lib/purge.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +47 -44
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +47 -25
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/lib/stale.js +14 -12
- package/dist/modules/query_index/lib/stale.js.map +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js.map +2 -2
- package/dist/modules/query_index/subscribers/delete_one.js +3 -2
- package/dist/modules/query_index/subscribers/delete_one.js.map +2 -2
- package/dist/modules/resources/commands/tag-assignments.js +1 -1
- package/dist/modules/resources/commands/tag-assignments.js.map +2 -2
- package/dist/modules/resources/commands/tags.js +1 -1
- package/dist/modules/resources/commands/tags.js.map +2 -2
- package/dist/modules/resources/data/entities.js +2 -1
- package/dist/modules/resources/data/entities.js.map +2 -2
- package/dist/modules/sales/commands/documentAddresses.js +2 -2
- package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
- package/dist/modules/sales/commands/notes.js.map +2 -2
- package/dist/modules/sales/commands/tags.js +1 -1
- package/dist/modules/sales/commands/tags.js.map +2 -2
- package/dist/modules/sales/data/enrichers.js +9 -8
- package/dist/modules/sales/data/enrichers.js.map +2 -2
- package/dist/modules/sales/data/entities.js +2 -11
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/shipping_carriers/data/entities.js +2 -1
- package/dist/modules/shipping_carriers/data/entities.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipping-service.js +1 -1
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/webhook-utils.js +2 -2
- package/dist/modules/shipping_carriers/lib/webhook-utils.js.map +2 -2
- package/dist/modules/staff/data/entities.js +1 -1
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +3 -5
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/api/context.js +2 -2
- package/dist/modules/translations/api/context.js.map +2 -2
- package/dist/modules/translations/commands/translations.js +46 -39
- package/dist/modules/translations/commands/translations.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +19 -10
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/data/entities.js +1 -1
- package/dist/modules/translations/data/entities.js.map +2 -2
- package/dist/modules/translations/lib/apply.js +4 -4
- package/dist/modules/translations/lib/apply.js.map +2 -2
- package/dist/modules/translations/lib/batch.js +3 -2
- package/dist/modules/translations/lib/batch.js.map +2 -2
- package/dist/modules/translations/subscribers/cleanup.js +3 -5
- package/dist/modules/translations/subscribers/cleanup.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +1 -1
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/cli.js +5 -5
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +2 -1
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/lib/event-logger.js +2 -2
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +16 -1
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +3 -3
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +1 -1
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +1 -1
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/jest.config.cjs +4 -2
- package/package.json +3 -3
- package/src/modules/api_keys/data/entities.ts +1 -1
- package/src/modules/api_keys/services/apiKeyService.ts +5 -5
- package/src/modules/attachments/api/library/[id]/route.ts +1 -1
- package/src/modules/attachments/api/library/route.ts +10 -12
- package/src/modules/attachments/api/partitions/route.ts +3 -3
- package/src/modules/attachments/api/route.ts +10 -8
- package/src/modules/attachments/api/transfer/route.ts +1 -1
- package/src/modules/attachments/data/entities.ts +2 -1
- package/src/modules/attachments/lib/ocrQueue.ts +1 -1
- package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +4 -4
- package/src/modules/audit_logs/api/audit-logs/actions/route.ts +4 -4
- package/src/modules/audit_logs/data/entities.ts +1 -1
- package/src/modules/audit_logs/services/actionLogService.ts +96 -87
- package/src/modules/auth/api/roles/acl/route.ts +1 -1
- package/src/modules/auth/api/users/acl/route.ts +2 -2
- package/src/modules/auth/api/users/resend-invite/route.ts +1 -1
- package/src/modules/auth/cli.ts +46 -40
- package/src/modules/auth/commands/users.ts +1 -1
- package/src/modules/auth/data/entities.ts +1 -1
- package/src/modules/auth/lib/setup-app.ts +3 -3
- package/src/modules/auth/services/authService.ts +2 -2
- package/src/modules/business_rules/api/rules/route.ts +3 -3
- package/src/modules/business_rules/api/sets/[id]/members/route.ts +7 -4
- package/src/modules/business_rules/api/sets/route.ts +3 -3
- package/src/modules/business_rules/cli.ts +1 -1
- package/src/modules/business_rules/data/entities.ts +2 -9
- package/src/modules/business_rules/lib/rule-engine.ts +1 -1
- package/src/modules/catalog/api/option-schemas/route.ts +0 -1
- package/src/modules/catalog/data/entities.ts +2 -11
- package/src/modules/configs/data/entities.ts +2 -1
- package/src/modules/currencies/commands/fetch-configs.ts +3 -3
- package/src/modules/currencies/data/entities.ts +1 -1
- package/src/modules/customer_accounts/api/signup.ts +1 -1
- package/src/modules/customer_accounts/data/entities.ts +1 -1
- package/src/modules/customer_accounts/services/customerInvitationService.ts +1 -1
- package/src/modules/customer_accounts/services/customerSessionService.ts +1 -1
- package/src/modules/customer_accounts/services/customerTokenService.ts +26 -15
- package/src/modules/customers/api/interactions/conflicts/route.ts +26 -23
- package/src/modules/customers/api/interactions/counts/route.ts +13 -11
- package/src/modules/customers/api/interactions/route.ts +32 -44
- package/src/modules/customers/api/utils.ts +45 -37
- package/src/modules/customers/cli.ts +88 -67
- package/src/modules/customers/commands/dictionaries.ts +1 -1
- package/src/modules/customers/commands/tags.ts +1 -1
- package/src/modules/customers/data/entities.ts +2 -12
- package/src/modules/customers/lib/interactionProjection.ts +36 -25
- package/src/modules/customers/lib/personCompanyLinkTable.ts +13 -18
- package/src/modules/dashboards/api/roles/widgets/route.ts +1 -1
- package/src/modules/dashboards/api/users/widgets/route.ts +1 -1
- package/src/modules/dashboards/data/entities.ts +1 -1
- package/src/modules/data_sync/api/mappings/route.ts +1 -1
- package/src/modules/data_sync/data/entities.ts +2 -1
- package/src/modules/data_sync/lib/id-mapping.ts +1 -1
- package/src/modules/data_sync/lib/sync-run-service.ts +1 -1
- package/src/modules/dictionaries/commands/factory.ts +1 -1
- package/src/modules/dictionaries/data/entities.ts +2 -9
- package/src/modules/directory/commands/organizations.ts +4 -4
- package/src/modules/directory/data/entities.ts +2 -1
- package/src/modules/entities/api/definitions.ts +2 -2
- package/src/modules/entities/api/encryption.ts +2 -2
- package/src/modules/entities/api/relations/options.ts +8 -3
- package/src/modules/entities/cli.ts +4 -4
- package/src/modules/entities/data/entities.ts +1 -1
- package/src/modules/entities/lib/field-definitions.ts +2 -2
- package/src/modules/entities/lib/register.ts +1 -1
- package/src/modules/feature_toggles/data/entities.ts +2 -9
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +10 -10
- package/src/modules/inbox_ops/data/entities.ts +2 -8
- package/src/modules/inbox_ops/lib/messagesIntegration.ts +12 -11
- package/src/modules/integrations/data/entities.ts +2 -1
- package/src/modules/integrations/lib/credentials-service.ts +1 -1
- package/src/modules/integrations/lib/log-service.ts +1 -1
- package/src/modules/integrations/lib/state-service.ts +1 -1
- package/src/modules/messages/api/route.ts +134 -123
- package/src/modules/messages/api/unread-count/route.ts +19 -16
- package/src/modules/messages/commands/confirmations.ts +1 -1
- package/src/modules/messages/commands/messages.ts +3 -3
- package/src/modules/messages/data/entities.ts +2 -1
- package/src/modules/messages/lib/email-sender.ts +1 -1
- package/src/modules/messages/lib/searchLookup.ts +16 -13
- package/src/modules/messages/lib/tokenConsumption.ts +16 -8
- package/src/modules/notifications/data/entities.ts +2 -1
- package/src/modules/notifications/lib/notificationRecipients.ts +42 -26
- package/src/modules/notifications/lib/notificationService.ts +53 -42
- package/src/modules/notifications/workers/create-notification.worker.ts +20 -17
- package/src/modules/payment_gateways/api/transactions/route.ts +2 -2
- package/src/modules/payment_gateways/data/entities.ts +2 -1
- package/src/modules/payment_gateways/lib/gateway-service.ts +1 -1
- package/src/modules/payment_gateways/lib/webhook-utils.ts +2 -2
- package/src/modules/perspectives/data/entities.ts +1 -1
- package/src/modules/planner/data/entities.ts +1 -1
- package/src/modules/progress/data/entities.ts +2 -1
- package/src/modules/progress/lib/progressServiceImpl.ts +1 -1
- package/src/modules/query_index/api/status.ts +85 -71
- package/src/modules/query_index/cli.ts +51 -31
- package/src/modules/query_index/data/entities.ts +1 -1
- package/src/modules/query_index/di.ts +41 -16
- package/src/modules/query_index/lib/batch.ts +68 -55
- package/src/modules/query_index/lib/coverage.ts +115 -88
- package/src/modules/query_index/lib/engine.ts +1036 -1096
- package/src/modules/query_index/lib/indexer.ts +115 -79
- package/src/modules/query_index/lib/jobs.ts +51 -31
- package/src/modules/query_index/lib/purge.ts +25 -19
- package/src/modules/query_index/lib/reindexer.ts +97 -84
- package/src/modules/query_index/lib/search-tokens.ts +67 -36
- package/src/modules/query_index/lib/stale.ts +14 -17
- package/src/modules/query_index/lib/subscriber-scope.ts +6 -5
- package/src/modules/query_index/subscribers/delete_one.ts +9 -6
- package/src/modules/resources/commands/tag-assignments.ts +1 -1
- package/src/modules/resources/commands/tags.ts +1 -1
- package/src/modules/resources/data/entities.ts +2 -1
- package/src/modules/sales/commands/documentAddresses.ts +2 -2
- package/src/modules/sales/commands/notes.ts +1 -1
- package/src/modules/sales/commands/tags.ts +1 -1
- package/src/modules/sales/data/enrichers.ts +17 -13
- package/src/modules/sales/data/entities.ts +2 -11
- package/src/modules/shipping_carriers/data/entities.ts +2 -1
- package/src/modules/shipping_carriers/lib/shipping-service.ts +1 -1
- package/src/modules/shipping_carriers/lib/webhook-utils.ts +2 -2
- package/src/modules/staff/data/entities.ts +1 -1
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +14 -11
- package/src/modules/translations/api/context.ts +4 -4
- package/src/modules/translations/commands/translations.ts +116 -81
- package/src/modules/translations/components/TranslationManager.tsx +23 -14
- package/src/modules/translations/data/entities.ts +1 -1
- package/src/modules/translations/i18n/de.json +1 -0
- package/src/modules/translations/i18n/en.json +1 -0
- package/src/modules/translations/i18n/es.json +1 -0
- package/src/modules/translations/i18n/pl.json +1 -0
- package/src/modules/translations/lib/apply.ts +6 -6
- package/src/modules/translations/lib/batch.ts +9 -7
- package/src/modules/translations/subscribers/cleanup.ts +10 -11
- package/src/modules/workflows/api/definitions/route.ts +1 -1
- package/src/modules/workflows/cli.ts +5 -5
- package/src/modules/workflows/data/entities.ts +2 -1
- package/src/modules/workflows/lib/event-logger.ts +2 -2
- package/src/modules/workflows/lib/seeds.ts +16 -1
- package/src/modules/workflows/lib/step-handler.ts +3 -3
- package/src/modules/workflows/lib/task-handler.ts +1 -1
- package/src/modules/workflows/lib/transition-handler.ts +1 -1
- package/src/modules/workflows/lib/workflow-executor.ts +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/workflows/lib/transition-handler.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Workflows Module - Transition Handler Service\n *\n * Handles workflow transitions between steps:\n * - Evaluating if a transition is valid (checking conditions)\n * - Executing transitions (moving from one step to another)\n * - Integrating with business rules engine for pre/post conditions\n * - Executing activities on transition\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport type { EventBus } from '@open-mercato/events'\nimport {\n WorkflowInstance,\n WorkflowDefinition,\n WorkflowEvent,\n} from '../data/entities'\nimport * as ruleEvaluator from '../../business_rules/lib/rule-evaluator'\nimport * as ruleEngine from '../../business_rules/lib/rule-engine'\nimport * as activityExecutor from './activity-executor'\nimport type { ActivityDefinition } from './activity-executor'\nimport * as stepHandler from './step-handler'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface TransitionEvaluationContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionEvaluationResult {\n isValid: boolean\n transition?: any\n reason?: string\n failedConditions?: string[]\n evaluationTime?: number\n}\n\nexport interface TransitionExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionExecutionResult {\n success: boolean\n nextStepId?: string\n pausedForActivities?: boolean\n conditionsEvaluated?: {\n preConditions: boolean\n postConditions: boolean\n }\n activitiesExecuted?: activityExecutor.ActivityExecutionResult[]\n error?: string\n}\n\nexport class TransitionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'TransitionError'\n }\n}\n\n// ============================================================================\n// Main Transition Functions\n// ============================================================================\n\n/**\n * Evaluate if a transition from current step to target step is valid\n *\n * Checks:\n * - Transition exists in workflow definition\n * - Pre-conditions pass (if any business rules defined)\n * - Transition condition evaluates to true (if specified)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID (optional - will auto-select if not provided)\n * @param context - Evaluation context\n * @returns Evaluation result with validity and reason\n */\nexport async function evaluateTransition(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string | undefined,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n const startTime = Date.now()\n\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n isValid: false,\n reason: `Workflow definition not found: ${instance.definitionId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Find transition\n const transitions = definition.definition.transitions || []\n let transition: any\n\n if (toStepId) {\n // Find specific transition\n transition = transitions.find(\n (t: any) => t.fromStepId === fromStepId && t.toStepId === toStepId\n )\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No transition found from ${fromStepId} to ${toStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n } else {\n // Auto-select first valid transition\n const availableTransitions = transitions.filter(\n (t: any) => t.fromStepId === fromStepId\n )\n\n if (availableTransitions.length === 0) {\n return {\n isValid: false,\n reason: `No transitions available from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Evaluate each transition to find first valid one\n for (const t of availableTransitions) {\n const result = await evaluateTransitionConditions(\n em,\n instance,\n t,\n context\n )\n\n if (result.isValid) {\n transition = t\n break\n }\n }\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No valid transitions found from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n }\n\n // Evaluate transition conditions (inline condition + business rules pre-conditions)\n const conditionResult = await evaluateTransitionConditions(\n em,\n instance,\n transition,\n context\n )\n\n return {\n ...conditionResult,\n transition,\n evaluationTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Transition evaluation error: ${errorMessage}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n}\n\n/**\n * Find all valid transitions from current step\n *\n * This function evaluates both inline conditions AND preConditions (business rules)\n * to determine which transitions are truly valid. This is important for decision\n * branching where multiple transitions exist with different preConditions.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param context - Evaluation context\n * @returns Array of evaluation results for all transitions, sorted by priority (desc)\n */\nexport async function findValidTransitions(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult[]> {\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return []\n }\n\n // Find all transitions from current step, sorted by priority (highest first)\n const transitions = (definition.definition.transitions || [])\n .filter((t: any) => t.fromStepId === fromStepId)\n .sort((a: any, b: any) => (b.priority || 0) - (a.priority || 0))\n\n // Evaluate each transition including preConditions\n const results: TransitionEvaluationResult[] = []\n\n for (const transition of transitions) {\n // First check inline condition\n const conditionResult = await evaluateTransition(\n em,\n instance,\n fromStepId,\n transition.toStepId,\n context\n )\n\n if (!conditionResult.isValid) {\n results.push(conditionResult)\n continue\n }\n\n // Also evaluate preConditions if they exist\n const preConditions = transition.preConditions || []\n if (preConditions.length > 0) {\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context as TransitionExecutionContext,\n null\n )\n\n if (!preConditionsResult.allowed) {\n // Transition is invalid due to preConditions\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => r.rule.ruleId || r.rule.ruleName)\n\n results.push({\n isValid: false,\n transition,\n reason: `Pre-conditions failed: ${failedRules.join(', ')}`,\n failedConditions: failedRules,\n })\n continue\n }\n }\n\n // Transition is valid (both condition and preConditions passed)\n results.push({\n ...conditionResult,\n transition,\n })\n }\n\n return results\n } catch (error) {\n console.error('Error finding valid transitions:', error)\n return []\n }\n}\n\n/**\n * Execute a transition from one step to another\n *\n * This is the main entry point for transition execution. It:\n * 1. Validates the transition\n * 2. Evaluates pre-conditions\n * 3. Executes activities (if any)\n * 4. Updates workflow instance state (atomically with activity outputs)\n * 5. Evaluates post-conditions\n * 6. Logs transition event\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution)\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID\n * @param context - Execution context\n * @returns Execution result\n */\nexport async function executeTransition(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string,\n context: TransitionExecutionContext\n): Promise<TransitionExecutionResult> {\n try {\n let eventBus: Pick<EventBus, 'emitEvent'> | null = null\n try {\n eventBus = container.resolve('eventBus') as EventBus\n } catch {\n eventBus = null\n }\n\n // First, evaluate if transition is valid\n const evaluation = await evaluateTransition(\n em,\n instance,\n fromStepId,\n toStepId,\n context\n )\n\n if (!evaluation.isValid) {\n return {\n success: false,\n error: evaluation.reason || 'Transition validation failed',\n }\n }\n\n const transition = evaluation.transition!\n\n // Evaluate pre-conditions (business rules)\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!preConditionsResult.allowed) {\n // Build detailed failure information\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => ({\n ruleId: r.rule.ruleId,\n ruleName: r.rule.ruleName,\n error: r.error,\n }))\n\n const failedRulesDetails = failedRules.length > 0\n ? failedRules.map(r => `${r.ruleId}: ${r.error || 'condition failed'}`).join('; ')\n : preConditionsResult.errors?.join(', ') || 'Unknown pre-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_REJECTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Pre-conditions failed',\n failedRules: failedRulesDetails,\n failedRulesDetail: failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Pre-conditions failed: ${failedRulesDetails}`,\n conditionsEvaluated: {\n preConditions: false,\n postConditions: false,\n },\n }\n }\n\n // Execute activities (if any)\n let activityOutputs: Record<string, any> = {}\n const activityResults: activityExecutor.ActivityExecutionResult[] = []\n\n if (transition.activities && transition.activities.length > 0) {\n const activityContext: activityExecutor.ActivityContext = {\n workflowInstance: instance,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n userId: context.userId,\n }\n\n // Execute all activities\n const results = await activityExecutor.executeActivities(\n em,\n container,\n transition.activities as ActivityDefinition[],\n activityContext\n )\n\n activityResults.push(...results)\n\n // Check for failures\n const failedActivities = results.filter(r => !r.success)\n\n if (failedActivities.length > 0) {\n const continueOnFailure = transition.continueOnActivityFailure ?? false\n\n // Log activity failures\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ACTIVITY_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n failedActivities: failedActivities.map(f => ({\n activityType: f.activityType,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n continueOnFailure,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (!continueOnFailure) {\n return {\n success: false,\n error: `Activities failed: ${failedActivities.map(f => f.error).join(', ')}`,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false,\n },\n }\n }\n }\n\n // Collect activity outputs for context update\n results.forEach(result => {\n if (result.success && result.output) {\n const key = result.activityName || result.activityType\n activityOutputs[key] = result.output\n }\n })\n }\n\n // Check if any activities are async - if so, pause before executing step\n const hasAsyncActivities = activityResults.some(r => r.async)\n\n if (hasAsyncActivities) {\n const pendingJobIds = activityResults\n .filter(a => a.async && a.jobId)\n .map(a => ({ activityId: a.activityId, jobId: a.jobId }))\n\n // Store pending transition state\n instance.pendingTransition = {\n toStepId,\n activityResults,\n timestamp: new Date(),\n }\n\n // Store pending activities in context for tracking\n instance.context = {\n ...instance.context,\n ...context.workflowContext,\n ...activityOutputs,\n _pendingAsyncActivities: pendingJobIds,\n }\n\n // Set status to waiting\n instance.status = 'WAITING_FOR_ACTIVITIES'\n instance.updatedAt = new Date()\n await em.flush()\n\n // Log event\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_PAUSED_FOR_ACTIVITIES',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId,\n pendingActivities: pendingJobIds,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Return WITHOUT executing step\n return {\n success: true,\n pausedForActivities: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false, // Not evaluated yet\n },\n activitiesExecuted: activityResults,\n }\n }\n\n // Update workflow instance - set current step and update context atomically\n instance.currentStepId = toStepId\n instance.context = {\n ...instance.context,\n ...context.workflowContext,\n ...activityOutputs, // Include activity outputs\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n\n // Execute the new step (this will create USER_TASK, handle END steps, etc.)\n const stepExecutionResult = await stepHandler.executeStep(\n em,\n instance,\n toStepId,\n {\n workflowContext: instance.context || {},\n userId: context.userId,\n triggerData: context.triggerData,\n },\n container\n )\n\n // Flush to database after step execution completes to make state visible to UI\n await em.flush()\n\n // Handle step execution failure\n if (stepExecutionResult.status === 'FAILED') {\n return {\n success: false,\n error: stepExecutionResult.error || 'Step execution failed',\n }\n }\n\n // Evaluate post-conditions (business rules)\n const postConditionsResult = await evaluatePostConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!postConditionsResult.allowed) {\n const failedRules = postConditionsResult.errors?.join(', ') || 'Unknown post-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_POST_CONDITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Post-conditions failed',\n failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Note: We don't roll back the transition on post-condition failure\n // Post-conditions are warnings, not blockers\n }\n\n // Log successful transition\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_EXECUTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n transitionName: transition.transitionName,\n preConditionsPassed: true,\n postConditionsPassed: postConditionsResult.allowed,\n activitiesExecuted: activityResults.length,\n activitiesSucceeded: activityResults.filter(r => r.success).length,\n activitiesFailed: activityResults.filter(r => !r.success).length,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: postConditionsResult.allowed,\n },\n activitiesExecuted: activityResults,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n error: errorMessage,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Transition execution failed: ${errorMessage}`,\n }\n }\n}\n\n// ============================================================================\n// Condition Evaluation\n// ============================================================================\n\n/**\n * Evaluate transition conditions (inline condition expression)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Evaluation context\n * @returns Evaluation result\n */\nasync function evaluateTransitionConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n try {\n // If no condition specified, transition is always valid\n if (!transition.condition) {\n return {\n isValid: true,\n }\n }\n\n // Build data context for rule evaluation\n const data = {\n ...instance.context,\n ...context.workflowContext,\n triggerData: context.triggerData,\n }\n\n // Build evaluation context\n const evalContext: ruleEvaluator.RuleEvaluationContext = {\n entityType: 'workflow:transition',\n entityId: instance.id,\n user: context.userId ? { id: context.userId } : undefined,\n }\n\n // Evaluate condition using expression evaluator\n const result = await ruleEvaluator.evaluateConditions(\n transition.condition,\n data,\n evalContext\n )\n\n return {\n isValid: result,\n reason: result ? undefined : 'Transition condition evaluated to false',\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Condition evaluation error: ${errorMessage}`,\n }\n }\n}\n\n/**\n * Evaluate pre-conditions using business rules engine\n *\n * Pre-conditions are GUARD rules that must pass before transition can execute.\n * If any GUARD rule fails, the transition is blocked.\n *\n * If the transition defines specific preConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, falls back to\n * discovery-based execution via executeRules.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePreConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific preConditions defined\n const preConditions = transition.preConditions || []\n\n // If no pre-conditions defined, allow transition\n if (preConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each pre-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of preConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'pre_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n // We don't have the full BusinessRule entity, but we can create a partial result\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n // Rule not found, disabled, or other errors\n const isRequired = condition.required !== false // Default to required\n if (isRequired) {\n allowed = false\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n }\n continue\n }\n\n // If required and condition failed, block transition\n const isRequired = condition.required !== false // Default to required\n if (isRequired && !result.conditionResult) {\n allowed = false\n errors.push(`Pre-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating pre-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n/**\n * Evaluate post-conditions using business rules engine\n *\n * Post-conditions are GUARD rules that should pass after transition executes.\n * Unlike pre-conditions, post-condition failures are logged but don't block the transition.\n *\n * If the transition defines specific postConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, returns allowed: true.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePostConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific postConditions defined\n const postConditions = transition.postConditions || []\n\n // If no post-conditions defined, allow\n if (postConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each post-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of postConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'post_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n // Post-conditions don't block, but track the failure\n allowed = false\n continue\n }\n\n // Track condition failures (post-conditions are warnings, not blockers)\n if (!result.conditionResult) {\n allowed = false\n errors.push(`Post-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating post-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log transition-related event to event sourcing table\n */\nasync function logTransitionEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n 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.persistAndFlush(workflowEvent)\n return workflowEvent\n}\n"],
|
|
5
|
-
"mappings": "AAeA;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,YAAY,mBAAmB;AAC/B,YAAY,gBAAgB;AAC5B,YAAY,sBAAsB;AAElC,YAAY,iBAAiB;AAsCtB,MAAM,wBAAwB,MAAM;AAAA,EACzC,YACE,SACO,MACA,SACP;AACA,UAAM,OAAO;AAHN;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAqBA,eAAsB,mBACpB,IACA,UACA,YACA,UACA,SACqC;AACrC,QAAM,YAAY,KAAK,IAAI;AAE3B,MAAI;AAEF,UAAM,aAAa,MAAM,GAAG,QAAQ,oBAAoB;AAAA,MACtD,IAAI,SAAS;AAAA,IACf,CAAC;AAED,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ,kCAAkC,SAAS,YAAY;AAAA,QAC/D,gBAAgB,KAAK,IAAI,IAAI;AAAA,MAC/B;AAAA,IACF;AAGA,UAAM,cAAc,WAAW,WAAW,eAAe,CAAC;AAC1D,QAAI;AAEJ,QAAI,UAAU;AAEZ,mBAAa,YAAY;AAAA,QACvB,CAAC,MAAW,EAAE,eAAe,cAAc,EAAE,aAAa;AAAA,MAC5D;AAEA,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ,4BAA4B,UAAU,OAAO,QAAQ;AAAA,UAC7D,gBAAgB,KAAK,IAAI,IAAI;AAAA,QAC/B;AAAA,MACF;AAAA,IACF,OAAO;AAEL,YAAM,uBAAuB,YAAY;AAAA,QACvC,CAAC,MAAW,EAAE,eAAe;AAAA,MAC/B;AAEA,UAAI,qBAAqB,WAAW,GAAG;AACrC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ,sCAAsC,UAAU;AAAA,UACxD,gBAAgB,KAAK,IAAI,IAAI;AAAA,QAC/B;AAAA,MACF;AAGA,iBAAW,KAAK,sBAAsB;AACpC,cAAM,SAAS,MAAM;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAEA,YAAI,OAAO,SAAS;AAClB,uBAAa;AACb;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ,wCAAwC,UAAU;AAAA,UAC1D,gBAAgB,KAAK,IAAI,IAAI;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAGA,UAAM,kBAAkB,MAAM;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,gBAAgB,KAAK,IAAI,IAAI;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,gCAAgC,YAAY;AAAA,MACpD,gBAAgB,KAAK,IAAI,IAAI;AAAA,IAC/B;AAAA,EACF;AACF;AAeA,eAAsB,qBACpB,IACA,UACA,YACA,SACuC;AACvC,MAAI;AAEF,UAAM,aAAa,MAAM,GAAG,QAAQ,oBAAoB;AAAA,MACtD,IAAI,SAAS;AAAA,IACf,CAAC;AAED,QAAI,CAAC,YAAY;AACf,aAAO,CAAC;AAAA,IACV;AAGA,UAAM,eAAe,WAAW,WAAW,eAAe,CAAC,GACxD,OAAO,CAAC,MAAW,EAAE,eAAe,UAAU,EAC9C,KAAK,CAAC,GAAQ,OAAY,EAAE,YAAY,MAAM,EAAE,YAAY,EAAE;AAGjE,UAAM,UAAwC,CAAC;AAE/C,eAAW,cAAc,aAAa;AAEpC,YAAM,kBAAkB,MAAM;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX;AAAA,MACF;AAEA,UAAI,CAAC,gBAAgB,SAAS;AAC5B,gBAAQ,KAAK,eAAe;AAC5B;AAAA,MACF;AAGA,YAAM,gBAAgB,WAAW,iBAAiB,CAAC;AACnD,UAAI,cAAc,SAAS,GAAG;AAC5B,cAAM,sBAAsB,MAAM;AAAA,UAChC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAEA,YAAI,CAAC,oBAAoB,SAAS;AAEhC,gBAAM,cAAc,oBAAoB,cACrC,OAAO,CAAC,MAAM,CAAC,EAAE,eAAe,EAChC,IAAI,CAAC,MAAM,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ;AAE9C,kBAAQ,KAAK;AAAA,YACX,SAAS;AAAA,YACT;AAAA,YACA,QAAQ,0BAA0B,YAAY,KAAK,IAAI,CAAC;AAAA,YACxD,kBAAkB;AAAA,UACpB,CAAC;AACD;AAAA,QACF;AAAA,MACF;AAGA,cAAQ,KAAK;AAAA,QACX,GAAG;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,MAAM,oCAAoC,KAAK;AACvD,WAAO,CAAC;AAAA,EACV;AACF;AAqBA,eAAsB,kBACpB,IACA,WACA,UACA,YACA,UACA,SACoC;AACpC,MAAI;AACF,QAAI,WAA+C;AACnD,QAAI;AACF,iBAAW,UAAU,QAAQ,UAAU;AAAA,IACzC,QAAQ;AACN,iBAAW;AAAA,IACb;AAGA,UAAM,aAAa,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,SAAS;AACvB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,WAAW,UAAU;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,aAAa,WAAW;AAG9B,UAAM,sBAAsB,MAAM;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,oBAAoB,SAAS;AAEhC,YAAM,cAAc,oBAAoB,cACrC,OAAO,CAAC,MAAM,CAAC,EAAE,eAAe,EAChC,IAAI,CAAC,OAAO;AAAA,QACX,QAAQ,EAAE,KAAK;AAAA,QACf,UAAU,EAAE,KAAK;AAAA,QACjB,OAAO,EAAE;AAAA,MACX,EAAE;AAEJ,YAAM,qBAAqB,YAAY,SAAS,IAC5C,YAAY,IAAI,OAAK,GAAG,EAAE,MAAM,KAAK,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,IAAI,IAC/E,oBAAoB,QAAQ,KAAK,IAAI,KAAK;AAE9C,YAAM,mBAAmB,IAAI;AAAA,QAC3B,oBAAoB,SAAS;AAAA,QAC7B,WAAW;AAAA,QACX,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,cAAc,WAAW,gBAAgB,GAAG,UAAU,KAAK,QAAQ;AAAA,UACnE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,mBAAmB;AAAA,QACrB;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,UAAU,SAAS;AAAA,QACnB,gBAAgB,SAAS;AAAA,MAC3B,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,0BAA0B,kBAAkB;AAAA,QACnD,qBAAqB;AAAA,UACnB,eAAe;AAAA,UACf,gBAAgB;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,kBAAuC,CAAC;AAC5C,UAAM,kBAA8D,CAAC;AAErE,QAAI,WAAW,cAAc,WAAW,WAAW,SAAS,GAAG;AAC7D,YAAM,kBAAoD;AAAA,QACxD,kBAAkB;AAAA,QAClB,iBAAiB;AAAA,UACf,GAAG,SAAS;AAAA,UACZ,GAAG,QAAQ;AAAA,QACb;AAAA,QACA,QAAQ,QAAQ;AAAA,MAClB;AAGA,YAAM,UAAU,MAAM,iBAAiB;AAAA,QACrC;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX;AAAA,MACF;AAEA,sBAAgB,KAAK,GAAG,OAAO;AAG/B,YAAM,mBAAmB,QAAQ,OAAO,OAAK,CAAC,EAAE,OAAO;AAEvD,UAAI,iBAAiB,SAAS,GAAG;AAC/B,cAAM,oBAAoB,WAAW,6BAA6B;AAGlE,cAAM,mBAAmB,IAAI;AAAA,UAC3B,oBAAoB,SAAS;AAAA,UAC7B,WAAW;AAAA,UACX,WAAW;AAAA,YACT;AAAA,YACA;AAAA,YACA,cAAc,WAAW,gBAAgB,GAAG,UAAU,KAAK,QAAQ;AAAA,YACnE,kBAAkB,iBAAiB,IAAI,QAAM;AAAA,cAC3C,cAAc,EAAE;AAAA,cAChB,cAAc,EAAE;AAAA,cAChB,OAAO,EAAE;AAAA,cACT,YAAY,EAAE;AAAA,YAChB,EAAE;AAAA,YACF;AAAA,UACF;AAAA,UACA,QAAQ,QAAQ;AAAA,UAChB,UAAU,SAAS;AAAA,UACnB,gBAAgB,SAAS;AAAA,QAC3B,CAAC;AAED,YAAI,CAAC,mBAAmB;AACtB,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAO,sBAAsB,iBAAiB,IAAI,OAAK,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;AAAA,YAC1E,qBAAqB;AAAA,cACnB,eAAe;AAAA,cACf,gBAAgB;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,cAAQ,QAAQ,YAAU;AACxB,YAAI,OAAO,WAAW,OAAO,QAAQ;AACnC,gBAAM,MAAM,OAAO,gBAAgB,OAAO;AAC1C,0BAAgB,GAAG,IAAI,OAAO;AAAA,QAChC;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,qBAAqB,gBAAgB,KAAK,OAAK,EAAE,KAAK;AAE5D,QAAI,oBAAoB;AACtB,YAAM,gBAAgB,gBACnB,OAAO,OAAK,EAAE,SAAS,EAAE,KAAK,EAC9B,IAAI,QAAM,EAAE,YAAY,EAAE,YAAY,OAAO,EAAE,MAAM,EAAE;AAG1D,eAAS,oBAAoB;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,WAAW,oBAAI,KAAK;AAAA,MACtB;AAGA,eAAS,UAAU;AAAA,QACjB,GAAG,SAAS;AAAA,QACZ,GAAG,QAAQ;AAAA,QACX,GAAG;AAAA,QACH,yBAAyB;AAAA,MAC3B;AAGA,eAAS,SAAS;AAClB,eAAS,YAAY,oBAAI,KAAK;AAC9B,YAAM,GAAG,MAAM;AAGf,YAAM,mBAAmB,IAAI;AAAA,QAC3B,oBAAoB,SAAS;AAAA,QAC7B,WAAW;AAAA,QACX,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,cAAc,WAAW;AAAA,UACzB,mBAAmB;AAAA,QACrB;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,UAAU,SAAS;AAAA,QACnB,gBAAgB,SAAS;AAAA,MAC3B,CAAC;AAGD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,qBAAqB;AAAA,QACrB,YAAY;AAAA,QACZ,qBAAqB;AAAA,UACnB,eAAe;AAAA,UACf,gBAAgB;AAAA;AAAA,QAClB;AAAA,QACA,oBAAoB;AAAA,MACtB;AAAA,IACF;AAGA,aAAS,gBAAgB;AACzB,aAAS,UAAU;AAAA,MACjB,GAAG,SAAS;AAAA,MACZ,GAAG,QAAQ;AAAA,MACX,GAAG;AAAA;AAAA,IACL;AACA,aAAS,YAAY,oBAAI,KAAK;AAE9B,UAAM,GAAG,MAAM;AAGf,UAAM,sBAAsB,MAAM,YAAY;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,iBAAiB,SAAS,WAAW,CAAC;AAAA,QACtC,QAAQ,QAAQ;AAAA,QAChB,aAAa,QAAQ;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AAGA,UAAM,GAAG,MAAM;AAGf,QAAI,oBAAoB,WAAW,UAAU;AAC3C,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,oBAAoB,SAAS;AAAA,MACtC;AAAA,IACF;AAGA,UAAM,uBAAuB,MAAM;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,qBAAqB,SAAS;AACjC,YAAM,cAAc,qBAAqB,QAAQ,KAAK,IAAI,KAAK;AAE/D,YAAM,mBAAmB,IAAI;AAAA,QAC3B,oBAAoB,SAAS;AAAA,QAC7B,WAAW;AAAA,QACX,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,cAAc,WAAW,gBAAgB,GAAG,UAAU,KAAK,QAAQ;AAAA,UACnE,QAAQ;AAAA,UACR;AAAA,QACF;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,UAAU,SAAS;AAAA,QACnB,gBAAgB,SAAS;AAAA,MAC3B,CAAC;AAAA,IAIH;AAGA,UAAM,mBAAmB,IAAI;AAAA,MAC3B,oBAAoB,SAAS;AAAA,MAC7B,WAAW;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,cAAc,WAAW,gBAAgB,GAAG,UAAU,KAAK,QAAQ;AAAA,QACnE,gBAAgB,WAAW;AAAA,QAC3B,qBAAqB;AAAA,QACrB,sBAAsB,qBAAqB;AAAA,QAC3C,oBAAoB,gBAAgB;AAAA,QACpC,qBAAqB,gBAAgB,OAAO,OAAK,EAAE,OAAO,EAAE;AAAA,QAC5D,kBAAkB,gBAAgB,OAAO,OAAK,CAAC,EAAE,OAAO,EAAE;AAAA,MAC5D;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,UAAU,SAAS;AAAA,MACnB,gBAAgB,SAAS;AAAA,IAC3B,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,qBAAqB;AAAA,QACnB,eAAe;AAAA,QACf,gBAAgB,qBAAqB;AAAA,MACvC;AAAA,MACA,oBAAoB;AAAA,IACtB;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAE1E,UAAM,mBAAmB,IAAI;AAAA,MAC3B,oBAAoB,SAAS;AAAA,MAC7B,WAAW;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,UAAU,SAAS;AAAA,MACnB,gBAAgB,SAAS;AAAA,IAC3B,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,gCAAgC,YAAY;AAAA,IACrD;AAAA,EACF;AACF;AAeA,eAAe,6BACb,IACA,UACA,YACA,SACqC;AACrC,MAAI;AAEF,QAAI,CAAC,WAAW,WAAW;AACzB,aAAO;AAAA,QACL,SAAS;AAAA,MACX;AAAA,IACF;AAGA,UAAM,OAAO;AAAA,MACX,GAAG,SAAS;AAAA,MACZ,GAAG,QAAQ;AAAA,MACX,aAAa,QAAQ;AAAA,IACvB;AAGA,UAAM,cAAmD;AAAA,MACvD,YAAY;AAAA,MACZ,UAAU,SAAS;AAAA,MACnB,MAAM,QAAQ,SAAS,EAAE,IAAI,QAAQ,OAAO,IAAI;AAAA,IAClD;AAGA,UAAM,SAAS,MAAM,cAAc;AAAA,MACjC,WAAW;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,SAAS,SAAY;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,+BAA+B,YAAY;AAAA,IACrD;AAAA,EACF;AACF;AAkBA,eAAe,sBACb,IACA,UACA,YACA,SACA,UACsC;AACtC,MAAI;AAEF,UAAM,aAAa,MAAM,GAAG,QAAQ,oBAAoB;AAAA,MACtD,IAAI,SAAS;AAAA,IACf,CAAC;AAED,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe,CAAC;AAAA,QAChB,oBAAoB;AAAA,MACtB;AAAA,IACF;AAGA,UAAM,gBAAgB,WAAW,iBAAiB,CAAC;AAGnD,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe,CAAC;AAAA,QAChB,oBAAoB;AAAA,MACtB;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,gBAAkD,CAAC;AACzD,UAAM,SAAmB,CAAC;AAC1B,QAAI,UAAU;AAEd,eAAW,aAAa,eAAe;AACrC,YAAM,SAAS,MAAM,WAAW,oBAAoB,IAAI;AAAA,QACtD,QAAQ,UAAU;AAAA;AAAA,QAClB,MAAM;AAAA,UACJ,oBAAoB,SAAS;AAAA,UAC7B,YAAY,WAAW;AAAA,UACvB,YAAY,WAAW;AAAA,UACvB,UAAU,WAAW;AAAA,UACrB,iBAAiB;AAAA,YACf,GAAG,SAAS;AAAA,YACZ,GAAG,QAAQ;AAAA,UACb;AAAA,UACA,aAAa,QAAQ;AAAA,QACvB;AAAA,QACA,MAAM,QAAQ,SAAS,EAAE,IAAI,QAAQ,OAAO,IAAI;AAAA,QAChD,UAAU,SAAS;AAAA,QACnB,gBAAgB,SAAS;AAAA,QACzB,YAAY,QAAQ;AAAA,QACpB,YAAY,YAAY,WAAW,UAAU;AAAA,QAC7C,UAAU,WAAW,gBAAgB,GAAG,WAAW,UAAU,KAAK,WAAW,QAAQ;AAAA,QACrF,WAAW;AAAA,MACb,CAAC;AAID,YAAM,aAA6C;AAAA,QACjD,MAAM;AAAA,UACJ,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO;AAAA,UACjB,UAAU;AAAA,QACZ;AAAA,QACA,iBAAiB,OAAO;AAAA,QACxB,iBAAiB,OAAO;AAAA,QACxB,eAAe,OAAO;AAAA,QACtB,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,MAChB;AACA,oBAAc,KAAK,UAAU;AAG7B,UAAI,OAAO,OAAO;AAEhB,cAAMA,cAAa,UAAU,aAAa;AAC1C,YAAIA,aAAY;AACd,oBAAU;AACV,iBAAO,KAAK,SAAS,OAAO,MAAM,MAAM,OAAO,KAAK,EAAE;AAAA,QACxD;AACA;AAAA,MACF;AAGA,YAAM,aAAa,UAAU,aAAa;AAC1C,UAAI,cAAc,CAAC,OAAO,iBAAiB;AACzC,kBAAU;AACV,eAAO,KAAK,kBAAkB,OAAO,YAAY,OAAO,MAAM,UAAU;AAAA,MAC1E;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,oBAAoB,KAAK,IAAI,IAAI;AAAA,MACjC,QAAQ,OAAO,SAAS,IAAI,SAAS;AAAA,IACvC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,oCAAoC,KAAK;AACvD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,eAAe,CAAC;AAAA,MAChB,oBAAoB;AAAA,MACpB,QAAQ,CAAC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACjE;AAAA,EACF;AACF;AAiBA,eAAe,uBACb,IACA,UACA,YACA,SACA,UACsC;AACtC,MAAI;AAEF,UAAM,aAAa,MAAM,GAAG,QAAQ,oBAAoB;AAAA,MACtD,IAAI,SAAS;AAAA,IACf,CAAC;AAED,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe,CAAC;AAAA,QAChB,oBAAoB;AAAA,MACtB;AAAA,IACF;AAGA,UAAM,iBAAiB,WAAW,kBAAkB,CAAC;AAGrD,QAAI,eAAe,WAAW,GAAG;AAC/B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe,CAAC;AAAA,QAChB,oBAAoB;AAAA,MACtB;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,gBAAkD,CAAC;AACzD,UAAM,SAAmB,CAAC;AAC1B,QAAI,UAAU;AAEd,eAAW,aAAa,gBAAgB;AACtC,YAAM,SAAS,MAAM,WAAW,oBAAoB,IAAI;AAAA,QACtD,QAAQ,UAAU;AAAA;AAAA,QAClB,MAAM;AAAA,UACJ,oBAAoB,SAAS;AAAA,UAC7B,YAAY,WAAW;AAAA,UACvB,YAAY,WAAW;AAAA,UACvB,UAAU,WAAW;AAAA,UACrB,iBAAiB;AAAA,YACf,GAAG,SAAS;AAAA,YACZ,GAAG,QAAQ;AAAA,UACb;AAAA,UACA,aAAa,QAAQ;AAAA,QACvB;AAAA,QACA,MAAM,QAAQ,SAAS,EAAE,IAAI,QAAQ,OAAO,IAAI;AAAA,QAChD,UAAU,SAAS;AAAA,QACnB,gBAAgB,SAAS;AAAA,QACzB,YAAY,QAAQ;AAAA,QACpB,YAAY,YAAY,WAAW,UAAU;AAAA,QAC7C,UAAU,WAAW,gBAAgB,GAAG,WAAW,UAAU,KAAK,WAAW,QAAQ;AAAA,QACrF,WAAW;AAAA,MACb,CAAC;AAGD,YAAM,aAA6C;AAAA,QACjD,MAAM;AAAA,UACJ,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO;AAAA,UACjB,UAAU;AAAA,QACZ;AAAA,QACA,iBAAiB,OAAO;AAAA,QACxB,iBAAiB,OAAO;AAAA,QACxB,eAAe,OAAO;AAAA,QACtB,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,MAChB;AACA,oBAAc,KAAK,UAAU;AAG7B,UAAI,OAAO,OAAO;AAChB,eAAO,KAAK,SAAS,OAAO,MAAM,MAAM,OAAO,KAAK,EAAE;AAEtD,kBAAU;AACV;AAAA,MACF;AAGA,UAAI,CAAC,OAAO,iBAAiB;AAC3B,kBAAU;AACV,eAAO,KAAK,mBAAmB,OAAO,YAAY,OAAO,MAAM,UAAU;AAAA,MAC3E;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,oBAAoB,KAAK,IAAI,IAAI;AAAA,MACjC,QAAQ,OAAO,SAAS,IAAI,SAAS;AAAA,IACvC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,qCAAqC,KAAK;AACxD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,eAAe,CAAC;AAAA,MAChB,oBAAoB;AAAA,MACpB,QAAQ,CAAC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACjE;AAAA,EACF;AACF;AASA,eAAe,mBACb,IACA,OAQwB;AACxB,QAAM,gBAAgB,GAAG,OAAO,eAAe;AAAA,IAC7C,GAAG;AAAA,IACH,YAAY,oBAAI,KAAK;AAAA,EACvB,CAAC;AAED,QAAM,GAAG,gBAAgB,aAAa;AACtC,SAAO;AACT;",
|
|
4
|
+
"sourcesContent": ["/**\n * Workflows Module - Transition Handler Service\n *\n * Handles workflow transitions between steps:\n * - Evaluating if a transition is valid (checking conditions)\n * - Executing transitions (moving from one step to another)\n * - Integrating with business rules engine for pre/post conditions\n * - Executing activities on transition\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport type { EventBus } from '@open-mercato/events'\nimport {\n WorkflowInstance,\n WorkflowDefinition,\n WorkflowEvent,\n} from '../data/entities'\nimport * as ruleEvaluator from '../../business_rules/lib/rule-evaluator'\nimport * as ruleEngine from '../../business_rules/lib/rule-engine'\nimport * as activityExecutor from './activity-executor'\nimport type { ActivityDefinition } from './activity-executor'\nimport * as stepHandler from './step-handler'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface TransitionEvaluationContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionEvaluationResult {\n isValid: boolean\n transition?: any\n reason?: string\n failedConditions?: string[]\n evaluationTime?: number\n}\n\nexport interface TransitionExecutionContext {\n workflowContext: Record<string, any>\n userId?: string\n triggerData?: any\n}\n\nexport interface TransitionExecutionResult {\n success: boolean\n nextStepId?: string\n pausedForActivities?: boolean\n conditionsEvaluated?: {\n preConditions: boolean\n postConditions: boolean\n }\n activitiesExecuted?: activityExecutor.ActivityExecutionResult[]\n error?: string\n}\n\nexport class TransitionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'TransitionError'\n }\n}\n\n// ============================================================================\n// Main Transition Functions\n// ============================================================================\n\n/**\n * Evaluate if a transition from current step to target step is valid\n *\n * Checks:\n * - Transition exists in workflow definition\n * - Pre-conditions pass (if any business rules defined)\n * - Transition condition evaluates to true (if specified)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID (optional - will auto-select if not provided)\n * @param context - Evaluation context\n * @returns Evaluation result with validity and reason\n */\nexport async function evaluateTransition(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string | undefined,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n const startTime = Date.now()\n\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n isValid: false,\n reason: `Workflow definition not found: ${instance.definitionId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Find transition\n const transitions = definition.definition.transitions || []\n let transition: any\n\n if (toStepId) {\n // Find specific transition\n transition = transitions.find(\n (t: any) => t.fromStepId === fromStepId && t.toStepId === toStepId\n )\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No transition found from ${fromStepId} to ${toStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n } else {\n // Auto-select first valid transition\n const availableTransitions = transitions.filter(\n (t: any) => t.fromStepId === fromStepId\n )\n\n if (availableTransitions.length === 0) {\n return {\n isValid: false,\n reason: `No transitions available from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n\n // Evaluate each transition to find first valid one\n for (const t of availableTransitions) {\n const result = await evaluateTransitionConditions(\n em,\n instance,\n t,\n context\n )\n\n if (result.isValid) {\n transition = t\n break\n }\n }\n\n if (!transition) {\n return {\n isValid: false,\n reason: `No valid transitions found from step ${fromStepId}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n }\n\n // Evaluate transition conditions (inline condition + business rules pre-conditions)\n const conditionResult = await evaluateTransitionConditions(\n em,\n instance,\n transition,\n context\n )\n\n return {\n ...conditionResult,\n transition,\n evaluationTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Transition evaluation error: ${errorMessage}`,\n evaluationTime: Date.now() - startTime,\n }\n }\n}\n\n/**\n * Find all valid transitions from current step\n *\n * This function evaluates both inline conditions AND preConditions (business rules)\n * to determine which transitions are truly valid. This is important for decision\n * branching where multiple transitions exist with different preConditions.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param context - Evaluation context\n * @returns Array of evaluation results for all transitions, sorted by priority (desc)\n */\nexport async function findValidTransitions(\n em: EntityManager,\n instance: WorkflowInstance,\n fromStepId: string,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult[]> {\n try {\n // Load workflow definition\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return []\n }\n\n // Find all transitions from current step, sorted by priority (highest first)\n const transitions = (definition.definition.transitions || [])\n .filter((t: any) => t.fromStepId === fromStepId)\n .sort((a: any, b: any) => (b.priority || 0) - (a.priority || 0))\n\n // Evaluate each transition including preConditions\n const results: TransitionEvaluationResult[] = []\n\n for (const transition of transitions) {\n // First check inline condition\n const conditionResult = await evaluateTransition(\n em,\n instance,\n fromStepId,\n transition.toStepId,\n context\n )\n\n if (!conditionResult.isValid) {\n results.push(conditionResult)\n continue\n }\n\n // Also evaluate preConditions if they exist\n const preConditions = transition.preConditions || []\n if (preConditions.length > 0) {\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context as TransitionExecutionContext,\n null\n )\n\n if (!preConditionsResult.allowed) {\n // Transition is invalid due to preConditions\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => r.rule.ruleId || r.rule.ruleName)\n\n results.push({\n isValid: false,\n transition,\n reason: `Pre-conditions failed: ${failedRules.join(', ')}`,\n failedConditions: failedRules,\n })\n continue\n }\n }\n\n // Transition is valid (both condition and preConditions passed)\n results.push({\n ...conditionResult,\n transition,\n })\n }\n\n return results\n } catch (error) {\n console.error('Error finding valid transitions:', error)\n return []\n }\n}\n\n/**\n * Execute a transition from one step to another\n *\n * This is the main entry point for transition execution. It:\n * 1. Validates the transition\n * 2. Evaluates pre-conditions\n * 3. Executes activities (if any)\n * 4. Updates workflow instance state (atomically with activity outputs)\n * 5. Evaluates post-conditions\n * 6. Logs transition event\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution)\n * @param instance - Workflow instance\n * @param fromStepId - Current step ID\n * @param toStepId - Target step ID\n * @param context - Execution context\n * @returns Execution result\n */\nexport async function executeTransition(\n em: EntityManager,\n container: AwilixContainer,\n instance: WorkflowInstance,\n fromStepId: string,\n toStepId: string,\n context: TransitionExecutionContext\n): Promise<TransitionExecutionResult> {\n try {\n let eventBus: Pick<EventBus, 'emitEvent'> | null = null\n try {\n eventBus = container.resolve('eventBus') as EventBus\n } catch {\n eventBus = null\n }\n\n // First, evaluate if transition is valid\n const evaluation = await evaluateTransition(\n em,\n instance,\n fromStepId,\n toStepId,\n context\n )\n\n if (!evaluation.isValid) {\n return {\n success: false,\n error: evaluation.reason || 'Transition validation failed',\n }\n }\n\n const transition = evaluation.transition!\n\n // Evaluate pre-conditions (business rules)\n const preConditionsResult = await evaluatePreConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!preConditionsResult.allowed) {\n // Build detailed failure information\n const failedRules = preConditionsResult.executedRules\n .filter((r) => !r.conditionResult)\n .map((r) => ({\n ruleId: r.rule.ruleId,\n ruleName: r.rule.ruleName,\n error: r.error,\n }))\n\n const failedRulesDetails = failedRules.length > 0\n ? failedRules.map(r => `${r.ruleId}: ${r.error || 'condition failed'}`).join('; ')\n : preConditionsResult.errors?.join(', ') || 'Unknown pre-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_REJECTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Pre-conditions failed',\n failedRules: failedRulesDetails,\n failedRulesDetail: failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Pre-conditions failed: ${failedRulesDetails}`,\n conditionsEvaluated: {\n preConditions: false,\n postConditions: false,\n },\n }\n }\n\n // Execute activities (if any)\n let activityOutputs: Record<string, any> = {}\n const activityResults: activityExecutor.ActivityExecutionResult[] = []\n\n if (transition.activities && transition.activities.length > 0) {\n const activityContext: activityExecutor.ActivityContext = {\n workflowInstance: instance,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n userId: context.userId,\n }\n\n // Execute all activities\n const results = await activityExecutor.executeActivities(\n em,\n container,\n transition.activities as ActivityDefinition[],\n activityContext\n )\n\n activityResults.push(...results)\n\n // Check for failures\n const failedActivities = results.filter(r => !r.success)\n\n if (failedActivities.length > 0) {\n const continueOnFailure = transition.continueOnActivityFailure ?? false\n\n // Log activity failures\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'ACTIVITY_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n failedActivities: failedActivities.map(f => ({\n activityType: f.activityType,\n activityName: f.activityName,\n error: f.error,\n retryCount: f.retryCount,\n })),\n continueOnFailure,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n if (!continueOnFailure) {\n return {\n success: false,\n error: `Activities failed: ${failedActivities.map(f => f.error).join(', ')}`,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false,\n },\n }\n }\n }\n\n // Collect activity outputs for context update\n results.forEach(result => {\n if (result.success && result.output) {\n const key = result.activityName || result.activityType\n activityOutputs[key] = result.output\n }\n })\n }\n\n // Check if any activities are async - if so, pause before executing step\n const hasAsyncActivities = activityResults.some(r => r.async)\n\n if (hasAsyncActivities) {\n const pendingJobIds = activityResults\n .filter(a => a.async && a.jobId)\n .map(a => ({ activityId: a.activityId, jobId: a.jobId }))\n\n // Store pending transition state\n instance.pendingTransition = {\n toStepId,\n activityResults,\n timestamp: new Date(),\n }\n\n // Store pending activities in context for tracking\n instance.context = {\n ...instance.context,\n ...context.workflowContext,\n ...activityOutputs,\n _pendingAsyncActivities: pendingJobIds,\n }\n\n // Set status to waiting\n instance.status = 'WAITING_FOR_ACTIVITIES'\n instance.updatedAt = new Date()\n await em.flush()\n\n // Log event\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_PAUSED_FOR_ACTIVITIES',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId,\n pendingActivities: pendingJobIds,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Return WITHOUT executing step\n return {\n success: true,\n pausedForActivities: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: false, // Not evaluated yet\n },\n activitiesExecuted: activityResults,\n }\n }\n\n // Update workflow instance - set current step and update context atomically\n instance.currentStepId = toStepId\n instance.context = {\n ...instance.context,\n ...context.workflowContext,\n ...activityOutputs, // Include activity outputs\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n\n // Execute the new step (this will create USER_TASK, handle END steps, etc.)\n const stepExecutionResult = await stepHandler.executeStep(\n em,\n instance,\n toStepId,\n {\n workflowContext: instance.context || {},\n userId: context.userId,\n triggerData: context.triggerData,\n },\n container\n )\n\n // Flush to database after step execution completes to make state visible to UI\n await em.flush()\n\n // Handle step execution failure\n if (stepExecutionResult.status === 'FAILED') {\n return {\n success: false,\n error: stepExecutionResult.error || 'Step execution failed',\n }\n }\n\n // Evaluate post-conditions (business rules)\n const postConditionsResult = await evaluatePostConditions(\n em,\n instance,\n transition,\n context,\n eventBus\n )\n\n if (!postConditionsResult.allowed) {\n const failedRules = postConditionsResult.errors?.join(', ') || 'Unknown post-condition failure'\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_POST_CONDITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n reason: 'Post-conditions failed',\n failedRules,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Note: We don't roll back the transition on post-condition failure\n // Post-conditions are warnings, not blockers\n }\n\n // Log successful transition\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_EXECUTED',\n eventData: {\n fromStepId,\n toStepId,\n transitionId: transition.transitionId || `${fromStepId}->${toStepId}`,\n transitionName: transition.transitionName,\n preConditionsPassed: true,\n postConditionsPassed: postConditionsResult.allowed,\n activitiesExecuted: activityResults.length,\n activitiesSucceeded: activityResults.filter(r => r.success).length,\n activitiesFailed: activityResults.filter(r => !r.success).length,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: true,\n nextStepId: toStepId,\n conditionsEvaluated: {\n preConditions: true,\n postConditions: postConditionsResult.allowed,\n },\n activitiesExecuted: activityResults,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n await logTransitionEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'TRANSITION_FAILED',\n eventData: {\n fromStepId,\n toStepId,\n error: errorMessage,\n },\n userId: context.userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return {\n success: false,\n error: `Transition execution failed: ${errorMessage}`,\n }\n }\n}\n\n// ============================================================================\n// Condition Evaluation\n// ============================================================================\n\n/**\n * Evaluate transition conditions (inline condition expression)\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Evaluation context\n * @returns Evaluation result\n */\nasync function evaluateTransitionConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionEvaluationContext\n): Promise<TransitionEvaluationResult> {\n try {\n // If no condition specified, transition is always valid\n if (!transition.condition) {\n return {\n isValid: true,\n }\n }\n\n // Build data context for rule evaluation\n const data = {\n ...instance.context,\n ...context.workflowContext,\n triggerData: context.triggerData,\n }\n\n // Build evaluation context\n const evalContext: ruleEvaluator.RuleEvaluationContext = {\n entityType: 'workflow:transition',\n entityId: instance.id,\n user: context.userId ? { id: context.userId } : undefined,\n }\n\n // Evaluate condition using expression evaluator\n const result = await ruleEvaluator.evaluateConditions(\n transition.condition,\n data,\n evalContext\n )\n\n return {\n isValid: result,\n reason: result ? undefined : 'Transition condition evaluated to false',\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n return {\n isValid: false,\n reason: `Condition evaluation error: ${errorMessage}`,\n }\n }\n}\n\n/**\n * Evaluate pre-conditions using business rules engine\n *\n * Pre-conditions are GUARD rules that must pass before transition can execute.\n * If any GUARD rule fails, the transition is blocked.\n *\n * If the transition defines specific preConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, falls back to\n * discovery-based execution via executeRules.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePreConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific preConditions defined\n const preConditions = transition.preConditions || []\n\n // If no pre-conditions defined, allow transition\n if (preConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each pre-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of preConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'pre_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n // We don't have the full BusinessRule entity, but we can create a partial result\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n // Rule not found, disabled, or other errors\n const isRequired = condition.required !== false // Default to required\n if (isRequired) {\n allowed = false\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n }\n continue\n }\n\n // If required and condition failed, block transition\n const isRequired = condition.required !== false // Default to required\n if (isRequired && !result.conditionResult) {\n allowed = false\n errors.push(`Pre-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating pre-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n/**\n * Evaluate post-conditions using business rules engine\n *\n * Post-conditions are GUARD rules that should pass after transition executes.\n * Unlike pre-conditions, post-condition failures are logged but don't block the transition.\n *\n * If the transition defines specific postConditions with ruleIds, those are\n * executed directly via executeRuleByRuleId. Otherwise, returns allowed: true.\n *\n * @param em - Entity manager\n * @param instance - Workflow instance\n * @param transition - Transition definition\n * @param context - Execution context\n * @returns Rule engine result\n */\nasync function evaluatePostConditions(\n em: EntityManager,\n instance: WorkflowInstance,\n transition: any,\n context: TransitionExecutionContext,\n eventBus: Pick<EventBus, 'emitEvent'> | null\n): Promise<ruleEngine.RuleEngineResult> {\n try {\n // Load workflow definition to get workflow ID\n const definition = await em.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Check if transition has specific postConditions defined\n const postConditions = transition.postConditions || []\n\n // If no post-conditions defined, allow\n if (postConditions.length === 0) {\n return {\n allowed: true,\n executedRules: [],\n totalExecutionTime: 0,\n }\n }\n\n // Execute each post-condition rule directly by ruleId\n const startTime = Date.now()\n const executedRules: ruleEngine.RuleExecutionResult[] = []\n const errors: string[] = []\n let allowed = true\n\n for (const condition of postConditions) {\n const result = await ruleEngine.executeRuleByRuleId(em, {\n ruleId: condition.ruleId, // String identifier\n data: {\n workflowInstanceId: instance.id,\n workflowId: definition.workflowId,\n fromStepId: transition.fromStepId,\n toStepId: transition.toStepId,\n workflowContext: {\n ...instance.context,\n ...context.workflowContext,\n },\n triggerData: context.triggerData,\n },\n user: context.userId ? { id: context.userId } : undefined,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n executedBy: context.userId,\n entityType: `workflow:${definition.workflowId}:transition`,\n entityId: transition.transitionId || `${transition.fromStepId}->${transition.toStepId}`,\n eventType: 'post_transition',\n })\n\n // Create a compatible RuleExecutionResult for tracking\n const ruleResult: ruleEngine.RuleExecutionResult = {\n rule: {\n ruleId: result.ruleId,\n ruleName: result.ruleName,\n ruleType: 'GUARD',\n } as any,\n conditionResult: result.conditionResult,\n actionsExecuted: result.actionsExecuted,\n executionTime: result.executionTime,\n error: result.error,\n logId: result.logId,\n }\n executedRules.push(ruleResult)\n\n // Handle rule errors\n if (result.error) {\n errors.push(`Rule '${result.ruleId}': ${result.error}`)\n // Post-conditions don't block, but track the failure\n allowed = false\n continue\n }\n\n // Track condition failures (post-conditions are warnings, not blockers)\n if (!result.conditionResult) {\n allowed = false\n errors.push(`Post-condition '${result.ruleName || result.ruleId}' failed`)\n }\n }\n\n return {\n allowed,\n executedRules,\n totalExecutionTime: Date.now() - startTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n } catch (error) {\n console.error('Error evaluating post-conditions:', error)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: [error instanceof Error ? error.message : String(error)],\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log transition-related event to event sourcing table\n */\nasync function logTransitionEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["isRequired"]
|
|
7
7
|
}
|
|
@@ -104,7 +104,7 @@ async function startWorkflow(em, options) {
|
|
|
104
104
|
createdAt: now,
|
|
105
105
|
updatedAt: now
|
|
106
106
|
});
|
|
107
|
-
await em.
|
|
107
|
+
await em.persist(instance).flush();
|
|
108
108
|
await logWorkflowEvent(em, {
|
|
109
109
|
workflowInstanceId: instance.id,
|
|
110
110
|
eventType: "WORKFLOW_STARTED",
|
|
@@ -637,7 +637,7 @@ async function logWorkflowEvent(em, event) {
|
|
|
637
637
|
...event,
|
|
638
638
|
occurredAt: /* @__PURE__ */ new Date()
|
|
639
639
|
});
|
|
640
|
-
await em.
|
|
640
|
+
await em.persist(workflowEvent).flush();
|
|
641
641
|
return workflowEvent;
|
|
642
642
|
}
|
|
643
643
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/workflows/lib/workflow-executor.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Workflows Module - Workflow Executor Service\n *\n * Main orchestrator for workflow execution. Handles workflow lifecycle:\n * - Starting workflow instances from definitions\n * - Executing workflow steps and transitions\n * - Completing workflows with final status\n * - Triggering compensation on failure\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager, LockMode } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n WorkflowDefinition,\n WorkflowInstance,\n WorkflowEvent,\n type WorkflowInstanceStatus,\n} from '../data/entities'\nimport { compensateWorkflow } from './compensation-handler'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StartWorkflowOptions {\n workflowId: string\n version?: number // Default to latest enabled version\n initialContext?: Record<string, any>\n correlationKey?: string\n metadata?: {\n entityType?: string\n entityId?: string\n initiatedBy?: string\n labels?: Record<string, string>\n }\n tenantId: string\n organizationId: string\n}\n\nexport interface ExecutionContext {\n userId?: string\n dryRun?: boolean\n timeout?: number\n}\n\nexport interface ExecutionResult {\n status: WorkflowInstanceStatus\n currentStep: string\n context: Record<string, any>\n events: WorkflowEventSummary[]\n errors?: string[]\n executionTime: number\n}\n\nexport interface WorkflowEventSummary {\n eventType: string\n occurredAt: Date\n data?: any\n}\n\nexport class WorkflowExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'WorkflowExecutionError'\n }\n}\n\n// ============================================================================\n// Main Orchestration Functions\n// ============================================================================\n\n/**\n * Start a new workflow instance from a definition\n *\n * @param em - Entity manager for database operations\n * @param options - Workflow start options\n * @returns Created workflow instance\n * @throws WorkflowExecutionError if definition not found or validation fails\n */\nexport async function startWorkflow(\n em: EntityManager,\n options: StartWorkflowOptions\n): Promise<WorkflowInstance> {\n const {\n workflowId,\n version,\n initialContext = {},\n correlationKey,\n metadata,\n tenantId,\n organizationId,\n } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${workflowId}${version ? ` v${version}` : ''}`,\n 'DEFINITION_NOT_FOUND',\n { workflowId, version }\n )\n }\n\n if (!definition.enabled) {\n throw new WorkflowExecutionError(\n `Workflow definition is disabled: ${workflowId}`,\n 'DEFINITION_DISABLED',\n { workflowId, version: definition.version }\n )\n }\n\n // Validate definition has required steps\n const { steps, transitions } = definition.definition\n if (!steps || steps.length < 2) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least START and END steps',\n 'INVALID_DEFINITION',\n { workflowId, stepsCount: steps?.length || 0 }\n )\n }\n\n if (!transitions || transitions.length < 1) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least one transition',\n 'INVALID_DEFINITION',\n { workflowId, transitionsCount: transitions?.length || 0 }\n )\n }\n\n // Find START step\n const startStep = steps.find((s: any) => s.stepType === 'START')\n if (!startStep) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have a START step',\n 'INVALID_DEFINITION',\n { workflowId }\n )\n }\n\n // Validate START step pre-conditions if defined\n if (startStep.preConditions && startStep.preConditions.length > 0) {\n const { validateWorkflowStart } = await import('./start-validator')\n\n const validationResult = await validateWorkflowStart(em, {\n workflowId,\n version: definition.version,\n context: initialContext,\n tenantId,\n organizationId,\n })\n\n if (!validationResult.canStart) {\n throw new WorkflowExecutionError(\n `Workflow start pre-conditions failed: ${validationResult.errors.map(e => e.message).join('; ')}`,\n 'START_PRE_CONDITIONS_FAILED',\n {\n workflowId,\n errors: validationResult.errors,\n validatedRules: validationResult.validatedRules,\n }\n )\n }\n }\n\n // Create workflow instance\n const now = new Date()\n const instance = em.create(WorkflowInstance, {\n definitionId: definition.id,\n workflowId: definition.workflowId,\n version: definition.version,\n status: 'RUNNING',\n currentStepId: startStep.stepId,\n context: initialContext,\n correlationKey,\n metadata,\n startedAt: now,\n retryCount: 0,\n tenantId,\n organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persistAndFlush(instance)\n\n // Log WORKFLOW_STARTED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'WORKFLOW_STARTED',\n eventData: {\n workflowId: instance.workflowId,\n version: instance.version,\n startStepId: startStep.stepId,\n initialContext,\n metadata,\n },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n\n return instance\n}\n\n/**\n * Execute a workflow instance\n *\n * Main execution loop that processes steps and transitions until:\n * - Workflow completes (reaches END step)\n * - Workflow waits (USER_TASK, SIGNAL, TIMER)\n * - Workflow fails (error occurs)\n * - Timeout is reached\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution and other services)\n * @param instanceId - Workflow instance ID\n * @param context - Execution context (userId, dryRun, timeout)\n * @returns Execution result with status and events\n */\nexport async function executeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n context?: ExecutionContext\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(\n callback: (trx: EntityManager) => Promise<TResult>,\n ) => Promise<TResult>\n }\n\n const runExecution = async (trx: EntityManager): Promise<ExecutionResult> => {\n const events: WorkflowEventSummary[] = []\n const errors: string[] = []\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status === 'COMPLETED') {\n return {\n status: 'COMPLETED',\n currentStep: instance.currentStepId,\n context: instance.context,\n events: [],\n executionTime: 0,\n }\n }\n\n if (instance.status === 'CANCELLED') {\n throw new WorkflowExecutionError(\n 'Cannot execute cancelled workflow',\n 'WORKFLOW_CANCELLED',\n { instanceId, status: instance.status }\n )\n }\n\n const definition = await trx.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const maxIterations = 100\n let iterations = 0\n\n while (iterations < maxIterations) {\n iterations++\n\n const currentInstance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: iterations > 1 })\n if (!currentInstance) {\n throw new WorkflowExecutionError(\n 'Instance not found during execution',\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n const currentStep = definition.definition.steps.find(\n (s: any) => s.stepId === currentInstance.currentStepId\n )\n\n if (currentStep?.stepType === 'END') {\n await completeWorkflow(trx, container, instanceId, 'COMPLETED')\n events.push({\n eventType: 'WORKFLOW_COMPLETED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'COMPLETED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (\n currentStep?.stepType === 'USER_TASK' ||\n currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||\n currentStep?.stepType === 'TIMER'\n ) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitions = definition.definition.transitions.filter(\n (t: any) =>\n t.fromStepId === currentInstance.currentStepId &&\n t.trigger === 'auto'\n )\n\n if (transitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitionHandler = await import('./transition-handler')\n const evalContext: any = {\n workflowContext: currentInstance.context,\n userId: context?.userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n trx,\n currentInstance,\n currentInstance.currentStepId!,\n evalContext\n )\n\n const validAutoTransitions = validTransitions.filter(\n (vt) => vt.isValid && vt.transition?.trigger === 'auto'\n )\n\n if (validAutoTransitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const selectedTransition = validAutoTransitions[0].transition\n\n try {\n const transitionResult = await transitionHandler.executeTransition(\n trx,\n container,\n currentInstance,\n selectedTransition.fromStepId,\n selectedTransition.toStepId,\n evalContext\n )\n\n if (!transitionResult.success) {\n const rejectionMessage = transitionResult.error || 'Transition failed'\n console.error(`[WORKFLOW] Transition rejected (instance: ${currentInstance.id}, workflow: ${currentInstance.workflowId}, step: ${currentInstance.currentStepId} \u2192 ${selectedTransition.toStepId}): ${rejectionMessage}`)\n errors.push(rejectionMessage)\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n events.push({\n eventType: 'TRANSITION_EXECUTED',\n occurredAt: new Date(),\n data: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n transitionId: selectedTransition.transitionId,\n },\n })\n\n if (transitionResult.pausedForActivities) {\n await logWorkflowEvent(trx, {\n workflowInstanceId: currentInstance.id,\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n eventData: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n pausedAtTransition: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n },\n },\n tenantId: currentInstance.tenantId,\n organizationId: currentInstance.organizationId,\n })\n\n events.push({\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n occurredAt: new Date(),\n data: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n },\n })\n\n return {\n status: 'WAITING_FOR_ACTIVITIES',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n await trx.flush()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(`[WORKFLOW] Transition execution failed (instance: ${currentInstance.id}, workflow: ${currentInstance.workflowId}, step: ${currentInstance.currentStepId} \u2192 ${selectedTransition.toStepId}):`, error)\n console.error('[WORKFLOW] Error stack:', error instanceof Error ? error.stack : 'No stack trace')\n errors.push(errorMessage)\n\n events.push({\n eventType: 'TRANSITION_FAILED',\n occurredAt: new Date(),\n data: {\n transitionId: selectedTransition.transitionId,\n error: errorMessage,\n },\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n errors.push('Maximum execution iterations reached - possible infinite loop')\n return {\n status: 'RUNNING',\n currentStep: instance.currentStepId,\n context: instance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(`[WORKFLOW] Execution failed (instance: ${instanceId}):`, error)\n if (error instanceof Error && error.stack) {\n console.error('[WORKFLOW] Error stack:', error.stack)\n }\n errors.push(errorMessage)\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: true })\n if (instance && instance.status === 'RUNNING') {\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n console.error(`[WORKFLOW] Failed to update instance ${instanceId} with error state:`, updateError)\n }\n\n throw error\n }\n }\n\n return typeof transactionalEm.transactional === 'function'\n ? transactionalEm.transactional((trx) => runExecution(trx))\n : runExecution(em)\n}\n\n/**\n * Complete a workflow instance with final status\n *\n * @param em - Entity manager\n * @param container\n * @param instanceId - Workflow instance ID\n * @param status - Final status (COMPLETED, FAILED, CANCELLED)\n * @param result - Optional result data\n */\nexport async function completeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED',\n result?: any\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)\n if (status === 'FAILED') {\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n\n if (definition && checkIfCompensationNeeded(definition)) {\n try {\n\n // Set error message before compensation\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n await em.flush()\n }\n\n const compensationResult = await compensateWorkflow(\n em,\n container,\n instance,\n definition,\n {\n continueOnError: true // Best-effort compensation\n }\n )\n\n console.log(\n `[Workflow] Compensation ${compensationResult.status}: ${compensationResult.compensatedActivities}/${compensationResult.totalActivities} activities`\n )\n\n // Note: instance status already updated by compensateWorkflow\n // It will be COMPENSATED or remain FAILED\n return\n } catch (error: any) {\n console.error(`[Workflow] Compensation failed with exception:`, error)\n // Continue to mark workflow as failed\n }\n }\n }\n\n // Original completion logic (no compensation needed or status is COMPLETED/CANCELLED)\n const now = new Date()\n instance.status = status\n instance.updatedAt = now\n\n switch (status) {\n case 'COMPLETED':\n instance.completedAt = now\n if (result) {\n instance.context = { ...instance.context, __result: result }\n }\n break\n\n case 'FAILED':\n instance.completedAt = now\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n }\n break\n\n case 'CANCELLED':\n instance.cancelledAt = now\n break\n }\n\n await em.flush()\n\n // Log completion event\n const eventType =\n status === 'COMPLETED'\n ? 'WORKFLOW_COMPLETED'\n : status === 'FAILED'\n ? 'WORKFLOW_FAILED'\n : 'WORKFLOW_CANCELLED'\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instanceId,\n eventType,\n eventData: result || {},\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Resume workflow after async activities complete\n *\n * Called by the activity worker after all async activities finish execution.\n * Checks if all activities are done, merges outputs into context, and resumes execution.\n *\n * @param em - Entity manager\n * @param container - DI container\n * @param instanceId - Workflow instance ID\n */\nexport async function resumeWorkflowAfterActivities(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string\n): Promise<void> {\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n\n const runResume = async (trx: EntityManager): Promise<{ continueExecution: boolean }> => {\n const instance = await trx.findOne(WorkflowInstance, {\n id: instanceId,\n status: 'WAITING_FOR_ACTIVITIES',\n }, { lockMode: LockMode.PESSIMISTIC_WRITE })\n\n if (!instance) {\n throw new Error('Workflow instance not waiting for activities')\n }\n\n const pendingJobIds = (instance.context._pendingAsyncActivities as any[]) || []\n\n const completedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n const failedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n const totalProcessed = completedActivities + failedActivities\n\n if (totalProcessed < pendingJobIds.length) {\n throw new Error('Activities still pending')\n }\n\n if (failedActivities > 0) {\n const failedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n instance.status = 'FAILED'\n instance.errorMessage = `${failedActivities} async activities failed`\n instance.errorDetails = {\n failedActivities: failedEvents.map(e => ({\n activityId: e.eventData.activityId,\n error: e.eventData.error,\n jobId: e.eventData.jobId,\n })),\n }\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: {\n reason: 'Async activities failed',\n failedActivities: instance.errorDetails.failedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: false }\n }\n\n const completedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n for (const event of completedEvents) {\n if (event.eventData.output) {\n instance.context = {\n ...instance.context,\n [`${event.eventData.activityId}_result`]: event.eventData.output,\n }\n }\n }\n\n delete instance.context._pendingAsyncActivities\n\n const pendingTransition = instance.pendingTransition\n\n if (!pendingTransition) {\n console.warn('[WORKFLOW] No pending transition found during resume')\n instance.status = 'RUNNING'\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'All async activities completed',\n completedActivities: completedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: true }\n }\n\n console.log('[WORKFLOW] Completing pending transition:', {\n toStepId: pendingTransition.toStepId,\n from: instance.currentStepId,\n })\n\n const definition = await trx.findOneOrFail(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)\n\n instance.currentStepId = pendingTransition.toStepId\n instance.status = 'RUNNING'\n instance.pendingTransition = null\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: pendingTransition.toStepId,\n stepName: step?.stepName,\n stepType: step?.stepType,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'Async activities completed, resuming pending transition',\n completedActivities: completedActivities,\n completedTransitionTo: pendingTransition.toStepId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { executeStep } = await import('./step-handler')\n await executeStep(\n trx,\n instance,\n pendingTransition.toStepId,\n {\n workflowContext: instance.context || {},\n userId: undefined,\n },\n container\n )\n\n return { continueExecution: true }\n }\n\n const resumeResult = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => runResume(trx))\n : await runResume(em)\n\n if (resumeResult.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n}\n\n/**\n * Check if workflow definition has any compensatable activities\n */\nfunction checkIfCompensationNeeded(definition: WorkflowDefinition): boolean {\n // Check if any activities have compensation defined\n for (const transition of definition.definition.transitions) {\n if (transition.activities) {\n for (const activity of transition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n }\n\n // Check root-level activities (legacy)\n if (definition.definition.activities) {\n for (const activity of definition.definition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get workflow instance by ID\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @returns Workflow instance or null if not found\n */\nexport async function getWorkflowInstance(\n em: EntityManager,\n instanceId: string\n): Promise<WorkflowInstance | null> {\n return em.findOne(WorkflowInstance, { id: instanceId })\n}\n\nasync function getWorkflowInstanceForExecution(\n em: EntityManager,\n instanceId: string,\n options?: { refresh?: boolean }\n): Promise<WorkflowInstance | null> {\n return em.findOne(\n WorkflowInstance,\n { id: instanceId },\n {\n lockMode: LockMode.PESSIMISTIC_WRITE,\n ...(options?.refresh ? { refresh: true } : {}),\n }\n )\n}\n\n/**\n * Update workflow context with new data\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @param updates - Context updates (merged with existing context)\n */\nexport async function updateWorkflowContext(\n em: EntityManager,\n instanceId: string,\n updates: Record<string, any>\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n}\n\n/**\n * Find workflow definition by ID and optional version\n *\n * @param em - Entity manager\n * @param options - Search options\n * @returns Workflow definition or null\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\n/**\n * Log workflow event to event sourcing table\n *\n * @param em - Entity manager\n * @param event - Event data\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId?: string\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persistAndFlush(workflowEvent)\n return workflowEvent\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Workflows Module - Workflow Executor Service\n *\n * Main orchestrator for workflow execution. Handles workflow lifecycle:\n * - Starting workflow instances from definitions\n * - Executing workflow steps and transitions\n * - Completing workflows with final status\n * - Triggering compensation on failure\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager, LockMode } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n WorkflowDefinition,\n WorkflowInstance,\n WorkflowEvent,\n type WorkflowInstanceStatus,\n} from '../data/entities'\nimport { compensateWorkflow } from './compensation-handler'\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface StartWorkflowOptions {\n workflowId: string\n version?: number // Default to latest enabled version\n initialContext?: Record<string, any>\n correlationKey?: string\n metadata?: {\n entityType?: string\n entityId?: string\n initiatedBy?: string\n labels?: Record<string, string>\n }\n tenantId: string\n organizationId: string\n}\n\nexport interface ExecutionContext {\n userId?: string\n dryRun?: boolean\n timeout?: number\n}\n\nexport interface ExecutionResult {\n status: WorkflowInstanceStatus\n currentStep: string\n context: Record<string, any>\n events: WorkflowEventSummary[]\n errors?: string[]\n executionTime: number\n}\n\nexport interface WorkflowEventSummary {\n eventType: string\n occurredAt: Date\n data?: any\n}\n\nexport class WorkflowExecutionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'WorkflowExecutionError'\n }\n}\n\n// ============================================================================\n// Main Orchestration Functions\n// ============================================================================\n\n/**\n * Start a new workflow instance from a definition\n *\n * @param em - Entity manager for database operations\n * @param options - Workflow start options\n * @returns Created workflow instance\n * @throws WorkflowExecutionError if definition not found or validation fails\n */\nexport async function startWorkflow(\n em: EntityManager,\n options: StartWorkflowOptions\n): Promise<WorkflowInstance> {\n const {\n workflowId,\n version,\n initialContext = {},\n correlationKey,\n metadata,\n tenantId,\n organizationId,\n } = options\n\n // Find workflow definition\n const definition = await findWorkflowDefinition(em, {\n workflowId,\n version,\n tenantId,\n organizationId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${workflowId}${version ? ` v${version}` : ''}`,\n 'DEFINITION_NOT_FOUND',\n { workflowId, version }\n )\n }\n\n if (!definition.enabled) {\n throw new WorkflowExecutionError(\n `Workflow definition is disabled: ${workflowId}`,\n 'DEFINITION_DISABLED',\n { workflowId, version: definition.version }\n )\n }\n\n // Validate definition has required steps\n const { steps, transitions } = definition.definition\n if (!steps || steps.length < 2) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least START and END steps',\n 'INVALID_DEFINITION',\n { workflowId, stepsCount: steps?.length || 0 }\n )\n }\n\n if (!transitions || transitions.length < 1) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have at least one transition',\n 'INVALID_DEFINITION',\n { workflowId, transitionsCount: transitions?.length || 0 }\n )\n }\n\n // Find START step\n const startStep = steps.find((s: any) => s.stepType === 'START')\n if (!startStep) {\n throw new WorkflowExecutionError(\n 'Workflow definition must have a START step',\n 'INVALID_DEFINITION',\n { workflowId }\n )\n }\n\n // Validate START step pre-conditions if defined\n if (startStep.preConditions && startStep.preConditions.length > 0) {\n const { validateWorkflowStart } = await import('./start-validator')\n\n const validationResult = await validateWorkflowStart(em, {\n workflowId,\n version: definition.version,\n context: initialContext,\n tenantId,\n organizationId,\n })\n\n if (!validationResult.canStart) {\n throw new WorkflowExecutionError(\n `Workflow start pre-conditions failed: ${validationResult.errors.map(e => e.message).join('; ')}`,\n 'START_PRE_CONDITIONS_FAILED',\n {\n workflowId,\n errors: validationResult.errors,\n validatedRules: validationResult.validatedRules,\n }\n )\n }\n }\n\n // Create workflow instance\n const now = new Date()\n const instance = em.create(WorkflowInstance, {\n definitionId: definition.id,\n workflowId: definition.workflowId,\n version: definition.version,\n status: 'RUNNING',\n currentStepId: startStep.stepId,\n context: initialContext,\n correlationKey,\n metadata,\n startedAt: now,\n retryCount: 0,\n tenantId,\n organizationId,\n createdAt: now,\n updatedAt: now,\n })\n\n await em.persist(instance).flush()\n\n // Log WORKFLOW_STARTED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n eventType: 'WORKFLOW_STARTED',\n eventData: {\n workflowId: instance.workflowId,\n version: instance.version,\n startStepId: startStep.stepId,\n initialContext,\n metadata,\n },\n userId: metadata?.initiatedBy,\n tenantId,\n organizationId,\n })\n\n return instance\n}\n\n/**\n * Execute a workflow instance\n *\n * Main execution loop that processes steps and transitions until:\n * - Workflow completes (reaches END step)\n * - Workflow waits (USER_TASK, SIGNAL, TIMER)\n * - Workflow fails (error occurs)\n * - Timeout is reached\n *\n * @param em - Entity manager\n * @param container - DI container (for activity execution and other services)\n * @param instanceId - Workflow instance ID\n * @param context - Execution context (userId, dryRun, timeout)\n * @returns Execution result with status and events\n */\nexport async function executeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n context?: ExecutionContext\n): Promise<ExecutionResult> {\n const startTime = Date.now()\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(\n callback: (trx: EntityManager) => Promise<TResult>,\n ) => Promise<TResult>\n }\n\n const runExecution = async (trx: EntityManager): Promise<ExecutionResult> => {\n const events: WorkflowEventSummary[] = []\n const errors: string[] = []\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n if (instance.status === 'COMPLETED') {\n return {\n status: 'COMPLETED',\n currentStep: instance.currentStepId,\n context: instance.context,\n events: [],\n executionTime: 0,\n }\n }\n\n if (instance.status === 'CANCELLED') {\n throw new WorkflowExecutionError(\n 'Cannot execute cancelled workflow',\n 'WORKFLOW_CANCELLED',\n { instanceId, status: instance.status }\n )\n }\n\n const definition = await trx.findOne(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n if (!definition) {\n throw new WorkflowExecutionError(\n `Workflow definition not found: ${instance.definitionId}`,\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const maxIterations = 100\n let iterations = 0\n\n while (iterations < maxIterations) {\n iterations++\n\n const currentInstance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: iterations > 1 })\n if (!currentInstance) {\n throw new WorkflowExecutionError(\n 'Instance not found during execution',\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n const currentStep = definition.definition.steps.find(\n (s: any) => s.stepId === currentInstance.currentStepId\n )\n\n if (currentStep?.stepType === 'END') {\n await completeWorkflow(trx, container, instanceId, 'COMPLETED')\n events.push({\n eventType: 'WORKFLOW_COMPLETED',\n occurredAt: new Date(),\n })\n\n return {\n status: 'COMPLETED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n if (\n currentStep?.stepType === 'USER_TASK' ||\n currentStep?.stepType === 'WAIT_FOR_SIGNAL' ||\n currentStep?.stepType === 'TIMER'\n ) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitions = definition.definition.transitions.filter(\n (t: any) =>\n t.fromStepId === currentInstance.currentStepId &&\n t.trigger === 'auto'\n )\n\n if (transitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const transitionHandler = await import('./transition-handler')\n const evalContext: any = {\n workflowContext: currentInstance.context,\n userId: context?.userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n trx,\n currentInstance,\n currentInstance.currentStepId!,\n evalContext\n )\n\n const validAutoTransitions = validTransitions.filter(\n (vt) => vt.isValid && vt.transition?.trigger === 'auto'\n )\n\n if (validAutoTransitions.length === 0) {\n return {\n status: 'RUNNING',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n const selectedTransition = validAutoTransitions[0].transition\n\n try {\n const transitionResult = await transitionHandler.executeTransition(\n trx,\n container,\n currentInstance,\n selectedTransition.fromStepId,\n selectedTransition.toStepId,\n evalContext\n )\n\n if (!transitionResult.success) {\n const rejectionMessage = transitionResult.error || 'Transition failed'\n console.error(`[WORKFLOW] Transition rejected (instance: ${currentInstance.id}, workflow: ${currentInstance.workflowId}, step: ${currentInstance.currentStepId} \u2192 ${selectedTransition.toStepId}): ${rejectionMessage}`)\n errors.push(rejectionMessage)\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n\n events.push({\n eventType: 'TRANSITION_EXECUTED',\n occurredAt: new Date(),\n data: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n transitionId: selectedTransition.transitionId,\n },\n })\n\n if (transitionResult.pausedForActivities) {\n await logWorkflowEvent(trx, {\n workflowInstanceId: currentInstance.id,\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n eventData: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n pausedAtTransition: {\n fromStepId: selectedTransition.fromStepId,\n toStepId: selectedTransition.toStepId,\n },\n },\n tenantId: currentInstance.tenantId,\n organizationId: currentInstance.organizationId,\n })\n\n events.push({\n eventType: 'WORKFLOW_WAITING_FOR_ACTIVITIES',\n occurredAt: new Date(),\n data: {\n pendingActivities: transitionResult.activitiesExecuted?.filter(a => a.async),\n },\n })\n\n return {\n status: 'WAITING_FOR_ACTIVITIES',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n executionTime: Date.now() - startTime,\n }\n }\n\n await trx.flush()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(`[WORKFLOW] Transition execution failed (instance: ${currentInstance.id}, workflow: ${currentInstance.workflowId}, step: ${currentInstance.currentStepId} \u2192 ${selectedTransition.toStepId}):`, error)\n console.error('[WORKFLOW] Error stack:', error instanceof Error ? error.stack : 'No stack trace')\n errors.push(errorMessage)\n\n events.push({\n eventType: 'TRANSITION_FAILED',\n occurredAt: new Date(),\n data: {\n transitionId: selectedTransition.transitionId,\n error: errorMessage,\n },\n })\n\n return {\n status: 'FAILED',\n currentStep: currentInstance.currentStepId,\n context: currentInstance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n }\n }\n\n errors.push('Maximum execution iterations reached - possible infinite loop')\n return {\n status: 'RUNNING',\n currentStep: instance.currentStepId,\n context: instance.context,\n events,\n errors,\n executionTime: Date.now() - startTime,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(`[WORKFLOW] Execution failed (instance: ${instanceId}):`, error)\n if (error instanceof Error && error.stack) {\n console.error('[WORKFLOW] Error stack:', error.stack)\n }\n errors.push(errorMessage)\n\n try {\n const instance = await getWorkflowInstanceForExecution(trx, instanceId, { refresh: true })\n if (instance && instance.status === 'RUNNING') {\n instance.status = 'FAILED'\n instance.errorMessage = errorMessage\n instance.errorDetails = error instanceof WorkflowExecutionError ? error.details : undefined\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: { error: errorMessage },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n } catch (updateError) {\n console.error(`[WORKFLOW] Failed to update instance ${instanceId} with error state:`, updateError)\n }\n\n throw error\n }\n }\n\n return typeof transactionalEm.transactional === 'function'\n ? transactionalEm.transactional((trx) => runExecution(trx))\n : runExecution(em)\n}\n\n/**\n * Complete a workflow instance with final status\n *\n * @param em - Entity manager\n * @param container\n * @param instanceId - Workflow instance ID\n * @param status - Final status (COMPLETED, FAILED, CANCELLED)\n * @param result - Optional result data\n */\nexport async function completeWorkflow(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string,\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED',\n result?: any\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n // Trigger compensation if workflow failed and has compensatable activities (Phase 8.2)\n if (status === 'FAILED') {\n const definition = await em.findOne(WorkflowDefinition, { id: instance.definitionId })\n\n if (definition && checkIfCompensationNeeded(definition)) {\n try {\n\n // Set error message before compensation\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n await em.flush()\n }\n\n const compensationResult = await compensateWorkflow(\n em,\n container,\n instance,\n definition,\n {\n continueOnError: true // Best-effort compensation\n }\n )\n\n console.log(\n `[Workflow] Compensation ${compensationResult.status}: ${compensationResult.compensatedActivities}/${compensationResult.totalActivities} activities`\n )\n\n // Note: instance status already updated by compensateWorkflow\n // It will be COMPENSATED or remain FAILED\n return\n } catch (error: any) {\n console.error(`[Workflow] Compensation failed with exception:`, error)\n // Continue to mark workflow as failed\n }\n }\n }\n\n // Original completion logic (no compensation needed or status is COMPLETED/CANCELLED)\n const now = new Date()\n instance.status = status\n instance.updatedAt = now\n\n switch (status) {\n case 'COMPLETED':\n instance.completedAt = now\n if (result) {\n instance.context = { ...instance.context, __result: result }\n }\n break\n\n case 'FAILED':\n instance.completedAt = now\n if (result?.error) {\n instance.errorMessage = result.error\n instance.errorDetails = result.details\n }\n break\n\n case 'CANCELLED':\n instance.cancelledAt = now\n break\n }\n\n await em.flush()\n\n // Log completion event\n const eventType =\n status === 'COMPLETED'\n ? 'WORKFLOW_COMPLETED'\n : status === 'FAILED'\n ? 'WORKFLOW_FAILED'\n : 'WORKFLOW_CANCELLED'\n\n await logWorkflowEvent(em, {\n workflowInstanceId: instanceId,\n eventType,\n eventData: result || {},\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n}\n\n/**\n * Resume workflow after async activities complete\n *\n * Called by the activity worker after all async activities finish execution.\n * Checks if all activities are done, merges outputs into context, and resumes execution.\n *\n * @param em - Entity manager\n * @param container - DI container\n * @param instanceId - Workflow instance ID\n */\nexport async function resumeWorkflowAfterActivities(\n em: EntityManager,\n container: AwilixContainer,\n instanceId: string\n): Promise<void> {\n const transactionalEm = em as EntityManager & {\n transactional?: <TResult>(callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n\n const runResume = async (trx: EntityManager): Promise<{ continueExecution: boolean }> => {\n const instance = await trx.findOne(WorkflowInstance, {\n id: instanceId,\n status: 'WAITING_FOR_ACTIVITIES',\n }, { lockMode: LockMode.PESSIMISTIC_WRITE })\n\n if (!instance) {\n throw new Error('Workflow instance not waiting for activities')\n }\n\n const pendingJobIds = (instance.context._pendingAsyncActivities as any[]) || []\n\n const completedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n const failedActivities = await trx.count(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n const totalProcessed = completedActivities + failedActivities\n\n if (totalProcessed < pendingJobIds.length) {\n throw new Error('Activities still pending')\n }\n\n if (failedActivities > 0) {\n const failedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_FAILED',\n eventData: { async: true },\n })\n\n instance.status = 'FAILED'\n instance.errorMessage = `${failedActivities} async activities failed`\n instance.errorDetails = {\n failedActivities: failedEvents.map(e => ({\n activityId: e.eventData.activityId,\n error: e.eventData.error,\n jobId: e.eventData.jobId,\n })),\n }\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_FAILED',\n eventData: {\n reason: 'Async activities failed',\n failedActivities: instance.errorDetails.failedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: false }\n }\n\n const completedEvents = await trx.find(WorkflowEvent, {\n workflowInstanceId: instanceId,\n eventType: 'ACTIVITY_COMPLETED',\n eventData: { async: true },\n })\n\n for (const event of completedEvents) {\n if (event.eventData.output) {\n instance.context = {\n ...instance.context,\n [`${event.eventData.activityId}_result`]: event.eventData.output,\n }\n }\n }\n\n delete instance.context._pendingAsyncActivities\n\n const pendingTransition = instance.pendingTransition\n\n if (!pendingTransition) {\n console.warn('[WORKFLOW] No pending transition found during resume')\n instance.status = 'RUNNING'\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'All async activities completed',\n completedActivities: completedActivities,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n return { continueExecution: true }\n }\n\n console.log('[WORKFLOW] Completing pending transition:', {\n toStepId: pendingTransition.toStepId,\n from: instance.currentStepId,\n })\n\n const definition = await trx.findOneOrFail(WorkflowDefinition, {\n id: instance.definitionId,\n })\n\n const step = definition.definition.steps.find(s => s.stepId === pendingTransition.toStepId)\n\n instance.currentStepId = pendingTransition.toStepId\n instance.status = 'RUNNING'\n instance.pendingTransition = null\n instance.updatedAt = new Date()\n await trx.flush()\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instance.id,\n eventType: 'STEP_ENTERED',\n eventData: {\n stepId: pendingTransition.toStepId,\n stepName: step?.stepName,\n stepType: step?.stepType,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n await logWorkflowEvent(trx, {\n workflowInstanceId: instanceId,\n eventType: 'WORKFLOW_RESUMED',\n eventData: {\n reason: 'Async activities completed, resuming pending transition',\n completedActivities: completedActivities,\n completedTransitionTo: pendingTransition.toStepId,\n },\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { executeStep } = await import('./step-handler')\n await executeStep(\n trx,\n instance,\n pendingTransition.toStepId,\n {\n workflowContext: instance.context || {},\n userId: undefined,\n },\n container\n )\n\n return { continueExecution: true }\n }\n\n const resumeResult = typeof transactionalEm.transactional === 'function'\n ? await transactionalEm.transactional((trx) => runResume(trx))\n : await runResume(em)\n\n if (resumeResult.continueExecution) {\n await executeWorkflow(em, container, instanceId)\n }\n}\n\n/**\n * Check if workflow definition has any compensatable activities\n */\nfunction checkIfCompensationNeeded(definition: WorkflowDefinition): boolean {\n // Check if any activities have compensation defined\n for (const transition of definition.definition.transitions) {\n if (transition.activities) {\n for (const activity of transition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n }\n\n // Check root-level activities (legacy)\n if (definition.definition.activities) {\n for (const activity of definition.definition.activities) {\n if (activity.compensation?.activityId) {\n return true\n }\n }\n }\n\n return false\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get workflow instance by ID\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @returns Workflow instance or null if not found\n */\nexport async function getWorkflowInstance(\n em: EntityManager,\n instanceId: string\n): Promise<WorkflowInstance | null> {\n return em.findOne(WorkflowInstance, { id: instanceId })\n}\n\nasync function getWorkflowInstanceForExecution(\n em: EntityManager,\n instanceId: string,\n options?: { refresh?: boolean }\n): Promise<WorkflowInstance | null> {\n return em.findOne(\n WorkflowInstance,\n { id: instanceId },\n {\n lockMode: LockMode.PESSIMISTIC_WRITE,\n ...(options?.refresh ? { refresh: true } : {}),\n }\n )\n}\n\n/**\n * Update workflow context with new data\n *\n * @param em - Entity manager\n * @param instanceId - Workflow instance ID\n * @param updates - Context updates (merged with existing context)\n */\nexport async function updateWorkflowContext(\n em: EntityManager,\n instanceId: string,\n updates: Record<string, any>\n): Promise<void> {\n const instance = await getWorkflowInstance(em, instanceId)\n if (!instance) {\n throw new WorkflowExecutionError(\n `Workflow instance not found: ${instanceId}`,\n 'INSTANCE_NOT_FOUND',\n { instanceId }\n )\n }\n\n instance.context = {\n ...instance.context,\n ...updates,\n }\n instance.updatedAt = new Date()\n\n await em.flush()\n}\n\n/**\n * Find workflow definition by ID and optional version\n *\n * @param em - Entity manager\n * @param options - Search options\n * @returns Workflow definition or null\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\n/**\n * Log workflow event to event sourcing table\n *\n * @param em - Entity manager\n * @param event - Event data\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId?: string\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/jest.config.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @type {import('jest').Config} */
|
|
2
2
|
module.exports = {
|
|
3
|
-
preset: 'ts-jest',
|
|
4
3
|
testEnvironment: 'node',
|
|
5
4
|
watchman: false,
|
|
6
5
|
rootDir: '.',
|
|
@@ -17,7 +16,7 @@ module.exports = {
|
|
|
17
16
|
},
|
|
18
17
|
transform: {
|
|
19
18
|
'^.+\\.(t|j)sx?$': [
|
|
20
|
-
'
|
|
19
|
+
'<rootDir>/../../scripts/jest-mikroorm-transformer.cjs',
|
|
21
20
|
{
|
|
22
21
|
tsconfig: {
|
|
23
22
|
jsx: 'react-jsx',
|
|
@@ -26,6 +25,9 @@ module.exports = {
|
|
|
26
25
|
],
|
|
27
26
|
},
|
|
28
27
|
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
|
28
|
+
transformIgnorePatterns: [
|
|
29
|
+
'node_modules/(?!(@mikro-orm)/)',
|
|
30
|
+
],
|
|
29
31
|
testMatch: ['<rootDir>/src/**/__tests__/**/*.test.(ts|tsx)'],
|
|
30
32
|
passWithNoTests: true,
|
|
31
33
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2694.732417c5ec",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -234,10 +234,10 @@
|
|
|
234
234
|
"ts-pattern": "^5.0.0"
|
|
235
235
|
},
|
|
236
236
|
"peerDependencies": {
|
|
237
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
237
|
+
"@open-mercato/shared": "0.5.1-develop.2694.732417c5ec"
|
|
238
238
|
},
|
|
239
239
|
"devDependencies": {
|
|
240
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
240
|
+
"@open-mercato/shared": "0.5.1-develop.2694.732417c5ec",
|
|
241
241
|
"@testing-library/dom": "^10.4.1",
|
|
242
242
|
"@testing-library/jest-dom": "^6.9.1",
|
|
243
243
|
"@testing-library/react": "^16.3.1",
|
|
@@ -109,7 +109,7 @@ export async function createApiKey(
|
|
|
109
109
|
expiresAt: input.expiresAt ?? null,
|
|
110
110
|
createdAt: new Date(),
|
|
111
111
|
})
|
|
112
|
-
await em.
|
|
112
|
+
await em.persist(record).flush()
|
|
113
113
|
if (opts.rbac) {
|
|
114
114
|
await opts.rbac.invalidateUserCache(`api_key:${record.id}`)
|
|
115
115
|
}
|
|
@@ -124,7 +124,7 @@ export async function deleteApiKey(
|
|
|
124
124
|
const record = await em.findOne(ApiKey, { id })
|
|
125
125
|
if (!record) return
|
|
126
126
|
record.deletedAt = new Date()
|
|
127
|
-
await em.
|
|
127
|
+
await em.persist(record).flush()
|
|
128
128
|
getSharedApiKeyAuthCache().invalidateByKeyId(record.id)
|
|
129
129
|
if (opts.rbac) {
|
|
130
130
|
await opts.rbac.invalidateUserCache(`api_key:${record.id}`)
|
|
@@ -200,7 +200,7 @@ export async function createSessionApiKey(
|
|
|
200
200
|
createdAt: new Date(),
|
|
201
201
|
})
|
|
202
202
|
|
|
203
|
-
await em.
|
|
203
|
+
await em.persist(record).flush()
|
|
204
204
|
|
|
205
205
|
return {
|
|
206
206
|
keyId: record.id,
|
|
@@ -270,7 +270,7 @@ export async function deleteSessionApiKey(
|
|
|
270
270
|
if (!record) return
|
|
271
271
|
|
|
272
272
|
record.deletedAt = new Date()
|
|
273
|
-
await em.
|
|
273
|
+
await em.persist(record).flush()
|
|
274
274
|
getSharedApiKeyAuthCache().invalidateByKeyId(record.id)
|
|
275
275
|
}
|
|
276
276
|
|
|
@@ -311,7 +311,7 @@ export async function withOnetimeApiKey<T>(
|
|
|
311
311
|
} finally {
|
|
312
312
|
try {
|
|
313
313
|
record.deletedAt = new Date()
|
|
314
|
-
await em.
|
|
314
|
+
await em.persist(record).flush()
|
|
315
315
|
getSharedApiKeyAuthCache().invalidateByKeyId(record.id)
|
|
316
316
|
} catch (error) {
|
|
317
317
|
console.error('[withOnetimeApiKey] Failed to soft-delete one-time API key:', error)
|
|
@@ -239,7 +239,7 @@ export async function DELETE(req: NextRequest, ctx: RouteContext) {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
await deletePartitionFile(record.partitionCode, record.storagePath, record.storageDriver)
|
|
242
|
-
await em.
|
|
242
|
+
await em.remove(record).flush()
|
|
243
243
|
|
|
244
244
|
if (dataEngine) {
|
|
245
245
|
await emitCrudSideEffects({
|
|
@@ -4,6 +4,7 @@ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
|
4
4
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
5
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
6
6
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
7
|
+
import { sql } from 'kysely'
|
|
7
8
|
import { Attachment, AttachmentPartition } from '../../data/entities'
|
|
8
9
|
import { buildAttachmentImageUrl, slugifyAttachmentFileName } from '../../lib/imageUrls'
|
|
9
10
|
import { readAttachmentMetadata } from '../../lib/metadata'
|
|
@@ -105,7 +106,7 @@ export async function GET(req: Request) {
|
|
|
105
106
|
{},
|
|
106
107
|
{ orderBy: { title: 'asc' }, fields: ['code', 'title', 'description'] as any },
|
|
107
108
|
)
|
|
108
|
-
const [records, total, partitions] = await Promise.all([qb.getResultList(), countQb.
|
|
109
|
+
const [records, total, partitions] = await Promise.all([qb.getResultList(), countQb.getCount('a.id', true), partitionsPromise])
|
|
109
110
|
const partitionTitleByCode = partitions.reduce<Record<string, string>>((acc, entry) => {
|
|
110
111
|
if (entry.code) acc[entry.code] = entry.title ?? entry.code
|
|
111
112
|
return acc
|
|
@@ -150,19 +151,16 @@ export async function GET(req: Request) {
|
|
|
150
151
|
}))
|
|
151
152
|
: items
|
|
152
153
|
|
|
153
|
-
const totalPages = Math.max(1, Math.ceil(total / pageSize))
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
.
|
|
157
|
-
|
|
158
|
-
)
|
|
159
|
-
.from('attachments')
|
|
160
|
-
.where('tenant_id', auth.tenantId)
|
|
154
|
+
const totalPages = Math.max(1, Math.ceil(Number(total) / pageSize))
|
|
155
|
+
const db = em.getKysely<any>() as any
|
|
156
|
+
let tagQuery = db
|
|
157
|
+
.selectFrom('attachments')
|
|
158
|
+
.select(sql<string>`distinct jsonb_array_elements_text(coalesce(storage_metadata->'tags', '[]'::jsonb))`.as('tag'))
|
|
159
|
+
.where('tenant_id', '=', auth.tenantId)
|
|
161
160
|
if (auth.orgId) {
|
|
162
|
-
tagQuery.
|
|
161
|
+
tagQuery = tagQuery.where('organization_id', '=', auth.orgId)
|
|
163
162
|
}
|
|
164
|
-
tagQuery.orderBy('tag', 'asc')
|
|
165
|
-
const tagRows: Array<{ tag?: string | null }> = await tagQuery
|
|
163
|
+
const tagRows = await tagQuery.orderBy('tag', 'asc').execute() as Array<{ tag?: string | null }>
|
|
166
164
|
const availableTags = tagRows
|
|
167
165
|
.map((row) => (typeof row.tag === 'string' ? row.tag.trim() : ''))
|
|
168
166
|
.filter((tag) => tag.length > 0)
|