@aifabrix/builder 2.43.0 → 2.44.0

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 (346) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +1 -1
  3. package/anchor-docs/README.md +10 -0
  4. package/anchor-docs/_TEMPLATE +24 -0
  5. package/bin/aifabrix.js +13 -4
  6. package/integration/hubspot-test/README.md +31 -0
  7. package/integration/hubspot-test/create-hubspot.js +5 -5
  8. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  9. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  10. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  11. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  12. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  13. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  14. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  15. package/integration/hubspot-test/test.js +35 -43
  16. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  17. package/integration/roundtrip-test-local/README.md +144 -0
  18. package/integration/roundtrip-test-local/application.yaml +13 -0
  19. package/integration/roundtrip-test-local/env.template +15 -0
  20. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  21. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  22. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  23. package/integration/roundtrip-test-local2/README.md +144 -0
  24. package/integration/roundtrip-test-local2/application.yaml +13 -0
  25. package/integration/roundtrip-test-local2/env.template +15 -0
  26. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  27. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  28. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  29. package/integration/test/wizard.yaml +8 -0
  30. package/jest.config.default.js +10 -0
  31. package/jest.config.integration.fixtures.js +22 -0
  32. package/jest.config.integration.js +21 -18
  33. package/jest.config.isolated.js +10 -0
  34. package/jest.projects.js +288 -0
  35. package/lib/api/datasources-core.api.js +3 -3
  36. package/lib/api/dev-mtls-request.js +110 -0
  37. package/lib/api/dev-server-https.js +145 -0
  38. package/lib/api/dev.api.js +133 -144
  39. package/lib/api/index.js +0 -1
  40. package/lib/api/pipeline.api.js +67 -20
  41. package/lib/api/types/dev.types.js +4 -3
  42. package/lib/api/types/pipeline.types.js +8 -5
  43. package/lib/api/types/validation-run.types.js +56 -0
  44. package/lib/api/validation-run.api.js +99 -0
  45. package/lib/api/validation-runner.js +99 -0
  46. package/lib/app/config.js +1 -1
  47. package/lib/app/deploy-status-display.js +2 -2
  48. package/lib/app/deploy.js +7 -6
  49. package/lib/app/display.js +2 -1
  50. package/lib/app/dockerfile.js +3 -2
  51. package/lib/app/down.js +2 -1
  52. package/lib/app/helpers.js +6 -5
  53. package/lib/app/index.js +27 -8
  54. package/lib/app/list.js +7 -6
  55. package/lib/app/push.js +4 -3
  56. package/lib/app/register.js +16 -7
  57. package/lib/app/rotate-secret.js +14 -13
  58. package/lib/app/run-container-start.js +184 -0
  59. package/lib/app/run-docker-fallback.js +108 -0
  60. package/lib/app/run-env-compose.js +30 -42
  61. package/lib/app/run-helpers.js +49 -126
  62. package/lib/app/run-infra-requirements.js +30 -0
  63. package/lib/app/run-resolve-image.js +21 -0
  64. package/lib/app/run.js +74 -21
  65. package/lib/app/show-display.js +1 -1
  66. package/lib/app/show.js +1 -1
  67. package/lib/build/index.js +13 -10
  68. package/lib/cli/index.js +2 -0
  69. package/lib/cli/setup-app.help.js +67 -0
  70. package/lib/cli/setup-app.js +57 -121
  71. package/lib/cli/setup-app.test-commands.js +179 -0
  72. package/lib/cli/setup-auth.js +19 -5
  73. package/lib/cli/setup-credential-deployment.js +22 -8
  74. package/lib/cli/setup-dev-path-commands.js +124 -0
  75. package/lib/cli/setup-dev.js +170 -113
  76. package/lib/cli/setup-environment.js +7 -1
  77. package/lib/cli/setup-external-system.js +62 -22
  78. package/lib/cli/setup-infra.js +126 -47
  79. package/lib/cli/setup-parameters.js +32 -0
  80. package/lib/cli/setup-secrets.js +106 -8
  81. package/lib/cli/setup-service-user.js +1 -1
  82. package/lib/cli/setup-utility.js +36 -20
  83. package/lib/commands/app-down.js +5 -7
  84. package/lib/commands/app-install.js +14 -7
  85. package/lib/commands/app-logs.js +13 -10
  86. package/lib/commands/app-shell.js +4 -1
  87. package/lib/commands/app-test.js +25 -19
  88. package/lib/commands/app.js +22 -10
  89. package/lib/commands/auth-config.js +6 -6
  90. package/lib/commands/auth-status.js +4 -3
  91. package/lib/commands/credential-env.js +4 -3
  92. package/lib/commands/credential-list.js +5 -4
  93. package/lib/commands/credential-push.js +4 -3
  94. package/lib/commands/datasource-unified-test-cli.js +495 -0
  95. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  96. package/lib/commands/datasource-validation-cli.js +129 -0
  97. package/lib/commands/datasource.js +105 -98
  98. package/lib/commands/deployment-list.js +6 -5
  99. package/lib/commands/dev-cli-handlers.js +122 -18
  100. package/lib/commands/dev-down.js +4 -3
  101. package/lib/commands/dev-init.js +231 -116
  102. package/lib/commands/dev-show-display.js +473 -0
  103. package/lib/commands/login-credentials.js +3 -2
  104. package/lib/commands/login-device.js +4 -3
  105. package/lib/commands/login.js +5 -4
  106. package/lib/commands/logout.js +8 -7
  107. package/lib/commands/parameters-validate.js +54 -0
  108. package/lib/commands/repair-datasource.js +314 -68
  109. package/lib/commands/repair-env-template.js +2 -2
  110. package/lib/commands/repair.js +21 -3
  111. package/lib/commands/secrets-list.js +23 -12
  112. package/lib/commands/secrets-remove-all.js +220 -0
  113. package/lib/commands/secrets-remove.js +21 -12
  114. package/lib/commands/secrets-set.js +21 -12
  115. package/lib/commands/secrets-validate.js +4 -4
  116. package/lib/commands/secure.js +10 -9
  117. package/lib/commands/service-user.js +26 -25
  118. package/lib/commands/test-e2e-external.js +27 -1
  119. package/lib/commands/up-common.js +3 -2
  120. package/lib/commands/up-dataplane.js +29 -16
  121. package/lib/commands/up-miso.js +19 -29
  122. package/lib/commands/upload.js +138 -39
  123. package/lib/commands/wizard-core-helpers.js +1 -1
  124. package/lib/commands/wizard-dataplane.js +4 -3
  125. package/lib/commands/wizard-helpers.js +3 -3
  126. package/lib/commands/wizard.js +2 -2
  127. package/lib/core/admin-secrets.js +14 -5
  128. package/lib/core/audit-logger.js +12 -4
  129. package/lib/core/config-attach-extensions.js +46 -0
  130. package/lib/core/config-runtime-paths.js +29 -0
  131. package/lib/core/config.js +55 -56
  132. package/lib/core/diff.js +3 -2
  133. package/lib/core/ensure-encryption-key.js +1 -1
  134. package/lib/core/secrets-ensure-infra.js +77 -0
  135. package/lib/core/secrets-ensure.js +120 -64
  136. package/lib/core/secrets-env-write.js +35 -7
  137. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  138. package/lib/core/secrets.js +200 -37
  139. package/lib/core/templates-env.js +4 -3
  140. package/lib/datasource/abac-validator.js +1 -10
  141. package/lib/datasource/deploy.js +75 -53
  142. package/lib/datasource/field-reference-validator.js +9 -6
  143. package/lib/datasource/integration-context.js +63 -0
  144. package/lib/datasource/list.js +8 -7
  145. package/lib/datasource/log-viewer.js +84 -53
  146. package/lib/datasource/resolve-app.js +4 -4
  147. package/lib/datasource/test-e2e.js +95 -146
  148. package/lib/datasource/test-integration.js +114 -122
  149. package/lib/datasource/unified-validation-run-body.js +65 -0
  150. package/lib/datasource/unified-validation-run-post.js +23 -0
  151. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  152. package/lib/datasource/unified-validation-run.js +92 -0
  153. package/lib/datasource/validate.js +157 -13
  154. package/lib/deployment/deployer.js +4 -3
  155. package/lib/deployment/environment.js +7 -6
  156. package/lib/deployment/push.js +17 -8
  157. package/lib/external-system/delete.js +4 -3
  158. package/lib/external-system/deploy.js +131 -53
  159. package/lib/external-system/download-helpers.js +1 -1
  160. package/lib/external-system/download.js +7 -6
  161. package/lib/external-system/generator.js +92 -6
  162. package/lib/external-system/integration-test-dispatch.js +26 -0
  163. package/lib/external-system/test-execution.js +5 -1
  164. package/lib/external-system/test-helpers.js +0 -4
  165. package/lib/external-system/test-system-level-helpers.js +110 -0
  166. package/lib/external-system/test-system-level.js +83 -44
  167. package/lib/external-system/test.js +59 -8
  168. package/lib/generator/builders.js +23 -11
  169. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  170. package/lib/generator/external.js +16 -4
  171. package/lib/generator/helpers.js +58 -3
  172. package/lib/generator/index.js +4 -0
  173. package/lib/generator/split-readme.js +12 -7
  174. package/lib/generator/split-variables.js +2 -1
  175. package/lib/generator/split.js +1 -1
  176. package/lib/generator/wizard-readme.js +3 -3
  177. package/lib/generator/wizard.js +8 -8
  178. package/lib/infrastructure/compose.js +60 -6
  179. package/lib/infrastructure/helpers.js +201 -29
  180. package/lib/infrastructure/index.js +28 -17
  181. package/lib/infrastructure/services.js +21 -15
  182. package/lib/internal/fs-real-sync.js +104 -0
  183. package/lib/internal/node-fs.js +98 -0
  184. package/lib/parameters/database-secret-values.js +173 -0
  185. package/lib/parameters/infra-kv-discovery.js +121 -0
  186. package/lib/parameters/infra-parameter-catalog.js +458 -0
  187. package/lib/parameters/infra-parameter-validate.js +64 -0
  188. package/lib/schema/application-schema.json +37 -17
  189. package/lib/schema/datasource-test-run.schema.json +493 -0
  190. package/lib/schema/deployment-rules.yaml +102 -63
  191. package/lib/schema/external-datasource.schema.json +1200 -442
  192. package/lib/schema/external-system.schema.json +181 -5
  193. package/lib/schema/flag-map-validation-run.json +31 -0
  194. package/lib/schema/infra-parameter.schema.json +106 -0
  195. package/lib/schema/infra.parameter.yaml +421 -0
  196. package/lib/schema/type/credential-auth-templates.json +40 -0
  197. package/lib/schema/type/document-storage.json +213 -0
  198. package/lib/schema/type/message-service.json +123 -0
  199. package/lib/schema/type/vector-store.json +88 -0
  200. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  201. package/lib/utils/api-error-handler.js +2 -2
  202. package/lib/utils/api.js +49 -14
  203. package/lib/utils/app-register-api.js +3 -2
  204. package/lib/utils/app-register-auth.js +1 -1
  205. package/lib/utils/app-register-config.js +4 -4
  206. package/lib/utils/app-register-display.js +3 -2
  207. package/lib/utils/app-register-validator.js +3 -2
  208. package/lib/utils/app-run-containers.js +26 -22
  209. package/lib/utils/app-scoped-config.js +31 -0
  210. package/lib/utils/app-service-env-from-builder.js +164 -0
  211. package/lib/utils/build-copy.js +1 -1
  212. package/lib/utils/build-helpers.js +20 -20
  213. package/lib/utils/build-resolve-image.js +165 -0
  214. package/lib/utils/cli-layout-chalk.js +8 -0
  215. package/lib/utils/cli-test-layout-chalk.js +267 -0
  216. package/lib/utils/cli-utils.js +88 -11
  217. package/lib/utils/compose-db-passwords.js +138 -0
  218. package/lib/utils/compose-generate-docker-compose.js +216 -0
  219. package/lib/utils/compose-generator.js +197 -291
  220. package/lib/utils/compose-miso-env.js +18 -0
  221. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  222. package/lib/utils/config-paths.js +166 -7
  223. package/lib/utils/config-scoped-resources-preference.js +41 -0
  224. package/lib/utils/controller-deployment-outcome.js +68 -0
  225. package/lib/utils/credential-display.js +2 -2
  226. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  227. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  228. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  229. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  230. package/lib/utils/datasource-test-run-display.js +442 -0
  231. package/lib/utils/datasource-test-run-exit.js +58 -0
  232. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  233. package/lib/utils/datasource-test-run-report-version.js +51 -0
  234. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  235. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  236. package/lib/utils/datasource-validation-watch.js +266 -0
  237. package/lib/utils/declarative-url-ports.js +47 -0
  238. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  239. package/lib/utils/dev-ca-install.js +185 -23
  240. package/lib/utils/dev-cert-helper.js +266 -17
  241. package/lib/utils/dev-hosts-helper.js +307 -0
  242. package/lib/utils/dev-init-cert-hints.js +37 -0
  243. package/lib/utils/dev-init-health-messages.js +52 -0
  244. package/lib/utils/dev-init-resolve.js +86 -0
  245. package/lib/utils/dev-init-ssh-merge.js +65 -0
  246. package/lib/utils/dev-ssh-config-helper.js +196 -0
  247. package/lib/utils/dev-user-groups.js +93 -0
  248. package/lib/utils/docker-build.js +42 -17
  249. package/lib/utils/docker-exec.js +28 -0
  250. package/lib/utils/docker-manifest-public-port.js +116 -0
  251. package/lib/utils/docker-not-running-hint.js +52 -0
  252. package/lib/utils/docker.js +98 -11
  253. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  254. package/lib/utils/env-config-loader.js +10 -91
  255. package/lib/utils/env-copy.js +19 -10
  256. package/lib/utils/env-map.js +35 -8
  257. package/lib/utils/env-template.js +2 -2
  258. package/lib/utils/environment-scoped-resources.js +144 -0
  259. package/lib/utils/error-formatter.js +92 -13
  260. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  261. package/lib/utils/error-formatters/network-errors.js +2 -1
  262. package/lib/utils/error-formatters/permission-errors.js +2 -1
  263. package/lib/utils/error-formatters/validation-errors.js +2 -1
  264. package/lib/utils/external-readme.js +8 -1
  265. package/lib/utils/external-system-display.js +234 -136
  266. package/lib/utils/external-system-local-test-tty.js +389 -0
  267. package/lib/utils/external-system-readiness-core.js +377 -0
  268. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  269. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  270. package/lib/utils/external-system-readiness-display.js +186 -0
  271. package/lib/utils/external-system-test-helpers.js +24 -6
  272. package/lib/utils/external-system-validators.js +30 -12
  273. package/lib/utils/health-check-url.js +119 -0
  274. package/lib/utils/health-check.js +59 -25
  275. package/lib/utils/help-builder.js +11 -8
  276. package/lib/utils/image-version.js +4 -8
  277. package/lib/utils/infra-containers.js +4 -7
  278. package/lib/utils/infra-env-defaults.js +162 -0
  279. package/lib/utils/infra-status-display.js +167 -0
  280. package/lib/utils/infra-status.js +16 -8
  281. package/lib/utils/local-secrets.js +3 -4
  282. package/lib/utils/paths.js +134 -47
  283. package/lib/utils/port-resolver.js +10 -23
  284. package/lib/utils/redis-env-scope.js +62 -0
  285. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  286. package/lib/utils/remote-builder-validation.js +99 -0
  287. package/lib/utils/remote-dev-auth.js +117 -21
  288. package/lib/utils/remote-docker-env.js +67 -15
  289. package/lib/utils/remote-secrets-loader.js +13 -4
  290. package/lib/utils/resolve-docker-image-ref.js +124 -0
  291. package/lib/utils/schema-loader.js +22 -9
  292. package/lib/utils/secrets-bash-kv.js +25 -0
  293. package/lib/utils/secrets-generator.js +169 -49
  294. package/lib/utils/secrets-helpers.js +70 -59
  295. package/lib/utils/secrets-kv-scope.js +60 -0
  296. package/lib/utils/secrets-utils.js +32 -38
  297. package/lib/utils/secrets-validation.js +3 -1
  298. package/lib/utils/secrets-yaml-preserve.js +109 -0
  299. package/lib/utils/ssh-key-helper.js +4 -2
  300. package/lib/utils/template-helpers.js +2 -2
  301. package/lib/utils/test-log-writer.js +3 -3
  302. package/lib/utils/token-manager.js +1 -2
  303. package/lib/utils/url-declarative-public-base.js +188 -0
  304. package/lib/utils/url-declarative-resolve-build.js +493 -0
  305. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  306. package/lib/utils/url-declarative-resolve.js +220 -0
  307. package/lib/utils/url-declarative-token-parse.js +74 -0
  308. package/lib/utils/url-declarative-url-flags.js +50 -0
  309. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  310. package/lib/utils/url-public-path-prefix.js +34 -0
  311. package/lib/utils/urls-local-registry.js +220 -0
  312. package/lib/utils/validation-report-tty-kit.js +77 -0
  313. package/lib/utils/validation-run-poll.js +89 -0
  314. package/lib/utils/validation-run-post-retry.js +73 -0
  315. package/lib/utils/validation-run-request.js +98 -0
  316. package/lib/utils/variable-transformer.js +21 -4
  317. package/lib/utils/yaml-preserve.js +33 -14
  318. package/lib/validation/datasource-warnings.js +56 -0
  319. package/lib/validation/env-template-auth.js +1 -1
  320. package/lib/validation/external-manifest-validator.js +27 -7
  321. package/lib/validation/validate-display.js +37 -31
  322. package/lib/validation/validate.js +4 -13
  323. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  324. package/lib/validation/validator.js +22 -65
  325. package/lib/validation/wizard-config-validator.js +2 -1
  326. package/package.json +7 -3
  327. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  328. package/scripts/diagnose-cli.js +150 -0
  329. package/scripts/install-local.js +304 -55
  330. package/templates/README.md +15 -2
  331. package/templates/applications/dataplane/application.yaml +52 -2
  332. package/templates/applications/dataplane/env.template +75 -17
  333. package/templates/applications/dataplane/rbac.yaml +8 -0
  334. package/templates/applications/keycloak/application.yaml +9 -1
  335. package/templates/applications/keycloak/env.template +15 -6
  336. package/templates/applications/miso-controller/application.yaml +10 -2
  337. package/templates/applications/miso-controller/env.template +42 -12
  338. package/templates/applications/miso-controller/rbac.yaml +5 -0
  339. package/templates/external-system/README.md.hbs +20 -7
  340. package/templates/external-system/deploy.js.hbs +5 -5
  341. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  342. package/templates/infra/compose.yaml.hbs +20 -4
  343. package/templates/python/docker-compose.hbs +16 -0
  344. package/templates/typescript/docker-compose.hbs +16 -0
  345. package/lib/api/external-test.api.js +0 -111
  346. package/lib/schema/env-config.yaml +0 -60
@@ -1,8 +1,9 @@
1
+ const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * External System Deployment Module
3
4
  *
4
5
  * Handles deployment of external systems via controller pipeline.
5
- * Uses unified controller pipeline (same as regular apps) - no direct dataplane calls.
6
+ * After deploy, fetches dataplane list + system for readiness summary.
6
7
  *
7
8
  * @fileoverview External system deployment for AI Fabrix Builder
8
9
  * @author AI Fabrix Team
@@ -17,69 +18,116 @@ const { detectAppType } = require('../utils/paths');
17
18
  const { logOfflinePathWhenType } = require('../utils/cli-utils');
18
19
  const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
19
20
  const { getExternalSystem } = require('../api/external-systems.api');
21
+ const { listDatasources } = require('../api/datasources-core.api');
22
+ const { testSystemViaPipeline } = require('../api/pipeline.api');
23
+ const { extractDatasources } = require('../datasource/list');
24
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
25
+ const { logDeployReadinessSummary } = require('../utils/external-system-readiness-deploy-display');
26
+ const { parseControllerDeploymentOutcome } = require('../utils/controller-deployment-outcome');
20
27
  const { generateControllerManifest } = require('../generator/external-controller-manifest');
21
28
  const { validateExternalSystemComplete } = require('../validation/validate');
22
29
  const { displayValidationResults } = require('../validation/validate-display');
23
30
 
24
31
  /**
25
- * Displays API and MCP documentation URLs from dataplane when available
32
+ * Lists datasources for a system and loads system record for docs URLs.
26
33
  * @async
27
- * @function displayDeploymentDocs
28
34
  * @param {string} controllerUrl - Controller base URL
29
35
  * @param {string} environment - Environment key
30
- * @param {Object} authConfig - Authentication configuration
31
- * @param {string} systemKey - External system key
36
+ * @param {Object} authConfig - Auth config
37
+ * @param {string} systemKey - System key
38
+ * @returns {Promise<{ dataplaneUrl: string, datasources: Object[], system: Object|null, error: Error|null }>}
32
39
  */
33
- async function displayDeploymentDocs(controllerUrl, environment, authConfig, systemKey) {
40
+ async function fetchDataplaneDeployReadiness(controllerUrl, environment, authConfig, systemKey) {
41
+ let dataplaneUrl;
34
42
  try {
35
- const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
36
- const res = await getExternalSystem(dataplaneUrl, systemKey, authConfig);
37
- const sys = res?.data || res;
38
- if (!sys) return;
39
-
40
- const apiDocumentUrl = sys.apiDocumentUrl;
41
- const mcpServerUrl = sys.mcpServerUrl;
42
- const openApiDocsPageUrl = sys.openApiDocsPageUrl;
43
-
44
- const urls = [];
45
- if (apiDocumentUrl && typeof apiDocumentUrl === 'string') {
46
- urls.push({ label: 'API Docs', url: apiDocumentUrl });
47
- }
48
- if (mcpServerUrl && typeof mcpServerUrl === 'string') {
49
- urls.push({ label: 'MCP Server', url: mcpServerUrl });
50
- }
51
- if (openApiDocsPageUrl && typeof openApiDocsPageUrl === 'string') {
52
- urls.push({ label: 'OpenAPI Docs Page', url: openApiDocsPageUrl });
43
+ dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
44
+ } catch (err) {
45
+ return { dataplaneUrl: null, datasources: [], system: null, error: err };
46
+ }
47
+
48
+ let datasources = [];
49
+ try {
50
+ const listRes = await listDatasources(dataplaneUrl, authConfig, {
51
+ sourceSystemIdOrKey: systemKey,
52
+ pageSize: 100
53
+ });
54
+ if (listRes.success && listRes.data) {
55
+ try {
56
+ datasources = extractDatasources(listRes);
57
+ } catch (e) {
58
+ logger.log(
59
+ chalk.yellow(
60
+ `⚠ Unable to parse datasources list from dataplane response: ${e && e.message ? e.message : 'unknown error'}`
61
+ )
62
+ );
63
+ datasources = [];
64
+ }
53
65
  }
66
+ } catch (err) {
67
+ return { dataplaneUrl, datasources: [], system: null, error: err };
68
+ }
54
69
 
55
- if (urls.length > 0) {
56
- logger.log(chalk.blue('\nDocumentation:'));
57
- urls.forEach(({ label, url }) => {
58
- logger.log(chalk.blue(` ${label}: ${url}`));
59
- });
70
+ try {
71
+ const getRes = await getExternalSystem(dataplaneUrl, systemKey, authConfig);
72
+ const system = unwrapApiData(getRes);
73
+ return {
74
+ dataplaneUrl,
75
+ datasources,
76
+ system: system && typeof system === 'object' ? system : null,
77
+ error: null
78
+ };
79
+ } catch (err) {
80
+ if (datasources.length === 0) {
81
+ return { dataplaneUrl, datasources, system: null, error: err };
60
82
  }
61
- } catch (_err) {
62
- // Silently ignore: dataplane may be unreachable or docs not configured
83
+ return { dataplaneUrl, datasources, system: null, error: null };
63
84
  }
64
85
  }
65
86
 
66
87
  /**
67
- * Deploys via controller and displays success summary with docs
88
+ * Deploys via controller and prints readiness summary (config / deployment / runtime layers).
68
89
  * @async
69
- * @function executeDeployAndDisplay
70
90
  * @param {Object} manifest - Controller manifest
71
91
  * @param {string} controllerUrl - Controller base URL
72
92
  * @param {string} environment - Environment key
73
93
  * @param {Object} authConfig - Authentication configuration
74
- * @param {Object} options - Deployment options
94
+ * @param {Object} options - Deployment options (poll, probe, probeTimeout)
75
95
  * @returns {Promise<Object>} Deployment result
76
96
  */
97
+ /**
98
+ * @param {Object} deploymentOutcome - from parseControllerDeploymentOutcome
99
+ */
100
+ function logImmediateControllerDeploymentOutcome(deploymentOutcome) {
101
+ if (deploymentOutcome.ok) {
102
+ logger.log(formatSuccessParagraph('Controller deployment OK'));
103
+ return;
104
+ }
105
+ logger.log(chalk.red('\nāœ– Controller deployment did not complete successfully'));
106
+ const parts = [deploymentOutcome.error, deploymentOutcome.message].filter(Boolean);
107
+ if (parts.length > 0) {
108
+ for (const line of parts) {
109
+ logger.log(chalk.red(` ${line}`));
110
+ }
111
+ return;
112
+ }
113
+ if (deploymentOutcome.statusLabel) {
114
+ logger.log(
115
+ chalk.yellow(
116
+ ` Controller status: ${deploymentOutcome.statusLabel} (no message or error in API response)`
117
+ )
118
+ );
119
+ return;
120
+ }
121
+ logger.log(chalk.gray(' See Deployment section below for details.'));
122
+ }
123
+
77
124
  async function executeDeployAndDisplay(manifest, controllerUrl, environment, authConfig, options) {
78
125
  const deployer = require('../deployment/deployer');
79
126
  const pollOpts = {
80
127
  poll: options.poll,
81
128
  pollInterval: options.pollInterval !== undefined ? options.pollInterval : 500,
82
- pollMaxAttempts: options.pollMaxAttempts,
129
+ // External-system deploy only: ~10s poll window (matches controller→dataplane publish timeout). Not used for Azure/webapp deploy polling.
130
+ pollMaxAttempts: options.pollMaxAttempts !== undefined ? options.pollMaxAttempts : 22,
83
131
  ...options
84
132
  };
85
133
  const result = await deployer.deployToController(
@@ -89,17 +137,54 @@ async function executeDeployAndDisplay(manifest, controllerUrl, environment, aut
89
137
  authConfig,
90
138
  pollOpts
91
139
  );
92
- logger.log(chalk.green('\nāœ… External system deployed successfully!'));
93
- logger.log(chalk.blue(`System: ${manifest.key}`));
94
- logger.log(chalk.blue(`Datasources: ${manifest.dataSources.length}`));
95
- await displayDeploymentDocs(controllerUrl, environment, authConfig, manifest.key);
140
+
141
+ const deploymentOutcome = parseControllerDeploymentOutcome(result);
142
+ logImmediateControllerDeploymentOutcome(deploymentOutcome);
143
+
144
+ const ctx = await fetchDataplaneDeployReadiness(
145
+ controllerUrl,
146
+ environment,
147
+ authConfig,
148
+ manifest.key
149
+ );
150
+
151
+ let probeData = null;
152
+ if (options.probe && ctx.dataplaneUrl && !ctx.error) {
153
+ logger.log(chalk.blue('\nRunning runtime checks (--probe)...'));
154
+ try {
155
+ const pr = await testSystemViaPipeline(ctx.dataplaneUrl, manifest.key, authConfig, {}, {
156
+ timeout: options.probeTimeout || 120000
157
+ });
158
+ if (pr.success === false) {
159
+ logger.log(
160
+ chalk.yellow(`⚠ Probe request failed: ${pr.formattedError || pr.error || 'unknown error'}`)
161
+ );
162
+ } else {
163
+ probeData = unwrapApiData(pr);
164
+ }
165
+ } catch (e) {
166
+ logger.log(chalk.yellow(`⚠ Probe failed: ${e.message}`));
167
+ }
168
+ }
169
+
170
+ logDeployReadinessSummary({
171
+ environment,
172
+ dataplaneUrl: ctx.dataplaneUrl,
173
+ manifest,
174
+ datasources: ctx.datasources,
175
+ systemFromDataplane: ctx.system,
176
+ fetchError: ctx.error,
177
+ deploymentOk: deploymentOutcome.ok,
178
+ deploymentDetail: deploymentOutcome.ok ? null : deploymentOutcome,
179
+ probeData
180
+ });
181
+
96
182
  return result;
97
183
  }
98
184
 
99
185
  /**
100
186
  * Prepares deployment configuration (auth, controller URL, environment)
101
187
  * @async
102
- * @function prepareDeploymentConfig
103
188
  * @param {string} appName - Application name
104
189
  * @param {Object} options - Deployment options
105
190
  * @returns {Promise<Object>} Deployment configuration
@@ -119,16 +204,12 @@ async function prepareDeploymentConfig(appName, _options) {
119
204
 
120
205
  /**
121
206
  * Deploys external system via controller pipeline (same as regular apps)
122
- * Uses unified controller pipeline - no direct dataplane calls
123
207
  *
124
208
  * @async
125
- * @function deployExternalSystem
126
209
  * @param {string} appName - Application name
127
210
  * @param {Object} options - Deployment options
128
- * @param {string} [options.environment] - Environment (dev, tst, pro)
129
- * @param {string} [options.controller] - Controller URL
130
- * @param {boolean} [options.poll] - Poll for deployment status
131
- * @param {number} [options.pollInterval] - Polling interval in milliseconds (default: 500ms for external systems)
211
+ * @param {boolean} [options.probe] - Run dataplane validation/run after deploy
212
+ * @param {number} [options.probeTimeout] - Probe timeout ms (default 120000)
132
213
  * @returns {Promise<Object>} Deployment result
133
214
  * @throws {Error} If deployment fails
134
215
  */
@@ -139,7 +220,6 @@ async function deployExternalSystem(appName, options = {}) {
139
220
 
140
221
  logger.log(chalk.blue(`\nšŸš€ Deploying external system: ${appName}`));
141
222
 
142
- // Step 0: Validate before deployment (same as validate command)
143
223
  logger.log(chalk.blue('šŸ” Validating external system before deployment...'));
144
224
  const validationResult = await validateExternalSystemComplete(appName, options);
145
225
 
@@ -148,15 +228,12 @@ async function deployExternalSystem(appName, options = {}) {
148
228
  throw new Error('Validation failed. Fix errors before deploying.');
149
229
  }
150
230
 
151
- logger.log(chalk.green('āœ“ Validation passed, proceeding with deployment...'));
231
+ logger.log(formatSuccessLine('Local validation passed, proceeding with deployment...'));
152
232
 
153
- // Step 1: Generate controller manifest (validated, ready for deployment)
154
233
  const manifest = await generateControllerManifest(appName, options);
155
234
 
156
- // Step 2: Get deployment configuration (auth, controller URL, etc.)
157
235
  const { environment, controllerUrl, authConfig } = await prepareDeploymentConfig(appName, options);
158
236
 
159
- // Step 3: Deploy via controller pipeline (same as regular apps)
160
237
  const result = await executeDeployAndDisplay(
161
238
  manifest,
162
239
  controllerUrl,
@@ -175,6 +252,7 @@ async function deployExternalSystem(appName, options = {}) {
175
252
  }
176
253
 
177
254
  module.exports = {
178
- deployExternalSystem
255
+ deployExternalSystem,
256
+ executeDeployAndDisplay,
257
+ fetchDataplaneDeployReadiness
179
258
  };
180
-
@@ -73,7 +73,7 @@ function generateReadme(systemKey, application, dataSources) {
73
73
  return {
74
74
  entityType: datasourceKeyOnly,
75
75
  displayName: ds.displayName || ds.name || ds.key || `Datasource ${index + 1}`,
76
- fileName: `${systemKey}-datasource-${datasourceKeyOnly}.yaml`
76
+ fileName: `${systemKey}-datasource-${datasourceKeyOnly}.json`
77
77
  };
78
78
  });
79
79
 
@@ -1,3 +1,4 @@
1
+ const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * External System Download Module
3
4
  *
@@ -129,7 +130,7 @@ async function setupAuthenticationAndDataplane(systemKey, _options, _config) {
129
130
  const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
130
131
  logger.log(chalk.blue('🌐 Resolving dataplane URL...'));
131
132
  const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
132
- logger.log(chalk.green(`āœ“ Dataplane URL: ${dataplaneUrl}`));
133
+ logger.log(formatSuccessLine(`Dataplane URL: ${dataplaneUrl}`));
133
134
 
134
135
  return { authConfig, dataplaneUrl };
135
136
  }
@@ -287,8 +288,8 @@ function validateAndLogDownloadedData(application, dataSources) {
287
288
  logger.log(chalk.blue('šŸ” Validating downloaded data...'));
288
289
  validateDownloadedData(application, dataSources);
289
290
  const systemType = validateSystemType(application);
290
- logger.log(chalk.green(`āœ“ System type: ${systemType}`));
291
- logger.log(chalk.green(`āœ“ Found ${dataSources.length} datasource(s)`));
291
+ logger.log(formatSuccessLine(`System type: ${systemType}`));
292
+ logger.log(formatSuccessLine(`Found ${dataSources.length} datasource(s)`));
292
293
  return systemType;
293
294
  }
294
295
 
@@ -367,7 +368,7 @@ async function processDownloadedSystem(systemKey, manifest, splitOptions = {}) {
367
368
  const deployJson = buildDeployJsonFromManifest(application, dataSources, version);
368
369
  const deployJsonPath = path.join(finalPath, `${systemKey}-deploy.json`);
369
370
  await fs.writeFile(deployJsonPath, JSON.stringify(deployJson, null, 2), 'utf8');
370
- logger.log(chalk.green(`āœ“ Created: ${path.relative(process.cwd(), deployJsonPath)}`));
371
+ logger.log(formatSuccessLine(`Created: ${path.relative(process.cwd(), deployJsonPath)}`));
371
372
 
372
373
  logger.log(chalk.blue('šŸ“‚ Splitting deploy JSON into component files...'));
373
374
  const splitResult = await generator.splitDeployJson(deployJsonPath, finalPath, splitOptions);
@@ -390,7 +391,7 @@ async function processDownloadedSystem(systemKey, manifest, splitOptions = {}) {
390
391
  * @param {number} datasourceCount - Number of datasources
391
392
  */
392
393
  function displayDownloadSuccess(systemKey, finalPath, datasourceCount) {
393
- logger.log(chalk.green('\nāœ… External system downloaded successfully!'));
394
+ logger.log(formatSuccessParagraph('External system downloaded successfully!'));
394
395
  logger.log(chalk.blue(`Location: ${finalPath}`));
395
396
  logger.log(chalk.blue(`System: ${systemKey}`));
396
397
  logger.log(chalk.blue(`Datasources: ${datasourceCount}`));
@@ -414,7 +415,7 @@ async function runConvertToJsonIfRequested(systemKey) {
414
415
  const { runConvert } = require('../commands/convert');
415
416
  try {
416
417
  await runConvert(systemKey, { format: 'json', force: true });
417
- logger.log(chalk.green('āœ“ Converted component files to JSON'));
418
+ logger.log(formatSuccessLine('Converted component files to JSON'));
418
419
  } catch (convertErr) {
419
420
  throw new Error(`Download succeeded but convert to JSON failed: ${convertErr.message}`);
420
421
  }
@@ -9,10 +9,10 @@
9
9
  * @version 2.0.0
10
10
  */
11
11
 
12
+ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
12
13
  const fs = require('fs').promises;
13
14
  const path = require('path');
14
15
  const handlebars = require('handlebars');
15
- const chalk = require('chalk');
16
16
  const logger = require('../utils/logger');
17
17
  const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
18
18
  const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
@@ -135,6 +135,68 @@ function resourceTypeToSchemaEntityType(resourceType) {
135
135
  return resourceType === 'document' ? 'documentStorage' : 'recordStorage';
136
136
  }
137
137
 
138
+ /**
139
+ * Build { dimKey, field } entries for root dimensions (v2.4+ dimensionBinding).
140
+ * @param {Object} dimensions - Map of dimension key → attribute path (e.g. metadata.country)
141
+ * @returns {Array<{ dimKey: string, field: string }>}
142
+ */
143
+ function buildDimensionBindingEntries(dimensions) {
144
+ if (!dimensions || typeof dimensions !== 'object' || Array.isArray(dimensions)) return [];
145
+ return Object.entries(dimensions).map(([dimKey, path]) => {
146
+ const field = typeof path === 'string' && path.startsWith('metadata.')
147
+ ? path.slice('metadata.'.length).trim()
148
+ : dimKey;
149
+ return { dimKey, field };
150
+ });
151
+ }
152
+
153
+ /**
154
+ * @param {string} schemaEntityType - Resolved schema entityType
155
+ * @returns {boolean}
156
+ */
157
+ function isStorageEntityType(schemaEntityType) {
158
+ return schemaEntityType === 'recordStorage' || schemaEntityType === 'documentStorage';
159
+ }
160
+
161
+ /**
162
+ * Puts externalId first for storage entity types when present (schema v2.4 join identity).
163
+ * @param {string[]} keys - Attribute / metadata property names
164
+ * @param {string} schemaEntityType - Resolved schema entityType
165
+ * @returns {string[]}
166
+ */
167
+ function orderMetadataAttributeKeys(keys, schemaEntityType) {
168
+ const out = [...keys];
169
+ if (isStorageEntityType(schemaEntityType) && out.includes('externalId')) {
170
+ return ['externalId', ...out.filter(k => k !== 'externalId')];
171
+ }
172
+ return out;
173
+ }
174
+
175
+ /**
176
+ * Default fieldMappings.attributes + metadata key order when the wizard/config omits attributes.
177
+ * @param {string} schemaEntityType - Resolved schema entityType
178
+ * @returns {{ merged: Object, keys: string[] }}
179
+ */
180
+ function defaultAttributesForEntityType(schemaEntityType) {
181
+ if (isStorageEntityType(schemaEntityType)) {
182
+ return {
183
+ merged: {
184
+ externalId: { expression: '{{raw.id}}' },
185
+ id: { expression: '{{raw.id}}' },
186
+ name: { expression: '{{raw.name}}' }
187
+ },
188
+ keys: ['externalId', 'id', 'name']
189
+ };
190
+ }
191
+ return {
192
+ merged: {
193
+ id: { expression: '{{raw.id}}' },
194
+ name: { expression: '{{raw.name}}' }
195
+ },
196
+ keys: ['id', 'name']
197
+ };
198
+ }
199
+
138
200
  /**
139
201
  * Build datasource context object for template rendering
140
202
  * @param {Object} opts - Options
@@ -151,9 +213,31 @@ function resourceTypeToSchemaEntityType(resourceType) {
151
213
  function buildDatasourceContext({ config, datasourceKey, dimensions, attributes, fullDatasourceKey, entityKey, schemaEntityType, resourceType }) {
152
214
  const displayName = config.datasourceDisplayName || datasourceKey.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
153
215
  const description = config.datasourceDescription || `External datasource for ${datasourceKey}`;
216
+ const attrsIn = attributes && typeof attributes === 'object' && !Array.isArray(attributes) ? attributes : {};
217
+ let mergedAttributes = { ...attrsIn };
218
+
219
+ let attributeKeysForMetadata;
220
+ if (Object.keys(mergedAttributes).length > 0) {
221
+ attributeKeysForMetadata = orderMetadataAttributeKeys(Object.keys(mergedAttributes), schemaEntityType);
222
+ } else {
223
+ const defaults = defaultAttributesForEntityType(schemaEntityType);
224
+ mergedAttributes = defaults.merged;
225
+ attributeKeysForMetadata = defaults.keys;
226
+ }
227
+
228
+ if (isStorageEntityType(schemaEntityType) && !mergedAttributes.externalId) {
229
+ mergedAttributes.externalId = { expression: '{{raw.id}}' };
230
+ attributeKeysForMetadata = orderMetadataAttributeKeys(Object.keys(mergedAttributes), schemaEntityType);
231
+ }
232
+
154
233
  const primaryKey = Array.isArray(config.primaryKey) && config.primaryKey.length > 0
155
234
  ? config.primaryKey
156
- : ['id'];
235
+ : (attributeKeysForMetadata.includes('id') ? ['id'] : [attributeKeysForMetadata[0]]);
236
+ const labelKey = Array.isArray(config.labelKey) && config.labelKey.length > 0
237
+ ? config.labelKey
238
+ : attributeKeysForMetadata;
239
+ const dimensionBindingEntries = buildDimensionBindingEntries(dimensions);
240
+
157
241
  return {
158
242
  fullDatasourceKey,
159
243
  entityKey,
@@ -163,9 +247,11 @@ function buildDatasourceContext({ config, datasourceKey, dimensions, attributes,
163
247
  schemaEntityType,
164
248
  resourceType,
165
249
  primaryKey,
250
+ labelKey,
251
+ attributeKeysForMetadata,
252
+ dimensionBindingEntries,
166
253
  systemType: config.systemType || 'openapi',
167
- dimensions: Object.keys(dimensions).length > 0 ? dimensions : null,
168
- attributes: Object.keys(attributes).length > 0 ? attributes : null,
254
+ attributes: mergedAttributes,
169
255
  raw: { id: '{{raw.id}}', name: '{{raw.name}}' }
170
256
  };
171
257
  }
@@ -250,7 +336,7 @@ async function generateExternalSystemFiles(appPath, appName, config, format = 'y
250
336
 
251
337
  // Generate external system file
252
338
  const systemPath = await generateExternalSystemTemplate(appPath, systemKey, config, fmt);
253
- logger.log(chalk.green(`āœ“ Generated external system: ${path.basename(systemPath)}`));
339
+ logger.log(formatSuccessLine(`Generated external system: ${path.basename(systemPath)}`));
254
340
 
255
341
  // Generate datasource JSON files
256
342
  const datasourcePaths = [];
@@ -278,7 +364,7 @@ async function generateExternalSystemFiles(appPath, appName, config, format = 'y
278
364
 
279
365
  const datasourcePath = await generateExternalDataSourceTemplate(appPath, datasourceKey, datasourceConfig, fmt);
280
366
  datasourcePaths.push(datasourcePath);
281
- logger.log(chalk.green(`āœ“ Generated datasource: ${path.basename(datasourcePath)}`));
367
+ logger.log(formatSuccessLine(`Generated datasource: ${path.basename(datasourcePath)}`));
282
368
  }
283
369
 
284
370
  // Update application config with externalIntegration block
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @fileoverview Dispatch rules for external test-integration (system vs per-datasource POST /validation/run).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ /**
8
+ * Use one externalSystem-scoped validation run when multiple datasources exist (default).
9
+ * Per-datasource runs when {@code options.perDatasource}, a datasource filter, or custom payload is set.
10
+ *
11
+ * @param {Object} options - CLI options
12
+ * @param {string} [options.datasource] - Single-datasource filter
13
+ * @param {boolean} [options.perDatasource] - Force one POST per datasource (externalDataSource scope)
14
+ * @param {Array<{data?: Object}>} datasourcesToTest - Entries from manifest
15
+ * @param {*} customPayload - Parsed payload from {@code --payload}, or null
16
+ * @returns {boolean}
17
+ */
18
+ function shouldUseSystemLevelIntegrationCall(options, datasourcesToTest, customPayload) {
19
+ const noDatasourceFilter = !options || !options.datasource;
20
+ const multi = Array.isArray(datasourcesToTest) && datasourcesToTest.length > 1;
21
+ const noCustomPayload = customPayload === null || customPayload === undefined;
22
+ const forcePerDs = options && options.perDatasource === true;
23
+ return noDatasourceFilter && multi && noCustomPayload && !forcePerDs;
24
+ }
25
+
26
+ module.exports = { shouldUseSystemLevelIntegrationCall };
@@ -11,6 +11,7 @@
11
11
  const chalk = require('chalk');
12
12
  const logger = require('../utils/logger');
13
13
  const testHelpers = require('../utils/external-system-test-helpers');
14
+ const { infoLine } = require('../utils/cli-test-layout-chalk');
14
15
 
15
16
  /**
16
17
  * Executes test for a single datasource
@@ -62,7 +63,10 @@ async function testSingleDatasourceIntegration(datasourceFile, systemKey, datapl
62
63
  const datasource = datasourceFile.data;
63
64
  const datasourceKey = datasource.key;
64
65
 
65
- logger.log(chalk.blue(`\nšŸ“” Testing datasource: ${datasourceKey}`));
66
+ if (options.verbose) {
67
+ logger.log('');
68
+ logger.log(infoLine(`šŸ“” Testing datasource: ${datasourceKey}`));
69
+ }
66
70
 
67
71
  // Determine payload to use
68
72
  const payloadTemplate = testHelpers.determinePayloadTemplate(datasource, datasourceKey, customPayload);
@@ -8,8 +8,6 @@
8
8
  * @version 2.0.0
9
9
  */
10
10
 
11
- const chalk = require('chalk');
12
- const logger = require('../utils/logger');
13
11
  const externalSystemSchema = require('../schema/external-system.schema.json');
14
12
  const { validateAgainstSchema } = require('../utils/external-system-validators');
15
13
 
@@ -63,7 +61,6 @@ function validateSystemFiles(systemFiles, schema) {
63
61
  * @param {Object} results - Test results object
64
62
  */
65
63
  function validateSystemFilesForTest(systemFiles, results) {
66
- logger.log(chalk.blue('šŸ“‹ Validating system files...'));
67
64
  const systemValidation = validateSystemFiles(systemFiles, externalSystemSchema);
68
65
  results.valid = systemValidation.valid;
69
66
  results.errors.push(...systemValidation.errors);
@@ -81,7 +78,6 @@ function validateSystemFilesForTest(systemFiles, results) {
81
78
  * @param {Function} determineDatasourcesToTest - Function to determine datasources to test
82
79
  */
83
80
  function validateDatasourceFilesForTest(datasourceFiles, systemFiles, results, options, validateSingleDatasource, determineDatasourcesToTest) {
84
- logger.log(chalk.blue('šŸ“‹ Validating datasource files...'));
85
81
  const datasourcesToTest = determineDatasourcesToTest(datasourceFiles, options.datasource);
86
82
  const systemKey = systemFiles.length > 0 ? systemFiles[0].data.key : null;
87
83
 
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Helpers for system-level pipeline test mapping (keeps runSystemLevelTest under max-lines-per-function).
3
+ * @fileoverview
4
+ */
5
+ 'use strict';
6
+
7
+ const { integrationResultFromEnvelope } = require('../utils/datasource-test-run-legacy-adapter');
8
+
9
+ /**
10
+ * Build a single failure-shaped datasource result row.
11
+ * @param {string} error
12
+ * @returns {Object}
13
+ */
14
+ function systemFailureRow(error) {
15
+ return {
16
+ key: 'system',
17
+ success: false,
18
+ skipped: false,
19
+ validationResults: {},
20
+ fieldMappingResults: {},
21
+ endpointTestResults: {},
22
+ error
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Map unified envelope-style response to datasourceResults.
28
+ * @param {Object} data
29
+ * @param {string} datasourceKey
30
+ * @returns {{ success: boolean, datasourceResults: Object[] }}
31
+ */
32
+ function mapEnvelopeSingleDatasource(data, datasourceKey) {
33
+ const legacy = integrationResultFromEnvelope(data, datasourceKey);
34
+ return {
35
+ success: legacy.success,
36
+ datasourceResults: [
37
+ {
38
+ key: legacy.key,
39
+ success: legacy.success,
40
+ skipped: legacy.skipped,
41
+ validationResults: legacy.validationResults,
42
+ fieldMappingResults: legacy.fieldMappingResults,
43
+ endpointTestResults: legacy.endpointTestResults,
44
+ error: legacy.error,
45
+ envelope: legacy.envelope
46
+ }
47
+ ]
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Map legacy array-shaped results to normalized datasource rows.
53
+ * @param {Array} rawResults
54
+ * @param {Object} data
55
+ * @returns {{ success: boolean, datasourceResults: Object[] }}
56
+ */
57
+ function mapLegacyRawResults(rawResults, data) {
58
+ const datasourceResults = [];
59
+ let success = true;
60
+
61
+ for (const r of rawResults) {
62
+ const dsKey = r.key || r.sourceKey || r.name || r.datasourceKey;
63
+ const dsResult = {
64
+ key: dsKey,
65
+ success: r.success !== false,
66
+ skipped: !!r.skipped,
67
+ reason: r.reason,
68
+ validationResults: r.validationResults || {},
69
+ fieldMappingResults: r.fieldMappingResults || {},
70
+ endpointTestResults: r.endpointTestResults || {}
71
+ };
72
+ if (r.error) dsResult.error = r.error;
73
+ if (!dsResult.success && !dsResult.skipped) success = false;
74
+ datasourceResults.push(dsResult);
75
+ }
76
+
77
+ if (rawResults.length === 0 && data.success === false) {
78
+ success = false;
79
+ datasourceResults.push(
80
+ systemFailureRow(data.error || data.formattedError || 'System test failed')
81
+ );
82
+ }
83
+
84
+ return { success, datasourceResults };
85
+ }
86
+
87
+ /**
88
+ * Normalize pipeline response body to { success, datasourceResults }.
89
+ * @param {Object} data
90
+ * @returns {{ success: boolean, datasourceResults: Object[] }}
91
+ */
92
+ function mapPipelineDataToDatasourceResults(data) {
93
+ if (
94
+ data &&
95
+ typeof data === 'object' &&
96
+ typeof data.status === 'string' &&
97
+ typeof data.datasourceKey === 'string'
98
+ ) {
99
+ return mapEnvelopeSingleDatasource(data, data.datasourceKey);
100
+ }
101
+
102
+ const rawResults =
103
+ data.datasourceResults || data.results || data.data?.datasourceResults || (Array.isArray(data) ? data : []);
104
+ return mapLegacyRawResults(rawResults, data);
105
+ }
106
+
107
+ module.exports = {
108
+ systemFailureRow,
109
+ mapPipelineDataToDatasourceResults
110
+ };