@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
@@ -0,0 +1,243 @@
1
+ /**
2
+ * @fileoverview TTY layout helpers for aifabrix identity commands (plan 151)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const logger = require('../utils/logger');
11
+ const {
12
+ formatBlockingError,
13
+ formatNextActions,
14
+ headerKeyValue,
15
+ sectionTitle
16
+ } = require('../utils/cli-layout-chalk');
17
+ const { readFkId, readFkKey, readFkName, formatFkLabel } = require('./fk-reference');
18
+ const { unwrapControllerData } = require('./identity-response-helpers');
19
+
20
+ /**
21
+ * @param {Object|null|undefined} response
22
+ * @returns {{ items: Object[], meta: Object|null }}
23
+ */
24
+ function extractPaginatedList(response) {
25
+ if (!response || response.success === false) {
26
+ return { items: [], meta: null };
27
+ }
28
+ const body = response.data;
29
+ if (body && Array.isArray(body.data)) {
30
+ return { items: body.data, meta: body.meta ?? null };
31
+ }
32
+ const unwrapped = unwrapControllerData(response);
33
+ if (Array.isArray(unwrapped)) {
34
+ return { items: unwrapped, meta: null };
35
+ }
36
+ if (unwrapped && Array.isArray(unwrapped.data)) {
37
+ return { items: unwrapped.data, meta: unwrapped.meta ?? null };
38
+ }
39
+ return { items: [], meta: null };
40
+ }
41
+
42
+ /**
43
+ * @param {Object} user
44
+ * @returns {string}
45
+ */
46
+ function formatUserDisplayName(user) {
47
+ const display = String(user?.displayName || '').trim();
48
+ if (display) {
49
+ return display;
50
+ }
51
+ const parts = [user?.firstName, user?.lastName].filter(Boolean).map(String);
52
+ const joined = parts.join(' ').trim();
53
+ return joined || '—';
54
+ }
55
+
56
+ /**
57
+ * @param {string} value
58
+ * @param {number} width
59
+ * @returns {string}
60
+ */
61
+ function padCell(value, width) {
62
+ const text = String(value ?? '—');
63
+ if (text.length <= width) {
64
+ return text.padEnd(width);
65
+ }
66
+ if (width <= 1) {
67
+ return text.slice(0, width);
68
+ }
69
+ return `${text.slice(0, width - 1)}…`;
70
+ }
71
+
72
+ /**
73
+ * @param {{ emoji?: string, title: string, context?: string, shown?: number, total?: number|null }} opts
74
+ */
75
+ function printIdentityListHeader(opts) {
76
+ const emoji = opts.emoji ? `${opts.emoji} ` : '';
77
+ const context = opts.context ? ` (${opts.context})` : '';
78
+ const shown = Number.isFinite(opts.shown) ? opts.shown : 0;
79
+ const total = Number.isFinite(opts.total) ? opts.total : null;
80
+ const count =
81
+ total !== null && total >= shown ? `${shown} shown of ${total}` : `${shown} shown`;
82
+ logger.log(chalk.bold(`\n${emoji}${opts.title}${context} — ${count}:\n`));
83
+ }
84
+
85
+ /**
86
+ * @param {Array<{ label: string, width: number, value: (row: Object) => string }>} columns
87
+ * @param {Object[]} rows
88
+ */
89
+ function printIdentityTable(columns, rows) {
90
+ const header = columns.map((col) => padCell(col.label, col.width)).join('');
91
+ logger.log(chalk.gray(header));
92
+ logger.log(chalk.gray('-'.repeat(columns.reduce((sum, col) => sum + col.width, 0))));
93
+ rows.forEach((row) => {
94
+ const line = columns.map((col) => padCell(col.value(row), col.width)).join('');
95
+ logger.log(line);
96
+ });
97
+ logger.log('');
98
+ }
99
+
100
+ /**
101
+ * @param {Object|null|undefined} meta
102
+ */
103
+ function printListPaginationFooter(meta) {
104
+ if (!meta || !Number.isFinite(meta.totalItems)) {
105
+ return;
106
+ }
107
+ const page = meta.currentPage ?? meta.page ?? 1;
108
+ const pageSize = meta.pageSize ?? meta.page_size;
109
+ const totalPages = meta.totalPages ?? meta.total_pages;
110
+ const parts = [`total ${meta.totalItems}`];
111
+ if (pageSize) {
112
+ parts.unshift(`page ${page}`);
113
+ }
114
+ if (totalPages) {
115
+ parts.push(`${totalPages} pages`);
116
+ }
117
+ logger.log(chalk.gray(` ${parts.join(' · ')}\n`));
118
+ }
119
+
120
+ /**
121
+ * @param {string} title
122
+ * @param {Array<{ label: string, value: string }>} fields
123
+ */
124
+ function printIdentityRecord(title, fields) {
125
+ logger.log(sectionTitle(title));
126
+ fields.forEach(({ label, value }) => {
127
+ logger.log(` ${headerKeyValue(`${label}:`, value || '—')}`);
128
+ });
129
+ logger.log('');
130
+ }
131
+
132
+ /**
133
+ * @param {string} message
134
+ * @param {string[]} [hints]
135
+ */
136
+ function printIdentityEmpty(message, hints = []) {
137
+ logger.log(chalk.gray(` ${message}\n`));
138
+ if (hints.length > 0) {
139
+ logger.log(formatNextActions(hints));
140
+ logger.log('');
141
+ }
142
+ }
143
+
144
+ /**
145
+ * @param {string} entity
146
+ * @param {string} query
147
+ * @param {string[]} [hints]
148
+ */
149
+ function printIdentityNotFound(entity, query, hints = []) {
150
+ logger.error(formatBlockingError(`${entity} not found: ${query}`));
151
+ if (hints.length > 0) {
152
+ logger.log(formatNextActions(hints));
153
+ }
154
+ }
155
+
156
+ const USER_LIST_COLUMNS = [
157
+ { label: 'Id', width: 38, value: (u) => u.id || '—' },
158
+ { label: 'Username', width: 16, value: (u) => u.username || '—' },
159
+ { label: 'Name', width: 22, value: (u) => formatUserDisplayName(u) },
160
+ { label: 'Email', width: 34, value: (u) => u.email || '—' },
161
+ { label: 'Status', width: 10, value: (u) => u.status || '—' }
162
+ ];
163
+
164
+ const GROUP_LIST_COLUMNS = [
165
+ { label: 'Id', width: 38, value: (g) => g.id || '—' },
166
+ { label: 'Name', width: 28, value: (g) => g.name || '—' },
167
+ { label: 'Display name', width: 28, value: (g) => g.displayName || '—' }
168
+ ];
169
+
170
+ /**
171
+ * @param {Object[]} memberships
172
+ */
173
+ function printUserGroupsTable(memberships) {
174
+ printIdentityTable(
175
+ [
176
+ { label: 'Group key', width: 28, value: (m) => readFkKey(m.groupId) || '—' },
177
+ { label: 'Group name', width: 28, value: (m) => formatFkLabel(m.groupId) },
178
+ { label: 'Group id', width: 38, value: (m) => readFkId(m.groupId) || '—' },
179
+ { label: 'Role hint', width: 12, value: (m) => m.roleHint || '—' }
180
+ ],
181
+ memberships
182
+ );
183
+ }
184
+
185
+ /**
186
+ * @param {Object[]} memberships
187
+ */
188
+ function printGroupMembersTable(memberships) {
189
+ printIdentityTable(
190
+ [
191
+ { label: 'User key', width: 22, value: (m) => readFkKey(m.userId) || '—' },
192
+ { label: 'User name', width: 24, value: (m) => formatFkLabel(m.userId) },
193
+ { label: 'User id', width: 38, value: (m) => readFkId(m.userId) || '—' },
194
+ { label: 'Role hint', width: 12, value: (m) => m.roleHint || '—' }
195
+ ],
196
+ memberships
197
+ );
198
+ }
199
+
200
+ /**
201
+ * @param {Object} user
202
+ */
203
+ function printUserRecord(user) {
204
+ printIdentityRecord('User', [
205
+ { label: 'Id', value: user.id },
206
+ { label: 'Email', value: user.email },
207
+ { label: 'Username', value: user.username },
208
+ { label: 'Name', value: formatUserDisplayName(user) },
209
+ { label: 'Display name', value: user.displayName },
210
+ { label: 'Status', value: user.status },
211
+ { label: 'Verified', value: user.emailVerified ? 'yes' : 'no' }
212
+ ]);
213
+ }
214
+
215
+ /**
216
+ * @param {Object} group
217
+ */
218
+ function printGroupRecord(group) {
219
+ printIdentityRecord('Group', [
220
+ { label: 'Id', value: group.id },
221
+ { label: 'Name', value: group.name },
222
+ { label: 'Display name', value: group.displayName },
223
+ { label: 'Description', value: group.description }
224
+ ]);
225
+ }
226
+
227
+ module.exports = {
228
+ extractPaginatedList,
229
+ formatUserDisplayName,
230
+ printIdentityListHeader,
231
+ printIdentityTable,
232
+ printListPaginationFooter,
233
+ printIdentityRecord,
234
+ printIdentityEmpty,
235
+ printIdentityNotFound,
236
+ USER_LIST_COLUMNS,
237
+ GROUP_LIST_COLUMNS,
238
+ printUserGroupsTable,
239
+ printGroupMembersTable,
240
+ printUserRecord,
241
+ printGroupRecord,
242
+ readFkName
243
+ };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @fileoverview Shared controller response helpers for identity modules
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * @param {Object} response
11
+ * @returns {any}
12
+ */
13
+ function unwrapControllerData(response) {
14
+ if (!response || response.success === false) {
15
+ return null;
16
+ }
17
+ return response?.data?.data ?? response?.data ?? response;
18
+ }
19
+
20
+ /**
21
+ * @param {Object} response
22
+ * @returns {string}
23
+ */
24
+ function apiErrorMessage(response) {
25
+ if (!response) {
26
+ return 'Request failed';
27
+ }
28
+ const err = response.error;
29
+ if (typeof err === 'string') {
30
+ return err;
31
+ }
32
+ if (err && typeof err === 'object') {
33
+ return err.formattedError || err.message || err.error || 'Request failed';
34
+ }
35
+ return response.formattedError || response.message || 'Request failed';
36
+ }
37
+
38
+ /**
39
+ * @param {Object} response
40
+ * @throws {Error}
41
+ */
42
+ function throwIfApiFailed(response) {
43
+ if (!response || response.success === false) {
44
+ throw new Error(apiErrorMessage(response));
45
+ }
46
+ }
47
+
48
+ module.exports = {
49
+ unwrapControllerData,
50
+ apiErrorMessage,
51
+ throwIfApiFailed
52
+ };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview User-facing identity sync failure messages
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * @param {Object|null|undefined} stats
11
+ * @returns {boolean}
12
+ */
13
+ function isZeroProgressSyncFailure(stats) {
14
+ const usersProcessed = Number(stats?.usersProcessed ?? 0);
15
+ const groupsProcessed = Number(stats?.groupsProcessed ?? 0);
16
+ return usersProcessed === 0 && groupsProcessed === 0;
17
+ }
18
+
19
+ /**
20
+ * Build a multi-line CLI message when controller sync stats report errors.
21
+ *
22
+ * @param {Object|null|undefined} stats
23
+ * @returns {string}
24
+ */
25
+ function buildSyncStatsFailureMessage(stats) {
26
+ const syncErrors = Number(stats?.errors ?? 0);
27
+ const usersProcessed = Number(stats?.usersProcessed ?? 0);
28
+ const groupsProcessed = Number(stats?.groupsProcessed ?? 0);
29
+
30
+ const lines = [
31
+ `Dataplane full sync reported ${syncErrors} error(s).`,
32
+ `usersProcessed=${usersProcessed} groupsProcessed=${groupsProcessed}.`
33
+ ];
34
+
35
+ if (isZeroProgressSyncFailure(stats)) {
36
+ lines.push(
37
+ '',
38
+ 'The controller accepted the sync request, but no identity data reached the dataplane.',
39
+ 'Common causes:',
40
+ ' • Expired or invalid dataplane client token (controller → dataplane auth)',
41
+ ' • Dataplane unreachable or unhealthy',
42
+ ' • Dataplane MISO_CLIENTID / MISO_CLIENTSECRET out of sync with the controller',
43
+ '',
44
+ 'Try:',
45
+ ' aifabrix auth status',
46
+ ' aifabrix run dataplane --reload',
47
+ 'Then retry:',
48
+ ' aifabrix identity sync -e dev --purge-cache',
49
+ '',
50
+ 'If it still fails, check miso-controller logs for the sync request.'
51
+ );
52
+ } else {
53
+ lines.push('Check miso-controller logs for the sync request.');
54
+ }
55
+
56
+ return lines.join('\n');
57
+ }
58
+
59
+ module.exports = {
60
+ isZeroProgressSyncFailure,
61
+ buildSyncStatsFailureMessage
62
+ };
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @fileoverview Resolve controller user id from id, email, or username
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { getUser, listUsers } = require('../api/users.api');
10
+ const { throwIfApiFailed, unwrapControllerData } = require('./identity-response-helpers');
11
+
12
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13
+
14
+ /**
15
+ * @param {string} value
16
+ * @returns {boolean}
17
+ */
18
+ function isLikelyUuid(value) {
19
+ return UUID_RE.test(String(value || '').trim());
20
+ }
21
+
22
+ /**
23
+ * @param {Object} response
24
+ * @returns {Object[]}
25
+ */
26
+ function extractUserListItems(response) {
27
+ const data = unwrapControllerData(response);
28
+ if (Array.isArray(data)) {
29
+ return data;
30
+ }
31
+ if (Array.isArray(data?.data)) {
32
+ return data.data;
33
+ }
34
+ return [];
35
+ }
36
+
37
+ /**
38
+ * @param {Object[]} items
39
+ * @param {string} value
40
+ * @returns {Object|null}
41
+ */
42
+ function pickUserMatch(items, value) {
43
+ const trimmed = String(value || '').trim();
44
+ if (!trimmed) {
45
+ return null;
46
+ }
47
+ const lower = trimmed.toLowerCase();
48
+ return (
49
+ items.find(
50
+ (user) =>
51
+ String(user.email || '').toLowerCase() === lower || String(user.username || '') === trimmed
52
+ ) || null
53
+ );
54
+ }
55
+
56
+ /**
57
+ * @async
58
+ * @param {string} controllerUrl
59
+ * @param {Object} authConfig
60
+ * @param {string} idOrEmail
61
+ * @returns {Promise<Object|null>}
62
+ */
63
+ async function lookupUserByIdOrEmail(controllerUrl, authConfig, idOrEmail) {
64
+ const value = String(idOrEmail || '').trim();
65
+ if (!value) {
66
+ return null;
67
+ }
68
+
69
+ if (isLikelyUuid(value)) {
70
+ const byId = await getUser(controllerUrl, authConfig, value);
71
+ if (byId && byId.success !== false) {
72
+ const row = unwrapControllerData(byId);
73
+ if (row?.id) {
74
+ return row;
75
+ }
76
+ }
77
+ return null;
78
+ }
79
+
80
+ if (value.includes('@')) {
81
+ const byEmailFilter = await listUsers(controllerUrl, authConfig, {
82
+ filter: `email:eq:${value}`,
83
+ pageSize: 1,
84
+ page: 1
85
+ });
86
+ throwIfApiFailed(byEmailFilter);
87
+ const filterMatch = pickUserMatch(extractUserListItems(byEmailFilter), value);
88
+ if (filterMatch?.id) {
89
+ return filterMatch;
90
+ }
91
+ }
92
+
93
+ const listed = await listUsers(controllerUrl, authConfig, {
94
+ search: value,
95
+ pageSize: 50,
96
+ page: 1
97
+ });
98
+ throwIfApiFailed(listed);
99
+ return pickUserMatch(extractUserListItems(listed), value);
100
+ }
101
+
102
+ /**
103
+ * @async
104
+ * @param {string} controllerUrl
105
+ * @param {Object} authConfig
106
+ * @param {string} idOrEmail
107
+ * @returns {Promise<string>} Controller user id
108
+ * @throws {Error} When value is empty or no matching user exists
109
+ */
110
+ async function resolveUserIdOrEmail(controllerUrl, authConfig, idOrEmail) {
111
+ const value = String(idOrEmail || '').trim();
112
+ if (!value) {
113
+ throw new Error('idOrEmail is required.');
114
+ }
115
+
116
+ const user = await lookupUserByIdOrEmail(controllerUrl, authConfig, value);
117
+ if (user?.id) {
118
+ return user.id;
119
+ }
120
+
121
+ throw new Error(`User not found: ${value}`);
122
+ }
123
+
124
+ module.exports = {
125
+ isLikelyUuid,
126
+ extractUserListItems,
127
+ lookupUserByIdOrEmail,
128
+ resolveUserIdOrEmail
129
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Default controller username when callers omit --username.
3
+ * Matches users.csv UserPrincipalName (email) convention.
4
+ *
5
+ * @fileoverview Identity username resolution
6
+ * @author AI Fabrix Team
7
+ * @version 1.0.0
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ /**
13
+ * @param {{ username?: string, email?: string }} input
14
+ * @returns {string}
15
+ * @throws {Error} When neither username nor email is non-empty
16
+ */
17
+ function resolveIdentityUsername(input) {
18
+ const username = String(input?.username || '').trim();
19
+ if (username) {
20
+ return username;
21
+ }
22
+ const email = String(input?.email || '').trim();
23
+ if (email) {
24
+ return email;
25
+ }
26
+ throw new Error('username or email is required');
27
+ }
28
+
29
+ module.exports = {
30
+ resolveIdentityUsername
31
+ };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Write admin-secrets.env from setup password bundles.
3
+ *
4
+ * @fileoverview Apply dev/pro bundles to admin-secrets.env
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fsRealSync = require('../internal/fs-real-sync');
12
+ const logger = require('../utils/logger');
13
+ const { applyPasswordBundleToAdminObj } = require('../core/admin-secrets-bundle');
14
+
15
+ const DEFAULT_ADMIN_OBJ = {
16
+ REDIS_HOST: 'local:redis:6379:0:',
17
+ REDIS_COMMANDER_USER: 'admin'
18
+ };
19
+
20
+ /**
21
+ * @param {() => object} getCoreSecrets
22
+ * @param {string} adminSecretsPath
23
+ * @param {Object.<string, string>} merged
24
+ * @param {string|null} logMessage
25
+ */
26
+ async function writeAdminSecretsFile(getCoreSecrets, adminSecretsPath, merged, logMessage) {
27
+ const { assertWritableSecretsPathForTests } = require('../utils/aifabrix-test-runtime-guard');
28
+ assertWritableSecretsPathForTests(adminSecretsPath);
29
+ const content = await getCoreSecrets().formatAdminSecretsContent(merged);
30
+ fsRealSync.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
31
+ if (logMessage) {
32
+ logger.log(logMessage);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @param {Object} ctx
38
+ * @param {() => object} ctx.getCoreSecrets
39
+ * @param {(bundle: object) => Promise<void>} [ctx.syncAdminKvFromPasswordBundle]
40
+ * @param {(bundle: object) => Promise<void>} [ctx.syncRequiredKvFromPasswordBundle]
41
+ * @param {boolean} [ctx.syncAdminKv]
42
+ * @param {(dir: string) => void} ctx.logVolumeResetHint
43
+ * @param {string} ctx.infraDirForHint
44
+ * @param {string} ctx.adminSecretsPath
45
+ * @param {Object} ctx.adminObj
46
+ * @param {Object} ctx.bundle
47
+ * @param {string} [ctx.email]
48
+ */
49
+ async function applyAdminSecretsFromBundle(ctx) {
50
+ const {
51
+ getCoreSecrets,
52
+ syncAdminKvFromPasswordBundle,
53
+ syncRequiredKvFromPasswordBundle,
54
+ syncAdminKv,
55
+ logVolumeResetHint,
56
+ infraDirForHint,
57
+ adminSecretsPath,
58
+ adminObj,
59
+ bundle,
60
+ email
61
+ } = ctx;
62
+ let merged = applyPasswordBundleToAdminObj({ ...DEFAULT_ADMIN_OBJ, ...adminObj }, bundle);
63
+ if (email && String(email).trim()) {
64
+ merged = { ...merged, PGADMIN_DEFAULT_EMAIL: String(email).trim() };
65
+ }
66
+ await writeAdminSecretsFile(
67
+ getCoreSecrets,
68
+ adminSecretsPath,
69
+ merged,
70
+ 'Updated admin credentials in admin-secrets.env.'
71
+ );
72
+ if (syncAdminKv && typeof syncAdminKvFromPasswordBundle === 'function') {
73
+ await syncAdminKvFromPasswordBundle(bundle);
74
+ } else if (typeof syncRequiredKvFromPasswordBundle === 'function') {
75
+ await syncRequiredKvFromPasswordBundle(bundle);
76
+ }
77
+ logVolumeResetHint(infraDirForHint);
78
+ }
79
+
80
+ module.exports = {
81
+ DEFAULT_ADMIN_OBJ,
82
+ writeAdminSecretsFile,
83
+ applyAdminSecretsFromBundle
84
+ };