@aifabrix/builder 2.52.0 → 2.53.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 (310) hide show
  1. package/lib/api/datasources-extended.api.js +8 -8
  2. package/lib/api/keycloak.api.js +92 -0
  3. package/lib/api/token-providers.api.js +77 -0
  4. package/lib/api/types/keycloak.types.js +23 -0
  5. package/lib/api/types/token-providers.types.js +65 -0
  6. package/lib/app/deploy-config.js +3 -2
  7. package/lib/app/down.js +16 -1
  8. package/lib/channels/add-channel.js +134 -57
  9. package/lib/channels/approval-guides/chatgpt.js +1 -1
  10. package/lib/channels/approval-guides/index.js +3 -0
  11. package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
  12. package/lib/channels/channel-add-ensure.js +128 -0
  13. package/lib/channels/channel-add-existing.js +72 -0
  14. package/lib/channels/channel-artifact-generator.js +11 -1
  15. package/lib/channels/channel-branding.js +94 -0
  16. package/lib/channels/channel-credential.js +8 -0
  17. package/lib/channels/channel-discovery.js +330 -0
  18. package/lib/channels/channel-external-system.js +1 -1
  19. package/lib/channels/channel-runtime-resolver.js +107 -14
  20. package/lib/channels/channel-status-display.js +36 -3
  21. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  22. package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
  23. package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
  24. package/lib/channels/microsoft-copilot-icons.js +74 -0
  25. package/lib/channels/microsoft-copilot-limits.js +103 -0
  26. package/lib/channels/microsoft-copilot-package.js +178 -52
  27. package/lib/channels/microsoft-copilot-validate.js +227 -0
  28. package/lib/cli/attach-default-help-examples.js +102 -0
  29. package/lib/cli/index.js +4 -0
  30. package/lib/cli/infra-guided.js +13 -6
  31. package/lib/cli/setup-credential-deployment.js +7 -5
  32. package/lib/cli/setup-infra.js +31 -4
  33. package/lib/cli/setup-utility-validate.js +1 -0
  34. package/lib/commands/channel-add-setup.js +28 -9
  35. package/lib/commands/channel.js +14 -10
  36. package/lib/commands/credential-push.js +37 -5
  37. package/lib/commands/integration-definition.js +158 -0
  38. package/lib/commands/package-score.js +72 -0
  39. package/lib/commands/repair-auth-apply.js +19 -5
  40. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  41. package/lib/commands/role-assistant-test-output.js +200 -0
  42. package/lib/commands/role-assistant.js +163 -166
  43. package/lib/datasource/capability/capability-resolve.js +15 -5
  44. package/lib/datasource/capability/copy-operations.js +14 -4
  45. package/lib/deployment/deployer-poll-run.js +2 -2
  46. package/lib/deployment/deployer.js +1 -1
  47. package/lib/deployment/environment.js +2 -2
  48. package/lib/external-system/deploy.js +11 -21
  49. package/lib/infrastructure/index.js +19 -4
  50. package/lib/integration-definition/apply.js +476 -0
  51. package/lib/integration-definition/canonical-json.js +51 -0
  52. package/lib/integration-definition/emit-suite-bid.js +94 -0
  53. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  54. package/lib/integration-definition/enrich-openapi-operations.js +433 -0
  55. package/lib/integration-definition/from-discovery.js +339 -0
  56. package/lib/integration-definition/hash.js +37 -0
  57. package/lib/integration-definition/index.js +37 -0
  58. package/lib/integration-definition/resource-type-catalog.js +59 -0
  59. package/lib/integration-definition/system-kind-enum.js +40 -0
  60. package/lib/integration-definition/validate.js +148 -0
  61. package/lib/lab/package-parity-score.js +417 -0
  62. package/lib/programmatic/builder-api-request.js +5 -1
  63. package/lib/programmatic/builder-help-governance.js +3 -2
  64. package/lib/programmatic/capability-registry.js +20 -0
  65. package/lib/programmatic/help-content/channel-onboarding.md +35 -0
  66. package/lib/programmatic/help-content/cip-overview.md +27 -0
  67. package/lib/programmatic/help-content/connected-system-ui.md +70 -0
  68. package/lib/programmatic/help-content/dimensions-guide.md +23 -0
  69. package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
  70. package/lib/programmatic/help-content/overview.md +25 -0
  71. package/lib/programmatic/help-content/subscription-guide.md +27 -0
  72. package/lib/programmatic/help-content/workflow.md +50 -0
  73. package/lib/programmatic/openapi-component-schemas.js +7 -1
  74. package/lib/programmatic/openapi-descriptions.js +46 -0
  75. package/lib/programmatic/openapi-envelope-examples.js +280 -0
  76. package/lib/programmatic/openapi-operation-bindings.js +50 -0
  77. package/lib/programmatic/openapi-request-schemas.js +40 -0
  78. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  79. package/lib/programmatic/openapi-result-schemas.js +76 -99
  80. package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
  81. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  82. package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
  83. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  84. package/lib/programmatic/openapi-spec.js +11 -1
  85. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  86. package/lib/programmatic/persist-supplied-openapi.js +180 -0
  87. package/lib/programmatic/route-handler-map.js +35 -1
  88. package/lib/programmatic/run-channel-package.js +236 -0
  89. package/lib/programmatic/run-integration-definition.js +77 -0
  90. package/lib/role-assistant/evidence-sync.js +55 -7
  91. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  92. package/lib/role-assistant/knowledge-sync.js +88 -93
  93. package/lib/role-assistant/test-cases-bid.js +155 -0
  94. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  95. package/lib/role-assistant/test-cases-honesty.js +24 -10
  96. package/lib/role-assistant/test-cases.js +28 -0
  97. package/lib/role-assistant/test-runner-attachments.js +118 -0
  98. package/lib/role-assistant/test-runner-bid-apply.js +201 -0
  99. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  100. package/lib/role-assistant/test-runner-start-payload.js +96 -0
  101. package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
  102. package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
  103. package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
  104. package/lib/role-assistant/test-runner-workhub.js +152 -107
  105. package/lib/role-assistant/test-runner.js +5 -63
  106. package/lib/role-assistant/test-suite.js +112 -0
  107. package/lib/schema/application-schema.json +56 -6
  108. package/lib/schema/external-datasource.schema.json +103 -17
  109. package/lib/schema/external-system.schema.json +54 -3
  110. package/lib/schema/integration-definition.schema.json +195 -0
  111. package/lib/utils/authentication-shape.js +6 -0
  112. package/lib/utils/compose-generator.js +10 -1
  113. package/lib/utils/compose-traefik-extra-routes.js +107 -0
  114. package/lib/utils/docker-build.js +2 -2
  115. package/lib/utils/help-builder.js +3 -1
  116. package/lib/utils/promote-dev-docker-image.js +102 -18
  117. package/lib/utils/transient-developer-id.js +28 -0
  118. package/package.json +14 -16
  119. package/templates/README.md +12 -1
  120. package/templates/applications/dataplane/application.yaml +10 -2
  121. package/templates/applications/dataplane/env.template +7 -6
  122. package/templates/applications/miso-controller/application.yaml +23 -8
  123. package/templates/applications/miso-controller/env.template +8 -2
  124. package/templates/applications/miso-controller/rbac.yaml +1 -0
  125. package/templates/channels/README.md +11 -1
  126. package/templates/channels/brand/color-192.png +0 -0
  127. package/templates/channels/brand/dark/128.png +0 -0
  128. package/templates/channels/brand/dark/192.png +0 -0
  129. package/templates/channels/brand/dark/256.png +0 -0
  130. package/templates/channels/brand/dark/32.png +0 -0
  131. package/templates/channels/brand/dark/512.png +0 -0
  132. package/templates/channels/brand/dark/64.png +0 -0
  133. package/templates/channels/brand/light/128.png +0 -0
  134. package/templates/channels/brand/light/192.png +0 -0
  135. package/templates/channels/brand/light/256.png +0 -0
  136. package/templates/channels/brand/light/32.png +0 -0
  137. package/templates/channels/brand/light/512.png +0 -0
  138. package/templates/channels/brand/light/64.png +0 -0
  139. package/templates/channels/brand/mono-white/128.png +0 -0
  140. package/templates/channels/brand/mono-white/192.png +0 -0
  141. package/templates/channels/brand/mono-white/256.png +0 -0
  142. package/templates/channels/brand/mono-white/32.png +0 -0
  143. package/templates/channels/brand/mono-white/512.png +0 -0
  144. package/templates/channels/brand/mono-white/64.png +0 -0
  145. package/templates/channels/brand/outline-32.png +0 -0
  146. package/templates/channels/chatgpt/install.template.md.hbs +6 -4
  147. package/templates/channels/chatgpt/integration/README.md +4 -5
  148. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  149. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
  150. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  151. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
  152. package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
  153. package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
  154. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  155. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  156. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
  157. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
  158. package/templates/channels/slack/integration/README.md +2 -4
  159. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  160. package/templates/channels/teams-bot/integration/README.md +3 -5
  161. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  162. package/templates/python/docker-compose.hbs +36 -0
  163. package/templates/typescript/docker-compose.hbs +36 -0
  164. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
  165. package/.cursor/process/README.md +0 -9
  166. package/.cursor/rules/anchor-docs.mdc +0 -15
  167. package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
  168. package/.cursor/rules/cli-layout.mdc +0 -81
  169. package/.cursor/rules/cli-product-neutral.mdc +0 -43
  170. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
  171. package/.cursor/rules/docs-rules.mdc +0 -32
  172. package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
  173. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
  174. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
  175. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
  176. package/.cursor/rules/project-rules.mdc +0 -913
  177. package/.cursor/skills/README.md +0 -15
  178. package/.dockerignore +0 -52
  179. package/.eslintignore +0 -22
  180. package/.markdownlint.json +0 -14
  181. package/anchor-docs/README.md +0 -10
  182. package/anchor-docs/_TEMPLATE +0 -24
  183. package/babel.config.js +0 -6
  184. package/bin/builder-api-cleanup.js +0 -26
  185. package/bin/builder-api-nest.js +0 -10
  186. package/bin/builder-api-spike.js +0 -19
  187. package/enterprise-knowledge/README.md +0 -50
  188. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
  189. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
  190. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
  191. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
  192. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
  193. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
  194. package/integration/README.md +0 -81
  195. package/integration/github/README.md +0 -53
  196. package/integration/github/application.json +0 -21
  197. package/integration/github/deploy.js +0 -72
  198. package/integration/github/env.template +0 -11
  199. package/integration/github/github-datasource-issue-comments.json +0 -239
  200. package/integration/github/github-datasource-issues.json +0 -399
  201. package/integration/github/github-datasource-repository.json +0 -354
  202. package/integration/github/github-deploy.json +0 -1202
  203. package/integration/github/github-system.json +0 -82
  204. package/integration/hubspot-test/README.md +0 -159
  205. package/integration/hubspot-test/application.json +0 -54
  206. package/integration/hubspot-test/companies.json +0 -2048
  207. package/integration/hubspot-test/create-hubspot.js +0 -523
  208. package/integration/hubspot-test/env.template +0 -4
  209. package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
  210. package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
  211. package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
  212. package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
  213. package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
  214. package/integration/hubspot-test/hubspot-test-system.json +0 -74
  215. package/integration/hubspot-test/rbac.json +0 -166
  216. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
  217. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
  218. package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
  219. package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
  220. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
  221. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
  222. package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
  223. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
  224. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  225. package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
  226. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
  227. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
  228. package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
  229. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
  230. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  231. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  232. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
  233. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
  234. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
  235. package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
  236. package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
  237. package/integration/hubspot-test/test-dataplane-down.js +0 -209
  238. package/integration/hubspot-test/test.js +0 -1588
  239. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
  240. package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
  241. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
  242. package/integration/roundtrip-test-local/README.md +0 -143
  243. package/integration/roundtrip-test-local/application.yaml +0 -13
  244. package/integration/roundtrip-test-local/env.template +0 -15
  245. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
  246. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
  247. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
  248. package/integration/roundtrip-test-local2/README.md +0 -143
  249. package/integration/roundtrip-test-local2/application.yaml +0 -13
  250. package/integration/roundtrip-test-local2/env.template +0 -15
  251. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
  252. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
  253. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
  254. package/integration/test/wizard.yaml +0 -8
  255. package/jest.config.coverage.js +0 -37
  256. package/jest.config.default.js +0 -11
  257. package/jest.config.integration.fixtures.js +0 -22
  258. package/jest.config.integration.js +0 -33
  259. package/jest.config.isolated.js +0 -11
  260. package/jest.config.manual.js +0 -30
  261. package/jest.global-live-fabrix-hooks.js +0 -36
  262. package/jest.isolated-projects.js +0 -260
  263. package/jest.projects.js +0 -76
  264. package/packages/builder-api/README.md +0 -120
  265. package/packages/builder-api/package.json +0 -30
  266. package/packages/builder-api/src/app.module.ts +0 -7
  267. package/packages/builder-api/src/auth/auth.module.ts +0 -5
  268. package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
  269. package/packages/builder-api/src/main.ts +0 -16
  270. package/packages/builder-api/tsconfig.json +0 -15
  271. package/scripts/check-builder-api-architecture-grep.js +0 -79
  272. package/scripts/check-datasource-test-run-schema-sync.js +0 -34
  273. package/scripts/ci-fix.sh +0 -19
  274. package/scripts/ci-simulate.sh +0 -19
  275. package/scripts/diagnose-cli.js +0 -150
  276. package/scripts/docker_image_content_gate.js +0 -47
  277. package/scripts/docker_image_content_gate.sh +0 -5
  278. package/scripts/export-builder-api-evidence.js +0 -262
  279. package/scripts/install-local.js +0 -490
  280. package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
  281. package/scripts/lib/builder-api-docker-staging-core.js +0 -183
  282. package/scripts/lib/docker-image-content-gate-core.js +0 -166
  283. package/scripts/lib/plan-actor.js +0 -109
  284. package/scripts/lib/plan-config.js +0 -20
  285. package/scripts/lib/plan-gates.js +0 -154
  286. package/scripts/lib/plan-meta.js +0 -104
  287. package/scripts/lib/plan-parse.js +0 -162
  288. package/scripts/lib/plan-prevalidate-gates.js +0 -337
  289. package/scripts/lib/plan-run-core.js +0 -125
  290. package/scripts/lib/plan-run-report.js +0 -119
  291. package/scripts/plan-approve.js +0 -24
  292. package/scripts/plan-archive.js +0 -49
  293. package/scripts/plan-run.js +0 -13
  294. package/scripts/plan-set-actor.js +0 -21
  295. package/scripts/plan-validate.js +0 -80
  296. package/scripts/pnpm/af.mjs +0 -110
  297. package/scripts/pnpm/check-quiet.mjs +0 -32
  298. package/scripts/pnpm/dev-install.mjs +0 -29
  299. package/scripts/pnpm/dev-reload.mjs +0 -18
  300. package/scripts/pnpm/help.mjs +0 -55
  301. package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
  302. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
  303. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
  304. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
  305. package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
  306. package/scripts/pnpm/lib/spinner.mjs +0 -42
  307. package/scripts/pnpm-global-remove.js +0 -48
  308. package/scripts/stage_builder_api_for_docker.js +0 -65
  309. package/scripts/sync-builder-api-template.js +0 -44
  310. package/scripts/test-dataplane-bootstrap.js +0 -331
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Compile a BID from discovery answer bindings (suite / Intent payload).
3
+ * @fileoverview Deterministic discovery → aifabrix.builder.integrationDefinition
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const crypto = require('crypto');
9
+ const { emitSuiteBid } = require('./emit-suite-bid');
10
+
11
+ const DEFAULT_GATES = [
12
+ 'GP',
13
+ 'G1',
14
+ 'G2',
15
+ 'G3',
16
+ 'G4',
17
+ 'G5',
18
+ 'G6',
19
+ 'G7',
20
+ 'G8',
21
+ 'G9',
22
+ 'G10',
23
+ 'G11',
24
+ 'G12'
25
+ ];
26
+
27
+ /**
28
+ * @param {unknown} value
29
+ * @returns {unknown}
30
+ */
31
+ function unwrapBinding(value) {
32
+ if (value && typeof value === 'object' && !Array.isArray(value) && 'value' in value) {
33
+ return /** @type {{ value: unknown }} */ (value).value;
34
+ }
35
+ return value;
36
+ }
37
+
38
+ /**
39
+ * Flatten suite answers / Intent structuredPayload into discovery bindings.
40
+ * @param {unknown} answersOrPayload
41
+ * @returns {Record<string, unknown>}
42
+ */
43
+ function discoveryBindingsFromAnswers(answersOrPayload) {
44
+ if (Array.isArray(answersOrPayload)) {
45
+ /** @type {Record<string, unknown>} */
46
+ const out = {};
47
+ for (const entry of answersOrPayload) {
48
+ if (!entry || typeof entry !== 'object') {
49
+ continue;
50
+ }
51
+ const when = /** @type {any} */ (entry).when;
52
+ const key = String((when && when.questionKey) || '').trim();
53
+ if (!key) {
54
+ continue;
55
+ }
56
+ const raw =
57
+ /** @type {any} */ (entry).value !== undefined
58
+ ? /** @type {any} */ (entry).value
59
+ : /** @type {any} */ (entry).answer;
60
+ out[key] = unwrapBinding(raw);
61
+ }
62
+ return out;
63
+ }
64
+ if (answersOrPayload && typeof answersOrPayload === 'object') {
65
+ /** @type {Record<string, unknown>} */
66
+ const out = {};
67
+ for (const [key, value] of Object.entries(answersOrPayload)) {
68
+ if (key.includes('.')) {
69
+ out[key] = unwrapBinding(value);
70
+ }
71
+ }
72
+ return out;
73
+ }
74
+ return {};
75
+ }
76
+
77
+ /**
78
+ * @param {Record<string, unknown>} bindings
79
+ * @returns {string[]}
80
+ */
81
+ function resolveApiGroups(bindings) {
82
+ const raw = bindings['system.apiGroups'];
83
+ if (Array.isArray(raw)) {
84
+ return raw.map((row) => String(row || '').trim()).filter(Boolean);
85
+ }
86
+ if (typeof raw === 'string' && raw.trim()) {
87
+ return [raw.trim()];
88
+ }
89
+ return [];
90
+ }
91
+
92
+ /**
93
+ * @param {Record<string, unknown>} bindings
94
+ * @param {string[]} groups
95
+ * @param {Record<string, string>} openapiSourceRefs
96
+ * @returns {object[]}
97
+ */
98
+ function buildDatasources(bindings, groups, openapiSourceRefs) {
99
+ const resourceTypes =
100
+ bindings['system.resourceTypes'] &&
101
+ typeof bindings['system.resourceTypes'] === 'object' &&
102
+ !Array.isArray(bindings['system.resourceTypes'])
103
+ ? /** @type {Record<string, unknown>} */ (bindings['system.resourceTypes'])
104
+ : {};
105
+ return groups.map((key) => {
106
+ const resourceType = String(resourceTypes[key] || key);
107
+ const openapiSourceRef =
108
+ (typeof openapiSourceRefs[key] === 'string' && openapiSourceRefs[key].trim()) ||
109
+ undefined;
110
+ const row = {
111
+ key,
112
+ displayName: key.charAt(0).toUpperCase() + key.slice(1),
113
+ entityType: 'recordStorage',
114
+ resourceType
115
+ };
116
+ if (openapiSourceRef) {
117
+ /** @type {any} */ (row).openapiSourceRef = openapiSourceRef;
118
+ }
119
+ const propertyKeys = bindings[`datasource.${key}.propertyKeys`];
120
+ if (Array.isArray(propertyKeys) && propertyKeys.length > 0) {
121
+ /** @type {any} */ (row).propertyKeys = propertyKeys
122
+ .map((item) => String(item || '').trim())
123
+ .filter(Boolean);
124
+ }
125
+ return row;
126
+ });
127
+ }
128
+
129
+ /**
130
+ * @param {Record<string, unknown>} bindings
131
+ * @returns {object[]}
132
+ */
133
+ function buildRelationships(bindings) {
134
+ const raw = bindings['system.relationships'];
135
+ if (!Array.isArray(raw)) {
136
+ return [];
137
+ }
138
+ return raw
139
+ .filter((row) => row && typeof row === 'object')
140
+ .map((row) => ({
141
+ from: String(/** @type {any} */ (row).from || ''),
142
+ to: String(/** @type {any} */ (row).to || ''),
143
+ kind: String(/** @type {any} */ (row).kind || '')
144
+ }))
145
+ .filter((row) => row.from && row.to && row.kind);
146
+ }
147
+
148
+ /**
149
+ * @param {string[]} groups
150
+ * @param {Record<string, unknown>} bindings
151
+ * @returns {Record<string, string[]>}
152
+ */
153
+ function buildCapabilities(groups, bindings) {
154
+ /** @type {Record<string, string[]>} */
155
+ const caps = {};
156
+ const named = String(bindings['system.namedWriteCapability'] || '').trim();
157
+ const [writeDs, writeCap] = named.includes('.')
158
+ ? named.split('.', 2)
159
+ : ['', ''];
160
+ for (const key of groups) {
161
+ const list = ['list', 'get'];
162
+ if (writeDs === key && writeCap) {
163
+ list.push(writeCap);
164
+ if (writeCap === 'createBasic') {
165
+ list.push('updateBasic', 'delete');
166
+ }
167
+ }
168
+ caps[key] = list;
169
+ }
170
+ return caps;
171
+ }
172
+
173
+ /**
174
+ * True when minimum discovery bindings exist for BID emission.
175
+ * @param {unknown} answersOrPayload
176
+ * @returns {boolean}
177
+ */
178
+ function discoveryReadyForBid(answersOrPayload) {
179
+ const bindings = discoveryBindingsFromAnswers(answersOrPayload);
180
+ if (resolveApiGroups(bindings).length === 0) {
181
+ return false;
182
+ }
183
+ if (!bindings['system.syncMode']) {
184
+ return false;
185
+ }
186
+ const resourceTypes = bindings['system.resourceTypes'];
187
+ if (!resourceTypes || typeof resourceTypes !== 'object' || Array.isArray(resourceTypes)) {
188
+ return false;
189
+ }
190
+ return Object.keys(resourceTypes).length > 0;
191
+ }
192
+
193
+ /**
194
+ * @param {Record<string, unknown>} bindings
195
+ * @param {string} key
196
+ * @returns {Record<string, string>}
197
+ */
198
+ function stringMapBinding(bindings, key) {
199
+ const raw = bindings[key];
200
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
201
+ return {};
202
+ }
203
+ /** @type {Record<string, string>} */
204
+ const out = {};
205
+ for (const [mapKey, value] of Object.entries(raw)) {
206
+ const trimmedKey = String(mapKey || '').trim();
207
+ const trimmedValue = String(value || '').trim();
208
+ if (trimmedKey && trimmedValue) {
209
+ out[trimmedKey] = trimmedValue;
210
+ }
211
+ }
212
+ return out;
213
+ }
214
+
215
+ function mergeStringMapRefs(fromBindings, fromOptions, fallback) {
216
+ if (fromOptions && typeof fromOptions === 'object') {
217
+ return { ...fromBindings, ...fromOptions };
218
+ }
219
+ if (Object.keys(fromBindings).length > 0) {
220
+ return fromBindings;
221
+ }
222
+ return fallback;
223
+ }
224
+
225
+ /**
226
+ * Compile BID from discovery bindings + package options.
227
+ * Builder-owned SSOT (not dataplane Runtime).
228
+ * @param {Object} options
229
+ * @param {unknown} [options.answers]
230
+ * @param {Record<string, unknown>} [options.bindings]
231
+ * @param {string} options.systemKey
232
+ * @param {string} [options.displayName]
233
+ * @param {string} [options.packageVersion]
234
+ * @param {string} [options.systemKind]
235
+ * @param {Record<string, string>} [options.connectionRefs]
236
+ * @param {Record<string, string>} [options.openapiSourceRefs]
237
+ * @param {string} options.suiteRunId
238
+ * @param {string} [options.definitionId]
239
+ * @param {string} [options.btAssistantKey]
240
+ * @param {string[]} [options.knowledgePackRefs]
241
+ * @returns {Record<string, unknown>}
242
+ */
243
+ function resolveBidInputs(options) {
244
+ const systemKey = String(options.systemKey || '').trim();
245
+ const suiteRunId = String(options.suiteRunId || '').trim();
246
+ if (!systemKey) {
247
+ throw new Error('bidFromDiscovery requires systemKey');
248
+ }
249
+ if (!suiteRunId) {
250
+ throw new Error('bidFromDiscovery requires suiteRunId');
251
+ }
252
+ const bindings = {
253
+ ...discoveryBindingsFromAnswers(options.answers),
254
+ ...(options.bindings && typeof options.bindings === 'object' ? options.bindings : {})
255
+ };
256
+ if (!discoveryReadyForBid(bindings)) {
257
+ throw new Error('bidFromDiscovery requires complete discovery bindings');
258
+ }
259
+ return {
260
+ systemKey,
261
+ suiteRunId,
262
+ bindings,
263
+ groups: resolveApiGroups(bindings),
264
+ syncMode: String(bindings['system.syncMode'] || 'incremental').trim() || 'incremental',
265
+ displayName: String(options.displayName || '').trim() || systemKey,
266
+ openapiSourceRefs: mergeStringMapRefs(
267
+ stringMapBinding(bindings, 'system.openapiSourceRefs'),
268
+ options.openapiSourceRefs,
269
+ {}
270
+ ),
271
+ connectionRefs: mergeStringMapRefs(
272
+ stringMapBinding(bindings, 'system.connectionRefs'),
273
+ options.connectionRefs,
274
+ { token: `kv://${systemKey}/token` }
275
+ )
276
+ };
277
+ }
278
+
279
+ function buildDiscoveryBidDraft(options, inputs) {
280
+ const {
281
+ systemKey,
282
+ groups,
283
+ bindings,
284
+ syncMode,
285
+ displayName,
286
+ openapiSourceRefs,
287
+ connectionRefs
288
+ } = inputs;
289
+ const draft = {
290
+ schemaName: 'aifabrix.builder.integrationDefinition',
291
+ schemaVersion: '1.0.0',
292
+ definitionId:
293
+ String(options.definitionId || '').trim() || crypto.randomUUID(),
294
+ meta: {
295
+ suiteRunId: 'pending',
296
+ producedAt: new Date().toISOString(),
297
+ btAssistantKey: options.btAssistantKey || 'ra-business-transformation',
298
+ knowledgePackRefs: Array.isArray(options.knowledgePackRefs)
299
+ ? options.knowledgePackRefs
300
+ : ['role-assistant/ra-business-transformation/knowledge/']
301
+ },
302
+ packageIdentity: {
303
+ systemKey,
304
+ packageVersion: String(options.packageVersion || '0.1.0'),
305
+ displayName
306
+ },
307
+ system: {
308
+ key: systemKey,
309
+ displayName,
310
+ systemKind: String(options.systemKind || 'crm'),
311
+ type: 'openapi',
312
+ connectionRefs
313
+ },
314
+ datasources: buildDatasources(bindings, groups, openapiSourceRefs),
315
+ relationships: buildRelationships(bindings),
316
+ sync: { mode: syncMode, datasources: groups },
317
+ capabilities: buildCapabilities(groups, bindings),
318
+ authority: { writeRequiresUserAuthority: true },
319
+ acceptance: { gates: DEFAULT_GATES }
320
+ };
321
+ return draft;
322
+ }
323
+
324
+ function bidFromDiscovery(options = {}) {
325
+ const inputs = resolveBidInputs(options);
326
+ const draft = buildDiscoveryBidDraft(options, inputs);
327
+ return emitSuiteBid(draft, {
328
+ suiteRunId: inputs.suiteRunId,
329
+ btAssistantKey: draft.meta.btAssistantKey,
330
+ answers: options.answers || inputs.bindings
331
+ });
332
+ }
333
+
334
+ module.exports = {
335
+ bidFromDiscovery,
336
+ discoveryBindingsFromAnswers,
337
+ discoveryReadyForBid,
338
+ unwrapBinding
339
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * BID definitionHash helpers.
3
+ * @fileoverview SHA-256 hash for aifabrix.builder.integrationDefinition
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const crypto = require('crypto');
9
+ const { canonicalJsonString, bidBodyWithoutHash } = require('./canonical-json');
10
+
11
+ /**
12
+ * Compute definitionHash for a BID object (excludes definitionHash field).
13
+ * @param {Record<string, unknown>} bid
14
+ * @returns {string} sha256:<hex>
15
+ */
16
+ function computeDefinitionHash(bid) {
17
+ const body = bidBodyWithoutHash(bid);
18
+ const digest = crypto.createHash('sha256').update(canonicalJsonString(body), 'utf8').digest('hex');
19
+ return `sha256:${digest}`;
20
+ }
21
+
22
+ /**
23
+ * Attach or refresh definitionHash on a BID object (mutates and returns).
24
+ * @param {Record<string, unknown>} bid
25
+ * @returns {Record<string, unknown>}
26
+ */
27
+ function withDefinitionHash(bid) {
28
+ const next = { ...bid };
29
+ delete next.definitionHash;
30
+ next.definitionHash = computeDefinitionHash(next);
31
+ return next;
32
+ }
33
+
34
+ module.exports = {
35
+ computeDefinitionHash,
36
+ withDefinitionHash
37
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Builder Integration Definition (BID) public API.
3
+ * @fileoverview aifabrix.builder.integrationDefinition v1.0.0
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { applyIntegrationDefinition, STAMP_FILE } = require('./apply');
9
+ const { computeDefinitionHash, withDefinitionHash } = require('./hash');
10
+ const { emitSuiteBid, fingerprintAnswers } = require('./emit-suite-bid');
11
+ const {
12
+ bidFromDiscovery,
13
+ discoveryBindingsFromAnswers,
14
+ discoveryReadyForBid
15
+ } = require('./from-discovery');
16
+ const {
17
+ validateIntegrationDefinition,
18
+ resetIntegrationDefinitionValidator,
19
+ INTEGRATION_DEFINITION_SCHEMA_NAME,
20
+ INTEGRATION_DEFINITION_SCHEMA_VERSION
21
+ } = require('./validate');
22
+
23
+ module.exports = {
24
+ applyIntegrationDefinition,
25
+ computeDefinitionHash,
26
+ withDefinitionHash,
27
+ emitSuiteBid,
28
+ fingerprintAnswers,
29
+ bidFromDiscovery,
30
+ discoveryBindingsFromAnswers,
31
+ discoveryReadyForBid,
32
+ validateIntegrationDefinition,
33
+ resetIntegrationDefinitionValidator,
34
+ INTEGRATION_DEFINITION_SCHEMA_NAME,
35
+ INTEGRATION_DEFINITION_SCHEMA_VERSION,
36
+ STAMP_FILE
37
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Offline resource-type catalog keys for BID product rules (same SSOT as help topic).
3
+ * @fileoverview Active keys from docs/builder-help/resource-type-catalog.json
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { loadResourceTypeCatalog } = require('../programmatic/builder-help-governance');
9
+
10
+ /** @type {Set<string>|null} */
11
+ let cachedActiveKeys = null;
12
+
13
+ /**
14
+ * @returns {Set<string>}
15
+ */
16
+ function getActiveResourceTypeKeys() {
17
+ if (cachedActiveKeys) {
18
+ return cachedActiveKeys;
19
+ }
20
+ const catalog = loadResourceTypeCatalog();
21
+ const keys = new Set();
22
+ for (const row of catalog.resourceTypes || []) {
23
+ if (!row || typeof row !== 'object') {
24
+ continue;
25
+ }
26
+ const key = String(row.key || '').trim();
27
+ const status = String(row.status || 'active').trim().toLowerCase();
28
+ if (key && status === 'active') {
29
+ keys.add(key);
30
+ }
31
+ }
32
+ cachedActiveKeys = keys;
33
+ return cachedActiveKeys;
34
+ }
35
+
36
+ /**
37
+ * Reset cache (tests).
38
+ */
39
+ function resetResourceTypeCatalogCache() {
40
+ cachedActiveKeys = null;
41
+ }
42
+
43
+ /**
44
+ * @param {string} key
45
+ * @returns {boolean}
46
+ */
47
+ function isActiveResourceTypeKey(key) {
48
+ const normalized = String(key || '').trim();
49
+ if (!normalized) {
50
+ return false;
51
+ }
52
+ return getActiveResourceTypeKeys().has(normalized);
53
+ }
54
+
55
+ module.exports = {
56
+ getActiveResourceTypeKeys,
57
+ isActiveResourceTypeKey,
58
+ resetResourceTypeCatalogCache
59
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Enterprise systemKind enum shared with external-system.schema.json.
3
+ * @fileoverview Load allowed systemKind values for BID product rules
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const externalSystemSchema = require('../schema/external-system.schema.json');
9
+
10
+ /** @type {Set<string>|null} */
11
+ let cachedKinds = null;
12
+
13
+ /**
14
+ * @returns {Set<string>}
15
+ */
16
+ function getAllowedSystemKinds() {
17
+ if (cachedKinds) {
18
+ return cachedKinds;
19
+ }
20
+ const values = externalSystemSchema?.properties?.systemKind?.enum;
21
+ cachedKinds = new Set(Array.isArray(values) ? values.map(String) : []);
22
+ return cachedKinds;
23
+ }
24
+
25
+ /**
26
+ * @param {string} kind
27
+ * @returns {boolean}
28
+ */
29
+ function isAllowedSystemKind(kind) {
30
+ const normalized = String(kind || '').trim();
31
+ if (!normalized) {
32
+ return false;
33
+ }
34
+ return getAllowedSystemKinds().has(normalized);
35
+ }
36
+
37
+ module.exports = {
38
+ getAllowedSystemKinds,
39
+ isAllowedSystemKind
40
+ };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Validate Builder Integration Definition (BID) v1.0.0.
3
+ * @fileoverview AJV + hash + product rules for BID
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Ajv = require('ajv');
9
+ const addFormats = require('ajv-formats');
10
+ const schema = require('../schema/integration-definition.schema.json');
11
+ const { computeDefinitionHash } = require('./hash');
12
+ const { isActiveResourceTypeKey } = require('./resource-type-catalog');
13
+ const { isAllowedSystemKind } = require('./system-kind-enum');
14
+
15
+ const GOLD_PATH_RE = /test-e2e-hubspot|knownPlatform|builder-hp-goal/i;
16
+
17
+ let cachedValidator = null;
18
+
19
+ /**
20
+ * @returns {import('ajv').ValidateFunction}
21
+ */
22
+ function getValidator() {
23
+ if (cachedValidator) {
24
+ return cachedValidator;
25
+ }
26
+ const ajv = new Ajv({ allErrors: true, strict: false });
27
+ addFormats(ajv);
28
+ cachedValidator = ajv.compile(schema);
29
+ return cachedValidator;
30
+ }
31
+
32
+ /**
33
+ * Reset validator cache (tests).
34
+ */
35
+ function resetIntegrationDefinitionValidator() {
36
+ cachedValidator = null;
37
+ }
38
+
39
+ /**
40
+ * @param {Record<string, unknown>} doc
41
+ * @param {string[]} errors
42
+ * @returns {void}
43
+ */
44
+ function appendAjvErrors(doc, errors) {
45
+ const validate = getValidator();
46
+ if (validate(doc)) {
47
+ return;
48
+ }
49
+ for (const err of validate.errors || []) {
50
+ errors.push(`${err.instancePath || '/'} ${err.message}`);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * @param {Record<string, unknown>} doc
56
+ * @param {string[]} errors
57
+ * @returns {void}
58
+ */
59
+ function appendIdentityAndHashErrors(doc, errors) {
60
+ if (doc.schemaVersion !== '1.0.0') {
61
+ errors.push(`Unsupported schemaVersion ${String(doc.schemaVersion)}; expected 1.0.0`);
62
+ }
63
+ const expectedHash = computeDefinitionHash(doc);
64
+ if (doc.definitionHash !== expectedHash) {
65
+ errors.push(`definitionHash mismatch: expected ${expectedHash}`);
66
+ }
67
+ const identity = /** @type {Record<string, unknown>} */ (doc.packageIdentity || {});
68
+ const system = /** @type {Record<string, unknown>} */ (doc.system || {});
69
+ if (identity.systemKey && system.key && identity.systemKey !== system.key) {
70
+ errors.push('packageIdentity.systemKey must match system.key');
71
+ }
72
+ }
73
+
74
+ /**
75
+ * @param {Record<string, unknown>} doc
76
+ * @param {string[]} errors
77
+ * @returns {void}
78
+ */
79
+ function appendProductRuleErrors(doc, errors) {
80
+ const blob = JSON.stringify(doc);
81
+ if (GOLD_PATH_RE.test(blob)) {
82
+ errors.push(
83
+ 'BID must not embed gold package paths or knownPlatform generation sources'
84
+ );
85
+ }
86
+ if (typeof doc.sync === 'object' && doc.sync && /** @type {any} */ (doc.sync).mode !== 'incremental') {
87
+ errors.push('sync.mode must be incremental');
88
+ }
89
+ }
90
+
91
+ /**
92
+ * @param {Record<string, unknown>} doc
93
+ * @param {string[]} errors
94
+ * @returns {void}
95
+ */
96
+ function appendCatalogAndKindErrors(doc, errors) {
97
+ const system = /** @type {Record<string, unknown>} */ (doc.system || {});
98
+ if (system.systemKind !== undefined && system.systemKind !== null && system.systemKind !== '') {
99
+ if (!isAllowedSystemKind(String(system.systemKind))) {
100
+ errors.push(
101
+ `system.systemKind '${String(system.systemKind)}' is not an enterprise catalog value (see external-system.schema.json)`
102
+ );
103
+ }
104
+ }
105
+ const datasources = Array.isArray(doc.datasources) ? doc.datasources : [];
106
+ datasources.forEach((row, index) => {
107
+ if (!row || typeof row !== 'object') {
108
+ return;
109
+ }
110
+ const resourceType = /** @type {Record<string, unknown>} */ (row).resourceType;
111
+ if (resourceType === undefined || resourceType === null || resourceType === '') {
112
+ return;
113
+ }
114
+ const key = String(resourceType);
115
+ if (!isActiveResourceTypeKey(key)) {
116
+ errors.push(
117
+ `datasources[${index}].resourceType '${key}' is not an active catalog key (GET /help?topic=resourceTypeCatalog)`
118
+ );
119
+ }
120
+ });
121
+ }
122
+
123
+ /**
124
+ * @param {unknown} bid
125
+ * @returns {{ valid: true, bid: Record<string, unknown> } | { valid: false, errors: string[] }}
126
+ */
127
+ function validateIntegrationDefinition(bid) {
128
+ const errors = [];
129
+ if (!bid || typeof bid !== 'object') {
130
+ return { valid: false, errors: ['BID must be an object'] };
131
+ }
132
+ const doc = /** @type {Record<string, unknown>} */ (bid);
133
+ appendAjvErrors(doc, errors);
134
+ appendIdentityAndHashErrors(doc, errors);
135
+ appendProductRuleErrors(doc, errors);
136
+ appendCatalogAndKindErrors(doc, errors);
137
+ if (errors.length) {
138
+ return { valid: false, errors };
139
+ }
140
+ return { valid: true, bid: doc };
141
+ }
142
+
143
+ module.exports = {
144
+ validateIntegrationDefinition,
145
+ resetIntegrationDefinitionValidator,
146
+ INTEGRATION_DEFINITION_SCHEMA_NAME: 'aifabrix.builder.integrationDefinition',
147
+ INTEGRATION_DEFINITION_SCHEMA_VERSION: '1.0.0'
148
+ };