@aifabrix/builder 2.44.3 → 2.44.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 (72) hide show
  1. package/.npmrc.token +1 -1
  2. package/integration/roundtrip-test-local/README.md +1 -2
  3. package/integration/roundtrip-test-local2/README.md +1 -2
  4. package/jest.projects.js +31 -15
  5. package/lib/api/certificates.api.js +21 -3
  6. package/lib/api/types/wizard.types.js +2 -1
  7. package/lib/certification/post-unified-cert-sync.js +13 -2
  8. package/lib/certification/sync-after-external-command.js +6 -3
  9. package/lib/certification/sync-system-certification.js +60 -14
  10. package/lib/cli/setup-app.help.js +1 -1
  11. package/lib/cli/setup-app.test-commands.js +75 -39
  12. package/lib/cli/setup-infra.js +6 -2
  13. package/lib/cli/setup-utility.js +20 -1
  14. package/lib/commands/datasource-unified-test-cli.js +81 -46
  15. package/lib/commands/datasource-unified-test-cli.options.js +4 -2
  16. package/lib/commands/datasource.js +3 -31
  17. package/lib/commands/repair-datasource-keys.js +1 -1
  18. package/lib/commands/repair-datasource-openapi.js +57 -0
  19. package/lib/commands/repair-datasource.js +5 -0
  20. package/lib/commands/repair-internal.js +2 -4
  21. package/lib/commands/repair-rbac.js +25 -2
  22. package/lib/commands/repair.js +2 -19
  23. package/lib/commands/test-e2e-external.js +9 -9
  24. package/lib/commands/up-common.js +25 -0
  25. package/lib/commands/upload.js +18 -4
  26. package/lib/commands/wizard-core.js +53 -11
  27. package/lib/commands/wizard-dataplane.js +14 -6
  28. package/lib/commands/wizard-entity-selection.js +71 -14
  29. package/lib/commands/wizard-headless.js +5 -2
  30. package/lib/commands/wizard-helpers.js +13 -1
  31. package/lib/commands/wizard.js +208 -60
  32. package/lib/datasource/datasource-validate-display.js +162 -0
  33. package/lib/datasource/datasource-validate-summary.js +194 -0
  34. package/lib/datasource/test-e2e.js +65 -37
  35. package/lib/datasource/unified-validation-run-body.js +1 -2
  36. package/lib/datasource/validate.js +14 -6
  37. package/lib/external-system/test.js +12 -8
  38. package/lib/generator/external-controller-manifest.js +12 -2
  39. package/lib/generator/wizard-prompts.js +7 -1
  40. package/lib/generator/wizard.js +34 -0
  41. package/lib/schema/cip-capacity-display.fallback.json +7 -0
  42. package/lib/schema/datasource-test-run.schema.json +79 -1
  43. package/lib/schema/external-datasource.schema.json +94 -2
  44. package/lib/schema/flag-map-validation-run.json +1 -2
  45. package/lib/schema/type/document-storage.json +83 -3
  46. package/lib/schema/wizard-config.schema.json +1 -1
  47. package/lib/utils/configuration-env-resolver.js +38 -0
  48. package/lib/utils/dataplane-resolver.js +3 -2
  49. package/lib/utils/datasource-test-run-capacity-operations.js +149 -0
  50. package/lib/utils/datasource-test-run-debug-display.js +143 -1
  51. package/lib/utils/datasource-test-run-display.js +46 -33
  52. package/lib/utils/datasource-test-run-tty-log.js +6 -2
  53. package/lib/utils/datasource-test-run-tty-meta-lines.js +123 -0
  54. package/lib/utils/error-formatter.js +32 -2
  55. package/lib/utils/external-readme.js +47 -3
  56. package/lib/utils/external-system-readiness-core.js +39 -0
  57. package/lib/utils/external-system-readiness-deploy-display.js +2 -3
  58. package/lib/utils/external-system-readiness-display-internals.js +3 -2
  59. package/lib/utils/external-system-system-test-tty.js +33 -9
  60. package/lib/utils/external-system-validators.js +62 -5
  61. package/lib/utils/load-cip-capacity-display-config.js +130 -0
  62. package/lib/utils/paths.js +10 -3
  63. package/lib/utils/schema-resolver.js +98 -2
  64. package/lib/utils/urls-local-registry.js +52 -10
  65. package/lib/utils/validation-run-poll.js +15 -4
  66. package/lib/utils/validation-run-request.js +4 -6
  67. package/lib/validation/dimension-display-helpers.js +60 -0
  68. package/lib/validation/validate-display-log-helpers.js +39 -0
  69. package/lib/validation/validate-display.js +89 -83
  70. package/package.json +1 -1
  71. package/templates/applications/miso-controller/env.template +6 -6
  72. package/templates/external-system/README.md.hbs +58 -32
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @fileoverview Shared log helpers for validate-display (layout.md tty-summary).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const logger = require('../utils/logger');
11
+ const { sectionTitle, metadata, successGlyph } = require('../utils/cli-test-layout-chalk');
12
+
13
+ function logSectionTitle(title) {
14
+ logger.log(`\n${sectionTitle(title)}`);
15
+ }
16
+
17
+ function logOkRowRest(message) {
18
+ logger.log(` ${successGlyph()} ${chalk.white(message)}`);
19
+ }
20
+
21
+ function logWarnRow(message) {
22
+ logger.log(` ${chalk.yellow('⚠')} ${chalk.white(message)}`);
23
+ }
24
+
25
+ function logDimLine(text) {
26
+ logger.log(metadata(` ${text}`));
27
+ }
28
+
29
+ function logErrorDetail(message) {
30
+ logger.log(` ${chalk.red(`• ${message}`)}`);
31
+ }
32
+
33
+ module.exports = {
34
+ logSectionTitle,
35
+ logOkRowRest,
36
+ logWarnRow,
37
+ logDimLine,
38
+ logErrorDetail
39
+ };
@@ -1,18 +1,30 @@
1
- const { formatBlockingError, formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
+ const {
2
+ headerKeyValue,
3
+ metadata,
4
+ formatDatasourceListRow,
5
+ formatBlockingError,
6
+ formatSuccessLine,
7
+ formatSuccessParagraph,
8
+ successGlyph,
9
+ failureGlyph
10
+ } = require('../utils/cli-test-layout-chalk');
2
11
  /**
3
- * Validation Display Utilities
4
- *
5
- * Display functions for validation results output.
6
- *
7
- * @fileoverview Validation display utilities for AI Fabrix Builder
12
+ * @fileoverview Validation display for `aifabrix validate` (tty-summary: cli-layout.mdc, layout.md).
8
13
  * @author AI Fabrix Team
9
- * @version 2.0.0
10
14
  */
11
15
 
12
16
  const path = require('path');
13
17
  const chalk = require('chalk');
14
18
  const logger = require('../utils/logger');
15
19
  const { loadConfigFile } = require('../utils/config-format');
20
+ const { flattenRootDimensionsForDisplay } = require('./dimension-display-helpers');
21
+ const {
22
+ logSectionTitle,
23
+ logOkRowRest,
24
+ logWarnRow,
25
+ logDimLine,
26
+ logErrorDetail
27
+ } = require('./validate-display-log-helpers');
16
28
 
17
29
  /**
18
30
  * Displays application validation results
@@ -24,26 +36,27 @@ function displayApplicationValidation(application) {
24
36
  return;
25
37
  }
26
38
 
27
- logger.log(chalk.blue('\nApplication:'));
39
+ logSectionTitle('Application');
28
40
  if (application.valid) {
29
- logger.log(chalk.green('Application configuration is valid'));
41
+ logOkRowRest('Application configuration is valid');
30
42
  } else {
31
- logger.log(chalk.red('Application configuration has errors:'));
43
+ logger.log(` ${failureGlyph()} ${chalk.red('Application configuration has errors:')}`);
32
44
  if (application.errors && application.errors.length > 0) {
33
45
  application.errors.forEach(error => {
34
- logger.log(chalk.red(` • ${error}`));
46
+ logErrorDetail(error);
35
47
  });
36
48
  }
37
49
  }
38
50
  if (application.warnings && application.warnings.length > 0) {
39
51
  application.warnings.forEach(warning => {
40
- logger.log(chalk.yellow(` ⚠ ${warning}`));
52
+ logger.log(` ${chalk.yellow('')} ${chalk.white(warning)}`);
41
53
  });
42
54
  }
43
55
  }
44
56
 
45
57
  /**
46
- * Extracts dimensions from a datasource file
58
+ * Extracts dimensions from a datasource file for CLI display.
59
+ * Local bindings become `metadata.<field>`; FK bindings become `fk:<fk>→<dimension>...` plus optional `(actor: ...)`.
47
60
  * @function extractDimensionsFromDatasource
48
61
  * @param {string} filePath - Path to datasource file
49
62
  * @returns {Object} Dimensions info { dimensions: Object, dimensionKeys: string[], hasDimensions: boolean }
@@ -52,15 +65,7 @@ function extractDimensionsFromDatasource(filePath) {
52
65
  try {
53
66
  const parsed = loadConfigFile(filePath);
54
67
 
55
- const rootFlat = {};
56
- const root = parsed.dimensions;
57
- if (root && typeof root === 'object' && !Array.isArray(root)) {
58
- for (const [dimKey, binding] of Object.entries(root)) {
59
- if (binding && typeof binding === 'object' && typeof binding.field === 'string') {
60
- rootFlat[dimKey] = `metadata.${binding.field}`;
61
- }
62
- }
63
- }
68
+ const rootFlat = flattenRootDimensionsForDisplay(parsed.dimensions);
64
69
  const abacDimensions = parsed.abac?.dimensions || {};
65
70
  const allDimensions = { ...rootFlat, ...abacDimensions };
66
71
  const dimensionKeys = Object.keys(allDimensions);
@@ -85,19 +90,19 @@ function displayExternalFilesValidation(externalFiles) {
85
90
  return;
86
91
  }
87
92
 
88
- logger.log(chalk.blue('\nExternal Integration Files:'));
93
+ logSectionTitle('External integration files');
89
94
  externalFiles.forEach(file => {
90
95
  if (file.valid) {
91
- logger.log(chalk.green(` ✔ ${file.file} (${file.type})`));
96
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
92
97
  } else {
93
- logger.log(chalk.red(` ✖ ${file.file} (${file.type}):`));
98
+ logger.log(formatDatasourceListRow('fail', file.file, file.type));
94
99
  file.errors.forEach(error => {
95
- logger.log(chalk.red(` • ${error}`));
100
+ logErrorDetail(error);
96
101
  });
97
102
  }
98
103
  if (file.warnings && file.warnings.length > 0) {
99
104
  file.warnings.forEach(warning => {
100
- logger.log(chalk.yellow(` ⚠ ${warning}`));
105
+ logger.log(` ${chalk.yellow('')} ${chalk.white(warning)}`);
101
106
  });
102
107
  }
103
108
  });
@@ -122,7 +127,7 @@ function displayDimensionsValidation(externalFiles) {
122
127
  return [];
123
128
  }
124
129
 
125
- logger.log(chalk.blue('\nDimensions (ABAC):'));
130
+ logSectionTitle('Dimensions (ABAC)');
126
131
 
127
132
  const warnings = [];
128
133
  let anyDatasourceHasDimensions = false;
@@ -132,19 +137,19 @@ function displayDimensionsValidation(externalFiles) {
132
137
 
133
138
  if (dimensionsInfo.hasDimensions) {
134
139
  anyDatasourceHasDimensions = true;
135
- logger.log(chalk.green(` ✔ ${file.file}`));
140
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
136
141
  dimensionsInfo.dimensionKeys.forEach(key => {
137
142
  const mapping = dimensionsInfo.dimensions[key];
138
- logger.log(chalk.gray(` ${key} → ${mapping}`));
143
+ logDimLine(`${key} → ${mapping}`);
139
144
  });
140
145
  } else {
141
- logger.log(chalk.yellow(` ⚠ ${file.file} - no dimensions configured`));
146
+ logWarnRow(`${file.file} no dimensions configured`);
142
147
  warnings.push(`${file.file} - no dimensions configured, ABAC filtering disabled`);
143
148
  }
144
149
  });
145
150
 
146
151
  if (!anyDatasourceHasDimensions) {
147
- logger.log(chalk.yellow('No dimensions configured - ABAC filtering disabled for all datasources'));
152
+ logWarnRow('No dimensions configured ABAC filtering disabled for all datasources');
148
153
  }
149
154
 
150
155
  return warnings;
@@ -160,18 +165,18 @@ function displayRbacValidation(rbac) {
160
165
  return;
161
166
  }
162
167
 
163
- logger.log(chalk.blue('\nRBAC Configuration:'));
168
+ logSectionTitle('RBAC configuration');
164
169
  if (rbac.valid) {
165
- logger.log(chalk.green('RBAC configuration is valid'));
170
+ logOkRowRest('RBAC configuration is valid');
166
171
  } else {
167
- logger.log(chalk.red('RBAC configuration has errors:'));
172
+ logger.log(` ${failureGlyph()} ${chalk.red('RBAC configuration has errors:')}`);
168
173
  rbac.errors.forEach(error => {
169
- logger.log(chalk.red(` • ${error}`));
174
+ logErrorDetail(error);
170
175
  });
171
176
  }
172
177
  if (rbac.warnings && rbac.warnings.length > 0) {
173
178
  rbac.warnings.forEach(warning => {
174
- logger.log(chalk.yellow(` ⚠ ${warning}`));
179
+ logger.log(` ${chalk.yellow('')} ${chalk.white(warning)}`);
175
180
  });
176
181
  }
177
182
  }
@@ -186,19 +191,20 @@ function displayFileValidation(result) {
186
191
  return;
187
192
  }
188
193
 
189
- logger.log(chalk.blue(`\nFile: ${result.file}`));
190
- logger.log(chalk.blue(`Type: ${result.type}`));
194
+ logSectionTitle('File');
195
+ logger.log(` ${headerKeyValue('Path:', result.file)}`);
196
+ logger.log(` ${headerKeyValue('Type:', String(result.type))}`);
191
197
  if (result.valid) {
192
- logger.log(chalk.green('File is valid'));
198
+ logOkRowRest('File is valid');
193
199
  } else {
194
- logger.log(chalk.red('File has errors:'));
200
+ logger.log(` ${failureGlyph()} ${chalk.red('File has errors:')}`);
195
201
  result.errors.forEach(error => {
196
- logger.log(chalk.red(` • ${error}`));
202
+ logErrorDetail(error);
197
203
  });
198
204
  }
199
205
  if (result.warnings && result.warnings.length > 0) {
200
206
  result.warnings.forEach(warning => {
201
- logger.log(chalk.yellow(` ⚠ ${warning}`));
207
+ logger.log(` ${chalk.yellow('')} ${chalk.white(warning)}`);
202
208
  });
203
209
  }
204
210
  }
@@ -213,9 +219,9 @@ function displayAggregatedWarnings(warnings) {
213
219
  return;
214
220
  }
215
221
 
216
- logger.log(chalk.yellow('\nWarnings:'));
222
+ logSectionTitle('Warnings');
217
223
  warnings.forEach(warning => {
218
- logger.log(chalk.yellow(` • ${warning}`));
224
+ logger.log(` ${chalk.yellow('⚠')} ${chalk.white(warning)}`);
219
225
  });
220
226
  }
221
227
 
@@ -226,18 +232,18 @@ function displayAggregatedWarnings(warnings) {
226
232
  * @returns {void}
227
233
  */
228
234
  function displayApplicationStep(application) {
229
- logger.log(chalk.blue('\nApplication:'));
235
+ logSectionTitle('Application');
230
236
  if (application.valid) {
231
- logger.log(chalk.green('Application configuration is valid'));
237
+ logOkRowRest('Application configuration is valid');
232
238
  } else {
233
- logger.log(chalk.red('Application configuration has errors:'));
239
+ logger.log(` ${failureGlyph()} ${chalk.red('Application configuration has errors:')}`);
234
240
  application.errors.forEach(error => {
235
- logger.log(chalk.red(` • ${error}`));
241
+ logErrorDetail(error);
236
242
  });
237
243
  }
238
244
  if (application.warnings && application.warnings.length > 0) {
239
245
  application.warnings.forEach(warning => {
240
- logger.log(chalk.yellow(` ⚠ ${warning}`));
246
+ logger.log(` ${chalk.yellow('')} ${chalk.white(warning)}`);
241
247
  });
242
248
  }
243
249
  }
@@ -255,19 +261,19 @@ function displayComponentsStep(components) {
255
261
  return;
256
262
  }
257
263
 
258
- logger.log(chalk.blue('\nExternal Integration Files:'));
264
+ logSectionTitle('External integration files');
259
265
  if (hasFiles) {
260
266
  components.files.forEach(file => {
261
267
  if (file.valid) {
262
- logger.log(chalk.green(` ✔ ${file.file} (${file.type})`));
268
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
263
269
  } else {
264
- logger.log(chalk.red(` ✖ ${file.file} (${file.type})`));
270
+ logger.log(formatDatasourceListRow('fail', file.file, file.type));
265
271
  }
266
272
  });
267
273
  }
268
274
  if (hasErrors) {
269
275
  components.errors.forEach(error => {
270
- logger.log(chalk.red(` • ${error}`));
276
+ logger.log(formatBlockingError(error));
271
277
  });
272
278
  }
273
279
  }
@@ -283,18 +289,18 @@ function displayDimensionsStep(datasourceFiles) {
283
289
  return;
284
290
  }
285
291
 
286
- logger.log(chalk.blue('\nDimensions (ABAC):'));
292
+ logSectionTitle('Dimensions (ABAC)');
287
293
  datasourceFiles.forEach(file => {
288
294
  try {
289
295
  const dimensionsInfo = extractDimensionsFromDatasource(file.path || file.file);
290
296
  if (dimensionsInfo.hasDimensions) {
291
- logger.log(chalk.green(` ✔ ${file.file}`));
297
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
292
298
  dimensionsInfo.dimensionKeys.forEach(key => {
293
299
  const mapping = dimensionsInfo.dimensions[key];
294
- logger.log(chalk.gray(` ${key} → ${mapping}`));
300
+ logDimLine(`${key} → ${mapping}`);
295
301
  });
296
302
  } else {
297
- logger.log(chalk.yellow(` ⚠ ${file.file} - no dimensions configured`));
303
+ logWarnRow(`${file.file} no dimensions configured`);
298
304
  }
299
305
  } catch {
300
306
  // Skip if file path not available
@@ -310,32 +316,32 @@ function displayDimensionsStep(datasourceFiles) {
310
316
  * @returns {void}
311
317
  */
312
318
  function displayManifestStep(manifest, componentFiles) {
313
- logger.log(chalk.blue('\nDeployment Manifest:'));
319
+ logSectionTitle('Deployment manifest');
314
320
  if (manifest.skipped) {
315
- logger.log(chalk.yellow(' Skipped (fix errors above first)'));
321
+ logger.log(` ${chalk.gray('⏭')} ${chalk.white('Skipped (fix errors above first)')}`);
316
322
  } else if (manifest.valid) {
317
- logger.log(chalk.green('Full deployment manifest is valid'));
323
+ logOkRowRest('Full deployment manifest is valid');
318
324
  if (componentFiles) {
319
325
  const datasourceFiles = componentFiles.filter(f => f.type === 'datasource' || f.type === 'external-datasource');
320
- logger.log(chalk.green('System configuration valid'));
321
- logger.log(chalk.green(` ${datasourceFiles.length} datasource(s) valid`));
322
- logger.log(chalk.green('Schema validation passed'));
326
+ logger.log(` ${successGlyph()} ${chalk.white('System configuration valid')}`);
327
+ logger.log(` ${successGlyph()} ${chalk.white(`${datasourceFiles.length} datasource(s) valid`)}`);
328
+ logger.log(` ${successGlyph()} ${chalk.white('Schema validation passed')}`);
323
329
  }
324
330
  } else {
325
- logger.log(chalk.red('Full deployment manifest validation failed:'));
331
+ logger.log(` ${failureGlyph()} ${chalk.red('Full deployment manifest validation failed:')}`);
326
332
  const errs = manifest.errors && manifest.errors.length > 0 ? manifest.errors : [];
327
333
  if (errs.length > 0) {
328
334
  errs.forEach(error => {
329
335
  const msg = typeof error === 'string' ? error : String(error);
330
- logger.log(chalk.red(` • ${msg}`));
336
+ logErrorDetail(msg);
331
337
  });
332
338
  } else {
333
- logger.log(chalk.red('No error details available (check schema and manifest structure).'));
339
+ logErrorDetail('No error details available (check schema and manifest structure).');
334
340
  }
335
341
  }
336
342
  if (manifest.warnings && manifest.warnings.length > 0) {
337
343
  manifest.warnings.forEach(warning => {
338
- logger.log(chalk.yellow(` ⚠ ${warning}`));
344
+ logger.log(` ${chalk.yellow('')} ${chalk.white(warning)}`);
339
345
  });
340
346
  }
341
347
  }
@@ -349,7 +355,7 @@ function displayStepByStepValidation(result) {
349
355
  if (result.valid) {
350
356
  logger.log(formatSuccessParagraph('Validation passed!'));
351
357
  } else {
352
- logger.log(chalk.red('\n✖ Validation failed!'));
358
+ logger.log(`\n${formatBlockingError('Validation failed!')}`);
353
359
  }
354
360
 
355
361
  displayApplicationStep(result.steps.application);
@@ -375,7 +381,7 @@ function displayStepByStepValidation(result) {
375
381
 
376
382
  displayOverallStatus(result);
377
383
  if (result.appPath) {
378
- logger.log(chalk.gray(`\n${path.resolve(result.appPath)}`));
384
+ logger.log(`\n${metadata(path.resolve(result.appPath))}`);
379
385
  }
380
386
  }
381
387
 
@@ -392,9 +398,9 @@ function displayBatchValidationResults(batchResult) {
392
398
 
393
399
  const results = batchResult.results;
394
400
  results.forEach(item => {
395
- logger.log(chalk.blue(`\n--- ${item.appName} ---`));
401
+ logger.log(`\n${metadata('──')} ${chalk.white.bold(item.appName)} ${metadata('──')}`);
396
402
  if (item.error) {
397
- logger.log(chalk.red(` ${item.error}`));
403
+ logger.log(` ${failureGlyph()} ${chalk.red(item.error)}`);
398
404
  } else if (item.result) {
399
405
  displayValidationResults(item.result);
400
406
  }
@@ -402,13 +408,13 @@ function displayBatchValidationResults(batchResult) {
402
408
 
403
409
  const passed = results.filter(r => r.result && r.result.valid).length;
404
410
  const failed = results.length - passed;
405
- logger.log(chalk.blue('\n--- Summary ---'));
411
+ logSectionTitle('Summary');
406
412
  if (failed === 0) {
407
- logger.log(formatSuccessLine(`${passed} passed, 0 failed`));
408
- logger.log(chalk.green('Overall: Passed'));
413
+ logger.log(` ${formatSuccessLine(`${passed} passed, 0 failed`)}`);
414
+ logger.log(` ${headerKeyValue('Overall:', chalk.green('Passed'))}`);
409
415
  } else {
410
- logger.log(formatBlockingError(`${passed} passed, ${failed} failed`));
411
- logger.log(chalk.red('Overall: Failed'));
416
+ logger.log(` ${formatBlockingError(`${passed} passed, ${failed} failed`)}`);
417
+ logger.log(` ${headerKeyValue('Overall:', chalk.red('Failed'))}`);
412
418
  }
413
419
  }
414
420
 
@@ -427,12 +433,13 @@ function displayOverallStatus(result) {
427
433
  }
428
434
  }
429
435
  const hasWarnings = result.warnings && result.warnings.length > 0;
436
+ logger.log('');
430
437
  if (hasErrors) {
431
- logger.log(chalk.red('\nOverall: Failed'));
438
+ logger.log(headerKeyValue('Overall:', chalk.red('Failed')));
432
439
  } else if (hasWarnings) {
433
- logger.log(chalk.yellow('\nOverall: Passed with warnings'));
440
+ logger.log(headerKeyValue('Overall:', chalk.yellow('Passed with warnings')));
434
441
  } else {
435
- logger.log(chalk.green('\nOverall: Passed'));
442
+ logger.log(headerKeyValue('Overall:', chalk.green('Passed')));
436
443
  }
437
444
  }
438
445
 
@@ -453,7 +460,7 @@ function displayValidationResults(result) {
453
460
  if (result.valid) {
454
461
  logger.log(formatSuccessParagraph('Validation passed!'));
455
462
  } else {
456
- logger.log(chalk.red('\n✖ Validation failed!'));
463
+ logger.log(`\n${formatBlockingError('Validation failed!')}`);
457
464
  }
458
465
 
459
466
  displayApplicationValidation(result.application);
@@ -471,10 +478,9 @@ function displayValidationResults(result) {
471
478
 
472
479
  displayOverallStatus(result);
473
480
  if (result.appPath) {
474
- logger.log(chalk.gray(`\n${path.resolve(result.appPath)}`));
481
+ logger.log(`\n${metadata(path.resolve(result.appPath))}`);
475
482
  }
476
483
  }
477
-
478
484
  module.exports = {
479
485
  displayValidationResults,
480
486
  displayBatchValidationResults,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.44.3",
3
+ "version": "2.44.5",
4
4
  "description": "AI Fabrix Local Fabric & Deployment SDK",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -28,8 +28,12 @@ SKIP_FIRST_TIME_SETUP=false
28
28
  # Optional custom controller key for onboarding (default: miso-controller)
29
29
  ONBOARDING_CONTROLLER_KEY=miso-controller
30
30
 
31
- # Optional infrastructure name override for onboarding (default: from INFRASTRUCTURE_NAME or aifabrix)
32
- ONBOARDING_INFRASTRUCTURE_NAME=
31
+ # Infrastructure/service name used by controller/onboarding flows
32
+ INFRASTRUCTURE_NAME=aifabrix
33
+
34
+ # Azure region (required for first-time onboarding: controller record / provisioning metadata).
35
+ # Use the region you deploy to (e.g. westeurope, eastus, northeurope). Single env name: LOCATION.
36
+ LOCATION=westeurope
33
37
 
34
38
  # Required for admin user creation during onboarding
35
39
  # Password for the initial administrator user (username: admin)
@@ -319,10 +323,6 @@ MISO_ENVIRONMENT=miso
319
323
  MISO_CLIENTID=kv://miso-controller-client-idKeyVault
320
324
  MISO_CLIENTSECRET=kv://miso-controller-client-secretKeyVault
321
325
 
322
- # Allowed origins for CORS validation (comma-separated)
323
- # Use wildcards for ports: http://localhost:*
324
- MISO_ALLOWED_ORIGINS=http://localhost:*,url://host-public,url://host-private,url://dataplane-host-public,url://dataplane-host-private
325
-
326
326
  # Evaluation mode (optional .env override of DB controller.configuration.evaluation):
327
327
  # When true (default if DB omits flag), infra deploy may coerce :envKey to `miso` — e2e poll on `dev` can 404.
328
328
  # Set false locally to force path envKey to match deploy + GET .../deployments/:id.
@@ -20,13 +20,15 @@
20
20
  - `deploy.js` – Deploy script for the integration
21
21
  - `wizard.yaml` – Wizard configuration (if created via wizard)
22
22
 
23
- Optional: `{{rbacOptionalFile}}` – Roles and permissions merged into the system when present.
23
+ Optional: `{{rbacOptionalFile}}` – Roles and permissions merged into the system when
24
+ present.
24
25
 
25
26
  ## Quick Start
26
27
 
27
28
  Login to your controller
29
+
28
30
  ```bash
29
- aifabrix auth config --set-controller <url> --set-environment dev
31
+ aifabrix auth config --set-controller URL --set-environment dev
30
32
  aifabrix login
31
33
  ```
32
34
 
@@ -45,22 +47,25 @@ Edit files in `integration/{{appName}}/`:
45
47
  - **Authentication**: `{{systemKey}}-system{{fileExt}}` (auth type, credentials placeholders)
46
48
  - **Field mappings**: `{{systemKey}}-datasource-*{{fileExt}}` (dimensions, attributes, operations)
47
49
  - **Credential and configuration**: `env.template` (security settings and configuration variables)
48
-
49
50
  {{#if secretPaths}}{{#if secretPaths.length}}
51
+
50
52
  ### Secrets
51
53
 
52
54
  Secrets are resolved from `.aifabrix` or key vault. Set them with:
53
55
 
54
56
  ```bash
55
57
  {{#each secretPaths}}
56
- aifabrix secret set {{path}} <your value> # {{description}}
58
+ aifabrix secret set {{path}} VALUE # {{description}}
57
59
  {{/each}}
58
60
  ```
59
61
  {{/if}}{{/if}}
60
62
 
61
63
  ### 3. Validate configuration (local only)
62
64
 
63
- `aifabrix validate` runs **on your machine**: it loads files under `integration/{{appName}}/`, checks them against the application and external-system / external-datasource JSON schemas, and runs related manifest rules. It does **not** call the dataplane or any other remote API.
65
+ `aifabrix validate` runs **on your machine**: it loads files under
66
+ `integration/{{appName}}/`, checks them against the application and
67
+ external-system / external-datasource JSON schemas, and runs related manifest rules.
68
+ It does **not** call the dataplane or any other remote API.
64
69
 
65
70
  ```bash
66
71
  aifabrix validate {{appName}}
@@ -70,19 +75,23 @@ Use this before upload or deploy to catch structural and policy errors early.
70
75
 
71
76
  ### 4. Repair Deployment Manifest
72
77
 
73
- **Run repair regularly.** It keeps naming conventions, filenames, and the deployment manifest aligned with AI Fabrix platform best practices. Use it after editing datasources, env.template, or system config—and run it often to catch drift early.
78
+ **Run repair regularly.** It keeps naming conventions, filenames, and the deployment
79
+ manifest aligned with AI Fabrix platform best practices. Use it after editing
80
+ datasources, env.template, or system config—and run it often to catch drift early.
74
81
 
75
82
  ```bash
76
83
  aifabrix repair {{appName}}
77
84
  ```
78
85
 
79
86
  Options:
80
- --auth <method> Set authentication method (oauth2, aad, apikey, basic, queryParam, oidc, hmac, none); updates system file and env.template
81
- --dry-run Report changes only; do not write
82
- --rbac Ensure RBAC permissions per datasource and add default Admin/Reader roles if none exist
83
- --expose Set exposed.attributes on each datasource to all fieldMappings.attributes keys
84
- --sync Add default sync section to datasources that lack it
85
- --test Generate testPayload.payloadTemplate and testPayload.expectedResult from attributes
87
+
88
+ - `--auth METHOD` Set authentication method (`oauth2`, `aad`, `apikey`, `basic`,
89
+ `queryParam`, `oidc`, `hmac`, `none`); updates system file and env.template
90
+ - `--dry-run` Report changes only; do not write
91
+ - `--rbac` Ensure RBAC permissions per datasource and add default Admin/Reader roles if none exist
92
+ - `--expose` Set `exposed.attributes` on each datasource to all `fieldMappings.attributes` keys
93
+ - `--sync` — Add default sync section to datasources that lack it
94
+ - `--test` — Generate `testPayload.payloadTemplate` and `testPayload.expectedResult` from attributes
86
95
 
87
96
  ### 5. Upload to dataplane
88
97
 
@@ -93,12 +102,16 @@ aifabrix upload {{appName}}
93
102
  ## Testing
94
103
 
95
104
  | Command | Where it runs | Calls dataplane? |
96
- |--------|----------------|------------------|
105
+ | --- | --- | --- |
97
106
  | `aifabrix validate {{appName}}` | Local (schemas / files) | No |
98
107
  | `aifabrix test {{appName}}` | Local (manifest / payload checks) | No |
99
- | `aifabrix test-integration {{appName}}`, `aifabrix test-e2e {{appName}}`, `aifabrix datasource test …`, `aifabrix datasource test-integration …`, `aifabrix datasource test-e2e …` | Through configured auth | Yes — unified validation / pipeline API |
108
+ | `aifabrix test-integration {{appName}}` | Auth + dataplane | Yes |
109
+ | `aifabrix test-e2e {{appName}}` | Auth + dataplane | Yes |
110
+ | Datasource `test` / `test-integration` / `test-e2e` | Auth + dataplane | Yes |
100
111
 
101
- So: **validate** (and **`test`**) stay offline; **all integration and E2E test commands** exercise the system **via the API** (after login and a reachable dataplane).
112
+ So: **validate** (and **`test`**) stay offline; **all integration and E2E test
113
+ commands** exercise the system **via the API** (after login and a reachable
114
+ dataplane).
102
115
 
103
116
  ### Local checks (no API)
104
117
 
@@ -120,14 +133,16 @@ aifabrix test-e2e {{appName}}
120
133
  ```
121
134
 
122
135
  Options:
123
- -e, --env <env> Environment: dev, tst, or pro (builder: dev/tst for container)
124
- -v, --verbose Show detailed step output and poll progress
125
- --debug Include debug output and write log to integration/{{appName}}/logs/
126
- --no-async Use sync mode (no polling); single POST per datasource
136
+
137
+ - `-e`, `--env ENV` Environment: `dev`, `tst`, or `pro` (builder: dev/tst for container)
138
+ - `-v`, `--verbose` — Show detailed step output and poll progress
139
+ - `-d`, `--debug` Include debug output and write log to `integration/{{appName}}/logs/`
140
+ - `--no-async` — Use sync mode (no polling); single POST per datasource
127
141
 
128
142
  ### E2E tests per datasource
129
143
 
130
- To run a full E2E test for a single datasource (config, credential, sync, data, CIP), use `aifabrix datasource test-e2e` with the datasource key and app:
144
+ To run a full E2E test for a single datasource (config, credential, sync, data,
145
+ CIP), use `aifabrix datasource test-e2e` with the datasource key and app:
131
146
 
132
147
  {{#if hasDatasources}}
133
148
  ```bash
@@ -140,26 +155,37 @@ aifabrix datasource test-e2e {{datasourceKey}} --app {{../appName}}
140
155
  {{/if}}
141
156
 
142
157
  Options:
143
- -a, --app {{appName}} App key (default: resolve from cwd if inside integration/{{appName}}/)
144
- -e, --env <env> Environment: dev, tst, or pro
145
- -v, --verbose Show detailed step output and poll progress
146
- --debug Include debug output and write log to integration/{{appName}}/logs/
147
- --test-crud Enable CRUD lifecycle test (body testCrud: true)
148
- --record-id <id> Record ID for test (body recordId)
149
- --no-cleanup Disable cleanup after test (body cleanup: false)
150
- --primary-key-value <value|@path> Primary key value or path to JSON file (e.g. @pk.json) for body primaryKeyValue
151
- --no-async Use sync mode (no polling); single POST, no asyncRun
158
+
159
+ - `-a`, `--app {{appName}}` — App key (default: resolve from cwd if inside `integration/{{appName}}/`)
160
+ - `-e`, `--env ENV` Environment: `dev`, `tst`, or `pro`
161
+ - `-v`, `--verbose` — Show detailed step output and poll progress
162
+ - `-d`, `--debug` Include debug output and write log to `integration/{{appName}}/logs/`
163
+ - `--no-run-scenarios` Skip expanding `testPayload.scenarios` in capacity step
164
+ - `--no-cleanup` — Disable cleanup after test (body cleanup: false)
165
+ - `--primary-key-value VALUE` — Primary key value or path to JSON file (e.g.
166
+ `@pk.json`) for body `primaryKeyValue`
167
+ - `--no-async` — Use sync mode (no polling); single POST, no asyncRun
152
168
 
153
169
  ## Deployment
154
170
 
155
- Deploy via miso-controller pipeline (same as regular apps). Auth and controller come from `aifabrix login` and `aifabrix auth config`:
171
+ Deploy via miso-controller pipeline (same as regular apps). Auth and controller
172
+ come from `aifabrix login` and `aifabrix auth config`:
156
173
 
157
174
  ```bash
158
175
  aifabrix deploy {{appName}}
159
176
  ```
160
177
 
178
+ ## Delete
179
+
180
+ ```bash
181
+ aifabrix delete {{appName}}
182
+ ```
183
+
161
184
  ## Troubleshooting
162
185
 
163
- - **Local validation errors**: Run `aifabrix validate {{appName}}` (and `aifabrix test {{appName}}`) — these only inspect files on disk, not the dataplane.
164
- - **Deployment / auth**: Run `aifabrix auth config --set-controller <url> --set-environment <env>` and `aifabrix login` before `aifabrix deploy`.
186
+ - **Local validation errors**: Run `aifabrix validate {{appName}}` (and
187
+ `aifabrix test {{appName}}`) these only inspect files on disk, not the dataplane.
188
+ - **Deployment / auth**: Run
189
+ `aifabrix auth config --set-controller URL --set-environment ENV` and
190
+ `aifabrix login` before `aifabrix deploy`.
165
191
  - **File not found**: Run commands from the project root (where `package.json` and `integration/` live).