@aifabrix/builder 2.45.5 → 2.47.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 (355) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/project-rules.mdc +1 -0
  4. package/.npmrc.token +1 -0
  5. package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
  6. package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
  7. package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
  8. package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
  9. package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
  10. package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
  11. package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
  12. package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
  13. package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
  14. package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
  15. package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
  16. package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
  17. package/.temp/validation/summary.txt +5 -0
  18. package/README.md +43 -17
  19. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  20. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  21. package/jest.config.default.js +2 -1
  22. package/jest.config.isolated.js +2 -1
  23. package/jest.global-live-fabrix-hooks.js +36 -0
  24. package/jest.isolated-projects.js +146 -0
  25. package/jest.projects.js +65 -136
  26. package/lib/api/api-response-errors.js +124 -0
  27. package/lib/api/dataplane-health.api.js +19 -7
  28. package/lib/api/governance-scenario-pack.api.js +159 -0
  29. package/lib/api/index.js +43 -3
  30. package/lib/api/lifecycle.api.js +98 -0
  31. package/lib/api/pipeline.api.js +3 -1
  32. package/lib/api/records-bulk.api.js +14 -1
  33. package/lib/api/resource-types.api.js +107 -0
  34. package/lib/api/runtime-configuration.api.js +72 -0
  35. package/lib/api/types/resource-types.types.js +45 -0
  36. package/lib/api/user-groups.api.js +9 -9
  37. package/lib/api/users.api.js +8 -8
  38. package/lib/api/validation-runner.js +3 -1
  39. package/lib/api/wizard.api.js +10 -2
  40. package/lib/app/deploy-config.js +4 -1
  41. package/lib/app/down.js +78 -27
  42. package/lib/app/index.js +2 -2
  43. package/lib/app/push.js +4 -5
  44. package/lib/app/register.js +7 -4
  45. package/lib/app/run-env-compose.js +84 -30
  46. package/lib/app/run-resolve-image.js +2 -1
  47. package/lib/app/run-stop-containers.js +113 -0
  48. package/lib/app/run.js +1 -31
  49. package/lib/app/show-display.js +35 -0
  50. package/lib/app/show.js +32 -1
  51. package/lib/build/index.js +22 -5
  52. package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
  53. package/lib/certification/sync-system-certification.js +13 -6
  54. package/lib/channels/add-channel.js +348 -0
  55. package/lib/channels/channel-artifact-generator.js +141 -0
  56. package/lib/channels/channel-audit.js +101 -0
  57. package/lib/channels/channel-auth-context.js +37 -0
  58. package/lib/channels/channel-credential.js +200 -0
  59. package/lib/channels/channel-display-name.js +64 -0
  60. package/lib/channels/channel-external-system.js +106 -0
  61. package/lib/channels/channel-integration-generator.js +274 -0
  62. package/lib/channels/channel-probe.js +89 -0
  63. package/lib/channels/channel-runtime-resolver.js +152 -0
  64. package/lib/channels/channel-status-display.js +141 -0
  65. package/lib/channels/channel-targets.js +115 -0
  66. package/lib/cli/index.js +20 -4
  67. package/lib/cli/infra-guided-auth.js +109 -0
  68. package/lib/cli/infra-guided.js +84 -81
  69. package/lib/cli/setup-app.help.js +0 -31
  70. package/lib/cli/setup-app.js +82 -5
  71. package/lib/cli/setup-app.test-commands.js +5 -57
  72. package/lib/cli/setup-auth.js +25 -0
  73. package/lib/cli/setup-certification-commands.js +147 -0
  74. package/lib/cli/setup-certification.help.js +141 -0
  75. package/lib/cli/setup-environment.js +19 -2
  76. package/lib/cli/setup-external-system-help.js +62 -0
  77. package/lib/cli/setup-external-system.js +25 -3
  78. package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
  79. package/lib/cli/setup-infra-up-platform-action.js +2 -1
  80. package/lib/cli/setup-infra.js +9 -1
  81. package/lib/cli/setup-platform.js +6 -1
  82. package/lib/cli/setup-secrets.js +33 -1
  83. package/lib/cli/setup-utility-help-after.js +25 -2
  84. package/lib/cli/setup-utility-repair.js +198 -0
  85. package/lib/cli/setup-utility-resolve.js +44 -5
  86. package/lib/cli/setup-utility-validate.js +197 -0
  87. package/lib/cli/setup-utility.js +4 -239
  88. package/lib/commands/app-logs.js +54 -26
  89. package/lib/commands/app.js +41 -0
  90. package/lib/commands/auth-status-client-tokens.js +214 -0
  91. package/lib/commands/auth-status-dataplane-version.js +142 -68
  92. package/lib/commands/auth-status.js +43 -54
  93. package/lib/commands/channel.js +58 -0
  94. package/lib/commands/datasource-test-trust-cli.js +27 -23
  95. package/lib/commands/datasource-unified-test-cli.js +6 -3
  96. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  97. package/lib/commands/datasource.js +8 -8
  98. package/lib/commands/dev-show-display.js +8 -1
  99. package/lib/commands/governance-cli-shared.js +94 -0
  100. package/lib/commands/governance-command-action.js +132 -0
  101. package/lib/commands/governance-download-external.js +34 -0
  102. package/lib/commands/governance-generate-external.js +71 -0
  103. package/lib/commands/governance-upload-external.js +36 -0
  104. package/lib/commands/governance-verify-external.js +64 -0
  105. package/lib/commands/governance.js +144 -0
  106. package/lib/commands/identity-apply-sync.js +49 -8
  107. package/lib/commands/identity-group-cli.js +66 -26
  108. package/lib/commands/identity-membership-role-cache.js +58 -37
  109. package/lib/commands/identity-shared.js +22 -1
  110. package/lib/commands/identity-user-cli.js +80 -34
  111. package/lib/commands/lifecycle-command-action.js +123 -0
  112. package/lib/commands/lifecycle-external.js +268 -0
  113. package/lib/commands/login.js +11 -2
  114. package/lib/commands/repair-auth-apply.js +153 -0
  115. package/lib/commands/repair-auth-config.js +8 -13
  116. package/lib/commands/repair-changed-files.js +41 -0
  117. package/lib/commands/repair-datasource-com-v2.js +15 -0
  118. package/lib/commands/repair-datasource-keys.js +4 -1
  119. package/lib/commands/repair-datasource-run.js +59 -0
  120. package/lib/commands/repair-datasource-service-contract.js +206 -0
  121. package/lib/commands/repair-datasource-test-payload.js +259 -0
  122. package/lib/commands/repair-datasource.js +49 -64
  123. package/lib/commands/repair-env-template.js +76 -25
  124. package/lib/commands/repair-external-run.js +216 -0
  125. package/lib/commands/repair-openapi-sync.js +49 -4
  126. package/lib/commands/repair-persist.js +4 -0
  127. package/lib/commands/repair-rbac.js +52 -1
  128. package/lib/commands/repair-steps.js +160 -0
  129. package/lib/commands/repair-system-alignment.js +7 -4
  130. package/lib/commands/repair.js +29 -296
  131. package/lib/commands/resource-type.js +371 -0
  132. package/lib/commands/secrets-get.js +184 -0
  133. package/lib/commands/secrets-remove-all.js +3 -1
  134. package/lib/commands/setup-image-refresh.js +146 -0
  135. package/lib/commands/setup-modes.js +158 -162
  136. package/lib/commands/setup-platform-auth.js +76 -0
  137. package/lib/commands/setup-prompts-admin.js +244 -0
  138. package/lib/commands/setup-prompts-platform-mode.js +70 -0
  139. package/lib/commands/setup-prompts-validators.js +36 -0
  140. package/lib/commands/setup-prompts.js +24 -76
  141. package/lib/commands/setup-run-context.js +45 -0
  142. package/lib/commands/setup-spinners.js +39 -0
  143. package/lib/commands/setup.js +27 -5
  144. package/lib/commands/teardown.js +39 -0
  145. package/lib/commands/test-e2e-external.js +24 -8
  146. package/lib/commands/test-governance-external.js +3 -24
  147. package/lib/commands/test-trust-external.js +48 -100
  148. package/lib/commands/up-common.js +57 -13
  149. package/lib/commands/up-dataplane.js +56 -15
  150. package/lib/commands/upload-publish-context.js +75 -0
  151. package/lib/commands/upload-sidecar-followups.js +89 -0
  152. package/lib/commands/upload.js +113 -110
  153. package/lib/commands/verify-governance-combined-external.js +61 -0
  154. package/lib/commands/verify-governance-command-action.js +64 -0
  155. package/lib/commands/verify-governance-db.js +102 -0
  156. package/lib/commands/verify-governance-external.js +77 -0
  157. package/lib/commands/verify-governance-result-builders.js +71 -0
  158. package/lib/commands/verify-operations-command-action.js +68 -0
  159. package/lib/commands/verify-operations-external.js +268 -0
  160. package/lib/commands/verify-operations-persist.js +75 -0
  161. package/lib/commands/verify-operations-step-plan.js +68 -0
  162. package/lib/commands/verify-operations-steps.js +111 -0
  163. package/lib/commands/verify-trust-command-action.js +73 -0
  164. package/lib/commands/verify-trust-external.js +59 -0
  165. package/lib/commands/wizard-config-normalizer.js +43 -23
  166. package/lib/commands/wizard-core.js +2 -0
  167. package/lib/core/admin-password-generator.js +38 -0
  168. package/lib/core/admin-secrets-bundle.js +111 -0
  169. package/lib/core/admin-secrets-env-overlay.js +62 -0
  170. package/lib/core/admin-secrets.js +32 -4
  171. package/lib/core/config-attach-extensions.js +3 -0
  172. package/lib/core/config-platform-controller.js +44 -0
  173. package/lib/core/config-setup-installation-profile.js +42 -0
  174. package/lib/core/config-setup-platform-mode.js +46 -0
  175. package/lib/core/config.js +46 -36
  176. package/lib/core/secrets-admin-env.js +6 -2
  177. package/lib/core/secrets-ensure.js +4 -0
  178. package/lib/core/secrets-env-content.js +54 -48
  179. package/lib/core/secrets-env-write.js +10 -1
  180. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  181. package/lib/core/setup-installation-profile.js +43 -0
  182. package/lib/core/setup-platform-mode.js +90 -0
  183. package/lib/datasource/agent-trust-debug-log.js +1 -1
  184. package/lib/datasource/agent-trust-run.js +5 -3
  185. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  186. package/lib/datasource/audit-evidence-extract.js +7 -4
  187. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  188. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  189. package/lib/datasource/capability/capability-diff-slice.js +2 -2
  190. package/lib/datasource/capability/capability-manifest.js +254 -0
  191. package/lib/datasource/capability/capability-resolve.js +3 -4
  192. package/lib/datasource/capability/copy-operations.js +5 -3
  193. package/lib/datasource/capability/remove-operations.js +2 -1
  194. package/lib/datasource/capability/run-capability-copy.js +32 -4
  195. package/lib/datasource/capability/run-capability-diff.js +3 -3
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -4
  197. package/lib/datasource/capability/run-capability-edit.js +4 -7
  198. package/lib/datasource/capability/run-capability-relate.js +2 -4
  199. package/lib/datasource/capability/run-capability-remove.js +2 -4
  200. package/lib/datasource/capability/validate-capability-slice.js +2 -1
  201. package/lib/datasource/datasource-identifier.js +2 -1
  202. package/lib/datasource/datasource-load-export-context.js +3 -0
  203. package/lib/datasource/datasource-validate-display.js +1 -1
  204. package/lib/datasource/field-reference-validator.js +24 -3
  205. package/lib/datasource/log-cleaner.js +2 -2
  206. package/lib/datasource/log-viewer.js +8 -8
  207. package/lib/datasource/orphan-profiles-validator.js +98 -0
  208. package/lib/datasource/test-e2e.js +4 -1
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run.js +5 -2
  211. package/lib/datasource/validate.js +41 -23
  212. package/lib/deployment/environment-poll-status.js +138 -0
  213. package/lib/deployment/environment.js +42 -34
  214. package/lib/external-system/download-helpers.js +87 -0
  215. package/lib/external-system/download.js +78 -138
  216. package/lib/external-system/generator.js +1 -55
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test.js +16 -21
  220. package/lib/generator/builders.js +11 -1
  221. package/lib/generator/external-controller-manifest.js +18 -0
  222. package/lib/generator/split.js +3 -1
  223. package/lib/generator/wizard.js +1 -28
  224. package/lib/governance/governance-cli-errors.js +96 -0
  225. package/lib/governance/governance-download-display.js +38 -0
  226. package/lib/governance/governance-run-display.js +215 -25
  227. package/lib/identity/fk-reference.js +65 -0
  228. package/lib/identity/identity-apply-core.js +13 -58
  229. package/lib/identity/identity-apply-phases.js +5 -1
  230. package/lib/identity/identity-display.js +243 -0
  231. package/lib/identity/identity-response-helpers.js +52 -0
  232. package/lib/identity/identity-sync-errors.js +62 -0
  233. package/lib/identity/resolve-user-id.js +129 -0
  234. package/lib/identity/username-default.js +31 -0
  235. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  236. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  237. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  238. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  239. package/lib/infrastructure/helpers.js +23 -129
  240. package/lib/infrastructure/index.js +5 -6
  241. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  242. package/lib/lifecycle/certification-progress.js +231 -0
  243. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  244. package/lib/lifecycle/exit-codes.js +24 -0
  245. package/lib/lifecycle/json-envelope.js +25 -0
  246. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  247. package/lib/lifecycle/logger-quiet.js +29 -0
  248. package/lib/lifecycle/open-api-published.js +59 -0
  249. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  250. package/lib/lifecycle/product-model.js +196 -0
  251. package/lib/lifecycle/report-display-trust.js +70 -0
  252. package/lib/lifecycle/report-display.js +472 -0
  253. package/lib/lifecycle/scenario-upload.js +191 -0
  254. package/lib/lifecycle/verify-step-progress.js +87 -0
  255. package/lib/parameters/infra-kv-discovery.js +27 -2
  256. package/lib/protection/auth-context.js +10 -4
  257. package/lib/resolvers/datasource-resolver.js +2 -3
  258. package/lib/resolvers/resource-type-file.js +159 -0
  259. package/lib/schema/application-schema.json +17 -1
  260. package/lib/schema/datasource-test-run.schema.json +89 -6
  261. package/lib/schema/deployment-rules.yaml +2 -1
  262. package/lib/schema/external-datasource.schema.json +2947 -2619
  263. package/lib/schema/external-system.schema.json +1418 -761
  264. package/lib/schema/infra.parameter.yaml +45 -0
  265. package/lib/schema/type/credential-field-registry.json +103 -97
  266. package/lib/schema/type/document-storage.json +9 -5
  267. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  268. package/lib/utils/api.js +55 -31
  269. package/lib/utils/app-relative-path-env.js +112 -0
  270. package/lib/utils/app-run-containers.js +25 -2
  271. package/lib/utils/authentication-shape.js +224 -0
  272. package/lib/utils/build-copy.js +36 -5
  273. package/lib/utils/build-resolve-image.js +66 -12
  274. package/lib/utils/celery-companion-apps.js +53 -0
  275. package/lib/utils/cli-secrets-error-format.js +83 -21
  276. package/lib/utils/cli-utils.js +20 -4
  277. package/lib/utils/compose-celery-worker.js +23 -0
  278. package/lib/utils/compose-generate-docker-compose.js +13 -1
  279. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  280. package/lib/utils/config-secrets-path.js +46 -0
  281. package/lib/utils/configuration-env-resolver.js +36 -0
  282. package/lib/utils/controller-url.js +88 -1
  283. package/lib/utils/credential-secrets-env-kv.js +216 -0
  284. package/lib/utils/credential-secrets-env.js +175 -257
  285. package/lib/utils/dataplane-resolver.js +18 -2
  286. package/lib/utils/declarative-url-ports.js +27 -4
  287. package/lib/utils/deployment-auth-mode.js +41 -0
  288. package/lib/utils/developer-volume-id.js +33 -0
  289. package/lib/utils/docker-build.js +1 -4
  290. package/lib/utils/env-copy.js +14 -9
  291. package/lib/utils/env-kv-orphan-lines.js +43 -0
  292. package/lib/utils/error-formatters/network-errors.js +13 -4
  293. package/lib/utils/external-env-template.js +11 -3
  294. package/lib/utils/external-system-readiness-core.js +10 -0
  295. package/lib/utils/external-system-readiness-display.js +80 -23
  296. package/lib/utils/external-system-validators.js +8 -2
  297. package/lib/utils/health-check.js +4 -1
  298. package/lib/utils/help-builder.js +13 -8
  299. package/lib/utils/keycloak-realm-ready.js +101 -0
  300. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  301. package/lib/utils/manifest-source-emit.js +2 -0
  302. package/lib/utils/paths.js +25 -0
  303. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  304. package/lib/utils/platform-controller-url.js +157 -0
  305. package/lib/utils/platform-kv-ref.js +57 -0
  306. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  307. package/lib/utils/postgres-wipe.js +9 -2
  308. package/lib/utils/resolve-env-mode.js +47 -0
  309. package/lib/utils/runtime-configuration-download.js +189 -0
  310. package/lib/utils/runtime-configuration-values.js +119 -0
  311. package/lib/utils/schema-loader.js +19 -4
  312. package/lib/utils/secrets-generator.js +31 -25
  313. package/lib/utils/secrets-missing-error.js +164 -0
  314. package/lib/utils/service-url-label.js +81 -0
  315. package/lib/utils/setup-quiet-output.js +25 -0
  316. package/lib/utils/template-helpers.js +15 -0
  317. package/lib/utils/token-manager-client-credentials.js +201 -0
  318. package/lib/utils/token-manager-messages.js +8 -0
  319. package/lib/utils/token-manager-refresh.js +12 -2
  320. package/lib/utils/token-manager.js +86 -105
  321. package/lib/utils/upload-pipeline-ui.js +12 -5
  322. package/lib/utils/upload-sync-options.js +42 -0
  323. package/lib/utils/url-declarative-public-base.js +21 -3
  324. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  325. package/lib/utils/validation-poll-ui.js +8 -0
  326. package/lib/utils/validation-run-stage.js +45 -0
  327. package/lib/utils/worker-sidecars.js +142 -0
  328. package/lib/validation/external-manifest-validator.js +2 -0
  329. package/lib/validation/runtime-configuration-rules.js +98 -0
  330. package/lib/validation/validate-display-dimensions.js +154 -0
  331. package/lib/validation/validate-display-sections.js +276 -0
  332. package/lib/validation/validate-display-steps.js +67 -0
  333. package/lib/validation/validate-display.js +24 -402
  334. package/package.json +1 -1
  335. package/templates/applications/dataplane/application.yaml +7 -1
  336. package/templates/applications/dataplane/env.template +50 -14
  337. package/templates/applications/dataplane/rbac.yaml +108 -1
  338. package/templates/applications/miso-controller/application.yaml +2 -2
  339. package/templates/applications/miso-controller/env.template +53 -122
  340. package/templates/applications/miso-controller/rbac.yaml +28 -13
  341. package/templates/channels/chatgpt/install.template.md.hbs +49 -0
  342. package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
  343. package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
  344. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
  345. package/templates/channels/slack/install.template.md.hbs +49 -0
  346. package/templates/channels/slack/manifest.template.json.hbs +66 -0
  347. package/templates/channels/teams-bot/install.template.md.hbs +49 -0
  348. package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
  349. package/templates/channels/web-embed/install.template.md.hbs +49 -0
  350. package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
  351. package/templates/external-system/README.md.hbs +74 -17
  352. package/templates/python/docker-compose.hbs +75 -18
  353. package/templates/typescript/docker-compose.hbs +70 -17
  354. package/lib/commands/test-governance-command-action.js +0 -55
  355. package/lib/commands/test-trust-command-action.js +0 -118
@@ -10,6 +10,7 @@
10
10
 
11
11
  const path = require('path');
12
12
  const fs = require('fs');
13
+ const { loadConfigFile } = require('../utils/config-format');
13
14
  const pathsUtil = require('../utils/paths');
14
15
  const {
15
16
  datasourceIdentifierMatchesFile,
@@ -22,7 +23,16 @@ const { validateFieldReferences } = require('./field-reference-validator');
22
23
  const { validateAbac } = require('./abac-validator');
23
24
  const { buildDatasourceValidateSummary } = require('./datasource-validate-summary');
24
25
 
25
- const EXCLUDE_JSON_NAMES = new Set(['application.json', 'rbac.json', 'package.json', 'package-lock.json']);
26
+ const DATASOURCE_CONFIG_EXTENSIONS = new Set(['.json', '.yaml', '.yml']);
27
+ const EXCLUDE_CONFIG_NAMES = new Set([
28
+ 'application.json',
29
+ 'application.yaml',
30
+ 'application.yml',
31
+ 'rbac.json',
32
+ 'rbac.yaml',
33
+ 'package.json',
34
+ 'package-lock.json'
35
+ ]);
26
36
 
27
37
  /**
28
38
  * Resolve identifier to an existing file path, or null.
@@ -64,11 +74,14 @@ function pickIntegrationAppForDatasourceKey(datasourceKey, appNames) {
64
74
  * @param {string} fileName
65
75
  * @returns {boolean}
66
76
  */
67
- function shouldScanJsonDatasourceCandidate(fileName) {
77
+ function shouldScanDatasourceConfigCandidate(fileName) {
68
78
  const lower = fileName.toLowerCase();
69
- if (!lower.endsWith('.json')) return false;
70
- if (EXCLUDE_JSON_NAMES.has(fileName)) return false;
79
+ const ext = path.extname(lower);
80
+ if (!DATASOURCE_CONFIG_EXTENSIONS.has(ext)) return false;
81
+ if (EXCLUDE_CONFIG_NAMES.has(fileName)) return false;
71
82
  if (lower.endsWith('-deploy.json') || lower.endsWith('-system.json')) return false;
83
+ if (lower.endsWith('-deploy.yaml') || lower.endsWith('-deploy.yml')) return false;
84
+ if (lower.endsWith('-system.yaml') || lower.endsWith('-system.yml')) return false;
72
85
  return true;
73
86
  }
74
87
 
@@ -86,13 +99,13 @@ function isDatasourceNamedJson(fileName) {
86
99
  * @param {string} datasourceKey
87
100
  * @returns {string[]}
88
101
  */
89
- function collectJsonPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey) {
102
+ function collectConfigPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey) {
90
103
  const hits = [];
91
104
  for (const name of scanOrder) {
92
105
  const full = path.join(dir, name);
93
106
  let parsed;
94
107
  try {
95
- parsed = JSON.parse(fs.readFileSync(full, 'utf8'));
108
+ parsed = loadConfigFile(full);
96
109
  } catch {
97
110
  continue;
98
111
  }
@@ -115,14 +128,14 @@ function resolvePathFromIntegrationFolderScan(appName, datasourceKey) {
115
128
  throw new Error(`Integration folder not found: ${dir}`);
116
129
  }
117
130
  const entries = fs.readdirSync(dir);
118
- const jsonFiles = entries.filter(shouldScanJsonDatasourceCandidate);
119
- const prefer = jsonFiles.filter(isDatasourceNamedJson);
120
- const scanOrder = [...prefer, ...jsonFiles.filter((f) => !prefer.includes(f))];
121
- const hits = collectJsonPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey);
131
+ const configFiles = entries.filter(shouldScanDatasourceConfigCandidate);
132
+ const prefer = configFiles.filter(isDatasourceNamedJson);
133
+ const scanOrder = [...prefer, ...configFiles.filter((f) => !prefer.includes(f))];
134
+ const hits = collectConfigPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey);
122
135
  if (hits.length === 0) {
123
136
  throw new Error(
124
- `No datasource JSON matching "${datasourceKey}" under integration/${appName}/. ` +
125
- `Checked: ${scanOrder.length ? scanOrder.join(', ') : '(no JSON candidates)'}`
137
+ `No datasource config matching "${datasourceKey}" under integration/${appName}/. ` +
138
+ `Checked: ${scanOrder.length ? scanOrder.join(', ') : '(no JSON/YAML candidates)'}`
126
139
  );
127
140
  }
128
141
  if (hits.length > 1) {
@@ -167,7 +180,8 @@ function resolveValidateInputPath(identifier) {
167
180
  }
168
181
  const asFile = tryResolveAsExistingFile(trimmed);
169
182
  if (asFile) return asFile;
170
- if (trimmed.toLowerCase().endsWith('.json')) {
183
+ const ext = path.extname(trimmed).toLowerCase();
184
+ if (DATASOURCE_CONFIG_EXTENSIONS.has(ext)) {
171
185
  throw new Error(`File not found: ${trimmed}`);
172
186
  }
173
187
  return resolvePathFromIntegrationDatasourceKey(trimmed);
@@ -187,6 +201,18 @@ function resolveValidateInputPath(identifier) {
187
201
  * const result = await validateDatasourceFile('./hubspot-deal.json');
188
202
  * // Returns: { valid: true, errors: [], warnings: [], resolvedPath: '...' }
189
203
  */
204
+ function buildParseFailureResult(filePath, error) {
205
+ const message =
206
+ error && error.message ? String(error.message) : 'Invalid config file';
207
+ return {
208
+ valid: false,
209
+ errors: [message],
210
+ warnings: [],
211
+ resolvedPath: filePath,
212
+ summary: null
213
+ };
214
+ }
215
+
190
216
  async function validateDatasourceFile(filePathOrKey) {
191
217
  if (!filePathOrKey || typeof filePathOrKey !== 'string') {
192
218
  throw new Error('File path is required and must be a string');
@@ -194,19 +220,11 @@ async function validateDatasourceFile(filePathOrKey) {
194
220
 
195
221
  const filePath = resolveValidateInputPath(filePathOrKey.trim());
196
222
 
197
- const content = fs.readFileSync(filePath, 'utf8');
198
223
  let parsed;
199
-
200
224
  try {
201
- parsed = JSON.parse(content);
225
+ parsed = loadConfigFile(filePath);
202
226
  } catch (error) {
203
- return {
204
- valid: false,
205
- errors: [`Invalid JSON syntax: ${error.message}`],
206
- warnings: [],
207
- resolvedPath: filePath,
208
- summary: null
209
- };
227
+ return buildParseFailureResult(filePath, error);
210
228
  }
211
229
 
212
230
  const summary = buildDatasourceValidateSummary(parsed);
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Poll helpers for environment deploy status (deployment-by-ID).
3
+ *
4
+ * @fileoverview Parse pipeline/environments deployment poll responses and fail fast on terminal HTTP errors
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ const TERMINAL_POLL_HTTP_STATUSES = new Set([400, 401, 403, 404, 410, 422]);
10
+
11
+ /**
12
+ * @param {Object|null|undefined} response - API client response
13
+ * @returns {boolean}
14
+ */
15
+ function isTerminalPollApiResponse(response) {
16
+ return Boolean(
17
+ response &&
18
+ response.success === false &&
19
+ typeof response.status === 'number' &&
20
+ TERMINAL_POLL_HTTP_STATUSES.has(response.status)
21
+ );
22
+ }
23
+
24
+ /**
25
+ * @param {Object|null|undefined} response - Successful API client response
26
+ * @returns {Object|null} Deployment record or null
27
+ */
28
+ function extractDeploymentRecord(response) {
29
+ if (!response || response.success === false) {
30
+ return null;
31
+ }
32
+ if (response?.data?.data) {
33
+ return response.data.data;
34
+ }
35
+ if (response?.data && typeof response.data === 'object' && response.data.status) {
36
+ return response.data;
37
+ }
38
+ return null;
39
+ }
40
+
41
+ /**
42
+ * @param {Object|null|undefined} pipelineRes
43
+ * @param {Object|null|undefined} envRes
44
+ * @returns {Error}
45
+ */
46
+ /**
47
+ * @param {string} requestedEnvKey
48
+ * @param {Error} error
49
+ * @returns {Error}
50
+ */
51
+ function enrichPollTerminalError(requestedEnvKey, error) {
52
+ if (!error?.pollTerminal || error.status !== 404) {
53
+ return error;
54
+ }
55
+ const base = error.message || '';
56
+ if (!base.includes('Environment with key')) {
57
+ return error;
58
+ }
59
+ error.message =
60
+ `${base}\n\n` +
61
+ 'The deployment may have been created under a different environment key ' +
62
+ '(for example evaluation-mode fallback to miso). Check controller logs for ' +
63
+ `effectiveEnvironmentKey, register '${requestedEnvKey}' in the controller, or run ` +
64
+ 'aifabrix env deploy miso.';
65
+ return error;
66
+ }
67
+
68
+ function buildPollStatusError(pipelineRes, envRes) {
69
+ const terminal = [pipelineRes, envRes].filter(isTerminalPollApiResponse);
70
+ const source = terminal[0] || pipelineRes || envRes;
71
+ const message = source?.formattedError || source?.error || 'Unable to retrieve deployment status';
72
+ const err = new Error(message);
73
+ err.pollTerminal = true;
74
+ if (typeof source?.status === 'number') {
75
+ err.status = source.status;
76
+ }
77
+ return err;
78
+ }
79
+
80
+ /**
81
+ * Fetches deployment status by ID (pipeline endpoint first, then environments).
82
+ *
83
+ * @async
84
+ * @param {Function} getPipelineDeployment - pipeline.api getPipelineDeployment
85
+ * @param {Function} getDeployment - deployments.api getDeployment
86
+ * @param {string} controllerUrl
87
+ * @param {string} envKey
88
+ * @param {string} deploymentId
89
+ * @param {Object} apiAuthConfig
90
+ * @returns {Promise<Object|null>} Deployment record or null when status is not yet available (retry)
91
+ * @throws {Error} When both endpoints return a terminal HTTP error (e.g. environment not found)
92
+ */
93
+ async function fetchDeploymentStatusById(
94
+ getPipelineDeployment,
95
+ getDeployment,
96
+ controllerUrl,
97
+ envKey,
98
+ deploymentId,
99
+ apiAuthConfig
100
+ ) {
101
+ let pipelineRes;
102
+ let envRes;
103
+
104
+ try {
105
+ pipelineRes = await getPipelineDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
106
+ const fromPipeline = extractDeploymentRecord(pipelineRes);
107
+ if (fromPipeline) {
108
+ return fromPipeline;
109
+ }
110
+ } catch (err) {
111
+ pipelineRes = { success: false, error: err?.message || String(err) };
112
+ }
113
+
114
+ try {
115
+ envRes = await getDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
116
+ const fromEnv = extractDeploymentRecord(envRes);
117
+ if (fromEnv) {
118
+ return fromEnv;
119
+ }
120
+ } catch (err) {
121
+ envRes = { success: false, error: err?.message || String(err) };
122
+ }
123
+
124
+ if (isTerminalPollApiResponse(pipelineRes) || isTerminalPollApiResponse(envRes)) {
125
+ throw buildPollStatusError(pipelineRes, envRes);
126
+ }
127
+
128
+ return null;
129
+ }
130
+
131
+ module.exports = {
132
+ TERMINAL_POLL_HTTP_STATUSES,
133
+ isTerminalPollApiResponse,
134
+ extractDeploymentRecord,
135
+ enrichPollTerminalError,
136
+ buildPollStatusError,
137
+ fetchDeploymentStatusById
138
+ };
@@ -25,6 +25,7 @@ const {
25
25
  buildEnvironmentConfigFromPreset,
26
26
  loadAndValidateEnvironmentDeployConfig
27
27
  } = require('./environment-config');
28
+ const { fetchDeploymentStatusById, enrichPollTerminalError } = require('./environment-poll-status');
28
29
 
29
30
  /**
30
31
  * Validates environment deployment prerequisites
@@ -161,31 +162,24 @@ async function sendEnvironmentDeployment(controllerUrl, envKey, authConfig, opti
161
162
  }
162
163
 
163
164
  /**
164
- * Fetches deployment status by ID (pipeline endpoint first, then environments)
165
- * Mirrors miso-controller manual test: GET pipeline/deployments/:id then GET environments/deployments/:id
165
+ * Fetches deployment status by ID (pipeline endpoint first, then environments).
166
166
  * @async
167
167
  * @param {string} controllerUrl - Controller URL
168
168
  * @param {string} envKey - Environment key
169
169
  * @param {string} deploymentId - Deployment ID
170
170
  * @param {Object} apiAuthConfig - Auth config { type: 'bearer', token }
171
- * @returns {Promise<Object|null>} Deployment record (status, progress, etc.) or null
171
+ * @returns {Promise<Object|null>} Deployment record or null when still in progress
172
+ * @throws {Error} On terminal poll errors (e.g. environment or deployment not found)
172
173
  */
173
174
  async function getDeploymentStatusById(controllerUrl, envKey, deploymentId, apiAuthConfig) {
174
- try {
175
- const pipelineRes = await getPipelineDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
176
- if (pipelineRes?.data?.data) return pipelineRes.data.data;
177
- if (pipelineRes?.data && typeof pipelineRes.data === 'object' && pipelineRes.data.status) return pipelineRes.data;
178
- } catch {
179
- // Fallback to environments endpoint
180
- }
181
- try {
182
- const envRes = await getDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
183
- if (envRes?.data?.data) return envRes.data.data;
184
- if (envRes?.data && typeof envRes.data === 'object' && envRes.data.status) return envRes.data;
185
- } catch {
186
- // Ignore
187
- }
188
- return null;
175
+ return fetchDeploymentStatusById(
176
+ getPipelineDeployment,
177
+ getDeployment,
178
+ controllerUrl,
179
+ envKey,
180
+ deploymentId,
181
+ apiAuthConfig
182
+ );
189
183
  }
190
184
 
191
185
  /**
@@ -218,6 +212,33 @@ function processDeploymentStatusResponse(deployment, validatedEnvKey) {
218
212
  return null;
219
213
  }
220
214
 
215
+ /**
216
+ * @param {number} attempt
217
+ * @param {number} maxAttempts
218
+ * @param {Object|null} deployment
219
+ */
220
+ function logPollAttemptProgress(attempt, maxAttempts, deployment) {
221
+ const progress = deployment?.progress ?? 0;
222
+ const statusLabel = deployment?.status ?? 'pending';
223
+ logger.log(chalk.gray(` Attempt ${attempt}/${maxAttempts}... Status: ${statusLabel} (${progress}%)`));
224
+ }
225
+
226
+ /**
227
+ * @param {Error} error
228
+ * @param {string} validatedEnvKey
229
+ * @throws {Error}
230
+ */
231
+ function handlePollIterationError(error, validatedEnvKey) {
232
+ const msg = error?.message || '';
233
+ const isDeploymentFailed =
234
+ msg.includes('Environment deployment failed') ||
235
+ (msg.includes('failed') && !error.pollTerminal);
236
+ if (error.pollTerminal || isDeploymentFailed) {
237
+ throw enrichPollTerminalError(validatedEnvKey, error);
238
+ }
239
+ logger.log(chalk.yellow(` ⚠ Status check failed (will retry): ${msg}`));
240
+ }
241
+
221
242
  /**
222
243
  * Polls environment deployment status
223
244
  * @async
@@ -231,44 +252,31 @@ function processDeploymentStatusResponse(deployment, validatedEnvKey) {
231
252
  async function pollEnvironmentStatus(deploymentId, controllerUrl, envKey, authConfig, options = {}) {
232
253
  const validatedUrl = validateControllerUrl(controllerUrl);
233
254
  const validatedEnvKey = validateEnvironmentKey(envKey);
234
-
235
255
  const pollInterval = options.pollInterval || 5000;
236
256
  const maxAttempts = options.maxAttempts || 60;
257
+ const apiAuthConfig = { type: 'bearer', token: authConfig.token };
237
258
 
238
259
  logger.log(chalk.blue(`⏳ Polling environment status (${pollInterval}ms intervals)...`));
239
260
 
240
- // Use centralized API client
241
- const apiAuthConfig = { type: 'bearer', token: authConfig.token };
242
-
243
261
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
244
262
  try {
245
263
  await new Promise(resolve => setTimeout(resolve, pollInterval));
246
-
247
264
  const deployment = await getDeploymentStatusById(
248
265
  validatedUrl,
249
266
  validatedEnvKey,
250
267
  deploymentId,
251
268
  apiAuthConfig
252
269
  );
253
- const progress = deployment?.progress ?? 0;
254
- const statusLabel = deployment?.status ?? 'pending';
255
- if (attempt <= maxAttempts) {
256
- logger.log(chalk.gray(` Attempt ${attempt}/${maxAttempts}... Status: ${statusLabel} (${progress}%)`));
257
- }
270
+ logPollAttemptProgress(attempt, maxAttempts, deployment);
258
271
  const statusResult = processDeploymentStatusResponse(deployment, validatedEnvKey);
259
272
  if (statusResult) {
260
273
  return statusResult;
261
274
  }
262
275
  } catch (error) {
263
- // If it's a terminal error (not a timeout), throw it
264
- if (error.message && error.message.includes('failed')) {
265
- throw error;
266
- }
267
- // Otherwise, continue polling
276
+ handlePollIterationError(error, validatedEnvKey);
268
277
  }
269
278
  }
270
279
 
271
- // Timeout
272
280
  throw new Error(`Environment deployment timeout after ${maxAttempts} attempts. Check controller logs for status.`);
273
281
  }
274
282
 
@@ -8,8 +8,90 @@
8
8
  * @version 2.0.0
9
9
  */
10
10
 
11
+ const {
12
+ formatSuccessLine,
13
+ formatSuccessParagraph,
14
+ sectionTitle,
15
+ headerKeyValue
16
+ } = require('../utils/cli-test-layout-chalk');
17
+ const logger = require('../utils/logger');
11
18
  const { generateExternalReadmeContent } = require('../utils/external-readme');
12
19
 
20
+ /**
21
+ * Validates system type from downloaded application
22
+ * @param {Object} application - External system configuration
23
+ * @returns {string} System type (openapi, mcp, custom)
24
+ */
25
+ function validateSystemType(application) {
26
+ if (!application || typeof application !== 'object') {
27
+ throw new Error('Application configuration is required');
28
+ }
29
+ const validTypes = ['openapi', 'mcp', 'custom'];
30
+ const systemType = application.type;
31
+ if (!systemType || !validTypes.includes(systemType)) {
32
+ throw new Error(`Invalid system type: ${systemType}. Must be one of: ${validTypes.join(', ')}`);
33
+ }
34
+ return systemType;
35
+ }
36
+
37
+ function validateApplicationConfig(application) {
38
+ if (!application || typeof application !== 'object') {
39
+ throw new Error('Application configuration is required');
40
+ }
41
+ if (!application.key || typeof application.key !== 'string') {
42
+ throw new Error('Application key is required');
43
+ }
44
+ }
45
+
46
+ function validateDatasourceConfig(datasource, applicationKey) {
47
+ if (!datasource.key || typeof datasource.key !== 'string') {
48
+ throw new Error('Datasource key is required for all datasources');
49
+ }
50
+ if (!datasource.systemKey || typeof datasource.systemKey !== 'string') {
51
+ throw new Error('Datasource systemKey is required for all datasources');
52
+ }
53
+ if (datasource.systemKey !== applicationKey) {
54
+ throw new Error(
55
+ `Datasource systemKey (${datasource.systemKey}) does not match application key (${applicationKey})`
56
+ );
57
+ }
58
+ }
59
+
60
+ function validateDownloadedData(application, dataSources) {
61
+ validateApplicationConfig(application);
62
+ if (!Array.isArray(dataSources)) {
63
+ throw new Error('DataSources must be an array');
64
+ }
65
+ for (const datasource of dataSources) {
66
+ validateDatasourceConfig(datasource, application.key);
67
+ }
68
+ }
69
+
70
+ function logDownloadCommandHeader(systemKey) {
71
+ logger.log('');
72
+ logger.log(sectionTitle('Download'));
73
+ logger.log(headerKeyValue('System:', systemKey));
74
+ }
75
+
76
+ function displayDownloadSuccess(systemKey, finalPath, datasourceCount) {
77
+ logger.log(
78
+ formatSuccessParagraph(
79
+ `Downloaded ${systemKey} (${datasourceCount} datasource${datasourceCount === 1 ? '' : 's'})`
80
+ )
81
+ );
82
+ logger.log(headerKeyValue('Location:', finalPath));
83
+ }
84
+
85
+ async function runConvertToJsonIfRequested(systemKey) {
86
+ const { runConvert } = require('../commands/convert');
87
+ try {
88
+ await runConvert(systemKey, { format: 'json', force: true });
89
+ logger.log(formatSuccessLine('Converted component files to JSON'));
90
+ } catch (convertErr) {
91
+ throw new Error(`Download succeeded but convert to JSON failed: ${convertErr.message}`);
92
+ }
93
+ }
94
+
13
95
  /**
14
96
  * Generates application.yaml content for downloaded system
15
97
  * @param {string} systemKey - System key
@@ -90,6 +172,11 @@ function generateReadme(systemKey, application, dataSources) {
90
172
  }
91
173
 
92
174
  module.exports = {
175
+ validateSystemType,
176
+ validateDownloadedData,
177
+ logDownloadCommandHeader,
178
+ displayDownloadSuccess,
179
+ runConvertToJsonIfRequested,
93
180
  generateVariablesYaml,
94
181
  generateReadme
95
182
  };