@aifabrix/builder 2.32.3 → 2.33.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.
Files changed (123) hide show
  1. package/.cursor/rules/project-rules.mdc +8 -0
  2. package/README.md +36 -8
  3. package/bin/aifabrix.js +6 -8
  4. package/integration/hubspot/README.md +8 -7
  5. package/integration/hubspot/companies.json +2048 -0
  6. package/integration/hubspot/create-hubspot.js +665 -0
  7. package/integration/hubspot/{hubspot-deploy-company.json → hubspot-datasource-company.json} +1 -1
  8. package/integration/hubspot/{hubspot-deploy-contact.json → hubspot-datasource-contact.json} +1 -1
  9. package/integration/hubspot/{hubspot-deploy-deal.json → hubspot-datasource-deal.json} +1 -1
  10. package/integration/hubspot/hubspot-deploy.json +832 -81
  11. package/integration/hubspot/hubspot-system.json +99 -0
  12. package/integration/hubspot/test-artifacts/wizard-hubspot-credential-real.yaml +20 -0
  13. package/integration/hubspot/test-artifacts/wizard-hubspot-env-vars.yaml +9 -0
  14. package/integration/hubspot/test-artifacts/wizard-invalid-add-datasource.yaml +5 -0
  15. package/integration/hubspot/test-artifacts/wizard-invalid-app-name.yaml +5 -0
  16. package/integration/hubspot/test-artifacts/wizard-invalid-credential-create.yaml +7 -0
  17. package/integration/hubspot/test-artifacts/wizard-invalid-credential-select.yaml +7 -0
  18. package/integration/hubspot/test-artifacts/wizard-invalid-known-platform.yaml +4 -0
  19. package/integration/hubspot/test-artifacts/wizard-invalid-missing-app.yaml +4 -0
  20. package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
  21. package/integration/hubspot/test-artifacts/wizard-invalid-mode.yaml +5 -0
  22. package/integration/hubspot/test-artifacts/wizard-invalid-openapi-file.yaml +5 -0
  23. package/integration/hubspot/test-artifacts/wizard-invalid-openapi-url.yaml +4 -0
  24. package/integration/hubspot/test-artifacts/wizard-invalid-source.yaml +4 -0
  25. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-array-test.yaml +5 -0
  26. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
  27. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
  28. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-test.yaml +5 -0
  29. package/integration/hubspot/test-artifacts/wizard-valid-for-rbac-test.yaml +5 -0
  30. package/integration/hubspot/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +5 -0
  31. package/integration/hubspot/test-dataplane-down-helpers.js +246 -0
  32. package/integration/hubspot/test-dataplane-down-tests.js +419 -0
  33. package/integration/hubspot/test-dataplane-down.js +157 -0
  34. package/integration/hubspot/test.js +1517 -0
  35. package/integration/hubspot/variables.yaml +4 -4
  36. package/integration/hubspot/wizard-hubspot-e2e.yaml +16 -0
  37. package/integration/hubspot/wizard-hubspot-platform.yaml +8 -0
  38. package/lib/api/applications.api.js +1 -0
  39. package/lib/api/types/wizard.types.js +176 -38
  40. package/lib/api/wizard.api.js +161 -23
  41. package/lib/app/deploy.js +116 -54
  42. package/lib/app/display.js +6 -5
  43. package/lib/app/dockerfile.js +2 -1
  44. package/lib/app/list.js +17 -10
  45. package/lib/app/readme.js +41 -112
  46. package/lib/app/register.js +44 -9
  47. package/lib/app/rotate-secret.js +48 -31
  48. package/lib/cli.js +219 -70
  49. package/lib/commands/app.js +4 -9
  50. package/lib/commands/auth-config.js +125 -0
  51. package/lib/commands/auth-status.js +7 -8
  52. package/lib/commands/datasource.js +3 -6
  53. package/lib/commands/login-credentials.js +4 -4
  54. package/lib/commands/login-device.js +26 -17
  55. package/lib/commands/login.js +12 -10
  56. package/lib/commands/wizard-config-normalizer.js +92 -0
  57. package/lib/commands/wizard-core.js +515 -0
  58. package/lib/commands/wizard-dataplane.js +122 -0
  59. package/lib/commands/wizard-headless.js +115 -0
  60. package/lib/commands/wizard.js +110 -332
  61. package/lib/core/config.js +46 -0
  62. package/lib/core/secrets.js +3 -22
  63. package/lib/core/templates-env.js +1 -1
  64. package/lib/datasource/deploy.js +29 -21
  65. package/lib/datasource/list.js +8 -6
  66. package/lib/deployment/deployer.js +25 -0
  67. package/lib/deployment/environment.js +10 -13
  68. package/lib/external-system/delete.js +151 -0
  69. package/lib/external-system/deploy.js +53 -378
  70. package/lib/external-system/download-helpers.js +45 -65
  71. package/lib/external-system/download.js +33 -13
  72. package/lib/external-system/generator.js +11 -7
  73. package/lib/external-system/test-auth.js +4 -3
  74. package/lib/generator/builders.js +3 -1
  75. package/lib/generator/external-controller-manifest.js +157 -0
  76. package/lib/generator/external-schema-utils.js +236 -0
  77. package/lib/generator/external.js +55 -3
  78. package/lib/generator/index.js +22 -10
  79. package/lib/generator/wizard-prompts.js +33 -10
  80. package/lib/generator/wizard.js +69 -86
  81. package/lib/infrastructure/compose.js +100 -0
  82. package/lib/infrastructure/helpers.js +139 -0
  83. package/lib/infrastructure/index.js +52 -311
  84. package/lib/infrastructure/services.js +168 -0
  85. package/lib/schema/application-schema.json +23 -4
  86. package/lib/schema/external-datasource.schema.json +2 -2
  87. package/lib/schema/wizard-config.schema.json +234 -0
  88. package/lib/utils/api.js +32 -50
  89. package/lib/utils/app-existence.js +42 -0
  90. package/lib/utils/app-register-config.js +7 -2
  91. package/lib/utils/auth-config-validator.js +92 -0
  92. package/lib/utils/command-header.js +43 -0
  93. package/lib/utils/compose-generator.js +113 -70
  94. package/lib/utils/controller-url.js +65 -17
  95. package/lib/utils/dataplane-health.js +115 -0
  96. package/lib/utils/dataplane-resolver.js +29 -0
  97. package/lib/utils/dev-config.js +6 -2
  98. package/lib/utils/env-copy.js +2 -1
  99. package/lib/utils/env-ports.js +2 -1
  100. package/lib/utils/env-template.js +1 -1
  101. package/lib/utils/error-formatter.js +49 -0
  102. package/lib/utils/external-readme.js +125 -0
  103. package/lib/utils/help-builder.js +190 -0
  104. package/lib/utils/infra-status.js +13 -3
  105. package/lib/utils/paths.js +17 -2
  106. package/lib/utils/port-resolver.js +111 -0
  107. package/lib/utils/secrets-helpers.js +3 -15
  108. package/lib/utils/secrets-utils.js +2 -2
  109. package/lib/utils/token-manager.js +9 -4
  110. package/lib/utils/variable-transformer.js +7 -2
  111. package/lib/validation/external-manifest-validator.js +202 -0
  112. package/lib/validation/validate-display.js +406 -0
  113. package/lib/validation/validate.js +159 -123
  114. package/lib/validation/validator.js +36 -3
  115. package/lib/validation/wizard-config-validator.js +267 -0
  116. package/package.json +4 -2
  117. package/templates/applications/README.md.hbs +18 -16
  118. package/templates/applications/miso-controller/env.template +1 -1
  119. package/templates/applications/miso-controller/rbac.yaml +7 -7
  120. package/templates/external-system/README.md.hbs +99 -0
  121. package/templates/infra/compose.yaml.hbs +35 -0
  122. package/templates/python/docker-compose.hbs +26 -0
  123. package/templates/typescript/docker-compose.hbs +26 -0
@@ -0,0 +1,99 @@
1
+ {
2
+ "key": "hubspot",
3
+ "displayName": "HubSpot CRM",
4
+ "description": "HubSpot CRM integration with OpenAPI support for companies, contacts, and deals",
5
+ "type": "openapi",
6
+ "enabled": true,
7
+ "environment": {
8
+ "baseUrl": "https://api.hubapi.com"
9
+ },
10
+ "authentication": {
11
+ "type": "oauth2",
12
+ "mode": "oauth2",
13
+ "oauth2": {
14
+ "tokenUrl": "{{TOKENURL}}",
15
+ "clientId": "{{CLIENTID}}",
16
+ "clientSecret": "{{CLIENTSECRET}}",
17
+ "scopes": [
18
+ "crm.objects.companies.read",
19
+ "crm.objects.companies.write",
20
+ "crm.objects.contacts.read",
21
+ "crm.objects.contacts.write",
22
+ "crm.objects.deals.read",
23
+ "crm.objects.deals.write"
24
+ ]
25
+ }
26
+ },
27
+ "configuration": [
28
+ {
29
+ "name": "CLIENTID",
30
+ "value": "hubspot-clientidKeyVault",
31
+ "location": "keyvault",
32
+ "required": true
33
+ },
34
+ {
35
+ "name": "CLIENTSECRET",
36
+ "value": "hubspot-clientsecretKeyVault",
37
+ "location": "keyvault",
38
+ "required": true
39
+ },
40
+ {
41
+ "name": "TOKENURL",
42
+ "value": "https://api.hubapi.com/oauth/v1/token",
43
+ "location": "variable",
44
+ "required": true
45
+ },
46
+ {
47
+ "name": "REDIRECT_URI",
48
+ "value": "hubspot-redirect-uriKeyVault",
49
+ "location": "keyvault",
50
+ "required": false
51
+ },
52
+ {
53
+ "name": "HUBSPOT_API_VERSION",
54
+ "value": "v3",
55
+ "location": "variable",
56
+ "required": false,
57
+ "portalInput": {
58
+ "field": "select",
59
+ "label": "HubSpot API Version",
60
+ "placeholder": "Select API version",
61
+ "options": [
62
+ "v1",
63
+ "v2",
64
+ "v3"
65
+ ],
66
+ "validation": {
67
+ "required": false
68
+ }
69
+ }
70
+ },
71
+ {
72
+ "name": "MAX_PAGE_SIZE",
73
+ "value": "100",
74
+ "location": "variable",
75
+ "required": false,
76
+ "portalInput": {
77
+ "field": "text",
78
+ "label": "Maximum Page Size",
79
+ "placeholder": "100",
80
+ "validation": {
81
+ "required": false,
82
+ "pattern": "^[0-9]+$",
83
+ "minLength": 1,
84
+ "maxLength": 1000
85
+ }
86
+ }
87
+ }
88
+ ],
89
+ "openapi": {
90
+ "documentKey": "hubspot-v3",
91
+ "autoDiscoverEntities": false
92
+ },
93
+ "tags": [
94
+ "crm",
95
+ "sales",
96
+ "marketing",
97
+ "hubspot"
98
+ ]
99
+ }
@@ -0,0 +1,20 @@
1
+ appName: hubspot-test-credential-real
2
+ mode: create-system
3
+ source:
4
+ type: openapi-file
5
+ filePath: /workspace/aifabrix-builder/integration/hubspot/companies.json
6
+ credential:
7
+ action: create
8
+ config:
9
+ key: hubspot-test-cred-real
10
+ displayName: HubSpot Test Credential (Real)
11
+ type: OAUTH2
12
+ config:
13
+ tokenUrl: ${HUBSPOT_TOKEN_URL}
14
+ clientId: ${HUBSPOT_CLIENT_ID}
15
+ clientSecret: ${HUBSPOT_CLIENT_SECRET}
16
+ scopes:
17
+ - crm.objects.companies.read
18
+ - crm.objects.companies.write
19
+ - crm.objects.contacts.read
20
+ - crm.objects.contacts.write
@@ -0,0 +1,9 @@
1
+ appName: hubspot-test-env-vars
2
+ mode: create-system
3
+ source:
4
+ type: openapi-file
5
+ filePath: /workspace/aifabrix-builder/integration/hubspot/companies.json
6
+ deployment:
7
+ controller: ${CONTROLLER_URL}
8
+ dataplane: ${DATAPLANE_URL}
9
+ environment: miso
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-add-datasource
2
+ mode: add-datasource
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: HubSpot-Test
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,7 @@
1
+ appName: hubspot-test-negative-credential-create
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
6
+ credential:
7
+ action: create
@@ -0,0 +1,7 @@
1
+ appName: hubspot-test-negative-credential-select
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
6
+ credential:
7
+ action: select
@@ -0,0 +1,4 @@
1
+ appName: hubspot-test-negative-platform
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
@@ -0,0 +1,4 @@
1
+ mode: create-system
2
+ source:
3
+ type: known-platform
4
+ platform: hubspot
@@ -0,0 +1,2 @@
1
+ appName: hubspot-test-negative-missing-source
2
+ mode: create-system
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-mode
2
+ mode: invalid-mode
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-openapi
2
+ mode: create-system
3
+ source:
4
+ type: openapi-file
5
+ filePath: /tmp/does-not-exist.json
@@ -0,0 +1,4 @@
1
+ appName: hubspot-test-negative-openapi-url
2
+ mode: create-system
3
+ source:
4
+ type: openapi-url
@@ -0,0 +1,4 @@
1
+ appName: hubspot-test-negative-source
2
+ mode: create-system
3
+ source:
4
+ type: invalid-type
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-dimension-array
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-dimension-invalid-key
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-dimension-invalid-path
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-dimension-missing
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-rbac-missing-role
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,5 @@
1
+ appName: hubspot-test-negative-rbac-invalid-yaml
2
+ mode: create-system
3
+ source:
4
+ type: known-platform
5
+ platform: hubspot
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Test Helper Utilities for Dataplane Down Tests
3
+ *
4
+ * Common utilities for dataplane down test suite.
5
+ *
6
+ * @fileoverview Helper utilities for dataplane down tests
7
+ * @author AI Fabrix Team
8
+ * @version 2.0.0
9
+ */
10
+ 'use strict';
11
+
12
+ const { execFile } = require('child_process');
13
+ const { promisify } = require('util');
14
+ const chalk = require('chalk');
15
+
16
+ const execFileAsync = promisify(execFile);
17
+
18
+ const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
19
+ const COMMAND_TIMEOUT_MS = 15 * 1000; // 15 seconds - shorter timeout to catch hanging commands
20
+
21
+ /**
22
+ * Logs info message
23
+ * @function logInfo
24
+ * @param {string} message - Message to log
25
+ * @returns {void}
26
+ */
27
+ function logInfo(message) {
28
+ // eslint-disable-next-line no-console
29
+ console.log(chalk.cyan(message));
30
+ }
31
+
32
+ /**
33
+ * Logs success message
34
+ * @function logSuccess
35
+ * @param {string} message - Message to log
36
+ * @returns {void}
37
+ */
38
+ function logSuccess(message) {
39
+ // eslint-disable-next-line no-console
40
+ console.log(chalk.green(message));
41
+ }
42
+
43
+ /**
44
+ * Logs error message
45
+ * @function logError
46
+ * @param {string} message - Message to log
47
+ * @returns {void}
48
+ */
49
+ function logError(message) {
50
+ // eslint-disable-next-line no-console
51
+ console.error(chalk.red(message));
52
+ }
53
+
54
+ /**
55
+ * Logs warning message
56
+ * @function logWarn
57
+ * @param {string} message - Message to log
58
+ * @returns {void}
59
+ */
60
+ function logWarn(message) {
61
+ // eslint-disable-next-line no-console
62
+ console.warn(chalk.yellow(message));
63
+ }
64
+
65
+ /**
66
+ * Runs a command
67
+ * @async
68
+ * @function runCommand
69
+ * @param {string} command - Command to run
70
+ * @param {string[]} args - Command arguments
71
+ * @returns {Promise<Object>} Command result object with success, stdout, stderr
72
+ */
73
+ async function runCommand(command, args) {
74
+ try {
75
+ const result = await execFileAsync(command, args, {
76
+ cwd: process.cwd(),
77
+ env: { ...process.env },
78
+ maxBuffer: MAX_OUTPUT_BYTES,
79
+ timeout: COMMAND_TIMEOUT_MS
80
+ });
81
+ return { success: true, stdout: result.stdout || '', stderr: result.stderr || '', error: null };
82
+ } catch (error) {
83
+ const stdout = error.stdout || '';
84
+ const stderr = error.stderr || '';
85
+ // Check if it's a timeout error
86
+ const isTimeout = error.code === 'ETIMEDOUT' ||
87
+ (error.message && error.message.includes('timeout'));
88
+ return { success: false, stdout, stderr, error, isTimeout };
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Validates error message contains expected patterns
94
+ * @function validateError
95
+ * @param {string} output - Combined stdout and stderr
96
+ * @param {string[]} expectedPatterns - Array of expected error patterns
97
+ * @returns {boolean} True if error matches expected patterns
98
+ */
99
+ function validateError(output, expectedPatterns) {
100
+ const lowerOutput = output.toLowerCase();
101
+ return expectedPatterns.some(pattern => lowerOutput.includes(pattern.toLowerCase()));
102
+ }
103
+
104
+ /**
105
+ * Checks if result indicates a timeout
106
+ * @function isTimeoutResult
107
+ * @param {Object} result - Command result
108
+ * @returns {boolean} True if timeout detected
109
+ */
110
+ function isTimeoutResult(result) {
111
+ return result.isTimeout || (result.error && (
112
+ result.error.code === 'ETIMEDOUT' ||
113
+ (result.error.message && result.error.message.includes('timeout'))
114
+ ));
115
+ }
116
+
117
+ /**
118
+ * Checks if output contains error indicators
119
+ * @function hasErrorIndicators
120
+ * @param {string} output - Combined output
121
+ * @param {string[]} expectedPatterns - Expected error patterns
122
+ * @param {Object} result - Command result
123
+ * @returns {boolean} True if error indicators found
124
+ */
125
+ function hasErrorIndicators(output, expectedPatterns, result) {
126
+ return validateError(output, expectedPatterns) ||
127
+ output.includes('Failed') ||
128
+ output.includes('Error') ||
129
+ output.includes('not found') ||
130
+ output.includes('External system') ||
131
+ output.includes('external system') ||
132
+ output.includes('timeout') ||
133
+ output.includes('ECONNREFUSED') ||
134
+ output.includes('ENOTFOUND') ||
135
+ output.includes('Command failed') ||
136
+ (result.error && result.error.message) ||
137
+ result.stderr.length > 0;
138
+ }
139
+
140
+ /**
141
+ * Validates download/delete command result
142
+ * @function validateDownloadDeleteResult
143
+ * @param {Object} result - Command result
144
+ * @param {string} output - Combined output
145
+ * @param {string[]} expectedPatterns - Expected error patterns
146
+ * @returns {Object} Validation result
147
+ */
148
+ function validateDownloadDeleteResult(result, output, expectedPatterns) {
149
+ const timeout = isTimeoutResult(result);
150
+ const isValid = (!result.success || timeout) && (
151
+ timeout ||
152
+ validateError(output, expectedPatterns) ||
153
+ output.includes('Failed') ||
154
+ output.includes('Error')
155
+ );
156
+
157
+ return {
158
+ isValid,
159
+ timeout,
160
+ output: timeout ? `${output}\n[Command timed out - this indicates the command may be hanging]` : output,
161
+ expectedPatterns: timeout ? [...expectedPatterns, 'timeout'] : expectedPatterns
162
+ };
163
+ }
164
+
165
+ /**
166
+ * Validates delete command result
167
+ * @function validateDeleteResult
168
+ * @param {Object} result - Command result
169
+ * @param {string} output - Combined output
170
+ * @param {string[]} expectedPatterns - Expected error patterns
171
+ * @returns {Object} Validation result
172
+ */
173
+ function validateDeleteResult(result, output, expectedPatterns) {
174
+ const timeout = isTimeoutResult(result);
175
+
176
+ if (result.success && !timeout) {
177
+ return {
178
+ isValid: false,
179
+ output: `Command succeeded when it should have failed. Output: ${output.substring(0, 200)}`,
180
+ expectedPatterns,
181
+ error: 'Command should have failed but succeeded'
182
+ };
183
+ }
184
+
185
+ const hasErrorIndicator = timeout || hasErrorIndicators(output, expectedPatterns, result);
186
+ const isValid = (!result.success || timeout) && (
187
+ timeout ||
188
+ hasErrorIndicator ||
189
+ result.error !== null
190
+ );
191
+
192
+ const fullOutput = timeout
193
+ ? `${output}\n[Command timed out after ${COMMAND_TIMEOUT_MS}ms - this indicates the command may be hanging when dataplane is down]`
194
+ : output;
195
+
196
+ return {
197
+ isValid,
198
+ output: fullOutput,
199
+ expectedPatterns: timeout ? [...expectedPatterns, 'timeout'] : expectedPatterns,
200
+ error: result.error ? (result.error.message || String(result.error)) : undefined
201
+ };
202
+ }
203
+
204
+ /**
205
+ * Validates wizard command result
206
+ * @function validateWizardResult
207
+ * @param {Object} result - Command result
208
+ * @param {string} output - Combined output
209
+ * @returns {Object} Validation result
210
+ */
211
+ function validateWizardResult(result, output) {
212
+ const expectedPatterns = [
213
+ 'failed to connect',
214
+ 'connection refused',
215
+ 'network error',
216
+ 'econnrefused',
217
+ 'fetch failed',
218
+ 'timeout',
219
+ 'unreachable',
220
+ 'failed to create wizard session'
221
+ ];
222
+
223
+ const isValid = !result.success && validateError(output, expectedPatterns);
224
+
225
+ return {
226
+ name: 'wizard',
227
+ success: isValid,
228
+ output,
229
+ expectedPatterns
230
+ };
231
+ }
232
+
233
+ module.exports = {
234
+ logInfo,
235
+ logSuccess,
236
+ logError,
237
+ logWarn,
238
+ runCommand,
239
+ validateError,
240
+ isTimeoutResult,
241
+ hasErrorIndicators,
242
+ validateDownloadDeleteResult,
243
+ validateDeleteResult,
244
+ validateWizardResult,
245
+ COMMAND_TIMEOUT_MS
246
+ };