@aifabrix/builder 2.43.0 → 2.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +1 -1
  3. package/anchor-docs/README.md +10 -0
  4. package/anchor-docs/_TEMPLATE +24 -0
  5. package/bin/aifabrix.js +13 -4
  6. package/integration/hubspot-test/README.md +31 -0
  7. package/integration/hubspot-test/create-hubspot.js +5 -5
  8. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  9. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  10. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  11. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  12. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  13. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  14. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  15. package/integration/hubspot-test/test.js +35 -43
  16. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  17. package/integration/roundtrip-test-local/README.md +144 -0
  18. package/integration/roundtrip-test-local/application.yaml +13 -0
  19. package/integration/roundtrip-test-local/env.template +15 -0
  20. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  21. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  22. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  23. package/integration/roundtrip-test-local2/README.md +144 -0
  24. package/integration/roundtrip-test-local2/application.yaml +13 -0
  25. package/integration/roundtrip-test-local2/env.template +15 -0
  26. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  27. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  28. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  29. package/integration/test/wizard.yaml +8 -0
  30. package/jest.config.default.js +10 -0
  31. package/jest.config.integration.fixtures.js +22 -0
  32. package/jest.config.integration.js +21 -18
  33. package/jest.config.isolated.js +10 -0
  34. package/jest.projects.js +288 -0
  35. package/lib/api/datasources-core.api.js +3 -3
  36. package/lib/api/dev-mtls-request.js +110 -0
  37. package/lib/api/dev-server-https.js +145 -0
  38. package/lib/api/dev.api.js +133 -144
  39. package/lib/api/index.js +0 -1
  40. package/lib/api/pipeline.api.js +67 -20
  41. package/lib/api/types/dev.types.js +4 -3
  42. package/lib/api/types/pipeline.types.js +8 -5
  43. package/lib/api/types/validation-run.types.js +56 -0
  44. package/lib/api/validation-run.api.js +99 -0
  45. package/lib/api/validation-runner.js +99 -0
  46. package/lib/app/config.js +1 -1
  47. package/lib/app/deploy-status-display.js +2 -2
  48. package/lib/app/deploy.js +7 -6
  49. package/lib/app/display.js +2 -1
  50. package/lib/app/dockerfile.js +3 -2
  51. package/lib/app/down.js +2 -1
  52. package/lib/app/helpers.js +6 -5
  53. package/lib/app/index.js +27 -8
  54. package/lib/app/list.js +7 -6
  55. package/lib/app/push.js +4 -3
  56. package/lib/app/register.js +16 -7
  57. package/lib/app/rotate-secret.js +14 -13
  58. package/lib/app/run-container-start.js +184 -0
  59. package/lib/app/run-docker-fallback.js +108 -0
  60. package/lib/app/run-env-compose.js +30 -42
  61. package/lib/app/run-helpers.js +49 -126
  62. package/lib/app/run-infra-requirements.js +30 -0
  63. package/lib/app/run-resolve-image.js +21 -0
  64. package/lib/app/run.js +74 -21
  65. package/lib/app/show-display.js +1 -1
  66. package/lib/app/show.js +1 -1
  67. package/lib/build/index.js +13 -10
  68. package/lib/cli/index.js +2 -0
  69. package/lib/cli/setup-app.help.js +67 -0
  70. package/lib/cli/setup-app.js +57 -121
  71. package/lib/cli/setup-app.test-commands.js +179 -0
  72. package/lib/cli/setup-auth.js +19 -5
  73. package/lib/cli/setup-credential-deployment.js +22 -8
  74. package/lib/cli/setup-dev-path-commands.js +124 -0
  75. package/lib/cli/setup-dev.js +170 -113
  76. package/lib/cli/setup-environment.js +7 -1
  77. package/lib/cli/setup-external-system.js +62 -22
  78. package/lib/cli/setup-infra.js +126 -47
  79. package/lib/cli/setup-parameters.js +32 -0
  80. package/lib/cli/setup-secrets.js +106 -8
  81. package/lib/cli/setup-service-user.js +1 -1
  82. package/lib/cli/setup-utility.js +36 -20
  83. package/lib/commands/app-down.js +5 -7
  84. package/lib/commands/app-install.js +14 -7
  85. package/lib/commands/app-logs.js +13 -10
  86. package/lib/commands/app-shell.js +4 -1
  87. package/lib/commands/app-test.js +25 -19
  88. package/lib/commands/app.js +22 -10
  89. package/lib/commands/auth-config.js +6 -6
  90. package/lib/commands/auth-status.js +4 -3
  91. package/lib/commands/credential-env.js +4 -3
  92. package/lib/commands/credential-list.js +5 -4
  93. package/lib/commands/credential-push.js +4 -3
  94. package/lib/commands/datasource-unified-test-cli.js +495 -0
  95. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  96. package/lib/commands/datasource-validation-cli.js +129 -0
  97. package/lib/commands/datasource.js +105 -98
  98. package/lib/commands/deployment-list.js +6 -5
  99. package/lib/commands/dev-cli-handlers.js +122 -18
  100. package/lib/commands/dev-down.js +4 -3
  101. package/lib/commands/dev-init.js +231 -116
  102. package/lib/commands/dev-show-display.js +473 -0
  103. package/lib/commands/login-credentials.js +3 -2
  104. package/lib/commands/login-device.js +4 -3
  105. package/lib/commands/login.js +5 -4
  106. package/lib/commands/logout.js +8 -7
  107. package/lib/commands/parameters-validate.js +54 -0
  108. package/lib/commands/repair-datasource.js +314 -68
  109. package/lib/commands/repair-env-template.js +2 -2
  110. package/lib/commands/repair.js +21 -3
  111. package/lib/commands/secrets-list.js +23 -12
  112. package/lib/commands/secrets-remove-all.js +220 -0
  113. package/lib/commands/secrets-remove.js +21 -12
  114. package/lib/commands/secrets-set.js +21 -12
  115. package/lib/commands/secrets-validate.js +4 -4
  116. package/lib/commands/secure.js +10 -9
  117. package/lib/commands/service-user.js +26 -25
  118. package/lib/commands/test-e2e-external.js +27 -1
  119. package/lib/commands/up-common.js +3 -2
  120. package/lib/commands/up-dataplane.js +29 -16
  121. package/lib/commands/up-miso.js +19 -29
  122. package/lib/commands/upload.js +138 -39
  123. package/lib/commands/wizard-core-helpers.js +1 -1
  124. package/lib/commands/wizard-dataplane.js +4 -3
  125. package/lib/commands/wizard-helpers.js +3 -3
  126. package/lib/commands/wizard.js +2 -2
  127. package/lib/core/admin-secrets.js +14 -5
  128. package/lib/core/audit-logger.js +12 -4
  129. package/lib/core/config-attach-extensions.js +46 -0
  130. package/lib/core/config-runtime-paths.js +29 -0
  131. package/lib/core/config.js +55 -56
  132. package/lib/core/diff.js +3 -2
  133. package/lib/core/ensure-encryption-key.js +1 -1
  134. package/lib/core/secrets-ensure-infra.js +77 -0
  135. package/lib/core/secrets-ensure.js +120 -64
  136. package/lib/core/secrets-env-write.js +35 -7
  137. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  138. package/lib/core/secrets.js +200 -37
  139. package/lib/core/templates-env.js +4 -3
  140. package/lib/datasource/abac-validator.js +1 -10
  141. package/lib/datasource/deploy.js +75 -53
  142. package/lib/datasource/field-reference-validator.js +9 -6
  143. package/lib/datasource/integration-context.js +63 -0
  144. package/lib/datasource/list.js +8 -7
  145. package/lib/datasource/log-viewer.js +84 -53
  146. package/lib/datasource/resolve-app.js +4 -4
  147. package/lib/datasource/test-e2e.js +95 -146
  148. package/lib/datasource/test-integration.js +114 -122
  149. package/lib/datasource/unified-validation-run-body.js +65 -0
  150. package/lib/datasource/unified-validation-run-post.js +23 -0
  151. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  152. package/lib/datasource/unified-validation-run.js +92 -0
  153. package/lib/datasource/validate.js +157 -13
  154. package/lib/deployment/deployer.js +4 -3
  155. package/lib/deployment/environment.js +7 -6
  156. package/lib/deployment/push.js +17 -8
  157. package/lib/external-system/delete.js +4 -3
  158. package/lib/external-system/deploy.js +131 -53
  159. package/lib/external-system/download-helpers.js +1 -1
  160. package/lib/external-system/download.js +7 -6
  161. package/lib/external-system/generator.js +92 -6
  162. package/lib/external-system/integration-test-dispatch.js +26 -0
  163. package/lib/external-system/test-execution.js +5 -1
  164. package/lib/external-system/test-helpers.js +0 -4
  165. package/lib/external-system/test-system-level-helpers.js +110 -0
  166. package/lib/external-system/test-system-level.js +83 -44
  167. package/lib/external-system/test.js +59 -8
  168. package/lib/generator/builders.js +23 -11
  169. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  170. package/lib/generator/external.js +16 -4
  171. package/lib/generator/helpers.js +58 -3
  172. package/lib/generator/index.js +4 -0
  173. package/lib/generator/split-readme.js +12 -7
  174. package/lib/generator/split-variables.js +2 -1
  175. package/lib/generator/split.js +1 -1
  176. package/lib/generator/wizard-readme.js +3 -3
  177. package/lib/generator/wizard.js +8 -8
  178. package/lib/infrastructure/compose.js +60 -6
  179. package/lib/infrastructure/helpers.js +201 -29
  180. package/lib/infrastructure/index.js +28 -17
  181. package/lib/infrastructure/services.js +21 -15
  182. package/lib/internal/fs-real-sync.js +104 -0
  183. package/lib/internal/node-fs.js +98 -0
  184. package/lib/parameters/database-secret-values.js +173 -0
  185. package/lib/parameters/infra-kv-discovery.js +121 -0
  186. package/lib/parameters/infra-parameter-catalog.js +458 -0
  187. package/lib/parameters/infra-parameter-validate.js +64 -0
  188. package/lib/schema/application-schema.json +37 -17
  189. package/lib/schema/datasource-test-run.schema.json +493 -0
  190. package/lib/schema/deployment-rules.yaml +102 -63
  191. package/lib/schema/external-datasource.schema.json +1200 -442
  192. package/lib/schema/external-system.schema.json +181 -5
  193. package/lib/schema/flag-map-validation-run.json +31 -0
  194. package/lib/schema/infra-parameter.schema.json +106 -0
  195. package/lib/schema/infra.parameter.yaml +421 -0
  196. package/lib/schema/type/credential-auth-templates.json +40 -0
  197. package/lib/schema/type/document-storage.json +213 -0
  198. package/lib/schema/type/message-service.json +123 -0
  199. package/lib/schema/type/vector-store.json +88 -0
  200. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  201. package/lib/utils/api-error-handler.js +2 -2
  202. package/lib/utils/api.js +49 -14
  203. package/lib/utils/app-register-api.js +3 -2
  204. package/lib/utils/app-register-auth.js +1 -1
  205. package/lib/utils/app-register-config.js +4 -4
  206. package/lib/utils/app-register-display.js +3 -2
  207. package/lib/utils/app-register-validator.js +3 -2
  208. package/lib/utils/app-run-containers.js +26 -22
  209. package/lib/utils/app-scoped-config.js +31 -0
  210. package/lib/utils/app-service-env-from-builder.js +164 -0
  211. package/lib/utils/build-copy.js +1 -1
  212. package/lib/utils/build-helpers.js +20 -20
  213. package/lib/utils/build-resolve-image.js +165 -0
  214. package/lib/utils/cli-layout-chalk.js +8 -0
  215. package/lib/utils/cli-test-layout-chalk.js +267 -0
  216. package/lib/utils/cli-utils.js +88 -11
  217. package/lib/utils/compose-db-passwords.js +138 -0
  218. package/lib/utils/compose-generate-docker-compose.js +216 -0
  219. package/lib/utils/compose-generator.js +197 -291
  220. package/lib/utils/compose-miso-env.js +18 -0
  221. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  222. package/lib/utils/config-paths.js +166 -7
  223. package/lib/utils/config-scoped-resources-preference.js +41 -0
  224. package/lib/utils/controller-deployment-outcome.js +68 -0
  225. package/lib/utils/credential-display.js +2 -2
  226. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  227. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  228. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  229. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  230. package/lib/utils/datasource-test-run-display.js +442 -0
  231. package/lib/utils/datasource-test-run-exit.js +58 -0
  232. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  233. package/lib/utils/datasource-test-run-report-version.js +51 -0
  234. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  235. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  236. package/lib/utils/datasource-validation-watch.js +266 -0
  237. package/lib/utils/declarative-url-ports.js +47 -0
  238. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  239. package/lib/utils/dev-ca-install.js +185 -23
  240. package/lib/utils/dev-cert-helper.js +266 -17
  241. package/lib/utils/dev-hosts-helper.js +307 -0
  242. package/lib/utils/dev-init-cert-hints.js +37 -0
  243. package/lib/utils/dev-init-health-messages.js +52 -0
  244. package/lib/utils/dev-init-resolve.js +86 -0
  245. package/lib/utils/dev-init-ssh-merge.js +65 -0
  246. package/lib/utils/dev-ssh-config-helper.js +196 -0
  247. package/lib/utils/dev-user-groups.js +93 -0
  248. package/lib/utils/docker-build.js +42 -17
  249. package/lib/utils/docker-exec.js +28 -0
  250. package/lib/utils/docker-manifest-public-port.js +116 -0
  251. package/lib/utils/docker-not-running-hint.js +52 -0
  252. package/lib/utils/docker.js +98 -11
  253. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  254. package/lib/utils/env-config-loader.js +10 -91
  255. package/lib/utils/env-copy.js +19 -10
  256. package/lib/utils/env-map.js +35 -8
  257. package/lib/utils/env-template.js +2 -2
  258. package/lib/utils/environment-scoped-resources.js +144 -0
  259. package/lib/utils/error-formatter.js +92 -13
  260. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  261. package/lib/utils/error-formatters/network-errors.js +2 -1
  262. package/lib/utils/error-formatters/permission-errors.js +2 -1
  263. package/lib/utils/error-formatters/validation-errors.js +2 -1
  264. package/lib/utils/external-readme.js +8 -1
  265. package/lib/utils/external-system-display.js +234 -136
  266. package/lib/utils/external-system-local-test-tty.js +389 -0
  267. package/lib/utils/external-system-readiness-core.js +377 -0
  268. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  269. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  270. package/lib/utils/external-system-readiness-display.js +186 -0
  271. package/lib/utils/external-system-test-helpers.js +24 -6
  272. package/lib/utils/external-system-validators.js +30 -12
  273. package/lib/utils/health-check-url.js +119 -0
  274. package/lib/utils/health-check.js +59 -25
  275. package/lib/utils/help-builder.js +11 -8
  276. package/lib/utils/image-version.js +4 -8
  277. package/lib/utils/infra-containers.js +4 -7
  278. package/lib/utils/infra-env-defaults.js +162 -0
  279. package/lib/utils/infra-status-display.js +167 -0
  280. package/lib/utils/infra-status.js +16 -8
  281. package/lib/utils/local-secrets.js +3 -4
  282. package/lib/utils/paths.js +134 -47
  283. package/lib/utils/port-resolver.js +10 -23
  284. package/lib/utils/redis-env-scope.js +62 -0
  285. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  286. package/lib/utils/remote-builder-validation.js +99 -0
  287. package/lib/utils/remote-dev-auth.js +117 -21
  288. package/lib/utils/remote-docker-env.js +67 -15
  289. package/lib/utils/remote-secrets-loader.js +13 -4
  290. package/lib/utils/resolve-docker-image-ref.js +124 -0
  291. package/lib/utils/schema-loader.js +22 -9
  292. package/lib/utils/secrets-bash-kv.js +25 -0
  293. package/lib/utils/secrets-generator.js +169 -49
  294. package/lib/utils/secrets-helpers.js +70 -59
  295. package/lib/utils/secrets-kv-scope.js +60 -0
  296. package/lib/utils/secrets-utils.js +32 -38
  297. package/lib/utils/secrets-validation.js +3 -1
  298. package/lib/utils/secrets-yaml-preserve.js +109 -0
  299. package/lib/utils/ssh-key-helper.js +4 -2
  300. package/lib/utils/template-helpers.js +2 -2
  301. package/lib/utils/test-log-writer.js +3 -3
  302. package/lib/utils/token-manager.js +1 -2
  303. package/lib/utils/url-declarative-public-base.js +188 -0
  304. package/lib/utils/url-declarative-resolve-build.js +493 -0
  305. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  306. package/lib/utils/url-declarative-resolve.js +220 -0
  307. package/lib/utils/url-declarative-token-parse.js +74 -0
  308. package/lib/utils/url-declarative-url-flags.js +50 -0
  309. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  310. package/lib/utils/url-public-path-prefix.js +34 -0
  311. package/lib/utils/urls-local-registry.js +220 -0
  312. package/lib/utils/validation-report-tty-kit.js +77 -0
  313. package/lib/utils/validation-run-poll.js +89 -0
  314. package/lib/utils/validation-run-post-retry.js +73 -0
  315. package/lib/utils/validation-run-request.js +98 -0
  316. package/lib/utils/variable-transformer.js +21 -4
  317. package/lib/utils/yaml-preserve.js +33 -14
  318. package/lib/validation/datasource-warnings.js +56 -0
  319. package/lib/validation/env-template-auth.js +1 -1
  320. package/lib/validation/external-manifest-validator.js +27 -7
  321. package/lib/validation/validate-display.js +37 -31
  322. package/lib/validation/validate.js +4 -13
  323. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  324. package/lib/validation/validator.js +22 -65
  325. package/lib/validation/wizard-config-validator.js +2 -1
  326. package/package.json +7 -3
  327. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  328. package/scripts/diagnose-cli.js +150 -0
  329. package/scripts/install-local.js +304 -55
  330. package/templates/README.md +15 -2
  331. package/templates/applications/dataplane/application.yaml +52 -2
  332. package/templates/applications/dataplane/env.template +75 -17
  333. package/templates/applications/dataplane/rbac.yaml +8 -0
  334. package/templates/applications/keycloak/application.yaml +9 -1
  335. package/templates/applications/keycloak/env.template +15 -6
  336. package/templates/applications/miso-controller/application.yaml +10 -2
  337. package/templates/applications/miso-controller/env.template +42 -12
  338. package/templates/applications/miso-controller/rbac.yaml +5 -0
  339. package/templates/external-system/README.md.hbs +20 -7
  340. package/templates/external-system/deploy.js.hbs +5 -5
  341. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  342. package/templates/infra/compose.yaml.hbs +20 -4
  343. package/templates/python/docker-compose.hbs +16 -0
  344. package/templates/typescript/docker-compose.hbs +16 -0
  345. package/lib/api/external-test.api.js +0 -111
  346. package/lib/schema/env-config.yaml +0 -60
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @fileoverview Exit code matrix for DatasourceTestRun after successful HTTP (plan §3.1).
3
+ * HTTP/transport failures are exit 3 (handled by callers).
4
+ * @author AI Fabrix Team
5
+ * @version 2.0.0
6
+ */
7
+
8
+ /**
9
+ * Compute CLI exit code from parsed DatasourceTestRun envelope.
10
+ * Ordering: status / warnings-as-errors → require-cert (§3.1).
11
+ * @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null|undefined} body
12
+ * @param {Object} [opts]
13
+ * @param {boolean} [opts.warningsAsErrors]
14
+ * @param {boolean} [opts.requireCert]
15
+ * @returns {number} 0 | 1 | 2 | 3 (3 = treat as parse/body unusable)
16
+ */
17
+ function computeExitCodeFromDatasourceTestRun(body, opts = {}) {
18
+ if (!body || typeof body !== 'object') {
19
+ return 3;
20
+ }
21
+ const status = body.status;
22
+ if (status === 'fail') {
23
+ return 1;
24
+ }
25
+ if (status === 'warn' && opts.warningsAsErrors === true) {
26
+ return 1;
27
+ }
28
+ if (status === 'ok' || status === 'skipped' || status === 'warn') {
29
+ if (opts.requireCert === true) {
30
+ const cert = body.certificate;
31
+ if (!cert) {
32
+ return 2;
33
+ }
34
+ if (cert.status === 'not_passed') {
35
+ return 2;
36
+ }
37
+ }
38
+ return 0;
39
+ }
40
+ return 3;
41
+ }
42
+
43
+ /**
44
+ * Exit code for poll timeout with last envelope (plan §3.4).
45
+ * @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null} lastBody
46
+ * @returns {number} 1 if root fail, else 3
47
+ */
48
+ function exitCodeForPollTimeout(lastBody) {
49
+ if (lastBody && typeof lastBody === 'object' && lastBody.status === 'fail') {
50
+ return 1;
51
+ }
52
+ return 3;
53
+ }
54
+
55
+ module.exports = {
56
+ computeExitCodeFromDatasourceTestRun,
57
+ exitCodeForPollTimeout
58
+ };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @fileoverview Map DatasourceTestRun envelope → legacy CLI display shapes (integration + E2E).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /**
8
+ * @param {Object|null} envelope
9
+ * @returns {string|null}
10
+ */
11
+ function firstIssueMessage(envelope) {
12
+ const v = envelope && envelope.validation;
13
+ const issues = v && Array.isArray(v.issues) ? v.issues : [];
14
+ const first = issues.find(i => i && (i.message || i.hint));
15
+ if (first) return String(first.message || first.hint);
16
+ const integ = envelope && envelope.integration;
17
+ const steps = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
18
+ const bad = steps.find(s => s && s.success === false && (s.message || s.error));
19
+ if (bad) return String(bad.message || bad.error || 'Integration step failed');
20
+ return null;
21
+ }
22
+
23
+ /**
24
+ * Legacy integration result for displayIntegrationTestResults / verbose details.
25
+ * @param {Object|null} envelope
26
+ * @param {string} datasourceKey
27
+ * @returns {Object}
28
+ */
29
+ function integrationResultFromEnvelope(envelope, datasourceKey) {
30
+ if (!envelope || typeof envelope !== 'object') {
31
+ return {
32
+ key: datasourceKey,
33
+ systemKey: 'unknown',
34
+ success: false,
35
+ skipped: false,
36
+ validationResults: {},
37
+ fieldMappingResults: {},
38
+ endpointTestResults: {},
39
+ error: 'No report envelope',
40
+ envelope: null
41
+ };
42
+ }
43
+ const success = envelope.status !== 'fail';
44
+ const err = success ? undefined : firstIssueMessage(envelope) || `status: ${envelope.status}`;
45
+ return {
46
+ key: datasourceKey,
47
+ systemKey: envelope.systemKey || 'unknown',
48
+ success,
49
+ skipped: false,
50
+ error: err,
51
+ envelope
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Map integration.stepResults → E2E-style steps for displayE2EResults.
57
+ * @param {Object|null} envelope
58
+ * @returns {{ steps: Object[], success: boolean, status?: string, error?: string }}
59
+ */
60
+ function e2eShapeFromEnvelope(envelope) {
61
+ if (!envelope || typeof envelope !== 'object') {
62
+ return { steps: [], success: false, error: 'No report envelope' };
63
+ }
64
+ const integ = envelope.integration;
65
+ const raw = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
66
+ const steps = raw.map(s => ({
67
+ name: s.name || 'step',
68
+ step: s.name,
69
+ success: s.success !== false,
70
+ message: s.message,
71
+ error: s.success === false ? s.message || 'failed' : undefined
72
+ }));
73
+ const success = envelope.status !== 'fail';
74
+ let status;
75
+ if (envelope.status === 'fail') status = 'failed';
76
+ else if (envelope.reportCompleteness && envelope.reportCompleteness !== 'full') {
77
+ status = 'completed';
78
+ } else {
79
+ status = 'completed';
80
+ }
81
+ return {
82
+ steps,
83
+ success,
84
+ status,
85
+ error: success ? undefined : firstIssueMessage(envelope) || undefined
86
+ };
87
+ }
88
+
89
+ module.exports = {
90
+ integrationResultFromEnvelope,
91
+ e2eShapeFromEnvelope,
92
+ firstIssueMessage
93
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @fileoverview reportVersion compatibility warnings (plan §3.15).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /** CLI-supported major reportVersion (bump when breaking). */
8
+ const SUPPORTED_MAJOR = 1;
9
+
10
+ /**
11
+ * Parse leading major from semver-like string (e.g. 1.1.0 → 1).
12
+ * @param {string} v
13
+ * @returns {number|null}
14
+ */
15
+ function parseMajor(v) {
16
+ if (!v || typeof v !== 'string') return null;
17
+ const m = /^v?(\d+)/.exec(v.trim());
18
+ if (!m) return null;
19
+ return parseInt(m[1], 10);
20
+ }
21
+
22
+ /**
23
+ * stderr messages for reportVersion handling.
24
+ * @param {string|undefined} reportVersion - From envelope
25
+ * @returns {{ level: 'none'|'warn'|'info', message: string }|null}
26
+ */
27
+ function getReportVersionStderrMessage(reportVersion) {
28
+ const major = parseMajor(reportVersion || '');
29
+ if (major === null) {
30
+ return null;
31
+ }
32
+ if (major < SUPPORTED_MAJOR - 1) {
33
+ return {
34
+ level: 'warn',
35
+ message: `reportVersion unsupported (got ${reportVersion}, support ${SUPPORTED_MAJOR - 1}–${SUPPORTED_MAJOR} major)`
36
+ };
37
+ }
38
+ if (major > SUPPORTED_MAJOR) {
39
+ return {
40
+ level: 'info',
41
+ message: 'Newer reportVersion; some fields may be ignored'
42
+ };
43
+ }
44
+ return null;
45
+ }
46
+
47
+ module.exports = {
48
+ SUPPORTED_MAJOR,
49
+ parseMajor,
50
+ getReportVersionStderrMessage
51
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @fileoverview SHA-256 compare Builder vs Dataplane DatasourceTestRun JSON Schema (plan §8.1).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const crypto = require('crypto');
8
+ const { nodeFs } = require('../internal/node-fs');
9
+
10
+ /**
11
+ * @param {string} filePath - Absolute path to file
12
+ * @returns {string} Lowercase hex SHA-256 of file bytes
13
+ */
14
+ function sha256FileSync(filePath) {
15
+ const buf = nodeFs().readFileSync(filePath);
16
+ return crypto.createHash('sha256').update(buf).digest('hex');
17
+ }
18
+
19
+ /**
20
+ * Compare two schema files; throws on mismatch when both exist.
21
+ * @param {string} builderSchemaPath
22
+ * @param {string} dataplaneSchemaPath
23
+ * @returns {{ skipped: boolean, reason?: string, builderSha?: string, dataplaneSha?: string }}
24
+ */
25
+ function assertDatasourceTestRunSchemasInSync(builderSchemaPath, dataplaneSchemaPath) {
26
+ if (!nodeFs().existsSync(builderSchemaPath)) {
27
+ throw new Error(`Builder schema not found: ${builderSchemaPath}`);
28
+ }
29
+ if (!nodeFs().existsSync(dataplaneSchemaPath)) {
30
+ return {
31
+ skipped: true,
32
+ reason: `Dataplane schema not found (set AIFABRIX_DATAPLANE_ROOT or checkout sibling repo): ${dataplaneSchemaPath}`
33
+ };
34
+ }
35
+ const builderSha = sha256FileSync(builderSchemaPath);
36
+ let dataplaneSha;
37
+ try {
38
+ dataplaneSha = sha256FileSync(dataplaneSchemaPath);
39
+ } catch (err) {
40
+ if (err && err.code === 'ENOENT') {
41
+ return {
42
+ skipped: true,
43
+ reason: `Dataplane schema not found (set AIFABRIX_DATAPLANE_ROOT or checkout sibling repo): ${dataplaneSchemaPath}`
44
+ };
45
+ }
46
+ throw err;
47
+ }
48
+ if (builderSha !== dataplaneSha) {
49
+ throw new Error(
50
+ `DatasourceTestRun schema drift: builder ${builderSha} ≠ dataplane ${dataplaneSha}`
51
+ );
52
+ }
53
+ return { skipped: false, builderSha, dataplaneSha };
54
+ }
55
+
56
+ module.exports = {
57
+ sha256FileSync,
58
+ assertDatasourceTestRunSchemasInSync
59
+ };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @fileoverview Log DatasourceTestRun to TTY — shared by datasource commands and external system server tests.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const chalk = require('chalk');
8
+ const logger = require('./logger');
9
+ const { getReportVersionStderrMessage } = require('./datasource-test-run-report-version');
10
+ const {
11
+ formatDatasourceTestRunSummary,
12
+ formatDatasourceTestRunTTY
13
+ } = require('./datasource-test-run-display');
14
+ const {
15
+ resolveDebugDisplayMode,
16
+ formatDatasourceTestRunDebugBlock
17
+ } = require('./datasource-test-run-debug-display');
18
+ const { analyzeCapabilityScope } = require('./datasource-test-run-capability-scope');
19
+
20
+ function emitReportVersionDiagnostics(envelope) {
21
+ if (!envelope || typeof envelope !== 'object') return;
22
+ const msg = getReportVersionStderrMessage(envelope.reportVersion);
23
+ if (!msg) return;
24
+ if (msg.level === 'warn') logger.warn(chalk.yellow(msg.message));
25
+ else if (msg.level === 'info') logger.log(chalk.gray(msg.message));
26
+ }
27
+
28
+ function emitCapabilityScopeDiagnostics(envelope, opts = {}) {
29
+ const scope = analyzeCapabilityScope(envelope, opts.requestedCapabilityKey);
30
+ if (scope.violated && scope.message) {
31
+ logger.warn(chalk.yellow(`⚠ ${scope.message}`));
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Print envelope (JSON, summary, or full TTY + optional debug appendix). Does not emit reportVersion/capability diagnostics.
37
+ * @param {Object} envelope
38
+ * @param {Object} options
39
+ * @param {boolean} [options.json]
40
+ * @param {boolean} [options.summary]
41
+ * @param {boolean|string} [options.debug]
42
+ * @param {string} [options.requestedCapabilityKey]
43
+ */
44
+ function printDatasourceTestRunForTTY(envelope, options = {}) {
45
+ const displayOpts = { focusCapabilityKey: options.requestedCapabilityKey };
46
+ if (options.json) {
47
+ logger.log(JSON.stringify(envelope));
48
+ return;
49
+ }
50
+ if (options.summary) {
51
+ logger.log(formatDatasourceTestRunSummary(envelope, displayOpts));
52
+ } else {
53
+ logger.log(formatDatasourceTestRunTTY(envelope, displayOpts));
54
+ }
55
+ const mode = resolveDebugDisplayMode(options.debug);
56
+ if (mode) {
57
+ const appendix = formatDatasourceTestRunDebugBlock(envelope, mode, process.stdout.isTTY);
58
+ if (appendix) logger.log(appendix);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Emit diagnostics + human output for one server validation run (integration / test / e2e).
64
+ * @param {Object|null|undefined} envelope
65
+ * @param {Object} options - Same flags as unified CLI (json, summary, debug, requestedCapabilityKey)
66
+ */
67
+ function logEnvelopeForInteractiveCli(envelope, options = {}) {
68
+ if (!envelope || typeof envelope !== 'object') return;
69
+ emitReportVersionDiagnostics(envelope);
70
+ emitCapabilityScopeDiagnostics(envelope, {
71
+ requestedCapabilityKey: options.requestedCapabilityKey
72
+ });
73
+ printDatasourceTestRunForTTY(envelope, options);
74
+ }
75
+
76
+ module.exports = {
77
+ emitReportVersionDiagnostics,
78
+ emitCapabilityScopeDiagnostics,
79
+ printDatasourceTestRunForTTY,
80
+ logEnvelopeForInteractiveCli
81
+ };
@@ -0,0 +1,266 @@
1
+ /**
2
+ * @fileoverview File watch + debounce for datasource validation CLI (plan §3.14).
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const path = require('path');
8
+ const { nodeFs } = require('../internal/node-fs');
9
+ const chalk = require('chalk');
10
+ const logger = require('./logger');
11
+
12
+ /**
13
+ * Resolve integration path at call time so tests' jest.mock('./paths') applies even if this module
14
+ * was first loaded in a worker before the mock (eager destructuring would keep the real fn).
15
+ * @param {string} appKey
16
+ * @returns {string}
17
+ */
18
+ function getIntegrationPathForWatch(appKey) {
19
+ return require('./paths').getIntegrationPath(appKey);
20
+ }
21
+
22
+ const DEFAULT_DEBOUNCE_MS = 500;
23
+ const MAX_DIR_DEPTH = 14;
24
+
25
+ const SKIP_DIR_NAMES = new Set(['node_modules', '.git', 'dist', 'logs', '.turbo']);
26
+
27
+ /**
28
+ * @param {Object|null|undefined} envelope
29
+ * @returns {string}
30
+ */
31
+ function fingerprintForWatchDiff(envelope) {
32
+ if (!envelope || typeof envelope !== 'object') return '';
33
+ const capList = (Array.isArray(envelope.capabilities) ? envelope.capabilities : [])
34
+ .map(c =>
35
+ c && c.key !== undefined && c.key !== null ? `${c.key}:${c.status}` : '?'
36
+ )
37
+ .sort()
38
+ .join('|');
39
+ const certSt = envelope.certificate && envelope.certificate.status;
40
+ return `status=${envelope.status}|cert=${certSt || 'none'}|caps=${capList}`;
41
+ }
42
+
43
+ /**
44
+ * @param {string|null} prev
45
+ * @param {string} next
46
+ * @param {boolean} fullDiff
47
+ * @returns {string|null}
48
+ */
49
+ function formatWatchFingerprintDiff(prev, next, fullDiff) {
50
+ if (prev === null || prev === undefined || prev === next) return null;
51
+ if (fullDiff) {
52
+ return `Watch diff:\n before: ${prev}\n after: ${next}`;
53
+ }
54
+ return `Watch diff: ${chalk.yellow(prev)} → ${chalk.green(next)}`;
55
+ }
56
+
57
+ /**
58
+ * @param {string} root
59
+ * @param {number} maxDepth
60
+ * @param {number} depth
61
+ * @returns {string[]}
62
+ */
63
+ function listDirectoriesRecursive(root, maxDepth, depth = 0) {
64
+ const out = [];
65
+ if (depth > maxDepth || !nodeFs().existsSync(root)) return out;
66
+ let st;
67
+ try {
68
+ st = nodeFs().statSync(root);
69
+ } catch {
70
+ return out;
71
+ }
72
+ if (!st.isDirectory()) {
73
+ return [root];
74
+ }
75
+ out.push(root);
76
+ let entries;
77
+ try {
78
+ entries = nodeFs().readdirSync(root, { withFileTypes: true });
79
+ } catch {
80
+ return out;
81
+ }
82
+ for (const ent of entries) {
83
+ if (SKIP_DIR_NAMES.has(ent.name)) continue;
84
+ if (ent.isDirectory()) {
85
+ out.push(...listDirectoriesRecursive(path.join(root, ent.name), maxDepth, depth + 1));
86
+ }
87
+ }
88
+ return out;
89
+ }
90
+
91
+ /**
92
+ * @param {string} appKey
93
+ * @param {string[]} [extraPaths]
94
+ * @param {boolean} [includeApplicationYaml]
95
+ * @returns {{ kind: 'file'|'dir', path: string }[]}
96
+ */
97
+ function buildWatchTargetList(appKey, extraPaths = [], includeApplicationYaml = false) {
98
+ const integrationRoot = getIntegrationPathForWatch(appKey);
99
+ const seen = new Set();
100
+ /** @type {{ kind: 'file'|'dir', path: string }[]} */
101
+ const list = [];
102
+
103
+ function addFile(abs) {
104
+ if (!nodeFs().existsSync(abs) || seen.has(abs)) return;
105
+ seen.add(abs);
106
+ list.push({ kind: 'file', path: abs });
107
+ }
108
+
109
+ function addDirTree(absRoot) {
110
+ if (!nodeFs().existsSync(absRoot)) return;
111
+ const st = nodeFs().statSync(absRoot);
112
+ if (st.isFile()) {
113
+ addFile(absRoot);
114
+ return;
115
+ }
116
+ const dirs = listDirectoriesRecursive(absRoot, MAX_DIR_DEPTH);
117
+ for (const d of dirs) {
118
+ if (seen.has(d)) continue;
119
+ seen.add(d);
120
+ list.push({ kind: 'dir', path: d });
121
+ }
122
+ }
123
+
124
+ addDirTree(integrationRoot);
125
+
126
+ for (const p of extraPaths) {
127
+ if (!p || typeof p !== 'string') continue;
128
+ const abs = path.resolve(p.trim());
129
+ if (!nodeFs().existsSync(abs)) continue;
130
+ const pst = nodeFs().statSync(abs);
131
+ if (pst.isFile()) {
132
+ addFile(abs);
133
+ } else {
134
+ addDirTree(abs);
135
+ }
136
+ }
137
+
138
+ if (includeApplicationYaml) {
139
+ const y = path.join(integrationRoot, 'application.yaml');
140
+ addFile(y);
141
+ }
142
+
143
+ return list;
144
+ }
145
+
146
+ /**
147
+ * @param {() => void} fn
148
+ * @param {number} ms
149
+ * @returns {() => void}
150
+ */
151
+ function debounce(fn, ms) {
152
+ let t = null;
153
+ return () => {
154
+ if (t) clearTimeout(t);
155
+ t = setTimeout(() => {
156
+ t = null;
157
+ fn();
158
+ }, ms);
159
+ };
160
+ }
161
+
162
+ /**
163
+ * @param {{ kind: 'file'|'dir', path: string }[]} targets
164
+ * @param {() => void} onEvent
165
+ * @returns {() => void}
166
+ */
167
+ function startWatchers(targets, onEvent) {
168
+ const handles = [];
169
+ for (const t of targets) {
170
+ try {
171
+ handles.push(nodeFs().watch(t.path, () => onEvent()));
172
+ } catch {
173
+ // ignore unreadable paths
174
+ }
175
+ }
176
+ return () => {
177
+ for (const h of handles) {
178
+ try {
179
+ h.close();
180
+ } catch {
181
+ // ignore
182
+ }
183
+ }
184
+ };
185
+ }
186
+
187
+ /**
188
+ * @param {Object} opts
189
+ * @param {string} opts.appKey
190
+ * @param {string[]} [opts.extraPaths]
191
+ * @param {boolean} [opts.includeApplicationYaml]
192
+ * @param {number} [opts.debounceMs]
193
+ * @param {boolean} [opts.watchCi]
194
+ * @param {boolean} [opts.watchFullDiff]
195
+ * @param {() => Promise<{ exitCode: number, envelope: Object|null }>} opts.runOnce
196
+ * @returns {Promise<void>}
197
+ */
198
+ async function runDatasourceValidationWatchLoop(opts) {
199
+ const {
200
+ appKey,
201
+ extraPaths = [],
202
+ includeApplicationYaml = false,
203
+ debounceMs = DEFAULT_DEBOUNCE_MS,
204
+ watchCi = false,
205
+ watchFullDiff = false,
206
+ runOnce
207
+ } = opts;
208
+
209
+ const targets = buildWatchTargetList(appKey, extraPaths, includeApplicationYaml);
210
+ if (targets.length === 0) {
211
+ logger.warn(chalk.yellow('Watch: no directories or files to watch; check integration path.'));
212
+ process.exit(4);
213
+ return;
214
+ }
215
+
216
+ let prevFp = null;
217
+ let running = false;
218
+
219
+ const execute = async() => {
220
+ if (running) return;
221
+ running = true;
222
+ try {
223
+ logger.log(chalk.blue('\n[watch] Running validation…'));
224
+ const { exitCode, envelope } = await runOnce();
225
+ const fp = fingerprintForWatchDiff(envelope);
226
+ const diffMsg = formatWatchFingerprintDiff(prevFp, fp, watchFullDiff);
227
+ if (diffMsg) logger.log(diffMsg);
228
+ prevFp = fp;
229
+ if (watchCi) {
230
+ process.exit(exitCode);
231
+ return;
232
+ }
233
+ logger.log(chalk.gray(`[watch] exit code ${exitCode} — waiting for file changes (Ctrl+C to stop)`));
234
+ } finally {
235
+ running = false;
236
+ }
237
+ };
238
+
239
+ await execute();
240
+
241
+ // In production, watchCi triggers process.exit inside execute; with a mocked exit (tests),
242
+ // still skip watcher setup so the async function can finish and no duplicate runs occur.
243
+ if (watchCi) {
244
+ return;
245
+ }
246
+
247
+ const onFs = debounce(execute, debounceMs);
248
+ const closeAll = startWatchers(targets, onFs);
249
+
250
+ const onSig = () => {
251
+ closeAll();
252
+ process.exit(130);
253
+ };
254
+ process.on('SIGINT', onSig);
255
+ process.on('SIGTERM', onSig);
256
+ }
257
+
258
+ module.exports = {
259
+ DEFAULT_DEBOUNCE_MS,
260
+ fingerprintForWatchDiff,
261
+ formatWatchFingerprintDiff,
262
+ buildWatchTargetList,
263
+ debounce,
264
+ startWatchers,
265
+ runDatasourceValidationWatchLoop
266
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Host port math for declarative url:// resolution (plan 122).
3
+ *
4
+ * @fileoverview publishedHostPort vs localHostPort from manifest port + developer-id
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * @param {string|number|null|undefined} raw - developer-id from config
13
+ * @returns {number} Numeric id; non-numeric or empty → 0
14
+ */
15
+ function parseDeveloperIdNum(raw) {
16
+ if (raw === null || raw === undefined || raw === '') {
17
+ return 0;
18
+ }
19
+ const parsed = parseInt(String(raw).trim(), 10);
20
+ return Number.isNaN(parsed) ? 0 : parsed;
21
+ }
22
+
23
+ /**
24
+ * Docker published host port: port + devId*100 (dev 0 → base port).
25
+ * @param {number} appPort - Manifest listen port
26
+ * @param {number} developerIdNum
27
+ * @returns {number}
28
+ */
29
+ function publishedHostPort(appPort, developerIdNum) {
30
+ return appPort + developerIdNum * 100;
31
+ }
32
+
33
+ /**
34
+ * Local workstation host port: port + 10 + devId*100 (dev 0 → port+10).
35
+ * @param {number} appPort
36
+ * @param {number} developerIdNum
37
+ * @returns {number}
38
+ */
39
+ function localHostPort(appPort, developerIdNum) {
40
+ return appPort + 10 + developerIdNum * 100;
41
+ }
42
+
43
+ module.exports = {
44
+ parseDeveloperIdNum,
45
+ publishedHostPort,
46
+ localHostPort
47
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Derive pipeline/env segment (dev|tst|pro|miso) from MISO_CLIENTID convention.
3
+ *
4
+ * @fileoverview Plan 122 — optional MISO_PIPELINE_ENV_KEY override
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const ENV_TOKENS = new Set(['dev', 'tst', 'pro', 'miso']);
12
+
13
+ /**
14
+ * @param {string|null|undefined} clientId - e.g. miso-controller-dev-dataplane
15
+ * @param {string|null|undefined} pipelineOverride - MISO_PIPELINE_ENV_KEY when set in resolved env
16
+ * @returns {string} Lowercase env key (default miso)
17
+ */
18
+ function deriveEnvKeyFromClientId(clientId, pipelineOverride) {
19
+ const o = pipelineOverride !== undefined && pipelineOverride !== null
20
+ ? String(pipelineOverride).trim().toLowerCase()
21
+ : '';
22
+ if (o && ENV_TOKENS.has(o)) {
23
+ return o;
24
+ }
25
+ if (!clientId || typeof clientId !== 'string') {
26
+ return 'miso';
27
+ }
28
+ const parts = clientId.split('-').filter(Boolean);
29
+ for (let i = parts.length - 1; i >= 0; i--) {
30
+ const p = parts[i].toLowerCase();
31
+ if (ENV_TOKENS.has(p)) {
32
+ return p;
33
+ }
34
+ }
35
+ return 'miso';
36
+ }
37
+
38
+ module.exports = {
39
+ deriveEnvKeyFromClientId,
40
+ ENV_TOKENS
41
+ };