@solidxai/core 0.1.13-beta.3 → 0.1.13-beta.5

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 (141) hide show
  1. package/dist/commands/seed.command.d.ts +2 -0
  2. package/dist/commands/seed.command.d.ts.map +1 -1
  3. package/dist/commands/seed.command.js +21 -0
  4. package/dist/commands/seed.command.js.map +1 -1
  5. package/dist/controllers/chatter-message.controller.d.ts +5 -0
  6. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  7. package/dist/controllers/chatter-message.controller.js +14 -0
  8. package/dist/controllers/chatter-message.controller.js.map +1 -1
  9. package/dist/entities/workflow-trigger-execution.entity.js +1 -1
  10. package/dist/entities/workflow-trigger-execution.entity.js.map +1 -1
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/interfaces.d.ts +1 -0
  16. package/dist/interfaces.d.ts.map +1 -1
  17. package/dist/interfaces.js.map +1 -1
  18. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  19. package/dist/seeders/module-metadata-seeder.service.js +44 -27
  20. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  21. package/dist/seeders/seed-data/solid-core-metadata.json +84 -70
  22. package/dist/services/chatter-message.service.d.ts +5 -0
  23. package/dist/services/chatter-message.service.d.ts.map +1 -1
  24. package/dist/services/chatter-message.service.js +18 -0
  25. package/dist/services/chatter-message.service.js.map +1 -1
  26. package/dist/services/workflow/nodes/execution-fail.node.d.ts +6 -0
  27. package/dist/services/workflow/nodes/execution-fail.node.d.ts.map +1 -0
  28. package/dist/services/workflow/nodes/execution-fail.node.js +81 -0
  29. package/dist/services/workflow/nodes/execution-fail.node.js.map +1 -0
  30. package/dist/services/workflow/nodes/for-each.node.d.ts +2 -0
  31. package/dist/services/workflow/nodes/for-each.node.d.ts.map +1 -1
  32. package/dist/services/workflow/nodes/for-each.node.js +114 -5
  33. package/dist/services/workflow/nodes/for-each.node.js.map +1 -1
  34. package/dist/services/workflow/nodes/if.node.d.ts.map +1 -1
  35. package/dist/services/workflow/nodes/if.node.js +7 -0
  36. package/dist/services/workflow/nodes/if.node.js.map +1 -1
  37. package/dist/services/workflow/nodes/log-write.node.d.ts.map +1 -1
  38. package/dist/services/workflow/nodes/log-write.node.js +2 -0
  39. package/dist/services/workflow/nodes/log-write.node.js.map +1 -1
  40. package/dist/services/workflow/nodes/loop-until.node.d.ts +12 -0
  41. package/dist/services/workflow/nodes/loop-until.node.d.ts.map +1 -0
  42. package/dist/services/workflow/nodes/loop-until.node.js +281 -0
  43. package/dist/services/workflow/nodes/loop-until.node.js.map +1 -0
  44. package/dist/services/workflow/nodes/parallel.node.d.ts.map +1 -1
  45. package/dist/services/workflow/nodes/parallel.node.js +7 -0
  46. package/dist/services/workflow/nodes/parallel.node.js.map +1 -1
  47. package/dist/services/workflow/nodes/sequential.node.d.ts.map +1 -1
  48. package/dist/services/workflow/nodes/sequential.node.js +7 -0
  49. package/dist/services/workflow/nodes/sequential.node.js.map +1 -1
  50. package/dist/services/workflow/nodes/switch.node.d.ts.map +1 -1
  51. package/dist/services/workflow/nodes/switch.node.js +7 -0
  52. package/dist/services/workflow/nodes/switch.node.js.map +1 -1
  53. package/dist/services/workflow/workflow-definition-validator.service.d.ts.map +1 -1
  54. package/dist/services/workflow/workflow-definition-validator.service.js +5 -2
  55. package/dist/services/workflow/workflow-definition-validator.service.js.map +1 -1
  56. package/dist/services/workflow/workflow-expression.service.d.ts.map +1 -1
  57. package/dist/services/workflow/workflow-expression.service.js +5 -0
  58. package/dist/services/workflow/workflow-expression.service.js.map +1 -1
  59. package/dist/services/workflow/workflow-node-registry.service.d.ts +2 -1
  60. package/dist/services/workflow/workflow-node-registry.service.d.ts.map +1 -1
  61. package/dist/services/workflow/workflow-node-registry.service.js +7 -0
  62. package/dist/services/workflow/workflow-node-registry.service.js.map +1 -1
  63. package/dist/services/workflow/workflow-runtime.service.d.ts +8 -0
  64. package/dist/services/workflow/workflow-runtime.service.d.ts.map +1 -1
  65. package/dist/services/workflow/workflow-runtime.service.js +197 -32
  66. package/dist/services/workflow/workflow-runtime.service.js.map +1 -1
  67. package/dist/solid-core.module.d.ts.map +1 -1
  68. package/dist/solid-core.module.js +4 -0
  69. package/dist/solid-core.module.js.map +1 -1
  70. package/dist/types/workflow-dsl.types.d.ts +14 -0
  71. package/dist/types/workflow-dsl.types.d.ts.map +1 -1
  72. package/dist/types/workflow-dsl.types.js.map +1 -1
  73. package/dist-tests/api/authenticate.spec.js +119 -0
  74. package/dist-tests/api/authenticate.spec.js.map +1 -0
  75. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
  76. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
  77. package/dist-tests/api/ping.spec.js +21 -0
  78. package/dist-tests/api/ping.spec.js.map +1 -0
  79. package/dist-tests/helpers/auth.js +41 -0
  80. package/dist-tests/helpers/auth.js.map +1 -0
  81. package/dist-tests/helpers/env.js +11 -0
  82. package/dist-tests/helpers/env.js.map +1 -0
  83. package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +136 -0
  84. package/docs/agent-builder/team-ready-note-agent-builder.md +305 -0
  85. package/docs/agent-hub-grooming.md +301 -0
  86. package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
  87. package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
  88. package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
  89. package/docs/datasource-introspection-ddl-analysis.md +326 -0
  90. package/docs/datasource-introspection-implementation-plan.md +306 -0
  91. package/docs/grouping-enhancements.md +89 -0
  92. package/docs/java-spring/README.md +3 -0
  93. package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
  94. package/docs/module-package-import-handoff.md +691 -0
  95. package/docs/seed-changes.md +65 -0
  96. package/docs/test-data-workflow.md +200 -0
  97. package/docs/type-declaration-import-issue.md +24 -0
  98. package/docs/workflow/business-automation-example-notes.md +309 -0
  99. package/docs/workflow/control-flow-node-addition-sop.md +324 -0
  100. package/docs/workflow/data-engineering-pipeline-example-notes.md +330 -0
  101. package/docs/workflow/foreach-example-notes.md +187 -0
  102. package/docs/workflow/hello-world-example-notes.md +271 -0
  103. package/docs/workflow/kestra-concepts-plugins-blueprints.md +315 -0
  104. package/docs/workflow/loop-until-example-notes.md +198 -0
  105. package/docs/workflow/microservices-and-apis-example-notes.md +264 -0
  106. package/docs/workflow/samples.md +25 -0
  107. package/docs/workflow/what-is-kestra.md +79 -0
  108. package/docs/workflow/workflow-core-module-handoff-summary.md +191 -0
  109. package/docs/workflow/workflow-module-brd.md +185 -0
  110. package/docs/workflow/workflow-module-domain-model.md +252 -0
  111. package/docs/workflow/workflow-module-metadata-dsl.md +302 -0
  112. package/docs/workflow/workflow-module-technical-spec.md +293 -0
  113. package/docs/workflow/workflow-node-type-contracts.md +635 -0
  114. package/docs/workflow/workflow-node-ui-metadata-contract.md +1262 -0
  115. package/docs/workflow/workflow-solidx-model-field-spec.md +284 -0
  116. package/package.json +1 -1
  117. package/src/commands/seed.command.ts +19 -0
  118. package/src/controllers/chatter-message.controller.ts +8 -0
  119. package/src/entities/workflow-trigger-execution.entity.ts +1 -1
  120. package/src/index.ts +2 -0
  121. package/src/interfaces.ts +1 -0
  122. package/src/seeders/module-metadata-seeder.service.ts +50 -36
  123. package/src/seeders/seed-data/solid-core-metadata.json +84 -70
  124. package/src/services/chatter-message.service.ts +26 -0
  125. package/src/services/workflow/nodes/execution-fail.node.ts +82 -0
  126. package/src/services/workflow/nodes/for-each.node.ts +140 -6
  127. package/src/services/workflow/nodes/if.node.ts +7 -0
  128. package/src/services/workflow/nodes/log-write.node.ts +2 -0
  129. package/src/services/workflow/nodes/loop-until.node.ts +343 -0
  130. package/src/services/workflow/nodes/parallel.node.ts +7 -0
  131. package/src/services/workflow/nodes/sequential.node.ts +7 -0
  132. package/src/services/workflow/nodes/switch.node.ts +7 -0
  133. package/src/services/workflow/workflow-definition-validator.service.ts +5 -2
  134. package/src/services/workflow/workflow-expression.service.ts +5 -0
  135. package/src/services/workflow/workflow-node-registry.service.ts +11 -0
  136. package/src/services/workflow/workflow-runtime.service.ts +274 -39
  137. package/src/solid-core.module.ts +4 -0
  138. package/src/types/workflow-dsl.types.ts +43 -0
  139. package/.claude/settings.local.json +0 -16
  140. package/CLAUDE.md +0 -26
  141. package/src/services/1.js +0 -6
@@ -13,27 +13,101 @@ let ForEachNode = class ForEachNode {
13
13
  async execute(context) {
14
14
  const configuration = context.node.configuration ?? {};
15
15
  const items = context.expression.interpolate(configuration.items ?? [], context);
16
+ const concurrencyLimit = this.resolveConcurrencyLimit(context.expression.interpolate(configuration.concurrencyLimit ?? 1, context));
17
+ const aggregateOutputs = Boolean(context.expression.interpolate(configuration.aggregateOutputs ?? false, context));
16
18
  if (!Array.isArray(items)) {
17
19
  throw new common_1.BadRequestException('forEach requires configuration.items array.');
18
20
  }
19
21
  const childNodes = context.node.tasks ?? [];
20
- for (let index = 0; index < items.length; index++) {
22
+ const iterationsByIndex = {};
23
+ const iterationsByKey = {};
24
+ const shouldAggregateByKey = aggregateOutputs && configuration.outputKey !== undefined && configuration.outputKey !== null;
25
+ await this.runIterations(items, concurrencyLimit, async (item, index) => {
21
26
  const inheritedOutputs = context.outputs ?? {};
22
27
  const iterationOutputs = { ...inheritedOutputs };
23
- await context.runNodes(childNodes, {
24
- item: items[index],
28
+ const parentLoops = context.loops ?? [];
29
+ const currentLoop = {
30
+ item,
25
31
  index,
32
+ nodeId: context.node.id,
33
+ stepExecutionKey: context.stepExecution.stepExecutionKey,
34
+ };
35
+ const loopContext = {
36
+ item,
37
+ index,
38
+ parent: parentLoops[parentLoops.length - 1],
39
+ parents: [...parentLoops].reverse(),
40
+ loops: [...parentLoops, currentLoop],
41
+ };
42
+ const outputKey = shouldAggregateByKey
43
+ ? String(context.expression.interpolate(configuration.outputKey, {
44
+ ...context,
45
+ ...loopContext,
46
+ outputs: iterationOutputs,
47
+ }))
48
+ : undefined;
49
+ const childOutputs = await context.runNodes(childNodes, {
50
+ ...loopContext,
26
51
  outputs: iterationOutputs,
27
52
  });
28
- }
53
+ if (aggregateOutputs) {
54
+ const iterationResult = {
55
+ item,
56
+ index,
57
+ outputs: childOutputs,
58
+ };
59
+ iterationsByIndex[index] = iterationResult;
60
+ if (outputKey !== undefined) {
61
+ iterationsByKey[outputKey] = iterationResult;
62
+ }
63
+ }
64
+ });
29
65
  return {
30
66
  output: {
31
67
  count: items.length,
32
68
  childNodeIds: childNodes.map((childNode) => childNode.id),
33
- iterationOutputsStoredOnSteps: true,
69
+ concurrencyLimit,
70
+ iterationOutputsStoredOnSteps: !aggregateOutputs,
71
+ ...(aggregateOutputs
72
+ ? {
73
+ iterations: {
74
+ byIndex: iterationsByIndex,
75
+ ...(shouldAggregateByKey
76
+ ? {
77
+ byKey: iterationsByKey,
78
+ }
79
+ : {}),
80
+ },
81
+ }
82
+ : {}),
34
83
  },
35
84
  };
36
85
  }
86
+ resolveConcurrencyLimit(value) {
87
+ const parsed = Number(value === '' || value === null || value === undefined ? 1 : value);
88
+ if (!Number.isFinite(parsed) || parsed < 0) {
89
+ throw new common_1.BadRequestException('forEach configuration.concurrencyLimit must be 0 or a positive number.');
90
+ }
91
+ return Math.floor(parsed);
92
+ }
93
+ async runIterations(items, concurrencyLimit, handler) {
94
+ if (concurrencyLimit === 1 || items.length <= 1) {
95
+ for (let index = 0; index < items.length; index++) {
96
+ await handler(items[index], index);
97
+ }
98
+ return;
99
+ }
100
+ const limit = concurrencyLimit === 0 ? items.length : concurrencyLimit;
101
+ let nextIndex = 0;
102
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
103
+ while (nextIndex < items.length) {
104
+ const index = nextIndex;
105
+ nextIndex += 1;
106
+ await handler(items[index], index);
107
+ }
108
+ });
109
+ await Promise.all(workers);
110
+ }
37
111
  };
38
112
  exports.ForEachNode = ForEachNode;
39
113
  exports.ForEachNode = ForEachNode = __decorate([
@@ -47,6 +121,8 @@ exports.ForEachNode = ForEachNode = __decorate([
47
121
  authoring: {
48
122
  defaultConfiguration: {
49
123
  items: '',
124
+ concurrencyLimit: 1,
125
+ aggregateOutputs: false,
50
126
  },
51
127
  configurationFields: [
52
128
  {
@@ -63,6 +139,32 @@ exports.ForEachNode = ForEachNode = __decorate([
63
139
  },
64
140
  },
65
141
  },
142
+ {
143
+ key: 'concurrencyLimit',
144
+ label: 'Concurrency Limit',
145
+ description: 'Maximum number of loop iterations to run at once. Use 1 for sequential execution and 0 for unlimited concurrency.',
146
+ valueType: 'number',
147
+ defaultValue: 1,
148
+ expressionAllowed: true,
149
+ group: 'General',
150
+ },
151
+ {
152
+ key: 'aggregateOutputs',
153
+ label: 'Aggregate Outputs',
154
+ description: 'Adds per-iteration child outputs to this forEach node output for downstream expressions.',
155
+ valueType: 'boolean',
156
+ defaultValue: false,
157
+ expressionAllowed: true,
158
+ group: 'General',
159
+ },
160
+ {
161
+ key: 'outputKey',
162
+ label: 'Output Key',
163
+ description: 'Optional expression used as the per-iteration key when aggregate outputs is enabled.',
164
+ valueType: 'string',
165
+ expressionAllowed: true,
166
+ group: 'General',
167
+ },
66
168
  ],
67
169
  childSlots: [
68
170
  {
@@ -73,6 +175,13 @@ exports.ForEachNode = ForEachNode = __decorate([
73
175
  layout: 'sequential',
74
176
  required: true,
75
177
  },
178
+ {
179
+ key: 'errors',
180
+ label: 'Errors',
181
+ description: 'Nodes that run sequentially if this loop fails.',
182
+ kind: 'sequence',
183
+ layout: 'sequential',
184
+ },
76
185
  ],
77
186
  supportsDescription: true,
78
187
  supportsName: true,
@@ -1 +1 @@
1
- {"version":3,"file":"for-each.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/for-each.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAqD;AACrD,2GAA4F;AA6DrF,IAAM,WAAW,GAAjB,MAAM,WAAW;IACtB,KAAK,CAAC,OAAO,CACX,OAAqC;QAErC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAEjF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,4BAAmB,CAAC,6CAA6C,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAE5C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YAClD,MAAM,gBAAgB,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;YAC/C,MAAM,gBAAgB,GAAG,EAAE,GAAG,gBAAgB,EAAE,CAAC;YAEjD,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE;gBACjC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC;gBAClB,KAAK;gBACL,OAAO,EAAE,gBAAgB;aAC1B,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,MAAM,EAAE;gBACN,KAAK,EAAE,KAAK,CAAC,MAAM;gBACnB,YAAY,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;gBAGzD,6BAA6B,EAAE,IAAI;aACpC;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAlCY,kCAAW;sBAAX,WAAW;IAtDvB,IAAA,uDAAoB,EAAC;QACpB,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,cAAc;QACxB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,mDAAmD;QAChE,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;QAC3B,SAAS,EAAE;YACT,oBAAoB,EAAE;gBACpB,KAAK,EAAE,EAAE;aACV;YACD,mBAAmB,EAAE;gBACnB;oBACE,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,OAAO;oBACd,WAAW,EAAE,4DAA4D;oBACzE,SAAS,EAAE,QAAQ;oBACnB,QAAQ,EAAE,IAAI;oBACd,iBAAiB,EAAE,IAAI;oBACvB,KAAK,EAAE,SAAS;oBAChB,QAAQ,EAAE;wBACR,MAAM,EAAE;4BACN,KAAK,EAAE,MAAM;yBACd;qBACF;iBACF;aACF;YACD,UAAU,EAAE;gBACV;oBACE,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,WAAW;oBAClB,WAAW,EAAE,oCAAoC;oBACjD,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,YAAY;oBACpB,QAAQ,EAAE,IAAI;iBACf;aACF;YACD,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,IAAI;SACnB;QACD,aAAa,EAAE;YACb,OAAO,EAAE,mEAAmE;SAC7E;QACD,EAAE,EAAE;YACF,IAAI,EAAE,YAAY;YAClB,SAAS,EAAE,SAAS;YACpB,mBAAmB,EAAE,SAAS;YAC9B,eAAe,EAAE,SAAS;YAC1B,SAAS,EAAE,IAAI;YACf,WAAW,EAAE;gBACX,UAAU,EAAE,CAAC,SAAS,CAAC;aACxB;SACF;KACF,CAAC;GACW,WAAW,CAkCvB","sourcesContent":["import { BadRequestException } from '@nestjs/common';\nimport { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'forEach',\n kind: 'control',\n category: 'control-flow',\n label: 'For Each',\n description: 'Runs child nodes once for every item in an array.',\n tags: ['loop', 'iteration'],\n authoring: {\n defaultConfiguration: {\n items: '',\n },\n configurationFields: [\n {\n key: 'items',\n label: 'Items',\n description: 'Array or expression resolving to an array to iterate over.',\n valueType: 'string',\n required: true,\n expressionAllowed: true,\n group: 'General',\n uiSchema: {\n layout: {\n width: 'full',\n },\n },\n },\n ],\n childSlots: [\n {\n key: 'tasks',\n label: 'Loop Body',\n description: 'Nodes that run once for each item.',\n kind: 'sequence',\n layout: 'sequential',\n required: true,\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary: 'Iterates over an array and runs the loop body once for each item.',\n },\n ui: {\n icon: 'si-refresh',\n iconColor: '#7c3aed',\n iconBackgroundColor: '#f3e8ff',\n iconBorderColor: '#d8b4fe',\n modalSize: 'lg',\n layoutHints: {\n groupOrder: ['General'],\n },\n },\n})\nexport class ForEachNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.node.configuration ?? {};\n const items = context.expression.interpolate(configuration.items ?? [], context);\n\n if (!Array.isArray(items)) {\n throw new BadRequestException('forEach requires configuration.items array.');\n }\n\n const childNodes = context.node.tasks ?? [];\n\n for (let index = 0; index < items.length; index++) {\n const inheritedOutputs = context.outputs ?? {};\n const iterationOutputs = { ...inheritedOutputs };\n\n await context.runNodes(childNodes, {\n item: items[index],\n index,\n outputs: iterationOutputs,\n });\n }\n\n return {\n output: {\n count: items.length,\n childNodeIds: childNodes.map((childNode) => childNode.id),\n // Keep the control-node output intentionally small. Per-iteration\n // outputs are already stored on the child workflowStepExecution rows.\n iterationOutputsStoredOnSteps: true,\n },\n };\n }\n}\n"]}
1
+ {"version":3,"file":"for-each.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/for-each.node.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException } from '@nestjs/common';\nimport { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'forEach',\n kind: 'control',\n category: 'control-flow',\n label: 'For Each',\n description: 'Runs child nodes once for every item in an array.',\n tags: ['loop', 'iteration'],\n authoring: {\n defaultConfiguration: {\n items: '',\n concurrencyLimit: 1,\n aggregateOutputs: false,\n },\n configurationFields: [\n {\n key: 'items',\n label: 'Items',\n description: 'Array or expression resolving to an array to iterate over.',\n valueType: 'string',\n required: true,\n expressionAllowed: true,\n group: 'General',\n uiSchema: {\n layout: {\n width: 'full',\n },\n },\n },\n {\n key: 'concurrencyLimit',\n label: 'Concurrency Limit',\n description:\n 'Maximum number of loop iterations to run at once. Use 1 for sequential execution and 0 for unlimited concurrency.',\n valueType: 'number',\n defaultValue: 1,\n expressionAllowed: true,\n group: 'General',\n },\n {\n key: 'aggregateOutputs',\n label: 'Aggregate Outputs',\n description:\n 'Adds per-iteration child outputs to this forEach node output for downstream expressions.',\n valueType: 'boolean',\n defaultValue: false,\n expressionAllowed: true,\n group: 'General',\n },\n {\n key: 'outputKey',\n label: 'Output Key',\n description:\n 'Optional expression used as the per-iteration key when aggregate outputs is enabled.',\n valueType: 'string',\n expressionAllowed: true,\n group: 'General',\n },\n ],\n childSlots: [\n {\n key: 'tasks',\n label: 'Loop Body',\n description: 'Nodes that run once for each item.',\n kind: 'sequence',\n layout: 'sequential',\n required: true,\n },\n {\n key: 'errors',\n label: 'Errors',\n description: 'Nodes that run sequentially if this loop fails.',\n kind: 'sequence',\n layout: 'sequential',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary: 'Iterates over an array and runs the loop body once for each item.',\n },\n ui: {\n icon: 'si-refresh',\n iconColor: '#7c3aed',\n iconBackgroundColor: '#f3e8ff',\n iconBorderColor: '#d8b4fe',\n modalSize: 'lg',\n layoutHints: {\n groupOrder: ['General'],\n },\n },\n})\nexport class ForEachNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.node.configuration ?? {};\n const items = context.expression.interpolate(configuration.items ?? [], context);\n const concurrencyLimit = this.resolveConcurrencyLimit(\n context.expression.interpolate(configuration.concurrencyLimit ?? 1, context),\n );\n const aggregateOutputs = Boolean(\n context.expression.interpolate(configuration.aggregateOutputs ?? false, context),\n );\n\n if (!Array.isArray(items)) {\n throw new BadRequestException('forEach requires configuration.items array.');\n }\n\n const childNodes = context.node.tasks ?? [];\n const iterationsByIndex: Record<number, any> = {};\n const iterationsByKey: Record<string, any> = {};\n const shouldAggregateByKey =\n aggregateOutputs && configuration.outputKey !== undefined && configuration.outputKey !== null;\n\n await this.runIterations(items, concurrencyLimit, async (item, index) => {\n const inheritedOutputs = context.outputs ?? {};\n const iterationOutputs = { ...inheritedOutputs };\n const parentLoops = context.loops ?? [];\n const currentLoop = {\n item,\n index,\n nodeId: context.node.id,\n stepExecutionKey: context.stepExecution.stepExecutionKey,\n };\n const loopContext = {\n item,\n index,\n parent: parentLoops[parentLoops.length - 1],\n parents: [...parentLoops].reverse(),\n loops: [...parentLoops, currentLoop],\n };\n const outputKey = shouldAggregateByKey\n ? String(context.expression.interpolate(configuration.outputKey, {\n ...context,\n ...loopContext,\n outputs: iterationOutputs,\n }))\n : undefined;\n\n const childOutputs = await context.runNodes(childNodes, {\n ...loopContext,\n outputs: iterationOutputs,\n });\n\n if (aggregateOutputs) {\n const iterationResult = {\n item,\n index,\n outputs: childOutputs,\n };\n\n iterationsByIndex[index] = iterationResult;\n if (outputKey !== undefined) {\n iterationsByKey[outputKey] = iterationResult;\n }\n }\n });\n\n return {\n output: {\n count: items.length,\n childNodeIds: childNodes.map((childNode) => childNode.id),\n concurrencyLimit,\n // Keep the control-node output intentionally small. Per-iteration\n // outputs are already stored on the child workflowStepExecution rows.\n iterationOutputsStoredOnSteps: !aggregateOutputs,\n ...(aggregateOutputs\n ? {\n iterations: {\n byIndex: iterationsByIndex,\n ...(shouldAggregateByKey\n ? {\n byKey: iterationsByKey,\n }\n : {}),\n },\n }\n : {}),\n },\n };\n }\n\n private resolveConcurrencyLimit(value: any): number {\n const parsed = Number(value === '' || value === null || value === undefined ? 1 : value);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new BadRequestException(\n 'forEach configuration.concurrencyLimit must be 0 or a positive number.',\n );\n }\n\n return Math.floor(parsed);\n }\n\n private async runIterations<T>(\n items: T[],\n concurrencyLimit: number,\n handler: (item: T, index: number) => Promise<void>,\n ): Promise<void> {\n if (concurrencyLimit === 1 || items.length <= 1) {\n for (let index = 0; index < items.length; index++) {\n await handler(items[index], index);\n }\n return;\n }\n\n const limit = concurrencyLimit === 0 ? items.length : concurrencyLimit;\n let nextIndex = 0;\n\n const workers = Array.from(\n { length: Math.min(limit, items.length) },\n async () => {\n while (nextIndex < items.length) {\n const index = nextIndex;\n nextIndex += 1;\n await handler(items[index], index);\n }\n },\n );\n\n await Promise.all(workers);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"if.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/if.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBAwDa,MAAO,YAAW,mBAAmB;IAC1C,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CA0BtC"}
1
+ {"version":3,"file":"if.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/if.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBA+Da,MAAO,YAAW,mBAAmB;IAC1C,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CA0BtC"}
@@ -71,6 +71,13 @@ exports.IfNode = IfNode = __decorate([
71
71
  description: 'Nodes that run when the condition evaluates to false.',
72
72
  kind: 'sequence',
73
73
  },
74
+ {
75
+ key: 'errors',
76
+ label: 'Errors',
77
+ description: 'Nodes that run sequentially if the selected branch fails.',
78
+ kind: 'sequence',
79
+ layout: 'sequential',
80
+ },
74
81
  ],
75
82
  supportsDescription: true,
76
83
  supportsName: true,
@@ -1 +1 @@
1
- {"version":3,"file":"if.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/if.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;AA+DrF,IAAM,MAAM,GAAZ,MAAM,MAAM;IACjB,KAAK,CAAC,OAAO,CACX,OAAqC;QAErC,MAAM,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS;YACrC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzE,MAAM,aAAa,GAAG,OAAO;YAC3B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE;YACzB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAE5B,MAAM,OAAO,CAAC,OAAO,CAAC;YACpB,KAAK,EAAE,MAAM;YACb,SAAS,EAAE,mBAAmB;YAC9B,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,YAAY,OAAO,CAAC,IAAI,CAAC,EAAE,kBAAkB,OAAO,GAAG;YAChE,OAAO,EAAE,EAAE,SAAS,EAAE;SACvB,CAAC,CAAC;QAEH,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAEtC,OAAO;YACL,MAAM,EAAE;gBACN,OAAO;gBACP,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;aAClC;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA7BY,wBAAM;iBAAN,MAAM;IAxDlB,IAAA,uDAAoB,EAAC;QACpB,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,cAAc;QACxB,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,8DAA8D;QAC3E,IAAI,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;QAChC,SAAS,EAAE;YACT,oBAAoB,EAAE;gBACpB,SAAS,EAAE,qCAAqC;aACjD;YACD,mBAAmB,EAAE;gBACnB;oBACE,GAAG,EAAE,WAAW;oBAChB,KAAK,EAAE,WAAW;oBAClB,WAAW,EAAE,iEAAiE;oBAC9E,SAAS,EAAE,YAAY;oBACvB,QAAQ,EAAE,IAAI;oBACd,iBAAiB,EAAE,IAAI;oBACvB,UAAU,EAAE,UAAU;oBACtB,KAAK,EAAE,SAAS;iBACjB;aACF;YACD,UAAU,EAAE;gBACV;oBACE,GAAG,EAAE,MAAM;oBACX,KAAK,EAAE,MAAM;oBACb,WAAW,EAAE,sDAAsD;oBACnE,IAAI,EAAE,UAAU;oBAChB,QAAQ,EAAE,IAAI;iBACf;gBACD;oBACE,GAAG,EAAE,MAAM;oBACX,KAAK,EAAE,MAAM;oBACb,WAAW,EAAE,uDAAuD;oBACpE,IAAI,EAAE,UAAU;iBACjB;aACF;YACD,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,IAAI;SACnB;QACD,aAAa,EAAE;YACb,OAAO,EACL,6OAA6O;SAChP;QACD,EAAE,EAAE;YACF,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,SAAS;YACpB,mBAAmB,EAAE,SAAS;YAC9B,eAAe,EAAE,SAAS;YAC1B,SAAS,EAAE,IAAI;YACf,WAAW,EAAE;gBACX,UAAU,EAAE,CAAC,SAAS,CAAC;aACxB;SACF;KACF,CAAC;GACW,MAAM,CA6BlB","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'if',\n kind: 'control',\n category: 'control-flow',\n label: 'If',\n description: 'Runs then or else child nodes based on a boolean expression.',\n tags: ['branching', 'condition'],\n authoring: {\n defaultConfiguration: {\n condition: '{{ input.shouldContinue === true }}',\n },\n configurationFields: [\n {\n key: 'condition',\n label: 'Condition',\n description: 'Boolean expression evaluated by the workflow expression engine.',\n valueType: 'expression',\n required: true,\n expressionAllowed: true,\n widgetHint: 'textarea',\n group: 'General',\n },\n ],\n childSlots: [\n {\n key: 'then',\n label: 'Then',\n description: 'Nodes that run when the condition evaluates to true.',\n kind: 'sequence',\n required: true,\n },\n {\n key: 'else',\n label: 'Else',\n description: 'Nodes that run when the condition evaluates to false.',\n kind: 'sequence',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary:\n 'Conditionally branches workflow execution into then or else node sequences. The node evaluates a boolean expression and executes either the then or else child sequence. Sequence order inside each branch remains implicit by array order.',\n },\n ui: {\n icon: 'si-code',\n iconColor: '#4f46e5',\n iconBackgroundColor: '#eef2ff',\n iconBorderColor: '#c7d2fe',\n modalSize: 'lg',\n layoutHints: {\n groupOrder: ['General'],\n },\n },\n})\nexport class IfNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const condition =\n context.node.configuration?.condition ??\n context.node.configuration?.expression;\n const matched = context.expression.evaluateCondition(condition, context);\n const selectedNodes = matched\n ? context.node.then ?? []\n : context.node.else ?? [];\n\n await context.emitLog({\n level: 'info',\n eventType: 'node.if.evaluated',\n source: 'if',\n message: `If node \"${context.node.id}\" evaluated to ${matched}.`,\n context: { condition },\n });\n\n await context.runNodes(selectedNodes);\n\n return {\n output: {\n matched,\n branch: matched ? 'then' : 'else',\n },\n };\n }\n}\n"]}
1
+ {"version":3,"file":"if.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/if.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;AAsErF,IAAM,MAAM,GAAZ,MAAM,MAAM;IACjB,KAAK,CAAC,OAAO,CACX,OAAqC;QAErC,MAAM,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS;YACrC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzE,MAAM,aAAa,GAAG,OAAO;YAC3B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE;YACzB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAE5B,MAAM,OAAO,CAAC,OAAO,CAAC;YACpB,KAAK,EAAE,MAAM;YACb,SAAS,EAAE,mBAAmB;YAC9B,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,YAAY,OAAO,CAAC,IAAI,CAAC,EAAE,kBAAkB,OAAO,GAAG;YAChE,OAAO,EAAE,EAAE,SAAS,EAAE;SACvB,CAAC,CAAC;QAEH,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAEtC,OAAO;YACL,MAAM,EAAE;gBACN,OAAO;gBACP,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;aAClC;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA7BY,wBAAM;iBAAN,MAAM;IA/DlB,IAAA,uDAAoB,EAAC;QACpB,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,cAAc;QACxB,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,8DAA8D;QAC3E,IAAI,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;QAChC,SAAS,EAAE;YACT,oBAAoB,EAAE;gBACpB,SAAS,EAAE,qCAAqC;aACjD;YACD,mBAAmB,EAAE;gBACnB;oBACE,GAAG,EAAE,WAAW;oBAChB,KAAK,EAAE,WAAW;oBAClB,WAAW,EAAE,iEAAiE;oBAC9E,SAAS,EAAE,YAAY;oBACvB,QAAQ,EAAE,IAAI;oBACd,iBAAiB,EAAE,IAAI;oBACvB,UAAU,EAAE,UAAU;oBACtB,KAAK,EAAE,SAAS;iBACjB;aACF;YACD,UAAU,EAAE;gBACV;oBACE,GAAG,EAAE,MAAM;oBACX,KAAK,EAAE,MAAM;oBACb,WAAW,EAAE,sDAAsD;oBACnE,IAAI,EAAE,UAAU;oBAChB,QAAQ,EAAE,IAAI;iBACf;gBACD;oBACE,GAAG,EAAE,MAAM;oBACX,KAAK,EAAE,MAAM;oBACb,WAAW,EAAE,uDAAuD;oBACpE,IAAI,EAAE,UAAU;iBACjB;gBACD;oBACE,GAAG,EAAE,QAAQ;oBACb,KAAK,EAAE,QAAQ;oBACf,WAAW,EAAE,2DAA2D;oBACxE,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,YAAY;iBACrB;aACF;YACD,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,IAAI;SACnB;QACD,aAAa,EAAE;YACb,OAAO,EACL,6OAA6O;SAChP;QACD,EAAE,EAAE;YACF,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,SAAS;YACpB,mBAAmB,EAAE,SAAS;YAC9B,eAAe,EAAE,SAAS;YAC1B,SAAS,EAAE,IAAI;YACf,WAAW,EAAE;gBACX,UAAU,EAAE,CAAC,SAAS,CAAC;aACxB;SACF;KACF,CAAC;GACW,MAAM,CA6BlB","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'if',\n kind: 'control',\n category: 'control-flow',\n label: 'If',\n description: 'Runs then or else child nodes based on a boolean expression.',\n tags: ['branching', 'condition'],\n authoring: {\n defaultConfiguration: {\n condition: '{{ input.shouldContinue === true }}',\n },\n configurationFields: [\n {\n key: 'condition',\n label: 'Condition',\n description: 'Boolean expression evaluated by the workflow expression engine.',\n valueType: 'expression',\n required: true,\n expressionAllowed: true,\n widgetHint: 'textarea',\n group: 'General',\n },\n ],\n childSlots: [\n {\n key: 'then',\n label: 'Then',\n description: 'Nodes that run when the condition evaluates to true.',\n kind: 'sequence',\n required: true,\n },\n {\n key: 'else',\n label: 'Else',\n description: 'Nodes that run when the condition evaluates to false.',\n kind: 'sequence',\n },\n {\n key: 'errors',\n label: 'Errors',\n description: 'Nodes that run sequentially if the selected branch fails.',\n kind: 'sequence',\n layout: 'sequential',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary:\n 'Conditionally branches workflow execution into then or else node sequences. The node evaluates a boolean expression and executes either the then or else child sequence. Sequence order inside each branch remains implicit by array order.',\n },\n ui: {\n icon: 'si-code',\n iconColor: '#4f46e5',\n iconBackgroundColor: '#eef2ff',\n iconBorderColor: '#c7d2fe',\n modalSize: 'lg',\n layoutHints: {\n groupOrder: ['General'],\n },\n },\n})\nexport class IfNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const condition =\n context.node.configuration?.condition ??\n context.node.configuration?.expression;\n const matched = context.expression.evaluateCondition(condition, context);\n const selectedNodes = matched\n ? context.node.then ?? []\n : context.node.else ?? [];\n\n await context.emitLog({\n level: 'info',\n eventType: 'node.if.evaluated',\n source: 'if',\n message: `If node \"${context.node.id}\" evaluated to ${matched}.`,\n context: { condition },\n });\n\n await context.runNodes(selectedNodes);\n\n return {\n output: {\n matched,\n branch: matched ? 'then' : 'else',\n },\n };\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"log-write.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/log-write.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBAqMa,YAAa,YAAW,mBAAmB;IAChD,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CAwBtC"}
1
+ {"version":3,"file":"log-write.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/log-write.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBAuMa,YAAa,YAAW,mBAAmB;IAChD,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CAwBtC"}
@@ -186,6 +186,7 @@ exports.LogWriteNode = LogWriteNode = __decorate([
186
186
  description: 'The resolved log level.',
187
187
  valueType: 'string',
188
188
  path: 'level',
189
+ includeInRuntimeContext: false,
189
190
  },
190
191
  {
191
192
  key: 'message',
@@ -193,6 +194,7 @@ exports.LogWriteNode = LogWriteNode = __decorate([
193
194
  description: 'The rendered log message.',
194
195
  valueType: 'string',
195
196
  path: 'message',
197
+ includeInRuntimeContext: false,
196
198
  },
197
199
  ],
198
200
  supportsExpressions: true,
@@ -1 +1 @@
1
- {"version":3,"file":"log-write.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/log-write.node.ts"],"names":[],"mappings":"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","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'log.write',\n kind: 'task',\n version: '1.0.0',\n category: 'core',\n subcategory: 'observability',\n label: 'Write Log',\n description: 'Writes an execution log entry and returns the rendered message.',\n tags: ['log', 'debug', 'observability'],\n aliases: ['log'],\n configSchema: {\n type: 'object',\n required: ['message'],\n properties: {\n level: {\n type: 'string',\n enum: ['debug', 'info', 'warn', 'error'],\n default: 'info',\n },\n message: {\n type: 'string',\n },\n context: {\n type: 'object',\n default: {},\n },\n metadata: {\n type: 'object',\n default: {},\n },\n },\n },\n uiSchema: {\n 'ui:order': ['level', 'message', 'context', 'metadata'],\n },\n outputSchema: {\n type: 'object',\n properties: {\n level: { type: 'string' },\n message: { type: 'string' },\n },\n },\n examples: [\n {\n key: 'simple-message',\n label: 'Simple log message',\n description: 'Write a simple interpolated log line.',\n language: 'yaml',\n snippet:\n 'message: \"Hello {{ input.name }}\"\\nlevel: info\\n',\n configurationOnly: true,\n },\n ],\n metrics: [\n {\n key: 'workflow.node.log.count',\n label: 'Log writes',\n description: 'Counts how many times the log node executes.',\n type: 'counter',\n tags: ['log', 'workflow'],\n },\n ],\n definitions: [\n {\n key: 'log-levels',\n label: 'Supported log levels',\n content:\n 'The node supports debug, info, warn, and error. The chosen level is stored alongside the log message.',\n },\n ],\n authoring: {\n defaultConfiguration: {\n level: 'info',\n context: {},\n metadata: {},\n },\n configurationLayout: {\n type: 'tabs',\n tabs: [\n {\n key: 'message',\n label: 'Message',\n groups: ['Message'],\n },\n {\n key: 'context',\n label: 'Context',\n fields: ['context'],\n },\n {\n key: 'metadata',\n label: 'Metadata',\n fields: ['metadata'],\n },\n ],\n },\n configurationFields: [\n {\n key: 'level',\n label: 'Level',\n description: 'The severity used for the emitted workflow log entry.',\n valueType: 'string',\n defaultValue: 'info',\n enumValues: ['debug', 'info', 'warn', 'error'],\n group: 'Message',\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The text to log. Expressions are allowed.',\n valueType: 'string',\n required: true,\n expressionAllowed: true,\n group: 'Message',\n },\n {\n key: 'context',\n label: 'Context',\n description: 'Optional structured context attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n {\n key: 'metadata',\n label: 'Metadata',\n description: 'Optional metadata attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n ],\n outputs: [\n {\n key: 'level',\n label: 'Level',\n description: 'The resolved log level.',\n valueType: 'string',\n path: 'level',\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The rendered log message.',\n valueType: 'string',\n path: 'message',\n },\n ],\n supportsExpressions: true,\n supportsDisableToggle: true,\n supportsName: true,\n supportsDescription: true,\n searchableText: ['log', 'message', 'debug', 'observability'],\n },\n runtime: {\n emitsLogs: true,\n emitsArtifacts: false,\n deterministicOutputs: true,\n executionMode: 'task',\n successStatuses: ['success'],\n },\n documentation: {\n summary:\n 'Use this node for debug messages, execution breadcrumbs, and quick expression verification.',\n },\n ui: {\n icon: 'si-file',\n iconColor: '#0284c7',\n iconBackgroundColor: '#e0f2fe',\n iconBorderColor: '#bae6fd',\n defaultEditorMode: 'schema',\n modalSize: 'xl',\n layoutHints: {\n preferredPanel: 'flow',\n groupOrder: ['Message', 'Advanced'],\n stickySummary: true,\n },\n },\n})\nexport class LogWriteNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.expression.interpolate(\n context.node.configuration ?? {},\n context,\n );\n const level = configuration.level ?? 'info';\n const message = configuration.message ?? context.node.name ?? context.node.id;\n\n await context.emitLog({\n level,\n message,\n eventType: 'node.log',\n source: 'log.write',\n context: configuration.context,\n metadata: configuration.metadata,\n });\n\n return {\n output: {\n level,\n message,\n },\n };\n }\n}\n"]}
1
+ {"version":3,"file":"log-write.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/log-write.node.ts"],"names":[],"mappings":"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","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'log.write',\n kind: 'task',\n version: '1.0.0',\n category: 'core',\n subcategory: 'observability',\n label: 'Write Log',\n description: 'Writes an execution log entry and returns the rendered message.',\n tags: ['log', 'debug', 'observability'],\n aliases: ['log'],\n configSchema: {\n type: 'object',\n required: ['message'],\n properties: {\n level: {\n type: 'string',\n enum: ['debug', 'info', 'warn', 'error'],\n default: 'info',\n },\n message: {\n type: 'string',\n },\n context: {\n type: 'object',\n default: {},\n },\n metadata: {\n type: 'object',\n default: {},\n },\n },\n },\n uiSchema: {\n 'ui:order': ['level', 'message', 'context', 'metadata'],\n },\n outputSchema: {\n type: 'object',\n properties: {\n level: { type: 'string' },\n message: { type: 'string' },\n },\n },\n examples: [\n {\n key: 'simple-message',\n label: 'Simple log message',\n description: 'Write a simple interpolated log line.',\n language: 'yaml',\n snippet:\n 'message: \"Hello {{ input.name }}\"\\nlevel: info\\n',\n configurationOnly: true,\n },\n ],\n metrics: [\n {\n key: 'workflow.node.log.count',\n label: 'Log writes',\n description: 'Counts how many times the log node executes.',\n type: 'counter',\n tags: ['log', 'workflow'],\n },\n ],\n definitions: [\n {\n key: 'log-levels',\n label: 'Supported log levels',\n content:\n 'The node supports debug, info, warn, and error. The chosen level is stored alongside the log message.',\n },\n ],\n authoring: {\n defaultConfiguration: {\n level: 'info',\n context: {},\n metadata: {},\n },\n configurationLayout: {\n type: 'tabs',\n tabs: [\n {\n key: 'message',\n label: 'Message',\n groups: ['Message'],\n },\n {\n key: 'context',\n label: 'Context',\n fields: ['context'],\n },\n {\n key: 'metadata',\n label: 'Metadata',\n fields: ['metadata'],\n },\n ],\n },\n configurationFields: [\n {\n key: 'level',\n label: 'Level',\n description: 'The severity used for the emitted workflow log entry.',\n valueType: 'string',\n defaultValue: 'info',\n enumValues: ['debug', 'info', 'warn', 'error'],\n group: 'Message',\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The text to log. Expressions are allowed.',\n valueType: 'string',\n required: true,\n expressionAllowed: true,\n group: 'Message',\n },\n {\n key: 'context',\n label: 'Context',\n description: 'Optional structured context attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n {\n key: 'metadata',\n label: 'Metadata',\n description: 'Optional metadata attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n ],\n outputs: [\n {\n key: 'level',\n label: 'Level',\n description: 'The resolved log level.',\n valueType: 'string',\n path: 'level',\n includeInRuntimeContext: false,\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The rendered log message.',\n valueType: 'string',\n path: 'message',\n includeInRuntimeContext: false,\n },\n ],\n supportsExpressions: true,\n supportsDisableToggle: true,\n supportsName: true,\n supportsDescription: true,\n searchableText: ['log', 'message', 'debug', 'observability'],\n },\n runtime: {\n emitsLogs: true,\n emitsArtifacts: false,\n deterministicOutputs: true,\n executionMode: 'task',\n successStatuses: ['success'],\n },\n documentation: {\n summary:\n 'Use this node for debug messages, execution breadcrumbs, and quick expression verification.',\n },\n ui: {\n icon: 'si-file',\n iconColor: '#0284c7',\n iconBackgroundColor: '#e0f2fe',\n iconBorderColor: '#bae6fd',\n defaultEditorMode: 'schema',\n modalSize: 'xl',\n layoutHints: {\n preferredPanel: 'flow',\n groupOrder: ['Message', 'Advanced'],\n stickySummary: true,\n },\n },\n})\nexport class LogWriteNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.expression.interpolate(\n context.node.configuration ?? {},\n context,\n );\n const level = configuration.level ?? 'info';\n const message = configuration.message ?? context.node.name ?? context.node.id;\n\n await context.emitLog({\n level,\n message,\n eventType: 'node.log',\n source: 'log.write',\n context: configuration.context,\n metadata: configuration.metadata,\n });\n\n return {\n output: {\n level,\n message,\n },\n };\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';
2
+ import { WorkflowNodeExecutionContext, WorkflowNodeHandlerResult } from '../../../types/workflow-dsl.types';
3
+ export declare class LoopUntilNode implements WorkflowNodeHandler {
4
+ execute(context: WorkflowNodeExecutionContext): Promise<WorkflowNodeHandlerResult>;
5
+ private resolveCheckFrequency;
6
+ private hasReachedGuardrail;
7
+ private optionalPositiveInteger;
8
+ private parseDurationMs;
9
+ private resolveBoolean;
10
+ private delay;
11
+ }
12
+ //# sourceMappingURL=loop-until.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-until.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/loop-until.node.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAS3C,qBAqHa,aAAc,YAAW,mBAAmB;IACjD,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;IA4FrC,OAAO,CAAC,qBAAqB;IAyB7B,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,eAAe;IAkDvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,KAAK;CAGd"}
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LoopUntilNode = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const workflow_node_provider_decorator_1 = require("../../../decorators/workflow-node-provider.decorator");
12
+ let LoopUntilNode = class LoopUntilNode {
13
+ async execute(context) {
14
+ const configuration = context.node.configuration ?? {};
15
+ const condition = configuration.condition ?? configuration.expression;
16
+ if (!condition) {
17
+ throw new common_1.BadRequestException('loopUntil requires configuration.condition.');
18
+ }
19
+ const checkFrequency = this.resolveCheckFrequency(context.expression.interpolate(configuration.checkFrequency ?? {}, context));
20
+ const childNodes = context.node.tasks ?? [];
21
+ const startedAt = Date.now();
22
+ let iterationCount = 0;
23
+ let conditionMatched = false;
24
+ let maxReached = false;
25
+ let latestChildOutputs = {};
26
+ while (true) {
27
+ iterationCount += 1;
28
+ context.outputs[context.node.id] = {
29
+ iterationCount,
30
+ conditionMatched: false,
31
+ maxReached: false,
32
+ };
33
+ const iterationOutputs = {
34
+ ...(context.outputs ?? {}),
35
+ };
36
+ latestChildOutputs = await context.runNodes(childNodes, {
37
+ outputs: iterationOutputs,
38
+ });
39
+ Object.assign(context.outputs, iterationOutputs);
40
+ conditionMatched = context.expression.evaluateCondition(condition, {
41
+ ...context,
42
+ outputs: context.outputs,
43
+ });
44
+ context.outputs[context.node.id] = {
45
+ iterationCount,
46
+ conditionMatched,
47
+ maxReached: false,
48
+ latestOutputs: latestChildOutputs,
49
+ };
50
+ await context.emitLog({
51
+ level: 'info',
52
+ eventType: 'node.loopUntil.evaluated',
53
+ source: 'loopUntil',
54
+ message: `LoopUntil node "${context.node.id}" iteration ${iterationCount} evaluated to ${conditionMatched}.`,
55
+ context: {
56
+ condition,
57
+ iterationCount,
58
+ conditionMatched,
59
+ },
60
+ });
61
+ if (conditionMatched) {
62
+ break;
63
+ }
64
+ maxReached = this.hasReachedGuardrail(iterationCount, startedAt, checkFrequency);
65
+ if (maxReached) {
66
+ if (checkFrequency.failOnMaxReached) {
67
+ throw new common_1.BadRequestException(`loopUntil "${context.node.id}" reached its maximum check frequency guardrail before the condition matched.`);
68
+ }
69
+ break;
70
+ }
71
+ if (checkFrequency.intervalMs > 0) {
72
+ await this.delay(checkFrequency.intervalMs);
73
+ }
74
+ }
75
+ return {
76
+ output: {
77
+ iterationCount,
78
+ conditionMatched,
79
+ maxReached,
80
+ latestOutputs: latestChildOutputs,
81
+ },
82
+ };
83
+ }
84
+ resolveCheckFrequency(value) {
85
+ const checkFrequency = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
86
+ const maxIterations = this.optionalPositiveInteger(checkFrequency.maxIterations, 'checkFrequency.maxIterations');
87
+ const maxDurationMs = checkFrequency.maxDuration === undefined ||
88
+ checkFrequency.maxDuration === null ||
89
+ checkFrequency.maxDuration === ''
90
+ ? undefined
91
+ : this.parseDurationMs(checkFrequency.maxDuration, 'checkFrequency.maxDuration');
92
+ return {
93
+ intervalMs: this.parseDurationMs(checkFrequency.interval ?? 'PT1M', 'checkFrequency.interval'),
94
+ maxIterations,
95
+ maxDurationMs,
96
+ failOnMaxReached: this.resolveBoolean(checkFrequency.failOnMaxReached),
97
+ };
98
+ }
99
+ hasReachedGuardrail(iterationCount, startedAt, checkFrequency) {
100
+ return ((checkFrequency.maxIterations !== undefined &&
101
+ iterationCount >= checkFrequency.maxIterations) ||
102
+ (checkFrequency.maxDurationMs !== undefined &&
103
+ Date.now() - startedAt >= checkFrequency.maxDurationMs));
104
+ }
105
+ optionalPositiveInteger(value, label) {
106
+ if (value === undefined || value === null || value === '') {
107
+ return undefined;
108
+ }
109
+ const parsed = Number(value);
110
+ if (!Number.isFinite(parsed) || parsed < 1) {
111
+ throw new common_1.BadRequestException(`${label} must be a positive integer.`);
112
+ }
113
+ return Math.floor(parsed);
114
+ }
115
+ parseDurationMs(value, label) {
116
+ if (typeof value === 'number') {
117
+ if (!Number.isFinite(value) || value < 0) {
118
+ throw new common_1.BadRequestException(`${label} must be a non-negative duration.`);
119
+ }
120
+ return value;
121
+ }
122
+ const raw = String(value ?? '').trim();
123
+ if (!raw) {
124
+ return 0;
125
+ }
126
+ if (/^\d+$/.test(raw)) {
127
+ return Number(raw);
128
+ }
129
+ const isoMatch = raw.match(/^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/i);
130
+ if (isoMatch) {
131
+ const [, days, hours, minutes, seconds] = isoMatch;
132
+ return (Number(days ?? 0) * 24 * 60 * 60 * 1000 +
133
+ Number(hours ?? 0) * 60 * 60 * 1000 +
134
+ Number(minutes ?? 0) * 60 * 1000 +
135
+ Number(seconds ?? 0) * 1000);
136
+ }
137
+ const unitMatch = raw.match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/i);
138
+ if (unitMatch) {
139
+ const amount = Number(unitMatch[1]);
140
+ const unit = unitMatch[2].toLowerCase();
141
+ const multiplier = unit === 'ms'
142
+ ? 1
143
+ : unit === 's'
144
+ ? 1000
145
+ : unit === 'm'
146
+ ? 60 * 1000
147
+ : unit === 'h'
148
+ ? 60 * 60 * 1000
149
+ : 24 * 60 * 60 * 1000;
150
+ return amount * multiplier;
151
+ }
152
+ throw new common_1.BadRequestException(`${label} must be milliseconds, 1s/1m style, or ISO-8601 duration.`);
153
+ }
154
+ resolveBoolean(value) {
155
+ if (value === true || value === 'true') {
156
+ return true;
157
+ }
158
+ return false;
159
+ }
160
+ delay(ms) {
161
+ return new Promise((resolve) => setTimeout(resolve, ms));
162
+ }
163
+ };
164
+ exports.LoopUntilNode = LoopUntilNode;
165
+ exports.LoopUntilNode = LoopUntilNode = __decorate([
166
+ (0, workflow_node_provider_decorator_1.WorkflowNodeProvider)({
167
+ type: 'loopUntil',
168
+ kind: 'control',
169
+ category: 'control-flow',
170
+ label: 'Loop Until',
171
+ description: 'Runs child nodes repeatedly until a condition evaluates true.',
172
+ tags: ['loop', 'iteration', 'condition', 'polling'],
173
+ authoring: {
174
+ defaultConfiguration: {
175
+ condition: '{{ outputs.checkStatus.ready == true }}',
176
+ checkFrequency: {
177
+ interval: 'PT1M',
178
+ failOnMaxReached: false,
179
+ },
180
+ },
181
+ configurationLayout: {
182
+ type: 'tabs',
183
+ tabs: [
184
+ {
185
+ key: 'condition',
186
+ label: 'Condition',
187
+ groups: ['Condition'],
188
+ },
189
+ {
190
+ key: 'guardrails',
191
+ label: 'Guardrails',
192
+ groups: ['Guardrails'],
193
+ },
194
+ ],
195
+ },
196
+ configurationFields: [
197
+ {
198
+ key: 'condition',
199
+ label: 'Condition',
200
+ description: 'Boolean expression evaluated after each loop iteration. It can read outputs from the latest child-node run.',
201
+ valueType: 'expression',
202
+ required: true,
203
+ expressionAllowed: true,
204
+ widgetHint: 'textarea',
205
+ group: 'Condition',
206
+ uiSchema: {
207
+ layout: {
208
+ width: 'full',
209
+ },
210
+ },
211
+ },
212
+ {
213
+ key: 'checkFrequency',
214
+ label: 'Check Frequency',
215
+ description: 'Optional loop guardrails: interval, maxIterations, maxDuration, and failOnMaxReached.',
216
+ valueType: 'object',
217
+ expressionAllowed: true,
218
+ widgetHint: 'yaml-editor',
219
+ group: 'Guardrails',
220
+ uiSchema: {
221
+ layout: {
222
+ width: 'full',
223
+ },
224
+ editor: {
225
+ height: 'min(320px, calc(90vh - 360px))',
226
+ },
227
+ },
228
+ },
229
+ ],
230
+ childSlots: [
231
+ {
232
+ key: 'tasks',
233
+ label: 'Loop Body',
234
+ description: 'Nodes that run before the condition is evaluated.',
235
+ kind: 'sequence',
236
+ layout: 'sequential',
237
+ required: true,
238
+ },
239
+ {
240
+ key: 'errors',
241
+ label: 'Errors',
242
+ description: 'Nodes that run sequentially if this loop fails.',
243
+ kind: 'sequence',
244
+ layout: 'sequential',
245
+ },
246
+ ],
247
+ outputs: [
248
+ {
249
+ key: 'iterationCount',
250
+ label: 'Iteration Count',
251
+ description: 'Number of loop body iterations that ran.',
252
+ valueType: 'number',
253
+ path: 'iterationCount',
254
+ },
255
+ {
256
+ key: 'conditionMatched',
257
+ label: 'Condition Matched',
258
+ description: 'Whether the loop stopped because the condition evaluated true.',
259
+ valueType: 'boolean',
260
+ path: 'conditionMatched',
261
+ },
262
+ ],
263
+ supportsDescription: true,
264
+ supportsName: true,
265
+ },
266
+ documentation: {
267
+ summary: 'Runs the loop body, evaluates the condition, and repeats after the configured interval until the condition is true or a guardrail is reached.',
268
+ },
269
+ ui: {
270
+ icon: 'si-repeat',
271
+ iconColor: '#0f766e',
272
+ iconBackgroundColor: '#ccfbf1',
273
+ iconBorderColor: '#99f6e4',
274
+ modalSize: 'lg',
275
+ layoutHints: {
276
+ groupOrder: ['Condition', 'Guardrails'],
277
+ },
278
+ },
279
+ })
280
+ ], LoopUntilNode);
281
+ //# sourceMappingURL=loop-until.node.js.map