@aifabrix/builder 2.41.0 → 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 +1 -1
- 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/jest.config.manual.js +2 -1
- 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/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 +23 -11
- package/lib/app/index.js +3 -1
- package/lib/app/prompts.js +44 -29
- package/lib/app/readme.js +8 -3
- package/lib/app/run-env-compose.js +64 -1
- package/lib/app/run-helpers.js +1 -1
- package/lib/app/show-display.js +1 -1
- package/lib/cli/setup-app.js +42 -11
- package/lib/cli/setup-credential-deployment.js +31 -6
- package/lib/cli/setup-dev.js +27 -0
- package/lib/cli/setup-environment.js +12 -4
- package/lib/cli/setup-external-system.js +19 -4
- package/lib/cli/setup-infra.js +54 -14
- package/lib/cli/setup-utility.js +117 -21
- 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-init.js +39 -1
- 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/test-e2e-external.js +165 -0
- package/lib/commands/upload.js +71 -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/config.js +7 -1
- package/lib/core/secrets.js +33 -12
- package/lib/datasource/deploy.js +12 -3
- package/lib/datasource/test-e2e.js +219 -0
- package/lib/datasource/test-integration.js +154 -0
- package/lib/deployment/deployer.js +7 -5
- package/lib/external-system/download.js +182 -204
- package/lib/external-system/generator.js +204 -56
- 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 +51 -18
- 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 +4 -1
- 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 +147 -158
- package/lib/infrastructure/compose.js +11 -1
- package/lib/infrastructure/index.js +11 -3
- package/lib/infrastructure/services.js +22 -11
- package/lib/schema/application-schema.json +8 -5
- package/lib/schema/external-datasource.schema.json +49 -26
- package/lib/schema/external-system.schema.json +82 -6
- package/lib/schema/wizard-config.schema.json +16 -0
- package/lib/utils/api.js +38 -10
- package/lib/utils/auth-headers.js +8 -7
- package/lib/utils/compose-generator.js +1 -1
- package/lib/utils/compose-handlebars-helpers.js +11 -0
- package/lib/utils/config-format-preference.js +51 -0
- package/lib/utils/config-format.js +36 -0
- package/lib/utils/configuration-env-resolver.js +179 -0
- package/lib/utils/credential-display.js +83 -0
- package/lib/utils/credential-secrets-env.js +115 -25
- 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/env-copy.js +23 -3
- package/lib/utils/error-formatters/http-status-errors.js +0 -1
- 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 +1 -0
- package/lib/utils/infra-status.js +50 -44
- package/lib/utils/local-secrets.js +5 -5
- package/lib/utils/paths.js +85 -4
- package/lib/utils/secrets-canonical.js +93 -0
- package/lib/utils/secrets-generator.js +20 -0
- package/lib/utils/secrets-helpers.js +75 -89
- package/lib/utils/test-log-writer.js +56 -0
- package/lib/utils/token-manager.js +24 -32
- 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 +7 -9
- package/lib/validation/wizard-datasource-validation.js +50 -0
- package/package.json +7 -2
- package/templates/applications/dataplane/application.yaml +1 -1
- package/templates/applications/dataplane/env.template +5 -5
- package/templates/applications/dataplane/rbac.yaml +2 -2
- package/templates/applications/miso-controller/env.template +1 -1
- 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 +4 -4
- package/templates/typescript/docker-compose.hbs +4 -4
- 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,20 +117,21 @@ 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);
|
|
119
135
|
|
|
120
136
|
const envTemplatePath = path.join(appPath, 'env.template');
|
|
121
137
|
try {
|
|
@@ -126,16 +142,25 @@ async function generateConfigFilesForWizard(params) {
|
|
|
126
142
|
}
|
|
127
143
|
|
|
128
144
|
// Generate README.md (use AI-generated content if available)
|
|
129
|
-
await generateReadme(
|
|
145
|
+
await generateReadme({
|
|
146
|
+
appPath,
|
|
147
|
+
appName,
|
|
148
|
+
systemKey: finalSystemKey,
|
|
149
|
+
systemConfig,
|
|
150
|
+
datasourceConfigs,
|
|
151
|
+
aiGeneratedContent: aiGeneratedReadme,
|
|
152
|
+
format
|
|
153
|
+
});
|
|
130
154
|
|
|
131
155
|
// Generate deployment scripts
|
|
132
156
|
const deployScripts = await generateDeployScripts(appPath, finalSystemKey, systemFileName, datasourceFileNames);
|
|
133
157
|
|
|
134
158
|
// Generate deployment manifest (<systemKey>-deploy.json) using controller format
|
|
135
|
-
const { generateControllerManifest } = require('./external-controller-manifest');
|
|
159
|
+
const { generateControllerManifest, toDeployJsonShape } = require('./external-controller-manifest');
|
|
136
160
|
const manifest = await generateControllerManifest(appName, { appPath });
|
|
161
|
+
const deployJson = toDeployJsonShape(manifest);
|
|
137
162
|
const deployManifestPath = path.join(appPath, `${finalSystemKey}-deploy.json`);
|
|
138
|
-
await fs.writeFile(deployManifestPath, JSON.stringify(
|
|
163
|
+
await fs.writeFile(deployManifestPath, JSON.stringify(deployJson, null, 2), 'utf8');
|
|
139
164
|
logger.log(chalk.green(`✓ Generated deployment manifest: ${finalSystemKey}-deploy.json`));
|
|
140
165
|
|
|
141
166
|
return {
|
|
@@ -151,24 +176,40 @@ async function prepareWizardContext(appName, systemConfig, datasourceConfigs) {
|
|
|
151
176
|
const appPath = path.join(process.cwd(), 'integration', appName);
|
|
152
177
|
await fs.mkdir(appPath, { recursive: true });
|
|
153
178
|
const finalSystemKey = appName;
|
|
179
|
+
const originalSystemKey = systemConfig.key || finalSystemKey;
|
|
154
180
|
const appDisplayName = appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
155
181
|
const updatedSystemConfig = { ...systemConfig, key: finalSystemKey, displayName: appDisplayName };
|
|
182
|
+
const originalPrefix = `${originalSystemKey}-`;
|
|
156
183
|
const updatedDatasourceConfigs = datasourceConfigs.map(ds => {
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
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}` };
|
|
161
196
|
});
|
|
162
197
|
return { appPath, finalSystemKey, updatedSystemConfig, updatedDatasourceConfigs, appDisplayName };
|
|
163
198
|
}
|
|
164
199
|
|
|
165
200
|
async function generateWizardFiles(appName, systemConfig, datasourceConfigs, systemKey, options = {}) {
|
|
166
201
|
try {
|
|
167
|
-
const { aiGeneratedReadme } = options || {};
|
|
202
|
+
const { aiGeneratedReadme, format } = options || {};
|
|
203
|
+
const fmt = format === 'json' ? 'json' : 'yaml';
|
|
204
|
+
const ext = FORMAT_EXT[fmt] || '.yaml';
|
|
168
205
|
const { appPath, finalSystemKey, updatedSystemConfig, updatedDatasourceConfigs } = await prepareWizardContext(appName, systemConfig, datasourceConfigs);
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
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}`;
|
|
172
213
|
const configFiles = await generateConfigFilesForWizard({
|
|
173
214
|
appPath,
|
|
174
215
|
appName,
|
|
@@ -177,7 +218,8 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
177
218
|
datasourceFileNames,
|
|
178
219
|
systemConfig: updatedSystemConfig,
|
|
179
220
|
datasourceConfigs: updatedDatasourceConfigs,
|
|
180
|
-
aiGeneratedReadme
|
|
221
|
+
aiGeneratedReadme,
|
|
222
|
+
format: fmt
|
|
181
223
|
});
|
|
182
224
|
return {
|
|
183
225
|
appPath,
|
|
@@ -190,22 +232,48 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
190
232
|
}
|
|
191
233
|
}
|
|
192
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
|
+
|
|
193
259
|
/**
|
|
194
|
-
* Generate or update application
|
|
260
|
+
* Generate or update application config with externalIntegration block
|
|
195
261
|
* @async
|
|
196
262
|
* @function generateOrUpdateVariablesYaml
|
|
197
263
|
* @param {Object} params - Parameters object
|
|
198
264
|
* @param {string} params.appPath - Application directory path
|
|
199
265
|
* @param {string} params.appName - Application name
|
|
200
|
-
* @param {string} params.systemKey - System key
|
|
201
266
|
* @param {string} params.systemFileName - System file name
|
|
202
267
|
* @param {string[]} params.datasourceFileNames - Array of datasource file names
|
|
203
268
|
* @param {Object} params.systemConfig - System configuration
|
|
269
|
+
* @param {string} [params.format] - Output format: 'yaml' (default) or 'json'
|
|
204
270
|
* @returns {Promise<string>} Path to application config file
|
|
205
271
|
* @throws {Error} If generation fails
|
|
206
272
|
*/
|
|
207
273
|
async function generateOrUpdateVariablesYaml(params) {
|
|
208
|
-
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';
|
|
209
277
|
let configPath;
|
|
210
278
|
let variables = {};
|
|
211
279
|
try {
|
|
@@ -213,115 +281,88 @@ async function generateOrUpdateVariablesYaml(params) {
|
|
|
213
281
|
configPath = resolveApplicationConfigPath(appPath);
|
|
214
282
|
variables = loadConfigFile(configPath) || {};
|
|
215
283
|
} catch {
|
|
216
|
-
configPath = path.join(appPath,
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Set basic app info if not present
|
|
220
|
-
if (!variables.app) {
|
|
221
|
-
variables.app = {
|
|
222
|
-
key: appName,
|
|
223
|
-
displayName: systemConfig.displayName || appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
|
|
224
|
-
description: systemConfig.description || `External system integration for ${appName}`,
|
|
225
|
-
type: 'external',
|
|
226
|
-
version: '1.0.0'
|
|
227
|
-
};
|
|
228
|
-
} else {
|
|
229
|
-
variables.app.version = variables.app.version || '1.0.0';
|
|
284
|
+
configPath = path.join(appPath, `application${ext}`);
|
|
230
285
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
};
|
|
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);
|
|
238
292
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
variables.externalIntegration = {
|
|
242
|
-
schemaBasePath: './',
|
|
243
|
-
systems: [systemFileName],
|
|
244
|
-
dataSources: datasourceFileNames,
|
|
245
|
-
autopublish: true,
|
|
246
|
-
version: systemConfig.version || '1.0.0'
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
writeConfigFile(configPath, variables);
|
|
250
|
-
logger.log(chalk.green('✓ Generated/updated application.yaml'));
|
|
251
|
-
return configPath;
|
|
293
|
+
logger.log(chalk.green(`✓ Generated/updated application${ext}`));
|
|
294
|
+
return targetPath;
|
|
252
295
|
} catch (error) {
|
|
253
296
|
throw new Error(`Failed to generate application config: ${error.message}`);
|
|
254
297
|
}
|
|
255
298
|
}
|
|
256
299
|
|
|
257
300
|
/**
|
|
258
|
-
* Adds API key authentication lines
|
|
259
|
-
* @function addApiKeyAuthLines
|
|
301
|
+
* Adds API key authentication lines with KV_* convention
|
|
260
302
|
* @param {Array<string>} lines - Lines array to append to
|
|
303
|
+
* @param {string} prefix - KV prefix (e.g. HUBSPOT)
|
|
261
304
|
*/
|
|
262
|
-
function addApiKeyAuthLines(lines) {
|
|
305
|
+
function addApiKeyAuthLines(lines, prefix) {
|
|
263
306
|
lines.push('# API Key Authentication');
|
|
264
|
-
lines.push(
|
|
307
|
+
lines.push(`KV_${prefix}_APIKEY=`);
|
|
265
308
|
lines.push('');
|
|
266
309
|
}
|
|
267
310
|
|
|
268
311
|
/**
|
|
269
|
-
* Adds OAuth2 authentication lines
|
|
270
|
-
* @function addOAuth2AuthLines
|
|
312
|
+
* Adds OAuth2 authentication lines with KV_* convention
|
|
271
313
|
* @param {Array<string>} lines - Lines array to append to
|
|
272
314
|
* @param {Object} auth - Authentication configuration
|
|
315
|
+
* @param {string} prefix - KV prefix
|
|
273
316
|
*/
|
|
274
|
-
function addOAuth2AuthLines(lines, auth) {
|
|
317
|
+
function addOAuth2AuthLines(lines, auth, prefix) {
|
|
275
318
|
lines.push('# OAuth2 Authentication');
|
|
276
|
-
lines.push(
|
|
277
|
-
lines.push(
|
|
278
|
-
lines.push(
|
|
279
|
-
lines.push('TOKEN_URL=kv://secrets/token-url');
|
|
280
|
-
if (auth.scope) {
|
|
281
|
-
lines.push(`SCOPE=${auth.scope}`);
|
|
282
|
-
}
|
|
319
|
+
lines.push(`KV_${prefix}_CLIENTID=`);
|
|
320
|
+
lines.push(`KV_${prefix}_CLIENTSECRET=`);
|
|
321
|
+
if (auth.scope) lines.push(`SCOPE=${auth.scope}`);
|
|
283
322
|
lines.push('');
|
|
284
323
|
}
|
|
285
324
|
|
|
286
325
|
/**
|
|
287
|
-
* Adds bearer token authentication lines
|
|
288
|
-
* @function addBearerTokenAuthLines
|
|
326
|
+
* Adds bearer token authentication lines with KV_* convention
|
|
289
327
|
* @param {Array<string>} lines - Lines array to append to
|
|
328
|
+
* @param {string} prefix - KV prefix
|
|
290
329
|
*/
|
|
291
|
-
function addBearerTokenAuthLines(lines) {
|
|
330
|
+
function addBearerTokenAuthLines(lines, prefix) {
|
|
292
331
|
lines.push('# Bearer Token Authentication');
|
|
293
|
-
lines.push(
|
|
332
|
+
lines.push(`KV_${prefix}_BEARERTOKEN=`);
|
|
294
333
|
lines.push('');
|
|
295
334
|
}
|
|
296
335
|
|
|
297
336
|
/**
|
|
298
|
-
* Adds basic authentication lines
|
|
299
|
-
* @function addBasicAuthLines
|
|
337
|
+
* Adds basic authentication lines with KV_* convention
|
|
300
338
|
* @param {Array<string>} lines - Lines array to append to
|
|
339
|
+
* @param {string} prefix - KV prefix
|
|
301
340
|
*/
|
|
302
|
-
function addBasicAuthLines(lines) {
|
|
341
|
+
function addBasicAuthLines(lines, prefix) {
|
|
303
342
|
lines.push('# Basic Authentication');
|
|
304
|
-
lines.push(
|
|
305
|
-
lines.push(
|
|
343
|
+
lines.push(`KV_${prefix}_USERNAME=`);
|
|
344
|
+
lines.push(`KV_${prefix}_PASSWORD=`);
|
|
306
345
|
lines.push('');
|
|
307
346
|
}
|
|
308
347
|
|
|
309
348
|
/**
|
|
310
|
-
* Adds authentication lines based on auth type
|
|
311
|
-
* @function addAuthenticationLines
|
|
349
|
+
* Adds authentication lines based on auth type. Uses KV_<APPKEY>_<VAR> convention.
|
|
312
350
|
* @param {Array<string>} lines - Lines array to append to
|
|
313
351
|
* @param {Object} auth - Authentication configuration
|
|
314
352
|
* @param {string} authType - Authentication type
|
|
353
|
+
* @param {string} systemKey - System key (e.g. hubspot) for KV_ prefix
|
|
315
354
|
*/
|
|
316
|
-
function addAuthenticationLines(lines, auth, authType) {
|
|
355
|
+
function addAuthenticationLines(lines, auth, authType, systemKey) {
|
|
356
|
+
const prefix = systemKeyToKvPrefix(systemKey);
|
|
357
|
+
if (!prefix) return;
|
|
317
358
|
if (authType === 'apikey' || authType === 'apiKey') {
|
|
318
|
-
addApiKeyAuthLines(lines);
|
|
359
|
+
addApiKeyAuthLines(lines, prefix);
|
|
319
360
|
} else if (authType === 'oauth2' || authType === 'oauth') {
|
|
320
|
-
addOAuth2AuthLines(lines, auth);
|
|
361
|
+
addOAuth2AuthLines(lines, auth || {}, prefix);
|
|
321
362
|
} else if (authType === 'bearer' || authType === 'token') {
|
|
322
|
-
addBearerTokenAuthLines(lines);
|
|
363
|
+
addBearerTokenAuthLines(lines, prefix);
|
|
323
364
|
} else if (authType === 'basic') {
|
|
324
|
-
addBasicAuthLines(lines);
|
|
365
|
+
addBasicAuthLines(lines, prefix);
|
|
325
366
|
}
|
|
326
367
|
}
|
|
327
368
|
|
|
@@ -340,23 +381,24 @@ function addBaseUrlLines(lines, systemConfig) {
|
|
|
340
381
|
}
|
|
341
382
|
|
|
342
383
|
/**
|
|
343
|
-
* Generate env.template with authentication variables
|
|
384
|
+
* Generate env.template with KV_* authentication variables
|
|
344
385
|
* @async
|
|
345
386
|
* @function generateEnvTemplate
|
|
346
387
|
* @param {string} appPath - Application directory path
|
|
347
|
-
* @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)
|
|
348
390
|
* @throws {Error} If generation fails
|
|
349
391
|
*/
|
|
350
|
-
async function generateEnvTemplate(appPath, systemConfig) {
|
|
392
|
+
async function generateEnvTemplate(appPath, systemConfig, finalSystemKey) {
|
|
351
393
|
try {
|
|
352
394
|
const envTemplatePath = path.join(appPath, 'env.template');
|
|
353
|
-
const
|
|
395
|
+
const systemKey = finalSystemKey || systemConfig?.key;
|
|
396
|
+
const lines = ['# Environment variables for external system integration', '# Use KV_* for credential push (aifabrix credential push)', ''];
|
|
354
397
|
|
|
355
|
-
|
|
356
|
-
const auth = systemConfig.authentication || systemConfig.auth || {};
|
|
398
|
+
const auth = systemConfig?.authentication || systemConfig?.auth || {};
|
|
357
399
|
const authType = auth.type || auth.authType || 'apikey';
|
|
358
400
|
|
|
359
|
-
addAuthenticationLines(lines, auth, authType);
|
|
401
|
+
addAuthenticationLines(lines, auth, authType, systemKey);
|
|
360
402
|
addBaseUrlLines(lines, systemConfig);
|
|
361
403
|
|
|
362
404
|
await fs.writeFile(envTemplatePath, lines.join('\n'), 'utf8');
|
|
@@ -401,59 +443,6 @@ async function generateDeployScripts(appPath, systemKey, systemFileName, datasou
|
|
|
401
443
|
}
|
|
402
444
|
}
|
|
403
445
|
|
|
404
|
-
/**
|
|
405
|
-
* Generate README.md with basic documentation
|
|
406
|
-
* @async
|
|
407
|
-
* @function generateReadme
|
|
408
|
-
* @param {string} appPath - Application directory path
|
|
409
|
-
* @param {string} appName - Application name
|
|
410
|
-
* @param {string} systemKey - System key
|
|
411
|
-
* @param {Object} systemConfig - System configuration
|
|
412
|
-
* @param {Object[]} datasourceConfigs - Array of datasource configurations
|
|
413
|
-
* @param {string} [aiGeneratedContent] - Optional AI-generated README content from dataplane
|
|
414
|
-
* @throws {Error} If generation fails
|
|
415
|
-
*/
|
|
416
|
-
async function generateReadme(appPath, appName, systemKey, systemConfig, datasourceConfigs, aiGeneratedContent) {
|
|
417
|
-
try {
|
|
418
|
-
const readmePath = path.join(appPath, 'README.md');
|
|
419
|
-
|
|
420
|
-
// Use AI-generated content if available, otherwise generate basic README
|
|
421
|
-
if (aiGeneratedContent) {
|
|
422
|
-
await fs.writeFile(readmePath, aiGeneratedContent, 'utf8');
|
|
423
|
-
logger.log(chalk.green('✓ Generated README.md (AI-generated from dataplane)'));
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const datasources = (Array.isArray(datasourceConfigs) ? datasourceConfigs : []).map((ds, index) => {
|
|
428
|
-
const entityType = ds.entityType || ds.entityKey || ds.key?.split('-').pop() || `datasource${index + 1}`;
|
|
429
|
-
const keySegment = toKeySegment(entityType);
|
|
430
|
-
const datasourceKey = ds.key || `${systemKey}-${keySegment}`;
|
|
431
|
-
const datasourceKeyOnly = datasourceKey.includes('-') && datasourceKey.startsWith(`${systemKey}-`)
|
|
432
|
-
? datasourceKey.substring(systemKey.length + 1)
|
|
433
|
-
: keySegment;
|
|
434
|
-
return {
|
|
435
|
-
entityType,
|
|
436
|
-
displayName: ds.displayName || ds.name || ds.key || `Datasource ${index + 1}`,
|
|
437
|
-
fileName: `${systemKey}-datasource-${datasourceKeyOnly}.yaml`
|
|
438
|
-
};
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
const readmeContent = generateExternalReadmeContent({
|
|
442
|
-
appName,
|
|
443
|
-
systemKey,
|
|
444
|
-
systemType: systemConfig.type || systemConfig.systemType,
|
|
445
|
-
displayName: systemConfig.displayName,
|
|
446
|
-
description: systemConfig.description,
|
|
447
|
-
datasources
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
await fs.writeFile(readmePath, readmeContent, 'utf8');
|
|
451
|
-
logger.log(chalk.green('✓ Generated README.md (template)'));
|
|
452
|
-
} catch (error) {
|
|
453
|
-
throw new Error(`Failed to generate README.md: ${error.message}`);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
446
|
module.exports = {
|
|
458
447
|
generateWizardFiles,
|
|
459
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);
|
|
@@ -89,7 +89,7 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
|
89
89
|
*/
|
|
90
90
|
async function startInfra(developerId = null, options = {}) {
|
|
91
91
|
const { devId, idNum, ports, templatePath, infraDir } = await prepareInfrastructureEnvironment(developerId, options);
|
|
92
|
-
const { traefik = false } = options;
|
|
92
|
+
const { traefik = false, pgadmin = true, redisCommander = true } = options;
|
|
93
93
|
const traefikConfig = buildTraefikConfig(traefik);
|
|
94
94
|
const validation = validateTraefikConfig(traefikConfig);
|
|
95
95
|
if (!validation.valid) {
|
|
@@ -100,10 +100,18 @@ async function startInfra(developerId = null, options = {}) {
|
|
|
100
100
|
registerHandlebarsHelper();
|
|
101
101
|
|
|
102
102
|
// Generate compose file
|
|
103
|
-
const composePath = generateComposeFile(templatePath, devId, idNum, ports, infraDir, {
|
|
103
|
+
const composePath = generateComposeFile(templatePath, devId, idNum, ports, infraDir, {
|
|
104
|
+
traefik: traefikConfig,
|
|
105
|
+
pgadmin: { enabled: !!pgadmin },
|
|
106
|
+
redisCommander: { enabled: !!redisCommander }
|
|
107
|
+
});
|
|
104
108
|
|
|
105
109
|
try {
|
|
106
|
-
await startDockerServicesAndConfigure(composePath, devId, idNum, infraDir
|
|
110
|
+
await startDockerServicesAndConfigure(composePath, devId, idNum, infraDir, {
|
|
111
|
+
pgadmin: !!pgadmin,
|
|
112
|
+
redisCommander: !!redisCommander,
|
|
113
|
+
traefik: !!traefik
|
|
114
|
+
});
|
|
107
115
|
} finally {
|
|
108
116
|
// Keep the compose file for stop commands
|
|
109
117
|
}
|
|
@@ -123,7 +123,7 @@ function cleanupRunFiles(runEnvPath, pgpassRunPath) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* Starts Docker services and configures pgAdmin.
|
|
126
|
+
* Starts Docker services and configures pgAdmin (when enabled).
|
|
127
127
|
* Writes decrypted admin secrets to a temporary .env in infra dir, runs compose, then deletes the file (ISO 27K).
|
|
128
128
|
*
|
|
129
129
|
* @async
|
|
@@ -132,11 +132,13 @@ function cleanupRunFiles(runEnvPath, pgpassRunPath) {
|
|
|
132
132
|
* @param {string} devId - Developer ID
|
|
133
133
|
* @param {number} idNum - Developer ID number
|
|
134
134
|
* @param {string} infraDir - Infrastructure directory
|
|
135
|
+
* @param {Object} [opts] - Options (pgadmin, redisCommander, traefik)
|
|
135
136
|
*/
|
|
136
|
-
async function startDockerServicesAndConfigure(composePath, devId, idNum, infraDir) {
|
|
137
|
+
async function startDockerServicesAndConfigure(composePath, devId, idNum, infraDir, opts = {}) {
|
|
137
138
|
let runEnvPath;
|
|
138
139
|
let pgpassRunPath;
|
|
139
140
|
let adminObj;
|
|
141
|
+
const { pgadmin = true, redisCommander = true, traefik = false } = opts;
|
|
140
142
|
try {
|
|
141
143
|
({ adminObj, runEnvPath } = await prepareRunEnv(infraDir));
|
|
142
144
|
} catch (err) {
|
|
@@ -146,8 +148,10 @@ async function startDockerServicesAndConfigure(composePath, devId, idNum, infraD
|
|
|
146
148
|
try {
|
|
147
149
|
const projectName = getInfraProjectName(devId);
|
|
148
150
|
await startDockerServices(composePath, projectName, runEnvPath, infraDir);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
if (pgadmin) {
|
|
152
|
+
pgpassRunPath = await writePgpassAndCopyPgAdminConfig(infraDir, adminObj, devId, idNum);
|
|
153
|
+
}
|
|
154
|
+
await waitForServices(devId, { pgadmin, redisCommander, traefik });
|
|
151
155
|
logger.log('All services are healthy and ready');
|
|
152
156
|
} finally {
|
|
153
157
|
cleanupRunFiles(runEnvPath, pgpassRunPath);
|
|
@@ -157,14 +161,16 @@ async function startDockerServicesAndConfigure(composePath, devId, idNum, infraD
|
|
|
157
161
|
/**
|
|
158
162
|
* Waits for services to be healthy
|
|
159
163
|
* @private
|
|
160
|
-
* @param {number} [devId] - Developer ID (optional, will be loaded from config if not provided)
|
|
164
|
+
* @param {number|string|null} [devId] - Developer ID (optional, will be loaded from config if not provided)
|
|
165
|
+
* @param {Object} [opts] - Options (pgadmin, redisCommander, traefik) - which optional services to expect
|
|
161
166
|
*/
|
|
162
|
-
async function waitForServices(devId = null) {
|
|
167
|
+
async function waitForServices(devId = null, opts = {}) {
|
|
163
168
|
const maxAttempts = 30;
|
|
164
169
|
const delay = 2000; // 2 seconds
|
|
170
|
+
const { pgadmin = true, redisCommander = true, traefik = false } = opts;
|
|
165
171
|
|
|
166
172
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
167
|
-
const health = await checkInfraHealth(devId);
|
|
173
|
+
const health = await checkInfraHealth(devId, { pgadmin, redisCommander, traefik });
|
|
168
174
|
const allHealthy = Object.values(health).every(status => status === 'healthy');
|
|
169
175
|
|
|
170
176
|
if (allHealthy) {
|
|
@@ -182,15 +188,17 @@ async function waitForServices(devId = null) {
|
|
|
182
188
|
|
|
183
189
|
/**
|
|
184
190
|
* Checks if infrastructure services are running
|
|
185
|
-
* Validates that all
|
|
191
|
+
* Validates that all expected services are healthy and accessible
|
|
186
192
|
*
|
|
187
193
|
* @async
|
|
188
194
|
* @function checkInfraHealth
|
|
189
195
|
* @param {number|string|null} [devId] - Developer ID (null = use current)
|
|
190
196
|
* @param {Object} [options] - Options
|
|
191
197
|
* @param {boolean} [options.strict=false] - When true, only consider current dev's containers (no fallback to dev 0); use for up-miso and status consistency
|
|
198
|
+
* @param {boolean} [options.pgadmin=true] - Include pgAdmin in health check
|
|
199
|
+
* @param {boolean} [options.redisCommander=true] - Include Redis Commander in health check
|
|
200
|
+
* @param {boolean} [options.traefik=false] - Include Traefik in health check
|
|
192
201
|
* @returns {Promise<Object>} Health status of each service
|
|
193
|
-
* @throws {Error} If health check fails
|
|
194
202
|
*
|
|
195
203
|
* @example
|
|
196
204
|
* const health = await checkInfraHealth();
|
|
@@ -199,7 +207,10 @@ async function waitForServices(devId = null) {
|
|
|
199
207
|
async function checkInfraHealth(devId = null, options = {}) {
|
|
200
208
|
const developerId = devId || await config.getDeveloperId();
|
|
201
209
|
const servicesWithHealthCheck = ['postgres', 'redis'];
|
|
202
|
-
const servicesWithoutHealthCheck = [
|
|
210
|
+
const servicesWithoutHealthCheck = [];
|
|
211
|
+
if (options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
|
|
212
|
+
if (options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
|
|
213
|
+
if (options.traefik === true) servicesWithoutHealthCheck.push('traefik');
|
|
203
214
|
const health = {};
|
|
204
215
|
const lookupOptions = options.strict ? { strict: true } : {};
|
|
205
216
|
|
|
@@ -208,7 +219,7 @@ async function checkInfraHealth(devId = null, options = {}) {
|
|
|
208
219
|
health[service] = await containerUtils.checkServiceWithHealthCheck(service, developerId, lookupOptions);
|
|
209
220
|
}
|
|
210
221
|
|
|
211
|
-
// Check if services without health checks are running
|
|
222
|
+
// Check if optional services without health checks are running
|
|
212
223
|
for (const service of servicesWithoutHealthCheck) {
|
|
213
224
|
health[service] = await containerUtils.checkServiceWithoutHealthCheck(service, developerId, lookupOptions);
|
|
214
225
|
}
|