@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.
Files changed (138) hide show
  1. package/.cursor/rules/docs-rules.mdc +30 -0
  2. package/README.md +1 -1
  3. package/integration/hubspot/README.md +8 -4
  4. package/integration/hubspot/application.json +54 -0
  5. package/integration/hubspot/create-hubspot.js +9 -136
  6. package/integration/hubspot/env.template +3 -4
  7. package/integration/hubspot/hubspot-datasource-company.json +343 -5
  8. package/integration/hubspot/hubspot-datasource-contact.json +413 -5
  9. package/integration/hubspot/hubspot-datasource-deal.json +341 -4
  10. package/integration/hubspot/hubspot-datasource-users.json +116 -0
  11. package/integration/hubspot/hubspot-deploy.json +1250 -108
  12. package/integration/hubspot/hubspot-system.json +15 -32
  13. package/integration/hubspot/test-dataplane-down-tests.js +17 -16
  14. package/integration/hubspot/test-dataplane-down.js +2 -2
  15. package/jest.config.manual.js +2 -1
  16. package/lib/api/external-test.api.js +111 -0
  17. package/lib/api/index.js +42 -19
  18. package/lib/api/pipeline.api.js +66 -120
  19. package/lib/api/types/pipeline.types.js +37 -0
  20. package/lib/api/wizard-platform.api.js +61 -0
  21. package/lib/api/wizard.api.js +34 -1
  22. package/lib/app/config.js +23 -11
  23. package/lib/app/index.js +3 -1
  24. package/lib/app/prompts.js +44 -29
  25. package/lib/app/readme.js +8 -3
  26. package/lib/app/run-env-compose.js +64 -1
  27. package/lib/app/run-helpers.js +1 -1
  28. package/lib/app/show-display.js +1 -1
  29. package/lib/cli/setup-app.js +42 -11
  30. package/lib/cli/setup-credential-deployment.js +31 -6
  31. package/lib/cli/setup-dev.js +27 -0
  32. package/lib/cli/setup-environment.js +12 -4
  33. package/lib/cli/setup-external-system.js +19 -4
  34. package/lib/cli/setup-infra.js +54 -14
  35. package/lib/cli/setup-utility.js +117 -21
  36. package/lib/commands/credential-env.js +162 -0
  37. package/lib/commands/credential-list.js +17 -22
  38. package/lib/commands/credential-push.js +96 -0
  39. package/lib/commands/datasource.js +77 -6
  40. package/lib/commands/dev-init.js +39 -1
  41. package/lib/commands/repair-auth-config.js +99 -0
  42. package/lib/commands/repair-datasource-keys.js +208 -0
  43. package/lib/commands/repair-datasource.js +235 -0
  44. package/lib/commands/repair-env-template.js +348 -0
  45. package/lib/commands/repair-internal.js +85 -0
  46. package/lib/commands/repair-rbac.js +158 -0
  47. package/lib/commands/repair.js +507 -0
  48. package/lib/commands/test-e2e-external.js +165 -0
  49. package/lib/commands/upload.js +71 -40
  50. package/lib/commands/wizard-core-helpers.js +226 -4
  51. package/lib/commands/wizard-core.js +67 -29
  52. package/lib/commands/wizard-dataplane.js +1 -1
  53. package/lib/commands/wizard-entity-selection.js +43 -0
  54. package/lib/commands/wizard-headless.js +44 -5
  55. package/lib/commands/wizard-helpers.js +7 -3
  56. package/lib/commands/wizard.js +86 -64
  57. package/lib/core/config.js +7 -1
  58. package/lib/core/secrets.js +33 -12
  59. package/lib/datasource/deploy.js +12 -3
  60. package/lib/datasource/test-e2e.js +219 -0
  61. package/lib/datasource/test-integration.js +154 -0
  62. package/lib/deployment/deployer.js +7 -5
  63. package/lib/external-system/download.js +182 -204
  64. package/lib/external-system/generator.js +204 -56
  65. package/lib/external-system/test-execution.js +2 -1
  66. package/lib/external-system/test-system-level.js +73 -0
  67. package/lib/external-system/test.js +51 -18
  68. package/lib/generator/external-controller-manifest.js +29 -2
  69. package/lib/generator/external-schema-utils.js +1 -1
  70. package/lib/generator/external.js +10 -3
  71. package/lib/generator/index.js +4 -1
  72. package/lib/generator/split-readme.js +1 -0
  73. package/lib/generator/split-variables.js +7 -1
  74. package/lib/generator/split.js +194 -54
  75. package/lib/generator/wizard-prompts-secondary.js +294 -0
  76. package/lib/generator/wizard-prompts.js +105 -106
  77. package/lib/generator/wizard-readme.js +88 -0
  78. package/lib/generator/wizard.js +147 -158
  79. package/lib/infrastructure/compose.js +11 -1
  80. package/lib/infrastructure/index.js +11 -3
  81. package/lib/infrastructure/services.js +22 -11
  82. package/lib/schema/application-schema.json +8 -5
  83. package/lib/schema/external-datasource.schema.json +49 -26
  84. package/lib/schema/external-system.schema.json +82 -6
  85. package/lib/schema/wizard-config.schema.json +16 -0
  86. package/lib/utils/api.js +38 -10
  87. package/lib/utils/auth-headers.js +8 -7
  88. package/lib/utils/compose-generator.js +1 -1
  89. package/lib/utils/compose-handlebars-helpers.js +11 -0
  90. package/lib/utils/config-format-preference.js +51 -0
  91. package/lib/utils/config-format.js +36 -0
  92. package/lib/utils/configuration-env-resolver.js +179 -0
  93. package/lib/utils/credential-display.js +83 -0
  94. package/lib/utils/credential-secrets-env.js +115 -25
  95. package/lib/utils/dataplane-pipeline-warning.js +28 -0
  96. package/lib/utils/deployment-validation-helpers.js +4 -4
  97. package/lib/utils/dev-ca-install.js +139 -0
  98. package/lib/utils/env-copy.js +23 -3
  99. package/lib/utils/error-formatters/http-status-errors.js +0 -1
  100. package/lib/utils/error-formatters/permission-errors.js +0 -1
  101. package/lib/utils/error-formatters/validation-errors.js +0 -1
  102. package/lib/utils/external-readme.js +56 -29
  103. package/lib/utils/external-system-display.js +59 -1
  104. package/lib/utils/external-system-test-helpers.js +21 -8
  105. package/lib/utils/external-system-validators.js +3 -0
  106. package/lib/utils/file-upload.js +20 -50
  107. package/lib/utils/help-builder.js +1 -0
  108. package/lib/utils/infra-status.js +50 -44
  109. package/lib/utils/local-secrets.js +5 -5
  110. package/lib/utils/paths.js +85 -4
  111. package/lib/utils/secrets-canonical.js +93 -0
  112. package/lib/utils/secrets-generator.js +20 -0
  113. package/lib/utils/secrets-helpers.js +75 -89
  114. package/lib/utils/test-log-writer.js +56 -0
  115. package/lib/utils/token-manager.js +24 -32
  116. package/lib/validation/env-template-auth.js +157 -0
  117. package/lib/validation/env-template-kv.js +41 -0
  118. package/lib/validation/external-manifest-validator.js +25 -0
  119. package/lib/validation/external-system-auth-rules.js +86 -0
  120. package/lib/validation/validate-batch.js +149 -0
  121. package/lib/validation/validate-datasource-keys-api.js +33 -0
  122. package/lib/validation/validate-display.js +94 -16
  123. package/lib/validation/validate.js +25 -12
  124. package/lib/validation/validator.js +7 -9
  125. package/lib/validation/wizard-datasource-validation.js +50 -0
  126. package/package.json +7 -2
  127. package/templates/applications/dataplane/application.yaml +1 -1
  128. package/templates/applications/dataplane/env.template +5 -5
  129. package/templates/applications/dataplane/rbac.yaml +2 -2
  130. package/templates/applications/miso-controller/env.template +1 -1
  131. package/templates/external-system/README.md.hbs +65 -25
  132. package/templates/external-system/deploy.js.hbs +4 -2
  133. package/templates/external-system/external-datasource.yaml.hbs +217 -0
  134. package/templates/external-system/external-system.json.hbs +1 -18
  135. package/templates/infra/compose.yaml.hbs +6 -0
  136. package/templates/python/docker-compose.hbs +4 -4
  137. package/templates/typescript/docker-compose.hbs +4 -4
  138. package/integration/hubspot/application.yaml +0 -37
@@ -0,0 +1,30 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+ # Documentation Rules – CLI User Docs
5
+
6
+ ## Audience
7
+
8
+ Documents under **docs/** (including **docs/commands/**) are **CLI developer / user documentation**. The audience is people who use the AI Fabrix Builder CLI or integrate it into workflows. They do not need to know how the CLI talks to the Controller or Dataplane over HTTP.
9
+
10
+ ## Do Not Include in CLI User Docs
11
+
12
+ - **REST API details** – No HTTP methods, URL paths, or endpoint names (e.g. `GET /api/v1/...`, `POST .../pipeline/upload`).
13
+ - **Request/response shapes** – No payload structures, status codes, or field names from backend APIs.
14
+ - **Backend implementation terms** – Avoid referring to “pipeline config endpoint”, “upload endpoint”, or similar; describe what the **command** does from the user’s perspective.
15
+
16
+ Keep these details in code (JSDoc, lib comments) or in separate API/implementation docs for contributors.
17
+
18
+ ## Do Include in CLI User Docs
19
+
20
+ - **What the command does** – Outcome and behavior in user terms (e.g. “Downloads the full manifest from the dataplane”, “Uploads config and publishes to the dataplane”).
21
+ - **Prerequisites** – Login, permissions, and auth in user terms (e.g. “Must be logged in with `aifabrix login`”; “Bearer token required” without naming the backend endpoint).
22
+ - **Options and arguments** – All flags, arguments, and examples.
23
+ - **What gets created or changed** – Files, folders, and config the user will see.
24
+ - **Troubleshooting** – Common errors and fixes in CLI terms (e.g. “Run `aifabrix login`” instead of “Ensure the pipeline config endpoint receives a Bearer token”).
25
+
26
+ ## When Editing docs/
27
+
28
+ - Prefer **command-centric** language: “the download command fetches…”, “upload publishes…”.
29
+ - Describe **auth** by what the user must do (login, device flow) and whether a Bearer token is required, not by which backend endpoint is called.
30
+ - If a command uses the dataplane or controller, say so in plain language (“from the dataplane”, “to the controller”) without exposing URLs or HTTP details.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@aifabrix/builder.svg)](https://www.npmjs.com/package/@aifabrix/builder)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Install the AI Fabrix platform and test it locally. Then add external integrations or build your own applications.
6
+ Open developer runtime for AI Fabrix ecosystem. Install the AI Fabrix platform and test it locally. Then add external integrations or build your own applications.
7
7
 
8
8
  ← **Full documentation:** [docs/README.md](docs/README.md) (table of contents for all guides)
9
9
 
@@ -1,17 +1,21 @@
1
- # HubSpot CRM Integration
1
+ # HubSpot CRM
2
2
 
3
- HubSpot CRM external system integration with companies, contacts, and deals
3
+ HubSpot CRM integration with OpenAPI support for companies, contacts, and deals
4
4
 
5
5
  ## System Information
6
6
 
7
7
  - **System Key**: `hubspot`
8
8
  - **System Type**: `openapi`
9
- - **Datasources**: 0
9
+ - **Datasources**: 4
10
10
 
11
11
  ## Files
12
12
 
13
13
  - `application.yaml` – Application configuration with `app` and `externalIntegration` blocks
14
- - `hubspot-system.json` – External system definition (authentication, OpenAPI/MCP, RBAC)
14
+ - `hubspot-system.yaml` – External system definition (authentication, OpenAPI/MCP, RBAC)
15
+ - `hubspot-datasource-deal.yaml` – Datasource: HubSpot Deal
16
+ - `hubspot-datasource-contact.yaml` – Datasource: HubSpot Contact
17
+ - `hubspot-datasource-users-datasource.yaml` – Datasource: HubSpot Users
18
+ - `hubspot-datasource-company.yaml` – Datasource: HubSpot Company
15
19
  - `env.template` – Environment variables template (secrets, API keys)
16
20
  - `hubspot-deploy.json` – Deployment manifest (generated by `aifabrix json`)
17
21
 
@@ -0,0 +1,54 @@
1
+ {
2
+ "app": {
3
+ "key": "hubspot",
4
+ "displayName": "HubSpot CRM",
5
+ "description": "HubSpot CRM integration with OpenAPI support for companies, contacts, and deals",
6
+ "type": "external"
7
+ },
8
+ "externalIntegration": {
9
+ "schemaBasePath": "./",
10
+ "systems": [
11
+ "hubspot-system.json"
12
+ ],
13
+ "dataSources": [
14
+ "hubspot-datasource-company.json",
15
+ "hubspot-datasource-contact.json",
16
+ "hubspot-datasource-deal.json",
17
+ "hubspot-datasource-users.json"
18
+ ],
19
+ "autopublish": true,
20
+ "version": "1.0.0"
21
+ },
22
+ "configuration": [
23
+ {
24
+ "name": "HUBSPOT_API_VERSION",
25
+ "portalInput": {
26
+ "field": "select",
27
+ "label": "HubSpot API Version",
28
+ "placeholder": "Select API version",
29
+ "options": [
30
+ "v1",
31
+ "v2",
32
+ "v3"
33
+ ],
34
+ "validation": {
35
+ "required": false
36
+ }
37
+ }
38
+ },
39
+ {
40
+ "name": "MAX_PAGE_SIZE",
41
+ "portalInput": {
42
+ "field": "text",
43
+ "label": "Maximum Page Size",
44
+ "placeholder": "100",
45
+ "validation": {
46
+ "required": false,
47
+ "pattern": "^[0-9]+$",
48
+ "minLength": 1,
49
+ "maxLength": 1000
50
+ }
51
+ }
52
+ }
53
+ ]
54
+ }
@@ -42,7 +42,6 @@ function printUsage() {
42
42
  ' --output <dir> Output directory for files (default: integration/<name>)',
43
43
  ' --controller <url> Controller URL (default: env CONTROLLER_URL)',
44
44
  ' --environment <env> Environment name (default: env ENVIRONMENT)',
45
- ' --dataplane <url> Dataplane URL (optional, will be auto-discovered)',
46
45
  ' --keep-wizard-files Keep wizard-generated files in integration/ directory',
47
46
  ' --help Show this help message',
48
47
  '',
@@ -66,7 +65,6 @@ function parseArgs(argv) {
66
65
  output: null,
67
66
  controller: DEFAULT_CONTROLLER_URL,
68
67
  environment: DEFAULT_ENVIRONMENT,
69
- dataplane: process.env.DATAPLANE_URL || null,
70
68
  keepWizardFiles: false,
71
69
  help: false
72
70
  };
@@ -76,8 +74,7 @@ function parseArgs(argv) {
76
74
  '--openapi': 'openapi',
77
75
  '--output': 'output',
78
76
  '--controller': 'controller',
79
- '--environment': 'environment',
80
- '--dataplane': 'dataplane'
77
+ '--environment': 'environment'
81
78
  };
82
79
 
83
80
  for (let i = 2; i < argv.length; i += 1) {
@@ -203,119 +200,16 @@ async function createWizardConfig(appName, openapiFile, controllerUrl, environme
203
200
  return configPath;
204
201
  }
205
202
 
206
- /**
207
- * Tests a single endpoint for reachability
208
- * @async
209
- * @function testEndpoint
210
- * @param {string} testUrl - URL to test
211
- * @param {number} timeoutMs - Timeout in milliseconds
212
- * @returns {Promise<boolean>} True if endpoint is reachable
213
- */
214
- async function testEndpoint(testUrl, timeoutMs) {
215
- try {
216
- const controller = new AbortController();
217
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
218
-
219
- const response = await Promise.race([
220
- fetch(testUrl, {
221
- method: 'GET',
222
- signal: controller.signal,
223
- headers: { 'Accept': 'application/json' }
224
- }),
225
- new Promise((_, reject) =>
226
- setTimeout(() => reject(new Error('Timeout')), timeoutMs)
227
- )
228
- ]).catch(() => null);
229
-
230
- clearTimeout(timeoutId);
231
-
232
- // If we get any response (even 404 or 401), the service is reachable
233
- // 401 is OK because it means the API is working, just needs auth
234
- if (response && (response.ok || response.status === 404 || response.status === 401)) {
235
- return true;
236
- }
237
-
238
- // If we get a 500 or other server error, the service is up but broken
239
- // Still consider it "reachable" - the wizard will handle the actual error
240
- return response && response.status >= 500;
241
- } catch (error) {
242
- // Timeout or abort means endpoint is not reachable
243
- return false;
244
- }
245
- }
246
-
247
- /**
248
- * Checks if dataplane URL is reachable and API is functional
249
- * @async
250
- * @function checkDataplaneHealth
251
- * @param {string} dataplaneUrl - Dataplane URL to check
252
- * @param {number} timeoutMs - Timeout in milliseconds (default: 5000)
253
- * @returns {Promise<boolean>} True if dataplane is reachable and functional
254
- */
255
- async function checkDataplaneHealth(dataplaneUrl, timeoutMs = 5000) {
256
- if (!dataplaneUrl) {
257
- return false;
258
- }
259
-
260
- const baseUrl = dataplaneUrl.replace(/\/$/, '');
261
- const endpointsToTest = ['/health', '/api/v1/health', '/api/health', ''];
262
-
263
- for (const endpoint of endpointsToTest) {
264
- const testUrl = endpoint ? `${baseUrl}${endpoint}` : baseUrl;
265
- const isReachable = await testEndpoint(testUrl, timeoutMs);
266
- if (isReachable) {
267
- return true;
268
- }
269
- }
270
-
271
- return false;
272
- }
273
-
274
- /**
275
- * Validates dataplane health before running wizard
276
- * @async
277
- * @function validateDataplaneHealth
278
- * @param {string} dataplaneUrl - Dataplane URL to check
279
- * @returns {Promise<Object|null>} Error object if unhealthy, null if healthy
280
- */
281
- async function validateDataplaneHealth(dataplaneUrl) {
282
- logInfo('Checking dataplane connectivity...');
283
- try {
284
- const isHealthy = await checkDataplaneHealth(dataplaneUrl, 5000);
285
- if (!isHealthy) {
286
- return {
287
- success: false,
288
- stdout: '',
289
- stderr: '',
290
- error: `Dataplane is not reachable at ${dataplaneUrl}.\n\n` +
291
- 'Please ensure the dataplane service is running and accessible, then try again.\n' +
292
- `You can check dataplane status with: curl ${dataplaneUrl}/health`
293
- };
294
- }
295
- logSuccess('✓ Dataplane is reachable');
296
- return null;
297
- } catch (error) {
298
- return {
299
- success: false,
300
- stdout: '',
301
- stderr: '',
302
- error: `Failed to check dataplane health: ${error.message}\n\n` +
303
- `The dataplane at ${dataplaneUrl} may be down or unreachable.`
304
- };
305
- }
306
- }
307
-
308
203
  /**
309
204
  * Builds wizard command arguments
310
205
  * @function buildWizardArgs
311
206
  * @param {string} configPath - Path to wizard config file
312
207
  * @param {string} controllerUrl - Controller URL
313
208
  * @param {string} environment - Environment name
314
- * @param {string|null} dataplaneUrl - Optional dataplane URL
315
209
  * @returns {string[]} Command arguments
316
210
  */
317
- function buildWizardArgs(configPath, controllerUrl, environment, dataplaneUrl) {
318
- const args = [
211
+ function buildWizardArgs(configPath, controllerUrl, environment) {
212
+ return [
319
213
  'bin/aifabrix.js',
320
214
  'wizard',
321
215
  '--config',
@@ -325,19 +219,13 @@ function buildWizardArgs(configPath, controllerUrl, environment, dataplaneUrl) {
325
219
  '--environment',
326
220
  environment
327
221
  ];
328
-
329
- if (dataplaneUrl) {
330
- args.push('--dataplane', dataplaneUrl);
331
- }
332
-
333
- return args;
334
222
  }
335
223
 
336
224
  /**
337
225
  * Handles wizard command execution errors
338
226
  * @function handleWizardError
339
227
  * @param {Error} error - Error object
340
- * @param {string|null} dataplaneUrl - Dataplane URL
228
+ * @param {string|null} dataplaneUrl - Dataplane URL (for error context; may be null when auto-discovered)
341
229
  * @returns {Object} Error result object
342
230
  */
343
231
  function handleWizardError(error, dataplaneUrl) {
@@ -382,21 +270,11 @@ function handleWizardError(error, dataplaneUrl) {
382
270
  * @param {string} configPath - Path to wizard config file
383
271
  * @param {string} controllerUrl - Controller URL
384
272
  * @param {string} environment - Environment name
385
- * @param {string|null} dataplaneUrl - Optional dataplane URL
386
273
  * @returns {Promise<Object>} Command result object
387
274
  */
388
- async function runWizard(configPath, controllerUrl, environment, dataplaneUrl) {
389
- if (dataplaneUrl) {
390
- const healthError = await validateDataplaneHealth(dataplaneUrl);
391
- if (healthError) {
392
- return healthError;
393
- }
394
- } else {
395
- logInfo('Note: No dataplane URL provided. Wizard will attempt to discover it from controller.');
396
- logInfo('If dataplane discovery fails or hangs, provide --dataplane <url> explicitly.');
397
- }
398
-
399
- const args = buildWizardArgs(configPath, controllerUrl, environment, dataplaneUrl);
275
+ async function runWizard(configPath, controllerUrl, environment) {
276
+ logInfo('Note: Dataplane URL is auto-discovered from the controller.');
277
+ const args = buildWizardArgs(configPath, controllerUrl, environment);
400
278
 
401
279
  try {
402
280
  const result = await execFileAsync('node', args, {
@@ -407,7 +285,7 @@ async function runWizard(configPath, controllerUrl, environment, dataplaneUrl) {
407
285
  });
408
286
  return { success: true, stdout: result.stdout || '', stderr: result.stderr || '' };
409
287
  } catch (error) {
410
- return handleWizardError(error, dataplaneUrl);
288
+ return handleWizardError(error, null);
411
289
  }
412
290
  }
413
291
 
@@ -529,12 +407,7 @@ async function executeWizard(args) {
529
407
  logSuccess(`✓ Created config: ${configPath}`);
530
408
 
531
409
  logInfo('\n2. Running wizard...');
532
- const wizardResult = await runWizard(
533
- configPath,
534
- args.controller,
535
- args.environment,
536
- args.dataplane
537
- );
410
+ const wizardResult = await runWizard(configPath, args.controller, args.environment);
538
411
 
539
412
  if (!wizardResult.success) {
540
413
  logError('Wizard failed:');
@@ -1,5 +1,4 @@
1
- CLIENTID=kv://hubspot-clientidKeyVault
2
- CLIENTSECRET=kv://hubspot-clientsecretKeyVault
3
- TOKENURL=https://api.hubapi.com/oauth/v1/token
4
1
  HUBSPOT_API_VERSION=v3
5
- MAX_PAGE_SIZE=100
2
+ MAX_PAGE_SIZE=100
3
+ KV_HUBSPOT_CLIENTID=kv://hubspot/clientid
4
+ KV_HUBSPOT_CLIENTSECRET=kv://hubspot/clientsecret