@aifabrix/builder 2.45.0 → 2.46.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 (352) 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/docs-rules.mdc +3 -1
  4. package/.cursor/rules/project-rules.mdc +1 -0
  5. package/README.md +43 -17
  6. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  7. package/jest.config.default.js +2 -1
  8. package/jest.config.isolated.js +2 -1
  9. package/jest.global-live-fabrix-hooks.js +36 -0
  10. package/jest.isolated-projects.js +130 -0
  11. package/jest.projects.js +69 -121
  12. package/lib/api/agent-metadata-validation.api.js +93 -0
  13. package/lib/api/api-response-errors.js +124 -0
  14. package/lib/api/audit-api-helpers.js +68 -0
  15. package/lib/api/audit.api.js +119 -0
  16. package/lib/api/auth-cache.api.js +44 -0
  17. package/lib/api/certificates.api.js +4 -4
  18. package/lib/api/credential.api.js +2 -2
  19. package/lib/api/dataplane-health.api.js +137 -0
  20. package/lib/api/dataplane-sync.api.js +27 -0
  21. package/lib/api/datasources-core.api.js +21 -18
  22. package/lib/api/datasources-extended.api.js +22 -22
  23. package/lib/api/dimensions.api.js +3 -0
  24. package/lib/api/external-systems.api.js +13 -13
  25. package/lib/api/governance-scenario-pack.api.js +159 -0
  26. package/lib/api/governance-scenarios.api.js +39 -0
  27. package/lib/api/groups.api.js +79 -0
  28. package/lib/api/index.js +88 -5
  29. package/lib/api/lifecycle.api.js +77 -0
  30. package/lib/api/pipeline.api.js +7 -5
  31. package/lib/api/protection.api.js +157 -0
  32. package/lib/api/records-bulk.api.js +43 -0
  33. package/lib/api/records-search-parse.js +49 -0
  34. package/lib/api/records-search.api.js +29 -0
  35. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  36. package/lib/api/types/audit.types.js +72 -0
  37. package/lib/api/types/dataplane-health.types.js +27 -0
  38. package/lib/api/types/dimensions.types.js +2 -0
  39. package/lib/api/types/governance-scenarios.types.js +39 -0
  40. package/lib/api/types/protection.types.js +69 -0
  41. package/lib/api/types/records-bulk.types.js +35 -0
  42. package/lib/api/types/records-search.types.js +28 -0
  43. package/lib/api/user-groups.api.js +50 -0
  44. package/lib/api/users.api.js +95 -0
  45. package/lib/api/validation-run.api.js +3 -3
  46. package/lib/api/validation-runner.js +5 -3
  47. package/lib/api/wizard-platform.api.js +3 -3
  48. package/lib/api/wizard.api.js +21 -21
  49. package/lib/app/deploy-config.js +4 -1
  50. package/lib/app/deploy.js +34 -19
  51. package/lib/app/down.js +20 -1
  52. package/lib/app/push.js +4 -5
  53. package/lib/app/register.js +7 -4
  54. package/lib/app/run-env-compose.js +84 -30
  55. package/lib/build/index.js +5 -0
  56. package/lib/certification/sync-system-certification.js +13 -6
  57. package/lib/cli/index.js +8 -2
  58. package/lib/cli/infra-guided-auth.js +109 -0
  59. package/lib/cli/infra-guided.js +91 -69
  60. package/lib/cli/setup-app.help.js +19 -2
  61. package/lib/cli/setup-app.js +58 -23
  62. package/lib/cli/setup-app.test-commands.js +28 -21
  63. package/lib/cli/setup-auth.js +55 -3
  64. package/lib/cli/setup-certification-commands.js +147 -0
  65. package/lib/cli/setup-certification.help.js +141 -0
  66. package/lib/cli/setup-environment.js +19 -2
  67. package/lib/cli/setup-external-system-help.js +62 -0
  68. package/lib/cli/setup-external-system.js +62 -6
  69. package/lib/cli/setup-infra.js +9 -1
  70. package/lib/cli/setup-platform.js +6 -1
  71. package/lib/cli/setup-secrets.js +33 -1
  72. package/lib/cli/setup-utility-help-after.js +65 -0
  73. package/lib/cli/setup-utility-repair.js +198 -0
  74. package/lib/cli/setup-utility-resolve.js +42 -6
  75. package/lib/cli/setup-utility-validate.js +197 -0
  76. package/lib/cli/setup-utility.js +41 -258
  77. package/lib/commands/auth-status-client-tokens.js +214 -0
  78. package/lib/commands/auth-status-dataplane-version.js +269 -0
  79. package/lib/commands/auth-status-display.js +94 -0
  80. package/lib/commands/auth-status.js +111 -53
  81. package/lib/commands/credential-push.js +10 -5
  82. package/lib/commands/datasource-load-export-cli.js +178 -0
  83. package/lib/commands/datasource-test-trust-cli.js +118 -0
  84. package/lib/commands/datasource-unified-test-cli.js +31 -20
  85. package/lib/commands/datasource-unified-test-cli.options.js +22 -3
  86. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  87. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  88. package/lib/commands/datasource.js +68 -1
  89. package/lib/commands/dev-show-display.js +8 -1
  90. package/lib/commands/dimension-value.js +43 -13
  91. package/lib/commands/dimension.js +38 -7
  92. package/lib/commands/governance-cli-shared.js +94 -0
  93. package/lib/commands/governance-command-action.js +132 -0
  94. package/lib/commands/governance-download-external.js +34 -0
  95. package/lib/commands/governance-generate-external.js +71 -0
  96. package/lib/commands/governance-upload-external.js +36 -0
  97. package/lib/commands/governance-verify-external.js +64 -0
  98. package/lib/commands/governance.js +144 -0
  99. package/lib/commands/identity-apply-sync.js +131 -0
  100. package/lib/commands/identity-group-cli.js +146 -0
  101. package/lib/commands/identity-membership-role-cache.js +175 -0
  102. package/lib/commands/identity-shared.js +94 -0
  103. package/lib/commands/identity-user-cli.js +158 -0
  104. package/lib/commands/identity.js +43 -0
  105. package/lib/commands/lifecycle-command-action.js +123 -0
  106. package/lib/commands/lifecycle-external.js +268 -0
  107. package/lib/commands/login.js +56 -17
  108. package/lib/commands/protection-cli-leaves.js +286 -0
  109. package/lib/commands/protection.js +50 -0
  110. package/lib/commands/repair-auth-apply.js +127 -0
  111. package/lib/commands/repair-changed-files.js +41 -0
  112. package/lib/commands/repair-datasource-keys.js +4 -1
  113. package/lib/commands/repair-datasource-run.js +59 -0
  114. package/lib/commands/repair-datasource-test-payload.js +259 -0
  115. package/lib/commands/repair-datasource.js +1 -51
  116. package/lib/commands/repair-env-template.js +64 -13
  117. package/lib/commands/repair-external-run.js +216 -0
  118. package/lib/commands/repair-openapi-sync.js +23 -0
  119. package/lib/commands/repair-persist.js +4 -0
  120. package/lib/commands/repair-rbac.js +52 -1
  121. package/lib/commands/repair-steps.js +145 -0
  122. package/lib/commands/repair.js +29 -286
  123. package/lib/commands/secrets-get.js +184 -0
  124. package/lib/commands/secrets-remove-all.js +3 -1
  125. package/lib/commands/setup-image-refresh.js +146 -0
  126. package/lib/commands/setup-modes.js +158 -162
  127. package/lib/commands/setup-platform-auth.js +76 -0
  128. package/lib/commands/setup-prompts-admin.js +244 -0
  129. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  130. package/lib/commands/setup-prompts-validators.js +36 -0
  131. package/lib/commands/setup-prompts.js +24 -76
  132. package/lib/commands/setup-run-context.js +45 -0
  133. package/lib/commands/setup-spinners.js +39 -0
  134. package/lib/commands/setup.js +27 -5
  135. package/lib/commands/teardown.js +39 -0
  136. package/lib/commands/test-e2e-external.js +61 -14
  137. package/lib/commands/test-governance-cli-options.js +47 -0
  138. package/lib/commands/test-governance-external.js +67 -0
  139. package/lib/commands/test-trust-cli-options.js +32 -0
  140. package/lib/commands/test-trust-external.js +126 -0
  141. package/lib/commands/up-common.js +25 -13
  142. package/lib/commands/up-dataplane.js +50 -13
  143. package/lib/commands/upload-publish-context.js +75 -0
  144. package/lib/commands/upload-sidecar-followups.js +89 -0
  145. package/lib/commands/upload.js +108 -105
  146. package/lib/commands/verify-governance-combined-external.js +61 -0
  147. package/lib/commands/verify-governance-command-action.js +64 -0
  148. package/lib/commands/verify-governance-db.js +102 -0
  149. package/lib/commands/verify-governance-external.js +77 -0
  150. package/lib/commands/verify-governance-result-builders.js +71 -0
  151. package/lib/commands/verify-operations-command-action.js +68 -0
  152. package/lib/commands/verify-operations-external.js +268 -0
  153. package/lib/commands/verify-operations-persist.js +75 -0
  154. package/lib/commands/verify-operations-step-plan.js +68 -0
  155. package/lib/commands/verify-operations-steps.js +111 -0
  156. package/lib/commands/verify-trust-command-action.js +70 -0
  157. package/lib/commands/verify-trust-external.js +67 -0
  158. package/lib/commands/wizard-config-normalizer.js +43 -23
  159. package/lib/commands/wizard-core.js +5 -0
  160. package/lib/core/admin-password-generator.js +38 -0
  161. package/lib/core/admin-secrets-bundle.js +111 -0
  162. package/lib/core/admin-secrets-env-overlay.js +62 -0
  163. package/lib/core/admin-secrets.js +32 -4
  164. package/lib/core/config-attach-extensions.js +3 -0
  165. package/lib/core/config-device-dataplane.js +185 -0
  166. package/lib/core/config-platform-controller.js +44 -0
  167. package/lib/core/config-setup-installation-profile.js +42 -0
  168. package/lib/core/config-setup-platform-mode.js +46 -0
  169. package/lib/core/config.js +46 -36
  170. package/lib/core/secrets-admin-env.js +6 -2
  171. package/lib/core/secrets-ensure.js +4 -0
  172. package/lib/core/secrets-env-content.js +54 -48
  173. package/lib/core/secrets-env-write.js +10 -1
  174. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  175. package/lib/core/setup-installation-profile.js +43 -0
  176. package/lib/core/setup-platform-mode.js +55 -0
  177. package/lib/datasource/agent-trust-debug-log.js +45 -0
  178. package/lib/datasource/agent-trust-fetch.js +115 -0
  179. package/lib/datasource/agent-trust-map.js +101 -0
  180. package/lib/datasource/agent-trust-mock.js +44 -0
  181. package/lib/datasource/agent-trust-run.js +95 -0
  182. package/lib/datasource/agent-trust-timeout.js +25 -0
  183. package/lib/datasource/audit-evidence-display.js +80 -0
  184. package/lib/datasource/audit-evidence-extract-debug.js +115 -0
  185. package/lib/datasource/audit-evidence-extract.js +180 -0
  186. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  187. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  188. package/lib/datasource/audit-evidence-poll.js +109 -0
  189. package/lib/datasource/audit-evidence-run.js +177 -0
  190. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  191. package/lib/datasource/audit-evidence-verify-matrix.js +205 -0
  192. package/lib/datasource/audit-evidence-verify.js +108 -0
  193. package/lib/datasource/bulk-loader-run-batches.js +100 -0
  194. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  195. package/lib/datasource/bulk-loader-service.js +127 -0
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  197. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  198. package/lib/datasource/datasource-exporter-service.js +144 -0
  199. package/lib/datasource/datasource-identifier.js +148 -0
  200. package/lib/datasource/datasource-load-export-context.js +95 -0
  201. package/lib/datasource/integration-context.js +6 -4
  202. package/lib/datasource/local-data-paths.js +145 -0
  203. package/lib/datasource/log-cleaner.js +241 -0
  204. package/lib/datasource/log-viewer.js +111 -6
  205. package/lib/datasource/record-file-parser.js +85 -0
  206. package/lib/datasource/record-mapper.js +129 -0
  207. package/lib/datasource/resolve-app.js +74 -55
  208. package/lib/datasource/test-e2e.js +29 -2
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  211. package/lib/datasource/unified-validation-run.js +47 -18
  212. package/lib/datasource/validate.js +37 -20
  213. package/lib/deployment/environment-poll-status.js +138 -0
  214. package/lib/deployment/environment.js +42 -34
  215. package/lib/external-system/download.js +21 -20
  216. package/lib/external-system/generator.js +5 -1
  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-system-level.js +25 -4
  220. package/lib/external-system/test.js +9 -7
  221. package/lib/generator/external-controller-manifest.js +15 -0
  222. package/lib/governance/governance-cli-errors.js +96 -0
  223. package/lib/governance/governance-download-display.js +38 -0
  224. package/lib/governance/governance-pack-loader.js +70 -0
  225. package/lib/governance/governance-run-display.js +309 -0
  226. package/lib/identity/identity-apply-core.js +108 -0
  227. package/lib/identity/identity-apply-phases.js +244 -0
  228. package/lib/identity/identity-apply-service.js +77 -0
  229. package/lib/identity/identity-csv-parser.js +114 -0
  230. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  231. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  232. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  233. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  234. package/lib/infrastructure/helpers.js +23 -129
  235. package/lib/infrastructure/index.js +5 -6
  236. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  237. package/lib/internal/fs-real-sync.js +29 -1
  238. package/lib/lifecycle/certification-progress.js +231 -0
  239. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  240. package/lib/lifecycle/exit-codes.js +24 -0
  241. package/lib/lifecycle/json-envelope.js +25 -0
  242. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  243. package/lib/lifecycle/logger-quiet.js +29 -0
  244. package/lib/lifecycle/open-api-published.js +59 -0
  245. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  246. package/lib/lifecycle/product-model.js +196 -0
  247. package/lib/lifecycle/report-display.js +471 -0
  248. package/lib/lifecycle/scenario-upload.js +191 -0
  249. package/lib/lifecycle/verify-step-progress.js +87 -0
  250. package/lib/parameters/infra-kv-discovery.js +27 -2
  251. package/lib/protection/auth-context.js +51 -0
  252. package/lib/protection/convert-batch.js +90 -0
  253. package/lib/protection/load.js +41 -0
  254. package/lib/protection/paths.js +158 -0
  255. package/lib/protection/preflight-datasource-ready.js +46 -0
  256. package/lib/protection/protection-create-probe-lines.js +142 -0
  257. package/lib/protection/protection-create-probes.js +95 -0
  258. package/lib/protection/protection-create-scaffold.js +281 -0
  259. package/lib/protection/protection-display-helpers.js +445 -0
  260. package/lib/protection/protection-display.js +215 -0
  261. package/lib/protection/protection-preset-registry.js +97 -0
  262. package/lib/protection/report-exit.js +62 -0
  263. package/lib/protection/resolve.js +202 -0
  264. package/lib/protection/run-commands-validate.js +130 -0
  265. package/lib/protection/run-commands.js +216 -0
  266. package/lib/protection/run-protection-create-helpers.js +134 -0
  267. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  268. package/lib/protection/run-protection-create.js +191 -0
  269. package/lib/protection/scope.js +22 -0
  270. package/lib/protection/sync-after-upload.js +64 -0
  271. package/lib/protection/upload-batch.js +127 -0
  272. package/lib/protection/validate-batch.js +113 -0
  273. package/lib/protection/validate-local.js +65 -0
  274. package/lib/resolvers/dimension-file.js +29 -4
  275. package/lib/schema/application-schema.json +1 -1
  276. package/lib/schema/datasource-test-run.schema.json +89 -6
  277. package/lib/schema/external-datasource.schema.json +2636 -2588
  278. package/lib/schema/external-system.schema.json +1089 -761
  279. package/lib/schema/flag-map-validation-run.json +2 -2
  280. package/lib/schema/infra.parameter.yaml +45 -0
  281. package/lib/schema/protection.schema.json +374 -0
  282. package/lib/schema/type/credential-field-registry.json +642 -0
  283. package/lib/schema/wizard-config.schema.json +1 -1
  284. package/lib/utils/agent-trust-run-display.js +231 -0
  285. package/lib/utils/agent-trust-run-exit.js +59 -0
  286. package/lib/utils/agent-trust-wait-ui.js +94 -0
  287. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  288. package/lib/utils/api.js +55 -31
  289. package/lib/utils/app-relative-path-env.js +112 -0
  290. package/lib/utils/cli-exit-codes.js +30 -0
  291. package/lib/utils/cli-secrets-error-format.js +83 -21
  292. package/lib/utils/cli-sync-options.js +33 -0
  293. package/lib/utils/cli-utils.js +16 -4
  294. package/lib/utils/compose-generate-docker-compose.js +4 -0
  295. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  296. package/lib/utils/config-secrets-path.js +46 -0
  297. package/lib/utils/controller-url.js +88 -1
  298. package/lib/utils/credential-push-ui.js +90 -0
  299. package/lib/utils/credential-secrets-env.js +137 -9
  300. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  301. package/lib/utils/dataplane-cli-version-help.js +74 -0
  302. package/lib/utils/dataplane-resolver.js +129 -2
  303. package/lib/utils/datasource-export-display.js +137 -0
  304. package/lib/utils/datasource-load-display.js +174 -0
  305. package/lib/utils/datasource-load-export-ui.js +120 -0
  306. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  307. package/lib/utils/datasource-test-run-display.js +3 -3
  308. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  309. package/lib/utils/declarative-url-ports.js +3 -3
  310. package/lib/utils/deployment-auth-mode.js +41 -0
  311. package/lib/utils/developer-volume-id.js +33 -0
  312. package/lib/utils/env-copy.js +14 -9
  313. package/lib/utils/env-kv-orphan-lines.js +43 -0
  314. package/lib/utils/error-formatters/network-errors.js +13 -4
  315. package/lib/utils/external-env-template.js +1 -0
  316. package/lib/utils/external-system-readiness-core.js +10 -0
  317. package/lib/utils/external-system-readiness-display.js +80 -23
  318. package/lib/utils/health-check.js +4 -1
  319. package/lib/utils/help-builder.js +35 -26
  320. package/lib/utils/keycloak-realm-ready.js +101 -0
  321. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  322. package/lib/utils/manifest-source-emit.js +24 -0
  323. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  324. package/lib/utils/platform-controller-url.js +156 -0
  325. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  326. package/lib/utils/postgres-wipe.js +9 -2
  327. package/lib/utils/resolve-env-mode.js +47 -0
  328. package/lib/utils/secrets-generator.js +31 -25
  329. package/lib/utils/secrets-missing-error.js +164 -0
  330. package/lib/utils/semver-compare.js +127 -0
  331. package/lib/utils/service-url-label.js +81 -0
  332. package/lib/utils/setup-quiet-output.js +25 -0
  333. package/lib/utils/template-helpers.js +15 -0
  334. package/lib/utils/token-manager-client-credentials.js +201 -0
  335. package/lib/utils/token-manager-messages.js +8 -0
  336. package/lib/utils/token-manager-refresh.js +12 -2
  337. package/lib/utils/token-manager.js +86 -105
  338. package/lib/utils/upload-pipeline-ui.js +98 -0
  339. package/lib/utils/upload-sync-options.js +42 -0
  340. package/lib/utils/url-declarative-public-base.js +21 -3
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  342. package/lib/utils/validation-poll-ui.js +22 -7
  343. package/lib/utils/validation-run-stage.js +45 -0
  344. package/lib/validation/wizard-config-validator.js +58 -19
  345. package/package.json +1 -1
  346. package/templates/applications/dataplane/application.yaml +2 -1
  347. package/templates/applications/dataplane/env.template +36 -1
  348. package/templates/applications/dataplane/rbac.yaml +4 -0
  349. package/templates/applications/miso-controller/env.template +16 -0
  350. package/templates/external-system/README.md.hbs +116 -11
  351. package/templates/python/docker-compose.hbs +19 -18
  352. package/templates/typescript/docker-compose.hbs +18 -17
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @fileoverview Export governed records via Records Search (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const { searchRecords } = require('../api/records-search.api');
12
+ const { resolveLoadExportContext } = require('./datasource-load-export-context');
13
+ const { resolveExportOptions } = require('./datasource-exporter-resolve');
14
+ const { runWithDatasourceLoadExportSpinner } = require('../utils/datasource-load-export-ui');
15
+
16
+ const DEFAULT_LIMIT = 1000;
17
+ const MAX_LIMIT = 10000;
18
+
19
+ /**
20
+ * @param {Object[]} data
21
+ * @param {string[]|undefined} fields
22
+ * @returns {Object[]}
23
+ */
24
+ function projectExportRows(data, fields) {
25
+ if (!fields || !fields.length) {
26
+ return data;
27
+ }
28
+ return data.map(row => {
29
+ if (!row || typeof row !== 'object') {
30
+ return row;
31
+ }
32
+ const meta =
33
+ row.metadata && typeof row.metadata === 'object' && !Array.isArray(row.metadata)
34
+ ? row.metadata
35
+ : row;
36
+ const out = {};
37
+ fields.forEach(field => {
38
+ if (Object.prototype.hasOwnProperty.call(meta, field)) {
39
+ out[field] = meta[field];
40
+ }
41
+ });
42
+ return out;
43
+ });
44
+ }
45
+
46
+ /**
47
+ * @param {string} filePath
48
+ * @param {'json'|'ndjson'} format
49
+ * @param {Object[]} rows
50
+ */
51
+ function writeExportFile(filePath, format, rows) {
52
+ const dir = path.dirname(filePath);
53
+ fs.mkdirSync(dir, { recursive: true });
54
+ if (format === 'ndjson') {
55
+ const body = rows.map(row => JSON.stringify(row)).join('\n');
56
+ fs.writeFileSync(filePath, body.length ? `${body}\n` : '', 'utf8');
57
+ return;
58
+ }
59
+ fs.writeFileSync(filePath, `${JSON.stringify(rows, null, 2)}\n`, 'utf8');
60
+ }
61
+
62
+ /**
63
+ * @async
64
+ * @param {Object} ctx
65
+ * @param {Object} resolved
66
+ * @returns {Promise<Object>}
67
+ */
68
+ async function executeDatasourceExportWork(ctx, resolved) {
69
+ const searchBody = {
70
+ intent: resolved.intent,
71
+ datasourceKeys: [ctx.datasourceKey],
72
+ searchMode: 'full',
73
+ limit: resolved.limit
74
+ };
75
+ if (resolved.filters) {
76
+ searchBody.filters = resolved.filters;
77
+ }
78
+
79
+ const response = await searchRecords(ctx.dataplaneUrl, ctx.authConfig, searchBody);
80
+ if (!response || response.success === false) {
81
+ const msg = response?.formattedError || response?.error || 'Records search request failed';
82
+ throw new Error(msg);
83
+ }
84
+
85
+ const data = Array.isArray(response.data) ? response.data : [];
86
+ const projected = projectExportRows(data, resolved.fields);
87
+ writeExportFile(resolved.outputPath, resolved.format, projected);
88
+
89
+ const meta = response.meta && typeof response.meta === 'object' ? response.meta : {};
90
+ const excluded = meta.excluded && typeof meta.excluded === 'object' ? meta.excluded : {};
91
+
92
+ return {
93
+ datasourceKey: ctx.datasourceKey,
94
+ systemKey: ctx.systemKey,
95
+ appKey: ctx.appKey,
96
+ outputFile: resolved.outputPath,
97
+ format: resolved.format,
98
+ recordCount: projected.length,
99
+ limit: resolved.limit,
100
+ intent: resolved.intent,
101
+ filters: resolved.filters || null,
102
+ fields: resolved.fields || null,
103
+ meta: { excluded, auditRef: meta.auditRef },
104
+ excludedAbac: Number(excluded.abac) || 0,
105
+ excludedFilter: Number(excluded.filter) || 0,
106
+ hitLimitCap: projected.length >= resolved.limit,
107
+ context: ctx
108
+ };
109
+ }
110
+
111
+ /**
112
+ * @async
113
+ * @param {string} datasourceKey
114
+ * @param {Object} options
115
+ * @returns {Promise<Object>}
116
+ */
117
+ async function runDatasourceExport(datasourceKey, options = {}) {
118
+ const ctx = await resolveLoadExportContext(datasourceKey, options);
119
+ const resolved = resolveExportOptions({
120
+ ...options,
121
+ systemKey: ctx.systemKey,
122
+ entitySuffix: ctx.entitySuffix
123
+ });
124
+ const startedAt = Date.now();
125
+
126
+ const payload = await runWithDatasourceLoadExportSpinner(
127
+ () => executeDatasourceExportWork(ctx, resolved),
128
+ {
129
+ operation: 'export',
130
+ datasourceKey: ctx.datasourceKey,
131
+ json: options.json === true
132
+ }
133
+ );
134
+
135
+ return { ...payload, durationMs: Date.now() - startedAt };
136
+ }
137
+
138
+ module.exports = {
139
+ runDatasourceExport,
140
+ projectExportRows,
141
+ writeExportFile,
142
+ DEFAULT_LIMIT,
143
+ MAX_LIMIT
144
+ };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * @fileoverview Match datasource CLI identifiers to integration files (key or filename stem).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const { getIntegrationPath } = require('../utils/paths');
11
+ const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
12
+ const { loadConfigFile } = require('../utils/config-format');
13
+
14
+ /**
15
+ * @param {string} fileRef
16
+ * @returns {string}
17
+ */
18
+ function datasourceFileStem(fileRef) {
19
+ return path.basename(String(fileRef || ''), path.extname(String(fileRef || '')));
20
+ }
21
+
22
+ /**
23
+ * True when identifier matches parsed `key` or the datasource JSON filename (with or without .json).
24
+ * @param {string} identifier
25
+ * @param {string} fileRef - Manifest-relative datasource path
26
+ * @param {Object|null} parsed
27
+ * @returns {boolean}
28
+ */
29
+ function datasourceIdentifierMatchesFile(identifier, fileRef, parsed) {
30
+ const id = String(identifier || '').trim();
31
+ if (!id || !parsed || typeof parsed !== 'object') {
32
+ return false;
33
+ }
34
+ if (parsed.key === id) {
35
+ return true;
36
+ }
37
+ const stem = datasourceFileStem(fileRef);
38
+ if (stem === id) {
39
+ return true;
40
+ }
41
+ if (`${stem}.json` === id.toLowerCase()) {
42
+ return true;
43
+ }
44
+ return false;
45
+ }
46
+
47
+ /**
48
+ * Pick integration app folder for a datasource identifier (longest matching prefix wins).
49
+ * @param {string} identifier
50
+ * @param {string[]} appNames
51
+ * @returns {string|null}
52
+ */
53
+ function pickIntegrationAppForDatasourceIdentifier(identifier, appNames) {
54
+ const id = String(identifier || '').trim();
55
+ if (!id) {
56
+ return null;
57
+ }
58
+ const matches = appNames.filter(app => id === app || id.startsWith(`${app}-`));
59
+ if (matches.length === 0) {
60
+ return null;
61
+ }
62
+ matches.sort((a, b) => b.length - a.length);
63
+ return matches[0];
64
+ }
65
+
66
+ /**
67
+ * List manifest datasource files for an integration app.
68
+ * @param {string} appKey
69
+ * @returns {{ appPath: string, schemaBasePath: string, datasourceFiles: string[] }|null}
70
+ */
71
+ function listDatasourceFilesForApp(appKey) {
72
+ const appPath = getIntegrationPath(appKey);
73
+ let config;
74
+ try {
75
+ const configPath = resolveApplicationConfigPath(appPath);
76
+ config = loadConfigFile(configPath);
77
+ } catch {
78
+ return null;
79
+ }
80
+ const schemaBasePath = config.externalIntegration?.schemaBasePath || './';
81
+ const datasourceFiles = config.externalIntegration?.dataSources || [];
82
+ return { appPath, schemaBasePath, datasourceFiles };
83
+ }
84
+
85
+ /**
86
+ * @param {string} appPath
87
+ * @param {string} schemaBasePath
88
+ * @param {string} fileRef
89
+ * @returns {string}
90
+ */
91
+ function resolveDatasourceFilePath(appPath, schemaBasePath, fileRef) {
92
+ if (path.isAbsolute(schemaBasePath)) {
93
+ return path.join(schemaBasePath, fileRef);
94
+ }
95
+ return path.join(appPath, schemaBasePath, fileRef);
96
+ }
97
+
98
+ /**
99
+ * Collect datasource file refs in one app that match the identifier.
100
+ * @param {string} appKey
101
+ * @param {string} identifier
102
+ * @returns {string[]}
103
+ */
104
+ function collectDatasourceFileRefsMatchingIdentifier(appKey, identifier) {
105
+ const listed = listDatasourceFilesForApp(appKey);
106
+ if (!listed) {
107
+ return [];
108
+ }
109
+ const fsSync = require('fs');
110
+ const hits = [];
111
+ for (const fileRef of listed.datasourceFiles) {
112
+ if (!fileRef || typeof fileRef !== 'string') {
113
+ continue;
114
+ }
115
+ const fullPath = resolveDatasourceFilePath(listed.appPath, listed.schemaBasePath, fileRef);
116
+ if (!fsSync.existsSync(fullPath)) {
117
+ continue;
118
+ }
119
+ try {
120
+ const parsed = loadConfigFile(fullPath);
121
+ if (datasourceIdentifierMatchesFile(identifier, fileRef, parsed)) {
122
+ hits.push(fileRef);
123
+ }
124
+ } catch {
125
+ // skip unreadable or invalid files
126
+ }
127
+ }
128
+ return hits;
129
+ }
130
+
131
+ /**
132
+ * @param {string} appKey
133
+ * @param {string} identifier
134
+ * @returns {boolean}
135
+ */
136
+ function appHasDatasourceIdentifier(appKey, identifier) {
137
+ return collectDatasourceFileRefsMatchingIdentifier(appKey, identifier).length > 0;
138
+ }
139
+
140
+ module.exports = {
141
+ datasourceFileStem,
142
+ datasourceIdentifierMatchesFile,
143
+ pickIntegrationAppForDatasourceIdentifier,
144
+ listDatasourceFilesForApp,
145
+ resolveDatasourceFilePath,
146
+ collectDatasourceFileRefsMatchingIdentifier,
147
+ appHasDatasourceIdentifier
148
+ };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @fileoverview Shared context resolution for datasource load/export (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { getConfig } = require('../core/config');
10
+ const { setupIntegrationTestAuth } = require('../external-system/test-auth');
11
+ const { applyLabDataplaneApiKeyBearer } = require('../utils/token-manager');
12
+ const { resolveAppKeyForDatasource } = require('./resolve-app');
13
+ const { getSystemKeyFromAppKey } = require('./integration-context');
14
+ const { loadDatasourceForApp } = require('./unified-validation-run-resolve');
15
+ const { findDatasourceFileByKey } = require('./integration-context');
16
+ const { getIntegrationPath } = require('../utils/paths');
17
+ const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
18
+ const { computeEntitySuffix } = require('./local-data-paths');
19
+
20
+ /**
21
+ * @param {string} appKey
22
+ * @throws {Error}
23
+ */
24
+ async function assertExternalIntegrationApp(appKey) {
25
+ const pathsUtil = require('../utils/paths');
26
+ const appType = await pathsUtil.detectAppType(appKey).catch(() => null);
27
+ if (!appType || appType.baseDir !== 'integration') {
28
+ throw new Error(
29
+ 'datasource load/export apply to external integration folders only (integration/<systemKey>/).'
30
+ );
31
+ }
32
+ }
33
+
34
+ /**
35
+ * @async
36
+ * @param {string} datasourceKey
37
+ * @param {Object} options
38
+ * @returns {Promise<Object>}
39
+ */
40
+ async function resolveLoadExportContext(datasourceKey, options = {}) {
41
+ const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
42
+ await assertExternalIntegrationApp(appKey);
43
+ const systemKey = await getSystemKeyFromAppKey(appKey);
44
+ const {
45
+ datasource,
46
+ datasourcePath,
47
+ datasourceKey: canonicalDatasourceKey
48
+ } = loadDatasourceForApp(appKey, datasourceKey, findDatasourceFileByKey);
49
+ const appPath = getIntegrationPath(appKey);
50
+ const manifestPath = resolveApplicationConfigPath(appPath);
51
+ const entitySuffix = computeEntitySuffix(systemKey, canonicalDatasourceKey);
52
+
53
+ let authConfig = options.authConfig;
54
+ let dataplaneUrl = options.dataplaneUrl || options.dataplane;
55
+ if (!authConfig || !dataplaneUrl) {
56
+ const configObj = await getConfig();
57
+ const auth = await setupIntegrationTestAuth(
58
+ appKey,
59
+ { environment: options.environment || options.env, dataplane: options.dataplane },
60
+ configObj
61
+ );
62
+ authConfig = auth.authConfig;
63
+ dataplaneUrl = auth.dataplaneUrl;
64
+ }
65
+
66
+ authConfig = applyLabDataplaneApiKeyBearer(authConfig);
67
+
68
+ return {
69
+ appKey,
70
+ systemKey,
71
+ datasourceKey: canonicalDatasourceKey,
72
+ datasource,
73
+ datasourcePath,
74
+ manifestPath,
75
+ entitySuffix,
76
+ authConfig,
77
+ dataplaneUrl,
78
+ environment: options.environment || options.env
79
+ };
80
+ }
81
+
82
+ /**
83
+ * Gray manifest label segment for TTY (integration/<appKey>).
84
+ * @param {string} appKey
85
+ * @returns {string}
86
+ */
87
+ function integrationManifestLabel(appKey) {
88
+ return `integration/${appKey}`;
89
+ }
90
+
91
+ module.exports = {
92
+ assertExternalIntegrationApp,
93
+ resolveLoadExportContext,
94
+ integrationManifestLabel
95
+ };
@@ -9,6 +9,10 @@ const fs = require('fs').promises;
9
9
  const { getIntegrationPath } = require('../utils/paths');
10
10
  const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
11
11
  const { loadConfigFile } = require('../utils/config-format');
12
+ const {
13
+ datasourceIdentifierMatchesFile,
14
+ resolveDatasourceFilePath
15
+ } = require('./datasource-identifier');
12
16
 
13
17
  /**
14
18
  * @param {string} appKey - Integration app key
@@ -43,13 +47,11 @@ function findDatasourceFileByKey(appPath, schemaBasePath, datasourceFiles, datas
43
47
  const fsSync = require('fs');
44
48
  for (const f of datasourceFiles) {
45
49
  if (!f || typeof f !== 'string') continue;
46
- const fullPath = path.isAbsolute(schemaBasePath)
47
- ? path.join(schemaBasePath, f)
48
- : path.join(appPath, schemaBasePath, f);
50
+ const fullPath = resolveDatasourceFilePath(appPath, schemaBasePath, f);
49
51
  if (!fsSync.existsSync(fullPath)) continue;
50
52
  try {
51
53
  const parsed = loadConfigFile(fullPath);
52
- if (parsed && parsed.key === datasourceKey) return f;
54
+ if (datasourceIdentifierMatchesFile(datasourceKey, f, parsed)) return f;
53
55
  } catch {
54
56
  // skip unreadable or invalid files
55
57
  }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * @fileoverview Resolve integration/.data/ paths for datasource load/export (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+ const { getCwdIntegrationRoot, getIntegrationRoot } = require('../utils/paths');
12
+
13
+ const DATA_DIR_NAME = '.data';
14
+
15
+ /**
16
+ * Absolute path to integration/.data (cwd integration root preferred).
17
+ * @returns {string}
18
+ */
19
+ function getIntegrationDataDir() {
20
+ const cwdRoot = getCwdIntegrationRoot();
21
+ const base = cwdRoot || getIntegrationRoot();
22
+ return path.join(base, DATA_DIR_NAME);
23
+ }
24
+
25
+ /**
26
+ * Entity suffix from datasource key and system key.
27
+ * @param {string} systemKey
28
+ * @param {string} datasourceKey
29
+ * @returns {string}
30
+ */
31
+ function computeEntitySuffix(systemKey, datasourceKey) {
32
+ const sys = String(systemKey || '').trim();
33
+ const key = String(datasourceKey || '').trim();
34
+ const prefix = `${sys}-`;
35
+ if (sys && key.startsWith(prefix)) {
36
+ return key.slice(prefix.length) || key;
37
+ }
38
+ const lastHyphen = key.lastIndexOf('-');
39
+ if (lastHyphen > 0) {
40
+ return key.slice(lastHyphen + 1);
41
+ }
42
+ return key;
43
+ }
44
+
45
+ /**
46
+ * Default fixture basename (without extension).
47
+ * @param {string} systemKey
48
+ * @param {string} entitySuffix
49
+ * @returns {string}
50
+ */
51
+ function defaultDataBasename(systemKey, entitySuffix) {
52
+ return `${systemKey}-data-${entitySuffix}`;
53
+ }
54
+
55
+ /**
56
+ * @param {string} dir
57
+ * @param {string} basename
58
+ * @param {'json'|'ndjson'} format
59
+ * @returns {string}
60
+ */
61
+ function dataFilePath(dir, basename, format) {
62
+ const ext = format === 'ndjson' ? '.ndjson' : '.json';
63
+ return path.join(dir, `${basename}${ext}`);
64
+ }
65
+
66
+ /**
67
+ * Infer format from file extension.
68
+ * @param {string} filePath
69
+ * @returns {'json'|'ndjson'}
70
+ */
71
+ function inferFormatFromPath(filePath) {
72
+ const ext = path.extname(filePath).toLowerCase();
73
+ if (ext === '.ndjson' || ext === '.jsonl') {
74
+ return 'ndjson';
75
+ }
76
+ return 'json';
77
+ }
78
+
79
+ /**
80
+ * Default integration/.data output path (file need not exist).
81
+ * @param {Object} opts
82
+ * @param {string} opts.systemKey
83
+ * @param {string} opts.entitySuffix
84
+ * @param {'json'|'ndjson'} [opts.format]
85
+ * @returns {{ filePath: string, format: 'json'|'ndjson' }}
86
+ */
87
+ function resolveDefaultDataOutputPath(opts) {
88
+ const dir = getIntegrationDataDir();
89
+ const basename = defaultDataBasename(opts.systemKey, opts.entitySuffix);
90
+ const format = opts.format === 'ndjson' ? 'ndjson' : 'json';
91
+ return { filePath: dataFilePath(dir, basename, format), format };
92
+ }
93
+
94
+ /**
95
+ * Resolve data file: --file override or default integration/.data paths.
96
+ * @param {Object} opts
97
+ * @param {string} opts.systemKey
98
+ * @param {string} opts.entitySuffix
99
+ * @param {string} [opts.file] - CLI --file
100
+ * @param {'json'|'ndjson'} [opts.format] - explicit format
101
+ * @returns {{ filePath: string, format: 'json'|'ndjson' }}
102
+ */
103
+ function resolveDataFilePath(opts) {
104
+ if (opts.file && String(opts.file).trim()) {
105
+ const filePath = path.resolve(String(opts.file).trim());
106
+ const format = opts.format || inferFormatFromPath(filePath);
107
+ return { filePath, format };
108
+ }
109
+
110
+ const dir = getIntegrationDataDir();
111
+ const basename = defaultDataBasename(opts.systemKey, opts.entitySuffix);
112
+ const jsonPath = dataFilePath(dir, basename, 'json');
113
+ const ndjsonPath = dataFilePath(dir, basename, 'ndjson');
114
+
115
+ if (opts.format === 'json' && fs.existsSync(jsonPath)) {
116
+ return { filePath: jsonPath, format: 'json' };
117
+ }
118
+ if (opts.format === 'ndjson' && fs.existsSync(ndjsonPath)) {
119
+ return { filePath: ndjsonPath, format: 'ndjson' };
120
+ }
121
+ if (!opts.format || opts.format === 'json') {
122
+ if (fs.existsSync(jsonPath)) {
123
+ return { filePath: jsonPath, format: 'json' };
124
+ }
125
+ }
126
+ if (!opts.format || opts.format === 'ndjson') {
127
+ if (fs.existsSync(ndjsonPath)) {
128
+ return { filePath: ndjsonPath, format: 'ndjson' };
129
+ }
130
+ }
131
+
132
+ throw new Error(
133
+ `No local data file found. Expected one of:\n ${jsonPath}\n ${ndjsonPath}\n` +
134
+ 'Use --file <path> to override.'
135
+ );
136
+ }
137
+
138
+ module.exports = {
139
+ getIntegrationDataDir,
140
+ computeEntitySuffix,
141
+ defaultDataBasename,
142
+ inferFormatFromPath,
143
+ resolveDefaultDataOutputPath,
144
+ resolveDataFilePath
145
+ };