@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 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
@@ -0,0 +1,8 @@
1
+ appName: test-hubspot
2
+ mode: create-system
3
+ source:
4
+ type: openapi-file
5
+ filePath: /workspace/aifabrix-builder/integration/hubspot/companies.json
6
+ credential:
7
+ action: skip
8
+ preferences: {}
@@ -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 };