@gadmin2n/schematics 0.0.144 → 0.0.146

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 (280) 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 +49 -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/src/modules/agenda/agenda.service.ts +14 -24
  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/seed/workflows.ts +0 -698
  253. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.external-decision.spec.ts +0 -183
  254. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/legacy-approval-config-migration.ts +0 -227
  255. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.spec.ts +0 -82
  256. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.ts +0 -111
  257. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +0 -54
  258. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.ts +0 -147
  259. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.module.ts +0 -10
  260. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +0 -350
  261. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.ts +0 -110
  262. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.ts +0 -1
  263. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/InstanceRequiredDialog.tsx +0 -106
  264. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.test.tsx +0 -45
  265. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.tsx +0 -43
  266. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeTypeBadge.tsx +0 -36
  267. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useNodeInstanceLibrary.ts +0 -41
  268. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.test.tsx +0 -47
  269. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.tsx +0 -182
  270. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.test.tsx +0 -34
  271. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.tsx +0 -16
  272. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.test.ts +0 -25
  273. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.ts +0 -42
  274. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.test.ts +0 -208
  275. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.ts +0 -246
  276. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/create.tsx +0 -111
  277. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/edit.tsx +0 -127
  278. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/index.tsx +0 -4
  279. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +0 -282
  280. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/show.tsx +0 -74
@@ -1,6 +1,7 @@
1
1
  import { HttpStatus, Injectable, Optional } from '@nestjs/common';
2
2
  import { Prisma } from '@prisma/client';
3
3
  import { PrismaService } from 'nestjs-prisma';
4
+ import { executeCode } from '../codeRuntime/code-executor';
4
5
  import { ExternalInteractionService } from '../externalInteraction/external-interaction.service';
5
6
  import type { ExternalResultInput } from '../externalInteraction/external-interaction.types';
6
7
  import { SubjectProviderRegistry } from '../subjectProvider/subject-provider.registry';
@@ -15,7 +16,6 @@ import {
15
16
  ApprovalConfigSnapshotDto,
16
17
  StartApprovalRequestDto,
17
18
  SubmitApprovalDecisionDto,
18
- SubmitExternalApprovalDecisionDto,
19
19
  } from './human-approval.dto';
20
20
  import { HumanApprovalDomainError } from './human-approval.errors';
21
21
 
@@ -42,48 +42,11 @@ export class HumanApprovalService {
42
42
  );
43
43
  }
44
44
 
45
- const existing = await this.prisma.approvalRequest.findUnique({
46
- where: {
47
- workflowInstanceId_nodeId: { workflowInstanceId, nodeId: input.nodeId },
48
- },
49
- include: { candidates: true },
50
- });
51
-
52
- const approvalWorkflowId = input.configSnapshot.approvalWorkflowId?.trim();
53
- let approvalWorkflow: { isEnabled: boolean; status: string } | null = null;
54
- if (approvalWorkflowId) {
55
- approvalWorkflow = await this.prisma.workflow.findUnique({
56
- where: { id: toBigInt(approvalWorkflowId) },
57
- select: { isEnabled: true, status: true },
58
- });
59
- if (
60
- !approvalWorkflow?.isEnabled ||
61
- approvalWorkflow.status !== 'PUBLISHED'
62
- )
63
- throw approvalError(
64
- 'APPROVAL_CONFIG_MISMATCH',
65
- `Approval Workflow ${approvalWorkflowId} was not found, published, or enabled`,
66
- HttpStatus.BAD_REQUEST,
67
- );
68
- }
69
-
70
- if (existing) {
71
- return attachApprovalWorkflowInvocation(
72
- existing,
73
- existing.candidates,
74
- approvalWorkflowId,
75
- input,
76
- );
77
- }
78
-
79
45
  let materializedSubjects;
80
46
  try {
81
- materializedSubjects = mergeSubjectSources(
82
- materializeApprovalSubjects(
83
- input.configSnapshot.subjects as unknown as ApprovalSubjectSource[],
84
- input.dynamicInputs,
85
- ),
86
- input.resolvedSubjects ?? [],
47
+ materializedSubjects = materializeApprovalSubjects(
48
+ input.configSnapshot.subjects as unknown as ApprovalSubjectSource[],
49
+ input.dynamicInputs,
87
50
  );
88
51
  } catch (error) {
89
52
  throw approvalError(
@@ -93,24 +56,62 @@ export class HumanApprovalService {
93
56
  );
94
57
  }
95
58
  const resolved = await this.resolveSubjects(materializedSubjects, actor);
96
- const startedAt = new Date();
97
- const expiresAt =
98
- input.configSnapshot.timeout.durationSeconds > 0
99
- ? new Date(
100
- startedAt.getTime() +
101
- input.configSnapshot.timeout.durationSeconds * 1000,
102
- )
103
- : null;
104
- const blocked = resolved.candidates.length === 0;
105
-
59
+ const requestHash = approvalRequestHash(input, resolved);
106
60
  return this.prisma.$transaction(async (tx) => {
61
+ assertWorkflowAcceptsApproval(
62
+ await lockWorkflowInstance(tx, workflowInstanceId),
63
+ );
64
+ const existing = await tx.approvalRequest.findUnique({
65
+ where: {
66
+ workflowInstanceId_nodeId: {
67
+ workflowInstanceId,
68
+ nodeId: input.nodeId,
69
+ },
70
+ },
71
+ include: {
72
+ candidates: true,
73
+ signalOutboxes: { orderBy: { id: 'desc' }, take: 1 },
74
+ },
75
+ });
76
+ if (existing) {
77
+ if (existing.requestHash !== requestHash)
78
+ throw approvalError(
79
+ 'APPROVAL_CONFIG_MISMATCH',
80
+ 'Approval request data changed during an idempotent retry',
81
+ HttpStatus.CONFLICT,
82
+ );
83
+ return attachCompletedResolution(
84
+ attachExternalApproval(existing, existing.candidates, input),
85
+ );
86
+ }
87
+
88
+ const reusable = await this.findCompletedRetryApproval(tx, {
89
+ workflowInstanceId,
90
+ workflowVersionId,
91
+ nodeId: input.nodeId,
92
+ configHash: input.configHash,
93
+ requestHash,
94
+ });
95
+ if (reusable) return attachCompletedResolution(reusable);
96
+
97
+ const startedAt = new Date();
98
+ const expiresAt =
99
+ input.configSnapshot.timeout.durationSeconds > 0
100
+ ? new Date(
101
+ startedAt.getTime() +
102
+ input.configSnapshot.timeout.durationSeconds * 1000,
103
+ )
104
+ : null;
105
+ const blocked = resolved.candidates.length === 0;
107
106
  const request = await tx.approvalRequest.create({
108
107
  data: {
109
108
  workflowInstanceId,
110
109
  nodeId: input.nodeId,
111
110
  workflowVersionId,
112
111
  configHash: input.configHash,
112
+ requestHash,
113
113
  configSnapshot: snapshot as Prisma.InputJsonValue,
114
+ task: input.task as unknown as Prisma.InputJsonValue,
114
115
  approvalRule: input.configSnapshot
115
116
  .approvalRule as unknown as Prisma.InputJsonValue,
116
117
  rejectionRule: input.configSnapshot
@@ -126,43 +127,100 @@ export class HumanApprovalService {
126
127
  subjects: { create: resolved.subjects },
127
128
  candidates: { create: resolved.candidates },
128
129
  },
130
+ include: { candidates: true },
129
131
  });
130
- if (approvalWorkflowId && !blocked) {
132
+ if (input.configSnapshot.external && !blocked) {
131
133
  if (
132
- !this.externalInteractions ||
133
- !input.tenantNamespace ||
134
- !input.approvalWorkflowRunId ||
135
134
  !input.callbackToken ||
136
- !approvalWorkflow
135
+ !input.callbackUrl ||
136
+ !input.tenantNamespace ||
137
+ !input.temporalRunId
137
138
  )
138
139
  throw approvalError(
139
140
  'APPROVAL_CONFIG_MISMATCH',
140
141
  'External approval callback runtime is not configured',
141
142
  HttpStatus.BAD_REQUEST,
142
143
  );
143
- const interaction =
144
- await this.externalInteractions.createInteractionInTransaction(
145
- {
146
- callbackToken: input.callbackToken,
147
- tenantNamespace: input.tenantNamespace,
148
- handlerType: 'EXTERNAL_WAIT',
149
- handlerConfig: { allowedOutcomes: ['RECEIVED'] },
150
- workflowInstanceId: String(workflowInstanceId),
151
- workflowVersionId: String(workflowVersionId),
152
- temporalRunId: input.approvalWorkflowRunId,
153
- nodeId: input.nodeId,
154
- ...(expiresAt && { expiresAt: expiresAt.toISOString() }),
155
- },
156
- tx,
144
+ if (!this.externalInteractions)
145
+ throw approvalError(
146
+ 'APPROVAL_CONFIG_MISMATCH',
147
+ 'External approval callback runtime is unavailable',
148
+ HttpStatus.BAD_REQUEST,
157
149
  );
158
- return attachApprovalWorkflowInvocation(
159
- request,
160
- resolved.candidates,
161
- approvalWorkflowId,
162
- { ...input, callbackToken: interaction.callbackToken },
150
+ await this.externalInteractions.createInteractionInTransaction(
151
+ {
152
+ callbackToken: input.callbackToken,
153
+ tenantNamespace: input.tenantNamespace,
154
+ handlerType: 'HUMAN_APPROVAL',
155
+ handlerConfig: {
156
+ approvalRequestId: String(request.id),
157
+ input: input.input,
158
+ callbackUrl: input.callbackUrl,
159
+ },
160
+ workflowInstanceId: String(workflowInstanceId),
161
+ workflowVersionId: String(workflowVersionId),
162
+ temporalRunId: input.temporalRunId,
163
+ nodeId: input.nodeId,
164
+ ...(expiresAt && { expiresAt: expiresAt.toISOString() }),
165
+ },
166
+ tx,
163
167
  );
164
168
  }
165
- return request;
169
+ return attachExternalApproval(request, request.candidates, input);
170
+ });
171
+ }
172
+
173
+ private async findCompletedRetryApproval(
174
+ tx: Prisma.TransactionClient,
175
+ input: {
176
+ workflowInstanceId: bigint;
177
+ workflowVersionId: bigint;
178
+ nodeId: string;
179
+ configHash: string;
180
+ requestHash: string;
181
+ },
182
+ ) {
183
+ const current = await tx.workflowInstance.findUnique({
184
+ where: { id: input.workflowInstanceId },
185
+ select: { id: true, workflowId: true, versionId: true, context: true },
186
+ });
187
+ if (!current || current.versionId !== input.workflowVersionId) return null;
188
+
189
+ const operationScopeId = readOperationScopeId(current.context, current.id);
190
+ const instanceFilters: any[] = [
191
+ {
192
+ context: {
193
+ path: ['system', 'operationScopeId'],
194
+ equals: operationScopeId,
195
+ },
196
+ },
197
+ ];
198
+ if (/^[1-9][0-9]*$/.test(operationScopeId))
199
+ instanceFilters.unshift({ id: BigInt(operationScopeId) });
200
+ const instances = await tx.workflowInstance.findMany({
201
+ where: {
202
+ workflowId: current.workflowId,
203
+ versionId: input.workflowVersionId,
204
+ OR: instanceFilters,
205
+ },
206
+ select: { id: true },
207
+ });
208
+ if (!instances.length) return null;
209
+
210
+ return tx.approvalRequest.findFirst({
211
+ where: {
212
+ workflowInstanceId: { in: instances.map(({ id }) => id) },
213
+ workflowVersionId: input.workflowVersionId,
214
+ nodeId: input.nodeId,
215
+ configHash: input.configHash,
216
+ requestHash: input.requestHash,
217
+ status: { in: ['APPROVED', 'REJECTED'] },
218
+ },
219
+ orderBy: { completedAt: 'desc' },
220
+ include: {
221
+ candidates: true,
222
+ signalOutboxes: { orderBy: { id: 'desc' }, take: 1 },
223
+ },
166
224
  });
167
225
  }
168
226
 
@@ -172,6 +230,10 @@ export class HumanApprovalService {
172
230
  actor: ActorContext,
173
231
  ) {
174
232
  return this.prisma.$transaction(async (tx) => {
233
+ assertWorkflowAcceptsApproval(
234
+ await lockWorkflowForApprovalRequest(tx, requestId),
235
+ );
236
+ await lockApprovalRequest(tx, requestId);
175
237
  const request = await tx.approvalRequest.findUnique({
176
238
  where: { id: requestId },
177
239
  include: {
@@ -205,71 +267,17 @@ export class HumanApprovalService {
205
267
  });
206
268
  }
207
269
 
208
- async submitExternalDecision(
209
- requestId: bigint,
210
- input: SubmitExternalApprovalDecisionDto,
211
- ) {
212
- return this.prisma.$transaction(async (tx) => {
213
- const request = await tx.approvalRequest.findUnique({
214
- where: { id: requestId },
215
- include: {
216
- candidates: true,
217
- decisions: { include: { candidate: true } },
218
- },
219
- });
220
- if (!request) throw notFound(requestId);
221
-
222
- const snapshot = asObject(request.configSnapshot);
223
- if (snapshot.approvalWorkflowId !== input.approvalWorkflowId)
224
- throw approvalError(
225
- 'APPROVAL_WORKFLOW_MISMATCH',
226
- 'Result Workflow does not match the Workflow selected by this approval request',
227
- HttpStatus.FORBIDDEN,
228
- );
229
-
230
- const candidate = request.candidates.find(
231
- (item) =>
232
- item.invalidatedAt === null && item.principalRef === input.approverId,
233
- );
234
- if (!candidate)
235
- throw approvalError(
236
- 'APPROVAL_NOT_CANDIDATE',
237
- 'External approver is not an active approval candidate',
238
- HttpStatus.FORBIDDEN,
239
- );
240
-
241
- return this.recordDecision(
242
- tx,
243
- request,
244
- candidate,
245
- input,
246
- `external:${input.approvalWorkflowId}:${input.approverId}`,
247
- {
248
- ...(input.payload ?? {}),
249
- externalEventId: input.eventId,
250
- approvalWorkflowId: input.approvalWorkflowId,
251
- },
252
- );
253
- });
254
- }
255
-
256
270
  async handleExternalInteractionDecision(
257
271
  tx: any,
258
272
  requestId: bigint,
259
273
  input: ExternalResultInput,
274
+ nodeInput: unknown,
275
+ callbackUrl?: string,
260
276
  ): Promise<'PENDING' | 'APPROVED' | 'REJECTED'> {
261
- if (input.outcome !== 'APPROVE' && input.outcome !== 'REJECT')
262
- throw approvalError(
263
- 'APPROVAL_CONFIG_MISMATCH',
264
- 'External approval outcome must be APPROVE or REJECT',
265
- HttpStatus.BAD_REQUEST,
266
- );
267
- if (!input.operatorId)
268
- throw approvalError(
269
- 'APPROVAL_NOT_CANDIDATE',
270
- 'External approval requires an operator',
271
- HttpStatus.FORBIDDEN,
272
- );
277
+ assertWorkflowAcceptsApproval(
278
+ await lockWorkflowForApprovalRequest(tx, requestId),
279
+ );
280
+ await lockApprovalRequest(tx, requestId);
273
281
  const request = await tx.approvalRequest.findUnique({
274
282
  where: { id: requestId },
275
283
  include: {
@@ -278,9 +286,70 @@ export class HumanApprovalService {
278
286
  },
279
287
  });
280
288
  if (!request) throw notFound(requestId);
289
+ const workflowInstance = await tx.workflowInstance.findUnique({
290
+ where: { id: request.workflowInstanceId },
291
+ select: { context: true },
292
+ });
293
+ if (!workflowInstance)
294
+ throw approvalError(
295
+ 'APPROVAL_CONFIG_MISMATCH',
296
+ 'Workflow instance context is unavailable',
297
+ HttpStatus.BAD_REQUEST,
298
+ );
299
+ const snapshot = request.configSnapshot as any;
300
+ const callbackConfig = snapshot.external?.callbackResult;
301
+ if (typeof callbackConfig?.script !== 'string')
302
+ throw approvalError(
303
+ 'APPROVAL_CONFIG_MISMATCH',
304
+ 'External approval callback configuration is invalid',
305
+ HttpStatus.BAD_REQUEST,
306
+ );
307
+ const normalized = asObject(
308
+ await executeCode(
309
+ callbackConfig,
310
+ nodeInput,
311
+ asObject(asObject(workflowInstance.context).workflow),
312
+ {
313
+ approval: {
314
+ requestId: String(request.id),
315
+ callbackToken: input.callbackToken,
316
+ ...(callbackUrl && { callbackUrl }),
317
+ expiresAt:
318
+ request.expiresAt instanceof Date
319
+ ? request.expiresAt.toISOString()
320
+ : request.expiresAt ?? null,
321
+ task: request.task,
322
+ candidates: request.candidates.map((candidate) => ({
323
+ approverId: candidate.principalRef,
324
+ displayName: candidate.displayName,
325
+ })),
326
+ },
327
+ callback: {
328
+ body: asObject(input.data).callback,
329
+ eventId: input.eventId,
330
+ outcome: input.outcome,
331
+ ...(input.operatorId && { operatorId: input.operatorId }),
332
+ ...(input.data && { data: input.data }),
333
+ },
334
+ },
335
+ ),
336
+ );
337
+ if (!['APPROVED', 'REJECTED'].includes(String(normalized.result)))
338
+ throw approvalError(
339
+ 'APPROVAL_CONFIG_MISMATCH',
340
+ 'External approval callback result must be APPROVED or REJECTED',
341
+ HttpStatus.BAD_REQUEST,
342
+ );
343
+ const operatorId = stringValue(normalized.operatorId);
344
+ const eventId = stringValue(normalized.eventId);
345
+ if (!operatorId || !eventId)
346
+ throw approvalError(
347
+ 'APPROVAL_CONFIG_MISMATCH',
348
+ 'External approval callback result requires eventId and operatorId',
349
+ HttpStatus.BAD_REQUEST,
350
+ );
281
351
  const candidate = request.candidates.find(
282
- (item) =>
283
- item.invalidatedAt === null && item.principalRef === input.operatorId,
352
+ (item) => item.invalidatedAt === null && item.principalRef === operatorId,
284
353
  );
285
354
  if (!candidate)
286
355
  throw approvalError(
@@ -288,20 +357,30 @@ export class HumanApprovalService {
288
357
  'External approver is not an active approval candidate',
289
358
  HttpStatus.FORBIDDEN,
290
359
  );
291
- const data = asObject(input.data);
360
+ if (
361
+ normalized.data !== undefined &&
362
+ (!normalized.data ||
363
+ typeof normalized.data !== 'object' ||
364
+ Array.isArray(normalized.data))
365
+ )
366
+ throw approvalError(
367
+ 'APPROVAL_CONFIG_MISMATCH',
368
+ 'External approval callback data must be a JSON object',
369
+ HttpStatus.BAD_REQUEST,
370
+ );
371
+ const data = asObject(normalized.data);
292
372
  const result = await this.recordDecision(
293
373
  tx,
294
374
  request,
295
375
  candidate,
296
376
  {
297
- decision: input.outcome,
298
- ...(typeof data.comment === 'string' && { comment: data.comment }),
299
- },
300
- `external-token:${input.operatorId}`,
301
- {
302
- ...data,
303
- externalEventId: input.eventId,
377
+ decision: normalized.result === 'APPROVED' ? 'APPROVE' : 'REJECT',
378
+ ...(typeof normalized.comment === 'string' && {
379
+ comment: normalized.comment,
380
+ }),
304
381
  },
382
+ `external-token:${operatorId}`,
383
+ { ...data, externalEventId: eventId },
305
384
  false,
306
385
  );
307
386
  return result.status;
@@ -366,8 +445,11 @@ export class HumanApprovalService {
366
445
  where: { id: request.id, status: 'PENDING' },
367
446
  data: { status, completedAt: new Date() },
368
447
  });
369
- if (changed.count === 1 && createSignalOutbox)
370
- await this.createSignal(tx, request, status, 'RULE_SATISFIED');
448
+ if (changed.count === 1) {
449
+ await blockCancellationAfterResolution(tx, request);
450
+ if (createSignalOutbox)
451
+ await this.createSignal(tx, request, status, 'RULE_SATISFIED');
452
+ }
371
453
  }
372
454
  return {
373
455
  decision,
@@ -378,8 +460,13 @@ export class HumanApprovalService {
378
460
  };
379
461
  }
380
462
 
381
- cancelRequest(requestId: bigint) {
382
- return this.finishPending(requestId, 'CANCELLED', 'WORKFLOW_CANCELLED');
463
+ cancelRequest(requestId: bigint, createSignalOutbox = true) {
464
+ return this.finishPending(
465
+ requestId,
466
+ 'CANCELLED',
467
+ 'WORKFLOW_CANCELLED',
468
+ createSignalOutbox,
469
+ );
383
470
  }
384
471
 
385
472
  async expireRequest(requestId: bigint) {
@@ -413,10 +500,7 @@ export class HumanApprovalService {
413
500
  },
414
501
  orderBy: { activeFrom: 'desc' },
415
502
  });
416
- return items.filter(
417
- (item) =>
418
- !stringValue(asObject(item.request.configSnapshot).approvalWorkflowId),
419
- );
503
+ return items;
420
504
  }
421
505
 
422
506
  async status(requestId: bigint) {
@@ -441,8 +525,12 @@ export class HumanApprovalService {
441
525
  requestId: bigint,
442
526
  status: SignalResult,
443
527
  reason: SignalReason,
528
+ createSignalOutbox = true,
444
529
  ) {
445
530
  return this.prisma.$transaction(async (tx) => {
531
+ const workflow = await lockWorkflowForApprovalRequest(tx, requestId);
532
+ if (status !== 'CANCELLED') assertWorkflowAcceptsApproval(workflow);
533
+ await lockApprovalRequest(tx, requestId);
446
534
  const request = await tx.approvalRequest.findUnique({
447
535
  where: { id: requestId },
448
536
  });
@@ -452,8 +540,12 @@ export class HumanApprovalService {
452
540
  where: { id: requestId, status: 'PENDING' },
453
541
  data: { status, completedAt: new Date() },
454
542
  });
455
- if (changed.count === 1)
456
- await this.createSignal(tx, request, status, reason);
543
+ if (changed.count === 1) {
544
+ if (status === 'APPROVED' || status === 'REJECTED')
545
+ await blockCancellationAfterResolution(tx, request);
546
+ if (createSignalOutbox)
547
+ await this.createSignal(tx, request, status, reason);
548
+ }
457
549
  return tx.approvalRequest.findUnique({ where: { id: requestId } });
458
550
  });
459
551
  }
@@ -550,44 +642,54 @@ export class HumanApprovalService {
550
642
  }
551
643
  }
552
644
 
553
- function attachApprovalWorkflowInvocation(
645
+ function candidateKey(value: { principalType: string; principalRef: string }) {
646
+ return `${value.principalType}\u0000${value.principalRef}`;
647
+ }
648
+
649
+ function attachExternalApproval(
554
650
  request: any,
555
- candidates: any[],
556
- approvalWorkflowId: string | undefined,
651
+ candidates: Array<{
652
+ principalRef: string;
653
+ displayName: string;
654
+ principalType: string;
655
+ }>,
557
656
  input: StartApprovalRequestDto,
558
657
  ) {
559
- if (
560
- !approvalWorkflowId ||
561
- request.status !== 'PENDING' ||
562
- !input.callbackToken
563
- )
658
+ if (!input.configSnapshot.external || request.status === 'BLOCKED')
564
659
  return request;
565
- const expiresAt = request.expiresAt
566
- ? new Date(request.expiresAt).toISOString()
567
- : null;
660
+ if (!input.callbackToken)
661
+ throw approvalError(
662
+ 'APPROVAL_CONFIG_MISMATCH',
663
+ 'External approval callback token is missing',
664
+ HttpStatus.BAD_REQUEST,
665
+ );
666
+ if (!input.callbackUrl)
667
+ throw approvalError(
668
+ 'APPROVAL_CONFIG_MISMATCH',
669
+ 'External approval callback URL is missing',
670
+ HttpStatus.BAD_REQUEST,
671
+ );
568
672
  return {
569
673
  ...request,
570
- approvalWorkflowInvocation: {
571
- workflowId: approvalWorkflowId,
572
- workflow: {
573
- ...(input.approvalWorkflowInputs ?? {}),
574
- requestId: String(request.id),
575
- callbackToken: input.callbackToken,
576
- candidates: candidates.map((candidate) => ({
674
+ externalApproval: {
675
+ requestId: String(request.id),
676
+ callbackToken: input.callbackToken,
677
+ callbackUrl: input.callbackUrl,
678
+ expiresAt:
679
+ request.expiresAt instanceof Date
680
+ ? request.expiresAt.toISOString()
681
+ : request.expiresAt ?? null,
682
+ task: input.task,
683
+ candidates: candidates
684
+ .filter((candidate) => candidate.principalType === 'USER')
685
+ .map((candidate) => ({
577
686
  approverId: candidate.principalRef,
578
687
  displayName: candidate.displayName,
579
- principalType: candidate.principalType,
580
688
  })),
581
- expiresAt,
582
- },
583
689
  },
584
690
  };
585
691
  }
586
692
 
587
- function candidateKey(value: { principalType: string; principalRef: string }) {
588
- return `${value.principalType}\u0000${value.principalRef}`;
589
- }
590
-
591
693
  function toBigInt(value: string | number | bigint): bigint {
592
694
  if (typeof value === 'number' && !Number.isSafeInteger(value)) {
593
695
  throw approvalError(
@@ -627,31 +729,171 @@ function closed(id: bigint, status: string) {
627
729
  );
628
730
  }
629
731
 
630
- function asObject(value: unknown): Record<string, unknown> {
732
+ function asObject(value: unknown): Record<string, any> {
631
733
  return value && typeof value === 'object' && !Array.isArray(value)
632
- ? (value as Record<string, unknown>)
734
+ ? (value as Record<string, any>)
633
735
  : {};
634
736
  }
635
737
 
738
+ function readOperationScopeId(context: unknown, instanceId: bigint): string {
739
+ const configured = asObject(asObject(context).system).operationScopeId;
740
+ return typeof configured === 'string' && configured
741
+ ? configured
742
+ : String(instanceId);
743
+ }
744
+
745
+ function approvalRequestHash(
746
+ input: StartApprovalRequestDto,
747
+ resolved: {
748
+ subjects: Array<{
749
+ provider: string;
750
+ ref: string;
751
+ resourceRevision?: number;
752
+ metadata?: Prisma.InputJsonValue;
753
+ }>;
754
+ candidates: Array<{
755
+ principalType: string;
756
+ principalRef: string;
757
+ displayName: string;
758
+ sourceRefs: Prisma.InputJsonValue;
759
+ }>;
760
+ },
761
+ ): string {
762
+ const subjects = [...resolved.subjects].sort((left, right) =>
763
+ `${left.provider}:${left.ref}`.localeCompare(
764
+ `${right.provider}:${right.ref}`,
765
+ ),
766
+ );
767
+ const candidates = resolved.candidates
768
+ .map((candidate) => ({
769
+ principalType: candidate.principalType,
770
+ principalRef: candidate.principalRef,
771
+ sourceRefs: Array.isArray(candidate.sourceRefs)
772
+ ? [...candidate.sourceRefs].sort()
773
+ : candidate.sourceRefs,
774
+ }))
775
+ .sort((left, right) =>
776
+ `${left.principalType}:${left.principalRef}`.localeCompare(
777
+ `${right.principalType}:${right.principalRef}`,
778
+ ),
779
+ );
780
+ return hashNodeInstanceConfig({
781
+ configHash: input.configHash,
782
+ input: input.input as Prisma.JsonValue,
783
+ task: input.task as unknown as Prisma.JsonValue,
784
+ dynamicInputs: (input.dynamicInputs ?? {}) as Prisma.JsonValue,
785
+ subjects,
786
+ candidates,
787
+ } as Prisma.JsonValue);
788
+ }
789
+
790
+ function attachCompletedResolution<T extends Record<string, any>>(request: T) {
791
+ if (request.status !== 'APPROVED' && request.status !== 'REJECTED')
792
+ return request;
793
+ const payload = asObject(request.signalOutboxes?.[0]?.payload);
794
+ return {
795
+ ...request,
796
+ reusedResolution: {
797
+ requestId: String(request.id),
798
+ result: request.status,
799
+ reason:
800
+ typeof payload.reason === 'string' ? payload.reason : 'RULE_SATISFIED',
801
+ decidedAt:
802
+ typeof payload.decidedAt === 'string'
803
+ ? payload.decidedAt
804
+ : request.completedAt instanceof Date
805
+ ? request.completedAt.toISOString()
806
+ : new Date().toISOString(),
807
+ },
808
+ };
809
+ }
810
+
636
811
  function stringValue(value: unknown): string | null {
637
812
  return typeof value === 'string' && value.trim() ? value.trim() : null;
638
813
  }
639
814
 
640
- function mergeSubjectSources(
641
- ...groups: Array<Array<{ provider: string; refs: string[] }>>
642
- ) {
643
- const refsByProvider = new Map<string, Set<string>>();
644
- for (const group of groups) {
645
- for (const source of group) {
646
- const refs = refsByProvider.get(source.provider) ?? new Set<string>();
647
- for (const ref of source.refs) {
648
- if (typeof ref === 'string' && ref.trim()) refs.add(ref.trim());
649
- }
650
- refsByProvider.set(source.provider, refs);
651
- }
652
- }
653
- return [...refsByProvider].map(([provider, refs]) => ({
654
- provider,
655
- refs: [...refs],
656
- }));
815
+ type LockedWorkflowInstance = {
816
+ id: bigint;
817
+ status: string;
818
+ };
819
+
820
+ async function lockWorkflowInstance(
821
+ tx: any,
822
+ workflowInstanceId: bigint,
823
+ ): Promise<LockedWorkflowInstance | null> {
824
+ if (typeof tx.$queryRawUnsafe !== 'function')
825
+ return { id: workflowInstanceId, status: 'RUNNING' };
826
+ const rows = await tx.$queryRawUnsafe(
827
+ `SELECT id, status::text AS status
828
+ FROM t_workflow_instance
829
+ WHERE id = $1
830
+ FOR UPDATE`,
831
+ workflowInstanceId,
832
+ );
833
+ return rows[0] ?? null;
834
+ }
835
+
836
+ async function lockWorkflowForApprovalRequest(
837
+ tx: any,
838
+ requestId: bigint,
839
+ ): Promise<LockedWorkflowInstance | null> {
840
+ if (typeof tx.$queryRawUnsafe !== 'function')
841
+ return { id: BigInt(0), status: 'RUNNING' };
842
+ const rows = await tx.$queryRawUnsafe(
843
+ `SELECT workflow.id, workflow.status::text AS status
844
+ FROM t_workflow_instance workflow
845
+ JOIN t_approval_request approval
846
+ ON approval.workflow_instance_id = workflow.id
847
+ WHERE approval.id = $1
848
+ FOR UPDATE OF workflow`,
849
+ requestId,
850
+ );
851
+ return rows[0] ?? null;
852
+ }
853
+
854
+ function assertWorkflowAcceptsApproval(
855
+ workflow: LockedWorkflowInstance | null,
856
+ ): asserts workflow is LockedWorkflowInstance {
857
+ if (!workflow)
858
+ throw approvalError(
859
+ 'APPROVAL_REQUEST_NOT_FOUND',
860
+ 'Workflow instance for approval request was not found',
861
+ HttpStatus.NOT_FOUND,
862
+ );
863
+ if (!['PENDING', 'RUNNING'].includes(workflow.status))
864
+ throw approvalError(
865
+ 'APPROVAL_REQUEST_CLOSED',
866
+ 'Workflow instance is no longer accepting approval changes',
867
+ HttpStatus.CONFLICT,
868
+ );
869
+ }
870
+
871
+ async function blockCancellationAfterResolution(
872
+ tx: any,
873
+ request: {
874
+ workflowInstanceId: bigint;
875
+ nodeId: string;
876
+ configSnapshot: unknown;
877
+ },
878
+ ): Promise<void> {
879
+ if (asObject(request.configSnapshot).blockCancellationOnResolved !== true)
880
+ return;
881
+ await tx.workflowInstance.updateMany({
882
+ where: {
883
+ id: request.workflowInstanceId,
884
+ cancellationBlockedAt: null,
885
+ },
886
+ data: {
887
+ cancellationBlockedAt: new Date(),
888
+ cancellationBlockedByNodeId: request.nodeId,
889
+ },
890
+ });
891
+ }
892
+
893
+ async function lockApprovalRequest(tx: any, requestId: bigint): Promise<void> {
894
+ if (typeof tx.$queryRawUnsafe !== 'function') return;
895
+ await tx.$queryRawUnsafe(
896
+ 'SELECT id FROM t_approval_request WHERE id = $1 FOR UPDATE',
897
+ requestId,
898
+ );
657
899
  }