@aifabrix/builder 2.49.2 → 2.50.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 (409) hide show
  1. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
  2. package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
  3. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
  4. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
  5. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
  6. package/.cursor/skills/README.md +1 -0
  7. package/.dockerignore +52 -0
  8. package/.eslintignore +22 -0
  9. package/README.md +2 -0
  10. package/bin/builder-api-cleanup.js +26 -0
  11. package/bin/builder-api-nest.js +10 -0
  12. package/bin/builder-api-spike.js +19 -0
  13. package/enterprise-knowledge/README.md +50 -0
  14. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
  15. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
  16. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
  17. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
  18. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
  19. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
  20. package/integration/README.md +81 -0
  21. package/integration/github/README.md +53 -0
  22. package/integration/github/application.json +21 -0
  23. package/integration/github/deploy.js +72 -0
  24. package/integration/github/env.template +11 -0
  25. package/integration/github/github-datasource-issue-comments.json +239 -0
  26. package/integration/github/github-datasource-issues.json +399 -0
  27. package/integration/github/github-datasource-repository.json +354 -0
  28. package/integration/github/github-deploy.json +1202 -0
  29. package/integration/github/github-system.json +82 -0
  30. package/integration/hubspot-test/README.md +1 -1
  31. package/jest.isolated-projects.js +31 -1
  32. package/jest.projects.js +87 -1
  33. package/lib/api/dev-server-https.js +1 -1
  34. package/lib/api/enterprise-knowledge.api.js +63 -0
  35. package/lib/api/evidence.api.js +172 -0
  36. package/lib/api/external-systems.api.js +8 -2
  37. package/lib/api/resource-types.api.js +1 -0
  38. package/lib/api/types/enterprise-knowledge.types.js +46 -0
  39. package/lib/api/types/evidence.types.js +67 -0
  40. package/lib/api/types/resource-types.types.js +2 -0
  41. package/lib/app/controller-application-filter.js +36 -0
  42. package/lib/app/deploy.js +1 -1
  43. package/lib/app/list-external-systems.js +130 -0
  44. package/lib/app/list.js +20 -8
  45. package/lib/app/run.js +3 -1
  46. package/lib/app/show-display.js +8 -3
  47. package/lib/app/show-online.js +178 -0
  48. package/lib/app/show.js +37 -88
  49. package/lib/build/builder-api-docker-staging.js +47 -0
  50. package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
  51. package/lib/build/standard-docker-build.js +2 -0
  52. package/lib/certification/post-unified-cert-sync.js +4 -31
  53. package/lib/certification/sync-after-external-command.js +0 -1
  54. package/lib/certification/sync-system-certification.js +0 -3
  55. package/lib/channels/add-channel.js +40 -34
  56. package/lib/channels/approval-guides/chatgpt.js +33 -0
  57. package/lib/channels/approval-guides/credential-portal.js +38 -0
  58. package/lib/channels/approval-guides/index.js +110 -0
  59. package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
  60. package/lib/channels/approval-guides/slack.js +34 -0
  61. package/lib/channels/approval-guides/teams-bot.js +35 -0
  62. package/lib/channels/approval-guides/web-embed.js +32 -0
  63. package/lib/channels/channel-approval-guide.js +11 -0
  64. package/lib/channels/channel-artifact-generator.js +16 -4
  65. package/lib/channels/channel-audit.js +3 -0
  66. package/lib/channels/channel-auth-context.js +1 -1
  67. package/lib/channels/channel-description.js +59 -0
  68. package/lib/channels/channel-integration-generator.js +13 -230
  69. package/lib/channels/channel-integration-template.js +94 -0
  70. package/lib/channels/channel-runtime-resolver.js +43 -3
  71. package/lib/channels/channel-status-display.js +66 -26
  72. package/lib/channels/channel-targets.js +3 -3
  73. package/lib/cli/index.js +27 -3
  74. package/lib/cli/infra-guided.js +5 -1
  75. package/lib/cli/setup-app-external-create.js +111 -0
  76. package/lib/cli/setup-app.help.js +1 -1
  77. package/lib/cli/setup-app.js +38 -125
  78. package/lib/cli/setup-app.test-commands.js +26 -52
  79. package/lib/cli/setup-certification-commands.js +4 -4
  80. package/lib/cli/setup-certification.help.js +9 -9
  81. package/lib/cli/setup-dev.js +7 -2
  82. package/lib/cli/setup-external-system-help.js +4 -6
  83. package/lib/cli/setup-external-system.js +58 -52
  84. package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
  85. package/lib/cli/setup-infra-up-platform-action.js +3 -1
  86. package/lib/cli/setup-infra.js +15 -0
  87. package/lib/cli/setup-list.js +43 -0
  88. package/lib/cli/setup-utility-repair.js +26 -7
  89. package/lib/cli/setup-utility.js +5 -3
  90. package/lib/commands/app.js +15 -43
  91. package/lib/commands/channel-add-setup.js +110 -0
  92. package/lib/commands/channel.js +42 -8
  93. package/lib/commands/datasource-sync-display.js +96 -0
  94. package/lib/commands/datasource-sync-policy.js +210 -0
  95. package/lib/commands/datasource-test-trust-cli.js +6 -6
  96. package/lib/commands/datasource-unified-test-cli.js +2 -1
  97. package/lib/commands/datasource-unified-test-cli.options.js +33 -23
  98. package/lib/commands/deploy-gate-failure-details.js +163 -0
  99. package/lib/commands/deploy-gate-orchestrator.js +322 -0
  100. package/lib/commands/dev-cli-handlers.js +1 -59
  101. package/lib/commands/dev-host-ops-params.js +91 -0
  102. package/lib/commands/dev-host-ops-poll.js +111 -0
  103. package/lib/commands/dev-host-ops.js +107 -94
  104. package/lib/commands/dev-init.js +3 -1
  105. package/lib/commands/enterprise-knowledge.js +284 -0
  106. package/lib/commands/evidence-cli-leaves.js +250 -0
  107. package/lib/commands/evidence.js +51 -0
  108. package/lib/commands/governance-cli-shared.js +2 -2
  109. package/lib/commands/governance-command-action.js +2 -2
  110. package/lib/commands/governance-fixture-subjects.js +85 -0
  111. package/lib/commands/governance.js +1 -1
  112. package/lib/commands/lifecycle-command-action.js +2 -2
  113. package/lib/commands/lifecycle-external.js +3 -3
  114. package/lib/commands/manifest-cli-auth.js +29 -0
  115. package/lib/commands/manifest-cli-commands.js +170 -0
  116. package/lib/commands/manifest-cli-integration-path.js +63 -0
  117. package/lib/commands/manifest.js +21 -0
  118. package/lib/commands/protection-cli-leaves.js +3 -3
  119. package/lib/commands/repair-auth-apply.js +15 -1
  120. package/lib/commands/repair-authentications-454.js +169 -0
  121. package/lib/commands/repair-capability-openapi-warnings.js +126 -0
  122. package/lib/commands/repair-datasource-apply.js +135 -0
  123. package/lib/commands/repair-datasource-auto-rbac.js +62 -1
  124. package/lib/commands/repair-datasource-http-service-contract.js +239 -0
  125. package/lib/commands/repair-datasource-operation-security.js +180 -0
  126. package/lib/commands/repair-datasource-run.js +7 -2
  127. package/lib/commands/repair-datasource-sync-operations.js +177 -0
  128. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
  129. package/lib/commands/repair-datasource.js +12 -68
  130. package/lib/commands/repair-env-template.js +11 -1
  131. package/lib/commands/repair-external-run.js +121 -31
  132. package/lib/commands/repair-internal.js +1 -1
  133. package/lib/commands/repair-openapi-export.js +156 -0
  134. package/lib/commands/repair-openapi-sync.js +19 -2
  135. package/lib/commands/repair-orchestration-datasource-split.js +259 -0
  136. package/lib/commands/repair-persist.js +22 -1
  137. package/lib/commands/repair-rbac-platform-preset.js +204 -0
  138. package/lib/commands/repair-rbac-reader-roles.js +191 -0
  139. package/lib/commands/repair-rbac.js +163 -86
  140. package/lib/commands/repair-steps.js +83 -18
  141. package/lib/commands/repair-system-permissions.js +1 -0
  142. package/lib/commands/repair.js +1 -1
  143. package/lib/commands/resource-type.js +65 -26
  144. package/lib/commands/run-post-publish-data-sync.js +68 -0
  145. package/lib/commands/setup-modes.js +1 -1
  146. package/lib/commands/test-e2e-external.js +21 -8
  147. package/lib/commands/test-governance-cli-options.js +2 -2
  148. package/lib/commands/test-trust-cli-options.js +2 -2
  149. package/lib/commands/up-builder-api-bootstrap.js +71 -0
  150. package/lib/commands/up-builder-api-provision.js +241 -0
  151. package/lib/commands/up-builder-api.js +88 -0
  152. package/lib/commands/up-common.js +25 -1
  153. package/lib/commands/upload-credential-push-log.js +117 -0
  154. package/lib/commands/upload-data-sync-finalize.js +60 -0
  155. package/lib/commands/upload-probe.js +66 -0
  156. package/lib/commands/upload-publish-context.js +4 -1
  157. package/lib/commands/upload-sidecar-followups.js +55 -27
  158. package/lib/commands/upload.js +116 -157
  159. package/lib/commands/verify-governance-combined-external.js +1 -1
  160. package/lib/commands/verify-governance-db.js +2 -2
  161. package/lib/commands/verify-operations-command-action.js +2 -2
  162. package/lib/commands/verify-operations-step-plan.js +2 -2
  163. package/lib/commands/verify-operations-steps.js +2 -2
  164. package/lib/commands/verify-trust-command-action.js +1 -1
  165. package/lib/commands/wizard-core.js +1 -1
  166. package/lib/commands/wizard-headless.js +2 -1
  167. package/lib/core/admin-secrets.js +2 -6
  168. package/lib/core/secrets-env-content.js +10 -4
  169. package/lib/core/secrets-env-write.js +2 -13
  170. package/lib/datasource/agent-trust-run.js +3 -3
  171. package/lib/datasource/deploy.js +3 -1
  172. package/lib/datasource/test-e2e.js +6 -1
  173. package/lib/datasource/unified-validation-run-body.js +4 -1
  174. package/lib/datasource/unified-validation-run.js +1 -1
  175. package/lib/deployment/deploy-poll-ui.js +73 -12
  176. package/lib/deployment/deployer-poll-run.js +113 -0
  177. package/lib/deployment/deployer.js +17 -87
  178. package/lib/evidence/dataplane-context.js +21 -0
  179. package/lib/evidence/evidence-display.js +78 -0
  180. package/lib/evidence/evidence-service.js +392 -0
  181. package/lib/external-system/deploy.js +290 -112
  182. package/lib/external-system/download.js +7 -3
  183. package/lib/external-system/test-execution.js +1 -1
  184. package/lib/external-system/test-system-level.js +8 -10
  185. package/lib/external-system/test.js +12 -6
  186. package/lib/generator/deploy-script.js +73 -0
  187. package/lib/generator/external.js +2 -1
  188. package/lib/generator/index.js +17 -2
  189. package/lib/generator/wizard.js +3 -36
  190. package/lib/internal/fs-real-sync.js +22 -1
  191. package/lib/internal/node-fs.js +2 -0
  192. package/lib/lifecycle/lifecycle-governance-options.js +1 -1
  193. package/lib/lifecycle/verify-step-progress.js +1 -1
  194. package/lib/programmatic/access-log.js +26 -0
  195. package/lib/programmatic/auth-config.js +44 -0
  196. package/lib/programmatic/bearer-auth.js +176 -0
  197. package/lib/programmatic/builder-api-request.js +175 -0
  198. package/lib/programmatic/builder-api-route-dispatch.js +82 -0
  199. package/lib/programmatic/builder-api-runtime-config.js +42 -0
  200. package/lib/programmatic/builder-api-server.js +230 -0
  201. package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
  202. package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
  203. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
  204. package/lib/programmatic/builder-help-envelope.js +36 -0
  205. package/lib/programmatic/builder-help-fixtures.js +200 -0
  206. package/lib/programmatic/builder-help-governance.js +172 -0
  207. package/lib/programmatic/builder-help-schema-catalog.js +92 -0
  208. package/lib/programmatic/builder-help.js +361 -0
  209. package/lib/programmatic/capability-registry.js +77 -0
  210. package/lib/programmatic/command-options.js +32 -0
  211. package/lib/programmatic/enterprise-mcp-client.js +98 -0
  212. package/lib/programmatic/http-problem-details.js +99 -0
  213. package/lib/programmatic/http-route-match.js +40 -0
  214. package/lib/programmatic/idempotency-cache.js +69 -0
  215. package/lib/programmatic/index.js +53 -0
  216. package/lib/programmatic/integration-path-scope.js +39 -0
  217. package/lib/programmatic/log-redaction.js +66 -0
  218. package/lib/programmatic/manifest-get-section.js +146 -0
  219. package/lib/programmatic/manifest-patch-section.js +252 -0
  220. package/lib/programmatic/manifest-repair.js +122 -0
  221. package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
  222. package/lib/programmatic/manifest-section-io.js +225 -0
  223. package/lib/programmatic/manifest-section-quality.js +171 -0
  224. package/lib/programmatic/manifest-section-registry-data.js +269 -0
  225. package/lib/programmatic/manifest-section-registry.js +205 -0
  226. package/lib/programmatic/nest-http-bridge.js +34 -0
  227. package/lib/programmatic/openapi-component-schemas.js +68 -0
  228. package/lib/programmatic/openapi-description-enricher.js +117 -0
  229. package/lib/programmatic/openapi-descriptions.js +190 -0
  230. package/lib/programmatic/openapi-docs-serving.js +123 -0
  231. package/lib/programmatic/openapi-help-schemas.js +63 -0
  232. package/lib/programmatic/openapi-manifest-schemas.js +141 -0
  233. package/lib/programmatic/openapi-operation-bindings.js +274 -0
  234. package/lib/programmatic/openapi-request-schemas.js +155 -0
  235. package/lib/programmatic/openapi-result-schemas.js +476 -0
  236. package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
  237. package/lib/programmatic/openapi-schema-descriptions-core.js +159 -0
  238. package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
  239. package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
  240. package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
  241. package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
  242. package/lib/programmatic/openapi-schema-helpers.js +93 -0
  243. package/lib/programmatic/openapi-spec.js +203 -0
  244. package/lib/programmatic/orchestration-openapi-meta.js +159 -0
  245. package/lib/programmatic/platform-rbac-catalog.js +90 -0
  246. package/lib/programmatic/request-timeout.js +53 -0
  247. package/lib/programmatic/route-handler-map.js +143 -0
  248. package/lib/programmatic/route-handlers-context.js +29 -0
  249. package/lib/programmatic/route-handlers.js +33 -0
  250. package/lib/programmatic/run-certify.js +57 -0
  251. package/lib/programmatic/run-enterprise-mcp.js +32 -0
  252. package/lib/programmatic/run-lifecycle.js +29 -0
  253. package/lib/programmatic/run-repair.js +41 -0
  254. package/lib/programmatic/run-repository-emcp.js +54 -0
  255. package/lib/programmatic/run-template-workspace.js +61 -0
  256. package/lib/programmatic/run-test.js +49 -0
  257. package/lib/programmatic/run-upload.js +63 -0
  258. package/lib/programmatic/run-validate.js +53 -0
  259. package/lib/programmatic/run-wizard.js +40 -0
  260. package/lib/programmatic/system-key.js +48 -0
  261. package/lib/programmatic/wizard-config-normalize.js +118 -0
  262. package/lib/programmatic/workspace-cleanup.js +128 -0
  263. package/lib/programmatic/workspace-context.js +145 -0
  264. package/lib/programmatic/workspace-lock.js +75 -0
  265. package/lib/programmatic/workspace-meta.js +64 -0
  266. package/lib/programmatic/workspace-ops.js +149 -0
  267. package/lib/protection/run-commands-upload-sync.js +35 -0
  268. package/lib/protection/run-commands.js +2 -20
  269. package/lib/protection/upload-batch.js +11 -7
  270. package/lib/resolvers/resource-type-file.js +22 -0
  271. package/lib/schema/external-datasource.schema.json +161 -1
  272. package/lib/schema/external-system.schema.json +244 -118
  273. package/lib/schema/flag-map-validation-run.json +3 -0
  274. package/lib/schema/type/credential-field-registry.json +2 -2
  275. package/lib/schema/type/document-storage.json +9 -0
  276. package/lib/utils/agent-trust-run-display.js +1 -1
  277. package/lib/utils/app-path-resolve.js +168 -0
  278. package/lib/utils/authentication-env-template.js +222 -0
  279. package/lib/utils/cli-sync-options.js +7 -11
  280. package/lib/utils/cli-utils.js +4 -0
  281. package/lib/utils/cli-workspace-options.js +29 -0
  282. package/lib/utils/compose-generate-docker-compose.js +102 -0
  283. package/lib/utils/configuration-env-resolver.js +203 -27
  284. package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
  285. package/lib/utils/datasource-test-run-certification-debug.js +130 -0
  286. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  287. package/lib/utils/datasource-test-run-debug-slice.js +7 -0
  288. package/lib/utils/datasource-test-run-display.js +2 -1
  289. package/lib/utils/dev-init-ssh-merge.js +165 -23
  290. package/lib/utils/dev-pin-share-instructions.js +110 -0
  291. package/lib/utils/dev-ssh-config-helper.js +177 -33
  292. package/lib/utils/enterprise-knowledge-paths.js +142 -0
  293. package/lib/utils/env-copy.js +2 -1
  294. package/lib/utils/env-dotenv-format.js +103 -0
  295. package/lib/utils/external-env-template.js +4 -1
  296. package/lib/utils/external-system-display.js +5 -1
  297. package/lib/utils/external-system-readiness-compact-blocks.js +221 -0
  298. package/lib/utils/external-system-readiness-compact-display.js +324 -0
  299. package/lib/utils/external-system-readiness-core.js +16 -0
  300. package/lib/utils/external-system-readiness-deploy-display.js +29 -11
  301. package/lib/utils/external-system-readiness-display-internals.js +3 -1
  302. package/lib/utils/external-system-readiness-display.js +20 -30
  303. package/lib/utils/external-system-system-test-tty-certification.js +135 -0
  304. package/lib/utils/external-system-system-test-tty.js +5 -41
  305. package/lib/utils/help-builder.js +6 -1
  306. package/lib/utils/host-ops-job-labels.js +236 -0
  307. package/lib/utils/host-ops-job-result.js +61 -0
  308. package/lib/utils/host-ops-poll-ui.js +163 -0
  309. package/lib/utils/integration-path-resolve.js +112 -0
  310. package/lib/utils/paths-reload-source.js +148 -0
  311. package/lib/utils/paths-system-builder-keys.js +25 -0
  312. package/lib/utils/paths.js +151 -26
  313. package/lib/utils/runtime-configuration-values.js +64 -2
  314. package/lib/utils/secrets-helpers.js +5 -1
  315. package/lib/utils/ssh-known-hosts.js +130 -0
  316. package/lib/utils/test-target-cli-options.js +75 -0
  317. package/lib/utils/upload-sync-options.js +4 -0
  318. package/lib/utils/validation-run-request.js +11 -2
  319. package/lib/validation/external-manifest-validator.js +11 -1
  320. package/lib/validation/openapi-contract-surface-validator.js +426 -0
  321. package/lib/validation/openapi-contract-vendor-validation.js +238 -0
  322. package/lib/validation/validate-external-file.js +160 -0
  323. package/lib/validation/validate.js +6 -117
  324. package/package.json +46 -29
  325. package/packages/builder-api/README.md +120 -0
  326. package/packages/builder-api/package.json +30 -0
  327. package/packages/builder-api/src/app.module.ts +7 -0
  328. package/packages/builder-api/src/auth/auth.module.ts +5 -0
  329. package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
  330. package/packages/builder-api/src/main.ts +16 -0
  331. package/packages/builder-api/tsconfig.json +15 -0
  332. package/scripts/check-builder-api-architecture-grep.js +79 -0
  333. package/scripts/docker_image_content_gate.js +47 -0
  334. package/scripts/docker_image_content_gate.sh +5 -0
  335. package/scripts/export-builder-api-evidence.js +262 -0
  336. package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
  337. package/scripts/lib/builder-api-docker-staging-core.js +183 -0
  338. package/scripts/lib/docker-image-content-gate-core.js +166 -0
  339. package/scripts/lib/plan-actor.js +109 -0
  340. package/scripts/lib/plan-config.js +20 -0
  341. package/scripts/lib/plan-gates.js +154 -0
  342. package/scripts/lib/plan-meta.js +104 -0
  343. package/scripts/lib/plan-parse.js +162 -0
  344. package/scripts/lib/plan-prevalidate-gates.js +326 -0
  345. package/scripts/lib/plan-run-core.js +125 -0
  346. package/scripts/lib/plan-run-report.js +108 -0
  347. package/scripts/plan-approve.js +24 -0
  348. package/scripts/plan-archive.js +49 -0
  349. package/scripts/plan-run.js +13 -0
  350. package/scripts/plan-set-actor.js +21 -0
  351. package/scripts/plan-validate.js +80 -0
  352. package/scripts/pnpm/af.mjs +110 -0
  353. package/scripts/pnpm/check-quiet.mjs +32 -0
  354. package/scripts/pnpm/dev-install.mjs +29 -0
  355. package/scripts/pnpm/dev-reload.mjs +18 -0
  356. package/scripts/pnpm/help.mjs +55 -0
  357. package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
  358. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
  359. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
  360. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
  361. package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
  362. package/scripts/pnpm/lib/spinner.mjs +42 -0
  363. package/scripts/stage_builder_api_for_docker.js +65 -0
  364. package/scripts/sync-builder-api-template.js +44 -0
  365. package/templates/README.md +3 -0
  366. package/templates/applications/builder-api/Dockerfile +38 -0
  367. package/templates/applications/builder-api/application.yaml +75 -0
  368. package/templates/applications/builder-api/env.template +48 -0
  369. package/templates/applications/dataplane/application.yaml +1 -1
  370. package/templates/applications/dataplane/env.template +10 -6
  371. package/templates/applications/dataplane/rbac.yaml +21 -1
  372. package/templates/applications/miso-controller/application.yaml +1 -1
  373. package/templates/applications/miso-controller/env.template +1 -3
  374. package/templates/channels/README.md +18 -0
  375. package/templates/channels/ai-fabrix-icon.jpg +0 -0
  376. package/templates/channels/chatgpt/install.template.md.hbs +21 -24
  377. package/templates/channels/chatgpt/integration/README.md +11 -0
  378. package/templates/channels/chatgpt/integration/application.json +15 -0
  379. package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
  380. package/templates/channels/chatgpt/integration/env.template +4 -0
  381. package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
  382. package/templates/channels/microsoft-copilot/integration/README.md +11 -0
  383. package/templates/channels/microsoft-copilot/integration/application.json +15 -0
  384. package/templates/channels/microsoft-copilot/integration/env.template +6 -0
  385. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
  386. package/templates/channels/slack/install.template.md.hbs +48 -18
  387. package/templates/channels/slack/integration/README.md +38 -0
  388. package/templates/channels/slack/integration/application.json +18 -0
  389. package/templates/channels/slack/integration/env.template +29 -0
  390. package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
  391. package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
  392. package/templates/channels/slack/integration/slack-system.json +86 -0
  393. package/templates/channels/slack/manifest.template.json.hbs +20 -10
  394. package/templates/channels/teams-bot/install.template.md.hbs +31 -17
  395. package/templates/channels/teams-bot/integration/README.md +18 -0
  396. package/templates/channels/teams-bot/integration/application.json +17 -0
  397. package/templates/channels/teams-bot/integration/env.template +5 -0
  398. package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
  399. package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
  400. package/templates/channels/web-embed/install.template.md.hbs +16 -26
  401. package/templates/channels/web-embed/integration/README.md +11 -0
  402. package/templates/channels/web-embed/integration/application.json +15 -0
  403. package/templates/channels/web-embed/integration/env.template +4 -0
  404. package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
  405. package/templates/openapi/redoc_page.html +86 -0
  406. package/templates/python/docker-compose.hbs +11 -0
  407. package/templates/python/requirements.txt +1 -1
  408. package/templates/typescript/docker-compose.hbs +11 -0
  409. package/lib/certification/cli-cert-sync-skip.js +0 -21
@@ -0,0 +1,322 @@
1
+ /**
2
+ * @fileoverview Deploy pre-promote baseline tests and optional --gate steps (456.9).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const { sectionTitle } = require('../utils/cli-test-layout-chalk');
11
+ const logger = require('../utils/logger');
12
+ const { formatDeployGateFailure } = require('./deploy-gate-failure-details');
13
+ const { testExternalSystem, testExternalSystemIntegration } = require('../external-system/test');
14
+ const { runWithVerifyStepProgress } = require('../lifecycle/verify-step-progress');
15
+ const { runTestE2EForExternalSystem, syncLocalIfRequested, resolveExternalIntegrationContext } = require('./test-e2e-external');
16
+ const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
17
+ const { resolveE2eSyncModeWhenPopulated } = require('./datasource-sync-policy');
18
+ const { runVerifyTrustForExternalSystem } = require('./verify-trust-external');
19
+ const { runVerifyGovernanceForExternalSystem } = require('./verify-governance-external');
20
+ const { runGovernanceGenerateForExternalSystem } = require('./governance-generate-external');
21
+ const { resolveGovernanceFixtureSubjectEmails } = require('./governance-fixture-subjects');
22
+ const { runVerifyGovernanceCombined } = require('./verify-governance-combined-external');
23
+ const { VERDICT } = require('../lifecycle/product-model');
24
+
25
+ const KNOWN_GATES = ['operations', 'trust', 'governance'];
26
+
27
+ /**
28
+ * @param {string|undefined} gateRaw
29
+ * @returns {string[]}
30
+ */
31
+ function parseDeployGateTokens(gateRaw) {
32
+ if (!gateRaw || typeof gateRaw !== 'string') {
33
+ return [];
34
+ }
35
+ const tokens = gateRaw
36
+ .split(',')
37
+ .map((part) => part.trim().toLowerCase())
38
+ .filter(Boolean);
39
+ if (tokens.includes('full')) {
40
+ return [...KNOWN_GATES];
41
+ }
42
+ return tokens.filter((token) => KNOWN_GATES.includes(token));
43
+ }
44
+
45
+ /**
46
+ * Strict promote posture suggests full optional gates when caller requests profile resolution.
47
+ * @returns {string[]}
48
+ */
49
+ function resolveStrictPromoteGateProfile() {
50
+ const level = (process.env.TRUST_CUSTOMER_POLICY_LEVEL || 'standard').trim().toLowerCase();
51
+ if (level === 'strict') {
52
+ return [...KNOWN_GATES];
53
+ }
54
+ return [];
55
+ }
56
+
57
+ /**
58
+ * @param {string|undefined} gateRaw
59
+ * @param {Object} [options]
60
+ * @returns {Set<string>}
61
+ */
62
+ function resolveDeployGateSet(gateRaw, options = {}) {
63
+ const explicit = parseDeployGateTokens(gateRaw);
64
+ if (explicit.length > 0) {
65
+ return new Set(explicit);
66
+ }
67
+ if (options.useStrictPromoteProfile === true) {
68
+ return new Set(resolveStrictPromoteGateProfile());
69
+ }
70
+ return new Set();
71
+ }
72
+
73
+ /**
74
+ * @param {Object} options
75
+ * @param {Object|null|undefined} uploadCtx
76
+ * @returns {Object}
77
+ */
78
+ function mergeUploadAuthOptions(options, uploadCtx) {
79
+ if (!uploadCtx?.authConfig || !uploadCtx?.dataplaneUrl) {
80
+ return { ...options, noPublish: true, verbose: false };
81
+ }
82
+ return {
83
+ ...options,
84
+ noPublish: true,
85
+ verbose: false,
86
+ authConfig: uploadCtx.authConfig,
87
+ dataplaneUrl: uploadCtx.dataplaneUrl,
88
+ silentResolve: true
89
+ };
90
+ }
91
+
92
+ /**
93
+ * @async
94
+ * @param {string} label
95
+ * @param {Function} runner
96
+ * @param {Function} isOk
97
+ * @param {Object} [stepOptions]
98
+ */
99
+ async function runRequiredDeployStep(label, runner, isOk, stepOptions = {}) {
100
+ return runWithVerifyStepProgress(
101
+ label,
102
+ async() => {
103
+ const outcome = await runner();
104
+ if (!isOk(outcome)) {
105
+ const detail = formatDeployGateFailure(label, outcome);
106
+ logger.log(chalk.red(`✖ ${detail}`));
107
+ const err = new Error(`${label} failed: ${detail}`);
108
+ err.gateFailure = true;
109
+ throw err;
110
+ }
111
+ return outcome;
112
+ },
113
+ { json: false, quietProgress: stepOptions.quietDeployUi === true }
114
+ );
115
+ }
116
+
117
+ /**
118
+ * @async
119
+ * @param {string} systemKey
120
+ * @param {Object} options
121
+ * @returns {Promise<{ unitPassed: boolean, integrationPassed: boolean }>}
122
+ */
123
+ async function runDeployBaselineSteps(systemKey, options) {
124
+ await runRequiredDeployStep(
125
+ 'Running unit tests',
126
+ () => testExternalSystem(systemKey, { verbose: false }),
127
+ (result) => result.valid === true,
128
+ options
129
+ );
130
+
131
+ let stepOptions = { ...options, noPublish: true, verbose: false, uploadStatus: 'published' };
132
+ if (!cliOptsSkipPublish(options)) {
133
+ const uploadCtx = await syncLocalIfRequested(systemKey, {
134
+ ...options,
135
+ uploadStatus: 'published',
136
+ minimal: true,
137
+ suppressSummary: true
138
+ });
139
+ stepOptions = mergeUploadAuthOptions({ ...options, uploadStatus: 'published' }, uploadCtx);
140
+ }
141
+
142
+ await runRequiredDeployStep(
143
+ 'Running integration tests',
144
+ () => testExternalSystemIntegration(systemKey, stepOptions),
145
+ (result) => result.success === true,
146
+ options
147
+ );
148
+
149
+ return { unitPassed: true, integrationPassed: true };
150
+ }
151
+
152
+ /**
153
+ * @async
154
+ * @param {string} systemKey
155
+ * @param {Object} options
156
+ * @returns {Promise<Object>}
157
+ */
158
+ async function runOperationsGate(systemKey, options) {
159
+ let stepOptions = mergeUploadAuthOptions(options, null);
160
+ if (!stepOptions.dataplaneUrl || !stepOptions.authConfig) {
161
+ try {
162
+ const uploadCtx = await syncLocalIfRequested(systemKey, { ...options, noPublish: true });
163
+ stepOptions = mergeUploadAuthOptions(options, uploadCtx);
164
+ } catch {
165
+ stepOptions = mergeUploadAuthOptions(options, null);
166
+ }
167
+ }
168
+
169
+ let e2eSyncMode = options.syncMode;
170
+ if (!e2eSyncMode && stepOptions.dataplaneUrl && stepOptions.authConfig) {
171
+ try {
172
+ const { keys } = resolveExternalIntegrationContext(systemKey);
173
+ e2eSyncMode = await resolveE2eSyncModeWhenPopulated(
174
+ stepOptions.dataplaneUrl,
175
+ stepOptions.authConfig,
176
+ keys
177
+ );
178
+ } catch {
179
+ e2eSyncMode = 'auto';
180
+ }
181
+ }
182
+
183
+ await runRequiredDeployStep(
184
+ 'Running operations gate (E2E)',
185
+ () =>
186
+ runTestE2EForExternalSystem(systemKey, {
187
+ ...stepOptions,
188
+ env: options.env,
189
+ async: options.async !== false,
190
+ quietPollUi: true,
191
+ syncMode: e2eSyncMode || stepOptions.syncMode
192
+ }),
193
+ (result) => result.success === true,
194
+ options
195
+ );
196
+
197
+ return { pillar: 'operations', verdict: VERDICT.VERIFIED };
198
+ }
199
+
200
+ /**
201
+ * @async
202
+ * @param {string} systemKey
203
+ * @param {Object} options
204
+ * @returns {Promise<Object>}
205
+ */
206
+ async function runTrustGate(systemKey, options) {
207
+ const result = await runRequiredDeployStep(
208
+ 'Running trust gate',
209
+ () => runVerifyTrustForExternalSystem(systemKey, { ...options, noPublish: true }),
210
+ (outcome) => outcome.verdict === VERDICT.VERIFIED,
211
+ options
212
+ );
213
+ return {
214
+ pillar: 'trust',
215
+ verdict: result.verdict,
216
+ percent: result.aiTrustPercent ?? undefined
217
+ };
218
+ }
219
+
220
+ /**
221
+ * @param {Object} options
222
+ * @returns {boolean}
223
+ */
224
+ function governanceSubjectsProvided(options) {
225
+ return Boolean(options.subjectEmail);
226
+ }
227
+
228
+ /**
229
+ * @async
230
+ * @param {string} systemKey
231
+ * @param {Object} options
232
+ * @returns {Promise<Object>}
233
+ */
234
+ async function runGovernanceGate(systemKey, options) {
235
+ const gateOptions = { ...options, noPublish: true };
236
+ let runner;
237
+ if (governanceSubjectsProvided(gateOptions)) {
238
+ runner = () => runVerifyGovernanceCombined(systemKey, gateOptions);
239
+ } else {
240
+ const fixtureEmails = resolveGovernanceFixtureSubjectEmails(systemKey);
241
+ if (fixtureEmails.length > 0) {
242
+ runner = async() => {
243
+ await runGovernanceGenerateForExternalSystem(systemKey, {
244
+ ...gateOptions,
245
+ subjectEmails: fixtureEmails
246
+ });
247
+ return runVerifyGovernanceForExternalSystem(systemKey, gateOptions);
248
+ };
249
+ } else {
250
+ runner = () => runVerifyGovernanceForExternalSystem(systemKey, gateOptions);
251
+ }
252
+ }
253
+ const result = await runRequiredDeployStep(
254
+ 'Running governance gate',
255
+ runner,
256
+ (outcome) => outcome.verdict === VERDICT.VERIFIED,
257
+ options
258
+ );
259
+ const scenarios = result.enforcementScenarios || {};
260
+ return {
261
+ pillar: 'governance',
262
+ verdict: result.verdict,
263
+ scenariosPassed: scenarios.passed,
264
+ scenariosTotal: scenarios.total
265
+ };
266
+ }
267
+
268
+ /**
269
+ * @async
270
+ * @param {string} systemKey
271
+ * @param {Set<string>} gates
272
+ * @param {Object} options
273
+ * @returns {Promise<Object[]>}
274
+ */
275
+ async function runDeployOptionalGates(systemKey, gates, options) {
276
+ const outcomes = [];
277
+ if (gates.has('operations')) {
278
+ outcomes.push(await runOperationsGate(systemKey, options));
279
+ }
280
+ if (gates.has('trust')) {
281
+ outcomes.push(await runTrustGate(systemKey, options));
282
+ }
283
+ if (gates.has('governance')) {
284
+ outcomes.push(await runGovernanceGate(systemKey, options));
285
+ }
286
+ return outcomes;
287
+ }
288
+
289
+ /**
290
+ * Baseline validate + test + test-integration, then optional --gate steps before controller deploy.
291
+ * @async
292
+ * @param {string} systemKey
293
+ * @param {Object} [options]
294
+ * @returns {Promise<{ baseline: { unitPassed: boolean, integrationPassed: boolean }, gates: Object[] }>}
295
+ */
296
+ async function runDeployGateOrchestrator(systemKey, options = {}) {
297
+ const quiet = options.quietDeployUi === true || options.verbose !== true;
298
+ if (!quiet) {
299
+ logger.log('');
300
+ logger.log(sectionTitle('Deploy preflight'));
301
+ }
302
+ const baseline = await runDeployBaselineSteps(systemKey, { ...options, quietDeployUi: quiet });
303
+ const gates = resolveDeployGateSet(options.gate, options);
304
+ if (gates.size === 0) {
305
+ return { baseline, gates: [] };
306
+ }
307
+ const gateOutcomes = await runDeployOptionalGates(systemKey, gates, {
308
+ ...options,
309
+ quietDeployUi: quiet
310
+ });
311
+ return { baseline, gates: gateOutcomes };
312
+ }
313
+
314
+ module.exports = {
315
+ KNOWN_GATES,
316
+ parseDeployGateTokens,
317
+ resolveStrictPromoteGateProfile,
318
+ resolveDeployGateSet,
319
+ runDeployBaselineSteps,
320
+ runDeployOptionalGates,
321
+ runDeployGateOrchestrator
322
+ };
@@ -17,6 +17,7 @@ const {
17
17
  augmentDevUserGroupsServerError
18
18
  } = require('../utils/dev-user-groups');
19
19
  const { handleProvisionDevUser, handleRemoveDevUser } = require('./dev-host-ops');
20
+ const { logDevPinShareInstructions } = require('../utils/dev-pin-share-instructions');
20
21
 
21
22
  const REMOTE_NOT_CONFIGURED_MSG = 'Remote server is not configured. Set remote-server and run "aifabrix dev init" first.';
22
23
 
@@ -149,64 +150,6 @@ async function handleDevUpdate(developerId, options) {
149
150
  }
150
151
  }
151
152
 
152
- function logPinHostsVariantLines(baseInit, id, hostsIp) {
153
- logger.log(
154
- chalk.cyan('2) Hosts file / administrator')
155
- + chalk.gray(
156
- ' — use when the hostname does not resolve and your organisation does not publish DNS for it. '
157
- + 'Run in an elevated terminal so the hosts file can be updated, or add the entry manually:'
158
- )
159
- );
160
- if (hostsIp) {
161
- logger.log(` ${baseInit} --add-hosts --hosts-ip ${hostsIp}`);
162
- } else {
163
- logger.log(` ${baseInit} --add-hosts --hosts-ip <server-LAN-IPv4>`);
164
- logger.log(
165
- chalk.gray(
166
- ` Replace <server-LAN-IPv4> with the Builder Server IPv4, or re-run: aifabrix dev pin ${id} --hosts-ip <ip>`
167
- )
168
- );
169
- }
170
- }
171
-
172
- /**
173
- * Log copy-paste dev init commands for the developer (standard vs hosts-file).
174
- * @param {Object} p
175
- * @param {string} p.id - Developer ID
176
- * @param {string} p.serverUrl - Builder Server base URL
177
- * @param {string} p.pin - One-time PIN
178
- * @param {string} p.expiresAt - PIN expiry (API string)
179
- * @param {string} [p.hostsIp] - Optional IPv4 for the hosts variant
180
- * @returns {void}
181
- */
182
- function logDevPinShareInstructions(p) {
183
- const { id, serverUrl, pin, expiresAt, hostsIp } = p;
184
- const baseInit = `aifabrix dev init --developer-id ${id} --server ${serverUrl} --pin ${pin}`;
185
- const pinOnly = `aifabrix dev init --pin ${pin}`;
186
- logger.log(formatSuccessLine(`PIN created for ${id}, expires ${expiresAt}.`));
187
- logger.log('');
188
- logger.log(
189
- chalk.bold('Share with the developer — they run one command (the PIN is one-time):')
190
- );
191
- logger.log('');
192
- logger.log(
193
- chalk.cyan('1) Standard')
194
- + chalk.gray(' — use when this machine can resolve the server hostname (DNS or hosts already set):')
195
- );
196
- logger.log(` ${baseInit}`);
197
- logger.log('');
198
- logPinHostsVariantLines(baseInit, id, hostsIp);
199
- logger.log('');
200
- logger.log(
201
- chalk.cyan('3) Config already has remote-server + developer-id')
202
- + chalk.gray(
203
- ' — e.g. second machine / SSH session after settings were merged; same onboarding, PIN only:'
204
- )
205
- );
206
- logger.log(` ${pinOnly}`);
207
- logger.log('');
208
- }
209
-
210
153
  /**
211
154
  * Handle dev pin – create/regenerate PIN (remote only).
212
155
  * @param {string} [developerId] - Developer ID (optional; uses config if omitted)
@@ -294,7 +237,6 @@ async function handleDevDelete(developerId, options = {}) {
294
237
  }
295
238
  }
296
239
  await handleRemoveDevUser(id, { ...options, developerId: id });
297
- logger.log(formatSuccessLine(`Developer ${id} removal queued and completed.`));
298
240
  }
299
241
 
300
242
  module.exports = {
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @fileoverview Map Commander options to host-ops job params
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ /**
8
+ * @param {Object} options
9
+ * @param {string[]} keys
10
+ * @returns {string|undefined}
11
+ */
12
+ function firstOption(options, ...keys) {
13
+ for (const key of keys) {
14
+ const value = options[key];
15
+ if (value !== undefined && value !== null && value !== '') {
16
+ return value;
17
+ }
18
+ }
19
+ return undefined;
20
+ }
21
+
22
+ /**
23
+ * @param {Object} params
24
+ * @param {Object} options
25
+ * @param {Array<[string, ...string[]]>} mappings
26
+ */
27
+ function assignStringParams(params, options, mappings) {
28
+ for (const [paramKey, ...optionKeys] of mappings) {
29
+ const value = firstOption(options, ...optionKeys);
30
+ if (value !== undefined) {
31
+ params[paramKey] = value;
32
+ }
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @param {Object} params
38
+ * @param {Object} options
39
+ * @param {Array<[string, ...string[]]>} mappings
40
+ */
41
+ function assignFlagParams(params, options, mappings) {
42
+ for (const [paramKey, ...optionKeys] of mappings) {
43
+ if (optionKeys.some((k) => Boolean(options[k]))) {
44
+ params[paramKey] = true;
45
+ }
46
+ }
47
+ }
48
+
49
+ const STRING_PARAM_MAPPINGS = [
50
+ ['include', 'include'],
51
+ ['exclude', 'exclude'],
52
+ ['builderVersion', 'builderVersion', 'builder-version'],
53
+ ['adminEmail', 'adminEmail', 'admin-email'],
54
+ ['adminPassword', 'adminPassword', 'admin-password'],
55
+ ['platform', 'platform'],
56
+ ['installation', 'installation']
57
+ ];
58
+
59
+ const FLAG_PARAM_MAPPINGS = [
60
+ ['skipCert', 'skipCert', 'skip-cert'],
61
+ ['skipPlatform', 'skipPlatform', 'skip-platform'],
62
+ ['skipCli', 'skipCli', 'skip-cli'],
63
+ ['check', 'check'],
64
+ ['failOnBlocked', 'failOnBlocked']
65
+ ];
66
+
67
+ /**
68
+ * Build job params from Commander options.
69
+ * @param {Object} options
70
+ * @param {string} [developerId]
71
+ * @returns {Object}
72
+ */
73
+ function buildJobParams(options, developerId) {
74
+ const params = {};
75
+ const id = developerId || firstOption(options, 'developerId', 'developer-id');
76
+ if (id) {
77
+ params.developerId = String(id).trim();
78
+ }
79
+ assignStringParams(params, options, STRING_PARAM_MAPPINGS);
80
+ assignFlagParams(params, options, FLAG_PARAM_MAPPINGS);
81
+ const timeoutMinutes = firstOption(options, 'timeoutMinutes', 'timeout-minutes');
82
+ if (timeoutMinutes) {
83
+ params.timeoutMinutes = parseInt(timeoutMinutes, 10);
84
+ }
85
+ return params;
86
+ }
87
+
88
+ module.exports = {
89
+ buildJobParams,
90
+ firstOption
91
+ };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @fileoverview Host-ops job polling loop
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ const hostOpsApi = require('../api/host-ops.api');
8
+ const { assertHostOpsJobSucceeded } = require('../utils/host-ops-job-result');
9
+
10
+ const POLL_INTERVAL_MS = 3000;
11
+ const POLL_TIMEOUT_MS = 3 * 60 * 60 * 1000;
12
+ const TRANSIENT_HTTP_STATUSES = new Set([502, 503, 504]);
13
+ /** Allow ~3 min of consecutive gateway errors (container restart during remove-dev-user). */
14
+ const MAX_TRANSIENT_POLL_ERRORS = 60;
15
+
16
+ function sleep(ms) {
17
+ return new Promise((resolve) => setTimeout(resolve, ms));
18
+ }
19
+
20
+ /**
21
+ * @param {Error} err
22
+ * @returns {boolean}
23
+ */
24
+ function isTransientHostOpsPollError(err) {
25
+ return Boolean(err && TRANSIENT_HTTP_STATUSES.has(err.status));
26
+ }
27
+
28
+ /**
29
+ * @param {Error} err
30
+ * @param {string} jobId
31
+ * @returns {Error}
32
+ */
33
+ function enhanceTransientHostOpsPollError(err, jobId) {
34
+ const status = err && err.status;
35
+ const base =
36
+ status === 502
37
+ ? 'Builder server returned Bad Gateway while waiting for the host job.'
38
+ : `Builder server returned HTTP ${status} while waiting for the host job.`;
39
+ const hint =
40
+ 'The job may still be running on the host (common during platform teardown or container restart). ' +
41
+ 'Wait 1–2 minutes, then run "aifabrix dev list" to verify. ' +
42
+ `Job id: ${jobId}`;
43
+ return new Error(`${base} ${hint}`);
44
+ }
45
+
46
+ /**
47
+ * @param {Object} auth
48
+ * @param {string} jobId
49
+ * @param {Object} pollUi
50
+ * @returns {Promise<Object>}
51
+ */
52
+ async function fetchHostOpsJobWithRetry(auth, jobId, pollUi) {
53
+ const started = Date.now();
54
+ for (let attempt = 0; attempt <= MAX_TRANSIENT_POLL_ERRORS; attempt += 1) {
55
+ try {
56
+ return await hostOpsApi.getHostOpsJob(
57
+ auth.serverUrl,
58
+ auth.clientCertPem,
59
+ jobId,
60
+ auth.serverCaPem || undefined
61
+ );
62
+ } catch (err) {
63
+ if (!isTransientHostOpsPollError(err)) {
64
+ throw err;
65
+ }
66
+ if (attempt >= MAX_TRANSIENT_POLL_ERRORS) {
67
+ throw enhanceTransientHostOpsPollError(err, jobId);
68
+ }
69
+ if (pollUi && typeof pollUi.onTransientError === 'function') {
70
+ pollUi.onTransientError(err, Date.now() - started);
71
+ }
72
+ await sleep(POLL_INTERVAL_MS);
73
+ }
74
+ }
75
+ throw new Error(`Failed to fetch host-ops job ${jobId} after transient retries`);
76
+ }
77
+
78
+ /**
79
+ * @param {Object} auth
80
+ * @param {string} jobId
81
+ * @param {Object} pollUi
82
+ * @param {boolean} json
83
+ * @returns {Promise<Object>}
84
+ */
85
+ async function pollHostOpsJobUntilTerminal(auth, jobId, pollUi, json) {
86
+ const started = Date.now();
87
+ while (Date.now() - started < POLL_TIMEOUT_MS) {
88
+ const job = await fetchHostOpsJobWithRetry(auth, jobId, pollUi);
89
+ if (!json) {
90
+ pollUi.onPollProgress(job.status);
91
+ }
92
+ if (job.status === 'failed') {
93
+ throw new Error(job.error || `Host-ops job ${jobId} failed`);
94
+ }
95
+ if (job.status === 'completed') {
96
+ assertHostOpsJobSucceeded(job);
97
+ return job;
98
+ }
99
+ await sleep(POLL_INTERVAL_MS);
100
+ }
101
+ throw new Error(`Timed out waiting for host-ops job ${jobId}`);
102
+ }
103
+
104
+ module.exports = {
105
+ POLL_INTERVAL_MS,
106
+ POLL_TIMEOUT_MS,
107
+ isTransientHostOpsPollError,
108
+ enhanceTransientHostOpsPollError,
109
+ fetchHostOpsJobWithRetry,
110
+ pollHostOpsJobUntilTerminal
111
+ };