@aifabrix/builder 2.40.2 → 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 (198) hide show
  1. package/.cursor/rules/docs-rules.mdc +30 -0
  2. package/README.md +7 -5
  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/integration/hubspot/test.js +1 -1
  16. package/jest.config.manual.js +2 -1
  17. package/lib/api/credential.api.js +40 -0
  18. package/lib/api/dev.api.js +423 -0
  19. package/lib/api/external-test.api.js +111 -0
  20. package/lib/api/index.js +42 -19
  21. package/lib/api/pipeline.api.js +66 -120
  22. package/lib/api/types/credential.types.js +23 -0
  23. package/lib/api/types/dev.types.js +140 -0
  24. package/lib/api/types/pipeline.types.js +37 -0
  25. package/lib/api/wizard-platform.api.js +61 -0
  26. package/lib/api/wizard.api.js +34 -1
  27. package/lib/app/config.js +44 -11
  28. package/lib/app/down.js +2 -1
  29. package/lib/app/index.js +12 -1
  30. package/lib/app/prompts.js +44 -29
  31. package/lib/app/push.js +36 -12
  32. package/lib/app/readme.js +9 -6
  33. package/lib/app/run-env-compose.js +264 -0
  34. package/lib/app/run-helpers.js +121 -118
  35. package/lib/app/run.js +148 -28
  36. package/lib/app/show-display.js +1 -1
  37. package/lib/app/show.js +5 -2
  38. package/lib/build/index.js +11 -3
  39. package/lib/cli/setup-app.js +172 -15
  40. package/lib/cli/setup-credential-deployment.js +31 -6
  41. package/lib/cli/setup-dev.js +206 -16
  42. package/lib/cli/setup-environment.js +16 -6
  43. package/lib/cli/setup-external-system.js +89 -24
  44. package/lib/cli/setup-infra.js +82 -15
  45. package/lib/cli/setup-secrets.js +52 -5
  46. package/lib/cli/setup-utility.js +129 -24
  47. package/lib/commands/app-install.js +172 -0
  48. package/lib/commands/app-shell.js +75 -0
  49. package/lib/commands/app-test.js +282 -0
  50. package/lib/commands/app.js +1 -1
  51. package/lib/commands/credential-env.js +162 -0
  52. package/lib/commands/credential-list.js +17 -22
  53. package/lib/commands/credential-push.js +96 -0
  54. package/lib/commands/datasource.js +77 -6
  55. package/lib/commands/dev-cli-handlers.js +141 -0
  56. package/lib/commands/dev-down.js +114 -0
  57. package/lib/commands/dev-init.js +347 -0
  58. package/lib/commands/repair-auth-config.js +99 -0
  59. package/lib/commands/repair-datasource-keys.js +208 -0
  60. package/lib/commands/repair-datasource.js +235 -0
  61. package/lib/commands/repair-env-template.js +348 -0
  62. package/lib/commands/repair-internal.js +85 -0
  63. package/lib/commands/repair-rbac.js +158 -0
  64. package/lib/commands/repair.js +507 -0
  65. package/lib/commands/secrets-list.js +118 -0
  66. package/lib/commands/secrets-remove.js +97 -0
  67. package/lib/commands/secrets-set.js +30 -17
  68. package/lib/commands/secrets-validate.js +50 -0
  69. package/lib/commands/test-e2e-external.js +165 -0
  70. package/lib/commands/up-dataplane.js +2 -2
  71. package/lib/commands/up-miso.js +0 -25
  72. package/lib/commands/upload.js +96 -40
  73. package/lib/commands/wizard-core-helpers.js +226 -4
  74. package/lib/commands/wizard-core.js +67 -29
  75. package/lib/commands/wizard-dataplane.js +1 -1
  76. package/lib/commands/wizard-entity-selection.js +43 -0
  77. package/lib/commands/wizard-headless.js +44 -5
  78. package/lib/commands/wizard-helpers.js +7 -3
  79. package/lib/commands/wizard.js +86 -64
  80. package/lib/core/admin-secrets.js +96 -0
  81. package/lib/core/config.js +7 -1
  82. package/lib/core/secrets-ensure.js +378 -0
  83. package/lib/core/secrets-env-write.js +157 -0
  84. package/lib/core/secrets.js +176 -89
  85. package/lib/datasource/deploy.js +12 -3
  86. package/lib/datasource/field-reference-validator.js +91 -0
  87. package/lib/datasource/test-e2e.js +219 -0
  88. package/lib/datasource/test-integration.js +154 -0
  89. package/lib/datasource/validate.js +21 -3
  90. package/lib/deployment/deployer.js +7 -5
  91. package/lib/deployment/environment-config.js +137 -0
  92. package/lib/deployment/environment.js +21 -98
  93. package/lib/deployment/push.js +32 -2
  94. package/lib/external-system/download.js +188 -203
  95. package/lib/external-system/generator.js +204 -56
  96. package/lib/external-system/test-auth.js +7 -3
  97. package/lib/external-system/test-execution.js +2 -1
  98. package/lib/external-system/test-system-level.js +73 -0
  99. package/lib/external-system/test.js +56 -19
  100. package/lib/generator/external-controller-manifest.js +29 -2
  101. package/lib/generator/external-schema-utils.js +1 -1
  102. package/lib/generator/external.js +10 -3
  103. package/lib/generator/index.js +177 -25
  104. package/lib/generator/split-readme.js +1 -0
  105. package/lib/generator/split-variables.js +7 -1
  106. package/lib/generator/split.js +194 -54
  107. package/lib/generator/wizard-prompts-secondary.js +294 -0
  108. package/lib/generator/wizard-prompts.js +105 -106
  109. package/lib/generator/wizard-readme.js +88 -0
  110. package/lib/generator/wizard.js +155 -158
  111. package/lib/infrastructure/compose.js +11 -1
  112. package/lib/infrastructure/helpers.js +103 -20
  113. package/lib/infrastructure/index.js +98 -12
  114. package/lib/infrastructure/services.js +88 -22
  115. package/lib/schema/application-schema.json +32 -8
  116. package/lib/schema/external-datasource.schema.json +49 -26
  117. package/lib/schema/external-system.schema.json +509 -411
  118. package/lib/schema/wizard-config.schema.json +16 -0
  119. package/lib/utils/api.js +41 -13
  120. package/lib/utils/app-register-auth.js +25 -3
  121. package/lib/utils/auth-headers.js +8 -7
  122. package/lib/utils/cli-utils.js +20 -0
  123. package/lib/utils/compose-generator.js +77 -76
  124. package/lib/utils/compose-handlebars-helpers.js +54 -0
  125. package/lib/utils/compose-vector-helper.js +18 -0
  126. package/lib/utils/config-format-preference.js +51 -0
  127. package/lib/utils/config-format.js +36 -0
  128. package/lib/utils/config-paths.js +127 -2
  129. package/lib/utils/configuration-env-resolver.js +179 -0
  130. package/lib/utils/credential-display.js +83 -0
  131. package/lib/utils/credential-secrets-env.js +357 -0
  132. package/lib/utils/dataplane-pipeline-warning.js +28 -0
  133. package/lib/utils/deployment-validation-helpers.js +4 -4
  134. package/lib/utils/dev-ca-install.js +139 -0
  135. package/lib/utils/dev-cert-helper.js +122 -0
  136. package/lib/utils/device-code-helpers.js +224 -0
  137. package/lib/utils/device-code.js +37 -336
  138. package/lib/utils/docker-build.js +40 -8
  139. package/lib/utils/env-copy.js +103 -13
  140. package/lib/utils/env-map.js +35 -5
  141. package/lib/utils/env-template.js +6 -5
  142. package/lib/utils/error-formatters/http-status-errors.js +20 -2
  143. package/lib/utils/error-formatters/permission-errors.js +0 -1
  144. package/lib/utils/error-formatters/validation-errors.js +0 -1
  145. package/lib/utils/external-readme.js +56 -29
  146. package/lib/utils/external-system-display.js +59 -1
  147. package/lib/utils/external-system-test-helpers.js +21 -8
  148. package/lib/utils/external-system-validators.js +3 -0
  149. package/lib/utils/file-upload.js +20 -50
  150. package/lib/utils/help-builder.js +16 -2
  151. package/lib/utils/infra-status.js +80 -45
  152. package/lib/utils/local-secrets.js +7 -52
  153. package/lib/utils/mutagen-install.js +195 -0
  154. package/lib/utils/mutagen.js +146 -0
  155. package/lib/utils/paths.js +128 -37
  156. package/lib/utils/port-resolver.js +28 -16
  157. package/lib/utils/remote-dev-auth.js +38 -0
  158. package/lib/utils/remote-docker-env.js +43 -0
  159. package/lib/utils/remote-secrets-loader.js +60 -0
  160. package/lib/utils/secrets-canonical.js +93 -0
  161. package/lib/utils/secrets-generator.js +114 -6
  162. package/lib/utils/secrets-helpers.js +108 -114
  163. package/lib/utils/secrets-path.js +2 -2
  164. package/lib/utils/secrets-utils.js +52 -1
  165. package/lib/utils/secrets-validation.js +84 -0
  166. package/lib/utils/ssh-key-helper.js +116 -0
  167. package/lib/utils/test-log-writer.js +56 -0
  168. package/lib/utils/token-manager-messages.js +90 -0
  169. package/lib/utils/token-manager.js +29 -36
  170. package/lib/utils/variable-transformer.js +3 -3
  171. package/lib/validation/env-template-auth.js +157 -0
  172. package/lib/validation/env-template-kv.js +41 -0
  173. package/lib/validation/external-manifest-validator.js +25 -0
  174. package/lib/validation/external-system-auth-rules.js +86 -0
  175. package/lib/validation/validate-batch.js +149 -0
  176. package/lib/validation/validate-datasource-keys-api.js +33 -0
  177. package/lib/validation/validate-display.js +94 -16
  178. package/lib/validation/validate.js +25 -12
  179. package/lib/validation/validator.js +72 -9
  180. package/lib/validation/wizard-datasource-validation.js +50 -0
  181. package/package.json +8 -3
  182. package/scripts/install-local.js +34 -15
  183. package/templates/README.md +0 -1
  184. package/templates/applications/README.md.hbs +4 -4
  185. package/templates/applications/dataplane/application.yaml +6 -5
  186. package/templates/applications/dataplane/env.template +15 -10
  187. package/templates/applications/dataplane/rbac.yaml +2 -2
  188. package/templates/applications/keycloak/env.template +2 -0
  189. package/templates/applications/miso-controller/application.yaml +1 -0
  190. package/templates/applications/miso-controller/env.template +12 -10
  191. package/templates/external-system/README.md.hbs +65 -25
  192. package/templates/external-system/deploy.js.hbs +4 -2
  193. package/templates/external-system/external-datasource.yaml.hbs +217 -0
  194. package/templates/external-system/external-system.json.hbs +1 -18
  195. package/templates/infra/compose.yaml.hbs +6 -0
  196. package/templates/python/docker-compose.hbs +49 -23
  197. package/templates/typescript/docker-compose.hbs +48 -22
  198. package/integration/hubspot/application.yaml +0 -37
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @fileoverview External test API - dataplane external endpoints (test, test-e2e)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const { ApiClient } = require('./index');
8
+
9
+ /**
10
+ * Run E2E test for one datasource (config, credential, sync, data, CIP) via dataplane external API.
11
+ * Requires Bearer token or API key; client credentials are not accepted.
12
+ * When asyncRun is true, POST returns 202 with { testRunId, status, startedAt }; caller must poll
13
+ * getE2ETestRun until status is 'completed' or 'failed'. When asyncRun is false, POST returns 200
14
+ * with sync body { steps, success, error?, ... }.
15
+ *
16
+ * @requiresPermission {Dataplane} external-data-source:read
17
+ * @async
18
+ * @function testDatasourceE2E
19
+ * @param {string} dataplaneUrl - Dataplane base URL
20
+ * @param {string} sourceIdOrKey - Source ID or datasource key (e.g. hubspot-test-v4-contacts)
21
+ * @param {Object} authConfig - Authentication configuration (must have token or apiKey; client creds rejected)
22
+ * @param {Object} [body] - Optional request body (e.g. includeDebug, testCrud, recordId, cleanup, primaryKeyValue)
23
+ * @param {Object} [options] - Optional options
24
+ * @param {boolean} [options.asyncRun] - If true, request async run (query param asyncRun=true); response may be 202 with testRunId
25
+ * @returns {Promise<Object>} Response with success, data (sync: steps/success/error; async start: testRunId/status/startedAt), status
26
+ * @throws {Error} If auth lacks Bearer/API_KEY or if test fails
27
+ */
28
+ async function testDatasourceE2E(dataplaneUrl, sourceIdOrKey, authConfig, body = {}, options = {}) {
29
+ if (!authConfig.token && !authConfig.apiKey) {
30
+ throw new Error(
31
+ 'E2E tests require Bearer token or API key. Run \'aifabrix login\' or configure API key. ' +
32
+ 'Client credentials are not supported for external test endpoints.'
33
+ );
34
+ }
35
+ const client = new ApiClient(dataplaneUrl, authConfig);
36
+ const postOptions = { body };
37
+ if (options.asyncRun === true) {
38
+ postOptions.params = { asyncRun: 'true' };
39
+ }
40
+ return await client.post(`/api/v1/external/${encodeURIComponent(sourceIdOrKey)}/test-e2e`, postOptions);
41
+ }
42
+
43
+ /**
44
+ * Poll E2E test run status. Call after testDatasourceE2E with asyncRun true when response has testRunId.
45
+ * Same auth as E2E (Bearer or API key).
46
+ *
47
+ * @requiresPermission {Dataplane} external-data-source:read
48
+ * @async
49
+ * @function getE2ETestRun
50
+ * @param {string} dataplaneUrl - Dataplane base URL
51
+ * @param {string} sourceIdOrKey - Source ID or datasource key
52
+ * @param {string} testRunId - Test run ID from async start response
53
+ * @param {Object} authConfig - Authentication configuration (must have token or apiKey)
54
+ * @returns {Promise<Object>} Poll response: { status, completedActions?, steps?, success?, error?, durationSeconds?, debug? }
55
+ * @throws {Error} If auth lacks Bearer/API_KEY, or if run not found/expired (404)
56
+ */
57
+ async function getE2ETestRun(dataplaneUrl, sourceIdOrKey, testRunId, authConfig) {
58
+ if (!authConfig.token && !authConfig.apiKey) {
59
+ throw new Error(
60
+ 'E2E poll requires Bearer token or API key. Run \'aifabrix login\' or configure API key.'
61
+ );
62
+ }
63
+ if (!testRunId || typeof testRunId !== 'string') {
64
+ throw new Error('testRunId is required for E2E poll');
65
+ }
66
+ const client = new ApiClient(dataplaneUrl, authConfig);
67
+ const response = await client.get(
68
+ `/api/v1/external/${encodeURIComponent(sourceIdOrKey)}/test-e2e/${encodeURIComponent(testRunId)}`
69
+ );
70
+ if (!response.success) {
71
+ if (response.status === 404) {
72
+ throw new Error(
73
+ `E2E test run not found or expired (run ID: ${testRunId}). The run may have been purged or the ID is invalid.`
74
+ );
75
+ }
76
+ throw new Error(response.formattedError || response.error || 'E2E poll failed');
77
+ }
78
+ return response.data || response;
79
+ }
80
+
81
+ /**
82
+ * Run config test for one datasource via dataplane external API.
83
+ * Requires Bearer token or API key; client credentials are not accepted.
84
+ *
85
+ * @requiresPermission {Dataplane} external-data-source:read
86
+ * @async
87
+ * @function testDatasourceConfig
88
+ * @param {string} dataplaneUrl - Dataplane base URL
89
+ * @param {string} sourceIdOrKey - Source ID or datasource key
90
+ * @param {Object} authConfig - Authentication configuration
91
+ * @param {Object} [body] - Optional request body
92
+ * @returns {Promise<Object>} Config test response
93
+ * @throws {Error} If auth lacks Bearer/API_KEY or if test fails
94
+ */
95
+ async function testDatasourceConfig(dataplaneUrl, sourceIdOrKey, authConfig, body = {}) {
96
+ if (!authConfig.token && !authConfig.apiKey) {
97
+ throw new Error(
98
+ 'External config tests require Bearer token or API key. Run \'aifabrix login\' or configure API key.'
99
+ );
100
+ }
101
+ const client = new ApiClient(dataplaneUrl, authConfig);
102
+ return await client.post(`/api/v1/external/${encodeURIComponent(sourceIdOrKey)}/test`, {
103
+ body
104
+ });
105
+ }
106
+
107
+ module.exports = {
108
+ testDatasourceE2E,
109
+ getE2ETestRun,
110
+ testDatasourceConfig
111
+ };
package/lib/api/index.js CHANGED
@@ -13,13 +13,12 @@ const { makeApiCall, authenticatedApiCall } = require('../utils/api');
13
13
  */
14
14
  class ApiClient {
15
15
  /**
16
- * Create an API client instance
16
+ * Create an API client instance.
17
+ * App endpoints receive token-only auth (Bearer). x-client-id/x-client-secret are not sent to app endpoints.
17
18
  * @param {string} baseUrl - Base URL for the API (controller URL)
18
19
  * @param {Object} [authConfig] - Authentication configuration
19
- * @param {string} [authConfig.type] - Auth type ('bearer' | 'client-credentials' | 'client-token')
20
+ * @param {string} [authConfig.type] - Auth type ('bearer' | 'client-token')
20
21
  * @param {string} [authConfig.token] - Bearer token
21
- * @param {string} [authConfig.clientId] - Client ID
22
- * @param {string} [authConfig.clientSecret] - Client secret
23
22
  */
24
23
  constructor(baseUrl, authConfig = {}) {
25
24
  if (baseUrl === null || baseUrl === undefined || typeof baseUrl !== 'string') {
@@ -48,26 +47,23 @@ class ApiClient {
48
47
  * Build request headers with authentication
49
48
  * @private
50
49
  * @param {Object} [additionalHeaders] - Additional headers to include
50
+ * @param {Object} [opts] - Options
51
+ * @param {boolean} [opts.skipContentType] - If true, do not set Content-Type (e.g. for FormData when boundary is set by fetch)
51
52
  * @returns {Object} Request headers
52
53
  */
53
- _buildHeaders(additionalHeaders = {}) {
54
- const headers = {
55
- 'Content-Type': 'application/json',
56
- ...additionalHeaders
57
- };
54
+ _buildHeaders(additionalHeaders = {}, opts = {}) {
55
+ const headers = { ...additionalHeaders };
56
+ if (!opts.skipContentType) {
57
+ headers['Content-Type'] = 'application/json';
58
+ }
58
59
 
59
- // Add authentication headers based on authConfig
60
- if (this.authConfig.type === 'bearer' || this.authConfig.type === 'client-token') {
61
- if (this.authConfig.token) {
60
+ // User token (bearer) Authorization: Bearer; application token (client-token) → x-client-token
61
+ if (this.authConfig.token) {
62
+ if (this.authConfig.type === 'client-token') {
63
+ headers['x-client-token'] = this.authConfig.token;
64
+ } else {
62
65
  headers['Authorization'] = `Bearer ${this.authConfig.token}`;
63
66
  }
64
- } else if (this.authConfig.type === 'client-credentials') {
65
- if (this.authConfig.clientId) {
66
- headers['x-client-id'] = this.authConfig.clientId;
67
- }
68
- if (this.authConfig.clientSecret) {
69
- headers['x-client-secret'] = this.authConfig.clientSecret;
70
- }
71
67
  }
72
68
 
73
69
  return headers;
@@ -153,6 +149,33 @@ class ApiClient {
153
149
  return await makeApiCall(url, requestOptions);
154
150
  }
155
151
 
152
+ /**
153
+ * POST multipart/form-data (e.g. file upload). Uses same auth as other methods; does not set Content-Type so fetch sets boundary.
154
+ * @async
155
+ * @param {string} endpoint - API endpoint path
156
+ * @param {FormData} formData - FormData body
157
+ * @param {Object} [options] - Request options
158
+ * @param {Object} [options.headers] - Additional headers
159
+ * @returns {Promise<Object>} API response
160
+ */
161
+ async postFormData(endpoint, formData, options = {}) {
162
+ const url = this._buildUrl(endpoint);
163
+ const headers = this._buildHeaders(options.headers || {}, { skipContentType: true });
164
+
165
+ const requestOptions = {
166
+ method: 'POST',
167
+ headers,
168
+ body: formData
169
+ };
170
+
171
+ const hasToken = this.authConfig.type === 'bearer' || this.authConfig.type === 'client-token';
172
+ if (hasToken && this.authConfig.token) {
173
+ return await authenticatedApiCall(url, requestOptions, this.authConfig);
174
+ }
175
+
176
+ return await makeApiCall(url, requestOptions);
177
+ }
178
+
156
179
  /**
157
180
  * Make a PATCH request
158
181
  * @async
@@ -14,7 +14,7 @@ const { ApiClient } = require('./index');
14
14
  * @function validatePipeline
15
15
  * @param {string} controllerUrl - Controller base URL
16
16
  * @param {string} envKey - Environment key
17
- * @param {Object} authConfig - Authentication configuration (supports client credentials)
17
+ * @param {Object} authConfig - Authentication configuration (Bearer token only for app endpoints)
18
18
  * @param {Object} validationData - Validation data
19
19
  * @param {string} validationData.clientId - Client ID for application authentication
20
20
  * @param {string} validationData.repositoryUrl - Repository URL for validation
@@ -37,7 +37,7 @@ async function validatePipeline(controllerUrl, envKey, authConfig, validationDat
37
37
  * @function deployPipeline
38
38
  * @param {string} controllerUrl - Controller base URL
39
39
  * @param {string} envKey - Environment key
40
- * @param {Object} authConfig - Authentication configuration (supports client credentials)
40
+ * @param {Object} authConfig - Authentication configuration (Bearer token only for app endpoints)
41
41
  * @param {Object} deployData - Deployment data
42
42
  * @param {string} deployData.validateToken - One-time deployment token from /validate endpoint
43
43
  * @param {string} deployData.imageTag - Container image tag to deploy
@@ -60,7 +60,7 @@ async function deployPipeline(controllerUrl, envKey, authConfig, deployData) {
60
60
  * @param {string} controllerUrl - Controller base URL
61
61
  * @param {string} envKey - Environment key
62
62
  * @param {string} deploymentId - Deployment ID
63
- * @param {Object} authConfig - Authentication configuration (supports client credentials)
63
+ * @param {Object} authConfig - Authentication configuration (Bearer token only for app endpoints)
64
64
  * @returns {Promise<Object>} Minimal deployment status response
65
65
  * @throws {Error} If request fails
66
66
  */
@@ -85,31 +85,9 @@ async function getPipelineHealth(controllerUrl, envKey) {
85
85
  return await client.get(`/api/v1/pipeline/${envKey}/health`);
86
86
  }
87
87
 
88
- /**
89
- * Publish one external system via dataplane pipeline endpoint
90
- * POST /api/v1/pipeline/publish (Dataplane OpenAPI operationId: publishExternalSystemViaPipeline)
91
- * Request body: external system JSON (external-system.schema.json). Optional field in body:
92
- * generateMcpContract (boolean, default true). Optional: generateOpenApiContract (boolean).
93
- * Do not use query parameters for MCP; use the field in the body only.
94
- * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
95
- * @async
96
- * @function publishSystemViaPipeline
97
- * @param {string} dataplaneUrl - Dataplane base URL
98
- * @param {Object} authConfig - Authentication configuration (must include token for Bearer; client id/secret rejected)
99
- * @param {Object} systemConfig - External system configuration (conforms to external-system.schema.json)
100
- * @returns {Promise<Object>} Published external system response
101
- * @throws {Error} If publish fails
102
- */
103
- async function publishSystemViaPipeline(dataplaneUrl, authConfig, systemConfig) {
104
- const client = new ApiClient(dataplaneUrl, authConfig);
105
- return await client.post('/api/v1/pipeline/publish', {
106
- body: systemConfig
107
- });
108
- }
109
-
110
88
  /**
111
89
  * Publish datasource via dataplane pipeline endpoint
112
- * POST /api/v1/pipeline/{systemKey}/publish (Dataplane OpenAPI operationId: publishExternalDataSourceViaPipeline)
90
+ * POST /api/v1/pipeline/{systemKey}/upload (Dataplane: renamed from /publish)
113
91
  * No generateMcpContract for this endpoint; dataplane always uses default (MCP generated).
114
92
  * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
115
93
  * @async
@@ -123,15 +101,62 @@ async function publishSystemViaPipeline(dataplaneUrl, authConfig, systemConfig)
123
101
  */
124
102
  async function publishDatasourceViaPipeline(dataplaneUrl, systemKey, authConfig, datasourceConfig) {
125
103
  const client = new ApiClient(dataplaneUrl, authConfig);
126
- return await client.post(`/api/v1/pipeline/${systemKey}/publish`, {
104
+ return await client.post(`/api/v1/pipeline/${systemKey}/upload`, {
127
105
  body: datasourceConfig
128
106
  });
129
107
  }
130
108
 
109
+ /**
110
+ * Validate pipeline config against Dataplane (dry-run; no publish).
111
+ * POST /api/v1/pipeline/validate
112
+ * @requiresPermission {Dataplane} external-system:read or external-system:publish
113
+ * @async
114
+ * @function validatePipelineConfig
115
+ * @param {string} dataplaneUrl - Dataplane base URL
116
+ * @param {Object} authConfig - Authentication configuration
117
+ * @param {Object} params - Request params
118
+ * @param {Object} params.config - Full config: { version, application, dataSources }
119
+ * @returns {Promise<Object>} { isValid, errors, warnings }
120
+ * @throws {Error} If request fails
121
+ */
122
+ async function validatePipelineConfig(dataplaneUrl, authConfig, { config }) {
123
+ const client = new ApiClient(dataplaneUrl, authConfig);
124
+ return await client.post('/api/v1/pipeline/validate', {
125
+ body: { config }
126
+ });
127
+ }
128
+
129
+ /**
130
+ * Test external system (all datasources) via dataplane pipeline endpoint
131
+ * POST /api/v1/pipeline/{systemKey}/test
132
+ * @requiresPermission {Dataplane} external-system:publish. Auth: Bearer or x-client-token only.
133
+ * @async
134
+ * @function testSystemViaPipeline
135
+ * @param {string} dataplaneUrl - Dataplane base URL
136
+ * @param {string} systemKey - System key
137
+ * @param {Object} authConfig - Authentication configuration (Bearer token)
138
+ * @param {Object} testData - Test data
139
+ * @param {Object} [testData.payloadTemplate] - Optional payload template
140
+ * @param {boolean} [testData.includeDebug] - Include debug output in response
141
+ * @param {Object} [options] - Request options
142
+ * @param {number} [options.timeout] - Request timeout in milliseconds
143
+ * @returns {Promise<Object>} Test response
144
+ * @throws {Error} If test fails
145
+ */
146
+ async function testSystemViaPipeline(dataplaneUrl, systemKey, authConfig, testData = {}, options = {}) {
147
+ const client = new ApiClient(dataplaneUrl, authConfig);
148
+ const requestOptions = { body: testData };
149
+ if (options.timeout) {
150
+ requestOptions.timeout = options.timeout;
151
+ }
152
+ return await client.post(`/api/v1/pipeline/${systemKey}/test`, requestOptions);
153
+ }
154
+
131
155
  /**
132
156
  * Test datasource via dataplane pipeline endpoint
133
157
  * POST /api/v1/pipeline/{systemKey}/{datasourceKey}/test (Dataplane OpenAPI operationId: testExternalDataSourceViaPipeline)
134
- * @requiresPermission {Dataplane} external-system:publish or external-data-source:read. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
158
+ * Supports client credentials for CI/CD.
159
+ * @requiresPermission {Dataplane} external-system:publish or external-data-source:read. Auth: Bearer or x-client-token only.
135
160
  * @async
136
161
  * @function testDatasourceViaPipeline
137
162
  * @param {Object} params - Function parameters
@@ -159,116 +184,37 @@ async function testDatasourceViaPipeline({ dataplaneUrl, systemKey, datasourceKe
159
184
  }
160
185
 
161
186
  /**
162
- * Deploy external system via dataplane pipeline endpoint
163
- * POST /api/v1/pipeline/deploy
164
- * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
165
- * @async
166
- * @function deployExternalSystemViaPipeline
167
- * @param {string} dataplaneUrl - Dataplane base URL
168
- * @param {Object} authConfig - Authentication configuration
169
- * @param {Object} systemConfig - External system configuration to deploy
170
- * @returns {Promise<Object>} Deployment response
171
- * @throws {Error} If deployment fails
172
- */
173
- async function deployExternalSystemViaPipeline(dataplaneUrl, authConfig, systemConfig) {
174
- const client = new ApiClient(dataplaneUrl, authConfig);
175
- return await client.post('/api/v1/pipeline/deploy', {
176
- body: systemConfig
177
- });
178
- }
179
-
180
- /**
181
- * Deploy datasource via dataplane pipeline endpoint
182
- * POST /api/v1/pipeline/{systemKey}/deploy
183
- * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
184
- * @async
185
- * @function deployDatasourceViaPipeline
186
- * @param {string} dataplaneUrl - Dataplane base URL
187
- * @param {string} systemKey - System key
188
- * @param {Object} authConfig - Authentication configuration
189
- * @param {Object} datasourceConfig - Datasource configuration to deploy
190
- * @returns {Promise<Object>} Deployment response
191
- * @throws {Error} If deployment fails
192
- */
193
- async function deployDatasourceViaPipeline(dataplaneUrl, systemKey, authConfig, datasourceConfig) {
194
- const client = new ApiClient(dataplaneUrl, authConfig);
195
- return await client.post(`/api/v1/pipeline/${systemKey}/deploy`, {
196
- body: datasourceConfig
197
- });
198
- }
199
-
200
- /**
201
- * Upload application configuration via dataplane pipeline endpoint
202
- * POST /api/v1/pipeline/upload (Dataplane OpenAPI operationId: uploadApplication)
203
- * Body: { version, application, dataSources }. Include application.generateMcpContract
204
- * and/or application.generateOpenApiContract to control contract generation when
205
- * publishing this upload (publish reads from stored config; no query param on publish).
187
+ * Upload application configuration via dataplane pipeline endpoint (single call: upload → validate → publish → controller register).
188
+ * POST /api/v1/pipeline/upload
189
+ * Body: { version, application, dataSources, status }. status "draft" (default) or "published".
190
+ * Include application.generateMcpContract and/or application.generateOpenApiContract to control contract generation.
206
191
  * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
207
192
  * @async
208
193
  * @function uploadApplicationViaPipeline
209
194
  * @param {string} dataplaneUrl - Dataplane base URL
210
195
  * @param {Object} authConfig - Authentication configuration (must include token for Bearer; client id/secret rejected)
211
- * @param {Object} applicationSchema - { version, application, dataSources }; application may include generateMcpContract, generateOpenApiContract
212
- * @returns {Promise<Object>} Upload response with uploadId
196
+ * @param {Object} payload - { version, application, dataSources }; optional status (default "draft")
197
+ * @param {string} [payload.status="draft"] - "draft" or "published"; Builder uses "draft"
198
+ * @returns {Promise<Object>} Publication result (system, datasources, warnings); no uploadId
213
199
  * @throws {Error} If upload fails
214
200
  */
215
- async function uploadApplicationViaPipeline(dataplaneUrl, authConfig, applicationSchema) {
201
+ async function uploadApplicationViaPipeline(dataplaneUrl, authConfig, payload) {
202
+ const body = { ...payload, status: payload.status ?? 'draft' };
216
203
  const client = new ApiClient(dataplaneUrl, authConfig);
217
204
  return await client.post('/api/v1/pipeline/upload', {
218
- body: applicationSchema
205
+ body
219
206
  });
220
207
  }
221
208
 
222
- /**
223
- * Validate upload via dataplane pipeline endpoint
224
- * POST /api/v1/pipeline/upload/{uploadId}/validate (Dataplane OpenAPI operationId: validateApplication)
225
- * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
226
- * @async
227
- * @function validateUploadViaPipeline
228
- * @param {string} dataplaneUrl - Dataplane base URL
229
- * @param {string} uploadId - Upload ID
230
- * @param {Object} authConfig - Authentication configuration
231
- * @returns {Promise<Object>} Validation response with changes and summary
232
- * @throws {Error} If validation fails
233
- */
234
- async function validateUploadViaPipeline(dataplaneUrl, uploadId, authConfig) {
235
- const client = new ApiClient(dataplaneUrl, authConfig);
236
- return await client.post(`/api/v1/pipeline/upload/${uploadId}/validate`);
237
- }
238
-
239
- /**
240
- * Publish upload via dataplane pipeline endpoint
241
- * POST /api/v1/pipeline/upload/{uploadId}/publish (Dataplane OpenAPI operationId: publishApplication)
242
- * No body or query parameters. MCP/OpenAPI generation is taken from the application config
243
- * that was uploaded (application.generateMcpContract, application.generateOpenApiContract).
244
- * To control MCP/OpenAPI, include those fields in the application object when calling
245
- * uploadApplicationViaPipeline.
246
- * @requiresPermission {Dataplane} external-system:publish. Auth: OAuth2 (Bearer) or API_KEY only; client id/secret are not accepted.
247
- * @async
248
- * @function publishUploadViaPipeline
249
- * @param {string} dataplaneUrl - Dataplane base URL
250
- * @param {string} uploadId - Upload ID
251
- * @param {Object} authConfig - Authentication configuration (must include token for Bearer; client id/secret rejected)
252
- * @returns {Promise<Object>} Publish response
253
- * @throws {Error} If publish fails
254
- */
255
- async function publishUploadViaPipeline(dataplaneUrl, uploadId, authConfig) {
256
- const client = new ApiClient(dataplaneUrl, authConfig);
257
- return await client.post(`/api/v1/pipeline/upload/${uploadId}/publish`);
258
- }
259
-
260
209
  module.exports = {
261
210
  validatePipeline,
262
211
  deployPipeline,
263
212
  getPipelineDeployment,
264
213
  getPipelineHealth,
265
- publishSystemViaPipeline,
266
214
  publishDatasourceViaPipeline,
215
+ validatePipelineConfig,
216
+ testSystemViaPipeline,
267
217
  testDatasourceViaPipeline,
268
- deployExternalSystemViaPipeline,
269
- deployDatasourceViaPipeline,
270
- uploadApplicationViaPipeline,
271
- validateUploadViaPipeline,
272
- publishUploadViaPipeline
218
+ uploadApplicationViaPipeline
273
219
  };
274
220
 
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Credential API type definitions (Dataplane secret store)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /**
8
+ * Single secret item for Dataplane credential secret store.
9
+ * Key is the kv:// path; value must be plain (resolved), never a kv:// reference.
10
+ * @typedef {Object} SecretStoreItem
11
+ * @property {string} key - kv:// path (e.g. kv://secrets/client-secret)
12
+ * @property {string} value - Plain secret value (encrypted at rest by dataplane)
13
+ */
14
+
15
+ /**
16
+ * Response from POST /api/v1/credential/secret (Dataplane).
17
+ * @typedef {Object} SecretStoreResponse
18
+ * @property {number} [stored] - Number of secrets stored
19
+ * @property {boolean} [success] - Request success flag
20
+ * @property {string} [error] - Error message when success is false
21
+ */
22
+
23
+ module.exports = {};
@@ -0,0 +1,140 @@
1
+ /**
2
+ * @fileoverview Builder Server (dev) API type definitions – issue-cert, settings, users, SSH keys, secrets
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ /**
8
+ * Issue certificate request (POST /api/dev/issue-cert). Public; no client cert.
9
+ * @typedef {Object} IssueCertDto
10
+ * @property {string} developerId - Developer ID (must match user for whom PIN was created)
11
+ * @property {string} pin - One-time PIN from POST /api/dev/users/:id/pin
12
+ * @property {string} csr - PEM-encoded Certificate Signing Request
13
+ */
14
+
15
+ /**
16
+ * Issue certificate response (POST /api/dev/issue-cert)
17
+ * @typedef {Object} IssueCertResponseDto
18
+ * @property {string} certificate - PEM-encoded X.509 certificate
19
+ * @property {number} validDays - Validity in days
20
+ * @property {string} validNotAfter - ISO 8601 validity end (UTC)
21
+ * @property {string} [caCertificate] - Optional PEM-encoded CA certificate (for remote Docker TLS; saved as ca.pem)
22
+ * @property {string} [ca] - Optional alias for caCertificate
23
+ */
24
+
25
+ /**
26
+ * Developer settings (GET /api/dev/settings). Cert-authenticated.
27
+ * @typedef {Object} SettingsResponseDto
28
+ * @property {string} user-mutagen-folder - Server path to workspace root (no app segment)
29
+ * @property {string} secrets-encryption - Encryption key (hex)
30
+ * @property {string} aifabrix-secrets - Path or URL for secrets
31
+ * @property {string} aifabrix-env-config - Env config path
32
+ * @property {string} remote-server - Builder-server base URL
33
+ * @property {string} docker-endpoint - Docker API endpoint
34
+ * @property {string} sync-ssh-user - SSH user for Mutagen
35
+ * @property {string} sync-ssh-host - SSH host for Mutagen
36
+ */
37
+
38
+ /**
39
+ * User list item (GET /api/dev/users)
40
+ * @typedef {Object} UserResponseDto
41
+ * @property {string} id - Developer ID
42
+ * @property {string} name - Display name
43
+ * @property {string} email - Email
44
+ * @property {string} createdAt - ISO 8601
45
+ * @property {boolean} certificateIssued - Whether cert was issued
46
+ * @property {string} [certificateValidNotAfter] - Cert validity end (optional)
47
+ * @property {string[]} groups - Access groups (admin, secret-manager, developer)
48
+ */
49
+
50
+ /**
51
+ * Create user request (POST /api/dev/users)
52
+ * @typedef {Object} CreateUserDto
53
+ * @property {string} developerId - Unique developer ID (numeric string)
54
+ * @property {string} name - Display name
55
+ * @property {string} email - Email
56
+ * @property {string[]} [groups] - Default [developer]
57
+ */
58
+
59
+ /**
60
+ * Update user request (PATCH /api/dev/users/:id). At least one field.
61
+ * @typedef {Object} UpdateUserDto
62
+ * @property {string} [name] - Display name
63
+ * @property {string} [email] - Email
64
+ * @property {string[]} [groups] - Access groups
65
+ */
66
+
67
+ /**
68
+ * Create PIN response (POST /api/dev/users/:id/pin)
69
+ * @typedef {Object} CreatePinResponseDto
70
+ * @property {string} pin - One-time PIN
71
+ * @property {string} expiresAt - ISO 8601
72
+ */
73
+
74
+ /**
75
+ * Add SSH key request (POST /api/dev/users/:id/ssh-keys)
76
+ * @typedef {Object} AddSshKeyDto
77
+ * @property {string} publicKey - SSH public key line
78
+ * @property {string} [label] - Optional label
79
+ */
80
+
81
+ /**
82
+ * SSH key item (list/add response)
83
+ * @typedef {Object} SshKeyItemDto
84
+ * @property {string} fingerprint - Key fingerprint
85
+ * @property {string} [label] - Optional label
86
+ * @property {string} [createdAt] - ISO 8601
87
+ */
88
+
89
+ /**
90
+ * Deleted response (DELETE endpoints)
91
+ * @typedef {Object} DeletedResponseDto
92
+ * @property {string} deleted - ID or key of deleted resource
93
+ */
94
+
95
+ /**
96
+ * Secret item (GET /api/dev/secrets)
97
+ * @typedef {Object} SecretItemDto
98
+ * @property {string} name - Secret key
99
+ * @property {string} value - Decrypted value
100
+ */
101
+
102
+ /**
103
+ * Add secret request (POST /api/dev/secrets)
104
+ * @typedef {Object} AddSecretDto
105
+ * @property {string} key - Secret key
106
+ * @property {string} value - Secret value
107
+ */
108
+
109
+ /**
110
+ * Add secret response
111
+ * @typedef {Object} AddSecretResponseDto
112
+ * @property {string} key - Key that was added/updated
113
+ */
114
+
115
+ /**
116
+ * Delete secret response
117
+ * @typedef {Object} DeleteSecretResponseDto
118
+ * @property {string} deleted - Key that was removed
119
+ */
120
+
121
+ /**
122
+ * Health response (GET /health)
123
+ * @typedef {Object} HealthResponseDto
124
+ * @property {string} status - Overall status, e.g. "ok"
125
+ * @property {Object} checks - Per-component health checks
126
+ * @property {string} checks.dataDir - Data directory check ("ok" or error)
127
+ * @property {string} checks.encryptionKey - Encryption key check ("ok" or error)
128
+ * @property {string} checks.ca - CA certificate check ("ok" or error)
129
+ * @property {string} checks.users - Users store check ("ok" or error)
130
+ * @property {string} checks.tokens - Tokens store check ("ok" or error)
131
+ */
132
+
133
+ /**
134
+ * Error response (all error responses)
135
+ * @typedef {Object} ErrorResponseDto
136
+ * @property {number} statusCode - HTTP status
137
+ * @property {string} error - Short error type
138
+ * @property {string} message - Human-readable message
139
+ * @property {string} [code] - Optional machine-readable code
140
+ */
@@ -121,5 +121,42 @@
121
121
  * @property {string} data.environment - Environment key
122
122
  */
123
123
 
124
+ /**
125
+ * Dataplane pipeline upload request body (single upload → validate → publish).
126
+ * @typedef {Object} PipelineUploadRequest
127
+ * @property {string} version - Config version (e.g. "1.0.0")
128
+ * @property {Object} application - Application/system config (external-system schema)
129
+ * @property {Object[]} dataSources - Data source configs
130
+ * @property {string} [status="draft"] - "draft" or "published"; Builder uses "draft"
131
+ */
132
+
133
+ /**
134
+ * Dataplane pipeline upload response (publication result; no uploadId).
135
+ * @typedef {Object} PipelineUploadResponse
136
+ * @property {boolean} success - Request success flag
137
+ * @property {Object} [data] - Publication result (system, datasources, warnings)
138
+ * @property {string} [data.systemKey] - Published system key
139
+ * @property {string[]} [data.datasourceKeys] - Published datasource keys
140
+ * @property {string[]} [data.warnings] - Warnings if any
141
+ * @property {string} [formattedError] - Formatted error message on failure
142
+ */
143
+
144
+ /**
145
+ * Dataplane pipeline validate request body (dry-run validation only).
146
+ * @typedef {Object} PipelineValidateConfigRequest
147
+ * @property {Object} config - Full config to validate
148
+ * @property {string} config.version - Config version
149
+ * @property {Object} config.application - Application config
150
+ * @property {Object[]} config.dataSources - Data source configs
151
+ */
152
+
153
+ /**
154
+ * Dataplane pipeline validate response.
155
+ * @typedef {Object} PipelineValidateConfigResponse
156
+ * @property {boolean} isValid - Whether config is valid
157
+ * @property {string[]} [errors] - Validation errors
158
+ * @property {string[]} [warnings] - Validation warnings
159
+ */
160
+
124
161
  module.exports = {};
125
162