@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,51 @@
1
+ /**
2
+ * Canonical JSON helpers for Builder Integration Definition hashing.
3
+ * @fileoverview Stable stringify for BID definitionHash
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ /**
9
+ * Recursively sort object keys for canonical JSON.
10
+ * @param {unknown} value
11
+ * @returns {unknown}
12
+ */
13
+ function sortValue(value) {
14
+ if (Array.isArray(value)) {
15
+ return value.map(sortValue);
16
+ }
17
+ if (value && typeof value === 'object' && !(value instanceof Date)) {
18
+ const out = {};
19
+ for (const key of Object.keys(value).sort()) {
20
+ out[key] = sortValue(value[key]);
21
+ }
22
+ return out;
23
+ }
24
+ return value;
25
+ }
26
+
27
+ /**
28
+ * Canonical JSON string (sorted keys, no whitespace variance).
29
+ * @param {unknown} value
30
+ * @returns {string}
31
+ */
32
+ function canonicalJsonString(value) {
33
+ return JSON.stringify(sortValue(value));
34
+ }
35
+
36
+ /**
37
+ * Clone BID without definitionHash for hashing.
38
+ * @param {Record<string, unknown>} bid
39
+ * @returns {Record<string, unknown>}
40
+ */
41
+ function bidBodyWithoutHash(bid) {
42
+ const clone = { ...bid };
43
+ delete clone.definitionHash;
44
+ return clone;
45
+ }
46
+
47
+ module.exports = {
48
+ sortValue,
49
+ canonicalJsonString,
50
+ bidBodyWithoutHash
51
+ };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Stamp suite provenance onto a BID template for hard GP acceptance.
3
+ * @fileoverview Suite-emitted BID: suiteRunId + answerFingerprint + definitionHash
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const crypto = require('crypto');
9
+ const { withDefinitionHash } = require('./hash');
10
+ const { canonicalJsonString } = require('./canonical-json');
11
+
12
+ /**
13
+ * Fingerprint discovery / case answers for BID meta.answerFingerprint.
14
+ * @param {unknown} answers
15
+ * @returns {string}
16
+ */
17
+ function fingerprintAnswers(answers) {
18
+ const digest = crypto
19
+ .createHash('sha256')
20
+ .update(canonicalJsonString(answers === null || answers === undefined ? null : answers), 'utf8')
21
+ .digest('hex');
22
+ return `sha256:${digest}`;
23
+ }
24
+
25
+ function resolvePriorMeta(baseBid) {
26
+ return baseBid.meta && typeof baseBid.meta === 'object' && !Array.isArray(baseBid.meta)
27
+ ? baseBid.meta
28
+ : {};
29
+ }
30
+
31
+ function resolveAnswerFingerprint(options) {
32
+ if (typeof options.answerFingerprint === 'string' && options.answerFingerprint.trim()) {
33
+ return options.answerFingerprint.trim();
34
+ }
35
+ return fingerprintAnswers(options.answers);
36
+ }
37
+
38
+ function resolveProducedAt(options) {
39
+ if (typeof options.producedAt === 'string' && options.producedAt.trim()) {
40
+ return options.producedAt.trim();
41
+ }
42
+ return new Date().toISOString();
43
+ }
44
+
45
+ function resolveBtAssistantKey(options, priorMeta) {
46
+ if (typeof options.btAssistantKey === 'string' && options.btAssistantKey.trim()) {
47
+ return options.btAssistantKey.trim();
48
+ }
49
+ if (typeof priorMeta.btAssistantKey === 'string' && priorMeta.btAssistantKey.trim()) {
50
+ return priorMeta.btAssistantKey.trim();
51
+ }
52
+ return 'ra-business-transformation';
53
+ }
54
+
55
+ /**
56
+ * Clone a BID template and stamp suite provenance (hard GP).
57
+ * Does not invent datasources/capabilities — only meta + hash refresh.
58
+ *
59
+ * @param {Record<string, unknown>} baseBid - Valid BID template (e.g. example-bid.json)
60
+ * @param {Object} options
61
+ * @param {string} options.suiteRunId - Suite / processExecution id (required for hard GP)
62
+ * @param {string} [options.producedAt] - ISO timestamp
63
+ * @param {string} [options.btAssistantKey]
64
+ * @param {unknown} [options.answers] - Case answers for answerFingerprint
65
+ * @param {string} [options.answerFingerprint] - Explicit fingerprint override
66
+ * @returns {Record<string, unknown>}
67
+ */
68
+ function emitSuiteBid(baseBid, options = {}) {
69
+ if (!baseBid || typeof baseBid !== 'object' || Array.isArray(baseBid)) {
70
+ throw new Error('emitSuiteBid requires a BID object');
71
+ }
72
+ const suiteRunId = String(options.suiteRunId || '').trim();
73
+ if (!suiteRunId) {
74
+ throw new Error('emitSuiteBid requires options.suiteRunId');
75
+ }
76
+ const priorMeta = resolvePriorMeta(baseBid);
77
+ const next = {
78
+ ...baseBid,
79
+ meta: {
80
+ ...priorMeta,
81
+ suiteRunId,
82
+ producedAt: resolveProducedAt(options),
83
+ btAssistantKey: resolveBtAssistantKey(options, priorMeta),
84
+ answerFingerprint: resolveAnswerFingerprint(options)
85
+ }
86
+ };
87
+ delete next.definitionHash;
88
+ return withDefinitionHash(next);
89
+ }
90
+
91
+ module.exports = {
92
+ emitSuiteBid,
93
+ fingerprintAnswers
94
+ };
@@ -0,0 +1,240 @@
1
+ /**
2
+ * CRM-style fieldMappings + properties query for OpenAPI object APIs.
3
+ * @fileoverview Keep BID propertyKeys durable across force-apply
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const RESERVED_ATTR = new Set(['id', 'externalId', 'associations']);
9
+
10
+ /**
11
+ * Seed metadataSchema + fieldMappings.attributes from BID propertyKeys.
12
+ * Does not write dimensions[] (repair / enrich owns dimensions alignment).
13
+ * @param {Record<string, unknown>} body
14
+ * @param {unknown} propertyKeys
15
+ * @returns {void}
16
+ */
17
+ function seedPropertyKeysOnDatasource(body, propertyKeys) {
18
+ const keys = Array.isArray(propertyKeys)
19
+ ? propertyKeys.map((row) => String(row || '').trim()).filter(Boolean)
20
+ : [];
21
+ if (keys.length === 0) {
22
+ return;
23
+ }
24
+ if (!body.metadataSchema || typeof body.metadataSchema !== 'object') {
25
+ body.metadataSchema = { type: 'object', properties: {} };
26
+ }
27
+ const schema = /** @type {any} */ (body.metadataSchema);
28
+ if (!schema.properties || typeof schema.properties !== 'object') {
29
+ schema.properties = {};
30
+ }
31
+ if (!body.fieldMappings || typeof body.fieldMappings !== 'object') {
32
+ body.fieldMappings = { attributes: {} };
33
+ }
34
+ const mappings = /** @type {any} */ (body.fieldMappings);
35
+ if (!mappings.attributes || typeof mappings.attributes !== 'object') {
36
+ mappings.attributes = {};
37
+ }
38
+ for (const key of keys) {
39
+ if (!schema.properties[key]) {
40
+ schema.properties[key] = {
41
+ type: 'string',
42
+ index: true,
43
+ filter: true,
44
+ description: `Synced property ${key}`
45
+ };
46
+ }
47
+ if (!mappings.attributes[key]) {
48
+ mappings.attributes[key] = {
49
+ expression: `{{raw.${key}}}`,
50
+ description: `Synced property ${key}`
51
+ };
52
+ }
53
+ }
54
+ }
55
+
56
+ function mappingAttributes(body) {
57
+ const mappings = /** @type {any} */ (body.fieldMappings);
58
+ if (mappings && mappings.attributes && typeof mappings.attributes === 'object') {
59
+ return mappings.attributes;
60
+ }
61
+ return {};
62
+ }
63
+
64
+ function propertyNameFromAttr(key, row) {
65
+ const expr =
66
+ row && typeof row === 'object' ? String(/** @type {any} */ (row).expression || '') : '';
67
+ const match = expr.match(/\{\{\s*raw\.properties\.([a-zA-Z0-9_]+)\s*\}\}/);
68
+ if (match) {
69
+ return match[1];
70
+ }
71
+ if (expr === `{{raw.${key}}}` || expr.includes(`raw.properties.${key}`)) {
72
+ return key;
73
+ }
74
+ return null;
75
+ }
76
+
77
+ /**
78
+ * Collect vendor property names from CRM-style attribute expressions + labelKey.
79
+ * @param {Record<string, unknown>} body
80
+ * @returns {string[]}
81
+ */
82
+ function collectCrmPropertyNames(body) {
83
+ const names = new Set();
84
+ const labelKeys = Array.isArray(body.labelKey) ? body.labelKey : [];
85
+ for (const label of labelKeys) {
86
+ const key = String(label || '').trim();
87
+ if (key) {
88
+ names.add(key);
89
+ }
90
+ }
91
+ for (const [key, row] of Object.entries(mappingAttributes(body))) {
92
+ if (RESERVED_ATTR.has(key)) {
93
+ continue;
94
+ }
95
+ const name = propertyNameFromAttr(key, row);
96
+ if (name) {
97
+ names.add(name);
98
+ }
99
+ }
100
+ return [...names].sort();
101
+ }
102
+
103
+ function ensureCrmPropertiesBag(schema) {
104
+ if (!schema || !schema.properties || typeof schema.properties !== 'object') {
105
+ return;
106
+ }
107
+ schema.properties.properties = {
108
+ type: 'object',
109
+ additionalProperties: true,
110
+ description: 'Vendor nested properties bag (CRM object APIs)'
111
+ };
112
+ schema.properties.associations = {
113
+ type: 'object',
114
+ additionalProperties: true,
115
+ description: 'Associated records bag from vendor list/get'
116
+ };
117
+ }
118
+
119
+ function rewriteCrmLabelExpressions(mappings, labelKeys) {
120
+ for (const label of labelKeys) {
121
+ if (mappings.attributes[label]) {
122
+ mappings.attributes[label].expression = `{{raw.properties.${label}}}`;
123
+ mappings.attributes[label].description =
124
+ 'Display label from vendor properties object';
125
+ }
126
+ }
127
+ }
128
+
129
+ function rewriteCrmAttributeExpressions(mappings, labelKeys) {
130
+ for (const [key, row] of Object.entries(mappings.attributes)) {
131
+ if (RESERVED_ATTR.has(key) || labelKeys.includes(key) || !row || typeof row !== 'object') {
132
+ continue;
133
+ }
134
+ const expr = String(/** @type {any} */ (row).expression || '');
135
+ if (expr === `{{raw.${key}}}` || !expr.includes('raw.properties.')) {
136
+ /** @type {any} */ (row).expression = `{{raw.properties.${key}}}`;
137
+ if (!/** @type {any} */ (row).description) {
138
+ /** @type {any} */ (row).description = `Synced property ${key}`;
139
+ }
140
+ }
141
+ }
142
+ }
143
+
144
+ function ensureCrmIdentityMappings(mappings) {
145
+ if (mappings.attributes.id) {
146
+ mappings.attributes.id.expression = '{{raw.id}}';
147
+ }
148
+ if (mappings.attributes.externalId) {
149
+ mappings.attributes.externalId.expression = '{{raw.id}}';
150
+ }
151
+ if (!mappings.attributes.associations) {
152
+ mappings.attributes.associations = {
153
+ expression: '{{raw.associations}}',
154
+ description: 'Associated records returned when OpenAPI associations query is set'
155
+ };
156
+ }
157
+ }
158
+
159
+ /**
160
+ * When collection paths look like CRM object APIs, prefer nested properties for labels
161
+ * and request those properties on list/get CIP queries.
162
+ * @param {Record<string, unknown>} body
163
+ * @param {string} samplePath
164
+ * @returns {void}
165
+ */
166
+ function maybeEnrichCrmStyleFieldMappings(body, samplePath) {
167
+ if (!/\/objects\//i.test(samplePath)) {
168
+ return;
169
+ }
170
+ const mappings = /** @type {any} */ (body.fieldMappings);
171
+ if (!mappings || !mappings.attributes || typeof mappings.attributes !== 'object') {
172
+ return;
173
+ }
174
+ const labelKeys = Array.isArray(body.labelKey) ? body.labelKey : ['name'];
175
+ ensureCrmPropertiesBag(/** @type {any} */ (body.metadataSchema));
176
+ rewriteCrmLabelExpressions(mappings, labelKeys);
177
+ rewriteCrmAttributeExpressions(mappings, labelKeys);
178
+ ensureCrmIdentityMappings(mappings);
179
+ applyCrmPropertiesQuery(body);
180
+ }
181
+
182
+ function resolveCipOperations(body) {
183
+ if (
184
+ body.execution &&
185
+ typeof body.execution === 'object' &&
186
+ /** @type {any} */ (body.execution).cip &&
187
+ typeof /** @type {any} */ (body.execution).cip === 'object'
188
+ ) {
189
+ return /** @type {any} */ (body.execution).cip.operations;
190
+ }
191
+ return null;
192
+ }
193
+
194
+ function applyPropertiesToFetchSteps(op, joined) {
195
+ if (!op || typeof op !== 'object' || !Array.isArray(/** @type {any} */ (op).steps)) {
196
+ return;
197
+ }
198
+ for (const step of /** @type {any} */ (op).steps) {
199
+ if (!step || !step.fetch || typeof step.fetch !== 'object') {
200
+ continue;
201
+ }
202
+ if (!step.fetch.query || typeof step.fetch.query !== 'object') {
203
+ step.fetch.query = {};
204
+ }
205
+ step.fetch.query.properties = joined;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Set CIP list/get query.properties from mapped CRM property names.
211
+ * @param {Record<string, unknown>} body
212
+ * @returns {void}
213
+ */
214
+ function applyCrmPropertiesQuery(body) {
215
+ const propertyNames = collectCrmPropertyNames(body);
216
+ if (propertyNames.length === 0) {
217
+ return;
218
+ }
219
+ const cipOps = resolveCipOperations(body);
220
+ if (!cipOps || typeof cipOps !== 'object') {
221
+ return;
222
+ }
223
+ const joined = propertyNames.join(',');
224
+ for (const [capKey, op] of Object.entries(cipOps)) {
225
+ const leaf = String(capKey || '')
226
+ .split('.')
227
+ .pop()
228
+ .toLowerCase();
229
+ if (leaf === 'list' || leaf === 'get') {
230
+ applyPropertiesToFetchSteps(op, joined);
231
+ }
232
+ }
233
+ }
234
+
235
+ module.exports = {
236
+ seedPropertyKeysOnDatasource,
237
+ collectCrmPropertyNames,
238
+ maybeEnrichCrmStyleFieldMappings,
239
+ applyCrmPropertiesQuery
240
+ };