@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
@@ -16,6 +16,9 @@ const { formatProgress } = require('./cli-test-layout-chalk');
16
16
  * @returns {boolean}
17
17
  */
18
18
  function shouldShowUploadPipelineProgress(options = {}) {
19
+ if (options.suppressPipelineSpinner === true) {
20
+ return false;
21
+ }
19
22
  return options.json !== true;
20
23
  }
21
24
 
@@ -35,17 +38,21 @@ function shouldUseUploadPipelineSpinner(options = {}) {
35
38
  * @param {string} systemKey
36
39
  * @returns {string}
37
40
  */
38
- function buildUploadPipelineSpinnerLabel(systemKey) {
41
+ function buildUploadPipelineSpinnerLabel(systemKey, opts = {}) {
42
+ if (opts.syncMode === true) {
43
+ return 'Checking config on dataplane…';
44
+ }
39
45
  const key = systemKey && String(systemKey).trim() ? String(systemKey).trim() : 'integration';
40
46
  return `Publishing ${key} to dataplane…`;
41
47
  }
42
48
 
43
49
  /**
44
50
  * @param {string} systemKey
51
+ * @param {Object} [opts]
45
52
  * @returns {string}
46
53
  */
47
- function buildUploadPipelineProgressText(systemKey) {
48
- return formatProgress(buildUploadPipelineSpinnerLabel(systemKey));
54
+ function buildUploadPipelineProgressText(systemKey, opts = {}) {
55
+ return formatProgress(buildUploadPipelineSpinnerLabel(systemKey, opts));
49
56
  }
50
57
 
51
58
  /**
@@ -64,12 +71,12 @@ async function runWithUploadPipelineSpinner(work, opts = {}) {
64
71
  }
65
72
 
66
73
  if (!shouldUseUploadPipelineSpinner(opts)) {
67
- logger.log(buildUploadPipelineProgressText(opts.systemKey));
74
+ logger.log(buildUploadPipelineProgressText(opts.systemKey, opts));
68
75
  return work();
69
76
  }
70
77
 
71
78
  const ora = require('ora');
72
- const label = buildUploadPipelineSpinnerLabel(opts.systemKey);
79
+ const label = buildUploadPipelineSpinnerLabel(opts.systemKey, opts);
73
80
  const spinner = ora({
74
81
  text: chalk.white(label),
75
82
  spinner: 'dots'
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Build options for `uploadExternalSystem` on test-command --sync paths.
3
+ *
4
+ * @fileoverview Minimal upload sync options (force, verbose)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * @param {Object} [options] - CLI options from test / sync callers
13
+ * @returns {{ minimal: true, verbose: boolean, silentResolve: true, syncMode: true, force?: true }}
14
+ */
15
+ function buildMinimalUploadSyncOptions(options = {}) {
16
+ const out = {
17
+ minimal: true,
18
+ // CLI -v on verify-* / test-* is for run output, not preflight upload banners.
19
+ verbose: false,
20
+ silentResolve: true,
21
+ syncMode: true,
22
+ suppressPipelineSpinner: options.suppressPipelineSpinner === true
23
+ };
24
+ if (options.force === true) {
25
+ out.force = true;
26
+ }
27
+ return out;
28
+ }
29
+
30
+ /**
31
+ * Minimal sync paths (verify-*, test --sync) always suppress upload sidecar chatter.
32
+ * @param {Object} [options]
33
+ * @returns {boolean}
34
+ */
35
+ function isQuietMinimalSync(options = {}) {
36
+ return options.minimal === true || options.syncMode === true;
37
+ }
38
+
39
+ module.exports = {
40
+ buildMinimalUploadSyncOptions,
41
+ isQuietMinimalSync
42
+ };
@@ -51,6 +51,12 @@ function hostPortForProfile(profile, listenPort, developerIdNum) {
51
51
  : localHostPort(listenPort, developerIdNum);
52
52
  }
53
53
 
54
+ function localhostFrontDoorBaseForMissingRemote(opts) {
55
+ const { profile, developerIdNum } = opts || {};
56
+ const port = hostPortForProfile(profile, 3000, developerIdNum);
57
+ return `http://localhost:${port}`.replace(/\/+$/, '');
58
+ }
59
+
54
60
  /**
55
61
  * Scheme for `declarativePublicUrlsUseLocalhost` bases: always **http** for loopback reachability
56
62
  * (ignore `tlsEnabled` / `remote-server` https — localhost URLs are not served with TLS in dev).
@@ -155,14 +161,26 @@ function templateUsesRemoteHostPlaceholder(hostTemplate) {
155
161
  * @returns {string|null}
156
162
  */
157
163
  function buildTraefikPublicBaseIfApplicable(opts) {
158
- const { traefik, pathActive, hostTemplate, developerIdRaw, remoteServer, infraTlsEnabled } =
159
- opts;
164
+ const {
165
+ traefik,
166
+ pathActive,
167
+ hostTemplate,
168
+ developerIdRaw,
169
+ remoteServer,
170
+ infraTlsEnabled,
171
+ profile,
172
+ developerIdNum
173
+ } = opts;
160
174
  // Plan 124: Traefik host authority only when pathActive (traefik ∧ frontDoorRouting.enabled)
161
175
  if (!traefik || !pathActive || !hostTemplate || !String(hostTemplate).trim()) {
162
176
  return null;
163
177
  }
164
178
  if (templateUsesRemoteHostPlaceholder(hostTemplate) && !String(remoteServer || '').trim()) {
165
- return null;
179
+ // Local full-platform (no remote domain): use the single localhost front door port (3000 + devId×100).
180
+ return localhostFrontDoorBaseForMissingRemote({
181
+ profile,
182
+ developerIdNum
183
+ });
166
184
  }
167
185
  const expanded = expandFrontDoorHostTemplateForUrls(hostTemplate, {
168
186
  developerIdRaw,
@@ -15,6 +15,7 @@ const yaml = require('js-yaml');
15
15
  const { existsSync, readFileSync } = require('../internal/fs-real-sync');
16
16
  const { DECLARATIVE_URL_INFRA_DEFAULTS } = require('./infra-env-defaults');
17
17
  const { computePathActive } = require('./url-declarative-url-flags');
18
+ const { resolveInactiveVdirRewriteEnvKeys } = require('./app-relative-path-env');
18
19
 
19
20
  /**
20
21
  * Treat common YAML / string forms as enabled (strict `=== true` alone missed some parsers).
@@ -52,16 +53,22 @@ const INACTIVE_VDIR_PUBLIC_ENV_FALLBACK =
52
53
  /**
53
54
  * @param {string} content - .env template fragment
54
55
  * @param {string} replacement
56
+ * @param {ReadonlySet<string>} rewriteKeys
55
57
  * @returns {string}
56
58
  */
57
- function applyInactiveVdirPublicTokenRewrite(content, replacement) {
59
+ function applyInactiveVdirPublicTokenRewrite(content, replacement, rewriteKeys) {
58
60
  if (!content || !content.includes(URL_DECLARATIVE_VDIR_PUBLIC_TOKEN)) {
59
61
  return content;
60
62
  }
61
63
  const escaped = URL_DECLARATIVE_VDIR_PUBLIC_TOKEN.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
62
64
  // End line with [ \t]* only — \s would consume \n and strip line endings from the file.
63
- const lineRe = new RegExp(`^(\\s*[A-Z][A-Z0-9_]*)\\s*=\\s*${escaped}[ \t]*$`, 'gm');
64
- return content.replace(lineRe, (_, lhs) => `${lhs}=${replacement}`);
65
+ const lineRe = new RegExp(`^(\\s*)([A-Z][A-Z0-9_]*)\\s*=\\s*${escaped}[ \t]*$`, 'gm');
66
+ return content.replace(lineRe, (match, indent, key) => {
67
+ if (!rewriteKeys.has(key)) {
68
+ return match;
69
+ }
70
+ return `${indent}${key}=${replacement}`;
71
+ });
65
72
  }
66
73
 
67
74
  /**
@@ -88,12 +95,15 @@ function rewriteInactiveDeclarativeVdirPublicContent(content, variablesPath, use
88
95
  if (pathActive) {
89
96
  return content;
90
97
  }
91
- return applyInactiveVdirPublicTokenRewrite(content, INACTIVE_VDIR_PUBLIC_ENV_FALLBACK);
98
+ const appKey = doc && doc.app && doc.app.key;
99
+ const rewriteKeys = resolveInactiveVdirRewriteEnvKeys(appKey);
100
+ return applyInactiveVdirPublicTokenRewrite(content, INACTIVE_VDIR_PUBLIC_ENV_FALLBACK, rewriteKeys);
92
101
  }
93
102
 
94
103
  module.exports = {
95
104
  URL_DECLARATIVE_VDIR_PUBLIC_TOKEN,
96
105
  INACTIVE_VDIR_PUBLIC_ENV_FALLBACK,
106
+ loadApplicationYamlDoc,
97
107
  applyInactiveVdirPublicTokenRewrite,
98
108
  rewriteInactiveDeclarativeVdirPublicContent,
99
109
  isFrontDoorRoutingEnabledInDoc
@@ -48,6 +48,14 @@ const NON_TTY_THROTTLE_MS = 5000;
48
48
  * @returns {{ usesSpinner: boolean, onPollProgress: Function, finish: () => void }}
49
49
  */
50
50
  function createValidationPollHandlers(deadlineMs, opts = {}) {
51
+ if (opts.quiet === true) {
52
+ return {
53
+ usesSpinner: false,
54
+ onPollProgress: () => {},
55
+ finish: () => {}
56
+ };
57
+ }
58
+
51
59
  const subject = opts.subject;
52
60
  if (shouldUseValidationPollSpinner()) {
53
61
  const ora = require('ora');
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @fileoverview Map legacy validation runType to contract stage (dataplane 370.07).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ /** @typedef {'readiness'|'simulation'|'integration'|'e2e'} ValidationRunStage */
8
+
9
+ /** @type {Record<string, ValidationRunStage>} */
10
+ const RUN_TYPE_TO_STAGE = {
11
+ test: 'readiness',
12
+ integration: 'integration',
13
+ e2e: 'e2e'
14
+ };
15
+
16
+ /**
17
+ * Contract stage for a CLI/API runType (default product mapping).
18
+ * @param {string} runType - test | integration | e2e
19
+ * @returns {ValidationRunStage}
20
+ */
21
+ function stageForRunType(runType) {
22
+ const key = String(runType || 'test');
23
+ return RUN_TYPE_TO_STAGE[key] || 'readiness';
24
+ }
25
+
26
+ /**
27
+ * Attach stage to a validation/run POST body when absent.
28
+ * @param {Object} body
29
+ * @param {string} [runType]
30
+ * @returns {Object}
31
+ */
32
+ function withStageOnValidationRunBody(body, runType) {
33
+ const out = { ...body };
34
+ const rt = runType || out.runType || 'test';
35
+ if (!out.stage) {
36
+ out.stage = stageForRunType(rt);
37
+ }
38
+ return out;
39
+ }
40
+
41
+ module.exports = {
42
+ RUN_TYPE_TO_STAGE,
43
+ stageForRunType,
44
+ withStageOnValidationRunBody
45
+ };
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Worker sidecar resolution from application.yaml build settings.
3
+ *
4
+ * @fileoverview Generic worker/beat companions driven by build.worker and imageRun* fields
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { buildDefaultLocalContainerName } = require('./environment-scoped-resources');
10
+
11
+ /**
12
+ * @param {object|null|undefined} build
13
+ * @param {string} field
14
+ * @returns {string|null}
15
+ */
16
+ function readImageRunCommand(build, field) {
17
+ if (!build || typeof build !== 'object') {
18
+ return null;
19
+ }
20
+ const raw = build[field];
21
+ if (typeof raw !== 'string') {
22
+ return null;
23
+ }
24
+ const trimmed = raw.trim();
25
+ return trimmed ? trimmed : null;
26
+ }
27
+
28
+ /**
29
+ * @param {object|null|undefined} appConfig
30
+ * @returns {boolean}
31
+ */
32
+ function isWorkerStackEnabled(appConfig) {
33
+ if (!appConfig || typeof appConfig !== 'object') {
34
+ return false;
35
+ }
36
+ return appConfig.build?.worker === true;
37
+ }
38
+
39
+ /**
40
+ * @param {string} appKey
41
+ * @param {object|null|undefined} appConfig
42
+ * @returns {{
43
+ * enabled: boolean,
44
+ * worker: { key: string, command: string }|null,
45
+ * beat: { key: string, command: string }|null,
46
+ * companions: Array<{ role: string, key: string, command: string }>
47
+ * }}
48
+ */
49
+ function resolveWorkerSidecars(appKey, appConfig) {
50
+ const empty = { enabled: false, worker: null, beat: null, companions: [] };
51
+ if (!isWorkerStackEnabled(appConfig)) {
52
+ return empty;
53
+ }
54
+
55
+ const build = appConfig.build && typeof appConfig.build === 'object' ? appConfig.build : {};
56
+ const workerCommand = readImageRunCommand(build, 'imageRunWorker');
57
+ const beatCommand = readImageRunCommand(build, 'imageRunBeat');
58
+ const companions = [];
59
+
60
+ if (workerCommand) {
61
+ companions.push({ role: 'worker', key: `${appKey}-worker`, command: workerCommand });
62
+ }
63
+ if (beatCommand) {
64
+ companions.push({ role: 'beat', key: `${appKey}-beat`, command: beatCommand });
65
+ }
66
+
67
+ if (companions.length === 0) {
68
+ return empty;
69
+ }
70
+
71
+ const worker = companions.find((entry) => entry.role === 'worker') || null;
72
+ const beat = companions.find((entry) => entry.role === 'beat') || null;
73
+
74
+ return {
75
+ enabled: true,
76
+ worker,
77
+ beat,
78
+ companions
79
+ };
80
+ }
81
+
82
+ /**
83
+ * @param {string} appKey
84
+ * @param {object|null|undefined} appConfig
85
+ * @returns {string[]}
86
+ */
87
+ function getWorkerCompanionAppKeys(appKey, appConfig) {
88
+ return resolveWorkerSidecars(appKey, appConfig).companions.map((entry) => entry.key);
89
+ }
90
+
91
+ /**
92
+ * @param {string} appKey
93
+ * @param {object} appConfig
94
+ * @param {{ devId: string|number, idNum: number }} ids
95
+ * @returns {{
96
+ * enabled: boolean,
97
+ * worker?: { key: string, containerName: string, command: string },
98
+ * beat?: { key: string, containerName: string, command: string }
99
+ * }}
100
+ */
101
+ function buildWorkerSidecarComposeContext(appKey, appConfig, ids) {
102
+ const sidecars = resolveWorkerSidecars(appKey, appConfig);
103
+ if (!sidecars.enabled) {
104
+ return { enabled: false };
105
+ }
106
+
107
+ const context = { enabled: true };
108
+ if (sidecars.worker) {
109
+ context.worker = {
110
+ key: sidecars.worker.key,
111
+ containerName: buildDefaultLocalContainerName(sidecars.worker.key, ids.devId, ids.idNum),
112
+ command: sidecars.worker.command
113
+ };
114
+ }
115
+ if (sidecars.beat) {
116
+ context.beat = {
117
+ key: sidecars.beat.key,
118
+ containerName: buildDefaultLocalContainerName(sidecars.beat.key, ids.devId, ids.idNum),
119
+ command: sidecars.beat.command
120
+ };
121
+ }
122
+ return context;
123
+ }
124
+
125
+ /**
126
+ * Azure startupCommand from compose imageRun (drops leading exec).
127
+ *
128
+ * @param {string} imageRun
129
+ * @returns {string}
130
+ */
131
+ function imageRunToStartupCommand(imageRun) {
132
+ return imageRun.replace(/^exec\s+/i, '').trim();
133
+ }
134
+
135
+ module.exports = {
136
+ readImageRunCommand,
137
+ isWorkerStackEnabled,
138
+ resolveWorkerSidecars,
139
+ getWorkerCompanionAppKeys,
140
+ buildWorkerSidecarComposeContext,
141
+ imageRunToStartupCommand
142
+ };
@@ -16,6 +16,7 @@ const path = require('path');
16
16
  const { formatValidationErrors } = require('../utils/error-formatter');
17
17
  const { validateFieldReferences } = require('../datasource/field-reference-validator');
18
18
  const { validateAbac } = require('../datasource/abac-validator');
19
+ const { validateManifestRuntimeConfiguration } = require('./runtime-configuration-rules');
19
20
 
20
21
  /**
21
22
  * Load and normalize external-system + external-datasource schema objects for manifest AJV.
@@ -247,6 +248,7 @@ async function validateControllerManifest(manifest) {
247
248
  validateInlineSystem(manifest, ajv, externalSystemSchema, errors);
248
249
  validateDatasources(manifest, ajv, externalDatasourceSchema, errors, warnings);
249
250
  validateDatasourceSystemKeyAlignment(manifest, errors);
251
+ errors.push(...validateManifestRuntimeConfiguration(manifest));
250
252
  validateConditionalRequirements(manifest, errors, warnings);
251
253
  validateRequiredFields(manifest, errors);
252
254
 
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Runtime configuration validation for external system manifests.
3
+ *
4
+ * @fileoverview Datasource override rules (v1: no keyvault overrides)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ /**
10
+ * @param {Array<{ name?: string, location?: string }>|undefined} systemConfiguration
11
+ * @returns {Map<string, { name?: string, location?: string }>}
12
+ */
13
+ function systemConfigDefsByName(systemConfiguration) {
14
+ const defsByName = new Map();
15
+ for (const item of systemConfiguration || []) {
16
+ if (item && item.name) {
17
+ defsByName.set(String(item.name).trim(), item);
18
+ }
19
+ }
20
+ return defsByName;
21
+ }
22
+
23
+ /**
24
+ * @param {string} prefix
25
+ * @param {Map<string, { name?: string, location?: string }>} defsByName
26
+ * @param {{ name?: string, value?: string }} override
27
+ * @returns {string[]}
28
+ */
29
+ function validateOverrideEntry(prefix, defsByName, override) {
30
+ if (!override || !override.name) {
31
+ return [];
32
+ }
33
+ const name = String(override.name).trim();
34
+ const def = defsByName.get(name);
35
+ if (!def) {
36
+ return [`${prefix}configuration override '${name}' is not declared on the parent system.`];
37
+ }
38
+ const errors = [];
39
+ if (String(def.location || 'variable').toLowerCase() === 'keyvault') {
40
+ errors.push(
41
+ `${prefix}configuration override '${name}' targets a keyvault system definition (not allowed in v1).`
42
+ );
43
+ }
44
+ const extraKeys = Object.keys(override).filter((key) => key !== 'name' && key !== 'value');
45
+ if (extraKeys.length > 0) {
46
+ errors.push(
47
+ `${prefix}configuration override '${name}' must contain only name and value (found: ${extraKeys.join(', ')}).`
48
+ );
49
+ }
50
+ return errors;
51
+ }
52
+
53
+ /**
54
+ * Validates datasource configuration[] overrides against parent system definitions.
55
+ *
56
+ * @param {Array<{ name?: string, location?: string }>|undefined} systemConfiguration
57
+ * @param {Array<{ name?: string, value?: string }>|undefined} datasourceConfiguration
58
+ * @param {string} [datasourceKey] - For error prefixes
59
+ * @returns {string[]} Validation errors
60
+ */
61
+ function validateDatasourceConfigurationOverrides(
62
+ systemConfiguration,
63
+ datasourceConfiguration,
64
+ datasourceKey
65
+ ) {
66
+ if (!Array.isArray(datasourceConfiguration) || datasourceConfiguration.length === 0) {
67
+ return [];
68
+ }
69
+ const prefix = datasourceKey ? `Datasource '${datasourceKey}': ` : '';
70
+ const defsByName = systemConfigDefsByName(systemConfiguration);
71
+ return datasourceConfiguration.flatMap((override) =>
72
+ validateOverrideEntry(prefix, defsByName, override)
73
+ );
74
+ }
75
+
76
+ /**
77
+ * @param {{ system?: { configuration?: unknown[] }, dataSources?: Array<{ key?: string, configuration?: unknown[] }> }} manifest
78
+ * @returns {string[]}
79
+ */
80
+ function validateManifestRuntimeConfiguration(manifest) {
81
+ const errors = [];
82
+ const systemConfiguration = manifest?.system?.configuration;
83
+ for (const ds of manifest?.dataSources || []) {
84
+ errors.push(
85
+ ...validateDatasourceConfigurationOverrides(
86
+ systemConfiguration,
87
+ ds?.configuration,
88
+ ds?.key
89
+ )
90
+ );
91
+ }
92
+ return errors;
93
+ }
94
+
95
+ module.exports = {
96
+ validateDatasourceConfigurationOverrides,
97
+ validateManifestRuntimeConfiguration
98
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @fileoverview Dimensions (ABAC) display helpers for validate-display.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { loadConfigFile } = require('../utils/config-format');
10
+ const { flattenRootDimensionsForDisplay } = require('./dimension-display-helpers');
11
+ const { formatDatasourceListRow } = require('../utils/cli-test-layout-chalk');
12
+ const logger = require('../utils/logger');
13
+ const {
14
+ logSectionTitle,
15
+ logWarnRow,
16
+ logDimLine
17
+ } = require('./validate-display-log-helpers');
18
+
19
+ /**
20
+ * True when datasource is orchestration-only (no ABAC dimensions contract).
21
+ * @param {string} filePath - Path to datasource JSON
22
+ * @returns {boolean}
23
+ */
24
+ function isOrchestrationOnlyDatasource(filePath) {
25
+ try {
26
+ const parsed = loadConfigFile(filePath);
27
+ return String(parsed?.entityType || '').trim() === 'none';
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Extracts dimensions from a datasource file for CLI display.
35
+ * Local bindings become `metadata.<field>`; FK bindings become `fk:<fk>→<dimension>...` plus optional `(actor: ...)`.
36
+ * @function extractDimensionsFromDatasource
37
+ * @param {string} filePath - Path to datasource file
38
+ * @returns {Object} Dimensions info { dimensions: Object, dimensionKeys: string[], hasDimensions: boolean }
39
+ */
40
+ function extractDimensionsFromDatasource(filePath) {
41
+ try {
42
+ const parsed = loadConfigFile(filePath);
43
+
44
+ const rootFlat = flattenRootDimensionsForDisplay(parsed.dimensions);
45
+ const abacDimensions = parsed.abac?.dimensions || {};
46
+ const allDimensions = { ...rootFlat, ...abacDimensions };
47
+ const dimensionKeys = Object.keys(allDimensions);
48
+
49
+ return {
50
+ dimensions: allDimensions,
51
+ dimensionKeys,
52
+ hasDimensions: dimensionKeys.length > 0
53
+ };
54
+ } catch {
55
+ return { dimensions: {}, dimensionKeys: [], hasDimensions: false };
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Displays Dimensions (ABAC) validation results for datasources
61
+ * @function displayDimensionsValidation
62
+ * @param {Array} externalFiles - External files validation results
63
+ * @returns {Array} Warnings to add to aggregated warnings
64
+ */
65
+ function displayDimensionsValidation(externalFiles) {
66
+ if (!externalFiles || externalFiles.length === 0) {
67
+ return [];
68
+ }
69
+
70
+ const datasourceFiles = externalFiles.filter(f =>
71
+ f.type === 'datasource' || f.type === 'external-datasource'
72
+ );
73
+
74
+ if (datasourceFiles.length === 0) {
75
+ return [];
76
+ }
77
+
78
+ logSectionTitle('Dimensions (ABAC)');
79
+
80
+ const warnings = [];
81
+ let anyDatasourceHasDimensions = false;
82
+
83
+ datasourceFiles.forEach(file => {
84
+ if (file.path && isOrchestrationOnlyDatasource(file.path)) {
85
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
86
+ logDimLine('orchestration-only (entityType=none) — dimensions N/A');
87
+ return;
88
+ }
89
+ const dimensionsInfo = extractDimensionsFromDatasource(file.path);
90
+
91
+ if (dimensionsInfo.hasDimensions) {
92
+ anyDatasourceHasDimensions = true;
93
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
94
+ dimensionsInfo.dimensionKeys.forEach(key => {
95
+ const mapping = dimensionsInfo.dimensions[key];
96
+ logDimLine(`${key} → ${mapping}`);
97
+ });
98
+ } else {
99
+ logWarnRow(`${file.file} — no dimensions configured`);
100
+ warnings.push(`${file.file} - no dimensions configured, ABAC filtering disabled`);
101
+ }
102
+ });
103
+
104
+ if (!anyDatasourceHasDimensions && datasourceFiles.some(
105
+ (file) => !(file.path && isOrchestrationOnlyDatasource(file.path))
106
+ )) {
107
+ logWarnRow('No dimensions configured — ABAC filtering disabled for all datasources');
108
+ }
109
+
110
+ return warnings;
111
+ }
112
+
113
+ /**
114
+ * Displays dimensions validation for datasources
115
+ * @function displayDimensionsStep
116
+ * @param {Array} datasourceFiles - Datasource files
117
+ * @returns {void}
118
+ */
119
+ function displayDimensionsStep(datasourceFiles) {
120
+ if (datasourceFiles.length === 0) {
121
+ return;
122
+ }
123
+
124
+ logSectionTitle('Dimensions (ABAC)');
125
+ datasourceFiles.forEach(file => {
126
+ try {
127
+ const dsPath = file.path || file.file;
128
+ if (dsPath && isOrchestrationOnlyDatasource(dsPath)) {
129
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
130
+ logDimLine('orchestration-only (entityType=none) — dimensions N/A');
131
+ return;
132
+ }
133
+ const dimensionsInfo = extractDimensionsFromDatasource(dsPath);
134
+ if (dimensionsInfo.hasDimensions) {
135
+ logger.log(formatDatasourceListRow('ok', file.file, file.type));
136
+ dimensionsInfo.dimensionKeys.forEach(key => {
137
+ const mapping = dimensionsInfo.dimensions[key];
138
+ logDimLine(`${key} → ${mapping}`);
139
+ });
140
+ } else {
141
+ logWarnRow(`${file.file} — no dimensions configured`);
142
+ }
143
+ } catch {
144
+ // Skip if file path not available
145
+ }
146
+ });
147
+ }
148
+
149
+ module.exports = {
150
+ isOrchestrationOnlyDatasource,
151
+ extractDimensionsFromDatasource,
152
+ displayDimensionsValidation,
153
+ displayDimensionsStep
154
+ };