@aifabrix/builder 2.41.0 → 2.42.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/.cursor/rules/docs-rules.mdc +30 -0
- package/README.md +2 -2
- package/integration/hubspot/README.md +11 -5
- 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 +36 -2
- package/lib/app/config.js +23 -11
- package/lib/app/index.js +5 -3
- package/lib/app/prompts.js +46 -31
- package/lib/app/readme.js +11 -4
- 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 +45 -14
- 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/auth-config.js +22 -12
- 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 +518 -0
- package/lib/commands/secrets-set.js +6 -0
- package/lib/commands/test-e2e-external.js +165 -0
- package/lib/commands/up-dataplane.js +90 -6
- package/lib/commands/upload.js +71 -40
- package/lib/commands/wizard-core-helpers.js +230 -5
- package/lib/commands/wizard-core.js +68 -29
- package/lib/commands/wizard-dataplane.js +1 -1
- package/lib/commands/wizard-entity-selection.js +43 -0
- package/lib/commands/wizard-headless.js +49 -5
- package/lib/commands/wizard-helpers.js +7 -3
- package/lib/commands/wizard.js +93 -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-helpers.js +3 -1
- 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 +4 -2
- 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 +326 -0
- package/lib/generator/wizard-prompts.js +105 -106
- package/lib/generator/wizard-readme.js +91 -0
- package/lib/generator/wizard.js +180 -179
- 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 +23 -1
- 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 +89 -30
- 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 +75 -22
- 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
|
@@ -3,19 +3,21 @@
|
|
|
3
3
|
* @author AI Fabrix Team
|
|
4
4
|
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
|
+
/* eslint-disable max-lines */
|
|
6
7
|
|
|
7
8
|
const chalk = require('chalk');
|
|
8
9
|
const ora = require('ora');
|
|
9
10
|
const path = require('path');
|
|
10
11
|
const fs = require('fs').promises;
|
|
11
12
|
const logger = require('../utils/logger');
|
|
12
|
-
const { getDeploymentAuth } = require('../utils/token-manager');
|
|
13
|
+
const { getDeploymentAuth, requireBearerForDataplanePipeline } = require('../utils/token-manager');
|
|
13
14
|
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
14
15
|
const { normalizeWizardConfigs } = require('./wizard-config-normalizer');
|
|
15
16
|
const {
|
|
16
17
|
createWizardSession,
|
|
17
18
|
updateWizardSession,
|
|
18
19
|
detectType,
|
|
20
|
+
getPlatformConfig,
|
|
19
21
|
generateConfig,
|
|
20
22
|
validateWizardConfig,
|
|
21
23
|
getDeploymentDocs,
|
|
@@ -29,9 +31,17 @@ const {
|
|
|
29
31
|
runCredentialSelectionLoop,
|
|
30
32
|
buildConfigPreferences,
|
|
31
33
|
buildConfigPayload,
|
|
34
|
+
buildPlatformConfigPayload,
|
|
32
35
|
extractConfigurationFromResponse,
|
|
33
|
-
|
|
36
|
+
writeDebugLog,
|
|
37
|
+
saveDebugManifestOnErrorAndThrow,
|
|
38
|
+
throwValidationFailureWithDebug,
|
|
39
|
+
resolveCredentialConfig,
|
|
40
|
+
fetchSystemsListForAddDatasource,
|
|
41
|
+
resolveExternalSystemForAddDatasource
|
|
34
42
|
} = require('./wizard-core-helpers');
|
|
43
|
+
const { validateDatasourceKeysBeforePlatformConfig } = require('../validation/validate-datasource-keys-api');
|
|
44
|
+
const { handleEntitySelection } = require('./wizard-entity-selection');
|
|
35
45
|
|
|
36
46
|
/**
|
|
37
47
|
* Validate app name and check if directory exists
|
|
@@ -263,35 +273,57 @@ async function handleTypeDetection(dataplaneUrl, authConfig, openapiSpec) {
|
|
|
263
273
|
* @param {Object} [options.configPrefs] - Preferences from wizard.yaml
|
|
264
274
|
* @param {string} [options.credentialIdOrKey] - Credential ID or key (optional)
|
|
265
275
|
* @param {string} [options.systemIdOrKey] - System ID or key (optional)
|
|
276
|
+
* @param {string} [options.sourceType] - Source type (use 'known-platform' to call platforms config endpoint)
|
|
277
|
+
* @param {string} [options.platformKey] - Platform key for known-platform (e.g. 'hubspot')
|
|
278
|
+
* @param {string} [options.appName] - App name for writing debug.log when debug=true
|
|
266
279
|
* @returns {Promise<Object>} Generated configuration
|
|
267
280
|
*/
|
|
281
|
+
async function callGenerateApi(dataplaneUrl, authConfig, options, prefs) {
|
|
282
|
+
if (options.sourceType === 'known-platform' && options.platformKey) {
|
|
283
|
+
await validateDatasourceKeysBeforePlatformConfig(
|
|
284
|
+
dataplaneUrl, authConfig, options.platformKey, options.datasourceKeys
|
|
285
|
+
);
|
|
286
|
+
const platformPayload = buildPlatformConfigPayload({
|
|
287
|
+
credentialIdOrKey: options.credentialIdOrKey,
|
|
288
|
+
datasourceKeys: options.datasourceKeys,
|
|
289
|
+
configurationValues: options.configurationValues,
|
|
290
|
+
debug: prefs.debug
|
|
291
|
+
});
|
|
292
|
+
return await getPlatformConfig(dataplaneUrl, authConfig, options.platformKey, platformPayload);
|
|
293
|
+
}
|
|
294
|
+
const configPayload = buildConfigPayload({
|
|
295
|
+
openapiSpec: options.openapiSpec,
|
|
296
|
+
detectedType: options.detectedType,
|
|
297
|
+
mode: options.mode,
|
|
298
|
+
prefs,
|
|
299
|
+
credentialIdOrKey: options.credentialIdOrKey,
|
|
300
|
+
systemIdOrKey: options.systemIdOrKey,
|
|
301
|
+
entityName: options.entityName,
|
|
302
|
+
systemDisplayName: options.systemDisplayName
|
|
303
|
+
});
|
|
304
|
+
return await generateConfig(dataplaneUrl, authConfig, configPayload);
|
|
305
|
+
}
|
|
268
306
|
|
|
269
307
|
async function handleConfigurationGeneration(dataplaneUrl, authConfig, options) {
|
|
270
308
|
logger.log(chalk.blue('\n\uD83D\uDCCB Step 5: Generate Configuration'));
|
|
271
309
|
const prefs = buildConfigPreferences(options.configPrefs);
|
|
272
310
|
const spinner = ora('Generating configuration via AI (10-30 seconds)...').start();
|
|
273
311
|
try {
|
|
274
|
-
const
|
|
275
|
-
openapiSpec: options.openapiSpec,
|
|
276
|
-
detectedType: options.detectedType,
|
|
277
|
-
mode: options.mode,
|
|
278
|
-
prefs,
|
|
279
|
-
credentialIdOrKey: options.credentialIdOrKey,
|
|
280
|
-
systemIdOrKey: options.systemIdOrKey
|
|
281
|
-
});
|
|
282
|
-
const generateResponse = await generateConfig(dataplaneUrl, authConfig, configPayload);
|
|
312
|
+
const generateResponse = await callGenerateApi(dataplaneUrl, authConfig, options, prefs);
|
|
283
313
|
spinner.stop();
|
|
284
314
|
if (!generateResponse.success) {
|
|
285
|
-
|
|
315
|
+
await saveDebugManifestOnErrorAndThrow(generateResponse, { enableDebug: prefs.debug, appName: options.appName });
|
|
286
316
|
}
|
|
287
317
|
const result = extractConfigurationFromResponse(generateResponse);
|
|
288
318
|
const normalized = normalizeWizardConfigs(result.systemConfig, result.datasourceConfigs);
|
|
319
|
+
if (prefs.debug && options.appName) {
|
|
320
|
+
const debugLog = generateResponse.data?.debugLog;
|
|
321
|
+
if (debugLog && typeof debugLog === 'string') {
|
|
322
|
+
await writeDebugLog(options.appName, debugLog);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
289
325
|
logger.log(chalk.green('\u2713 Configuration generated successfully'));
|
|
290
|
-
return {
|
|
291
|
-
systemConfig: normalized.systemConfig,
|
|
292
|
-
datasourceConfigs: normalized.datasourceConfigs,
|
|
293
|
-
systemKey: result.systemKey
|
|
294
|
-
};
|
|
326
|
+
return { systemConfig: normalized.systemConfig, datasourceConfigs: normalized.datasourceConfigs, systemKey: result.systemKey };
|
|
295
327
|
} catch (error) {
|
|
296
328
|
spinner.stop();
|
|
297
329
|
throw error;
|
|
@@ -306,9 +338,11 @@ async function handleConfigurationGeneration(dataplaneUrl, authConfig, options)
|
|
|
306
338
|
* @param {Object} authConfig - Authentication configuration
|
|
307
339
|
* @param {Object} systemConfig - System configuration
|
|
308
340
|
* @param {Object[]} datasourceConfigs - Datasource configurations
|
|
341
|
+
* @param {Object} [options] - Optional options
|
|
342
|
+
* @param {boolean} [options.debug] - When true, save debug manifest on validation failure
|
|
343
|
+
* @param {string} [options.appName] - App name for writing debug files
|
|
309
344
|
*/
|
|
310
|
-
|
|
311
|
-
async function validateWizardConfiguration(dataplaneUrl, authConfig, systemConfig, datasourceConfigs) {
|
|
345
|
+
async function validateWizardConfiguration(dataplaneUrl, authConfig, systemConfig, datasourceConfigs, options = {}) {
|
|
312
346
|
logger.log(chalk.blue('\n\uD83D\uDCCB Step 6: Validate Configuration'));
|
|
313
347
|
const spinner = ora('Validating configuration...').start();
|
|
314
348
|
try {
|
|
@@ -322,16 +356,13 @@ async function validateWizardConfiguration(dataplaneUrl, authConfig, systemConfi
|
|
|
322
356
|
const errorDetail = validateResponse.errorData?.detail || validateResponse.errorData?.message;
|
|
323
357
|
const errorMsg = errors.length > 0 ? errors.map(e => e.message || e).join(', ') : errorDetail || validateResponse.error || 'Validation failed';
|
|
324
358
|
spinner.stop();
|
|
325
|
-
|
|
359
|
+
await throwValidationFailureWithDebug(validateResponse, systemConfig, configs, errorMsg, options);
|
|
326
360
|
}
|
|
327
361
|
if (validateResponse.data?.warnings?.length > 0) warnings.push(...validateResponse.data.warnings);
|
|
328
362
|
}
|
|
329
363
|
spinner.stop();
|
|
330
364
|
logger.log(chalk.green('\u2713 Configuration validated successfully'));
|
|
331
|
-
if (warnings.length > 0) {
|
|
332
|
-
logger.log(chalk.yellow('\n\u26A0 Warnings:'));
|
|
333
|
-
warnings.forEach(w => logger.log(chalk.yellow(` - ${w.message || w}`)));
|
|
334
|
-
}
|
|
365
|
+
if (warnings.length > 0) logger.log(chalk.yellow('\n\u26A0 Warnings:\n' + warnings.map(w => ` - ${w.message || w}`).join('\n')));
|
|
335
366
|
} catch (error) {
|
|
336
367
|
spinner.stop();
|
|
337
368
|
throw error;
|
|
@@ -370,7 +401,9 @@ async function tryUpdateReadmeFromDeploymentDocs(appPath, appName, dataplaneUrl,
|
|
|
370
401
|
? await postDeploymentDocs(dataplaneUrl, authConfig, systemKey, body)
|
|
371
402
|
: await getDeploymentDocs(dataplaneUrl, authConfig, systemKey);
|
|
372
403
|
const content = docsResponse?.data?.content ?? docsResponse?.content;
|
|
373
|
-
|
|
404
|
+
// Only overwrite README when the API returns substantial content; otherwise keep the template README
|
|
405
|
+
const MIN_README_LENGTH = 400;
|
|
406
|
+
if (content && typeof content === 'string' && content.trim().length >= MIN_README_LENGTH) {
|
|
374
407
|
const readmePath = path.join(appPath, 'README.md');
|
|
375
408
|
await fs.writeFile(readmePath, content, 'utf8');
|
|
376
409
|
logger.log(chalk.gray(' Updated README.md from deployment-docs API (application config + deploy JSON).'));
|
|
@@ -393,7 +426,9 @@ async function handleFileSaving(appName, systemConfig, datasourceConfigs, system
|
|
|
393
426
|
logger.log(chalk.blue('\n\uD83D\uDCCB Step 7: Save Files'));
|
|
394
427
|
const spinner = ora('Saving files...').start();
|
|
395
428
|
try {
|
|
396
|
-
const
|
|
429
|
+
const config = require('../core/config');
|
|
430
|
+
const format = (await config.getFormat()) || 'yaml';
|
|
431
|
+
const generatedFiles = await generateWizardFiles(appName, systemConfig, datasourceConfigs, systemKey, { aiGeneratedReadme: null, format });
|
|
397
432
|
if (systemKey && dataplaneUrl && authConfig && generatedFiles.appPath) {
|
|
398
433
|
try {
|
|
399
434
|
await tryUpdateReadmeFromDeploymentDocs(generatedFiles.appPath, appName, dataplaneUrl, authConfig, systemKey);
|
|
@@ -427,14 +462,14 @@ async function setupDataplaneAndAuth(options, appName) {
|
|
|
427
462
|
const { resolveEnvironment } = require('../core/config');
|
|
428
463
|
const environment = await resolveEnvironment();
|
|
429
464
|
const controllerUrl = await resolveControllerUrl();
|
|
430
|
-
//
|
|
431
|
-
// Some dataplanes accept only client credentials; getDeploymentAuth tries all.
|
|
465
|
+
// getDeploymentAuth returns token-based auth only (Bearer); never client-credentials for app endpoints.
|
|
432
466
|
let authConfig;
|
|
433
467
|
try {
|
|
434
468
|
authConfig = await getDeploymentAuth(controllerUrl, environment, appName);
|
|
435
469
|
} catch (error) {
|
|
436
470
|
throw new Error(`Authentication failed: ${error.message}`);
|
|
437
471
|
}
|
|
472
|
+
requireBearerForDataplanePipeline(authConfig);
|
|
438
473
|
const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
|
|
439
474
|
let dataplaneUrl;
|
|
440
475
|
try {
|
|
@@ -459,8 +494,12 @@ module.exports = {
|
|
|
459
494
|
handleOpenApiParsing,
|
|
460
495
|
handleCredentialSelection,
|
|
461
496
|
handleTypeDetection,
|
|
497
|
+
handleEntitySelection,
|
|
462
498
|
handleConfigurationGeneration,
|
|
463
499
|
validateWizardConfiguration,
|
|
464
500
|
handleFileSaving,
|
|
465
|
-
setupDataplaneAndAuth
|
|
501
|
+
setupDataplaneAndAuth,
|
|
502
|
+
resolveCredentialConfig,
|
|
503
|
+
fetchSystemsListForAddDatasource,
|
|
504
|
+
resolveExternalSystemForAddDatasource
|
|
466
505
|
};
|
|
@@ -59,7 +59,7 @@ function isNotFoundError(error) {
|
|
|
59
59
|
function createDataplaneNotFoundError() {
|
|
60
60
|
return new Error(
|
|
61
61
|
'Could not discover dataplane URL from controller. No dataplane service application found in this environment. ' +
|
|
62
|
-
'
|
|
62
|
+
'Ensure the dataplane service is registered in the controller.'
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Entity selection step for OpenAPI multi-entity wizard flow
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const logger = require('../utils/logger');
|
|
9
|
+
const { discoverEntities } = require('../api/wizard.api');
|
|
10
|
+
const { validateEntityNameForOpenApi } = require('../validation/wizard-datasource-validation');
|
|
11
|
+
const { promptForEntitySelection } = require('../generator/wizard-prompts');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Handle entity selection step (OpenAPI multi-entity).
|
|
15
|
+
* Calls discover-entities; if entities found, prompts user to select one.
|
|
16
|
+
* @async
|
|
17
|
+
* @param {string} dataplaneUrl - Dataplane URL
|
|
18
|
+
* @param {Object} authConfig - Authentication configuration
|
|
19
|
+
* @param {Object} openapiSpec - OpenAPI specification
|
|
20
|
+
* @returns {Promise<string|null>} Selected entity name or null (skip)
|
|
21
|
+
*/
|
|
22
|
+
async function handleEntitySelection(dataplaneUrl, authConfig, openapiSpec) {
|
|
23
|
+
if (!openapiSpec || typeof openapiSpec !== 'object') return null;
|
|
24
|
+
try {
|
|
25
|
+
const response = await discoverEntities(dataplaneUrl, authConfig, openapiSpec);
|
|
26
|
+
const entities = response?.data?.entities;
|
|
27
|
+
if (!Array.isArray(entities) || entities.length === 0) return null;
|
|
28
|
+
|
|
29
|
+
logger.log(chalk.blue('\n\uD83D\uDCCB Step 4.5: Select Entity'));
|
|
30
|
+
const entityName = await promptForEntitySelection(entities);
|
|
31
|
+
const validation = validateEntityNameForOpenApi(entityName, entities);
|
|
32
|
+
if (!validation.valid) {
|
|
33
|
+
throw new Error(`Invalid entity '${entityName}'. Available: ${entities.map(e => e.name).join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
logger.log(chalk.green(`\u2713 Selected entity: ${entityName}`));
|
|
36
|
+
return entityName;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.log(chalk.yellow(`Warning: Entity discovery failed, using default: ${error.message}`));
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { handleEntitySelection };
|
|
@@ -22,6 +22,30 @@ const {
|
|
|
22
22
|
handleFileSaving,
|
|
23
23
|
setupDataplaneAndAuth
|
|
24
24
|
} = require('./wizard-core');
|
|
25
|
+
const { discoverEntities } = require('../api/wizard.api');
|
|
26
|
+
const { validateEntityNameForOpenApi } = require('../validation/wizard-datasource-validation');
|
|
27
|
+
const { humanizeAppKey } = require('../generator/wizard-prompts-secondary');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Validate entityName for headless config (throws if invalid)
|
|
31
|
+
* @async
|
|
32
|
+
* @param {string} entityName - Entity from source
|
|
33
|
+
* @param {Object} openapiSpec - OpenAPI spec
|
|
34
|
+
* @param {string} sourceType - Source type
|
|
35
|
+
* @param {string} dataplaneUrl - Dataplane URL
|
|
36
|
+
* @param {Object} authConfig - Auth config
|
|
37
|
+
* @throws {Error} If entityName invalid
|
|
38
|
+
*/
|
|
39
|
+
async function validateHeadlessEntityName(entityName, openapiSpec, sourceType, dataplaneUrl, authConfig) {
|
|
40
|
+
if (!entityName || !openapiSpec || sourceType === 'known-platform') return;
|
|
41
|
+
const discoverResponse = await discoverEntities(dataplaneUrl, authConfig, openapiSpec);
|
|
42
|
+
const entities = discoverResponse?.data?.entities || [];
|
|
43
|
+
const validation = validateEntityNameForOpenApi(entityName, entities);
|
|
44
|
+
if (!validation.valid) {
|
|
45
|
+
const available = entities.map(e => e.name).join(', ');
|
|
46
|
+
throw new Error(`Invalid entityName '${entityName}'. Available from discover-entities: ${available || 'none'}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
25
49
|
|
|
26
50
|
/**
|
|
27
51
|
* Execute wizard flow from config file (headless mode)
|
|
@@ -30,11 +54,15 @@ const {
|
|
|
30
54
|
* @param {Object} wizardConfig - Validated wizard configuration
|
|
31
55
|
* @param {string} dataplaneUrl - Dataplane URL
|
|
32
56
|
* @param {Object} authConfig - Authentication configuration
|
|
57
|
+
* @param {Object} [opts] - Optional overrides
|
|
58
|
+
* @param {boolean} [opts.debug] - Enable debug (CLI --debug); overrides wizard.yaml preferences.debug
|
|
33
59
|
* @returns {Promise<void>} Resolves when wizard flow completes
|
|
34
60
|
* @throws {Error} If wizard flow fails
|
|
35
61
|
*/
|
|
36
|
-
async function executeWizardFromConfig(wizardConfig, dataplaneUrl, authConfig) {
|
|
62
|
+
async function executeWizardFromConfig(wizardConfig, dataplaneUrl, authConfig, opts = {}) {
|
|
37
63
|
const { appName, mode, systemIdOrKey, source, credential, preferences } = wizardConfig;
|
|
64
|
+
const configPrefs = { ...preferences };
|
|
65
|
+
if (opts.debug === true) configPrefs.debug = true;
|
|
38
66
|
|
|
39
67
|
// Step 1: Create Session
|
|
40
68
|
const { sessionId } = await handleModeSelection(dataplaneUrl, authConfig, mode, systemIdOrKey);
|
|
@@ -51,18 +79,31 @@ async function executeWizardFromConfig(wizardConfig, dataplaneUrl, authConfig) {
|
|
|
51
79
|
// Step 4: Detect Type
|
|
52
80
|
const detectedType = await handleTypeDetection(dataplaneUrl, authConfig, openapiSpec);
|
|
53
81
|
|
|
82
|
+
await validateHeadlessEntityName(source?.entityName, openapiSpec, sourceType, dataplaneUrl, authConfig);
|
|
83
|
+
|
|
84
|
+
const systemDisplayName = wizardConfig.systemDisplayName ||
|
|
85
|
+
(mode === 'create-system' ? humanizeAppKey(appName) : undefined);
|
|
86
|
+
|
|
54
87
|
// Step 5: Generate Configuration
|
|
55
88
|
const { systemConfig, datasourceConfigs, systemKey } = await handleConfigurationGeneration(dataplaneUrl, authConfig, {
|
|
56
89
|
mode,
|
|
57
90
|
openapiSpec,
|
|
58
91
|
detectedType,
|
|
59
|
-
configPrefs
|
|
92
|
+
configPrefs,
|
|
60
93
|
credentialIdOrKey,
|
|
61
|
-
systemIdOrKey
|
|
94
|
+
systemIdOrKey,
|
|
95
|
+
sourceType,
|
|
96
|
+
platformKey: sourceType === 'known-platform' ? sourceData : undefined,
|
|
97
|
+
datasourceKeys: source?.datasourceKeys,
|
|
98
|
+
configurationValues: source?.configurationValues,
|
|
99
|
+
entityName: source?.entityName,
|
|
100
|
+
appName,
|
|
101
|
+
systemDisplayName
|
|
62
102
|
});
|
|
63
103
|
|
|
64
104
|
// Step 6: Validate Configuration
|
|
65
|
-
|
|
105
|
+
const debugOpts = opts.debug ? { debug: true, appName } : {};
|
|
106
|
+
await validateWizardConfiguration(dataplaneUrl, authConfig, systemConfig, datasourceConfigs, debugOpts);
|
|
66
107
|
|
|
67
108
|
// Step 7: Save Files
|
|
68
109
|
await handleFileSaving(
|
|
@@ -87,6 +128,9 @@ async function executeWizardFromConfig(wizardConfig, dataplaneUrl, authConfig) {
|
|
|
87
128
|
async function handleWizardHeadless(options) {
|
|
88
129
|
logger.log(chalk.blue('\n\uD83E\uDDD9 AI Fabrix External System Wizard (Headless Mode)\n'));
|
|
89
130
|
logger.log(chalk.gray(`Reading configuration from: ${options.config}`));
|
|
131
|
+
if (options.debug) {
|
|
132
|
+
logger.log(chalk.gray('[DEBUG] Wizard debug mode enabled'));
|
|
133
|
+
}
|
|
90
134
|
|
|
91
135
|
// Validate wizard config file
|
|
92
136
|
const validationResult = await validateWizardConfigFile(options.config);
|
|
@@ -109,7 +153,7 @@ async function handleWizardHeadless(options) {
|
|
|
109
153
|
const { dataplaneUrl, authConfig } = await setupDataplaneAndAuth(options, appName);
|
|
110
154
|
|
|
111
155
|
// Execute wizard flow from config
|
|
112
|
-
await executeWizardFromConfig(wizardConfig, dataplaneUrl, authConfig);
|
|
156
|
+
await executeWizardFromConfig(wizardConfig, dataplaneUrl, authConfig, { debug: options.debug });
|
|
113
157
|
}
|
|
114
158
|
|
|
115
159
|
module.exports = { handleWizardHeadless, executeWizardFromConfig };
|
|
@@ -10,15 +10,17 @@ const chalk = require('chalk');
|
|
|
10
10
|
const logger = require('../utils/logger');
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Build preferences object for wizard.yaml (schema shape: intent, fieldOnboardingLevel, enableOpenAPIGeneration, enableMCP, enableABAC, enableRBAC)
|
|
13
|
+
* Build preferences object for wizard.yaml (schema shape: intent, fieldOnboardingLevel, enableOpenAPIGeneration, enableMCP, enableABAC, enableRBAC, debug)
|
|
14
14
|
* @param {string} intent - User intent
|
|
15
15
|
* @param {Object} preferences - From promptForUserPreferences (fieldOnboardingLevel, mcp, abac, rbac)
|
|
16
|
+
* @param {Object} [opts] - Optional overrides
|
|
17
|
+
* @param {boolean} [opts.debug] - Enable debug (CLI --debug); saved to wizard.yaml for headless runs
|
|
16
18
|
* @returns {Object} Preferences for wizard-config schema
|
|
17
19
|
*/
|
|
18
|
-
function buildPreferencesForSave(intent, preferences) {
|
|
20
|
+
function buildPreferencesForSave(intent, preferences, opts = {}) {
|
|
19
21
|
const level = preferences?.fieldOnboardingLevel;
|
|
20
22
|
const validLevel = level === 'standard' || level === 'minimal' ? level : 'full';
|
|
21
|
-
|
|
23
|
+
const result = {
|
|
22
24
|
intent: intent || 'general integration',
|
|
23
25
|
fieldOnboardingLevel: validLevel,
|
|
24
26
|
enableOpenAPIGeneration: true,
|
|
@@ -26,6 +28,8 @@ function buildPreferencesForSave(intent, preferences) {
|
|
|
26
28
|
enableABAC: Boolean(preferences?.abac),
|
|
27
29
|
enableRBAC: Boolean(preferences?.rbac)
|
|
28
30
|
};
|
|
31
|
+
if (opts.debug === true || preferences?.debug === true) result.debug = true;
|
|
32
|
+
return result;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/**
|