@nocobase/flow-engine 2.0.0-alpha.7 → 2.0.0-alpha.71

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 (589) hide show
  1. package/lib/BlockScopedFlowEngine.d.ts +23 -0
  2. package/lib/BlockScopedFlowEngine.js +91 -0
  3. package/lib/FlowContextProvider.d.ts +2 -2
  4. package/lib/FlowContextProvider.js +3 -3
  5. package/lib/FlowDefinition.d.ts +6 -4
  6. package/lib/JSRunner.d.ts +6 -0
  7. package/lib/JSRunner.js +27 -1
  8. package/lib/ViewScopedFlowEngine.d.ts +1 -1
  9. package/lib/ViewScopedFlowEngine.js +18 -1
  10. package/lib/acl/Acl.d.ts +12 -12
  11. package/lib/acl/Acl.js +88 -30
  12. package/lib/components/DynamicFlowsEditor.js +2 -4
  13. package/lib/components/FieldModelRenderer.js +17 -9
  14. package/lib/components/FieldSkeleton.d.ts +10 -0
  15. package/lib/components/FieldSkeleton.js +64 -0
  16. package/lib/components/FlowContextSelector.js +19 -3
  17. package/lib/components/FlowModelRenderer.d.ts +4 -6
  18. package/lib/components/FlowModelRenderer.js +35 -53
  19. package/lib/components/FormItem.js +5 -1
  20. package/lib/components/MobilePopup.d.ts +20 -0
  21. package/lib/components/MobilePopup.js +102 -0
  22. package/lib/components/MobilePopup.style.d.ts +17 -0
  23. package/lib/components/MobilePopup.style.js +186 -0
  24. package/lib/components/common/withFlowDesignMode.d.ts +1 -1
  25. package/lib/components/common/withFlowDesignMode.js +5 -5
  26. package/lib/components/dnd/gridDragPlanner.d.ts +1 -0
  27. package/lib/components/dnd/gridDragPlanner.js +53 -1
  28. package/lib/components/index.d.ts +1 -0
  29. package/lib/components/index.js +3 -1
  30. package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +71 -53
  31. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +19 -0
  32. package/lib/components/settings/wrappers/component/SelectWithTitle.js +136 -0
  33. package/lib/components/settings/wrappers/component/SwitchWithTitle.d.ts +10 -0
  34. package/lib/components/settings/wrappers/component/SwitchWithTitle.js +111 -0
  35. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +233 -97
  36. package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +71 -54
  37. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +2 -2
  38. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +63 -23
  39. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +13 -2
  40. package/lib/components/settings/wrappers/embedded/FlowSettings.js +42 -28
  41. package/lib/components/settings/wrappers/embedded/FlowsSettings.js +3 -3
  42. package/lib/components/settings/wrappers/embedded/FlowsSettingsContent.js +52 -32
  43. package/lib/components/subModel/AddSubModelButton.d.ts +7 -0
  44. package/lib/components/subModel/AddSubModelButton.js +78 -8
  45. package/lib/components/subModel/LazyDropdown.js +14 -15
  46. package/lib/components/subModel/utils.d.ts +1 -1
  47. package/lib/components/subModel/utils.js +21 -11
  48. package/lib/components/variables/VariableInput.js +26 -6
  49. package/lib/components/variables/VariableTag.js +43 -2
  50. package/lib/components/variables/types.d.ts +2 -0
  51. package/lib/components/variables/utils.js +4 -2
  52. package/lib/data-source/index.d.ts +23 -4
  53. package/lib/data-source/index.js +135 -14
  54. package/lib/data-source/jioToJoiSchema.js +1 -0
  55. package/lib/emitter.d.ts +6 -0
  56. package/lib/emitter.js +12 -0
  57. package/lib/executor/FlowExecutor.d.ts +6 -6
  58. package/lib/executor/FlowExecutor.js +302 -99
  59. package/lib/flow-registry/GlobalFlowRegistry.d.ts +1 -0
  60. package/lib/flow-registry/GlobalFlowRegistry.js +3 -0
  61. package/lib/flow-registry/InstanceFlowRegistry.d.ts +1 -0
  62. package/lib/flow-registry/InstanceFlowRegistry.js +3 -0
  63. package/lib/flowContext.d.ts +105 -6
  64. package/lib/flowContext.js +447 -139
  65. package/lib/flowEngine.d.ts +71 -1
  66. package/lib/flowEngine.js +319 -16
  67. package/lib/flowSettings.d.ts +4 -3
  68. package/lib/flowSettings.js +45 -21
  69. package/lib/hooks/useApplyAutoFlows.d.ts +1 -0
  70. package/lib/hooks/useApplyAutoFlows.js +3 -2
  71. package/lib/index.d.ts +14 -3
  72. package/lib/index.js +54 -7
  73. package/lib/locale/de-DE.json +62 -0
  74. package/lib/locale/en-US.json +57 -45
  75. package/lib/locale/es-ES.json +62 -0
  76. package/lib/locale/fr-FR.json +62 -0
  77. package/lib/locale/hu-HU.json +62 -0
  78. package/lib/locale/id-ID.json +62 -0
  79. package/lib/locale/index.d.ts +114 -90
  80. package/lib/locale/it-IT.json +62 -0
  81. package/lib/locale/ja-JP.json +62 -0
  82. package/lib/locale/ko-KR.json +62 -0
  83. package/lib/locale/nl-NL.json +62 -0
  84. package/lib/locale/pt-BR.json +62 -0
  85. package/lib/locale/ru-RU.json +62 -0
  86. package/lib/locale/tr-TR.json +62 -0
  87. package/lib/locale/uk-UA.json +62 -0
  88. package/lib/locale/vi-VN.json +62 -0
  89. package/lib/locale/zh-CN.json +58 -46
  90. package/lib/locale/zh-TW.json +62 -0
  91. package/lib/models/CollectionFieldModel.d.ts +7 -2
  92. package/lib/models/CollectionFieldModel.js +63 -16
  93. package/lib/models/flowModel.d.ts +76 -32
  94. package/lib/models/flowModel.js +300 -112
  95. package/lib/models/forkFlowModel.d.ts +8 -4
  96. package/lib/models/forkFlowModel.js +38 -8
  97. package/lib/provider.d.ts +3 -1
  98. package/lib/provider.js +14 -11
  99. package/lib/reactive/index.d.ts +10 -0
  100. package/lib/{runjs-context/snippets/global/api-request-post.snippet.js → reactive/index.js} +14 -15
  101. package/lib/reactive/observer.d.ts +19 -0
  102. package/lib/reactive/observer.js +109 -0
  103. package/lib/resources/baseRecordResource.d.ts +6 -0
  104. package/lib/resources/baseRecordResource.js +38 -3
  105. package/lib/resources/multiRecordResource.d.ts +5 -2
  106. package/lib/resources/multiRecordResource.js +26 -10
  107. package/lib/resources/singleRecordResource.js +8 -3
  108. package/lib/resources/sqlResource.d.ts +5 -3
  109. package/lib/resources/sqlResource.js +30 -28
  110. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +1 -6
  111. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +37 -20
  112. package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +1 -6
  113. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +46 -33
  114. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +1 -2
  115. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +14 -15
  116. package/lib/runjs-context/contexts/{LinkageRunJSContext.d.ts → JSColumnRunJSContext.d.ts} +6 -3
  117. package/lib/runjs-context/contexts/JSColumnRunJSContext.js +78 -0
  118. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.d.ts +16 -0
  119. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +125 -0
  120. package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +1 -6
  121. package/lib/runjs-context/contexts/JSFieldRunJSContext.js +28 -24
  122. package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +1 -6
  123. package/lib/runjs-context/contexts/JSItemRunJSContext.js +34 -20
  124. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +1 -2
  125. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +16 -17
  126. package/lib/runjs-context/contexts/base.d.ts +9 -0
  127. package/lib/runjs-context/contexts/base.js +879 -0
  128. package/lib/runjs-context/contributions.d.ts +33 -0
  129. package/lib/runjs-context/contributions.js +88 -0
  130. package/lib/runjs-context/helpers.d.ts +5 -2
  131. package/lib/runjs-context/helpers.js +36 -27
  132. package/lib/runjs-context/registry.d.ts +7 -4
  133. package/lib/runjs-context/registry.js +10 -42
  134. package/lib/runjs-context/setup.d.ts +9 -0
  135. package/lib/runjs-context/setup.js +88 -0
  136. package/lib/runjs-context/snippets/global/{copy-record-json.snippet.js → api-request.snippet.js} +25 -10
  137. package/lib/runjs-context/snippets/global/clipboard-copy-text.snippet.js +61 -0
  138. package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.js → import-esm.snippet.js} +26 -12
  139. package/lib/runjs-context/snippets/global/message-error.snippet.js +6 -0
  140. package/lib/runjs-context/snippets/global/message-success.snippet.js +6 -0
  141. package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +3 -8
  142. package/lib/runjs-context/snippets/global/notification-open.snippet.js +8 -1
  143. package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +10 -3
  144. package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +10 -3
  145. package/lib/runjs-context/snippets/global/query-selector.snippet.js +53 -0
  146. package/lib/runjs-context/snippets/global/require-amd.snippet.d.ts +11 -0
  147. package/lib/runjs-context/snippets/global/{requireAsync.snippet.js → require-amd.snippet.js} +16 -13
  148. package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +3 -8
  149. package/lib/runjs-context/snippets/global/window-open.snippet.js +8 -1
  150. package/lib/runjs-context/snippets/index.d.ts +24 -3
  151. package/lib/runjs-context/snippets/index.js +183 -40
  152. package/lib/runjs-context/snippets/scene/block/add-event-listener.snippet.d.ts +11 -0
  153. package/lib/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.js +11 -2
  154. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.d.ts +11 -0
  155. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.js +64 -0
  156. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.d.ts +11 -0
  157. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.js +99 -0
  158. package/lib/runjs-context/snippets/{libs → scene/block}/echarts-init.snippet.js +24 -7
  159. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.d.ts +11 -0
  160. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.js +65 -0
  161. package/lib/runjs-context/snippets/scene/block/render-button-handler.snippet.d.ts +11 -0
  162. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-button-handler.snippet.js +17 -9
  163. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.d.ts +11 -0
  164. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.js +57 -0
  165. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.d.ts +11 -0
  166. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.js +71 -0
  167. package/lib/runjs-context/snippets/scene/block/render-react-jsx.snippet.d.ts +11 -0
  168. package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.js → block/render-react-jsx.snippet.js} +26 -13
  169. package/lib/runjs-context/snippets/scene/block/render-react.snippet.d.ts +11 -0
  170. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-react.snippet.js +18 -17
  171. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.d.ts +11 -0
  172. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.js +95 -0
  173. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.d.ts +11 -0
  174. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.js +84 -0
  175. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.d.ts +11 -0
  176. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.js +60 -0
  177. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.d.ts +11 -0
  178. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.js +283 -0
  179. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.d.ts +11 -0
  180. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.js +124 -0
  181. package/lib/runjs-context/snippets/scene/detail/color-by-value.snippet.d.ts +11 -0
  182. package/lib/runjs-context/snippets/scene/{jsfield → detail}/color-by-value.snippet.js +13 -3
  183. package/lib/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.d.ts +11 -0
  184. package/lib/runjs-context/snippets/{global → scene/detail}/copy-to-clipboard.snippet.js +28 -6
  185. package/lib/runjs-context/snippets/scene/detail/format-number.snippet.d.ts +11 -0
  186. package/lib/runjs-context/snippets/scene/{jsfield → detail}/format-number.snippet.js +13 -3
  187. package/lib/runjs-context/snippets/scene/detail/innerHTML-value.snippet.d.ts +11 -0
  188. package/lib/runjs-context/snippets/scene/{jsfield → detail}/innerHTML-value.snippet.js +13 -3
  189. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.d.ts +11 -0
  190. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.js +82 -0
  191. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.d.ts +11 -0
  192. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.js +80 -0
  193. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.d.ts +11 -0
  194. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.js +74 -0
  195. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.d.ts +11 -0
  196. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.js +63 -0
  197. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.d.ts +11 -0
  198. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.js +81 -0
  199. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.d.ts +11 -0
  200. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.js +64 -0
  201. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.d.ts +11 -0
  202. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.js +74 -0
  203. package/lib/runjs-context/snippets/scene/form/render-basic.snippet.d.ts +11 -0
  204. package/lib/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.js +11 -2
  205. package/lib/runjs-context/snippets/scene/form/set-disabled.snippet.d.ts +11 -0
  206. package/lib/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.js +12 -3
  207. package/lib/runjs-context/snippets/scene/form/set-field-value.snippet.d.ts +11 -0
  208. package/lib/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.js +12 -3
  209. package/lib/runjs-context/snippets/scene/form/set-required.snippet.d.ts +11 -0
  210. package/lib/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.js +12 -3
  211. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.d.ts +11 -0
  212. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.js +67 -0
  213. package/lib/runjs-context/snippets/scene/form/toggle-visible.snippet.d.ts +11 -0
  214. package/lib/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.js +12 -3
  215. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.d.ts +11 -0
  216. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.js +64 -0
  217. package/lib/runjs-context/snippets/scene/table/collection-selected-count.snippet.d.ts +11 -0
  218. package/lib/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.js +11 -2
  219. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.d.ts +11 -0
  220. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.js +79 -0
  221. package/lib/runjs-context/snippets/scene/table/destroy-selected.snippet.d.ts +11 -0
  222. package/lib/runjs-context/snippets/{global/log-json-record.snippet.js → scene/table/destroy-selected.snippet.js} +24 -11
  223. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.d.ts +11 -0
  224. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.js +64 -0
  225. package/lib/runjs-context/snippets/scene/table/iterate-selected-rows.snippet.d.ts +11 -0
  226. package/lib/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.js +11 -2
  227. package/lib/runjs-context/snippets/types.d.ts +9 -1
  228. package/lib/runjsLibs.d.ts +28 -0
  229. package/lib/runjsLibs.js +532 -0
  230. package/lib/scheduler/ModelOperationScheduler.d.ts +53 -0
  231. package/lib/scheduler/ModelOperationScheduler.js +262 -0
  232. package/lib/types.d.ts +66 -7
  233. package/lib/types.js +4 -3
  234. package/lib/utils/associationObjectVariable.d.ts +32 -0
  235. package/lib/utils/associationObjectVariable.js +157 -0
  236. package/lib/utils/createCollectionContextMeta.d.ts +1 -1
  237. package/lib/utils/createCollectionContextMeta.js +9 -4
  238. package/lib/utils/createEphemeralContext.d.ts +13 -0
  239. package/lib/utils/createEphemeralContext.js +140 -0
  240. package/lib/utils/flows.d.ts +10 -0
  241. package/lib/{runjs-context/snippets/global/console-log-ctx.snippet.js → utils/flows.js} +21 -14
  242. package/lib/utils/index.d.ts +9 -3
  243. package/lib/utils/index.js +30 -2
  244. package/lib/utils/jsxTransform.d.ts +15 -0
  245. package/lib/utils/jsxTransform.js +68 -0
  246. package/lib/utils/params-resolvers.js +19 -12
  247. package/lib/utils/parsePathnameToViewParams.d.ts +1 -1
  248. package/lib/utils/parsePathnameToViewParams.js +41 -5
  249. package/lib/utils/pruneFilter.d.ts +21 -0
  250. package/lib/{runjs-context/snippets/global/try-catch-async.snippet.js → utils/pruneFilter.js} +24 -16
  251. package/lib/utils/resolveModuleUrl.d.ts +58 -0
  252. package/lib/utils/resolveModuleUrl.js +65 -0
  253. package/lib/utils/runjsModuleLoader.d.ts +58 -0
  254. package/lib/utils/runjsModuleLoader.js +422 -0
  255. package/lib/utils/runjsTemplateCompat.d.ts +35 -0
  256. package/lib/utils/runjsTemplateCompat.js +743 -0
  257. package/lib/utils/safeGlobals.d.ts +6 -8
  258. package/lib/utils/safeGlobals.js +169 -14
  259. package/lib/utils/schema-utils.d.ts +6 -0
  260. package/lib/utils/schema-utils.js +71 -6
  261. package/lib/utils/serverContextParams.d.ts +4 -0
  262. package/lib/utils/serverContextParams.js +2 -0
  263. package/lib/utils/translation.d.ts +4 -1
  264. package/lib/utils/translation.js +6 -2
  265. package/lib/utils/variablesParams.d.ts +22 -5
  266. package/lib/utils/variablesParams.js +141 -61
  267. package/lib/views/DialogComponent.js +1 -5
  268. package/lib/views/DrawerComponent.js +18 -9
  269. package/lib/views/PageComponent.js +5 -5
  270. package/lib/views/ViewNavigation.d.ts +11 -15
  271. package/lib/views/ViewNavigation.js +37 -19
  272. package/lib/views/createViewMeta.d.ts +27 -5
  273. package/lib/views/createViewMeta.js +338 -72
  274. package/lib/views/index.d.ts +1 -1
  275. package/lib/views/index.js +4 -0
  276. package/lib/views/useDialog.d.ts +10 -9
  277. package/lib/views/useDialog.js +46 -34
  278. package/lib/views/useDrawer.d.ts +10 -9
  279. package/lib/views/useDrawer.js +74 -48
  280. package/lib/views/usePage.d.ts +14 -9
  281. package/lib/views/usePage.js +82 -33
  282. package/lib/views/usePopover.js +4 -1
  283. package/lib/views/viewEvents.d.ts +17 -0
  284. package/lib/views/viewEvents.js +90 -0
  285. package/package.json +6 -3
  286. package/src/BlockScopedFlowEngine.ts +85 -0
  287. package/src/FlowContextProvider.tsx +4 -2
  288. package/src/JSRunner.ts +39 -1
  289. package/src/ViewScopedFlowEngine.ts +21 -1
  290. package/src/__tests__/JSRunner.test.ts +125 -52
  291. package/src/__tests__/blockScopedFlowEngine.test.ts +154 -0
  292. package/src/__tests__/createViewMeta.popup.test.ts +203 -0
  293. package/src/__tests__/flow-engine.test.ts +3 -0
  294. package/src/__tests__/flowContext.test.ts +160 -0
  295. package/src/__tests__/flowContextCreateJSRunner.test.ts +163 -0
  296. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
  297. package/src/__tests__/flowEngine.destroyModel.test.ts +74 -0
  298. package/src/__tests__/flowEngine.moveModel.test.ts +43 -0
  299. package/src/__tests__/flowEngine.removeModel.test.ts +72 -0
  300. package/src/__tests__/flowEngine.saveModel.test.ts +4 -0
  301. package/src/__tests__/flowModel.openView.navigation.test.ts +31 -2
  302. package/src/__tests__/flowRunJSContextDefine.test.ts +508 -0
  303. package/src/__tests__/flowSettings.open.test.tsx +71 -15
  304. package/src/__tests__/flowSettings.test.ts +2 -0
  305. package/src/__tests__/globalFlowRegistry.test.ts +1 -1
  306. package/src/__tests__/modelOperationScheduler.test.ts +346 -0
  307. package/src/__tests__/objectVariable.test.ts +464 -0
  308. package/src/__tests__/provider.test.tsx +0 -5
  309. package/src/__tests__/runjsContext.test.ts +219 -35
  310. package/src/__tests__/runjsContextImplementations.test.ts +217 -0
  311. package/src/__tests__/runjsContextRuntime.test.ts +269 -0
  312. package/src/__tests__/runjsEdgeCases.test.ts +281 -0
  313. package/src/__tests__/runjsExternalLibs.test.ts +242 -0
  314. package/src/__tests__/runjsLibsLazyLoading.test.ts +44 -0
  315. package/src/__tests__/runjsLocales.test.ts +39 -0
  316. package/src/__tests__/runjsPreprocessDefault.test.ts +49 -0
  317. package/src/__tests__/runjsRuntimeFeatures.test.ts +461 -0
  318. package/src/__tests__/runjsSnippets.test.ts +140 -0
  319. package/src/__tests__/viewScopedFlowEngine.test.ts +101 -3
  320. package/src/acl/Acl.tsx +85 -31
  321. package/src/acl/__tests__/Acl.test.tsx +43 -1
  322. package/src/components/DynamicFlowsEditor.tsx +0 -10
  323. package/src/components/FieldModelRenderer.tsx +22 -9
  324. package/src/components/FieldSkeleton.tsx +27 -0
  325. package/src/components/FlowContextSelector.tsx +20 -2
  326. package/src/components/FlowModelRenderer.tsx +52 -84
  327. package/src/components/FormItem.tsx +8 -1
  328. package/src/components/MobilePopup.style.ts +220 -0
  329. package/src/components/MobilePopup.tsx +86 -0
  330. package/src/components/__tests__/FlowModelRenderer.test.tsx +89 -0
  331. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +6 -6
  332. package/src/components/__tests__/gridDragPlanner.test.ts +141 -1
  333. package/src/components/common/withFlowDesignMode.tsx +5 -5
  334. package/src/components/dnd/gridDragPlanner.ts +60 -0
  335. package/src/components/index.ts +1 -0
  336. package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +34 -17
  337. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +110 -0
  338. package/src/components/settings/wrappers/component/SwitchWithTitle.tsx +83 -0
  339. package/src/components/settings/wrappers/component/__tests__/InlineControls.test.tsx +74 -0
  340. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +272 -125
  341. package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +34 -18
  342. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +56 -18
  343. package/src/components/settings/wrappers/contextual/StepSettings.tsx +1 -2
  344. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +13 -1
  345. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +624 -0
  346. package/src/components/settings/wrappers/embedded/FlowSettings.tsx +47 -35
  347. package/src/components/settings/wrappers/embedded/FlowsSettings.tsx +1 -1
  348. package/src/components/settings/wrappers/embedded/FlowsSettingsContent.tsx +64 -42
  349. package/src/components/subModel/AddSubModelButton.tsx +104 -9
  350. package/src/components/subModel/LazyDropdown.tsx +14 -14
  351. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +168 -7
  352. package/src/components/subModel/__tests__/utils.test.ts +12 -12
  353. package/src/components/subModel/utils.ts +25 -6
  354. package/src/components/variables/VariableInput.tsx +32 -6
  355. package/src/components/variables/VariableTag.tsx +54 -2
  356. package/src/components/variables/types.ts +2 -0
  357. package/src/components/variables/utils.ts +7 -3
  358. package/src/data-source/index.ts +143 -12
  359. package/src/data-source/jioToJoiSchema.ts +1 -0
  360. package/src/emitter.ts +14 -0
  361. package/src/executor/FlowExecutor.ts +383 -119
  362. package/src/executor/__tests__/ctx-defs-injection.test.ts +197 -0
  363. package/src/executor/__tests__/flowExecutor.test.ts +217 -5
  364. package/src/flow-registry/GlobalFlowRegistry.ts +1 -0
  365. package/src/flow-registry/InstanceFlowRegistry.ts +1 -0
  366. package/src/flow-registry/__tests__/globalFlowRegistry.test.ts +54 -0
  367. package/src/flowContext.ts +646 -158
  368. package/src/flowEngine.ts +385 -14
  369. package/src/flowSettings.ts +59 -30
  370. package/src/hooks/useApplyAutoFlows.ts +5 -3
  371. package/src/index.ts +26 -3
  372. package/src/locale/de-DE.json +62 -0
  373. package/src/locale/en-US.json +57 -45
  374. package/src/locale/es-ES.json +62 -0
  375. package/src/locale/fr-FR.json +62 -0
  376. package/src/locale/hu-HU.json +62 -0
  377. package/src/locale/id-ID.json +62 -0
  378. package/src/locale/it-IT.json +62 -0
  379. package/src/locale/ja-JP.json +62 -0
  380. package/src/locale/ko-KR.json +62 -0
  381. package/src/locale/nl-NL.json +62 -0
  382. package/src/locale/pt-BR.json +62 -0
  383. package/src/locale/ru-RU.json +62 -0
  384. package/src/locale/tr-TR.json +62 -0
  385. package/src/locale/uk-UA.json +62 -0
  386. package/src/locale/vi-VN.json +62 -0
  387. package/src/locale/zh-CN.json +58 -46
  388. package/src/locale/zh-TW.json +62 -0
  389. package/src/models/CollectionFieldModel.tsx +82 -18
  390. package/src/models/__tests__/dispatchEvent.behavior.test.ts +169 -0
  391. package/src/models/__tests__/dispatchEvent.when.test.ts +356 -0
  392. package/src/models/__tests__/flowEngine.resolveUse.test.ts +170 -0
  393. package/src/models/__tests__/flowModel.clone.test.ts +416 -0
  394. package/src/models/__tests__/flowModel.getFlows.sort.test.ts +33 -9
  395. package/src/models/__tests__/flowModel.scheduleModelOperation.test.tsx +129 -0
  396. package/src/models/__tests__/flowModel.test.ts +296 -119
  397. package/src/models/__tests__/forkFlowModel.test.ts +40 -7
  398. package/src/models/flowModel.tsx +426 -148
  399. package/src/models/forkFlowModel.ts +48 -8
  400. package/src/provider.tsx +18 -14
  401. package/src/reactive/__tests__/observer.test.tsx +211 -0
  402. package/src/reactive/index.ts +11 -0
  403. package/src/reactive/observer.tsx +101 -0
  404. package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
  405. package/src/resources/__tests__/sqlResource.test.ts +60 -0
  406. package/src/resources/baseRecordResource.ts +46 -3
  407. package/src/resources/multiRecordResource.ts +28 -12
  408. package/src/resources/singleRecordResource.ts +9 -3
  409. package/src/resources/sqlResource.ts +33 -32
  410. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +38 -21
  411. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +50 -34
  412. package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +15 -16
  413. package/src/runjs-context/contexts/JSColumnRunJSContext.ts +58 -0
  414. package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +106 -0
  415. package/src/runjs-context/contexts/JSFieldRunJSContext.ts +30 -25
  416. package/src/runjs-context/contexts/JSItemRunJSContext.ts +35 -21
  417. package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +17 -18
  418. package/src/runjs-context/contexts/base.ts +871 -0
  419. package/src/runjs-context/contributions.ts +88 -0
  420. package/src/runjs-context/helpers.ts +32 -30
  421. package/src/runjs-context/registry.ts +16 -47
  422. package/src/runjs-context/setup.ts +57 -0
  423. package/src/runjs-context/snippets/global/api-request.snippet.ts +38 -0
  424. package/src/runjs-context/snippets/global/clipboard-copy-text.snippet.ts +42 -0
  425. package/src/runjs-context/snippets/global/import-esm.snippet.ts +39 -0
  426. package/src/runjs-context/snippets/global/message-error.snippet.ts +6 -0
  427. package/src/runjs-context/snippets/global/message-success.snippet.ts +6 -0
  428. package/src/runjs-context/snippets/global/notification-open.snippet.ts +11 -1
  429. package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +10 -3
  430. package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +10 -3
  431. package/src/runjs-context/snippets/global/query-selector.snippet.ts +34 -0
  432. package/src/runjs-context/snippets/global/require-amd.snippet.ts +30 -0
  433. package/src/runjs-context/snippets/global/window-open.snippet.ts +11 -1
  434. package/src/runjs-context/snippets/index.ts +212 -39
  435. package/src/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.ts +14 -2
  436. package/src/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.ts +45 -0
  437. package/src/runjs-context/snippets/scene/block/chartjs-bar.snippet.ts +80 -0
  438. package/src/runjs-context/snippets/scene/block/echarts-init.snippet.ts +44 -0
  439. package/src/runjs-context/snippets/scene/block/render-antd-icons.snippet.ts +46 -0
  440. package/src/runjs-context/snippets/scene/block/render-button-handler.snippet.ts +35 -0
  441. package/src/runjs-context/snippets/scene/block/render-iframe.snippet.ts +38 -0
  442. package/src/runjs-context/snippets/scene/block/render-info-card.snippet.ts +52 -0
  443. package/src/runjs-context/snippets/scene/block/render-react-jsx.snippet.ts +39 -0
  444. package/src/runjs-context/snippets/scene/block/render-react.snippet.ts +38 -0
  445. package/src/runjs-context/snippets/scene/block/render-statistics.snippet.ts +76 -0
  446. package/src/runjs-context/snippets/scene/block/render-timeline.snippet.ts +65 -0
  447. package/src/runjs-context/snippets/scene/block/resource-example.snippet.ts +46 -0
  448. package/src/runjs-context/snippets/scene/block/three-users-orbit.snippet.ts +264 -0
  449. package/src/runjs-context/snippets/scene/block/vue-component.snippet.ts +105 -0
  450. package/src/runjs-context/snippets/scene/detail/color-by-value.snippet.ts +33 -0
  451. package/src/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.ts +45 -0
  452. package/src/runjs-context/snippets/scene/detail/format-number.snippet.ts +32 -0
  453. package/src/runjs-context/snippets/scene/detail/innerHTML-value.snippet.ts +31 -0
  454. package/src/runjs-context/snippets/scene/detail/percentage-bar.snippet.ts +63 -0
  455. package/src/runjs-context/snippets/scene/detail/relative-time.snippet.ts +61 -0
  456. package/src/runjs-context/snippets/scene/detail/status-tag.snippet.ts +55 -0
  457. package/src/runjs-context/snippets/scene/form/calculate-total.snippet.ts +44 -0
  458. package/src/runjs-context/snippets/scene/form/cascade-select.snippet.ts +62 -0
  459. package/src/runjs-context/snippets/scene/form/conditional-required.snippet.ts +45 -0
  460. package/src/runjs-context/snippets/scene/form/copy-field-values.snippet.ts +55 -0
  461. package/src/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.ts +14 -2
  462. package/src/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.ts +15 -3
  463. package/src/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.ts +15 -3
  464. package/src/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.ts +15 -3
  465. package/src/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.ts +48 -0
  466. package/src/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.ts +15 -3
  467. package/src/runjs-context/snippets/scene/table/cell-open-dialog.snippet.ts +45 -0
  468. package/src/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.ts +14 -2
  469. package/src/runjs-context/snippets/scene/table/concat-fields.snippet.ts +60 -0
  470. package/src/runjs-context/snippets/scene/table/destroy-selected.snippet.ts +36 -0
  471. package/src/runjs-context/snippets/scene/table/export-selected-json.snippet.ts +45 -0
  472. package/src/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.ts +14 -2
  473. package/src/runjs-context/snippets/types.ts +5 -1
  474. package/src/runjsLibs.ts +622 -0
  475. package/src/scheduler/ModelOperationScheduler.ts +306 -0
  476. package/src/types.ts +86 -5
  477. package/src/utils/__tests__/createCollectionContextMeta.test.ts +51 -0
  478. package/src/utils/__tests__/flows.test.ts +65 -0
  479. package/src/utils/__tests__/jsxTransform.test.ts +38 -0
  480. package/src/utils/__tests__/params-resolvers.test.ts +40 -0
  481. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +25 -0
  482. package/src/utils/__tests__/pruneFilter.test.ts +38 -0
  483. package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +38 -0
  484. package/src/utils/__tests__/runjsTemplateCompat.test.ts +159 -0
  485. package/src/utils/__tests__/safeGlobals.test.ts +79 -2
  486. package/src/utils/__tests__/utils.test.ts +114 -15
  487. package/src/utils/__tests__/variablesParams.test.ts +120 -0
  488. package/src/utils/associationObjectVariable.ts +180 -0
  489. package/src/utils/createCollectionContextMeta.ts +9 -3
  490. package/src/utils/createEphemeralContext.ts +142 -0
  491. package/src/utils/flows.ts +23 -0
  492. package/src/utils/index.ts +17 -3
  493. package/src/utils/jsxTransform.ts +39 -0
  494. package/src/utils/params-resolvers.ts +25 -11
  495. package/src/utils/parsePathnameToViewParams.ts +50 -6
  496. package/src/utils/pruneFilter.ts +41 -0
  497. package/src/utils/resolveModuleUrl.ts +91 -0
  498. package/src/utils/runjsModuleLoader.ts +553 -0
  499. package/src/utils/runjsTemplateCompat.ts +828 -0
  500. package/src/utils/safeGlobals.ts +181 -15
  501. package/src/utils/schema-utils.ts +81 -3
  502. package/src/utils/serverContextParams.ts +6 -0
  503. package/src/utils/translation.ts +7 -2
  504. package/src/utils/variablesParams.ts +164 -72
  505. package/src/views/DialogComponent.tsx +1 -4
  506. package/src/views/DrawerComponent.tsx +19 -7
  507. package/src/views/PageComponent.tsx +3 -5
  508. package/src/views/ViewNavigation.ts +49 -43
  509. package/src/views/__tests__/FlowView.usePage.test.tsx +186 -0
  510. package/src/views/__tests__/ViewNavigation.test.ts +54 -34
  511. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +159 -0
  512. package/src/views/__tests__/viewEvents.resolveOpenerEngine.test.ts +28 -0
  513. package/src/views/createViewMeta.ts +402 -73
  514. package/src/views/index.tsx +1 -1
  515. package/src/views/useDialog.tsx +52 -31
  516. package/src/views/useDrawer.tsx +99 -55
  517. package/src/views/usePage.tsx +101 -33
  518. package/src/views/usePopover.tsx +4 -1
  519. package/src/views/viewEvents.ts +55 -0
  520. package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +0 -38
  521. package/lib/runjs-context/contexts/FlowRunJSContext.js +0 -217
  522. package/lib/runjs-context/contexts/LinkageRunJSContext.js +0 -62
  523. package/lib/runjs-context/index.d.ts +0 -19
  524. package/lib/runjs-context/index.js +0 -57
  525. package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +0 -16
  526. package/lib/runjs-context/snippets/global/api-request-get.snippet.js +0 -42
  527. package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +0 -16
  528. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +0 -16
  529. package/lib/runjs-context/snippets/global/requireAsync.snippet.d.ts +0 -16
  530. package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +0 -16
  531. package/lib/runjs-context/snippets/global/sleep.snippet.js +0 -43
  532. package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +0 -16
  533. package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +0 -15
  534. package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +0 -15
  535. package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +0 -15
  536. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +0 -15
  537. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +0 -43
  538. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +0 -15
  539. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +0 -40
  540. package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +0 -15
  541. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +0 -15
  542. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +0 -42
  543. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +0 -15
  544. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js +0 -46
  545. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +0 -15
  546. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +0 -41
  547. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +0 -15
  548. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +0 -41
  549. package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +0 -15
  550. package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +0 -15
  551. package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +0 -15
  552. package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +0 -15
  553. package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +0 -15
  554. package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +0 -15
  555. package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +0 -15
  556. package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +0 -15
  557. package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +0 -15
  558. package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +0 -15
  559. package/src/runjs-context/contexts/FlowRunJSContext.ts +0 -190
  560. package/src/runjs-context/contexts/LinkageRunJSContext.ts +0 -35
  561. package/src/runjs-context/index.ts +0 -20
  562. package/src/runjs-context/snippets/global/api-request-get.snippet.ts +0 -20
  563. package/src/runjs-context/snippets/global/api-request-post.snippet.ts +0 -20
  564. package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +0 -19
  565. package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +0 -21
  566. package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +0 -21
  567. package/src/runjs-context/snippets/global/log-json-record.snippet.ts +0 -21
  568. package/src/runjs-context/snippets/global/requireAsync.snippet.ts +0 -24
  569. package/src/runjs-context/snippets/global/sleep.snippet.ts +0 -21
  570. package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +0 -22
  571. package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +0 -23
  572. package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +0 -24
  573. package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +0 -21
  574. package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +0 -18
  575. package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +0 -20
  576. package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +0 -24
  577. package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +0 -19
  578. package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +0 -24
  579. package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +0 -24
  580. package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +0 -30
  581. package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +0 -34
  582. package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +0 -20
  583. package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +0 -19
  584. package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +0 -18
  585. /package/lib/runjs-context/snippets/global/{copy-record-json.snippet.d.ts → api-request.snippet.d.ts} +0 -0
  586. /package/lib/runjs-context/snippets/global/{copy-to-clipboard.snippet.d.ts → clipboard-copy-text.snippet.d.ts} +0 -0
  587. /package/lib/runjs-context/snippets/global/{log-json-record.snippet.d.ts → import-esm.snippet.d.ts} +0 -0
  588. /package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.d.ts → query-selector.snippet.d.ts} +0 -0
  589. /package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.d.ts → block/echarts-init.snippet.d.ts} +0 -0
@@ -11,18 +11,69 @@ import _ from 'lodash';
11
11
  import { FlowRuntimeContext } from '../flowContext';
12
12
  import { FlowEngine } from '../flowEngine';
13
13
  import type { FlowModel } from '../models';
14
+ import type { DispatchEventOptions } from '../types';
14
15
  import type { ActionDefinition, ApplyFlowCacheEntry, StepDefinition } from '../types';
15
16
  import { FlowExitException, resolveDefaultParams } from '../utils';
16
17
  import { FlowExitAllException } from '../utils/exceptions';
17
18
  import { setupRuntimeContextSteps } from '../utils/setupRuntimeContextSteps';
19
+ import { createEphemeralContext } from '../utils/createEphemeralContext';
20
+ import type { ScheduledCancel } from '../scheduler/ModelOperationScheduler';
18
21
 
19
22
  export class FlowExecutor {
20
23
  constructor(private readonly engine: FlowEngine) {}
21
24
 
25
+ private async emitModelEventIf(
26
+ eventName: string | undefined,
27
+ topic: string,
28
+ payload: Record<string, any>,
29
+ ): Promise<void> {
30
+ if (!eventName) return;
31
+ await this.engine.emitter.emitAsync(`model:event:${eventName}:${topic}`, payload);
32
+ }
33
+
34
+ /** Cache wrapper for applyFlow cache lifecycle */
35
+ private async withApplyFlowCache<T>(cacheKey: string | null, executor: () => Promise<T>): Promise<T> {
36
+ if (!cacheKey || !this.engine) return await executor();
37
+
38
+ const cachedEntry = this.engine.applyFlowCache.get(cacheKey);
39
+ if (cachedEntry) {
40
+ if (cachedEntry.status === 'resolved') return cachedEntry.data as T;
41
+ if (cachedEntry.status === 'rejected') throw cachedEntry.error;
42
+ if (cachedEntry.status === 'pending') return await cachedEntry.promise;
43
+ }
44
+
45
+ const promise = executor()
46
+ .then((result) => {
47
+ this.engine.applyFlowCache.set(cacheKey, {
48
+ status: 'resolved',
49
+ data: result,
50
+ promise: Promise.resolve(result),
51
+ } as ApplyFlowCacheEntry);
52
+ return result;
53
+ })
54
+ .catch((err) => {
55
+ this.engine.applyFlowCache.set(cacheKey, {
56
+ status: 'rejected',
57
+ error: err,
58
+ promise: Promise.reject(err),
59
+ } as ApplyFlowCacheEntry);
60
+ throw err;
61
+ });
62
+
63
+ this.engine.applyFlowCache.set(cacheKey, { status: 'pending', promise } as ApplyFlowCacheEntry);
64
+ return await promise;
65
+ }
66
+
22
67
  /**
23
68
  * Execute a single flow on model.
24
69
  */
25
- async runFlow(model: FlowModel, flowKey: string, inputArgs?: Record<string, any>, runId?: string): Promise<any> {
70
+ async runFlow(
71
+ model: FlowModel,
72
+ flowKey: string,
73
+ inputArgs?: Record<string, any>,
74
+ runId?: string,
75
+ eventName?: string,
76
+ ): Promise<any> {
26
77
  const flow = model.getFlow(flowKey);
27
78
 
28
79
  if (!flow) {
@@ -46,43 +97,65 @@ export class FlowExecutor {
46
97
 
47
98
  let lastResult: any;
48
99
  const stepResults: Record<string, any> = flowContext.stepResults;
100
+
101
+ // Build steps with optional eventStep injection (when flow.on is configured)
49
102
  let eventStep = model.getEvent(typeof flow.on === 'string' ? flow.on : (flow.on as any)?.eventName);
50
103
  if (eventStep) {
51
- eventStep = { ...eventStep }; // clone to avoid side effects
52
- eventStep.defaultParams = { ..._.get(flow, 'on.defaultParams', {}), ...eventStep.defaultParams };
104
+ eventStep = { ...eventStep } as any; // clone to avoid side effects
105
+ (eventStep as any).defaultParams = {
106
+ ..._.get(flow, 'on.defaultParams', {}),
107
+ ...(eventStep as any).defaultParams,
108
+ };
53
109
  }
54
- // Execute the event step first since it's usually the trigger condition - if the condition is not met, subsequent steps don't need to execute
55
- const stepDefs = eventStep ? { eventStep, ...flow.steps } : flow.steps; // Record<string, StepDefinition>
110
+ const stepDefs: Record<string, StepDefinition> = eventStep
111
+ ? { eventStep: eventStep as any, ...flow.steps }
112
+ : flow.steps;
56
113
 
57
114
  // Setup steps meta and runtime mapping
58
115
  setupRuntimeContextSteps(flowContext, stepDefs, model, flowKey);
59
116
  const stepsRuntime = flowContext.steps as Record<string, { params: any; uiSchema?: any; result?: any }>;
60
117
 
61
- for (const stepKey in stepDefs) {
62
- if (!Object.prototype.hasOwnProperty.call(stepDefs, stepKey)) continue;
63
- const step: StepDefinition = stepDefs[stepKey];
64
- let handler: ActionDefinition['handler'] | undefined;
118
+ const flowEventBasePayload = {
119
+ uid: model.uid,
120
+ model,
121
+ runId: flowContext.runId,
122
+ inputArgs,
123
+ flowKey,
124
+ };
125
+
126
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:start`, flowEventBasePayload);
127
+
128
+ for (const [stepKey, step] of Object.entries(stepDefs) as [string, StepDefinition][]) {
129
+ // Resolve handler and params
130
+ let handler: ActionDefinition<FlowModel, FlowRuntimeContext>['handler'] | undefined;
65
131
  let combinedParams: Record<string, any> = {};
66
- let actionDefinition: ActionDefinition | undefined;
67
132
  let useRawParams: StepDefinition['useRawParams'] = step.useRawParams;
68
-
133
+ let runtimeCtx: FlowRuntimeContext;
69
134
  if (step.use) {
70
- // Step references a registered action
71
- actionDefinition = model.getAction(step.use);
135
+ const actionDefinition = model.getAction(step.use);
72
136
  if (!actionDefinition) {
73
137
  flowContext.logger.error(
74
138
  `BaseModel.applyFlow: Action '${step.use}' not found for step '${stepKey}' in flow '${flowKey}'. Skipping.`,
75
139
  );
76
140
  continue;
77
141
  }
142
+
143
+ // 为当前 step 创建“临时上下文”,并直接注入 action 与 step 提供的定义(step 覆盖 action)
144
+ runtimeCtx = await createEphemeralContext<FlowRuntimeContext>(flowContext, {
145
+ ...actionDefinition,
146
+ ...step,
147
+ });
148
+
78
149
  handler = step.handler || actionDefinition.handler;
79
150
  useRawParams = useRawParams ?? actionDefinition.useRawParams;
80
- const actionDefaultParams = await resolveDefaultParams(actionDefinition.defaultParams, flowContext);
81
- const stepDefaultParams = await resolveDefaultParams(step.defaultParams, flowContext);
151
+ const actionDefaultParams = await resolveDefaultParams(actionDefinition.defaultParams, runtimeCtx);
152
+ const stepDefaultParams = await resolveDefaultParams(step.defaultParams, runtimeCtx);
82
153
  combinedParams = { ...actionDefaultParams, ...stepDefaultParams };
83
154
  } else if (step.handler) {
155
+ // 对于内联 handler,为该步创建临时上下文并注入 step 定义
156
+ runtimeCtx = await createEphemeralContext<FlowRuntimeContext>(flowContext, step);
84
157
  handler = step.handler;
85
- const stepDefaultParams = await resolveDefaultParams(step.defaultParams, flowContext);
158
+ const stepDefaultParams = await resolveDefaultParams(step.defaultParams, runtimeCtx);
86
159
  combinedParams = { ...stepDefaultParams };
87
160
  } else {
88
161
  flowContext.logger.error(
@@ -97,12 +170,11 @@ export class FlowExecutor {
97
170
  }
98
171
  if (typeof useRawParams === 'function') {
99
172
  // eslint-disable-next-line react-hooks/rules-of-hooks
100
- useRawParams = await useRawParams(flowContext);
173
+ useRawParams = await useRawParams(runtimeCtx);
101
174
  }
102
175
  if (!useRawParams) {
103
- combinedParams = await flowContext.resolveJsonTemplate(combinedParams);
176
+ combinedParams = await runtimeCtx.resolveJsonTemplate(combinedParams);
104
177
  }
105
-
106
178
  try {
107
179
  if (!handler) {
108
180
  flowContext.logger.error(
@@ -110,24 +182,59 @@ export class FlowExecutor {
110
182
  );
111
183
  continue;
112
184
  }
113
- const currentStepResult = handler(flowContext, combinedParams);
185
+
186
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:start`, {
187
+ ...flowEventBasePayload,
188
+ stepKey,
189
+ });
190
+ const currentStepResult = handler(runtimeCtx, combinedParams);
114
191
  const isAwait = step.isAwait !== false;
115
192
  lastResult = isAwait ? await currentStepResult : currentStepResult;
116
193
 
117
- // Store step result
194
+ // Store step result and update context
118
195
  stepResults[stepKey] = lastResult;
119
- // update the context
120
196
  stepsRuntime[stepKey].result = stepResults[stepKey];
197
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:end`, {
198
+ ...flowEventBasePayload,
199
+ result: lastResult,
200
+ stepKey,
201
+ });
121
202
  } catch (error) {
203
+ if (!(error instanceof FlowExitException) && !(error instanceof FlowExitAllException)) {
204
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:error`, {
205
+ ...flowEventBasePayload,
206
+ error,
207
+ stepKey,
208
+ });
209
+ }
122
210
  if (error instanceof FlowExitException) {
123
211
  flowContext.logger.info(`[FlowEngine] ${error.message}`);
212
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:end`, {
213
+ ...flowEventBasePayload,
214
+ stepKey,
215
+ });
216
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:end`, {
217
+ ...flowEventBasePayload,
218
+ result: stepResults,
219
+ });
124
220
  return Promise.resolve(stepResults);
125
221
  }
126
222
  if (error instanceof FlowExitAllException) {
127
223
  flowContext.logger.info(`[FlowEngine] ${error.message}`);
128
- // 传递特殊控制信号,让上层可中止后续流程
224
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:end`, {
225
+ ...flowEventBasePayload,
226
+ stepKey,
227
+ });
228
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:end`, {
229
+ ...flowEventBasePayload,
230
+ result: error,
231
+ });
129
232
  return Promise.resolve(error);
130
233
  }
234
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:error`, {
235
+ ...flowEventBasePayload,
236
+ error,
237
+ });
131
238
  flowContext.logger.error(
132
239
  { err: error },
133
240
  `BaseModel.applyFlow: Error executing step '${stepKey}' in flow '${flowKey}':`,
@@ -135,122 +242,279 @@ export class FlowExecutor {
135
242
  return Promise.reject(error);
136
243
  }
137
244
  }
245
+ await this.emitModelEventIf(eventName, `flow:${flowKey}:end`, {
246
+ ...flowEventBasePayload,
247
+ result: stepResults,
248
+ });
138
249
  return Promise.resolve(stepResults);
139
250
  }
140
251
 
141
252
  /**
142
- * Execute all auto-apply flows for model.
253
+ * Dispatch an event to flows bound via flow.on and execute them.
143
254
  */
144
- async runAutoFlows(model: FlowModel, inputArgs?: Record<string, any>, useCache = true): Promise<any[]> {
145
- const autoApplyFlows = model.getAutoFlows();
255
+ async dispatchEvent(
256
+ model: FlowModel,
257
+ eventName: string,
258
+ inputArgs?: Record<string, any>,
259
+ options?: DispatchEventOptions,
260
+ ): Promise<any> {
261
+ const isBeforeRender = eventName === 'beforeRender';
262
+ // 由模型层决定缺省值;执行器仅按显式 options 执行
263
+ const sequential = !!options?.sequential;
264
+ const useCache = !!options?.useCache;
265
+ // beforeRender 特殊处理:出错时一律抛出(用于错误边界捕获)
266
+ const throwOnError = isBeforeRender;
146
267
 
147
- if (autoApplyFlows.length === 0) {
148
- model.context.logger.warn(`FlowModel: No auto-apply flows found for model '${model.uid}'`);
149
- return [];
150
- }
151
-
152
- const cacheKey = useCache
153
- ? FlowEngine.generateApplyFlowCacheKey(model.getAutoFlowCacheScope(), 'all', model.uid)
154
- : null;
268
+ const runId = `${model.uid}-${eventName}-${Date.now()}`;
269
+ const logger = model.context.logger;
270
+ const eventBasePayload = {
271
+ uid: model.uid,
272
+ model,
273
+ runId,
274
+ inputArgs,
275
+ };
155
276
 
156
- if (cacheKey && this.engine) {
157
- const cachedEntry = this.engine.applyFlowCache.get(cacheKey);
158
- if (cachedEntry) {
159
- if (cachedEntry.status === 'resolved') {
160
- model.context.logger.debug(`[FlowEngine.applyAutoFlows] Using cached result for model: ${model.uid}`);
161
- return cachedEntry.data;
162
- }
163
- if (cachedEntry.status === 'rejected') throw cachedEntry.error;
164
- if (cachedEntry.status === 'pending') return await cachedEntry.promise;
277
+ try {
278
+ await this.emitModelEventIf(eventName, 'start', eventBasePayload);
279
+ await model.onDispatchEventStart?.(eventName, options, inputArgs);
280
+ } catch (err) {
281
+ if (isBeforeRender && err instanceof FlowExitException) {
282
+ logger.debug(`[FlowModel.dispatchEvent] ${err.message}`);
283
+ return [];
165
284
  }
285
+ // 进入错误钩子并记录
286
+ try {
287
+ await model.onDispatchEventError?.(eventName, options, inputArgs, err as Error);
288
+ } finally {
289
+ logger.error({ err }, `BaseModel.dispatchEvent: Start hook error for event '${eventName}'`);
290
+ }
291
+ if (throwOnError) throw err;
292
+ return;
166
293
  }
167
294
 
168
- const executeAutoFlows = async (): Promise<any[]> => {
169
- const results: any[] = [];
170
- const runId = `${model.uid}-autoFlow-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
171
- const logger = model.context.logger.child({ module: 'flow-engine', component: 'FlowExecutor', runId });
172
- logger.debug(
173
- `[FlowExecutor] runAutoFlows: uid=${model.uid}, isFork=${
174
- (model as any)?.isFork === true
175
- }, useCache=${useCache}, runId=${runId}, flows=${autoApplyFlows.map((f) => f.key).join(',')}`,
176
- );
177
- try {
178
- if (autoApplyFlows.length === 0) {
179
- logger.warn(`FlowModel: No auto-apply flows found for model '${model.uid}'`);
180
- } else {
181
- for (const flow of autoApplyFlows) {
182
- try {
183
- logger.debug(`[FlowExecutor] runFlow: uid=${model.uid}, flowKey=${flow.key}`);
184
- const result = await this.runFlow(model, flow.key, inputArgs, runId);
185
- if (result instanceof FlowExitAllException) {
186
- logger.debug(`[FlowEngine.applyAutoFlows] ${result.message}`);
187
- break; // 终止后续流程执行
295
+ // 构造待执行的 flows 列表
296
+ const flows = isBeforeRender
297
+ ? model.getEventFlows('beforeRender') // beforeRender 事件集合(兼容未声明 on 且非 manual 的定义)
298
+ : Array.from(model.getFlows().values()).filter((flow) => {
299
+ const on = flow.on;
300
+ if (!on) return false;
301
+ if (typeof on === 'string') return on === eventName;
302
+ if (typeof on === 'object') return on.eventName === eventName;
303
+ return false;
304
+ });
305
+
306
+ // 路由系统的“重放打开视图”会再次 dispatchEvent('click'),但这不应重复触发用户配置的动态事件流。
307
+ // 约定:由路由重放触发时,会在 inputArgs 中携带 triggerByRouter: true
308
+ const isRouterReplayClick = eventName === 'click' && inputArgs?.triggerByRouter === true;
309
+ const flowsToRun = isRouterReplayClick
310
+ ? flows.filter((flow) => {
311
+ const reg = flow['flowRegistry'] as any;
312
+ const type = reg?.constructor?._type as 'instance' | 'global' | undefined;
313
+ return type !== 'instance';
314
+ })
315
+ : flows;
316
+
317
+ // 记录本次 dispatchEvent 内注册的调度任务,用于在结束/错误后兜底清理未触发的任务
318
+ const scheduledCancels: ScheduledCancel[] = [];
319
+
320
+ // 组装执行函数(返回值用于缓存;beforeRender 返回 results:any[],其它返回 true)
321
+ const execute = async () => {
322
+ if (sequential) {
323
+ // 顺序执行:动态流(实例级)优先,其次静态流;各自组内再按 sort 升序,最后保持原始顺序稳定
324
+ const flowsWithIndex = flowsToRun.map((f, i) => ({ f, i }));
325
+ const ordered = flowsWithIndex
326
+ .slice()
327
+ .sort((a, b) => {
328
+ const regA = a.f['flowRegistry'] as any;
329
+ const regB = b.f['flowRegistry'] as any;
330
+ const typeA = regA?.constructor?._type as 'instance' | 'global' | undefined;
331
+ const typeB = regB?.constructor?._type as 'instance' | 'global' | undefined;
332
+ const groupA = typeA === 'instance' ? 0 : 1; // 实例=0,静态=1
333
+ const groupB = typeB === 'instance' ? 0 : 1;
334
+ if (groupA !== groupB) return groupA - groupB;
335
+ const sa = a.f.sort ?? 0;
336
+ const sb = b.f.sort ?? 0;
337
+ if (sa !== sb) return sa - sb;
338
+ return a.i - b.i; // 稳定排序:保持原有相对顺序
339
+ })
340
+ .map((x) => x.f);
341
+ const results: any[] = [];
342
+
343
+ // 预处理:当事件流配置了 on.phase 时,将其执行移动到指定节点,并从“立即执行列表”中移除
344
+ const staticFlowsByKey = new Map(
345
+ ordered
346
+ .filter((f) => {
347
+ const reg = f['flowRegistry'] as any;
348
+ const type = reg?.constructor?._type as 'instance' | 'global' | undefined;
349
+ return type !== 'instance';
350
+ })
351
+ .map((f) => [f.key, f] as const),
352
+ );
353
+ const scheduled = new Set<string>();
354
+ const scheduleGroups = new Map<string, Array<{ flow: any; order: number }>>();
355
+ ordered.forEach((flow, indexInOrdered) => {
356
+ const on = flow.on;
357
+ const onObj = typeof on === 'object' ? (on as any) : undefined;
358
+ if (!onObj) return;
359
+
360
+ const phase: any = onObj.phase;
361
+ const flowKey: any = onObj.flowKey;
362
+ const stepKey: any = onObj.stepKey;
363
+
364
+ // 默认:beforeAllFlows(保持现有行为)
365
+ if (!phase || phase === 'beforeAllFlows') return;
366
+
367
+ let whenKey: string | null = null;
368
+ if (phase === 'afterAllFlows') {
369
+ whenKey = `event:${eventName}:end`;
370
+ } else if (phase === 'beforeFlow' || phase === 'afterFlow') {
371
+ if (!flowKey) {
372
+ // 配置不完整:降级到“全部静态流之后”
373
+ whenKey = `event:${eventName}:end`;
374
+ } else {
375
+ const anchorFlow = staticFlowsByKey.get(String(flowKey));
376
+ if (anchorFlow) {
377
+ const anchorPhase = phase === 'beforeFlow' ? 'start' : 'end';
378
+ whenKey = `event:${eventName}:flow:${String(flowKey)}:${anchorPhase}`;
379
+ } else {
380
+ // 锚点不存在(flow 被删除或覆盖等):降级到“全部静态流之后”
381
+ whenKey = `event:${eventName}:end`;
382
+ }
383
+ }
384
+ } else if (phase === 'beforeStep' || phase === 'afterStep') {
385
+ if (!flowKey || !stepKey) {
386
+ // 配置不完整:降级到“全部静态流之后”
387
+ whenKey = `event:${eventName}:end`;
388
+ } else {
389
+ const anchorFlow = staticFlowsByKey.get(String(flowKey));
390
+ const anchorStepExists = !!anchorFlow?.hasStep?.(String(stepKey));
391
+ if (anchorFlow && anchorStepExists) {
392
+ const anchorPhase = phase === 'beforeStep' ? 'start' : 'end';
393
+ whenKey = `event:${eventName}:flow:${String(flowKey)}:step:${String(stepKey)}:${anchorPhase}`;
394
+ } else {
395
+ // 锚点不存在(flow/step 被删除或覆盖等):降级到“全部静态流之后”
396
+ whenKey = `event:${eventName}:end`;
188
397
  }
189
- results.push(result);
190
- } catch (error) {
191
- logger.error({ err: error }, `FlowModel.applyAutoFlows: Error executing auto-apply flow '${flow.key}':`);
192
- throw error;
193
398
  }
399
+ } else {
400
+ // 未知 phase:忽略
401
+ return;
402
+ }
403
+
404
+ if (!whenKey) return;
405
+ scheduled.add(flow.key);
406
+ const list = scheduleGroups.get(whenKey) || [];
407
+ list.push({ flow, order: indexInOrdered });
408
+ scheduleGroups.set(whenKey, list);
409
+ });
410
+
411
+ // 注册调度(同锚点按 flow.sort 升序;sort 相同保持稳定顺序)
412
+ for (const [whenKey, list] of scheduleGroups.entries()) {
413
+ const sorted = list.slice().sort((a, b) => {
414
+ const sa = a.flow.sort ?? 0;
415
+ const sb = b.flow.sort ?? 0;
416
+ if (sa !== sb) return sa - sb;
417
+ return a.order - b.order;
418
+ });
419
+ for (const it of sorted) {
420
+ const cancel = model.scheduleModelOperation(
421
+ model.uid,
422
+ async (m) => {
423
+ const res = await this.runFlow(m, it.flow.key, inputArgs, runId, eventName);
424
+ results.push(res);
425
+ },
426
+ { when: whenKey as any },
427
+ );
428
+ scheduledCancels.push(cancel);
429
+ }
430
+ }
431
+
432
+ for (const flow of ordered) {
433
+ if (scheduled.has(flow.key)) continue;
434
+ try {
435
+ logger.debug(
436
+ `BaseModel '${model.uid}' dispatching event '${eventName}' to flow '${flow.key}' (sequential).`,
437
+ );
438
+ const result = await this.runFlow(model, flow.key, inputArgs, runId, eventName);
439
+ if (result instanceof FlowExitAllException) {
440
+ logger.debug(`[FlowEngine.dispatchEvent] ${result.message}`);
441
+ break; // 终止后续
442
+ }
443
+ results.push(result);
444
+ } catch (error) {
445
+ logger.error(
446
+ { err: error },
447
+ `BaseModel.dispatchEvent: Error executing event-triggered flow '${flow.key}' for event '${eventName}' (sequential):`,
448
+ );
449
+ throw error;
194
450
  }
195
451
  }
196
452
  return results;
197
- } catch (error) {
198
- if (error instanceof FlowExitException) {
199
- logger.debug(`[FlowEngine.applyAutoFlows] ${error.message}`);
200
- return results;
201
- }
202
- throw error;
203
453
  }
454
+
455
+ // 并行
456
+ const results = await Promise.all(
457
+ flowsToRun.map(async (flow) => {
458
+ logger.debug(`BaseModel '${model.uid}' dispatching event '${eventName}' to flow '${flow.key}'.`);
459
+ try {
460
+ return await this.runFlow(model, flow.key, inputArgs, runId, eventName);
461
+ } catch (error) {
462
+ logger.error(
463
+ { err: error },
464
+ `BaseModel.dispatchEvent: Error executing event-triggered flow '${flow.key}' for event '${eventName}':`,
465
+ );
466
+ if (throwOnError) throw error;
467
+ return undefined;
468
+ }
469
+ }),
470
+ );
471
+ return results.filter((x) => x !== undefined);
204
472
  };
205
473
 
206
- if (!cacheKey || !this.engine) {
207
- return await executeAutoFlows();
208
- }
474
+ // 缓存键:按事件+scope 统一管理(beforeRender 也使用事件名 beforeRender)
475
+ const argsKey = useCache ? JSON.stringify(inputArgs ?? {}) : '';
476
+ const cacheKey = useCache
477
+ ? FlowEngine.generateApplyFlowCacheKey(
478
+ `event:${model.getFlowCacheScope(eventName)}:${argsKey}`,
479
+ eventName,
480
+ model.uid,
481
+ )
482
+ : null;
209
483
 
210
- const promise = executeAutoFlows()
211
- .then((result) => {
212
- this.engine.applyFlowCache.set(cacheKey, {
213
- status: 'resolved',
214
- data: result,
215
- promise: Promise.resolve(result),
216
- } as ApplyFlowCacheEntry);
217
- return result;
218
- })
219
- .catch((err) => {
220
- this.engine.applyFlowCache.set(cacheKey, {
221
- status: 'rejected',
222
- error: err,
223
- promise: Promise.reject(err),
224
- } as ApplyFlowCacheEntry);
225
- throw err;
484
+ try {
485
+ const result = await this.withApplyFlowCache(cacheKey, execute);
486
+ // 事件结束钩子
487
+ try {
488
+ await model.onDispatchEventEnd?.(eventName, options, inputArgs, result);
489
+ } catch (hookErr) {
490
+ logger.error({ err: hookErr }, `BaseModel.dispatchEvent: End hook error for event '${eventName}'`);
491
+ }
492
+ await this.emitModelEventIf(eventName, 'end', {
493
+ ...eventBasePayload,
494
+ result,
226
495
  });
227
-
228
- this.engine.applyFlowCache.set(cacheKey, { status: 'pending', promise } as ApplyFlowCacheEntry);
229
- return await promise;
230
- }
231
-
232
- /**
233
- * Dispatch an event to flows bound via flow.on and execute them.
234
- */
235
- async dispatchEvent(model: FlowModel, eventName: string, inputArgs?: Record<string, any>): Promise<void> {
236
- const flows = Array.from(model.getFlows().values()).filter((flow) => {
237
- const on = flow.on;
238
- if (!on) return false;
239
- if (typeof on === 'string') return on === eventName;
240
- if (typeof on === 'object') return on.eventName === eventName;
241
- return false;
242
- });
243
- const runId = `${model.uid}-${eventName}-${Date.now()}`;
244
- const logger = model.context.logger;
245
- const promises = flows.map((flow) => {
246
- logger.debug(`BaseModel '${model.uid}' dispatching event '${eventName}' to flow '${flow.key}'.`);
247
- return this.runFlow(model, flow.key, inputArgs, runId).catch((error) => {
248
- logger.error(
249
- { err: error },
250
- `BaseModel.dispatchEvent: Error executing event-triggered flow '${flow.key}' for event '${eventName}':`,
251
- );
496
+ return result;
497
+ } catch (error) {
498
+ // 进入错误钩子并记录
499
+ try {
500
+ await model.onDispatchEventError?.(eventName, options, inputArgs, error as Error);
501
+ } catch (_) {
502
+ // swallow secondary hook error
503
+ }
504
+ model.context.logger.error(
505
+ { err: error },
506
+ `BaseModel.dispatchEvent: Error executing event '${eventName}' for model '${model.uid}':`,
507
+ );
508
+ await this.emitModelEventIf(eventName, 'error', {
509
+ ...eventBasePayload,
510
+ error,
252
511
  });
253
- });
254
- await Promise.all(promises);
512
+ if (throwOnError) throw error;
513
+ } finally {
514
+ // 清理未触发的调度任务,避免跨事件/跨 runId 残留导致意外执行
515
+ for (const cancel of scheduledCancels) {
516
+ cancel();
517
+ }
518
+ }
255
519
  }
256
520
  }