@aifabrix/builder 2.54.1 → 2.55.2

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 (253) hide show
  1. package/README.md +8 -0
  2. package/lib/agent-kit/apply-ops.js +82 -0
  3. package/lib/agent-kit/checksums.js +28 -0
  4. package/lib/agent-kit/classify.js +113 -0
  5. package/lib/agent-kit/claude-shim.js +61 -0
  6. package/lib/agent-kit/constants.js +55 -0
  7. package/lib/agent-kit/file-list.js +103 -0
  8. package/lib/agent-kit/host-approve.js +172 -0
  9. package/lib/agent-kit/hosting/github.js +63 -0
  10. package/lib/agent-kit/hosts.js +71 -0
  11. package/lib/agent-kit/init.js +319 -0
  12. package/lib/agent-kit/kit-root.js +17 -0
  13. package/lib/agent-kit/managed-section.js +79 -0
  14. package/lib/agent-kit/package-load.js +45 -0
  15. package/lib/agent-kit/plan-ops.js +69 -0
  16. package/lib/agent-kit/remote-prompts.js +272 -0
  17. package/lib/agent-kit/render-host-markdown.js +40 -0
  18. package/lib/agent-kit/repo-guard.js +47 -0
  19. package/lib/agent-kit/report.js +107 -0
  20. package/lib/agent-kit/run.js +82 -0
  21. package/lib/agent-kit/scm/git.js +122 -0
  22. package/lib/agent-kit/start.js +310 -0
  23. package/lib/agent-kit/state-file.js +83 -0
  24. package/lib/agent-kit/status.js +50 -0
  25. package/lib/agent-kit/v1-detect.js +81 -0
  26. package/lib/agent-kit/validate-kit.js +87 -0
  27. package/lib/agent-kit/workspace-name.js +40 -0
  28. package/lib/agent-kit/workspace-skeleton.js +103 -0
  29. package/lib/api/role-assistant-test-pack.api.js +86 -0
  30. package/lib/api/work-search.api.js +31 -4
  31. package/lib/api/work.api.js +19 -12
  32. package/lib/app/deploy.js +7 -4
  33. package/lib/app/list-external-systems.js +2 -1
  34. package/lib/app/offer-create-from-template.js +184 -0
  35. package/lib/app/show-display.js +33 -6
  36. package/lib/app/show.js +25 -2
  37. package/lib/channels/add-channel.js +1 -0
  38. package/lib/channels/approval-guides/claude.js +2 -2
  39. package/lib/channels/channel-add-failure.js +1 -0
  40. package/lib/channels/channel-add-remaining.js +15 -9
  41. package/lib/channels/channel-definition-status.js +115 -0
  42. package/lib/channels/channel-description.js +2 -1
  43. package/lib/channels/channel-install-envelope.js +4 -2
  44. package/lib/channels/channel-integration-generator.js +2 -0
  45. package/lib/channels/channel-runtime-resolver.js +14 -0
  46. package/lib/channels/channel-targets.js +31 -5
  47. package/lib/channels/claude-setup-values.js +4 -1
  48. package/lib/channels/slack-channel-add.js +59 -6
  49. package/lib/channels/slack-mcp-callback.js +51 -0
  50. package/lib/channels/slack-mcp-runtime.js +156 -0
  51. package/lib/channels/slack-provisioning/install-cli.js +14 -2
  52. package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
  53. package/lib/cli/index.js +4 -0
  54. package/lib/cli/setup-app.js +8 -1
  55. package/lib/cli/setup-auth.js +11 -2
  56. package/lib/cli/setup-certification-commands.js +2 -2
  57. package/lib/cli/setup-certification.help.js +3 -1
  58. package/lib/commands/agent-kit-help.js +149 -0
  59. package/lib/commands/agent-kit.js +417 -0
  60. package/lib/commands/auth-status-user.js +99 -0
  61. package/lib/commands/auth-status.js +14 -4
  62. package/lib/commands/channel-add-help.js +5 -5
  63. package/lib/commands/datasource-capability-relate-cli.js +5 -4
  64. package/lib/commands/datasource-load-export-cli.js +7 -2
  65. package/lib/commands/datasource-test-trust-cli.js +5 -1
  66. package/lib/commands/governance-command-action.js +5 -4
  67. package/lib/commands/identity-membership-role-cache.js +6 -1
  68. package/lib/commands/lifecycle-command-action.js +16 -15
  69. package/lib/commands/login-credentials.js +8 -3
  70. package/lib/commands/login-device.js +14 -5
  71. package/lib/commands/login.js +14 -1
  72. package/lib/commands/logout.js +50 -15
  73. package/lib/commands/repair-auth-apply.js +1 -1
  74. package/lib/commands/repair-datasource-key-skip.js +39 -0
  75. package/lib/commands/repair-datasource-keys.js +24 -12
  76. package/lib/commands/repair-rbac.js +16 -10
  77. package/lib/commands/role-assistant-copy-output.js +61 -0
  78. package/lib/commands/role-assistant-copy.js +155 -0
  79. package/lib/commands/role-assistant-test-output.js +8 -9
  80. package/lib/commands/role-assistant-test-result-rows.js +42 -0
  81. package/lib/commands/role-assistant.js +140 -59
  82. package/lib/commands/search.js +143 -0
  83. package/lib/commands/test-trust-external.js +7 -5
  84. package/lib/commands/upload-sidecar-followups.js +4 -1
  85. package/lib/commands/verify-governance-command-action.js +9 -7
  86. package/lib/commands/verify-operations-command-action.js +9 -8
  87. package/lib/commands/verify-operations-skip-e2e.js +131 -0
  88. package/lib/commands/verify-operations-step-plan.js +6 -33
  89. package/lib/commands/verify-operations-steps.js +3 -1
  90. package/lib/commands/verify-trust-command-action.js +6 -5
  91. package/lib/datasource/capability/relate-operations.js +28 -10
  92. package/lib/datasource/capability/run-capability-relate.js +48 -25
  93. package/lib/datasource/datasource-identifier.js +13 -5
  94. package/lib/deployment/deployer-poll-run.js +117 -35
  95. package/lib/external-system/deploy-dataplane-published.js +70 -0
  96. package/lib/external-system/deploy.js +12 -2
  97. package/lib/external-system/download-role-assistant.js +41 -15
  98. package/lib/external-system/download.js +8 -3
  99. package/lib/generator/helpers.js +12 -1
  100. package/lib/generator/wizard-datasource-key.js +54 -0
  101. package/lib/generator/wizard.js +55 -54
  102. package/lib/integration-definition/apply-datasource-keys.js +75 -0
  103. package/lib/integration-definition/apply-relationships.js +195 -0
  104. package/lib/integration-definition/apply-static-enterprise.js +232 -0
  105. package/lib/integration-definition/apply-system-file.js +71 -0
  106. package/lib/integration-definition/apply-test-endpoint.js +89 -0
  107. package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
  108. package/lib/integration-definition/apply.js +78 -59
  109. package/lib/integration-definition/enrich-openapi-operations.js +36 -10
  110. package/lib/integration-definition/enrich-openapi-pick.js +87 -0
  111. package/lib/lifecycle/role-assistant-governance.js +56 -21
  112. package/lib/programmatic/capability-registry.js +1 -0
  113. package/lib/programmatic/index.js +2 -0
  114. package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
  115. package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
  116. package/lib/programmatic/openapi-component-schemas.js +1 -0
  117. package/lib/programmatic/openapi-descriptions.js +9 -3
  118. package/lib/programmatic/openapi-envelope-examples.js +7 -0
  119. package/lib/programmatic/openapi-operation-bindings.js +5 -0
  120. package/lib/programmatic/openapi-request-schemas.js +5 -0
  121. package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
  122. package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
  123. package/lib/programmatic/openapi-spec.js +1 -0
  124. package/lib/programmatic/request-timeout.js +3 -0
  125. package/lib/programmatic/route-handler-map.js +7 -0
  126. package/lib/programmatic/run-channel-catalog.js +50 -8
  127. package/lib/programmatic/run-channel-install-options.js +5 -1
  128. package/lib/programmatic/run-download.js +41 -0
  129. package/lib/protection/auth-context.js +3 -1
  130. package/lib/protection/protection-display.js +3 -2
  131. package/lib/protection/report-exit.js +50 -0
  132. package/lib/protection/run-commands.js +2 -0
  133. package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
  134. package/lib/role-assistant/knowledge-sync.js +9 -126
  135. package/lib/role-assistant/package-validate.js +175 -0
  136. package/lib/role-assistant/test-case-assertion-row.js +36 -0
  137. package/lib/role-assistant/test-case-copy-bind.js +77 -0
  138. package/lib/role-assistant/test-case-copy-expected.js +127 -0
  139. package/lib/role-assistant/test-case-copy-from-work.js +90 -0
  140. package/lib/role-assistant/test-case-copy-interactions.js +67 -0
  141. package/lib/role-assistant/test-case-copy.js +119 -0
  142. package/lib/role-assistant/test-case-expected-catalog.js +135 -0
  143. package/lib/role-assistant/test-case-validate.js +88 -0
  144. package/lib/role-assistant/test-cases-bid.js +117 -4
  145. package/lib/role-assistant/test-cases-evaluate.js +149 -31
  146. package/lib/role-assistant/test-cases-evidence.js +44 -5
  147. package/lib/role-assistant/test-cases-honesty.js +155 -6
  148. package/lib/role-assistant/test-cases-lifecycle.js +297 -0
  149. package/lib/role-assistant/test-cases-search-graph.js +122 -0
  150. package/lib/role-assistant/test-cases-search.js +20 -2
  151. package/lib/role-assistant/test-cases.js +34 -168
  152. package/lib/role-assistant/test-pack-map.js +180 -0
  153. package/lib/role-assistant/test-pack-sync.js +187 -0
  154. package/lib/role-assistant/test-runner-debug.js +54 -0
  155. package/lib/role-assistant/test-runner-respond-body.js +36 -0
  156. package/lib/role-assistant/test-runner-search.js +20 -5
  157. package/lib/role-assistant/test-runner-start-payload.js +63 -10
  158. package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
  159. package/lib/role-assistant/test-runner-workhub.js +45 -21
  160. package/lib/role-assistant/test-runner.js +53 -10
  161. package/lib/schema/external-datasource.schema.json +36 -5
  162. package/lib/schema/external-system.schema.json +20 -2
  163. package/lib/schema/infra-parameter.schema.json +51 -3
  164. package/lib/schema/infra.parameter.yaml +476 -40
  165. package/lib/schema/role-assistant-test-case.schema.json +408 -0
  166. package/lib/schema/type/document-storage.json +1 -1
  167. package/lib/search/dataplane-context.js +23 -0
  168. package/lib/search/search-args.js +211 -0
  169. package/lib/search/search-display.js +238 -0
  170. package/lib/search/search-errors.js +50 -0
  171. package/lib/search/search-prompts.js +119 -0
  172. package/lib/search/search-roles.js +85 -0
  173. package/lib/search/search-run.js +241 -0
  174. package/lib/search/search-skills.js +198 -0
  175. package/lib/utils/api-required-permissions.js +271 -0
  176. package/lib/utils/api.js +16 -13
  177. package/lib/utils/authentication-slot-show.js +153 -0
  178. package/lib/utils/cli-json-exit.js +41 -0
  179. package/lib/utils/cli-utils.js +23 -5
  180. package/lib/utils/controller-url.js +78 -4
  181. package/lib/utils/credential-display.js +43 -1
  182. package/lib/utils/deployment-errors.js +15 -0
  183. package/lib/utils/deployment-validation-helpers.js +4 -1
  184. package/lib/utils/device-code.js +31 -10
  185. package/lib/utils/error-formatters/error-parser.js +16 -1
  186. package/lib/utils/error-formatters/permission-errors.js +19 -5
  187. package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
  188. package/lib/utils/external-system-readiness-compact-display.js +30 -1
  189. package/lib/utils/external-system-validators.js +2 -1
  190. package/lib/utils/help-builder.js +3 -1
  191. package/lib/utils/keycloak-realm-ready.js +5 -2
  192. package/lib/utils/logger.js +1 -0
  193. package/lib/utils/paths.js +26 -5
  194. package/lib/utils/schema-loader.js +37 -0
  195. package/lib/utils/secrets-helpers.js +2 -2
  196. package/lib/utils/write-stream-and-wait.js +63 -0
  197. package/lib/validation/validate-external-file.js +5 -1
  198. package/lib/validation/validate.js +3 -2
  199. package/package.json +20 -6
  200. package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
  201. package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
  202. package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
  203. package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
  204. package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
  205. package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
  206. package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
  207. package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
  208. package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
  209. package/templates/agent-kit/agent-kit.yaml +45 -0
  210. package/templates/agent-kit/instructions/AGENTKIT.md +104 -0
  211. package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
  212. package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
  213. package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
  214. package/templates/agent-kit/parity-inventory.yaml +188 -0
  215. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +59 -0
  216. package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
  217. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
  218. package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
  219. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
  220. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +52 -0
  221. package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
  222. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
  223. package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
  224. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +51 -0
  225. package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
  226. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
  227. package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
  228. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +43 -0
  229. package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
  230. package/templates/agent-kit/skills/shared/hosts.md +65 -0
  231. package/templates/agent-kit/skills/shared/login.md +16 -0
  232. package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
  233. package/templates/agent-kit/workspace/LICENSE.mit +21 -0
  234. package/templates/agent-kit/workspace/README.md +89 -0
  235. package/templates/applications/builder-api/Dockerfile +3 -1
  236. package/templates/applications/dataplane/application.yaml +2 -3
  237. package/templates/applications/dataplane/env.template +5 -5
  238. package/templates/applications/dataplane/rbac.yaml +28 -0
  239. package/templates/applications/keycloak/env.template +3 -3
  240. package/templates/applications/miso-controller/application.yaml +21 -2
  241. package/templates/applications/miso-controller/env.template +96 -25
  242. package/templates/applications/miso-controller/rbac.yaml +5 -0
  243. package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
  244. package/templates/channels/claude/channel.json +1 -1
  245. package/templates/channels/claude/install.template.md.hbs +1 -0
  246. package/templates/channels/claude/integration/claude-system.json +1 -1
  247. package/templates/channels/slack/channel.json +11 -0
  248. package/templates/channels/slack/install.template.md.hbs +9 -0
  249. package/templates/channels/slack/integration/slack-system.json +11 -0
  250. package/templates/channels/slack/manifest.template.json.hbs +6 -3
  251. package/templates/channels/teams-bot/channel.json +1 -0
  252. package/templates/python/docker-compose.hbs +14 -0
  253. package/templates/typescript/docker-compose.hbs +14 -0
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Canonical tenant-global datasource keys for BID apply.
3
+ *
4
+ * @fileoverview Prefix single-token keys; keep unique kebab keys
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { isScopedKebabKey } = require('../commands/repair-datasource-key-skip');
10
+
11
+ /**
12
+ * @param {string} dsKey
13
+ * @param {string} systemKey
14
+ * @returns {string}
15
+ */
16
+ function canonicalDatasourceKey(dsKey, systemKey) {
17
+ const key = String(dsKey || '').trim();
18
+ const sys = String(systemKey || '').trim();
19
+ if (!key) {
20
+ return key;
21
+ }
22
+ if (sys && key.startsWith(`${sys}-`)) {
23
+ return key;
24
+ }
25
+ if (isScopedKebabKey(key)) {
26
+ return key;
27
+ }
28
+ return sys ? `${sys}-${key}` : key;
29
+ }
30
+
31
+ /**
32
+ * @param {Array<{ key?: string }>} datasources
33
+ * @param {string} systemKey
34
+ * @returns {Map<string, string>}
35
+ */
36
+ function canonicalDatasourceKeyMap(datasources, systemKey) {
37
+ const map = new Map();
38
+ for (const ds of datasources || []) {
39
+ const from = String(ds.key || '').trim();
40
+ if (!from) {
41
+ continue;
42
+ }
43
+ map.set(from, canonicalDatasourceKey(from, systemKey));
44
+ }
45
+ return map;
46
+ }
47
+
48
+ /**
49
+ * @param {string} systemKey
50
+ * @param {string} canonicalKey
51
+ * @returns {string}
52
+ */
53
+ function datasourceFileName(systemKey, canonicalKey) {
54
+ const sys = String(systemKey || '');
55
+ const key = String(canonicalKey || '');
56
+ const suffix = sys && key.startsWith(`${sys}-`) ? key.slice(sys.length + 1) : key;
57
+ return `${sys}-datasource-${suffix}.json`;
58
+ }
59
+
60
+ /**
61
+ * @param {string} key
62
+ * @param {Map<string, string>} keyMap
63
+ * @returns {string}
64
+ */
65
+ function remapKey(key, keyMap) {
66
+ const raw = String(key || '').trim();
67
+ return (keyMap && keyMap.get(raw)) || raw;
68
+ }
69
+
70
+ module.exports = {
71
+ canonicalDatasourceKey,
72
+ canonicalDatasourceKeyMap,
73
+ datasourceFileName,
74
+ remapKey
75
+ };
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Compile BID relationships[] into EDS foreignKeys and child type:fk dimensions.
3
+ *
4
+ * @fileoverview BID relationship compile for apply
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { remapKey } = require('./apply-datasource-keys');
10
+
11
+ /**
12
+ * @param {Record<string, unknown>} rel
13
+ * @returns {string[]}
14
+ */
15
+ function carrierFieldsFromRelationship(rel) {
16
+ if (Array.isArray(rel.fields) && rel.fields.length > 0) {
17
+ return rel.fields.map((row) => String(row || '').trim()).filter(Boolean);
18
+ }
19
+ if (typeof rel.field === 'string' && rel.field.trim()) {
20
+ return [rel.field.trim()];
21
+ }
22
+ if (typeof rel.carrier === 'string' && rel.carrier.trim()) {
23
+ return [rel.carrier.trim()];
24
+ }
25
+ return [];
26
+ }
27
+
28
+ /**
29
+ * @param {string[]} fields
30
+ * @returns {string}
31
+ */
32
+ function fkNameFromCarrier(fields) {
33
+ const raw = String((fields && fields[0]) || '').trim();
34
+ if (/^[a-z][a-zA-Z0-9]*$/.test(raw)) {
35
+ return raw;
36
+ }
37
+ const camel = raw.replace(/[-_]([a-zA-Z0-9])/g, (_, ch) => String(ch).toUpperCase());
38
+ return /^[a-z][a-zA-Z0-9]*$/.test(camel) ? camel : '';
39
+ }
40
+
41
+ /**
42
+ * @param {Record<string, unknown>} body
43
+ * @param {string} carrier
44
+ * @returns {void}
45
+ */
46
+ function carrierPropertyNode(props, carrier) {
47
+ const existing = props[carrier] && typeof props[carrier] === 'object'
48
+ ? /** @type {Record<string, unknown>} */ (props[carrier])
49
+ : { type: 'string' };
50
+ return { ...existing, type: existing.type || 'string', index: true, filter: true };
51
+ }
52
+
53
+ function ensureCarrierMappings(body, carrier) {
54
+ if (!body.fieldMappings || typeof body.fieldMappings !== 'object') {
55
+ body.fieldMappings = { attributes: {} };
56
+ }
57
+ const mappings = /** @type {Record<string, unknown>} */ (body.fieldMappings);
58
+ if (!mappings.attributes || typeof mappings.attributes !== 'object') {
59
+ mappings.attributes = {};
60
+ }
61
+ const attrs = /** @type {Record<string, unknown>} */ (mappings.attributes);
62
+ if (!attrs[carrier]) {
63
+ attrs[carrier] = { expression: `{{raw.${carrier}}}`, description: 'Join carrier' };
64
+ }
65
+ }
66
+
67
+ function ensureCarrierExposed(body, carrier) {
68
+ if (!body.exposed || typeof body.exposed !== 'object') {
69
+ body.exposed = {};
70
+ }
71
+ const exposed = /** @type {Record<string, unknown>} */ (body.exposed);
72
+ const filterable = Array.isArray(exposed.filterable) ? [...exposed.filterable] : [];
73
+ if (!filterable.includes(carrier)) {
74
+ filterable.push(carrier);
75
+ }
76
+ exposed.filterable = filterable;
77
+ }
78
+
79
+ function ensureCarrierOnChild(body, carrier) {
80
+ if (!body.metadataSchema || typeof body.metadataSchema !== 'object') {
81
+ body.metadataSchema = { type: 'object', properties: {} };
82
+ }
83
+ const schema = /** @type {Record<string, unknown>} */ (body.metadataSchema);
84
+ if (!schema.properties || typeof schema.properties !== 'object') {
85
+ schema.properties = {};
86
+ }
87
+ const props = /** @type {Record<string, unknown>} */ (schema.properties);
88
+ props[carrier] = carrierPropertyNode(props, carrier);
89
+ ensureCarrierMappings(body, carrier);
90
+ ensureCarrierExposed(body, carrier);
91
+ }
92
+
93
+ /**
94
+ * @param {Record<string, unknown>} childBody
95
+ * @param {Record<string, unknown>} parentBody
96
+ * @param {string} fkName
97
+ * @returns {void}
98
+ */
99
+ function copyParentCatalogDimsAsFk(childBody, parentBody, fkName) {
100
+ const parentDims = parentBody.dimensions;
101
+ if (!parentDims || typeof parentDims !== 'object' || Array.isArray(parentDims)) {
102
+ return;
103
+ }
104
+ if (!childBody.dimensions || typeof childBody.dimensions !== 'object') {
105
+ childBody.dimensions = {};
106
+ }
107
+ const childDims = /** @type {Record<string, unknown>} */ (childBody.dimensions);
108
+ for (const [dimKey, binding] of Object.entries(parentDims)) {
109
+ if (!binding || typeof binding !== 'object' || childDims[dimKey]) {
110
+ continue;
111
+ }
112
+ childDims[dimKey] = { type: 'fk', via: [{ fk: fkName, dimension: dimKey }] };
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @param {Array<{ name: string, body: Record<string, unknown> }>} dsFiles
118
+ * @returns {Map<string, Record<string, unknown>>}
119
+ */
120
+ function bodiesByKey(dsFiles) {
121
+ const map = new Map();
122
+ for (const file of dsFiles || []) {
123
+ const key = String(file.body && file.body.key ? file.body.key : '').trim();
124
+ if (key) {
125
+ map.set(key, file.body);
126
+ }
127
+ }
128
+ return map;
129
+ }
130
+
131
+ /**
132
+ * @param {Record<string, unknown>} childBody
133
+ * @param {string} name
134
+ * @param {string[]} fields
135
+ * @param {string} targetKey
136
+ * @returns {void}
137
+ */
138
+ function upsertForeignKey(childBody, name, fields, targetKey) {
139
+ if (!Array.isArray(childBody.foreignKeys)) {
140
+ childBody.foreignKeys = [];
141
+ }
142
+ const rows = /** @type {Array<Record<string, unknown>>} */ (childBody.foreignKeys);
143
+ const next = {
144
+ name,
145
+ fields,
146
+ targetDatasource: targetKey,
147
+ targetFields: ['externalId']
148
+ };
149
+ const idx = rows.findIndex((row) => row && row.name === name);
150
+ if (idx >= 0) {
151
+ rows[idx] = { ...rows[idx], ...next };
152
+ return;
153
+ }
154
+ rows.push(next);
155
+ }
156
+
157
+ /**
158
+ * @param {Array<{ name: string, body: Record<string, unknown> }>} dsFiles
159
+ * @param {unknown[]} relationships
160
+ * @param {Map<string, string>} keyMap
161
+ * @returns {void}
162
+ */
163
+ function applyBidRelationships(dsFiles, relationships, keyMap) {
164
+ if (!Array.isArray(relationships) || relationships.length === 0) {
165
+ return;
166
+ }
167
+ const bodies = bodiesByKey(dsFiles);
168
+ for (const rel of relationships) {
169
+ if (!rel || typeof rel !== 'object') {
170
+ continue;
171
+ }
172
+ const row = /** @type {Record<string, unknown>} */ (rel);
173
+ const fields = carrierFieldsFromRelationship(row);
174
+ const fkName = fkNameFromCarrier(fields);
175
+ if (!fkName) {
176
+ continue;
177
+ }
178
+ const fromKey = remapKey(String(row.from || ''), keyMap);
179
+ const toKey = remapKey(String(row.to || ''), keyMap);
180
+ const childBody = bodies.get(fromKey);
181
+ const parentBody = bodies.get(toKey);
182
+ if (!childBody || !parentBody) {
183
+ continue;
184
+ }
185
+ ensureCarrierOnChild(childBody, fkName);
186
+ upsertForeignKey(childBody, fkName, [fkName], toKey);
187
+ copyParentCatalogDimsAsFk(childBody, parentBody, fkName);
188
+ }
189
+ }
190
+
191
+ module.exports = {
192
+ applyBidRelationships,
193
+ carrierFieldsFromRelationship,
194
+ fkNameFromCarrier
195
+ };
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Static file-load CIP + published enterprise REST paths for BID apply.
3
+ *
4
+ * @fileoverview authType none uses record fetch; stamp enterprise path
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const PLACEHOLDER_HOST = /example\.invalid|api\.example\.com/i;
10
+
11
+ /**
12
+ * @param {Record<string, unknown>} bid
13
+ * @returns {boolean}
14
+ */
15
+ function isStaticFileLoadBid(bid) {
16
+ const system = bid && bid.system && typeof bid.system === 'object'
17
+ ? /** @type {Record<string, unknown>} */ (bid.system)
18
+ : {};
19
+ const auth = system.authentication && typeof system.authentication === 'object'
20
+ ? /** @type {Record<string, unknown>} */ (system.authentication)
21
+ : null;
22
+ if (auth && auth.authType === 'none') {
23
+ return true;
24
+ }
25
+ if (String(system.type || '') === 'custom' && !hasVendorBaseUrl(system)) {
26
+ return true;
27
+ }
28
+ return false;
29
+ }
30
+
31
+ /**
32
+ * @param {Record<string, unknown>} system
33
+ * @returns {boolean}
34
+ */
35
+ function hasVendorBaseUrl(system) {
36
+ const refs = system.connectionRefs && typeof system.connectionRefs === 'object'
37
+ ? /** @type {Record<string, string>} */ (system.connectionRefs)
38
+ : {};
39
+ const url = String(refs.baseUrl || '').trim();
40
+ if (!url || PLACEHOLDER_HOST.test(url)) {
41
+ return false;
42
+ }
43
+ return /^https?:\/\//i.test(url);
44
+ }
45
+
46
+ /**
47
+ * @param {Record<string, unknown>} op
48
+ * @returns {void}
49
+ */
50
+ function setRecordFetch(op) {
51
+ const steps = Array.isArray(op.steps) ? op.steps : [];
52
+ let found = false;
53
+ for (const step of steps) {
54
+ if (step && step.fetch && typeof step.fetch === 'object') {
55
+ step.fetch = { source: 'record' };
56
+ found = true;
57
+ }
58
+ }
59
+ if (!found) {
60
+ steps.unshift({ fetch: { source: 'record' } });
61
+ if (!steps.some((row) => row && row.output)) {
62
+ steps.push({ output: { mode: 'records' } });
63
+ }
64
+ op.steps = steps;
65
+ }
66
+ op.enabled = true;
67
+ }
68
+
69
+ /**
70
+ * @param {Record<string, unknown>} body
71
+ * @param {string} capKey
72
+ * @returns {void}
73
+ */
74
+ function ensureRecordCapability(body, capKey) {
75
+ if (!body.execution || typeof body.execution !== 'object') {
76
+ body.execution = { engine: 'cip' };
77
+ }
78
+ const execution = /** @type {Record<string, unknown>} */ (body.execution);
79
+ if (!execution.cip || typeof execution.cip !== 'object') {
80
+ execution.cip = { version: '1.0', operations: {} };
81
+ }
82
+ const cip = /** @type {Record<string, unknown>} */ (execution.cip);
83
+ if (!cip.operations || typeof cip.operations !== 'object') {
84
+ cip.operations = {};
85
+ }
86
+ const ops = /** @type {Record<string, unknown>} */ (cip.operations);
87
+ if (!ops[capKey] || typeof ops[capKey] !== 'object') {
88
+ ops[capKey] = { enabled: true, description: `Local ${capKey}`, steps: [] };
89
+ }
90
+ if (capKey === 'create' || capKey === 'update') {
91
+ ops[capKey].shape = capKey;
92
+ }
93
+ setRecordFetch(/** @type {Record<string, unknown>} */ (ops[capKey]));
94
+ }
95
+
96
+ /**
97
+ * @param {Record<string, unknown>} body
98
+ * @param {string} capKey
99
+ * @param {boolean} overwritePath
100
+ * @returns {void}
101
+ */
102
+ function stampEnterpriseOp(body, capKey, overwritePath) {
103
+ const resourceType = String(body.resourceType || '').trim();
104
+ if (!resourceType) {
105
+ return;
106
+ }
107
+ if (!body.openapi || typeof body.openapi !== 'object') {
108
+ body.openapi = { enabled: true, operations: {} };
109
+ }
110
+ const openapi = /** @type {Record<string, unknown>} */ (body.openapi);
111
+ openapi.enabled = true;
112
+ if (!openapi.operations || typeof openapi.operations !== 'object') {
113
+ openapi.operations = {};
114
+ }
115
+ const ops = /** @type {Record<string, unknown>} */ (openapi.operations);
116
+ const prev = ops[capKey] && typeof ops[capKey] === 'object'
117
+ ? /** @type {Record<string, unknown>} */ (ops[capKey])
118
+ : {};
119
+ const next = { ...prev, operationId: prev.operationId || capKey };
120
+ if (!next.restRuntime) {
121
+ next.restRuntime = { pathKind: 'collectionSubresource' };
122
+ }
123
+ if (overwritePath || !next.path) {
124
+ next.path = `/enterprise/${resourceType}/${capKey}`;
125
+ next.method = next.method || 'POST';
126
+ }
127
+ ops[capKey] = next;
128
+ }
129
+
130
+ /**
131
+ * @param {Record<string, unknown>} body
132
+ * @param {string} capKey
133
+ * @returns {void}
134
+ */
135
+ function ensureCapabilityObject(body, capKey) {
136
+ if (!Array.isArray(body.capabilities)) {
137
+ body.capabilities = [];
138
+ }
139
+ const keys = capabilityKeysOf(body);
140
+ if (keys.includes(capKey) || keys.includes(`${capKey}Basic`)) {
141
+ return;
142
+ }
143
+ body.capabilities.push({
144
+ key: capKey,
145
+ description: `Local ${capKey}`,
146
+ riskLevel: 'medium',
147
+ approvalRequired: false
148
+ });
149
+ }
150
+
151
+ function capabilityKeysOf(body) {
152
+ if (!Array.isArray(body.capabilities)) {
153
+ return ['list', 'get'];
154
+ }
155
+ return body.capabilities
156
+ .map((row) => (row && typeof row === 'object' ? row.key : row))
157
+ .filter((key) => typeof key === 'string' && key.trim())
158
+ .map((key) => String(key).trim());
159
+ }
160
+
161
+ /**
162
+ * @param {Record<string, unknown>} body
163
+ * @returns {boolean}
164
+ */
165
+ function isRecordStorageBody(body) {
166
+ if (String(body.entityType || '') !== 'recordStorage') {
167
+ return false;
168
+ }
169
+ return String(body.storageType || '') !== 'view';
170
+ }
171
+
172
+ function hasWriteCapability(body) {
173
+ return capabilityKeysOf(body).some((key) => /^create/i.test(key) || /^update/i.test(key));
174
+ }
175
+
176
+ function hasVendorWriteBinding(body) {
177
+ const ops = body.openapi && body.openapi.operations;
178
+ if (!ops || typeof ops !== 'object') {
179
+ return false;
180
+ }
181
+ return ['create', 'createBasic', 'update', 'updateBasic'].some((key) => {
182
+ const row = ops[key];
183
+ const method = String((row && row.method) || '').toUpperCase();
184
+ return method === 'POST' || method === 'PUT' || method === 'PATCH';
185
+ });
186
+ }
187
+
188
+ function applyGetOnlyLocalPersist(body) {
189
+ if (hasVendorWriteBinding(body) || hasWriteCapability(body)) {
190
+ return;
191
+ }
192
+ for (const key of ['create', 'update']) {
193
+ ensureCapabilityObject(body, key);
194
+ ensureRecordCapability(body, key);
195
+ stampEnterpriseOp(body, key, true);
196
+ }
197
+ }
198
+
199
+ function applyStaticRecordCaps(body, caps) {
200
+ for (const key of caps.filter((row) => row === 'list' || row === 'get')) {
201
+ ensureRecordCapability(body, key);
202
+ stampEnterpriseOp(body, key, true);
203
+ }
204
+ }
205
+
206
+ function applyStaticAndEnterprise(dsFiles, bid) {
207
+ const staticLoad = isStaticFileLoadBid(bid);
208
+ for (const file of dsFiles || []) {
209
+ const body = file.body;
210
+ if (!body || typeof body !== 'object') {
211
+ continue;
212
+ }
213
+ if (!isRecordStorageBody(body)) {
214
+ continue;
215
+ }
216
+ if (staticLoad) {
217
+ applyStaticRecordCaps(body, capabilityKeysOf(body));
218
+ }
219
+ applyGetOnlyLocalPersist(body);
220
+ for (const key of capabilityKeysOf(body)) {
221
+ stampEnterpriseOp(body, key, staticLoad);
222
+ }
223
+ }
224
+ }
225
+
226
+ module.exports = {
227
+ isStaticFileLoadBid,
228
+ hasVendorBaseUrl,
229
+ applyStaticAndEnterprise,
230
+ stampEnterpriseOp,
231
+ ensureRecordCapability
232
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * BID apply system.json body (auth none for static file-load).
3
+ *
4
+ * @fileoverview System manifest emit for integration-definition apply
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { canonicalDatasourceKeyMap } = require('./apply-datasource-keys');
10
+ const { isStaticFileLoadBid } = require('./apply-static-enterprise');
11
+
12
+ /**
13
+ * @param {Record<string, unknown>} bid
14
+ * @param {Record<string, unknown>} identity
15
+ * @returns {Record<string, unknown>}
16
+ */
17
+ function buildSystemAuthentication(bid, identity) {
18
+ if (isStaticFileLoadBid(bid)) {
19
+ return { authType: 'none' };
20
+ }
21
+ const system = /** @type {Record<string, unknown>} */ (bid.system);
22
+ const refs = /** @type {Record<string, string>} */ (system.connectionRefs || {});
23
+ const tokenRef = refs.token || refs.apiKey || Object.values(refs)[0] || `kv://${identity.systemKey}/token`;
24
+ return {
25
+ authType: 'credential',
26
+ credential: {
27
+ credentialKey: `${identity.systemKey}-cred`,
28
+ method: 'bearerToken',
29
+ variables: {
30
+ baseUrl: refs.baseUrl || 'https://example.invalid',
31
+ headerName: 'Authorization',
32
+ prefix: 'Bearer'
33
+ },
34
+ security: {
35
+ token: tokenRef
36
+ },
37
+ writeOnce: true
38
+ }
39
+ };
40
+ }
41
+
42
+ /**
43
+ * @param {Record<string, unknown>} bid
44
+ * @returns {Record<string, unknown>}
45
+ */
46
+ function buildSystemFile(bid) {
47
+ const system = /** @type {Record<string, unknown>} */ (bid.system);
48
+ const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
49
+ const keyMap = canonicalDatasourceKeyMap(
50
+ /** @type {any[]} */ (bid.datasources) || [],
51
+ identity.systemKey
52
+ );
53
+ const staticLoad = isStaticFileLoadBid(bid);
54
+ return {
55
+ key: system.key,
56
+ displayName: system.displayName || identity.displayName,
57
+ description: system.description || identity.displayName,
58
+ type: system.type || (staticLoad ? 'custom' : 'openapi'),
59
+ enabled: true,
60
+ systemKind: system.systemKind || (staticLoad ? 'custom' : 'crm'),
61
+ authentication: buildSystemAuthentication(bid, identity),
62
+ dataSources: (/** @type {any[]} */ (bid.datasources) || []).map(
63
+ (d) => keyMap.get(String(d.key)) || d.key
64
+ )
65
+ };
66
+ }
67
+
68
+ module.exports = {
69
+ buildSystemAuthentication,
70
+ buildSystemFile
71
+ };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Stamp credential testEndpoint from the first vendor list GET + required query mins.
3
+ *
4
+ * @fileoverview Honour OpenAPI query minimums on generated probe URLs
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * @param {Record<string, unknown>} body
11
+ * @returns {Record<string, unknown>}
12
+ */
13
+ function listFetchQuery(body) {
14
+ const ops = body.execution && body.execution.cip && body.execution.cip.operations;
15
+ const list = ops && ops.list && typeof ops.list === 'object' ? ops.list : null;
16
+ const steps = list && Array.isArray(list.steps) ? list.steps : [];
17
+ const fetchStep = steps.find((row) => row && row.fetch && typeof row.fetch.query === 'object');
18
+ return fetchStep ? /** @type {Record<string, unknown>} */ (fetchStep.fetch.query) : {};
19
+ }
20
+
21
+ /**
22
+ * @param {Record<string, unknown>} query
23
+ * @returns {string}
24
+ */
25
+ function probeQueryString(query) {
26
+ const parts = [];
27
+ for (const [name, value] of Object.entries(query || {})) {
28
+ if (value === undefined || value === null) {
29
+ continue;
30
+ }
31
+ const raw = String(value);
32
+ if (raw.includes('{{')) {
33
+ continue;
34
+ }
35
+ parts.push(`${encodeURIComponent(name)}=${encodeURIComponent(raw)}`);
36
+ }
37
+ return parts.join('&');
38
+ }
39
+
40
+ /**
41
+ * @param {Array<{ body?: Record<string, unknown> }>} dsFiles
42
+ * @returns {string}
43
+ */
44
+ function firstVendorListProbe(dsFiles) {
45
+ for (const file of dsFiles || []) {
46
+ const body = file && file.body;
47
+ const list = body && body.openapi && body.openapi.operations && body.openapi.operations.list;
48
+ if (!list || String(list.method || '').toUpperCase() !== 'GET') {
49
+ continue;
50
+ }
51
+ const opPath = String(list.path || '').trim();
52
+ if (!opPath || opPath.startsWith('/enterprise/')) {
53
+ continue;
54
+ }
55
+ const qs = probeQueryString(listFetchQuery(body));
56
+ return qs ? `${opPath}?${qs}` : opPath;
57
+ }
58
+ return '';
59
+ }
60
+
61
+ /**
62
+ * @param {Record<string, unknown>} system
63
+ * @param {Array<{ body?: Record<string, unknown> }>} dsFiles
64
+ * @returns {void}
65
+ */
66
+ function stampCredentialTestEndpoint(system, dsFiles) {
67
+ const auth = system && system.authentication;
68
+ const cred = auth && auth.credential && typeof auth.credential === 'object'
69
+ ? auth.credential
70
+ : null;
71
+ if (!cred) {
72
+ return;
73
+ }
74
+ if (!cred.variables || typeof cred.variables !== 'object') {
75
+ cred.variables = {};
76
+ }
77
+ if (String(cred.variables.testEndpoint || '').trim()) {
78
+ return;
79
+ }
80
+ const probe = firstVendorListProbe(dsFiles);
81
+ if (probe) {
82
+ cred.variables.testEndpoint = probe;
83
+ }
84
+ }
85
+
86
+ module.exports = {
87
+ stampCredentialTestEndpoint,
88
+ firstVendorListProbe
89
+ };