@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.
- package/.cursor/rules/docs-rules.mdc +30 -0
- package/README.md +7 -5
- package/integration/hubspot/README.md +8 -4
- package/integration/hubspot/application.json +54 -0
- package/integration/hubspot/create-hubspot.js +9 -136
- package/integration/hubspot/env.template +3 -4
- package/integration/hubspot/hubspot-datasource-company.json +343 -5
- package/integration/hubspot/hubspot-datasource-contact.json +413 -5
- package/integration/hubspot/hubspot-datasource-deal.json +341 -4
- package/integration/hubspot/hubspot-datasource-users.json +116 -0
- package/integration/hubspot/hubspot-deploy.json +1250 -108
- package/integration/hubspot/hubspot-system.json +15 -32
- package/integration/hubspot/test-dataplane-down-tests.js +17 -16
- package/integration/hubspot/test-dataplane-down.js +2 -2
- package/integration/hubspot/test.js +1 -1
- package/jest.config.manual.js +2 -1
- package/lib/api/credential.api.js +40 -0
- package/lib/api/dev.api.js +423 -0
- package/lib/api/external-test.api.js +111 -0
- package/lib/api/index.js +42 -19
- package/lib/api/pipeline.api.js +66 -120
- package/lib/api/types/credential.types.js +23 -0
- package/lib/api/types/dev.types.js +140 -0
- package/lib/api/types/pipeline.types.js +37 -0
- package/lib/api/wizard-platform.api.js +61 -0
- package/lib/api/wizard.api.js +34 -1
- package/lib/app/config.js +44 -11
- package/lib/app/down.js +2 -1
- package/lib/app/index.js +12 -1
- package/lib/app/prompts.js +44 -29
- package/lib/app/push.js +36 -12
- package/lib/app/readme.js +9 -6
- package/lib/app/run-env-compose.js +264 -0
- package/lib/app/run-helpers.js +121 -118
- package/lib/app/run.js +148 -28
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +5 -2
- package/lib/build/index.js +11 -3
- package/lib/cli/setup-app.js +172 -15
- package/lib/cli/setup-credential-deployment.js +31 -6
- package/lib/cli/setup-dev.js +206 -16
- package/lib/cli/setup-environment.js +16 -6
- package/lib/cli/setup-external-system.js +89 -24
- package/lib/cli/setup-infra.js +82 -15
- package/lib/cli/setup-secrets.js +52 -5
- package/lib/cli/setup-utility.js +129 -24
- package/lib/commands/app-install.js +172 -0
- package/lib/commands/app-shell.js +75 -0
- package/lib/commands/app-test.js +282 -0
- package/lib/commands/app.js +1 -1
- package/lib/commands/credential-env.js +162 -0
- package/lib/commands/credential-list.js +17 -22
- package/lib/commands/credential-push.js +96 -0
- package/lib/commands/datasource.js +77 -6
- package/lib/commands/dev-cli-handlers.js +141 -0
- package/lib/commands/dev-down.js +114 -0
- package/lib/commands/dev-init.js +347 -0
- package/lib/commands/repair-auth-config.js +99 -0
- package/lib/commands/repair-datasource-keys.js +208 -0
- package/lib/commands/repair-datasource.js +235 -0
- package/lib/commands/repair-env-template.js +348 -0
- package/lib/commands/repair-internal.js +85 -0
- package/lib/commands/repair-rbac.js +158 -0
- package/lib/commands/repair.js +507 -0
- package/lib/commands/secrets-list.js +118 -0
- package/lib/commands/secrets-remove.js +97 -0
- package/lib/commands/secrets-set.js +30 -17
- package/lib/commands/secrets-validate.js +50 -0
- package/lib/commands/test-e2e-external.js +165 -0
- package/lib/commands/up-dataplane.js +2 -2
- package/lib/commands/up-miso.js +0 -25
- package/lib/commands/upload.js +96 -40
- package/lib/commands/wizard-core-helpers.js +226 -4
- package/lib/commands/wizard-core.js +67 -29
- package/lib/commands/wizard-dataplane.js +1 -1
- package/lib/commands/wizard-entity-selection.js +43 -0
- package/lib/commands/wizard-headless.js +44 -5
- package/lib/commands/wizard-helpers.js +7 -3
- package/lib/commands/wizard.js +86 -64
- package/lib/core/admin-secrets.js +96 -0
- package/lib/core/config.js +7 -1
- package/lib/core/secrets-ensure.js +378 -0
- package/lib/core/secrets-env-write.js +157 -0
- package/lib/core/secrets.js +176 -89
- package/lib/datasource/deploy.js +12 -3
- package/lib/datasource/field-reference-validator.js +91 -0
- package/lib/datasource/test-e2e.js +219 -0
- package/lib/datasource/test-integration.js +154 -0
- package/lib/datasource/validate.js +21 -3
- package/lib/deployment/deployer.js +7 -5
- package/lib/deployment/environment-config.js +137 -0
- package/lib/deployment/environment.js +21 -98
- package/lib/deployment/push.js +32 -2
- package/lib/external-system/download.js +188 -203
- package/lib/external-system/generator.js +204 -56
- package/lib/external-system/test-auth.js +7 -3
- package/lib/external-system/test-execution.js +2 -1
- package/lib/external-system/test-system-level.js +73 -0
- package/lib/external-system/test.js +56 -19
- package/lib/generator/external-controller-manifest.js +29 -2
- package/lib/generator/external-schema-utils.js +1 -1
- package/lib/generator/external.js +10 -3
- package/lib/generator/index.js +177 -25
- package/lib/generator/split-readme.js +1 -0
- package/lib/generator/split-variables.js +7 -1
- package/lib/generator/split.js +194 -54
- package/lib/generator/wizard-prompts-secondary.js +294 -0
- package/lib/generator/wizard-prompts.js +105 -106
- package/lib/generator/wizard-readme.js +88 -0
- package/lib/generator/wizard.js +155 -158
- package/lib/infrastructure/compose.js +11 -1
- package/lib/infrastructure/helpers.js +103 -20
- package/lib/infrastructure/index.js +98 -12
- package/lib/infrastructure/services.js +88 -22
- package/lib/schema/application-schema.json +32 -8
- package/lib/schema/external-datasource.schema.json +49 -26
- package/lib/schema/external-system.schema.json +509 -411
- package/lib/schema/wizard-config.schema.json +16 -0
- package/lib/utils/api.js +41 -13
- package/lib/utils/app-register-auth.js +25 -3
- package/lib/utils/auth-headers.js +8 -7
- package/lib/utils/cli-utils.js +20 -0
- package/lib/utils/compose-generator.js +77 -76
- package/lib/utils/compose-handlebars-helpers.js +54 -0
- package/lib/utils/compose-vector-helper.js +18 -0
- package/lib/utils/config-format-preference.js +51 -0
- package/lib/utils/config-format.js +36 -0
- package/lib/utils/config-paths.js +127 -2
- package/lib/utils/configuration-env-resolver.js +179 -0
- package/lib/utils/credential-display.js +83 -0
- package/lib/utils/credential-secrets-env.js +357 -0
- package/lib/utils/dataplane-pipeline-warning.js +28 -0
- package/lib/utils/deployment-validation-helpers.js +4 -4
- package/lib/utils/dev-ca-install.js +139 -0
- package/lib/utils/dev-cert-helper.js +122 -0
- package/lib/utils/device-code-helpers.js +224 -0
- package/lib/utils/device-code.js +37 -336
- package/lib/utils/docker-build.js +40 -8
- package/lib/utils/env-copy.js +103 -13
- package/lib/utils/env-map.js +35 -5
- package/lib/utils/env-template.js +6 -5
- package/lib/utils/error-formatters/http-status-errors.js +20 -2
- package/lib/utils/error-formatters/permission-errors.js +0 -1
- package/lib/utils/error-formatters/validation-errors.js +0 -1
- package/lib/utils/external-readme.js +56 -29
- package/lib/utils/external-system-display.js +59 -1
- package/lib/utils/external-system-test-helpers.js +21 -8
- package/lib/utils/external-system-validators.js +3 -0
- package/lib/utils/file-upload.js +20 -50
- package/lib/utils/help-builder.js +16 -2
- package/lib/utils/infra-status.js +80 -45
- package/lib/utils/local-secrets.js +7 -52
- package/lib/utils/mutagen-install.js +195 -0
- package/lib/utils/mutagen.js +146 -0
- package/lib/utils/paths.js +128 -37
- package/lib/utils/port-resolver.js +28 -16
- package/lib/utils/remote-dev-auth.js +38 -0
- package/lib/utils/remote-docker-env.js +43 -0
- package/lib/utils/remote-secrets-loader.js +60 -0
- package/lib/utils/secrets-canonical.js +93 -0
- package/lib/utils/secrets-generator.js +114 -6
- package/lib/utils/secrets-helpers.js +108 -114
- package/lib/utils/secrets-path.js +2 -2
- package/lib/utils/secrets-utils.js +52 -1
- package/lib/utils/secrets-validation.js +84 -0
- package/lib/utils/ssh-key-helper.js +116 -0
- package/lib/utils/test-log-writer.js +56 -0
- package/lib/utils/token-manager-messages.js +90 -0
- package/lib/utils/token-manager.js +29 -36
- package/lib/utils/variable-transformer.js +3 -3
- package/lib/validation/env-template-auth.js +157 -0
- package/lib/validation/env-template-kv.js +41 -0
- package/lib/validation/external-manifest-validator.js +25 -0
- package/lib/validation/external-system-auth-rules.js +86 -0
- package/lib/validation/validate-batch.js +149 -0
- package/lib/validation/validate-datasource-keys-api.js +33 -0
- package/lib/validation/validate-display.js +94 -16
- package/lib/validation/validate.js +25 -12
- package/lib/validation/validator.js +72 -9
- package/lib/validation/wizard-datasource-validation.js +50 -0
- package/package.json +8 -3
- package/scripts/install-local.js +34 -15
- package/templates/README.md +0 -1
- package/templates/applications/README.md.hbs +4 -4
- package/templates/applications/dataplane/application.yaml +6 -5
- package/templates/applications/dataplane/env.template +15 -10
- package/templates/applications/dataplane/rbac.yaml +2 -2
- package/templates/applications/keycloak/env.template +2 -0
- package/templates/applications/miso-controller/application.yaml +1 -0
- package/templates/applications/miso-controller/env.template +12 -10
- package/templates/external-system/README.md.hbs +65 -25
- package/templates/external-system/deploy.js.hbs +4 -2
- package/templates/external-system/external-datasource.yaml.hbs +217 -0
- package/templates/external-system/external-system.json.hbs +1 -18
- package/templates/infra/compose.yaml.hbs +6 -0
- package/templates/python/docker-compose.hbs +49 -23
- package/templates/typescript/docker-compose.hbs +48 -22
- package/integration/hubspot/application.yaml +0 -37
package/lib/generator/wizard.js
CHANGED
|
@@ -15,7 +15,8 @@ const chalk = require('chalk');
|
|
|
15
15
|
const logger = require('../utils/logger');
|
|
16
16
|
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
17
17
|
const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
|
|
18
|
-
const {
|
|
18
|
+
const { systemKeyToKvPrefix } = require('../utils/credential-secrets-env');
|
|
19
|
+
const { generateReadme } = require('./wizard-readme');
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Converts a string to a schema-valid key segment (lowercase letters, numbers, hyphens only).
|
|
@@ -41,45 +42,59 @@ function toKeySegment(str) {
|
|
|
41
42
|
* @returns {Promise<Object>} Object with generated file paths
|
|
42
43
|
* @throws {Error} If file generation fails
|
|
43
44
|
*/
|
|
45
|
+
/** Extension for format */
|
|
46
|
+
const FORMAT_EXT = { yaml: '.yaml', json: '.json' };
|
|
47
|
+
|
|
44
48
|
/**
|
|
45
|
-
* Writes system
|
|
49
|
+
* Writes system config file
|
|
46
50
|
* @async
|
|
47
51
|
* @function writeSystemYamlFile
|
|
48
52
|
* @param {string} appPath - Application path
|
|
49
53
|
* @param {string} finalSystemKey - Final system key
|
|
50
54
|
* @param {Object} systemConfig - System configuration
|
|
55
|
+
* @param {string} [format] - Output format: 'yaml' (default) or 'json'
|
|
51
56
|
* @returns {Promise<string>} System file path
|
|
52
57
|
*/
|
|
53
|
-
async function writeSystemYamlFile(appPath, finalSystemKey, systemConfig) {
|
|
54
|
-
const
|
|
58
|
+
async function writeSystemYamlFile(appPath, finalSystemKey, systemConfig, format = 'yaml') {
|
|
59
|
+
const ext = FORMAT_EXT[format === 'json' ? 'json' : 'yaml'] || '.yaml';
|
|
60
|
+
const systemFileName = `${finalSystemKey}-system${ext}`;
|
|
55
61
|
const systemFilePath = path.join(appPath, systemFileName);
|
|
56
|
-
writeConfigFile(systemFilePath, systemConfig);
|
|
62
|
+
writeConfigFile(systemFilePath, systemConfig, format === 'json' ? 'json' : 'yaml');
|
|
57
63
|
logger.log(chalk.green(`✓ Generated system file: ${systemFileName}`));
|
|
58
64
|
return systemFilePath;
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
/**
|
|
62
|
-
* Writes datasource
|
|
68
|
+
* Writes datasource config files
|
|
63
69
|
* @async
|
|
64
70
|
* @function writeDatasourceYamlFiles
|
|
65
71
|
* @param {string} appPath - Application path
|
|
66
72
|
* @param {string} finalSystemKey - Final system key
|
|
67
73
|
* @param {Object[]} datasourceConfigs - Array of datasource configurations
|
|
74
|
+
* @param {string} [format] - Output format: 'yaml' (default) or 'json'
|
|
68
75
|
* @returns {Promise<string[]>} Array of datasource file names
|
|
69
76
|
*/
|
|
70
|
-
async function writeDatasourceYamlFiles(appPath, finalSystemKey, datasourceConfigs) {
|
|
77
|
+
async function writeDatasourceYamlFiles(appPath, finalSystemKey, datasourceConfigs, format = 'yaml') {
|
|
78
|
+
const ext = FORMAT_EXT[format === 'json' ? 'json' : 'yaml'] || '.yaml';
|
|
79
|
+
const fmt = format === 'json' ? 'json' : 'yaml';
|
|
71
80
|
const datasourceFileNames = [];
|
|
81
|
+
const usedBaseNames = new Set();
|
|
72
82
|
for (const datasourceConfig of datasourceConfigs) {
|
|
73
|
-
const
|
|
74
|
-
const keySegment = toKeySegment(entityType);
|
|
75
|
-
const datasourceKey = datasourceConfig.key || `${finalSystemKey}-${keySegment}`;
|
|
76
|
-
// Extract datasource key (remove system key prefix if present); use normalized segment for filename
|
|
83
|
+
const datasourceKey = datasourceConfig.key || '';
|
|
77
84
|
const datasourceKeyOnly = datasourceKey.includes('-') && datasourceKey.startsWith(`${finalSystemKey}-`)
|
|
78
85
|
? datasourceKey.substring(finalSystemKey.length + 1)
|
|
79
|
-
:
|
|
80
|
-
const
|
|
86
|
+
: (datasourceConfig.entityType || datasourceConfig.entityKey || datasourceKey.split('-').pop() || 'default');
|
|
87
|
+
const keySegment = toKeySegment(datasourceKeyOnly);
|
|
88
|
+
let baseName = keySegment;
|
|
89
|
+
if (usedBaseNames.has(baseName)) {
|
|
90
|
+
let suffix = 1;
|
|
91
|
+
while (usedBaseNames.has(`${baseName}-${suffix}`)) suffix++;
|
|
92
|
+
baseName = `${baseName}-${suffix}`;
|
|
93
|
+
}
|
|
94
|
+
usedBaseNames.add(baseName);
|
|
95
|
+
const datasourceFileName = `${finalSystemKey}-datasource-${baseName}${ext}`;
|
|
81
96
|
const datasourceFilePath = path.join(appPath, datasourceFileName);
|
|
82
|
-
writeConfigFile(datasourceFilePath, datasourceConfig);
|
|
97
|
+
writeConfigFile(datasourceFilePath, datasourceConfig, fmt);
|
|
83
98
|
datasourceFileNames.push(datasourceFileName);
|
|
84
99
|
logger.log(chalk.green(`✓ Generated datasource file: ${datasourceFileName}`));
|
|
85
100
|
}
|
|
@@ -102,32 +117,50 @@ async function writeDatasourceYamlFiles(appPath, finalSystemKey, datasourceConfi
|
|
|
102
117
|
* @returns {Promise<Object>} Object with file paths
|
|
103
118
|
*/
|
|
104
119
|
async function generateConfigFilesForWizard(params) {
|
|
105
|
-
const { appPath, appName, finalSystemKey, systemFileName, datasourceFileNames, systemConfig, datasourceConfigs, aiGeneratedReadme } = params;
|
|
120
|
+
const { appPath, appName, finalSystemKey, systemFileName, datasourceFileNames, systemConfig, datasourceConfigs, aiGeneratedReadme, format } = params;
|
|
106
121
|
|
|
107
|
-
// Generate or update application
|
|
122
|
+
// Generate or update application config with externalIntegration block
|
|
108
123
|
const configPath = await generateOrUpdateVariablesYaml({
|
|
109
124
|
appPath,
|
|
110
125
|
appName,
|
|
111
126
|
systemKey: finalSystemKey,
|
|
112
127
|
systemFileName,
|
|
113
128
|
datasourceFileNames,
|
|
114
|
-
systemConfig
|
|
129
|
+
systemConfig,
|
|
130
|
+
format: format || 'yaml'
|
|
115
131
|
});
|
|
116
132
|
|
|
117
|
-
// Generate env.template with authentication variables
|
|
118
|
-
await generateEnvTemplate(appPath, systemConfig);
|
|
133
|
+
// Generate env.template with KV_* authentication variables
|
|
134
|
+
await generateEnvTemplate(appPath, systemConfig, finalSystemKey);
|
|
135
|
+
|
|
136
|
+
const envTemplatePath = path.join(appPath, 'env.template');
|
|
137
|
+
try {
|
|
138
|
+
const secretsEnsure = require('../core/secrets-ensure');
|
|
139
|
+
await secretsEnsure.ensureSecretsFromEnvTemplate(envTemplatePath, { emptyValuesForCredentials: true });
|
|
140
|
+
} catch (err) {
|
|
141
|
+
if (err.code !== 'ENOENT') logger.warn(`Could not ensure integration placeholder secrets: ${err.message}`);
|
|
142
|
+
}
|
|
119
143
|
|
|
120
144
|
// Generate README.md (use AI-generated content if available)
|
|
121
|
-
await generateReadme(
|
|
145
|
+
await generateReadme({
|
|
146
|
+
appPath,
|
|
147
|
+
appName,
|
|
148
|
+
systemKey: finalSystemKey,
|
|
149
|
+
systemConfig,
|
|
150
|
+
datasourceConfigs,
|
|
151
|
+
aiGeneratedContent: aiGeneratedReadme,
|
|
152
|
+
format
|
|
153
|
+
});
|
|
122
154
|
|
|
123
155
|
// Generate deployment scripts
|
|
124
156
|
const deployScripts = await generateDeployScripts(appPath, finalSystemKey, systemFileName, datasourceFileNames);
|
|
125
157
|
|
|
126
158
|
// Generate deployment manifest (<systemKey>-deploy.json) using controller format
|
|
127
|
-
const { generateControllerManifest } = require('./external-controller-manifest');
|
|
159
|
+
const { generateControllerManifest, toDeployJsonShape } = require('./external-controller-manifest');
|
|
128
160
|
const manifest = await generateControllerManifest(appName, { appPath });
|
|
161
|
+
const deployJson = toDeployJsonShape(manifest);
|
|
129
162
|
const deployManifestPath = path.join(appPath, `${finalSystemKey}-deploy.json`);
|
|
130
|
-
await fs.writeFile(deployManifestPath, JSON.stringify(
|
|
163
|
+
await fs.writeFile(deployManifestPath, JSON.stringify(deployJson, null, 2), 'utf8');
|
|
131
164
|
logger.log(chalk.green(`✓ Generated deployment manifest: ${finalSystemKey}-deploy.json`));
|
|
132
165
|
|
|
133
166
|
return {
|
|
@@ -143,24 +176,40 @@ async function prepareWizardContext(appName, systemConfig, datasourceConfigs) {
|
|
|
143
176
|
const appPath = path.join(process.cwd(), 'integration', appName);
|
|
144
177
|
await fs.mkdir(appPath, { recursive: true });
|
|
145
178
|
const finalSystemKey = appName;
|
|
179
|
+
const originalSystemKey = systemConfig.key || finalSystemKey;
|
|
146
180
|
const appDisplayName = appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
147
181
|
const updatedSystemConfig = { ...systemConfig, key: finalSystemKey, displayName: appDisplayName };
|
|
182
|
+
const originalPrefix = `${originalSystemKey}-`;
|
|
148
183
|
const updatedDatasourceConfigs = datasourceConfigs.map(ds => {
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
184
|
+
let newKey;
|
|
185
|
+
const dsKey = ds.key || '';
|
|
186
|
+
if (dsKey && dsKey.startsWith(originalPrefix)) {
|
|
187
|
+
newKey = `${finalSystemKey}-${dsKey.substring(originalPrefix.length)}`;
|
|
188
|
+
} else {
|
|
189
|
+
const entityType = ds.entityType || ds.entityKey || dsKey.split('-').pop() || 'default';
|
|
190
|
+
const keySegment = toKeySegment(entityType);
|
|
191
|
+
newKey = `${finalSystemKey}-${keySegment}`;
|
|
192
|
+
}
|
|
193
|
+
const entityType = ds.entityType || ds.entityKey || newKey.split('-').pop() || 'default';
|
|
194
|
+
const entityDisplayName = String(entityType).charAt(0).toUpperCase() + String(entityType).slice(1).replace(/-/g, ' ');
|
|
195
|
+
return { ...ds, key: newKey, systemKey: finalSystemKey, displayName: ds.displayName || `${appDisplayName} ${entityDisplayName}` };
|
|
153
196
|
});
|
|
154
197
|
return { appPath, finalSystemKey, updatedSystemConfig, updatedDatasourceConfigs, appDisplayName };
|
|
155
198
|
}
|
|
156
199
|
|
|
157
200
|
async function generateWizardFiles(appName, systemConfig, datasourceConfigs, systemKey, options = {}) {
|
|
158
201
|
try {
|
|
159
|
-
const { aiGeneratedReadme } = options || {};
|
|
202
|
+
const { aiGeneratedReadme, format } = options || {};
|
|
203
|
+
const fmt = format === 'json' ? 'json' : 'yaml';
|
|
204
|
+
const ext = FORMAT_EXT[fmt] || '.yaml';
|
|
160
205
|
const { appPath, finalSystemKey, updatedSystemConfig, updatedDatasourceConfigs } = await prepareWizardContext(appName, systemConfig, datasourceConfigs);
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
206
|
+
const systemConfigWithDataSourcesKeys = {
|
|
207
|
+
...updatedSystemConfig,
|
|
208
|
+
dataSources: updatedDatasourceConfigs.map(ds => ds.key)
|
|
209
|
+
};
|
|
210
|
+
const systemFilePath = await writeSystemYamlFile(appPath, finalSystemKey, systemConfigWithDataSourcesKeys, fmt);
|
|
211
|
+
const datasourceFileNames = await writeDatasourceYamlFiles(appPath, finalSystemKey, updatedDatasourceConfigs, fmt);
|
|
212
|
+
const systemFileName = `${finalSystemKey}-system${ext}`;
|
|
164
213
|
const configFiles = await generateConfigFilesForWizard({
|
|
165
214
|
appPath,
|
|
166
215
|
appName,
|
|
@@ -169,7 +218,8 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
169
218
|
datasourceFileNames,
|
|
170
219
|
systemConfig: updatedSystemConfig,
|
|
171
220
|
datasourceConfigs: updatedDatasourceConfigs,
|
|
172
|
-
aiGeneratedReadme
|
|
221
|
+
aiGeneratedReadme,
|
|
222
|
+
format: fmt
|
|
173
223
|
});
|
|
174
224
|
return {
|
|
175
225
|
appPath,
|
|
@@ -182,22 +232,48 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
182
232
|
}
|
|
183
233
|
}
|
|
184
234
|
|
|
235
|
+
function mergeAppAndExternalIntegration(variables, appName, systemFileName, datasourceFileNames, systemConfig) {
|
|
236
|
+
if (!variables.app) {
|
|
237
|
+
variables.app = {
|
|
238
|
+
key: appName,
|
|
239
|
+
displayName: systemConfig.displayName || appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
|
|
240
|
+
description: systemConfig.description || `External system integration for ${appName}`,
|
|
241
|
+
type: 'external',
|
|
242
|
+
version: '1.0.0'
|
|
243
|
+
};
|
|
244
|
+
} else {
|
|
245
|
+
variables.app.version = variables.app.version || '1.0.0';
|
|
246
|
+
}
|
|
247
|
+
if (!variables.deployment) {
|
|
248
|
+
variables.deployment = { controllerUrl: '', environment: 'dev' };
|
|
249
|
+
}
|
|
250
|
+
variables.externalIntegration = {
|
|
251
|
+
schemaBasePath: './',
|
|
252
|
+
systems: [systemFileName],
|
|
253
|
+
dataSources: datasourceFileNames,
|
|
254
|
+
autopublish: true,
|
|
255
|
+
version: systemConfig.version || '1.0.0'
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
185
259
|
/**
|
|
186
|
-
* Generate or update application
|
|
260
|
+
* Generate or update application config with externalIntegration block
|
|
187
261
|
* @async
|
|
188
262
|
* @function generateOrUpdateVariablesYaml
|
|
189
263
|
* @param {Object} params - Parameters object
|
|
190
264
|
* @param {string} params.appPath - Application directory path
|
|
191
265
|
* @param {string} params.appName - Application name
|
|
192
|
-
* @param {string} params.systemKey - System key
|
|
193
266
|
* @param {string} params.systemFileName - System file name
|
|
194
267
|
* @param {string[]} params.datasourceFileNames - Array of datasource file names
|
|
195
268
|
* @param {Object} params.systemConfig - System configuration
|
|
269
|
+
* @param {string} [params.format] - Output format: 'yaml' (default) or 'json'
|
|
196
270
|
* @returns {Promise<string>} Path to application config file
|
|
197
271
|
* @throws {Error} If generation fails
|
|
198
272
|
*/
|
|
199
273
|
async function generateOrUpdateVariablesYaml(params) {
|
|
200
|
-
const { appPath, appName, systemFileName, datasourceFileNames, systemConfig } = params;
|
|
274
|
+
const { appPath, appName, systemFileName, datasourceFileNames, systemConfig, format } = params;
|
|
275
|
+
const fmt = format === 'json' ? 'json' : 'yaml';
|
|
276
|
+
const ext = FORMAT_EXT[fmt] || '.yaml';
|
|
201
277
|
let configPath;
|
|
202
278
|
let variables = {};
|
|
203
279
|
try {
|
|
@@ -205,115 +281,88 @@ async function generateOrUpdateVariablesYaml(params) {
|
|
|
205
281
|
configPath = resolveApplicationConfigPath(appPath);
|
|
206
282
|
variables = loadConfigFile(configPath) || {};
|
|
207
283
|
} catch {
|
|
208
|
-
configPath = path.join(appPath,
|
|
284
|
+
configPath = path.join(appPath, `application${ext}`);
|
|
209
285
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
description: systemConfig.description || `External system integration for ${appName}`,
|
|
217
|
-
type: 'external',
|
|
218
|
-
version: '1.0.0'
|
|
219
|
-
};
|
|
220
|
-
} else {
|
|
221
|
-
variables.app.version = variables.app.version || '1.0.0';
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Set deployment config if not present
|
|
225
|
-
if (!variables.deployment) {
|
|
226
|
-
variables.deployment = {
|
|
227
|
-
controllerUrl: '',
|
|
228
|
-
environment: 'dev'
|
|
229
|
-
};
|
|
286
|
+
mergeAppAndExternalIntegration(variables, appName, systemFileName, datasourceFileNames, systemConfig);
|
|
287
|
+
const targetPath = path.join(appPath, `application${ext}`);
|
|
288
|
+
writeConfigFile(targetPath, variables, fmt);
|
|
289
|
+
if (path.normalize(configPath) !== path.normalize(targetPath)) {
|
|
290
|
+
const fsSync = require('fs');
|
|
291
|
+
if (fsSync.existsSync(configPath)) fsSync.unlinkSync(configPath);
|
|
230
292
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
variables.externalIntegration = {
|
|
234
|
-
schemaBasePath: './',
|
|
235
|
-
systems: [systemFileName],
|
|
236
|
-
dataSources: datasourceFileNames,
|
|
237
|
-
autopublish: true,
|
|
238
|
-
version: systemConfig.version || '1.0.0'
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
writeConfigFile(configPath, variables);
|
|
242
|
-
logger.log(chalk.green('✓ Generated/updated application.yaml'));
|
|
243
|
-
return configPath;
|
|
293
|
+
logger.log(chalk.green(`✓ Generated/updated application${ext}`));
|
|
294
|
+
return targetPath;
|
|
244
295
|
} catch (error) {
|
|
245
296
|
throw new Error(`Failed to generate application config: ${error.message}`);
|
|
246
297
|
}
|
|
247
298
|
}
|
|
248
299
|
|
|
249
300
|
/**
|
|
250
|
-
* Adds API key authentication lines
|
|
251
|
-
* @function addApiKeyAuthLines
|
|
301
|
+
* Adds API key authentication lines with KV_* convention
|
|
252
302
|
* @param {Array<string>} lines - Lines array to append to
|
|
303
|
+
* @param {string} prefix - KV prefix (e.g. HUBSPOT)
|
|
253
304
|
*/
|
|
254
|
-
function addApiKeyAuthLines(lines) {
|
|
305
|
+
function addApiKeyAuthLines(lines, prefix) {
|
|
255
306
|
lines.push('# API Key Authentication');
|
|
256
|
-
lines.push(
|
|
307
|
+
lines.push(`KV_${prefix}_APIKEY=`);
|
|
257
308
|
lines.push('');
|
|
258
309
|
}
|
|
259
310
|
|
|
260
311
|
/**
|
|
261
|
-
* Adds OAuth2 authentication lines
|
|
262
|
-
* @function addOAuth2AuthLines
|
|
312
|
+
* Adds OAuth2 authentication lines with KV_* convention
|
|
263
313
|
* @param {Array<string>} lines - Lines array to append to
|
|
264
314
|
* @param {Object} auth - Authentication configuration
|
|
315
|
+
* @param {string} prefix - KV prefix
|
|
265
316
|
*/
|
|
266
|
-
function addOAuth2AuthLines(lines, auth) {
|
|
317
|
+
function addOAuth2AuthLines(lines, auth, prefix) {
|
|
267
318
|
lines.push('# OAuth2 Authentication');
|
|
268
|
-
lines.push(
|
|
269
|
-
lines.push(
|
|
270
|
-
lines.push(
|
|
271
|
-
lines.push('TOKEN_URL=kv://secrets/token-url');
|
|
272
|
-
if (auth.scope) {
|
|
273
|
-
lines.push(`SCOPE=${auth.scope}`);
|
|
274
|
-
}
|
|
319
|
+
lines.push(`KV_${prefix}_CLIENTID=`);
|
|
320
|
+
lines.push(`KV_${prefix}_CLIENTSECRET=`);
|
|
321
|
+
if (auth.scope) lines.push(`SCOPE=${auth.scope}`);
|
|
275
322
|
lines.push('');
|
|
276
323
|
}
|
|
277
324
|
|
|
278
325
|
/**
|
|
279
|
-
* Adds bearer token authentication lines
|
|
280
|
-
* @function addBearerTokenAuthLines
|
|
326
|
+
* Adds bearer token authentication lines with KV_* convention
|
|
281
327
|
* @param {Array<string>} lines - Lines array to append to
|
|
328
|
+
* @param {string} prefix - KV prefix
|
|
282
329
|
*/
|
|
283
|
-
function addBearerTokenAuthLines(lines) {
|
|
330
|
+
function addBearerTokenAuthLines(lines, prefix) {
|
|
284
331
|
lines.push('# Bearer Token Authentication');
|
|
285
|
-
lines.push(
|
|
332
|
+
lines.push(`KV_${prefix}_BEARERTOKEN=`);
|
|
286
333
|
lines.push('');
|
|
287
334
|
}
|
|
288
335
|
|
|
289
336
|
/**
|
|
290
|
-
* Adds basic authentication lines
|
|
291
|
-
* @function addBasicAuthLines
|
|
337
|
+
* Adds basic authentication lines with KV_* convention
|
|
292
338
|
* @param {Array<string>} lines - Lines array to append to
|
|
339
|
+
* @param {string} prefix - KV prefix
|
|
293
340
|
*/
|
|
294
|
-
function addBasicAuthLines(lines) {
|
|
341
|
+
function addBasicAuthLines(lines, prefix) {
|
|
295
342
|
lines.push('# Basic Authentication');
|
|
296
|
-
lines.push(
|
|
297
|
-
lines.push(
|
|
343
|
+
lines.push(`KV_${prefix}_USERNAME=`);
|
|
344
|
+
lines.push(`KV_${prefix}_PASSWORD=`);
|
|
298
345
|
lines.push('');
|
|
299
346
|
}
|
|
300
347
|
|
|
301
348
|
/**
|
|
302
|
-
* Adds authentication lines based on auth type
|
|
303
|
-
* @function addAuthenticationLines
|
|
349
|
+
* Adds authentication lines based on auth type. Uses KV_<APPKEY>_<VAR> convention.
|
|
304
350
|
* @param {Array<string>} lines - Lines array to append to
|
|
305
351
|
* @param {Object} auth - Authentication configuration
|
|
306
352
|
* @param {string} authType - Authentication type
|
|
353
|
+
* @param {string} systemKey - System key (e.g. hubspot) for KV_ prefix
|
|
307
354
|
*/
|
|
308
|
-
function addAuthenticationLines(lines, auth, authType) {
|
|
355
|
+
function addAuthenticationLines(lines, auth, authType, systemKey) {
|
|
356
|
+
const prefix = systemKeyToKvPrefix(systemKey);
|
|
357
|
+
if (!prefix) return;
|
|
309
358
|
if (authType === 'apikey' || authType === 'apiKey') {
|
|
310
|
-
addApiKeyAuthLines(lines);
|
|
359
|
+
addApiKeyAuthLines(lines, prefix);
|
|
311
360
|
} else if (authType === 'oauth2' || authType === 'oauth') {
|
|
312
|
-
addOAuth2AuthLines(lines, auth);
|
|
361
|
+
addOAuth2AuthLines(lines, auth || {}, prefix);
|
|
313
362
|
} else if (authType === 'bearer' || authType === 'token') {
|
|
314
|
-
addBearerTokenAuthLines(lines);
|
|
363
|
+
addBearerTokenAuthLines(lines, prefix);
|
|
315
364
|
} else if (authType === 'basic') {
|
|
316
|
-
addBasicAuthLines(lines);
|
|
365
|
+
addBasicAuthLines(lines, prefix);
|
|
317
366
|
}
|
|
318
367
|
}
|
|
319
368
|
|
|
@@ -332,23 +381,24 @@ function addBaseUrlLines(lines, systemConfig) {
|
|
|
332
381
|
}
|
|
333
382
|
|
|
334
383
|
/**
|
|
335
|
-
* Generate env.template with authentication variables
|
|
384
|
+
* Generate env.template with KV_* authentication variables
|
|
336
385
|
* @async
|
|
337
386
|
* @function generateEnvTemplate
|
|
338
387
|
* @param {string} appPath - Application directory path
|
|
339
|
-
* @param {Object} systemConfig - System configuration
|
|
388
|
+
* @param {Object} systemConfig - System configuration (must have key for systemKey)
|
|
389
|
+
* @param {string} [finalSystemKey] - Final system key for KV_ prefix (default: systemConfig.key)
|
|
340
390
|
* @throws {Error} If generation fails
|
|
341
391
|
*/
|
|
342
|
-
async function generateEnvTemplate(appPath, systemConfig) {
|
|
392
|
+
async function generateEnvTemplate(appPath, systemConfig, finalSystemKey) {
|
|
343
393
|
try {
|
|
344
394
|
const envTemplatePath = path.join(appPath, 'env.template');
|
|
345
|
-
const
|
|
395
|
+
const systemKey = finalSystemKey || systemConfig?.key;
|
|
396
|
+
const lines = ['# Environment variables for external system integration', '# Use KV_* for credential push (aifabrix credential push)', ''];
|
|
346
397
|
|
|
347
|
-
|
|
348
|
-
const auth = systemConfig.authentication || systemConfig.auth || {};
|
|
398
|
+
const auth = systemConfig?.authentication || systemConfig?.auth || {};
|
|
349
399
|
const authType = auth.type || auth.authType || 'apikey';
|
|
350
400
|
|
|
351
|
-
addAuthenticationLines(lines, auth, authType);
|
|
401
|
+
addAuthenticationLines(lines, auth, authType, systemKey);
|
|
352
402
|
addBaseUrlLines(lines, systemConfig);
|
|
353
403
|
|
|
354
404
|
await fs.writeFile(envTemplatePath, lines.join('\n'), 'utf8');
|
|
@@ -393,59 +443,6 @@ async function generateDeployScripts(appPath, systemKey, systemFileName, datasou
|
|
|
393
443
|
}
|
|
394
444
|
}
|
|
395
445
|
|
|
396
|
-
/**
|
|
397
|
-
* Generate README.md with basic documentation
|
|
398
|
-
* @async
|
|
399
|
-
* @function generateReadme
|
|
400
|
-
* @param {string} appPath - Application directory path
|
|
401
|
-
* @param {string} appName - Application name
|
|
402
|
-
* @param {string} systemKey - System key
|
|
403
|
-
* @param {Object} systemConfig - System configuration
|
|
404
|
-
* @param {Object[]} datasourceConfigs - Array of datasource configurations
|
|
405
|
-
* @param {string} [aiGeneratedContent] - Optional AI-generated README content from dataplane
|
|
406
|
-
* @throws {Error} If generation fails
|
|
407
|
-
*/
|
|
408
|
-
async function generateReadme(appPath, appName, systemKey, systemConfig, datasourceConfigs, aiGeneratedContent) {
|
|
409
|
-
try {
|
|
410
|
-
const readmePath = path.join(appPath, 'README.md');
|
|
411
|
-
|
|
412
|
-
// Use AI-generated content if available, otherwise generate basic README
|
|
413
|
-
if (aiGeneratedContent) {
|
|
414
|
-
await fs.writeFile(readmePath, aiGeneratedContent, 'utf8');
|
|
415
|
-
logger.log(chalk.green('✓ Generated README.md (AI-generated from dataplane)'));
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const datasources = (Array.isArray(datasourceConfigs) ? datasourceConfigs : []).map((ds, index) => {
|
|
420
|
-
const entityType = ds.entityType || ds.entityKey || ds.key?.split('-').pop() || `datasource${index + 1}`;
|
|
421
|
-
const keySegment = toKeySegment(entityType);
|
|
422
|
-
const datasourceKey = ds.key || `${systemKey}-${keySegment}`;
|
|
423
|
-
const datasourceKeyOnly = datasourceKey.includes('-') && datasourceKey.startsWith(`${systemKey}-`)
|
|
424
|
-
? datasourceKey.substring(systemKey.length + 1)
|
|
425
|
-
: keySegment;
|
|
426
|
-
return {
|
|
427
|
-
entityType,
|
|
428
|
-
displayName: ds.displayName || ds.name || ds.key || `Datasource ${index + 1}`,
|
|
429
|
-
fileName: `${systemKey}-datasource-${datasourceKeyOnly}.yaml`
|
|
430
|
-
};
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
const readmeContent = generateExternalReadmeContent({
|
|
434
|
-
appName,
|
|
435
|
-
systemKey,
|
|
436
|
-
systemType: systemConfig.type || systemConfig.systemType,
|
|
437
|
-
displayName: systemConfig.displayName,
|
|
438
|
-
description: systemConfig.description,
|
|
439
|
-
datasources
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
await fs.writeFile(readmePath, readmeContent, 'utf8');
|
|
443
|
-
logger.log(chalk.green('✓ Generated README.md (template)'));
|
|
444
|
-
} catch (error) {
|
|
445
|
-
throw new Error(`Failed to generate README.md: ${error.message}`);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
446
|
module.exports = {
|
|
450
447
|
generateWizardFiles,
|
|
451
448
|
generateDeployScripts
|
|
@@ -63,6 +63,8 @@ function validateTraefikConfig(traefikConfig) {
|
|
|
63
63
|
* @param {string} infraDir - Infrastructure directory
|
|
64
64
|
* @param {Object} [options] - Additional options
|
|
65
65
|
* @param {Object|boolean} [options.traefik] - Traefik configuration
|
|
66
|
+
* @param {Object} [options.pgadmin] - pgAdmin config { enabled: boolean }
|
|
67
|
+
* @param {Object} [options.redisCommander] - Redis Commander config { enabled: boolean }
|
|
66
68
|
* @returns {string} Path to generated compose file
|
|
67
69
|
*/
|
|
68
70
|
function generateComposeFile(templatePath, devId, idNum, ports, infraDir, options = {}) {
|
|
@@ -74,6 +76,12 @@ function generateComposeFile(templatePath, devId, idNum, ports, infraDir, option
|
|
|
74
76
|
const traefikConfig = typeof options.traefik === 'object'
|
|
75
77
|
? options.traefik
|
|
76
78
|
: buildTraefikConfig(!!options.traefik);
|
|
79
|
+
const pgadminConfig = options.pgadmin && typeof options.pgadmin.enabled === 'boolean'
|
|
80
|
+
? options.pgadmin
|
|
81
|
+
: { enabled: true };
|
|
82
|
+
const redisCommanderConfig = options.redisCommander && typeof options.redisCommander.enabled === 'boolean'
|
|
83
|
+
? options.redisCommander
|
|
84
|
+
: { enabled: true };
|
|
77
85
|
const composeContent = template({
|
|
78
86
|
devId: devId,
|
|
79
87
|
postgresPort: ports.postgres,
|
|
@@ -86,7 +94,9 @@ function generateComposeFile(templatePath, devId, idNum, ports, infraDir, option
|
|
|
86
94
|
serversJsonPath: serversJsonPath,
|
|
87
95
|
pgpassPath: pgpassPath,
|
|
88
96
|
infraDir: infraDir,
|
|
89
|
-
traefik: traefikConfig
|
|
97
|
+
traefik: traefikConfig,
|
|
98
|
+
pgadmin: pgadminConfig,
|
|
99
|
+
redisCommander: redisCommanderConfig
|
|
90
100
|
});
|
|
91
101
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
92
102
|
fs.writeFileSync(composePath, composeContent);
|