@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
@@ -0,0 +1,694 @@
1
+ import Ajv, { type ErrorObject, type ValidateFunction } from 'ajv';
2
+ import addFormats from 'ajv-formats';
3
+ import type {
4
+ CallableWorkflowOption,
5
+ WorkflowDSL,
6
+ WorkflowEdge,
7
+ WorkflowNode,
8
+ WorkflowNodeType,
9
+ } from '../types';
10
+ import { isParameterBindingValid } from '../types/parameter-binding';
11
+
12
+ export interface WorkflowDslValidationOptions {
13
+ nodeTypes?: WorkflowNodeType[];
14
+ referencedConfigs?: Record<string, Record<string, any>>;
15
+ callableWorkflows?: CallableWorkflowOption[];
16
+ validationMode?: 'draft' | 'publish';
17
+ }
18
+
19
+ export type WorkflowDslValidationResult =
20
+ | { ok: true; dsl: WorkflowDSL }
21
+ | { ok: false; error: string };
22
+
23
+ const BRANCH_NODE_TYPES = new Set([
24
+ 'if_else',
25
+ 'switch',
26
+ 'approval',
27
+ 'human_approval',
28
+ 'external_wait',
29
+ ]);
30
+ const FOR_EACH_BODY_TYPES = new Set([
31
+ 'http_request',
32
+ 'code',
33
+ 'db_execute',
34
+ 'sub_workflow',
35
+ ]);
36
+ const PARALLEL_BODY_TYPES = new Set([
37
+ ...FOR_EACH_BODY_TYPES,
38
+ 'delay',
39
+ 'if_else',
40
+ 'switch',
41
+ 'approval',
42
+ 'human_approval',
43
+ 'external_wait',
44
+ ]);
45
+ const RUNTIME_PORTS: Record<string, { input: string; output: string }> = {
46
+ http_request: { input: 'request-in', output: 'response-out' },
47
+ code: { input: 'data-in', output: 'result-out' },
48
+ };
49
+ const configSchemaAjv = new Ajv({ allErrors: true, strict: false });
50
+ addFormats(configSchemaAjv);
51
+ const configSchemaValidators = new WeakMap<object, ValidateFunction>();
52
+
53
+ export function validateWorkflowDsl(
54
+ value: unknown,
55
+ options: WorkflowDslValidationOptions = {},
56
+ ): WorkflowDslValidationResult {
57
+ try {
58
+ assertWorkflowDsl(value, options);
59
+ return { ok: true, dsl: value as WorkflowDSL };
60
+ } catch (error) {
61
+ return {
62
+ ok: false,
63
+ error: error instanceof Error ? error.message : String(error),
64
+ };
65
+ }
66
+ }
67
+
68
+ function assertWorkflowDsl(
69
+ value: unknown,
70
+ options: WorkflowDslValidationOptions,
71
+ ): asserts value is WorkflowDSL {
72
+ const isPublishValidation = options.validationMode !== 'draft';
73
+ if (!value || typeof value !== 'object' || Array.isArray(value))
74
+ fail('DSL 根节点必须是对象');
75
+ const dsl = value as Partial<WorkflowDSL>;
76
+ if (!Array.isArray(dsl.nodes)) fail('DSL.nodes 必须是数组');
77
+ if (!Array.isArray(dsl.edges)) fail('DSL.edges 必须是数组');
78
+ if (isPublishValidation && dsl.nodes.length === 0)
79
+ fail('Workflow 至少需要一个节点');
80
+ const workflowDsl = dsl as WorkflowDSL;
81
+
82
+ if (
83
+ isPublishValidation &&
84
+ options.nodeTypes &&
85
+ options.nodeTypes.length === 0
86
+ )
87
+ fail('节点类型尚未加载,暂时无法校验 Workflow');
88
+ const nodeTypeMap = options.nodeTypes
89
+ ? new Map(options.nodeTypes.map((nodeType) => [nodeType.type, nodeType]))
90
+ : null;
91
+ const nodeIds = new Set<string>();
92
+ for (const [index, node] of dsl.nodes.entries()) {
93
+ if (!node || typeof node !== 'object') fail(`节点 [${index}] 必须是对象`);
94
+ if (typeof node.id !== 'string' || !node.id)
95
+ fail(`节点 [${index}] 缺少有效 id`);
96
+ if (nodeIds.has(node.id)) fail(`节点 id 重复:${node.id}`);
97
+ nodeIds.add(node.id);
98
+ if (typeof node.type !== 'string' || !node.type)
99
+ fail(`节点 ${node.id} 缺少有效 type`);
100
+ if (isPublishValidation && nodeTypeMap && !nodeTypeMap.has(node.type))
101
+ fail(`节点 ${node.id} 使用了未知类型:${node.type}`);
102
+ if (
103
+ !node.position ||
104
+ !Number.isFinite(node.position.x) ||
105
+ !Number.isFinite(node.position.y)
106
+ )
107
+ fail(`节点 ${node.id} 缺少有效位置`);
108
+ if (!isObject(node.config)) fail(`节点 ${node.id} 的 config 必须是对象`);
109
+ if (!isPublishValidation) continue;
110
+
111
+ const config = effectiveConfig(node, options.referencedConfigs);
112
+ if (!isObject(config)) fail(`节点 ${node.id} 的有效配置必须是对象`);
113
+ const nodeType = nodeTypeMap?.get(node.type);
114
+ if (nodeType) validateConfigSchema(node.label, nodeType, config);
115
+ if (node.type === 'sub_workflow') {
116
+ if (!isPositiveId(config.workflowId))
117
+ fail(`调用 Workflow 节点 ${node.id} 缺少有效 workflowId`);
118
+ if (!isPositiveId(config.workflowVersionId))
119
+ fail(`调用 Workflow 节点 ${node.id} 缺少有效 workflowVersionId`);
120
+ if (options.callableWorkflows) {
121
+ const workflow = options.callableWorkflows.find(
122
+ (item) => item.id === config.workflowId,
123
+ );
124
+ if (!workflow)
125
+ fail(
126
+ `调用 Workflow 节点 ${node.id} 选择了不存在或不可调用的 Workflow:${config.workflowId}`,
127
+ );
128
+ const version = workflow.versions.find(
129
+ (item) => item.id === config.workflowVersionId,
130
+ );
131
+ if (!version)
132
+ fail(
133
+ `调用 Workflow 节点 ${node.id} 选择的版本 ${config.workflowVersionId} 不属于 Workflow ${config.workflowId}`,
134
+ );
135
+ validateCallableInputBindings(node.id, version.inputParameters, config);
136
+ }
137
+ }
138
+ }
139
+
140
+ const triggers = dsl.nodes.filter((node) => node.type.endsWith('_trigger'));
141
+ if (isPublishValidation && triggers.length !== 1)
142
+ fail('Workflow 必须且只能包含一个触发节点');
143
+
144
+ const edgeIds = new Set<string>();
145
+ for (const [index, edge] of dsl.edges.entries()) {
146
+ if (!edge || typeof edge !== 'object') fail(`连线 [${index}] 必须是对象`);
147
+ if (typeof edge.id !== 'string' || !edge.id)
148
+ fail(`连线 [${index}] 缺少有效 id`);
149
+ if (edgeIds.has(edge.id)) fail(`连线 id 重复:${edge.id}`);
150
+ edgeIds.add(edge.id);
151
+ if (!nodeIds.has(edge.source)) fail(`连线 ${edge.id} 的起点不存在`);
152
+ if (!nodeIds.has(edge.target)) fail(`连线 ${edge.id} 的终点不存在`);
153
+ if (edge.source === edge.target) fail(`连线 ${edge.id} 不能连接节点自身`);
154
+ if (edge.kind && !['FLOW', 'CALL', 'RETURN'].includes(edge.kind))
155
+ fail(`连线 ${edge.id} 使用了不支持的类型:${edge.kind}`);
156
+ if (!edge.kind && edge.pairId)
157
+ fail(`普通 FLOW 连线 ${edge.id} 不能携带 pairId`);
158
+ if ((edge.kind === 'CALL' || edge.kind === 'RETURN') && !edge.pairId)
159
+ fail(`${edge.kind} 连线 ${edge.id} 缺少 pairId`);
160
+ if (edge.kind !== 'RETURN' && edge.valueType !== undefined)
161
+ fail(`只有 RETURN 连线可以设置 valueType:${edge.id}`);
162
+ }
163
+
164
+ if (!isPublishValidation) return;
165
+
166
+ const nodes = new Map(dsl.nodes.map((node) => [node.id, node]));
167
+ const flows = dsl.edges.filter((edge) => !edge.kind || edge.kind === 'FLOW');
168
+ const mainFlows = flows.filter((edge) => !edge.pairId);
169
+ const calls = dsl.edges.filter((edge) => edge.kind === 'CALL');
170
+ const returns = dsl.edges.filter((edge) => edge.kind === 'RETURN');
171
+
172
+ validateFlowDag(nodeIds, flows);
173
+ validateMainFlow(dsl.nodes, mainFlows, triggers[0].id);
174
+ validateHandles(flows, nodes, options);
175
+ validateOwnedPipelines(workflowDsl, calls, returns, nodes, options);
176
+ validateReachability(workflowDsl, triggers[0].id, calls);
177
+ }
178
+
179
+ function validateConfigSchema(
180
+ nodeLabel: string,
181
+ nodeType: WorkflowNodeType,
182
+ config: Record<string, any>,
183
+ ) {
184
+ const displayName = nodeLabel.trim() || nodeType.label;
185
+ if (
186
+ nodeType.runtimeKey === 'human_approval' &&
187
+ (!Array.isArray(config.subjects) || config.subjects.length === 0)
188
+ )
189
+ fail(`节点“${displayName}”必须至少设置一位固定审批人或动态审批人`);
190
+
191
+ const invalidBindingPath =
192
+ nodeType.type === 'if_else' ? findInvalidParameterBinding(config) : null;
193
+ if (invalidBindingPath)
194
+ fail(
195
+ `节点“${displayName}”的“${bindingLabel(
196
+ invalidBindingPath,
197
+ )}”没有填写有效的字段路径或固定值`,
198
+ );
199
+
200
+ const schema = nodeType.configSchema as object;
201
+ let validate = configSchemaValidators.get(schema);
202
+ try {
203
+ if (!validate) {
204
+ validate = configSchemaAjv.compile(schema);
205
+ configSchemaValidators.set(schema, validate);
206
+ }
207
+ } catch (error) {
208
+ fail(
209
+ `节点类型 ${nodeType.label} 的配置 Schema 无效:${
210
+ error instanceof Error ? error.message : String(error)
211
+ }`,
212
+ );
213
+ }
214
+ if (validate(config)) return;
215
+ fail(
216
+ `节点“${displayName}”的配置不符合 ${nodeType.label} 要求:${formatSchemaErrors(validate.errors ?? [])}`,
217
+ );
218
+ }
219
+
220
+ function findInvalidParameterBinding(
221
+ value: unknown,
222
+ path = '参数',
223
+ ): string | null {
224
+ if (Array.isArray(value)) {
225
+ for (let index = 0; index < value.length; index++) {
226
+ const invalid = findInvalidParameterBinding(
227
+ value[index],
228
+ `${path}[${index}]`,
229
+ );
230
+ if (invalid) return invalid;
231
+ }
232
+ return null;
233
+ }
234
+ if (!isObject(value)) return null;
235
+
236
+ const bindingCandidate =
237
+ Object.prototype.hasOwnProperty.call(value, 'source') &&
238
+ (Object.prototype.hasOwnProperty.call(value, 'path') ||
239
+ Object.prototype.hasOwnProperty.call(value, 'valueType') ||
240
+ Object.prototype.hasOwnProperty.call(value, 'value'));
241
+ if (bindingCandidate && !isParameterBindingValid(value)) return path;
242
+
243
+ for (const [key, child] of Object.entries(value)) {
244
+ if (['body', 'inputSchema'].includes(key)) continue;
245
+ const invalid = findInvalidParameterBinding(child, `${path}.${key}`);
246
+ if (invalid) return invalid;
247
+ }
248
+ return null;
249
+ }
250
+
251
+ function bindingLabel(path: string): string {
252
+ const condition = /^参数\.conditions\[(\d+)]\.(left|right)$/.exec(path);
253
+ if (!condition) return path;
254
+ const side = condition[2] === 'left' ? '要判断的数据' : '用于比较的数据';
255
+ return `条件 ${Number(condition[1]) + 1} · ${side}`;
256
+ }
257
+
258
+ function formatSchemaErrors(errors: ErrorObject[]): string {
259
+ return errors
260
+ .map(
261
+ (error) => `${error.instancePath || '/'} ${error.message ?? '配置无效'}`,
262
+ )
263
+ .join(';');
264
+ }
265
+
266
+ function validateCallableInputBindings(
267
+ nodeId: string,
268
+ inputParameters: CallableWorkflowOption['versions'][number]['inputParameters'],
269
+ config: Record<string, any>,
270
+ ) {
271
+ const bindings = isObject(config.inputBindings) ? config.inputBindings : {};
272
+ const declaredKeys = new Set(
273
+ inputParameters.map((parameter) => parameter.key),
274
+ );
275
+ const extraParameter = Object.keys(bindings).find(
276
+ (key) => !declaredKeys.has(key),
277
+ );
278
+ if (extraParameter)
279
+ fail(`调用 Workflow 节点 ${nodeId} 包含未声明的参数:${extraParameter}`);
280
+ const invalidParameter = inputParameters.find(
281
+ (parameter) =>
282
+ (parameter.required || bindings[parameter.key] !== undefined) &&
283
+ !isParameterBindingValid(bindings[parameter.key]),
284
+ );
285
+ if (invalidParameter)
286
+ fail(
287
+ `调用 Workflow 节点 ${nodeId} 的参数来源无效:${
288
+ invalidParameter.label ?? invalidParameter.key
289
+ }`,
290
+ );
291
+ }
292
+
293
+ function validateMainFlow(
294
+ nodes: WorkflowNode[],
295
+ mainFlows: WorkflowEdge[],
296
+ triggerId: string,
297
+ ) {
298
+ for (const node of nodes) {
299
+ const incoming = mainFlows.filter((edge) => edge.target === node.id);
300
+ const outgoing = mainFlows.filter((edge) => edge.source === node.id);
301
+ if (node.id === triggerId && incoming.length > 0)
302
+ fail('触发节点不能有主流程输入');
303
+ if (incoming.length > 1) fail(`节点 ${node.id} 不能有多条主流程输入`);
304
+ if (!BRANCH_NODE_TYPES.has(node.type) && outgoing.length > 1)
305
+ fail(`节点 ${node.id} 不能有多条主流程输出`);
306
+ const handles = new Set<string>();
307
+ for (const edge of outgoing) {
308
+ const handle = edge.sourceHandle ?? '';
309
+ if (handles.has(handle)) fail(`节点 ${node.id} 的同一出口只能连接一次`);
310
+ handles.add(handle);
311
+ }
312
+ }
313
+ }
314
+
315
+ function validateHandles(
316
+ flows: WorkflowEdge[],
317
+ nodes: Map<string, WorkflowNode>,
318
+ options: WorkflowDslValidationOptions,
319
+ ) {
320
+ const typeMap = new Map(
321
+ (options.nodeTypes ?? []).map((nodeType) => [nodeType.type, nodeType]),
322
+ );
323
+ for (const edge of flows) {
324
+ const source = nodes.get(edge.source)!;
325
+ const target = nodes.get(edge.target)!;
326
+ const targetHandle = RUNTIME_PORTS[target.type]?.input;
327
+ if ((edge.targetHandle ?? '') !== (targetHandle ?? ''))
328
+ fail(
329
+ targetHandle
330
+ ? `连线 ${edge.id} 进入 ${target.type} 时必须使用 ${targetHandle}`
331
+ : `连线 ${edge.id} 的目标节点没有命名输入端口`,
332
+ );
333
+
334
+ const sourceHandles = outputHandles(
335
+ source,
336
+ typeMap.get(source.type),
337
+ options,
338
+ );
339
+ if (sourceHandles === null) continue;
340
+ if (sourceHandles.length === 0) {
341
+ if (edge.sourceHandle) fail(`连线 ${edge.id} 的起点没有命名输出端口`);
342
+ continue;
343
+ }
344
+ if (!edge.sourceHandle)
345
+ fail(`连线 ${edge.id} 必须选择 ${source.type} 的输出端口`);
346
+ if (!sourceHandles.includes(edge.sourceHandle))
347
+ fail(`连线 ${edge.id} 使用了无效输出端口:${edge.sourceHandle}`);
348
+ }
349
+ }
350
+
351
+ function outputHandles(
352
+ node: WorkflowNode,
353
+ nodeType: WorkflowNodeType | undefined,
354
+ options: WorkflowDslValidationOptions,
355
+ ): string[] | null {
356
+ const runtimeOutput = RUNTIME_PORTS[node.type]?.output;
357
+ if (runtimeOutput) return [runtimeOutput];
358
+ if (node.type === 'switch') {
359
+ const config = effectiveConfig(node, options.referencedConfigs);
360
+ const cases = Array.isArray(config.cases) ? config.cases : [];
361
+ return [
362
+ ...cases
363
+ .map((item) => (isObject(item) ? item.id : undefined))
364
+ .filter((id): id is string => typeof id === 'string' && id.length > 0),
365
+ 'default',
366
+ ];
367
+ }
368
+ if (nodeType?.outputs === null) return null;
369
+ return nodeType?.outputs ?? null;
370
+ }
371
+
372
+ function validateOwnedPipelines(
373
+ dsl: WorkflowDSL,
374
+ calls: WorkflowEdge[],
375
+ returns: WorkflowEdge[],
376
+ nodes: Map<string, WorkflowNode>,
377
+ options: WorkflowDslValidationOptions,
378
+ ) {
379
+ const typeMap = new Map(
380
+ (options.nodeTypes ?? []).map((nodeType) => [nodeType.type, nodeType]),
381
+ );
382
+ const pairedFlows = dsl.edges.filter(
383
+ (edge) => edge.kind === 'FLOW' && edge.pairId,
384
+ );
385
+ for (const flow of pairedFlows) {
386
+ if (calls.filter((call) => call.pairId === flow.pairId).length !== 1)
387
+ fail(`管道 FLOW 连线 ${flow.id} 必须属于唯一 CALL`);
388
+ }
389
+ for (const result of returns) {
390
+ if (calls.filter((call) => call.pairId === result.pairId).length !== 1)
391
+ fail(`RETURN 连线 ${result.id} 必须属于唯一 CALL`);
392
+ }
393
+
394
+ const owners = new Map<string, Set<string>>();
395
+ for (const call of calls) {
396
+ const source = nodes.get(call.source);
397
+ if (!source || !['for_each', 'parallel'].includes(source.type))
398
+ fail(`CALL 连线 ${call.id} 只能从循环或并行节点发出`);
399
+ const ports = ownerPipelinePorts(source, call.sourceHandle, options);
400
+ if (!ports) fail(`CALL 连线 ${call.id} 必须使用有效的 START 端口`);
401
+ const pairedReturns = returns.filter(
402
+ (result) => result.pairId === call.pairId,
403
+ );
404
+ const pairFlows = pairedFlows.filter((edge) => edge.pairId === call.pairId);
405
+ let body: Set<string>;
406
+ if (source.type === 'for_each') {
407
+ if (pairedReturns.length !== 1)
408
+ fail(`CALL 管道 ${call.pairId} 必须且只能有一条 RETURN`);
409
+ const result = pairedReturns[0];
410
+ validatePipelineReturn(call, result, ports.end, nodes, typeMap, options);
411
+ body = linearBody(call.target, result.source, pairFlows, call.pairId!);
412
+ } else {
413
+ if (pairedReturns.length === 0)
414
+ fail(`并行分支管道 ${call.pairId} 的每个出口都必须返回 END`);
415
+ for (const result of pairedReturns)
416
+ validatePipelineReturn(
417
+ call,
418
+ result,
419
+ ports.end,
420
+ nodes,
421
+ typeMap,
422
+ options,
423
+ );
424
+ body = branchedBody(
425
+ call,
426
+ pairFlows,
427
+ pairedReturns,
428
+ nodes,
429
+ typeMap,
430
+ options,
431
+ );
432
+ }
433
+ for (const nodeId of body) {
434
+ const allowedTypes =
435
+ source.type === 'parallel' ? PARALLEL_BODY_TYPES : FOR_EACH_BODY_TYPES;
436
+ if (!allowedTypes.has(nodes.get(nodeId)?.type ?? ''))
437
+ fail(`节点 ${nodeId} 不能用于 START / END 处理链`);
438
+ if (
439
+ dsl.edges.some(
440
+ (edge) =>
441
+ (!edge.kind || edge.kind === 'FLOW') &&
442
+ !edge.pairId &&
443
+ (edge.source === nodeId || edge.target === nodeId),
444
+ )
445
+ )
446
+ fail(`START / END 处理链节点 ${nodeId} 不能同时属于主流程`);
447
+ const pairIds = owners.get(nodeId) ?? new Set<string>();
448
+ pairIds.add(call.pairId!);
449
+ owners.set(nodeId, pairIds);
450
+ }
451
+ }
452
+
453
+ for (const node of dsl.nodes.filter((item) => item.type === 'for_each')) {
454
+ if (calls.filter((call) => call.source === node.id).length !== 1)
455
+ fail(`循环节点 ${node.id} 必须拥有一条完整处理链`);
456
+ }
457
+ for (const node of dsl.nodes.filter((item) => item.type === 'parallel')) {
458
+ const config = effectiveConfig(node, options.referencedConfigs);
459
+ const branches = parallelBranches(config);
460
+ if (branches.length < 2) fail(`并行节点 ${node.id} 至少需要两个分支`);
461
+ const ownedCalls = calls.filter((call) => call.source === node.id);
462
+ if (ownedCalls.length !== branches.length)
463
+ fail(`并行节点 ${node.id} 的每个分支都必须连接完整 START / END 处理链`);
464
+ for (const branch of branches) {
465
+ if (
466
+ ownedCalls.filter((call) => call.sourceHandle === `${branch.id}-start`)
467
+ .length !== 1
468
+ )
469
+ fail(`并行节点 ${node.id} 的分支“${branch.label}”缺少 START 处理链`);
470
+ }
471
+ }
472
+ for (const [nodeId, pairIds] of owners) {
473
+ if (pairIds.size > 1)
474
+ fail(`节点 ${nodeId} 不能属于多个 START / END 处理链`);
475
+ }
476
+ }
477
+
478
+ function ownerPipelinePorts(
479
+ node: WorkflowNode,
480
+ sourceHandle: string | undefined,
481
+ options: WorkflowDslValidationOptions,
482
+ ): { end: string } | null {
483
+ if (node.type === 'for_each')
484
+ return sourceHandle === 'start' ? { end: 'end' } : null;
485
+ if (node.type !== 'parallel') return null;
486
+ const branches = parallelBranches(
487
+ effectiveConfig(node, options.referencedConfigs),
488
+ );
489
+ const branch = branches.find((item) => `${item.id}-start` === sourceHandle);
490
+ return branch ? { end: `${branch.id}-end` } : null;
491
+ }
492
+
493
+ function parallelBranches(
494
+ config: Record<string, any>,
495
+ ): Array<{ id: string; label: string }> {
496
+ return (Array.isArray(config.branches) ? config.branches : []).filter(
497
+ (item): item is { id: string; label: string } =>
498
+ isObject(item) &&
499
+ typeof item.id === 'string' &&
500
+ item.id.length > 0 &&
501
+ typeof item.label === 'string' &&
502
+ item.label.length > 0,
503
+ );
504
+ }
505
+
506
+ function assertPipelineBoundaryHandles(
507
+ call: WorkflowEdge,
508
+ result: WorkflowEdge,
509
+ nodes: Map<string, WorkflowNode>,
510
+ typeMap: Map<string, WorkflowNodeType>,
511
+ options: WorkflowDslValidationOptions,
512
+ ) {
513
+ const input = RUNTIME_PORTS[nodes.get(call.target)?.type ?? '']?.input;
514
+ if ((call.targetHandle ?? '') !== (input ?? ''))
515
+ fail(
516
+ input
517
+ ? `CALL 连线 ${call.id} 必须进入 ${input}`
518
+ : `CALL 连线 ${call.id} 的目标节点没有命名输入端口`,
519
+ );
520
+ const source = nodes.get(result.source)!;
521
+ const outputs = outputHandles(source, typeMap.get(source.type), options);
522
+ if (outputs === null) return;
523
+ if (outputs.length === 0 && result.sourceHandle)
524
+ fail(`RETURN 连线 ${result.id} 的起点没有命名输出端口`);
525
+ if (outputs.length > 0 && !outputs.includes(result.sourceHandle ?? ''))
526
+ fail(`RETURN 连线 ${result.id} 必须从有效输出端口返回`);
527
+ }
528
+
529
+ function validatePipelineReturn(
530
+ call: WorkflowEdge,
531
+ result: WorkflowEdge,
532
+ endHandle: string,
533
+ nodes: Map<string, WorkflowNode>,
534
+ typeMap: Map<string, WorkflowNodeType>,
535
+ options: WorkflowDslValidationOptions,
536
+ ) {
537
+ if (result.target !== call.source || result.targetHandle !== endHandle)
538
+ fail(`RETURN 连线 ${result.id} 必须返回对应的 END 端口`);
539
+ if (result.valueType !== 'JSON')
540
+ fail(`RETURN 连线 ${result.id} 必须使用 JSON valueType`);
541
+ assertPipelineBoundaryHandles(call, result, nodes, typeMap, options);
542
+ }
543
+
544
+ function branchedBody(
545
+ call: WorkflowEdge,
546
+ flows: WorkflowEdge[],
547
+ returns: WorkflowEdge[],
548
+ nodes: Map<string, WorkflowNode>,
549
+ typeMap: Map<string, WorkflowNodeType>,
550
+ options: WorkflowDslValidationOptions,
551
+ ): Set<string> {
552
+ const body = new Set([call.target]);
553
+ let changed = true;
554
+ while (changed) {
555
+ changed = false;
556
+ for (const edge of flows) {
557
+ if (!body.has(edge.source) || body.has(edge.target)) continue;
558
+ body.add(edge.target);
559
+ changed = true;
560
+ }
561
+ }
562
+ if (
563
+ flows.some((edge) => !body.has(edge.source) || !body.has(edge.target)) ||
564
+ returns.some((edge) => !body.has(edge.source))
565
+ )
566
+ fail(`并行分支管道 ${call.pairId} 包含断开的连线`);
567
+
568
+ for (const nodeId of body) {
569
+ const incoming = flows.filter((edge) => edge.target === nodeId);
570
+ if (
571
+ (nodeId === call.target && incoming.length > 0) ||
572
+ (nodeId !== call.target && incoming.length !== 1)
573
+ )
574
+ fail(`并行分支管道 ${call.pairId} 不能合流`);
575
+
576
+ const node = nodes.get(nodeId)!;
577
+ const outputs = outputHandles(node, typeMap.get(node.type), options);
578
+ const outgoing = [
579
+ ...flows.filter((edge) => edge.source === nodeId),
580
+ ...returns.filter((edge) => edge.source === nodeId),
581
+ ];
582
+ if (outputs === null || outputs.length <= 1) {
583
+ if (outgoing.length !== 1)
584
+ fail(`并行分支节点 ${nodeId} 必须连接一个后续节点或 END`);
585
+ continue;
586
+ }
587
+ for (const handle of outputs) {
588
+ if (outgoing.filter((edge) => edge.sourceHandle === handle).length !== 1)
589
+ fail(`并行分支节点 ${nodeId} 的每个出口都必须连接后续节点或 END`);
590
+ }
591
+ if (outgoing.length !== outputs.length)
592
+ fail(`并行分支节点 ${nodeId} 使用了重复或无效出口`);
593
+ }
594
+ return body;
595
+ }
596
+
597
+ function linearBody(
598
+ first: string,
599
+ last: string,
600
+ flows: WorkflowEdge[],
601
+ pairId: string,
602
+ ): Set<string> {
603
+ const body = new Set([first]);
604
+ let current = first;
605
+ while (current !== last) {
606
+ const next = flows.filter((edge) => edge.source === current);
607
+ if (next.length !== 1) fail(`循环处理链 ${pairId} 必须是一条连续直线`);
608
+ current = next[0].target;
609
+ if (body.has(current)) fail(`循环处理链 ${pairId} 不能形成回路`);
610
+ body.add(current);
611
+ }
612
+ if (flows.some((edge) => edge.source === last))
613
+ fail(`循环处理链 ${pairId} 必须在 RETURN 前结束`);
614
+ if (flows.length !== body.size - 1)
615
+ fail(`循环处理链 ${pairId} 包含断开的 FLOW 连线`);
616
+ return body;
617
+ }
618
+
619
+ function validateReachability(
620
+ dsl: WorkflowDSL,
621
+ triggerId: string,
622
+ calls: WorkflowEdge[],
623
+ ) {
624
+ const callablePairs = new Set(calls.map((edge) => edge.pairId));
625
+ const reachable = new Set([triggerId]);
626
+ let changed = true;
627
+ while (changed) {
628
+ changed = false;
629
+ for (const edge of dsl.edges) {
630
+ if (
631
+ edge.kind === 'RETURN' ||
632
+ (edge.kind === 'FLOW' &&
633
+ edge.pairId &&
634
+ !callablePairs.has(edge.pairId)) ||
635
+ !reachable.has(edge.source) ||
636
+ reachable.has(edge.target)
637
+ )
638
+ continue;
639
+ reachable.add(edge.target);
640
+ changed = true;
641
+ }
642
+ }
643
+ const unreachable = dsl.nodes
644
+ .map((node) => node.id)
645
+ .filter((id) => !reachable.has(id));
646
+ if (unreachable.length > 0)
647
+ fail(`存在未连接到触发节点的节点:${unreachable.join(', ')}`);
648
+ }
649
+
650
+ function validateFlowDag(nodeIds: Set<string>, flows: WorkflowEdge[]) {
651
+ const indegree = new Map([...nodeIds].map((id) => [id, 0]));
652
+ const adjacency = new Map([...nodeIds].map((id) => [id, [] as string[]]));
653
+ for (const edge of flows) {
654
+ indegree.set(edge.target, indegree.get(edge.target)! + 1);
655
+ adjacency.get(edge.source)!.push(edge.target);
656
+ }
657
+ const queue = [...indegree.entries()]
658
+ .filter(([, count]) => count === 0)
659
+ .map(([id]) => id);
660
+ let visited = 0;
661
+ while (queue.length > 0) {
662
+ const id = queue.shift()!;
663
+ visited++;
664
+ for (const next of adjacency.get(id) ?? []) {
665
+ const count = indegree.get(next)! - 1;
666
+ indegree.set(next, count);
667
+ if (count === 0) queue.push(next);
668
+ }
669
+ }
670
+ if (visited !== nodeIds.size) fail('Workflow FLOW 连线不能形成回路');
671
+ }
672
+
673
+ function effectiveConfig(
674
+ node: WorkflowNode,
675
+ referencedConfigs?: Record<string, Record<string, any>>,
676
+ ): Record<string, any> {
677
+ return node.instanceRef
678
+ ? (node.configOverride ??
679
+ referencedConfigs?.[node.instanceRef.instanceId] ??
680
+ node.config)
681
+ : node.config;
682
+ }
683
+
684
+ function isPositiveId(value: unknown): boolean {
685
+ return typeof value === 'string' && /^[1-9]\d*$/.test(value);
686
+ }
687
+
688
+ function isObject(value: unknown): value is Record<string, any> {
689
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
690
+ }
691
+
692
+ function fail(message: string): never {
693
+ throw new Error(message);
694
+ }