@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
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Datasource E2E test - run full E2E test via dataplane external API
3
- * @fileoverview Datasource E2E test logic (config, credential, sync, data, CIP)
2
+ * Datasource E2E test unified POST /api/v1/validation/run (runType=e2e).
3
+ * @fileoverview Datasource E2E via DatasourceTestRun envelope
4
4
  * @author AI Fabrix Team
5
5
  * @version 2.0.0
6
6
  */
7
- /* eslint-disable max-statements -- Auth setup, API call, polling, debug log */
8
7
 
9
8
  const path = require('path');
10
9
  const fs = require('fs').promises;
@@ -12,19 +11,24 @@ const chalk = require('chalk');
12
11
  const logger = require('../utils/logger');
13
12
  const { getIntegrationPath } = require('../utils/paths');
14
13
  const { resolveAppKeyForDatasource } = require('./resolve-app');
15
- const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
16
- const { resolveControllerUrl } = require('../utils/controller-url');
17
- const { getDeviceOnlyAuth } = require('../utils/token-manager');
18
- const { testDatasourceE2E, getE2ETestRun } = require('../api/external-test.api');
14
+ const { infoLine } = require('../utils/cli-test-layout-chalk');
15
+ const { runUnifiedDatasourceValidation } = require('./unified-validation-run');
16
+ const { includeDebugForRequest } = require('../utils/validation-run-request');
17
+ const { e2eShapeFromEnvelope } = require('../utils/datasource-test-run-legacy-adapter');
19
18
  const { writeTestLog } = require('../utils/test-log-writer');
20
19
 
21
- const DEFAULT_POLL_INTERVAL_MS = 2500;
22
20
  const DEFAULT_POLL_TIMEOUT_MS = 15 * 60 * 1000;
23
21
 
22
+ function logE2eDatasourceBanner(datasourceKey, verbose) {
23
+ if (!verbose) return;
24
+ logger.log('');
25
+ logger.log(infoLine(`🧪 Running E2E test for datasource: ${datasourceKey}`));
26
+ }
27
+
24
28
  /**
25
29
  * Resolve primaryKeyValue for request body: string as-is, or read and parse JSON from @path
26
- * @param {string} [value] - Literal value or path prefixed with @ (e.g. @pk.json)
27
- * @returns {Promise<string|Object|null>} Resolved value for body.primaryKeyValue, or null if absent
30
+ * @param {string} [value]
31
+ * @returns {Promise<string|Object|null>}
28
32
  */
29
33
  async function resolvePrimaryKeyValue(value) {
30
34
  if (value === null || value === undefined || value === '') return null;
@@ -37,174 +41,119 @@ async function resolvePrimaryKeyValue(value) {
37
41
  return str;
38
42
  }
39
43
 
40
- /**
41
- * Build E2E request body from options
42
- * @param {Object} options - Command options
43
- * @returns {Promise<Object>} Request body
44
- */
45
- async function buildE2EBody(options) {
46
- const body = {};
47
- if (options.debug) body.includeDebug = true;
48
- if (options.verbose) body.audit = true;
49
- if (options.testCrud === true) body.testCrud = true;
50
- if (options.recordId !== undefined && options.recordId !== null && options.recordId !== '') body.recordId = String(options.recordId);
51
- if (options.cleanup === false) body.cleanup = false;
52
- else if (options.cleanup === true) body.cleanup = true;
53
- const pk = await resolvePrimaryKeyValue(options.primaryKeyValue);
54
- if (pk !== null && pk !== undefined) body.primaryKeyValue = pk;
55
- return body;
44
+ function e2eIntegrationLogDir(appKey) {
45
+ return path.dirname(getIntegrationPath(appKey));
56
46
  }
57
47
 
58
48
  /**
59
- * Poll E2E test run until completed or failed
60
- * @param {string} dataplaneUrl - Dataplane URL
61
- * @param {string} sourceIdOrKey - Source ID or key
62
- * @param {string} testRunId - Test run ID
63
- * @param {Object} authConfig - Auth config
64
- * @param {Object} opts - Poll options
65
- * @param {number} [opts.intervalMs] - Poll interval (ms)
66
- * @param {number} [opts.timeoutMs] - Max wait (ms)
67
- * @param {boolean} [opts.verbose] - Log each poll
68
- * @returns {Promise<Object>} Final poll result (status completed or failed)
49
+ * Throw when unified run failed, timed out, or needs async; optionally write debug log.
50
+ * @returns {Promise<void>}
69
51
  */
70
- async function pollE2ETestRun(dataplaneUrl, sourceIdOrKey, testRunId, authConfig, opts = {}) {
71
- const intervalMs = opts.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
72
- const timeoutMs = opts.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
73
- const verbose = opts.verbose === true;
74
- const deadline = Date.now() + timeoutMs;
75
- let last;
76
- while (Date.now() < deadline) {
77
- last = await getE2ETestRun(dataplaneUrl, sourceIdOrKey, testRunId, authConfig);
78
- if (last.status === 'completed' || last.status === 'failed') {
79
- return last;
52
+ async function throwIfUnifiedE2EBlocked(unifiedResult, appKey, options, requestMeta) {
53
+ if (unifiedResult.apiError) {
54
+ const msg =
55
+ unifiedResult.apiError.formattedError ||
56
+ unifiedResult.apiError.error ||
57
+ 'E2E request failed';
58
+ if (options.debug) {
59
+ await writeTestLog(
60
+ appKey,
61
+ { request: requestMeta, error: msg },
62
+ 'test-e2e',
63
+ e2eIntegrationLogDir(appKey)
64
+ );
80
65
  }
81
- if (verbose) {
82
- const steps = last.completedActions || [];
83
- logger.log(chalk.gray(` Polling… status: ${last.status}, ${steps.length} step(s) completed`));
66
+ throw new Error(msg);
67
+ }
68
+ if (unifiedResult.pollTimedOut) {
69
+ const err = new Error('Report incomplete: timeout');
70
+ if (options.debug) {
71
+ await writeTestLog(
72
+ appKey,
73
+ { request: requestMeta, error: err.message },
74
+ 'test-e2e',
75
+ e2eIntegrationLogDir(appKey)
76
+ );
84
77
  }
85
- await new Promise(r => setTimeout(r, intervalMs));
78
+ throw err;
79
+ }
80
+ if (unifiedResult.incompleteNoAsync) {
81
+ throw new Error(
82
+ 'Report incomplete: async polling disabled (--no-async) but server returned partial report.'
83
+ );
86
84
  }
87
- throw new Error(
88
- `E2E test run did not complete within ${timeoutMs / 1000}s (run ID: ${testRunId})`
89
- );
90
85
  }
91
86
 
92
87
  /**
93
- * Run E2E test for one datasource (Bearer token or API key required; no client credentials).
94
- * Default: async start + polling until completed/failed. Use options.async === false for sync.
95
- *
88
+ * Run E2E test for one datasource (unified validation API; deployment auth like test-integration).
96
89
  * @async
97
- * @param {string} datasourceKey - Datasource key (used as sourceIdOrKey)
98
- * @param {Object} options - Options
99
- * @param {string} [options.app] - App key (or resolve from cwd)
100
- * @param {string} [options.environment] - Environment (dev, tst, pro)
101
- * @param {boolean} [options.debug] - Include debug, write log file
102
- * @param {boolean} [options.verbose] - Verbose output (e.g. poll progress)
103
- * @param {boolean} [options.async] - If false, use sync mode (no polling). Default true.
104
- * @param {boolean} [options.testCrud] - Set body testCrud true
105
- * @param {string} [options.recordId] - Set body recordId
106
- * @param {boolean} [options.cleanup] - Set body cleanup (default true)
107
- * @param {string} [options.primaryKeyValue] - Set body primaryKeyValue (string or @path to JSON)
108
- * @param {number} [options.pollIntervalMs] - Poll interval in ms (default 2500)
109
- * @param {number} [options.pollTimeoutMs] - Poll timeout in ms (default 15 min)
110
- * @returns {Promise<Object>} E2E test result (steps, success, error, etc.)
90
+ * @param {string} datasourceKey
91
+ * @param {Object} options
92
+ * @param {boolean} [options.sync] - Publish local datasource JSON before validation when true
93
+ * @returns {Promise<Object>} Shape compatible with displayE2EResults (steps, success, status)
111
94
  */
112
95
  async function runDatasourceTestE2E(datasourceKey, options = {}) {
113
96
  if (!datasourceKey || typeof datasourceKey !== 'string') {
114
97
  throw new Error('Datasource key is required');
115
98
  }
116
99
  const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
117
- const controllerUrl = await resolveControllerUrl();
118
- const { resolveEnvironment } = require('../core/config');
119
- const environment = options.environment || await resolveEnvironment();
120
- const authConfig = await getDeviceOnlyAuth(controllerUrl);
121
- const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
122
100
 
123
- logger.log(chalk.blue(`\n🧪 Running E2E test for datasource: ${datasourceKey}`));
101
+ logE2eDatasourceBanner(datasourceKey, options.verbose);
102
+
103
+ const pk = await resolvePrimaryKeyValue(options.primaryKeyValue);
104
+ const timeoutRaw =
105
+ options.timeout !== undefined && options.timeout !== null && options.timeout !== ''
106
+ ? parseInt(String(options.timeout), 10)
107
+ : options.pollTimeoutMs;
108
+ const timeoutMs =
109
+ Number.isFinite(timeoutRaw) && timeoutRaw > 0 ? timeoutRaw : DEFAULT_POLL_TIMEOUT_MS;
124
110
 
125
- const body = await buildE2EBody(options);
126
- const useAsync = options.async !== false;
127
111
  const requestMeta = {
128
- sourceIdOrKey: datasourceKey,
129
- dataplaneUrl,
130
- includeDebug: options.debug,
112
+ datasourceKey,
113
+ runType: 'e2e',
114
+ includeDebug: includeDebugForRequest(options.debug),
131
115
  testCrud: options.testCrud,
132
116
  recordId: options.recordId,
133
117
  cleanup: options.cleanup,
134
- primaryKeyValue: options.primaryKeyValue !== undefined && options.primaryKeyValue !== null
118
+ primaryKeyValue: pk !== undefined && pk !== null
135
119
  };
136
120
 
137
- const execOpts = {
138
- dataplaneUrl,
139
- datasourceKey,
140
- authConfig,
141
- body,
142
- useAsync,
121
+ const unifiedResult = await runUnifiedDatasourceValidation(datasourceKey, {
122
+ app: options.app,
123
+ environment: options.environment,
124
+ runType: 'e2e',
125
+ debug: options.debug,
143
126
  verbose: options.verbose,
144
- pollIntervalMs: options.pollIntervalMs,
145
- pollTimeoutMs: options.pollTimeoutMs
146
- };
147
- let data;
148
- try {
149
- data = await executeE2EWithOptionalPoll(execOpts);
150
- } catch (error) {
151
- if (options.debug) {
152
- const appPath = getIntegrationPath(appKey);
153
- const integrationDir = path.dirname(appPath);
154
- await writeTestLog(appKey, { request: requestMeta, error: error.message }, 'test-e2e', integrationDir);
155
- }
156
- throw error;
157
- }
127
+ async: options.async !== false,
128
+ noAsync: options.async === false,
129
+ testCrud: options.testCrud,
130
+ recordId: options.recordId,
131
+ cleanup: options.cleanup,
132
+ primaryKeyValue: pk,
133
+ capabilityKey: options.capabilityKey,
134
+ timeout: timeoutMs,
135
+ sync: options.sync === true
136
+ });
158
137
 
159
- if (options.debug) {
160
- const appPath = getIntegrationPath(appKey);
161
- const integrationDir = path.dirname(appPath);
162
- const logPath = await writeTestLog(appKey, { request: requestMeta, response: data }, 'test-e2e', integrationDir);
163
- logger.log(chalk.gray(` Debug log: ${logPath}`));
164
- }
138
+ await throwIfUnifiedE2EBlocked(unifiedResult, appKey, options, requestMeta);
165
139
 
166
- return data;
167
- }
140
+ const display = e2eShapeFromEnvelope(unifiedResult.envelope);
141
+ Object.assign(display, { datasourceTestRun: unifiedResult.envelope });
168
142
 
169
- /**
170
- * Call E2E API and optionally poll until completed. On throw, caller should log if debug.
171
- * @param {Object} opts - Options
172
- * @param {string} opts.dataplaneUrl - Dataplane URL
173
- * @param {string} opts.datasourceKey - Source key
174
- * @param {Object} opts.authConfig - Auth config
175
- * @param {Object} opts.body - Request body
176
- * @param {boolean} opts.useAsync - Whether to use async + poll
177
- * @param {boolean} opts.verbose - Verbose poll progress
178
- * @param {number} [opts.pollIntervalMs] - Override poll interval (ms)
179
- * @param {number} [opts.pollTimeoutMs] - Override poll timeout (ms)
180
- * @returns {Promise<Object>} Final result data
181
- */
182
- /* eslint-disable-next-line max-params -- single opts object; destructuring in body */
183
- async function executeE2EWithOptionalPoll(opts) {
184
- const { dataplaneUrl, datasourceKey, authConfig, body, useAsync, verbose, pollIntervalMs, pollTimeoutMs } = opts;
185
- const response = await testDatasourceE2E(dataplaneUrl, datasourceKey, authConfig, body, {
186
- asyncRun: useAsync
187
- });
188
- let data = response.data || response;
189
- const runId = (data?.testRunId !== null && data?.testRunId !== undefined)
190
- ? (typeof data.testRunId === 'string' ? data.testRunId : data.testRunId.id || data.testRunId.key)
191
- : null;
192
- if (useAsync && runId) {
193
- data = await pollE2ETestRun(
194
- dataplaneUrl,
195
- datasourceKey,
196
- runId,
197
- authConfig,
198
- {
199
- intervalMs: pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,
200
- timeoutMs: pollTimeoutMs ?? DEFAULT_POLL_TIMEOUT_MS,
201
- verbose
202
- }
143
+ if (options.debug) {
144
+ const logPath = await writeTestLog(
145
+ appKey,
146
+ { request: requestMeta, response: unifiedResult.envelope },
147
+ 'test-e2e',
148
+ e2eIntegrationLogDir(appKey)
203
149
  );
150
+ logger.log(chalk.gray(` Debug log: ${logPath}`));
204
151
  }
205
- return data;
152
+
153
+ return display;
206
154
  }
207
155
 
208
156
  module.exports = {
209
- runDatasourceTestE2E
157
+ runDatasourceTestE2E,
158
+ resolvePrimaryKeyValue
210
159
  };
@@ -1,174 +1,166 @@
1
1
  /**
2
- * Datasource integration test - run config test for one datasource via pipeline
2
+ * Datasource integration test unified dataplane validation (runType=integration).
3
3
  * @fileoverview Datasource integration test logic
4
4
  * @author AI Fabrix Team
5
5
  * @version 2.0.0
6
6
  */
7
- /* eslint-disable max-lines-per-function,max-statements,complexity -- Load config, resolve datasource, call pipeline test */
8
7
 
9
- const path = require('path');
10
8
  const chalk = require('chalk');
11
9
  const logger = require('../utils/logger');
12
- const { getIntegrationPath } = require('../utils/paths');
13
10
  const { resolveAppKeyForDatasource } = require('./resolve-app');
14
- const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
15
- const { loadConfigFile } = require('../utils/config-format');
16
- const { setupIntegrationTestAuth } = require('../external-system/test-auth');
17
- const { getConfig } = require('../core/config');
18
- const { testDatasourceViaPipeline } = require('../api/pipeline.api');
11
+ const { infoLine } = require('../utils/cli-test-layout-chalk');
12
+ const {
13
+ getSystemKeyFromAppKey,
14
+ findDatasourceFileByKey
15
+ } = require('./integration-context');
16
+ const { runUnifiedDatasourceValidation } = require('./unified-validation-run');
17
+ const { integrationResultFromEnvelope } = require('../utils/datasource-test-run-legacy-adapter');
19
18
  const { writeTestLog } = require('../utils/test-log-writer');
20
- const testHelpers = require('../utils/external-system-test-helpers');
21
- const fs = require('fs').promises;
22
19
 
23
20
  /**
24
- * Get systemKey for an integration app (from application config and first system file)
25
- * @param {string} appKey - Integration app key
21
+ * @param {string} appKey - Integration folder name (same as --app; system key in publish flows)
26
22
  * @returns {Promise<string>} systemKey
27
23
  */
28
- async function getSystemKeyFromAppKey(appKey) {
29
- const appPath = getIntegrationPath(appKey);
30
- const configPath = resolveApplicationConfigPath(appPath);
31
- const config = loadConfigFile(configPath);
32
- if (!config.externalIntegration || !config.externalIntegration.systems || config.externalIntegration.systems.length === 0) {
33
- throw new Error(`No externalIntegration.systems found in ${configPath}`);
34
- }
35
- const systemFile = config.externalIntegration.systems[0];
36
- const systemPath = path.isAbsolute(systemFile)
37
- ? systemFile
38
- : path.join(appPath, systemFile);
39
- const systemContent = await fs.readFile(systemPath, 'utf8');
40
- const yaml = require('js-yaml');
41
- const systemConfig = yaml.load(systemContent);
42
- return systemConfig?.key || path.basename(systemFile, '-system.yaml').replace('-system', '');
24
+ async function getSystemKeyFromAppKeyExport(appKey) {
25
+ return getSystemKeyFromAppKey(appKey);
26
+ }
27
+
28
+ function legacyFailureShell(datasourceKey, systemKey, error, datasourceTestRun, runMeta) {
29
+ return {
30
+ key: datasourceKey,
31
+ systemKey,
32
+ success: false,
33
+ skipped: false,
34
+ validationResults: {},
35
+ fieldMappingResults: {},
36
+ endpointTestResults: {},
37
+ error,
38
+ datasourceTestRun,
39
+ runMeta
40
+ };
43
41
  }
44
42
 
45
43
  /**
46
- * Find a datasource filename by matching the key inside the file (fallback when filename-base match fails).
47
- * @param {string} appPath - Integration app directory path
48
- * @param {string} schemaBasePath - Schema base path (relative or absolute)
49
- * @param {string[]} datasourceFiles - List of datasource filenames from application config
50
- * @param {string} datasourceKey - Datasource key to find
51
- * @returns {string|null} Filename if found, null otherwise
44
+ * @returns {{ body: Object, apiErrMsg?: string }|null}
52
45
  */
53
- function findDatasourceFileByKey(appPath, schemaBasePath, datasourceFiles, datasourceKey) {
54
- const fsSync = require('fs');
55
- for (const f of datasourceFiles) {
56
- if (!f || typeof f !== 'string') continue;
57
- const fullPath = path.isAbsolute(schemaBasePath)
58
- ? path.join(schemaBasePath, f)
59
- : path.join(appPath, schemaBasePath, f);
60
- if (!fsSync.existsSync(fullPath)) continue;
61
- try {
62
- const parsed = loadConfigFile(fullPath);
63
- if (parsed && parsed.key === datasourceKey) return f;
64
- } catch {
65
- // skip unreadable or invalid files
66
- }
46
+ function integrationEarlyExitBody(datasourceKey, systemKey, unifiedResult, runMeta) {
47
+ if (unifiedResult.apiError) {
48
+ const errMsg =
49
+ unifiedResult.apiError.formattedError ||
50
+ unifiedResult.apiError.error ||
51
+ 'Request failed';
52
+ return {
53
+ body: legacyFailureShell(datasourceKey, systemKey, errMsg, null, runMeta),
54
+ apiErrMsg: errMsg
55
+ };
56
+ }
57
+ if (unifiedResult.pollTimedOut) {
58
+ return {
59
+ body: legacyFailureShell(
60
+ datasourceKey,
61
+ systemKey,
62
+ 'Report incomplete: timeout',
63
+ unifiedResult.envelope,
64
+ runMeta
65
+ )
66
+ };
67
+ }
68
+ if (unifiedResult.incompleteNoAsync) {
69
+ return {
70
+ body: legacyFailureShell(
71
+ datasourceKey,
72
+ systemKey,
73
+ 'Report incomplete (async required)',
74
+ unifiedResult.envelope,
75
+ runMeta
76
+ )
77
+ };
67
78
  }
68
79
  return null;
69
80
  }
70
81
 
71
82
  /**
72
- * Run integration test for one datasource
83
+ * Run integration test for one datasource (unified validation API).
73
84
  * @async
74
85
  * @param {string} datasourceKey - Datasource key
75
86
  * @param {Object} options - Options
76
87
  * @param {string} [options.app] - App key (or resolve from cwd)
77
88
  * @param {string} [options.payload] - Path to custom payload file
78
89
  * @param {string} [options.environment] - Environment (dev, tst, pro)
79
- * @param {boolean} [options.debug] - Include debug, write log file
80
- * @param {number} [options.timeout] - Request timeout ms
81
- * @returns {Promise<Object>} Test result
90
+ * @param {boolean} [options.verbose] - explain=true on request
91
+ * @param {boolean|string} [options.debug] - Truthy enables includeDebug and log file; string `summary`|`full`|`raw` selects TTY appendix (CLI)
92
+ * @param {number|string} [options.timeout] - Aggregate timeout ms
93
+ * @param {boolean} [options.sync] - Publish local datasource JSON before validation when true
94
+ * @returns {Promise<Object>} Legacy-shaped result + datasourceTestRun / runMeta when present
82
95
  */
96
+ function logIntegrationDatasourceBanner(datasourceKey, systemKey, verbose) {
97
+ if (!verbose) return;
98
+ logger.log('');
99
+ logger.log(infoLine(`📡 Testing datasource: ${datasourceKey} (system: ${systemKey})`));
100
+ }
101
+
83
102
  async function runDatasourceTestIntegration(datasourceKey, options = {}) {
84
103
  if (!datasourceKey || typeof datasourceKey !== 'string') {
85
104
  throw new Error('Datasource key is required');
86
105
  }
87
106
  const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
88
107
  const systemKey = await getSystemKeyFromAppKey(appKey);
89
- const appPath = getIntegrationPath(appKey);
90
- const config = loadConfigFile(resolveApplicationConfigPath(appPath));
91
- const schemaBasePath = config.externalIntegration?.schemaBasePath || './';
92
- const datasourceFiles = config.externalIntegration?.dataSources || [];
93
- let datasourceFile = datasourceFiles.find(f => {
94
- const base = path.basename(f, path.extname(f));
95
- return base === datasourceKey || base.includes(datasourceKey);
96
- });
97
- if (!datasourceFile) {
98
- datasourceFile = findDatasourceFileByKey(appPath, schemaBasePath, datasourceFiles, datasourceKey);
99
- }
100
- if (!datasourceFile) {
101
- throw new Error(`Datasource '${datasourceKey}' not found in application config`);
102
- }
103
- const datasourcePath = path.isAbsolute(schemaBasePath)
104
- ? path.join(schemaBasePath, datasourceFile)
105
- : path.join(appPath, schemaBasePath, datasourceFile);
106
- const datasource = loadConfigFile(datasourcePath);
107
- if (datasource.key !== datasourceKey) {
108
- throw new Error(`Datasource key mismatch: file has '${datasource.key}', expected '${datasourceKey}'`);
109
- }
110
108
 
111
- const configObj = await getConfig();
112
- const { authConfig, dataplaneUrl } = await setupIntegrationTestAuth(appKey, options, configObj);
113
- const customPayload = await testHelpers.loadCustomPayload(options.payload);
114
- const payloadTemplate = testHelpers.determinePayloadTemplate(datasource, datasourceKey, customPayload);
115
- if (!payloadTemplate) {
116
- throw new Error(`No test payload found for datasource '${datasourceKey}'`);
117
- }
109
+ logIntegrationDatasourceBanner(datasourceKey, systemKey, options.verbose);
118
110
 
119
- logger.log(chalk.blue(`\n📡 Testing datasource: ${datasourceKey} (system: ${systemKey})`));
111
+ const unifiedResult = await runUnifiedDatasourceValidation(datasourceKey, {
112
+ app: options.app,
113
+ environment: options.environment,
114
+ runType: 'integration',
115
+ payload: options.payload,
116
+ debug: options.debug,
117
+ verbose: options.verbose,
118
+ timeout: options.timeout,
119
+ async: true,
120
+ noAsync: false,
121
+ sync: options.sync === true
122
+ });
120
123
 
121
- const testData = { payloadTemplate };
122
- if (options.debug) {
123
- testData.includeDebug = true;
124
- }
125
- const timeout = parseInt(options.timeout, 10) || 30000;
124
+ const runMeta = {
125
+ apiError: unifiedResult.apiError,
126
+ pollTimedOut: unifiedResult.pollTimedOut,
127
+ incompleteNoAsync: unifiedResult.incompleteNoAsync
128
+ };
126
129
 
127
- let response;
128
- try {
129
- response = await testDatasourceViaPipeline({
130
- dataplaneUrl,
131
- systemKey,
132
- datasourceKey,
133
- authConfig,
134
- testData,
135
- options: { timeout }
136
- });
137
- } catch (error) {
138
- const result = { key: datasourceKey, success: false, error: error.message };
139
- if (options.debug) {
140
- await writeTestLog(appKey, { request: { systemKey, datasourceKey }, error: error.message }, 'test-integration');
130
+ const early = integrationEarlyExitBody(datasourceKey, systemKey, unifiedResult, runMeta);
131
+ if (early) {
132
+ if (early.apiErrMsg && options.debug) {
133
+ await writeTestLog(
134
+ appKey,
135
+ { request: { systemKey, datasourceKey }, error: early.apiErrMsg },
136
+ 'test-integration'
137
+ );
141
138
  }
142
- return result;
139
+ return early.body;
143
140
  }
144
141
 
145
- const data = response.data || response;
146
- const success = data.success !== false;
147
- const result = {
148
- key: datasourceKey,
149
- systemKey,
150
- success,
151
- skipped: false,
152
- validationResults: data.validationResults || {},
153
- fieldMappingResults: data.fieldMappingResults || {},
154
- endpointTestResults: data.endpointTestResults || {}
155
- };
156
- if (data.error) {
157
- result.error = data.error;
158
- }
142
+ const legacy = integrationResultFromEnvelope(unifiedResult.envelope, datasourceKey);
143
+ legacy.systemKey = systemKey;
144
+ legacy.datasourceTestRun = unifiedResult.envelope;
145
+ legacy.runMeta = { apiError: null, pollTimedOut: false, incompleteNoAsync: false };
159
146
 
160
- if (options.debug) {
161
- const logPath = await writeTestLog(appKey, {
162
- request: { systemKey, datasourceKey, includeDebug: true },
163
- response: data
164
- }, 'test-integration');
147
+ if (options.debug && unifiedResult.envelope) {
148
+ const logPath = await writeTestLog(
149
+ appKey,
150
+ {
151
+ request: { systemKey, datasourceKey, includeDebug: true },
152
+ response: unifiedResult.envelope
153
+ },
154
+ 'test-integration'
155
+ );
165
156
  logger.log(chalk.gray(` Debug log: ${logPath}`));
166
157
  }
167
158
 
168
- return result;
159
+ return legacy;
169
160
  }
170
161
 
171
162
  module.exports = {
172
163
  runDatasourceTestIntegration,
173
- getSystemKeyFromAppKey
164
+ getSystemKeyFromAppKey: getSystemKeyFromAppKeyExport,
165
+ findDatasourceFileByKey
174
166
  };
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @fileoverview Build ValidationRunRequest body for unified datasource runs.
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const {
8
+ buildExternalDataSourceValidationRequest,
9
+ buildE2eOptionsFromCli,
10
+ includeDebugForRequest
11
+ } = require('../utils/validation-run-request');
12
+ const testHelpers = require('../utils/external-system-test-helpers');
13
+
14
+ /**
15
+ * @param {Object} params
16
+ * @param {string} params.systemKey
17
+ * @param {string} params.datasourceKey
18
+ * @param {'test'|'integration'|'e2e'} params.runType
19
+ * @param {Object} params.datasource - Loaded datasource config
20
+ * @param {string} [params.payloadPath]
21
+ * @param {boolean} params.useAsync
22
+ * @param {Object} params.options - CLI options (debug, verbose, e2e fields, capabilityKey)
23
+ * @returns {Promise<import('../api/types/validation-run.types').ValidationRunRequestBody>}
24
+ */
25
+ async function buildUnifiedValidationBody(params) {
26
+ const { systemKey, datasourceKey, runType, datasource, payloadPath, useAsync, options } = params;
27
+
28
+ let payloadTemplate;
29
+ if (payloadPath || runType === 'integration') {
30
+ const customPayload = await testHelpers.loadCustomPayload(payloadPath);
31
+ payloadTemplate = testHelpers.determinePayloadTemplate(datasource, datasourceKey, customPayload);
32
+ if (runType === 'integration' && !payloadTemplate) {
33
+ throw new Error(`No test payload found for datasource '${datasourceKey}'`);
34
+ }
35
+ }
36
+
37
+ const e2eExtra = options.capabilityKey
38
+ ? { capabilityKeys: [String(options.capabilityKey).trim()] }
39
+ : undefined;
40
+ const e2eOptions =
41
+ runType === 'e2e'
42
+ ? buildE2eOptionsFromCli({
43
+ debug: options.debug,
44
+ verbose: options.verbose,
45
+ testCrud: options.testCrud,
46
+ recordId: options.recordId,
47
+ cleanup: options.cleanup,
48
+ primaryKeyValue: options.primaryKeyValue,
49
+ e2eOptionsExtra: e2eExtra
50
+ })
51
+ : undefined;
52
+
53
+ return buildExternalDataSourceValidationRequest({
54
+ systemKey,
55
+ datasourceKey,
56
+ runType,
57
+ payloadTemplate,
58
+ asyncRun: runType === 'e2e' && useAsync === true,
59
+ includeDebug: includeDebugForRequest(options.debug),
60
+ explain: options.verbose === true,
61
+ e2eOptions: e2eOptions && Object.keys(e2eOptions).length > 0 ? e2eOptions : undefined
62
+ });
63
+ }
64
+
65
+ module.exports = { buildUnifiedValidationBody };