@aifabrix/builder 2.44.5 → 2.44.6

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 (207) hide show
  1. package/.cursor/rules/cli-layout.mdc +1 -1
  2. package/.cursor/rules/project-rules.mdc +1 -1
  3. package/.npmrc.token +1 -1
  4. package/README.md +15 -23
  5. package/integration/hubspot-test/README.md +2 -0
  6. package/integration/hubspot-test/test.js +5 -3
  7. package/jest.projects.js +48 -2
  8. package/lib/api/controller-health.api.js +49 -0
  9. package/lib/api/dimension-values.api.js +82 -0
  10. package/lib/api/dimensions.api.js +114 -0
  11. package/lib/api/external-systems.api.js +1 -0
  12. package/lib/api/integration-clients.api.js +168 -0
  13. package/lib/api/types/dimension-values.types.js +28 -0
  14. package/lib/api/types/dimensions.types.js +31 -0
  15. package/lib/api/types/integration-clients.types.js +45 -0
  16. package/lib/api/validation-runner.js +46 -25
  17. package/lib/app/deploy-config.js +11 -1
  18. package/lib/app/deploy-status-display.js +3 -3
  19. package/lib/app/deploy.js +36 -14
  20. package/lib/app/display.js +15 -11
  21. package/lib/app/push.js +46 -23
  22. package/lib/app/register.js +1 -1
  23. package/lib/app/restart-display.js +95 -0
  24. package/lib/app/rotate-secret.js +1 -1
  25. package/lib/app/run-container-start.js +12 -6
  26. package/lib/app/run-env-compose.js +30 -1
  27. package/lib/app/run-helpers.js +44 -12
  28. package/lib/app/run-reload-sync.js +148 -0
  29. package/lib/app/run-resolve-image.js +51 -1
  30. package/lib/app/run.js +99 -73
  31. package/lib/build/index.js +75 -45
  32. package/lib/cli/doctor-check.js +117 -0
  33. package/lib/cli/index.js +8 -2
  34. package/lib/cli/infra-guided.js +445 -0
  35. package/lib/cli/setup-app.js +20 -2
  36. package/lib/cli/setup-auth.js +26 -0
  37. package/lib/cli/setup-dev-path-commands.js +50 -3
  38. package/lib/cli/setup-infra.js +134 -61
  39. package/lib/cli/setup-integration-client.js +182 -0
  40. package/lib/cli/setup-parameters.js +21 -2
  41. package/lib/cli/setup-platform.js +102 -0
  42. package/lib/cli/setup-secrets.js +18 -6
  43. package/lib/cli/setup-utility.js +78 -33
  44. package/lib/commands/datasource-capability-dimension-cli.js +128 -0
  45. package/lib/commands/datasource-capability-output.js +29 -0
  46. package/lib/commands/datasource-capability-relate-cli.js +140 -0
  47. package/lib/commands/datasource-capability.js +411 -0
  48. package/lib/commands/datasource-unified-test-cli.options.js +1 -1
  49. package/lib/commands/datasource.js +53 -13
  50. package/lib/commands/dev-down.js +3 -3
  51. package/lib/commands/dev-infra-gate.js +32 -0
  52. package/lib/commands/dev-init.js +13 -7
  53. package/lib/commands/dimension-value.js +179 -0
  54. package/lib/commands/dimension.js +330 -0
  55. package/lib/commands/integration-client.js +430 -0
  56. package/lib/commands/login-device.js +65 -30
  57. package/lib/commands/login.js +21 -10
  58. package/lib/commands/parameters-validate.js +78 -13
  59. package/lib/commands/repair-datasource-auto-rbac.js +166 -0
  60. package/lib/commands/repair-datasource-keys.js +10 -5
  61. package/lib/commands/repair-datasource.js +19 -7
  62. package/lib/commands/repair-env-template.js +4 -1
  63. package/lib/commands/repair-openapi-sync.js +172 -0
  64. package/lib/commands/repair-persist.js +102 -0
  65. package/lib/commands/repair-rbac-extract.js +27 -0
  66. package/lib/commands/repair-rbac-migrate.js +186 -0
  67. package/lib/commands/repair-rbac.js +214 -31
  68. package/lib/commands/repair-system-alignment.js +246 -0
  69. package/lib/commands/repair-system-permissions.js +168 -0
  70. package/lib/commands/repair.js +120 -338
  71. package/lib/commands/secure.js +1 -1
  72. package/lib/commands/setup-modes.js +455 -0
  73. package/lib/commands/setup-prompts.js +388 -0
  74. package/lib/commands/setup.js +149 -0
  75. package/lib/commands/teardown.js +228 -0
  76. package/lib/commands/up-common.js +79 -19
  77. package/lib/commands/up-dataplane.js +33 -11
  78. package/lib/commands/up-miso.js +7 -11
  79. package/lib/commands/upload.js +109 -23
  80. package/lib/commands/wizard-core-helpers.js +14 -11
  81. package/lib/commands/wizard-core.js +6 -5
  82. package/lib/commands/wizard-dataplane.js +2 -2
  83. package/lib/commands/wizard-entity-selection.js +4 -3
  84. package/lib/commands/wizard-headless.js +2 -1
  85. package/lib/commands/wizard.js +2 -1
  86. package/lib/constants/infra-compose-service-names.js +40 -0
  87. package/lib/core/env-reader.js +16 -3
  88. package/lib/core/secrets-admin-env.js +101 -0
  89. package/lib/core/secrets-ensure-infra.js +34 -1
  90. package/lib/core/secrets-ensure.js +88 -66
  91. package/lib/core/secrets-env-content.js +432 -0
  92. package/lib/core/secrets-env-write.js +27 -1
  93. package/lib/core/secrets-load.js +248 -0
  94. package/lib/core/secrets-names.js +32 -0
  95. package/lib/core/secrets.js +17 -757
  96. package/lib/datasource/capability/basic-exposure.js +76 -0
  97. package/lib/datasource/capability/capability-diff-slice.js +41 -0
  98. package/lib/datasource/capability/capability-key.js +34 -0
  99. package/lib/datasource/capability/capability-resolve.js +172 -0
  100. package/lib/datasource/capability/capability-storage-keys.js +22 -0
  101. package/lib/datasource/capability/copy-operations.js +348 -0
  102. package/lib/datasource/capability/copy-test-payload.js +139 -0
  103. package/lib/datasource/capability/create-operations.js +235 -0
  104. package/lib/datasource/capability/dimension-operations.js +151 -0
  105. package/lib/datasource/capability/dimension-validate.js +219 -0
  106. package/lib/datasource/capability/json-pointer.js +31 -0
  107. package/lib/datasource/capability/reference-rewrite.js +51 -0
  108. package/lib/datasource/capability/relate-operations.js +325 -0
  109. package/lib/datasource/capability/relate-validate.js +219 -0
  110. package/lib/datasource/capability/remove-operations.js +275 -0
  111. package/lib/datasource/capability/run-capability-copy.js +152 -0
  112. package/lib/datasource/capability/run-capability-diff.js +135 -0
  113. package/lib/datasource/capability/run-capability-dimension.js +291 -0
  114. package/lib/datasource/capability/run-capability-edit.js +377 -0
  115. package/lib/datasource/capability/run-capability-relate.js +193 -0
  116. package/lib/datasource/capability/run-capability-remove.js +105 -0
  117. package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
  118. package/lib/datasource/capability/validate-capability-slice.js +35 -0
  119. package/lib/datasource/list.js +136 -23
  120. package/lib/datasource/log-viewer.js +2 -4
  121. package/lib/datasource/unified-validation-run.js +51 -16
  122. package/lib/datasource/validate.js +53 -1
  123. package/lib/deployment/deploy-poll-ui.js +60 -0
  124. package/lib/deployment/deployer-status.js +29 -3
  125. package/lib/deployment/deployer.js +48 -30
  126. package/lib/deployment/environment.js +7 -2
  127. package/lib/deployment/poll-interval.js +72 -0
  128. package/lib/deployment/push.js +11 -9
  129. package/lib/external-system/deploy.js +4 -1
  130. package/lib/external-system/download.js +61 -32
  131. package/lib/external-system/sync-deploy-manifest.js +33 -0
  132. package/lib/infrastructure/index.js +49 -19
  133. package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
  134. package/lib/parameters/infra-kv-discovery.js +29 -4
  135. package/lib/parameters/infra-parameter-catalog.js +6 -3
  136. package/lib/parameters/infra-parameter-validate.js +67 -19
  137. package/lib/resolvers/datasource-resolver.js +53 -0
  138. package/lib/resolvers/dimension-file.js +52 -0
  139. package/lib/resolvers/manifest-resolver.js +133 -0
  140. package/lib/schema/external-datasource.schema.json +183 -53
  141. package/lib/schema/external-system.schema.json +23 -10
  142. package/lib/schema/infra.parameter.yaml +26 -11
  143. package/lib/schema/wizard-config.schema.json +1 -1
  144. package/lib/utils/aifabrix-config-dir-walk.js +40 -0
  145. package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
  146. package/lib/utils/app-run-containers.js +2 -2
  147. package/lib/utils/bash-secret-env.js +59 -0
  148. package/lib/utils/cli-secrets-error-format.js +78 -0
  149. package/lib/utils/cli-test-layout-chalk.js +31 -9
  150. package/lib/utils/cli-utils.js +4 -36
  151. package/lib/utils/datasource-test-run-display.js +8 -0
  152. package/lib/utils/dev-hosts-helper.js +3 -2
  153. package/lib/utils/dev-init-ssh-merge.js +2 -1
  154. package/lib/utils/docker-build.js +17 -9
  155. package/lib/utils/docker-reload-mount.js +127 -0
  156. package/lib/utils/external-readme.js +71 -2
  157. package/lib/utils/external-system-local-test-tty.js +3 -2
  158. package/lib/utils/external-system-readiness-core.js +45 -12
  159. package/lib/utils/external-system-readiness-deploy-display.js +3 -3
  160. package/lib/utils/external-system-readiness-display-internals.js +33 -3
  161. package/lib/utils/external-system-readiness-display.js +10 -1
  162. package/lib/utils/file-upload.js +40 -3
  163. package/lib/utils/health-check-db-init.js +107 -0
  164. package/lib/utils/health-check-public-warn.js +69 -0
  165. package/lib/utils/health-check-url.js +19 -4
  166. package/lib/utils/health-check.js +135 -105
  167. package/lib/utils/help-builder.js +5 -1
  168. package/lib/utils/image-name.js +34 -7
  169. package/lib/utils/integration-file-backup.js +74 -0
  170. package/lib/utils/mutagen-install.js +30 -3
  171. package/lib/utils/paths.js +108 -25
  172. package/lib/utils/postgres-wipe.js +212 -0
  173. package/lib/utils/register-aifabrix-shell-env.js +15 -0
  174. package/lib/utils/remote-dev-auth.js +21 -5
  175. package/lib/utils/remote-docker-env.js +9 -1
  176. package/lib/utils/remote-secrets-loader.js +42 -3
  177. package/lib/utils/resolve-docker-image-ref.js +9 -3
  178. package/lib/utils/secrets-ancestor-paths.js +47 -0
  179. package/lib/utils/secrets-helpers.js +17 -10
  180. package/lib/utils/secrets-kv-refs.js +42 -0
  181. package/lib/utils/secrets-kv-scope.js +19 -2
  182. package/lib/utils/secrets-materialize-local.js +134 -0
  183. package/lib/utils/secrets-path.js +24 -10
  184. package/lib/utils/secrets-utils.js +2 -2
  185. package/lib/utils/system-builder-root.js +34 -0
  186. package/lib/utils/url-declarative-resolve-build.js +6 -1
  187. package/lib/utils/url-declarative-runtime-base-path.js +32 -0
  188. package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
  189. package/lib/utils/urls-local-registry.js +23 -12
  190. package/lib/utils/validation-poll-ui.js +81 -0
  191. package/lib/utils/validation-run-poll.js +29 -5
  192. package/lib/utils/with-muted-logger.js +53 -0
  193. package/package.json +1 -1
  194. package/templates/applications/dataplane/application.yaml +1 -1
  195. package/templates/applications/dataplane/rbac.yaml +10 -10
  196. package/templates/applications/keycloak/env.template +8 -6
  197. package/templates/applications/miso-controller/application.yaml +7 -0
  198. package/templates/applications/miso-controller/env.template +1 -1
  199. package/templates/applications/miso-controller/rbac.yaml +9 -9
  200. package/templates/external-system/README.md.hbs +83 -123
  201. package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
  202. package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
  203. package/.nyc_output/processinfo/index.json +0 -1
  204. package/lib/api/service-users.api.js +0 -150
  205. package/lib/api/types/service-users.types.js +0 -65
  206. package/lib/cli/setup-service-user.js +0 -187
  207. package/lib/commands/service-user.js +0 -429
@@ -50,7 +50,7 @@ Markdown headings in `layout.md` may use emoji for doc navigation; **user-facing
50
50
 
51
51
  - **Canonical helpers:** `lib/utils/cli-test-layout-chalk.js` (see symbol → helper table in [layout.md](./layout.md) § “Implementation map”).
52
52
  - **Preferred import alias:** `lib/utils/cli-layout-chalk.js` re-exports the same API when the path should not contain `test`.
53
- - **Prefer** `formatSuccessLine`, `formatSuccessParagraph`, `formatBlockingError`, `failureGlyph`, `successGlyph`, and other exported section helpers over ad hoc `` chalk.green(`✔ …`) `` for one-off success/error lines.
53
+ - **Prefer** `formatSuccessLine`, `formatSuccessParagraph`, `formatWarningLine`, `formatBlockingError`, `failureGlyph`, `successGlyph`, and other exported section helpers over ad hoc `` chalk.green(`✔ …`) `` for one-off success/error lines.
54
54
  - **Composite / indented lines** (e.g. `successGlyph()` + `chalk.white(…)`, or ` ✔ …` in validate-style output) may stay raw chalk **only** when a single helper would not match the spec; keep glyphs canonical.
55
55
  - **Tests:** extend or add tests under `tests/lib/utils/cli-test-layout-chalk.test.js` (and command tests) when behavior or snapshots encode layout.
56
56
 
@@ -28,7 +28,7 @@ When adding or changing CLI commands, subcommands, flags, help text, or terminal
28
28
 
29
29
  - **Rule**: `.cursor/rules/cli-layout.mdc`
30
30
  - **Visual/layout spec**: `.cursor/rules/layout.md`
31
- - **Per-command output profiles**: `.cursor/rules/cli-output-command-matrix.md` (update for every new leaf command)
31
+ - **Per-command output profiles**: `.cursor/rules/cli-output-command-matrix.md` (update for every new leaf command; see matrix **Layout compliance** for `cli-test-layout-chalk` adoption status)
32
32
 
33
33
  ## Architecture Patterns
34
34
 
package/.npmrc.token CHANGED
@@ -1 +1 @@
1
- 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
1
+ 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
package/README.md CHANGED
@@ -42,33 +42,25 @@ npm install -g @aifabrix/builder
42
42
 
43
43
  Get the platform running locally so you can try it.
44
44
 
45
- 1. **Start local infrastructure** (Postgres, Redis, optional Traefik):
45
+ **One-shot install:**
46
46
 
47
- ```bash
48
- aifabrix up-infra
49
- ```
50
-
51
- First-time run creates required infra secrets automatically. Use `aifabrix up-infra --adminPassword <password>` to set a custom admin password for Postgres, pgAdmin, and Redis Commander.
52
-
53
- 2. **Start the platform** (Keycloak, Miso Controller, Dataplane) from community images:
54
-
55
- ```bash
56
- aifabrix up-platform
57
- ```
47
+ ```bash
48
+ aifabrix setup
49
+ ```
58
50
 
59
- Or run platform apps separately: `aifabrix up-miso` then `aifabrix up-dataplane`. Infra must be up first.
51
+ `aifabrix setup` detects your local state and either runs a fresh-install wizard (admin email/password, optional AI tool keys) or shows a mode menu (re-install, wipe data, clean files, update images). It then runs `up-infra` and `up-platform` for you. Use `aifabrix teardown` to fully remove the local installation. See [Infrastructure commands](docs/commands/infrastructure.md#aifabrix-setup) for details and CI flags.
60
52
 
61
- 3. **Configure secrets** You need either **OpenAI** or **Azure OpenAI**:
53
+ If you prefer to set the AI tool key outside the wizard, use one of:
62
54
 
63
- - **OpenAI:** set your API key:
64
- ```bash
65
- aifabrix secret set secrets-openaiApiKeyVault <your-openai-secret-key>
66
- ```
67
- - **Azure OpenAI:** set endpoint and API key:
68
- ```bash
69
- aifabrix secret set azure-openaiapi-urlKeyVault <your-azure-openai-endpoint-url>
70
- aifabrix secret set secrets-azureOpenaiApiKeyVault <your-azure-openai-secret-key>
71
- ```
55
+ - **OpenAI:** set your API key:
56
+ ```bash
57
+ aifabrix secret set secrets-openaiApiKeyVault <your-openai-secret-key>
58
+ ```
59
+ - **Azure OpenAI:** set endpoint and API key:
60
+ ```bash
61
+ aifabrix secret set azure-openaiapi-urlKeyVault <your-azure-openai-endpoint-url>
62
+ aifabrix secret set secrets-azureOpenaiApiKeyVault <your-azure-openai-secret-key>
63
+ ```
72
64
 
73
65
  Secrets are stored in `~/.aifabrix/secrets.local.yaml` or the file from `aifabrix-secrets` in your config (e.g. `builder/secrets.local.yaml`).
74
66
 
@@ -150,6 +150,8 @@ If you see **"Invalid token or insufficient permissions"** or **"Failed to creat
150
150
 
151
151
  If the dataplane is configured to accept device tokens for the wizard API, ensure you are logged in with `aifabrix login` and that the controller URL and environment match (e.g. `dev`). No client credentials are needed.
152
152
 
153
+ When this error appears, `pnpm test:hubspot-wizard` **skips** the live wizard cases (exit code 0) so optional CI/agents are not blocked; configure client credentials or dataplane auth to run those cases for real.
154
+
153
155
  ## Troubleshooting
154
156
 
155
157
  - **Validation errors**: Run `aifabrix validate hubspot-test --type external` to see schema and manifest errors.
@@ -796,8 +796,8 @@ async function testDownloadAndSplit(appName, context, options) {
796
796
  }
797
797
 
798
798
  /**
799
- * Returns a skip message only when the wizard failure is due to dataplane unreachable (no service).
800
- * Does not skip for auth/session errors when dataplane is up (so tests fail with the real error).
799
+ * Returns a skip message when the wizard cannot run due to environment (dataplane missing,
800
+ * or dataplane rejecting the CLI token for wizard session).
801
801
  * @param {string} errorOutput - Combined stdout + stderr from wizard command
802
802
  * @returns {string|null} Skip message or null
803
803
  */
@@ -1257,7 +1257,9 @@ async function createSystemForNegativeTest(appName, configName, context, options
1257
1257
  });
1258
1258
  const wizardResult = await runWizard(configPath, context, options);
1259
1259
  if (!wizardResult.success) {
1260
- throw new SkipTestError(`Wizard failed to create system: ${wizardResult.stderr}`);
1260
+ const errorOutput = `${wizardResult.stdout}\n${wizardResult.stderr}`;
1261
+ const skipMsg = getWizardEnvironmentSkipMessage(errorOutput);
1262
+ throw new SkipTestError(skipMsg || `Wizard failed to create system: ${wizardResult.stderr}`);
1261
1263
  }
1262
1264
  await new Promise(resolve => setTimeout(resolve, 200));
1263
1265
  return path.join(process.cwd(), 'integration', appName);
package/jest.projects.js CHANGED
@@ -83,6 +83,10 @@ const defaultProject = {
83
83
  '\\\\tests\\\\lib\\\\commands\\\\parameters-validate.test.js',
84
84
  'lib/commands/parameters-validate.test.js',
85
85
  'parameters-validate\\.test\\.js',
86
+ '/tests/lib/commands/repair-openapi-sync.test.js',
87
+ '\\\\tests\\\\lib\\\\commands\\\\repair-openapi-sync.test.js',
88
+ 'lib/commands/repair-openapi-sync.test.js',
89
+ 'repair-openapi-sync\\.test\\.js',
86
90
  '/tests/lib/utils/datasource-test-run-schema-sync.test.js',
87
91
  '\\\\tests\\\\lib\\\\utils\\\\datasource-test-run-schema-sync.test.js',
88
92
  'lib/utils/datasource-test-run-schema-sync.test.js',
@@ -157,6 +161,14 @@ const defaultProject = {
157
161
  '\\\\tests\\\\lib\\\\utils\\\\paths-app-listing.test.js',
158
162
  'lib/utils/paths-app-listing.test.js',
159
163
  'paths-app-listing\\.test\\.js',
164
+ '/tests/lib/utils/paths-system-builder-resolution.test.js',
165
+ '\\\\tests\\\\lib\\\\utils\\\\paths-system-builder-resolution.test.js',
166
+ 'lib/utils/paths-system-builder-resolution.test.js',
167
+ 'paths-system-builder-resolution\\.test\\.js',
168
+ '/tests/lib/utils/secrets-ancestor-paths.test.js',
169
+ '\\\\tests\\\\lib\\\\utils\\\\secrets-ancestor-paths.test.js',
170
+ 'lib/utils/secrets-ancestor-paths.test.js',
171
+ 'secrets-ancestor-paths\\.test\\.js',
160
172
  '/tests/lib/generator/generator-external-rbac.test.js',
161
173
  '\\\\tests\\\\lib\\\\generator\\\\generator-external-rbac.test.js',
162
174
  'lib/generator/generator-external-rbac.test.js',
@@ -206,7 +218,27 @@ const defaultProject = {
206
218
  'application-frontdoor-paths\\.contract\\.test\\.js',
207
219
  '/tests/lib/core/admin-secrets.test.js',
208
220
  '\\\\tests\\\\lib\\\\core\\\\admin-secrets.test.js',
209
- 'lib/core/admin-secrets.test.js'
221
+ 'lib/core/admin-secrets.test.js',
222
+ '/tests/lib/datasource/validate-datasource-parsed.test.js',
223
+ '\\\\tests\\\\lib\\\\datasource\\\\validate-datasource-parsed.test.js',
224
+ 'lib/datasource/validate-datasource-parsed.test.js',
225
+ 'validate-datasource-parsed\\.test\\.js',
226
+ '/tests/lib/datasource/run-capability-copy.test.js',
227
+ '\\\\tests\\\\lib\\\\datasource\\\\run-capability-copy.test.js',
228
+ 'lib/datasource/run-capability-copy.test.js',
229
+ 'run-capability-copy\\.test\\.js',
230
+ '/tests/lib/datasource/run-capability-diff.test.js',
231
+ '\\\\tests\\\\lib\\\\datasource\\\\run-capability-diff.test.js',
232
+ 'lib/datasource/run-capability-diff.test.js',
233
+ 'run-capability-diff\\.test\\.js',
234
+ '/tests/lib/datasource/run-capability-edit.test.js',
235
+ '\\\\tests\\\\lib\\\\datasource\\\\run-capability-edit.test.js',
236
+ 'lib/datasource/run-capability-edit.test.js',
237
+ 'run-capability-edit\\.test\\.js',
238
+ '/tests/lib/datasource/run-capability-remove.test.js',
239
+ '\\\\tests\\\\lib\\\\datasource\\\\run-capability-remove.test.js',
240
+ 'lib/datasource/run-capability-remove.test.js',
241
+ 'run-capability-remove\\.test\\.js'
210
242
  ];
211
243
  if (process.env.INCLUDE_LOCAL_TESTS !== 'true') {
212
244
  patterns.push('/tests/local/');
@@ -226,7 +258,12 @@ const isolatedProjects = [
226
258
  makeIsolatedProject('external-system-display', ['**/tests/lib/utils/external-system-display.test.js']),
227
259
  makeIsolatedProject('dev-hosts-helper', ['**/tests/lib/utils/dev-hosts-helper.test.js']),
228
260
  makeIsolatedProject('parameters-validate', ['**/tests/lib/commands/parameters-validate.test.js']),
261
+ makeIsolatedProject('repair-openapi-sync', ['**/tests/lib/commands/repair-openapi-sync.test.js']),
229
262
  makeIsolatedProject('paths-app-listing', ['**/tests/lib/utils/paths-app-listing.test.js']),
263
+ makeIsolatedProject('paths-system-builder-resolution', [
264
+ '**/tests/lib/utils/paths-system-builder-resolution.test.js'
265
+ ]),
266
+ makeIsolatedProject('secrets-ancestor-paths', ['**/tests/lib/utils/secrets-ancestor-paths.test.js']),
230
267
  makeIsolatedProject('datasource-validation-watch', [
231
268
  '**/tests/lib/utils/datasource-validation-watch.test.js'
232
269
  ]),
@@ -302,7 +339,16 @@ const isolatedProjects = [
302
339
  makeIsolatedProject('schema-241-alignment', ['**/tests/lib/validation/schema-241-alignment.test.js']),
303
340
  makeIsolatedProject('schema-resolver-order', ['**/tests/lib/utils/schema-resolver-order.test.js']),
304
341
  makeIsolatedProject('app-module', ['**/tests/lib/app/app.test.js']),
305
- makeIsolatedProject('admin-secrets', ['**/tests/lib/core/admin-secrets.test.js'])
342
+ makeIsolatedProject('admin-secrets', ['**/tests/lib/core/admin-secrets.test.js']),
343
+ makeIsolatedProject('validate-datasource-parsed', [
344
+ '**/tests/lib/datasource/validate-datasource-parsed.test.js'
345
+ ]),
346
+ makeIsolatedProject('capability-run-real-fs', [
347
+ '**/tests/lib/datasource/run-capability-copy.test.js',
348
+ '**/tests/lib/datasource/run-capability-diff.test.js',
349
+ '**/tests/lib/datasource/run-capability-edit.test.js',
350
+ '**/tests/lib/datasource/run-capability-remove.test.js'
351
+ ])
306
352
  ];
307
353
 
308
354
  const allProjects = [defaultProject, ...isolatedProjects];
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Controller health (public) — deployment mode for Builder polling tuning.
3
+ *
4
+ * GET /api/v1/health returns `{ data: { deploymentType, ... } }` (miso-controller).
5
+ *
6
+ * @fileoverview Read controller deployment type without authentication
7
+ * @author AI Fabrix Team
8
+ * @version 2.0.0
9
+ */
10
+
11
+ const { ApiClient } = require('./index');
12
+
13
+ /**
14
+ * Extract deploymentType from harmonized API JSON body.
15
+ * @param {Object} response - Result from ApiClient.get / makeApiCall shape `{ success, data }`
16
+ * @returns {string|undefined} Normalized lowercase deployment type or undefined
17
+ */
18
+ function extractDeploymentTypeFromHealthResponse(response) {
19
+ if (!response || response.success === false || response.data === null) {
20
+ return undefined;
21
+ }
22
+ const body = response.data;
23
+ if (!body || typeof body !== 'object') {
24
+ return undefined;
25
+ }
26
+ const payload = body.data !== undefined ? body.data : body;
27
+ if (!payload || typeof payload !== 'object') {
28
+ return undefined;
29
+ }
30
+ const dt = payload.deploymentType;
31
+ return typeof dt === 'string' ? dt.trim().toLowerCase() : undefined;
32
+ }
33
+
34
+ /**
35
+ * Fetch controller DEPLOYMENT mode label (public endpoint, no auth).
36
+ * @async
37
+ * @param {string} controllerUrl - Controller base URL
38
+ * @returns {Promise<string|undefined>} e.g. 'database', 'local', 'azure', 'azure-mock'
39
+ */
40
+ async function getControllerDeploymentType(controllerUrl) {
41
+ const client = new ApiClient(controllerUrl);
42
+ const response = await client.get('/api/v1/health');
43
+ return extractDeploymentTypeFromHealthResponse(response);
44
+ }
45
+
46
+ module.exports = {
47
+ getControllerDeploymentType,
48
+ extractDeploymentTypeFromHealthResponse
49
+ };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @fileoverview Dimension values API (Controller)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { ApiClient } = require('./index');
10
+
11
+ /**
12
+ * List dimension values for a dimension
13
+ * @requiresPermission {Controller} dimensions:read
14
+ * @async
15
+ * @function listDimensionValues
16
+ * @param {string} controllerUrl
17
+ * @param {Object} authConfig
18
+ * @param {string} dimensionIdOrKey
19
+ * @param {Object} [options]
20
+ * @param {number} [options.page]
21
+ * @param {number} [options.pageSize]
22
+ * @param {string} [options.sort]
23
+ * @param {string} [options.filter]
24
+ * @param {string} [options.search]
25
+ * @returns {Promise<Object>}
26
+ */
27
+ async function listDimensionValues(controllerUrl, authConfig, dimensionIdOrKey, options = {}) {
28
+ const client = new ApiClient(controllerUrl, authConfig);
29
+ return await client.get(`/api/v1/dimensions/${encodeURIComponent(dimensionIdOrKey)}/values`, {
30
+ params: options
31
+ });
32
+ }
33
+
34
+ /**
35
+ * Create a dimension value under a dimension
36
+ * @requiresPermission {Controller} dimensions:create
37
+ * @async
38
+ * @function createDimensionValue
39
+ * @param {string} controllerUrl
40
+ * @param {Object} authConfig
41
+ * @param {string} dimensionIdOrKey
42
+ * @param {Object} body
43
+ * @param {string} body.value
44
+ * @param {string} [body.displayName]
45
+ * @param {string} [body.description]
46
+ * @returns {Promise<Object>}
47
+ */
48
+ async function createDimensionValue(controllerUrl, authConfig, dimensionIdOrKey, body) {
49
+ const client = new ApiClient(controllerUrl, authConfig);
50
+ const payload = { value: body.value };
51
+ if (body.displayName !== undefined && body.displayName !== null && body.displayName !== '') {
52
+ payload.displayName = body.displayName;
53
+ }
54
+ if (body.description !== undefined && body.description !== null && body.description !== '') {
55
+ payload.description = body.description;
56
+ }
57
+ return await client.post(`/api/v1/dimensions/${encodeURIComponent(dimensionIdOrKey)}/values`, {
58
+ body: payload
59
+ });
60
+ }
61
+
62
+ /**
63
+ * Delete a dimension value by id
64
+ * @requiresPermission {Controller} dimensions:delete
65
+ * @async
66
+ * @function deleteDimensionValue
67
+ * @param {string} controllerUrl
68
+ * @param {Object} authConfig
69
+ * @param {string} dimensionValueId
70
+ * @returns {Promise<Object>}
71
+ */
72
+ async function deleteDimensionValue(controllerUrl, authConfig, dimensionValueId) {
73
+ const client = new ApiClient(controllerUrl, authConfig);
74
+ return await client.delete(`/api/v1/dimension-values/${encodeURIComponent(dimensionValueId)}`);
75
+ }
76
+
77
+ module.exports = {
78
+ listDimensionValues,
79
+ createDimensionValue,
80
+ deleteDimensionValue
81
+ };
82
+
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @fileoverview Dimensions API (Controller /api/v1/dimensions)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { ApiClient } = require('./index');
10
+
11
+ const BASE = '/api/v1/dimensions';
12
+
13
+ /**
14
+ * List dimensions (paginated)
15
+ * @requiresPermission {Controller} dimensions:read
16
+ * @async
17
+ * @function listDimensions
18
+ * @param {string} controllerUrl
19
+ * @param {Object} authConfig
20
+ * @param {Object} [options]
21
+ * @param {number} [options.page]
22
+ * @param {number} [options.pageSize]
23
+ * @param {string} [options.sort]
24
+ * @param {string} [options.filter]
25
+ * @param {string} [options.search]
26
+ * @returns {Promise<Object>}
27
+ */
28
+ async function listDimensions(controllerUrl, authConfig, options = {}) {
29
+ const client = new ApiClient(controllerUrl, authConfig);
30
+ return await client.get(BASE, { params: options });
31
+ }
32
+
33
+ /**
34
+ * Get a dimension by id or key
35
+ * @requiresPermission {Controller} dimensions:read
36
+ * @async
37
+ * @function getDimension
38
+ * @param {string} controllerUrl
39
+ * @param {Object} authConfig
40
+ * @param {string} dimensionIdOrKey
41
+ * @param {Object} [options]
42
+ * @param {boolean} [options.includeValues]
43
+ * @returns {Promise<Object>}
44
+ */
45
+ async function getDimension(controllerUrl, authConfig, dimensionIdOrKey, options = {}) {
46
+ const client = new ApiClient(controllerUrl, authConfig);
47
+ const params = {};
48
+ if (options.includeValues !== undefined && options.includeValues !== null) {
49
+ params.includeValues = options.includeValues;
50
+ }
51
+ return await client.get(`${BASE}/${encodeURIComponent(dimensionIdOrKey)}`, { params });
52
+ }
53
+
54
+ /**
55
+ * Create a dimension
56
+ * @requiresPermission {Controller} dimensions:create
57
+ * @async
58
+ * @function createDimension
59
+ * @param {string} controllerUrl
60
+ * @param {Object} authConfig
61
+ * @param {Object} body
62
+ * @returns {Promise<Object>}
63
+ */
64
+ async function createDimension(controllerUrl, authConfig, body) {
65
+ const client = new ApiClient(controllerUrl, authConfig);
66
+ const payload = {
67
+ key: body.key,
68
+ displayName: body.displayName,
69
+ dataType: body.dataType
70
+ };
71
+ if (body.description !== undefined && body.description !== null && body.description !== '') {
72
+ payload.description = body.description;
73
+ }
74
+ if (body.isRequired !== undefined && body.isRequired !== null) {
75
+ payload.isRequired = Boolean(body.isRequired);
76
+ }
77
+ return await client.post(BASE, { body: payload });
78
+ }
79
+
80
+ /**
81
+ * Create-if-missing (idempotent by default): if a dimension already exists for the key, return it as success.
82
+ * @requiresPermission {Controller} dimensions:read + dimensions:create
83
+ * @async
84
+ * @function createDimensionIdempotent
85
+ * @param {string} controllerUrl
86
+ * @param {Object} authConfig
87
+ * @param {Object} body
88
+ * @returns {Promise<{ created: boolean, response: Object }>}
89
+ */
90
+ async function createDimensionIdempotent(controllerUrl, authConfig, body) {
91
+ const key = String(body?.key || '').trim();
92
+ if (!key) {
93
+ throw new Error('Dimension key is required');
94
+ }
95
+ const getRes = await getDimension(controllerUrl, authConfig, key);
96
+ if (getRes && getRes.success === true) {
97
+ return { created: false, response: getRes };
98
+ }
99
+ // Not found or other read failure; attempt create and let errors surface.
100
+ const createRes = await createDimension(controllerUrl, authConfig, body);
101
+ if (createRes && createRes.success === true) {
102
+ return { created: true, response: createRes };
103
+ }
104
+ const msg = createRes?.error || createRes?.formattedError || 'Failed to create dimension';
105
+ throw new Error(msg);
106
+ }
107
+
108
+ module.exports = {
109
+ listDimensions,
110
+ getDimension,
111
+ createDimension,
112
+ createDimensionIdempotent
113
+ };
114
+
@@ -60,6 +60,7 @@ async function createExternalSystem(dataplaneUrl, authConfig, systemData) {
60
60
  * @param {Object} authConfig - Authentication configuration
61
61
  * @returns {Promise<Object>} External system details response. May include optional fields:
62
62
  * - {string} [mcpServerUrl] - Full URL of external system MCP server when configured
63
+ * - {string} [mcpDocsPageUrl] - Full URL of MCP OpenAPI docs page (builder may derive when absent)
63
64
  * - {string} [apiDocumentUrl] - Full URL of API document (OpenAPI spec) when configured
64
65
  * - {string} [openApiDocsPageUrl] - Full URL of dataplane API docs page when showOpenApiDocs is true
65
66
  * @throws {Error} If request fails
@@ -0,0 +1,168 @@
1
+ /**
2
+ * @fileoverview Integration clients API (Controller /api/v1/integration-clients)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const { ApiClient } = require('./index');
8
+
9
+ const BASE = '/api/v1/integration-clients';
10
+
11
+ /**
12
+ * Create integration client; returns one-time clientSecret
13
+ * @requiresPermission {Controller} integration-client:create
14
+ * @async
15
+ * @function createIntegrationClient
16
+ * @param {string} controllerUrl - Controller base URL
17
+ * @param {Object} authConfig - Authentication configuration (bearer or client-credentials)
18
+ * @param {Object} body - Request body
19
+ * @param {string} body.key - Key (required)
20
+ * @param {string} body.displayName - Display name (required)
21
+ * @param {string[]} body.redirectUris - Redirect URIs (required, min 1)
22
+ * @param {string[]} [body.groupNames] - Group names (optional)
23
+ * @param {string} [body.description] - Optional description
24
+ * @param {string} [body.keycloakClientId] - Optional Keycloak client id
25
+ * @returns {Promise<Object>} API response
26
+ * @throws {Error} If request fails
27
+ */
28
+ async function createIntegrationClient(controllerUrl, authConfig, body) {
29
+ const client = new ApiClient(controllerUrl, authConfig);
30
+ const payload = {
31
+ key: body.key,
32
+ displayName: body.displayName,
33
+ redirectUris: body.redirectUris,
34
+ groupNames: Array.isArray(body.groupNames) ? body.groupNames : []
35
+ };
36
+ if (body.description !== undefined && body.description !== null && body.description !== '') {
37
+ payload.description = body.description;
38
+ }
39
+ if (body.keycloakClientId) {
40
+ payload.keycloakClientId = body.keycloakClientId;
41
+ }
42
+ return await client.post(BASE, { body: payload });
43
+ }
44
+
45
+ /**
46
+ * List integration clients
47
+ * @requiresPermission {Controller} integration-client:read
48
+ * @async
49
+ * @function listIntegrationClients
50
+ * @param {string} controllerUrl - Controller base URL
51
+ * @param {Object} authConfig - Authentication configuration
52
+ * @param {Object} [options] - Query options
53
+ * @param {number} [options.page] - Page number
54
+ * @param {number} [options.pageSize] - Page size
55
+ * @param {string} [options.sort] - Sort
56
+ * @param {string} [options.filter] - Filter
57
+ * @param {string} [options.search] - Search
58
+ * @returns {Promise<Object>} API response
59
+ * @throws {Error} If request fails
60
+ */
61
+ async function listIntegrationClients(controllerUrl, authConfig, options = {}) {
62
+ const client = new ApiClient(controllerUrl, authConfig);
63
+ const params = {};
64
+ if (options.page !== undefined && options.page !== null) params.page = options.page;
65
+ if (options.pageSize !== undefined && options.pageSize !== null) params.pageSize = options.pageSize;
66
+ if (options.sort) params.sort = options.sort;
67
+ if (options.filter) params.filter = options.filter;
68
+ if (options.search) params.search = options.search;
69
+ return await client.get(BASE, { params });
70
+ }
71
+
72
+ /**
73
+ * Get integration client by id
74
+ * @requiresPermission {Controller} integration-client:read
75
+ * @async
76
+ * @function getIntegrationClient
77
+ * @param {string} controllerUrl - Controller base URL
78
+ * @param {Object} authConfig - Authentication configuration
79
+ * @param {string} id - Integration client id
80
+ * @returns {Promise<Object>} API response
81
+ * @throws {Error} If request fails
82
+ */
83
+ async function getIntegrationClient(controllerUrl, authConfig, id) {
84
+ const client = new ApiClient(controllerUrl, authConfig);
85
+ return await client.get(`${BASE}/${encodeURIComponent(id)}`);
86
+ }
87
+
88
+ /**
89
+ * Regenerate client secret (shown once)
90
+ * @requiresPermission {Controller} integration-client:update
91
+ * @async
92
+ * @function regenerateIntegrationClientSecret
93
+ * @param {string} controllerUrl - Controller base URL
94
+ * @param {Object} authConfig - Authentication configuration
95
+ * @param {string} id - Integration client id
96
+ * @returns {Promise<Object>} API response
97
+ * @throws {Error} If request fails
98
+ */
99
+ async function regenerateIntegrationClientSecret(controllerUrl, authConfig, id) {
100
+ const client = new ApiClient(controllerUrl, authConfig);
101
+ return await client.post(`${BASE}/${encodeURIComponent(id)}/regenerate-secret`);
102
+ }
103
+
104
+ /**
105
+ * Deactivate integration client
106
+ * @requiresPermission {Controller} integration-client:delete
107
+ * @async
108
+ * @function deleteIntegrationClient
109
+ * @param {string} controllerUrl - Controller base URL
110
+ * @param {Object} authConfig - Authentication configuration
111
+ * @param {string} id - Integration client id
112
+ * @returns {Promise<Object>} API response
113
+ * @throws {Error} If request fails
114
+ */
115
+ async function deleteIntegrationClient(controllerUrl, authConfig, id) {
116
+ const client = new ApiClient(controllerUrl, authConfig);
117
+ return await client.delete(`${BASE}/${encodeURIComponent(id)}`);
118
+ }
119
+
120
+ /**
121
+ * Replace group memberships
122
+ * @requiresPermission {Controller} integration-client:update
123
+ * @async
124
+ * @function updateIntegrationClientGroups
125
+ * @param {string} controllerUrl - Controller base URL
126
+ * @param {Object} authConfig - Authentication configuration
127
+ * @param {string} id - Integration client id
128
+ * @param {Object} body - Body with groupNames
129
+ * @param {string[]} body.groupNames - Group names
130
+ * @returns {Promise<Object>} API response
131
+ * @throws {Error} If request fails
132
+ */
133
+ async function updateIntegrationClientGroups(controllerUrl, authConfig, id, body) {
134
+ const client = new ApiClient(controllerUrl, authConfig);
135
+ return await client.put(`${BASE}/${encodeURIComponent(id)}/groups`, {
136
+ body: { groupNames: body.groupNames }
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Replace redirect URIs
142
+ * @requiresPermission {Controller} integration-client:update
143
+ * @async
144
+ * @function updateIntegrationClientRedirectUris
145
+ * @param {string} controllerUrl - Controller base URL
146
+ * @param {Object} authConfig - Authentication configuration
147
+ * @param {string} id - Integration client id
148
+ * @param {Object} body - Body with redirectUris
149
+ * @param {string[]} body.redirectUris - Redirect URIs (min 1)
150
+ * @returns {Promise<Object>} API response
151
+ * @throws {Error} If request fails
152
+ */
153
+ async function updateIntegrationClientRedirectUris(controllerUrl, authConfig, id, body) {
154
+ const client = new ApiClient(controllerUrl, authConfig);
155
+ return await client.put(`${BASE}/${encodeURIComponent(id)}/redirect-uris`, {
156
+ body: { redirectUris: body.redirectUris }
157
+ });
158
+ }
159
+
160
+ module.exports = {
161
+ createIntegrationClient,
162
+ listIntegrationClients,
163
+ getIntegrationClient,
164
+ regenerateIntegrationClientSecret,
165
+ deleteIntegrationClient,
166
+ updateIntegrationClientGroups,
167
+ updateIntegrationClientRedirectUris
168
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @fileoverview Dimension values API type definitions (Controller)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /**
8
+ * Create dimension value payload
9
+ * @typedef {Object} DimensionValueCreateRequest
10
+ * @property {string} value
11
+ * @property {string} [displayName]
12
+ * @property {string} [description]
13
+ */
14
+
15
+ /**
16
+ * Dimension value entity
17
+ * @typedef {Object} DimensionValue
18
+ * @property {string} id
19
+ * @property {string} dimensionId
20
+ * @property {string} value
21
+ * @property {string|null} [displayName]
22
+ * @property {string|null} [description]
23
+ * @property {string|null} [createdBy]
24
+ * @property {string|null} [updatedBy]
25
+ * @property {string} [createdAt]
26
+ * @property {string} [updatedAt]
27
+ */
28
+