@acorex/platform 21.0.0-next.5 → 21.0.0-next.51

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 (124) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +281 -23
  2. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  3. package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs +163 -0
  4. package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +1047 -263
  6. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-core.mjs +1138 -510
  8. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-domain.mjs +557 -826
  10. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-builder.mjs +804 -186
  12. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs +121 -0
  14. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-layout-components.mjs +6208 -2344
  16. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-layout-designer.mjs +456 -204
  18. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  19. package/fesm2022/acorex-platform-layout-entity.mjs +18632 -10286
  20. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-views.mjs +538 -168
  22. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-widget-core.mjs +720 -456
  24. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  25. package/fesm2022/{acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs → acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs} +10 -10
  26. package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs.map +1 -0
  27. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CDYAGBku.mjs +103 -0
  28. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CDYAGBku.mjs.map +1 -0
  29. package/fesm2022/{acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs → acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs} +6 -7
  30. package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs.map +1 -0
  31. package/fesm2022/{acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs → acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs} +12 -12
  32. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs.map +1 -0
  33. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BGO75IMz.mjs +116 -0
  34. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BGO75IMz.mjs.map +1 -0
  35. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DmzNTYiS.mjs} +6 -6
  36. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DmzNTYiS.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-BNG_588B.mjs} +5 -5
  38. package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-BNG_588B.mjs.map +1 -0
  39. package/fesm2022/{acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs} +6 -6
  40. package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-layout-widgets.mjs +8728 -4269
  42. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  43. package/fesm2022/acorex-platform-native.mjs +8 -7
  44. package/fesm2022/acorex-platform-native.mjs.map +1 -1
  45. package/fesm2022/acorex-platform-runtime.mjs +391 -166
  46. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  47. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cx1lLUaR.mjs +160 -0
  48. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cx1lLUaR.mjs.map +1 -0
  49. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-AOrcgjDF.mjs +120 -0
  50. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-AOrcgjDF.mjs.map +1 -0
  51. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs → acorex-platform-themes-default-entity-master-single-view.component-BfCeUU5F.mjs} +19 -26
  52. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-BfCeUU5F.mjs.map +1 -0
  53. package/fesm2022/{acorex-platform-themes-default-error-401.component-cfREo88K.mjs → acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs} +4 -4
  54. package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +1 -0
  55. package/fesm2022/{acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs → acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs} +4 -4
  56. package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +1 -0
  57. package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs +19 -0
  58. package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs.map +1 -0
  59. package/fesm2022/acorex-platform-themes-default.mjs +1836 -67
  60. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  61. package/fesm2022/{acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs → acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs} +6 -6
  62. package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs.map +1 -0
  63. package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs → acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs} +6 -6
  64. package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs.map +1 -0
  65. package/fesm2022/{acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs → acorex-platform-themes-shared-settings.provider-DK6R87Lf.mjs} +24 -25
  66. package/fesm2022/acorex-platform-themes-shared-settings.provider-DK6R87Lf.mjs.map +1 -0
  67. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs +94 -0
  68. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs.map +1 -0
  69. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs +86 -0
  70. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs.map +1 -0
  71. package/fesm2022/acorex-platform-themes-shared.mjs +674 -573
  72. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  73. package/fesm2022/acorex-platform-workflow.mjs +1715 -535
  74. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  75. package/fesm2022/acorex-platform.mjs.map +1 -1
  76. package/package.json +37 -37
  77. package/{auth/index.d.ts → types/acorex-platform-auth.d.ts} +241 -4
  78. package/{common/index.d.ts → types/acorex-platform-common.d.ts} +598 -80
  79. package/{core/index.d.ts → types/acorex-platform-core.d.ts} +595 -132
  80. package/{domain/index.d.ts → types/acorex-platform-domain.d.ts} +744 -412
  81. package/{layout/builder/index.d.ts → types/acorex-platform-layout-builder.d.ts} +193 -48
  82. package/types/acorex-platform-layout-components.d.ts +2979 -0
  83. package/{layout/designer/index.d.ts → types/acorex-platform-layout-designer.d.ts} +96 -18
  84. package/{layout/entity/index.d.ts → types/acorex-platform-layout-entity.d.ts} +1601 -261
  85. package/{layout/views/index.d.ts → types/acorex-platform-layout-views.d.ts} +116 -55
  86. package/{layout/widget-core/index.d.ts → types/acorex-platform-layout-widget-core.d.ts} +272 -124
  87. package/{layout/widgets/index.d.ts → types/acorex-platform-layout-widgets.d.ts} +1055 -157
  88. package/{native/index.d.ts → types/acorex-platform-native.d.ts} +0 -7
  89. package/types/acorex-platform-runtime.d.ts +571 -0
  90. package/{themes/default/index.d.ts → types/acorex-platform-themes-default.d.ts} +122 -5
  91. package/{themes/shared/index.d.ts → types/acorex-platform-themes-shared.d.ts} +1 -1
  92. package/types/acorex-platform-workflow.d.ts +1884 -0
  93. package/fesm2022/acorex-platform-common-common-settings.provider-zhqNP3xb.mjs +0 -71
  94. package/fesm2022/acorex-platform-common-common-settings.provider-zhqNP3xb.mjs.map +0 -1
  95. package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs.map +0 -1
  96. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs +0 -135
  97. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +0 -1
  98. package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs.map +0 -1
  99. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs.map +0 -1
  100. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +0 -1
  101. package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs.map +0 -1
  102. package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs.map +0 -1
  103. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs +0 -157
  104. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +0 -1
  105. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs +0 -1542
  106. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs.map +0 -1
  107. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +0 -101
  108. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +0 -1
  109. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +0 -1
  110. package/fesm2022/acorex-platform-themes-default-error-401.component-cfREo88K.mjs.map +0 -1
  111. package/fesm2022/acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs.map +0 -1
  112. package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs +0 -19
  113. package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs.map +0 -1
  114. package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs.map +0 -1
  115. package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs.map +0 -1
  116. package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +0 -1
  117. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs +0 -65
  118. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs.map +0 -1
  119. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs +0 -64
  120. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs.map +0 -1
  121. package/layout/components/index.d.ts +0 -1669
  122. package/runtime/index.d.ts +0 -307
  123. package/workflow/index.d.ts +0 -1808
  124. /package/{index.d.ts → types/acorex-platform.d.ts} +0 -0
@@ -1,8 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, Optional, Inject, NgModule, InjectionToken } from '@angular/core';
2
+ import { Injectable, inject, InjectionToken, Optional, Inject, NgModule } from '@angular/core';
3
3
  import { Subject, filter } from 'rxjs';
4
4
  import { cloneDeep, get, set } from 'lodash-es';
5
- import { setSmart } from '@acorex/platform/core';
5
+ import { setSmart, AXPExpressionEvaluatorService, AXPDataGenerator } from '@acorex/platform/core';
6
+ import { AXTranslationService } from '@acorex/core/translation';
6
7
  import { AXPCommandService } from '@acorex/platform/runtime';
7
8
 
8
9
  class AXPWorkflowError extends Error {
@@ -23,10 +24,10 @@ class AXPWorkflowEventService {
23
24
  get events$() {
24
25
  return this.eventSubject.asObservable();
25
26
  }
26
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
27
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowEventService, providedIn: 'root' }); }
27
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
28
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowEventService, providedIn: 'root' }); }
28
29
  }
29
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowEventService, decorators: [{
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowEventService, decorators: [{
30
31
  type: Injectable,
31
32
  args: [{
32
33
  providedIn: 'root',
@@ -116,10 +117,10 @@ class AXPWorkflowRegistryService {
116
117
  });
117
118
  }
118
119
  }
119
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
120
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowRegistryService, providedIn: 'root' }); }
120
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
121
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRegistryService, providedIn: 'root' }); }
121
122
  }
122
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowRegistryService, decorators: [{
123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRegistryService, decorators: [{
123
124
  type: Injectable,
124
125
  args: [{
125
126
  providedIn: 'root',
@@ -158,17 +159,17 @@ class AXPWorkflowAction {
158
159
  dispatch(event) {
159
160
  this.eventService.dispatch(event);
160
161
  }
161
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowAction, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
162
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowAction }); }
162
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowAction, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
163
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowAction }); }
163
164
  }
164
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowAction, decorators: [{
165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowAction, decorators: [{
165
166
  type: Injectable
166
167
  }] });
167
168
  class AXPWorkflowFunction {
168
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowFunction, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
169
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowFunction }); }
169
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowFunction, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
170
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowFunction }); }
170
171
  }
171
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowFunction, decorators: [{
172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowFunction, decorators: [{
172
173
  type: Injectable
173
174
  }] });
174
175
  function createWorkFlowEvent(type) {
@@ -184,10 +185,10 @@ class AXPWorkflowDecideAction extends AXPWorkflowAction {
184
185
  async execute(context) {
185
186
  // its a fake action
186
187
  }
187
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDecideAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
188
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDecideAction, providedIn: 'root' }); }
188
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDecideAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
189
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDecideAction, providedIn: 'root' }); }
189
190
  }
190
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDecideAction, decorators: [{
191
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDecideAction, decorators: [{
191
192
  type: Injectable,
192
193
  args: [{
193
194
  providedIn: 'root',
@@ -373,10 +374,10 @@ class AXPWorkflowService {
373
374
  }
374
375
  return this.injector.get(functionType);
375
376
  }
376
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowService, deps: [{ token: AXPWorkflowRegistryService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
377
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowService, providedIn: 'root' }); }
377
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowService, deps: [{ token: AXPWorkflowRegistryService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
378
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowService, providedIn: 'root' }); }
378
379
  }
379
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowService, decorators: [{
380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowService, decorators: [{
380
381
  type: Injectable,
381
382
  args: [{
382
383
  providedIn: 'root',
@@ -401,268 +402,10 @@ class AXPStartWorkflowAction extends AXPWorkflowAction {
401
402
  throw e;
402
403
  }
403
404
  }
404
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPStartWorkflowAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
405
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPStartWorkflowAction, providedIn: 'root' }); }
405
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPStartWorkflowAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
406
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPStartWorkflowAction, providedIn: 'root' }); }
406
407
  }
407
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPStartWorkflowAction, decorators: [{
408
- type: Injectable,
409
- args: [{
410
- providedIn: 'root',
411
- }]
412
- }] });
413
-
414
- class AXPWorkflowModule {
415
- static forRoot(config) {
416
- return {
417
- ngModule: AXPWorkflowModule,
418
- providers: [
419
- {
420
- provide: 'AXPWorkflowModuleFactory',
421
- useFactory: (registry) => () => {
422
- registry.registerAction('start-workflow', AXPStartWorkflowAction);
423
- registry.registerAction('decide', AXPWorkflowDecideAction);
424
- //
425
- if (config?.functions) {
426
- for (const [key, type] of Object.entries(config.functions)) {
427
- registry.registerFunction(key, type);
428
- }
429
- }
430
- //
431
- if (config?.actions) {
432
- for (const [key, type] of Object.entries(config.actions)) {
433
- registry.registerAction(key, type);
434
- }
435
- }
436
- //
437
- if (config?.workflows) {
438
- for (const [key, type] of Object.entries(config.workflows)) {
439
- registry.registerWorkflow(key, type);
440
- }
441
- }
442
- },
443
- deps: [AXPWorkflowRegistryService],
444
- multi: true,
445
- },
446
- ...Object.values(config?.actions ?? { AXPStartWorkflowAction }),
447
- ...Object.values(config?.functions ?? {}),
448
- ],
449
- };
450
- }
451
- static forChild(config) {
452
- return {
453
- ngModule: AXPWorkflowModule,
454
- providers: [
455
- // Built-in activities are already registered in forRoot via @NgModule providers
456
- // No need to register again in forChild
457
- {
458
- provide: 'AXPWorkflowModuleFactory',
459
- useFactory: (registry) => () => {
460
- registry.registerAction('start-workflow', AXPStartWorkflowAction);
461
- registry.registerAction('decide', AXPWorkflowDecideAction);
462
- //
463
- if (config?.functions) {
464
- for (const [key, type] of Object.entries(config.functions)) {
465
- registry.registerFunction(key, type);
466
- }
467
- }
468
- //
469
- if (config?.actions) {
470
- for (const [key, type] of Object.entries(config.actions)) {
471
- registry.registerAction(key, type);
472
- }
473
- }
474
- //
475
- if (config?.workflows) {
476
- for (const [key, type] of Object.entries(config.workflows)) {
477
- registry.registerWorkflow(key, type);
478
- }
479
- }
480
- },
481
- deps: [AXPWorkflowRegistryService],
482
- multi: true,
483
- },
484
- ...Object.values(config?.actions ?? {}),
485
- ...Object.values(config?.functions ?? {}),
486
- ],
487
- };
488
- }
489
- /**
490
- * @ignore
491
- */
492
- constructor(instances) {
493
- instances?.forEach((f) => {
494
- f();
495
- });
496
- }
497
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowModule, deps: [{ token: 'AXPWorkflowModuleFactory', optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
498
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowModule }); }
499
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowModule }); }
500
- }
501
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowModule, decorators: [{
502
- type: NgModule,
503
- args: [{
504
- imports: [],
505
- exports: [],
506
- declarations: [],
507
- providers: [],
508
- }]
509
- }], ctorParameters: () => [{ type: undefined, decorators: [{
510
- type: Optional
511
- }, {
512
- type: Inject,
513
- args: ['AXPWorkflowModuleFactory']
514
- }] }] });
515
-
516
- /**
517
- * Injection token for workflow definition loaders.
518
- * Multiple loaders can be provided (multi: true).
519
- */
520
- const AXP_WORKFLOW_DEFINITION_LOADER = new InjectionToken('AXP_WORKFLOW_DEFINITION_LOADER');
521
- /**
522
- * Resolver service for workflow definitions.
523
- * Aggregates all registered loaders and resolves workflow definitions.
524
- */
525
- class AXPWorkflowDefinitionResolver {
526
- constructor() {
527
- this.loaders = inject(AXP_WORKFLOW_DEFINITION_LOADER, { optional: true });
528
- }
529
- /**
530
- * Get workflow definition by name (unique key).
531
- * Tries all registered loaders until one returns a definition.
532
- * @param name - The workflow name (unique key)
533
- * @returns Workflow definition or null if not found
534
- */
535
- async get(name) {
536
- const loaderArray = Array.isArray(this.loaders) ? this.loaders : this.loaders ? [this.loaders] : [];
537
- for (const loader of loaderArray) {
538
- try {
539
- const definition = await loader.get(name);
540
- if (definition) {
541
- return definition;
542
- }
543
- }
544
- catch (error) {
545
- console.warn(`[AXPWorkflowDefinitionResolver] Loader failed for ${name}:`, error);
546
- }
547
- }
548
- return null;
549
- }
550
- /**
551
- * Get all available workflow names from all loaders.
552
- * @returns Array of unique workflow names
553
- */
554
- async getAllNames() {
555
- const loaderArray = Array.isArray(this.loaders) ? this.loaders : this.loaders ? [this.loaders] : [];
556
- const allNames = new Set();
557
- for (const loader of loaderArray) {
558
- if (loader.getAllNames) {
559
- try {
560
- const names = await loader.getAllNames();
561
- names.forEach((name) => allNames.add(name));
562
- }
563
- catch (error) {
564
- console.warn('[AXPWorkflowDefinitionResolver] Failed to get names from loader:', error);
565
- }
566
- }
567
- }
568
- return Array.from(allNames);
569
- }
570
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDefinitionResolver, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
571
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDefinitionResolver, providedIn: 'root' }); }
572
- }
573
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDefinitionResolver, decorators: [{
574
- type: Injectable,
575
- args: [{ providedIn: 'root' }]
576
- }] });
577
-
578
- /**
579
- * Registry service for workflow definitions.
580
- * Caches loaded definitions and provides change notifications.
581
- */
582
- class AXPWorkflowDefinitionRegistryService {
583
- constructor() {
584
- this.resolver = inject(AXPWorkflowDefinitionResolver);
585
- this.cache = new Map();
586
- this.onChanged = new Subject();
587
- }
588
- /**
589
- * Observable for workflow definition changes.
590
- */
591
- get onChanged$() {
592
- return this.onChanged.asObservable();
593
- }
594
- /**
595
- * Get workflow definition by name (unique key).
596
- * Uses cache if available, otherwise loads from resolver.
597
- * @param name - The workflow name (unique key)
598
- * @returns Workflow definition or null if not found
599
- */
600
- async get(name) {
601
- // Check cache first
602
- if (this.cache.has(name)) {
603
- return this.cache.get(name);
604
- }
605
- // Load from resolver
606
- const definition = await this.resolver.get(name);
607
- if (definition) {
608
- this.cache.set(name, definition);
609
- this.onChanged.next({ name, action: 'registered' });
610
- }
611
- return definition;
612
- }
613
- /**
614
- * Register a workflow definition in the cache.
615
- * @param definition - The workflow definition to register
616
- */
617
- register(definition) {
618
- this.cache.set(definition.name, definition);
619
- this.onChanged.next({ name: definition.name, action: 'registered' });
620
- }
621
- /**
622
- * Update a workflow definition in the cache.
623
- * @param definition - The updated workflow definition
624
- */
625
- update(definition) {
626
- if (this.cache.has(definition.name)) {
627
- this.cache.set(definition.name, definition);
628
- this.onChanged.next({ name: definition.name, action: 'updated' });
629
- }
630
- }
631
- /**
632
- * Remove a workflow definition from the cache.
633
- * @param name - The workflow name to remove
634
- */
635
- remove(name) {
636
- if (this.cache.has(name)) {
637
- this.cache.delete(name);
638
- this.onChanged.next({ name, action: 'removed' });
639
- }
640
- }
641
- /**
642
- * Clear all cached workflow definitions.
643
- */
644
- clear() {
645
- this.cache.clear();
646
- }
647
- /**
648
- * Check if a workflow definition is cached.
649
- * @param definitionId - The workflow definition ID
650
- * @returns True if cached, false otherwise
651
- */
652
- has(definitionId) {
653
- return this.cache.has(definitionId);
654
- }
655
- /**
656
- * Get all cached workflow definition IDs.
657
- * @returns Array of definition IDs (only those that have been loaded)
658
- */
659
- getAllIds() {
660
- return Array.from(this.cache.keys());
661
- }
662
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDefinitionRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
663
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDefinitionRegistryService, providedIn: 'root' }); }
664
- }
665
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowDefinitionRegistryService, decorators: [{
408
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPStartWorkflowAction, decorators: [{
666
409
  type: Injectable,
667
410
  args: [{
668
411
  providedIn: 'root',
@@ -675,6 +418,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
675
418
  // Compatible with Elsa backend while using ACoreX naming conventions
676
419
  // ============================================
677
420
 
421
+ // Note:
422
+ // Previous versions defined dedicated activity result/command types here
423
+ // (AXPActivityResult / AXPActivity) that wrapped output and outcome.
424
+ // Activities are now modeled directly as AXPCommand with outcome stored in
425
+ // AXPExecuteCommandResult.metadata.outcome.
426
+
678
427
  const AXP_ACTIVITY_PROVIDER = new InjectionToken('AXP_ACTIVITY_PROVIDER', {
679
428
  factory: () => [],
680
429
  });
@@ -850,6 +599,19 @@ class AXPActivityDefinitionService {
850
599
  this.pendingActivityRequests.set(name, requestPromise);
851
600
  return requestPromise;
852
601
  }
602
+ /**
603
+ * Get all activity definitions (flat list) by loading root categories and their activities.
604
+ * Used by activity selector UIs (e.g. automation command configurator).
605
+ */
606
+ async getAllActivities() {
607
+ const categories = await this.getCategories(undefined);
608
+ const all = [];
609
+ for (const cat of categories) {
610
+ const activities = await this.getActivitiesByCategoryId(cat.id);
611
+ all.push(...activities);
612
+ }
613
+ return all;
614
+ }
853
615
  /**
854
616
  * Get category ID containing a specific activity definition
855
617
  *
@@ -867,7 +629,7 @@ class AXPActivityDefinitionService {
867
629
  if (definition && definition.category) {
868
630
  // Try to find category by name/id
869
631
  const categories = await this.getCategories();
870
- const found = categories.find(cat => cat.id === definition.category || cat.title === definition.category);
632
+ const found = categories.find((cat) => cat.id === definition.category);
871
633
  if (found) {
872
634
  return found.id;
873
635
  }
@@ -1094,10 +856,10 @@ class AXPActivityDefinitionService {
1094
856
  this.pendingActivitiesRequests.clear();
1095
857
  this.pendingActivityRequests.clear();
1096
858
  }
1097
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPActivityDefinitionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1098
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPActivityDefinitionService, providedIn: 'root' }); }
859
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityDefinitionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
860
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityDefinitionService, providedIn: 'root' }); }
1099
861
  }
1100
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPActivityDefinitionService, decorators: [{
862
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityDefinitionService, decorators: [{
1101
863
  type: Injectable,
1102
864
  args: [{
1103
865
  providedIn: 'root',
@@ -1105,359 +867,1777 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
1105
867
  }] });
1106
868
 
1107
869
  /**
1108
- * Abstract service for workflow execution operations.
870
+ * Injection token for workflow engine.
871
+ * Default implementation is AXPWorkflowLocalEngine.
872
+ */
873
+ const AXP_WORKFLOW_ENGINE = new InjectionToken('AXP_WORKFLOW_ENGINE');
874
+
875
+ //#region ---- Error Codes ----
876
+ /**
877
+ * Stable workflow engine error codes for UI branching (toasts, take-over flow, etc.).
878
+ */
879
+ const AXP_WORKFLOW_ERROR_CODES = {
880
+ TASK_NOT_ASSIGNEE: 'WORKFLOW_TASK_NOT_ASSIGNEE',
881
+ CLAIM_REQUIRED: 'WORKFLOW_CLAIM_REQUIRED',
882
+ REASSIGN_NOT_ALLOWED: 'WORKFLOW_REASSIGN_NOT_ALLOWED',
883
+ };
884
+ //#endregion
885
+ //#region ---- Engine Error ----
886
+ /**
887
+ * Business-rule failure from {@link AXPWorkflowEngine} (expected, user-facing).
888
+ */
889
+ class AXPWorkflowEngineError extends Error {
890
+ constructor(message, code, details) {
891
+ super(message);
892
+ this.code = code;
893
+ this.details = details;
894
+ this.name = 'AXPWorkflowEngineError';
895
+ }
896
+ }
897
+ /**
898
+ * Resolves a stable error code from an unknown thrown value.
899
+ */
900
+ function getWorkflowEngineErrorCode(error) {
901
+ if (error instanceof AXPWorkflowEngineError) {
902
+ return error.code;
903
+ }
904
+ return undefined;
905
+ }
906
+ /**
907
+ * Resolves a user-facing message and optional code from an unknown thrown value.
908
+ */
909
+ function getWorkflowEngineErrorInfo(error) {
910
+ if (error instanceof AXPWorkflowEngineError) {
911
+ return { message: error.message, code: error.code };
912
+ }
913
+ if (error instanceof Error) {
914
+ return { message: error.message };
915
+ }
916
+ return { message: 'An unexpected workflow error occurred' };
917
+ }
918
+ //#endregion
919
+
920
+ /**
921
+ * Activity types that use the task board (suspend until user acts via inbox), not inline interactive execution.
922
+ */
923
+ const AXP_WORKFLOW_TASK_BOARD_ACTIVITY_TYPES = [
924
+ 'workflow-activity:human-task',
925
+ 'workflow-activity:cartable',
926
+ ];
927
+ function axpIsWorkflowTaskBoardActivityType(activityType) {
928
+ return !!activityType && AXP_WORKFLOW_TASK_BOARD_ACTIVITY_TYPES.includes(activityType);
929
+ }
930
+
931
+ //#endregion
932
+ /**
933
+ * Workflow Expression Scope Service
934
+ *
935
+ * Shared service for building expression evaluation scope from workflow data.
936
+ * Used by both Local Engine and Mock Runtime to manage workflow data (inputs, variables, outputs).
1109
937
  *
1110
- * This service handles communication with backend for workflow execution.
938
+ * Responsibilities:
939
+ * - Build expression evaluation scope from workflow state
940
+ * - Provide context.eval() function for accessing workflow data
941
+ * - Manage workflow data structure (inputs, variables, outputs)
1111
942
  *
1112
- * Implementation should be provided in connectivity layer:
1113
- * - Mock implementation: @acorex/connectivity/mock
1114
- * - API implementation: @acorex/connectivity/api
943
+ * This service does NOT:
944
+ * - Execute activities
945
+ * - Evaluate expressions (delegates to AXPExpressionEvaluatorService)
946
+ * - Manage workflow state (handled by runtime)
1115
947
  *
1116
948
  * @example
1117
949
  * ```typescript
1118
- * // In connectivity/mock
1119
- * @Injectable()
1120
- * export class AXCWorkflowExecutionService implements AXPWorkflowExecutionService {
1121
- * async startExecution(request: AXPStartWorkflowExecutionRequest): Promise<AXPStartWorkflowExecutionResponse> {
1122
- * // Mock implementation
1123
- * }
1124
- * }
950
+ * const scopeService = inject(WorkflowExpressionScopeService);
1125
951
  *
1126
- * // In connectivity/api
1127
- * @Injectable()
1128
- * export class AXCWorkflowExecutionService implements AXPWorkflowExecutionService {
1129
- * constructor(private http: HttpClient) {}
952
+ * // Build scope from workflow state
953
+ * const scope = scopeService.buildScope({
954
+ * inputs: state.input || {},
955
+ * variables: state.variables || {},
956
+ * outputs: activityOutputs
957
+ * });
1130
958
  *
1131
- * async startExecution(request: AXPStartWorkflowExecutionRequest): Promise<AXPStartWorkflowExecutionResponse> {
1132
- * return firstValueFrom(
1133
- * this.http.post<AXPStartWorkflowExecutionResponse>(
1134
- * `${this.config.baseUrl}/api/workflows/${request.workflowId}/start`,
1135
- * { input: request.input }
1136
- * )
1137
- * );
1138
- * }
1139
- * }
959
+ * // Or build from state directly
960
+ * const scope = scopeService.buildScopeFromState(state, activityOutputs);
1140
961
  * ```
1141
962
  */
1142
- class AXPWorkflowExecutionService {
1143
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowExecutionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1144
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowExecutionService }); }
1145
- }
1146
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWorkflowExecutionService, decorators: [{
1147
- type: Injectable
1148
- }] });
1149
-
1150
- //#endregion
1151
- /**
1152
- * Production Workflow Coordinator.
1153
- *
1154
- * Separates frontend/backend execution:
1155
- * - Frontend activities: Execute with AXPCommand in browser
1156
- * - Backend activities: Execute via API calls to backend
1157
- * - State caching: Caches workflow state in client for performance
1158
- *
1159
- */
1160
- class WorkflowCoordinator {
1161
- constructor() {
1162
- //#region ---- Services & Dependencies ----
1163
- this.workflowExecutionService = inject(AXPWorkflowExecutionService);
1164
- this.commandService = inject(AXPCommandService);
1165
- //#endregion
1166
- //#region ---- State Cache (Client-side for Performance) ----
1167
- /**
1168
- * Cache workflow states in memory for quick access.
1169
- * Key: executionId
1170
- * Value: AXPWorkflowExecutionState
1171
- */
1172
- this.stateCache = new Map();
1173
- }
1174
- //#endregion
1175
- //#region ---- Public Methods ----
963
+ class WorkflowExpressionScopeService {
964
+ //#region ---- Private Helpers (dot-notation input normalization) ----
1176
965
  /**
1177
- * Start workflow execution in backend.
1178
- *
1179
- * Backend decides what to do: returns pendingTask or indicates completion.
1180
- * Frontend only calls API - no business logic here.
1181
- *
1182
- * @param workflowId - Workflow ID
1183
- * @param input - Initial input data
1184
- * @returns Execution result with pendingTask (if any)
1185
- *
1186
- * @example
1187
- * ```typescript
1188
- * const result = await coordinator.startWorkflow('my-workflow', { userId: '123' });
1189
- *
1190
- * if (result.pendingTask) {
1191
- * // Execute task if frontend, or wait for backend to complete
1192
- * if (result.pendingTask.executionMode === 'frontend') {
1193
- * await coordinator.executeTask(result.pendingTask);
1194
- * await coordinator.completeTask(result.executionId, result.pendingTask, outcome, output);
1195
- * }
1196
- * }
1197
- * ```
966
+ * Collect dot-notation key-value pairs from nested objects so that e.g.
967
+ * { metadata: { "metadata.questionnaire.id": "x" } } becomes { "metadata.questionnaire.id": "x" } at root.
968
+ * Top-level non-dot keys are kept as-is.
1198
969
  */
1199
- async startWorkflow(workflowId, input = {}) {
1200
- try {
1201
- const execution = await this.startWorkflowExecution(workflowId, input);
1202
- const result = {
1203
- success: true,
1204
- output: execution.state.output,
1205
- nextTask: execution.pendingTask || null,
1206
- executionId: execution.executionId,
1207
- state: execution.state
1208
- };
1209
- return result;
1210
- }
1211
- catch (error) {
1212
- console.error('[WorkflowCoordinator] ❌ Error in startWorkflow', error);
1213
- return {
1214
- success: false,
1215
- error: error.message || 'Failed to start workflow',
1216
- nextTask: null
1217
- };
970
+ flattenDotKeysFromTree(obj) {
971
+ if (obj === null || typeof obj !== 'object')
972
+ return obj;
973
+ const result = {};
974
+ for (const [key, value] of Object.entries(obj)) {
975
+ if (key.includes('.')) {
976
+ result[key] = value;
977
+ }
978
+ else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
979
+ for (const [k, v] of Object.entries(value)) {
980
+ if (k.includes('.')) {
981
+ result[k] = v;
982
+ }
983
+ else {
984
+ result[key + '.' + k] = v;
985
+ }
986
+ }
987
+ }
988
+ else {
989
+ result[key] = value;
990
+ }
1218
991
  }
992
+ return result;
1219
993
  }
1220
994
  /**
1221
- * Execute a frontend task using AXPCommand.
1222
- *
1223
- * Only executes if task.executionMode is 'frontend' or 'both'.
1224
- * Backend tasks are handled automatically by backend.
1225
- *
1226
- * @param task - Task to execute
1227
- * @returns Execution result with output and outcome
995
+ * Expand flat keys with dots into nested objects.
996
+ * e.g. { "metadata.questionnaire.id": "x" } -> { metadata: { questionnaire: { id: "x" } } }.
1228
997
  */
1229
- async executeTask(task) {
1230
- // Only execute frontend tasks
1231
- if (task.executionMode !== 'frontend' && task.executionMode !== 'both') {
1232
- throw new Error(`Task '${task.activityId}' is not a frontend task. Backend handles it automatically.`);
998
+ expandDotKeys(obj) {
999
+ if (obj === null || typeof obj !== 'object')
1000
+ return obj;
1001
+ const result = {};
1002
+ const dotKeys = [];
1003
+ const simpleKeys = [];
1004
+ for (const [key, value] of Object.entries(obj)) {
1005
+ if (key.includes('.')) {
1006
+ dotKeys.push([key, value]);
1007
+ }
1008
+ else {
1009
+ simpleKeys.push([key, value]);
1010
+ }
1011
+ }
1012
+ for (const [key, value] of dotKeys) {
1013
+ const parts = key.split('.');
1014
+ let current = result;
1015
+ for (let i = 0; i < parts.length - 1; i++) {
1016
+ const part = parts[i];
1017
+ if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {
1018
+ current[part] = {};
1019
+ }
1020
+ current = current[part];
1021
+ }
1022
+ current[parts[parts.length - 1]] = value;
1233
1023
  }
1234
- return await this.executeFrontendActivity(task);
1024
+ for (const [key, value] of simpleKeys) {
1025
+ result[key] = value;
1026
+ }
1027
+ return result;
1235
1028
  }
1236
1029
  /**
1237
- * Complete a task and get next task from backend.
1238
- *
1239
- * Sends task result to backend API.
1240
- * Backend decides: next task, fail, or complete workflow.
1030
+ * Normalize workflow input so that flat dot-notation keys (e.g. from form schema
1031
+ * "metadata.questionnaire.id") become nested for expression access (inputs.metadata.questionnaire.id).
1032
+ */
1033
+ normalizeInputs(input) {
1034
+ if (!input || typeof input !== 'object')
1035
+ return {};
1036
+ const flattened = this.flattenDotKeysFromTree(input);
1037
+ return this.expandDotKeys(flattened);
1038
+ }
1039
+ //#endregion
1040
+ //#region ---- Public Methods ----
1041
+ /**
1042
+ * Build expression evaluation scope for workflow activities.
1043
+ *
1044
+ * Provides workflow-specific data (inputs, variables, outputs) and context.eval() function.
1045
+ * Other data (session, current user, etc.) are provided by expression evaluator scope providers.
1046
+ *
1047
+ * Scope includes:
1048
+ * - inputs: Workflow input values (accessible as inputs.propertyName)
1049
+ * - variables: Workflow state variables (accessible as variables.propertyName or vars.propertyName)
1050
+ * - outputs: Previous activity outputs (accessible as outputs.activityId)
1051
+ * - context.eval(path): Function to access nested properties from workflow data
1052
+ *
1053
+ * Expressions can use:
1054
+ * - {{inputs.userName}} - Direct access to workflow input
1055
+ * - {{variables.someVar}} or {{vars.someVar}} - Direct access to workflow variable
1056
+ * - {{outputs.activityId.property}} - Direct access to previous activity output
1057
+ * - {{context.eval("inputs.userName")}} - Access via context.eval (supports nested paths)
1058
+ * - {{context.eval("variables.someVar")}} - Access variables via context.eval
1059
+ * - {{context.eval("outputs.activityId.property")}} - Access outputs via context.eval
1060
+ * - {{session.currentUser().name}} - Access current user via expression evaluator scope providers
1061
+ *
1062
+ * The context.eval() function provides a unified way to access all workflow data,
1063
+ * similar to how entity-detail-list uses context.eval() to access parent data.
1064
+ *
1065
+ * @param context - Workflow expression context containing inputs, variables, and outputs
1066
+ * @returns Expression evaluator scope with workflow data and context.eval() function
1067
+ */
1068
+ buildScope(context) {
1069
+ // Normalize inputs so flat dot-notation keys (e.g. metadata.questionnaire.id from forms) become nested for expressions
1070
+ const inputs = this.normalizeInputs(context.inputs || {});
1071
+ // Build merged workflow data object for context.eval()
1072
+ // This allows expressions like: context.eval("inputs.userName") or context.eval("variables.count")
1073
+ const workflowData = {
1074
+ inputs,
1075
+ variables: context.variables || {},
1076
+ vars: context.variables || {}, // Alias for convenience
1077
+ outputs: context.outputs || {},
1078
+ };
1079
+ // Build scope object with workflow-specific data and context.eval()
1080
+ // Note: AXPExpressionEvaluatorScope type expects { [namespace]: { [name]: Function } }
1081
+ // but evaluate() method actually accepts flat objects with values too
1082
+ // We'll use 'any' to allow both values and functions
1083
+ const scope = {
1084
+ // Direct access to workflow data
1085
+ inputs: workflowData.inputs,
1086
+ variables: workflowData.variables,
1087
+ vars: workflowData.vars,
1088
+ outputs: workflowData.outputs,
1089
+ // Context object with eval function (similar to entity-detail-list pattern)
1090
+ context: {
1091
+ eval: (path) => {
1092
+ // Use lodash get to access nested properties
1093
+ // Supports paths like: "inputs.userName", "variables.count", "outputs.activityId.property"
1094
+ return get(workflowData, path);
1095
+ },
1096
+ },
1097
+ };
1098
+ return scope;
1099
+ }
1100
+ /**
1101
+ * Build expression evaluation scope from workflow instance state.
1102
+ *
1103
+ * Convenience method that extracts data from AXPWorkflowInstanceState.
1104
+ *
1105
+ * @param state - Workflow instance state
1106
+ * @param activityOutputs - Map of activity outputs (activityId -> output)
1107
+ * @returns Expression evaluator scope with workflow data and context.eval() function
1108
+ */
1109
+ buildScopeFromState(state, activityOutputs) {
1110
+ // Convert activity outputs to record format
1111
+ const outputs = {};
1112
+ if (activityOutputs) {
1113
+ if (activityOutputs instanceof Map) {
1114
+ activityOutputs.forEach((output, activityId) => {
1115
+ outputs[activityId] = output;
1116
+ });
1117
+ }
1118
+ else {
1119
+ Object.assign(outputs, activityOutputs);
1120
+ }
1121
+ }
1122
+ // Convenience alias for the last activity output (if available).
1123
+ // This allows expressions like: {{outputs.last.someField}}
1124
+ if (outputs['last'] === undefined && state.lastActivityOutput !== undefined) {
1125
+ outputs['last'] = state.lastActivityOutput;
1126
+ }
1127
+ return this.buildScope({
1128
+ inputs: this.normalizeInputs((state.input || {})),
1129
+ variables: state.variables || {},
1130
+ outputs: outputs,
1131
+ });
1132
+ }
1133
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowExpressionScopeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1134
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowExpressionScopeService, providedIn: 'root' }); }
1135
+ }
1136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowExpressionScopeService, decorators: [{
1137
+ type: Injectable,
1138
+ args: [{
1139
+ providedIn: 'root'
1140
+ }]
1141
+ }] });
1142
+
1143
+ //#region ---- Constants ----
1144
+ /**
1145
+ * Activity types handled internally by the workflow engine (e.g. mock backend).
1146
+ * When such an activity is not registered as Command on the client, we skip execution
1147
+ * without warning — the engine will run it when executing the workflow.
1148
+ */
1149
+ const ENGINE_BUILTIN_ACTIVITY_TYPES = new Set([
1150
+ 'workflow-activity:set-variable',
1151
+ 'workflow-activity:http-request',
1152
+ 'workflow-activity:resolve-employee-user-id',
1153
+ ]);
1154
+ //#endregion
1155
+ /**
1156
+ * Activity Executor Service
1157
+ *
1158
+ * Service for executing workflow activities via CommandBus.
1159
+ * Automatically evaluates expressions in activity inputs before execution.
1160
+ *
1161
+ * @example
1162
+ * ```typescript
1163
+ * const executor = inject(ActivityExecutor);
1164
+ *
1165
+ * // Execute activity with task and workflow state (expressions will be evaluated)
1166
+ * const result = await executor.execute(task, workflowState, activityOutputs);
1167
+ * ```
1168
+ */
1169
+ class ActivityExecutor {
1170
+ constructor() {
1171
+ //#region ---- Services & Dependencies ----
1172
+ this.commandService = inject(AXPCommandService);
1173
+ this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
1174
+ this.expressionScopeService = inject(WorkflowExpressionScopeService);
1175
+ this.translateService = inject(AXTranslationService);
1176
+ }
1177
+ //#endregion
1178
+ //#region ---- Public Methods ----
1179
+ /**
1180
+ * Execute a workflow activity with expression evaluation.
1181
+ *
1182
+ * Evaluates expressions in activity inputs using workflow state,
1183
+ * then executes the activity via CommandBus.
1241
1184
  *
1242
- * @param executionId - Execution ID
1243
- * @param task - Completed task
1244
- * @param outcome - Task outcome (e.g., 'Done', 'Confirmed', 'Cancelled')
1245
- * @param output - Task output/result
1246
- * @returns Next task from backend (if any)
1185
+ * @param task - Workflow task containing activity information
1186
+ * @param workflowState - Current workflow instance state (for expression evaluation)
1187
+ * @param activityOutputs - Map of previous activity outputs (for expression evaluation)
1188
+ * @returns Execution result with output and outcome
1247
1189
  */
1248
- async completeTask(executionId, task, outcome, output) {
1190
+ async execute(task, workflowState, activityOutputs) {
1249
1191
  try {
1250
- // Send result to backend - backend decides next step
1251
- const response = await this.workflowExecutionService.resumeExecution({
1252
- executionId,
1253
- stepId: task.activityId,
1254
- taskToken: task.taskToken,
1255
- outcome,
1256
- userInput: output
1257
- });
1258
- // Update cache
1259
- if (response.state) {
1260
- this.stateCache.set(executionId, response.state);
1192
+ const activityName = task.activityType;
1193
+ // Evaluate inputs if workflow state is provided
1194
+ let evaluatedInputs = task.input || {};
1195
+ if (workflowState) {
1196
+ // Prefer explicit outputs, fallback to outputs stored in state
1197
+ const outputsForScope = activityOutputs ??
1198
+ workflowState.activityOutputs ??
1199
+ undefined;
1200
+ // Build expression scope from workflow state
1201
+ const scope = this.expressionScopeService.buildScopeFromState(workflowState, outputsForScope);
1202
+ // Evaluate all inputs recursively (handles nested objects and arrays)
1203
+ evaluatedInputs = await this.expressionEvaluator.evaluate(task.input || {}, scope);
1204
+ }
1205
+ // Check if command exists
1206
+ const commandExists = this.commandService.exists(activityName);
1207
+ if (!commandExists) {
1208
+ if (!ENGINE_BUILTIN_ACTIVITY_TYPES.has(activityName)) {
1209
+ console.warn(`[ActivityExecutor] ⚠️ Activity '${activityName}' is not registered as Command. ` +
1210
+ `Skipping execution.`);
1211
+ }
1212
+ return {
1213
+ output: null,
1214
+ outcome: 'Done'
1215
+ };
1261
1216
  }
1217
+ // Flatten properties if nested (designer-style nested payload)
1218
+ let commandInput = evaluatedInputs;
1219
+ if (commandInput['properties'] && typeof commandInput['properties'] === 'object') {
1220
+ // Flatten: {properties: {text: "..."}} -> {text: "..."}
1221
+ commandInput = { ...commandInput['properties'] };
1222
+ }
1223
+ // Execute activity via CommandBus
1224
+ // Activities (AXPActivity) return {output, outcome}; legacy may return {output, outcomes}
1225
+ const result = await this.commandService.execute(activityName, commandInput);
1226
+ if (!result) {
1227
+ return {
1228
+ output: null,
1229
+ outcome: 'Failed',
1230
+ };
1231
+ }
1232
+ if (!result.success) {
1233
+ return {
1234
+ output: {
1235
+ error: await this.resolveCommandMessageTextForError(result.message?.text),
1236
+ },
1237
+ outcome: 'Failed',
1238
+ };
1239
+ }
1240
+ const commandResult = result.data;
1241
+ // Prefer unified outcome in result.metadata; fall back to legacy data.outcome/outcomes.
1242
+ const metadataOutcome = result?.metadata?.['outcome'];
1243
+ let outcome = 'Done';
1244
+ if (typeof metadataOutcome === 'string' && metadataOutcome.length > 0) {
1245
+ outcome = metadataOutcome;
1246
+ }
1247
+ else if (typeof commandResult?.outcome === 'string' && commandResult.outcome.length > 0) {
1248
+ outcome = commandResult.outcome;
1249
+ }
1250
+ else {
1251
+ const outcomes = (commandResult?.outcomes ?? {});
1252
+ if (outcomes && typeof outcomes === 'object' && Object.keys(outcomes).length > 0) {
1253
+ outcome = outcomes['Done'] ? 'Done' : Object.keys(outcomes)[0] || 'Done';
1254
+ }
1255
+ }
1256
+ // Prefer output wrapper when present; otherwise treat data itself as output.
1257
+ const output = commandResult && typeof commandResult === 'object' && 'output' in commandResult
1258
+ ? commandResult.output
1259
+ : commandResult;
1262
1260
  return {
1263
- success: true,
1264
- output: response.output,
1265
- nextTask: response.nextTask || null,
1266
- executionId,
1267
- state: response.state
1261
+ output: output ?? null,
1262
+ outcome,
1268
1263
  };
1269
1264
  }
1270
1265
  catch (error) {
1266
+ console.error(`[ActivityExecutor] ❌ Error evaluating expressions or executing activity:`, error);
1271
1267
  return {
1272
- success: false,
1273
- error: error.message || 'Failed to complete task',
1274
- nextTask: null
1268
+ output: { error: error.message || 'Unknown error' },
1269
+ outcome: 'Failed'
1275
1270
  };
1276
1271
  }
1277
1272
  }
1278
1273
  /**
1279
- * Execute workflow by ID (backward compatibility).
1274
+ * Resolves command failure message text for workflow output: `@` keys via translate, MLS maps via resolve.
1275
+ */
1276
+ async resolveCommandMessageTextForError(value) {
1277
+ if (value == null) {
1278
+ return '';
1279
+ }
1280
+ if (typeof value === 'string') {
1281
+ return value.startsWith('@') ? await this.translateService.translateAsync(value) : value;
1282
+ }
1283
+ return this.translateService.resolve(value);
1284
+ }
1285
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ActivityExecutor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1286
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ActivityExecutor, providedIn: 'root' }); }
1287
+ }
1288
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ActivityExecutor, decorators: [{
1289
+ type: Injectable,
1290
+ args: [{
1291
+ providedIn: 'root'
1292
+ }]
1293
+ }] });
1294
+
1295
+ //#endregion
1296
+ /**
1297
+ * Workflow Manager - Facade for workflow lifecycle orchestration.
1298
+ *
1299
+ * This service is the ONLY interface the frontend uses to interact with workflows.
1300
+ * It follows Clean Architecture principles and does NOT contain execution or business logic.
1301
+ *
1302
+ * Responsibilities:
1303
+ * - Orchestrate workflow lifecycle (start, execute, complete, resume)
1304
+ * - Delegate execution to ActivityExecutor
1305
+ * - Cache workflow state in memory
1306
+ * - Expose a stable API for UI
1307
+ *
1308
+ * Rules:
1309
+ * - No HTTP calls (delegates to AXPWorkflowEngine)
1310
+ * - No CommandBus / Command execution (delegates to ActivityExecutor)
1311
+ * - No workflow branching logic (backend decides)
1312
+ * - No business validation (backend validates)
1313
+ * - No backend assumptions (uses abstract runtime service)
1314
+ */
1315
+ class AXPWorkflowManager {
1316
+ constructor() {
1317
+ //#region ---- Services & Dependencies ----
1318
+ this.workflowEngine = inject(AXP_WORKFLOW_ENGINE);
1319
+ this.activityExecutor = inject(ActivityExecutor);
1320
+ //#endregion
1321
+ //#region ---- State Cache ----
1322
+ /**
1323
+ * Cache workflow states in memory for quick access.
1324
+ * Key: instanceId
1325
+ * Value: AXPWorkflowInstanceState
1326
+ */
1327
+ this.stateCache = new Map();
1328
+ /**
1329
+ * Cache TTL in milliseconds (5 minutes).
1330
+ */
1331
+ this.CACHE_TTL = 5 * 60 * 1000;
1332
+ }
1333
+ //#endregion
1334
+ //#region ---- Public Methods ----
1335
+ /**
1336
+ * Execute frontend activities interactively until reaching workflow-activity:human-task or completion.
1337
+ *
1338
+ * Interactive = show form/popup immediately (user sees and acts). Only workflow-activity:human-task
1339
+ * is not interactive (goes to task board). Other frontend activities (show-layout-popup, show-toast, etc.)
1340
+ * even with taskType human-task in definition are executed here.
1341
+ *
1342
+ * @param instanceId - Workflow instance ID
1343
+ * @param task - Current task to execute
1344
+ * @param state - Current workflow state
1345
+ * @param lastActivityOutput - Last activity output (for expression evaluation)
1346
+ * @returns Final result with nextTask (if workflow-activity:human-task) or completion status
1347
+ */
1348
+ async executeInteractiveFlow(instanceId, task, state, activityOutputs) {
1349
+ let currentTask = task;
1350
+ let currentState = state;
1351
+ let currentActivityOutputs = {
1352
+ ...(currentState.activityOutputs || {}),
1353
+ ...(activityOutputs || {}),
1354
+ };
1355
+ const maxIterations = 100; // Prevent infinite loops
1356
+ let iterationCount = 0;
1357
+ while (currentTask && iterationCount < maxIterations) {
1358
+ iterationCount++;
1359
+ // Interactive = frontend executionMode and NOT task-board activities (human-task, cartable)
1360
+ const isInteractive = (currentTask.executionMode === 'frontend' || currentTask.executionMode === 'both') &&
1361
+ !axpIsWorkflowTaskBoardActivityType(currentTask.activityType);
1362
+ if (isInteractive) {
1363
+ // Execute frontend activity
1364
+ const execResult = await this.activityExecutor.execute(currentTask, currentState, currentActivityOutputs);
1365
+ // Track outputs locally (backend should also persist and return them)
1366
+ currentActivityOutputs = {
1367
+ ...currentActivityOutputs,
1368
+ [currentTask.activityId]: execResult.output,
1369
+ };
1370
+ // Send result to backend
1371
+ const completeResponse = await this.workflowEngine.frontActivtyComplete({
1372
+ instanceId,
1373
+ activityNode: currentTask.activityId,
1374
+ output: execResult.output || {},
1375
+ outcome: execResult.outcome,
1376
+ });
1377
+ // Update state cache
1378
+ if (completeResponse.state) {
1379
+ const normalizedState = { ...completeResponse.state };
1380
+ if (normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
1381
+ normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
1382
+ }
1383
+ currentState = normalizedState;
1384
+ // Prefer outputs returned by backend; fallback to local cache
1385
+ currentActivityOutputs = {
1386
+ ...currentActivityOutputs,
1387
+ ...(normalizedState.activityOutputs || {}),
1388
+ };
1389
+ this.stateCache.set(instanceId, normalizedState);
1390
+ }
1391
+ // Backend decides: if no nextTask, workflow is completed
1392
+ if (!completeResponse.nextTask) {
1393
+ return {
1394
+ nextTask: null,
1395
+ state: currentState,
1396
+ output: completeResponse.output,
1397
+ };
1398
+ }
1399
+ // Backend decides: if nextTask is task-board activity or not frontend, return it (task board or done)
1400
+ const nextInteractive = (completeResponse.nextTask.executionMode === 'frontend' || completeResponse.nextTask.executionMode === 'both') &&
1401
+ !axpIsWorkflowTaskBoardActivityType(completeResponse.nextTask.activityType);
1402
+ if (!nextInteractive) {
1403
+ return {
1404
+ nextTask: completeResponse.nextTask,
1405
+ state: currentState,
1406
+ };
1407
+ }
1408
+ // Continue with next interactive frontend task
1409
+ currentTask = completeResponse.nextTask;
1410
+ }
1411
+ else {
1412
+ // Not interactive (e.g. human-task / cartable) - return as-is for task board
1413
+ return {
1414
+ nextTask: currentTask,
1415
+ state: currentState,
1416
+ };
1417
+ }
1418
+ }
1419
+ // Max iterations reached
1420
+ if (iterationCount >= maxIterations) {
1421
+ console.warn(`[AXPWorkflowManager] ⚠️ Maximum iterations (${maxIterations}) reached`);
1422
+ }
1423
+ return {
1424
+ nextTask: currentTask,
1425
+ state: currentState,
1426
+ };
1427
+ }
1428
+ /**
1429
+ * Start a new workflow instance.
1280
1430
  *
1281
- * @deprecated Use startWorkflow + executeTask + completeTask pattern instead.
1282
- * This method is kept for backward compatibility but will be removed.
1431
+ * Creates a new workflow instance in backend and returns instance ID.
1432
+ * Backend decides what to do: returns pendingTask or indicates completion.
1433
+ *
1434
+ * @param workflowId - Workflow ID to start
1435
+ * @param input - Initial input data (optional)
1436
+ * @returns Start result with instanceId, state, and nextTask
1437
+ *
1438
+ * @example
1439
+ * ```typescript
1440
+ * const result = await workflowManager.start('my-workflow', { userId: '123' });
1441
+ *
1442
+ * if (result.success && result.nextTask) {
1443
+ * // Execute task if frontend
1444
+ * if (result.nextTask.executionMode === 'frontend') {
1445
+ * const execResult = await workflowManager.execute(result.nextTask);
1446
+ * await workflowManager.complete(result.instanceId!, result.nextTask, execResult.outcome, execResult.output);
1447
+ * }
1448
+ * }
1449
+ * ```
1283
1450
  */
1284
- async executeWorkflowById(workflowId, input = {}) {
1285
- // Just start workflow - caller should handle task execution
1286
- return await this.startWorkflow(workflowId, input);
1451
+ async start(workflowId, input = {}) {
1452
+ try {
1453
+ const response = await this.workflowEngine.start({
1454
+ workflowId,
1455
+ input,
1456
+ });
1457
+ // Cache state (normalize Date)
1458
+ let startNormalizedState = { ...response.state };
1459
+ if (startNormalizedState.lastUpdated && !(startNormalizedState.lastUpdated instanceof Date)) {
1460
+ startNormalizedState.lastUpdated = new Date(startNormalizedState.lastUpdated);
1461
+ }
1462
+ this.stateCache.set(response.instanceId, startNormalizedState);
1463
+ // 🎯 Interactive flow: Execute frontend activities that are NOT task-board types (those go to task board)
1464
+ let finalNextTask = response.pendingTask || null;
1465
+ let finalOutput = startNormalizedState.output;
1466
+ const pendingTask = response.pendingTask;
1467
+ if (pendingTask &&
1468
+ (pendingTask.executionMode === 'frontend' || pendingTask.executionMode === 'both') &&
1469
+ !axpIsWorkflowTaskBoardActivityType(pendingTask.activityType)) {
1470
+ const interactiveResult = await this.executeInteractiveFlow(response.instanceId, pendingTask, startNormalizedState, response.activityOutputs || response.state.activityOutputs);
1471
+ finalNextTask = interactiveResult.nextTask;
1472
+ startNormalizedState = interactiveResult.state;
1473
+ if (interactiveResult.output !== undefined) {
1474
+ finalOutput = interactiveResult.output;
1475
+ }
1476
+ // Update cache with final state
1477
+ this.stateCache.set(response.instanceId, startNormalizedState);
1478
+ }
1479
+ // If backend returned null or non-executable task, return it as-is
1480
+ // Backend already decided workflow status (suspended, completed, etc.)
1481
+ return {
1482
+ success: true,
1483
+ instanceId: response.instanceId,
1484
+ state: startNormalizedState,
1485
+ nextTask: finalNextTask,
1486
+ output: finalOutput,
1487
+ };
1488
+ }
1489
+ catch (error) {
1490
+ console.error('[AXPWorkflowManager] ❌ Error starting workflow:', error);
1491
+ return {
1492
+ success: false,
1493
+ error: error.message || 'Failed to start workflow',
1494
+ };
1495
+ }
1287
1496
  }
1288
1497
  /**
1289
1498
  * Resume a suspended workflow (e.g., after user interaction).
1290
1499
  *
1291
1500
  * Backend determines nextStep based on outcome and outcomeConnections.
1292
- * Client only provides executionId, stepId, outcome, and optional userInput.
1501
+ * Client only provides instanceId, stepId, outcome, and optional userInput.
1293
1502
  *
1294
- * @param executionId - Workflow execution ID
1503
+ * @param instanceId - Workflow instance ID
1295
1504
  * @param stepId - Step ID that was waiting for user input
1296
1505
  * @param outcome - User action outcome (e.g., 'Confirmed', 'Cancelled', 'Submitted')
1297
1506
  * @param userInput - Optional user input data
1507
+ * @param taskToken - Secure task token (required for secure resumption)
1508
+ * @returns Resume result with next task (if any)
1298
1509
  */
1299
- async resumeWorkflow(executionId, stepId, outcome, userInput, taskToken) {
1510
+ async resume(instanceId, stepId, outcome, userInput, taskToken) {
1300
1511
  try {
1301
1512
  // Ensure taskToken is provided for secure resumption
1302
1513
  if (!taskToken) {
1303
- throw new Error('Missing taskToken for resumeWorkflow');
1514
+ throw new Error('Missing taskToken for resume operation');
1304
1515
  }
1305
1516
  // Backend handles everything: checks outcomeConnections and determines nextStep
1306
- const response = await this.workflowExecutionService.resumeExecution({
1307
- executionId,
1517
+ const response = await this.workflowEngine.resume({
1518
+ instanceId,
1308
1519
  stepId,
1309
1520
  taskToken,
1310
1521
  outcome,
1311
- userInput
1522
+ userInput,
1312
1523
  });
1313
1524
  // Update cache with state from backend
1314
- if (response.state) {
1315
- this.stateCache.set(executionId, response.state);
1525
+ let normalizedState = response.state ? { ...response.state } : undefined;
1526
+ if (normalizedState && normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
1527
+ normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
1316
1528
  }
1529
+ if (normalizedState) {
1530
+ this.stateCache.set(instanceId, normalizedState);
1531
+ }
1532
+ // 🎯 Interactive flow: Execute frontend activities that are NOT task-board types (those go to task board)
1533
+ let finalNextTask = response.nextTask || null;
1534
+ let finalOutput = response.output;
1535
+ const nextTask = response.nextTask;
1536
+ if (nextTask &&
1537
+ (nextTask.executionMode === 'frontend' || nextTask.executionMode === 'both') &&
1538
+ !axpIsWorkflowTaskBoardActivityType(nextTask.activityType)) {
1539
+ const interactiveResult = await this.executeInteractiveFlow(instanceId, nextTask, normalizedState, normalizedState?.activityOutputs);
1540
+ finalNextTask = interactiveResult.nextTask;
1541
+ normalizedState = interactiveResult.state;
1542
+ if (interactiveResult.output !== undefined) {
1543
+ finalOutput = interactiveResult.output;
1544
+ }
1545
+ // Update cache with final state
1546
+ this.stateCache.set(instanceId, normalizedState);
1547
+ }
1548
+ // If backend returned null or non-executable task, return it as-is
1549
+ // Backend already decided workflow status (suspended, completed, etc.)
1317
1550
  return {
1318
1551
  success: true,
1319
- output: response.output,
1320
- nextTask: response.nextTask || null, // Backend determines this from outcomeConnections
1321
- executionId,
1322
- state: response.state
1552
+ instanceId,
1553
+ state: normalizedState || response.state,
1554
+ nextTask: finalNextTask,
1555
+ output: finalOutput,
1323
1556
  };
1324
1557
  }
1325
1558
  catch (error) {
1559
+ const { message, code } = getWorkflowEngineErrorInfo(error);
1326
1560
  return {
1327
1561
  success: false,
1328
- error: error.message || 'Failed to resume workflow',
1329
- nextTask: null
1562
+ instanceId,
1563
+ error: message,
1564
+ errorCode: code,
1330
1565
  };
1331
1566
  }
1332
1567
  }
1333
1568
  /**
1334
- * Get workflow execution state (from cache or backend).
1569
+ * Get workflow instance state.
1570
+ *
1571
+ * Retrieves state from cache (if valid) or from backend.
1572
+ *
1573
+ * @param instanceId - Workflow instance ID
1574
+ * @returns Workflow instance state or null if not found
1335
1575
  */
1336
- async getWorkflowState(executionId) {
1576
+ async getState(instanceId) {
1337
1577
  // Check cache first
1338
- const cached = this.stateCache.get(executionId);
1578
+ const cached = this.stateCache.get(instanceId);
1339
1579
  if (cached) {
1340
- // Cache is valid for 5 minutes
1341
- const cacheAge = Date.now() - cached.lastUpdated.getTime();
1342
- if (cacheAge < 5 * 60 * 1000) {
1343
- return cached;
1580
+ // Normalize lastUpdated to Date (for cache safety)
1581
+ const normalizedCached = { ...cached };
1582
+ if (normalizedCached.lastUpdated && !(normalizedCached.lastUpdated instanceof Date)) {
1583
+ normalizedCached.lastUpdated = new Date(normalizedCached.lastUpdated);
1584
+ }
1585
+ // Validate cache age
1586
+ const cacheAge = Date.now() - normalizedCached.lastUpdated.getTime();
1587
+ if (cacheAge < this.CACHE_TTL) {
1588
+ return normalizedCached;
1344
1589
  }
1345
1590
  }
1346
1591
  // Fetch from backend
1347
1592
  try {
1348
- const state = await this.workflowExecutionService.getExecutionState({
1349
- executionId
1593
+ const state = await this.workflowEngine.getState({
1594
+ instanceId,
1350
1595
  });
1596
+ // Normalize lastUpdated to Date (for cache safety)
1597
+ const normalizedState = { ...state };
1598
+ if (normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
1599
+ normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
1600
+ }
1351
1601
  // Update cache
1352
- this.stateCache.set(executionId, state);
1353
- return state;
1602
+ this.stateCache.set(instanceId, normalizedState);
1603
+ return normalizedState;
1354
1604
  }
1355
- catch {
1605
+ catch (error) {
1606
+ console.error('[AXPWorkflowManager] ❌ Error getting workflow state:', error);
1356
1607
  return null;
1357
1608
  }
1358
1609
  }
1359
- //#endregion
1360
- //#region ---- Private Methods ----
1361
1610
  /**
1362
- * Execute a frontend activity using CommandBus.
1363
- *
1364
- * Frontend activities are executed in the browser using AXPCommandService.
1365
- * Activities can also be executed in both frontend and backend (hybrid mode).
1366
- *
1367
- * @param task - Frontend task to execute
1368
- * @returns Execution result with output and outcome
1611
+ * Claim a pooled workflow task (assign current user on the bookmark without advancing the workflow).
1612
+ * Supported only when the injected workflow engine implements {@link AXPWorkflowEngine.claimTask}.
1369
1613
  */
1370
- async executeFrontendActivity(task) {
1614
+ async claimTask(instanceId, bookmarkId, stepId) {
1615
+ const claim = this.workflowEngine.claimTask?.bind(this.workflowEngine);
1616
+ if (!claim) {
1617
+ return {
1618
+ success: false,
1619
+ instanceId,
1620
+ error: 'Claim task is not supported by this workflow engine',
1621
+ };
1622
+ }
1371
1623
  try {
1372
- // Check if command exists
1373
- const commandExists = this.commandService.exists(task.activityType);
1374
- if (!commandExists) {
1375
- console.warn(`[WorkflowCoordinator] ⚠️ Frontend activity '${task.activityType}' is not registered. Skipping execution.`);
1376
- return {
1377
- output: null,
1378
- outcome: 'Done'
1379
- };
1380
- }
1381
- // Execute activity via CommandBus
1382
- // Activities registered as AXPCommand return {output, outcomes}
1383
- // 🎯 Flatten properties if nested (workflow-studio format)
1384
- let commandInput = task.input || task.config || {};
1385
- if (commandInput['properties'] && typeof commandInput['properties'] === 'object') {
1386
- // Flatten: {properties: {text: "..."}} -> {text: "..."}
1387
- commandInput = { ...commandInput['properties'] };
1388
- }
1389
- const result = await this.commandService.execute(task.activityType, commandInput);
1390
- if (!result) {
1391
- return {
1392
- output: null,
1393
- outcome: 'Failed',
1394
- };
1395
- }
1396
- if (!result.success) {
1397
- return {
1398
- output: {
1399
- error: result.message?.text,
1400
- },
1401
- outcome: 'Failed',
1402
- };
1403
- }
1404
- const commandResult = result.data;
1405
- const outcomes = commandResult?.outcomes ?? {};
1406
- let outcome = 'Done';
1407
- if (Object.keys(outcomes).length > 0) {
1408
- outcome = outcomes['Done'] ? 'Done' : Object.keys(outcomes)[0] || 'Done';
1409
- }
1624
+ const result = await claim({ instanceId, bookmarkId, stepId });
1410
1625
  return {
1411
- output: commandResult?.output ?? null,
1412
- outcome,
1626
+ success: result.success,
1627
+ instanceId,
1628
+ error: result.error,
1629
+ errorCode: result.errorCode,
1413
1630
  };
1414
1631
  }
1415
1632
  catch (error) {
1416
- console.error(`[WorkflowCoordinator] Error executing frontend activity '${task.activityType}':`, error);
1633
+ const { message, code } = getWorkflowEngineErrorInfo(error);
1417
1634
  return {
1418
- output: { error: error.message || 'Unknown error' },
1419
- outcome: 'Failed'
1635
+ success: false,
1636
+ instanceId,
1637
+ error: message,
1638
+ errorCode: code,
1420
1639
  };
1421
1640
  }
1422
1641
  }
1423
1642
  /**
1424
- * Start workflow execution in backend.
1425
- * Backend returns executionId, initial state, and first task to execute.
1643
+ * Reassign a human-task bookmark to the current user without advancing the workflow.
1644
+ * Supported only when the injected workflow engine implements {@link AXPWorkflowEngine.reassignTaskToSelf}.
1426
1645
  */
1427
- async startWorkflowExecution(workflowId, input) {
1428
- const response = await this.workflowExecutionService.startExecution({
1429
- workflowId,
1430
- input
1431
- });
1432
- // Cache state
1433
- this.stateCache.set(response.executionId, response.state);
1434
- return {
1435
- executionId: response.executionId,
1436
- state: response.state,
1437
- pendingTask: response.pendingTask
1438
- };
1646
+ async reassignTaskToSelf(instanceId, bookmarkId, stepId) {
1647
+ const reassign = this.workflowEngine.reassignTaskToSelf?.bind(this.workflowEngine);
1648
+ if (!reassign) {
1649
+ return {
1650
+ success: false,
1651
+ instanceId,
1652
+ error: 'Reassign task is not supported by this workflow engine',
1653
+ };
1654
+ }
1655
+ try {
1656
+ const result = await reassign({ instanceId, bookmarkId, stepId });
1657
+ return {
1658
+ success: result.success,
1659
+ instanceId,
1660
+ error: result.error,
1661
+ errorCode: result.errorCode,
1662
+ };
1663
+ }
1664
+ catch (error) {
1665
+ const { message, code } = getWorkflowEngineErrorInfo(error);
1666
+ return {
1667
+ success: false,
1668
+ instanceId,
1669
+ error: message,
1670
+ errorCode: code,
1671
+ };
1672
+ }
1439
1673
  }
1440
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: WorkflowCoordinator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1441
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: WorkflowCoordinator, providedIn: 'root' }); }
1674
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1675
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowManager, providedIn: 'root' }); }
1442
1676
  }
1443
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: WorkflowCoordinator, decorators: [{
1677
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowManager, decorators: [{
1444
1678
  type: Injectable,
1445
1679
  args: [{
1446
- providedIn: 'root'
1680
+ providedIn: 'root',
1447
1681
  }]
1448
1682
  }] });
1449
1683
 
1684
+ const AXP_WORKFLOW_PROVIDER = new InjectionToken('AXP_WORKFLOW_PROVIDER', {
1685
+ factory: () => [],
1686
+ });
1687
+ const AXP_WORKFLOW_CATEGORY_PROVIDER = new InjectionToken('AXP_WORKFLOW_CATEGORY_PROVIDER', {
1688
+ factory: () => [],
1689
+ });
1690
+
1691
+ //#endregion
1450
1692
  /**
1451
- * Types and interfaces for Workflow Execution Service.
1693
+ * Local engine implementation that manages workflow progression and state.
1694
+ *
1695
+ * This engine:
1696
+ * - Returns frontend/both activities as pendingTask (does NOT execute them)
1697
+ * - Skips backend activities (does not error, continues execution)
1698
+ * - Maintains workflow state in memory
1699
+ * - Does not require backend API calls
1700
+ *
1701
+ * Execution of frontend tasks is handled by AXPWorkflowManager via ActivityExecutor.
1702
+ * This engine only manages workflow progression and state storage.
1703
+ *
1704
+ * This is the DEFAULT engine provider. Applications can override it with
1705
+ * an API-based engine implementation.
1452
1706
  */
1453
-
1454
- // Production Workflow Coordinator (Frontend/Backend Separation)
1455
-
1456
- // Workflow Definition Types (Storage/Database)
1707
+ class AXPWorkflowLocalEngine {
1708
+ constructor() {
1709
+ //#region ---- Services & Dependencies ----
1710
+ this.activityDefinitionService = inject(AXPActivityDefinitionService);
1711
+ this.workflowProviders = inject(AXP_WORKFLOW_PROVIDER, { optional: true }) || [];
1712
+ this.multiLanguageResolver = inject(AXTranslationService);
1713
+ //#endregion
1714
+ //#region ---- Instance Storage ----
1715
+ /**
1716
+ * In-memory storage for workflow instances.
1717
+ * Key: instanceId
1718
+ * Value: LocalWorkflowState
1719
+ */
1720
+ this.instances = new Map();
1721
+ /**
1722
+ * Task token storage for secure resume operations.
1723
+ * Key: taskToken
1724
+ * Value: { instanceId, activityId }
1725
+ */
1726
+ this.taskTokens = new Map();
1727
+ }
1728
+ //#endregion
1729
+ //#region ---- Public Methods (AXPWorkflowEngine) ----
1730
+ /**
1731
+ * Start a new workflow instance.
1732
+ *
1733
+ * Creates an in-memory workflow instance and progresses it.
1734
+ * Frontend/both activities are returned as pendingTask for external execution.
1735
+ * Backend activities are skipped.
1736
+ */
1737
+ async start(request) {
1738
+ console.log(`[WorkflowLocalEngine] 🚀 Starting workflow: ${request.workflowId}`, request);
1739
+ // Generate instance ID
1740
+ const instanceId = AXPDataGenerator.uuid();
1741
+ const now = new Date();
1742
+ // Load workflow definition
1743
+ console.log(`[WorkflowLocalEngine] 📥 Loading workflow definition: ${request.workflowId}`);
1744
+ const definition = await this.getDefinition(request.workflowId);
1745
+ if (!definition) {
1746
+ console.error(`[WorkflowLocalEngine] ❌ Workflow definition not found: ${request.workflowId}`);
1747
+ throw new Error(`Workflow definition not found: ${request.workflowId}`);
1748
+ }
1749
+ console.log(`[WorkflowLocalEngine] ✅ Definition loaded:`, {
1750
+ name: definition.name,
1751
+ activitiesCount: definition.graph?.activities?.length || 0,
1752
+ connectionsCount: definition.graph?.connections?.length || 0,
1753
+ });
1754
+ // Initialize workflow state
1755
+ const state = {
1756
+ instanceId,
1757
+ workflowId: request.workflowId,
1758
+ status: 'running',
1759
+ variables: {},
1760
+ activityOutputs: {},
1761
+ lastActivityOutput: undefined,
1762
+ input: request.input || {},
1763
+ output: undefined,
1764
+ lastUpdated: now,
1765
+ };
1766
+ // Create local state
1767
+ const localState = {
1768
+ instanceId,
1769
+ workflowId: request.workflowId,
1770
+ definition,
1771
+ state,
1772
+ completedActivities: new Set(),
1773
+ activityResults: new Map(),
1774
+ };
1775
+ // Store instance
1776
+ this.instances.set(instanceId, localState);
1777
+ // Execute workflow steps
1778
+ console.log(`[WorkflowLocalEngine] ⚙️ Executing workflow steps...`);
1779
+ const pendingTask = await this.executeWorkflowSteps(localState);
1780
+ // Update state
1781
+ localState.state.lastUpdated = new Date();
1782
+ console.log(`[WorkflowLocalEngine] ✅ Workflow started:`, {
1783
+ instanceId,
1784
+ status: localState.state.status,
1785
+ hasPendingTask: !!pendingTask,
1786
+ pendingTaskType: pendingTask?.activityType,
1787
+ });
1788
+ return {
1789
+ instanceId,
1790
+ state: localState.state,
1791
+ pendingTask: pendingTask || null,
1792
+ activityOutputs: localState.state.activityOutputs,
1793
+ lastActivityOutput: localState.state.lastActivityOutput,
1794
+ };
1795
+ }
1796
+ /**
1797
+ * Resume a suspended workflow instance.
1798
+ *
1799
+ * Validates task token, applies externally executed result,
1800
+ * and continues progressing workflow steps.
1801
+ */
1802
+ async resume(request) {
1803
+ // Validate task token
1804
+ const tokenInfo = this.taskTokens.get(request.taskToken);
1805
+ if (!tokenInfo || tokenInfo.instanceId !== request.instanceId || tokenInfo.activityId !== request.stepId) {
1806
+ throw new Error('Invalid task token');
1807
+ }
1808
+ // Get instance
1809
+ const localState = this.instances.get(request.instanceId);
1810
+ if (!localState) {
1811
+ throw new Error(`Workflow instance not found: ${request.instanceId}`);
1812
+ }
1813
+ // Store activity result (from external execution)
1814
+ const outcome = request.outcome ?? 'Done';
1815
+ localState.activityResults.set(request.stepId, {
1816
+ output: request.userInput || {},
1817
+ outcome,
1818
+ });
1819
+ localState.completedActivities.add(request.stepId);
1820
+ // Store activity output for expression evaluation
1821
+ localState.state.activityOutputs = {
1822
+ ...(localState.state.activityOutputs || {}),
1823
+ [request.stepId]: request.userInput || {},
1824
+ };
1825
+ localState.state.lastActivityOutput = request.userInput || {};
1826
+ // Merge output/userInput into state variables
1827
+ if (request.userInput) {
1828
+ localState.state.variables = {
1829
+ ...localState.state.variables,
1830
+ ...(request.userInput || {}),
1831
+ };
1832
+ }
1833
+ localState.state.variables = {
1834
+ ...localState.state.variables,
1835
+ [`${request.stepId}_outcome`]: outcome,
1836
+ [`${request.stepId}_activityOutput`]: request.userInput || {},
1837
+ };
1838
+ // Mark activity as completed and continue progression
1839
+ // Continue progressing workflow steps (skipping backend activities)
1840
+ const nextTask = await this.executeWorkflowSteps(localState);
1841
+ // Update state
1842
+ localState.state.lastUpdated = new Date();
1843
+ // Determine final status
1844
+ if (!nextTask && localState.state.status === 'running') {
1845
+ localState.state.status = 'completed';
1846
+ localState.state.output = localState.state.variables;
1847
+ }
1848
+ return {
1849
+ output: request.userInput || {},
1850
+ outcomes: { [outcome]: true },
1851
+ state: localState.state,
1852
+ nextTask: nextTask || null,
1853
+ };
1854
+ }
1855
+ /**
1856
+ * Get current workflow instance state.
1857
+ */
1858
+ async getState(request) {
1859
+ const localState = this.instances.get(request.instanceId);
1860
+ if (!localState) {
1861
+ throw new Error(`Workflow instance not found: ${request.instanceId}`);
1862
+ }
1863
+ // Normalize lastUpdated to Date (for cache safety)
1864
+ const state = { ...localState.state };
1865
+ if (state.lastUpdated && !(state.lastUpdated instanceof Date)) {
1866
+ state.lastUpdated = new Date(state.lastUpdated);
1867
+ }
1868
+ return state;
1869
+ }
1870
+ //#endregion
1871
+ //#region ---- Private Methods ----
1872
+ /**
1873
+ * Get workflow definition from available providers.
1874
+ */
1875
+ async getDefinition(workflowId) {
1876
+ // Try all providers in order
1877
+ const resolvedProviders = await Promise.allSettled(this.workflowProviders);
1878
+ for (const p of resolvedProviders) {
1879
+ if (p.status === 'fulfilled' && p.value) {
1880
+ const provider = p.value;
1881
+ // Check if provider has getByName method
1882
+ if (typeof provider.getByName === 'function') {
1883
+ try {
1884
+ const definition = await provider.getByName(workflowId);
1885
+ if (definition) {
1886
+ return definition;
1887
+ }
1888
+ }
1889
+ catch {
1890
+ // Continue on error - try other providers
1891
+ }
1892
+ }
1893
+ }
1894
+ }
1895
+ return null;
1896
+ }
1897
+ /**
1898
+ * Progress workflow steps starting from the current position.
1899
+ *
1900
+ * For frontend/both activities: returns task immediately (suspends workflow).
1901
+ * For backend activities: skips and continues.
1902
+ *
1903
+ * Returns the next pending task (if frontend activity found) or null (if completed).
1904
+ */
1905
+ async executeWorkflowSteps(localState) {
1906
+ const graph = localState.definition.graph;
1907
+ const activities = graph.activities || [];
1908
+ const connections = graph.connections || [];
1909
+ // Build activity map
1910
+ const activityMap = new Map();
1911
+ activities.forEach((activity) => {
1912
+ activityMap.set(activity.id, activity);
1913
+ });
1914
+ // Build connection graph
1915
+ const outgoingConnections = new Map();
1916
+ const incomingConnections = new Map();
1917
+ connections.forEach((conn) => {
1918
+ const sourceId = conn.source.activtyName;
1919
+ const targetId = conn.target.activtyName;
1920
+ if (!outgoingConnections.has(sourceId)) {
1921
+ outgoingConnections.set(sourceId, []);
1922
+ }
1923
+ outgoingConnections.get(sourceId).push(conn);
1924
+ if (!incomingConnections.has(targetId)) {
1925
+ incomingConnections.set(targetId, []);
1926
+ }
1927
+ incomingConnections.get(targetId).push(conn);
1928
+ });
1929
+ // Find starting activity (use startActivityId or no incoming connections, or first activity)
1930
+ let currentActivityId = localState.currentActivityId;
1931
+ if (!currentActivityId) {
1932
+ // Use startActivityId if available
1933
+ if (graph.startActivityId) {
1934
+ currentActivityId = graph.startActivityId;
1935
+ }
1936
+ else {
1937
+ // Find root activity (no incoming connections)
1938
+ for (const activity of activities) {
1939
+ if (!incomingConnections.has(activity.id)) {
1940
+ currentActivityId = activity.id;
1941
+ break;
1942
+ }
1943
+ }
1944
+ // If no root found, use first activity
1945
+ if (!currentActivityId && activities.length > 0) {
1946
+ currentActivityId = activities[0].id;
1947
+ }
1948
+ }
1949
+ }
1950
+ // Execute workflow steps
1951
+ while (currentActivityId) {
1952
+ const activity = activityMap.get(currentActivityId);
1953
+ if (!activity) {
1954
+ break;
1955
+ }
1956
+ // Skip if already completed
1957
+ if (localState.completedActivities.has(currentActivityId)) {
1958
+ // Move to next activity
1959
+ const nextId = this.getNextActivityId(currentActivityId, outgoingConnections, localState.activityResults);
1960
+ currentActivityId = nextId ?? undefined;
1961
+ continue;
1962
+ }
1963
+ // Get activity definition to retrieve executionMode and title
1964
+ console.log(`[WorkflowLocalEngine] 🔍 Getting activity definition for: ${activity.name}`);
1965
+ const activityDefinition = await this.activityDefinitionService.getActivityByName(activity.name);
1966
+ console.log(`[WorkflowLocalEngine] 📋 Activity definition:`, {
1967
+ name: activityDefinition?.name,
1968
+ type: activityDefinition?.type,
1969
+ executionMode: activityDefinition?.executionMode,
1970
+ title: activityDefinition?.title,
1971
+ found: !!activityDefinition,
1972
+ });
1973
+ const executionMode = activityDefinition?.executionMode || 'frontend';
1974
+ const activityTitle = this.multiLanguageResolver.resolve(activityDefinition?.title) || activityDefinition?.name;
1975
+ // Handle backend activities: skip
1976
+ if (executionMode === 'backend') {
1977
+ console.log(`[WorkflowLocalEngine] ⏭️ Skipping backend activity: ${activity.name} (${activity.id})`);
1978
+ localState.completedActivities.add(currentActivityId);
1979
+ localState.activityResults.set(currentActivityId, {
1980
+ output: null,
1981
+ outcome: 'Done',
1982
+ });
1983
+ // Move to next activity
1984
+ const nextId = this.getNextActivityId(currentActivityId, outgoingConnections, localState.activityResults);
1985
+ currentActivityId = nextId ?? undefined;
1986
+ continue;
1987
+ }
1988
+ // Handle frontend/both activities: return as pendingTask (do NOT execute)
1989
+ if (executionMode === 'frontend' || executionMode === 'both') {
1990
+ // Create task for external execution
1991
+ // Note: Expression evaluation will be done by ActivityExecutor
1992
+ const task = {
1993
+ taskToken: AXPDataGenerator.uuid(),
1994
+ activityId: activity.id,
1995
+ activityType: activity.name,
1996
+ activityName: activityTitle || undefined,
1997
+ executionMode: executionMode,
1998
+ input: activity.inputs || {}, // Pass raw inputs - executor will evaluate
1999
+ };
2000
+ // Store task token for secure resume
2001
+ this.taskTokens.set(task.taskToken, {
2002
+ instanceId: localState.instanceId,
2003
+ activityId: activity.id,
2004
+ });
2005
+ // Update state to indicate suspension
2006
+ localState.currentActivityId = currentActivityId;
2007
+ localState.state.status = 'suspended';
2008
+ localState.state.currentStepId = currentActivityId;
2009
+ // Return task immediately - AXPWorkflowManager will execute it
2010
+ return task;
2011
+ }
2012
+ // Move to next activity
2013
+ const nextId = this.getNextActivityId(currentActivityId, outgoingConnections, localState.activityResults);
2014
+ currentActivityId = nextId ?? undefined;
2015
+ }
2016
+ // Workflow completed
2017
+ localState.state.status = 'completed';
2018
+ localState.state.output = localState.state.variables;
2019
+ localState.currentActivityId = undefined;
2020
+ return null;
2021
+ }
2022
+ /**
2023
+ * Get next activity ID based on connections and outcomes.
2024
+ */
2025
+ getNextActivityId(currentActivityId, outgoingConnections, activityResults) {
2026
+ const connections = outgoingConnections.get(currentActivityId) || [];
2027
+ if (connections.length === 0) {
2028
+ return null; // No outgoing connections - workflow ends
2029
+ }
2030
+ // Get current activity result
2031
+ const result = activityResults.get(currentActivityId);
2032
+ const outcome = result?.outcome || 'Done';
2033
+ // Find connection matching outcome
2034
+ // Outcome matching is typically done via port name (e.g., "Done", "Failed")
2035
+ for (const conn of connections) {
2036
+ const sourcePort = conn.source.port || 'Done';
2037
+ if (sourcePort === outcome) {
2038
+ return conn.target.activtyName;
2039
+ }
2040
+ }
2041
+ // If no matching outcome, use first connection (default path)
2042
+ if (connections.length > 0) {
2043
+ return connections[0].target.activtyName;
2044
+ }
2045
+ return null;
2046
+ }
2047
+ async frontActivtyComplete(request) {
2048
+ const localState = this.instances.get(request.instanceId);
2049
+ if (!localState) {
2050
+ throw new Error(`Workflow instance not found: ${request.instanceId}`);
2051
+ }
2052
+ // Store activity result
2053
+ const outcome = request.outcome ?? 'Done';
2054
+ localState.activityResults.set(request.activityNode, {
2055
+ output: request.output || {},
2056
+ outcome,
2057
+ });
2058
+ localState.completedActivities.add(request.activityNode);
2059
+ // Store outputs for expression evaluation
2060
+ localState.state.activityOutputs = {
2061
+ ...(localState.state.activityOutputs || {}),
2062
+ [request.activityNode]: request.output || {},
2063
+ };
2064
+ localState.state.lastActivityOutput = request.output || {};
2065
+ // Merge output into workflow variables
2066
+ localState.state.variables = {
2067
+ ...localState.state.variables,
2068
+ ...(request.output || {}),
2069
+ };
2070
+ // Continue workflow progression
2071
+ const nextTask = await this.executeWorkflowSteps(localState);
2072
+ // Update state timestamp
2073
+ localState.state.lastUpdated = new Date();
2074
+ // Determine final status
2075
+ if (!nextTask && localState.state.status === 'running') {
2076
+ localState.state.status = 'completed';
2077
+ localState.state.output = localState.state.variables;
2078
+ }
2079
+ return {
2080
+ output: request.output || {},
2081
+ outcomes: { [outcome]: true },
2082
+ nextTask: nextTask || null,
2083
+ state: localState.state,
2084
+ };
2085
+ }
2086
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowLocalEngine, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2087
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowLocalEngine }); }
2088
+ }
2089
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowLocalEngine, decorators: [{
2090
+ type: Injectable
2091
+ }] });
2092
+
2093
+ // Workflow Runtime Services
2094
+
2095
+ //#region ---- Imports ----
2096
+ //#endregion
2097
+ /**
2098
+ * Optimized Workflow Definition Service
2099
+ *
2100
+ * Manages workflow definitions (metadata) for UI and tooling.
2101
+ * Similar to AXPActivityDefinitionService - only handles metadata, not execution.
2102
+ *
2103
+ * Performance optimizations:
2104
+ * 1. Uses childrenCount to determine if category has children (no query needed)
2105
+ * 2. Uses itemsCount to determine if category has workflows (no query needed)
2106
+ * 3. Aggressive caching prevents duplicate API calls
2107
+ * 4. Single pending request per resource prevents race conditions
2108
+ * 5. Lazy loading - only loads data when needed
2109
+ */
2110
+ class AXPWorkflowDefinitionService {
2111
+ constructor() {
2112
+ //#region ---- Providers & Caches ----
2113
+ this.categoryProviders = inject(AXP_WORKFLOW_CATEGORY_PROVIDER, { optional: true }) || [];
2114
+ this.workflowProviders = inject(AXP_WORKFLOW_PROVIDER, { optional: true }) || [];
2115
+ //#endregion
2116
+ //#region ---- Cache Storage ----
2117
+ /** Cache for categories by id - O(1) lookup */
2118
+ this.categoriesById = new Map();
2119
+ /** Cache for categories by parentId - O(1) lookup */
2120
+ this.categoriesByParentId = new Map();
2121
+ /** Cache for workflow definitions by categoryId - O(1) lookup */
2122
+ this.workflowsByCategory = new Map();
2123
+ /** Cache for individual workflow definitions by name - O(1) lookup */
2124
+ this.workflowsByName = new Map();
2125
+ /** Track which provider index owns each category (by category ID) */
2126
+ this.categoryOwnership = new Map(); // Maps categoryId → provider index
2127
+ /** Pending API requests to prevent duplicate calls */
2128
+ this.pendingCategoriesRequests = new Map();
2129
+ this.pendingWorkflowsRequests = new Map();
2130
+ this.pendingWorkflowRequests = new Map();
2131
+ }
2132
+ //#endregion
2133
+ //#region ---- Public API: Categories ----
2134
+ /**
2135
+ * Get categories by parentId with aggressive caching
2136
+ *
2137
+ * Optimization: Returns cached result immediately if available,
2138
+ * preventing unnecessary API calls during navigation
2139
+ *
2140
+ * @param parentId - Parent category ID (undefined = root categories)
2141
+ * @returns Array of categories with count metadata (childrenCount, itemsCount)
2142
+ */
2143
+ async getCategories(parentId) {
2144
+ // ✅ Fast path: Return cached result
2145
+ if (this.categoriesByParentId.has(parentId)) {
2146
+ return this.categoriesByParentId.get(parentId);
2147
+ }
2148
+ // ✅ Prevent duplicate requests: Return pending promise
2149
+ if (this.pendingCategoriesRequests.has(parentId)) {
2150
+ return this.pendingCategoriesRequests.get(parentId);
2151
+ }
2152
+ // ✅ Create single request and cache it
2153
+ const requestPromise = this.loadCategoriesFromProviders(parentId);
2154
+ this.pendingCategoriesRequests.set(parentId, requestPromise);
2155
+ return requestPromise;
2156
+ }
2157
+ /**
2158
+ * Get single category by ID with O(1) lookup
2159
+ *
2160
+ * Optimization: Uses Map for instant retrieval, falls back to
2161
+ * searching cache, then providers if not found
2162
+ */
2163
+ async getCategoryById(categoryId) {
2164
+ // ✅ Fast path: O(1) lookup in cache
2165
+ if (this.categoriesById.has(categoryId)) {
2166
+ return this.categoriesById.get(categoryId);
2167
+ }
2168
+ // ✅ Search in cached parent-child lists
2169
+ for (const categories of this.categoriesByParentId.values()) {
2170
+ const found = categories.find(cat => cat.id === categoryId);
2171
+ if (found) {
2172
+ this.categoriesById.set(categoryId, found);
2173
+ return found;
2174
+ }
2175
+ }
2176
+ // ✅ Load root categories if not loaded
2177
+ if (!this.categoriesByParentId.has(undefined)) {
2178
+ await this.getCategories();
2179
+ if (this.categoriesById.has(categoryId)) {
2180
+ return this.categoriesById.get(categoryId);
2181
+ }
2182
+ }
2183
+ // ✅ Breadth-first search through hierarchy
2184
+ return this.searchCategoryInHierarchy(categoryId);
2185
+ }
2186
+ /**
2187
+ * Get category path from root to specified category
2188
+ *
2189
+ * Optimization: Builds path using cached categories only
2190
+ */
2191
+ async getCategoriesPathById(categoryId) {
2192
+ const path = [];
2193
+ let currentCategoryId = categoryId;
2194
+ while (currentCategoryId) {
2195
+ const category = await this.getCategoryById(currentCategoryId);
2196
+ if (!category) {
2197
+ throw new Error(`Category '${currentCategoryId}' not found`);
2198
+ }
2199
+ path.unshift(category);
2200
+ currentCategoryId = category.parentId;
2201
+ }
2202
+ return path;
2203
+ }
2204
+ //#endregion
2205
+ //#region ---- Public API: Workflow Definitions ----
2206
+ /**
2207
+ * Get workflow definitions for a category with smart caching
2208
+ *
2209
+ * Optimization: Checks itemsCount before querying
2210
+ * - If itemsCount = 0, returns empty array (no API call)
2211
+ * - If itemsCount > 0, loads and caches workflow definitions
2212
+ * - Returns cached result on subsequent calls
2213
+ *
2214
+ * @param categoryId - Category ID to get workflow definitions from
2215
+ * @returns Array of workflow definitions
2216
+ */
2217
+ async getWorkflowsByCategoryId(categoryId) {
2218
+ // ✅ Fast path: Return cached result
2219
+ if (this.workflowsByCategory.has(categoryId)) {
2220
+ return this.workflowsByCategory.get(categoryId);
2221
+ }
2222
+ // ✅ Smart optimization: Check itemsCount before querying
2223
+ const category = await this.getCategoryById(categoryId);
2224
+ if (category && category.itemsCount !== undefined && category.itemsCount === 0) {
2225
+ // Category has no workflows - cache empty array and skip API call
2226
+ const emptyArray = [];
2227
+ this.workflowsByCategory.set(categoryId, emptyArray);
2228
+ return emptyArray;
2229
+ }
2230
+ // ✅ Prevent duplicate requests
2231
+ if (this.pendingWorkflowsRequests.has(categoryId)) {
2232
+ return this.pendingWorkflowsRequests.get(categoryId);
2233
+ }
2234
+ // ✅ Load from providers
2235
+ const requestPromise = this.loadWorkflowsFromProviders(categoryId);
2236
+ this.pendingWorkflowsRequests.set(categoryId, requestPromise);
2237
+ return requestPromise;
2238
+ }
2239
+ /**
2240
+ * Get single workflow definition by name with O(1) lookup
2241
+ *
2242
+ * Optimization: Uses Map for instant retrieval
2243
+ *
2244
+ * @param name - Workflow name (unique identifier)
2245
+ * @returns Workflow definition or undefined if not found
2246
+ */
2247
+ async getWorkflowByName(name) {
2248
+ // ✅ Fast path: O(1) lookup in cache
2249
+ if (this.workflowsByName.has(name)) {
2250
+ return this.workflowsByName.get(name);
2251
+ }
2252
+ // ✅ Prevent duplicate requests
2253
+ if (this.pendingWorkflowRequests.has(name)) {
2254
+ return this.pendingWorkflowRequests.get(name);
2255
+ }
2256
+ // ✅ Load from providers
2257
+ const requestPromise = this.loadWorkflowFromProviders(name);
2258
+ this.pendingWorkflowRequests.set(name, requestPromise);
2259
+ return requestPromise;
2260
+ }
2261
+ /**
2262
+ * Get category ID containing a specific workflow definition
2263
+ *
2264
+ * Optimization: Searches cache first, loads on-demand if needed
2265
+ */
2266
+ async getCategoryIdByWorkflowName(workflowName) {
2267
+ // ✅ Search in cached workflow definitions
2268
+ for (const [categoryId, definitions] of this.workflowsByCategory.entries()) {
2269
+ if (definitions.some(def => def.name === workflowName)) {
2270
+ return categoryId;
2271
+ }
2272
+ }
2273
+ // ✅ Try loading the workflow definition to find its category
2274
+ // Note: AXPWorkflowDefinition doesn't have category field
2275
+ // Category is managed separately through category providers
2276
+ // This method searches through cached categories
2277
+ const definition = await this.getWorkflowByName(workflowName);
2278
+ if (definition) {
2279
+ // Search through all categories to find which one contains this workflow
2280
+ const categories = await this.getCategories();
2281
+ for (const category of categories) {
2282
+ const workflows = await this.getWorkflowsByCategoryId(category.id);
2283
+ if (workflows.some(w => w.name === workflowName)) {
2284
+ return category.id;
2285
+ }
2286
+ }
2287
+ }
2288
+ return undefined;
2289
+ }
2290
+ /**
2291
+ * Get category path for a workflow
2292
+ */
2293
+ async getCategoriesPathByWorkflowName(workflowName) {
2294
+ const categoryId = await this.getCategoryIdByWorkflowName(workflowName);
2295
+ if (!categoryId) {
2296
+ throw new Error(`Workflow '${workflowName}' not found in any category`);
2297
+ }
2298
+ return this.getCategoriesPathById(categoryId);
2299
+ }
2300
+ //#endregion
2301
+ //#region ---- Private: Data Loading ----
2302
+ /**
2303
+ * Load categories from providers and cache results
2304
+ *
2305
+ * Optimization: Tracks provider ownership to avoid unnecessary API calls
2306
+ * - For root (parentId = undefined): Query ALL providers
2307
+ * - For children: Only query the provider that owns the parent
2308
+ */
2309
+ async loadCategoriesFromProviders(parentId) {
2310
+ try {
2311
+ const resolvedProviders = await Promise.allSettled(this.categoryProviders);
2312
+ const categories = [];
2313
+ // Determine which provider(s) to query
2314
+ const providerIndicesToQuery = parentId
2315
+ ? this.getProviderIndexForCategory(parentId)
2316
+ : null; // Root: query all providers
2317
+ for (let i = 0; i < resolvedProviders.length; i++) {
2318
+ const p = resolvedProviders[i];
2319
+ // Skip if we have a specific provider index and this isn't it
2320
+ if (providerIndicesToQuery !== null && !providerIndicesToQuery.includes(i)) {
2321
+ continue;
2322
+ }
2323
+ if (p.status === 'fulfilled' && p.value && typeof p.value.getList === 'function') {
2324
+ try {
2325
+ const cats = await p.value.getList(parentId);
2326
+ if (Array.isArray(cats) && cats.length > 0) {
2327
+ categories.push(...cats);
2328
+ // ✅ Track ownership: This provider INDEX owns these categories
2329
+ cats.forEach(cat => this.categoryOwnership.set(cat.id, i));
2330
+ }
2331
+ }
2332
+ catch {
2333
+ // Continue on error - try other providers
2334
+ }
2335
+ }
2336
+ }
2337
+ // ✅ Cache results for fast subsequent access
2338
+ this.categoriesByParentId.set(parentId, categories);
2339
+ categories.forEach(cat => this.categoriesById.set(cat.id, cat));
2340
+ return categories;
2341
+ }
2342
+ finally {
2343
+ this.pendingCategoriesRequests.delete(parentId);
2344
+ }
2345
+ }
2346
+ /**
2347
+ * Get the provider index that owns a specific category
2348
+ *
2349
+ * @returns Array with provider index, or null if ownership unknown (query all)
2350
+ */
2351
+ getProviderIndexForCategory(categoryId) {
2352
+ const ownerIndex = this.categoryOwnership.get(categoryId);
2353
+ if (ownerIndex !== undefined) {
2354
+ return [ownerIndex];
2355
+ }
2356
+ // Ownership unknown - will query all providers (fallback)
2357
+ return null;
2358
+ }
2359
+ /**
2360
+ * Load workflow definitions from providers and cache results
2361
+ *
2362
+ * Optimization: Only queries the provider that owns the category
2363
+ * Uses provider INDEX to match category provider with workflow provider
2364
+ */
2365
+ async loadWorkflowsFromProviders(categoryId) {
2366
+ try {
2367
+ const resolvedProviders = await Promise.allSettled(this.workflowProviders);
2368
+ const definitions = [];
2369
+ // ✅ Smart routing: Get provider INDEX that owns this category
2370
+ const ownerIndex = this.categoryOwnership.get(categoryId);
2371
+ const providerIndicesToQuery = ownerIndex !== undefined ? [ownerIndex] : null;
2372
+ for (let i = 0; i < resolvedProviders.length; i++) {
2373
+ const p = resolvedProviders[i];
2374
+ // Skip if we have a specific provider index and this isn't it
2375
+ if (providerIndicesToQuery !== null && !providerIndicesToQuery.includes(i)) {
2376
+ continue;
2377
+ }
2378
+ if (p.status === 'fulfilled' && p.value && typeof p.value.getList === 'function') {
2379
+ try {
2380
+ const defs = await p.value.getList(categoryId);
2381
+ if (Array.isArray(defs)) {
2382
+ definitions.push(...defs);
2383
+ }
2384
+ }
2385
+ catch {
2386
+ // Continue on error - try other providers
2387
+ }
2388
+ }
2389
+ }
2390
+ // ✅ Cache results for fast subsequent access
2391
+ this.workflowsByCategory.set(categoryId, definitions);
2392
+ definitions.forEach(def => {
2393
+ if (def.name) {
2394
+ this.workflowsByName.set(def.name, def);
2395
+ }
2396
+ });
2397
+ return definitions;
2398
+ }
2399
+ finally {
2400
+ this.pendingWorkflowsRequests.delete(categoryId);
2401
+ }
2402
+ }
2403
+ /**
2404
+ * Load single workflow definition from providers and cache result
2405
+ */
2406
+ async loadWorkflowFromProviders(name) {
2407
+ try {
2408
+ const resolvedProviders = await Promise.allSettled(this.workflowProviders);
2409
+ // Try providers first
2410
+ for (const p of resolvedProviders) {
2411
+ if (p.status === 'fulfilled' && p.value && typeof p.value.getByName === 'function') {
2412
+ try {
2413
+ const definition = await p.value.getByName(name);
2414
+ if (definition) {
2415
+ this.workflowsByName.set(name, definition);
2416
+ return definition;
2417
+ }
2418
+ }
2419
+ catch {
2420
+ // Continue on error
2421
+ }
2422
+ }
2423
+ }
2424
+ // Fallback: Search in cached workflow definitions
2425
+ for (const definitions of this.workflowsByCategory.values()) {
2426
+ const found = definitions.find(def => def.name === name);
2427
+ if (found) {
2428
+ this.workflowsByName.set(name, found);
2429
+ return found;
2430
+ }
2431
+ }
2432
+ return undefined;
2433
+ }
2434
+ finally {
2435
+ this.pendingWorkflowRequests.delete(name);
2436
+ }
2437
+ }
2438
+ /**
2439
+ * Breadth-first search through category hierarchy
2440
+ */
2441
+ async searchCategoryInHierarchy(categoryId) {
2442
+ const searchQueue = [undefined];
2443
+ const searched = new Set();
2444
+ while (searchQueue.length > 0) {
2445
+ const parentId = searchQueue.shift();
2446
+ if (searched.has(parentId))
2447
+ continue;
2448
+ searched.add(parentId);
2449
+ const categories = await this.getCategories(parentId);
2450
+ const found = categories.find(cat => cat.id === categoryId);
2451
+ if (found) {
2452
+ return found;
2453
+ }
2454
+ // ✅ Optimization: Only search children if childrenCount > 0
2455
+ for (const category of categories) {
2456
+ if (category.childrenCount > 0 && !searched.has(category.id)) {
2457
+ searchQueue.push(category.id);
2458
+ }
2459
+ }
2460
+ }
2461
+ return undefined;
2462
+ }
2463
+ //#endregion
2464
+ //#region ---- Cache Management ----
2465
+ /**
2466
+ * Check if category has children (uses cached count)
2467
+ */
2468
+ categoryHasChildren(categoryId) {
2469
+ const category = this.categoriesById.get(categoryId);
2470
+ return category ? category.childrenCount > 0 : false;
2471
+ }
2472
+ /**
2473
+ * Check if category has workflows (uses cached count)
2474
+ */
2475
+ categoryHasWorkflows(categoryId) {
2476
+ const category = this.categoriesById.get(categoryId);
2477
+ return category ? (category.itemsCount ?? 0) > 0 : false;
2478
+ }
2479
+ /**
2480
+ * Clear all caches
2481
+ */
2482
+ clearAllCache() {
2483
+ this.categoriesById.clear();
2484
+ this.categoriesByParentId.clear();
2485
+ this.workflowsByCategory.clear();
2486
+ this.workflowsByName.clear();
2487
+ this.categoryOwnership.clear();
2488
+ this.pendingCategoriesRequests.clear();
2489
+ this.pendingWorkflowsRequests.clear();
2490
+ this.pendingWorkflowRequests.clear();
2491
+ }
2492
+ /**
2493
+ * Clear categories cache only
2494
+ */
2495
+ clearCategoriesCache() {
2496
+ this.categoriesById.clear();
2497
+ this.categoriesByParentId.clear();
2498
+ this.categoryOwnership.clear();
2499
+ this.pendingCategoriesRequests.clear();
2500
+ }
2501
+ /**
2502
+ * Clear workflows cache only
2503
+ */
2504
+ clearWorkflowsCache() {
2505
+ this.workflowsByCategory.clear();
2506
+ this.workflowsByName.clear();
2507
+ this.pendingWorkflowsRequests.clear();
2508
+ this.pendingWorkflowRequests.clear();
2509
+ }
2510
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDefinitionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2511
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDefinitionService, providedIn: 'root' }); }
2512
+ }
2513
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDefinitionService, decorators: [{
2514
+ type: Injectable,
2515
+ args: [{
2516
+ providedIn: 'root',
2517
+ }]
2518
+ }] });
2519
+
2520
+ // Workflow Instance Types (Storage/Database)
2521
+
2522
+ class AXPWorkflowModule {
2523
+ static forRoot(config) {
2524
+ return {
2525
+ ngModule: AXPWorkflowModule,
2526
+ providers: [
2527
+ {
2528
+ provide: 'AXPWorkflowModuleFactory',
2529
+ useFactory: (registry) => () => {
2530
+ registry.registerAction('start-workflow', AXPStartWorkflowAction);
2531
+ registry.registerAction('decide', AXPWorkflowDecideAction);
2532
+ //
2533
+ if (config?.functions) {
2534
+ for (const [key, type] of Object.entries(config.functions)) {
2535
+ registry.registerFunction(key, type);
2536
+ }
2537
+ }
2538
+ //
2539
+ if (config?.actions) {
2540
+ for (const [key, type] of Object.entries(config.actions)) {
2541
+ registry.registerAction(key, type);
2542
+ }
2543
+ }
2544
+ //
2545
+ if (config?.workflows) {
2546
+ for (const [key, type] of Object.entries(config.workflows)) {
2547
+ registry.registerWorkflow(key, type);
2548
+ }
2549
+ }
2550
+ },
2551
+ deps: [AXPWorkflowRegistryService],
2552
+ multi: true,
2553
+ },
2554
+ ...Object.values(config?.actions ?? { AXPStartWorkflowAction }),
2555
+ ...Object.values(config?.functions ?? {}),
2556
+ ],
2557
+ };
2558
+ }
2559
+ static forChild(config) {
2560
+ return {
2561
+ ngModule: AXPWorkflowModule,
2562
+ providers: [
2563
+ // Built-in activities are already registered in forRoot via @NgModule providers
2564
+ // No need to register again in forChild
2565
+ {
2566
+ provide: 'AXPWorkflowModuleFactory',
2567
+ useFactory: (registry) => () => {
2568
+ registry.registerAction('start-workflow', AXPStartWorkflowAction);
2569
+ registry.registerAction('decide', AXPWorkflowDecideAction);
2570
+ //
2571
+ if (config?.functions) {
2572
+ for (const [key, type] of Object.entries(config.functions)) {
2573
+ registry.registerFunction(key, type);
2574
+ }
2575
+ }
2576
+ //
2577
+ if (config?.actions) {
2578
+ for (const [key, type] of Object.entries(config.actions)) {
2579
+ registry.registerAction(key, type);
2580
+ }
2581
+ }
2582
+ //
2583
+ if (config?.workflows) {
2584
+ for (const [key, type] of Object.entries(config.workflows)) {
2585
+ registry.registerWorkflow(key, type);
2586
+ }
2587
+ }
2588
+ },
2589
+ deps: [AXPWorkflowRegistryService],
2590
+ multi: true,
2591
+ },
2592
+ ...Object.values(config?.actions ?? {}),
2593
+ ...Object.values(config?.functions ?? {}),
2594
+ ],
2595
+ };
2596
+ }
2597
+ /**
2598
+ * @ignore
2599
+ */
2600
+ constructor(instances) {
2601
+ instances?.forEach((f) => {
2602
+ f();
2603
+ });
2604
+ }
2605
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule, deps: [{ token: 'AXPWorkflowModuleFactory', optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
2606
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule }); }
2607
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule, providers: [
2608
+ AXPWorkflowLocalEngine,
2609
+ {
2610
+ provide: AXP_WORKFLOW_ENGINE,
2611
+ useExisting: AXPWorkflowLocalEngine,
2612
+ },
2613
+ AXPWorkflowManager,
2614
+ ] }); }
2615
+ }
2616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule, decorators: [{
2617
+ type: NgModule,
2618
+ args: [{
2619
+ imports: [],
2620
+ exports: [],
2621
+ declarations: [],
2622
+ providers: [
2623
+ AXPWorkflowLocalEngine,
2624
+ {
2625
+ provide: AXP_WORKFLOW_ENGINE,
2626
+ useExisting: AXPWorkflowLocalEngine,
2627
+ },
2628
+ AXPWorkflowManager,
2629
+ ],
2630
+ }]
2631
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
2632
+ type: Optional
2633
+ }, {
2634
+ type: Inject,
2635
+ args: ['AXPWorkflowModuleFactory']
2636
+ }] }] });
1457
2637
 
1458
2638
  /**
1459
2639
  * Generated bundle index. Do not edit.
1460
2640
  */
1461
2641
 
1462
- export { AXPActivityDefinitionService, AXPWorkflowAction, AXPWorkflowContext, AXPWorkflowDefinitionRegistryService, AXPWorkflowDefinitionResolver, AXPWorkflowError, AXPWorkflowEventService, AXPWorkflowExecutionService, AXPWorkflowFunction, AXPWorkflowModule, AXPWorkflowRegistryService, AXPWorkflowService, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_DEFINITION_LOADER, WorkflowCoordinator, createWorkFlowEvent, ofType };
2642
+ export { AXPActivityDefinitionService, AXPWorkflowAction, AXPWorkflowContext, AXPWorkflowDefinitionService, AXPWorkflowEngineError, AXPWorkflowError, AXPWorkflowEventService, AXPWorkflowFunction, AXPWorkflowLocalEngine, AXPWorkflowManager, AXPWorkflowModule, AXPWorkflowRegistryService, AXPWorkflowService, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER, AXP_WORKFLOW_ENGINE, AXP_WORKFLOW_ERROR_CODES, AXP_WORKFLOW_PROVIDER, AXP_WORKFLOW_TASK_BOARD_ACTIVITY_TYPES, ActivityExecutor, WorkflowExpressionScopeService, axpIsWorkflowTaskBoardActivityType, createWorkFlowEvent, getWorkflowEngineErrorCode, getWorkflowEngineErrorInfo, ofType };
1463
2643
  //# sourceMappingURL=acorex-platform-workflow.mjs.map