@aifabrix/builder 2.40.2 → 2.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/.cursor/rules/docs-rules.mdc +30 -0
  2. package/README.md +7 -5
  3. package/integration/hubspot/README.md +8 -4
  4. package/integration/hubspot/application.json +54 -0
  5. package/integration/hubspot/create-hubspot.js +9 -136
  6. package/integration/hubspot/env.template +3 -4
  7. package/integration/hubspot/hubspot-datasource-company.json +343 -5
  8. package/integration/hubspot/hubspot-datasource-contact.json +413 -5
  9. package/integration/hubspot/hubspot-datasource-deal.json +341 -4
  10. package/integration/hubspot/hubspot-datasource-users.json +116 -0
  11. package/integration/hubspot/hubspot-deploy.json +1250 -108
  12. package/integration/hubspot/hubspot-system.json +15 -32
  13. package/integration/hubspot/test-dataplane-down-tests.js +17 -16
  14. package/integration/hubspot/test-dataplane-down.js +2 -2
  15. package/integration/hubspot/test.js +1 -1
  16. package/jest.config.manual.js +2 -1
  17. package/lib/api/credential.api.js +40 -0
  18. package/lib/api/dev.api.js +423 -0
  19. package/lib/api/external-test.api.js +111 -0
  20. package/lib/api/index.js +42 -19
  21. package/lib/api/pipeline.api.js +66 -120
  22. package/lib/api/types/credential.types.js +23 -0
  23. package/lib/api/types/dev.types.js +140 -0
  24. package/lib/api/types/pipeline.types.js +37 -0
  25. package/lib/api/wizard-platform.api.js +61 -0
  26. package/lib/api/wizard.api.js +34 -1
  27. package/lib/app/config.js +44 -11
  28. package/lib/app/down.js +2 -1
  29. package/lib/app/index.js +12 -1
  30. package/lib/app/prompts.js +44 -29
  31. package/lib/app/push.js +36 -12
  32. package/lib/app/readme.js +9 -6
  33. package/lib/app/run-env-compose.js +264 -0
  34. package/lib/app/run-helpers.js +121 -118
  35. package/lib/app/run.js +148 -28
  36. package/lib/app/show-display.js +1 -1
  37. package/lib/app/show.js +5 -2
  38. package/lib/build/index.js +11 -3
  39. package/lib/cli/setup-app.js +172 -15
  40. package/lib/cli/setup-credential-deployment.js +31 -6
  41. package/lib/cli/setup-dev.js +206 -16
  42. package/lib/cli/setup-environment.js +16 -6
  43. package/lib/cli/setup-external-system.js +89 -24
  44. package/lib/cli/setup-infra.js +82 -15
  45. package/lib/cli/setup-secrets.js +52 -5
  46. package/lib/cli/setup-utility.js +129 -24
  47. package/lib/commands/app-install.js +172 -0
  48. package/lib/commands/app-shell.js +75 -0
  49. package/lib/commands/app-test.js +282 -0
  50. package/lib/commands/app.js +1 -1
  51. package/lib/commands/credential-env.js +162 -0
  52. package/lib/commands/credential-list.js +17 -22
  53. package/lib/commands/credential-push.js +96 -0
  54. package/lib/commands/datasource.js +77 -6
  55. package/lib/commands/dev-cli-handlers.js +141 -0
  56. package/lib/commands/dev-down.js +114 -0
  57. package/lib/commands/dev-init.js +347 -0
  58. package/lib/commands/repair-auth-config.js +99 -0
  59. package/lib/commands/repair-datasource-keys.js +208 -0
  60. package/lib/commands/repair-datasource.js +235 -0
  61. package/lib/commands/repair-env-template.js +348 -0
  62. package/lib/commands/repair-internal.js +85 -0
  63. package/lib/commands/repair-rbac.js +158 -0
  64. package/lib/commands/repair.js +507 -0
  65. package/lib/commands/secrets-list.js +118 -0
  66. package/lib/commands/secrets-remove.js +97 -0
  67. package/lib/commands/secrets-set.js +30 -17
  68. package/lib/commands/secrets-validate.js +50 -0
  69. package/lib/commands/test-e2e-external.js +165 -0
  70. package/lib/commands/up-dataplane.js +2 -2
  71. package/lib/commands/up-miso.js +0 -25
  72. package/lib/commands/upload.js +96 -40
  73. package/lib/commands/wizard-core-helpers.js +226 -4
  74. package/lib/commands/wizard-core.js +67 -29
  75. package/lib/commands/wizard-dataplane.js +1 -1
  76. package/lib/commands/wizard-entity-selection.js +43 -0
  77. package/lib/commands/wizard-headless.js +44 -5
  78. package/lib/commands/wizard-helpers.js +7 -3
  79. package/lib/commands/wizard.js +86 -64
  80. package/lib/core/admin-secrets.js +96 -0
  81. package/lib/core/config.js +7 -1
  82. package/lib/core/secrets-ensure.js +378 -0
  83. package/lib/core/secrets-env-write.js +157 -0
  84. package/lib/core/secrets.js +176 -89
  85. package/lib/datasource/deploy.js +12 -3
  86. package/lib/datasource/field-reference-validator.js +91 -0
  87. package/lib/datasource/test-e2e.js +219 -0
  88. package/lib/datasource/test-integration.js +154 -0
  89. package/lib/datasource/validate.js +21 -3
  90. package/lib/deployment/deployer.js +7 -5
  91. package/lib/deployment/environment-config.js +137 -0
  92. package/lib/deployment/environment.js +21 -98
  93. package/lib/deployment/push.js +32 -2
  94. package/lib/external-system/download.js +188 -203
  95. package/lib/external-system/generator.js +204 -56
  96. package/lib/external-system/test-auth.js +7 -3
  97. package/lib/external-system/test-execution.js +2 -1
  98. package/lib/external-system/test-system-level.js +73 -0
  99. package/lib/external-system/test.js +56 -19
  100. package/lib/generator/external-controller-manifest.js +29 -2
  101. package/lib/generator/external-schema-utils.js +1 -1
  102. package/lib/generator/external.js +10 -3
  103. package/lib/generator/index.js +177 -25
  104. package/lib/generator/split-readme.js +1 -0
  105. package/lib/generator/split-variables.js +7 -1
  106. package/lib/generator/split.js +194 -54
  107. package/lib/generator/wizard-prompts-secondary.js +294 -0
  108. package/lib/generator/wizard-prompts.js +105 -106
  109. package/lib/generator/wizard-readme.js +88 -0
  110. package/lib/generator/wizard.js +155 -158
  111. package/lib/infrastructure/compose.js +11 -1
  112. package/lib/infrastructure/helpers.js +103 -20
  113. package/lib/infrastructure/index.js +98 -12
  114. package/lib/infrastructure/services.js +88 -22
  115. package/lib/schema/application-schema.json +32 -8
  116. package/lib/schema/external-datasource.schema.json +49 -26
  117. package/lib/schema/external-system.schema.json +509 -411
  118. package/lib/schema/wizard-config.schema.json +16 -0
  119. package/lib/utils/api.js +41 -13
  120. package/lib/utils/app-register-auth.js +25 -3
  121. package/lib/utils/auth-headers.js +8 -7
  122. package/lib/utils/cli-utils.js +20 -0
  123. package/lib/utils/compose-generator.js +77 -76
  124. package/lib/utils/compose-handlebars-helpers.js +54 -0
  125. package/lib/utils/compose-vector-helper.js +18 -0
  126. package/lib/utils/config-format-preference.js +51 -0
  127. package/lib/utils/config-format.js +36 -0
  128. package/lib/utils/config-paths.js +127 -2
  129. package/lib/utils/configuration-env-resolver.js +179 -0
  130. package/lib/utils/credential-display.js +83 -0
  131. package/lib/utils/credential-secrets-env.js +357 -0
  132. package/lib/utils/dataplane-pipeline-warning.js +28 -0
  133. package/lib/utils/deployment-validation-helpers.js +4 -4
  134. package/lib/utils/dev-ca-install.js +139 -0
  135. package/lib/utils/dev-cert-helper.js +122 -0
  136. package/lib/utils/device-code-helpers.js +224 -0
  137. package/lib/utils/device-code.js +37 -336
  138. package/lib/utils/docker-build.js +40 -8
  139. package/lib/utils/env-copy.js +103 -13
  140. package/lib/utils/env-map.js +35 -5
  141. package/lib/utils/env-template.js +6 -5
  142. package/lib/utils/error-formatters/http-status-errors.js +20 -2
  143. package/lib/utils/error-formatters/permission-errors.js +0 -1
  144. package/lib/utils/error-formatters/validation-errors.js +0 -1
  145. package/lib/utils/external-readme.js +56 -29
  146. package/lib/utils/external-system-display.js +59 -1
  147. package/lib/utils/external-system-test-helpers.js +21 -8
  148. package/lib/utils/external-system-validators.js +3 -0
  149. package/lib/utils/file-upload.js +20 -50
  150. package/lib/utils/help-builder.js +16 -2
  151. package/lib/utils/infra-status.js +80 -45
  152. package/lib/utils/local-secrets.js +7 -52
  153. package/lib/utils/mutagen-install.js +195 -0
  154. package/lib/utils/mutagen.js +146 -0
  155. package/lib/utils/paths.js +128 -37
  156. package/lib/utils/port-resolver.js +28 -16
  157. package/lib/utils/remote-dev-auth.js +38 -0
  158. package/lib/utils/remote-docker-env.js +43 -0
  159. package/lib/utils/remote-secrets-loader.js +60 -0
  160. package/lib/utils/secrets-canonical.js +93 -0
  161. package/lib/utils/secrets-generator.js +114 -6
  162. package/lib/utils/secrets-helpers.js +108 -114
  163. package/lib/utils/secrets-path.js +2 -2
  164. package/lib/utils/secrets-utils.js +52 -1
  165. package/lib/utils/secrets-validation.js +84 -0
  166. package/lib/utils/ssh-key-helper.js +116 -0
  167. package/lib/utils/test-log-writer.js +56 -0
  168. package/lib/utils/token-manager-messages.js +90 -0
  169. package/lib/utils/token-manager.js +29 -36
  170. package/lib/utils/variable-transformer.js +3 -3
  171. package/lib/validation/env-template-auth.js +157 -0
  172. package/lib/validation/env-template-kv.js +41 -0
  173. package/lib/validation/external-manifest-validator.js +25 -0
  174. package/lib/validation/external-system-auth-rules.js +86 -0
  175. package/lib/validation/validate-batch.js +149 -0
  176. package/lib/validation/validate-datasource-keys-api.js +33 -0
  177. package/lib/validation/validate-display.js +94 -16
  178. package/lib/validation/validate.js +25 -12
  179. package/lib/validation/validator.js +72 -9
  180. package/lib/validation/wizard-datasource-validation.js +50 -0
  181. package/package.json +8 -3
  182. package/scripts/install-local.js +34 -15
  183. package/templates/README.md +0 -1
  184. package/templates/applications/README.md.hbs +4 -4
  185. package/templates/applications/dataplane/application.yaml +6 -5
  186. package/templates/applications/dataplane/env.template +15 -10
  187. package/templates/applications/dataplane/rbac.yaml +2 -2
  188. package/templates/applications/keycloak/env.template +2 -0
  189. package/templates/applications/miso-controller/application.yaml +1 -0
  190. package/templates/applications/miso-controller/env.template +12 -10
  191. package/templates/external-system/README.md.hbs +65 -25
  192. package/templates/external-system/deploy.js.hbs +4 -2
  193. package/templates/external-system/external-datasource.yaml.hbs +217 -0
  194. package/templates/external-system/external-system.json.hbs +1 -18
  195. package/templates/infra/compose.yaml.hbs +6 -0
  196. package/templates/python/docker-compose.hbs +49 -23
  197. package/templates/typescript/docker-compose.hbs +48 -22
  198. package/integration/hubspot/application.yaml +0 -37
@@ -9,10 +9,7 @@
9
9
  * @version 2.0.0
10
10
  */
11
11
 
12
- const fs = require('fs');
13
- const path = require('path');
14
12
  const chalk = require('chalk');
15
- const Ajv = require('ajv');
16
13
  const logger = require('../utils/logger');
17
14
  const config = require('../core/config');
18
15
  const { resolveControllerUrl } = require('../utils/controller-url');
@@ -21,9 +18,12 @@ const { getOrRefreshDeviceToken } = require('../utils/token-manager');
21
18
  const { getPipelineDeployment } = require('../api/pipeline.api');
22
19
  const { deployEnvironment: deployEnvironmentInfra, getDeployment } = require('../api/deployments.api');
23
20
  const { handleDeploymentErrors } = require('../utils/deployment-errors');
24
- const { formatValidationErrors } = require('../utils/error-formatter');
25
21
  const auditLogger = require('../core/audit-logger');
26
- const environmentDeployRequestSchema = require('../schema/environment-deploy-request.schema.json');
22
+ const {
23
+ normalizePreset,
24
+ buildEnvironmentConfigFromPreset,
25
+ loadAndValidateEnvironmentDeployConfig
26
+ } = require('./environment-config');
27
27
 
28
28
  /**
29
29
  * Validates environment deployment prerequisites
@@ -82,102 +82,26 @@ async function getEnvironmentAuth(controllerUrl) {
82
82
  * @returns {Promise<Object>} Deployment result
83
83
  * @throws {Error} If deployment fails
84
84
  */
85
- /** Reads and parses config file; throws if missing, unreadable, or invalid structure. */
86
- function parseEnvironmentConfigFile(resolvedPath) {
87
- let raw;
88
- try {
89
- raw = fs.readFileSync(resolvedPath, 'utf8');
90
- } catch (e) {
91
- throw new Error(`Cannot read config file: ${resolvedPath}. ${e.message}`);
92
- }
93
- let parsed;
94
- try {
95
- parsed = JSON.parse(raw);
96
- } catch (e) {
97
- throw new Error(
98
- `Invalid JSON in config file: ${resolvedPath}\n${e.message}\n` +
99
- 'Expected format: { "environmentConfig": { "key", "environment", "preset", "serviceName", "location" }, "dryRun": false }'
100
- );
101
- }
102
- if (parsed === null || typeof parsed !== 'object') {
103
- throw new Error(
104
- `Config file must be a JSON object with "environmentConfig". File: ${resolvedPath}\n` +
105
- 'Example: { "environmentConfig": { "key": "dev", "environment": "dev", "preset": "s", "serviceName": "aifabrix", "location": "swedencentral" }, "dryRun": false }'
106
- );
107
- }
108
- if (parsed.environmentConfig === undefined) {
109
- throw new Error(
110
- `Config file must contain "environmentConfig" (object). File: ${resolvedPath}\n` +
111
- 'Example: { "environmentConfig": { "key": "dev", "environment": "dev", "preset": "s", "serviceName": "aifabrix", "location": "swedencentral" } }'
112
- );
113
- }
114
- if (typeof parsed.environmentConfig !== 'object' || parsed.environmentConfig === null) {
115
- throw new Error(`"environmentConfig" must be an object. File: ${resolvedPath}`);
116
- }
117
- return parsed;
118
- }
119
-
120
85
  /**
121
- * Validates parsed config against schema and returns deploy request.
122
- * @param {Object} parsed - Parsed config object
123
- * @param {string} resolvedPath - Path for error messages
124
- * @returns {Object} { environmentConfig, dryRun? }
125
- */
126
- function validateEnvironmentDeployParsed(parsed, resolvedPath) {
127
- const ajv = new Ajv({ allErrors: true, strict: false });
128
- const validate = ajv.compile(environmentDeployRequestSchema);
129
- if (!validate(parsed)) {
130
- const messages = formatValidationErrors(validate.errors);
131
- throw new Error(
132
- `Environment config validation failed (${resolvedPath}):\n • ${messages.join('\n • ')}\n` +
133
- 'Fix the config file and run the command again. See templates/infra/environment-dev.json for a valid example.'
134
- );
135
- }
136
- return {
137
- environmentConfig: parsed.environmentConfig,
138
- dryRun: Boolean(parsed.dryRun)
139
- };
140
- }
141
-
142
- /**
143
- * Loads and validates environment deploy config from a JSON file
144
- * @param {string} configPath - Absolute or relative path to config JSON
145
- * @returns {Object} Valid deploy request { environmentConfig, dryRun? }
146
- * @throws {Error} If file missing, invalid JSON, or validation fails
147
- */
148
- function loadAndValidateEnvironmentDeployConfig(configPath) {
149
- const resolvedPath = path.isAbsolute(configPath) ? configPath : path.resolve(process.cwd(), configPath);
150
- if (!fs.existsSync(resolvedPath)) {
151
- throw new Error(
152
- `Environment config file not found: ${resolvedPath}\n` +
153
- 'Use --config <file> with a JSON file containing "environmentConfig" (e.g. templates/infra/environment-dev.json).'
154
- );
155
- }
156
- const parsed = parseEnvironmentConfigFile(resolvedPath);
157
- return validateEnvironmentDeployParsed(parsed, resolvedPath);
158
- }
159
-
160
- /**
161
- * Builds environment deployment request from options (config file required)
86
+ * Builds environment deployment request from options (config file or --preset)
87
+ * When --config is provided, uses that file; otherwise uses --preset (default s).
162
88
  * @function buildEnvironmentDeploymentRequest
163
89
  * @param {string} validatedEnvKey - Validated environment key
164
- * @param {Object} options - Deployment options (must include options.config)
90
+ * @param {Object} options - Deployment options (options.config optional; options.preset used when no config)
165
91
  * @returns {Object} Deployment request object for API
166
92
  */
167
93
  function buildEnvironmentDeploymentRequest(validatedEnvKey, options) {
168
- if (!options.config || typeof options.config !== 'string') {
169
- throw new Error(
170
- 'Environment deploy requires a config file with "environmentConfig". Use --config <file>.\n' +
171
- 'Example: aifabrix environment deploy dev --config templates/infra/environment-dev.json'
172
- );
173
- }
174
- const deployRequest = loadAndValidateEnvironmentDeployConfig(options.config);
175
- if (deployRequest.environmentConfig.key && deployRequest.environmentConfig.key !== validatedEnvKey) {
176
- logger.log(chalk.yellow(
177
- `⚠ Config key "${deployRequest.environmentConfig.key}" does not match deploy target "${validatedEnvKey}"; using target "${validatedEnvKey}".`
178
- ));
94
+ if (options.config && typeof options.config === 'string') {
95
+ const deployRequest = loadAndValidateEnvironmentDeployConfig(options.config);
96
+ if (deployRequest.environmentConfig.key && deployRequest.environmentConfig.key !== validatedEnvKey) {
97
+ logger.log(chalk.yellow(
98
+ `⚠ Config key "${deployRequest.environmentConfig.key}" does not match deploy target "${validatedEnvKey}"; using target "${validatedEnvKey}".`
99
+ ));
100
+ }
101
+ return deployRequest;
179
102
  }
180
- return deployRequest;
103
+ const preset = normalizePreset(options.preset);
104
+ return buildEnvironmentConfigFromPreset(validatedEnvKey, preset);
181
105
  }
182
106
 
183
107
  /**
@@ -371,7 +295,8 @@ function displayDeploymentResults(result) {
371
295
  * @param {string} envKey - Environment key (miso, dev, tst, pro)
372
296
  * @param {Object} options - Deployment options
373
297
  * @param {string} options.controller - Controller URL (required)
374
- * @param {string} [options.config] - Environment configuration file (optional)
298
+ * @param {string} [options.config] - Environment configuration file (optional; if omitted, --preset is used)
299
+ * @param {string} [options.preset] - Environment size preset: s, m, l, xl (default: s), used when config is not provided
375
300
  * @param {boolean} [options.skipValidation] - Skip validation checks
376
301
  * @param {boolean} [options.poll] - Poll for deployment status (default: true)
377
302
  * @param {boolean} [options.noPoll] - Do not poll for status
@@ -492,6 +417,4 @@ async function deployEnvironment(envKey, options = {}) {
492
417
  throw error;
493
418
  }
494
419
  }
495
- module.exports = {
496
- deployEnvironment
497
- };
420
+ module.exports = { deployEnvironment };
@@ -16,6 +16,29 @@ const logger = require('../utils/logger');
16
16
 
17
17
  const execAsync = promisify(exec);
18
18
 
19
+ /** Timeout for az account show (fail fast when not logged in) */
20
+ const AZ_ACCOUNT_SHOW_TIMEOUT_MS = 10000;
21
+ /** Timeout for az acr show (avoid hang when Azure CLI prompts for login) */
22
+ const AZ_ACR_SHOW_TIMEOUT_MS = 15000;
23
+ /** Timeout for az acr login */
24
+ const AZ_ACR_LOGIN_TIMEOUT_MS = 120000;
25
+
26
+ /**
27
+ * Check if user is logged in to Azure CLI
28
+ * Fails fast so push does not hang when user is not logged in.
29
+ * @param {Object} [execOptions] - Options for exec (e.g. shell on Windows)
30
+ * @returns {Promise<boolean>} True if logged in
31
+ */
32
+ async function checkAzureLogin(execOptions = {}) {
33
+ const options = process.platform === 'win32' ? { shell: true, ...execOptions } : execOptions;
34
+ try {
35
+ await execAsync('az account show', { ...options, timeout: AZ_ACCOUNT_SHOW_TIMEOUT_MS });
36
+ return true;
37
+ } catch (_error) {
38
+ return false;
39
+ }
40
+ }
41
+
19
42
  /**
20
43
  * Check if Azure CLI is installed
21
44
  * @returns {Promise<boolean>} True if Azure CLI is available
@@ -128,7 +151,7 @@ async function checkACRAuthentication(registry) {
128
151
  const registryName = extractRegistryName(registry);
129
152
  // On Windows, use shell option to ensure proper command resolution
130
153
  const options = process.platform === 'win32' ? { shell: true } : {};
131
- await execAsync(`az acr show --name ${registryName}`, options);
154
+ await execAsync(`az acr show --name ${registryName}`, { ...options, timeout: AZ_ACR_SHOW_TIMEOUT_MS });
132
155
  return true;
133
156
  } catch (error) {
134
157
  return false;
@@ -146,9 +169,15 @@ async function authenticateACR(registry) {
146
169
  logger.log(chalk.blue(`Authenticating with ${registry}...`));
147
170
  // On Windows, use shell option to ensure proper command resolution
148
171
  const options = process.platform === 'win32' ? { shell: true } : {};
149
- await execAsync(`az acr login --name ${registryName}`, options);
172
+ await execAsync(`az acr login --name ${registryName}`, { ...options, timeout: AZ_ACR_LOGIN_TIMEOUT_MS });
150
173
  logger.log(chalk.green(`✓ Authenticated with ${registry}`));
151
174
  } catch (error) {
175
+ const msg = error.message || String(error);
176
+ if (msg.includes('ETIMEDOUT') || msg.includes('timeout')) {
177
+ throw new Error(
178
+ 'Authentication timed out. Make sure you\'re logged in to Azure first: az login'
179
+ );
180
+ }
152
181
  throw new Error(`Failed to authenticate with Azure Container Registry: ${error.message}`);
153
182
  }
154
183
  }
@@ -267,6 +296,7 @@ async function pushImage(imageWithTag, registry = null) {
267
296
 
268
297
  module.exports = {
269
298
  checkAzureCLIInstalled,
299
+ checkAzureLogin,
270
300
  extractRegistryName,
271
301
  validateRegistryURL,
272
302
  checkACRAuthentication,