cxtms 1.9.13

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 (215) hide show
  1. package/README.md +384 -0
  2. package/dist/cli.d.ts +6 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +4784 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/extractUtils.d.ts +11 -0
  7. package/dist/extractUtils.d.ts.map +1 -0
  8. package/dist/extractUtils.js +19 -0
  9. package/dist/extractUtils.js.map +1 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +11 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/types.d.ts +129 -0
  15. package/dist/types.d.ts.map +1 -0
  16. package/dist/types.js +6 -0
  17. package/dist/types.js.map +1 -0
  18. package/dist/utils/schemaLoader.d.ts +17 -0
  19. package/dist/utils/schemaLoader.d.ts.map +1 -0
  20. package/dist/utils/schemaLoader.js +134 -0
  21. package/dist/utils/schemaLoader.js.map +1 -0
  22. package/dist/validator.d.ts +72 -0
  23. package/dist/validator.d.ts.map +1 -0
  24. package/dist/validator.js +432 -0
  25. package/dist/validator.js.map +1 -0
  26. package/dist/workflowValidator.d.ts +103 -0
  27. package/dist/workflowValidator.d.ts.map +1 -0
  28. package/dist/workflowValidator.js +753 -0
  29. package/dist/workflowValidator.js.map +1 -0
  30. package/package.json +51 -0
  31. package/schemas/actions/all.json +27 -0
  32. package/schemas/actions/clipboard.json +46 -0
  33. package/schemas/actions/confirm.json +21 -0
  34. package/schemas/actions/consoleLog.json +16 -0
  35. package/schemas/actions/dialog.json +25 -0
  36. package/schemas/actions/fileDownload.json +16 -0
  37. package/schemas/actions/forEach.json +31 -0
  38. package/schemas/actions/if.json +12 -0
  39. package/schemas/actions/mutation.json +25 -0
  40. package/schemas/actions/navigate.json +18 -0
  41. package/schemas/actions/navigateBack.json +22 -0
  42. package/schemas/actions/navigateBackOrClose.json +21 -0
  43. package/schemas/actions/notification.json +19 -0
  44. package/schemas/actions/openBarcodeScanner.json +104 -0
  45. package/schemas/actions/query.json +32 -0
  46. package/schemas/actions/refresh.json +13 -0
  47. package/schemas/actions/resetDirtyState.json +22 -0
  48. package/schemas/actions/setFields.json +21 -0
  49. package/schemas/actions/setStore.json +13 -0
  50. package/schemas/actions/validateForm.json +15 -0
  51. package/schemas/actions/workflow.json +24 -0
  52. package/schemas/components/README.md +147 -0
  53. package/schemas/components/appComponent.json +58 -0
  54. package/schemas/components/barcodeScanner.json +69 -0
  55. package/schemas/components/button.json +123 -0
  56. package/schemas/components/calendar.json +489 -0
  57. package/schemas/components/card.json +176 -0
  58. package/schemas/components/collection.json +54 -0
  59. package/schemas/components/dataGrid.json +119 -0
  60. package/schemas/components/datasource.json +151 -0
  61. package/schemas/components/dropdown.json +57 -0
  62. package/schemas/components/field-collection.json +618 -0
  63. package/schemas/components/field.json +265 -0
  64. package/schemas/components/form.json +234 -0
  65. package/schemas/components/index.json +71 -0
  66. package/schemas/components/layout.json +69 -0
  67. package/schemas/components/module.json +167 -0
  68. package/schemas/components/navDropdown.json +36 -0
  69. package/schemas/components/navbar.json +78 -0
  70. package/schemas/components/navbarItem.json +28 -0
  71. package/schemas/components/navbarLink.json +36 -0
  72. package/schemas/components/row.json +31 -0
  73. package/schemas/components/slot.json +30 -0
  74. package/schemas/components/tab.json +34 -0
  75. package/schemas/components/tabs.json +35 -0
  76. package/schemas/components/timeline.json +172 -0
  77. package/schemas/components/timelineGrid.json +328 -0
  78. package/schemas/fields/README.md +66 -0
  79. package/schemas/fields/attachment.json +156 -0
  80. package/schemas/fields/autocomplete-googleplaces.json +130 -0
  81. package/schemas/fields/checkbox.json +82 -0
  82. package/schemas/fields/date.json +88 -0
  83. package/schemas/fields/datetime.json +75 -0
  84. package/schemas/fields/email.json +75 -0
  85. package/schemas/fields/index.json +53 -0
  86. package/schemas/fields/number.json +91 -0
  87. package/schemas/fields/password.json +70 -0
  88. package/schemas/fields/radio.json +94 -0
  89. package/schemas/fields/rangedatetime.json +56 -0
  90. package/schemas/fields/select-async.json +334 -0
  91. package/schemas/fields/select.json +115 -0
  92. package/schemas/fields/tel.json +79 -0
  93. package/schemas/fields/text.json +86 -0
  94. package/schemas/fields/textarea.json +95 -0
  95. package/schemas/fields/time.json +91 -0
  96. package/schemas/fields/url.json +74 -0
  97. package/schemas/schema.graphql +12248 -0
  98. package/schemas/schemas.json +610 -0
  99. package/schemas/workflows/activity.json +96 -0
  100. package/schemas/workflows/common/condition.json +48 -0
  101. package/schemas/workflows/common/expression.json +76 -0
  102. package/schemas/workflows/common/mapping.json +173 -0
  103. package/schemas/workflows/common/step.json +38 -0
  104. package/schemas/workflows/flow/aggregation.json +44 -0
  105. package/schemas/workflows/flow/entity.json +129 -0
  106. package/schemas/workflows/flow/state.json +105 -0
  107. package/schemas/workflows/flow/transition.json +143 -0
  108. package/schemas/workflows/input.json +122 -0
  109. package/schemas/workflows/output.json +61 -0
  110. package/schemas/workflows/schedule.json +26 -0
  111. package/schemas/workflows/tasks/accounting-transaction.json +95 -0
  112. package/schemas/workflows/tasks/action-event.json +65 -0
  113. package/schemas/workflows/tasks/all.json +152 -0
  114. package/schemas/workflows/tasks/appmodule.json +56 -0
  115. package/schemas/workflows/tasks/attachment.json +97 -0
  116. package/schemas/workflows/tasks/authentication.json +86 -0
  117. package/schemas/workflows/tasks/caching.json +68 -0
  118. package/schemas/workflows/tasks/charge.json +92 -0
  119. package/schemas/workflows/tasks/commodity.json +92 -0
  120. package/schemas/workflows/tasks/contact-address.json +72 -0
  121. package/schemas/workflows/tasks/contact-payment-method.json +72 -0
  122. package/schemas/workflows/tasks/contact.json +82 -0
  123. package/schemas/workflows/tasks/csv.json +81 -0
  124. package/schemas/workflows/tasks/document-render.json +105 -0
  125. package/schemas/workflows/tasks/document-send.json +84 -0
  126. package/schemas/workflows/tasks/edi.json +157 -0
  127. package/schemas/workflows/tasks/email-send.json +110 -0
  128. package/schemas/workflows/tasks/error.json +72 -0
  129. package/schemas/workflows/tasks/export.json +90 -0
  130. package/schemas/workflows/tasks/filetransfer.json +102 -0
  131. package/schemas/workflows/tasks/flow-transition.json +68 -0
  132. package/schemas/workflows/tasks/foreach.json +69 -0
  133. package/schemas/workflows/tasks/generic.json +47 -0
  134. package/schemas/workflows/tasks/graphql.json +78 -0
  135. package/schemas/workflows/tasks/httpRequest.json +161 -0
  136. package/schemas/workflows/tasks/import.json +64 -0
  137. package/schemas/workflows/tasks/inventory.json +67 -0
  138. package/schemas/workflows/tasks/job.json +88 -0
  139. package/schemas/workflows/tasks/log.json +73 -0
  140. package/schemas/workflows/tasks/map.json +58 -0
  141. package/schemas/workflows/tasks/movement.json +54 -0
  142. package/schemas/workflows/tasks/note.json +59 -0
  143. package/schemas/workflows/tasks/number.json +65 -0
  144. package/schemas/workflows/tasks/order-tracking-event.json +109 -0
  145. package/schemas/workflows/tasks/order.json +139 -0
  146. package/schemas/workflows/tasks/payment.json +85 -0
  147. package/schemas/workflows/tasks/pdf-document.json +60 -0
  148. package/schemas/workflows/tasks/postal-codes.json +92 -0
  149. package/schemas/workflows/tasks/resolve-timezone.json +65 -0
  150. package/schemas/workflows/tasks/setVariable.json +76 -0
  151. package/schemas/workflows/tasks/switch.json +75 -0
  152. package/schemas/workflows/tasks/template.json +73 -0
  153. package/schemas/workflows/tasks/tracking-event.json +137 -0
  154. package/schemas/workflows/tasks/transmission.json +185 -0
  155. package/schemas/workflows/tasks/unzip-file.json +68 -0
  156. package/schemas/workflows/tasks/user.json +70 -0
  157. package/schemas/workflows/tasks/validation.json +99 -0
  158. package/schemas/workflows/tasks/while.json +53 -0
  159. package/schemas/workflows/tasks/workflow-execute.json +82 -0
  160. package/schemas/workflows/trigger.json +90 -0
  161. package/schemas/workflows/variable.json +46 -0
  162. package/schemas/workflows/workflow.json +335 -0
  163. package/scripts/postinstall.js +291 -0
  164. package/scripts/setup-vscode.js +80 -0
  165. package/skills/cxtms-developer/SKILL.md +118 -0
  166. package/skills/cxtms-developer/ref-cli-auth.md +120 -0
  167. package/skills/cxtms-developer/ref-entity-accounting.md +180 -0
  168. package/skills/cxtms-developer/ref-entity-commodity.md +239 -0
  169. package/skills/cxtms-developer/ref-entity-contact.md +163 -0
  170. package/skills/cxtms-developer/ref-entity-geography.md +154 -0
  171. package/skills/cxtms-developer/ref-entity-job.md +77 -0
  172. package/skills/cxtms-developer/ref-entity-notification.md +85 -0
  173. package/skills/cxtms-developer/ref-entity-order-sub.md +160 -0
  174. package/skills/cxtms-developer/ref-entity-order.md +183 -0
  175. package/skills/cxtms-developer/ref-entity-organization.md +41 -0
  176. package/skills/cxtms-developer/ref-entity-rate.md +182 -0
  177. package/skills/cxtms-developer/ref-entity-shared.md +176 -0
  178. package/skills/cxtms-developer/ref-entity-warehouse.md +115 -0
  179. package/skills/cxtms-developer/ref-graphql-query.md +309 -0
  180. package/skills/cxtms-module-builder/SKILL.md +477 -0
  181. package/skills/cxtms-module-builder/ref-components-data.md +293 -0
  182. package/skills/cxtms-module-builder/ref-components-display.md +411 -0
  183. package/skills/cxtms-module-builder/ref-components-forms.md +369 -0
  184. package/skills/cxtms-module-builder/ref-components-interactive.md +317 -0
  185. package/skills/cxtms-module-builder/ref-components-layout.md +390 -0
  186. package/skills/cxtms-module-builder/ref-components-specialized.md +477 -0
  187. package/skills/cxtms-workflow-builder/SKILL.md +438 -0
  188. package/skills/cxtms-workflow-builder/ref-accounting.md +66 -0
  189. package/skills/cxtms-workflow-builder/ref-communication.md +169 -0
  190. package/skills/cxtms-workflow-builder/ref-entity.md +342 -0
  191. package/skills/cxtms-workflow-builder/ref-expressions-ncalc.md +128 -0
  192. package/skills/cxtms-workflow-builder/ref-expressions-template.md +161 -0
  193. package/skills/cxtms-workflow-builder/ref-filetransfer.md +80 -0
  194. package/skills/cxtms-workflow-builder/ref-flow.md +210 -0
  195. package/skills/cxtms-workflow-builder/ref-other.md +157 -0
  196. package/skills/cxtms-workflow-builder/ref-query.md +105 -0
  197. package/skills/cxtms-workflow-builder/ref-utilities.md +417 -0
  198. package/templates/module-configuration.yaml +44 -0
  199. package/templates/module-form.yaml +152 -0
  200. package/templates/module-grid.yaml +229 -0
  201. package/templates/module-select.yaml +139 -0
  202. package/templates/module.yaml +84 -0
  203. package/templates/workflow-api-tracking.yaml +189 -0
  204. package/templates/workflow-basic.yaml +76 -0
  205. package/templates/workflow-document.yaml +155 -0
  206. package/templates/workflow-entity-trigger.yaml +90 -0
  207. package/templates/workflow-ftp-edi.yaml +158 -0
  208. package/templates/workflow-ftp-tracking.yaml +161 -0
  209. package/templates/workflow-mcp-tool.yaml +112 -0
  210. package/templates/workflow-public-api.yaml +135 -0
  211. package/templates/workflow-scheduled-execute.yaml +75 -0
  212. package/templates/workflow-scheduled.yaml +125 -0
  213. package/templates/workflow-utility.yaml +96 -0
  214. package/templates/workflow-webhook.yaml +128 -0
  215. package/templates/workflow.yaml +140 -0
@@ -0,0 +1,753 @@
1
+ "use strict";
2
+ /**
3
+ * Workflow validator for CargoXplorer YAML workflow files
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.WorkflowValidator = void 0;
43
+ const ajv_1 = __importDefault(require("ajv"));
44
+ const ajv_formats_1 = __importDefault(require("ajv-formats"));
45
+ const fs = __importStar(require("fs"));
46
+ const path = __importStar(require("path"));
47
+ const yaml_1 = __importDefault(require("yaml"));
48
+ class WorkflowValidator {
49
+ constructor(options = {}) {
50
+ this.schemasDir = options.schemasPath || path.join(__dirname, '../schemas/workflows');
51
+ this.options = {
52
+ schemasPath: this.schemasDir,
53
+ strictMode: options.strictMode ?? true,
54
+ includeWarnings: options.includeWarnings ?? true,
55
+ validateTasks: options.validateTasks ?? true,
56
+ validateExpressions: options.validateExpressions ?? false
57
+ };
58
+ // Initialize Ajv with Draft 7 support
59
+ this.ajv = new ajv_1.default({
60
+ strict: false,
61
+ allErrors: true,
62
+ verbose: true,
63
+ validateFormats: true,
64
+ allowUnionTypes: true
65
+ });
66
+ // Add format validators
67
+ (0, ajv_formats_1.default)(this.ajv);
68
+ // Load all workflow schemas
69
+ this.schemas = this.loadWorkflowSchemas(this.schemasDir);
70
+ // Register schemas with Ajv
71
+ this.registerSchemas();
72
+ }
73
+ /**
74
+ * Load all workflow schemas from the schemas/workflows directory
75
+ */
76
+ loadWorkflowSchemas(schemasDir) {
77
+ const schemas = new Map();
78
+ // Load main workflow.json
79
+ const mainSchemaPath = path.join(schemasDir, 'workflow.json');
80
+ if (fs.existsSync(mainSchemaPath)) {
81
+ const schema = JSON.parse(fs.readFileSync(mainSchemaPath, 'utf-8'));
82
+ schemas.set('workflow.json', {
83
+ schema,
84
+ uri: `file:///${mainSchemaPath.replace(/\\/g, '/')}`
85
+ });
86
+ }
87
+ // Load workflow sub-schemas
88
+ const subSchemas = ['input.json', 'output.json', 'variable.json', 'trigger.json', 'schedule.json', 'activity.json'];
89
+ for (const schemaFile of subSchemas) {
90
+ const schemaPath = path.join(schemasDir, schemaFile);
91
+ if (fs.existsSync(schemaPath)) {
92
+ const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf-8'));
93
+ schemas.set(schemaFile, {
94
+ schema,
95
+ uri: `file:///${schemaPath.replace(/\\/g, '/')}`
96
+ });
97
+ }
98
+ }
99
+ // Load task schemas from tasks/ subdirectory
100
+ const tasksDir = path.join(schemasDir, 'tasks');
101
+ if (fs.existsSync(tasksDir)) {
102
+ this.loadSchemasFromDir(tasksDir, 'tasks', schemas);
103
+ }
104
+ // Load common schemas from common/ subdirectory
105
+ const commonDir = path.join(schemasDir, 'common');
106
+ if (fs.existsSync(commonDir)) {
107
+ this.loadSchemasFromDir(commonDir, 'common', schemas);
108
+ }
109
+ // Load flow schemas from flow/ subdirectory
110
+ const flowDir = path.join(schemasDir, 'flow');
111
+ if (fs.existsSync(flowDir)) {
112
+ this.loadSchemasFromDir(flowDir, 'flow', schemas);
113
+ }
114
+ return schemas;
115
+ }
116
+ /**
117
+ * Recursively load schemas from a directory
118
+ */
119
+ loadSchemasFromDir(dir, relativePath, schemas) {
120
+ const files = fs.readdirSync(dir);
121
+ for (const file of files) {
122
+ const filePath = path.join(dir, file);
123
+ const stat = fs.statSync(filePath);
124
+ if (stat.isDirectory()) {
125
+ this.loadSchemasFromDir(filePath, `${relativePath}/${file}`, schemas);
126
+ }
127
+ else if (file.endsWith('.json')) {
128
+ try {
129
+ const schema = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
130
+ const key = `${relativePath}/${file}`;
131
+ schemas.set(key, {
132
+ schema,
133
+ uri: `file:///${filePath.replace(/\\/g, '/')}`
134
+ });
135
+ }
136
+ catch (error) {
137
+ console.error(`Error loading schema ${filePath}:`, error);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Register all loaded schemas with Ajv
144
+ */
145
+ registerSchemas() {
146
+ for (const [key, entry] of this.schemas.entries()) {
147
+ try {
148
+ this.ajv.addSchema(entry.schema, key);
149
+ }
150
+ catch (error) {
151
+ console.error(`Error adding schema ${key}:`, error);
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Validate a YAML workflow file
157
+ */
158
+ async validateWorkflow(filePath) {
159
+ const errors = [];
160
+ const warnings = [];
161
+ try {
162
+ // Check if file exists
163
+ if (!fs.existsSync(filePath)) {
164
+ errors.push({
165
+ type: 'file_not_found',
166
+ path: filePath,
167
+ message: `File not found: ${filePath}`
168
+ });
169
+ return this.createResult(filePath, errors, warnings);
170
+ }
171
+ // Read and parse YAML
172
+ const content = fs.readFileSync(filePath, 'utf-8');
173
+ let workflowData;
174
+ try {
175
+ workflowData = yaml_1.default.parse(content);
176
+ }
177
+ catch (yamlError) {
178
+ errors.push({
179
+ type: 'yaml_syntax_error',
180
+ path: filePath,
181
+ message: `YAML syntax error: ${yamlError.message}`
182
+ });
183
+ return this.createResult(filePath, errors, warnings);
184
+ }
185
+ // Validate workflow structure
186
+ this.validateWorkflowStructure(workflowData, errors, warnings, filePath);
187
+ // Validate inputs and variables
188
+ this.validateInputs(workflowData, errors);
189
+ this.validateVariables(workflowData, errors);
190
+ // Validate against main workflow schema
191
+ const validate = this.ajv.getSchema('workflow.json');
192
+ if (validate && !validate(workflowData)) {
193
+ this.addAjvErrors(validate.errors, '', errors);
194
+ }
195
+ const isFlowWorkflow = workflowData.workflow?.workflowType === 'Flow';
196
+ if (isFlowWorkflow) {
197
+ // Validate Flow-specific sections
198
+ this.validateFlowWorkflow(workflowData, errors, warnings);
199
+ }
200
+ else {
201
+ // Validate activities recursively (standard workflows)
202
+ if (workflowData.activities && Array.isArray(workflowData.activities)) {
203
+ this.validateActivities(workflowData.activities, 'activities', errors, warnings);
204
+ }
205
+ }
206
+ // Validate workflow-level event handler steps
207
+ this.validateEventSteps(workflowData.events, 'events', ['onWorkflowStarted', 'onWorkflowCompleted', 'onWorkflowExecuted', 'onWorkflowFailed'], errors, warnings);
208
+ // Warn on deprecated onWorkflowExecuted
209
+ if (workflowData.events && !Array.isArray(workflowData.events) && workflowData.events.onWorkflowExecuted) {
210
+ warnings.push({
211
+ type: 'deprecated_property',
212
+ path: 'events.onWorkflowExecuted',
213
+ message: 'Use "onWorkflowCompleted" instead of "onWorkflowExecuted"'
214
+ });
215
+ }
216
+ return this.createResult(filePath, errors, warnings);
217
+ }
218
+ catch (error) {
219
+ errors.push({
220
+ type: 'unexpected_error',
221
+ path: filePath,
222
+ message: `Unexpected error: ${error.message}`
223
+ });
224
+ return this.createResult(filePath, errors, warnings);
225
+ }
226
+ }
227
+ /**
228
+ * Normalize file path: forward slashes, strip leading ./
229
+ */
230
+ normalizeFilePath(p) {
231
+ return p.replace(/\\/g, '/').replace(/^\.\//, '');
232
+ }
233
+ /**
234
+ * Validate top-level workflow structure
235
+ */
236
+ validateWorkflowStructure(workflowData, errors, warnings, filePath) {
237
+ // Check required top-level properties
238
+ if (!workflowData.workflow) {
239
+ errors.push({
240
+ type: 'missing_property',
241
+ path: 'workflow',
242
+ message: 'Missing required property: workflow'
243
+ });
244
+ return;
245
+ }
246
+ const isFlowWorkflow = workflowData.workflow?.workflowType === 'Flow';
247
+ if (isFlowWorkflow) {
248
+ if (!workflowData.entity) {
249
+ errors.push({
250
+ type: 'missing_property',
251
+ path: 'entity',
252
+ message: 'Missing required property: entity (required for Flow workflows)'
253
+ });
254
+ }
255
+ }
256
+ else {
257
+ if (!workflowData.activities) {
258
+ errors.push({
259
+ type: 'missing_property',
260
+ path: 'activities',
261
+ message: 'Missing required property: activities'
262
+ });
263
+ }
264
+ }
265
+ // Validate workflow metadata
266
+ const workflow = workflowData.workflow;
267
+ if (!workflow.workflowId) {
268
+ errors.push({
269
+ type: 'missing_property',
270
+ path: 'workflow.workflowId',
271
+ message: 'Missing required property: workflow.workflowId'
272
+ });
273
+ }
274
+ if (!workflow.name) {
275
+ errors.push({
276
+ type: 'missing_property',
277
+ path: 'workflow.name',
278
+ message: 'Missing required property: workflow.name'
279
+ });
280
+ }
281
+ // Check for deprecated properties
282
+ this.checkDeprecatedProperties(workflow, 'workflow', warnings);
283
+ // filePath / fileName deprecation and validation
284
+ if (workflow.fileName && !workflow.filePath) {
285
+ warnings.push({
286
+ type: 'deprecated_property',
287
+ path: 'workflow.fileName',
288
+ message: 'Use "filePath" instead of "fileName" in workflow section'
289
+ });
290
+ }
291
+ const declaredPath = workflow.filePath ?? workflow.fileName;
292
+ if (declaredPath && filePath) {
293
+ const normalizedActual = this.normalizeFilePath(filePath);
294
+ const normalizedDeclared = this.normalizeFilePath(declaredPath);
295
+ if (!normalizedActual.endsWith(normalizedDeclared)) {
296
+ warnings.push({
297
+ type: 'file_path_mismatch',
298
+ path: 'workflow.filePath',
299
+ message: `Declared filePath "${normalizedDeclared}" does not match actual file path "${normalizedActual}"`
300
+ });
301
+ }
302
+ }
303
+ }
304
+ /**
305
+ * Validate workflow inputs.
306
+ * Top-level input properties are: name, type, props.
307
+ * Settings like required, displayName, description belong inside props.
308
+ */
309
+ validateInputs(workflowData, errors) {
310
+ const inputs = workflowData.inputs;
311
+ if (!inputs || !Array.isArray(inputs))
312
+ return;
313
+ const propsOnlyFields = ['required', 'isRequired', 'displayName', 'description', 'multiple', 'visible', 'defaultValue', 'mapping', 'filter', 'options'];
314
+ inputs.forEach((input, index) => {
315
+ const inputPath = `inputs[${index}]`;
316
+ for (const field of propsOnlyFields) {
317
+ if (field in input) {
318
+ errors.push({
319
+ type: 'schema_violation',
320
+ path: `${inputPath}.${field}`,
321
+ message: `Invalid top-level property '${field}'. Move it inside 'props'`
322
+ });
323
+ }
324
+ }
325
+ });
326
+ }
327
+ /**
328
+ * Validate workflow variables.
329
+ * Top-level variable properties are: name, value, fromConfig.
330
+ */
331
+ validateVariables(workflowData, errors) {
332
+ const variables = workflowData.variables;
333
+ if (!variables || !Array.isArray(variables))
334
+ return;
335
+ variables.forEach((variable, index) => {
336
+ const varPath = `variables[${index}]`;
337
+ if ('type' in variable) {
338
+ errors.push({
339
+ type: 'schema_violation',
340
+ path: `${varPath}.type`,
341
+ message: `Invalid property 'type' on variable. Variables only support 'name', 'value', and 'fromConfig'`
342
+ });
343
+ }
344
+ });
345
+ }
346
+ /**
347
+ * Validate activities array recursively
348
+ */
349
+ validateActivities(activities, basePath, errors, warnings) {
350
+ activities.forEach((activity, index) => {
351
+ const activityPath = `${basePath}[${index}]`;
352
+ this.validateActivity(activity, activityPath, errors, warnings);
353
+ });
354
+ }
355
+ /**
356
+ * Validate a single activity
357
+ */
358
+ validateActivity(activity, activityPath, errors, warnings) {
359
+ if (!activity || typeof activity !== 'object') {
360
+ errors.push({
361
+ type: 'invalid_activity',
362
+ path: activityPath,
363
+ message: 'Activity must be an object'
364
+ });
365
+ return;
366
+ }
367
+ // Check for required properties
368
+ if (!activity.name) {
369
+ errors.push({
370
+ type: 'missing_property',
371
+ path: `${activityPath}.name`,
372
+ message: 'Activity must have a name property'
373
+ });
374
+ }
375
+ if (!activity.steps || !Array.isArray(activity.steps)) {
376
+ errors.push({
377
+ type: 'missing_property',
378
+ path: `${activityPath}.steps`,
379
+ message: 'Activity must have a steps array'
380
+ });
381
+ return;
382
+ }
383
+ // Validate each step
384
+ activity.steps.forEach((step, stepIndex) => {
385
+ const stepPath = `${activityPath}.steps[${stepIndex}]`;
386
+ this.validateStep(step, stepPath, errors, warnings);
387
+ });
388
+ // Validate activity-level event handler steps
389
+ this.validateEventSteps(activity.events, `${activityPath}.events`, ['onActivityStarted', 'onActivityCompleted', 'onActivityFailed'], errors, warnings);
390
+ }
391
+ /**
392
+ * Validate steps inside event handlers (object format)
393
+ */
394
+ validateEventSteps(events, basePath, eventNames, errors, warnings) {
395
+ if (!events || typeof events !== 'object' || Array.isArray(events))
396
+ return;
397
+ for (const eventName of eventNames) {
398
+ const steps = events[eventName];
399
+ if (steps && Array.isArray(steps)) {
400
+ steps.forEach((step, index) => {
401
+ this.validateStep(step, `${basePath}.${eventName}[${index}]`, errors, warnings);
402
+ });
403
+ }
404
+ }
405
+ }
406
+ /**
407
+ * Validate a single step (task)
408
+ */
409
+ validateStep(step, stepPath, errors, warnings) {
410
+ if (!step || typeof step !== 'object') {
411
+ errors.push({
412
+ type: 'schema_violation',
413
+ path: stepPath,
414
+ message: 'Step must be an object'
415
+ });
416
+ return;
417
+ }
418
+ // Check for task type
419
+ if (!step.task) {
420
+ errors.push({
421
+ type: 'missing_property',
422
+ path: `${stepPath}.task`,
423
+ message: 'Step must have a task property'
424
+ });
425
+ return;
426
+ }
427
+ // Validate nested structures (foreach, switch, while)
428
+ this.validateNestedSteps(step, stepPath, errors, warnings);
429
+ }
430
+ /**
431
+ * Validate nested structures within control flow tasks
432
+ */
433
+ validateNestedSteps(step, stepPath, errors, warnings) {
434
+ const taskType = step.task;
435
+ // Handle foreach
436
+ if (taskType === 'foreach') {
437
+ if (step.steps && Array.isArray(step.steps)) {
438
+ step.steps.forEach((nestedStep, index) => {
439
+ this.validateStep(nestedStep, `${stepPath}.steps[${index}]`, errors, warnings);
440
+ });
441
+ }
442
+ }
443
+ // Handle switch
444
+ if (taskType === 'switch') {
445
+ if (step.cases && Array.isArray(step.cases)) {
446
+ step.cases.forEach((caseItem, caseIndex) => {
447
+ if (caseItem.steps && Array.isArray(caseItem.steps)) {
448
+ caseItem.steps.forEach((nestedStep, stepIndex) => {
449
+ this.validateStep(nestedStep, `${stepPath}.cases[${caseIndex}].steps[${stepIndex}]`, errors, warnings);
450
+ });
451
+ }
452
+ });
453
+ }
454
+ if (step.default && step.default.steps && Array.isArray(step.default.steps)) {
455
+ step.default.steps.forEach((nestedStep, index) => {
456
+ this.validateStep(nestedStep, `${stepPath}.default.steps[${index}]`, errors, warnings);
457
+ });
458
+ }
459
+ }
460
+ // Handle while
461
+ if (taskType === 'while') {
462
+ if (step.steps && Array.isArray(step.steps)) {
463
+ step.steps.forEach((nestedStep, index) => {
464
+ this.validateStep(nestedStep, `${stepPath}.steps[${index}]`, errors, warnings);
465
+ });
466
+ }
467
+ }
468
+ }
469
+ /**
470
+ * Validate Flow workflow sections (entity, states, transitions, aggregations)
471
+ */
472
+ validateFlowWorkflow(workflowData, errors, warnings) {
473
+ this.validateFlowEntity(workflowData, errors);
474
+ const stateNames = this.validateFlowStates(workflowData, errors, warnings);
475
+ this.validateFlowTransitions(workflowData, stateNames, errors, warnings);
476
+ this.validateFlowAggregations(workflowData, errors);
477
+ }
478
+ /**
479
+ * Validate Flow entity section
480
+ */
481
+ validateFlowEntity(workflowData, errors) {
482
+ const entity = workflowData.entity;
483
+ if (!entity)
484
+ return;
485
+ if (!entity.name) {
486
+ errors.push({
487
+ type: 'missing_property',
488
+ path: 'entity.name',
489
+ message: 'Entity name is required for Flow workflows'
490
+ });
491
+ }
492
+ }
493
+ /**
494
+ * Validate Flow states and return set of state names
495
+ */
496
+ validateFlowStates(workflowData, errors, warnings) {
497
+ const stateNames = new Set();
498
+ const states = workflowData.states;
499
+ if (!states || !Array.isArray(states))
500
+ return stateNames;
501
+ let initialStateCount = 0;
502
+ const parentStates = new Set();
503
+ // First pass: collect state names and parents
504
+ for (const state of states) {
505
+ if (state.name)
506
+ stateNames.add(state.name);
507
+ if (state.parent)
508
+ parentStates.add(state.parent);
509
+ }
510
+ // Second pass: validate each state
511
+ states.forEach((state, index) => {
512
+ const statePath = `states[${index}]`;
513
+ if (!state.name) {
514
+ errors.push({
515
+ type: 'missing_property',
516
+ path: `${statePath}.name`,
517
+ message: 'State name is required'
518
+ });
519
+ return;
520
+ }
521
+ // Check for duplicate names
522
+ const duplicates = states.filter((s) => s.name?.toLowerCase() === state.name?.toLowerCase());
523
+ if (duplicates.length > 1) {
524
+ errors.push({
525
+ type: 'schema_violation',
526
+ path: `${statePath}.name`,
527
+ message: `Duplicate state name '${state.name}'`
528
+ });
529
+ }
530
+ if (state.isInitial)
531
+ initialStateCount++;
532
+ // Validate parent reference
533
+ if (state.parent && !stateNames.has(state.parent)) {
534
+ errors.push({
535
+ type: 'schema_violation',
536
+ path: `${statePath}.parent`,
537
+ message: `Parent state '${state.parent}' not found`
538
+ });
539
+ }
540
+ // Validate onEnter/onExit steps
541
+ if (state.onEnter && Array.isArray(state.onEnter)) {
542
+ state.onEnter.forEach((step, stepIndex) => {
543
+ this.validateStep(step, `${statePath}.onEnter[${stepIndex}]`, errors, warnings);
544
+ });
545
+ }
546
+ if (state.onExit && Array.isArray(state.onExit)) {
547
+ state.onExit.forEach((step, stepIndex) => {
548
+ this.validateStep(step, `${statePath}.onExit[${stepIndex}]`, errors, warnings);
549
+ });
550
+ }
551
+ });
552
+ if (initialStateCount > 1) {
553
+ errors.push({
554
+ type: 'schema_violation',
555
+ path: 'states',
556
+ message: `Found ${initialStateCount} initial states. At most one state can be marked as initial.`
557
+ });
558
+ }
559
+ return stateNames;
560
+ }
561
+ /**
562
+ * Validate Flow transitions
563
+ */
564
+ validateFlowTransitions(workflowData, stateNames, errors, warnings) {
565
+ const transitions = workflowData.transitions;
566
+ if (!transitions || !Array.isArray(transitions))
567
+ return;
568
+ const transitionNames = new Set();
569
+ transitions.forEach((transition, index) => {
570
+ const transPath = `transitions[${index}]`;
571
+ if (!transition.name) {
572
+ errors.push({
573
+ type: 'missing_property',
574
+ path: `${transPath}.name`,
575
+ message: 'Transition name is required'
576
+ });
577
+ }
578
+ else if (transitionNames.has(transition.name.toLowerCase())) {
579
+ errors.push({
580
+ type: 'schema_violation',
581
+ path: `${transPath}.name`,
582
+ message: `Duplicate transition name '${transition.name}'`
583
+ });
584
+ }
585
+ else {
586
+ transitionNames.add(transition.name.toLowerCase());
587
+ }
588
+ // Validate from states
589
+ if (transition.from && stateNames.size > 0) {
590
+ const fromStates = Array.isArray(transition.from) ? transition.from : [transition.from];
591
+ for (const fromState of fromStates) {
592
+ if (fromState !== '*' && !stateNames.has(fromState)) {
593
+ errors.push({
594
+ type: 'schema_violation',
595
+ path: `${transPath}.from`,
596
+ message: `Source state '${fromState}' not found in states`
597
+ });
598
+ }
599
+ }
600
+ }
601
+ // Validate to state
602
+ if (transition.to && stateNames.size > 0 && !stateNames.has(transition.to)) {
603
+ errors.push({
604
+ type: 'schema_violation',
605
+ path: `${transPath}.to`,
606
+ message: `Target state '${transition.to}' not found in states`
607
+ });
608
+ }
609
+ // Validate trigger
610
+ const validTriggers = ['auto', 'manual', 'event'];
611
+ if (transition.trigger && !validTriggers.includes(transition.trigger)) {
612
+ errors.push({
613
+ type: 'schema_violation',
614
+ path: `${transPath}.trigger`,
615
+ message: `Invalid trigger '${transition.trigger}'. Valid triggers: ${validTriggers.join(', ')}`
616
+ });
617
+ }
618
+ // Validate event trigger requires eventName
619
+ if (transition.trigger === 'event' && !transition.eventName) {
620
+ errors.push({
621
+ type: 'missing_property',
622
+ path: `${transPath}.eventName`,
623
+ message: "eventName is required when trigger is 'event'"
624
+ });
625
+ }
626
+ // Validate transition steps
627
+ if (transition.steps && Array.isArray(transition.steps)) {
628
+ transition.steps.forEach((step, stepIndex) => {
629
+ this.validateStep(step, `${transPath}.steps[${stepIndex}]`, errors, warnings);
630
+ });
631
+ }
632
+ });
633
+ }
634
+ /**
635
+ * Validate Flow aggregations
636
+ */
637
+ validateFlowAggregations(workflowData, errors) {
638
+ const aggregations = workflowData.aggregations;
639
+ if (!aggregations || !Array.isArray(aggregations))
640
+ return;
641
+ const validFunctions = ['all', 'any', 'sum', 'count', 'first', 'last', 'distinct', 'groupBy'];
642
+ const aggregationNames = new Set();
643
+ aggregations.forEach((aggregation, index) => {
644
+ const aggPath = `aggregations[${index}]`;
645
+ if (!aggregation.name) {
646
+ errors.push({
647
+ type: 'missing_property',
648
+ path: `${aggPath}.name`,
649
+ message: 'Aggregation name is required'
650
+ });
651
+ }
652
+ else if (aggregationNames.has(aggregation.name.toLowerCase())) {
653
+ errors.push({
654
+ type: 'schema_violation',
655
+ path: `${aggPath}.name`,
656
+ message: `Duplicate aggregation name '${aggregation.name}'`
657
+ });
658
+ }
659
+ else {
660
+ aggregationNames.add(aggregation.name.toLowerCase());
661
+ }
662
+ if (!aggregation.expression) {
663
+ errors.push({
664
+ type: 'missing_property',
665
+ path: `${aggPath}.expression`,
666
+ message: 'Aggregation expression is required'
667
+ });
668
+ }
669
+ else {
670
+ const fnMatch = aggregation.expression.match(/^(\w+)\s*\(/);
671
+ if (fnMatch) {
672
+ if (!validFunctions.includes(fnMatch[1].toLowerCase())) {
673
+ errors.push({
674
+ type: 'schema_violation',
675
+ path: `${aggPath}.expression`,
676
+ message: `Invalid aggregation function '${fnMatch[1]}'. Valid functions: ${validFunctions.join(', ')}`
677
+ });
678
+ }
679
+ }
680
+ else {
681
+ errors.push({
682
+ type: 'schema_violation',
683
+ path: `${aggPath}.expression`,
684
+ message: 'Aggregation expression must start with a function call'
685
+ });
686
+ }
687
+ }
688
+ });
689
+ }
690
+ /**
691
+ * Convert Ajv errors to our error format
692
+ */
693
+ addAjvErrors(ajvErrors, basePath, errors) {
694
+ if (!ajvErrors)
695
+ return;
696
+ for (const error of ajvErrors) {
697
+ const errorPath = basePath ? `${basePath}${error.instancePath}` : error.instancePath.slice(1);
698
+ errors.push({
699
+ type: 'schema_violation',
700
+ path: errorPath || '/',
701
+ message: error.message || 'Schema validation failed',
702
+ schemaPath: error.schemaPath
703
+ });
704
+ }
705
+ }
706
+ /**
707
+ * Check for deprecated properties
708
+ */
709
+ checkDeprecatedProperties(obj, path, warnings) {
710
+ const deprecations = {
711
+ // Add deprecated workflow properties here as needed
712
+ };
713
+ for (const [oldProp, message] of Object.entries(deprecations)) {
714
+ if (oldProp in obj) {
715
+ warnings.push({
716
+ type: 'deprecated_property',
717
+ path: `${path}.${oldProp}`,
718
+ message
719
+ });
720
+ }
721
+ }
722
+ }
723
+ /**
724
+ * Create validation result
725
+ */
726
+ createResult(filePath, errors, warnings) {
727
+ const errorsByType = {};
728
+ errors.forEach(error => {
729
+ errorsByType[error.type] = (errorsByType[error.type] || 0) + 1;
730
+ });
731
+ return {
732
+ isValid: errors.length === 0,
733
+ errors,
734
+ warnings: this.options.includeWarnings ? warnings : [],
735
+ summary: {
736
+ file: filePath,
737
+ timestamp: new Date().toISOString(),
738
+ status: errors.length === 0 ? 'PASSED' : 'FAILED',
739
+ errorCount: errors.length,
740
+ warningCount: warnings.length,
741
+ errorsByType
742
+ }
743
+ };
744
+ }
745
+ /**
746
+ * Get all loaded schema keys
747
+ */
748
+ getLoadedSchemas() {
749
+ return Array.from(this.schemas.keys());
750
+ }
751
+ }
752
+ exports.WorkflowValidator = WorkflowValidator;
753
+ //# sourceMappingURL=workflowValidator.js.map