@aifabrix/builder 2.45.5 → 2.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/project-rules.mdc +1 -0
  4. package/.npmrc.token +1 -0
  5. package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
  6. package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
  7. package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
  8. package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
  9. package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
  10. package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
  11. package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
  12. package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
  13. package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
  14. package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
  15. package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
  16. package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
  17. package/.temp/validation/summary.txt +5 -0
  18. package/README.md +43 -17
  19. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  20. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  21. package/jest.config.default.js +2 -1
  22. package/jest.config.isolated.js +2 -1
  23. package/jest.global-live-fabrix-hooks.js +36 -0
  24. package/jest.isolated-projects.js +146 -0
  25. package/jest.projects.js +65 -136
  26. package/lib/api/api-response-errors.js +124 -0
  27. package/lib/api/dataplane-health.api.js +19 -7
  28. package/lib/api/governance-scenario-pack.api.js +159 -0
  29. package/lib/api/index.js +43 -3
  30. package/lib/api/lifecycle.api.js +98 -0
  31. package/lib/api/pipeline.api.js +3 -1
  32. package/lib/api/records-bulk.api.js +14 -1
  33. package/lib/api/resource-types.api.js +107 -0
  34. package/lib/api/runtime-configuration.api.js +72 -0
  35. package/lib/api/types/resource-types.types.js +45 -0
  36. package/lib/api/user-groups.api.js +9 -9
  37. package/lib/api/users.api.js +8 -8
  38. package/lib/api/validation-runner.js +3 -1
  39. package/lib/api/wizard.api.js +10 -2
  40. package/lib/app/deploy-config.js +4 -1
  41. package/lib/app/down.js +78 -27
  42. package/lib/app/index.js +2 -2
  43. package/lib/app/push.js +4 -5
  44. package/lib/app/register.js +7 -4
  45. package/lib/app/run-env-compose.js +84 -30
  46. package/lib/app/run-resolve-image.js +2 -1
  47. package/lib/app/run-stop-containers.js +113 -0
  48. package/lib/app/run.js +1 -31
  49. package/lib/app/show-display.js +35 -0
  50. package/lib/app/show.js +32 -1
  51. package/lib/build/index.js +22 -5
  52. package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
  53. package/lib/certification/sync-system-certification.js +13 -6
  54. package/lib/channels/add-channel.js +348 -0
  55. package/lib/channels/channel-artifact-generator.js +141 -0
  56. package/lib/channels/channel-audit.js +101 -0
  57. package/lib/channels/channel-auth-context.js +37 -0
  58. package/lib/channels/channel-credential.js +200 -0
  59. package/lib/channels/channel-display-name.js +64 -0
  60. package/lib/channels/channel-external-system.js +106 -0
  61. package/lib/channels/channel-integration-generator.js +274 -0
  62. package/lib/channels/channel-probe.js +89 -0
  63. package/lib/channels/channel-runtime-resolver.js +152 -0
  64. package/lib/channels/channel-status-display.js +141 -0
  65. package/lib/channels/channel-targets.js +115 -0
  66. package/lib/cli/index.js +20 -4
  67. package/lib/cli/infra-guided-auth.js +109 -0
  68. package/lib/cli/infra-guided.js +84 -81
  69. package/lib/cli/setup-app.help.js +0 -31
  70. package/lib/cli/setup-app.js +82 -5
  71. package/lib/cli/setup-app.test-commands.js +5 -57
  72. package/lib/cli/setup-auth.js +25 -0
  73. package/lib/cli/setup-certification-commands.js +147 -0
  74. package/lib/cli/setup-certification.help.js +141 -0
  75. package/lib/cli/setup-environment.js +19 -2
  76. package/lib/cli/setup-external-system-help.js +62 -0
  77. package/lib/cli/setup-external-system.js +25 -3
  78. package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
  79. package/lib/cli/setup-infra-up-platform-action.js +2 -1
  80. package/lib/cli/setup-infra.js +9 -1
  81. package/lib/cli/setup-platform.js +6 -1
  82. package/lib/cli/setup-secrets.js +33 -1
  83. package/lib/cli/setup-utility-help-after.js +25 -2
  84. package/lib/cli/setup-utility-repair.js +198 -0
  85. package/lib/cli/setup-utility-resolve.js +44 -5
  86. package/lib/cli/setup-utility-validate.js +197 -0
  87. package/lib/cli/setup-utility.js +4 -239
  88. package/lib/commands/app-logs.js +54 -26
  89. package/lib/commands/app.js +41 -0
  90. package/lib/commands/auth-status-client-tokens.js +214 -0
  91. package/lib/commands/auth-status-dataplane-version.js +142 -68
  92. package/lib/commands/auth-status.js +43 -54
  93. package/lib/commands/channel.js +58 -0
  94. package/lib/commands/datasource-test-trust-cli.js +27 -23
  95. package/lib/commands/datasource-unified-test-cli.js +6 -3
  96. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  97. package/lib/commands/datasource.js +8 -8
  98. package/lib/commands/dev-show-display.js +8 -1
  99. package/lib/commands/governance-cli-shared.js +94 -0
  100. package/lib/commands/governance-command-action.js +132 -0
  101. package/lib/commands/governance-download-external.js +34 -0
  102. package/lib/commands/governance-generate-external.js +71 -0
  103. package/lib/commands/governance-upload-external.js +36 -0
  104. package/lib/commands/governance-verify-external.js +64 -0
  105. package/lib/commands/governance.js +144 -0
  106. package/lib/commands/identity-apply-sync.js +49 -8
  107. package/lib/commands/identity-group-cli.js +66 -26
  108. package/lib/commands/identity-membership-role-cache.js +58 -37
  109. package/lib/commands/identity-shared.js +22 -1
  110. package/lib/commands/identity-user-cli.js +80 -34
  111. package/lib/commands/lifecycle-command-action.js +123 -0
  112. package/lib/commands/lifecycle-external.js +268 -0
  113. package/lib/commands/login.js +11 -2
  114. package/lib/commands/repair-auth-apply.js +153 -0
  115. package/lib/commands/repair-auth-config.js +8 -13
  116. package/lib/commands/repair-changed-files.js +41 -0
  117. package/lib/commands/repair-datasource-com-v2.js +15 -0
  118. package/lib/commands/repair-datasource-keys.js +4 -1
  119. package/lib/commands/repair-datasource-run.js +59 -0
  120. package/lib/commands/repair-datasource-service-contract.js +206 -0
  121. package/lib/commands/repair-datasource-test-payload.js +259 -0
  122. package/lib/commands/repair-datasource.js +49 -64
  123. package/lib/commands/repair-env-template.js +76 -25
  124. package/lib/commands/repair-external-run.js +216 -0
  125. package/lib/commands/repair-openapi-sync.js +49 -4
  126. package/lib/commands/repair-persist.js +4 -0
  127. package/lib/commands/repair-rbac.js +52 -1
  128. package/lib/commands/repair-steps.js +160 -0
  129. package/lib/commands/repair-system-alignment.js +7 -4
  130. package/lib/commands/repair.js +29 -296
  131. package/lib/commands/resource-type.js +371 -0
  132. package/lib/commands/secrets-get.js +184 -0
  133. package/lib/commands/secrets-remove-all.js +3 -1
  134. package/lib/commands/setup-image-refresh.js +146 -0
  135. package/lib/commands/setup-modes.js +158 -162
  136. package/lib/commands/setup-platform-auth.js +76 -0
  137. package/lib/commands/setup-prompts-admin.js +244 -0
  138. package/lib/commands/setup-prompts-platform-mode.js +70 -0
  139. package/lib/commands/setup-prompts-validators.js +36 -0
  140. package/lib/commands/setup-prompts.js +24 -76
  141. package/lib/commands/setup-run-context.js +45 -0
  142. package/lib/commands/setup-spinners.js +39 -0
  143. package/lib/commands/setup.js +27 -5
  144. package/lib/commands/teardown.js +39 -0
  145. package/lib/commands/test-e2e-external.js +24 -8
  146. package/lib/commands/test-governance-external.js +3 -24
  147. package/lib/commands/test-trust-external.js +48 -100
  148. package/lib/commands/up-common.js +57 -13
  149. package/lib/commands/up-dataplane.js +56 -15
  150. package/lib/commands/upload-publish-context.js +75 -0
  151. package/lib/commands/upload-sidecar-followups.js +89 -0
  152. package/lib/commands/upload.js +113 -110
  153. package/lib/commands/verify-governance-combined-external.js +61 -0
  154. package/lib/commands/verify-governance-command-action.js +64 -0
  155. package/lib/commands/verify-governance-db.js +102 -0
  156. package/lib/commands/verify-governance-external.js +77 -0
  157. package/lib/commands/verify-governance-result-builders.js +71 -0
  158. package/lib/commands/verify-operations-command-action.js +68 -0
  159. package/lib/commands/verify-operations-external.js +268 -0
  160. package/lib/commands/verify-operations-persist.js +75 -0
  161. package/lib/commands/verify-operations-step-plan.js +68 -0
  162. package/lib/commands/verify-operations-steps.js +111 -0
  163. package/lib/commands/verify-trust-command-action.js +73 -0
  164. package/lib/commands/verify-trust-external.js +59 -0
  165. package/lib/commands/wizard-config-normalizer.js +43 -23
  166. package/lib/commands/wizard-core.js +2 -0
  167. package/lib/core/admin-password-generator.js +38 -0
  168. package/lib/core/admin-secrets-bundle.js +111 -0
  169. package/lib/core/admin-secrets-env-overlay.js +62 -0
  170. package/lib/core/admin-secrets.js +32 -4
  171. package/lib/core/config-attach-extensions.js +3 -0
  172. package/lib/core/config-platform-controller.js +44 -0
  173. package/lib/core/config-setup-installation-profile.js +42 -0
  174. package/lib/core/config-setup-platform-mode.js +46 -0
  175. package/lib/core/config.js +46 -36
  176. package/lib/core/secrets-admin-env.js +6 -2
  177. package/lib/core/secrets-ensure.js +4 -0
  178. package/lib/core/secrets-env-content.js +54 -48
  179. package/lib/core/secrets-env-write.js +10 -1
  180. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  181. package/lib/core/setup-installation-profile.js +43 -0
  182. package/lib/core/setup-platform-mode.js +90 -0
  183. package/lib/datasource/agent-trust-debug-log.js +1 -1
  184. package/lib/datasource/agent-trust-run.js +5 -3
  185. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  186. package/lib/datasource/audit-evidence-extract.js +7 -4
  187. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  188. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  189. package/lib/datasource/capability/capability-diff-slice.js +2 -2
  190. package/lib/datasource/capability/capability-manifest.js +254 -0
  191. package/lib/datasource/capability/capability-resolve.js +3 -4
  192. package/lib/datasource/capability/copy-operations.js +5 -3
  193. package/lib/datasource/capability/remove-operations.js +2 -1
  194. package/lib/datasource/capability/run-capability-copy.js +32 -4
  195. package/lib/datasource/capability/run-capability-diff.js +3 -3
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -4
  197. package/lib/datasource/capability/run-capability-edit.js +4 -7
  198. package/lib/datasource/capability/run-capability-relate.js +2 -4
  199. package/lib/datasource/capability/run-capability-remove.js +2 -4
  200. package/lib/datasource/capability/validate-capability-slice.js +2 -1
  201. package/lib/datasource/datasource-identifier.js +2 -1
  202. package/lib/datasource/datasource-load-export-context.js +3 -0
  203. package/lib/datasource/datasource-validate-display.js +1 -1
  204. package/lib/datasource/field-reference-validator.js +24 -3
  205. package/lib/datasource/log-cleaner.js +2 -2
  206. package/lib/datasource/log-viewer.js +8 -8
  207. package/lib/datasource/orphan-profiles-validator.js +98 -0
  208. package/lib/datasource/test-e2e.js +4 -1
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run.js +5 -2
  211. package/lib/datasource/validate.js +41 -23
  212. package/lib/deployment/environment-poll-status.js +138 -0
  213. package/lib/deployment/environment.js +42 -34
  214. package/lib/external-system/download-helpers.js +87 -0
  215. package/lib/external-system/download.js +78 -138
  216. package/lib/external-system/generator.js +1 -55
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test.js +16 -21
  220. package/lib/generator/builders.js +11 -1
  221. package/lib/generator/external-controller-manifest.js +18 -0
  222. package/lib/generator/split.js +3 -1
  223. package/lib/generator/wizard.js +1 -28
  224. package/lib/governance/governance-cli-errors.js +96 -0
  225. package/lib/governance/governance-download-display.js +38 -0
  226. package/lib/governance/governance-run-display.js +215 -25
  227. package/lib/identity/fk-reference.js +65 -0
  228. package/lib/identity/identity-apply-core.js +13 -58
  229. package/lib/identity/identity-apply-phases.js +5 -1
  230. package/lib/identity/identity-display.js +243 -0
  231. package/lib/identity/identity-response-helpers.js +52 -0
  232. package/lib/identity/identity-sync-errors.js +62 -0
  233. package/lib/identity/resolve-user-id.js +129 -0
  234. package/lib/identity/username-default.js +31 -0
  235. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  236. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  237. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  238. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  239. package/lib/infrastructure/helpers.js +23 -129
  240. package/lib/infrastructure/index.js +5 -6
  241. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  242. package/lib/lifecycle/certification-progress.js +231 -0
  243. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  244. package/lib/lifecycle/exit-codes.js +24 -0
  245. package/lib/lifecycle/json-envelope.js +25 -0
  246. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  247. package/lib/lifecycle/logger-quiet.js +29 -0
  248. package/lib/lifecycle/open-api-published.js +59 -0
  249. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  250. package/lib/lifecycle/product-model.js +196 -0
  251. package/lib/lifecycle/report-display-trust.js +70 -0
  252. package/lib/lifecycle/report-display.js +472 -0
  253. package/lib/lifecycle/scenario-upload.js +191 -0
  254. package/lib/lifecycle/verify-step-progress.js +87 -0
  255. package/lib/parameters/infra-kv-discovery.js +27 -2
  256. package/lib/protection/auth-context.js +10 -4
  257. package/lib/resolvers/datasource-resolver.js +2 -3
  258. package/lib/resolvers/resource-type-file.js +159 -0
  259. package/lib/schema/application-schema.json +17 -1
  260. package/lib/schema/datasource-test-run.schema.json +89 -6
  261. package/lib/schema/deployment-rules.yaml +2 -1
  262. package/lib/schema/external-datasource.schema.json +2947 -2619
  263. package/lib/schema/external-system.schema.json +1418 -761
  264. package/lib/schema/infra.parameter.yaml +45 -0
  265. package/lib/schema/type/credential-field-registry.json +103 -97
  266. package/lib/schema/type/document-storage.json +9 -5
  267. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  268. package/lib/utils/api.js +55 -31
  269. package/lib/utils/app-relative-path-env.js +112 -0
  270. package/lib/utils/app-run-containers.js +25 -2
  271. package/lib/utils/authentication-shape.js +224 -0
  272. package/lib/utils/build-copy.js +36 -5
  273. package/lib/utils/build-resolve-image.js +66 -12
  274. package/lib/utils/celery-companion-apps.js +53 -0
  275. package/lib/utils/cli-secrets-error-format.js +83 -21
  276. package/lib/utils/cli-utils.js +20 -4
  277. package/lib/utils/compose-celery-worker.js +23 -0
  278. package/lib/utils/compose-generate-docker-compose.js +13 -1
  279. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  280. package/lib/utils/config-secrets-path.js +46 -0
  281. package/lib/utils/configuration-env-resolver.js +36 -0
  282. package/lib/utils/controller-url.js +88 -1
  283. package/lib/utils/credential-secrets-env-kv.js +216 -0
  284. package/lib/utils/credential-secrets-env.js +175 -257
  285. package/lib/utils/dataplane-resolver.js +18 -2
  286. package/lib/utils/declarative-url-ports.js +27 -4
  287. package/lib/utils/deployment-auth-mode.js +41 -0
  288. package/lib/utils/developer-volume-id.js +33 -0
  289. package/lib/utils/docker-build.js +1 -4
  290. package/lib/utils/env-copy.js +14 -9
  291. package/lib/utils/env-kv-orphan-lines.js +43 -0
  292. package/lib/utils/error-formatters/network-errors.js +13 -4
  293. package/lib/utils/external-env-template.js +11 -3
  294. package/lib/utils/external-system-readiness-core.js +10 -0
  295. package/lib/utils/external-system-readiness-display.js +80 -23
  296. package/lib/utils/external-system-validators.js +8 -2
  297. package/lib/utils/health-check.js +4 -1
  298. package/lib/utils/help-builder.js +13 -8
  299. package/lib/utils/keycloak-realm-ready.js +101 -0
  300. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  301. package/lib/utils/manifest-source-emit.js +2 -0
  302. package/lib/utils/paths.js +25 -0
  303. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  304. package/lib/utils/platform-controller-url.js +157 -0
  305. package/lib/utils/platform-kv-ref.js +57 -0
  306. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  307. package/lib/utils/postgres-wipe.js +9 -2
  308. package/lib/utils/resolve-env-mode.js +47 -0
  309. package/lib/utils/runtime-configuration-download.js +189 -0
  310. package/lib/utils/runtime-configuration-values.js +119 -0
  311. package/lib/utils/schema-loader.js +19 -4
  312. package/lib/utils/secrets-generator.js +31 -25
  313. package/lib/utils/secrets-missing-error.js +164 -0
  314. package/lib/utils/service-url-label.js +81 -0
  315. package/lib/utils/setup-quiet-output.js +25 -0
  316. package/lib/utils/template-helpers.js +15 -0
  317. package/lib/utils/token-manager-client-credentials.js +201 -0
  318. package/lib/utils/token-manager-messages.js +8 -0
  319. package/lib/utils/token-manager-refresh.js +12 -2
  320. package/lib/utils/token-manager.js +86 -105
  321. package/lib/utils/upload-pipeline-ui.js +12 -5
  322. package/lib/utils/upload-sync-options.js +42 -0
  323. package/lib/utils/url-declarative-public-base.js +21 -3
  324. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  325. package/lib/utils/validation-poll-ui.js +8 -0
  326. package/lib/utils/validation-run-stage.js +45 -0
  327. package/lib/utils/worker-sidecars.js +142 -0
  328. package/lib/validation/external-manifest-validator.js +2 -0
  329. package/lib/validation/runtime-configuration-rules.js +98 -0
  330. package/lib/validation/validate-display-dimensions.js +154 -0
  331. package/lib/validation/validate-display-sections.js +276 -0
  332. package/lib/validation/validate-display-steps.js +67 -0
  333. package/lib/validation/validate-display.js +24 -402
  334. package/package.json +1 -1
  335. package/templates/applications/dataplane/application.yaml +7 -1
  336. package/templates/applications/dataplane/env.template +50 -14
  337. package/templates/applications/dataplane/rbac.yaml +108 -1
  338. package/templates/applications/miso-controller/application.yaml +2 -2
  339. package/templates/applications/miso-controller/env.template +53 -122
  340. package/templates/applications/miso-controller/rbac.yaml +28 -13
  341. package/templates/channels/chatgpt/install.template.md.hbs +49 -0
  342. package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
  343. package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
  344. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
  345. package/templates/channels/slack/install.template.md.hbs +49 -0
  346. package/templates/channels/slack/manifest.template.json.hbs +66 -0
  347. package/templates/channels/teams-bot/install.template.md.hbs +49 -0
  348. package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
  349. package/templates/channels/web-embed/install.template.md.hbs +49 -0
  350. package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
  351. package/templates/external-system/README.md.hbs +74 -17
  352. package/templates/python/docker-compose.hbs +75 -18
  353. package/templates/typescript/docker-compose.hbs +70 -17
  354. package/lib/commands/test-governance-command-action.js +0 -55
  355. package/lib/commands/test-trust-command-action.js +0 -118
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Infer which platform service a request URL targets (CLI error copy).
3
+ *
4
+ * @fileoverview Service label heuristics for network error messages
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /** @type {readonly string[]} */
12
+ const DATAPLANE_PATH_PREFIXES = Object.freeze([
13
+ '/api/v1/external',
14
+ '/api/v1/validation',
15
+ '/api/v1/records',
16
+ '/api/v1/wizard',
17
+ '/api/v1/admin',
18
+ '/api/v1/health',
19
+ '/api/v1/dataplane',
20
+ '/api/v1/policy',
21
+ '/api/v1/mcp',
22
+ '/api/v1/ide',
23
+ '/api/v1/knowledgebase'
24
+ ]);
25
+
26
+ /** @type {readonly string[]} */
27
+ const CONTROLLER_PATH_PREFIXES = Object.freeze([
28
+ '/api/v1/auth',
29
+ '/api/v1/applications',
30
+ '/api/v1/pipeline',
31
+ '/api/v1/environments',
32
+ '/api/v1/deployments',
33
+ '/api/v1/datasources',
34
+ '/api/v1/external-systems',
35
+ '/api/controller'
36
+ ]);
37
+
38
+ /**
39
+ * @param {string} url - Full request URL
40
+ * @returns {'dataplane'|'controller'|'service'}
41
+ */
42
+ function inferServiceLabelFromUrl(url) {
43
+ if (!url || typeof url !== 'string') {
44
+ return 'service';
45
+ }
46
+ try {
47
+ const path = new URL(url.trim()).pathname || '';
48
+ for (const prefix of DATAPLANE_PATH_PREFIXES) {
49
+ if (path.startsWith(prefix)) {
50
+ return 'dataplane';
51
+ }
52
+ }
53
+ for (const prefix of CONTROLLER_PATH_PREFIXES) {
54
+ if (path.startsWith(prefix)) {
55
+ return 'controller';
56
+ }
57
+ }
58
+ } catch {
59
+ return 'service';
60
+ }
61
+ return 'service';
62
+ }
63
+
64
+ /**
65
+ * @param {'dataplane'|'controller'|'service'} label
66
+ * @returns {string}
67
+ */
68
+ function serviceLabelDisplayName(label) {
69
+ if (label === 'dataplane') {
70
+ return 'dataplane';
71
+ }
72
+ if (label === 'controller') {
73
+ return 'controller';
74
+ }
75
+ return 'service';
76
+ }
77
+
78
+ module.exports = {
79
+ inferServiceLabelFromUrl,
80
+ serviceLabelDisplayName
81
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Suppress verbose CLI detail during `aifabrix setup` (guided milestones only).
3
+ *
4
+ * @fileoverview Setup quiet output flag
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * @returns {boolean} True while `aifabrix setup` is running
13
+ */
14
+ function isSetupQuietOutput() {
15
+ try {
16
+ const { isSetupCommandFlow } = require('../commands/setup-run-context');
17
+ return isSetupCommandFlow();
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+
23
+ module.exports = {
24
+ isSetupQuietOutput
25
+ };
@@ -110,6 +110,20 @@ function updateDatabaseConfig(variables, options, appName) {
110
110
  * @param {Object} options - CLI options
111
111
  * @param {Object} config - Final configuration
112
112
  */
113
+ async function patchEnvTemplateRelativePathKey(appPath, appName) {
114
+ const fsSync = require('fs');
115
+ const envTemplatePath = path.join(appPath, 'env.template');
116
+ if (!fsSync.existsSync(envTemplatePath)) {
117
+ return;
118
+ }
119
+ const { renameAppRelativePathEnvKeyInTemplate } = require('./app-relative-path-env');
120
+ const raw = await fs.readFile(envTemplatePath, 'utf8');
121
+ const patched = renameAppRelativePathEnvKeyInTemplate(raw, appName);
122
+ if (patched !== raw) {
123
+ await fs.writeFile(envTemplatePath, patched, 'utf8');
124
+ }
125
+ }
126
+
113
127
  async function updateTemplateVariables(appPath, appName, options, config) {
114
128
  const { resolveApplicationConfigPath } = require('./app-config-resolver');
115
129
  const { loadConfigFile, writeConfigFile } = require('./config-format');
@@ -123,6 +137,7 @@ async function updateTemplateVariables(appPath, appName, options, config) {
123
137
  updateDatabaseConfig(variables, options, appName);
124
138
 
125
139
  writeConfigFile(variablesPath, variables);
140
+ await patchEnvTemplateRelativePathKey(appPath, appName);
126
141
  } catch (error) {
127
142
  if (error.message && !error.message.includes('not found')) {
128
143
  logger.warn(chalk.yellow(`⚠ Warning: Could not update application config: ${error.message}`));
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Client credential loading from secrets.local.yaml and environment.
3
+ *
4
+ * @fileoverview Client credentials helpers for token-manager
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const yaml = require('js-yaml');
13
+ const logger = require('./logger');
14
+ const pathsUtil = require('./paths');
15
+
16
+ /** App key used for dataplane client credentials in secrets.local.yaml */
17
+ const DATAPLANE_APP_KEY = 'dataplane';
18
+
19
+ /**
20
+ * @returns {string}
21
+ */
22
+ function getSecretsFilePath() {
23
+ return pathsUtil.getPrimaryUserSecretsLocalPath();
24
+ }
25
+
26
+ /**
27
+ * Validate that secrets.local.yaml contains dataplane client credentials.
28
+ * @param {string} [secretsFilePath] - Path to secrets file; defaults to ~/.aifabrix/secrets.local.yaml
29
+ * @returns {{ valid: boolean, hint?: string }}
30
+ */
31
+ function validateDataplaneSecrets(secretsFilePath) {
32
+ const filePath = secretsFilePath || getSecretsFilePath();
33
+ const hint = 'Dataplane credentials are missing. Run: aifabrix app rotate-secret dataplane';
34
+ try {
35
+ if (!fs.existsSync(filePath)) {
36
+ return { valid: false, hint };
37
+ }
38
+ const content = fs.readFileSync(filePath, 'utf8');
39
+ const secrets = yaml.load(content) || {};
40
+ const clientIdKey = `${DATAPLANE_APP_KEY}-client-idKeyVault`;
41
+ const clientSecretKey = `${DATAPLANE_APP_KEY}-client-secretKeyVault`;
42
+ const hasId =
43
+ secrets[clientIdKey] !== null &&
44
+ secrets[clientIdKey] !== undefined &&
45
+ String(secrets[clientIdKey]).trim() !== '';
46
+ const hasSecret =
47
+ secrets[clientSecretKey] !== null &&
48
+ secrets[clientSecretKey] !== undefined &&
49
+ String(secrets[clientSecretKey]).trim() !== '';
50
+ if (hasId && hasSecret) {
51
+ return { valid: true };
52
+ }
53
+ return { valid: false, hint };
54
+ } catch {
55
+ return { valid: false, hint };
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Read client id/secret for one app key from secrets.local.yaml.
61
+ * @param {string} appName - Application key
62
+ * @returns {{ clientId: string, clientSecret: string }|null}
63
+ */
64
+ function readClientCredentialsFromSecretsFile(appName) {
65
+ try {
66
+ const secretsFile = getSecretsFilePath();
67
+ if (!fs.existsSync(secretsFile)) {
68
+ return null;
69
+ }
70
+ const content = fs.readFileSync(secretsFile, 'utf8');
71
+ const secrets = yaml.load(content) || {};
72
+ const clientId = secrets[`${appName}-client-idKeyVault`];
73
+ const clientSecret = secrets[`${appName}-client-secretKeyVault`];
74
+ if (clientId && clientSecret) {
75
+ return {
76
+ clientId: String(clientId),
77
+ clientSecret: String(clientSecret)
78
+ };
79
+ }
80
+ } catch (error) {
81
+ logger.warn(`Failed to load credentials from secrets.local.yaml: ${error.message}`);
82
+ }
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * App keys to try when resolving client credentials (integration app, then dataplane).
88
+ * @param {string} appName
89
+ * @returns {string[]}
90
+ */
91
+ function credentialAppKeysToTry(appName) {
92
+ const keys = [appName];
93
+ if (appName !== DATAPLANE_APP_KEY) {
94
+ keys.push(DATAPLANE_APP_KEY);
95
+ }
96
+ return keys;
97
+ }
98
+
99
+ /**
100
+ * @returns {{ clientId: string, clientSecret: string }|null}
101
+ */
102
+ function readClientCredentialsFromEnv() {
103
+ const pairs = [
104
+ [process.env.CLIENTID || process.env.CLIENT_ID, process.env.CLIENTSECRET || process.env.CLIENT_SECRET],
105
+ [
106
+ process.env.MISO_CLIENTID || process.env.MISO_CLIENT_ID,
107
+ process.env.MISO_CLIENTSECRET || process.env.MISO_CLIENT_SECRET
108
+ ]
109
+ ];
110
+ for (const [clientId, clientSecret] of pairs) {
111
+ if (clientId && clientSecret) {
112
+ return {
113
+ clientId: String(clientId).trim(),
114
+ clientSecret: String(clientSecret).trim()
115
+ };
116
+ }
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Decrypt secure:// client credential entries from secrets.local.yaml when needed.
123
+ * @param {string} appName
124
+ * @param {{ clientId: string, clientSecret: string }} raw
125
+ * @returns {Promise<{ clientId: string, clientSecret: string }|null>}
126
+ */
127
+ async function decryptClientCredentialsFromSecrets(appName, raw) {
128
+ const { isEncrypted } = require('./secrets-encryption');
129
+ if (!isEncrypted(raw.clientId) && !isEncrypted(raw.clientSecret)) {
130
+ return raw;
131
+ }
132
+ try {
133
+ const { decryptSecretsObject } = require('../core/secrets-load');
134
+ const idKey = `${appName}-client-idKeyVault`;
135
+ const secretKey = `${appName}-client-secretKeyVault`;
136
+ const decrypted = await decryptSecretsObject({
137
+ [idKey]: raw.clientId,
138
+ [secretKey]: raw.clientSecret
139
+ });
140
+ const clientId = decrypted[idKey];
141
+ const clientSecret = decrypted[secretKey];
142
+ if (clientId && clientSecret) {
143
+ return {
144
+ clientId: String(clientId),
145
+ clientSecret: String(clientSecret)
146
+ };
147
+ }
148
+ } catch (error) {
149
+ logger.warn(`Failed to decrypt client credentials for ${appName}: ${error.message}`);
150
+ }
151
+ return null;
152
+ }
153
+
154
+ /**
155
+ * @param {string} appName
156
+ * @returns {Promise<{ clientId: string, clientSecret: string }|null>}
157
+ */
158
+ async function readClientCredentialsFromSecretsFileDecrypted(appName) {
159
+ const raw = readClientCredentialsFromSecretsFile(appName);
160
+ if (!raw) {
161
+ return null;
162
+ }
163
+ return decryptClientCredentialsFromSecrets(appName, raw);
164
+ }
165
+
166
+ /**
167
+ * @param {string} appName
168
+ * @returns {Promise<{ credentialApp: string, credentials: { clientId: string, clientSecret: string }|null }>}
169
+ */
170
+ async function resolveCredentialAppForDeployment(appName) {
171
+ const fromEnv = readClientCredentialsFromEnv();
172
+ if (fromEnv) {
173
+ return { credentialApp: appName, credentials: fromEnv };
174
+ }
175
+ for (const key of credentialAppKeysToTry(appName)) {
176
+ const fromFile = await readClientCredentialsFromSecretsFileDecrypted(key);
177
+ if (fromFile) {
178
+ return { credentialApp: key, credentials: fromFile };
179
+ }
180
+ }
181
+ return { credentialApp: appName, credentials: null };
182
+ }
183
+
184
+ /**
185
+ * @param {string} appName
186
+ * @returns {Promise<{ clientId: string, clientSecret: string }|null>}
187
+ */
188
+ async function loadClientCredentials(appName) {
189
+ if (!appName || typeof appName !== 'string') {
190
+ throw new Error('App name is required and must be a string');
191
+ }
192
+ const resolved = await resolveCredentialAppForDeployment(appName);
193
+ return resolved.credentials;
194
+ }
195
+
196
+ module.exports = {
197
+ DATAPLANE_APP_KEY,
198
+ validateDataplaneSecrets,
199
+ loadClientCredentials,
200
+ resolveCredentialAppForDeployment
201
+ };
@@ -39,6 +39,10 @@ function resetRefreshWarnedUrlsForTesting() {
39
39
  * @param {string} errorMessage - Full error message to log
40
40
  */
41
41
  function warnRefreshTokenExpiredOnce(controllerUrl, errorMessage) {
42
+ const { isSetupPlatformFlow } = require('../commands/setup-run-context');
43
+ if (isSetupPlatformFlow()) {
44
+ return;
45
+ }
42
46
  const key = (controllerUrl && typeof controllerUrl === 'string' && controllerUrl.trim())
43
47
  ? config.normalizeControllerUrl(controllerUrl)
44
48
  : '__no_url__';
@@ -72,6 +76,10 @@ function formatRefreshFailureMessage(errorMessage, controllerUrl) {
72
76
  * @param {string} errorMessage - Raw error message
73
77
  */
74
78
  function warnRefreshFailureOnce(controllerUrl, errorMessage) {
79
+ const { isSetupPlatformFlow } = require('../commands/setup-run-context');
80
+ if (isSetupPlatformFlow()) {
81
+ return;
82
+ }
75
83
  const key = (controllerUrl && typeof controllerUrl === 'string' && controllerUrl.trim())
76
84
  ? config.normalizeControllerUrl(controllerUrl)
77
85
  : '__no_url__';
@@ -79,11 +79,21 @@ async function callTokenApi(controllerUrl, credentials) {
79
79
  }
80
80
 
81
81
  const responseData = response.data;
82
- if (!responseData || !responseData.token) {
82
+ const token =
83
+ responseData?.token ||
84
+ responseData?.data?.token ||
85
+ responseData?.data?.data?.token ||
86
+ responseData?.accessToken;
87
+ if (!token) {
83
88
  throw new Error('Invalid response: missing token');
84
89
  }
85
90
 
86
- return responseData;
91
+ return {
92
+ ...responseData,
93
+ token,
94
+ expiresIn: responseData.expiresIn ?? responseData.data?.expiresIn,
95
+ expiresAt: responseData.expiresAt ?? responseData.data?.expiresAt
96
+ };
87
97
  }
88
98
 
89
99
  /**
@@ -9,99 +9,19 @@
9
9
  * @version 2.0.0
10
10
  */
11
11
 
12
- const fs = require('fs');
13
- const yaml = require('js-yaml');
14
12
  const config = require('../core/config');
15
13
  const logger = require('./logger');
16
- const pathsUtil = require('./paths');
17
14
  const {
18
15
  refreshClientToken,
19
16
  refreshDeviceToken
20
17
  } = require('./token-manager-refresh');
21
18
  const { warnRefreshFailureOnce, warnRefreshTokenExpiredOnce } = require('./token-manager-messages');
22
-
23
- /** App key used for dataplane client credentials in secrets.local.yaml */
24
- const DATAPLANE_APP_KEY = 'dataplane';
25
-
26
- function getSecretsFilePath() {
27
- return pathsUtil.getPrimaryUserSecretsLocalPath();
28
- }
29
-
30
- /**
31
- * Validate that secrets.local.yaml contains dataplane client credentials.
32
- * If missing, the developer should run: aifabrix app rotate-secret dataplane
33
- * @param {string} [secretsFilePath] - Path to secrets file; defaults to ~/.aifabrix/secrets.local.yaml
34
- * @returns {{ valid: boolean, hint?: string }}
35
- */
36
- function validateDataplaneSecrets(secretsFilePath) {
37
- const filePath = secretsFilePath || getSecretsFilePath();
38
- const hint = 'Dataplane credentials are missing. Run: aifabrix app rotate-secret dataplane';
39
- try {
40
- if (!fs.existsSync(filePath)) {
41
- return { valid: false, hint };
42
- }
43
- const content = fs.readFileSync(filePath, 'utf8');
44
- const secrets = yaml.load(content) || {};
45
- const clientIdKey = `${DATAPLANE_APP_KEY}-client-idKeyVault`;
46
- const clientSecretKey = `${DATAPLANE_APP_KEY}-client-secretKeyVault`;
47
- const hasId = secrets[clientIdKey] !== null && secrets[clientIdKey] !== undefined && String(secrets[clientIdKey]).trim() !== '';
48
- const hasSecret = secrets[clientSecretKey] !== null && secrets[clientSecretKey] !== undefined && String(secrets[clientSecretKey]).trim() !== '';
49
- if (hasId && hasSecret) {
50
- return { valid: true };
51
- }
52
- return { valid: false, hint };
53
- } catch {
54
- return { valid: false, hint };
55
- }
56
- }
57
-
58
- /**
59
- * Load client credentials from secrets.local.yaml or process.env (e.g. integration/hubspot-test/.env).
60
- * Reads secrets file using pattern: <app-name>-client-idKeyVault and <app-name>-client-secretKeyVault.
61
- * If not found, checks process.env.CLIENTID and process.env.CLIENTSECRET (set when .env is loaded).
62
- * @param {string} appName - Application name
63
- * @returns {Promise<{clientId: string, clientSecret: string}|null>} Credentials or null if not found
64
- */
65
- async function loadClientCredentials(appName) {
66
- if (!appName || typeof appName !== 'string') {
67
- throw new Error('App name is required and must be a string');
68
- }
69
-
70
- try {
71
- const secretsFile = getSecretsFilePath();
72
- if (fs.existsSync(secretsFile)) {
73
- const content = fs.readFileSync(secretsFile, 'utf8');
74
- const secrets = yaml.load(content) || {};
75
-
76
- const clientIdKey = `${appName}-client-idKeyVault`;
77
- const clientSecretKey = `${appName}-client-secretKeyVault`;
78
-
79
- const clientId = secrets[clientIdKey];
80
- const clientSecret = secrets[clientSecretKey];
81
-
82
- if (clientId && clientSecret) {
83
- return {
84
- clientId: String(clientId),
85
- clientSecret: String(clientSecret)
86
- };
87
- }
88
- }
89
- } catch (error) {
90
- logger.warn(`Failed to load credentials from secrets.local.yaml: ${error.message}`);
91
- }
92
-
93
- // Fallback: use CLIENTID/CLIENTSECRET from process.env (e.g. from integration/hubspot-test/.env)
94
- const envClientId = process.env.CLIENTID || process.env.CLIENT_ID;
95
- const envClientSecret = process.env.CLIENTSECRET || process.env.CLIENT_SECRET;
96
- if (envClientId && envClientSecret) {
97
- return {
98
- clientId: String(envClientId).trim(),
99
- clientSecret: String(envClientSecret).trim()
100
- };
101
- }
102
-
103
- return null;
104
- }
19
+ const {
20
+ DATAPLANE_APP_KEY,
21
+ validateDataplaneSecrets,
22
+ loadClientCredentials,
23
+ resolveCredentialAppForDeployment
24
+ } = require('./token-manager-client-credentials');
105
25
 
106
26
  /**
107
27
  * Get device token for controller
@@ -201,8 +121,12 @@ async function getOrRefreshDeviceToken(controllerUrl) {
201
121
  // Token needs refresh (expired or within 15 minutes of expiry)
202
122
  // Try to refresh if refresh token exists
203
123
  if (!tokenInfo.refreshToken) {
204
- // No refresh token available
205
- logger.warn('Access token expired and no refresh token available. Please login again using: aifabrix login');
124
+ const { isSetupPlatformFlow } = require('../commands/setup-run-context');
125
+ if (!isSetupPlatformFlow()) {
126
+ logger.warn(
127
+ 'Access token expired and no refresh token available. Please login again using: aifabrix login'
128
+ );
129
+ }
206
130
  return null;
207
131
  }
208
132
 
@@ -302,27 +226,34 @@ async function tryClientTokenAuth(environment, appName, controllerUrl) {
302
226
  * @returns {Promise<{type: 'bearer'|'client-token', token: string, controller: string}>} Auth config: bearer = user token, client-token = app token (x-client-token header)
303
227
  * @throws {Error} If no authentication method is available
304
228
  */
305
- async function getDeploymentAuth(controllerUrl, environment, appName) {
229
+ async function getDeploymentAuth(controllerUrl, environment, appName, options = {}) {
230
+ const { getDeploymentAuthMode, shouldUseDeviceTokenForDeployment } = require('./deployment-auth-mode');
306
231
  validateDeploymentAuthParams(controllerUrl, environment, appName);
232
+ const mode = getDeploymentAuthMode(options);
307
233
 
308
- // Priority 1: Try device token (for user-level audit)
309
- const deviceAuth = await tryDeviceTokenAuth(controllerUrl);
310
- if (deviceAuth) {
311
- return deviceAuth;
234
+ if (shouldUseDeviceTokenForDeployment(mode)) {
235
+ const deviceAuth = await tryDeviceTokenAuth(controllerUrl);
236
+ if (deviceAuth) {
237
+ return deviceAuth;
238
+ }
239
+ if (mode === 'device') {
240
+ throw new Error(
241
+ 'Device token required (AIFABRIX_DEPLOYMENT_AUTH=device). Run: aifabrix login'
242
+ );
243
+ }
312
244
  }
313
245
 
314
- // Priority 2: Try client token (application-level)
315
- const clientTokenAuth = await tryClientTokenAuth(environment, appName, controllerUrl);
246
+ const { credentialApp, credentials } = await resolveCredentialAppForDeployment(appName);
247
+
248
+ const clientTokenAuth = await tryClientTokenAuth(environment, credentialApp, controllerUrl);
316
249
  if (clientTokenAuth) {
317
250
  return clientTokenAuth;
318
251
  }
319
252
 
320
- // Priority 3: Exchange client credentials for a token (never return client-credentials for app endpoints)
321
- const credentials = await loadClientCredentials(appName);
322
- if (credentials && credentials.clientId && credentials.clientSecret) {
253
+ if (credentials?.clientId && credentials?.clientSecret) {
323
254
  try {
324
- const refreshed = await refreshClientToken(environment, appName, controllerUrl);
325
- if (refreshed && refreshed.token) {
255
+ const refreshed = await refreshClientToken(environment, credentialApp, controllerUrl);
256
+ if (refreshed?.token) {
326
257
  return {
327
258
  type: 'client-token',
328
259
  token: refreshed.token,
@@ -334,7 +265,11 @@ async function getDeploymentAuth(controllerUrl, environment, appName) {
334
265
  }
335
266
  }
336
267
 
337
- throw new Error(`No authentication method available. Run 'aifabrix login' for device token, or add credentials to ~/.aifabrix/secrets.local.yaml as '${appName}-client-idKeyVault' and '${appName}-client-secretKeyVault'`);
268
+ throw new Error(
269
+ 'No authentication method available. For CI: set AIFABRIX_DEPLOYMENT_AUTH=client-credentials and ' +
270
+ `MISO_CLIENTID/MISO_CLIENTSECRET in .env or '${credentialApp}-client-idKeyVault' in secrets.local.yaml. ` +
271
+ 'For interactive use: aifabrix login'
272
+ );
338
273
  }
339
274
 
340
275
  /**
@@ -451,19 +386,63 @@ async function getDeviceOnlyAuth(controllerUrl) {
451
386
  }
452
387
 
453
388
  /**
454
- * Ensures auth config has a Bearer token for Dataplane pipeline endpoints.
455
- * Dataplane pipeline (upload, validate, publish, test) accepts OAuth2 (Bearer) or API_KEY only;
456
- * client id/secret are rejected. Call this before invoking pipeline API functions.
389
+ * Ensures auth config has a token Dataplane pipeline endpoints accept (Bearer or x-client-token).
390
+ * Dataplane pipeline rejects raw client id/secret; use POST /api/v1/auth/token first.
391
+ * When {@link process.env.AIFABRIX_DEPLOYMENT_AUTH} is `client-credentials`, keep application
392
+ * `x-client-token` auth (do not substitute API_KEY).
457
393
  * @param {Object} authConfig - Authentication configuration (may have token, clientId, clientSecret)
458
394
  * @throws {Error} If authConfig has only client id/secret (no token)
459
395
  */
396
+ /**
397
+ * Lab bypass: records/search accepts Bearer API_KEY but rejects x-client-token on some stacks.
398
+ * @param {Object} authConfig
399
+ * @returns {Object}
400
+ */
401
+ function applyLabDataplaneApiKeyBearer(authConfig) {
402
+ const labKey = process.env.AIFABRIX_DATAPLANE_API_KEY || '';
403
+ if (!labKey) {
404
+ return authConfig;
405
+ }
406
+ authConfig.type = 'bearer';
407
+ authConfig.token = String(labKey);
408
+ return authConfig;
409
+ }
410
+
460
411
  function requireBearerForDataplanePipeline(authConfig) {
412
+ if (authConfig.type === 'client-token' && authConfig.token) {
413
+ return;
414
+ }
415
+
416
+ const preferAppClientToken =
417
+ String(process.env.AIFABRIX_DEPLOYMENT_AUTH || '').toLowerCase() === 'client-credentials';
418
+
419
+ if (!preferAppClientToken && process.env.API_KEY) {
420
+ const apiKey = String(process.env.API_KEY);
421
+ if (authConfig.type === 'bearer' && authConfig.token !== apiKey) {
422
+ authConfig.token = apiKey;
423
+ return;
424
+ }
425
+ if (authConfig.type === 'client-token') {
426
+ authConfig.type = 'bearer';
427
+ authConfig.token = apiKey;
428
+ return;
429
+ }
430
+ }
431
+
461
432
  if (authConfig.token) {
462
433
  return;
463
434
  }
435
+
436
+ if (!preferAppClientToken && process.env.API_KEY) {
437
+ authConfig.type = 'bearer';
438
+ authConfig.token = String(process.env.API_KEY);
439
+ return;
440
+ }
441
+
464
442
  if (authConfig.clientId || authConfig.clientSecret) {
465
443
  throw new Error(
466
- 'Dataplane pipeline endpoints require OAuth2 (Bearer token). Client id/secret are not accepted. Run "aifabrix login" to authenticate, then retry.'
444
+ 'Dataplane pipeline endpoints require OAuth2 (Bearer token) or x-client-token. ' +
445
+ 'Client id/secret are not accepted. Run "aifabrix login" to authenticate, then retry.'
467
446
  );
468
447
  }
469
448
  }
@@ -477,6 +456,7 @@ module.exports = {
477
456
  refreshClientToken,
478
457
  refreshDeviceToken,
479
458
  loadClientCredentials,
459
+ resolveCredentialAppForDeployment,
480
460
  getOrRefreshClientToken,
481
461
  getOrRefreshDeviceToken,
482
462
  forceRefreshDeviceToken,
@@ -484,5 +464,6 @@ module.exports = {
484
464
  getDeviceOnlyAuth,
485
465
  extractClientCredentials,
486
466
  requireBearerForDataplanePipeline,
467
+ applyLabDataplaneApiKeyBearer,
487
468
  validateDataplaneSecrets
488
469
  };