@aifabrix/builder 2.51.1 → 2.52.1

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 (187) hide show
  1. package/jest.isolated-projects.js +25 -2
  2. package/jest.projects.js +4 -1
  3. package/lib/api/datasources-extended.api.js +8 -8
  4. package/lib/api/keycloak.api.js +92 -0
  5. package/lib/api/token-providers.api.js +77 -0
  6. package/lib/api/types/keycloak.types.js +23 -0
  7. package/lib/api/types/token-providers.types.js +65 -0
  8. package/lib/app/down.js +16 -1
  9. package/lib/app/run-container-start.js +4 -0
  10. package/lib/app/run-deploy-job.js +135 -27
  11. package/lib/app/run-env-compose.js +32 -0
  12. package/lib/app/run-env-recovery.js +35 -0
  13. package/lib/app/run-helpers.js +5 -6
  14. package/lib/app/run.js +11 -3
  15. package/lib/channels/add-channel.js +126 -19
  16. package/lib/channels/approval-guides/chatgpt.js +12 -9
  17. package/lib/channels/approval-guides/microsoft-copilot.js +16 -12
  18. package/lib/channels/channel-add-ensure.js +128 -0
  19. package/lib/channels/channel-artifact-generator.js +11 -1
  20. package/lib/channels/channel-branding.js +94 -0
  21. package/lib/channels/channel-credential.js +8 -0
  22. package/lib/channels/channel-discovery.js +330 -0
  23. package/lib/channels/channel-external-system.js +1 -1
  24. package/lib/channels/channel-runtime-resolver.js +103 -14
  25. package/lib/channels/channel-status-display.js +7 -1
  26. package/lib/channels/channel-targets.js +18 -1
  27. package/lib/channels/chatgpt-runtime-contract.js +1 -1
  28. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  29. package/lib/channels/microsoft-copilot-entra-sso-form.js +180 -0
  30. package/lib/channels/microsoft-copilot-entra-sso.js +264 -0
  31. package/lib/channels/microsoft-copilot-icons.js +74 -0
  32. package/lib/channels/microsoft-copilot-limits.js +84 -0
  33. package/lib/channels/microsoft-copilot-package.js +130 -49
  34. package/lib/channels/microsoft-copilot-validate.js +197 -0
  35. package/lib/cli/index.js +2 -0
  36. package/lib/cli/infra-guided-footers.js +1 -1
  37. package/lib/cli/infra-guided-public-url-warn.js +55 -0
  38. package/lib/cli/infra-guided.js +78 -62
  39. package/lib/cli/setup-app.help.js +4 -0
  40. package/lib/cli/setup-app.test-commands.js +59 -28
  41. package/lib/cli/setup-external-system.js +50 -12
  42. package/lib/cli/setup-infra.js +31 -4
  43. package/lib/commands/channel-add-setup.js +35 -10
  44. package/lib/commands/channel.js +27 -12
  45. package/lib/commands/deploy-gate-orchestrator.js +3 -2
  46. package/lib/commands/governance-verify-external.js +2 -5
  47. package/lib/commands/integration-definition.js +158 -0
  48. package/lib/commands/lifecycle-external.js +14 -7
  49. package/lib/commands/repair-auth-apply.js +19 -5
  50. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  51. package/lib/commands/role-assistant-test-output.js +200 -0
  52. package/lib/commands/role-assistant.js +131 -114
  53. package/lib/commands/test-governance-external.js +2 -5
  54. package/lib/commands/up-miso.js +61 -24
  55. package/lib/commands/upload-data-sync-finalize.js +20 -3
  56. package/lib/commands/verify-governance-external.js +2 -5
  57. package/lib/commands/verify-operations-external.js +2 -5
  58. package/lib/commands/verify-operations-step-plan.js +31 -0
  59. package/lib/commands/verify-trust-command-action.js +2 -5
  60. package/lib/datasource/capability/capability-resolve.js +15 -5
  61. package/lib/datasource/capability/copy-operations.js +14 -4
  62. package/lib/datasource/datasource-identifier.js +4 -3
  63. package/lib/datasource/integration-context.js +3 -3
  64. package/lib/datasource/resolve-app.js +90 -8
  65. package/lib/datasource/test-e2e.js +2 -2
  66. package/lib/datasource/unified-validation-run-body.js +15 -1
  67. package/lib/datasource/unified-validation-run-resolve.js +2 -2
  68. package/lib/external-system/deploy-helpers.js +9 -5
  69. package/lib/external-system/deploy.js +2 -1
  70. package/lib/external-system/test-system-level.js +21 -3
  71. package/lib/external-system/test.js +4 -4
  72. package/lib/generator/builders.js +9 -15
  73. package/lib/infrastructure/index.js +19 -4
  74. package/lib/integration-definition/apply.js +478 -0
  75. package/lib/integration-definition/canonical-json.js +51 -0
  76. package/lib/integration-definition/emit-suite-bid.js +94 -0
  77. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  78. package/lib/integration-definition/enrich-openapi-operations.js +434 -0
  79. package/lib/integration-definition/from-discovery.js +339 -0
  80. package/lib/integration-definition/hash.js +37 -0
  81. package/lib/integration-definition/index.js +37 -0
  82. package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +205 -0
  83. package/lib/integration-definition/resource-type-catalog.js +59 -0
  84. package/lib/integration-definition/system-kind-enum.js +40 -0
  85. package/lib/integration-definition/validate.js +148 -0
  86. package/lib/programmatic/builder-api-request.js +5 -1
  87. package/lib/programmatic/builder-help-governance.js +3 -2
  88. package/lib/programmatic/capability-registry.js +19 -0
  89. package/lib/programmatic/openapi-component-schemas.js +6 -1
  90. package/lib/programmatic/openapi-descriptions.js +40 -0
  91. package/lib/programmatic/openapi-envelope-examples.js +269 -0
  92. package/lib/programmatic/openapi-operation-bindings.js +45 -0
  93. package/lib/programmatic/openapi-request-schemas.js +14 -0
  94. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  95. package/lib/programmatic/openapi-result-schemas.js +46 -99
  96. package/lib/programmatic/openapi-schema-descriptions-core.js +7 -4
  97. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  98. package/lib/programmatic/openapi-schema-descriptions-operations.js +24 -0
  99. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  100. package/lib/programmatic/openapi-spec.js +11 -1
  101. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  102. package/lib/programmatic/route-handler-map.js +29 -1
  103. package/lib/programmatic/run-channel-package.js +236 -0
  104. package/lib/programmatic/run-integration-definition.js +69 -0
  105. package/lib/role-assistant/knowledge-markdown-frontmatter.js +75 -0
  106. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  107. package/lib/role-assistant/knowledge-sync.js +104 -89
  108. package/lib/role-assistant/test-cases-bid.js +155 -0
  109. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  110. package/lib/role-assistant/test-cases-honesty.js +24 -10
  111. package/lib/role-assistant/test-cases.js +28 -0
  112. package/lib/role-assistant/test-runner-bid-apply.js +122 -0
  113. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  114. package/lib/role-assistant/test-runner-workhub-answers.js +289 -46
  115. package/lib/role-assistant/test-runner-workhub.js +121 -25
  116. package/lib/role-assistant/test-suite.js +119 -0
  117. package/lib/schema/application-schema.json +64 -32
  118. package/lib/schema/external-datasource.schema.json +103 -17
  119. package/lib/schema/external-system.schema.json +54 -3
  120. package/lib/schema/infra.parameter.yaml +0 -20
  121. package/lib/schema/integration-definition.schema.json +195 -0
  122. package/lib/utils/authentication-shape.js +6 -0
  123. package/lib/utils/certify-external-workspace.js +40 -0
  124. package/lib/utils/docker-build.js +3 -3
  125. package/lib/utils/docker-run-ephemeral.js +77 -17
  126. package/lib/utils/health-check-public-warn.js +31 -13
  127. package/lib/utils/health-check.js +11 -1
  128. package/lib/utils/help-builder.js +1 -0
  129. package/lib/utils/paths.js +13 -15
  130. package/lib/utils/promote-dev-docker-image.js +97 -18
  131. package/lib/utils/role-assistant-paths.js +76 -14
  132. package/lib/utils/transient-developer-id.js +28 -0
  133. package/lib/utils/upload-sync-options.js +7 -4
  134. package/lib/validation/reserved-system-key-prefixes.js +56 -0
  135. package/lib/validation/validate.js +54 -19
  136. package/package.json +1 -1
  137. package/scripts/pnpm/af.mjs +24 -9
  138. package/scripts/pnpm/help.mjs +1 -1
  139. package/templates/applications/builder-api/application.yaml +3 -3
  140. package/templates/applications/dataplane/application.yaml +5 -5
  141. package/templates/applications/dataplane/env.template +8 -7
  142. package/templates/applications/dataplane/rbac.yaml +10 -10
  143. package/templates/applications/keycloak/application.yaml +2 -2
  144. package/templates/applications/keycloak/env.template +5 -2
  145. package/templates/applications/miso-controller/application.yaml +25 -11
  146. package/templates/applications/miso-controller/env.template +24 -5
  147. package/templates/channels/README.md +11 -1
  148. package/templates/channels/brand/color-192.png +0 -0
  149. package/templates/channels/brand/dark/128.png +0 -0
  150. package/templates/channels/brand/dark/192.png +0 -0
  151. package/templates/channels/brand/dark/256.png +0 -0
  152. package/templates/channels/brand/dark/32.png +0 -0
  153. package/templates/channels/brand/dark/512.png +0 -0
  154. package/templates/channels/brand/dark/64.png +0 -0
  155. package/templates/channels/brand/light/128.png +0 -0
  156. package/templates/channels/brand/light/192.png +0 -0
  157. package/templates/channels/brand/light/256.png +0 -0
  158. package/templates/channels/brand/light/32.png +0 -0
  159. package/templates/channels/brand/light/512.png +0 -0
  160. package/templates/channels/brand/light/64.png +0 -0
  161. package/templates/channels/brand/mono-white/128.png +0 -0
  162. package/templates/channels/brand/mono-white/192.png +0 -0
  163. package/templates/channels/brand/mono-white/256.png +0 -0
  164. package/templates/channels/brand/mono-white/32.png +0 -0
  165. package/templates/channels/brand/mono-white/512.png +0 -0
  166. package/templates/channels/brand/mono-white/64.png +0 -0
  167. package/templates/channels/brand/outline-32.png +0 -0
  168. package/templates/channels/chatgpt/install.template.md.hbs +76 -36
  169. package/templates/channels/chatgpt/integration/README.md +4 -4
  170. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  171. package/templates/channels/chatgpt/manifest.template.json.hbs +3 -3
  172. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +10 -16
  173. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  174. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +27 -0
  175. package/templates/channels/microsoft-copilot/install.template.md.hbs +39 -20
  176. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  177. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  178. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +7 -7
  179. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +11 -0
  180. package/templates/channels/slack/install.template.md.hbs +6 -1
  181. package/templates/channels/slack/integration/README.md +2 -4
  182. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  183. package/templates/channels/teams-bot/integration/README.md +3 -5
  184. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  185. package/templates/python/docker-compose.hbs +10 -0
  186. package/templates/typescript/docker-compose.hbs +10 -0
  187. /package/.cursor/plans/{Done → Archive}/157.1-security-quality-violations-by-type.csv +0 -0
@@ -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,205 @@
1
+ {
2
+ "openapi": "3.0.1",
3
+ "info": {
4
+ "title": "CRM Companies (enrichment fixture)",
5
+ "version": "1.0.0"
6
+ },
7
+ "paths": {
8
+ "/crm/v3/objects/companies": {
9
+ "get": {
10
+ "operationId": "get-/crm/v3/objects/companies",
11
+ "summary": "List companies",
12
+ "parameters": [
13
+ {
14
+ "name": "limit",
15
+ "in": "query",
16
+ "schema": { "type": "integer" }
17
+ },
18
+ {
19
+ "name": "after",
20
+ "in": "query",
21
+ "schema": { "type": "string" }
22
+ },
23
+ {
24
+ "name": "properties",
25
+ "in": "query",
26
+ "schema": { "type": "string" }
27
+ },
28
+ {
29
+ "name": "associations",
30
+ "in": "query",
31
+ "schema": { "type": "string" }
32
+ }
33
+ ],
34
+ "responses": {
35
+ "200": {
36
+ "description": "Results use paging.next.after as the cursor for the next page.",
37
+ "content": {
38
+ "application/json": {
39
+ "schema": {
40
+ "type": "object",
41
+ "properties": {
42
+ "results": {
43
+ "type": "array",
44
+ "items": { "$ref": "#/components/schemas/Company" }
45
+ },
46
+ "paging": {
47
+ "type": "object",
48
+ "properties": {
49
+ "next": {
50
+ "type": "object",
51
+ "properties": {
52
+ "after": { "type": "string" }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ },
64
+ "post": {
65
+ "operationId": "post-/crm/v3/objects/companies",
66
+ "summary": "Create company",
67
+ "requestBody": {
68
+ "required": true,
69
+ "content": {
70
+ "application/json": {
71
+ "schema": {
72
+ "type": "object",
73
+ "properties": {
74
+ "properties": {
75
+ "type": "object",
76
+ "additionalProperties": { "type": "string" }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ },
83
+ "responses": {
84
+ "201": {
85
+ "description": "Created",
86
+ "content": {
87
+ "application/json": {
88
+ "schema": { "$ref": "#/components/schemas/Company" }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ },
95
+ "/crm/v3/objects/companies/{companyId}": {
96
+ "get": {
97
+ "operationId": "get-/crm/v3/objects/companies/{companyId}",
98
+ "summary": "Get company",
99
+ "parameters": [
100
+ {
101
+ "name": "companyId",
102
+ "in": "path",
103
+ "required": true,
104
+ "schema": { "type": "string" }
105
+ },
106
+ {
107
+ "name": "properties",
108
+ "in": "query",
109
+ "schema": { "type": "string" }
110
+ },
111
+ {
112
+ "name": "associations",
113
+ "in": "query",
114
+ "schema": { "type": "string" }
115
+ }
116
+ ],
117
+ "responses": {
118
+ "200": {
119
+ "description": "OK",
120
+ "content": {
121
+ "application/json": {
122
+ "schema": { "$ref": "#/components/schemas/Company" }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ },
128
+ "patch": {
129
+ "operationId": "patch-/crm/v3/objects/companies/{companyId}",
130
+ "summary": "Update company",
131
+ "parameters": [
132
+ {
133
+ "name": "companyId",
134
+ "in": "path",
135
+ "required": true,
136
+ "schema": { "type": "string" }
137
+ }
138
+ ],
139
+ "requestBody": {
140
+ "required": true,
141
+ "content": {
142
+ "application/json": {
143
+ "schema": {
144
+ "type": "object",
145
+ "properties": {
146
+ "properties": {
147
+ "type": "object",
148
+ "additionalProperties": { "type": "string" }
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ },
155
+ "responses": {
156
+ "200": {
157
+ "description": "OK",
158
+ "content": {
159
+ "application/json": {
160
+ "schema": { "$ref": "#/components/schemas/Company" }
161
+ }
162
+ }
163
+ }
164
+ }
165
+ },
166
+ "delete": {
167
+ "operationId": "delete-/crm/v3/objects/companies/{companyId}",
168
+ "summary": "Delete company",
169
+ "parameters": [
170
+ {
171
+ "name": "companyId",
172
+ "in": "path",
173
+ "required": true,
174
+ "schema": { "type": "string" }
175
+ }
176
+ ],
177
+ "responses": {
178
+ "204": { "description": "No Content" }
179
+ }
180
+ }
181
+ }
182
+ },
183
+ "components": {
184
+ "schemas": {
185
+ "Company": {
186
+ "type": "object",
187
+ "properties": {
188
+ "id": { "type": "string" },
189
+ "properties": {
190
+ "type": "object",
191
+ "properties": {
192
+ "name": { "type": "string" },
193
+ "country": { "type": "string" }
194
+ },
195
+ "additionalProperties": { "type": "string" }
196
+ },
197
+ "associations": {
198
+ "type": "object",
199
+ "additionalProperties": true
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
@@ -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
+ };