@aifabrix/builder 2.7.0 → 2.9.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 (47) hide show
  1. package/.cursor/rules/project-rules.mdc +680 -0
  2. package/integration/hubspot/README.md +136 -0
  3. package/integration/hubspot/env.template +9 -0
  4. package/integration/hubspot/hubspot-deploy-company.json +200 -0
  5. package/integration/hubspot/hubspot-deploy-contact.json +228 -0
  6. package/integration/hubspot/hubspot-deploy-deal.json +248 -0
  7. package/integration/hubspot/hubspot-deploy.json +91 -0
  8. package/integration/hubspot/variables.yaml +17 -0
  9. package/lib/app-config.js +13 -2
  10. package/lib/app-deploy.js +9 -3
  11. package/lib/app-dockerfile.js +14 -1
  12. package/lib/app-prompts.js +177 -13
  13. package/lib/app-push.js +16 -1
  14. package/lib/app-register.js +37 -5
  15. package/lib/app-rotate-secret.js +10 -0
  16. package/lib/app-run.js +19 -0
  17. package/lib/app.js +70 -25
  18. package/lib/audit-logger.js +9 -4
  19. package/lib/build.js +25 -13
  20. package/lib/cli.js +109 -2
  21. package/lib/commands/login.js +40 -3
  22. package/lib/config.js +121 -114
  23. package/lib/datasource-deploy.js +14 -20
  24. package/lib/environment-deploy.js +305 -0
  25. package/lib/external-system-deploy.js +345 -0
  26. package/lib/external-system-download.js +431 -0
  27. package/lib/external-system-generator.js +190 -0
  28. package/lib/external-system-test.js +446 -0
  29. package/lib/generator-builders.js +323 -0
  30. package/lib/generator.js +200 -292
  31. package/lib/schema/application-schema.json +830 -800
  32. package/lib/schema/external-datasource.schema.json +868 -46
  33. package/lib/schema/external-system.schema.json +98 -80
  34. package/lib/schema/infrastructure-schema.json +1 -1
  35. package/lib/templates.js +32 -1
  36. package/lib/utils/cli-utils.js +4 -4
  37. package/lib/utils/device-code.js +10 -2
  38. package/lib/utils/external-system-display.js +159 -0
  39. package/lib/utils/external-system-validators.js +245 -0
  40. package/lib/utils/paths.js +151 -1
  41. package/lib/utils/schema-resolver.js +7 -2
  42. package/lib/utils/token-encryption.js +68 -0
  43. package/lib/validator.js +52 -5
  44. package/package.json +1 -1
  45. package/tatus +181 -0
  46. package/templates/external-system/external-datasource.json.hbs +55 -0
  47. package/templates/external-system/external-system.json.hbs +37 -0
@@ -0,0 +1,248 @@
1
+ {
2
+ "key": "hubspot-deal",
3
+ "displayName": "HubSpot Deal",
4
+ "description": "HubSpot deals datasource with field mappings for CRM deal data",
5
+ "systemKey": "hubspot",
6
+ "entityKey": "deal",
7
+ "resourceType": "deal",
8
+ "enabled": true,
9
+ "version": "1.0.0",
10
+ "metadataSchema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "id": {
14
+ "type": "string"
15
+ },
16
+ "properties": {
17
+ "type": "object",
18
+ "properties": {
19
+ "dealname": {
20
+ "type": "object",
21
+ "properties": {
22
+ "value": {
23
+ "type": "string"
24
+ }
25
+ }
26
+ },
27
+ "amount": {
28
+ "type": "object",
29
+ "properties": {
30
+ "value": {
31
+ "type": "string"
32
+ }
33
+ }
34
+ },
35
+ "deal_currency_code": {
36
+ "type": "object",
37
+ "properties": {
38
+ "value": {
39
+ "type": "string"
40
+ }
41
+ }
42
+ },
43
+ "dealstage": {
44
+ "type": "object",
45
+ "properties": {
46
+ "value": {
47
+ "type": "string"
48
+ }
49
+ }
50
+ },
51
+ "pipeline": {
52
+ "type": "object",
53
+ "properties": {
54
+ "value": {
55
+ "type": "string"
56
+ }
57
+ }
58
+ },
59
+ "closedate": {
60
+ "type": "object",
61
+ "properties": {
62
+ "value": {
63
+ "type": "string"
64
+ }
65
+ }
66
+ },
67
+ "dealtype": {
68
+ "type": "object",
69
+ "properties": {
70
+ "value": {
71
+ "type": "string"
72
+ }
73
+ }
74
+ },
75
+ "createdate": {
76
+ "type": "object",
77
+ "properties": {
78
+ "value": {
79
+ "type": "string"
80
+ }
81
+ }
82
+ },
83
+ "hs_lastmodifieddate": {
84
+ "type": "object",
85
+ "properties": {
86
+ "value": {
87
+ "type": "string"
88
+ }
89
+ }
90
+ }
91
+ }
92
+ },
93
+ "associations": {
94
+ "type": "object",
95
+ "properties": {
96
+ "companies": {
97
+ "type": "object",
98
+ "properties": {
99
+ "results": {
100
+ "type": "array",
101
+ "items": {
102
+ "type": "object",
103
+ "properties": {
104
+ "id": {
105
+ "type": "string"
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ },
112
+ "contacts": {
113
+ "type": "object",
114
+ "properties": {
115
+ "results": {
116
+ "type": "array",
117
+ "items": {
118
+ "type": "object",
119
+ "properties": {
120
+ "id": {
121
+ "type": "string"
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ },
131
+ "required": ["id", "properties"]
132
+ },
133
+ "fieldMappings": {
134
+ "accessFields": ["stage", "pipeline"],
135
+ "fields": {
136
+ "id": {
137
+ "expression": "{{id}}",
138
+ "type": "string",
139
+ "description": "Unique deal identifier",
140
+ "required": true
141
+ },
142
+ "dealName": {
143
+ "expression": "{{properties.dealname.value}} | trim",
144
+ "type": "string",
145
+ "description": "Deal name",
146
+ "required": false
147
+ },
148
+ "amount": {
149
+ "expression": "{{properties.amount.value}}",
150
+ "type": "string",
151
+ "description": "Deal amount",
152
+ "required": false
153
+ },
154
+ "currency": {
155
+ "expression": "{{properties.deal_currency_code.value}} | toUpper | trim",
156
+ "type": "string",
157
+ "description": "Currency code",
158
+ "required": false
159
+ },
160
+ "stage": {
161
+ "expression": "{{properties.dealstage.value}} | trim",
162
+ "type": "string",
163
+ "description": "Deal stage for ABAC filtering",
164
+ "required": false
165
+ },
166
+ "pipeline": {
167
+ "expression": "{{properties.pipeline.value}} | trim",
168
+ "type": "string",
169
+ "description": "Pipeline name for ABAC filtering",
170
+ "required": false
171
+ },
172
+ "closeDate": {
173
+ "expression": "{{properties.closedate.value}}",
174
+ "type": "string",
175
+ "description": "Expected close date",
176
+ "required": false
177
+ },
178
+ "dealType": {
179
+ "expression": "{{properties.dealtype.value}} | trim",
180
+ "type": "string",
181
+ "description": "Deal type",
182
+ "required": false
183
+ },
184
+ "associatedCompany": {
185
+ "expression": "{{associations.companies.results[0].id}}",
186
+ "type": "string",
187
+ "description": "Associated company ID",
188
+ "required": false
189
+ },
190
+ "associatedContacts": {
191
+ "expression": "{{associations.contacts.results}}",
192
+ "type": "array",
193
+ "description": "Array of associated contact IDs",
194
+ "required": false
195
+ },
196
+ "createdAt": {
197
+ "expression": "{{properties.createdate.value}}",
198
+ "type": "string",
199
+ "description": "Creation timestamp",
200
+ "required": false
201
+ },
202
+ "updatedAt": {
203
+ "expression": "{{properties.hs_lastmodifieddate.value}}",
204
+ "type": "string",
205
+ "description": "Last modification timestamp",
206
+ "required": false
207
+ }
208
+ }
209
+ },
210
+ "exposed": {
211
+ "fields": ["id", "dealName", "amount", "currency", "stage", "pipeline", "closeDate", "dealType", "associatedCompany", "associatedContacts", "createdAt", "updatedAt"],
212
+ "description": "Exposed fields for HubSpot deals"
213
+ },
214
+ "openapi": {
215
+ "enabled": true,
216
+ "documentKey": "hubspot-v3",
217
+ "baseUrl": "https://api.hubapi.com",
218
+ "operations": {
219
+ "list": {
220
+ "operationId": "getDeals",
221
+ "method": "GET",
222
+ "path": "/crm/v3/objects/deals"
223
+ },
224
+ "get": {
225
+ "operationId": "getDeal",
226
+ "method": "GET",
227
+ "path": "/crm/v3/objects/deals/{dealId}"
228
+ },
229
+ "create": {
230
+ "operationId": "createDeal",
231
+ "method": "POST",
232
+ "path": "/crm/v3/objects/deals"
233
+ },
234
+ "update": {
235
+ "operationId": "updateDeal",
236
+ "method": "PATCH",
237
+ "path": "/crm/v3/objects/deals/{dealId}"
238
+ },
239
+ "delete": {
240
+ "operationId": "deleteDeal",
241
+ "method": "DELETE",
242
+ "path": "/crm/v3/objects/deals/{dealId}"
243
+ }
244
+ },
245
+ "autoRbac": true
246
+ }
247
+ }
248
+
@@ -0,0 +1,91 @@
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": ["v1", "v2", "v3"],
62
+ "validation": {
63
+ "required": false
64
+ }
65
+ }
66
+ },
67
+ {
68
+ "name": "MAX_PAGE_SIZE",
69
+ "value": "100",
70
+ "location": "variable",
71
+ "required": false,
72
+ "portalInput": {
73
+ "field": "text",
74
+ "label": "Maximum Page Size",
75
+ "placeholder": "100",
76
+ "validation": {
77
+ "required": false,
78
+ "pattern": "^[0-9]+$",
79
+ "min": 1,
80
+ "max": 1000
81
+ }
82
+ }
83
+ }
84
+ ],
85
+ "openapi": {
86
+ "documentKey": "hubspot-v3",
87
+ "autoDiscoverEntities": false
88
+ },
89
+ "tags": ["crm", "sales", "marketing", "hubspot"]
90
+ }
91
+
@@ -0,0 +1,17 @@
1
+ app:
2
+ key: hubspot
3
+ displayName: "HubSpot CRM Integration"
4
+ description: "HubSpot CRM external system integration with companies, contacts, and deals"
5
+ type: external
6
+
7
+ externalIntegration:
8
+ schemaBasePath: ./
9
+ systems:
10
+ - hubspot-deploy.json
11
+ dataSources:
12
+ - hubspot-deploy-company.json
13
+ - hubspot-deploy-contact.json
14
+ - hubspot-deploy-deal.json
15
+ autopublish: true
16
+ version: 1.0.0
17
+
package/lib/app-config.js CHANGED
@@ -54,6 +54,11 @@ async function generateVariablesYamlFile(appPath, appName, config) {
54
54
  * @param {Object} existingEnv - Existing environment variables
55
55
  */
56
56
  async function generateEnvTemplateFile(appPath, config, existingEnv) {
57
+ // Skip env.template for external type
58
+ if (config.type === 'external') {
59
+ return;
60
+ }
61
+
57
62
  const envTemplatePath = path.join(appPath, 'env.template');
58
63
  if (!(await fileExists(envTemplatePath))) {
59
64
  let envTemplate;
@@ -94,13 +99,18 @@ async function generateRbacYamlFile(appPath, appName, config) {
94
99
  }
95
100
 
96
101
  /**
97
- * Generates aifabrix-deploy.json file
102
+ * Generates <app-name>-deploy.json file (consistent naming for all apps)
98
103
  * @async
99
104
  * @param {string} appPath - Path to application directory
100
105
  * @param {string} appName - Application name
101
106
  * @param {Object} config - Application configuration
102
107
  */
103
108
  async function generateDeployJsonFile(appPath, appName, config) {
109
+ // Skip for external type (external system JSON is generated separately)
110
+ if (config.type === 'external') {
111
+ return;
112
+ }
113
+
104
114
  const deployJson = {
105
115
  apiVersion: 'v1',
106
116
  kind: 'ApplicationDeployment',
@@ -128,8 +138,9 @@ async function generateDeployJsonFile(appPath, appName, config) {
128
138
  }
129
139
  };
130
140
 
141
+ // Use consistent naming: <app-name>-deploy.json
131
142
  await fs.writeFile(
132
- path.join(appPath, 'aifabrix-deploy.json'),
143
+ path.join(appPath, `${appName}-deploy.json`),
133
144
  JSON.stringify(deployJson, null, 2)
134
145
  );
135
146
  }
package/lib/app-deploy.js CHANGED
@@ -17,6 +17,7 @@ const pushUtils = require('./push');
17
17
  const logger = require('./utils/logger');
18
18
  const config = require('./config');
19
19
  const { getDeploymentAuth } = require('./utils/token-manager');
20
+ const { detectAppType } = require('./utils/paths');
20
21
 
21
22
  /**
22
23
  * Validate application name format
@@ -215,10 +216,11 @@ function validateDeploymentConfig(deploymentConfig) {
215
216
  * @throws {Error} If configuration is invalid
216
217
  */
217
218
  async function loadDeploymentConfig(appName, options) {
218
- const builderPath = path.join(process.cwd(), 'builder', appName);
219
- await validateAppDirectory(builderPath, appName);
219
+ // Detect app type and get correct path (integration or builder)
220
+ const { appPath } = await detectAppType(appName);
221
+ await validateAppDirectory(appPath, appName);
220
222
 
221
- const variablesPath = path.join(builderPath, 'variables.yaml');
223
+ const variablesPath = path.join(appPath, 'variables.yaml');
222
224
  const variables = await loadVariablesFile(variablesPath);
223
225
 
224
226
  const deploymentConfig = extractDeploymentConfig(options, variables);
@@ -366,6 +368,10 @@ async function deployApp(appName, options = {}) {
366
368
 
367
369
  validateAppName(appName);
368
370
 
371
+ // 2. Check if app type is external - use normal deployment flow with application-schema.json
372
+ // External systems now deploy via miso controller as normal application (full application file)
373
+ // The json command generates application-schema.json which is used for deployment
374
+
369
375
  // 2. Load deployment configuration
370
376
  config = await loadDeploymentConfig(appName, options);
371
377
  controllerUrl = config.controllerUrl || options.controller || 'unknown';
@@ -84,11 +84,24 @@ async function generateAndCopyDockerfile(appPath, dockerfilePath, config) {
84
84
  * @returns {Promise<string>} Path to generated Dockerfile
85
85
  */
86
86
  async function generateDockerfileForApp(appName, options = {}) {
87
+ // Check if app type is external - skip Dockerfile generation
88
+ const { detectAppType } = require('./utils/paths');
89
+ try {
90
+ const { isExternal } = await detectAppType(appName);
91
+ if (isExternal) {
92
+ logger.log(chalk.yellow('⚠️ External systems don\'t require Dockerfiles. Skipping...'));
93
+ return null;
94
+ }
95
+ } catch (error) {
96
+ // If detection fails, continue with normal generation
97
+ // (detectAppType throws if app doesn't exist, which is fine for dockerfile command)
98
+ }
87
99
  try {
88
100
  // Validate app name
89
101
  validateAppName(appName);
90
102
 
91
- const appPath = path.join(process.cwd(), 'builder', appName);
103
+ // Detect app type and get correct path (integration or builder)
104
+ const { appPath } = await detectAppType(appName);
92
105
  const dockerfilePath = path.join(appPath, 'Dockerfile');
93
106
 
94
107
  // Check if Dockerfile already exists