@aifabrix/builder 2.31.1 → 2.32.1
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/README.md +9 -9
- package/integration/hubspot/README.md +2 -2
- package/integration/hubspot/hubspot-deploy-company.json +17 -14
- package/integration/hubspot/hubspot-deploy-contact.json +19 -16
- package/integration/hubspot/hubspot-deploy-deal.json +21 -18
- package/lib/api/types/datasources.types.js +31 -5
- package/lib/api/types/wizard.types.js +142 -0
- package/lib/api/wizard.api.js +177 -0
- package/lib/{app-config.js → app/config.js} +4 -4
- package/lib/{app-deploy.js → app/deploy.js} +8 -8
- package/lib/app/display.js +90 -0
- package/lib/{app-dockerfile.js → app/dockerfile.js} +4 -4
- package/lib/{app-down.js → app/down.js} +4 -4
- package/lib/app/helpers.js +218 -0
- package/lib/app/index.js +298 -0
- package/lib/{app-list.js → app/list.js} +6 -6
- package/lib/{app-push.js → app/push.js} +4 -4
- package/lib/{app-readme.js → app/readme.js} +34 -13
- package/lib/{app-register.js → app/register.js} +9 -9
- package/lib/{app-rotate-secret.js → app/rotate-secret.js} +10 -10
- package/lib/{app-run-helpers.js → app/run-helpers.js} +10 -10
- package/lib/{app-run.js → app/run.js} +6 -6
- package/lib/{build.js → build/index.js} +59 -32
- package/lib/build/package.json +7 -0
- package/lib/cli.js +245 -179
- package/lib/commands/app.js +3 -3
- package/lib/commands/datasource.js +4 -4
- package/lib/commands/login-credentials.js +209 -0
- package/lib/commands/login-device.js +254 -0
- package/lib/commands/login.js +67 -378
- package/lib/commands/logout.js +1 -1
- package/lib/commands/secrets-set.js +1 -1
- package/lib/commands/secure.js +2 -2
- package/lib/commands/wizard.js +498 -0
- package/lib/{audit-logger.js → core/audit-logger.js} +1 -1
- package/lib/{config.js → core/config.js} +28 -26
- package/lib/{diff.js → core/diff.js} +157 -72
- package/lib/{secrets.js → core/secrets.js} +86 -49
- package/lib/{templates.js → core/templates-env.js} +14 -222
- package/lib/core/templates.js +279 -0
- package/lib/{datasource-deploy.js → datasource/deploy.js} +6 -6
- package/lib/{datasource-diff.js → datasource/diff.js} +2 -2
- package/lib/datasource/list.js +223 -0
- package/lib/{datasource-validate.js → datasource/validate.js} +2 -2
- package/lib/{deployer.js → deployment/deployer.js} +48 -18
- package/lib/{environment-deploy.js → deployment/environment.js} +163 -84
- package/lib/{push.js → deployment/push.js} +1 -1
- package/lib/external-system/deploy-helpers.js +145 -0
- package/lib/{external-system-deploy.js → external-system/deploy.js} +156 -111
- package/lib/external-system/download-helpers.js +114 -0
- package/lib/{external-system-download.js → external-system/download.js} +92 -135
- package/lib/{external-system-generator.js → external-system/generator.js} +15 -11
- package/lib/external-system/test-auth.js +40 -0
- package/lib/external-system/test-execution.js +84 -0
- package/lib/external-system/test-helpers.js +109 -0
- package/lib/{external-system-test.js → external-system/test.js} +174 -192
- package/lib/{generator-builders.js → generator/builders.js} +87 -10
- package/lib/{generator-external.js → generator/external.js} +115 -52
- package/lib/{github-generator.js → generator/github.js} +116 -15
- package/lib/{generator-helpers.js → generator/helpers.js} +92 -42
- package/lib/{generator.js → generator/index.js} +49 -22
- package/lib/{generator-split.js → generator/split.js} +108 -55
- package/lib/generator/wizard-prompts.js +357 -0
- package/lib/generator/wizard.js +490 -0
- package/lib/{infra.js → infrastructure/index.js} +49 -22
- package/lib/schema/external-datasource.schema.json +145 -133
- package/lib/schema/external-system.schema.json +42 -0
- package/lib/utils/api.js +9 -5
- package/lib/utils/app-register-api.js +60 -32
- package/lib/utils/app-register-auth.js +172 -47
- package/lib/utils/app-register-config.js +130 -59
- package/lib/utils/app-run-containers.js +29 -8
- package/lib/utils/build-helpers.js +1 -1
- package/lib/utils/cli-utils.js +78 -30
- package/lib/utils/compose-generator.js +145 -65
- package/lib/utils/config-paths.js +2 -0
- package/lib/utils/deployment-errors.js +1 -1
- package/lib/utils/device-code.js +99 -41
- package/lib/utils/env-config-loader.js +1 -1
- package/lib/utils/env-copy.js +21 -18
- package/lib/utils/env-endpoints.js +115 -67
- package/lib/utils/env-map.js +13 -14
- package/lib/utils/env-ports.js +45 -25
- package/lib/utils/env-template.js +84 -42
- package/lib/utils/error-formatter.js +26 -9
- package/lib/utils/error-formatters/error-parser.js +90 -4
- package/lib/utils/error-formatters/http-status-errors.js +54 -17
- package/lib/utils/error-formatters/network-errors.js +103 -26
- package/lib/utils/external-system-display.js +184 -90
- package/lib/utils/external-system-validators.js +164 -42
- package/lib/utils/file-upload.js +109 -0
- package/lib/utils/health-check.js +199 -83
- package/lib/utils/infra-containers.js +1 -1
- package/lib/utils/infra-status.js +66 -15
- package/lib/utils/local-secrets.js +45 -25
- package/lib/utils/paths.js +45 -33
- package/lib/utils/schema-loader.js +42 -25
- package/lib/utils/schema-resolver.js +123 -74
- package/lib/utils/secrets-encryption.js +62 -25
- package/lib/utils/secrets-helpers.js +126 -63
- package/lib/utils/secrets-path.js +1 -1
- package/lib/utils/secrets-url.js +1 -1
- package/lib/utils/token-manager-refresh.js +181 -0
- package/lib/utils/token-manager.js +76 -123
- package/lib/utils/variable-transformer.js +154 -77
- package/lib/utils/yaml-preserve.js +41 -47
- package/lib/{template-validator.js → validation/template.js} +54 -23
- package/lib/{validate.js → validation/validate.js} +205 -125
- package/lib/{validator.js → validation/validator.js} +58 -39
- package/package.json +31 -2
- package/templates/external-system/deploy.ps1.hbs +34 -0
- package/templates/external-system/deploy.sh.hbs +34 -0
- package/templates/external-system/external-datasource.json.hbs +31 -12
- package/lib/app.js +0 -467
- package/lib/datasource-list.js +0 -141
- /package/lib/{app-prompts.js → app/prompts.js} +0 -0
- /package/lib/{env-reader.js → core/env-reader.js} +0 -0
- /package/lib/{key-generator.js → core/key-generator.js} +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External System Deployment Helpers
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for external system deployment validation
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Deployment helper utilities for external system deployment
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs').promises;
|
|
12
|
+
const fsSync = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const yaml = require('js-yaml');
|
|
15
|
+
const { detectAppType, getDeployJsonPath } = require('../utils/paths');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Loads variables.yaml for an application
|
|
19
|
+
* @async
|
|
20
|
+
* @function loadVariablesYaml
|
|
21
|
+
* @param {string} appName - Application name
|
|
22
|
+
* @returns {Promise<Object>} Variables configuration
|
|
23
|
+
* @throws {Error} If file cannot be loaded
|
|
24
|
+
*/
|
|
25
|
+
async function loadVariablesYaml(appName) {
|
|
26
|
+
// Detect app type and get correct path (integration or builder)
|
|
27
|
+
const { appPath } = await detectAppType(appName);
|
|
28
|
+
const variablesPath = path.join(appPath, 'variables.yaml');
|
|
29
|
+
const content = await fs.readFile(variablesPath, 'utf8');
|
|
30
|
+
return yaml.load(content);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validates a single system file
|
|
35
|
+
* @async
|
|
36
|
+
* @function validateSingleSystemFile
|
|
37
|
+
* @param {string} systemFile - System file name
|
|
38
|
+
* @param {string} appName - Application name
|
|
39
|
+
* @param {string} schemasPath - Schemas path
|
|
40
|
+
* @returns {Promise<string>} Validated system file path
|
|
41
|
+
* @throws {Error} If file not found
|
|
42
|
+
*/
|
|
43
|
+
async function validateSingleSystemFile(systemFile, appName, schemasPath) {
|
|
44
|
+
// Try new naming first: <app-name>-deploy.json in same folder
|
|
45
|
+
const newSystemPath = getDeployJsonPath(appName, 'external', true);
|
|
46
|
+
if (fsSync.existsSync(newSystemPath)) {
|
|
47
|
+
return newSystemPath;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Fall back to specified path
|
|
51
|
+
const systemPath = path.join(schemasPath, systemFile);
|
|
52
|
+
try {
|
|
53
|
+
await fs.access(systemPath);
|
|
54
|
+
return systemPath;
|
|
55
|
+
} catch {
|
|
56
|
+
throw new Error(`External system file not found: ${systemPath} (also checked: ${newSystemPath})`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Validates system files
|
|
62
|
+
* @async
|
|
63
|
+
* @function validateSystemFiles
|
|
64
|
+
* @param {string[]} systemFiles - Array of system file names
|
|
65
|
+
* @param {string} appName - Application name
|
|
66
|
+
* @param {string} schemasPath - Schemas path
|
|
67
|
+
* @returns {Promise<string[]>} Array of validated system file paths
|
|
68
|
+
*/
|
|
69
|
+
async function validateSystemFiles(systemFiles, appName, schemasPath) {
|
|
70
|
+
const validatedFiles = [];
|
|
71
|
+
for (const systemFile of systemFiles) {
|
|
72
|
+
const validatedPath = await validateSingleSystemFile(systemFile, appName, schemasPath);
|
|
73
|
+
validatedFiles.push(validatedPath);
|
|
74
|
+
}
|
|
75
|
+
return validatedFiles;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Validates a single datasource file
|
|
80
|
+
* @async
|
|
81
|
+
* @function validateSingleDatasourceFile
|
|
82
|
+
* @param {string} datasourceFile - Datasource file name
|
|
83
|
+
* @param {string} appPath - Application path
|
|
84
|
+
* @param {string} schemasPath - Schemas path
|
|
85
|
+
* @returns {Promise<string>} Validated datasource file path
|
|
86
|
+
* @throws {Error} If file not found
|
|
87
|
+
*/
|
|
88
|
+
async function validateSingleDatasourceFile(datasourceFile, appPath, schemasPath) {
|
|
89
|
+
// Try same folder first (new structure)
|
|
90
|
+
const datasourcePath = path.join(appPath, datasourceFile);
|
|
91
|
+
try {
|
|
92
|
+
await fs.access(datasourcePath);
|
|
93
|
+
return datasourcePath;
|
|
94
|
+
} catch {
|
|
95
|
+
// Fall back to schemaBasePath
|
|
96
|
+
const fallbackPath = path.join(schemasPath, datasourceFile);
|
|
97
|
+
try {
|
|
98
|
+
await fs.access(fallbackPath);
|
|
99
|
+
return fallbackPath;
|
|
100
|
+
} catch {
|
|
101
|
+
throw new Error(`External datasource file not found: ${datasourcePath} or ${fallbackPath}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Validates datasource files
|
|
108
|
+
* @async
|
|
109
|
+
* @function validateDatasourceFiles
|
|
110
|
+
* @param {string[]} datasourceFiles - Array of datasource file names
|
|
111
|
+
* @param {string} appPath - Application path
|
|
112
|
+
* @param {string} schemasPath - Schemas path
|
|
113
|
+
* @returns {Promise<string[]>} Array of validated datasource file paths
|
|
114
|
+
*/
|
|
115
|
+
async function validateDatasourceFiles(datasourceFiles, appPath, schemasPath) {
|
|
116
|
+
const validatedFiles = [];
|
|
117
|
+
for (const datasourceFile of datasourceFiles) {
|
|
118
|
+
const validatedPath = await validateSingleDatasourceFile(datasourceFile, appPath, schemasPath);
|
|
119
|
+
validatedFiles.push(validatedPath);
|
|
120
|
+
}
|
|
121
|
+
return validatedFiles;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Extracts system key from system file path
|
|
126
|
+
* @function extractSystemKey
|
|
127
|
+
* @param {string} systemFilePath - System file path
|
|
128
|
+
* @returns {string} System key
|
|
129
|
+
*/
|
|
130
|
+
function extractSystemKey(systemFilePath) {
|
|
131
|
+
// Normalize path separators first (handles Windows backslashes)
|
|
132
|
+
const normalizedPath = systemFilePath.replace(/\\/g, '/');
|
|
133
|
+
const systemFileName = path.basename(normalizedPath, '.json');
|
|
134
|
+
return systemFileName.replace(/-deploy$/, '');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
loadVariablesYaml,
|
|
139
|
+
validateSingleSystemFile,
|
|
140
|
+
validateSystemFiles,
|
|
141
|
+
validateSingleDatasourceFile,
|
|
142
|
+
validateDatasourceFiles,
|
|
143
|
+
extractSystemKey
|
|
144
|
+
};
|
|
145
|
+
|
|
@@ -10,9 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const fs = require('fs').promises;
|
|
13
|
-
const fsSync = require('fs');
|
|
14
13
|
const path = require('path');
|
|
15
|
-
const yaml = require('js-yaml');
|
|
16
14
|
const chalk = require('chalk');
|
|
17
15
|
const {
|
|
18
16
|
deployExternalSystemViaPipeline,
|
|
@@ -20,13 +18,19 @@ const {
|
|
|
20
18
|
uploadApplicationViaPipeline,
|
|
21
19
|
validateUploadViaPipeline,
|
|
22
20
|
publishUploadViaPipeline
|
|
23
|
-
} = require('
|
|
24
|
-
const { getDeploymentAuth } = require('
|
|
25
|
-
const { getConfig } = require('
|
|
26
|
-
const logger = require('
|
|
27
|
-
const { getDataplaneUrl } = require('
|
|
28
|
-
const { detectAppType
|
|
29
|
-
const { generateExternalSystemApplicationSchema } = require('
|
|
21
|
+
} = require('../api/pipeline.api');
|
|
22
|
+
const { getDeploymentAuth } = require('../utils/token-manager');
|
|
23
|
+
const { getConfig } = require('../core/config');
|
|
24
|
+
const logger = require('../utils/logger');
|
|
25
|
+
const { getDataplaneUrl } = require('../datasource/deploy');
|
|
26
|
+
const { detectAppType } = require('../utils/paths');
|
|
27
|
+
const { generateExternalSystemApplicationSchema } = require('../generator/external');
|
|
28
|
+
const {
|
|
29
|
+
loadVariablesYaml,
|
|
30
|
+
validateSystemFiles,
|
|
31
|
+
validateDatasourceFiles,
|
|
32
|
+
extractSystemKey
|
|
33
|
+
} = require('./deploy-helpers');
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
36
|
* Loads variables.yaml for an application
|
|
@@ -36,14 +40,6 @@ const { generateExternalSystemApplicationSchema } = require('./generator');
|
|
|
36
40
|
* @returns {Promise<Object>} Variables configuration
|
|
37
41
|
* @throws {Error} If file cannot be loaded
|
|
38
42
|
*/
|
|
39
|
-
async function loadVariablesYaml(appName) {
|
|
40
|
-
// Detect app type and get correct path (integration or builder)
|
|
41
|
-
const { appPath } = await detectAppType(appName);
|
|
42
|
-
const variablesPath = path.join(appPath, 'variables.yaml');
|
|
43
|
-
const content = await fs.readFile(variablesPath, 'utf8');
|
|
44
|
-
return yaml.load(content);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
43
|
/**
|
|
48
44
|
* Validates external system files exist
|
|
49
45
|
* @async
|
|
@@ -52,6 +48,7 @@ async function loadVariablesYaml(appName) {
|
|
|
52
48
|
* @returns {Promise<Object>} Validation result with file paths
|
|
53
49
|
* @throws {Error} If validation fails
|
|
54
50
|
*/
|
|
51
|
+
|
|
55
52
|
async function validateExternalSystemFiles(appName) {
|
|
56
53
|
const variables = await loadVariablesYaml(appName);
|
|
57
54
|
|
|
@@ -70,53 +67,18 @@ async function validateExternalSystemFiles(appName) {
|
|
|
70
67
|
: path.join(appPath, schemaBasePath);
|
|
71
68
|
|
|
72
69
|
// Validate system files
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
for (const systemFile of variables.externalIntegration.systems) {
|
|
76
|
-
// Try new naming first: <app-name>-deploy.json in same folder
|
|
77
|
-
const newSystemPath = getDeployJsonPath(appName, 'external', true);
|
|
78
|
-
if (fsSync.existsSync(newSystemPath)) {
|
|
79
|
-
systemFiles.push(newSystemPath);
|
|
80
|
-
} else {
|
|
81
|
-
// Fall back to specified path
|
|
82
|
-
const systemPath = path.join(schemasPath, systemFile);
|
|
83
|
-
try {
|
|
84
|
-
await fs.access(systemPath);
|
|
85
|
-
systemFiles.push(systemPath);
|
|
86
|
-
} catch {
|
|
87
|
-
throw new Error(`External system file not found: ${systemPath} (also checked: ${newSystemPath})`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
} else {
|
|
70
|
+
const systemFilesList = variables.externalIntegration.systems || [];
|
|
71
|
+
if (systemFilesList.length === 0) {
|
|
92
72
|
throw new Error('No external system files specified in externalIntegration.systems');
|
|
93
73
|
}
|
|
74
|
+
const systemFiles = await validateSystemFiles(systemFilesList, appName, schemasPath);
|
|
94
75
|
|
|
95
|
-
// Validate datasource files
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
for (const datasourceFile of variables.externalIntegration.dataSources) {
|
|
99
|
-
// Try same folder first (new structure)
|
|
100
|
-
const datasourcePath = path.join(appPath, datasourceFile);
|
|
101
|
-
try {
|
|
102
|
-
await fs.access(datasourcePath);
|
|
103
|
-
datasourceFiles.push(datasourcePath);
|
|
104
|
-
} catch {
|
|
105
|
-
// Fall back to schemaBasePath
|
|
106
|
-
const fallbackPath = path.join(schemasPath, datasourceFile);
|
|
107
|
-
try {
|
|
108
|
-
await fs.access(fallbackPath);
|
|
109
|
-
datasourceFiles.push(fallbackPath);
|
|
110
|
-
} catch {
|
|
111
|
-
throw new Error(`External datasource file not found: ${datasourcePath} or ${fallbackPath}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
76
|
+
// Validate datasource files
|
|
77
|
+
const datasourceFilesList = variables.externalIntegration.dataSources || [];
|
|
78
|
+
const datasourceFiles = await validateDatasourceFiles(datasourceFilesList, appPath, schemasPath);
|
|
116
79
|
|
|
117
|
-
// Extract systemKey from system file
|
|
118
|
-
const
|
|
119
|
-
const systemKey = systemFileName.replace(/-deploy$/, '');
|
|
80
|
+
// Extract systemKey from system file
|
|
81
|
+
const systemKey = extractSystemKey(systemFiles[0]);
|
|
120
82
|
|
|
121
83
|
return {
|
|
122
84
|
systemFiles,
|
|
@@ -134,57 +96,121 @@ async function validateExternalSystemFiles(appName) {
|
|
|
134
96
|
* @returns {Promise<void>} Resolves when deployment completes
|
|
135
97
|
* @throws {Error} If deployment fails
|
|
136
98
|
*/
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Validates and prepares deployment configuration
|
|
101
|
+
* @async
|
|
102
|
+
* @function prepareDeploymentConfig
|
|
103
|
+
* @param {string} appName - Application name
|
|
104
|
+
* @param {Object} options - Deployment options
|
|
105
|
+
* @returns {Promise<Object>} Deployment configuration
|
|
106
|
+
*/
|
|
107
|
+
async function prepareDeploymentConfig(appName, options) {
|
|
108
|
+
const { systemFiles, datasourceFiles, systemKey } = await validateExternalSystemFiles(appName);
|
|
140
109
|
|
|
141
|
-
|
|
142
|
-
|
|
110
|
+
const config = await getConfig();
|
|
111
|
+
const environment = options.environment || 'dev';
|
|
112
|
+
const controllerUrl = options.controller || config.deployment?.controllerUrl || 'http://localhost:3000';
|
|
113
|
+
const authConfig = await getDeploymentAuth(controllerUrl, environment, appName);
|
|
143
114
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const controllerUrl = options.controller || config.deployment?.controllerUrl || 'http://localhost:3000';
|
|
148
|
-
const authConfig = await getDeploymentAuth(controllerUrl, environment, appName);
|
|
115
|
+
if (!authConfig.token && !authConfig.clientId) {
|
|
116
|
+
throw new Error('Authentication required. Run "aifabrix login" or "aifabrix app register" first.');
|
|
117
|
+
}
|
|
149
118
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
119
|
+
return { systemFiles, datasourceFiles, systemKey, environment, controllerUrl, authConfig };
|
|
120
|
+
}
|
|
153
121
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Gets dataplane URL from controller
|
|
124
|
+
* @async
|
|
125
|
+
* @function getDataplaneUrlForDeployment
|
|
126
|
+
* @param {string} controllerUrl - Controller URL
|
|
127
|
+
* @param {string} appName - Application name
|
|
128
|
+
* @param {string} environment - Environment key
|
|
129
|
+
* @param {Object} authConfig - Authentication configuration
|
|
130
|
+
* @returns {Promise<string>} Dataplane URL
|
|
131
|
+
*/
|
|
132
|
+
async function getDataplaneUrlForDeployment(controllerUrl, appName, environment, authConfig) {
|
|
133
|
+
logger.log(chalk.blue('🌐 Getting dataplane URL from controller...'));
|
|
134
|
+
const dataplaneUrl = await getDataplaneUrl(controllerUrl, appName, environment, authConfig);
|
|
135
|
+
logger.log(chalk.green(`✓ Dataplane URL: ${dataplaneUrl}`));
|
|
136
|
+
return dataplaneUrl;
|
|
137
|
+
}
|
|
158
138
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Deploys external system via pipeline
|
|
141
|
+
* @async
|
|
142
|
+
* @function deploySystem
|
|
143
|
+
* @param {string} dataplaneUrl - Dataplane URL
|
|
144
|
+
* @param {Object} authConfig - Authentication configuration
|
|
145
|
+
* @param {string} systemFilePath - Path to system file
|
|
146
|
+
* @param {string} systemKey - System key
|
|
147
|
+
* @returns {Promise<void>}
|
|
148
|
+
*/
|
|
149
|
+
async function deploySystem(dataplaneUrl, authConfig, systemFilePath, systemKey) {
|
|
150
|
+
logger.log(chalk.blue(`Deploying external system: ${systemKey}...`));
|
|
151
|
+
const systemContent = await fs.readFile(systemFilePath, 'utf8');
|
|
152
|
+
const systemJson = JSON.parse(systemContent);
|
|
163
153
|
|
|
164
|
-
|
|
154
|
+
const systemResponse = await deployExternalSystemViaPipeline(dataplaneUrl, authConfig, systemJson);
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
156
|
+
if (!systemResponse.success) {
|
|
157
|
+
throw new Error(`Failed to deploy external system: ${systemResponse.error || systemResponse.formattedError}`);
|
|
158
|
+
}
|
|
169
159
|
|
|
170
|
-
|
|
160
|
+
logger.log(chalk.green(`✓ External system deployed: ${systemKey}`));
|
|
161
|
+
}
|
|
171
162
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Deploys a single datasource via pipeline
|
|
165
|
+
* @async
|
|
166
|
+
* @function deploySingleDatasource
|
|
167
|
+
* @param {string} dataplaneUrl - Dataplane URL
|
|
168
|
+
* @param {string} systemKey - System key
|
|
169
|
+
* @param {Object} authConfig - Authentication configuration
|
|
170
|
+
* @param {string} datasourceFile - Path to datasource file
|
|
171
|
+
* @returns {Promise<void>}
|
|
172
|
+
*/
|
|
173
|
+
async function deploySingleDatasource(dataplaneUrl, systemKey, authConfig, datasourceFile) {
|
|
174
|
+
const datasourceName = path.basename(datasourceFile, '.json');
|
|
175
|
+
logger.log(chalk.blue(`Deploying datasource: ${datasourceName}...`));
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
const datasourceContent = await fs.readFile(datasourceFile, 'utf8');
|
|
178
|
+
const datasourceJson = JSON.parse(datasourceContent);
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
const datasourceResponse = await deployDatasourceViaPipeline(dataplaneUrl, systemKey, authConfig, datasourceJson);
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
if (!datasourceResponse.success) {
|
|
183
|
+
throw new Error(`Failed to deploy datasource ${datasourceName}: ${datasourceResponse.error || datasourceResponse.formattedError}`);
|
|
184
|
+
}
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
logger.log(chalk.green(`✓ Datasource deployed: ${datasourceName}`));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Deploys all datasources
|
|
191
|
+
* @async
|
|
192
|
+
* @function deployAllDatasources
|
|
193
|
+
* @param {string} dataplaneUrl - Dataplane URL
|
|
194
|
+
* @param {string} systemKey - System key
|
|
195
|
+
* @param {Object} authConfig - Authentication configuration
|
|
196
|
+
* @param {string[]} datasourceFiles - Array of datasource file paths
|
|
197
|
+
* @returns {Promise<void>}
|
|
198
|
+
*/
|
|
199
|
+
async function deployAllDatasources(dataplaneUrl, systemKey, authConfig, datasourceFiles) {
|
|
200
|
+
for (const datasourceFile of datasourceFiles) {
|
|
201
|
+
await deploySingleDatasource(dataplaneUrl, systemKey, authConfig, datasourceFile);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function buildExternalSystem(appName, options = {}) {
|
|
206
|
+
try {
|
|
207
|
+
logger.log(chalk.blue(`\n🔨 Building external system: ${appName}`));
|
|
208
|
+
|
|
209
|
+
const { systemFiles, datasourceFiles, systemKey, environment, controllerUrl, authConfig } = await prepareDeploymentConfig(appName, options);
|
|
210
|
+
const dataplaneUrl = await getDataplaneUrlForDeployment(controllerUrl, appName, environment, authConfig);
|
|
211
|
+
|
|
212
|
+
await deploySystem(dataplaneUrl, authConfig, systemFiles[0], systemKey);
|
|
213
|
+
await deployAllDatasources(dataplaneUrl, systemKey, authConfig, datasourceFiles);
|
|
188
214
|
|
|
189
215
|
logger.log(chalk.green('\n✅ External system built successfully!'));
|
|
190
216
|
logger.log(chalk.blue(`System: ${systemKey}`));
|
|
@@ -268,26 +294,45 @@ async function uploadApplication(dataplaneUrl, authConfig, applicationSchema) {
|
|
|
268
294
|
* @returns {Promise<void>}
|
|
269
295
|
* @throws {Error} If validation fails
|
|
270
296
|
*/
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const validateData = validateResponse.data.data || validateResponse.data;
|
|
280
|
-
|
|
281
|
-
// Display changes
|
|
282
|
-
if (validateData.changes && validateData.changes.length > 0) {
|
|
297
|
+
/**
|
|
298
|
+
* Displays validation changes
|
|
299
|
+
* @function displayValidationChanges
|
|
300
|
+
* @param {Object[]} changes - Array of changes
|
|
301
|
+
*/
|
|
302
|
+
function displayValidationChanges(changes) {
|
|
303
|
+
if (changes && changes.length > 0) {
|
|
283
304
|
logger.log(chalk.blue('\n📋 Changes to be published:'));
|
|
284
|
-
for (const change of
|
|
305
|
+
for (const change of changes) {
|
|
285
306
|
const changeType = change.type || 'unknown';
|
|
286
307
|
const changeEntity = change.entity || change.key || 'unknown';
|
|
287
308
|
const emoji = changeType === 'new' ? '➕' : changeType === 'modified' ? '✏️' : '🗑️';
|
|
288
309
|
logger.log(chalk.gray(` ${emoji} ${changeType}: ${changeEntity}`));
|
|
289
310
|
}
|
|
290
311
|
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Validates upload response
|
|
316
|
+
* @function validateUploadResponse
|
|
317
|
+
* @param {Object} validateResponse - Validation response
|
|
318
|
+
* @returns {Object} Validation data
|
|
319
|
+
* @throws {Error} If validation failed
|
|
320
|
+
*/
|
|
321
|
+
function validateUploadResponse(validateResponse) {
|
|
322
|
+
if (!validateResponse.success || !validateResponse.data) {
|
|
323
|
+
throw new Error(`Validation failed: ${validateResponse.error || validateResponse.formattedError || 'Unknown error'}`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return validateResponse.data.data || validateResponse.data;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function validateUpload(dataplaneUrl, uploadId, authConfig) {
|
|
330
|
+
logger.log(chalk.blue('🔍 Validating upload...'));
|
|
331
|
+
const validateResponse = await validateUploadViaPipeline(dataplaneUrl, uploadId, authConfig);
|
|
332
|
+
|
|
333
|
+
const validateData = validateUploadResponse(validateResponse);
|
|
334
|
+
|
|
335
|
+
displayValidationChanges(validateData.changes);
|
|
291
336
|
|
|
292
337
|
if (validateData.summary) {
|
|
293
338
|
logger.log(chalk.blue(`\n📊 Summary: ${validateData.summary}`));
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External System Download Helpers
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for external system download file generation
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Download helper utilities for external system download
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generates variables.yaml content for downloaded system
|
|
13
|
+
* @param {string} systemKey - System key
|
|
14
|
+
* @param {Object} application - External system configuration
|
|
15
|
+
* @param {Array} dataSources - Array of datasource configurations
|
|
16
|
+
* @returns {Object} Variables YAML object
|
|
17
|
+
*/
|
|
18
|
+
function generateVariablesYaml(systemKey, application, dataSources) {
|
|
19
|
+
const systemFileName = `${systemKey}-deploy.json`;
|
|
20
|
+
const datasourceFiles = dataSources.map(ds => {
|
|
21
|
+
// Extract entity type from datasource key or use entityType/entityKey (backward compatibility)
|
|
22
|
+
const entityType = ds.entityType || ds.entityKey || ds.key.split('-').pop();
|
|
23
|
+
return `${systemKey}-deploy-${entityType}.json`;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
name: systemKey,
|
|
28
|
+
displayName: application.displayName || systemKey,
|
|
29
|
+
description: application.description || `External system integration for ${systemKey}`,
|
|
30
|
+
externalIntegration: {
|
|
31
|
+
schemaBasePath: './',
|
|
32
|
+
systems: [systemFileName],
|
|
33
|
+
dataSources: datasourceFiles,
|
|
34
|
+
autopublish: false,
|
|
35
|
+
version: application.version || '1.0.0'
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generates README.md with setup instructions
|
|
42
|
+
* @param {string} systemKey - System key
|
|
43
|
+
* @param {Object} application - External system configuration
|
|
44
|
+
* @param {Array} dataSources - Array of datasource configurations
|
|
45
|
+
* @returns {string} README.md content
|
|
46
|
+
*/
|
|
47
|
+
function generateReadme(systemKey, application, dataSources) {
|
|
48
|
+
const displayName = application.displayName || systemKey;
|
|
49
|
+
const description = application.description || `External system integration for ${systemKey}`;
|
|
50
|
+
const systemType = application.type || 'unknown';
|
|
51
|
+
|
|
52
|
+
const lines = [
|
|
53
|
+
`# ${displayName}`,
|
|
54
|
+
'',
|
|
55
|
+
description,
|
|
56
|
+
'',
|
|
57
|
+
'## System Information',
|
|
58
|
+
'',
|
|
59
|
+
`- **System Key**: \`${systemKey}\``,
|
|
60
|
+
`- **System Type**: \`${systemType}\``,
|
|
61
|
+
`- **Datasources**: ${dataSources.length}`,
|
|
62
|
+
'',
|
|
63
|
+
'## Files',
|
|
64
|
+
'',
|
|
65
|
+
'- `variables.yaml` - Application configuration with externalIntegration block',
|
|
66
|
+
`- \`${systemKey}-deploy.json\` - External system definition`
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
dataSources.forEach(ds => {
|
|
70
|
+
const entityType = ds.entityType || ds.entityKey || ds.key.split('-').pop();
|
|
71
|
+
lines.push(`- \`${systemKey}-deploy-${entityType}.json\` - Datasource: ${ds.displayName || ds.key}`);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
lines.push(
|
|
75
|
+
'- `env.template` - Environment variables template',
|
|
76
|
+
'',
|
|
77
|
+
'## Setup Instructions',
|
|
78
|
+
'',
|
|
79
|
+
'1. Review and update configuration files as needed',
|
|
80
|
+
'2. Set up environment variables in `env.template`',
|
|
81
|
+
'3. Run unit tests: `aifabrix test ${systemKey}`',
|
|
82
|
+
'4. Run integration tests: `aifabrix test-integration ${systemKey}`',
|
|
83
|
+
'5. Deploy: `aifabrix deploy ${systemKey} --environment dev`',
|
|
84
|
+
'',
|
|
85
|
+
'## Testing',
|
|
86
|
+
'',
|
|
87
|
+
'### Unit Tests',
|
|
88
|
+
'Run local validation without API calls:',
|
|
89
|
+
'```bash',
|
|
90
|
+
`aifabrix test ${systemKey}`,
|
|
91
|
+
'```',
|
|
92
|
+
'',
|
|
93
|
+
'### Integration Tests',
|
|
94
|
+
'Run integration tests via dataplane:',
|
|
95
|
+
'```bash',
|
|
96
|
+
`aifabrix test-integration ${systemKey} --environment dev`,
|
|
97
|
+
'```',
|
|
98
|
+
'',
|
|
99
|
+
'## Deployment',
|
|
100
|
+
'',
|
|
101
|
+
'Deploy to dataplane via miso-controller:',
|
|
102
|
+
'```bash',
|
|
103
|
+
`aifabrix deploy ${systemKey} --environment dev`,
|
|
104
|
+
'```'
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
return lines.join('\n');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = {
|
|
111
|
+
generateVariablesYaml,
|
|
112
|
+
generateReadme
|
|
113
|
+
};
|
|
114
|
+
|