@aifabrix/builder 2.43.0 → 2.44.1

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 (371) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/.cursor/rules/cli-layout.mdc +75 -0
  3. package/.cursor/rules/project-rules.mdc +8 -0
  4. package/.npmrc.token +1 -0
  5. package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  6. package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  7. package/.nyc_output/processinfo/index.json +1 -0
  8. package/README.md +1 -1
  9. package/anchor-docs/README.md +10 -0
  10. package/anchor-docs/_TEMPLATE +24 -0
  11. package/bin/aifabrix.js +13 -4
  12. package/integration/hubspot-test/README.md +31 -0
  13. package/integration/hubspot-test/create-hubspot.js +5 -5
  14. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  15. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  16. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  17. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  18. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  19. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  20. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  21. package/integration/hubspot-test/test.js +35 -43
  22. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  23. package/integration/roundtrip-test-local/README.md +144 -0
  24. package/integration/roundtrip-test-local/application.yaml +13 -0
  25. package/integration/roundtrip-test-local/env.template +15 -0
  26. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  27. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  28. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  29. package/integration/roundtrip-test-local2/README.md +144 -0
  30. package/integration/roundtrip-test-local2/application.yaml +13 -0
  31. package/integration/roundtrip-test-local2/env.template +15 -0
  32. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  33. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  34. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  35. package/integration/test/wizard.yaml +8 -0
  36. package/jest.config.default.js +10 -0
  37. package/jest.config.integration.fixtures.js +22 -0
  38. package/jest.config.integration.js +21 -18
  39. package/jest.config.isolated.js +10 -0
  40. package/jest.projects.js +301 -0
  41. package/lib/api/certificates.api.js +62 -0
  42. package/lib/api/datasources-core.api.js +3 -3
  43. package/lib/api/dev-mtls-request.js +110 -0
  44. package/lib/api/dev-server-https.js +145 -0
  45. package/lib/api/dev.api.js +133 -144
  46. package/lib/api/index.js +11 -3
  47. package/lib/api/pipeline.api.js +67 -20
  48. package/lib/api/types/certificates.types.js +48 -0
  49. package/lib/api/types/dev.types.js +4 -3
  50. package/lib/api/types/pipeline.types.js +8 -5
  51. package/lib/api/types/validation-run.types.js +56 -0
  52. package/lib/api/validation-run.api.js +111 -0
  53. package/lib/api/validation-runner.js +109 -0
  54. package/lib/app/certification-show-enrich.js +129 -0
  55. package/lib/app/certification-verify-rows.js +60 -0
  56. package/lib/app/config.js +1 -1
  57. package/lib/app/deploy-status-display.js +2 -2
  58. package/lib/app/deploy.js +7 -6
  59. package/lib/app/display.js +2 -1
  60. package/lib/app/dockerfile.js +3 -2
  61. package/lib/app/down.js +2 -1
  62. package/lib/app/helpers.js +6 -5
  63. package/lib/app/index.js +27 -8
  64. package/lib/app/list.js +7 -6
  65. package/lib/app/push.js +4 -3
  66. package/lib/app/register.js +16 -7
  67. package/lib/app/rotate-secret.js +14 -13
  68. package/lib/app/run-container-start.js +184 -0
  69. package/lib/app/run-docker-fallback.js +108 -0
  70. package/lib/app/run-env-compose.js +30 -42
  71. package/lib/app/run-helpers.js +49 -126
  72. package/lib/app/run-infra-requirements.js +30 -0
  73. package/lib/app/run-resolve-image.js +21 -0
  74. package/lib/app/run.js +74 -21
  75. package/lib/app/show-display.js +44 -1
  76. package/lib/app/show.js +93 -9
  77. package/lib/build/index.js +13 -10
  78. package/lib/certification/cli-cert-sync-skip.js +21 -0
  79. package/lib/certification/merge-certification-from-artifact.js +185 -0
  80. package/lib/certification/post-unified-cert-sync.js +33 -0
  81. package/lib/certification/sync-after-external-command.js +52 -0
  82. package/lib/certification/sync-system-certification.js +197 -0
  83. package/lib/cli/index.js +2 -0
  84. package/lib/cli/setup-app.help.js +67 -0
  85. package/lib/cli/setup-app.js +61 -121
  86. package/lib/cli/setup-app.test-commands.js +195 -0
  87. package/lib/cli/setup-auth.js +19 -5
  88. package/lib/cli/setup-credential-deployment.js +22 -8
  89. package/lib/cli/setup-dev-path-commands.js +124 -0
  90. package/lib/cli/setup-dev.js +170 -113
  91. package/lib/cli/setup-environment.js +7 -1
  92. package/lib/cli/setup-external-system.js +84 -23
  93. package/lib/cli/setup-infra.js +126 -47
  94. package/lib/cli/setup-parameters.js +32 -0
  95. package/lib/cli/setup-secrets.js +137 -18
  96. package/lib/cli/setup-service-user.js +1 -1
  97. package/lib/cli/setup-utility.js +54 -22
  98. package/lib/commands/app-down.js +5 -7
  99. package/lib/commands/app-install.js +14 -7
  100. package/lib/commands/app-logs.js +13 -10
  101. package/lib/commands/app-shell.js +4 -1
  102. package/lib/commands/app-test.js +25 -19
  103. package/lib/commands/app.js +32 -11
  104. package/lib/commands/auth-config.js +6 -6
  105. package/lib/commands/auth-status.js +4 -3
  106. package/lib/commands/credential-env.js +4 -3
  107. package/lib/commands/credential-list.js +5 -4
  108. package/lib/commands/credential-push.js +4 -3
  109. package/lib/commands/datasource-unified-test-cli.js +428 -0
  110. package/lib/commands/datasource-unified-test-cli.options.js +191 -0
  111. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
  112. package/lib/commands/datasource-validation-cli.js +143 -0
  113. package/lib/commands/datasource.js +125 -95
  114. package/lib/commands/deployment-list.js +6 -5
  115. package/lib/commands/dev-cli-handlers.js +122 -18
  116. package/lib/commands/dev-down.js +4 -3
  117. package/lib/commands/dev-init.js +231 -116
  118. package/lib/commands/dev-show-display.js +473 -0
  119. package/lib/commands/login-credentials.js +3 -2
  120. package/lib/commands/login-device.js +4 -3
  121. package/lib/commands/login.js +5 -4
  122. package/lib/commands/logout.js +8 -7
  123. package/lib/commands/parameters-validate.js +54 -0
  124. package/lib/commands/repair-datasource.js +314 -68
  125. package/lib/commands/repair-env-template.js +2 -2
  126. package/lib/commands/repair.js +21 -3
  127. package/lib/commands/secrets-list.js +23 -12
  128. package/lib/commands/secrets-remove-all.js +220 -0
  129. package/lib/commands/secrets-remove.js +21 -12
  130. package/lib/commands/secrets-set.js +21 -12
  131. package/lib/commands/secrets-validate.js +4 -4
  132. package/lib/commands/secure.js +10 -9
  133. package/lib/commands/service-user.js +26 -25
  134. package/lib/commands/test-e2e-external.js +27 -1
  135. package/lib/commands/up-common.js +3 -2
  136. package/lib/commands/up-dataplane.js +29 -16
  137. package/lib/commands/up-miso.js +19 -29
  138. package/lib/commands/upload.js +149 -39
  139. package/lib/commands/wizard-core-helpers.js +1 -1
  140. package/lib/commands/wizard-dataplane.js +4 -3
  141. package/lib/commands/wizard-helpers.js +3 -3
  142. package/lib/commands/wizard.js +2 -2
  143. package/lib/core/admin-secrets.js +14 -5
  144. package/lib/core/audit-logger.js +12 -4
  145. package/lib/core/config-attach-extensions.js +46 -0
  146. package/lib/core/config-runtime-paths.js +29 -0
  147. package/lib/core/config.js +55 -56
  148. package/lib/core/diff.js +3 -2
  149. package/lib/core/ensure-encryption-key.js +1 -1
  150. package/lib/core/secrets-ensure-infra.js +77 -0
  151. package/lib/core/secrets-ensure.js +120 -64
  152. package/lib/core/secrets-env-write.js +35 -7
  153. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  154. package/lib/core/secrets.js +200 -37
  155. package/lib/core/templates-env.js +4 -3
  156. package/lib/datasource/abac-validator.js +1 -10
  157. package/lib/datasource/deploy.js +75 -53
  158. package/lib/datasource/field-reference-validator.js +9 -6
  159. package/lib/datasource/integration-context.js +63 -0
  160. package/lib/datasource/list.js +8 -7
  161. package/lib/datasource/log-viewer.js +189 -67
  162. package/lib/datasource/resolve-app.js +4 -4
  163. package/lib/datasource/test-e2e.js +113 -146
  164. package/lib/datasource/test-integration.js +114 -122
  165. package/lib/datasource/unified-validation-run-body.js +68 -0
  166. package/lib/datasource/unified-validation-run-post.js +23 -0
  167. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  168. package/lib/datasource/unified-validation-run.js +93 -0
  169. package/lib/datasource/validate.js +157 -13
  170. package/lib/deployment/deployer.js +4 -3
  171. package/lib/deployment/environment.js +7 -6
  172. package/lib/deployment/push.js +17 -8
  173. package/lib/external-system/delete.js +4 -3
  174. package/lib/external-system/deploy.js +166 -53
  175. package/lib/external-system/download-helpers.js +1 -1
  176. package/lib/external-system/download.js +7 -6
  177. package/lib/external-system/generator.js +92 -6
  178. package/lib/external-system/integration-test-dispatch.js +26 -0
  179. package/lib/external-system/test-execution.js +5 -1
  180. package/lib/external-system/test-helpers.js +0 -4
  181. package/lib/external-system/test-system-level-helpers.js +110 -0
  182. package/lib/external-system/test-system-level.js +83 -44
  183. package/lib/external-system/test.js +59 -8
  184. package/lib/generator/builders.js +23 -11
  185. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  186. package/lib/generator/external.js +16 -4
  187. package/lib/generator/helpers.js +58 -3
  188. package/lib/generator/index.js +4 -0
  189. package/lib/generator/split-readme.js +12 -7
  190. package/lib/generator/split-variables.js +2 -1
  191. package/lib/generator/split.js +1 -1
  192. package/lib/generator/wizard-readme.js +3 -3
  193. package/lib/generator/wizard.js +8 -8
  194. package/lib/infrastructure/compose.js +70 -7
  195. package/lib/infrastructure/helpers-docker-check.js +67 -0
  196. package/lib/infrastructure/helpers.js +203 -42
  197. package/lib/infrastructure/index.js +31 -18
  198. package/lib/infrastructure/services.js +21 -67
  199. package/lib/internal/fs-real-sync.js +104 -0
  200. package/lib/internal/node-fs.js +98 -0
  201. package/lib/parameters/database-secret-values.js +173 -0
  202. package/lib/parameters/infra-kv-discovery.js +121 -0
  203. package/lib/parameters/infra-parameter-catalog.js +458 -0
  204. package/lib/parameters/infra-parameter-validate.js +64 -0
  205. package/lib/schema/application-schema.json +37 -17
  206. package/lib/schema/datasource-test-run.schema.json +493 -0
  207. package/lib/schema/deployment-rules.yaml +102 -63
  208. package/lib/schema/external-datasource.schema.json +1200 -442
  209. package/lib/schema/external-system.schema.json +203 -5
  210. package/lib/schema/flag-map-validation-run.json +31 -0
  211. package/lib/schema/infra-parameter.schema.json +106 -0
  212. package/lib/schema/infra.parameter.yaml +421 -0
  213. package/lib/schema/type/credential-auth-templates.json +40 -0
  214. package/lib/schema/type/document-storage.json +226 -0
  215. package/lib/schema/type/message-service.json +123 -0
  216. package/lib/schema/type/vector-store.json +88 -0
  217. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  218. package/lib/utils/api-error-handler.js +2 -2
  219. package/lib/utils/api.js +77 -17
  220. package/lib/utils/app-register-api.js +3 -2
  221. package/lib/utils/app-register-auth.js +1 -1
  222. package/lib/utils/app-register-config.js +4 -4
  223. package/lib/utils/app-register-display.js +3 -2
  224. package/lib/utils/app-register-validator.js +3 -2
  225. package/lib/utils/app-run-containers.js +26 -22
  226. package/lib/utils/app-scoped-config.js +31 -0
  227. package/lib/utils/app-service-env-from-builder.js +164 -0
  228. package/lib/utils/build-copy.js +1 -1
  229. package/lib/utils/build-helpers.js +20 -20
  230. package/lib/utils/build-resolve-image.js +165 -0
  231. package/lib/utils/cli-layout-chalk.js +8 -0
  232. package/lib/utils/cli-test-layout-chalk.js +267 -0
  233. package/lib/utils/cli-utils.js +88 -11
  234. package/lib/utils/compose-db-passwords.js +138 -0
  235. package/lib/utils/compose-generate-docker-compose.js +216 -0
  236. package/lib/utils/compose-generator.js +197 -291
  237. package/lib/utils/compose-miso-env.js +18 -0
  238. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  239. package/lib/utils/config-paths.js +166 -7
  240. package/lib/utils/config-scoped-resources-preference.js +41 -0
  241. package/lib/utils/configuration-env-resolver.js +11 -8
  242. package/lib/utils/controller-deployment-outcome.js +68 -0
  243. package/lib/utils/credential-display.js +2 -2
  244. package/lib/utils/credential-secrets-env.js +5 -5
  245. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  246. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  247. package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
  248. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  249. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  250. package/lib/utils/datasource-test-run-display.js +459 -0
  251. package/lib/utils/datasource-test-run-exit.js +83 -0
  252. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  253. package/lib/utils/datasource-test-run-report-version.js +51 -0
  254. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  255. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  256. package/lib/utils/datasource-validation-watch.js +266 -0
  257. package/lib/utils/declarative-url-ports.js +47 -0
  258. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  259. package/lib/utils/dev-ca-install.js +185 -23
  260. package/lib/utils/dev-cert-helper.js +266 -17
  261. package/lib/utils/dev-hosts-helper.js +307 -0
  262. package/lib/utils/dev-init-cert-hints.js +37 -0
  263. package/lib/utils/dev-init-health-messages.js +52 -0
  264. package/lib/utils/dev-init-resolve.js +86 -0
  265. package/lib/utils/dev-init-ssh-merge.js +65 -0
  266. package/lib/utils/dev-ssh-config-helper.js +196 -0
  267. package/lib/utils/dev-user-groups.js +93 -0
  268. package/lib/utils/docker-build.js +42 -17
  269. package/lib/utils/docker-exec.js +28 -0
  270. package/lib/utils/docker-manifest-public-port.js +116 -0
  271. package/lib/utils/docker-not-running-hint.js +52 -0
  272. package/lib/utils/docker.js +98 -11
  273. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  274. package/lib/utils/env-config-loader.js +10 -91
  275. package/lib/utils/env-copy.js +19 -10
  276. package/lib/utils/env-map.js +35 -8
  277. package/lib/utils/env-template.js +2 -2
  278. package/lib/utils/environment-scoped-resources.js +144 -0
  279. package/lib/utils/error-formatter.js +92 -13
  280. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  281. package/lib/utils/error-formatters/network-errors.js +2 -1
  282. package/lib/utils/error-formatters/permission-errors.js +2 -1
  283. package/lib/utils/error-formatters/validation-errors.js +2 -1
  284. package/lib/utils/external-readme.js +8 -1
  285. package/lib/utils/external-system-display.js +242 -136
  286. package/lib/utils/external-system-local-test-tty.js +389 -0
  287. package/lib/utils/external-system-readiness-core.js +377 -0
  288. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  289. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  290. package/lib/utils/external-system-readiness-display.js +186 -0
  291. package/lib/utils/external-system-system-test-tty-overview.js +120 -0
  292. package/lib/utils/external-system-system-test-tty.js +417 -0
  293. package/lib/utils/external-system-test-helpers.js +24 -6
  294. package/lib/utils/external-system-validators.js +30 -12
  295. package/lib/utils/health-check-url.js +119 -0
  296. package/lib/utils/health-check.js +59 -25
  297. package/lib/utils/help-builder.js +11 -8
  298. package/lib/utils/image-version.js +4 -8
  299. package/lib/utils/infra-containers.js +4 -7
  300. package/lib/utils/infra-env-defaults.js +162 -0
  301. package/lib/utils/infra-status-display.js +167 -0
  302. package/lib/utils/infra-status.js +16 -8
  303. package/lib/utils/local-secrets.js +3 -4
  304. package/lib/utils/paths.js +148 -47
  305. package/lib/utils/port-resolver.js +10 -23
  306. package/lib/utils/redis-env-scope.js +62 -0
  307. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  308. package/lib/utils/remote-builder-validation.js +99 -0
  309. package/lib/utils/remote-dev-auth.js +117 -21
  310. package/lib/utils/remote-docker-env.js +67 -15
  311. package/lib/utils/remote-secrets-loader.js +13 -4
  312. package/lib/utils/resolve-docker-image-ref.js +124 -0
  313. package/lib/utils/schema-loader.js +22 -9
  314. package/lib/utils/secrets-bash-kv.js +25 -0
  315. package/lib/utils/secrets-generator.js +169 -49
  316. package/lib/utils/secrets-helpers.js +70 -59
  317. package/lib/utils/secrets-kv-scope.js +60 -0
  318. package/lib/utils/secrets-utils.js +32 -38
  319. package/lib/utils/secrets-validation.js +3 -1
  320. package/lib/utils/secrets-yaml-preserve.js +109 -0
  321. package/lib/utils/ssh-key-helper.js +4 -2
  322. package/lib/utils/template-helpers.js +2 -2
  323. package/lib/utils/test-log-writer.js +3 -3
  324. package/lib/utils/token-manager.js +1 -2
  325. package/lib/utils/url-declarative-public-base.js +188 -0
  326. package/lib/utils/url-declarative-resolve-build.js +493 -0
  327. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  328. package/lib/utils/url-declarative-resolve.js +220 -0
  329. package/lib/utils/url-declarative-token-parse.js +74 -0
  330. package/lib/utils/url-declarative-url-flags.js +50 -0
  331. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  332. package/lib/utils/url-public-path-prefix.js +34 -0
  333. package/lib/utils/urls-local-registry.js +220 -0
  334. package/lib/utils/validation-report-tty-kit.js +77 -0
  335. package/lib/utils/validation-run-poll.js +112 -0
  336. package/lib/utils/validation-run-post-retry.js +85 -0
  337. package/lib/utils/validation-run-request.js +116 -0
  338. package/lib/utils/variable-transformer.js +21 -4
  339. package/lib/utils/yaml-preserve.js +33 -14
  340. package/lib/validation/datasource-warnings.js +56 -0
  341. package/lib/validation/env-template-auth.js +1 -1
  342. package/lib/validation/external-manifest-validator.js +27 -7
  343. package/lib/validation/validate-display.js +37 -31
  344. package/lib/validation/validate-external-cert-sync.js +23 -0
  345. package/lib/validation/validate.js +8 -14
  346. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  347. package/lib/validation/validator.js +22 -65
  348. package/lib/validation/wizard-config-validator.js +2 -1
  349. package/package.json +9 -4
  350. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  351. package/scripts/diagnose-cli.js +150 -0
  352. package/scripts/install-local.js +307 -55
  353. package/scripts/pnpm-global-remove.js +48 -0
  354. package/templates/README.md +15 -2
  355. package/templates/applications/dataplane/application.yaml +52 -2
  356. package/templates/applications/dataplane/env.template +79 -17
  357. package/templates/applications/dataplane/rbac.yaml +8 -0
  358. package/templates/applications/keycloak/application.yaml +9 -1
  359. package/templates/applications/keycloak/env.template +15 -6
  360. package/templates/applications/miso-controller/application.yaml +10 -2
  361. package/templates/applications/miso-controller/env.template +42 -12
  362. package/templates/applications/miso-controller/rbac.yaml +5 -0
  363. package/templates/external-system/README.md.hbs +20 -7
  364. package/templates/external-system/deploy.js.hbs +5 -5
  365. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  366. package/templates/infra/compose.yaml.hbs +33 -16
  367. package/templates/infra/servers.json.hbs +3 -1
  368. package/templates/python/docker-compose.hbs +16 -0
  369. package/templates/typescript/docker-compose.hbs +16 -0
  370. package/lib/api/external-test.api.js +0 -111
  371. 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,166 @@ 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');
30
+ const { maybeSyncSystemCertificationFromDataplane } = require('../certification/sync-system-certification');
31
+ const { cliOptsSkipCertSync } = require('../certification/cli-cert-sync-skip');
23
32
 
24
33
  /**
25
- * Displays API and MCP documentation URLs from dataplane when available
34
+ * Lists datasources for a system and loads system record for docs URLs.
26
35
  * @async
27
- * @function displayDeploymentDocs
28
36
  * @param {string} controllerUrl - Controller base URL
29
37
  * @param {string} environment - Environment key
30
- * @param {Object} authConfig - Authentication configuration
31
- * @param {string} systemKey - External system key
38
+ * @param {Object} authConfig - Auth config
39
+ * @param {string} systemKey - System key
40
+ * @returns {Promise<{ dataplaneUrl: string, datasources: Object[], system: Object|null, error: Error|null }>}
32
41
  */
33
- async function displayDeploymentDocs(controllerUrl, environment, authConfig, systemKey) {
42
+ async function fetchDataplaneDeployReadiness(controllerUrl, environment, authConfig, systemKey) {
43
+ let dataplaneUrl;
34
44
  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 });
45
+ dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
46
+ } catch (err) {
47
+ return { dataplaneUrl: null, datasources: [], system: null, error: err };
48
+ }
49
+
50
+ let datasources = [];
51
+ try {
52
+ const listRes = await listDatasources(dataplaneUrl, authConfig, {
53
+ sourceSystemIdOrKey: systemKey,
54
+ pageSize: 100
55
+ });
56
+ if (listRes.success && listRes.data) {
57
+ try {
58
+ datasources = extractDatasources(listRes);
59
+ } catch (e) {
60
+ logger.log(
61
+ chalk.yellow(
62
+ `⚠ Unable to parse datasources list from dataplane response: ${e && e.message ? e.message : 'unknown error'}`
63
+ )
64
+ );
65
+ datasources = [];
66
+ }
53
67
  }
68
+ } catch (err) {
69
+ return { dataplaneUrl, datasources: [], system: null, error: err };
70
+ }
54
71
 
55
- if (urls.length > 0) {
56
- logger.log(chalk.blue('\nDocumentation:'));
57
- urls.forEach(({ label, url }) => {
58
- logger.log(chalk.blue(` ${label}: ${url}`));
59
- });
72
+ try {
73
+ const getRes = await getExternalSystem(dataplaneUrl, systemKey, authConfig);
74
+ const system = unwrapApiData(getRes);
75
+ return {
76
+ dataplaneUrl,
77
+ datasources,
78
+ system: system && typeof system === 'object' ? system : null,
79
+ error: null
80
+ };
81
+ } catch (err) {
82
+ if (datasources.length === 0) {
83
+ return { dataplaneUrl, datasources, system: null, error: err };
60
84
  }
61
- } catch (_err) {
62
- // Silently ignore: dataplane may be unreachable or docs not configured
85
+ return { dataplaneUrl, datasources, system: null, error: null };
63
86
  }
64
87
  }
65
88
 
66
89
  /**
67
- * Deploys via controller and displays success summary with docs
90
+ * Deploys via controller and prints readiness summary (config / deployment / runtime layers).
68
91
  * @async
69
- * @function executeDeployAndDisplay
70
92
  * @param {Object} manifest - Controller manifest
71
93
  * @param {string} controllerUrl - Controller base URL
72
94
  * @param {string} environment - Environment key
73
95
  * @param {Object} authConfig - Authentication configuration
74
- * @param {Object} options - Deployment options
96
+ * @param {Object} options - Deployment options (poll, probe, probeTimeout)
75
97
  * @returns {Promise<Object>} Deployment result
76
98
  */
99
+ /**
100
+ * @param {Object} deploymentOutcome - from parseControllerDeploymentOutcome
101
+ */
102
+ /**
103
+ * Optional dataplane validation/run after external deploy (--probe).
104
+ * @async
105
+ * @param {{ dataplaneUrl: string|null, error: Error|null }} ctx
106
+ * @param {string} systemKey
107
+ * @param {Object} authConfig
108
+ * @param {Object} options
109
+ * @returns {Promise<Object|null>} Unwrapped probe payload or null
110
+ */
111
+ async function runOptionalExternalDeployProbe(ctx, systemKey, authConfig, options) {
112
+ if (!options.probe || !ctx.dataplaneUrl || ctx.error) return null;
113
+ logger.log(chalk.blue('\nRunning runtime checks (--probe)...'));
114
+ try {
115
+ const pr = await testSystemViaPipeline(ctx.dataplaneUrl, systemKey, authConfig, {}, {
116
+ timeout: options.probeTimeout || 120000
117
+ });
118
+ if (pr.success === false) {
119
+ logger.log(chalk.yellow(`⚠ Probe request failed: ${pr.formattedError || pr.error || 'unknown error'}`));
120
+ return null;
121
+ }
122
+ return unwrapApiData(pr);
123
+ } catch (e) {
124
+ logger.log(chalk.yellow(`⚠ Probe failed: ${e.message}`));
125
+ return null;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * @param {Object} deploymentOutcome
131
+ * @param {{ dataplaneUrl: string|null, error: Error|null }} ctx
132
+ * @param {Object} manifest
133
+ * @param {Object} options
134
+ * @param {Object} authConfig
135
+ * @returns {Promise<void>}
136
+ */
137
+ async function maybeSyncCertificationAfterExternalDeploy(deploymentOutcome, ctx, manifest, options, authConfig) {
138
+ if (!deploymentOutcome.ok || !ctx.dataplaneUrl || ctx.error) return;
139
+ const dsKeys = (manifest.dataSources || []).map((ds) => ds && ds.key).filter(Boolean);
140
+ await maybeSyncSystemCertificationFromDataplane({
141
+ label: 'deploy',
142
+ noCertSync: cliOptsSkipCertSync(options),
143
+ systemKey: manifest.key,
144
+ dataplaneUrl: ctx.dataplaneUrl,
145
+ authConfig,
146
+ datasourceKeys: dsKeys
147
+ });
148
+ }
149
+
150
+ function logImmediateControllerDeploymentOutcome(deploymentOutcome) {
151
+ if (deploymentOutcome.ok) {
152
+ logger.log(formatSuccessParagraph('Controller deployment OK'));
153
+ return;
154
+ }
155
+ logger.log(chalk.red('\n✖ Controller deployment did not complete successfully'));
156
+ const parts = [deploymentOutcome.error, deploymentOutcome.message].filter(Boolean);
157
+ if (parts.length > 0) {
158
+ for (const line of parts) {
159
+ logger.log(chalk.red(` ${line}`));
160
+ }
161
+ return;
162
+ }
163
+ if (deploymentOutcome.statusLabel) {
164
+ logger.log(
165
+ chalk.yellow(
166
+ ` Controller status: ${deploymentOutcome.statusLabel} (no message or error in API response)`
167
+ )
168
+ );
169
+ return;
170
+ }
171
+ logger.log(chalk.gray(' See Deployment section below for details.'));
172
+ }
173
+
77
174
  async function executeDeployAndDisplay(manifest, controllerUrl, environment, authConfig, options) {
78
175
  const deployer = require('../deployment/deployer');
79
176
  const pollOpts = {
80
177
  poll: options.poll,
81
178
  pollInterval: options.pollInterval !== undefined ? options.pollInterval : 500,
82
- pollMaxAttempts: options.pollMaxAttempts,
179
+ // External-system deploy only: ~10s poll window (matches controller→dataplane publish timeout). Not used for Azure/webapp deploy polling.
180
+ pollMaxAttempts: options.pollMaxAttempts !== undefined ? options.pollMaxAttempts : 22,
83
181
  ...options
84
182
  };
85
183
  const result = await deployer.deployToController(
@@ -89,17 +187,39 @@ async function executeDeployAndDisplay(manifest, controllerUrl, environment, aut
89
187
  authConfig,
90
188
  pollOpts
91
189
  );
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);
190
+
191
+ const deploymentOutcome = parseControllerDeploymentOutcome(result);
192
+ logImmediateControllerDeploymentOutcome(deploymentOutcome);
193
+
194
+ const ctx = await fetchDataplaneDeployReadiness(
195
+ controllerUrl,
196
+ environment,
197
+ authConfig,
198
+ manifest.key
199
+ );
200
+
201
+ const probeData = await runOptionalExternalDeployProbe(ctx, manifest.key, authConfig, options);
202
+
203
+ logDeployReadinessSummary({
204
+ environment,
205
+ dataplaneUrl: ctx.dataplaneUrl,
206
+ manifest,
207
+ datasources: ctx.datasources,
208
+ systemFromDataplane: ctx.system,
209
+ fetchError: ctx.error,
210
+ deploymentOk: deploymentOutcome.ok,
211
+ deploymentDetail: deploymentOutcome.ok ? null : deploymentOutcome,
212
+ probeData
213
+ });
214
+
215
+ await maybeSyncCertificationAfterExternalDeploy(deploymentOutcome, ctx, manifest, options, authConfig);
216
+
96
217
  return result;
97
218
  }
98
219
 
99
220
  /**
100
221
  * Prepares deployment configuration (auth, controller URL, environment)
101
222
  * @async
102
- * @function prepareDeploymentConfig
103
223
  * @param {string} appName - Application name
104
224
  * @param {Object} options - Deployment options
105
225
  * @returns {Promise<Object>} Deployment configuration
@@ -119,16 +239,12 @@ async function prepareDeploymentConfig(appName, _options) {
119
239
 
120
240
  /**
121
241
  * Deploys external system via controller pipeline (same as regular apps)
122
- * Uses unified controller pipeline - no direct dataplane calls
123
242
  *
124
243
  * @async
125
- * @function deployExternalSystem
126
244
  * @param {string} appName - Application name
127
245
  * @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)
246
+ * @param {boolean} [options.probe] - Run dataplane validation/run after deploy
247
+ * @param {number} [options.probeTimeout] - Probe timeout ms (default 120000)
132
248
  * @returns {Promise<Object>} Deployment result
133
249
  * @throws {Error} If deployment fails
134
250
  */
@@ -139,7 +255,6 @@ async function deployExternalSystem(appName, options = {}) {
139
255
 
140
256
  logger.log(chalk.blue(`\n🚀 Deploying external system: ${appName}`));
141
257
 
142
- // Step 0: Validate before deployment (same as validate command)
143
258
  logger.log(chalk.blue('🔍 Validating external system before deployment...'));
144
259
  const validationResult = await validateExternalSystemComplete(appName, options);
145
260
 
@@ -148,15 +263,12 @@ async function deployExternalSystem(appName, options = {}) {
148
263
  throw new Error('Validation failed. Fix errors before deploying.');
149
264
  }
150
265
 
151
- logger.log(chalk.green(' Validation passed, proceeding with deployment...'));
266
+ logger.log(formatSuccessLine('Local validation passed, proceeding with deployment...'));
152
267
 
153
- // Step 1: Generate controller manifest (validated, ready for deployment)
154
268
  const manifest = await generateControllerManifest(appName, options);
155
269
 
156
- // Step 2: Get deployment configuration (auth, controller URL, etc.)
157
270
  const { environment, controllerUrl, authConfig } = await prepareDeploymentConfig(appName, options);
158
271
 
159
- // Step 3: Deploy via controller pipeline (same as regular apps)
160
272
  const result = await executeDeployAndDisplay(
161
273
  manifest,
162
274
  controllerUrl,
@@ -175,6 +287,7 @@ async function deployExternalSystem(appName, options = {}) {
175
287
  }
176
288
 
177
289
  module.exports = {
178
- deployExternalSystem
290
+ deployExternalSystem,
291
+ executeDeployAndDisplay,
292
+ fetchDataplaneDeployReadiness
179
293
  };
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