@aifabrix/builder 2.44.3 → 2.44.4

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 (56) 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 +12 -1
  5. package/lib/api/certificates.api.js +21 -3
  6. package/lib/certification/post-unified-cert-sync.js +13 -2
  7. package/lib/certification/sync-after-external-command.js +6 -3
  8. package/lib/certification/sync-system-certification.js +60 -14
  9. package/lib/cli/setup-app.test-commands.js +67 -35
  10. package/lib/cli/setup-utility.js +1 -1
  11. package/lib/commands/datasource-unified-test-cli.js +81 -46
  12. package/lib/commands/datasource-unified-test-cli.options.js +4 -2
  13. package/lib/commands/datasource.js +3 -31
  14. package/lib/commands/repair-datasource-keys.js +1 -1
  15. package/lib/commands/repair-datasource-openapi.js +57 -0
  16. package/lib/commands/repair-datasource.js +5 -0
  17. package/lib/commands/repair-internal.js +2 -4
  18. package/lib/commands/repair.js +1 -2
  19. package/lib/commands/test-e2e-external.js +5 -6
  20. package/lib/commands/upload.js +18 -4
  21. package/lib/commands/wizard-dataplane.js +14 -6
  22. package/lib/datasource/datasource-validate-display.js +162 -0
  23. package/lib/datasource/datasource-validate-summary.js +194 -0
  24. package/lib/datasource/test-e2e.js +65 -37
  25. package/lib/datasource/unified-validation-run-body.js +1 -2
  26. package/lib/datasource/validate.js +14 -6
  27. package/lib/external-system/test.js +12 -8
  28. package/lib/generator/external-controller-manifest.js +12 -2
  29. package/lib/schema/cip-capacity-display.fallback.json +7 -0
  30. package/lib/schema/datasource-test-run.schema.json +79 -1
  31. package/lib/schema/external-datasource.schema.json +94 -2
  32. package/lib/schema/flag-map-validation-run.json +1 -2
  33. package/lib/schema/type/document-storage.json +83 -3
  34. package/lib/utils/configuration-env-resolver.js +38 -0
  35. package/lib/utils/dataplane-resolver.js +3 -2
  36. package/lib/utils/datasource-test-run-capacity-operations.js +149 -0
  37. package/lib/utils/datasource-test-run-debug-display.js +143 -1
  38. package/lib/utils/datasource-test-run-display.js +46 -33
  39. package/lib/utils/datasource-test-run-tty-log.js +6 -2
  40. package/lib/utils/datasource-test-run-tty-meta-lines.js +123 -0
  41. package/lib/utils/error-formatter.js +32 -2
  42. package/lib/utils/external-system-readiness-core.js +39 -0
  43. package/lib/utils/external-system-readiness-deploy-display.js +2 -3
  44. package/lib/utils/external-system-readiness-display-internals.js +3 -2
  45. package/lib/utils/external-system-system-test-tty.js +33 -9
  46. package/lib/utils/external-system-validators.js +62 -5
  47. package/lib/utils/load-cip-capacity-display-config.js +130 -0
  48. package/lib/utils/paths.js +10 -3
  49. package/lib/utils/schema-resolver.js +98 -2
  50. package/lib/utils/validation-run-poll.js +15 -4
  51. package/lib/utils/validation-run-request.js +4 -6
  52. package/lib/validation/dimension-display-helpers.js +60 -0
  53. package/lib/validation/validate-display-log-helpers.js +39 -0
  54. package/lib/validation/validate-display.js +89 -83
  55. package/package.json +1 -1
  56. package/templates/external-system/README.md.hbs +1 -2
@@ -175,6 +175,96 @@ function resolveDatasourceFiles(schemaBasePath, datasourceFiles) {
175
175
  return datasourceFiles.map(fileName => resolveSingleExternalFile(schemaBasePath, fileName, 'datasource'));
176
176
  }
177
177
 
178
+ /**
179
+ * @param {string} schemaBasePath
180
+ * @param {string[]} systemFileNames
181
+ * @returns {string[]|null}
182
+ */
183
+ function readSystemDatasourceKeyOrder(schemaBasePath, systemFileNames) {
184
+ if (!Array.isArray(systemFileNames) || systemFileNames.length === 0) {
185
+ return null;
186
+ }
187
+ const systemPath = path.join(schemaBasePath, systemFileNames[0]);
188
+ if (!fs.existsSync(systemPath)) {
189
+ return null;
190
+ }
191
+ try {
192
+ const systemParsed = loadConfigFile(systemPath);
193
+ const orderKeys = Array.isArray(systemParsed.dataSources) ? systemParsed.dataSources : null;
194
+ return orderKeys && orderKeys.length > 0 ? orderKeys : null;
195
+ } catch {
196
+ return null;
197
+ }
198
+ }
199
+
200
+ /**
201
+ * @param {string} schemaBasePath
202
+ * @param {string[]} datasourceFileNames
203
+ * @returns {Map<string, string>}
204
+ */
205
+ function mapDatasourceKeysToFilenames(schemaBasePath, datasourceFileNames) {
206
+ const byKey = new Map();
207
+ for (const fileName of datasourceFileNames) {
208
+ if (typeof fileName !== 'string') {
209
+ continue;
210
+ }
211
+ const fp = path.join(schemaBasePath, fileName);
212
+ if (!fs.existsSync(fp)) {
213
+ continue;
214
+ }
215
+ try {
216
+ const d = loadConfigFile(fp);
217
+ const k = d && typeof d.key === 'string' ? d.key.trim() : '';
218
+ if (k) {
219
+ byKey.set(k, fileName);
220
+ }
221
+ } catch {
222
+ /* tail via original list */
223
+ }
224
+ }
225
+ return byKey;
226
+ }
227
+
228
+ /**
229
+ * Reorder datasource filenames to match external system JSON `dataSources` key order when present.
230
+ * Keeps application.yaml list membership but fixes FK-safe sequencing when filenames were sorted or drifted.
231
+ *
232
+ * @param {string} schemaBasePath
233
+ * @param {string[]} systemFileNames - externalIntegration.systems
234
+ * @param {string[]} datasourceFileNames - externalIntegration.dataSources filenames
235
+ * @returns {string[]} Same filenames, system-declaration order first, then any leftovers in original order
236
+ */
237
+ function orderDatasourceFileNamesBySystemKeys(
238
+ schemaBasePath,
239
+ systemFileNames,
240
+ datasourceFileNames
241
+ ) {
242
+ if (!Array.isArray(datasourceFileNames) || datasourceFileNames.length <= 1) {
243
+ return datasourceFileNames;
244
+ }
245
+ const orderKeys = readSystemDatasourceKeyOrder(schemaBasePath, systemFileNames);
246
+ if (!orderKeys) {
247
+ return datasourceFileNames;
248
+ }
249
+ const byKey = mapDatasourceKeysToFilenames(schemaBasePath, datasourceFileNames);
250
+ const out = [];
251
+ const used = new Set();
252
+ for (const k of orderKeys) {
253
+ const ks = typeof k === 'string' ? k.trim() : '';
254
+ const f = ks ? byKey.get(ks) : null;
255
+ if (f && !used.has(f)) {
256
+ out.push(f);
257
+ used.add(f);
258
+ }
259
+ }
260
+ for (const fileName of datasourceFileNames) {
261
+ if (fileName && !used.has(fileName)) {
262
+ out.push(fileName);
263
+ }
264
+ }
265
+ return out.length ? out : datasourceFileNames;
266
+ }
267
+
178
268
  /**
179
269
  * Loads and validates application config
180
270
  * @async
@@ -206,13 +296,19 @@ async function resolveExternalFiles(appName, options = {}) {
206
296
 
207
297
  const schemaBasePath = await resolveSchemaBasePath(appName, options);
208
298
  const systemFiles = resolveSystemFiles(schemaBasePath, variables.externalIntegration.systems);
209
- const datasourceFiles = resolveDatasourceFiles(schemaBasePath, variables.externalIntegration.dataSources);
299
+ const orderedNames = orderDatasourceFileNamesBySystemKeys(
300
+ schemaBasePath,
301
+ variables.externalIntegration.systems,
302
+ variables.externalIntegration.dataSources || []
303
+ );
304
+ const datasourceFiles = resolveDatasourceFiles(schemaBasePath, orderedNames);
210
305
 
211
306
  return [...systemFiles, ...datasourceFiles];
212
307
  }
213
308
 
214
309
  module.exports = {
215
310
  resolveSchemaBasePath,
216
- resolveExternalFiles
311
+ resolveExternalFiles,
312
+ orderDatasourceFileNamesBySystemKeys
217
313
  };
218
314
 
@@ -8,16 +8,25 @@ const chalk = require('chalk');
8
8
  const logger = require('./logger');
9
9
  const { getValidationRunWithTransportRetry } = require('./validation-run-post-retry');
10
10
 
11
- const INITIAL_INTERVAL_MS = 2000;
11
+ /** Short fixed delay while waiting for async E2E (typically a few seconds). */
12
+ const FAST_POLL_COUNT = 24;
13
+ const FAST_POLL_INTERVAL_MS = 400;
14
+ /** After fast phase, exponential backoff to limit load on long runs. */
15
+ const SLOW_BASE_INTERVAL_MS = 2000;
12
16
  const MAX_INTERVAL_MS = 15000;
13
17
 
14
18
  /**
15
- * Delay between polls after attempt `n` (0-based): 2s, 4s, 8s, … cap 15s.
19
+ * Delay between polls after attempt `n` (0-based).
20
+ * Fast phase (~10s of 400ms gaps) so CLI detects completion quickly; then 2s, 4s, … cap 15s.
16
21
  * @param {number} attemptIndex - Zero-based poll index after initial POST
17
22
  * @returns {number}
18
23
  */
19
24
  function nextPollDelayMs(attemptIndex) {
20
- const raw = INITIAL_INTERVAL_MS * 2 ** Math.max(0, attemptIndex);
25
+ if (attemptIndex < FAST_POLL_COUNT) {
26
+ return FAST_POLL_INTERVAL_MS;
27
+ }
28
+ const slowIndex = attemptIndex - FAST_POLL_COUNT;
29
+ const raw = SLOW_BASE_INTERVAL_MS * 2 ** Math.max(0, slowIndex);
21
30
  return Math.min(raw, MAX_INTERVAL_MS);
22
31
  }
23
32
 
@@ -104,7 +113,9 @@ async function pollValidationRunUntilComplete(opts) {
104
113
  }
105
114
 
106
115
  module.exports = {
107
- INITIAL_INTERVAL_MS,
116
+ FAST_POLL_COUNT,
117
+ FAST_POLL_INTERVAL_MS,
118
+ SLOW_BASE_INTERVAL_MS,
108
119
  MAX_INTERVAL_MS,
109
120
  nextPollDelayMs,
110
121
  pollValidationRunUntilComplete,
@@ -36,9 +36,8 @@ function assignOptionalNonNegativeInt(e2e, key, raw) {
36
36
  * @param {Object} options - CLI-derived options
37
37
  * @param {boolean} [options.debug]
38
38
  * @param {boolean} [options.verbose]
39
- * @param {boolean} [options.testCrud]
40
- * @param {string} [options.recordId]
41
39
  * @param {boolean} [options.cleanup]
40
+ * @param {boolean} [options.runScenarios] - false when --no-run-scenarios
42
41
  * @param {string|Object} [options.primaryKeyValue]
43
42
  * @param {Object} [options.e2eOptionsExtra] - Shallow-merged last (e.g. server-specific drill-down fields)
44
43
  * @returns {Object}
@@ -47,15 +46,14 @@ function buildE2eOptionsFromCli(options = {}) {
47
46
  const e2e = {};
48
47
  if (options.debug) e2e.includeDebug = true;
49
48
  if (options.verbose) e2e.audit = true;
50
- if (options.testCrud === true) e2e.testCrud = true;
51
- if (options.recordId !== undefined && options.recordId !== null && options.recordId !== '') {
52
- e2e.recordId = String(options.recordId);
53
- }
54
49
  if (options.cleanup === false) e2e.cleanup = false;
55
50
  else if (options.cleanup === true) e2e.cleanup = true;
56
51
  if (options.primaryKeyValue !== undefined && options.primaryKeyValue !== null) {
57
52
  e2e.primaryKeyValue = options.primaryKeyValue;
58
53
  }
54
+ if (options.runScenarios === false) {
55
+ e2e.runScenarios = false;
56
+ }
59
57
  assignOptionalNonNegativeInt(e2e, 'minVectorHits', options.minVectorHits);
60
58
  assignOptionalNonNegativeInt(e2e, 'minProcessed', options.minProcessed);
61
59
  assignOptionalNonNegativeInt(e2e, 'minRecordCount', options.minRecordCount);
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @fileoverview Flatten datasource root `dimensions` for validate CLI output.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ /**
8
+ * @param {Array<{ fk?: string, dimension?: string }>} via - dimensionBinding.via
9
+ * @returns {string}
10
+ */
11
+ function formatFkViaChain(via) {
12
+ return via
13
+ .map(v =>
14
+ v && typeof v.fk === 'string' && typeof v.dimension === 'string' ? `${v.fk}→${v.dimension}` : ''
15
+ )
16
+ .filter(Boolean)
17
+ .join(', ');
18
+ }
19
+
20
+ /**
21
+ * @param {unknown} actor - dimensionBinding.actor
22
+ * @returns {string}
23
+ */
24
+ function formatFkActorSuffix(actor) {
25
+ return typeof actor === 'string' && actor.length > 0 ? ` (actor: ${actor})` : '';
26
+ }
27
+
28
+ /**
29
+ * Flatten root dimensions: local → metadata.<field>, fk → fk:<chain> (actor: ...).
30
+ * @param {Record<string, unknown>|null|undefined} root - datasource.dimensions
31
+ * @returns {Record<string, string>}
32
+ */
33
+ function flattenRootDimensionsForDisplay(root) {
34
+ const rootFlat = {};
35
+ if (!root || typeof root !== 'object' || Array.isArray(root)) {
36
+ return rootFlat;
37
+ }
38
+ for (const [dimKey, binding] of Object.entries(root)) {
39
+ if (!binding || typeof binding !== 'object') {
40
+ continue;
41
+ }
42
+ if (typeof binding.field === 'string') {
43
+ rootFlat[dimKey] = `metadata.${binding.field}`;
44
+ continue;
45
+ }
46
+ if (binding.type !== 'fk' || !Array.isArray(binding.via)) {
47
+ continue;
48
+ }
49
+ const chain = formatFkViaChain(binding.via);
50
+ if (!chain) {
51
+ continue;
52
+ }
53
+ rootFlat[dimKey] = `fk:${chain}${formatFkActorSuffix(binding.actor)}`;
54
+ }
55
+ return rootFlat;
56
+ }
57
+
58
+ module.exports = {
59
+ flattenRootDimensionsForDisplay
60
+ };
@@ -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
+ };