@aifabrix/builder 2.49.1 → 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 (413) hide show
  1. package/.cursor/process/README.md +9 -0
  2. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
  3. package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
  4. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
  5. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
  6. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
  7. package/.cursor/skills/README.md +1 -0
  8. package/.dockerignore +52 -0
  9. package/.eslintignore +22 -0
  10. package/README.md +2 -0
  11. package/bin/builder-api-cleanup.js +26 -0
  12. package/bin/builder-api-nest.js +10 -0
  13. package/bin/builder-api-spike.js +19 -0
  14. package/enterprise-knowledge/README.md +50 -0
  15. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
  16. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
  17. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
  18. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
  19. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
  20. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
  21. package/integration/README.md +81 -0
  22. package/integration/github/README.md +53 -0
  23. package/integration/github/application.json +21 -0
  24. package/integration/github/deploy.js +72 -0
  25. package/integration/github/env.template +11 -0
  26. package/integration/github/github-datasource-issue-comments.json +239 -0
  27. package/integration/github/github-datasource-issues.json +399 -0
  28. package/integration/github/github-datasource-repository.json +354 -0
  29. package/integration/github/github-deploy.json +1202 -0
  30. package/integration/github/github-system.json +82 -0
  31. package/integration/hubspot-test/README.md +1 -1
  32. package/jest.isolated-projects.js +31 -1
  33. package/jest.projects.js +87 -1
  34. package/lib/api/dev-server-https.js +1 -1
  35. package/lib/api/dev.api.js +1 -0
  36. package/lib/api/enterprise-knowledge.api.js +63 -0
  37. package/lib/api/evidence.api.js +172 -0
  38. package/lib/api/external-systems.api.js +8 -2
  39. package/lib/api/host-ops.api.js +69 -0
  40. package/lib/api/resource-types.api.js +1 -0
  41. package/lib/api/types/enterprise-knowledge.types.js +46 -0
  42. package/lib/api/types/evidence.types.js +67 -0
  43. package/lib/api/types/resource-types.types.js +2 -0
  44. package/lib/app/controller-application-filter.js +36 -0
  45. package/lib/app/deploy.js +1 -1
  46. package/lib/app/list-external-systems.js +130 -0
  47. package/lib/app/list.js +20 -8
  48. package/lib/app/run.js +3 -1
  49. package/lib/app/show-display.js +8 -3
  50. package/lib/app/show-online.js +178 -0
  51. package/lib/app/show.js +37 -88
  52. package/lib/build/builder-api-docker-staging.js +47 -0
  53. package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
  54. package/lib/build/standard-docker-build.js +2 -0
  55. package/lib/certification/post-unified-cert-sync.js +4 -31
  56. package/lib/certification/sync-after-external-command.js +0 -1
  57. package/lib/certification/sync-system-certification.js +0 -3
  58. package/lib/channels/add-channel.js +40 -34
  59. package/lib/channels/approval-guides/chatgpt.js +33 -0
  60. package/lib/channels/approval-guides/credential-portal.js +38 -0
  61. package/lib/channels/approval-guides/index.js +110 -0
  62. package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
  63. package/lib/channels/approval-guides/slack.js +34 -0
  64. package/lib/channels/approval-guides/teams-bot.js +35 -0
  65. package/lib/channels/approval-guides/web-embed.js +32 -0
  66. package/lib/channels/channel-approval-guide.js +11 -0
  67. package/lib/channels/channel-artifact-generator.js +16 -4
  68. package/lib/channels/channel-audit.js +3 -0
  69. package/lib/channels/channel-auth-context.js +1 -1
  70. package/lib/channels/channel-description.js +59 -0
  71. package/lib/channels/channel-integration-generator.js +13 -230
  72. package/lib/channels/channel-integration-template.js +94 -0
  73. package/lib/channels/channel-runtime-resolver.js +43 -3
  74. package/lib/channels/channel-status-display.js +66 -26
  75. package/lib/channels/channel-targets.js +3 -3
  76. package/lib/cli/index.js +27 -3
  77. package/lib/cli/infra-guided.js +5 -1
  78. package/lib/cli/setup-app-external-create.js +111 -0
  79. package/lib/cli/setup-app.help.js +1 -1
  80. package/lib/cli/setup-app.js +38 -125
  81. package/lib/cli/setup-app.test-commands.js +26 -52
  82. package/lib/cli/setup-certification-commands.js +4 -4
  83. package/lib/cli/setup-certification.help.js +9 -9
  84. package/lib/cli/setup-dev-path-commands.js +24 -0
  85. package/lib/cli/setup-dev.js +115 -16
  86. package/lib/cli/setup-external-system-help.js +4 -6
  87. package/lib/cli/setup-external-system.js +58 -52
  88. package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
  89. package/lib/cli/setup-infra-up-platform-action.js +3 -1
  90. package/lib/cli/setup-infra.js +15 -0
  91. package/lib/cli/setup-list.js +43 -0
  92. package/lib/cli/setup-utility-repair.js +26 -7
  93. package/lib/cli/setup-utility.js +5 -3
  94. package/lib/commands/app.js +15 -43
  95. package/lib/commands/channel-add-setup.js +110 -0
  96. package/lib/commands/channel.js +42 -8
  97. package/lib/commands/datasource-sync-display.js +96 -0
  98. package/lib/commands/datasource-sync-policy.js +210 -0
  99. package/lib/commands/datasource-test-trust-cli.js +6 -6
  100. package/lib/commands/datasource-unified-test-cli.js +2 -1
  101. package/lib/commands/datasource-unified-test-cli.options.js +33 -23
  102. package/lib/commands/deploy-gate-failure-details.js +163 -0
  103. package/lib/commands/deploy-gate-orchestrator.js +322 -0
  104. package/lib/commands/dev-cli-handlers.js +64 -61
  105. package/lib/commands/dev-host-ops-params.js +91 -0
  106. package/lib/commands/dev-host-ops-poll.js +111 -0
  107. package/lib/commands/dev-host-ops.js +252 -0
  108. package/lib/commands/dev-init.js +3 -1
  109. package/lib/commands/enterprise-knowledge.js +284 -0
  110. package/lib/commands/evidence-cli-leaves.js +250 -0
  111. package/lib/commands/evidence.js +51 -0
  112. package/lib/commands/governance-cli-shared.js +2 -2
  113. package/lib/commands/governance-command-action.js +2 -2
  114. package/lib/commands/governance-fixture-subjects.js +85 -0
  115. package/lib/commands/governance.js +1 -1
  116. package/lib/commands/lifecycle-command-action.js +2 -2
  117. package/lib/commands/lifecycle-external.js +3 -3
  118. package/lib/commands/manifest-cli-auth.js +29 -0
  119. package/lib/commands/manifest-cli-commands.js +170 -0
  120. package/lib/commands/manifest-cli-integration-path.js +63 -0
  121. package/lib/commands/manifest.js +21 -0
  122. package/lib/commands/protection-cli-leaves.js +3 -3
  123. package/lib/commands/repair-auth-apply.js +15 -1
  124. package/lib/commands/repair-authentications-454.js +169 -0
  125. package/lib/commands/repair-capability-openapi-warnings.js +126 -0
  126. package/lib/commands/repair-datasource-apply.js +135 -0
  127. package/lib/commands/repair-datasource-auto-rbac.js +62 -1
  128. package/lib/commands/repair-datasource-http-service-contract.js +239 -0
  129. package/lib/commands/repair-datasource-operation-security.js +180 -0
  130. package/lib/commands/repair-datasource-run.js +7 -2
  131. package/lib/commands/repair-datasource-sync-operations.js +177 -0
  132. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
  133. package/lib/commands/repair-datasource.js +12 -68
  134. package/lib/commands/repair-env-template.js +11 -1
  135. package/lib/commands/repair-external-run.js +121 -31
  136. package/lib/commands/repair-internal.js +1 -1
  137. package/lib/commands/repair-openapi-export.js +156 -0
  138. package/lib/commands/repair-openapi-sync.js +19 -2
  139. package/lib/commands/repair-orchestration-datasource-split.js +259 -0
  140. package/lib/commands/repair-persist.js +22 -1
  141. package/lib/commands/repair-rbac-platform-preset.js +204 -0
  142. package/lib/commands/repair-rbac-reader-roles.js +191 -0
  143. package/lib/commands/repair-rbac.js +163 -86
  144. package/lib/commands/repair-steps.js +83 -18
  145. package/lib/commands/repair-system-permissions.js +1 -0
  146. package/lib/commands/repair.js +1 -1
  147. package/lib/commands/resource-type.js +65 -26
  148. package/lib/commands/run-post-publish-data-sync.js +68 -0
  149. package/lib/commands/setup-modes.js +1 -1
  150. package/lib/commands/test-e2e-external.js +21 -8
  151. package/lib/commands/test-governance-cli-options.js +2 -2
  152. package/lib/commands/test-trust-cli-options.js +2 -2
  153. package/lib/commands/up-builder-api-bootstrap.js +71 -0
  154. package/lib/commands/up-builder-api-provision.js +241 -0
  155. package/lib/commands/up-builder-api.js +88 -0
  156. package/lib/commands/up-common.js +25 -1
  157. package/lib/commands/upload-credential-push-log.js +117 -0
  158. package/lib/commands/upload-data-sync-finalize.js +60 -0
  159. package/lib/commands/upload-probe.js +66 -0
  160. package/lib/commands/upload-publish-context.js +4 -1
  161. package/lib/commands/upload-sidecar-followups.js +55 -27
  162. package/lib/commands/upload.js +116 -157
  163. package/lib/commands/verify-governance-combined-external.js +1 -1
  164. package/lib/commands/verify-governance-db.js +2 -2
  165. package/lib/commands/verify-operations-command-action.js +2 -2
  166. package/lib/commands/verify-operations-step-plan.js +2 -2
  167. package/lib/commands/verify-operations-steps.js +2 -2
  168. package/lib/commands/verify-trust-command-action.js +1 -1
  169. package/lib/commands/wizard-core.js +1 -1
  170. package/lib/commands/wizard-headless.js +2 -1
  171. package/lib/core/admin-secrets.js +2 -6
  172. package/lib/core/secrets-env-content.js +10 -4
  173. package/lib/core/secrets-env-write.js +2 -13
  174. package/lib/datasource/agent-trust-run.js +3 -3
  175. package/lib/datasource/deploy.js +3 -1
  176. package/lib/datasource/test-e2e.js +6 -1
  177. package/lib/datasource/unified-validation-run-body.js +4 -1
  178. package/lib/datasource/unified-validation-run.js +1 -1
  179. package/lib/deployment/deploy-poll-ui.js +73 -12
  180. package/lib/deployment/deployer-poll-run.js +113 -0
  181. package/lib/deployment/deployer.js +17 -87
  182. package/lib/evidence/dataplane-context.js +21 -0
  183. package/lib/evidence/evidence-display.js +78 -0
  184. package/lib/evidence/evidence-service.js +392 -0
  185. package/lib/external-system/deploy.js +290 -112
  186. package/lib/external-system/download.js +7 -3
  187. package/lib/external-system/test-execution.js +1 -1
  188. package/lib/external-system/test-system-level.js +8 -10
  189. package/lib/external-system/test.js +12 -6
  190. package/lib/generator/deploy-script.js +73 -0
  191. package/lib/generator/external.js +2 -1
  192. package/lib/generator/index.js +17 -2
  193. package/lib/generator/wizard.js +3 -36
  194. package/lib/internal/fs-real-sync.js +22 -1
  195. package/lib/internal/node-fs.js +2 -0
  196. package/lib/lifecycle/lifecycle-governance-options.js +1 -1
  197. package/lib/lifecycle/verify-step-progress.js +1 -1
  198. package/lib/programmatic/access-log.js +26 -0
  199. package/lib/programmatic/auth-config.js +44 -0
  200. package/lib/programmatic/bearer-auth.js +176 -0
  201. package/lib/programmatic/builder-api-request.js +175 -0
  202. package/lib/programmatic/builder-api-route-dispatch.js +82 -0
  203. package/lib/programmatic/builder-api-runtime-config.js +42 -0
  204. package/lib/programmatic/builder-api-server.js +230 -0
  205. package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
  206. package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
  207. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
  208. package/lib/programmatic/builder-help-envelope.js +36 -0
  209. package/lib/programmatic/builder-help-fixtures.js +200 -0
  210. package/lib/programmatic/builder-help-governance.js +172 -0
  211. package/lib/programmatic/builder-help-schema-catalog.js +92 -0
  212. package/lib/programmatic/builder-help.js +361 -0
  213. package/lib/programmatic/capability-registry.js +77 -0
  214. package/lib/programmatic/command-options.js +32 -0
  215. package/lib/programmatic/enterprise-mcp-client.js +98 -0
  216. package/lib/programmatic/http-problem-details.js +99 -0
  217. package/lib/programmatic/http-route-match.js +40 -0
  218. package/lib/programmatic/idempotency-cache.js +69 -0
  219. package/lib/programmatic/index.js +53 -0
  220. package/lib/programmatic/integration-path-scope.js +39 -0
  221. package/lib/programmatic/log-redaction.js +66 -0
  222. package/lib/programmatic/manifest-get-section.js +146 -0
  223. package/lib/programmatic/manifest-patch-section.js +252 -0
  224. package/lib/programmatic/manifest-repair.js +122 -0
  225. package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
  226. package/lib/programmatic/manifest-section-io.js +225 -0
  227. package/lib/programmatic/manifest-section-quality.js +171 -0
  228. package/lib/programmatic/manifest-section-registry-data.js +269 -0
  229. package/lib/programmatic/manifest-section-registry.js +205 -0
  230. package/lib/programmatic/nest-http-bridge.js +34 -0
  231. package/lib/programmatic/openapi-component-schemas.js +68 -0
  232. package/lib/programmatic/openapi-description-enricher.js +117 -0
  233. package/lib/programmatic/openapi-descriptions.js +190 -0
  234. package/lib/programmatic/openapi-docs-serving.js +123 -0
  235. package/lib/programmatic/openapi-help-schemas.js +63 -0
  236. package/lib/programmatic/openapi-manifest-schemas.js +141 -0
  237. package/lib/programmatic/openapi-operation-bindings.js +274 -0
  238. package/lib/programmatic/openapi-request-schemas.js +155 -0
  239. package/lib/programmatic/openapi-result-schemas.js +476 -0
  240. package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
  241. package/lib/programmatic/openapi-schema-descriptions-core.js +159 -0
  242. package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
  243. package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
  244. package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
  245. package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
  246. package/lib/programmatic/openapi-schema-helpers.js +93 -0
  247. package/lib/programmatic/openapi-spec.js +203 -0
  248. package/lib/programmatic/orchestration-openapi-meta.js +159 -0
  249. package/lib/programmatic/platform-rbac-catalog.js +90 -0
  250. package/lib/programmatic/request-timeout.js +53 -0
  251. package/lib/programmatic/route-handler-map.js +143 -0
  252. package/lib/programmatic/route-handlers-context.js +29 -0
  253. package/lib/programmatic/route-handlers.js +33 -0
  254. package/lib/programmatic/run-certify.js +57 -0
  255. package/lib/programmatic/run-enterprise-mcp.js +32 -0
  256. package/lib/programmatic/run-lifecycle.js +29 -0
  257. package/lib/programmatic/run-repair.js +41 -0
  258. package/lib/programmatic/run-repository-emcp.js +54 -0
  259. package/lib/programmatic/run-template-workspace.js +61 -0
  260. package/lib/programmatic/run-test.js +49 -0
  261. package/lib/programmatic/run-upload.js +63 -0
  262. package/lib/programmatic/run-validate.js +53 -0
  263. package/lib/programmatic/run-wizard.js +40 -0
  264. package/lib/programmatic/system-key.js +48 -0
  265. package/lib/programmatic/wizard-config-normalize.js +118 -0
  266. package/lib/programmatic/workspace-cleanup.js +128 -0
  267. package/lib/programmatic/workspace-context.js +145 -0
  268. package/lib/programmatic/workspace-lock.js +75 -0
  269. package/lib/programmatic/workspace-meta.js +64 -0
  270. package/lib/programmatic/workspace-ops.js +149 -0
  271. package/lib/protection/run-commands-upload-sync.js +35 -0
  272. package/lib/protection/run-commands.js +2 -20
  273. package/lib/protection/upload-batch.js +11 -7
  274. package/lib/resolvers/resource-type-file.js +22 -0
  275. package/lib/schema/external-datasource.schema.json +161 -1
  276. package/lib/schema/external-system.schema.json +242 -4
  277. package/lib/schema/flag-map-validation-run.json +3 -0
  278. package/lib/schema/type/credential-field-registry.json +2 -2
  279. package/lib/schema/type/document-storage.json +9 -0
  280. package/lib/utils/agent-trust-run-display.js +1 -1
  281. package/lib/utils/app-path-resolve.js +168 -0
  282. package/lib/utils/authentication-env-template.js +222 -0
  283. package/lib/utils/cli-sync-options.js +7 -11
  284. package/lib/utils/cli-utils.js +4 -0
  285. package/lib/utils/cli-workspace-options.js +29 -0
  286. package/lib/utils/compose-generate-docker-compose.js +102 -0
  287. package/lib/utils/configuration-env-resolver.js +203 -27
  288. package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
  289. package/lib/utils/datasource-test-run-certification-debug.js +130 -0
  290. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  291. package/lib/utils/datasource-test-run-debug-slice.js +7 -0
  292. package/lib/utils/datasource-test-run-display.js +2 -1
  293. package/lib/utils/dev-init-ssh-merge.js +165 -23
  294. package/lib/utils/dev-pin-share-instructions.js +110 -0
  295. package/lib/utils/dev-ssh-config-helper.js +177 -33
  296. package/lib/utils/enterprise-knowledge-paths.js +142 -0
  297. package/lib/utils/env-copy.js +2 -1
  298. package/lib/utils/env-dotenv-format.js +103 -0
  299. package/lib/utils/external-env-template.js +4 -1
  300. package/lib/utils/external-system-display.js +5 -1
  301. package/lib/utils/external-system-readiness-compact-blocks.js +221 -0
  302. package/lib/utils/external-system-readiness-compact-display.js +324 -0
  303. package/lib/utils/external-system-readiness-core.js +16 -0
  304. package/lib/utils/external-system-readiness-deploy-display.js +29 -11
  305. package/lib/utils/external-system-readiness-display-internals.js +3 -1
  306. package/lib/utils/external-system-readiness-display.js +20 -30
  307. package/lib/utils/external-system-system-test-tty-certification.js +135 -0
  308. package/lib/utils/external-system-system-test-tty.js +5 -41
  309. package/lib/utils/help-builder.js +6 -1
  310. package/lib/utils/host-ops-job-labels.js +236 -0
  311. package/lib/utils/host-ops-job-result.js +61 -0
  312. package/lib/utils/host-ops-poll-ui.js +163 -0
  313. package/lib/utils/integration-path-resolve.js +112 -0
  314. package/lib/utils/paths-reload-source.js +148 -0
  315. package/lib/utils/paths-system-builder-keys.js +25 -0
  316. package/lib/utils/paths.js +151 -26
  317. package/lib/utils/runtime-configuration-values.js +64 -2
  318. package/lib/utils/secrets-helpers.js +5 -1
  319. package/lib/utils/ssh-known-hosts.js +130 -0
  320. package/lib/utils/test-target-cli-options.js +75 -0
  321. package/lib/utils/upload-sync-options.js +4 -0
  322. package/lib/utils/validation-run-request.js +11 -2
  323. package/lib/validation/external-manifest-validator.js +11 -1
  324. package/lib/validation/openapi-contract-surface-validator.js +426 -0
  325. package/lib/validation/openapi-contract-vendor-validation.js +238 -0
  326. package/lib/validation/validate-external-file.js +160 -0
  327. package/lib/validation/validate.js +6 -117
  328. package/package.json +46 -29
  329. package/packages/builder-api/README.md +120 -0
  330. package/packages/builder-api/package.json +30 -0
  331. package/packages/builder-api/src/app.module.ts +7 -0
  332. package/packages/builder-api/src/auth/auth.module.ts +5 -0
  333. package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
  334. package/packages/builder-api/src/main.ts +16 -0
  335. package/packages/builder-api/tsconfig.json +15 -0
  336. package/scripts/check-builder-api-architecture-grep.js +79 -0
  337. package/scripts/docker_image_content_gate.js +47 -0
  338. package/scripts/docker_image_content_gate.sh +5 -0
  339. package/scripts/export-builder-api-evidence.js +262 -0
  340. package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
  341. package/scripts/lib/builder-api-docker-staging-core.js +183 -0
  342. package/scripts/lib/docker-image-content-gate-core.js +166 -0
  343. package/scripts/lib/plan-actor.js +109 -0
  344. package/scripts/lib/plan-config.js +20 -0
  345. package/scripts/lib/plan-gates.js +154 -0
  346. package/scripts/lib/plan-meta.js +104 -0
  347. package/scripts/lib/plan-parse.js +162 -0
  348. package/scripts/lib/plan-prevalidate-gates.js +326 -0
  349. package/scripts/lib/plan-run-core.js +125 -0
  350. package/scripts/lib/plan-run-report.js +108 -0
  351. package/scripts/plan-approve.js +24 -0
  352. package/scripts/plan-archive.js +49 -0
  353. package/scripts/plan-run.js +13 -0
  354. package/scripts/plan-set-actor.js +21 -0
  355. package/scripts/plan-validate.js +80 -0
  356. package/scripts/pnpm/af.mjs +110 -0
  357. package/scripts/pnpm/check-quiet.mjs +32 -0
  358. package/scripts/pnpm/dev-install.mjs +29 -0
  359. package/scripts/pnpm/dev-reload.mjs +18 -0
  360. package/scripts/pnpm/help.mjs +55 -0
  361. package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
  362. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
  363. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
  364. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
  365. package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
  366. package/scripts/pnpm/lib/spinner.mjs +42 -0
  367. package/scripts/stage_builder_api_for_docker.js +65 -0
  368. package/scripts/sync-builder-api-template.js +44 -0
  369. package/templates/README.md +3 -0
  370. package/templates/applications/builder-api/Dockerfile +38 -0
  371. package/templates/applications/builder-api/application.yaml +75 -0
  372. package/templates/applications/builder-api/env.template +48 -0
  373. package/templates/applications/dataplane/application.yaml +1 -1
  374. package/templates/applications/dataplane/env.template +10 -6
  375. package/templates/applications/dataplane/rbac.yaml +21 -1
  376. package/templates/applications/miso-controller/application.yaml +1 -1
  377. package/templates/applications/miso-controller/env.template +1 -3
  378. package/templates/channels/README.md +18 -0
  379. package/templates/channels/ai-fabrix-icon.jpg +0 -0
  380. package/templates/channels/chatgpt/install.template.md.hbs +21 -24
  381. package/templates/channels/chatgpt/integration/README.md +11 -0
  382. package/templates/channels/chatgpt/integration/application.json +15 -0
  383. package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
  384. package/templates/channels/chatgpt/integration/env.template +4 -0
  385. package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
  386. package/templates/channels/microsoft-copilot/integration/README.md +11 -0
  387. package/templates/channels/microsoft-copilot/integration/application.json +15 -0
  388. package/templates/channels/microsoft-copilot/integration/env.template +6 -0
  389. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
  390. package/templates/channels/slack/install.template.md.hbs +48 -18
  391. package/templates/channels/slack/integration/README.md +38 -0
  392. package/templates/channels/slack/integration/application.json +18 -0
  393. package/templates/channels/slack/integration/env.template +29 -0
  394. package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
  395. package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
  396. package/templates/channels/slack/integration/slack-system.json +86 -0
  397. package/templates/channels/slack/manifest.template.json.hbs +20 -10
  398. package/templates/channels/teams-bot/install.template.md.hbs +31 -17
  399. package/templates/channels/teams-bot/integration/README.md +18 -0
  400. package/templates/channels/teams-bot/integration/application.json +17 -0
  401. package/templates/channels/teams-bot/integration/env.template +5 -0
  402. package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
  403. package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
  404. package/templates/channels/web-embed/install.template.md.hbs +16 -26
  405. package/templates/channels/web-embed/integration/README.md +11 -0
  406. package/templates/channels/web-embed/integration/application.json +15 -0
  407. package/templates/channels/web-embed/integration/env.template +4 -0
  408. package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
  409. package/templates/openapi/redoc_page.html +86 -0
  410. package/templates/python/docker-compose.hbs +11 -0
  411. package/templates/python/requirements.txt +1 -1
  412. package/templates/typescript/docker-compose.hbs +11 -0
  413. package/lib/certification/cli-cert-sync-skip.js +0 -21
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Multi-user workspace context for builder-api programmatic flows.
3
+ *
4
+ * @fileoverview WorkspaceContext paths under WORKSPACE_ROOT/{userId}/integration/{systemKey}/
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const path = require('path');
12
+ const fs = require('../internal/fs-real-sync');
13
+ const { assertValidSystemKey, assertValidUserId } = require('./system-key');
14
+ const { runWithIntegrationPathScope } = require('./integration-path-scope');
15
+
16
+ /** Server-side workspace integrations use JSON manifests (plan 154.0). */
17
+ const WORKSPACE_INTEGRATION_FORMAT = 'json';
18
+
19
+ /**
20
+ * @typedef {Object} WorkspaceContext
21
+ * @property {string} userId
22
+ * @property {string} workspaceRoot
23
+ * @property {string} systemKey
24
+ * @property {string} environment
25
+ * @property {string} controllerUrl
26
+ * @property {string} dataplaneUrl
27
+ * @property {string} bearerToken
28
+ */
29
+
30
+ /**
31
+ * @param {string} segment
32
+ * @returns {string}
33
+ */
34
+ function resolveWorkspaceRoot(segment) {
35
+ if (segment && typeof segment === 'string' && segment.trim()) {
36
+ return path.resolve(segment.trim());
37
+ }
38
+ const fromEnv = process.env.WORKSPACE_ROOT;
39
+ if (fromEnv && typeof fromEnv === 'string' && fromEnv.trim()) {
40
+ return path.resolve(fromEnv.trim());
41
+ }
42
+ return path.resolve(process.cwd(), '.temp', 'builder-workspaces');
43
+ }
44
+
45
+ /**
46
+ * @param {Object} params
47
+ * @param {string} params.userId
48
+ * @param {string} params.systemKey
49
+ * @param {string} params.bearerToken
50
+ * @param {string} [params.workspaceRoot]
51
+ * @param {string} [params.environment]
52
+ * @param {string} [params.controllerUrl]
53
+ * @param {string} [params.dataplaneUrl]
54
+ * @returns {WorkspaceContext}
55
+ */
56
+ function createWorkspaceContext(params) {
57
+ const userId = assertValidUserId(params.userId);
58
+ const systemKey = assertValidSystemKey(params.systemKey);
59
+ const bearerToken = params.bearerToken;
60
+ if (!bearerToken || typeof bearerToken !== 'string') {
61
+ throw new Error('bearerToken is required');
62
+ }
63
+
64
+ const workspaceRoot = resolveWorkspaceRoot(params.workspaceRoot);
65
+ const userRoot = path.join(workspaceRoot, userId);
66
+ const integrationRoot = path.join(userRoot, 'integration');
67
+ const useExplicitIntegration = Boolean(params.integrationPath);
68
+ const integrationPath = useExplicitIntegration
69
+ ? path.resolve(params.integrationPath)
70
+ : path.join(integrationRoot, systemKey);
71
+
72
+ if (useExplicitIntegration) {
73
+ if (path.basename(integrationPath) !== systemKey) {
74
+ throw new Error(`integrationPath must end with systemKey "${systemKey}"`);
75
+ }
76
+ } else {
77
+ assertPathContained(integrationPath, workspaceRoot);
78
+ }
79
+
80
+ return {
81
+ userId,
82
+ workspaceRoot,
83
+ systemKey,
84
+ environment: params.environment || process.env.DEFAULT_ENVIRONMENT || 'dev',
85
+ controllerUrl:
86
+ params.controllerUrl ||
87
+ process.env.MISO_CONTROLLER_URL ||
88
+ process.env.CONTROLLER_URL ||
89
+ '',
90
+ dataplaneUrl: params.dataplaneUrl || process.env.DATAPLANE_URL || '',
91
+ bearerToken,
92
+ getUserRoot: () => userRoot,
93
+ getIntegrationRoot: () => integrationRoot,
94
+ getIntegrationPath: () => integrationPath
95
+ };
96
+ }
97
+
98
+ /**
99
+ * @param {string} targetPath
100
+ * @param {string} workspaceRoot
101
+ */
102
+ function assertPathContained(targetPath, workspaceRoot) {
103
+ const resolvedTarget = path.resolve(targetPath);
104
+ const resolvedRoot = path.resolve(workspaceRoot);
105
+ const rootWithSep = resolvedRoot.endsWith(path.sep) ? resolvedRoot : `${resolvedRoot}${path.sep}`;
106
+ if (resolvedTarget !== resolvedRoot && !resolvedTarget.startsWith(rootWithSep)) {
107
+ throw new Error('Path escapes workspace root');
108
+ }
109
+ }
110
+
111
+ /**
112
+ * @param {WorkspaceContext} ctx
113
+ * @param {() => Promise<*> | *} fn
114
+ * @returns {Promise<*>}
115
+ */
116
+ function runWithWorkspaceContext(ctx, fn) {
117
+ const scope = {
118
+ resolveIntegrationPath: (systemKey) => {
119
+ assertValidSystemKey(systemKey);
120
+ if (systemKey !== ctx.systemKey) {
121
+ const alt = path.join(ctx.getIntegrationRoot(), systemKey);
122
+ assertPathContained(alt, ctx.workspaceRoot);
123
+ return alt;
124
+ }
125
+ return ctx.getIntegrationPath();
126
+ }
127
+ };
128
+ return runWithIntegrationPathScope(scope, fn);
129
+ }
130
+
131
+ /**
132
+ * @param {WorkspaceContext} ctx
133
+ */
134
+ function ensureIntegrationDirectory(ctx) {
135
+ fs.mkdirSync(ctx.getIntegrationPath(), { recursive: true });
136
+ }
137
+
138
+ module.exports = {
139
+ WORKSPACE_INTEGRATION_FORMAT,
140
+ createWorkspaceContext,
141
+ runWithWorkspaceContext,
142
+ ensureIntegrationDirectory,
143
+ resolveWorkspaceRoot,
144
+ assertPathContained
145
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * In-memory workspace lock (userId + systemKey) — V1 single replica.
3
+ *
4
+ * @fileoverview 409 Conflict when concurrent mutating access
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /** @type {Map<string, { acquiredAt: number }>} */
12
+ const locks = new Map();
13
+
14
+ /**
15
+ * @param {string} userId
16
+ * @param {string} systemKey
17
+ * @returns {string}
18
+ */
19
+ function lockKey(userId, systemKey) {
20
+ return `${userId}:${systemKey}`;
21
+ }
22
+
23
+ /**
24
+ * @param {string} userId
25
+ * @param {string} systemKey
26
+ * @returns {boolean}
27
+ */
28
+ function tryAcquireWorkspaceLock(userId, systemKey) {
29
+ const key = lockKey(userId, systemKey);
30
+ if (locks.has(key)) {
31
+ return false;
32
+ }
33
+ locks.set(key, { acquiredAt: Date.now() });
34
+ return true;
35
+ }
36
+
37
+ /**
38
+ * @param {string} userId
39
+ * @param {string} systemKey
40
+ */
41
+ function releaseWorkspaceLock(userId, systemKey) {
42
+ locks.delete(lockKey(userId, systemKey));
43
+ }
44
+
45
+ /**
46
+ * @param {string} userId
47
+ * @param {string} systemKey
48
+ * @param {() => Promise<*>} fn
49
+ * @returns {Promise<*>}
50
+ */
51
+ async function withWorkspaceLock(userId, systemKey, fn) {
52
+ if (!tryAcquireWorkspaceLock(userId, systemKey)) {
53
+ const err = new Error('Workspace is locked by another request');
54
+ err.statusCode = 409;
55
+ err.retryAfter = 5;
56
+ throw err;
57
+ }
58
+ try {
59
+ return await fn();
60
+ } finally {
61
+ releaseWorkspaceLock(userId, systemKey);
62
+ }
63
+ }
64
+
65
+ /** Test helper */
66
+ function clearWorkspaceLocks() {
67
+ locks.clear();
68
+ }
69
+
70
+ module.exports = {
71
+ tryAcquireWorkspaceLock,
72
+ releaseWorkspaceLock,
73
+ withWorkspaceLock,
74
+ clearWorkspaceLocks
75
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * `.builder-workspace-meta.json` helpers for builder-api workspaces.
3
+ *
4
+ * @fileoverview Workspace metadata (no secret fields)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('../internal/fs-real-sync');
12
+ const path = require('path');
13
+
14
+ const META_FILENAME = '.builder-workspace-meta.json';
15
+
16
+ /**
17
+ * @param {import('./workspace-context').WorkspaceContext} ctx
18
+ * @returns {string}
19
+ */
20
+ function getMetaPath(ctx) {
21
+ return path.join(ctx.getIntegrationPath(), META_FILENAME);
22
+ }
23
+
24
+ /**
25
+ * @param {import('./workspace-context').WorkspaceContext} ctx
26
+ * @returns {Object|null}
27
+ */
28
+ function readWorkspaceMeta(ctx) {
29
+ const metaPath = getMetaPath(ctx);
30
+ if (!fs.existsSync(metaPath)) {
31
+ return null;
32
+ }
33
+ const raw = fs.readFileSync(metaPath, 'utf8');
34
+ return JSON.parse(raw);
35
+ }
36
+
37
+ /**
38
+ * @param {import('./workspace-context').WorkspaceContext} ctx
39
+ * @param {{ lastOperation?: string, lastUploadId?: string|null }} patch
40
+ * @returns {Object}
41
+ */
42
+ function touchWorkspaceMeta(ctx, patch = {}) {
43
+ const metaPath = getMetaPath(ctx);
44
+ const now = new Date().toISOString();
45
+ const existing = readWorkspaceMeta(ctx);
46
+ const next = {
47
+ ownerUserId: ctx.userId,
48
+ systemKey: ctx.systemKey,
49
+ createdAt: existing?.createdAt || now,
50
+ lastModifiedAt: now,
51
+ lastOperation: patch.lastOperation || existing?.lastOperation || 'init',
52
+ lastUploadId: patch.lastUploadId !== undefined ? patch.lastUploadId : existing?.lastUploadId ?? null
53
+ };
54
+ fs.mkdirSync(path.dirname(metaPath), { recursive: true });
55
+ fs.writeFileSync(metaPath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
56
+ return next;
57
+ }
58
+
59
+ module.exports = {
60
+ META_FILENAME,
61
+ getMetaPath,
62
+ readWorkspaceMeta,
63
+ touchWorkspaceMeta
64
+ };
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Workspace CRUD for builder-api (list, create, manifest, delete).
3
+ *
4
+ * @fileoverview Multi-user integration folder operations
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('../internal/fs-real-sync');
12
+ const path = require('path');
13
+ const { assertValidSystemKey } = require('./system-key');
14
+ const { ensureIntegrationDirectory } = require('./workspace-context');
15
+ const { readWorkspaceMeta, touchWorkspaceMeta, META_FILENAME } = require('./workspace-meta');
16
+
17
+ const SECRET_FILE_NAMES = new Set(['.env', 'secrets.local.yaml']);
18
+
19
+ /**
20
+ * @param {import('./workspace-context').WorkspaceContext} ctx
21
+ * @returns {string[]}
22
+ */
23
+ function listSystemKeys(ctx) {
24
+ const root = ctx.getIntegrationRoot();
25
+ if (!fs.existsSync(root)) {
26
+ return [];
27
+ }
28
+ return fs
29
+ .readdirSync(root, { withFileTypes: true })
30
+ .filter((d) => d.isDirectory() && !d.name.startsWith('.'))
31
+ .map((d) => d.name)
32
+ .sort();
33
+ }
34
+
35
+ /**
36
+ * @param {import('./workspace-context').WorkspaceContext} ctx
37
+ * @returns {{ systems: Object[] }}
38
+ */
39
+ function listSystems(ctx) {
40
+ const keys = listSystemKeys(ctx);
41
+ const systems = keys.map((systemKey) => ({
42
+ systemKey,
43
+ meta: readWorkspaceMetaForKey(ctx, systemKey)
44
+ }));
45
+ return { systems };
46
+ }
47
+
48
+ /**
49
+ * @param {import('./workspace-context').WorkspaceContext} ctx
50
+ * @param {string} systemKey
51
+ * @returns {Object|null}
52
+ */
53
+ function readWorkspaceMetaForKey(ctx, systemKey) {
54
+ const metaPath = path.join(ctx.getIntegrationRoot(), systemKey, META_FILENAME);
55
+ if (!fs.existsSync(metaPath)) {
56
+ return null;
57
+ }
58
+ return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
59
+ }
60
+
61
+ /**
62
+ * @param {import('./workspace-context').WorkspaceContext} ctx
63
+ * @param {string} [systemKey]
64
+ */
65
+ function createSystem(ctx, systemKey = ctx.systemKey) {
66
+ assertValidSystemKey(systemKey);
67
+ const prior = ctx.systemKey;
68
+ if (systemKey !== prior) {
69
+ throw new Error('createSystem systemKey must match workspace context for V1');
70
+ }
71
+ ensureIntegrationDirectory(ctx);
72
+ const meta = touchWorkspaceMeta(ctx, { lastOperation: 'create' });
73
+ return { systemKey, meta };
74
+ }
75
+
76
+ /**
77
+ * @param {string} filePath
78
+ * @param {string} integrationPath
79
+ * @returns {boolean}
80
+ */
81
+ function isSecretPath(filePath, integrationPath) {
82
+ const rel = path.relative(integrationPath, filePath);
83
+ const base = path.basename(filePath);
84
+ if (SECRET_FILE_NAMES.has(base)) {
85
+ return true;
86
+ }
87
+ return rel.includes('secrets') && base.endsWith('.yaml');
88
+ }
89
+
90
+ /**
91
+ * @param {import('./workspace-context').WorkspaceContext} ctx
92
+ * @returns {{ systemKey: string, files: Object[], meta: Object|null }}
93
+ */
94
+ function getSystemManifest(ctx) {
95
+ const integrationPath = ctx.getIntegrationPath();
96
+ if (!fs.existsSync(integrationPath)) {
97
+ const err = new Error('System workspace not found');
98
+ err.statusCode = 404;
99
+ throw err;
100
+ }
101
+ const files = [];
102
+ const walk = (dir, prefix = '') => {
103
+ for (const name of fs.readdirSync(dir)) {
104
+ if (name === META_FILENAME && !prefix) {
105
+ continue;
106
+ }
107
+ const full = path.join(dir, name);
108
+ const rel = prefix ? `${prefix}/${name}` : name;
109
+ if (isSecretPath(full, integrationPath)) {
110
+ files.push({ path: rel, redacted: true });
111
+ continue;
112
+ }
113
+ const stat = fs.statSync(full);
114
+ if (stat.isDirectory()) {
115
+ files.push({ path: rel, isDirectory: true });
116
+ walk(full, rel);
117
+ } else {
118
+ files.push({ path: rel, sizeBytes: stat.size });
119
+ }
120
+ }
121
+ };
122
+ walk(integrationPath);
123
+ return {
124
+ systemKey: ctx.systemKey,
125
+ meta: readWorkspaceMeta(ctx),
126
+ files
127
+ };
128
+ }
129
+
130
+ /**
131
+ * @param {import('./workspace-context').WorkspaceContext} ctx
132
+ */
133
+ function deleteSystem(ctx) {
134
+ const integrationPath = ctx.getIntegrationPath();
135
+ if (!fs.existsSync(integrationPath)) {
136
+ const err = new Error('System workspace not found');
137
+ err.statusCode = 404;
138
+ throw err;
139
+ }
140
+ fs.rmSync(integrationPath, { recursive: true, force: true });
141
+ return { systemKey: ctx.systemKey, deleted: true };
142
+ }
143
+
144
+ module.exports = {
145
+ listSystems,
146
+ createSystem,
147
+ getSystemManifest,
148
+ deleteSystem
149
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @fileoverview Protection upload sync step after manifest publish.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { resolveSyncPlan, executeSyncPlan } = require('../commands/datasource-sync-policy');
10
+ const { logDatasourceSyncSummary } = require('../commands/datasource-sync-display');
11
+
12
+ /**
13
+ * @param {Object} ctx
14
+ * @param {string} datasourceKey
15
+ * @param {Object} opts
16
+ * @returns {Promise<void>}
17
+ */
18
+ async function runProtectionUploadDataSync(ctx, datasourceKey, opts) {
19
+ const plan = await resolveSyncPlan({
20
+ syncExplicit: opts.sync === true,
21
+ skipSync: false,
22
+ datasourceKeys: [datasourceKey],
23
+ dataplaneUrl: ctx.dataplaneUrl,
24
+ authConfig: ctx.authConfig
25
+ });
26
+ const syncResult = await executeSyncPlan(plan, ctx.dataplaneUrl, ctx.authConfig);
27
+ logDatasourceSyncSummary(syncResult, {
28
+ label: 'Protection upload data sync',
29
+ syncExplicit: opts.sync === true
30
+ });
31
+ }
32
+
33
+ module.exports = {
34
+ runProtectionUploadDataSync
35
+ };
@@ -19,7 +19,7 @@ const {
19
19
  findProtectionKeyByDatasource
20
20
  } = require('../api/protection.api');
21
21
  const { preflightDatasourceReady } = require('./preflight-datasource-ready');
22
- const { syncDatasourceAfterProtectionUpload } = require('./sync-after-upload');
22
+ const { runProtectionUploadDataSync } = require('./run-commands-upload-sync');
23
23
  const {
24
24
  formatProtectionListTTY,
25
25
  formatProtectionShowTTY,
@@ -69,25 +69,7 @@ async function runProtectionUpload(datasourceKey, manifest, opts, logger) {
69
69
  )
70
70
  );
71
71
 
72
- if (!opts.noSync) {
73
- logger.log(formatProgress(`Syncing datasource ${datasourceKey}...`));
74
- const sync = await syncDatasourceAfterProtectionUpload(
75
- ctx.dataplaneUrl,
76
- ctx.authConfig,
77
- datasourceKey
78
- );
79
- if (sync.syncJobId) {
80
- logger.log(formatSuccessLine(`Sync started (syncJobId: ${sync.syncJobId})`));
81
- } else if (sync.warning) {
82
- logger.log(formatWarningLine(`Sync warning: ${sync.warning}`));
83
- }
84
- } else {
85
- logger.log(
86
- chalk.gray(
87
- 'Sync skipped (--no-sync). Protection active on dataplane; projections update on next datasource sync.'
88
- )
89
- );
90
- }
72
+ await runProtectionUploadDataSync(ctx, datasourceKey, opts, logger);
91
73
  return 0;
92
74
  }
93
75
 
@@ -14,7 +14,7 @@ const { resolveProtectionDataplaneContext } = require('./auth-context');
14
14
  const { validateProtection, uploadProtection } = require('../api/protection.api');
15
15
  const { exitCodeFromProtectionReport } = require('./report-exit');
16
16
  const { preflightDatasourceReady } = require('./preflight-datasource-ready');
17
- const { syncUniqueDatasourcesAfterUpload } = require('./sync-after-upload');
17
+ const { resolveSyncPlan, executeSyncPlan } = require('../commands/datasource-sync-policy');
18
18
  const { formatProtectionBatchUploadTTY } = require('./protection-display');
19
19
 
20
20
  /**
@@ -87,12 +87,16 @@ async function runUploadProtectionBatch(opts = {}) {
87
87
  }
88
88
 
89
89
  let syncResults = [];
90
- if (!opts.dryRun && !opts.noSync && uploadedDatasourceKeys.length) {
91
- syncResults = await syncUniqueDatasourcesAfterUpload(
92
- ctx.dataplaneUrl,
93
- ctx.authConfig,
94
- uploadedDatasourceKeys
95
- );
90
+ if (!opts.dryRun && uploadedDatasourceKeys.length) {
91
+ const plan = await resolveSyncPlan({
92
+ syncExplicit: opts.sync === true,
93
+ skipSync: false,
94
+ datasourceKeys: uploadedDatasourceKeys,
95
+ dataplaneUrl: ctx.dataplaneUrl,
96
+ authConfig: ctx.authConfig
97
+ });
98
+ const executed = await executeSyncPlan(plan, ctx.dataplaneUrl, ctx.authConfig);
99
+ syncResults = executed.executed;
96
100
  }
97
101
 
98
102
  const ok = results.length > 0 && results.every((r) => r.ok);
@@ -19,6 +19,7 @@ const { existsSync, readFileSync } = require('../internal/fs-real-sync');
19
19
  * @property {string} [category]
20
20
  * @property {string} [defaultRiskLevel]
21
21
  * @property {string} [status]
22
+ * @property {string} domain
22
23
  */
23
24
 
24
25
  const CATEGORIES = new Set([
@@ -32,6 +33,7 @@ const CATEGORIES = new Set([
32
33
 
33
34
  const RISK_LEVELS = new Set(['low', 'medium', 'high', 'critical']);
34
35
  const STATUSES = new Set(['draft', 'active', 'deprecated', 'retired']);
36
+ const DOMAIN_KEY_PATTERN = /^[a-z][a-z0-9-]*$/;
35
37
 
36
38
  /**
37
39
  * @param {string} filePath
@@ -75,6 +77,25 @@ function applyOptionalEnumField(parsed, field, allowedValues, label) {
75
77
  parsed[field] = value;
76
78
  }
77
79
 
80
+ /**
81
+ * @param {object} entry
82
+ * @param {number} index
83
+ * @returns {void}
84
+ */
85
+ function applyRequiredDomainField(entry, index) {
86
+ const raw = entry.domain;
87
+ const value = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
88
+ if (!value) {
89
+ throw new Error(`resourceTypes[${index}].domain is required`);
90
+ }
91
+ if (!DOMAIN_KEY_PATTERN.test(value)) {
92
+ throw new Error(
93
+ 'domain must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens'
94
+ );
95
+ }
96
+ entry.domain = value;
97
+ }
98
+
78
99
  /**
79
100
  * @param {object} parsed
80
101
  * @returns {void}
@@ -102,6 +123,7 @@ function normalizeResourceTypeCreateRow(row, index) {
102
123
  applyOptionalEnumField(entry, 'category', CATEGORIES, 'category');
103
124
  applyOptionalEnumField(entry, 'defaultRiskLevel', RISK_LEVELS, 'defaultRiskLevel');
104
125
  applyOptionalEnumField(entry, 'status', STATUSES, 'status');
126
+ applyRequiredDomainField(entry, index);
105
127
  const key = String(entry.key || '').trim();
106
128
  if (!key) {
107
129
  throw new Error(`resourceTypes[${index}].key is required`);