@aifabrix/builder 2.8.0 → 2.10.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 (46) hide show
  1. package/integration/hubspot/README.md +136 -0
  2. package/integration/hubspot/env.template +9 -0
  3. package/integration/hubspot/hubspot-deploy-company.json +200 -0
  4. package/integration/hubspot/hubspot-deploy-contact.json +228 -0
  5. package/integration/hubspot/hubspot-deploy-deal.json +248 -0
  6. package/integration/hubspot/hubspot-deploy.json +91 -0
  7. package/integration/hubspot/variables.yaml +17 -0
  8. package/lib/app-config.js +4 -3
  9. package/lib/app-deploy.js +8 -20
  10. package/lib/app-dockerfile.js +7 -9
  11. package/lib/app-prompts.js +6 -5
  12. package/lib/app-push.js +9 -9
  13. package/lib/app-register.js +23 -5
  14. package/lib/app-rotate-secret.js +10 -0
  15. package/lib/app-run.js +5 -11
  16. package/lib/app.js +42 -14
  17. package/lib/build.js +20 -16
  18. package/lib/cli.js +61 -2
  19. package/lib/commands/login.js +7 -1
  20. package/lib/datasource-deploy.js +14 -20
  21. package/lib/external-system-deploy.js +123 -40
  22. package/lib/external-system-download.js +431 -0
  23. package/lib/external-system-generator.js +13 -10
  24. package/lib/external-system-test.js +446 -0
  25. package/lib/generator-builders.js +323 -0
  26. package/lib/generator.js +200 -292
  27. package/lib/schema/application-schema.json +853 -852
  28. package/lib/schema/env-config.yaml +9 -1
  29. package/lib/schema/external-datasource.schema.json +823 -49
  30. package/lib/schema/external-system.schema.json +96 -78
  31. package/lib/templates.js +36 -5
  32. package/lib/utils/api-error-handler.js +12 -12
  33. package/lib/utils/cli-utils.js +4 -4
  34. package/lib/utils/device-code.js +65 -2
  35. package/lib/utils/env-template.js +5 -4
  36. package/lib/utils/external-system-display.js +159 -0
  37. package/lib/utils/external-system-validators.js +245 -0
  38. package/lib/utils/paths.js +151 -1
  39. package/lib/utils/schema-resolver.js +7 -2
  40. package/lib/validator.js +5 -2
  41. package/package.json +1 -1
  42. package/templates/applications/keycloak/env.template +8 -2
  43. package/templates/applications/keycloak/variables.yaml +3 -3
  44. package/templates/applications/miso-controller/env.template +23 -10
  45. package/templates/applications/miso-controller/rbac.yaml +263 -213
  46. package/templates/applications/miso-controller/variables.yaml +3 -3
@@ -0,0 +1,323 @@
1
+ /**
2
+ * AI Fabrix Builder Deployment JSON Builder Helpers
3
+ *
4
+ * Helper functions for building deployment manifest structures
5
+ *
6
+ * @fileoverview Builder helper functions for deployment JSON generation
7
+ * @author AI Fabrix Team
8
+ * @version 2.0.0
9
+ */
10
+
11
+ /**
12
+ * Sanitizes authentication type - map keycloak to azure (schema allows: azure, local, none)
13
+ * @function sanitizeAuthType
14
+ * @param {string} authType - Authentication type
15
+ * @returns {string} Sanitized authentication type
16
+ */
17
+ function sanitizeAuthType(authType) {
18
+ if (authType === 'keycloak') {
19
+ return 'azure';
20
+ }
21
+ if (authType && !['azure', 'local', 'none'].includes(authType)) {
22
+ return 'azure'; // Default to azure if invalid type
23
+ }
24
+ return authType;
25
+ }
26
+
27
+ /**
28
+ * Filters configuration based on registry mode
29
+ * When registryMode is "external", only DOCKER_REGISTRY_SERVER_* variables are allowed
30
+ * @function filterConfigurationByRegistryMode
31
+ * @param {Array} configuration - Environment configuration
32
+ * @param {string} registryMode - Registry mode ('external' or 'internal')
33
+ * @returns {Array} Filtered configuration
34
+ */
35
+ function filterConfigurationByRegistryMode(configuration, registryMode) {
36
+ if (registryMode !== 'external') {
37
+ return configuration;
38
+ }
39
+
40
+ const allowedDockerRegistryVars = [
41
+ 'DOCKER_REGISTRY_SERVER_URL',
42
+ 'DOCKER_REGISTRY_SERVER_USERNAME',
43
+ 'DOCKER_REGISTRY_SERVER_PASSWORD'
44
+ ];
45
+ return configuration.filter(config => allowedDockerRegistryVars.includes(config.name));
46
+ }
47
+
48
+ function buildImageReference(variables) {
49
+ const imageName = variables.image?.name || variables.app?.key || 'app';
50
+ const registry = variables.image?.registry;
51
+ const tag = variables.image?.tag || 'latest';
52
+
53
+ if (registry) {
54
+ return `${registry}/${imageName}:${tag}`;
55
+ }
56
+
57
+ return `${imageName}:${tag}`;
58
+ }
59
+
60
+ function buildHealthCheck(variables) {
61
+ const healthCheck = {
62
+ path: variables.healthCheck?.path || '/health',
63
+ interval: variables.healthCheck?.interval || 30
64
+ };
65
+
66
+ // Add optional probe fields if present
67
+ if (variables.healthCheck?.probePath) {
68
+ healthCheck.probePath = variables.healthCheck.probePath;
69
+ }
70
+ if (variables.healthCheck?.probeRequestType) {
71
+ healthCheck.probeRequestType = variables.healthCheck.probeRequestType;
72
+ }
73
+ if (variables.healthCheck?.probeProtocol) {
74
+ healthCheck.probeProtocol = variables.healthCheck.probeProtocol;
75
+ }
76
+ if (variables.healthCheck?.probeIntervalInSeconds) {
77
+ healthCheck.probeIntervalInSeconds = variables.healthCheck.probeIntervalInSeconds;
78
+ }
79
+
80
+ return healthCheck;
81
+ }
82
+
83
+ function buildRequirements(variables) {
84
+ const requires = variables.requires || {};
85
+
86
+ return {
87
+ database: requires.database || false,
88
+ databases: requires.databases || (requires.database ? [{ name: variables.app?.key || 'app' }] : []),
89
+ redis: requires.redis || false,
90
+ storage: requires.storage || false,
91
+ storageSize: requires.storageSize || '1Gi'
92
+ };
93
+ }
94
+
95
+ function buildAuthentication(rbac) {
96
+ if (!rbac) {
97
+ return {
98
+ type: 'none',
99
+ enableSSO: false,
100
+ requiredRoles: []
101
+ };
102
+ }
103
+
104
+ return {
105
+ type: 'azure', // Default to azure (enum: azure, local, none)
106
+ enableSSO: true,
107
+ requiredRoles: rbac.roles?.map(role => role.value) || []
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Builds base deployment structure
113
+ * @function buildBaseDeployment
114
+ * @param {string} appName - Application name
115
+ * @param {Object} variables - Variables configuration
116
+ * @param {Array} filteredConfiguration - Filtered environment configuration
117
+ * @returns {Object} Base deployment structure
118
+ */
119
+ function buildBaseDeployment(appName, variables, filteredConfiguration) {
120
+ const requires = variables.requires || {};
121
+ return {
122
+ key: variables.app?.key || appName,
123
+ displayName: variables.app?.displayName || appName,
124
+ description: variables.app?.description || '',
125
+ type: variables.app?.type || 'webapp',
126
+ image: buildImageReference(variables),
127
+ registryMode: variables.image?.registryMode || 'external',
128
+ port: variables.port || 3000,
129
+ requiresDatabase: requires.database || false,
130
+ requiresRedis: requires.redis || false,
131
+ requiresStorage: requires.storage || false,
132
+ databases: requires.databases || (requires.database ? [{ name: variables.app?.key || 'app' }] : []),
133
+ configuration: filteredConfiguration
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Builds authentication configuration from variables or RBAC
139
+ * @function buildAuthenticationConfig
140
+ * @param {Object} variables - Variables configuration
141
+ * @param {Object|null} rbac - RBAC configuration
142
+ * @returns {Object} Authentication configuration
143
+ */
144
+ function buildAuthenticationConfig(variables, rbac) {
145
+ if (variables.authentication) {
146
+ const auth = {
147
+ enableSSO: variables.authentication.enableSSO !== undefined ? variables.authentication.enableSSO : true
148
+ };
149
+
150
+ // When enableSSO is false, default type to 'none' and requiredRoles to []
151
+ // When enableSSO is true, require type and requiredRoles
152
+ // Sanitize auth type (e.g., map keycloak to azure)
153
+ if (auth.enableSSO === false) {
154
+ auth.type = sanitizeAuthType(variables.authentication.type || 'none');
155
+ auth.requiredRoles = variables.authentication.requiredRoles || [];
156
+ } else {
157
+ auth.type = sanitizeAuthType(variables.authentication.type || 'azure');
158
+ auth.requiredRoles = variables.authentication.requiredRoles || [];
159
+ }
160
+
161
+ if (variables.authentication.endpoints) {
162
+ auth.endpoints = variables.authentication.endpoints;
163
+ }
164
+ return auth;
165
+ }
166
+ return buildAuthentication(rbac);
167
+ }
168
+
169
+ /**
170
+ * Validates and transforms repository configuration
171
+ * @function validateRepositoryConfig
172
+ * @param {Object} repository - Repository configuration
173
+ * @returns {Object|null} Validated repository config or null
174
+ */
175
+ function validateRepositoryConfig(repository) {
176
+ if (!repository || (!repository.enabled && !repository.repositoryUrl)) {
177
+ return null;
178
+ }
179
+
180
+ if (repository.repositoryUrl && repository.repositoryUrl.trim()) {
181
+ return {
182
+ enabled: repository.enabled || false,
183
+ repositoryUrl: repository.repositoryUrl
184
+ };
185
+ }
186
+
187
+ if (repository.enabled) {
188
+ return { enabled: true };
189
+ }
190
+
191
+ return null;
192
+ }
193
+
194
+ /**
195
+ * Validates and transforms build fields
196
+ * @function validateBuildFields
197
+ * @param {Object} build - Build configuration
198
+ * @returns {Object|null} Validated build config or null
199
+ */
200
+ function validateBuildFields(build) {
201
+ if (!build) {
202
+ return null;
203
+ }
204
+
205
+ const buildConfig = {};
206
+ if (build.envOutputPath) {
207
+ buildConfig.envOutputPath = build.envOutputPath;
208
+ }
209
+ if (build.dockerfile && build.dockerfile.trim()) {
210
+ buildConfig.dockerfile = build.dockerfile;
211
+ }
212
+
213
+ return Object.keys(buildConfig).length > 0 ? buildConfig : null;
214
+ }
215
+
216
+ /**
217
+ * Validates and transforms deployment fields
218
+ * @function validateDeploymentFields
219
+ * @param {Object} deployment - Deployment configuration
220
+ * @returns {Object|null} Validated deployment config or null
221
+ */
222
+ function validateDeploymentFields(deployment) {
223
+ if (!deployment) {
224
+ return null;
225
+ }
226
+
227
+ const deploymentConfig = {};
228
+ if (deployment.controllerUrl && deployment.controllerUrl.trim() && deployment.controllerUrl.startsWith('https://')) {
229
+ deploymentConfig.controllerUrl = deployment.controllerUrl;
230
+ }
231
+
232
+ return Object.keys(deploymentConfig).length > 0 ? deploymentConfig : null;
233
+ }
234
+
235
+ /**
236
+ * Adds optional fields to deployment manifest
237
+ * @function buildOptionalFields
238
+ * @param {Object} deployment - Deployment manifest
239
+ * @param {Object} variables - Variables configuration
240
+ * @param {Object|null} rbac - RBAC configuration
241
+ * @returns {Object} Deployment manifest with optional fields
242
+ */
243
+ function buildOptionalFields(deployment, variables, rbac) {
244
+ if (variables.healthCheck) {
245
+ deployment.healthCheck = buildHealthCheck(variables);
246
+ }
247
+
248
+ deployment.authentication = buildAuthenticationConfig(variables, rbac);
249
+
250
+ // Add roles and permissions (from variables.yaml or rbac.yaml)
251
+ // Priority: variables.yaml > rbac.yaml
252
+ if (variables.roles) {
253
+ deployment.roles = variables.roles;
254
+ } else if (rbac && rbac.roles) {
255
+ deployment.roles = rbac.roles;
256
+ }
257
+
258
+ if (variables.permissions) {
259
+ deployment.permissions = variables.permissions;
260
+ } else if (rbac && rbac.permissions) {
261
+ deployment.permissions = rbac.permissions;
262
+ }
263
+
264
+ const repository = validateRepositoryConfig(variables.repository);
265
+ if (repository) {
266
+ deployment.repository = repository;
267
+ }
268
+
269
+ const build = validateBuildFields(variables.build);
270
+ if (build) {
271
+ deployment.build = build;
272
+ }
273
+
274
+ const deploymentConfig = validateDeploymentFields(variables.deployment);
275
+ if (deploymentConfig) {
276
+ deployment.deployment = deploymentConfig;
277
+ }
278
+
279
+ if (variables.startupCommand) {
280
+ deployment.startupCommand = variables.startupCommand;
281
+ }
282
+ if (variables.runtimeVersion) {
283
+ deployment.runtimeVersion = variables.runtimeVersion;
284
+ }
285
+ if (variables.scaling) {
286
+ deployment.scaling = variables.scaling;
287
+ }
288
+ if (variables.frontDoorRouting) {
289
+ deployment.frontDoorRouting = variables.frontDoorRouting;
290
+ }
291
+
292
+ return deployment;
293
+ }
294
+
295
+ /**
296
+ * Builds deployment manifest structure
297
+ * @param {string} appName - Application name
298
+ * @param {Object} variables - Variables configuration
299
+ * @param {string} deploymentKey - Deployment key
300
+ * @param {Array} configuration - Environment configuration
301
+ * @param {Object|null} rbac - RBAC configuration
302
+ * @returns {Object} Deployment manifest
303
+ */
304
+ function buildManifestStructure(appName, variables, deploymentKey, configuration, rbac) {
305
+ const registryMode = variables.image?.registryMode || 'external';
306
+ const filteredConfiguration = filterConfigurationByRegistryMode(configuration, registryMode);
307
+ const deployment = buildBaseDeployment(appName, variables, filteredConfiguration);
308
+ return buildOptionalFields(deployment, variables, rbac);
309
+ }
310
+
311
+ module.exports = {
312
+ buildImageReference,
313
+ buildHealthCheck,
314
+ buildRequirements,
315
+ buildAuthentication,
316
+ buildBaseDeployment,
317
+ buildAuthenticationConfig,
318
+ buildOptionalFields,
319
+ buildManifestStructure,
320
+ filterConfigurationByRegistryMode,
321
+ sanitizeAuthType
322
+ };
323
+