@open-mercato/core 0.7.1-develop.7193.1.910a5b0a1e → 0.7.1-develop.7195.1.b5efd1d51a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/AGENTS.md +4 -3
- package/agentic/standalone-guide.md +1 -1
- package/build.mjs +16 -0
- package/dist/bootstrap.js +7 -3
- package/dist/bootstrap.js.map +2 -2
- package/dist/generated/entities/action_log/index.js +2 -0
- package/dist/generated/entities/action_log/index.js.map +2 -2
- package/dist/generated/entities/user/index.js +2 -0
- package/dist/generated/entities/user/index.js.map +2 -2
- package/dist/generated/entities/user_task/index.js +14 -0
- package/dist/generated/entities/user_task/index.js.map +2 -2
- package/dist/generated/entities/workflow_definition/index.js +6 -0
- package/dist/generated/entities/workflow_definition/index.js.map +2 -2
- package/dist/generated/entities/workflow_definition_draft/index.js +25 -0
- package/dist/generated/entities/workflow_definition_draft/index.js.map +7 -0
- package/dist/generated/entities/workflow_definition_metric_rollup/index.js +23 -0
- package/dist/generated/entities/workflow_definition_metric_rollup/index.js.map +7 -0
- package/dist/generated/entities/workflow_instance/index.js +4 -0
- package/dist/generated/entities/workflow_instance/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +4 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +39 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/workflowsFixtures.js +477 -2
- package/dist/helpers/integration/workflowsFixtures.js.map +2 -2
- package/dist/helpers/integration/workflowsUi.js +148 -0
- package/dist/helpers/integration/workflowsUi.js.map +7 -0
- package/dist/modules/attachments/lib/createFromBuffer.js +79 -0
- package/dist/modules/attachments/lib/createFromBuffer.js.map +7 -0
- package/dist/modules/audit_logs/data/entities.js +5 -0
- package/dist/modules/audit_logs/data/entities.js.map +2 -2
- package/dist/modules/audit_logs/data/validators.js +1 -0
- package/dist/modules/audit_logs/data/validators.js.map +2 -2
- package/dist/modules/audit_logs/lib/projections.js +2 -1
- package/dist/modules/audit_logs/lib/projections.js.map +2 -2
- package/dist/modules/audit_logs/migrations/Migration20260625120000.js +15 -0
- package/dist/modules/audit_logs/migrations/Migration20260625120000.js.map +7 -0
- package/dist/modules/audit_logs/services/actionLogService.js +3 -0
- package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
- package/dist/modules/auth/data/entities.js +6 -0
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/lib/executionPrincipal.js +140 -0
- package/dist/modules/auth/lib/executionPrincipal.js.map +7 -0
- package/dist/modules/auth/migrations/Migration20260625050000.js +13 -0
- package/dist/modules/auth/migrations/Migration20260625050000.js.map +7 -0
- package/dist/modules/business_rules/components/InlineRuleEditor.js +154 -0
- package/dist/modules/business_rules/components/InlineRuleEditor.js.map +7 -0
- package/dist/modules/business_rules/data/validators.js +6 -0
- package/dist/modules/business_rules/data/validators.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +5 -3
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +5 -0
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/workflows.js +19 -0
- package/dist/modules/catalog/workflows.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/cli.js +80 -0
- package/dist/modules/customer_accounts/cli.js.map +7 -0
- package/dist/modules/customer_accounts/lib/customerRoleAclSync.js +59 -0
- package/dist/modules/customer_accounts/lib/customerRoleAclSync.js.map +7 -0
- package/dist/modules/customer_accounts/setup.js +4 -2
- package/dist/modules/customer_accounts/setup.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +4 -0
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/components/detail/ChangelogEntryRow.js +1 -1
- package/dist/modules/customers/components/detail/ChangelogEntryRow.js.map +2 -2
- package/dist/modules/customers/components/detail/utils.js +2 -0
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/events.js +13 -2
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/link-workflow-task-handler.js +64 -0
- package/dist/modules/customers/lib/link-workflow-task-handler.js.map +7 -0
- package/dist/modules/customers/lib/todoCompatibility.js +1 -1
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/customers/lib/workflowTaskLink.js +9 -0
- package/dist/modules/customers/lib/workflowTaskLink.js.map +7 -0
- package/dist/modules/customers/subscribers/link-workflow-task.js +12 -0
- package/dist/modules/customers/subscribers/link-workflow-task.js.map +7 -0
- package/dist/modules/customers/workflows.js +29 -0
- package/dist/modules/customers/workflows.js.map +7 -0
- package/dist/modules/entities/api/records.js +13 -33
- package/dist/modules/entities/api/records.js.map +3 -3
- package/dist/modules/entities/lib/entityClassification.js +60 -0
- package/dist/modules/entities/lib/entityClassification.js.map +7 -0
- package/dist/modules/sales/commands/documents.js +31 -0
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/events.js +12 -1
- package/dist/modules/sales/events.js.map +2 -2
- package/dist/modules/sales/workflows.js +12 -1
- package/dist/modules/sales/workflows.js.map +2 -2
- package/dist/modules/seeds/cli.js +199 -0
- package/dist/modules/seeds/cli.js.map +7 -0
- package/dist/modules/seeds/examples/sample-seed.json +26 -0
- package/dist/modules/seeds/index.js +12 -0
- package/dist/modules/seeds/index.js.map +7 -0
- package/dist/modules/workflows/acl.js +96 -0
- package/dist/modules/workflows/acl.js.map +2 -2
- package/dist/modules/workflows/ai-agents.js +50 -0
- package/dist/modules/workflows/ai-agents.js.map +7 -0
- package/dist/modules/workflows/ai-tools/authoring-pack.js +582 -0
- package/dist/modules/workflows/ai-tools/authoring-pack.js.map +7 -0
- package/dist/modules/workflows/ai-tools/types.js +43 -0
- package/dist/modules/workflows/ai-tools/types.js.map +7 -0
- package/dist/modules/workflows/ai-tools.js +10 -0
- package/dist/modules/workflows/ai-tools.js.map +7 -0
- package/dist/modules/workflows/api/command-settings/route.js +137 -0
- package/dist/modules/workflows/api/command-settings/route.js.map +7 -0
- package/dist/modules/workflows/api/commands/route.js +72 -0
- package/dist/modules/workflows/api/commands/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/callers/route.js +76 -0
- package/dist/modules/workflows/api/definitions/[id]/callers/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/context-schema/route.js +134 -0
- package/dist/modules/workflows/api/definitions/[id]/context-schema/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js +5 -1
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/draft/route.js +286 -0
- package/dist/modules/workflows/api/definitions/[id]/draft/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/publish/route.js +207 -0
- package/dist/modules/workflows/api/definitions/[id]/publish/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js +5 -0
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +93 -9
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +3 -3
- package/dist/modules/workflows/api/definitions/[id]/test-step/route.js +210 -0
- package/dist/modules/workflows/api/definitions/[id]/test-step/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/generate/route.js +233 -0
- package/dist/modules/workflows/api/definitions/generate/route.js.map +7 -0
- package/dist/modules/workflows/api/definitions/route.js +61 -113
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/serialize.js +9 -0
- package/dist/modules/workflows/api/definitions/serialize.js.map +2 -2
- package/dist/modules/workflows/api/endpoints/route.js +69 -0
- package/dist/modules/workflows/api/endpoints/route.js.map +7 -0
- package/dist/modules/workflows/api/functions/route.js +73 -0
- package/dist/modules/workflows/api/functions/route.js.map +7 -0
- package/dist/modules/workflows/api/grantable-features/route.js +75 -0
- package/dist/modules/workflows/api/grantable-features/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/[id]/context/route.js +180 -0
- package/dist/modules/workflows/api/instances/[id]/context/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/[id]/rerun-step/route.js +184 -0
- package/dist/modules/workflows/api/instances/[id]/rerun-step/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/[id]/retry/route.js +12 -2
- package/dist/modules/workflows/api/instances/[id]/retry/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/step-through/route.js +148 -0
- package/dist/modules/workflows/api/instances/[id]/step-through/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/[id]/steps/route.js +123 -0
- package/dist/modules/workflows/api/instances/[id]/steps/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/[id]/would-do/route.js +172 -0
- package/dist/modules/workflows/api/instances/[id]/would-do/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/bulk-replay/route.js +117 -0
- package/dist/modules/workflows/api/instances/bulk-replay/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/failure-queue/route.js +165 -0
- package/dist/modules/workflows/api/instances/failure-queue/route.js.map +7 -0
- package/dist/modules/workflows/api/instances/route.js +94 -3
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/metrics/definitions/route.js +188 -0
- package/dist/modules/workflows/api/metrics/definitions/route.js.map +7 -0
- package/dist/modules/workflows/api/openapi.js +415 -4
- package/dist/modules/workflows/api/openapi.js.map +2 -2
- package/dist/modules/workflows/api/portal/tasks/[id]/complete/route.js +132 -0
- package/dist/modules/workflows/api/portal/tasks/[id]/complete/route.js.map +7 -0
- package/dist/modules/workflows/api/portal/tasks/[id]/route.js +97 -0
- package/dist/modules/workflows/api/portal/tasks/[id]/route.js.map +7 -0
- package/dist/modules/workflows/api/portal/tasks/route.js +126 -0
- package/dist/modules/workflows/api/portal/tasks/route.js.map +7 -0
- package/dist/modules/workflows/api/rule-usage/route.js +80 -0
- package/dist/modules/workflows/api/rule-usage/route.js.map +7 -0
- package/dist/modules/workflows/api/task-settings/route.js +107 -0
- package/dist/modules/workflows/api/task-settings/route.js.map +7 -0
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js +27 -16
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js +40 -16
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/reassign/route.js +150 -0
- package/dist/modules/workflows/api/tasks/[id]/reassign/route.js.map +7 -0
- package/dist/modules/workflows/api/tasks/[id]/route.js +39 -6
- package/dist/modules/workflows/api/tasks/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/unclaim/route.js +100 -0
- package/dist/modules/workflows/api/tasks/[id]/unclaim/route.js.map +7 -0
- package/dist/modules/workflows/api/tasks/route.js +37 -6
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/serialize.js +83 -0
- package/dist/modules/workflows/api/tasks/serialize.js.map +7 -0
- package/dist/modules/workflows/api/templates/route.js +69 -0
- package/dist/modules/workflows/api/templates/route.js.map +7 -0
- package/dist/modules/workflows/api/work-inbox/next/route.js +129 -0
- package/dist/modules/workflows/api/work-inbox/next/route.js.map +7 -0
- package/dist/modules/workflows/api/work-inbox/route.js +119 -0
- package/dist/modules/workflows/api/work-inbox/route.js.map +7 -0
- package/dist/modules/workflows/backend/config/workflows/page.js +10 -0
- package/dist/modules/workflows/backend/config/workflows/page.js.map +7 -0
- package/dist/modules/workflows/backend/config/workflows/page.meta.js +35 -0
- package/dist/modules/workflows/backend/config/workflows/page.meta.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/[id]/page.js +6 -271
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +3 -3
- package/dist/modules/workflows/backend/definitions/create/page.js +7 -56
- package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +131 -51
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +2606 -677
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +3 -3
- package/dist/modules/workflows/backend/instances/[id]/page.js +532 -421
- package/dist/modules/workflows/backend/instances/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js +1 -1
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +1 -1
- package/dist/modules/workflows/backend/instances/failure-queue/page.js +211 -0
- package/dist/modules/workflows/backend/instances/failure-queue/page.js.map +7 -0
- package/dist/modules/workflows/backend/instances/failure-queue/page.meta.js +20 -0
- package/dist/modules/workflows/backend/instances/failure-queue/page.meta.js.map +7 -0
- package/dist/modules/workflows/backend/instances/page.js +159 -22
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.meta.js +1 -1
- package/dist/modules/workflows/backend/instances/page.meta.js.map +1 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js +553 -392
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +3 -3
- package/dist/modules/workflows/backend/tasks/page.js +8 -250
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.meta.js +1 -0
- package/dist/modules/workflows/backend/tasks/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/work-inbox/page.js +399 -0
- package/dist/modules/workflows/backend/work-inbox/page.js.map +7 -0
- package/dist/modules/workflows/backend/work-inbox/page.meta.js +19 -0
- package/dist/modules/workflows/backend/work-inbox/page.meta.js.map +7 -0
- package/dist/modules/workflows/cli.js +1 -1
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/commands/tasks.js +81 -0
- package/dist/modules/workflows/commands/tasks.js.map +7 -0
- package/dist/modules/workflows/components/ActivitiesEditor.js +281 -287
- package/dist/modules/workflows/components/ActivitiesEditor.js.map +2 -2
- package/dist/modules/workflows/components/ActivityEditDialog.js +220 -0
- package/dist/modules/workflows/components/ActivityEditDialog.js.map +7 -0
- package/dist/modules/workflows/components/AgentSelector.js +115 -0
- package/dist/modules/workflows/components/AgentSelector.js.map +7 -0
- package/dist/modules/workflows/components/AnnotationEditDialog.js +110 -0
- package/dist/modules/workflows/components/AnnotationEditDialog.js.map +7 -0
- package/dist/modules/workflows/components/BusinessRuleUsagePanel.js +71 -0
- package/dist/modules/workflows/components/BusinessRuleUsagePanel.js.map +7 -0
- package/dist/modules/workflows/components/BusinessRulesSelector.js +151 -93
- package/dist/modules/workflows/components/BusinessRulesSelector.js.map +2 -2
- package/dist/modules/workflows/components/ConfigJsonTextarea.js +85 -0
- package/dist/modules/workflows/components/ConfigJsonTextarea.js.map +7 -0
- package/dist/modules/workflows/components/ContextSchemaEditor.js +150 -0
- package/dist/modules/workflows/components/ContextSchemaEditor.js.map +7 -0
- package/dist/modules/workflows/components/DefinitionErrorHandlerField.js +102 -0
- package/dist/modules/workflows/components/DefinitionErrorHandlerField.js.map +7 -0
- package/dist/modules/workflows/components/DefinitionMetadataDrawer.js +377 -0
- package/dist/modules/workflows/components/DefinitionMetadataDrawer.js.map +7 -0
- package/dist/modules/workflows/components/DefinitionMetricsCells.js +132 -0
- package/dist/modules/workflows/components/DefinitionMetricsCells.js.map +7 -0
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +307 -216
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/components/EdgeEditDialog.js +11 -18
- package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js +112 -72
- package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js.map +2 -2
- package/dist/modules/workflows/components/InputDataPanel.js +128 -0
- package/dist/modules/workflows/components/InputDataPanel.js.map +7 -0
- package/dist/modules/workflows/components/InspectorPanel.js +161 -0
- package/dist/modules/workflows/components/InspectorPanel.js.map +7 -0
- package/dist/modules/workflows/components/NodeEditDialog.js +363 -41
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js +714 -159
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +2 -2
- package/dist/modules/workflows/components/StepsEditor.js.map +2 -2
- package/dist/modules/workflows/components/TemplateGalleryDialog.js +148 -0
- package/dist/modules/workflows/components/TemplateGalleryDialog.js.map +7 -0
- package/dist/modules/workflows/components/TransitionsEditor.js +80 -74
- package/dist/modules/workflows/components/TransitionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/TriggersDialog.js +53 -0
- package/dist/modules/workflows/components/TriggersDialog.js.map +7 -0
- package/dist/modules/workflows/components/TriggersEditor.js +331 -0
- package/dist/modules/workflows/components/TriggersEditor.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowAiDraftDialog.js +278 -0
- package/dist/modules/workflows/components/WorkflowAiDraftDialog.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowCodeView.js +173 -0
- package/dist/modules/workflows/components/WorkflowCodeView.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowCommandPalette.js +62 -0
- package/dist/modules/workflows/components/WorkflowCommandPalette.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowCompensationGhostEdge.js +70 -0
- package/dist/modules/workflows/components/WorkflowCompensationGhostEdge.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowDataMappingEdge.js +36 -0
- package/dist/modules/workflows/components/WorkflowDataMappingEdge.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowGraph.js +4 -2
- package/dist/modules/workflows/components/WorkflowGraph.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js +324 -86
- package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +3 -3
- package/dist/modules/workflows/components/WorkflowIconPicker.js +109 -0
- package/dist/modules/workflows/components/WorkflowIconPicker.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowLegend.js +45 -29
- package/dist/modules/workflows/components/WorkflowLegend.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowNodeCard.js +221 -22
- package/dist/modules/workflows/components/WorkflowNodeCard.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowRouteChips.js +111 -0
- package/dist/modules/workflows/components/WorkflowRouteChips.js.map +7 -0
- package/dist/modules/workflows/components/WorkflowSelector.js +108 -88
- package/dist/modules/workflows/components/WorkflowSelector.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowTransitionEdge.js +61 -11
- package/dist/modules/workflows/components/WorkflowTransitionEdge.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowTransitionLabel.js +15 -5
- package/dist/modules/workflows/components/WorkflowTransitionLabel.js.map +2 -2
- package/dist/modules/workflows/components/fields/ActivityArrayEditor.js +88 -21
- package/dist/modules/workflows/components/fields/ActivityArrayEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/ActivityConfigFields.js +615 -0
- package/dist/modules/workflows/components/fields/ActivityConfigFields.js.map +7 -0
- package/dist/modules/workflows/components/fields/ActivityTestPanel.js +191 -0
- package/dist/modules/workflows/components/fields/ActivityTestPanel.js.map +7 -0
- package/dist/modules/workflows/components/fields/AgentInvokeConfigField.js +488 -0
- package/dist/modules/workflows/components/fields/AgentInvokeConfigField.js.map +7 -0
- package/dist/modules/workflows/components/fields/AgentReviewOnBreachField.js +61 -0
- package/dist/modules/workflows/components/fields/AgentReviewOnBreachField.js.map +7 -0
- package/dist/modules/workflows/components/fields/BranchingRoutesEditor.js +227 -0
- package/dist/modules/workflows/components/fields/BranchingRoutesEditor.js.map +7 -0
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +37 -4
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/CommandPicker.js +111 -0
- package/dist/modules/workflows/components/fields/CommandPicker.js.map +7 -0
- package/dist/modules/workflows/components/fields/EndpointPicker.js +235 -0
- package/dist/modules/workflows/components/fields/EndpointPicker.js.map +7 -0
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +2 -2
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/FunctionPicker.js +55 -0
- package/dist/modules/workflows/components/fields/FunctionPicker.js.map +7 -0
- package/dist/modules/workflows/components/fields/MappingArrayEditor.js +38 -15
- package/dist/modules/workflows/components/fields/MappingArrayEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/PortFieldArrayEditor.js +206 -0
- package/dist/modules/workflows/components/fields/PortFieldArrayEditor.js.map +7 -0
- package/dist/modules/workflows/components/fields/RolesMultiSelect.js +53 -0
- package/dist/modules/workflows/components/fields/RolesMultiSelect.js.map +7 -0
- package/dist/modules/workflows/components/fields/RouteOrderEditor.js +130 -0
- package/dist/modules/workflows/components/fields/RouteOrderEditor.js.map +7 -0
- package/dist/modules/workflows/components/fields/SchemaBuilderDialog.js +104 -0
- package/dist/modules/workflows/components/fields/SchemaBuilderDialog.js.map +7 -0
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +2 -2
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/TaskAssignmentField.js +210 -0
- package/dist/modules/workflows/components/fields/TaskAssignmentField.js.map +7 -0
- package/dist/modules/workflows/components/fields/TaskDeadlineFields.js +126 -0
- package/dist/modules/workflows/components/fields/TaskDeadlineFields.js.map +7 -0
- package/dist/modules/workflows/components/fields/TaskDecisionsField.js +218 -0
- package/dist/modules/workflows/components/fields/TaskDecisionsField.js.map +7 -0
- package/dist/modules/workflows/components/fields/TaskEntityBindingsField.js +114 -0
- package/dist/modules/workflows/components/fields/TaskEntityBindingsField.js.map +7 -0
- package/dist/modules/workflows/components/fields/TemplateTextControl.js +64 -0
- package/dist/modules/workflows/components/fields/TemplateTextControl.js.map +7 -0
- package/dist/modules/workflows/components/fields/VariablePickerButton.js +121 -0
- package/dist/modules/workflows/components/fields/VariablePickerButton.js.map +7 -0
- package/dist/modules/workflows/components/fields/ledgerDropTarget.js +35 -0
- package/dist/modules/workflows/components/fields/ledgerDropTarget.js.map +7 -0
- package/dist/modules/workflows/components/fields/useActivityTypeOptions.js +16 -0
- package/dist/modules/workflows/components/fields/useActivityTypeOptions.js.map +7 -0
- package/dist/modules/workflows/components/formConfig.js +39 -10
- package/dist/modules/workflows/components/formConfig.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileDefinitionDetail.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileMetadataSheet.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileTaskForm.js +29 -2
- package/dist/modules/workflows/components/mobile/MobileTaskForm.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileVisualEditor.js +64 -65
- package/dist/modules/workflows/components/mobile/MobileVisualEditor.js.map +2 -2
- package/dist/modules/workflows/components/nodes/AnnotationGroupNode.js +64 -0
- package/dist/modules/workflows/components/nodes/AnnotationGroupNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/AutomatedNode.js +24 -16
- package/dist/modules/workflows/components/nodes/AutomatedNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/EndNode.js +13 -12
- package/dist/modules/workflows/components/nodes/EndNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/ErrorOutputHandle.js +29 -0
- package/dist/modules/workflows/components/nodes/ErrorOutputHandle.js.map +7 -0
- package/dist/modules/workflows/components/nodes/IfElseNode.js +51 -0
- package/dist/modules/workflows/components/nodes/IfElseNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/InvokeAgentNode.js +122 -0
- package/dist/modules/workflows/components/nodes/InvokeAgentNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/NodeOutcomeRows.js +100 -0
- package/dist/modules/workflows/components/nodes/NodeOutcomeRows.js.map +7 -0
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js +18 -14
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js +18 -14
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/StartNode.js +66 -15
- package/dist/modules/workflows/components/nodes/StartNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/StickyNoteNode.js +54 -0
- package/dist/modules/workflows/components/nodes/StickyNoteNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/SubWorkflowNode.js +107 -41
- package/dist/modules/workflows/components/nodes/SubWorkflowNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/SwitchNode.js +51 -0
- package/dist/modules/workflows/components/nodes/SwitchNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/TriggerCap.js +65 -0
- package/dist/modules/workflows/components/nodes/TriggerCap.js.map +7 -0
- package/dist/modules/workflows/components/nodes/TriggerNode.js +111 -0
- package/dist/modules/workflows/components/nodes/TriggerNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/UserTaskNode.js +43 -17
- package/dist/modules/workflows/components/nodes/UserTaskNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/WaitForConditionNode.js +53 -0
- package/dist/modules/workflows/components/nodes/WaitForConditionNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/WaitForSignalNode.js +21 -15
- package/dist/modules/workflows/components/nodes/WaitForSignalNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/WaitForTimerNode.js +21 -15
- package/dist/modules/workflows/components/nodes/WaitForTimerNode.js.map +2 -2
- package/dist/modules/workflows/components/nodes/index.js +14 -0
- package/dist/modules/workflows/components/nodes/index.js.map +2 -2
- package/dist/modules/workflows/components/portal/PortalTaskForm.js +196 -0
- package/dist/modules/workflows/components/portal/PortalTaskForm.js.map +7 -0
- package/dist/modules/workflows/components/run/AgentActivityPanel.js +22 -0
- package/dist/modules/workflows/components/run/AgentActivityPanel.js.map +7 -0
- package/dist/modules/workflows/components/run/RerunStepDialog.js +106 -0
- package/dist/modules/workflows/components/run/RerunStepDialog.js.map +7 -0
- package/dist/modules/workflows/components/run/RunEventBadge.js +30 -0
- package/dist/modules/workflows/components/run/RunEventBadge.js.map +7 -0
- package/dist/modules/workflows/components/run/RunGantt.js +130 -0
- package/dist/modules/workflows/components/run/RunGantt.js.map +7 -0
- package/dist/modules/workflows/components/run/RunStatusBadge.js +82 -0
- package/dist/modules/workflows/components/run/RunStatusBadge.js.map +7 -0
- package/dist/modules/workflows/components/run/RunStepInspector.js +116 -0
- package/dist/modules/workflows/components/run/RunStepInspector.js.map +7 -0
- package/dist/modules/workflows/components/run/WouldDoReport.js +52 -0
- package/dist/modules/workflows/components/run/WouldDoReport.js.map +7 -0
- package/dist/modules/workflows/components/run/useAgentLabels.js +28 -0
- package/dist/modules/workflows/components/run/useAgentLabels.js.map +7 -0
- package/dist/modules/workflows/components/run/useLastRunOverlay.js +89 -0
- package/dist/modules/workflows/components/run/useLastRunOverlay.js.map +7 -0
- package/dist/modules/workflows/components/run/useLiveAgentActions.js +41 -0
- package/dist/modules/workflows/components/run/useLiveAgentActions.js.map +7 -0
- package/dist/modules/workflows/components/run/useLiveRunUpdates.js +57 -0
- package/dist/modules/workflows/components/run/useLiveRunUpdates.js.map +7 -0
- package/dist/modules/workflows/components/settings/CommandSettingsPageClient.js +156 -0
- package/dist/modules/workflows/components/settings/CommandSettingsPageClient.js.map +7 -0
- package/dist/modules/workflows/components/work-inbox/EntityContextPanel.js +72 -0
- package/dist/modules/workflows/components/work-inbox/EntityContextPanel.js.map +7 -0
- package/dist/modules/workflows/components/work-inbox/ReassignTaskDialog.js +156 -0
- package/dist/modules/workflows/components/work-inbox/ReassignTaskDialog.js.map +7 -0
- package/dist/modules/workflows/components/work-inbox/StatusChip.js +46 -0
- package/dist/modules/workflows/components/work-inbox/StatusChip.js.map +7 -0
- package/dist/modules/workflows/components/work-inbox/TaskActionNotice.js +53 -0
- package/dist/modules/workflows/components/work-inbox/TaskActionNotice.js.map +7 -0
- package/dist/modules/workflows/components/work-inbox/TaskFormFields.js +261 -0
- package/dist/modules/workflows/components/work-inbox/TaskFormFields.js.map +7 -0
- package/dist/modules/workflows/components/work-inbox/WorkInboxEmptyState.js +27 -0
- package/dist/modules/workflows/components/work-inbox/WorkInboxEmptyState.js.map +7 -0
- package/dist/modules/workflows/data/activity-config-schemas.js +191 -0
- package/dist/modules/workflows/data/activity-config-schemas.js.map +7 -0
- package/dist/modules/workflows/data/activity-config-warnings.js +42 -0
- package/dist/modules/workflows/data/activity-config-warnings.js.map +7 -0
- package/dist/modules/workflows/data/branching-route-warnings.js +65 -0
- package/dist/modules/workflows/data/branching-route-warnings.js.map +7 -0
- package/dist/modules/workflows/data/entities.js +144 -4
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/metrics-validators.js +35 -0
- package/dist/modules/workflows/data/metrics-validators.js.map +7 -0
- package/dist/modules/workflows/data/task-primitives.js +14 -0
- package/dist/modules/workflows/data/task-primitives.js.map +7 -0
- package/dist/modules/workflows/data/validators.js +504 -61
- package/dist/modules/workflows/data/validators.js.map +3 -3
- package/dist/modules/workflows/di.js +16 -1
- package/dist/modules/workflows/di.js.map +2 -2
- package/dist/modules/workflows/events.js +66 -8
- package/dist/modules/workflows/events.js.map +2 -2
- package/dist/modules/workflows/examples/oze-residential-install-60-nodes.json +1545 -0
- package/dist/modules/workflows/examples/sales-pipeline-definition.json +35 -35
- package/dist/modules/workflows/examples/templates/lead-to-install.json +160 -0
- package/dist/modules/workflows/examples/templates/order-approval.json +230 -0
- package/dist/modules/workflows/examples/templates/task-escalation.json +110 -0
- package/dist/modules/workflows/examples/templates/webhook-integration.json +113 -0
- package/dist/modules/workflows/extension-points.js +1 -1
- package/dist/modules/workflows/extension-points.js.map +2 -2
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.js +144 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.js.map +7 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.meta.js +12 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.meta.js.map +7 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/page.js +114 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/page.js.map +7 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/page.meta.js +18 -0
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/page.meta.js.map +7 -0
- package/dist/modules/workflows/lib/activity-executor.js +505 -137
- package/dist/modules/workflows/lib/activity-executor.js.map +3 -3
- package/dist/modules/workflows/lib/activity-queue-types.js +3 -1
- package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
- package/dist/modules/workflows/lib/activity-registry-bootstrap.js +2 -0
- package/dist/modules/workflows/lib/activity-registry-bootstrap.js.map +7 -0
- package/dist/modules/workflows/lib/activity-registry.js +27 -0
- package/dist/modules/workflows/lib/activity-registry.js.map +7 -0
- package/dist/modules/workflows/lib/activity-types.js +291 -0
- package/dist/modules/workflows/lib/activity-types.js.map +7 -0
- package/dist/modules/workflows/lib/activity-worker-handler.js +456 -32
- package/dist/modules/workflows/lib/activity-worker-handler.js.map +3 -3
- package/dist/modules/workflows/lib/advanced-config.js +31 -0
- package/dist/modules/workflows/lib/advanced-config.js.map +7 -0
- package/dist/modules/workflows/lib/agent-disposition-task.js +198 -0
- package/dist/modules/workflows/lib/agent-disposition-task.js.map +7 -0
- package/dist/modules/workflows/lib/agent-outcome-paths.js +82 -0
- package/dist/modules/workflows/lib/agent-outcome-paths.js.map +7 -0
- package/dist/modules/workflows/lib/agent-result-mapping.js +54 -0
- package/dist/modules/workflows/lib/agent-result-mapping.js.map +7 -0
- package/dist/modules/workflows/lib/agent-review-inspector.js +61 -0
- package/dist/modules/workflows/lib/agent-review-inspector.js.map +7 -0
- package/dist/modules/workflows/lib/agent-review.js +66 -0
- package/dist/modules/workflows/lib/agent-review.js.map +7 -0
- package/dist/modules/workflows/lib/ai-authoring.js +155 -0
- package/dist/modules/workflows/lib/ai-authoring.js.map +7 -0
- package/dist/modules/workflows/lib/ai-draft-runner.js +43 -0
- package/dist/modules/workflows/lib/ai-draft-runner.js.map +7 -0
- package/dist/modules/workflows/lib/annotation-events.js +10 -0
- package/dist/modules/workflows/lib/annotation-events.js.map +7 -0
- package/dist/modules/workflows/lib/branching-routes.js +182 -0
- package/dist/modules/workflows/lib/branching-routes.js.map +7 -0
- package/dist/modules/workflows/lib/breach-routing.js +50 -0
- package/dist/modules/workflows/lib/breach-routing.js.map +7 -0
- package/dist/modules/workflows/lib/bulk-replay.js +101 -0
- package/dist/modules/workflows/lib/bulk-replay.js.map +7 -0
- package/dist/modules/workflows/lib/business-rule-usage.js +91 -0
- package/dist/modules/workflows/lib/business-rule-usage.js.map +7 -0
- package/dist/modules/workflows/lib/caller-graph.js +53 -0
- package/dist/modules/workflows/lib/caller-graph.js.map +7 -0
- package/dist/modules/workflows/lib/code-view-apply.js +86 -0
- package/dist/modules/workflows/lib/code-view-apply.js.map +7 -0
- package/dist/modules/workflows/lib/collect-validation-issues.js +164 -0
- package/dist/modules/workflows/lib/collect-validation-issues.js.map +7 -0
- package/dist/modules/workflows/lib/compensation-ghosts.js +72 -0
- package/dist/modules/workflows/lib/compensation-ghosts.js.map +7 -0
- package/dist/modules/workflows/lib/component-guard.js +7 -0
- package/dist/modules/workflows/lib/component-guard.js.map +7 -0
- package/dist/modules/workflows/lib/condition-handler.js +443 -0
- package/dist/modules/workflows/lib/condition-handler.js.map +7 -0
- package/dist/modules/workflows/lib/context-ledger.js +448 -0
- package/dist/modules/workflows/lib/context-ledger.js.map +7 -0
- package/dist/modules/workflows/lib/crud-form-dialogs-flag.js +8 -0
- package/dist/modules/workflows/lib/crud-form-dialogs-flag.js.map +7 -0
- package/dist/modules/workflows/lib/data-edge-mapping.js +63 -0
- package/dist/modules/workflows/lib/data-edge-mapping.js.map +7 -0
- package/dist/modules/workflows/lib/definition-context-schema.js +56 -0
- package/dist/modules/workflows/lib/definition-context-schema.js.map +7 -0
- package/dist/modules/workflows/lib/definition-edit-safety.js +123 -0
- package/dist/modules/workflows/lib/definition-edit-safety.js.map +7 -0
- package/dist/modules/workflows/lib/definition-error-body.js +33 -0
- package/dist/modules/workflows/lib/definition-error-body.js.map +7 -0
- package/dist/modules/workflows/lib/definition-evaluation.js +79 -0
- package/dist/modules/workflows/lib/definition-evaluation.js.map +7 -0
- package/dist/modules/workflows/lib/definition-grant.js +90 -0
- package/dist/modules/workflows/lib/definition-grant.js.map +7 -0
- package/dist/modules/workflows/lib/definition-json-locations.js +139 -0
- package/dist/modules/workflows/lib/definition-json-locations.js.map +7 -0
- package/dist/modules/workflows/lib/definition-payload.js +31 -0
- package/dist/modules/workflows/lib/definition-payload.js.map +7 -0
- package/dist/modules/workflows/lib/draft-restore.js +49 -0
- package/dist/modules/workflows/lib/draft-restore.js.map +7 -0
- package/dist/modules/workflows/lib/dry-run.js +106 -0
- package/dist/modules/workflows/lib/dry-run.js.map +7 -0
- package/dist/modules/workflows/lib/duration.js +66 -17
- package/dist/modules/workflows/lib/duration.js.map +2 -2
- package/dist/modules/workflows/lib/edge-reattachment.js +79 -0
- package/dist/modules/workflows/lib/edge-reattachment.js.map +7 -0
- package/dist/modules/workflows/lib/edgeFormTransforms.js +7 -11
- package/dist/modules/workflows/lib/edgeFormTransforms.js.map +2 -2
- package/dist/modules/workflows/lib/editor-annotations.js +195 -0
- package/dist/modules/workflows/lib/editor-annotations.js.map +7 -0
- package/dist/modules/workflows/lib/editor-commands.js +103 -0
- package/dist/modules/workflows/lib/editor-commands.js.map +7 -0
- package/dist/modules/workflows/lib/editor-history.js +51 -0
- package/dist/modules/workflows/lib/editor-history.js.map +7 -0
- package/dist/modules/workflows/lib/endpoint-catalog.js +181 -0
- package/dist/modules/workflows/lib/endpoint-catalog.js.map +7 -0
- package/dist/modules/workflows/lib/endpoint-path.js +90 -0
- package/dist/modules/workflows/lib/endpoint-path.js.map +7 -0
- package/dist/modules/workflows/lib/engine-version.js +42 -0
- package/dist/modules/workflows/lib/engine-version.js.map +7 -0
- package/dist/modules/workflows/lib/error-handler.js +132 -0
- package/dist/modules/workflows/lib/error-handler.js.map +7 -0
- package/dist/modules/workflows/lib/error-routing.js +104 -0
- package/dist/modules/workflows/lib/error-routing.js.map +7 -0
- package/dist/modules/workflows/lib/event-logger.js +23 -0
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/expression-refs.js +168 -0
- package/dist/modules/workflows/lib/expression-refs.js.map +7 -0
- package/dist/modules/workflows/lib/failure-grouping.js +62 -0
- package/dist/modules/workflows/lib/failure-grouping.js.map +7 -0
- package/dist/modules/workflows/lib/find-definition.js +1 -0
- package/dist/modules/workflows/lib/find-definition.js.map +2 -2
- package/dist/modules/workflows/lib/flow-logic-warnings.js +338 -0
- package/dist/modules/workflows/lib/flow-logic-warnings.js.map +7 -0
- package/dist/modules/workflows/lib/graph-utils.js +328 -77
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/dist/modules/workflows/lib/icon-search.js +32 -0
- package/dist/modules/workflows/lib/icon-search.js.map +7 -0
- package/dist/modules/workflows/lib/insert-at-cursor.js +26 -0
- package/dist/modules/workflows/lib/insert-at-cursor.js.map +7 -0
- package/dist/modules/workflows/lib/instance-date-filter.js +28 -0
- package/dist/modules/workflows/lib/instance-date-filter.js.map +7 -0
- package/dist/modules/workflows/lib/interpolation-pipeline.js +271 -0
- package/dist/modules/workflows/lib/interpolation-pipeline.js.map +7 -0
- package/dist/modules/workflows/lib/ledger-drag.js +28 -0
- package/dist/modules/workflows/lib/ledger-drag.js.map +7 -0
- package/dist/modules/workflows/lib/ledger-entry-display.js +66 -0
- package/dist/modules/workflows/lib/ledger-entry-display.js.map +7 -0
- package/dist/modules/workflows/lib/ledger-schema-flatten.js +82 -0
- package/dist/modules/workflows/lib/ledger-schema-flatten.js.map +7 -0
- package/dist/modules/workflows/lib/metrics/definition-metrics.js +110 -0
- package/dist/modules/workflows/lib/metrics/definition-metrics.js.map +7 -0
- package/dist/modules/workflows/lib/metrics/metrics-display.js +26 -0
- package/dist/modules/workflows/lib/metrics/metrics-display.js.map +7 -0
- package/dist/modules/workflows/lib/metrics/rollup-schedule.js +7 -0
- package/dist/modules/workflows/lib/metrics/rollup-schedule.js.map +7 -0
- package/dist/modules/workflows/lib/metrics/rollup-service.js +160 -0
- package/dist/modules/workflows/lib/metrics/rollup-service.js.map +7 -0
- package/dist/modules/workflows/lib/node-config-summary.js +128 -0
- package/dist/modules/workflows/lib/node-config-summary.js.map +7 -0
- package/dist/modules/workflows/lib/node-geometry.js +53 -0
- package/dist/modules/workflows/lib/node-geometry.js.map +7 -0
- package/dist/modules/workflows/lib/node-nudge.js +44 -0
- package/dist/modules/workflows/lib/node-nudge.js.map +7 -0
- package/dist/modules/workflows/lib/node-outcome-rows.js +88 -0
- package/dist/modules/workflows/lib/node-outcome-rows.js.map +7 -0
- package/dist/modules/workflows/lib/node-placement.js +55 -0
- package/dist/modules/workflows/lib/node-placement.js.map +7 -0
- package/dist/modules/workflows/lib/node-type-icons.js +54 -13
- package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
- package/dist/modules/workflows/lib/nodeFormTransforms.js +329 -19
- package/dist/modules/workflows/lib/nodeFormTransforms.js.map +2 -2
- package/dist/modules/workflows/lib/outcome-routing.js +158 -0
- package/dist/modules/workflows/lib/outcome-routing.js.map +7 -0
- package/dist/modules/workflows/lib/owned-definition.js +107 -0
- package/dist/modules/workflows/lib/owned-definition.js.map +7 -0
- package/dist/modules/workflows/lib/owned-node-changes.js +10 -0
- package/dist/modules/workflows/lib/owned-node-changes.js.map +7 -0
- package/dist/modules/workflows/lib/palette-drag.js +36 -0
- package/dist/modules/workflows/lib/palette-drag.js.map +7 -0
- package/dist/modules/workflows/lib/palette-drop.js +45 -0
- package/dist/modules/workflows/lib/palette-drop.js.map +7 -0
- package/dist/modules/workflows/lib/parallel-handler.js +57 -2
- package/dist/modules/workflows/lib/parallel-handler.js.map +2 -2
- package/dist/modules/workflows/lib/port-contract.js +54 -0
- package/dist/modules/workflows/lib/port-contract.js.map +7 -0
- package/dist/modules/workflows/lib/portal-task-access.js +89 -0
- package/dist/modules/workflows/lib/portal-task-access.js.map +7 -0
- package/dist/modules/workflows/lib/rerun-from-step.js +65 -0
- package/dist/modules/workflows/lib/rerun-from-step.js.map +7 -0
- package/dist/modules/workflows/lib/route-chip-events.js +23 -0
- package/dist/modules/workflows/lib/route-chip-events.js.map +7 -0
- package/dist/modules/workflows/lib/route-chips.js +91 -0
- package/dist/modules/workflows/lib/route-chips.js.map +7 -0
- package/dist/modules/workflows/lib/route-edge.js +17 -0
- package/dist/modules/workflows/lib/route-edge.js.map +7 -0
- package/dist/modules/workflows/lib/route-kinds.js +67 -0
- package/dist/modules/workflows/lib/route-kinds.js.map +7 -0
- package/dist/modules/workflows/lib/route-priority.js +104 -0
- package/dist/modules/workflows/lib/route-priority.js.map +7 -0
- package/dist/modules/workflows/lib/run-duration.js +44 -0
- package/dist/modules/workflows/lib/run-duration.js.map +7 -0
- package/dist/modules/workflows/lib/run-event-tone.js +25 -0
- package/dist/modules/workflows/lib/run-event-tone.js.map +7 -0
- package/dist/modules/workflows/lib/run-execution.js +305 -0
- package/dist/modules/workflows/lib/run-execution.js.map +7 -0
- package/dist/modules/workflows/lib/run-gantt.js +180 -0
- package/dist/modules/workflows/lib/run-gantt.js.map +7 -0
- package/dist/modules/workflows/lib/run-outcome-evidence.js +33 -0
- package/dist/modules/workflows/lib/run-outcome-evidence.js.map +7 -0
- package/dist/modules/workflows/lib/run-outcome.js +48 -0
- package/dist/modules/workflows/lib/run-outcome.js.map +7 -0
- package/dist/modules/workflows/lib/sample-resolver.js +71 -0
- package/dist/modules/workflows/lib/sample-resolver.js.map +7 -0
- package/dist/modules/workflows/lib/seeds.js +1 -1
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/server-output-contract.js +65 -0
- package/dist/modules/workflows/lib/server-output-contract.js.map +7 -0
- package/dist/modules/workflows/lib/set-variable.js +47 -0
- package/dist/modules/workflows/lib/set-variable.js.map +7 -0
- package/dist/modules/workflows/lib/signal-handler.js +63 -4
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/start-fixtures.js +42 -0
- package/dist/modules/workflows/lib/start-fixtures.js.map +7 -0
- package/dist/modules/workflows/lib/status-colors.js +153 -22
- package/dist/modules/workflows/lib/status-colors.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +529 -53
- package/dist/modules/workflows/lib/step-handler.js.map +3 -3
- package/dist/modules/workflows/lib/step-presentation.js +147 -0
- package/dist/modules/workflows/lib/step-presentation.js.map +7 -0
- package/dist/modules/workflows/lib/step-through.js +26 -0
- package/dist/modules/workflows/lib/step-through.js.map +7 -0
- package/dist/modules/workflows/lib/step-type-conversion.js +167 -0
- package/dist/modules/workflows/lib/step-type-conversion.js.map +7 -0
- package/dist/modules/workflows/lib/subgraph-clipboard.js +114 -0
- package/dist/modules/workflows/lib/subgraph-clipboard.js.map +7 -0
- package/dist/modules/workflows/lib/task-decision-context.js +38 -0
- package/dist/modules/workflows/lib/task-decision-context.js.map +7 -0
- package/dist/modules/workflows/lib/task-decisions.js +49 -0
- package/dist/modules/workflows/lib/task-decisions.js.map +7 -0
- package/dist/modules/workflows/lib/task-entity-access.js +62 -0
- package/dist/modules/workflows/lib/task-entity-access.js.map +7 -0
- package/dist/modules/workflows/lib/task-entity-aliases.js +39 -0
- package/dist/modules/workflows/lib/task-entity-aliases.js.map +7 -0
- package/dist/modules/workflows/lib/task-entity-types.js +36 -0
- package/dist/modules/workflows/lib/task-entity-types.js.map +7 -0
- package/dist/modules/workflows/lib/task-form-registry.js +33 -0
- package/dist/modules/workflows/lib/task-form-registry.js.map +7 -0
- package/dist/modules/workflows/lib/task-form-schema.js +75 -0
- package/dist/modules/workflows/lib/task-form-schema.js.map +7 -0
- package/dist/modules/workflows/lib/task-handler.js +251 -32
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-inspector-config.js +182 -0
- package/dist/modules/workflows/lib/task-inspector-config.js.map +7 -0
- package/dist/modules/workflows/lib/task-list-query.js +19 -0
- package/dist/modules/workflows/lib/task-list-query.js.map +7 -0
- package/dist/modules/workflows/lib/task-notifications.js +119 -0
- package/dist/modules/workflows/lib/task-notifications.js.map +7 -0
- package/dist/modules/workflows/lib/task-permission-settings.js +43 -0
- package/dist/modules/workflows/lib/task-permission-settings.js.map +7 -0
- package/dist/modules/workflows/lib/task-presets.js +35 -0
- package/dist/modules/workflows/lib/task-presets.js.map +7 -0
- package/dist/modules/workflows/lib/task-quick-action.js +45 -0
- package/dist/modules/workflows/lib/task-quick-action.js.map +7 -0
- package/dist/modules/workflows/lib/task-resolution.js +120 -0
- package/dist/modules/workflows/lib/task-resolution.js.map +7 -0
- package/dist/modules/workflows/lib/task-sla.js +357 -0
- package/dist/modules/workflows/lib/task-sla.js.map +7 -0
- package/dist/modules/workflows/lib/task-visibility-request.js +266 -0
- package/dist/modules/workflows/lib/task-visibility-request.js.map +7 -0
- package/dist/modules/workflows/lib/task-visibility.js +194 -0
- package/dist/modules/workflows/lib/task-visibility.js.map +7 -0
- package/dist/modules/workflows/lib/timer-handler.js +3 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +148 -20
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/trigger-node.js +121 -0
- package/dist/modules/workflows/lib/trigger-node.js.map +7 -0
- package/dist/modules/workflows/lib/visual-editor-navigation.js +14 -0
- package/dist/modules/workflows/lib/visual-editor-navigation.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/empty-state.js +52 -0
- package/dist/modules/workflows/lib/work-inbox/empty-state.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/entity-links.js +63 -0
- package/dist/modules/workflows/lib/work-inbox/entity-links.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/navigation.js +11 -0
- package/dist/modules/workflows/lib/work-inbox/navigation.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/presentation.js +90 -0
- package/dist/modules/workflows/lib/work-inbox/presentation.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/provider.js +118 -0
- package/dist/modules/workflows/lib/work-inbox/provider.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/query.js +70 -0
- package/dist/modules/workflows/lib/work-inbox/query.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/service.js +56 -0
- package/dist/modules/workflows/lib/work-inbox/service.js.map +7 -0
- package/dist/modules/workflows/lib/work-inbox/user-task-source.js +149 -0
- package/dist/modules/workflows/lib/work-inbox/user-task-source.js.map +7 -0
- package/dist/modules/workflows/lib/workflow-command-enablement.js +57 -0
- package/dist/modules/workflows/lib/workflow-command-enablement.js.map +7 -0
- package/dist/modules/workflows/lib/workflow-command-settings.js +54 -0
- package/dist/modules/workflows/lib/workflow-command-settings.js.map +7 -0
- package/dist/modules/workflows/lib/workflow-executor.js +658 -6
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-function-registry.js +40 -0
- package/dist/modules/workflows/lib/workflow-function-registry.js.map +7 -0
- package/dist/modules/workflows/lib/workflow-safe-commands.js +11 -1
- package/dist/modules/workflows/lib/workflow-safe-commands.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-templates.js +69 -0
- package/dist/modules/workflows/lib/workflow-templates.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260626214855_workflows.js +15 -0
- package/dist/modules/workflows/migrations/Migration20260626214855_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260626222424_workflows.js +17 -0
- package/dist/modules/workflows/migrations/Migration20260626222424_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260727074335_workflows.js +15 -0
- package/dist/modules/workflows/migrations/Migration20260727074335_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260728104038_workflows.js +13 -0
- package/dist/modules/workflows/migrations/Migration20260728104038_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260728163001_workflows.js +15 -0
- package/dist/modules/workflows/migrations/Migration20260728163001_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260729061736_workflows.js +13 -0
- package/dist/modules/workflows/migrations/Migration20260729061736_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260729192652_workflows.js +12 -0
- package/dist/modules/workflows/migrations/Migration20260729192652_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260730085000_workflows.js +13 -0
- package/dist/modules/workflows/migrations/Migration20260730085000_workflows.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260730092706_workflows.js +13 -0
- package/dist/modules/workflows/migrations/Migration20260730092706_workflows.js.map +7 -0
- package/dist/modules/workflows/notifications.js +38 -10
- package/dist/modules/workflows/notifications.js.map +2 -2
- package/dist/modules/workflows/setup.js +81 -1
- package/dist/modules/workflows/setup.js.map +2 -2
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +19 -27
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +2 -2
- package/dist/modules/workflows/subscribers/task-deadline-breached-notification.js +24 -0
- package/dist/modules/workflows/subscribers/task-deadline-breached-notification.js.map +7 -0
- package/dist/modules/workflows/subscribers/task-reminder-notification.js +24 -0
- package/dist/modules/workflows/subscribers/task-reminder-notification.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/pending-work/widget.client.js +73 -0
- package/dist/modules/workflows/widgets/injection/pending-work/widget.client.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/pending-work/widget.js +17 -0
- package/dist/modules/workflows/widgets/injection/pending-work/widget.js.map +7 -0
- package/dist/modules/workflows/widgets/injection-table.js +26 -0
- package/dist/modules/workflows/widgets/injection-table.js.map +2 -2
- package/dist/modules/workflows/workers/workflow-activities.worker.js +61 -39
- package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
- package/dist/modules/workflows/workers/workflow-definition-metric-rollup.worker.js +40 -0
- package/dist/modules/workflows/workers/workflow-definition-metric-rollup.worker.js.map +7 -0
- package/dist/modules/workflows/workers/workflow-instance-bulk-replay.js +43 -0
- package/dist/modules/workflows/workers/workflow-instance-bulk-replay.js.map +7 -0
- package/dist/modules/workflows/workers/workflow-invoke-agent.worker.js +30 -0
- package/dist/modules/workflows/workers/workflow-invoke-agent.worker.js.map +7 -0
- package/generated/entities/action_log/index.ts +1 -0
- package/generated/entities/user/index.ts +1 -0
- package/generated/entities/user_task/index.ts +7 -0
- package/generated/entities/workflow_definition/index.ts +3 -0
- package/generated/entities/workflow_definition_draft/index.ts +11 -0
- package/generated/entities/workflow_definition_metric_rollup/index.ts +10 -0
- package/generated/entities/workflow_instance/index.ts +2 -0
- package/generated/entities.ids.generated.ts +4 -1
- package/generated/entity-fields-registry.ts +39 -0
- package/jest.setup.ts +13 -0
- package/package.json +8 -7
- package/src/bootstrap.ts +13 -3
- package/src/helpers/integration/workflowsFixtures.ts +765 -5
- package/src/helpers/integration/workflowsUi.ts +318 -0
- package/src/modules/attachments/lib/createFromBuffer.ts +120 -0
- package/src/modules/audit_logs/data/entities.ts +12 -0
- package/src/modules/audit_logs/data/validators.ts +1 -0
- package/src/modules/audit_logs/lib/projections.ts +5 -1
- package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +26 -0
- package/src/modules/audit_logs/migrations/Migration20260625120000.ts +15 -0
- package/src/modules/audit_logs/services/actionLogService.ts +3 -0
- package/src/modules/auth/data/entities.ts +21 -0
- package/src/modules/auth/i18n/de.json +31 -0
- package/src/modules/auth/i18n/en.json +31 -0
- package/src/modules/auth/i18n/es.json +31 -0
- package/src/modules/auth/i18n/ko.json +31 -0
- package/src/modules/auth/i18n/pl.json +31 -0
- package/src/modules/auth/lib/executionPrincipal.ts +235 -0
- package/src/modules/auth/migrations/.snapshot-open-mercato.json +16 -0
- package/src/modules/auth/migrations/Migration20260625050000.ts +21 -0
- package/src/modules/business_rules/components/InlineRuleEditor.tsx +231 -0
- package/src/modules/business_rules/data/validators.ts +6 -0
- package/src/modules/business_rules/i18n/de.json +4 -0
- package/src/modules/business_rules/i18n/en.json +4 -0
- package/src/modules/business_rules/i18n/es.json +4 -0
- package/src/modules/business_rules/i18n/ko.json +4 -0
- package/src/modules/business_rules/i18n/pl.json +4 -0
- package/src/modules/business_rules/lib/rule-engine.ts +15 -1
- package/src/modules/catalog/commands/products.ts +12 -0
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/ko.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/catalog/workflows.ts +35 -0
- package/src/modules/customer_accounts/AGENTS.md +11 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +2 -0
- package/src/modules/customer_accounts/cli.ts +96 -0
- package/src/modules/customer_accounts/i18n/de.json +5 -0
- package/src/modules/customer_accounts/i18n/en.json +5 -0
- package/src/modules/customer_accounts/i18n/es.json +5 -0
- package/src/modules/customer_accounts/i18n/ko.json +5 -0
- package/src/modules/customer_accounts/i18n/pl.json +5 -0
- package/src/modules/customer_accounts/lib/customerRoleAclSync.ts +92 -0
- package/src/modules/customer_accounts/setup.ts +15 -3
- package/src/modules/customers/commands/deals.ts +5 -0
- package/src/modules/customers/components/detail/ChangelogEntryRow.tsx +4 -2
- package/src/modules/customers/components/detail/utils.ts +2 -0
- package/src/modules/customers/events.ts +21 -3
- package/src/modules/customers/i18n/de.json +4 -0
- package/src/modules/customers/i18n/en.json +4 -0
- package/src/modules/customers/i18n/es.json +4 -0
- package/src/modules/customers/i18n/ko.json +4 -0
- package/src/modules/customers/i18n/pl.json +4 -0
- package/src/modules/customers/lib/link-workflow-task-handler.ts +136 -0
- package/src/modules/customers/lib/todoCompatibility.ts +4 -1
- package/src/modules/customers/lib/workflowTaskLink.ts +23 -0
- package/src/modules/customers/subscribers/link-workflow-task.ts +19 -0
- package/src/modules/customers/workflows.ts +57 -0
- package/src/modules/entities/api/records.ts +18 -62
- package/src/modules/entities/lib/entityClassification.ts +102 -0
- package/src/modules/sales/commands/documents.ts +46 -0
- package/src/modules/sales/events.ts +20 -2
- package/src/modules/sales/i18n/de.json +2 -1
- package/src/modules/sales/i18n/en.json +2 -1
- package/src/modules/sales/i18n/es.json +2 -1
- package/src/modules/sales/i18n/ko.json +2 -1
- package/src/modules/sales/i18n/pl.json +2 -1
- package/src/modules/sales/workflows.ts +12 -1
- package/src/modules/seeds/README.md +86 -0
- package/src/modules/seeds/cli.ts +220 -0
- package/src/modules/seeds/examples/sample-seed.json +26 -0
- package/src/modules/seeds/index.ts +11 -0
- package/src/modules/workflows/AGENTS.md +851 -10
- package/src/modules/workflows/acl.ts +96 -0
- package/src/modules/workflows/ai-agents.ts +80 -0
- package/src/modules/workflows/ai-tools/authoring-pack.ts +798 -0
- package/src/modules/workflows/ai-tools/types.ts +117 -0
- package/src/modules/workflows/ai-tools.ts +20 -0
- package/src/modules/workflows/api/command-settings/route.ts +171 -0
- package/src/modules/workflows/api/commands/route.ts +109 -0
- package/src/modules/workflows/api/definitions/[id]/callers/route.ts +95 -0
- package/src/modules/workflows/api/definitions/[id]/context-schema/route.ts +187 -0
- package/src/modules/workflows/api/definitions/[id]/customize/route.ts +6 -1
- package/src/modules/workflows/api/definitions/[id]/draft/route.ts +395 -0
- package/src/modules/workflows/api/definitions/[id]/publish/route.ts +250 -0
- package/src/modules/workflows/api/definitions/[id]/reset-to-code/route.ts +5 -0
- package/src/modules/workflows/api/definitions/[id]/route.ts +107 -7
- package/src/modules/workflows/api/definitions/[id]/test-step/route.ts +288 -0
- package/src/modules/workflows/api/definitions/generate/route.ts +335 -0
- package/src/modules/workflows/api/definitions/route.ts +88 -113
- package/src/modules/workflows/api/definitions/serialize.ts +9 -0
- package/src/modules/workflows/api/endpoints/route.ts +88 -0
- package/src/modules/workflows/api/functions/route.ts +91 -0
- package/src/modules/workflows/api/grantable-features/route.ts +102 -0
- package/src/modules/workflows/api/instances/[id]/context/route.ts +214 -0
- package/src/modules/workflows/api/instances/[id]/rerun-step/route.ts +226 -0
- package/src/modules/workflows/api/instances/[id]/retry/route.ts +18 -2
- package/src/modules/workflows/api/instances/[id]/step-through/route.ts +195 -0
- package/src/modules/workflows/api/instances/[id]/steps/route.ts +160 -0
- package/src/modules/workflows/api/instances/[id]/would-do/route.ts +216 -0
- package/src/modules/workflows/api/instances/bulk-replay/route.ts +141 -0
- package/src/modules/workflows/api/instances/failure-queue/route.ts +197 -0
- package/src/modules/workflows/api/instances/route.ts +135 -3
- package/src/modules/workflows/api/metrics/definitions/route.ts +262 -0
- package/src/modules/workflows/api/openapi.ts +549 -2
- package/src/modules/workflows/api/portal/tasks/[id]/complete/route.ts +160 -0
- package/src/modules/workflows/api/portal/tasks/[id]/route.ts +124 -0
- package/src/modules/workflows/api/portal/tasks/route.ts +157 -0
- package/src/modules/workflows/api/rule-usage/route.ts +94 -0
- package/src/modules/workflows/api/task-settings/route.ts +138 -0
- package/src/modules/workflows/api/tasks/[id]/claim/route.ts +42 -17
- package/src/modules/workflows/api/tasks/[id]/complete/route.ts +47 -15
- package/src/modules/workflows/api/tasks/[id]/reassign/route.ts +197 -0
- package/src/modules/workflows/api/tasks/[id]/route.ts +57 -6
- package/src/modules/workflows/api/tasks/[id]/unclaim/route.ts +132 -0
- package/src/modules/workflows/api/tasks/route.ts +60 -5
- package/src/modules/workflows/api/tasks/serialize.ts +119 -0
- package/src/modules/workflows/api/templates/route.ts +87 -0
- package/src/modules/workflows/api/work-inbox/next/route.ts +170 -0
- package/src/modules/workflows/api/work-inbox/route.ts +153 -0
- package/src/modules/workflows/backend/config/workflows/page.meta.ts +33 -0
- package/src/modules/workflows/backend/config/workflows/page.tsx +12 -0
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +19 -343
- package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/create/page.tsx +19 -59
- package/src/modules/workflows/backend/definitions/page.tsx +156 -76
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +3129 -584
- package/src/modules/workflows/backend/instances/[id]/page.meta.ts +1 -1
- package/src/modules/workflows/backend/instances/[id]/page.tsx +711 -539
- package/src/modules/workflows/backend/instances/failure-queue/page.meta.ts +16 -0
- package/src/modules/workflows/backend/instances/failure-queue/page.tsx +311 -0
- package/src/modules/workflows/backend/instances/page.meta.ts +1 -1
- package/src/modules/workflows/backend/instances/page.tsx +218 -38
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +639 -400
- package/src/modules/workflows/backend/tasks/page.meta.ts +7 -0
- package/src/modules/workflows/backend/tasks/page.tsx +20 -333
- package/src/modules/workflows/backend/work-inbox/page.meta.ts +15 -0
- package/src/modules/workflows/backend/work-inbox/page.tsx +506 -0
- package/src/modules/workflows/cli.ts +1 -1
- package/src/modules/workflows/commands/tasks.ts +146 -0
- package/src/modules/workflows/components/ActivitiesEditor.tsx +91 -114
- package/src/modules/workflows/components/ActivityEditDialog.tsx +244 -0
- package/src/modules/workflows/components/AgentSelector.tsx +200 -0
- package/src/modules/workflows/components/AnnotationEditDialog.tsx +157 -0
- package/src/modules/workflows/components/BusinessRuleUsagePanel.tsx +106 -0
- package/src/modules/workflows/components/BusinessRulesSelector.tsx +71 -17
- package/src/modules/workflows/components/ConfigJsonTextarea.tsx +111 -0
- package/src/modules/workflows/components/ContextSchemaEditor.tsx +165 -0
- package/src/modules/workflows/components/DefinitionErrorHandlerField.tsx +133 -0
- package/src/modules/workflows/components/DefinitionMetadataDrawer.tsx +456 -0
- package/src/modules/workflows/components/DefinitionMetricsCells.tsx +212 -0
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +196 -95
- package/src/modules/workflows/components/EdgeEditDialog.tsx +15 -16
- package/src/modules/workflows/components/EdgeEditDialogCrudForm.tsx +130 -80
- package/src/modules/workflows/components/InputDataPanel.tsx +177 -0
- package/src/modules/workflows/components/InspectorPanel.tsx +250 -0
- package/src/modules/workflows/components/NodeEditDialog.tsx +444 -38
- package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +848 -178
- package/src/modules/workflows/components/StepsEditor.tsx +9 -2
- package/src/modules/workflows/components/TemplateGalleryDialog.tsx +205 -0
- package/src/modules/workflows/components/TransitionsEditor.tsx +98 -89
- package/src/modules/workflows/components/TriggersDialog.tsx +83 -0
- package/src/modules/workflows/components/TriggersEditor.tsx +363 -0
- package/src/modules/workflows/components/WorkflowAiDraftDialog.tsx +383 -0
- package/src/modules/workflows/components/WorkflowCodeView.tsx +257 -0
- package/src/modules/workflows/components/WorkflowCommandPalette.tsx +82 -0
- package/src/modules/workflows/components/WorkflowCompensationGhostEdge.tsx +78 -0
- package/src/modules/workflows/components/WorkflowDataMappingEdge.tsx +46 -0
- package/src/modules/workflows/components/WorkflowGraph.tsx +54 -1
- package/src/modules/workflows/components/WorkflowGraphImpl.tsx +463 -37
- package/src/modules/workflows/components/WorkflowIconPicker.tsx +144 -0
- package/src/modules/workflows/components/WorkflowLegend.tsx +59 -33
- package/src/modules/workflows/components/WorkflowNodeCard.tsx +355 -28
- package/src/modules/workflows/components/WorkflowRouteChips.tsx +145 -0
- package/src/modules/workflows/components/WorkflowSelector.tsx +33 -14
- package/src/modules/workflows/components/WorkflowTransitionEdge.tsx +83 -10
- package/src/modules/workflows/components/WorkflowTransitionLabel.tsx +13 -2
- package/src/modules/workflows/components/fields/ActivityArrayEditor.tsx +120 -30
- package/src/modules/workflows/components/fields/ActivityConfigFields.tsx +675 -0
- package/src/modules/workflows/components/fields/ActivityTestPanel.tsx +250 -0
- package/src/modules/workflows/components/fields/AgentInvokeConfigField.tsx +580 -0
- package/src/modules/workflows/components/fields/AgentReviewOnBreachField.tsx +88 -0
- package/src/modules/workflows/components/fields/BranchingRoutesEditor.tsx +323 -0
- package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +36 -4
- package/src/modules/workflows/components/fields/CommandPicker.tsx +158 -0
- package/src/modules/workflows/components/fields/EndpointPicker.tsx +330 -0
- package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +2 -2
- package/src/modules/workflows/components/fields/FunctionPicker.tsx +68 -0
- package/src/modules/workflows/components/fields/MappingArrayEditor.tsx +46 -12
- package/src/modules/workflows/components/fields/PortFieldArrayEditor.tsx +255 -0
- package/src/modules/workflows/components/fields/RolesMultiSelect.tsx +68 -0
- package/src/modules/workflows/components/fields/RouteOrderEditor.tsx +169 -0
- package/src/modules/workflows/components/fields/SchemaBuilderDialog.tsx +139 -0
- package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +2 -2
- package/src/modules/workflows/components/fields/TaskAssignmentField.tsx +355 -0
- package/src/modules/workflows/components/fields/TaskDeadlineFields.tsx +172 -0
- package/src/modules/workflows/components/fields/TaskDecisionsField.tsx +294 -0
- package/src/modules/workflows/components/fields/TaskEntityBindingsField.tsx +156 -0
- package/src/modules/workflows/components/fields/TemplateTextControl.tsx +85 -0
- package/src/modules/workflows/components/fields/VariablePickerButton.tsx +177 -0
- package/src/modules/workflows/components/fields/ledgerDropTarget.ts +55 -0
- package/src/modules/workflows/components/fields/useActivityTypeOptions.ts +19 -0
- package/src/modules/workflows/components/formConfig.tsx +84 -10
- package/src/modules/workflows/components/mobile/MobileDefinitionDetail.tsx +5 -0
- package/src/modules/workflows/components/mobile/MobileMetadataSheet.tsx +10 -0
- package/src/modules/workflows/components/mobile/MobileTaskForm.tsx +55 -19
- package/src/modules/workflows/components/mobile/MobileVisualEditor.tsx +49 -40
- package/src/modules/workflows/components/nodes/AnnotationGroupNode.tsx +81 -0
- package/src/modules/workflows/components/nodes/AutomatedNode.tsx +34 -17
- package/src/modules/workflows/components/nodes/EndNode.tsx +15 -14
- package/src/modules/workflows/components/nodes/ErrorOutputHandle.tsx +32 -0
- package/src/modules/workflows/components/nodes/IfElseNode.tsx +64 -0
- package/src/modules/workflows/components/nodes/InvokeAgentNode.tsx +180 -0
- package/src/modules/workflows/components/nodes/NodeOutcomeRows.tsx +143 -0
- package/src/modules/workflows/components/nodes/ParallelForkNode.tsx +28 -15
- package/src/modules/workflows/components/nodes/ParallelJoinNode.tsx +28 -15
- package/src/modules/workflows/components/nodes/StartNode.tsx +78 -18
- package/src/modules/workflows/components/nodes/StickyNoteNode.tsx +65 -0
- package/src/modules/workflows/components/nodes/SubWorkflowNode.tsx +124 -23
- package/src/modules/workflows/components/nodes/SwitchNode.tsx +64 -0
- package/src/modules/workflows/components/nodes/TriggerCap.tsx +103 -0
- package/src/modules/workflows/components/nodes/TriggerNode.tsx +151 -0
- package/src/modules/workflows/components/nodes/UserTaskNode.tsx +67 -22
- package/src/modules/workflows/components/nodes/WaitForConditionNode.tsx +74 -0
- package/src/modules/workflows/components/nodes/WaitForSignalNode.tsx +31 -17
- package/src/modules/workflows/components/nodes/WaitForTimerNode.tsx +31 -16
- package/src/modules/workflows/components/nodes/index.ts +17 -0
- package/src/modules/workflows/components/portal/PortalTaskForm.tsx +280 -0
- package/src/modules/workflows/components/run/AgentActivityPanel.tsx +48 -0
- package/src/modules/workflows/components/run/RerunStepDialog.tsx +133 -0
- package/src/modules/workflows/components/run/RunEventBadge.tsx +37 -0
- package/src/modules/workflows/components/run/RunGantt.tsx +180 -0
- package/src/modules/workflows/components/run/RunStatusBadge.tsx +112 -0
- package/src/modules/workflows/components/run/RunStepInspector.tsx +176 -0
- package/src/modules/workflows/components/run/WouldDoReport.tsx +93 -0
- package/src/modules/workflows/components/run/useAgentLabels.ts +42 -0
- package/src/modules/workflows/components/run/useLastRunOverlay.ts +150 -0
- package/src/modules/workflows/components/run/useLiveAgentActions.ts +70 -0
- package/src/modules/workflows/components/run/useLiveRunUpdates.ts +89 -0
- package/src/modules/workflows/components/settings/CommandSettingsPageClient.tsx +228 -0
- package/src/modules/workflows/components/work-inbox/EntityContextPanel.tsx +179 -0
- package/src/modules/workflows/components/work-inbox/ReassignTaskDialog.tsx +203 -0
- package/src/modules/workflows/components/work-inbox/StatusChip.tsx +61 -0
- package/src/modules/workflows/components/work-inbox/TaskActionNotice.tsx +77 -0
- package/src/modules/workflows/components/work-inbox/TaskFormFields.tsx +322 -0
- package/src/modules/workflows/components/work-inbox/WorkInboxEmptyState.tsx +43 -0
- package/src/modules/workflows/data/activity-config-schemas.ts +249 -0
- package/src/modules/workflows/data/activity-config-warnings.ts +71 -0
- package/src/modules/workflows/data/branching-route-warnings.ts +129 -0
- package/src/modules/workflows/data/entities.ts +397 -4
- package/src/modules/workflows/data/metrics-validators.ts +51 -0
- package/src/modules/workflows/data/task-primitives.ts +36 -0
- package/src/modules/workflows/data/types.ts +81 -2
- package/src/modules/workflows/data/validators.ts +729 -60
- package/src/modules/workflows/di.ts +22 -0
- package/src/modules/workflows/events.ts +68 -8
- package/src/modules/workflows/examples/oze-residential-install-60-nodes.json +1545 -0
- package/src/modules/workflows/examples/sales-pipeline-definition.json +35 -35
- package/src/modules/workflows/examples/templates/lead-to-install.json +160 -0
- package/src/modules/workflows/examples/templates/order-approval.json +230 -0
- package/src/modules/workflows/examples/templates/task-escalation.json +110 -0
- package/src/modules/workflows/examples/templates/webhook-integration.json +113 -0
- package/src/modules/workflows/extension-points.ts +1 -1
- package/src/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.meta.ts +21 -0
- package/src/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.tsx +212 -0
- package/src/modules/workflows/frontend/[orgSlug]/portal/tasks/page.meta.ts +25 -0
- package/src/modules/workflows/frontend/[orgSlug]/portal/tasks/page.tsx +185 -0
- package/src/modules/workflows/i18n/de.json +1083 -24
- package/src/modules/workflows/i18n/en.json +1081 -22
- package/src/modules/workflows/i18n/es.json +1083 -24
- package/src/modules/workflows/i18n/ko.json +1072 -13
- package/src/modules/workflows/i18n/pl.json +1082 -23
- package/src/modules/workflows/lib/activity-executor.ts +855 -186
- package/src/modules/workflows/lib/activity-queue-types.ts +120 -1
- package/src/modules/workflows/lib/activity-registry-bootstrap.ts +7 -0
- package/src/modules/workflows/lib/activity-registry.ts +89 -0
- package/src/modules/workflows/lib/activity-types.ts +415 -0
- package/src/modules/workflows/lib/activity-worker-handler.ts +744 -35
- package/src/modules/workflows/lib/advanced-config.ts +41 -0
- package/src/modules/workflows/lib/agent-disposition-task.ts +343 -0
- package/src/modules/workflows/lib/agent-outcome-paths.ts +153 -0
- package/src/modules/workflows/lib/agent-result-mapping.ts +88 -0
- package/src/modules/workflows/lib/agent-review-inspector.ts +125 -0
- package/src/modules/workflows/lib/agent-review.ts +171 -0
- package/src/modules/workflows/lib/ai-authoring.ts +402 -0
- package/src/modules/workflows/lib/ai-draft-runner.ts +105 -0
- package/src/modules/workflows/lib/annotation-events.ts +15 -0
- package/src/modules/workflows/lib/branching-routes.ts +280 -0
- package/src/modules/workflows/lib/breach-routing.ts +142 -0
- package/src/modules/workflows/lib/bulk-replay.ts +185 -0
- package/src/modules/workflows/lib/business-rule-usage.ts +154 -0
- package/src/modules/workflows/lib/caller-graph.ts +104 -0
- package/src/modules/workflows/lib/code-view-apply.ts +178 -0
- package/src/modules/workflows/lib/collect-validation-issues.ts +239 -0
- package/src/modules/workflows/lib/compensation-ghosts.ts +134 -0
- package/src/modules/workflows/lib/component-guard.ts +13 -0
- package/src/modules/workflows/lib/condition-handler.ts +658 -0
- package/src/modules/workflows/lib/context-ledger.ts +814 -0
- package/src/modules/workflows/lib/crud-form-dialogs-flag.ts +5 -0
- package/src/modules/workflows/lib/data-edge-mapping.ts +112 -0
- package/src/modules/workflows/lib/definition-context-schema.ts +103 -0
- package/src/modules/workflows/lib/definition-edit-safety.ts +228 -0
- package/src/modules/workflows/lib/definition-error-body.ts +43 -0
- package/src/modules/workflows/lib/definition-evaluation.ts +156 -0
- package/src/modules/workflows/lib/definition-grant.ts +211 -0
- package/src/modules/workflows/lib/definition-json-locations.ts +226 -0
- package/src/modules/workflows/lib/definition-payload.ts +81 -0
- package/src/modules/workflows/lib/draft-restore.ts +72 -0
- package/src/modules/workflows/lib/dry-run.ts +203 -0
- package/src/modules/workflows/lib/duration.ts +138 -24
- package/src/modules/workflows/lib/edge-reattachment.ts +186 -0
- package/src/modules/workflows/lib/edgeFormTransforms.ts +15 -14
- package/src/modules/workflows/lib/editor-annotations.ts +301 -0
- package/src/modules/workflows/lib/editor-commands.ts +205 -0
- package/src/modules/workflows/lib/editor-history.ts +151 -0
- package/src/modules/workflows/lib/endpoint-catalog.ts +283 -0
- package/src/modules/workflows/lib/endpoint-path.ts +134 -0
- package/src/modules/workflows/lib/engine-version.ts +67 -0
- package/src/modules/workflows/lib/error-handler.ts +192 -0
- package/src/modules/workflows/lib/error-routing.ts +236 -0
- package/src/modules/workflows/lib/event-logger.ts +27 -0
- package/src/modules/workflows/lib/expression-refs.ts +291 -0
- package/src/modules/workflows/lib/failure-grouping.ts +134 -0
- package/src/modules/workflows/lib/find-definition.ts +4 -0
- package/src/modules/workflows/lib/flow-logic-warnings.ts +591 -0
- package/src/modules/workflows/lib/graph-utils.ts +620 -110
- package/src/modules/workflows/lib/icon-search.ts +65 -0
- package/src/modules/workflows/lib/insert-at-cursor.ts +53 -0
- package/src/modules/workflows/lib/instance-date-filter.ts +56 -0
- package/src/modules/workflows/lib/interpolation-pipeline.ts +351 -0
- package/src/modules/workflows/lib/ledger-drag.ts +61 -0
- package/src/modules/workflows/lib/ledger-entry-display.ts +89 -0
- package/src/modules/workflows/lib/ledger-schema-flatten.ts +137 -0
- package/src/modules/workflows/lib/metrics/definition-metrics.ts +268 -0
- package/src/modules/workflows/lib/metrics/metrics-display.ts +57 -0
- package/src/modules/workflows/lib/metrics/rollup-schedule.ts +26 -0
- package/src/modules/workflows/lib/metrics/rollup-service.ts +292 -0
- package/src/modules/workflows/lib/node-config-summary.ts +235 -0
- package/src/modules/workflows/lib/node-geometry.ts +168 -0
- package/src/modules/workflows/lib/node-nudge.ts +63 -0
- package/src/modules/workflows/lib/node-outcome-rows.ts +195 -0
- package/src/modules/workflows/lib/node-placement.ts +104 -0
- package/src/modules/workflows/lib/node-type-icons.ts +71 -10
- package/src/modules/workflows/lib/nodeFormTransforms.ts +519 -28
- package/src/modules/workflows/lib/outcome-routing.ts +346 -0
- package/src/modules/workflows/lib/owned-definition.ts +188 -0
- package/src/modules/workflows/lib/owned-node-changes.ts +29 -0
- package/src/modules/workflows/lib/palette-drag.ts +68 -0
- package/src/modules/workflows/lib/palette-drop.ts +114 -0
- package/src/modules/workflows/lib/parallel-handler.ts +79 -2
- package/src/modules/workflows/lib/port-contract.ts +107 -0
- package/src/modules/workflows/lib/portal-task-access.ts +220 -0
- package/src/modules/workflows/lib/rerun-from-step.ts +140 -0
- package/src/modules/workflows/lib/route-chip-events.ts +45 -0
- package/src/modules/workflows/lib/route-chips.ts +177 -0
- package/src/modules/workflows/lib/route-edge.ts +57 -0
- package/src/modules/workflows/lib/route-kinds.ts +166 -0
- package/src/modules/workflows/lib/route-priority.ts +197 -0
- package/src/modules/workflows/lib/run-duration.ts +70 -0
- package/src/modules/workflows/lib/run-event-tone.ts +46 -0
- package/src/modules/workflows/lib/run-execution.ts +598 -0
- package/src/modules/workflows/lib/run-gantt.ts +311 -0
- package/src/modules/workflows/lib/run-outcome-evidence.ts +60 -0
- package/src/modules/workflows/lib/run-outcome.ts +142 -0
- package/src/modules/workflows/lib/sample-resolver.ts +113 -0
- package/src/modules/workflows/lib/seeds.ts +3 -1
- package/src/modules/workflows/lib/server-output-contract.ts +120 -0
- package/src/modules/workflows/lib/set-variable.ts +94 -0
- package/src/modules/workflows/lib/signal-handler.ts +134 -4
- package/src/modules/workflows/lib/start-fixtures.ts +93 -0
- package/src/modules/workflows/lib/status-colors.ts +220 -21
- package/src/modules/workflows/lib/step-handler.ts +744 -68
- package/src/modules/workflows/lib/step-presentation.ts +295 -0
- package/src/modules/workflows/lib/step-through.ts +71 -0
- package/src/modules/workflows/lib/step-type-conversion.ts +263 -0
- package/src/modules/workflows/lib/subgraph-clipboard.ts +214 -0
- package/src/modules/workflows/lib/task-decision-context.ts +76 -0
- package/src/modules/workflows/lib/task-decisions.ts +117 -0
- package/src/modules/workflows/lib/task-entity-access.ts +181 -0
- package/src/modules/workflows/lib/task-entity-aliases.ts +77 -0
- package/src/modules/workflows/lib/task-entity-types.ts +66 -0
- package/src/modules/workflows/lib/task-form-registry.ts +123 -0
- package/src/modules/workflows/lib/task-form-schema.ts +129 -0
- package/src/modules/workflows/lib/task-handler.ts +492 -51
- package/src/modules/workflows/lib/task-inspector-config.ts +348 -0
- package/src/modules/workflows/lib/task-list-query.ts +46 -0
- package/src/modules/workflows/lib/task-notifications.ts +218 -0
- package/src/modules/workflows/lib/task-permission-settings.ts +117 -0
- package/src/modules/workflows/lib/task-presets.ts +95 -0
- package/src/modules/workflows/lib/task-quick-action.ts +111 -0
- package/src/modules/workflows/lib/task-resolution.ts +270 -0
- package/src/modules/workflows/lib/task-sla.ts +628 -0
- package/src/modules/workflows/lib/task-visibility-request.ts +668 -0
- package/src/modules/workflows/lib/task-visibility.ts +627 -0
- package/src/modules/workflows/lib/timer-handler.ts +8 -1
- package/src/modules/workflows/lib/transition-handler.ts +228 -20
- package/src/modules/workflows/lib/trigger-node.ts +272 -0
- package/src/modules/workflows/lib/visual-editor-navigation.ts +29 -0
- package/src/modules/workflows/lib/work-inbox/empty-state.ts +150 -0
- package/src/modules/workflows/lib/work-inbox/entity-links.ts +99 -0
- package/src/modules/workflows/lib/work-inbox/navigation.ts +28 -0
- package/src/modules/workflows/lib/work-inbox/presentation.ts +163 -0
- package/src/modules/workflows/lib/work-inbox/provider.ts +390 -0
- package/src/modules/workflows/lib/work-inbox/query.ts +103 -0
- package/src/modules/workflows/lib/work-inbox/service.ts +122 -0
- package/src/modules/workflows/lib/work-inbox/user-task-source.ts +240 -0
- package/src/modules/workflows/lib/workflow-command-enablement.ts +188 -0
- package/src/modules/workflows/lib/workflow-command-settings.ts +124 -0
- package/src/modules/workflows/lib/workflow-executor.ts +1036 -10
- package/src/modules/workflows/lib/workflow-function-registry.ts +44 -0
- package/src/modules/workflows/lib/workflow-safe-commands.ts +42 -1
- package/src/modules/workflows/lib/workflow-templates.ts +91 -0
- package/src/modules/workflows/migrations/.snapshot-open-mercato.json +2321 -698
- package/src/modules/workflows/migrations/Migration20260626214855_workflows.ts +15 -0
- package/src/modules/workflows/migrations/Migration20260626222424_workflows.ts +17 -0
- package/src/modules/workflows/migrations/Migration20260727074335_workflows.ts +15 -0
- package/src/modules/workflows/migrations/Migration20260728104038_workflows.ts +13 -0
- package/src/modules/workflows/migrations/Migration20260728163001_workflows.ts +36 -0
- package/src/modules/workflows/migrations/Migration20260729061736_workflows.ts +13 -0
- package/src/modules/workflows/migrations/Migration20260729192652_workflows.ts +11 -0
- package/src/modules/workflows/migrations/Migration20260730085000_workflows.ts +13 -0
- package/src/modules/workflows/migrations/Migration20260730092706_workflows.ts +13 -0
- package/src/modules/workflows/notifications.ts +40 -10
- package/src/modules/workflows/setup.ts +128 -0
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +36 -45
- package/src/modules/workflows/subscribers/task-deadline-breached-notification.ts +31 -0
- package/src/modules/workflows/subscribers/task-reminder-notification.ts +31 -0
- package/src/modules/workflows/widgets/injection/pending-work/widget.client.tsx +119 -0
- package/src/modules/workflows/widgets/injection/pending-work/widget.ts +27 -0
- package/src/modules/workflows/widgets/injection-table.ts +52 -2
- package/src/modules/workflows/workers/workflow-activities.worker.ts +95 -42
- package/src/modules/workflows/workers/workflow-definition-metric-rollup.worker.ts +71 -0
- package/src/modules/workflows/workers/workflow-instance-bulk-replay.ts +51 -0
- package/src/modules/workflows/workers/workflow-invoke-agent.worker.ts +72 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/workflows/lib/task-handler.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Workflows Module - User Task Handler Service\n *\n * Handles user task lifecycle operations:\n * - Completing user tasks\n * - Claiming tasks from role queues\n * - Reassigning tasks\n * - Escalating overdue tasks\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n UserTask,\n WorkflowInstance,\n WorkflowEvent,\n StepInstance,\n} from '../data/entities'\nimport { executeWorkflow } from './workflow-executor'\nimport { findDefinitionForInstance } from './find-definition'\nimport * as stepHandler from './step-handler'\nimport * as transitionHandler from './transition-handler'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface CompleteUserTaskOptions {\n taskId: string\n formData: Record<string, any>\n userId: string\n comments?: string\n}\n\nexport class UserTaskError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'UserTaskError'\n }\n}\n\n// ============================================================================\n// User Task Completion\n// ============================================================================\n\n/**\n * Complete a user task and resume workflow execution\n *\n * This function:\n * 1. Validates the task exists and can be completed\n * 2. Updates the task with form data and completion info\n * 3. Merges form data into workflow context\n * 4. Logs completion event\n * 5. Resumes workflow execution\n *\n * @param em - Entity manager\n * @param container - DI container for workflow execution\n * @param options - Task completion options\n * @throws UserTaskError if task not found or validation fails\n */\nexport async function completeUserTask(\n em: EntityManager,\n container: AwilixContainer,\n options: CompleteUserTaskOptions\n): Promise<void> {\n const { taskId, formData, userId, comments } = options\n\n // Fetch task\n const task = await em.findOne(UserTask, {\n id: taskId,\n status: { $in: ['PENDING', 'IN_PROGRESS'] },\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already completed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n // Validate form data against schema (simple validation for MVP)\n // In Phase 7, we'll add comprehensive JSON Schema validation\n if (task.formSchema) {\n try {\n validateFormData(formData, task.formSchema)\n } catch (error) {\n throw new UserTaskError(\n error instanceof Error ? error.message : 'Form validation failed',\n 'FORM_VALIDATION_FAILED',\n { taskId, formSchema: task.formSchema, formData }\n )\n }\n }\n\n // Update task\n const now = new Date()\n task.status = 'COMPLETED'\n task.formData = formData\n task.completedBy = userId\n task.completedAt = now\n task.comments = comments || null\n task.updatedAt = now\n\n await em.flush()\n\n // Fetch workflow instance\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (!instance) {\n throw new UserTaskError(\n 'Workflow instance not found',\n 'INSTANCE_NOT_FOUND',\n { workflowInstanceId: task.workflowInstanceId }\n )\n }\n\n // Branch-scoped completion: when the task belongs to a parallel branch,\n // merge form data into the branch namespace and resume just that branch.\n if (task.branchInstanceId) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n branchInstanceId: task.branchInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: { taskId: task.id, taskName: task.taskName, completedBy: userId, formData },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { resumeBranch } = await import('./parallel-handler')\n const resumed = await resumeBranch(em, {\n instanceId: instance.id,\n branchInstanceId: task.branchInstanceId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n contextMerge: formData,\n exitStepInstanceId: task.stepInstanceId,\n exitOutput: { userTaskId: task.id, formData },\n })\n\n if (resumed) {\n await executeWorkflow(em, container, instance.id, { userId })\n }\n return\n }\n\n // Merge form data into workflow context\n instance.context = {\n ...instance.context,\n ...formData,\n }\n instance.updatedAt = now\n\n // Log USER_TASK_COMPLETED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n completedBy: userId,\n formData,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Mark the step instance as completed\n const stepInstance = await em.findOne(StepInstance, {\n id: task.stepInstanceId,\n status: 'ACTIVE',\n })\n\n if (stepInstance) {\n await stepHandler.exitStep(em, stepInstance, { userTaskId: task.id, formData })\n }\n\n // Find the next automatic transition from the current step\n const currentStepId = instance.currentStepId\n\n // Load workflow definition to find transitions\n const definition = await findDefinitionForInstance(em, instance)\n\n if (!definition) {\n throw new UserTaskError(\n 'Workflow definition not found',\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n // Find automatic transitions from current step\n const autoTransitions = (definition.definition.transitions || []).filter(\n (t: any) => t.fromStepId === currentStepId && t.trigger === 'auto'\n )\n\n if (autoTransitions.length === 0) {\n // No automatic transitions, workflow stays paused at current step\n return\n }\n\n // Find valid transitions using transition handler\n const transitionContext = {\n workflowContext: instance.context,\n userId,\n }\n\n const validTransitions = await transitionHandler.findValidTransitions(\n em,\n instance,\n currentStepId,\n transitionContext\n )\n\n const firstValidTransition = validTransitions.find(t => t.isValid)\n\n if (!firstValidTransition || !firstValidTransition.transition) {\n // Resume workflow execution anyway, maybe conditions will be met later\n instance.status = 'RUNNING'\n await em.flush()\n return\n }\n\n // Execute the transition to move to next step\n\n const transitionResult = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n currentStepId,\n firstValidTransition.transition.toStepId,\n transitionContext\n )\n\n if (!transitionResult.success) {\n logger.error('Transition failed', { component: 'task-handler', err: transitionResult.error })\n // Don't throw, just leave workflow in current state\n return\n }\n\n // Now continue workflow execution from the new step\n await executeWorkflow(em, container, instance.id, { userId })\n}\n\n/**\n * Claim a user task from a role queue\n *\n * Allows a user to claim a task that's assigned to their role(s).\n * Prevents race conditions by checking task status.\n *\n * @param em - Entity manager\n * @param taskId - Task ID to claim\n * @param userId - User claiming the task\n * @throws UserTaskError if task cannot be claimed\n */\nexport async function claimUserTask(\n em: EntityManager,\n taskId: string,\n userId: string\n): Promise<void> {\n const task = await em.findOne(UserTask, {\n id: taskId,\n status: 'PENDING',\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n if (task.assignedTo) {\n throw new UserTaskError(\n 'Task is already assigned to a specific user',\n 'TASK_ALREADY_ASSIGNED',\n { taskId, assignedTo: task.assignedTo }\n )\n }\n\n if (!task.assignedToRoles || task.assignedToRoles.length === 0) {\n throw new UserTaskError(\n 'Task is not assigned to any roles',\n 'TASK_NOT_ROLE_ASSIGNED',\n { taskId }\n )\n }\n\n // Update task\n const now = new Date()\n task.claimedBy = userId\n task.claimedAt = now\n task.status = 'IN_PROGRESS'\n task.updatedAt = now\n\n await em.flush()\n\n // Log event\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (instance) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_STARTED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n claimedBy: userId,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log workflow event to event sourcing table\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string | null\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Validate form data against JSON schema (basic validation for MVP)\n *\n * In Phase 7, we'll implement comprehensive JSON Schema validation.\n * For MVP, we do basic type checking.\n *\n * @param formData - User-provided form data\n * @param formSchema - JSON schema defining expected structure\n * @throws Error if validation fails\n */\nfunction validateFormData(\n formData: Record<string, any>,\n formSchema: any\n): void {\n // For MVP: Basic validation - just check required fields exist\n if (!formSchema || !formSchema.properties) {\n return // No schema to validate against\n }\n\n const requiredFields = formSchema.required || []\n\n for (const field of requiredFields) {\n if (!(field in formData) || formData[field] === null || formData[field] === undefined) {\n throw new Error(`Required field missing: ${field}`)\n }\n }\n\n // Additional type validation can be added in Phase 7\n // For now, this basic validation is sufficient\n}\n"],
|
|
5
|
-
"mappings": "AAcA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,iCAAiC;AAC1C,YAAY,iBAAiB;AAC7B,YAAY,uBAAuB;AACnC,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,WAAW;
|
|
4
|
+
"sourcesContent": ["/**\n * Workflows Module - User Task Handler Service\n *\n * Handles user task lifecycle operations:\n * - Completing user tasks\n * - Claiming tasks from role queues\n * - Reassigning tasks\n * - Escalating overdue tasks\n *\n * Functional API (no classes) following Open Mercato conventions.\n */\n\nimport { EntityManager } from '@mikro-orm/core'\nimport type { AwilixContainer } from 'awilix'\nimport {\n UserTask,\n WorkflowInstance,\n WorkflowEvent,\n StepInstance,\n} from '../data/entities'\nimport { executeWorkflow } from './workflow-executor'\nimport { findDefinitionForInstance } from './find-definition'\nimport {\n findTaskDecision,\n findTaskDecisionTransition,\n withRecordedDecision,\n} from './task-decisions'\nimport { loadTaskDecisionContext } from './task-decision-context'\nimport { readRequiredFormFields } from './task-form-schema'\nimport * as stepHandler from './step-handler'\nimport * as transitionHandler from './transition-handler'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\n/**\n * Tenant/organization the caller is acting within. Every task lookup filters on\n * it, so a task id from another tenant resolves to \"not found\" instead of being\n * mutated.\n */\nexport interface UserTaskScope {\n tenantId: string\n organizationId: string\n}\n\n/**\n * Shape of the `taskHandler` DI registration (`di.ts`).\n *\n * The functions below stay exported \u2014 third-party modules may import them and\n * `BACKWARD_COMPATIBILITY.md` \u00A73 freezes import paths \u2014 but callers inside the\n * platform MUST resolve this service instead, per the module's first rule.\n */\nexport interface TaskHandlerService {\n completeUserTask: typeof completeUserTask\n claimUserTask: typeof claimUserTask\n releaseUserTask: typeof releaseUserTask\n reassignUserTask: typeof reassignUserTask\n}\n\nexport interface CompleteUserTaskOptions {\n taskId: string\n formData: Record<string, any>\n userId: string\n comments?: string\n /**\n * The decision button the assignee pressed, when the step authored any.\n *\n * It does two things: it SELECTS the outgoing route (the decision's\n * `transitionId` wins over the first-valid-transition default), and it is\n * RECORDED as part of the completion payload. Omitted, completion behaves\n * exactly as it always did.\n */\n decisionId?: string\n scope: UserTaskScope\n}\n\nexport class UserTaskError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: any\n ) {\n super(message)\n this.name = 'UserTaskError'\n }\n}\n\n// ============================================================================\n// User Task Completion\n// ============================================================================\n\n/**\n * Complete a user task and resume workflow execution\n *\n * This function:\n * 1. Validates the task exists and can be completed\n * 2. Updates the task with form data and completion info\n * 3. Merges form data into workflow context\n * 4. Logs completion event\n * 5. Resumes workflow execution\n *\n * @param em - Entity manager\n * @param container - DI container for workflow execution\n * @param options - Task completion options\n * @throws UserTaskError if task not found or validation fails\n */\nexport async function completeUserTask(\n em: EntityManager,\n container: AwilixContainer,\n options: CompleteUserTaskOptions\n): Promise<void> {\n const { taskId, formData, userId, comments, decisionId, scope } = options\n\n // Fetch task\n const task = await em.findOne(UserTask, {\n id: taskId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n status: { $in: ['PENDING', 'IN_PROGRESS'] },\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already completed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n // A task addressed to one person is that person's to finish. Tasks that name\n // nobody \u2014 agent dispositions, role queues nobody has claimed \u2014 stay open to\n // anyone the route's feature gate already admitted, so this narrows the\n // over-permissive case without stranding the unassigned ones.\n const claimant = task.claimedBy ?? task.assignedTo\n if (claimant && claimant !== userId) {\n throw new UserTaskError(\n 'Task is assigned to another user',\n 'TASK_ASSIGNED_TO_ANOTHER_USER',\n { taskId, assignedTo: claimant }\n )\n }\n\n // Validate form data against schema (simple validation for MVP)\n // In Phase 7, we'll add comprehensive JSON Schema validation\n if (task.formSchema) {\n try {\n validateFormData(formData, task.formSchema)\n } catch (error) {\n throw new UserTaskError(\n error instanceof Error ? error.message : 'Form validation failed',\n 'FORM_VALIDATION_FAILED',\n { taskId, formSchema: task.formSchema, formData }\n )\n }\n }\n\n // Resolve the pressed decision BEFORE anything is mutated: an unknown\n // decision id must leave the task untouched rather than complete it down the\n // default route. The list is re-resolved from the instance's pinned\n // definition, so it is exactly the list the assignee was shown.\n const chosenDecision = decisionId\n ? findTaskDecision((await loadTaskDecisionContext(em, task)).decisions, decisionId)\n : null\n\n if (decisionId && !chosenDecision) {\n throw new UserTaskError(\n 'Unknown decision for this task',\n 'UNKNOWN_DECISION',\n { taskId, decisionId }\n )\n }\n\n // The chosen decision rides along inside the completion payload the task\n // already persists \u2014 no new column, and downstream route conditions can read\n // it once the payload is merged into the run context.\n const completionData = withRecordedDecision(formData, chosenDecision?.id)\n\n // Update task\n const now = new Date()\n task.status = 'COMPLETED'\n task.formData = completionData\n task.completedBy = userId\n task.completedAt = now\n task.comments = comments || null\n task.updatedAt = now\n\n await em.flush()\n\n // Fetch workflow instance\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (!instance) {\n throw new UserTaskError(\n 'Workflow instance not found',\n 'INSTANCE_NOT_FOUND',\n { workflowInstanceId: task.workflowInstanceId }\n )\n }\n\n // Branch-scoped completion: when the task belongs to a parallel branch,\n // merge form data into the branch namespace and resume just that branch.\n //\n // The decision is RECORDED here exactly as it is on the main path, but it does\n // not select the route: a branch advances through `resumeBranch` with its own\n // token, and overriding a branch's outgoing route is a parallel-execution\n // change rather than a task-surface one.\n if (task.branchInstanceId) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n branchInstanceId: task.branchInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n completedBy: userId,\n formData: completionData,\n ...(chosenDecision ? { decisionId: chosenDecision.id } : {}),\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n const { resumeBranch } = await import('./parallel-handler')\n const resumed = await resumeBranch(em, {\n instanceId: instance.id,\n branchInstanceId: task.branchInstanceId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n contextMerge: completionData,\n exitStepInstanceId: task.stepInstanceId,\n exitOutput: { userTaskId: task.id, formData: completionData },\n })\n\n if (resumed) {\n await executeWorkflow(em, container, instance.id, { userId })\n }\n return\n }\n\n // Merge form data into workflow context\n instance.context = {\n ...instance.context,\n ...completionData,\n }\n instance.updatedAt = now\n\n // Log USER_TASK_COMPLETED event\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_COMPLETED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n completedBy: userId,\n formData: completionData,\n ...(chosenDecision ? { decisionId: chosenDecision.id } : {}),\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n\n // Mark the step instance as completed\n const stepInstance = await em.findOne(StepInstance, {\n id: task.stepInstanceId,\n status: 'ACTIVE',\n })\n\n if (stepInstance) {\n await stepHandler.exitStep(em, stepInstance, { userTaskId: task.id, formData: completionData })\n }\n\n // Find the next automatic transition from the current step\n const currentStepId = instance.currentStepId\n\n // Load workflow definition to find transitions\n const definition = await findDefinitionForInstance(em, instance)\n\n if (!definition) {\n throw new UserTaskError(\n 'Workflow definition not found',\n 'DEFINITION_NOT_FOUND',\n { definitionId: instance.definitionId }\n )\n }\n\n const transitionContext = {\n workflowContext: instance.context,\n userId,\n }\n\n // A decision names the route to take. It is bound to the transition's durable\n // id, so it survives every route reorder, and it is looked up among the routes\n // LEAVING this step only \u2014 a button can never send the run down a route that\n // does not start where the run currently is. A decision whose route no longer\n // exists there falls through to the default evaluation rather than stranding\n // the run at a step it already completed.\n const decisionTransition = chosenDecision\n ? findTaskDecisionTransition(\n definition.definition.transitions || [],\n chosenDecision.transitionId,\n currentStepId\n )\n : null\n\n if (chosenDecision && !decisionTransition) {\n logger.warn('Task decision route not found on the current step; falling back to auto routing', {\n component: 'task-handler',\n taskId: task.id,\n decisionId: chosenDecision.id,\n transitionId: chosenDecision.transitionId,\n currentStepId,\n })\n }\n\n let selectedTransition = decisionTransition ?? null\n let targetStepId = selectedTransition?.toStepId ?? null\n\n if (!targetStepId) {\n // Find automatic transitions from current step\n const autoTransitions = (definition.definition.transitions || []).filter(\n (t: any) => t.fromStepId === currentStepId && t.trigger === 'auto'\n )\n\n if (autoTransitions.length === 0) {\n // No automatic transitions, workflow stays paused at current step\n return\n }\n\n // Find valid transitions using transition handler\n const validTransitions = await transitionHandler.findValidTransitions(\n em,\n instance,\n currentStepId,\n transitionContext\n )\n\n const firstValidTransition = validTransitions.find(t => t.isValid)\n\n if (!firstValidTransition || !firstValidTransition.transition) {\n // Resume workflow execution anyway, maybe conditions will be met later\n instance.status = 'RUNNING'\n await em.flush()\n return\n }\n\n targetStepId = firstValidTransition.transition.toStepId\n selectedTransition = firstValidTransition.transition\n }\n\n // Resume from the paused wait BEFORE executing the transition, exactly as\n // `sendSignal` does. Without it the executor's defense-in-depth PAUSED check\n // stops the run at the first step the completion traverses, so the instance\n // sits there as PAUSED and never reaches END. Guarded on PAUSED so completing\n // a stale task can never resurrect a CANCELLED or terminal run.\n if (instance.status === 'PAUSED') {\n instance.status = 'RUNNING'\n await em.flush()\n }\n\n // Execute the transition to move to next step\n\n const transitionResult = await transitionHandler.executeTransition(\n em,\n container,\n instance,\n currentStepId,\n targetStepId,\n { ...transitionContext, transitionId: selectedTransition?.transitionId },\n )\n\n if (!transitionResult.success) {\n logger.error('Transition failed', { component: 'task-handler', err: transitionResult.error })\n // Don't throw, just leave workflow in current state\n return\n }\n\n // Now continue workflow execution from the new step\n await executeWorkflow(em, container, instance.id, { userId })\n}\n\n/**\n * Whether the caller belongs to at least one of the task's queues.\n *\n * Exact string equality on role NAMES \u2014 no case folding and no trimming, because\n * the names on both sides come from the same tenant role table and normalizing\n * one side would let `Approver` claim an `approver` queue that RBAC treats as a\n * different role.\n */\nfunction hasRoleOverlap(\n taskRoles: readonly string[],\n callerRoleNames: readonly string[],\n): boolean {\n if (callerRoleNames.length === 0) return false\n const held = new Set(callerRoleNames)\n return taskRoles.some((role) => held.has(role))\n}\n\n/**\n * Claim a user task from a role queue\n *\n * Allows a user to claim a task that's assigned to their role(s).\n *\n * The claim itself is a COMPARE-AND-SET, not a read-then-write: the lookup\n * below only decides which error to report, while the row is taken with a\n * conditional `UPDATE \u2026 WHERE status = 'PENDING' AND claimed_by IS NULL`. Two\n * callers racing for the same task \u2014 which is exactly what the work inbox's\n * claim-next affordance produces \u2014 therefore cannot both win; the loser sees\n * zero affected rows and the same `TASK_NOT_FOUND` it would have seen a moment\n * later. Reading the status and flushing the entity afterwards would have let\n * both transactions read `PENDING` and both write.\n *\n * Membership in the queue is a REQUIREMENT, not a hint: a caller who holds none\n * of `assignedToRoles` is refused with the same `TASK_NOT_FOUND` a nonexistent\n * id produces, so a queue the caller does not belong to is indistinguishable\n * from a task that is not there. Holding `workflows.tasks.claim` admits you to\n * the endpoint; it does not admit you to somebody else's queue.\n *\n * `assignedToRoles` and `callerRoleNames` are both role NAMES \u2014 the Studio\n * picker writes names, the engine copies them onto the task, and `auth.roles`\n * carries names. A role RENAME therefore orphans existing assignments; moving\n * the comparison onto immutable role ids is a coordinated data + authored-\n * definition migration and is deliberately not done here.\n *\n * @param em - Entity manager\n * @param taskId - Task ID to claim\n * @param userId - User claiming the task\n * @param scope - Tenant/organization the caller acts within; both the lookup and\n * the conditional update filter on it, so a task belonging to another tenant\n * is never reachable and never writable\n * @param callerRoleNames - Server-derived role names of the caller (`auth.roles`),\n * never client-supplied. Required rather than optional so a caller that cannot\n * supply them fails to compile instead of silently claiming any queue.\n * @throws UserTaskError if task cannot be claimed\n */\nexport async function claimUserTask(\n em: EntityManager,\n taskId: string,\n userId: string,\n scope: UserTaskScope,\n callerRoleNames: readonly string[]\n): Promise<void> {\n const task = await em.findOne(UserTask, {\n id: taskId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n status: 'PENDING',\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or already claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n if (task.assignedTo) {\n throw new UserTaskError(\n 'Task is already assigned to a specific user',\n 'TASK_ALREADY_ASSIGNED',\n { taskId, assignedTo: task.assignedTo }\n )\n }\n\n if (!task.assignedToRoles || task.assignedToRoles.length === 0) {\n throw new UserTaskError(\n 'Task is not assigned to any roles',\n 'TASK_NOT_ROLE_ASSIGNED',\n { taskId }\n )\n }\n\n if (!hasRoleOverlap(task.assignedToRoles, callerRoleNames)) {\n throw new UserTaskError(\n 'Task not found or already claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n const now = new Date()\n const claimed = await em.nativeUpdate(\n UserTask,\n {\n id: taskId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n status: 'PENDING',\n claimedBy: null,\n },\n {\n claimedBy: userId,\n claimedAt: now,\n status: 'IN_PROGRESS',\n updatedAt: now,\n },\n )\n\n if (claimed === 0) {\n throw new UserTaskError(\n 'Task not found or already claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n // The conditional update above already wrote the row; mirroring it onto the\n // managed entity keeps the caller's identity-mapped copy from reporting the\n // pre-claim state back to the client.\n task.claimedBy = userId\n task.claimedAt = now\n task.status = 'IN_PROGRESS'\n task.updatedAt = now\n\n await em.flush()\n\n // Log event\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (instance) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_STARTED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n claimedBy: userId,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n}\n\n/**\n * Release a claimed task back to its role queue.\n *\n * The counterpart of `claimUserTask`, and deliberately its mirror image: the\n * write is the same compare-and-set, guarded on the caller still being the\n * claimant, so a task reassigned or completed in the meantime is refused rather\n * than silently reopened. It uses the EXISTING statuses \u2014 the row goes back to\n * `PENDING` \u2014 because adding a `UserTaskStatus` value is an Ask-First\n * state-machine change and a released task is exactly as pending as it was\n * before anyone claimed it.\n *\n * @throws UserTaskError if the task is not the caller's to release\n */\nexport async function releaseUserTask(\n em: EntityManager,\n taskId: string,\n userId: string,\n scope: UserTaskScope\n): Promise<void> {\n const task = await em.findOne(UserTask, {\n id: taskId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n status: 'IN_PROGRESS',\n })\n\n if (!task) {\n throw new UserTaskError(\n 'Task not found or not claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n if (task.claimedBy !== userId) {\n throw new UserTaskError(\n 'Task is claimed by another user',\n 'TASK_ASSIGNED_TO_ANOTHER_USER',\n { taskId, claimedBy: task.claimedBy }\n )\n }\n\n const now = new Date()\n const released = await em.nativeUpdate(\n UserTask,\n {\n id: taskId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n status: 'IN_PROGRESS',\n claimedBy: userId,\n },\n {\n claimedBy: null,\n claimedAt: null,\n status: 'PENDING',\n updatedAt: now,\n },\n )\n\n if (released === 0) {\n throw new UserTaskError(\n 'Task not found or not claimed',\n 'TASK_NOT_FOUND',\n { taskId }\n )\n }\n\n task.claimedBy = null\n task.claimedAt = null\n task.status = 'PENDING'\n task.updatedAt = now\n\n await em.flush()\n\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (instance) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n eventType: 'USER_TASK_RELEASED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n releasedBy: userId,\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n}\n\n// ============================================================================\n// User Task Reassignment\n// ============================================================================\n\n/**\n * The new owner of a task, as the reassign route resolved it.\n *\n * At least one of the two must be non-empty, and the route enforces it: the\n * shape \u00A76.4 makes uncompletable is precisely \"no assignee AND no role queue\",\n * so a reassignment that produced it would be the one write that can create the\n * problem reassignment exists to fix.\n */\nexport interface ReassignUserTaskTarget {\n assignedTo?: string | null\n assignedToRoles?: readonly string[] | null\n}\n\nexport interface ReassignUserTaskOptions {\n taskId: string\n /** Who performed the reassignment \u2014 recorded on `reassigned_by`. */\n userId: string\n target: ReassignUserTaskTarget\n reason?: string | null\n scope: UserTaskScope\n}\n\n/**\n * Statuses a task can be reassigned in.\n *\n * The same pair `completeUserTask` accepts: moving a COMPLETED or CANCELLED row\n * to somebody else records an audit trail for work that can never be done, and\n * the assignee would be handed a task whose Complete button always fails.\n */\nconst REASSIGNABLE_STATUSES: readonly string[] = ['PENDING', 'IN_PROGRESS']\n\n/**\n * Move a task to a different assignee or role queue, with an audit trail.\n *\n * This is the ACT half of the \u00A76.4 model's central asymmetry: administration\n * widens seeing, never acting, so an administrator who can see a colleague's\n * task \u2014 or a task that belongs to nobody at all \u2014 takes it first and the taking\n * is permanently recorded. It is also the documented remedy for the one shape\n * the model leaves uncompletable (no assignee, no claim, no role queue), which\n * is why it deliberately accepts a task in exactly that state.\n *\n * No new `UserTaskStatus` value is introduced. The audit lives on the columns\n * Phase 4a added (`reassigned_by` / `reassigned_at` / `reassign_reason`) plus a\n * `WorkflowEvent`, and a reassigned task is exactly as pending or in-progress as\n * it was \u2014 the same choice `releaseUserTask` made, and the one Phase 3a's\n * failure queue made when it reused `PAUSED` plus a marker.\n *\n * An in-flight CLAIM is always released. Handing a row to somebody else while a\n * colleague still holds it would leave `claimedBy ?? assignedTo` naming the old\n * claimant, so the predicate would keep treating the task as theirs and the new\n * assignee could not act on what they were just given.\n *\n * @throws UserTaskError when the task is absent from the caller's scope or is\n * in a terminal status\n */\nexport async function reassignUserTask(\n em: EntityManager,\n options: ReassignUserTaskOptions,\n): Promise<UserTask> {\n const { taskId, userId, target, reason, scope } = options\n\n const task = await em.findOne(UserTask, {\n id: taskId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n\n if (!task) {\n throw new UserTaskError('Task not found', 'TASK_NOT_FOUND', { taskId })\n }\n\n if (!REASSIGNABLE_STATUSES.includes(task.status)) {\n throw new UserTaskError(\n 'Task is no longer open and cannot be reassigned',\n 'TASK_NOT_REASSIGNABLE',\n { taskId, status: task.status },\n )\n }\n\n const assignedTo = target.assignedTo ?? null\n const assignedToRoles =\n target.assignedToRoles && target.assignedToRoles.length > 0 ? [...target.assignedToRoles] : null\n\n const previous = {\n assignedTo: task.assignedTo ?? null,\n assignedToRoles: task.assignedToRoles ?? null,\n claimedBy: task.claimedBy ?? null,\n }\n\n const now = new Date()\n\n task.assignedTo = assignedTo\n // Reassignment is a backoffice administration act and its target is resolved\n // from the tenant's user/role vocabulary, so the row lands in the backoffice\n // namespace. Portal reassignment would need a portal principal picker and is\n // not part of this surface.\n task.assigneeKind = 'user'\n task.assignedToRoles = assignedToRoles\n task.claimedBy = null\n task.claimedAt = null\n // A queued task must be PENDING to be claimable, and a task whose claim was\n // just released is exactly as pending as it was before anyone claimed it.\n if (task.status === 'IN_PROGRESS') task.status = 'PENDING'\n task.reassignedBy = userId\n task.reassignedAt = now\n task.reassignReason = reason ?? null\n task.updatedAt = now\n\n await em.flush()\n\n const instance = await em.findOne(WorkflowInstance, task.workflowInstanceId)\n if (instance) {\n await logWorkflowEvent(em, {\n workflowInstanceId: instance.id,\n stepInstanceId: task.stepInstanceId,\n branchInstanceId: task.branchInstanceId ?? null,\n eventType: 'USER_TASK_REASSIGNED',\n eventData: {\n taskId: task.id,\n taskName: task.taskName,\n reassignedBy: userId,\n reason: reason ?? null,\n from: previous,\n to: { assignedTo, assignedToRoles },\n },\n userId,\n tenantId: instance.tenantId,\n organizationId: instance.organizationId,\n })\n }\n\n return task\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Log workflow event to event sourcing table\n */\nasync function logWorkflowEvent(\n em: EntityManager,\n event: {\n workflowInstanceId: string\n stepInstanceId: string | null\n branchInstanceId?: string | null\n eventType: string\n eventData: any\n userId?: string\n tenantId: string\n organizationId: string\n }\n): Promise<WorkflowEvent> {\n const workflowEvent = em.create(WorkflowEvent, {\n ...event,\n occurredAt: new Date(),\n })\n\n await em.persist(workflowEvent).flush()\n return workflowEvent\n}\n\n/**\n * Validate form data against the task's authored schema.\n *\n * Required-field presence in BOTH accepted `formSchema` shapes: the JSON-Schema\n * form and the `{ fields: [...] }` form the Studio writes, whose per-field\n * `required: true` flag this used to ignore entirely \u2014 so a task authored in\n * the visual editor validated nothing however many fields its author marked\n * mandatory. Both shapes now resolve through `lib/task-form-schema.ts`, the\n * same module the renderer walks, so they cannot drift apart again.\n *\n * Presence-only, deliberately: type checking would need the full JSON-Schema\n * vocabulary, and what matters is that a required field cannot be skipped.\n *\n * @param formData - User-provided form data\n * @param formSchema - Authored schema, in either accepted shape\n * @throws Error if validation fails\n */\nexport function validateFormData(\n formData: Record<string, any>,\n formSchema: unknown\n): void {\n for (const field of readRequiredFormFields(formSchema)) {\n if (!(field in formData) || formData[field] === null || formData[field] === undefined) {\n throw new Error(`Required field missing: ${field}`)\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { flattenTaskText } from "./task-resolution.js";
|
|
2
|
+
const TASK_PRIORITY_VALUES = ["low", "medium", "high", "extreme"];
|
|
3
|
+
const TASK_ON_BREACH_ACTIONS = ["notify", "reassign", "route"];
|
|
4
|
+
const TASK_DECISION_STYLES = [
|
|
5
|
+
"primary",
|
|
6
|
+
"secondary",
|
|
7
|
+
"destructive"
|
|
8
|
+
];
|
|
9
|
+
const TASK_ASSIGNEE_KINDS = ["user", "customer"];
|
|
10
|
+
const TASK_ASSIGNEE_KIND_MODES = {
|
|
11
|
+
user: ["role", "user", "dynamic", "rule"],
|
|
12
|
+
customer: ["user", "dynamic"]
|
|
13
|
+
};
|
|
14
|
+
function isTaskAssigneeKind(value) {
|
|
15
|
+
return typeof value === "string" && TASK_ASSIGNEE_KINDS.includes(value);
|
|
16
|
+
}
|
|
17
|
+
function deriveTaskAssigneeKind(config) {
|
|
18
|
+
return config.assigneeKind === "customer" ? "customer" : "user";
|
|
19
|
+
}
|
|
20
|
+
function assignmentModesForAssigneeKind(kind) {
|
|
21
|
+
return TASK_ASSIGNEE_KIND_MODES[kind] ?? TASK_ASSIGNEE_KIND_MODES.user;
|
|
22
|
+
}
|
|
23
|
+
function coerceAssignmentModeToAssigneeKind(mode, kind) {
|
|
24
|
+
const allowed = assignmentModesForAssigneeKind(kind);
|
|
25
|
+
if (allowed.includes(mode)) return mode;
|
|
26
|
+
if (allowed.includes("dynamic")) return "dynamic";
|
|
27
|
+
return allowed[0] ?? "role";
|
|
28
|
+
}
|
|
29
|
+
function resolveTaskAssigneeKindPersistence(original, edited) {
|
|
30
|
+
if (edited === "customer") return "customer";
|
|
31
|
+
return original === "user" ? "user" : void 0;
|
|
32
|
+
}
|
|
33
|
+
const TEMPLATE_TOKEN_PATTERN = /\{\{[^}]+\}\}/;
|
|
34
|
+
let draftKeyCounter = 0;
|
|
35
|
+
function nextDraftKey(prefix) {
|
|
36
|
+
draftKeyCounter += 1;
|
|
37
|
+
return `${prefix}_${draftKeyCounter}`;
|
|
38
|
+
}
|
|
39
|
+
function generateDecisionId() {
|
|
40
|
+
return `d_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 11)}`;
|
|
41
|
+
}
|
|
42
|
+
function flattenTaskTextForEditing(value) {
|
|
43
|
+
return flattenTaskText(value) ?? "";
|
|
44
|
+
}
|
|
45
|
+
function applyEditedTaskText(original, edited) {
|
|
46
|
+
if (!edited.trim().length) return void 0;
|
|
47
|
+
if (original != null && flattenTaskTextForEditing(original) === edited) return original;
|
|
48
|
+
return edited;
|
|
49
|
+
}
|
|
50
|
+
function isTaskPriority(value) {
|
|
51
|
+
return typeof value === "string" && TASK_PRIORITY_VALUES.includes(value);
|
|
52
|
+
}
|
|
53
|
+
function deriveTaskAssignmentMode(config) {
|
|
54
|
+
if (typeof config.assignmentRule === "string" && config.assignmentRule.length > 0) return "rule";
|
|
55
|
+
const assignedTo = config.assignedTo;
|
|
56
|
+
if (typeof assignedTo === "string" && assignedTo.length > 0) {
|
|
57
|
+
return TEMPLATE_TOKEN_PATTERN.test(assignedTo) ? "dynamic" : "user";
|
|
58
|
+
}
|
|
59
|
+
return "role";
|
|
60
|
+
}
|
|
61
|
+
function entityBindingsToDrafts(bindings) {
|
|
62
|
+
if (!Array.isArray(bindings)) return [];
|
|
63
|
+
return bindings.map((binding) => ({
|
|
64
|
+
key: nextDraftKey("binding"),
|
|
65
|
+
entityType: typeof binding?.entityType === "string" ? binding.entityType : "",
|
|
66
|
+
idPath: typeof binding?.idPath === "string" ? binding.idPath : "",
|
|
67
|
+
label: flattenTaskTextForEditing(binding?.label),
|
|
68
|
+
...binding?.label != null ? { labelSource: binding.label } : {}
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
function draftsToEntityBindings(drafts) {
|
|
72
|
+
if (!Array.isArray(drafts)) return void 0;
|
|
73
|
+
const bindings = drafts.reduce((acc, draft) => {
|
|
74
|
+
const entityType = draft.entityType.trim();
|
|
75
|
+
const idPath = draft.idPath.trim();
|
|
76
|
+
if (!entityType || !idPath) return acc;
|
|
77
|
+
const label = applyEditedTaskText(draft.labelSource, draft.label);
|
|
78
|
+
acc.push({ entityType, idPath, ...label !== void 0 ? { label } : {} });
|
|
79
|
+
return acc;
|
|
80
|
+
}, []);
|
|
81
|
+
return bindings.length > 0 ? bindings : void 0;
|
|
82
|
+
}
|
|
83
|
+
function remindersToOffsets(reminders) {
|
|
84
|
+
if (!Array.isArray(reminders)) return [];
|
|
85
|
+
return reminders.map((reminder) => typeof reminder?.offset === "string" ? reminder.offset : "");
|
|
86
|
+
}
|
|
87
|
+
function offsetsToReminders(offsets) {
|
|
88
|
+
if (!Array.isArray(offsets)) return void 0;
|
|
89
|
+
const reminders = offsets.map((offset) => typeof offset === "string" ? offset.trim() : "").filter((offset) => offset.length > 0).map((offset) => ({ offset }));
|
|
90
|
+
return reminders.length > 0 ? reminders : void 0;
|
|
91
|
+
}
|
|
92
|
+
function onBreachToDraft(onBreach) {
|
|
93
|
+
return {
|
|
94
|
+
action: onBreach?.action ?? "",
|
|
95
|
+
reassignTo: onBreach?.reassignTo ?? "",
|
|
96
|
+
transitionId: onBreach?.transitionId ?? ""
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function draftToOnBreach(draft) {
|
|
100
|
+
const action = draft?.action;
|
|
101
|
+
if (!action) return void 0;
|
|
102
|
+
if (action === "reassign") {
|
|
103
|
+
const reassignTo = draft?.reassignTo.trim() ?? "";
|
|
104
|
+
return reassignTo ? { action, reassignTo } : { action };
|
|
105
|
+
}
|
|
106
|
+
if (action === "route") {
|
|
107
|
+
const transitionId = draft?.transitionId.trim() ?? "";
|
|
108
|
+
return transitionId ? { action, transitionId } : { action };
|
|
109
|
+
}
|
|
110
|
+
return { action };
|
|
111
|
+
}
|
|
112
|
+
function decisionsToDrafts(decisions) {
|
|
113
|
+
if (!Array.isArray(decisions)) return [];
|
|
114
|
+
return decisions.map((decision) => ({
|
|
115
|
+
key: nextDraftKey("decision"),
|
|
116
|
+
id: typeof decision?.id === "string" ? decision.id : "",
|
|
117
|
+
label: flattenTaskTextForEditing(decision?.label),
|
|
118
|
+
...decision?.label != null ? { labelSource: decision.label } : {},
|
|
119
|
+
transitionId: typeof decision?.transitionId === "string" ? decision.transitionId : "",
|
|
120
|
+
style: decision?.style ?? ""
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
function draftsToDecisions(drafts) {
|
|
124
|
+
if (!Array.isArray(drafts)) return void 0;
|
|
125
|
+
const decisions = drafts.reduce((acc, draft) => {
|
|
126
|
+
const id = draft.id.trim();
|
|
127
|
+
const transitionId = draft.transitionId.trim();
|
|
128
|
+
if (!id || !transitionId) return acc;
|
|
129
|
+
const label = applyEditedTaskText(draft.labelSource, draft.label) ?? id;
|
|
130
|
+
acc.push({ id, label, transitionId, ...draft.style ? { style: draft.style } : {} });
|
|
131
|
+
return acc;
|
|
132
|
+
}, []);
|
|
133
|
+
return decisions.length > 0 ? decisions : void 0;
|
|
134
|
+
}
|
|
135
|
+
function newDecisionDraft(transitionId = "") {
|
|
136
|
+
return { key: nextDraftKey("decision"), id: generateDecisionId(), label: "", transitionId, style: "" };
|
|
137
|
+
}
|
|
138
|
+
function newEntityBindingDraft() {
|
|
139
|
+
return { key: nextDraftKey("binding"), entityType: "", idPath: "", label: "" };
|
|
140
|
+
}
|
|
141
|
+
function resolveTaskDeadlinePersistence(config, edited) {
|
|
142
|
+
const duration = edited.trim();
|
|
143
|
+
if (!duration) return {};
|
|
144
|
+
if (config.deadline) {
|
|
145
|
+
return { deadline: config.deadline.duration === duration ? config.deadline : { duration } };
|
|
146
|
+
}
|
|
147
|
+
return { slaDuration: duration };
|
|
148
|
+
}
|
|
149
|
+
function readTaskDeadlineDraft(config) {
|
|
150
|
+
const duration = config.deadline?.duration ?? config.slaDuration;
|
|
151
|
+
return typeof duration === "string" ? duration : "";
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
TASK_ASSIGNEE_KINDS,
|
|
155
|
+
TASK_ASSIGNEE_KIND_MODES,
|
|
156
|
+
TASK_DECISION_STYLES,
|
|
157
|
+
TASK_ON_BREACH_ACTIONS,
|
|
158
|
+
TASK_PRIORITY_VALUES,
|
|
159
|
+
applyEditedTaskText,
|
|
160
|
+
assignmentModesForAssigneeKind,
|
|
161
|
+
coerceAssignmentModeToAssigneeKind,
|
|
162
|
+
decisionsToDrafts,
|
|
163
|
+
deriveTaskAssigneeKind,
|
|
164
|
+
deriveTaskAssignmentMode,
|
|
165
|
+
draftToOnBreach,
|
|
166
|
+
draftsToDecisions,
|
|
167
|
+
draftsToEntityBindings,
|
|
168
|
+
entityBindingsToDrafts,
|
|
169
|
+
flattenTaskTextForEditing,
|
|
170
|
+
generateDecisionId,
|
|
171
|
+
isTaskAssigneeKind,
|
|
172
|
+
isTaskPriority,
|
|
173
|
+
newDecisionDraft,
|
|
174
|
+
newEntityBindingDraft,
|
|
175
|
+
offsetsToReminders,
|
|
176
|
+
onBreachToDraft,
|
|
177
|
+
readTaskDeadlineDraft,
|
|
178
|
+
remindersToOffsets,
|
|
179
|
+
resolveTaskAssigneeKindPersistence,
|
|
180
|
+
resolveTaskDeadlinePersistence
|
|
181
|
+
};
|
|
182
|
+
//# sourceMappingURL=task-inspector-config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/workflows/lib/task-inspector-config.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Task inspector \u2194 `userTaskConfig` mapping (spec \u00A76.1).\n *\n * PURE by construction (no React, ORM, DI or xyflow imports): the inspector\n * sections are thin controls over the drafts this module produces, so every\n * rule about what a save writes is unit-testable without rendering a dialog.\n *\n * The governing rule everywhere below is UNTOUCHED MEANS UNCHANGED. A config\n * that carried no inspector vocabulary must serialize byte-identically after a\n * save that never touched these sections, and a value the author did not edit\n * must come back in the shape it was authored in \u2014 that is why every mapper\n * takes the ORIGINAL alongside the edited draft rather than rebuilding from\n * the draft alone.\n */\n\nimport { flattenTaskText } from './task-resolution'\nimport type {\n TaskDeadline,\n TaskDecision,\n TaskEntityBinding,\n TaskLocalizedString,\n TaskOnBreach,\n TaskPriority,\n TaskReminder,\n UserTaskAssigneeKind,\n UserTaskConfig,\n} from '../data/validators'\n\n/** Mirrors the platform's priority labels; `''` is \"not set\". */\nexport const TASK_PRIORITY_VALUES: readonly TaskPriority[] = ['low', 'medium', 'high', 'extreme'] as const\n\nexport const TASK_ON_BREACH_ACTIONS: readonly TaskOnBreach['action'][] = ['notify', 'reassign', 'route'] as const\n\nexport const TASK_DECISION_STYLES: readonly NonNullable<TaskDecision['style']>[] = [\n 'primary',\n 'secondary',\n 'destructive',\n] as const\n\n/**\n * Which of the four \u00A76.1 assignment tabs a stored config belongs to. Derived,\n * never persisted: the tab IS the three assignment keys, so there is no fifth\n * source of truth to keep in sync.\n */\nexport type TaskAssignmentMode = 'role' | 'user' | 'dynamic' | 'rule'\n\n/**\n * Which principal namespace the task is addressed to (design \u00A77.1). `'user'` is\n * the backoffice; `'customer'` is a portal principal, and the only value the\n * engine treats as portal work.\n */\nexport const TASK_ASSIGNEE_KINDS: readonly UserTaskAssigneeKind[] = ['user', 'customer'] as const\n\n/**\n * The assignment modes each audience can actually be EXECUTED in \u2014 read off\n * `resolveTaskAssignment`, not off what the tab strip happens to render.\n *\n * `assigneeKind: 'customer'` is honoured ONLY when an individual assignee\n * resolves to a non-empty string, and it forces `assignedToRoles` to null. So\n * the two modes that name no individual are inert for a portal task: a role\n * queue leaves `assignedTo` null (the row is created backoffice), and\n * `assignmentRule` is not read by `resolveTaskAssignment` at all. Offering them\n * under the customer audience would be offering an author a control the engine\n * silently discards.\n *\n * Order mirrors the full list so a tab does not move when the audience changes.\n */\nexport const TASK_ASSIGNEE_KIND_MODES: Record<UserTaskAssigneeKind, readonly TaskAssignmentMode[]> = {\n user: ['role', 'user', 'dynamic', 'rule'],\n customer: ['user', 'dynamic'],\n}\n\nexport function isTaskAssigneeKind(value: unknown): value is UserTaskAssigneeKind {\n return typeof value === 'string' && (TASK_ASSIGNEE_KINDS as readonly string[]).includes(value)\n}\n\n/**\n * The audience a stored config opens on. Absent means `'user'` \u2014 which is what\n * every definition authored before the key existed has always meant, and why\n * nothing has to be written for the default.\n */\nexport function deriveTaskAssigneeKind(\n config: Pick<UserTaskConfig, 'assigneeKind'>,\n): UserTaskAssigneeKind {\n return config.assigneeKind === 'customer' ? 'customer' : 'user'\n}\n\nexport function assignmentModesForAssigneeKind(\n kind: UserTaskAssigneeKind,\n): readonly TaskAssignmentMode[] {\n return TASK_ASSIGNEE_KIND_MODES[kind] ?? TASK_ASSIGNEE_KIND_MODES.user\n}\n\n/**\n * The tab a mode collapses to when the audience no longer offers it.\n *\n * Only the customer audience narrows the set, and what it drops are the two\n * modes that name no individual. Landing on Dynamic rather than on the first\n * remaining tab is the honest default: a portal principal's id comes out of the\n * run context, it is not a literal an author types.\n */\nexport function coerceAssignmentModeToAssigneeKind(\n mode: TaskAssignmentMode,\n kind: UserTaskAssigneeKind,\n): TaskAssignmentMode {\n const allowed = assignmentModesForAssigneeKind(kind)\n if (allowed.includes(mode)) return mode\n if (allowed.includes('dynamic')) return 'dynamic'\n return allowed[0] ?? 'role'\n}\n\n/**\n * What the audience picker writes back.\n *\n * `'customer'` is the only value the engine acts on, so it is the only value\n * that has to be persisted: a step left on the backoffice audience writes\n * NOTHING and a config that never declared the key serializes byte-identically\n * after a save that opened the inspector. The one exception is a config that\n * already spelled `'user'` explicitly \u2014 the same \"untouched means unchanged\"\n * rule `resolveTaskDeadlinePersistence` follows for its two keys, so opening the\n * inspector never rewrites a shape the author chose.\n */\nexport function resolveTaskAssigneeKindPersistence(\n original: UserTaskAssigneeKind | undefined,\n edited: UserTaskAssigneeKind,\n): UserTaskAssigneeKind | undefined {\n if (edited === 'customer') return 'customer'\n return original === 'user' ? 'user' : undefined\n}\n\nexport interface TaskEntityBindingDraft {\n /** Stable React key; never persisted. */\n key: string\n entityType: string\n idPath: string\n label: string\n /** The authored label before editing, so a locale map survives an untouched save. */\n labelSource?: TaskLocalizedString\n}\n\nexport interface TaskOnBreachDraft {\n action: '' | TaskOnBreach['action']\n reassignTo: string\n transitionId: string\n}\n\nexport interface TaskDecisionDraft {\n /** Stable React key; never persisted (the durable `id` below is). */\n key: string\n id: string\n label: string\n labelSource?: TaskLocalizedString\n transitionId: string\n style: '' | NonNullable<TaskDecision['style']>\n}\n\nconst TEMPLATE_TOKEN_PATTERN = /\\{\\{[^}]+\\}\\}/\n\nlet draftKeyCounter = 0\n\nfunction nextDraftKey(prefix: string): string {\n draftKeyCounter += 1\n return `${prefix}_${draftKeyCounter}`\n}\n\n/** A durable, opaque decision id \u2014 never an index, never derived from the label. */\nexport function generateDecisionId(): string {\n return `d_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 11)}`\n}\n\n/** The single-line form of authored copy, for editing in a plain control. */\nexport function flattenTaskTextForEditing(value: TaskLocalizedString | undefined | null): string {\n return flattenTaskText(value) ?? ''\n}\n\n/**\n * Write edited copy back. Text identical to what the control was seeded with\n * returns the ORIGINAL value, so a locale map an author never touched is never\n * flattened to the tenant default by opening the inspector.\n */\nexport function applyEditedTaskText(\n original: TaskLocalizedString | undefined | null,\n edited: string,\n): TaskLocalizedString | undefined {\n if (!edited.trim().length) return undefined\n if (original != null && flattenTaskTextForEditing(original) === edited) return original\n return edited\n}\n\nexport function isTaskPriority(value: unknown): value is TaskPriority {\n return typeof value === 'string' && (TASK_PRIORITY_VALUES as readonly string[]).includes(value)\n}\n\n/**\n * Which tab a stored assignment opens on. An `assignedTo` carrying a `{{\u2026}}`\n * pill is Dynamic; a plain one is User; a business rule wins over both because\n * it is the only form the engine resolves through another module.\n */\nexport function deriveTaskAssignmentMode(\n config: Pick<UserTaskConfig, 'assignedTo' | 'assignmentRule'>,\n): TaskAssignmentMode {\n if (typeof config.assignmentRule === 'string' && config.assignmentRule.length > 0) return 'rule'\n const assignedTo = config.assignedTo\n if (typeof assignedTo === 'string' && assignedTo.length > 0) {\n return TEMPLATE_TOKEN_PATTERN.test(assignedTo) ? 'dynamic' : 'user'\n }\n return 'role'\n}\n\nexport function entityBindingsToDrafts(\n bindings: TaskEntityBinding[] | undefined | null,\n): TaskEntityBindingDraft[] {\n if (!Array.isArray(bindings)) return []\n return bindings.map((binding) => ({\n key: nextDraftKey('binding'),\n entityType: typeof binding?.entityType === 'string' ? binding.entityType : '',\n idPath: typeof binding?.idPath === 'string' ? binding.idPath : '',\n label: flattenTaskTextForEditing(binding?.label),\n ...(binding?.label != null ? { labelSource: binding.label } : {}),\n }))\n}\n\n/** Rows missing an entity type or an id path describe nothing and are dropped. */\nexport function draftsToEntityBindings(\n drafts: TaskEntityBindingDraft[] | undefined | null,\n): TaskEntityBinding[] | undefined {\n if (!Array.isArray(drafts)) return undefined\n const bindings = drafts.reduce<TaskEntityBinding[]>((acc, draft) => {\n const entityType = draft.entityType.trim()\n const idPath = draft.idPath.trim()\n if (!entityType || !idPath) return acc\n const label = applyEditedTaskText(draft.labelSource, draft.label)\n acc.push({ entityType, idPath, ...(label !== undefined ? { label } : {}) })\n return acc\n }, [])\n return bindings.length > 0 ? bindings : undefined\n}\n\nexport function remindersToOffsets(reminders: TaskReminder[] | undefined | null): string[] {\n if (!Array.isArray(reminders)) return []\n return reminders.map((reminder) => (typeof reminder?.offset === 'string' ? reminder.offset : ''))\n}\n\nexport function offsetsToReminders(offsets: string[] | undefined | null): TaskReminder[] | undefined {\n if (!Array.isArray(offsets)) return undefined\n const reminders = offsets\n .map((offset) => (typeof offset === 'string' ? offset.trim() : ''))\n .filter((offset) => offset.length > 0)\n .map((offset) => ({ offset }))\n return reminders.length > 0 ? reminders : undefined\n}\n\nexport function onBreachToDraft(onBreach: TaskOnBreach | undefined | null): TaskOnBreachDraft {\n return {\n action: onBreach?.action ?? '',\n reassignTo: onBreach?.reassignTo ?? '',\n transitionId: onBreach?.transitionId ?? '',\n }\n}\n\n/** Only the qualifier the chosen action actually uses is persisted. */\nexport function draftToOnBreach(draft: TaskOnBreachDraft | undefined | null): TaskOnBreach | undefined {\n const action = draft?.action\n if (!action) return undefined\n if (action === 'reassign') {\n const reassignTo = draft?.reassignTo.trim() ?? ''\n return reassignTo ? { action, reassignTo } : { action }\n }\n if (action === 'route') {\n const transitionId = draft?.transitionId.trim() ?? ''\n return transitionId ? { action, transitionId } : { action }\n }\n return { action }\n}\n\nexport function decisionsToDrafts(decisions: TaskDecision[] | undefined | null): TaskDecisionDraft[] {\n if (!Array.isArray(decisions)) return []\n return decisions.map((decision) => ({\n key: nextDraftKey('decision'),\n id: typeof decision?.id === 'string' ? decision.id : '',\n label: flattenTaskTextForEditing(decision?.label),\n ...(decision?.label != null ? { labelSource: decision.label } : {}),\n transitionId: typeof decision?.transitionId === 'string' ? decision.transitionId : '',\n style: decision?.style ?? '',\n }))\n}\n\n/**\n * A decision without a durable id or a route it points at is not a button the\n * task surface could render, so it is dropped rather than persisted broken. A\n * decision whose route was DELETED still persists \u2014 that is the Problems-panel\n * warning's job, not a silent deletion of the author's work.\n */\nexport function draftsToDecisions(\n drafts: TaskDecisionDraft[] | undefined | null,\n): TaskDecision[] | undefined {\n if (!Array.isArray(drafts)) return undefined\n const decisions = drafts.reduce<TaskDecision[]>((acc, draft) => {\n const id = draft.id.trim()\n const transitionId = draft.transitionId.trim()\n if (!id || !transitionId) return acc\n const label = applyEditedTaskText(draft.labelSource, draft.label) ?? id\n acc.push({ id, label, transitionId, ...(draft.style ? { style: draft.style } : {}) })\n return acc\n }, [])\n return decisions.length > 0 ? decisions : undefined\n}\n\nexport function newDecisionDraft(transitionId = ''): TaskDecisionDraft {\n return { key: nextDraftKey('decision'), id: generateDecisionId(), label: '', transitionId, style: '' }\n}\n\nexport function newEntityBindingDraft(): TaskEntityBindingDraft {\n return { key: nextDraftKey('binding'), entityType: '', idPath: '', label: '' }\n}\n\nexport interface TaskDeadlinePersistence {\n deadline?: TaskDeadline\n slaDuration?: string\n}\n\n/**\n * Which key the edited deadline is written back to.\n *\n * `deadline` is the business-word superset and `slaDuration` the original bare\n * form, and 1.1 declared that the bare form keeps working forever. So the\n * inspector edits whichever key the config already carries and NEVER migrates\n * one to the other: a definition authored before this section keeps saving the\n * shape an older engine can read, and a definition that already declares a\n * `deadline` keeps it.\n */\nexport function resolveTaskDeadlinePersistence(\n config: Pick<UserTaskConfig, 'deadline' | 'slaDuration'>,\n edited: string,\n): TaskDeadlinePersistence {\n const duration = edited.trim()\n if (!duration) return {}\n if (config.deadline) {\n return { deadline: config.deadline.duration === duration ? config.deadline : { duration } }\n }\n return { slaDuration: duration }\n}\n\n/** The duration the deadline control opens with, whichever key carries it. */\nexport function readTaskDeadlineDraft(config: Pick<UserTaskConfig, 'deadline' | 'slaDuration'>): string {\n const duration = config.deadline?.duration ?? config.slaDuration\n return typeof duration === 'string' ? duration : ''\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const TEXT_FILTERS = ["status", "workflowInstanceId"];
|
|
2
|
+
const FLAG_FILTERS = ["myTasks", "overdue"];
|
|
3
|
+
function buildTaskListQueryParams(filters, pagination) {
|
|
4
|
+
const params = new URLSearchParams();
|
|
5
|
+
params.set("limit", String(pagination.limit));
|
|
6
|
+
params.set("offset", String(pagination.offset));
|
|
7
|
+
for (const key of TEXT_FILTERS) {
|
|
8
|
+
const value = filters[key];
|
|
9
|
+
if (typeof value === "string" && value.length > 0) params.set(key, value);
|
|
10
|
+
}
|
|
11
|
+
for (const key of FLAG_FILTERS) {
|
|
12
|
+
if (filters[key] === "true") params.set(key, "true");
|
|
13
|
+
}
|
|
14
|
+
return params;
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
buildTaskListQueryParams
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=task-list-query.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/workflows/lib/task-list-query.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Query-string builder for the user-task inbox list request (PURE).\n *\n * The inbox defaults its view filter to \"My Tasks\", so every filter the page\n * offers has to reach `GET /api/workflows/tasks`. Forwarding only a subset is\n * silent: the default view claims to show the caller's tasks while listing\n * every task in the organization. Keeping the builder outside the component\n * makes the forwarded set unit-testable.\n */\n\nexport type TaskListFilterValues = Record<string, unknown>\n\nexport type TaskListPagination = {\n limit: number\n offset: number\n}\n\nconst TEXT_FILTERS = ['status', 'workflowInstanceId'] as const\nconst FLAG_FILTERS = ['myTasks', 'overdue'] as const\n\n/**\n * @deprecated The inbox moved to `/backend/work-inbox`; use\n * `buildWorkInboxListQueryParams` from `lib/work-inbox/query.ts`, which forwards\n * the kind/module/entity-type/role filters the Work Inbox adds. Kept exported\n * because import paths are a frozen contract surface\n * (BACKWARD_COMPATIBILITY.md \u00A73) and `GET /api/workflows/tasks` still exists.\n */\nexport function buildTaskListQueryParams(\n filters: TaskListFilterValues,\n pagination: TaskListPagination,\n): URLSearchParams {\n const params = new URLSearchParams()\n params.set('limit', String(pagination.limit))\n params.set('offset', String(pagination.offset))\n\n for (const key of TEXT_FILTERS) {\n const value = filters[key]\n if (typeof value === 'string' && value.length > 0) params.set(key, value)\n }\n\n for (const key of FLAG_FILTERS) {\n if (filters[key] === 'true') params.set(key, 'true')\n }\n\n return params\n}\n"],
|
|
5
|
+
"mappings": "AAiBA,MAAM,eAAe,CAAC,UAAU,oBAAoB;AACpD,MAAM,eAAe,CAAC,WAAW,SAAS;AASnC,SAAS,yBACd,SACA,YACiB;AACjB,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,SAAS,OAAO,WAAW,KAAK,CAAC;AAC5C,SAAO,IAAI,UAAU,OAAO,WAAW,MAAM,CAAC;AAE9C,aAAW,OAAO,cAAc;AAC9B,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,OAAO,UAAU,YAAY,MAAM,SAAS,EAAG,QAAO,IAAI,KAAK,KAAK;AAAA,EAC1E;AAEA,aAAW,OAAO,cAAc;AAC9B,QAAI,QAAQ,GAAG,MAAM,OAAQ,QAAO,IAAI,KAAK,MAAM;AAAA,EACrD;AAEA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { resolveNotificationService } from "../../notifications/lib/notificationService.js";
|
|
2
|
+
import {
|
|
3
|
+
buildNotificationFromType,
|
|
4
|
+
buildRoleNotificationFromType
|
|
5
|
+
} from "../../notifications/lib/notificationBuilder.js";
|
|
6
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
7
|
+
const logger = createLogger("workflows");
|
|
8
|
+
const TASK_NOTIFICATION_SOURCE_ENTITY_TYPE = "workflows:user_task";
|
|
9
|
+
function buildTaskDeepLink(taskId) {
|
|
10
|
+
return `/backend/tasks/${taskId}`;
|
|
11
|
+
}
|
|
12
|
+
function buildTaskNotificationGroupKey(taskId, notificationType) {
|
|
13
|
+
const base = `${TASK_NOTIFICATION_SOURCE_ENTITY_TYPE}:${taskId}`;
|
|
14
|
+
return notificationType ? `${base}:${notificationType}` : base;
|
|
15
|
+
}
|
|
16
|
+
async function resolveRoleIdsByName(ctx, tenantId, roleNames) {
|
|
17
|
+
const rootEm = ctx.resolve("em");
|
|
18
|
+
const em = rootEm.fork();
|
|
19
|
+
const { findWithDecryption } = await import("@open-mercato/shared/lib/encryption/find");
|
|
20
|
+
const { Role } = await import("../../auth/data/entities.js");
|
|
21
|
+
const roles = await findWithDecryption(
|
|
22
|
+
em,
|
|
23
|
+
Role,
|
|
24
|
+
{ name: { $in: roleNames }, tenantId, deletedAt: null },
|
|
25
|
+
{},
|
|
26
|
+
{ tenantId }
|
|
27
|
+
);
|
|
28
|
+
return roles.map((role) => role.id).filter((roleId) => typeof roleId === "string" && roleId.length > 0);
|
|
29
|
+
}
|
|
30
|
+
function normalizeAssignedRoles(roles) {
|
|
31
|
+
return Array.isArray(roles) ? roles.filter((role) => typeof role === "string" && role.length > 0) : [];
|
|
32
|
+
}
|
|
33
|
+
async function deliverTaskNotification(ctx, typeDef, recipients, content, component) {
|
|
34
|
+
const assignedToRoles = normalizeAssignedRoles(recipients.assignedToRoles);
|
|
35
|
+
if (!recipients.assignedUserId && assignedToRoles.length === 0) return;
|
|
36
|
+
const effectiveTypeDef = content.actions ? {
|
|
37
|
+
...typeDef,
|
|
38
|
+
actions: content.actions,
|
|
39
|
+
...content.primaryActionId ? { primaryActionId: content.primaryActionId } : {}
|
|
40
|
+
} : typeDef;
|
|
41
|
+
try {
|
|
42
|
+
const notificationService = resolveNotificationService(ctx);
|
|
43
|
+
const scope = {
|
|
44
|
+
tenantId: content.tenantId,
|
|
45
|
+
organizationId: content.organizationId ?? null
|
|
46
|
+
};
|
|
47
|
+
const common = {
|
|
48
|
+
bodyVariables: content.bodyVariables,
|
|
49
|
+
sourceEntityType: TASK_NOTIFICATION_SOURCE_ENTITY_TYPE,
|
|
50
|
+
sourceEntityId: content.taskId,
|
|
51
|
+
linkHref: buildTaskDeepLink(content.taskId),
|
|
52
|
+
groupKey: content.groupKey
|
|
53
|
+
};
|
|
54
|
+
if (recipients.assignedUserId) {
|
|
55
|
+
await notificationService.create(
|
|
56
|
+
buildNotificationFromType(effectiveTypeDef, {
|
|
57
|
+
...common,
|
|
58
|
+
recipientUserId: recipients.assignedUserId
|
|
59
|
+
}),
|
|
60
|
+
scope
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const roleIds = await resolveRoleIdsByName(ctx, content.tenantId, assignedToRoles);
|
|
65
|
+
if (roleIds.length === 0) {
|
|
66
|
+
logger.warn("Task assigned to roles that resolve to no role in this tenant", {
|
|
67
|
+
component,
|
|
68
|
+
taskId: content.taskId
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
for (const roleId of roleIds) {
|
|
73
|
+
await notificationService.createForRole(
|
|
74
|
+
buildRoleNotificationFromType(effectiveTypeDef, { ...common, roleId }),
|
|
75
|
+
scope
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
logger.error("Failed to create notification", { component, err });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function notifyTaskLifecycleEvent(options) {
|
|
83
|
+
const { ctx, payload, notificationType, component } = options;
|
|
84
|
+
if (!payload?.taskId || !payload?.tenantId) return;
|
|
85
|
+
const typeDef = options.notificationTypes.find((type) => type.type === notificationType);
|
|
86
|
+
if (!typeDef) return;
|
|
87
|
+
await deliverTaskNotification(
|
|
88
|
+
ctx,
|
|
89
|
+
typeDef,
|
|
90
|
+
{ assignedUserId: payload.assignedUserId, assignedToRoles: payload.assignedToRoles },
|
|
91
|
+
{
|
|
92
|
+
taskId: payload.taskId,
|
|
93
|
+
tenantId: payload.tenantId,
|
|
94
|
+
organizationId: payload.organizationId ?? null,
|
|
95
|
+
bodyVariables: {
|
|
96
|
+
taskName: payload.taskName,
|
|
97
|
+
workflowName: payload.workflowName,
|
|
98
|
+
dueDate: payload.dueDate ?? ""
|
|
99
|
+
},
|
|
100
|
+
groupKey: buildTaskNotificationGroupKey(
|
|
101
|
+
payload.taskId,
|
|
102
|
+
options.groupByType ? notificationType : void 0
|
|
103
|
+
),
|
|
104
|
+
...options.actions ? { actions: options.actions } : {},
|
|
105
|
+
...options.primaryActionId ? { primaryActionId: options.primaryActionId } : {}
|
|
106
|
+
},
|
|
107
|
+
component
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
export {
|
|
111
|
+
TASK_NOTIFICATION_SOURCE_ENTITY_TYPE,
|
|
112
|
+
buildTaskDeepLink,
|
|
113
|
+
buildTaskNotificationGroupKey,
|
|
114
|
+
deliverTaskNotification,
|
|
115
|
+
normalizeAssignedRoles,
|
|
116
|
+
notifyTaskLifecycleEvent,
|
|
117
|
+
resolveRoleIdsByName
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=task-notifications.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/workflows/lib/task-notifications.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Delivering a task notification to whoever the task actually names.\n *\n * One place, three subscribers: assignment, reminder and deadline breach all\n * address the same audience \u2014 the individual assignee when there is one, and\n * otherwise every member of the authored role queue. Keeping the recipient\n * resolution here is what stops a reminder from reaching a narrower audience\n * than the assignment did.\n *\n * The caller supplies the `groupKey` so a retried delivery refreshes one row in\n * place. Assignment keeps its historic bare `workflows:user_task:<id>` key;\n * reminder and breach suffix the type, so a reminder never overwrites the\n * assignment it is reminding about.\n */\n\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'\nimport { resolveNotificationService } from '../../notifications/lib/notificationService'\nimport {\n buildNotificationFromType,\n buildRoleNotificationFromType,\n} from '../../notifications/lib/notificationBuilder'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('workflows')\n\nexport interface TaskNotificationResolverContext {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport interface TaskNotificationRecipients {\n assignedUserId?: string | null\n assignedToRoles?: string[] | null\n}\n\nexport interface TaskNotificationContent {\n taskId: string\n tenantId: string\n organizationId?: string | null\n bodyVariables: Record<string, string>\n groupKey: string\n /** Overrides the type definition's static actions when the caller computed them per task. */\n actions?: NotificationTypeDefinition['actions']\n primaryActionId?: string\n}\n\nexport const TASK_NOTIFICATION_SOURCE_ENTITY_TYPE = 'workflows:user_task'\n\nexport function buildTaskDeepLink(taskId: string): string {\n return `/backend/tasks/${taskId}`\n}\n\n/** Historic key for the assignment notification; kept byte-identical. */\nexport function buildTaskNotificationGroupKey(taskId: string, notificationType?: string): string {\n const base = `${TASK_NOTIFICATION_SOURCE_ENTITY_TYPE}:${taskId}`\n return notificationType ? `${base}:${notificationType}` : base\n}\n\n/**\n * `UserTask.assignedToRoles` stores role NAMES (that is what the Studio's role\n * picker and the task API's `myTasks` filter both speak), while the\n * notification service addresses a role by id. Resolve the names against the\n * caller's tenant so a role name from another tenant can never widen delivery.\n */\nexport async function resolveRoleIdsByName(\n ctx: TaskNotificationResolverContext,\n tenantId: string,\n roleNames: string[]\n): Promise<string[]> {\n const rootEm = ctx.resolve<EntityManager>('em')\n const em = rootEm.fork()\n const { findWithDecryption } = await import('@open-mercato/shared/lib/encryption/find')\n const { Role } = await import('../../auth/data/entities')\n\n const roles = await findWithDecryption(\n em,\n Role,\n { name: { $in: roleNames }, tenantId, deletedAt: null },\n {},\n { tenantId }\n )\n\n return roles\n .map((role) => role.id)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)\n}\n\nexport function normalizeAssignedRoles(roles: unknown): string[] {\n return Array.isArray(roles)\n ? roles.filter((role): role is string => typeof role === 'string' && role.length > 0)\n : []\n}\n\n/**\n * Create the notification for one task event, addressed to the assignee or to\n * the role queue. Best-effort by contract: a delivery failure must never break\n * the workflow engine or the queue job that triggered it.\n */\nexport async function deliverTaskNotification(\n ctx: TaskNotificationResolverContext,\n typeDef: NotificationTypeDefinition,\n recipients: TaskNotificationRecipients,\n content: TaskNotificationContent,\n component: string\n): Promise<void> {\n const assignedToRoles = normalizeAssignedRoles(recipients.assignedToRoles)\n if (!recipients.assignedUserId && assignedToRoles.length === 0) return\n\n const effectiveTypeDef: NotificationTypeDefinition = content.actions\n ? {\n ...typeDef,\n actions: content.actions,\n ...(content.primaryActionId ? { primaryActionId: content.primaryActionId } : {}),\n }\n : typeDef\n\n try {\n const notificationService = resolveNotificationService(ctx)\n const scope = {\n tenantId: content.tenantId,\n organizationId: content.organizationId ?? null,\n }\n\n const common = {\n bodyVariables: content.bodyVariables,\n sourceEntityType: TASK_NOTIFICATION_SOURCE_ENTITY_TYPE,\n sourceEntityId: content.taskId,\n linkHref: buildTaskDeepLink(content.taskId),\n groupKey: content.groupKey,\n }\n\n if (recipients.assignedUserId) {\n await notificationService.create(\n buildNotificationFromType(effectiveTypeDef, {\n ...common,\n recipientUserId: recipients.assignedUserId,\n }),\n scope\n )\n return\n }\n\n const roleIds = await resolveRoleIdsByName(ctx, content.tenantId, assignedToRoles)\n if (roleIds.length === 0) {\n logger.warn('Task assigned to roles that resolve to no role in this tenant', {\n component,\n taskId: content.taskId,\n })\n return\n }\n\n for (const roleId of roleIds) {\n await notificationService.createForRole(\n buildRoleNotificationFromType(effectiveTypeDef, { ...common, roleId }),\n scope\n )\n }\n } catch (err) {\n logger.error('Failed to create notification', { component, err })\n }\n}\n\n/**\n * Payload shape shared by every task lifecycle event that produces a\n * notification. The three subscribers differ only in which notification type\n * they name, which is why they route through one function.\n */\nexport type TaskLifecycleNotificationPayload = {\n taskId: string\n taskName: string\n workflowName: string\n assignedUserId?: string | null\n assignedToRoles?: string[] | null\n dueDate?: string | null\n tenantId: string\n organizationId?: string | null\n}\n\nexport async function notifyTaskLifecycleEvent(options: {\n ctx: TaskNotificationResolverContext\n notificationTypes: NotificationTypeDefinition[]\n notificationType: string\n payload: TaskLifecycleNotificationPayload\n /** Omit to reuse the historic bare group key (assignment only). */\n groupByType?: boolean\n actions?: NotificationTypeDefinition['actions']\n primaryActionId?: string\n component: string\n}): Promise<void> {\n const { ctx, payload, notificationType, component } = options\n if (!payload?.taskId || !payload?.tenantId) return\n\n const typeDef = options.notificationTypes.find((type) => type.type === notificationType)\n if (!typeDef) return\n\n await deliverTaskNotification(\n ctx,\n typeDef,\n { assignedUserId: payload.assignedUserId, assignedToRoles: payload.assignedToRoles },\n {\n taskId: payload.taskId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n bodyVariables: {\n taskName: payload.taskName,\n workflowName: payload.workflowName,\n dueDate: payload.dueDate ?? '',\n },\n groupKey: buildTaskNotificationGroupKey(\n payload.taskId,\n options.groupByType ? notificationType : undefined\n ),\n ...(options.actions ? { actions: options.actions } : {}),\n ...(options.primaryActionId ? { primaryActionId: options.primaryActionId } : {}),\n },\n component\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { parseBooleanFromUnknown } from "@open-mercato/shared/lib/boolean";
|
|
2
|
+
const WORKFLOWS_CONFIG_MODULE = "workflows";
|
|
3
|
+
const TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY = "task_permissions_business_context";
|
|
4
|
+
const TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT = true;
|
|
5
|
+
async function readTaskPermissionsBusinessContext(moduleConfigService, tenantId) {
|
|
6
|
+
if (!moduleConfigService) return TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT;
|
|
7
|
+
try {
|
|
8
|
+
const value = await moduleConfigService.getValue(
|
|
9
|
+
WORKFLOWS_CONFIG_MODULE,
|
|
10
|
+
TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY,
|
|
11
|
+
{
|
|
12
|
+
defaultValue: TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT,
|
|
13
|
+
scope: { tenantId }
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
const parsed = parseBooleanFromUnknown(value);
|
|
17
|
+
return parsed === null ? TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT : parsed;
|
|
18
|
+
} catch {
|
|
19
|
+
return TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function resolveTaskVisibilityPolicy(moduleConfigService, tenantId) {
|
|
23
|
+
return {
|
|
24
|
+
businessContextEnabled: await readTaskPermissionsBusinessContext(moduleConfigService, tenantId)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async function writeTaskPermissionsBusinessContext(moduleConfigService, tenantId, enabled) {
|
|
28
|
+
await moduleConfigService.setValue(
|
|
29
|
+
WORKFLOWS_CONFIG_MODULE,
|
|
30
|
+
TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY,
|
|
31
|
+
enabled,
|
|
32
|
+
{ tenantId }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT,
|
|
37
|
+
TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY,
|
|
38
|
+
WORKFLOWS_CONFIG_MODULE,
|
|
39
|
+
readTaskPermissionsBusinessContext,
|
|
40
|
+
resolveTaskVisibilityPolicy,
|
|
41
|
+
writeTaskPermissionsBusinessContext
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=task-permission-settings.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/workflows/lib/task-permission-settings.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The tenant opt-out from the \u00A76.4 task-permission model.\n *\n * ## What it is\n *\n * One tenant-scoped boolean, `workflows` / `task_permissions_business_context`,\n * default `true`. `true` is the new model. `false` restores the pre-change READ\n * filter \u2014 `SCOPE \u2227 workflows.tasks.view` \u2014 on the task list, the task detail\n * and the work inbox, and nothing else.\n *\n * ## What it is NOT\n *\n * **It is a `SELECT` filter, not an authorization mode.** `actable` and\n * `claimable` are computed by the new rule whether it is on or off: completing\n * still requires being the assignee or claimant, claiming still requires role\n * overlap on an unclaimed `PENDING` row, tenant and organization scoping are\n * never reachable by a setting, and the portal routes never consult it at all.\n * If `businessContextEnabled` is read anywhere outside a read filter, that is a\n * review failure. The predicate enforces this structurally \u2014 the flag reaches\n * `decideTaskVisibility` as `policy` and only ever widens `visible`.\n *\n * ## Why the read fails to `true`\n *\n * The exemplar this route is copied from (`entities/api/entity-settings.ts`)\n * swallows read errors and returns its permissive default. Inverted here on\n * purpose: a config read that fails \u2014 no container, no service, a broken row \u2014\n * must NOT silently reopen every task in the tenant to everyone holding\n * `workflows.tasks.view`. Only an explicitly stored, explicitly false value\n * opts a tenant out.\n *\n * ## Lifecycle\n *\n * A migration aid with a removal date. It exists for one minor release so a\n * tenant with an unusual role topology can keep the lights on while they grant\n * `workflows.tasks.view_all`, and it is removed in the release after. A\n * permanent opt-out is a permanent second security model to test.\n */\n\nimport { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'\nimport type { TaskVisibilityPolicy } from './task-visibility'\n\n/** `module_configs.module_id` for the workflows module's own settings. */\nexport const WORKFLOWS_CONFIG_MODULE = 'workflows'\n\n/** `module_configs.name`. Well within `moduleConfigKeySchema`'s 128 chars. */\nexport const TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY = 'task_permissions_business_context'\n\n/** Default-ON at release, per the spec's flagged BC paragraph. */\nexport const TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT = true\n\n/** The `ModuleConfigService` slice this needs, so tests need no container. */\nexport type TaskPermissionsConfigService = {\n getValue: (\n moduleId: string,\n name: string,\n options?: { defaultValue?: unknown; scope?: { tenantId?: string | null } },\n ) => Promise<unknown>\n setValue: (\n moduleId: string,\n name: string,\n value: unknown,\n scope?: { tenantId?: string | null },\n ) => Promise<unknown>\n}\n\n/**\n * Read the tenant's setting.\n *\n * Tenant-scoped only \u2014 never organization-scoped. One organization inside a\n * tenant running wide open next to a narrow one is unreviewable, so the scope\n * carries `tenantId` and nothing else. Callers MUST pass the tenant id from the\n * authenticated context, never from request input.\n */\nexport async function readTaskPermissionsBusinessContext(\n moduleConfigService: TaskPermissionsConfigService | null | undefined,\n tenantId: string | null,\n): Promise<boolean> {\n if (!moduleConfigService) return TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT\n try {\n const value = await moduleConfigService.getValue(\n WORKFLOWS_CONFIG_MODULE,\n TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY,\n {\n defaultValue: TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT,\n scope: { tenantId },\n },\n )\n const parsed = parseBooleanFromUnknown(value)\n // An unparseable stored value is a resolution failure, not an opt-out.\n return parsed === null ? TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT : parsed\n } catch {\n return TASK_PERMISSIONS_BUSINESS_CONTEXT_DEFAULT\n }\n}\n\n/** The `policy` argument `decideTaskVisibility` and the filter builders take. */\nexport async function resolveTaskVisibilityPolicy(\n moduleConfigService: TaskPermissionsConfigService | null | undefined,\n tenantId: string | null,\n): Promise<TaskVisibilityPolicy> {\n return {\n businessContextEnabled: await readTaskPermissionsBusinessContext(moduleConfigService, tenantId),\n }\n}\n\nexport async function writeTaskPermissionsBusinessContext(\n moduleConfigService: TaskPermissionsConfigService,\n tenantId: string,\n enabled: boolean,\n): Promise<void> {\n await moduleConfigService.setValue(\n WORKFLOWS_CONFIG_MODULE,\n TASK_PERMISSIONS_BUSINESS_CONTEXT_KEY,\n enabled,\n { tenantId },\n )\n}\n"],
|
|
5
|
+
"mappings": "AAsCA,SAAS,+BAA+B;AAIjC,MAAM,0BAA0B;AAGhC,MAAM,wCAAwC;AAG9C,MAAM,4CAA4C;AAyBzD,eAAsB,mCACpB,qBACA,UACkB;AAClB,MAAI,CAAC,oBAAqB,QAAO;AACjC,MAAI;AACF,UAAM,QAAQ,MAAM,oBAAoB;AAAA,MACtC;AAAA,MACA;AAAA,MACA;AAAA,QACE,cAAc;AAAA,QACd,OAAO,EAAE,SAAS;AAAA,MACpB;AAAA,IACF;AACA,UAAM,SAAS,wBAAwB,KAAK;AAE5C,WAAO,WAAW,OAAO,4CAA4C;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,4BACpB,qBACA,UAC+B;AAC/B,SAAO;AAAA,IACL,wBAAwB,MAAM,mCAAmC,qBAAqB,QAAQ;AAAA,EAChG;AACF;AAEA,eAAsB,oCACpB,qBACA,UACA,SACe;AACf,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,SAAS;AAAA,EACb;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|