@aifabrix/builder 2.33.6 → 2.36.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/README.md +5 -0
- package/integration/test-hubspot/wizard.yaml +8 -0
- package/lib/api/wizard.api.js +24 -1
- package/lib/app/show-display.js +184 -0
- package/lib/app/show.js +642 -0
- package/lib/cli.js +28 -7
- package/lib/commands/wizard-core-helpers.js +278 -0
- package/lib/commands/wizard-core.js +26 -145
- package/lib/commands/wizard-headless.js +2 -2
- package/lib/commands/wizard-helpers.js +143 -0
- package/lib/commands/wizard.js +275 -68
- package/lib/generator/index.js +32 -0
- package/lib/generator/wizard-prompts.js +111 -44
- package/lib/utils/cli-utils.js +40 -1
- package/lib/validation/wizard-config-validator.js +35 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -121,6 +121,11 @@ Build --> Run[Run Locally]:::base
|
|
|
121
121
|
Run --> Deploy[Deploy to Azure]:::primary
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
- **Tests**: `npm test` (runs via wrapper; handles known Jest/Node exit issues).
|
|
127
|
+
- **Coverage**: `npm run test:coverage` — runs tests with coverage through the same wrapper. May take 3–5 minutes for the full suite. If the process exits with a signal after "Ran all test suites", the wrapper treats it as success and coverage is written to `coverage/`. Use `test:coverage:nyc` only if you need nyc-specific reporters.
|
|
128
|
+
|
|
124
129
|
## Requirements
|
|
125
130
|
|
|
126
131
|
- **Docker Desktop** - For running containers
|
package/lib/api/wizard.api.js
CHANGED
|
@@ -326,6 +326,28 @@ async function getDeploymentDocs(dataplaneUrl, authConfig, systemKey) {
|
|
|
326
326
|
return await client.get(`/api/v1/wizard/deployment-docs/${systemKey}`);
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Get known wizard platforms from dataplane.
|
|
331
|
+
* GET /api/v1/wizard/platforms
|
|
332
|
+
* Expected response: { platforms: [ { key: string, displayName?: string } ] } or equivalent.
|
|
333
|
+
* On 404 or error, returns empty array (caller should hide "Known platform" choice).
|
|
334
|
+
* @async
|
|
335
|
+
* @function getWizardPlatforms
|
|
336
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
337
|
+
* @param {Object} authConfig - Authentication configuration
|
|
338
|
+
* @returns {Promise<Array<{key: string, displayName?: string}>>} List of platforms (empty on 404/error)
|
|
339
|
+
*/
|
|
340
|
+
async function getWizardPlatforms(dataplaneUrl, authConfig) {
|
|
341
|
+
try {
|
|
342
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
343
|
+
const response = await client.get('/api/v1/wizard/platforms');
|
|
344
|
+
const platforms = response?.data?.platforms ?? response?.platforms ?? [];
|
|
345
|
+
return Array.isArray(platforms) ? platforms : [];
|
|
346
|
+
} catch (error) {
|
|
347
|
+
return [];
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
329
351
|
module.exports = {
|
|
330
352
|
createWizardSession,
|
|
331
353
|
getWizardSession,
|
|
@@ -342,5 +364,6 @@ module.exports = {
|
|
|
342
364
|
validateStep,
|
|
343
365
|
getPreview,
|
|
344
366
|
testMcpConnection,
|
|
345
|
-
getDeploymentDocs
|
|
367
|
+
getDeploymentDocs,
|
|
368
|
+
getWizardPlatforms
|
|
346
369
|
};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-readable display for aifabrix show command.
|
|
3
|
+
* Single display function for offline and online (unified summary shape).
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview Display formatting for show command
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const chalk = require('chalk');
|
|
13
|
+
const logger = require('../utils/logger');
|
|
14
|
+
|
|
15
|
+
function logSourceAndHeader(summary) {
|
|
16
|
+
const isOffline = summary.source === 'offline';
|
|
17
|
+
const sourceLabel = isOffline
|
|
18
|
+
? `Source: offline (${summary.path || '—'})`
|
|
19
|
+
: `Source: online (${summary.controllerUrl || '—'})`;
|
|
20
|
+
logger.log(sourceLabel);
|
|
21
|
+
logger.log('');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function logApplicationRequired(a) {
|
|
25
|
+
logger.log('📱 Application');
|
|
26
|
+
logger.log(` Key: ${a.key ?? '—'}`);
|
|
27
|
+
logger.log(` Display name: ${a.displayName ?? '—'}`);
|
|
28
|
+
logger.log(` Description: ${a.description ?? '—'}`);
|
|
29
|
+
logger.log(` Type: ${a.type ?? '—'}`);
|
|
30
|
+
const port = (a.port !== undefined && a.port !== null) ? a.port : '—';
|
|
31
|
+
logger.log(` Port: ${port}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function logApplicationOptional(a) {
|
|
35
|
+
if (a.deploymentKey !== undefined) logger.log(` Deployment: ${a.deploymentKey ?? '—'}`);
|
|
36
|
+
if (a.image !== undefined) logger.log(` Image: ${a.image ?? '—'}`);
|
|
37
|
+
if (a.registryMode !== undefined) logger.log(` Registry: ${a.registryMode ?? '—'}`);
|
|
38
|
+
if (a.healthCheck !== undefined) logger.log(` Health: ${a.healthCheck ?? '—'}`);
|
|
39
|
+
if (a.build !== undefined) logger.log(` Build: ${a.build ?? '—'}`);
|
|
40
|
+
if (a.status !== undefined) logger.log(` Status: ${a.status ?? '—'}`);
|
|
41
|
+
if (a.url !== undefined) logger.log(` URL: ${a.url ?? '—'}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function logApplicationFields(a) {
|
|
45
|
+
logApplicationRequired(a);
|
|
46
|
+
logApplicationOptional(a);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function logApplicationExternalIntegration(ei) {
|
|
50
|
+
logger.log(' External integration:');
|
|
51
|
+
logger.log(` schemaBasePath: ${ei.schemaBasePath}`);
|
|
52
|
+
logger.log(` systems: [${(ei.systems || []).join(', ')}]`);
|
|
53
|
+
logger.log(` dataSources: [${(ei.dataSources || []).join(', ')}]`);
|
|
54
|
+
logger.log(chalk.gray('\n For external system data as on dataplane, run with --online.'));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function logApplicationSection(a, isExternal) {
|
|
58
|
+
logApplicationFields(a);
|
|
59
|
+
if (isExternal && a.externalIntegration) {
|
|
60
|
+
logApplicationExternalIntegration(a.externalIntegration);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function logRolesSection(roles) {
|
|
65
|
+
if (roles.length === 0) return;
|
|
66
|
+
logger.log('');
|
|
67
|
+
logger.log('👥 Roles');
|
|
68
|
+
roles.forEach((r) => {
|
|
69
|
+
const ro = typeof r === 'object' ? r : { name: r, value: r };
|
|
70
|
+
const name = ro.name ?? ro.value ?? '—';
|
|
71
|
+
const value = ro.value ?? ro.name ?? '—';
|
|
72
|
+
logger.log(` • ${name} (${value})`);
|
|
73
|
+
if (ro.description) logger.log(` \t${ro.description}`);
|
|
74
|
+
if (ro.groups && ro.groups.length > 0) logger.log(` \tgroups: [${ro.groups.join(', ')}]`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function logPermissionsSection(permissions) {
|
|
79
|
+
if (permissions.length === 0) return;
|
|
80
|
+
logger.log('');
|
|
81
|
+
logger.log('🛡️ Permissions');
|
|
82
|
+
permissions.forEach((p) => {
|
|
83
|
+
const name = p.name ?? '—';
|
|
84
|
+
const roleList = (p.roles || []).join(', ');
|
|
85
|
+
logger.log(` • ${name}`);
|
|
86
|
+
logger.log(` \troles: [${roleList}]`);
|
|
87
|
+
if (p.description) logger.log(` \t${p.description}`);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function logAuthSection(authentication) {
|
|
92
|
+
if (!authentication) return;
|
|
93
|
+
logger.log('');
|
|
94
|
+
logger.log('🔐 Authentication');
|
|
95
|
+
const sso = authentication.enableSSO ? 'enabled' : 'disabled';
|
|
96
|
+
logger.log(` SSO: ${sso} type: ${authentication.type ?? '—'} requiredRoles: [${(authentication.requiredRoles || []).join(', ')}]`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function logConfigurationsSection(portalInputConfigurations) {
|
|
100
|
+
if (portalInputConfigurations.length === 0) return;
|
|
101
|
+
logger.log('');
|
|
102
|
+
logger.log('📝 Configurations');
|
|
103
|
+
portalInputConfigurations.forEach((c) => {
|
|
104
|
+
logger.log(` ${c.label ?? c.name ?? '—'}: ${c.value ?? '—'}`);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function logDatabasesSection(dbNames) {
|
|
109
|
+
if (dbNames.length === 0) return;
|
|
110
|
+
logger.log('');
|
|
111
|
+
logger.log('🗄️ Databases');
|
|
112
|
+
logger.log(` ${dbNames.join(', ')}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function logExternalSystemMain(ext) {
|
|
116
|
+
logger.log('🔗 External system (dataplane)');
|
|
117
|
+
logger.log(` Dataplane: ${ext.dataplaneUrl}`);
|
|
118
|
+
logger.log(` System key: ${ext.systemKey}`);
|
|
119
|
+
logger.log(` Display name: ${ext.displayName}`);
|
|
120
|
+
logger.log(` Type: ${ext.type}`);
|
|
121
|
+
logger.log(` Status: ${ext.status}`);
|
|
122
|
+
logger.log(` Version: ${ext.version ?? '—'}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function logExternalSystemDataSources(dataSources) {
|
|
126
|
+
if (!dataSources || dataSources.length === 0) return;
|
|
127
|
+
logger.log(' DataSources:');
|
|
128
|
+
dataSources.forEach((ds) => {
|
|
129
|
+
logger.log(` • ${ds.key} ${ds.displayName ?? ''} (systemKey: ${ds.systemKey ?? '—'})`);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function logExternalSystemApplication(ap) {
|
|
134
|
+
if (!ap) return;
|
|
135
|
+
logger.log(' Application (from dataplane):');
|
|
136
|
+
logger.log(` key: ${ap.key} displayName: ${ap.displayName} type: ${ap.type}`);
|
|
137
|
+
if (ap.roles) logger.log(` roles: ${Array.isArray(ap.roles) ? ap.roles.join(', ') : ap.roles}`);
|
|
138
|
+
if (ap.permissions) logger.log(` permissions: ${Array.isArray(ap.permissions) ? ap.permissions.join(', ') : ap.permissions}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function logExternalSystemSection(ext) {
|
|
142
|
+
if (!ext) return;
|
|
143
|
+
logger.log('');
|
|
144
|
+
if (ext.error) {
|
|
145
|
+
logger.log('🔗 External system (dataplane): not available (dataplane unreachable or not found).');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
logExternalSystemMain(ext);
|
|
149
|
+
logExternalSystemDataSources(ext.dataSources);
|
|
150
|
+
logExternalSystemApplication(ext.application);
|
|
151
|
+
if (ext.openapiFiles && ext.openapiFiles.length > 0) {
|
|
152
|
+
logger.log(` OpenAPI files: ${ext.openapiFiles.length}`);
|
|
153
|
+
}
|
|
154
|
+
if (ext.openapiEndpoints && ext.openapiEndpoints.length > 0) {
|
|
155
|
+
const sample = ext.openapiEndpoints.slice(0, 3).map((e) => `${e.method || 'GET'} ${e.path || e.pathPattern || e}`).join(', ');
|
|
156
|
+
logger.log(` OpenAPI endpoints: ${ext.openapiEndpoints.length} (e.g. ${sample}${ext.openapiEndpoints.length > 3 ? ' …' : ''})`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Format and print human-readable show output (offline or online).
|
|
162
|
+
* @param {Object} summary - Unified summary (buildOfflineSummaryFromDeployJson or buildOnlineSummary)
|
|
163
|
+
*/
|
|
164
|
+
function display(summary) {
|
|
165
|
+
const a = summary.application;
|
|
166
|
+
const roles = summary.roles ?? a.roles ?? [];
|
|
167
|
+
const permissions = summary.permissions ?? a.permissions ?? [];
|
|
168
|
+
const authentication = summary.authentication ?? a.authentication;
|
|
169
|
+
const portalInputConfigurations = summary.portalInputConfigurations ?? a.portalInputConfigurations ?? [];
|
|
170
|
+
const databases = summary.databases ?? a.databases ?? [];
|
|
171
|
+
const dbNames = Array.isArray(databases) ? databases.map((d) => (d && d.name) || d).filter(Boolean) : [];
|
|
172
|
+
|
|
173
|
+
logSourceAndHeader(summary);
|
|
174
|
+
logApplicationSection(a, summary.isExternal);
|
|
175
|
+
logRolesSection(roles);
|
|
176
|
+
logPermissionsSection(permissions);
|
|
177
|
+
logAuthSection(authentication);
|
|
178
|
+
logConfigurationsSection(portalInputConfigurations);
|
|
179
|
+
logDatabasesSection(dbNames);
|
|
180
|
+
logExternalSystemSection(summary.externalSystem);
|
|
181
|
+
logger.log('');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = { display };
|