@aifabrix/builder 2.39.2 → 2.40.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.
- package/.cursor/rules/project-rules.mdc +6 -6
- package/README.md +2 -2
- package/babel.config.js +6 -0
- package/integration/hubspot/README.md +53 -141
- package/integration/hubspot/application.yaml +37 -0
- package/integration/hubspot/env.template +2 -11
- package/integration/hubspot/hubspot-deploy.json +1 -0
- package/integration/hubspot/test.js +5 -5
- package/lib/api/credentials.api.js +5 -5
- package/lib/api/deployments.api.js +2 -2
- package/lib/api/pipeline.api.js +17 -17
- package/lib/api/wizard.api.js +2 -2
- package/lib/app/config.js +11 -6
- package/lib/app/deploy-config.js +13 -16
- package/lib/app/deploy.js +29 -22
- package/lib/app/display.js +1 -1
- package/lib/app/dockerfile.js +11 -12
- package/lib/app/helpers.js +51 -13
- package/lib/app/index.js +14 -2
- package/lib/app/prompts.js +37 -45
- package/lib/app/push.js +8 -11
- package/lib/app/readme.js +16 -12
- package/lib/app/register.js +3 -3
- package/lib/app/run-helpers.js +31 -22
- package/lib/app/run.js +44 -5
- package/lib/app/show-display.js +104 -44
- package/lib/app/show.js +123 -43
- package/lib/build/index.js +11 -18
- package/lib/cli/setup-app.js +38 -28
- package/lib/cli/setup-auth.js +18 -15
- package/lib/cli/setup-credential-deployment.js +3 -1
- package/lib/cli/setup-external-system.js +35 -16
- package/lib/cli/setup-infra.js +45 -23
- package/lib/cli/setup-utility.js +79 -31
- package/lib/commands/app-logs.js +165 -10
- package/lib/commands/app.js +30 -26
- package/lib/commands/convert.js +202 -0
- package/lib/commands/credential-list.js +78 -17
- package/lib/commands/datasource.js +24 -24
- package/lib/commands/deployment-list.js +13 -6
- package/lib/commands/up-common.js +80 -42
- package/lib/commands/up-dataplane.js +15 -14
- package/lib/commands/up-miso.js +15 -14
- package/lib/commands/upload.js +163 -0
- package/lib/commands/wizard-core.js +5 -4
- package/lib/core/diff.js +84 -9
- package/lib/core/key-generator.js +9 -12
- package/lib/core/secrets-docker-env.js +2 -2
- package/lib/core/secrets.js +3 -2
- package/lib/core/templates.js +2 -2
- package/lib/datasource/deploy.js +2 -1
- package/lib/deployment/deployer.js +76 -48
- package/lib/external-system/delete.js +0 -1
- package/lib/external-system/deploy-helpers.js +5 -6
- package/lib/external-system/deploy.js +7 -2
- package/lib/external-system/download-helpers.js +4 -4
- package/lib/external-system/download.js +11 -10
- package/lib/external-system/generator.js +19 -17
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +1 -1
- package/lib/generator/external-controller-manifest.js +26 -29
- package/lib/generator/external-schema-utils.js +6 -18
- package/lib/generator/external.js +32 -27
- package/lib/generator/github.js +1 -1
- package/lib/generator/helpers.js +12 -19
- package/lib/generator/index.js +15 -15
- package/lib/generator/parse-image.js +35 -0
- package/lib/generator/split-readme.js +105 -0
- package/lib/generator/split-variables.js +149 -0
- package/lib/generator/split.js +86 -246
- package/lib/generator/wizard.js +46 -69
- package/lib/schema/application-schema.json +4 -4
- package/lib/schema/deployment-rules.yaml +0 -4
- package/lib/schema/external-datasource.schema.json +5 -0
- package/lib/schema/external-system.schema.json +10 -0
- package/lib/utils/app-config-resolver.js +52 -0
- package/lib/utils/app-register-api.js +1 -1
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +16 -23
- package/lib/utils/app-register-display.js +22 -3
- package/lib/utils/app-register-validator.js +2 -2
- package/lib/utils/cli-utils.js +47 -3
- package/lib/utils/config-format.js +154 -0
- package/lib/utils/config-paths.js +19 -52
- package/lib/utils/config-tokens.js +1 -0
- package/lib/utils/docker-build.js +71 -94
- package/lib/utils/dockerfile-utils.js +1 -1
- package/lib/utils/env-copy.js +4 -4
- package/lib/utils/env-ports.js +2 -2
- package/lib/utils/error-formatter.js +1 -1
- package/lib/utils/error-formatters/validation-errors.js +1 -1
- package/lib/utils/external-readme.js +12 -5
- package/lib/utils/external-system-test-helpers.js +2 -0
- package/lib/utils/health-check.js +55 -66
- package/lib/utils/image-version.js +12 -21
- package/lib/utils/paths.js +39 -66
- package/lib/utils/port-resolver.js +8 -8
- package/lib/utils/schema-loader.js +22 -0
- package/lib/utils/schema-resolver.js +23 -33
- package/lib/utils/secrets-helpers.js +7 -7
- package/lib/utils/secrets-utils.js +10 -12
- package/lib/utils/template-helpers.js +13 -13
- package/lib/utils/token-manager.js +20 -2
- package/lib/utils/variable-transformer.js +2 -2
- package/lib/validation/validate-display.js +3 -4
- package/lib/validation/validate.js +33 -27
- package/lib/validation/validator.js +50 -30
- package/package.json +2 -1
- package/templates/README.md +1 -1
- package/templates/applications/README.md.hbs +3 -3
- package/templates/applications/miso-controller/env.template +3 -1
- package/templates/external-system/README.md.hbs +4 -4
- package/integration/hubspot/variables.yaml +0 -17
- /package/templates/applications/dataplane/{variables.yaml → application.yaml} +0 -0
- /package/templates/applications/keycloak/{variables.yaml → application.yaml} +0 -0
- /package/templates/applications/miso-controller/{variables.yaml → application.yaml} +0 -0
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
|
-
const
|
|
13
|
+
const yaml = require('js-yaml');
|
|
14
14
|
const validator = require('./validator');
|
|
15
15
|
const { resolveExternalFiles } = require('../utils/schema-resolver');
|
|
16
16
|
const { loadExternalSystemSchema, loadExternalDataSourceSchema, detectSchemaType } = require('../utils/schema-loader');
|
|
17
17
|
const { formatValidationErrors } = require('../utils/error-formatter');
|
|
18
18
|
const { detectAppType } = require('../utils/paths');
|
|
19
|
+
const { logOfflinePathWhenType } = require('../utils/cli-utils');
|
|
20
|
+
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
19
21
|
const { displayValidationResults } = require('./validate-display');
|
|
20
22
|
const { generateControllerManifest } = require('../generator/external-controller-manifest');
|
|
21
23
|
const { validateControllerManifest } = require('./external-manifest-validator');
|
|
@@ -43,8 +45,8 @@ async function validateFilePath(filePath) {
|
|
|
43
45
|
* @param {string} appName - Application name
|
|
44
46
|
* @returns {Promise<Array>} Array of validation results
|
|
45
47
|
*/
|
|
46
|
-
async function validateExternalFilesForApp(appName) {
|
|
47
|
-
const files = await resolveExternalFiles(appName);
|
|
48
|
+
async function validateExternalFilesForApp(appName, options = {}) {
|
|
49
|
+
const files = await resolveExternalFiles(appName, options);
|
|
48
50
|
const validations = [];
|
|
49
51
|
|
|
50
52
|
for (const file of files) {
|
|
@@ -105,21 +107,23 @@ function aggregateValidationResults(appValidation, externalValidations, rbacVali
|
|
|
105
107
|
* @returns {Promise<Object>} Validation result
|
|
106
108
|
*/
|
|
107
109
|
/**
|
|
108
|
-
* Parses
|
|
110
|
+
* Parses external system/datasource file content (JSON or YAML).
|
|
109
111
|
* @function parseJsonFileContent
|
|
110
|
-
* @param {string} filePath - File path
|
|
112
|
+
* @param {string} filePath - File path (.json, .yaml, or .yml)
|
|
111
113
|
* @returns {Object} Parse result with parsed object or error
|
|
112
114
|
*/
|
|
113
115
|
function parseJsonFileContent(filePath) {
|
|
114
116
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
117
|
+
const isYaml = /\.(yaml|yml)$/i.test(filePath);
|
|
115
118
|
try {
|
|
116
|
-
|
|
119
|
+
const parsed = isYaml ? yaml.load(content) : JSON.parse(content);
|
|
120
|
+
return { parsed: parsed || {}, error: null };
|
|
117
121
|
} catch (error) {
|
|
118
122
|
return {
|
|
119
123
|
parsed: null,
|
|
120
124
|
error: {
|
|
121
125
|
valid: false,
|
|
122
|
-
errors: [`Invalid JSON syntax: ${error.message}`],
|
|
126
|
+
errors: [isYaml ? `Invalid YAML syntax: ${error.message}` : `Invalid JSON syntax: ${error.message}`],
|
|
123
127
|
warnings: []
|
|
124
128
|
}
|
|
125
129
|
};
|
|
@@ -206,7 +210,7 @@ async function validateExternalFile(filePath, type) {
|
|
|
206
210
|
* @function validateAppOrFile
|
|
207
211
|
* @param {string} appOrFile - Application name or file path
|
|
208
212
|
* @param {Object} [options] - Validation options
|
|
209
|
-
*
|
|
213
|
+
*
|
|
210
214
|
* @returns {Promise<Object>} Validation result with aggregated results
|
|
211
215
|
* @throws {Error} If validation fails
|
|
212
216
|
*
|
|
@@ -239,9 +243,9 @@ async function validateRbacForExternalSystem(isExternal, appName) {
|
|
|
239
243
|
}
|
|
240
244
|
|
|
241
245
|
/**
|
|
242
|
-
* Loads and checks
|
|
246
|
+
* Loads and checks application config for externalIntegration
|
|
243
247
|
* @function loadVariablesAndCheckExternalIntegration
|
|
244
|
-
* @param {string} variablesPath - Path to
|
|
248
|
+
* @param {string} variablesPath - Path to application config
|
|
245
249
|
* @param {Object} appValidation - Application validation result
|
|
246
250
|
* @returns {Object|null} Variables object or null if no externalIntegration
|
|
247
251
|
*/
|
|
@@ -265,7 +269,7 @@ function loadVariablesAndCheckExternalIntegration(variablesPath, appValidation)
|
|
|
265
269
|
valid: appValidation.valid,
|
|
266
270
|
application: appValidation,
|
|
267
271
|
externalFiles: [],
|
|
268
|
-
warnings: [`Could not parse
|
|
272
|
+
warnings: [`Could not parse application config to check externalIntegration: ${error.message}`]
|
|
269
273
|
};
|
|
270
274
|
}
|
|
271
275
|
|
|
@@ -287,9 +291,9 @@ function loadVariablesAndCheckExternalIntegration(variablesPath, appValidation)
|
|
|
287
291
|
* @param {string} appName - Application name
|
|
288
292
|
* @returns {Promise<Object>} Application validation result
|
|
289
293
|
*/
|
|
290
|
-
async function validateApplicationStep(appName) {
|
|
294
|
+
async function validateApplicationStep(appName, options = {}) {
|
|
291
295
|
try {
|
|
292
|
-
const appValidation = await validator.validateApplication(appName);
|
|
296
|
+
const appValidation = await validator.validateApplication(appName, options);
|
|
293
297
|
return {
|
|
294
298
|
valid: appValidation.valid,
|
|
295
299
|
errors: appValidation.errors || [],
|
|
@@ -311,9 +315,9 @@ async function validateApplicationStep(appName) {
|
|
|
311
315
|
* @param {string} appName - Application name
|
|
312
316
|
* @returns {Promise<Object>} Components validation result
|
|
313
317
|
*/
|
|
314
|
-
async function validateComponentsStep(appName) {
|
|
318
|
+
async function validateComponentsStep(appName, options = {}) {
|
|
315
319
|
try {
|
|
316
|
-
const externalValidations = await validateExternalFilesForApp(appName);
|
|
320
|
+
const externalValidations = await validateExternalFilesForApp(appName, options);
|
|
317
321
|
const componentErrors = [];
|
|
318
322
|
const componentWarnings = [];
|
|
319
323
|
const componentFiles = [];
|
|
@@ -357,9 +361,9 @@ async function validateComponentsStep(appName) {
|
|
|
357
361
|
* @param {string} appName - Application name
|
|
358
362
|
* @returns {Promise<Object>} Manifest validation result
|
|
359
363
|
*/
|
|
360
|
-
async function validateManifestStep(appName) {
|
|
364
|
+
async function validateManifestStep(appName, options = {}) {
|
|
361
365
|
try {
|
|
362
|
-
const manifest = await generateControllerManifest(appName);
|
|
366
|
+
const manifest = await generateControllerManifest(appName, options);
|
|
363
367
|
const manifestValidation = await validateControllerManifest(manifest);
|
|
364
368
|
return {
|
|
365
369
|
valid: manifestValidation.valid,
|
|
@@ -389,7 +393,7 @@ async function validateManifestStep(appName) {
|
|
|
389
393
|
* const result = await validateExternalSystemComplete('my-hubspot');
|
|
390
394
|
* // Returns: { valid: true, errors: [], warnings: [], steps: {...} }
|
|
391
395
|
*/
|
|
392
|
-
async function validateExternalSystemComplete(appName) {
|
|
396
|
+
async function validateExternalSystemComplete(appName, options = {}) {
|
|
393
397
|
if (!appName || typeof appName !== 'string') {
|
|
394
398
|
throw new Error('App name is required and must be a string');
|
|
395
399
|
}
|
|
@@ -400,11 +404,13 @@ async function validateExternalSystemComplete(appName) {
|
|
|
400
404
|
manifest: { valid: false, errors: [], warnings: [] }
|
|
401
405
|
};
|
|
402
406
|
|
|
407
|
+
const externalOptions = { ...options };
|
|
408
|
+
|
|
403
409
|
// Step 1: Validate Application Config
|
|
404
|
-
steps.application = await validateApplicationStep(appName);
|
|
410
|
+
steps.application = await validateApplicationStep(appName, externalOptions);
|
|
405
411
|
|
|
406
412
|
// Step 2: Validate Individual Components
|
|
407
|
-
steps.components = await validateComponentsStep(appName);
|
|
413
|
+
steps.components = await validateComponentsStep(appName, externalOptions);
|
|
408
414
|
|
|
409
415
|
// If components have errors, return early (don't validate manifest)
|
|
410
416
|
if (!steps.components.valid) {
|
|
@@ -417,7 +423,7 @@ async function validateExternalSystemComplete(appName) {
|
|
|
417
423
|
}
|
|
418
424
|
|
|
419
425
|
// Step 3 & 4: Generate and Validate Full Manifest (only if Step 2 passes)
|
|
420
|
-
steps.manifest = await validateManifestStep(appName);
|
|
426
|
+
steps.manifest = await validateManifestStep(appName, externalOptions);
|
|
421
427
|
|
|
422
428
|
// Aggregate Results
|
|
423
429
|
const allErrors = [...steps.application.errors, ...steps.components.errors, ...steps.manifest.errors];
|
|
@@ -442,23 +448,23 @@ async function validateAppOrFile(appOrFile, options = {}) {
|
|
|
442
448
|
}
|
|
443
449
|
|
|
444
450
|
const appName = appOrFile;
|
|
445
|
-
const { appPath, isExternal } = await detectAppType(appName
|
|
451
|
+
const { appPath, isExternal } = await detectAppType(appName);
|
|
452
|
+
logOfflinePathWhenType(appPath);
|
|
446
453
|
|
|
447
|
-
|
|
448
|
-
if (isExternal && options.type === 'external') {
|
|
454
|
+
if (isExternal) {
|
|
449
455
|
return await validateExternalSystemComplete(appName);
|
|
450
456
|
}
|
|
451
457
|
|
|
452
|
-
const appValidation = await validator.validateApplication(appName);
|
|
458
|
+
const appValidation = await validator.validateApplication(appName, options);
|
|
453
459
|
const rbacValidation = await validateRbacForExternalSystem(isExternal, appName);
|
|
454
460
|
|
|
455
|
-
const variablesPath =
|
|
461
|
+
const variablesPath = resolveApplicationConfigPath(appPath);
|
|
456
462
|
const earlyReturn = loadVariablesAndCheckExternalIntegration(variablesPath, appValidation);
|
|
457
463
|
if (earlyReturn) {
|
|
458
464
|
return earlyReturn;
|
|
459
465
|
}
|
|
460
466
|
|
|
461
|
-
const externalValidations = await validateExternalFilesForApp(appName);
|
|
467
|
+
const externalValidations = await validateExternalFilesForApp(appName, options);
|
|
462
468
|
return aggregateValidationResults(appValidation, externalValidations, rbacValidation);
|
|
463
469
|
}
|
|
464
470
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AI Fabrix Builder Schema Validation
|
|
3
3
|
*
|
|
4
4
|
* This module provides schema validation with developer-friendly error messages.
|
|
5
|
-
* Validates
|
|
5
|
+
* Validates application.yaml, rbac.yaml, and env.template files.
|
|
6
6
|
*
|
|
7
7
|
* @fileoverview Schema validation with friendly error messages for AI Fabrix Builder
|
|
8
8
|
* @author AI Fabrix Team
|
|
@@ -19,10 +19,11 @@ const externalDataSourceSchema = require('../schema/external-datasource.schema.j
|
|
|
19
19
|
const { transformVariablesForValidation } = require('../utils/variable-transformer');
|
|
20
20
|
const { checkEnvironment } = require('../utils/environment-checker');
|
|
21
21
|
const { formatValidationErrors } = require('../utils/error-formatter');
|
|
22
|
-
const { detectAppType } = require('../utils/paths');
|
|
22
|
+
const { detectAppType, resolveApplicationConfigPath } = require('../utils/paths');
|
|
23
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
* Validates
|
|
26
|
+
* Validates application config file against application schema
|
|
26
27
|
* Provides detailed error messages for configuration issues
|
|
27
28
|
*
|
|
28
29
|
* @async
|
|
@@ -36,27 +37,17 @@ const { detectAppType } = require('../utils/paths');
|
|
|
36
37
|
* // Returns: { valid: true, errors: [], warnings: [] }
|
|
37
38
|
*/
|
|
38
39
|
/**
|
|
39
|
-
* Loads and parses
|
|
40
|
+
* Loads and parses application config (application.yaml or application.json) via resolver + converter.
|
|
40
41
|
* @async
|
|
41
42
|
* @function loadVariablesYaml
|
|
42
43
|
* @param {string} appName - Application name
|
|
43
44
|
* @returns {Promise<Object>} Variables object
|
|
44
45
|
* @throws {Error} If file not found or invalid
|
|
45
46
|
*/
|
|
46
|
-
async function loadVariablesYaml(appName) {
|
|
47
|
-
const { appPath } = await detectAppType(appName);
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
if (!fs.existsSync(variablesPath)) {
|
|
51
|
-
throw new Error(`variables.yaml not found: ${variablesPath}`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const content = fs.readFileSync(variablesPath, 'utf8');
|
|
55
|
-
try {
|
|
56
|
-
return yaml.load(content);
|
|
57
|
-
} catch (error) {
|
|
58
|
-
throw new Error(`Invalid YAML syntax in variables.yaml: ${error.message}`);
|
|
59
|
-
}
|
|
47
|
+
async function loadVariablesYaml(appName, options = {}) {
|
|
48
|
+
const { appPath } = await detectAppType(appName, options);
|
|
49
|
+
const configPath = resolveApplicationConfigPath(appPath);
|
|
50
|
+
return loadConfigFile(configPath);
|
|
60
51
|
}
|
|
61
52
|
|
|
62
53
|
/**
|
|
@@ -119,12 +110,12 @@ function validateFrontDoorRouting(variables, errors) {
|
|
|
119
110
|
}
|
|
120
111
|
}
|
|
121
112
|
|
|
122
|
-
async function validateVariables(appName) {
|
|
113
|
+
async function validateVariables(appName, options = {}) {
|
|
123
114
|
if (!appName || typeof appName !== 'string') {
|
|
124
115
|
throw new Error('App name is required and must be a string');
|
|
125
116
|
}
|
|
126
117
|
|
|
127
|
-
const variables = await loadVariablesYaml(appName);
|
|
118
|
+
const variables = await loadVariablesYaml(appName, options);
|
|
128
119
|
const transformed = transformVariablesForValidation(variables, appName);
|
|
129
120
|
const validate = setupAjvValidator();
|
|
130
121
|
const valid = validate(transformed);
|
|
@@ -203,16 +194,18 @@ function validatePermissions(permissions) {
|
|
|
203
194
|
return errors;
|
|
204
195
|
}
|
|
205
196
|
|
|
206
|
-
async function validateRbac(appName) {
|
|
197
|
+
async function validateRbac(appName, options = {}) {
|
|
207
198
|
if (!appName || typeof appName !== 'string') {
|
|
208
199
|
throw new Error('App name is required and must be a string');
|
|
209
200
|
}
|
|
210
201
|
|
|
211
202
|
// Support both builder/ and integration/ directories using detectAppType
|
|
212
|
-
const { appPath } = await detectAppType(appName);
|
|
213
|
-
const
|
|
203
|
+
const { appPath } = await detectAppType(appName, options);
|
|
204
|
+
const rbacYaml = path.join(appPath, 'rbac.yaml');
|
|
205
|
+
const rbacYml = path.join(appPath, 'rbac.yml');
|
|
206
|
+
const rbacPath = fs.existsSync(rbacYaml) ? rbacYaml : (fs.existsSync(rbacYml) ? rbacYml : null);
|
|
214
207
|
|
|
215
|
-
if (!
|
|
208
|
+
if (!rbacPath) {
|
|
216
209
|
return { valid: true, errors: [], warnings: ['rbac.yaml not found - authentication disabled'] };
|
|
217
210
|
}
|
|
218
211
|
|
|
@@ -251,13 +244,13 @@ async function validateRbac(appName) {
|
|
|
251
244
|
* const result = await validateEnvTemplate('myapp');
|
|
252
245
|
* // Returns: { valid: true, errors: [], warnings: [] }
|
|
253
246
|
*/
|
|
254
|
-
async function validateEnvTemplate(appName) {
|
|
247
|
+
async function validateEnvTemplate(appName, options = {}) {
|
|
255
248
|
if (!appName || typeof appName !== 'string') {
|
|
256
249
|
throw new Error('App name is required and must be a string');
|
|
257
250
|
}
|
|
258
251
|
|
|
259
252
|
// Support both builder/ and integration/ directories using detectAppType
|
|
260
|
-
const { appPath } = await detectAppType(appName);
|
|
253
|
+
const { appPath } = await detectAppType(appName, options);
|
|
261
254
|
const templatePath = path.join(appPath, 'env.template');
|
|
262
255
|
|
|
263
256
|
if (!fs.existsSync(templatePath)) {
|
|
@@ -305,6 +298,32 @@ async function validateEnvTemplate(appName) {
|
|
|
305
298
|
};
|
|
306
299
|
}
|
|
307
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Validates a single object against the application schema (no app-name resolution).
|
|
303
|
+
* Supports both flat root (key, displayName, ...) and nested shape (app: {...}).
|
|
304
|
+
* Used by diff and other callers that have already parsed the config.
|
|
305
|
+
*
|
|
306
|
+
* @function validateObjectAgainstApplicationSchema
|
|
307
|
+
* @param {Object} obj - Parsed config object (root or { app, deployment })
|
|
308
|
+
* @returns {{ valid: boolean, errors: string[] }} Validation result
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* const result = validateObjectAgainstApplicationSchema(parsed);
|
|
312
|
+
* if (!result.valid) throw new Error(result.errors.join('; '));
|
|
313
|
+
*/
|
|
314
|
+
function validateObjectAgainstApplicationSchema(obj) {
|
|
315
|
+
if (!obj || typeof obj !== 'object') {
|
|
316
|
+
return { valid: false, errors: ['Config must be an object'] };
|
|
317
|
+
}
|
|
318
|
+
const toValidate = obj.app && typeof obj.app === 'object' && !obj.key ? obj.app : obj;
|
|
319
|
+
const validate = setupAjvValidator();
|
|
320
|
+
const valid = validate(toValidate);
|
|
321
|
+
return {
|
|
322
|
+
valid: !!valid,
|
|
323
|
+
errors: valid ? [] : formatValidationErrors(validate.errors)
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
308
327
|
/**
|
|
309
328
|
* Validates deployment JSON against application schema
|
|
310
329
|
* Ensures generated <app-name>-deploy.json matches the schema structure
|
|
@@ -360,14 +379,14 @@ function validateDeploymentJson(deployment) {
|
|
|
360
379
|
* const result = await validateApplication('myapp');
|
|
361
380
|
* // Returns: { valid: true, variables: {...}, rbac: {...}, env: {...} }
|
|
362
381
|
*/
|
|
363
|
-
async function validateApplication(appName) {
|
|
382
|
+
async function validateApplication(appName, options = {}) {
|
|
364
383
|
if (!appName || typeof appName !== 'string') {
|
|
365
384
|
throw new Error('App name is required and must be a string');
|
|
366
385
|
}
|
|
367
386
|
|
|
368
|
-
const variables = await validateVariables(appName);
|
|
369
|
-
const rbac = await validateRbac(appName);
|
|
370
|
-
const env = await validateEnvTemplate(appName);
|
|
387
|
+
const variables = await validateVariables(appName, options);
|
|
388
|
+
const rbac = await validateRbac(appName, options);
|
|
389
|
+
const env = await validateEnvTemplate(appName, options);
|
|
371
390
|
|
|
372
391
|
const valid = variables.valid && rbac.valid && env.valid;
|
|
373
392
|
const errors = [...(variables.errors || []), ...(rbac.errors || []), ...(env.errors || [])];
|
|
@@ -392,6 +411,7 @@ module.exports = {
|
|
|
392
411
|
validateRbac,
|
|
393
412
|
validateEnvTemplate,
|
|
394
413
|
validateDeploymentJson,
|
|
414
|
+
validateObjectAgainstApplicationSchema,
|
|
395
415
|
checkEnvironment,
|
|
396
416
|
formatValidationErrors,
|
|
397
417
|
validateApplication
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aifabrix/builder",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.40.0",
|
|
4
4
|
"description": "AI Fabrix Local Fabric & Deployment SDK",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"ora": "^5.4.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
+
"@babel/preset-env": "^7.29.0",
|
|
81
82
|
"@bcoe/v8-coverage": "^1.0.2",
|
|
82
83
|
"@types/node": "^20.10.0",
|
|
83
84
|
"cross-env": "^10.1.0",
|
package/templates/README.md
CHANGED
|
@@ -106,7 +106,7 @@ Create your own step templates in `templates/github/steps/{your-step}.hbs` and r
|
|
|
106
106
|
|
|
107
107
|
### Language and Infrastructure Templates
|
|
108
108
|
|
|
109
|
-
These templates are processed automatically by the AI Fabrix Builder SDK based on the application schema defined in `
|
|
109
|
+
These templates are processed automatically by the AI Fabrix Builder SDK based on the application schema defined in `application.yaml`. The generated files will be valid Docker files after template processing.
|
|
110
110
|
|
|
111
111
|
## VS Code Configuration
|
|
112
112
|
|
|
@@ -61,7 +61,7 @@ aifabrix build {{appName}} --tag v1.0.0
|
|
|
61
61
|
aifabrix push {{appName}} --registry {{registry}} --tag "v1.0.0,latest"
|
|
62
62
|
|
|
63
63
|
# Deploy (controller and environment from config; set via aifabrix login or aifabrix auth config)
|
|
64
|
-
aifabrix deploy {{appName}} --
|
|
64
|
+
aifabrix deploy {{appName}} --local
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
---
|
|
@@ -132,7 +132,7 @@ aifabrix push {{appName}} --registry {{registry}} --tag "v1.0.0,latest,stable"
|
|
|
132
132
|
### Deploy Options
|
|
133
133
|
|
|
134
134
|
```bash
|
|
135
|
-
aifabrix deploy {{appName}} --
|
|
135
|
+
aifabrix deploy {{appName}} --local # Uses controller and environment from config
|
|
136
136
|
aifabrix deploy {{appName}} --no-poll # Deploy without polling for status
|
|
137
137
|
```
|
|
138
138
|
|
|
@@ -166,7 +166,7 @@ Controller URL and environment (for `deploy`, `app register`, etc.) are set via
|
|
|
166
166
|
|
|
167
167
|
- **"Docker not running"** → Start Docker Desktop
|
|
168
168
|
- **"Not logged in"** → Run `aifabrix login` first
|
|
169
|
-
- **"Port already in use"** → Use `aifabrix run {{appName}} --port <port>` or set `build.localPort` in `
|
|
169
|
+
- **"Port already in use"** → Use `aifabrix run {{appName}} --port <port>` or set `build.localPort` in `application.yaml` (default: {{localPort}})
|
|
170
170
|
- **"Authentication failed"** → Run `aifabrix login` again
|
|
171
171
|
- **"Build fails"** → Check Docker is running and `aifabrix-secrets` in `config.yaml` is configured correctly
|
|
172
172
|
- **"Can't connect"** → Verify infrastructure is running{{#if hasDatabase}} and PostgreSQL is accessible{{/if}}
|
|
@@ -105,7 +105,9 @@ REDIS_PERMISSIONS_TTL=900
|
|
|
105
105
|
# (KeycloakConfiguration + Application url/internalUrl). Sync env->DB at startup via
|
|
106
106
|
# sync-application-urls-from-env.service.
|
|
107
107
|
#
|
|
108
|
-
#
|
|
108
|
+
# Azure Entra SSO during onboarding: true = skip (default), false = onboard Azure Entra SSO client in Keycloak
|
|
109
|
+
# (onboarding Azure SSO requires Entra admin consent and Azure app credentials).
|
|
110
|
+
KEYCLOAK_SKIP_AZURE_ENTRA_SSO=false
|
|
109
111
|
|
|
110
112
|
KEYCLOAK_REALM=aifabrix
|
|
111
113
|
KEYCLOAK_SERVER_URL=kv://keycloak-server-urlKeyVault
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
## Files
|
|
12
12
|
|
|
13
|
-
- `
|
|
14
|
-
- `{{systemKey}}-system.
|
|
13
|
+
- `application.yaml` – Application configuration with `app` and `externalIntegration` blocks
|
|
14
|
+
- `{{systemKey}}-system.yaml` – External system definition (authentication, OpenAPI/MCP, RBAC)
|
|
15
15
|
{{#each datasources}}
|
|
16
16
|
- `{{fileName}}` – Datasource: {{displayName}}
|
|
17
17
|
{{/each}}
|
|
@@ -38,8 +38,8 @@ aifabrix wizard --app {{appName}}
|
|
|
38
38
|
|
|
39
39
|
Edit files in `integration/{{appName}}/`:
|
|
40
40
|
|
|
41
|
-
- **Authentication**: `{{systemKey}}-system.
|
|
42
|
-
- **Field mappings**: `{{systemKey}}-datasource-*.
|
|
41
|
+
- **Authentication**: `{{systemKey}}-system.yaml` (auth type, credentials placeholders)
|
|
42
|
+
- **Field mappings**: `{{systemKey}}-datasource-*.yaml` (dimensions, attributes, operations)
|
|
43
43
|
|
|
44
44
|
### 3. Validate Configuration
|
|
45
45
|
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
app:
|
|
2
|
-
key: hubspot
|
|
3
|
-
displayName: "HubSpot CRM Integration"
|
|
4
|
-
description: "HubSpot CRM external system integration with companies, contacts, and deals"
|
|
5
|
-
type: external
|
|
6
|
-
|
|
7
|
-
externalIntegration:
|
|
8
|
-
schemaBasePath: ./
|
|
9
|
-
systems:
|
|
10
|
-
- hubspot-system.json
|
|
11
|
-
dataSources:
|
|
12
|
-
- hubspot-datasource-company.json
|
|
13
|
-
- hubspot-datasource-contact.json
|
|
14
|
-
- hubspot-datasource-deal.json
|
|
15
|
-
autopublish: true
|
|
16
|
-
version: 1.0.0
|
|
17
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|