@gadmin2n/schematics 0.0.144 → 0.0.145

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/config/.types.d.ts +10 -0
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/approval.prisma +2 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +140 -19
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +2 -2
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/data-mngt.seed.ts +0 -2
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +694 -327
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-outbox.ts +57 -0
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +35 -5
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflows.ts +224 -59
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-executor.spec.ts +23 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-executor.ts +16 -5
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.spec.ts +98 -0
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.ts +26 -6
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.dto.ts +17 -2
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.spec.ts +1 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.ts +3 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.dto.ts +0 -2
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-signal-outbox.service.spec.ts +30 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-signal-outbox.service.ts +28 -6
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.spec.ts +63 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.ts +151 -38
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-wait.handler.ts +4 -1
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/human-approval.handler.spec.ts +16 -5
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/human-approval.handler.ts +23 -6
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.spec.ts +130 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.ts +62 -62
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.dto.ts +15 -1
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.spec.ts +70 -9
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.ts +31 -7
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-signal-outbox.service.spec.ts +30 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-signal-outbox.service.ts +28 -6
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.spec.ts +50 -3
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.ts +26 -3
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.dto.ts +53 -47
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.errors.ts +0 -1
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.spec.ts +541 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.ts +442 -200
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/outbox-retry.util.ts +1 -0
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.spec.ts +150 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.ts +56 -40
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.dto.ts +16 -60
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.controller.ts +13 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.spec.ts +44 -0
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.ts +6 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +258 -12
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.ts +127 -14
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/manual-workflow-execution.spec.ts +85 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/manual-workflow-execution.ts +108 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/parameter-binding.ts +5 -5
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.spec.ts +96 -25
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +77 -34
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.spec.ts +23 -34
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.ts +0 -21
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +245 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +639 -188
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +408 -235
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.types.ts +1 -3
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.spec.ts +279 -95
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.ts +360 -80
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-catalog.spec.ts +323 -0
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +773 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution.dto.ts +7 -13
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.dto.ts +0 -16
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.service.spec.ts +184 -0
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.service.ts +69 -138
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.spec.ts +113 -0
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.ts +59 -13
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-runtime.facade.ts +86 -0
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-switch-config.spec.ts +25 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-switch-config.ts +45 -0
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.spec.ts +78 -43
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +103 -40
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.dto.ts +57 -0
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +3 -1
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +1000 -240
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +2184 -317
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +279 -2
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.ts +5 -1
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.spec.ts +4 -1
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.ts +5 -1
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.spec.ts +12 -3
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.ts +10 -1
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +2 -24
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.ts +3 -70
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +3 -1
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/RowActions.tsx +25 -5
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/WorkflowActionButton.test.tsx +71 -0
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/WorkflowActionButton.tsx +89 -0
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/index.ts +1 -0
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/header.tsx +52 -12
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +12 -0
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/constants/layout.ts +2 -2
  93. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddDataModal.tsx +10 -33
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddPageModal.tsx +13 -37
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/DevShell.tsx +55 -7
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/style.css +14 -0
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/http.ts +10 -0
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/list.tsx +1 -0
  99. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/workflowAction.ts +19 -0
  100. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/index.ts +1 -0
  101. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/types.ts +3 -1
  102. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +1 -6
  103. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useReferenceUpload.ts +95 -0
  104. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +2 -2
  105. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +672 -110
  106. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +2 -2
  107. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +676 -114
  108. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +13 -1
  109. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +1 -0
  110. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasEditPage.tsx +38 -4
  111. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +276 -376
  112. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/CanvasAiModal.tsx +126 -6
  113. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/DecisionModal.test.tsx +50 -0
  114. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/DecisionModal.tsx +48 -11
  115. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/inbox.tsx +32 -34
  116. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/RegisterBusinessEventModal.test.tsx +111 -0
  117. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/RegisterBusinessEventModal.tsx +167 -0
  118. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/business-events.css +99 -0
  119. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/detail.test.tsx +106 -0
  120. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/detail.tsx +324 -0
  121. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/index.test.tsx +73 -0
  122. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/index.tsx +359 -0
  123. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CanvasZoomControls.tsx +46 -0
  124. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CreateNodeInstanceDrawer.tsx +9 -1
  125. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.test.tsx +105 -4
  126. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.tsx +90 -48
  127. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DeletableEdge.tsx +3 -2
  128. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.test.tsx +259 -0
  129. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +167 -103
  130. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/EnhancedFlowRenderer.tsx +142 -140
  131. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.test.tsx +60 -15
  132. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.tsx +25 -12
  133. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/FlowRenderer.tsx +364 -200
  134. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NewNodeDefaults.test.tsx +220 -52
  135. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.test.tsx +260 -0
  136. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.tsx +300 -130
  137. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +507 -33
  138. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +630 -592
  139. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ParameterBindingEditor.tsx +67 -70
  140. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.test.tsx +90 -0
  141. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.tsx +325 -0
  142. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/RunWorkflowModal.test.tsx +52 -0
  143. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/RunWorkflowModal.tsx +14 -9
  144. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/StatusCards.tsx +2 -1
  145. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/VersionPanel.tsx +2 -1
  146. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.test.tsx +42 -0
  147. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.tsx +76 -0
  148. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowWorkspaceHeader.tsx +56 -0
  149. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/parameter-binding-editor.css +46 -0
  150. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/workflow-code-editor.css +34 -0
  151. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/ConnectionModal.test.tsx +53 -7
  152. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/ConnectionModal.tsx +123 -62
  153. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connections.css +85 -0
  154. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connectionsApi.ts +29 -0
  155. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.test.tsx +75 -0
  156. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.tsx +69 -36
  157. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.test.tsx +494 -0
  158. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +665 -194
  159. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useReferencedNodeInstanceConfigs.test.tsx +92 -0
  160. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useReferencedNodeInstanceConfigs.ts +96 -0
  161. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useWorkflowAgent.test.tsx +297 -0
  162. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useWorkflowAgent.ts +135 -65
  163. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +53 -42
  164. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +344 -155
  165. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instances.tsx +79 -58
  166. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/CreateNodeInstanceModal.tsx +123 -144
  167. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/NodeInstanceForm.tsx +169 -98
  168. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/node-instance-form.css +91 -0
  169. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/index.tsx +54 -31
  170. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-config.css +854 -0
  171. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaField.tsx +41 -14
  172. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaForm.test.tsx +75 -0
  173. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaForm.tsx +3 -0
  174. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +20 -2
  175. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/widget-registry.tsx +2 -1
  176. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +61 -66
  177. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRuleEditor.test.tsx +33 -1
  178. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRuleEditor.tsx +47 -15
  179. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/BranchConfigEditors.test.tsx +104 -0
  180. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CallableInputParametersEditor.tsx +22 -52
  181. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.test.tsx +72 -0
  182. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.tsx +78 -70
  183. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CronTriggerConfigEditor.tsx +569 -0
  184. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +130 -0
  185. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DelayConfigEditor.tsx +100 -0
  186. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +620 -0
  187. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.test.tsx +22 -45
  188. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.tsx +25 -92
  189. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalWaitConfigEditor.tsx +3 -11
  190. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ForEachConfigEditor.test.tsx +58 -0
  191. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ForEachConfigEditor.tsx +107 -0
  192. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.test.tsx +212 -31
  193. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.tsx +214 -304
  194. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.test.tsx +175 -40
  195. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.tsx +693 -293
  196. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/IfElseConfigEditor.tsx +190 -0
  197. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ManualTriggerConfigEditor.test.tsx +152 -0
  198. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ManualTriggerConfigEditor.tsx +286 -0
  199. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ParallelConfigEditor.tsx +101 -0
  200. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ParameterBindingListEditor.tsx +99 -0
  201. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +495 -0
  202. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubWorkflowConfigEditor.test.tsx +124 -0
  203. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubWorkflowConfigEditor.tsx +222 -0
  204. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.tsx +2 -4
  205. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SwitchConfigEditor.tsx +204 -0
  206. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupCreateModal.tsx +3 -1
  207. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupEditModal.tsx +9 -6
  208. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/callable-workflow.ts +4 -0
  209. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/code-config.css +96 -0
  210. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/event-catalog.api.ts +117 -0
  211. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/http-request-config.css +242 -0
  212. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/human-approval-config.css +194 -0
  213. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +264 -167
  214. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +6 -9
  215. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types/parameter-binding.ts +19 -16
  216. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +28 -4
  217. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/useWorkflowFormValidation.test.tsx +59 -0
  218. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/useWorkflowFormValidation.ts +24 -0
  219. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.test.ts +311 -0
  220. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.ts +198 -0
  221. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/mainFlowConnection.test.ts +143 -0
  222. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/mainFlowConnection.ts +19 -0
  223. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +103 -5
  224. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/removeWorkflowEdges.test.ts +158 -3
  225. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/removeWorkflowEdges.ts +117 -9
  226. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveEffectiveOutput.test.ts +70 -0
  227. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveEffectiveOutput.ts +48 -0
  228. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveLookupPorts.test.ts +55 -0
  229. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveLookupPorts.ts +95 -22
  230. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.test.ts +148 -1
  231. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.ts +62 -11
  232. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveWorkflowDisplay.test.ts +19 -0
  233. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveWorkflowDisplay.ts +1 -1
  234. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/subWorkflowChange.test.ts +45 -0
  235. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/subWorkflowChange.ts +26 -0
  236. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/validateWorkflowDsl.test.ts +502 -0
  237. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/validateWorkflowDsl.ts +694 -0
  238. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowDateTime.test.ts +27 -0
  239. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowDateTime.ts +33 -0
  240. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowHistory.test.ts +34 -0
  241. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowHistory.ts +52 -0
  242. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowPublishError.test.ts +99 -0
  243. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowPublishError.ts +91 -0
  244. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowSkillPrompt.test.ts +74 -0
  245. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowSkillPrompt.ts +120 -0
  246. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/workflow-ui.css +481 -0
  247. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/index.css +1 -1
  248. package/package.json +1 -1
  249. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/WorkflowEventOutbox.ts +0 -62
  250. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/migrate-human-approval-configs.ts +0 -86
  251. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-event-trigger.ts +0 -60
  252. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.external-decision.spec.ts +0 -183
  253. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/legacy-approval-config-migration.ts +0 -227
  254. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.spec.ts +0 -82
  255. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.ts +0 -111
  256. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +0 -54
  257. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.ts +0 -147
  258. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.module.ts +0 -10
  259. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +0 -350
  260. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.ts +0 -110
  261. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.ts +0 -1
  262. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/InstanceRequiredDialog.tsx +0 -106
  263. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.test.tsx +0 -45
  264. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.tsx +0 -43
  265. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeTypeBadge.tsx +0 -36
  266. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useNodeInstanceLibrary.ts +0 -41
  267. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.test.tsx +0 -47
  268. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.tsx +0 -182
  269. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.test.tsx +0 -34
  270. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.tsx +0 -16
  271. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.test.ts +0 -25
  272. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.ts +0 -42
  273. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.test.ts +0 -208
  274. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.ts +0 -246
  275. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/create.tsx +0 -111
  276. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/edit.tsx +0 -127
  277. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/index.tsx +0 -4
  278. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +0 -282
  279. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/show.tsx +0 -74
@@ -1,4 +1,17 @@
1
- import { validateDslGraph } from './dsl-validate.util';
1
+ import { validateDslGraph as validateDslGraphRaw } from './dsl-validate.util';
2
+
3
+ function validateDslGraph(dsl: any) {
4
+ if (!dsl || typeof dsl !== 'object') return validateDslGraphRaw(dsl);
5
+ return validateDslGraphRaw({
6
+ ...dsl,
7
+ edges: Array.isArray(dsl?.edges)
8
+ ? dsl.edges.map((edge: any, index: number) => ({
9
+ id: `edge-${index}`,
10
+ ...edge,
11
+ }))
12
+ : dsl?.edges,
13
+ });
14
+ }
2
15
 
3
16
  describe('validateDslGraph', () => {
4
17
  const validDsl = {
@@ -18,20 +31,19 @@ describe('validateDslGraph', () => {
18
31
  expect(() => validateDslGraph(validDsl)).not.toThrow();
19
32
  });
20
33
 
21
- it('accepts a diamond DAG', () => {
34
+ it('accepts distinct conditional branches', () => {
22
35
  expect(() =>
23
36
  validateDslGraph({
24
37
  nodes: [
25
38
  { id: 't1', type: 'manual_trigger' },
26
- { id: 'a', type: 'http_request' },
39
+ { id: 'a', type: 'if_else' },
27
40
  { id: 'b', type: 'http_request' },
28
41
  { id: 'c', type: 'code' },
29
42
  ],
30
43
  edges: [
31
44
  { source: 't1', target: 'a' },
32
- { source: 't1', target: 'b' },
33
- { source: 'a', target: 'c' },
34
- { source: 'b', target: 'c' },
45
+ { source: 'a', target: 'b', sourceHandle: 'true' },
46
+ { source: 'a', target: 'c', sourceHandle: 'false' },
35
47
  ],
36
48
  }),
37
49
  ).not.toThrow();
@@ -106,11 +118,199 @@ describe('validateDslGraph', () => {
106
118
  nodes: [{ id: 'n1', type: 'http_request' }],
107
119
  edges: [],
108
120
  }),
109
- ).toThrow('at least one *_trigger node');
121
+ ).toThrow('exactly one *_trigger node');
122
+ });
123
+
124
+ it('rejects more than one trigger node', () => {
125
+ expect(() =>
126
+ validateDslGraph({
127
+ nodes: [
128
+ { id: 'manual', type: 'manual_trigger' },
129
+ { id: 'event', type: 'event_trigger' },
130
+ ],
131
+ edges: [],
132
+ }),
133
+ ).toThrow('exactly one *_trigger node');
134
+ });
135
+ });
136
+
137
+ describe('main-flow semantics', () => {
138
+ it('rejects joins because input has no unambiguous predecessor', () => {
139
+ expect(() =>
140
+ validateDslGraph({
141
+ nodes: [
142
+ { id: 'trigger', type: 'manual_trigger' },
143
+ { id: 'branch', type: 'if_else' },
144
+ { id: 'left', type: 'code' },
145
+ { id: 'right', type: 'code' },
146
+ { id: 'join', type: 'code' },
147
+ ],
148
+ edges: [
149
+ { source: 'trigger', target: 'branch' },
150
+ { source: 'branch', target: 'left', sourceHandle: 'true' },
151
+ { source: 'branch', target: 'right', sourceHandle: 'false' },
152
+ { source: 'left', target: 'join' },
153
+ { source: 'right', target: 'join' },
154
+ ],
155
+ }),
156
+ ).toThrow('main-flow joins are not supported');
157
+ });
158
+
159
+ it('rejects multiple outgoing edges from an ordinary node', () => {
160
+ expect(() =>
161
+ validateDslGraph({
162
+ nodes: [
163
+ { id: 'trigger', type: 'manual_trigger' },
164
+ { id: 'left', type: 'code' },
165
+ { id: 'right', type: 'code' },
166
+ ],
167
+ edges: [
168
+ { source: 'trigger', target: 'left' },
169
+ { source: 'trigger', target: 'right' },
170
+ ],
171
+ }),
172
+ ).toThrow('at most one outgoing FLOW edge');
173
+ });
174
+
175
+ it('rejects duplicate connections from one conditional output', () => {
176
+ expect(() =>
177
+ validateDslGraph({
178
+ nodes: [
179
+ { id: 'trigger', type: 'manual_trigger' },
180
+ { id: 'branch', type: 'if_else' },
181
+ { id: 'left', type: 'code' },
182
+ { id: 'right', type: 'code' },
183
+ ],
184
+ edges: [
185
+ { source: 'trigger', target: 'branch' },
186
+ { source: 'branch', target: 'left', sourceHandle: 'true' },
187
+ { source: 'branch', target: 'right', sourceHandle: 'true' },
188
+ ],
189
+ }),
190
+ ).toThrow('each output to at most one next node');
191
+ });
192
+
193
+ it('accepts Parallel START / END pipelines and one main OUT', () => {
194
+ expect(() =>
195
+ validateDslGraph({
196
+ nodes: [
197
+ { id: 'trigger', type: 'manual_trigger' },
198
+ { id: 'parallel', type: 'parallel' },
199
+ { id: 'left', type: 'code' },
200
+ { id: 'right', type: 'code' },
201
+ { id: 'after', type: 'code' },
202
+ ],
203
+ edges: [
204
+ { source: 'trigger', target: 'parallel' },
205
+ { source: 'parallel', target: 'after' },
206
+ {
207
+ source: 'parallel',
208
+ target: 'left',
209
+ kind: 'CALL',
210
+ pairId: 'left-pair',
211
+ sourceHandle: 'left-start',
212
+ },
213
+ {
214
+ source: 'left',
215
+ target: 'parallel',
216
+ kind: 'RETURN',
217
+ pairId: 'left-pair',
218
+ targetHandle: 'left-end',
219
+ },
220
+ {
221
+ source: 'parallel',
222
+ target: 'right',
223
+ kind: 'CALL',
224
+ pairId: 'right-pair',
225
+ sourceHandle: 'right-start',
226
+ },
227
+ {
228
+ source: 'right',
229
+ target: 'parallel',
230
+ kind: 'RETURN',
231
+ pairId: 'right-pair',
232
+ targetHandle: 'right-end',
233
+ },
234
+ ],
235
+ }),
236
+ ).not.toThrow();
237
+ });
238
+
239
+ it('rejects nodes disconnected from the trigger', () => {
240
+ expect(() =>
241
+ validateDslGraph({
242
+ nodes: [
243
+ { id: 'trigger', type: 'manual_trigger' },
244
+ { id: 'orphan', type: 'code' },
245
+ ],
246
+ edges: [],
247
+ }),
248
+ ).toThrow('not connected to its trigger');
110
249
  });
111
250
  });
112
251
 
113
252
  describe('edge errors', () => {
253
+ it('rejects an edge without id', () => {
254
+ expect(() =>
255
+ validateDslGraphRaw({
256
+ nodes: [{ id: 't1', type: 'manual_trigger' }],
257
+ edges: [{ source: 't1', target: 't1' }],
258
+ }),
259
+ ).toThrow('non-empty string id');
260
+ });
261
+
262
+ it('rejects duplicate edge ids', () => {
263
+ expect(() =>
264
+ validateDslGraphRaw({
265
+ nodes: [
266
+ { id: 't1', type: 'manual_trigger' },
267
+ { id: 'a', type: 'code' },
268
+ ],
269
+ edges: [
270
+ { id: 'same', source: 't1', target: 'a' },
271
+ { id: 'same', source: 't1', target: 'a' },
272
+ ],
273
+ }),
274
+ ).toThrow('Duplicate edge id');
275
+ });
276
+
277
+ it('rejects an orphan paired FLOW as unreachable runtime flow', () => {
278
+ expect(() =>
279
+ validateDslGraph({
280
+ nodes: [
281
+ { id: 't1', type: 'manual_trigger' },
282
+ { id: 'a', type: 'code' },
283
+ ],
284
+ edges: [
285
+ {
286
+ source: 't1',
287
+ target: 'a',
288
+ kind: 'FLOW',
289
+ pairId: 'ghost',
290
+ },
291
+ ],
292
+ }),
293
+ ).toThrow('not connected to its trigger');
294
+ });
295
+
296
+ it('rejects an edge with pairId and an omitted kind', () => {
297
+ expect(() =>
298
+ validateDslGraph({
299
+ nodes: [
300
+ { id: 'trigger', type: 'manual_trigger' },
301
+ { id: 'code', type: 'code' },
302
+ ],
303
+ edges: [
304
+ {
305
+ source: 'trigger',
306
+ target: 'code',
307
+ pairId: 'ghost',
308
+ },
309
+ ],
310
+ }),
311
+ ).toThrow('must explicitly declare kind');
312
+ });
313
+
114
314
  it('rejects edge with unknown source', () => {
115
315
  expect(() =>
116
316
  validateDslGraph({
@@ -143,6 +343,42 @@ describe('validateDslGraph', () => {
143
343
  }),
144
344
  ).toThrow('Self-loop');
145
345
  });
346
+
347
+ it('rejects removed DATA edges', () => {
348
+ expect(() =>
349
+ validateDslGraph({
350
+ nodes: [
351
+ { id: 'trigger', type: 'manual_trigger' },
352
+ { id: 'action', type: 'code' },
353
+ ],
354
+ edges: [
355
+ {
356
+ source: 'trigger',
357
+ target: 'action',
358
+ kind: 'DATA',
359
+ },
360
+ ],
361
+ }),
362
+ ).toThrow('DATA edges are no longer supported');
363
+ });
364
+
365
+ it('rejects unknown edge kinds', () => {
366
+ expect(() =>
367
+ validateDslGraph({
368
+ nodes: [
369
+ { id: 'trigger', type: 'manual_trigger' },
370
+ { id: 'action', type: 'code' },
371
+ ],
372
+ edges: [
373
+ {
374
+ source: 'trigger',
375
+ target: 'action',
376
+ kind: 'UNKNOWN',
377
+ },
378
+ ],
379
+ }),
380
+ ).toThrow('Unsupported edge kind: "UNKNOWN"');
381
+ });
146
382
  });
147
383
 
148
384
  describe('cycle detection', () => {
@@ -208,13 +444,23 @@ describe('validateDslGraph', () => {
208
444
  validateDslGraph({
209
445
  nodes: [
210
446
  { id: 'trigger', type: 'manual_trigger' },
211
- { id: 'approval', type: 'human_approval' },
212
- { id: 'lookup', type: 'http_request' },
447
+ { id: 'loop', type: 'for_each' },
448
+ { id: 'body', type: 'code' },
213
449
  ],
214
450
  edges: [
215
- { source: 'trigger', target: 'approval', kind: 'FLOW' },
216
- { source: 'approval', target: 'lookup', kind: 'CALL' },
217
- { source: 'lookup', target: 'approval', kind: 'RETURN' },
451
+ { source: 'trigger', target: 'loop', kind: 'FLOW' },
452
+ {
453
+ source: 'loop',
454
+ target: 'body',
455
+ kind: 'CALL',
456
+ pairId: 'loop-body',
457
+ },
458
+ {
459
+ source: 'body',
460
+ target: 'loop',
461
+ kind: 'RETURN',
462
+ pairId: 'loop-body',
463
+ },
218
464
  ],
219
465
  }),
220
466
  ).not.toThrow();
@@ -10,8 +10,9 @@
10
10
  * 1. nodes / edges are present and well-typed
11
11
  * 2. every edge references existing nodes
12
12
  * 3. node ids are unique
13
- * 4. there is at least one trigger node
14
- * 5. graph is a DAG (Kahn's algorithm — no cycles)
13
+ * 4. there is exactly one trigger node and every node is reachable from it
14
+ * 5. main FLOW has unambiguous input/output cardinality
15
+ * 6. graph is a DAG (Kahn's algorithm — no cycles)
15
16
  *
16
17
  * Throws Error with a human-readable message on the first failure;
17
18
  * caller should map to BadRequestException.
@@ -19,9 +20,12 @@
19
20
  export interface DslGraphLike {
20
21
  nodes?: Array<{ id?: string; type?: string }>;
21
22
  edges?: Array<{
23
+ id?: string;
22
24
  source?: string;
23
25
  target?: string;
24
- kind?: 'FLOW' | 'DATA' | 'CALL' | 'RETURN';
26
+ kind?: string;
27
+ pairId?: string;
28
+ sourceHandle?: string;
25
29
  }>;
26
30
  }
27
31
 
@@ -56,14 +60,23 @@ export function validateDslGraph(dsl: unknown): void {
56
60
  }
57
61
  }
58
62
 
59
- // 2. at least one trigger node
60
- const hasTrigger = g.nodes.some((n) => n.type!.endsWith('_trigger'));
61
- if (!hasTrigger) {
62
- throw new Error('DSL must contain at least one *_trigger node');
63
- }
63
+ // 2. exactly one trigger node. The worker starts every trigger successor,
64
+ // so accepting multiple triggers would execute unrelated entry paths in the
65
+ // same run regardless of which trigger actually started it.
66
+ const triggerNodes = g.nodes.filter((n) => n.type!.endsWith('_trigger'));
67
+ if (triggerNodes.length !== 1)
68
+ throw new Error('DSL must contain exactly one *_trigger node');
64
69
 
65
- // 3. edges reference existing nodes; no self-loops
70
+ // 3. edge ids unique + non-empty; edges reference existing nodes; no self-loops
71
+ const edgeIdSet = new Set<string>();
66
72
  for (const e of g.edges) {
73
+ if (!e || typeof e.id !== 'string' || e.id.length === 0) {
74
+ throw new Error('Every edge must have a non-empty string id');
75
+ }
76
+ if (edgeIdSet.has(e.id)) {
77
+ throw new Error(`Duplicate edge id: "${e.id}"`);
78
+ }
79
+ edgeIdSet.add(e.id);
67
80
  if (!e || typeof e.source !== 'string' || typeof e.target !== 'string') {
68
81
  throw new Error('Every edge must have string source and target');
69
82
  }
@@ -76,19 +89,119 @@ export function validateDslGraph(dsl: unknown): void {
76
89
  if (e.source === e.target) {
77
90
  throw new Error(`Self-loop detected on node "${e.source}"`);
78
91
  }
92
+ if (e.kind === 'DATA')
93
+ throw new Error(
94
+ 'DATA edges are no longer supported; use structured bindings or a CALL / RETURN pipeline',
95
+ );
96
+ if (e.pairId && e.kind === undefined)
97
+ throw new Error(
98
+ `Edge "${e.id}" with pairId must explicitly declare kind FLOW, CALL, or RETURN`,
99
+ );
100
+ if (e.kind !== undefined && !['FLOW', 'CALL', 'RETURN'].includes(e.kind))
101
+ throw new Error(`Unsupported edge kind: "${e.kind}"`);
102
+ }
103
+
104
+ const nodeById = new Map(g.nodes.map((node) => [node.id!, node]));
105
+ const edges = g.edges;
106
+ const mainEdges = edges.filter(
107
+ (edge) => (!edge.kind || edge.kind === 'FLOW') && !edge.pairId,
108
+ );
109
+
110
+ validateAcyclicMainFlow(idSet, edges);
111
+
112
+ // 4. main-flow topology. A node receives one well-defined `input`: the
113
+ // immediately preceding node's output. There is no merge node today, so a
114
+ // main-flow join would either deadlock on an unselected branch or leave the
115
+ // runtime unable to choose which predecessor is `input`.
116
+ for (const node of g.nodes) {
117
+ const incoming = mainEdges.filter((edge) => edge.target === node.id);
118
+ const outgoing = mainEdges.filter((edge) => edge.source === node.id);
119
+
120
+ if (node.type!.endsWith('_trigger') && incoming.length > 0)
121
+ throw new Error(`Trigger node "${node.id}" cannot have an incoming FLOW`);
122
+ if (incoming.length > 1)
123
+ throw new Error(
124
+ `Node "${node.id}" has multiple incoming FLOW edges; main-flow joins are not supported`,
125
+ );
126
+ const isBranchNode = [
127
+ 'if_else',
128
+ 'switch',
129
+ 'approval',
130
+ 'external_wait',
131
+ ].includes(node.type!);
132
+ if (!isBranchNode && outgoing.length > 1)
133
+ throw new Error(
134
+ `Node "${node.id}" can have at most one outgoing FLOW edge`,
135
+ );
136
+
137
+ const branchesByHandle = new Map<string, number>();
138
+ for (const edge of outgoing) {
139
+ const handle = edge.sourceHandle ?? '';
140
+ branchesByHandle.set(handle, (branchesByHandle.get(handle) ?? 0) + 1);
141
+ }
142
+ if ([...branchesByHandle.values()].some((count) => count > 1))
143
+ throw new Error(
144
+ `Node "${node.id}" can connect each output to at most one next node`,
145
+ );
79
146
  }
80
147
 
81
- // 4. cycle detection — Kahn's algorithm.
82
- // 注意:parallel/for_each 节点的"分支"在 worker 侧也是普通的 edge,因此用普通 DAG 校验即可。
148
+ // Every node must belong to the single entry graph. CALL edges make inline
149
+ // loop bodies reachable. A paired FLOW is only traversable when its pair is
150
+ // owned by exactly one CALL; otherwise it is not executable main flow.
151
+ const callablePairIds = new Set(
152
+ edges
153
+ .filter(
154
+ (edge) =>
155
+ edge.kind === 'CALL' &&
156
+ edge.pairId &&
157
+ edges.filter(
158
+ (candidate) =>
159
+ candidate.kind === 'CALL' && candidate.pairId === edge.pairId,
160
+ ).length === 1,
161
+ )
162
+ .map((edge) => edge.pairId)
163
+ .filter((pairId): pairId is string => Boolean(pairId)),
164
+ );
165
+ const reachable = new Set<string>([triggerNodes[0].id!]);
166
+ let changed = true;
167
+ while (changed) {
168
+ changed = false;
169
+ for (const edge of edges) {
170
+ if (
171
+ edge.kind === 'RETURN' ||
172
+ (edge.kind === 'FLOW' &&
173
+ Boolean(edge.pairId) &&
174
+ !callablePairIds.has(edge.pairId ?? '')) ||
175
+ !reachable.has(edge.source!) ||
176
+ reachable.has(edge.target!)
177
+ )
178
+ continue;
179
+ reachable.add(edge.target!);
180
+ changed = true;
181
+ }
182
+ }
183
+ const unreachable = [...nodeById.keys()].filter((id) => !reachable.has(id));
184
+ if (unreachable.length > 0)
185
+ throw new Error(
186
+ `DSL contains nodes that are not connected to its trigger: [${unreachable.join(
187
+ ', ',
188
+ )}]`,
189
+ );
190
+ }
191
+
192
+ function validateAcyclicMainFlow(
193
+ idSet: Set<string>,
194
+ edges: NonNullable<DslGraphLike['edges']>,
195
+ ): void {
196
+ // Paired For Each / lookup FLOW chains must also be acyclic. CALL and RETURN
197
+ // edges describe invocation boundaries rather than normal execution order.
83
198
  const indegree = new Map<string, number>();
84
199
  const adj = new Map<string, string[]>();
85
200
  for (const id of idSet) {
86
201
  indegree.set(id, 0);
87
202
  adj.set(id, []);
88
203
  }
89
- for (const e of g.edges.filter(
90
- (edge) => !edge.kind || edge.kind === 'FLOW',
91
- )) {
204
+ for (const e of edges.filter((edge) => !edge.kind || edge.kind === 'FLOW')) {
92
205
  indegree.set(e.target!, indegree.get(e.target!)! + 1);
93
206
  adj.get(e.source!)!.push(e.target!);
94
207
  }
@@ -0,0 +1,85 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ import {
3
+ assertManualWorkflowExecution,
4
+ normalizeIdempotencyKey,
5
+ scopedIdempotencyKey,
6
+ workflowDataHash,
7
+ } from './manual-workflow-execution';
8
+
9
+ describe('manual Workflow execution', () => {
10
+ it('accepts a valid manual trigger input', () => {
11
+ expect(() =>
12
+ assertManualWorkflowExecution(
13
+ {
14
+ nodes: [
15
+ {
16
+ type: 'manual_trigger',
17
+ config: {
18
+ inputSchema: {
19
+ type: 'object',
20
+ required: ['orderId'],
21
+ properties: { orderId: { type: 'string' } },
22
+ },
23
+ },
24
+ },
25
+ ],
26
+ },
27
+ { orderId: 'O-1' },
28
+ ),
29
+ ).not.toThrow();
30
+ });
31
+
32
+ it('rejects a non-manual trigger and invalid input', () => {
33
+ expect(() =>
34
+ assertManualWorkflowExecution(
35
+ { nodes: [{ type: 'webhook_trigger', config: {} }] },
36
+ {},
37
+ ),
38
+ ).toThrow(BadRequestException);
39
+
40
+ expect(() =>
41
+ assertManualWorkflowExecution(
42
+ {
43
+ nodes: [
44
+ {
45
+ type: 'manual_trigger',
46
+ config: {
47
+ inputSchema: {
48
+ type: 'object',
49
+ required: ['orderId'],
50
+ },
51
+ },
52
+ },
53
+ ],
54
+ },
55
+ {},
56
+ ),
57
+ ).toThrow(BadRequestException);
58
+ });
59
+
60
+ it('normalizes, scopes, and compares idempotent requests', () => {
61
+ expect(normalizeIdempotencyKey(' request-1 ')).toBe('request-1');
62
+ expect(scopedIdempotencyKey('manual', 'request-1')).toMatch(
63
+ /^manual:[a-f0-9]{64}$/,
64
+ );
65
+ expect(
66
+ workflowDataHash(
67
+ {
68
+ orderId: 'O-1',
69
+ receivedAt: 'first',
70
+ headers: { 'x-workflow-timestamp': 'first' },
71
+ },
72
+ ['receivedAt', 'headers.x-workflow-timestamp'],
73
+ ),
74
+ ).toBe(
75
+ workflowDataHash(
76
+ {
77
+ receivedAt: 'retry',
78
+ orderId: 'O-1',
79
+ headers: { 'x-workflow-timestamp': 'retry' },
80
+ },
81
+ ['receivedAt', 'headers.x-workflow-timestamp'],
82
+ ),
83
+ );
84
+ });
85
+ });
@@ -0,0 +1,108 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ import Ajv from 'ajv';
3
+ import addFormats from 'ajv-formats';
4
+ import { createHash } from 'crypto';
5
+
6
+ const ajv = new Ajv({ allErrors: true, strict: false });
7
+ addFormats(ajv);
8
+
9
+ export function assertManualWorkflowExecution(
10
+ dsl: unknown,
11
+ workflowData: Record<string, unknown>,
12
+ ): void {
13
+ const nodes = Array.isArray((dsl as any)?.nodes) ? (dsl as any).nodes : [];
14
+ const triggers = nodes.filter(
15
+ (node: any) =>
16
+ typeof node?.type === 'string' && node.type.endsWith('_trigger'),
17
+ );
18
+ const manualTriggers = triggers.filter(
19
+ (node: any) => node.type === 'manual_trigger',
20
+ );
21
+
22
+ if (triggers.length !== 1 || manualTriggers.length !== 1) {
23
+ throw new BadRequestException({
24
+ code: 'WORKFLOW_ACTION_REQUIRES_MANUAL_TRIGGER',
25
+ message: '只有“手动触发”的 Workflow 可以绑定到页面按钮',
26
+ });
27
+ }
28
+
29
+ const inputSchema = manualTriggers[0]?.config?.inputSchema;
30
+ if (!inputSchema || typeof inputSchema !== 'object') return;
31
+
32
+ let validate;
33
+ try {
34
+ validate = ajv.compile(inputSchema);
35
+ } catch {
36
+ throw new BadRequestException({
37
+ code: 'WORKFLOW_INPUT_SCHEMA_INVALID',
38
+ message: 'Workflow 的启动数据规则无效,请重新发布后再试',
39
+ });
40
+ }
41
+ if (validate(workflowData)) return;
42
+
43
+ throw new BadRequestException({
44
+ code: 'WORKFLOW_INPUT_INVALID',
45
+ message: '启动数据不符合 Workflow 的要求',
46
+ details: (validate.errors ?? []).map((error) => ({
47
+ path: error.instancePath || '/',
48
+ message: error.message,
49
+ })),
50
+ });
51
+ }
52
+
53
+ export function normalizeIdempotencyKey(value: string | undefined): string {
54
+ const key = value?.trim() ?? '';
55
+ if (!key || key.length > 128 || /[\u0000-\u001f\u007f]/.test(key)) {
56
+ throw new BadRequestException({
57
+ code: 'IDEMPOTENCY_KEY_INVALID',
58
+ message: 'Idempotency-Key 必须是 1 到 128 个字符',
59
+ });
60
+ }
61
+ return key;
62
+ }
63
+
64
+ export function workflowDataHash(
65
+ workflowData: Record<string, unknown>,
66
+ ignoredFields: string[] = [],
67
+ ): string {
68
+ return createHash('sha256')
69
+ .update(stableJson(omitPaths(workflowData, ignoredFields)))
70
+ .digest('hex');
71
+ }
72
+
73
+ export function scopedIdempotencyKey(scope: string, value: string): string {
74
+ return `${scope}:${createHash('sha256').update(value).digest('hex')}`;
75
+ }
76
+
77
+ function omitPaths(value: unknown, paths: string[]): unknown {
78
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return value;
79
+ return Object.fromEntries(
80
+ Object.entries(value as Record<string, unknown>)
81
+ .filter(([key]) => !paths.includes(key))
82
+ .map(([key, child]) => [
83
+ key,
84
+ omitPaths(
85
+ child,
86
+ paths
87
+ .filter((path) => path.startsWith(`${key}.`))
88
+ .map((path) => path.slice(key.length + 1)),
89
+ ),
90
+ ]),
91
+ );
92
+ }
93
+
94
+ function stableJson(value: unknown): string {
95
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`;
96
+ if (value && typeof value === 'object') {
97
+ return `{${Object.keys(value as Record<string, unknown>)
98
+ .sort()
99
+ .map(
100
+ (key) =>
101
+ `${JSON.stringify(key)}:${stableJson(
102
+ (value as Record<string, unknown>)[key],
103
+ )}`,
104
+ )
105
+ .join(',')}}`;
106
+ }
107
+ return JSON.stringify(value) ?? 'null';
108
+ }