@aifabrix/builder 2.37.9 → 2.39.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 (74) hide show
  1. package/.cursor/rules/project-rules.mdc +3 -0
  2. package/README.md +19 -0
  3. package/integration/hubspot/hubspot-deploy.json +1 -5
  4. package/integration/hubspot/hubspot-system.json +0 -3
  5. package/lib/api/applications.api.js +29 -1
  6. package/lib/api/auth.api.js +14 -0
  7. package/lib/api/credentials.api.js +34 -0
  8. package/lib/api/datasources-core.api.js +16 -1
  9. package/lib/api/datasources-extended.api.js +18 -1
  10. package/lib/api/deployments.api.js +32 -0
  11. package/lib/api/environments.api.js +11 -0
  12. package/lib/api/external-systems.api.js +16 -1
  13. package/lib/api/pipeline.api.js +12 -4
  14. package/lib/api/service-users.api.js +41 -0
  15. package/lib/api/types/applications.types.js +1 -1
  16. package/lib/api/types/deployments.types.js +1 -1
  17. package/lib/api/types/pipeline.types.js +1 -1
  18. package/lib/api/types/service-users.types.js +24 -0
  19. package/lib/api/wizard.api.js +40 -1
  20. package/lib/app/deploy.js +86 -21
  21. package/lib/app/rotate-secret.js +3 -1
  22. package/lib/app/run-helpers.js +35 -2
  23. package/lib/app/show-display.js +30 -11
  24. package/lib/app/show.js +34 -8
  25. package/lib/cli/index.js +4 -0
  26. package/lib/cli/setup-app.js +40 -0
  27. package/lib/cli/setup-credential-deployment.js +72 -0
  28. package/lib/cli/setup-infra.js +3 -3
  29. package/lib/cli/setup-service-user.js +52 -0
  30. package/lib/cli/setup-utility.js +1 -25
  31. package/lib/commands/app-down.js +80 -0
  32. package/lib/commands/app-logs.js +146 -0
  33. package/lib/commands/app.js +24 -1
  34. package/lib/commands/credential-list.js +104 -0
  35. package/lib/commands/deployment-list.js +184 -0
  36. package/lib/commands/service-user.js +193 -0
  37. package/lib/commands/up-common.js +74 -5
  38. package/lib/commands/up-dataplane.js +13 -7
  39. package/lib/commands/up-miso.js +17 -24
  40. package/lib/core/templates.js +2 -2
  41. package/lib/external-system/deploy.js +79 -15
  42. package/lib/generator/builders.js +8 -27
  43. package/lib/generator/external-controller-manifest.js +5 -4
  44. package/lib/generator/index.js +16 -14
  45. package/lib/generator/split.js +1 -0
  46. package/lib/generator/wizard.js +4 -1
  47. package/lib/schema/application-schema.json +6 -14
  48. package/lib/schema/deployment-rules.yaml +121 -0
  49. package/lib/schema/external-system.schema.json +0 -16
  50. package/lib/utils/app-register-config.js +10 -12
  51. package/lib/utils/app-run-containers.js +2 -1
  52. package/lib/utils/compose-generator.js +2 -1
  53. package/lib/utils/deployment-errors.js +10 -0
  54. package/lib/utils/environment-checker.js +25 -6
  55. package/lib/utils/help-builder.js +0 -1
  56. package/lib/utils/image-version.js +209 -0
  57. package/lib/utils/schema-loader.js +1 -1
  58. package/lib/utils/variable-transformer.js +7 -33
  59. package/lib/validation/external-manifest-validator.js +1 -1
  60. package/package.json +1 -1
  61. package/templates/applications/README.md.hbs +1 -3
  62. package/templates/applications/dataplane/Dockerfile +2 -2
  63. package/templates/applications/dataplane/README.md +20 -6
  64. package/templates/applications/dataplane/env.template +31 -2
  65. package/templates/applications/dataplane/rbac.yaml +1 -1
  66. package/templates/applications/dataplane/variables.yaml +7 -4
  67. package/templates/applications/keycloak/Dockerfile +3 -3
  68. package/templates/applications/keycloak/README.md +14 -4
  69. package/templates/applications/keycloak/env.template +17 -2
  70. package/templates/applications/keycloak/variables.yaml +2 -1
  71. package/templates/applications/miso-controller/README.md +1 -3
  72. package/templates/applications/miso-controller/env.template +85 -25
  73. package/templates/applications/miso-controller/rbac.yaml +15 -0
  74. package/templates/applications/miso-controller/variables.yaml +24 -23
@@ -262,6 +262,8 @@ const appResponse = await registerApplication(controllerUrl, environment, data,
262
262
  - Gradually migrate modules to use centralized API client
263
263
  - Eventually deprecate direct usage of `lib/utils/api.js`
264
264
 
265
+ **API Permissions**: When adding or changing `lib/api` functions that call Controller or Dataplane, document required permissions. See [permissions-guide.md](permissions-guide.md) for how to update `@requiresPermission` JSDoc and [docs/commands/permissions.md](../docs/commands/permissions.md).
266
+
265
267
  ## Code Style
266
268
 
267
269
  ### JavaScript Conventions
@@ -880,6 +882,7 @@ Define request/response types using JSDoc `@typedef`:
880
882
  - ✅ Use centralized API client (`lib/api/`) for new API calls
881
883
  - ✅ Define request/response types using JSDoc `@typedef` in `lib/api/types/`
882
884
  - ✅ Use domain-specific API modules (`lib/api/*.api.js`) instead of direct `makeApiCall`
885
+ - ✅ When adding lib/api functions that call Controller/Dataplane, add `@requiresPermission` JSDoc per [permissions-guide.md](permissions-guide.md)
883
886
 
884
887
  ### Must Not Do (❌)
885
888
  - ❌ Never hardcode secrets, passwords, or tokens
package/README.md CHANGED
@@ -9,6 +9,25 @@ Install the AI Fabrix platform and test it locally. Then add external integratio
9
9
 
10
10
  ---
11
11
 
12
+ ## Why AI Fabrix Builder?
13
+
14
+ - **Build perspective:** Everything is driven by declarative config and JSON schemas—no hidden logic, AI assistant–friendly.
15
+ - **Industry standards and security:** Follow industry standards and high security (e.g. ISO 27k); no secrets in version control.
16
+ - **Full lifecycle in your version control:** Configuration, apps, and integrations live in your own VCS (GitHub, GitLab, Azure DevOps).
17
+ - **One tool from day one:** Single CLI for local infra, app and integration creation, build, run, and deploy—same workflow for apps and integrations.
18
+ - **Consistency and production readiness:** Schema-driven; deploy apps and integrations to the same controller/dataplane; production-ready secrets with `kv://` and Azure Key Vault.
19
+ - **Application development:** Use **[miso-client](https://github.com/esystemsdev/aifabrix-miso-client)** for TypeScript and Python to talk to the dataplane and controller (see [templates/applications/dataplane/README.md](templates/applications/dataplane/README.md) and the repo for usage).
20
+
21
+ ---
22
+
23
+ ## Prerequisites
24
+
25
+ - **Node.js 18+** – Recommended for running the CLI.
26
+ - **AI Fabrix Azure / platform:** Install from **Azure Marketplace** or run via **Docker** (e.g. `aifabrix up-platform`). You need **full access to Docker** (docker commands) where applicable.
27
+ - **Secrets before platform:** Add secrets (e.g. OpenAI or Azure OpenAI) **before** running `aifabrix up-platform`; the platform reads them from the place you configure. See [Infrastructure](docs/infrastructure.md) and secrets configuration.
28
+
29
+ ---
30
+
12
31
  ## Install
13
32
 
14
33
  ```bash
@@ -22,9 +22,6 @@
22
22
  "description": "HubSpot CRM integration with OpenAPI support for companies, contacts, and deals",
23
23
  "type": "openapi",
24
24
  "enabled": true,
25
- "environment": {
26
- "baseUrl": "https://api.hubapi.com"
27
- },
28
25
  "authentication": {
29
26
  "type": "oauth2",
30
27
  "mode": "oauth2",
@@ -839,6 +836,5 @@
839
836
  ],
840
837
  "requiresDatabase": false,
841
838
  "requiresRedis": false,
842
- "requiresStorage": false,
843
- "deploymentKey": "9b5209bed2ef1eccb04fa83be73a74cf3a9c84d5d2580a95028d34fdb8db78a8"
839
+ "requiresStorage": false
844
840
  }
@@ -4,9 +4,6 @@
4
4
  "description": "HubSpot CRM integration with OpenAPI support for companies, contacts, and deals",
5
5
  "type": "openapi",
6
6
  "enabled": true,
7
- "environment": {
8
- "baseUrl": "https://api.hubapi.com"
9
- },
10
7
  "authentication": {
11
8
  "type": "oauth2",
12
9
  "mode": "oauth2",
@@ -9,6 +9,7 @@ const { ApiClient } = require('./index');
9
9
  /**
10
10
  * List all template applications
11
11
  * GET /api/v1/applications
12
+ * @requiresPermission {Controller} applications:read
12
13
  * @async
13
14
  * @function listApplications
14
15
  * @param {string} controllerUrl - Controller base URL
@@ -32,6 +33,7 @@ async function listApplications(controllerUrl, authConfig, options = {}) {
32
33
  /**
33
34
  * Create new template application
34
35
  * POST /api/v1/applications
36
+ * @requiresPermission {Controller} applications:create
35
37
  * @async
36
38
  * @function createApplication
37
39
  * @param {string} controllerUrl - Controller base URL
@@ -55,6 +57,7 @@ async function createApplication(controllerUrl, authConfig, applicationData) {
55
57
  /**
56
58
  * Get template application details
57
59
  * GET /api/v1/applications/{appKey}
60
+ * @requiresPermission {Controller} applications:read
58
61
  * @async
59
62
  * @function getApplication
60
63
  * @param {string} controllerUrl - Controller base URL
@@ -71,6 +74,7 @@ async function getApplication(controllerUrl, appKey, authConfig) {
71
74
  /**
72
75
  * Update template application
73
76
  * PATCH /api/v1/applications/{appKey}
77
+ * @requiresPermission {Controller} applications:update
74
78
  * @async
75
79
  * @function updateApplication
76
80
  * @param {string} controllerUrl - Controller base URL
@@ -95,6 +99,7 @@ async function updateApplication(controllerUrl, appKey, authConfig, updateData)
95
99
  /**
96
100
  * Delete template application
97
101
  * DELETE /api/v1/applications/{appKey}
102
+ * @requiresPermission {Controller} applications:delete
98
103
  * @async
99
104
  * @function deleteApplication
100
105
  * @param {string} controllerUrl - Controller base URL
@@ -111,6 +116,7 @@ async function deleteApplication(controllerUrl, appKey, authConfig) {
111
116
  /**
112
117
  * Register application in an environment
113
118
  * POST /api/v1/environments/{envKey}/applications/register
119
+ * @requiresPermission {Controller} environments-applications:create
114
120
  * @async
115
121
  * @function registerApplication
116
122
  * @param {string} controllerUrl - Controller base URL
@@ -139,6 +145,7 @@ async function registerApplication(controllerUrl, envKey, authConfig, registrati
139
145
  /**
140
146
  * Rotate application secret
141
147
  * POST /api/v1/environments/{envKey}/applications/{appKey}/rotate-secret
148
+ * @requiresPermission {Controller} environments-applications:update
142
149
  * @async
143
150
  * @function rotateApplicationSecret
144
151
  * @param {string} controllerUrl - Controller base URL
@@ -153,6 +160,26 @@ async function rotateApplicationSecret(controllerUrl, envKey, appKey, authConfig
153
160
  return await client.post(`/api/v1/environments/${envKey}/applications/${appKey}/rotate-secret`);
154
161
  }
155
162
 
163
+ /**
164
+ * Get application status (metadata only, no configuration)
165
+ * GET /api/v1/environments/{envKey}/applications/{appKey}/status
166
+ * @requiresPermission {Controller} Bearer or app client credentials (environments-applications:read)
167
+ * @async
168
+ * @function getApplicationStatus
169
+ * @param {string} controllerUrl - Controller base URL
170
+ * @param {string} envKey - Environment key
171
+ * @param {string} appKey - Application key
172
+ * @param {Object} authConfig - Authentication configuration
173
+ * @returns {Promise<Object>} Response with data: { id, key, displayName, url, internalUrl, port, status, runtimeStatus, environmentId, createdAt, updatedAt, image, description }
174
+ * @throws {Error} If request fails
175
+ */
176
+ async function getApplicationStatus(controllerUrl, envKey, appKey, authConfig) {
177
+ const client = new ApiClient(controllerUrl, authConfig);
178
+ return await client.get(
179
+ `/api/v1/environments/${envKey}/applications/${appKey}/status`
180
+ );
181
+ }
182
+
156
183
  module.exports = {
157
184
  listApplications,
158
185
  createApplication,
@@ -160,6 +187,7 @@ module.exports = {
160
187
  updateApplication,
161
188
  deleteApplication,
162
189
  registerApplication,
163
- rotateApplicationSecret
190
+ rotateApplicationSecret,
191
+ getApplicationStatus
164
192
  };
165
193
 
@@ -9,6 +9,7 @@ const { ApiClient } = require('./index');
9
9
  /**
10
10
  * Get authentication token using client credentials
11
11
  * POST /api/v1/auth/token
12
+ * @requiresPermission {Controller} Client credentials (no scope in spec)
12
13
  * @async
13
14
  * @function getToken
14
15
  * @param {string} clientId - Client ID
@@ -30,6 +31,7 @@ async function getToken(clientId, clientSecret, controllerUrl) {
30
31
  /**
31
32
  * Get client token for frontend application
32
33
  * GET/POST /api/v1/auth/client-token
34
+ * @requiresPermission {Controller} Client credentials or unauthenticated
33
35
  * @async
34
36
  * @function getClientToken
35
37
  * @param {string} controllerUrl - Controller base URL
@@ -50,6 +52,7 @@ async function getClientToken(controllerUrl, method = 'POST') {
50
52
  /**
51
53
  * Get current user information
52
54
  * GET /api/v1/auth/user
55
+ * @requiresPermission {Controller} auth:read
53
56
  * @async
54
57
  * @function getAuthUser
55
58
  * @param {string} controllerUrl - Controller base URL
@@ -65,6 +68,7 @@ async function getAuthUser(controllerUrl, authConfig) {
65
68
  /**
66
69
  * Get login URL for OAuth2 authorization flow
67
70
  * GET /api/v1/auth/login
71
+ * @requiresPermission {Controller} Client credentials
68
72
  * @async
69
73
  * @function getAuthLogin
70
74
  * @param {string} controllerUrl - Controller base URL
@@ -84,6 +88,7 @@ async function getAuthLogin(controllerUrl, redirect, state, authConfig) {
84
88
  /**
85
89
  * Initiate OAuth2 Device Code Flow
86
90
  * POST /api/v1/auth/login
91
+ * @requiresPermission {Controller} Public (no auth required for device code initiation)
87
92
  * @async
88
93
  * @function initiateDeviceCodeFlow
89
94
  * @param {string} controllerUrl - Controller base URL
@@ -122,6 +127,7 @@ async function initiateDeviceCodeFlow(controllerUrl, environment, scope) {
122
127
  /**
123
128
  * Poll for device code token
124
129
  * POST /api/v1/auth/login/device/token
130
+ * @requiresPermission {Controller} Public
125
131
  * @async
126
132
  * @function pollDeviceCodeToken
127
133
  * @param {string} deviceCode - Device code from initiate device code flow
@@ -139,6 +145,7 @@ async function pollDeviceCodeToken(deviceCode, controllerUrl) {
139
145
  /**
140
146
  * Refresh device code access token
141
147
  * POST /api/v1/auth/login/device/refresh
148
+ * @requiresPermission {Controller} Bearer token (refresh token)
142
149
  * @async
143
150
  * @function refreshDeviceToken
144
151
  * @param {string} refreshToken - Refresh token obtained from device code token flow
@@ -156,6 +163,7 @@ async function refreshDeviceToken(refreshToken, controllerUrl) {
156
163
  /**
157
164
  * Refresh user access token
158
165
  * POST /api/v1/auth/refresh
166
+ * @requiresPermission {Controller} Bearer token (refresh token)
159
167
  * @async
160
168
  * @function refreshUserToken
161
169
  * @param {string} refreshToken - Refresh token obtained from OAuth callback flow
@@ -173,6 +181,7 @@ async function refreshUserToken(refreshToken, controllerUrl) {
173
181
  /**
174
182
  * Validate authentication token
175
183
  * POST /api/v1/auth/validate
184
+ * @requiresPermission {Controller} auth:read or client credentials
176
185
  * @async
177
186
  * @function validateToken
178
187
  * @param {string} token - JWT token to validate
@@ -202,6 +211,7 @@ async function validateToken(token, controllerUrl, authConfig, environment, appl
202
211
  /**
203
212
  * Get user roles
204
213
  * GET /api/v1/auth/roles
214
+ * @requiresPermission {Controller} auth:read
205
215
  * @async
206
216
  * @function getAuthRoles
207
217
  * @param {string} controllerUrl - Controller base URL
@@ -221,6 +231,7 @@ async function getAuthRoles(controllerUrl, authConfig, environment, application)
221
231
  /**
222
232
  * Refresh user roles
223
233
  * GET /api/v1/auth/roles/refresh
234
+ * @requiresPermission {Controller} auth:read
224
235
  * @async
225
236
  * @function refreshAuthRoles
226
237
  * @param {string} controllerUrl - Controller base URL
@@ -236,6 +247,7 @@ async function refreshAuthRoles(controllerUrl, authConfig) {
236
247
  /**
237
248
  * Get user permissions
238
249
  * GET /api/v1/auth/permissions
250
+ * @requiresPermission {Controller} auth:read
239
251
  * @async
240
252
  * @function getAuthPermissions
241
253
  * @param {string} controllerUrl - Controller base URL
@@ -255,6 +267,7 @@ async function getAuthPermissions(controllerUrl, authConfig, environment, applic
255
267
  /**
256
268
  * Refresh user permissions
257
269
  * GET /api/v1/auth/permissions/refresh
270
+ * @requiresPermission {Controller} auth:read
258
271
  * @async
259
272
  * @function refreshAuthPermissions
260
273
  * @param {string} controllerUrl - Controller base URL
@@ -270,6 +283,7 @@ async function refreshAuthPermissions(controllerUrl, authConfig) {
270
283
  /**
271
284
  * Get device code login diagnostics
272
285
  * GET /api/v1/auth/login/diagnostics
286
+ * @requiresPermission {Controller} Public
273
287
  * @async
274
288
  * @function getAuthLoginDiagnostics
275
289
  * @param {string} controllerUrl - Controller base URL
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @fileoverview Credentials API functions (controller/dataplane credential list)
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const { ApiClient } = require('./index');
8
+
9
+ /**
10
+ * List credentials from controller or dataplane
11
+ * GET /api/v1/credential
12
+ * Used by `aifabrix credential list`. Call with controller or dataplane base URL per deployment.
13
+ * @requiresPermission {Dataplane} credential:read (when baseUrl is dataplane; controller may differ)
14
+ * @async
15
+ * @function listCredentials
16
+ * @param {string} baseUrl - Controller or dataplane base URL
17
+ * @param {Object} authConfig - Authentication configuration
18
+ * @param {Object} [options] - List options
19
+ * @param {boolean} [options.activeOnly] - If true, return only active credentials
20
+ * @param {number} [options.page] - Page number
21
+ * @param {number} [options.pageSize] - Items per page
22
+ * @returns {Promise<Object>} Response with credentials (e.g. data.credentials or data.items)
23
+ * @throws {Error} If request fails
24
+ */
25
+ async function listCredentials(baseUrl, authConfig, options = {}) {
26
+ const client = new ApiClient(baseUrl, authConfig);
27
+ return await client.get('/api/v1/credential', {
28
+ params: options
29
+ });
30
+ }
31
+
32
+ module.exports = {
33
+ listCredentials
34
+ };
@@ -1,67 +1,82 @@
1
1
  /**
2
- * @fileoverview Datasources Core API functions
2
+ * @fileoverview Datasources Core API functions (Dataplane /api/v1/external/). All functions require Dataplane auth; scope per endpoint in dataplane OpenAPI (e.g. external-system:read, external-system:create).
3
3
  * @author AI Fabrix Team
4
4
  * @version 2.0.0
5
5
  */
6
6
 
7
7
  const { ApiClient } = require('./index');
8
8
 
9
+ /** @requiresPermission {Dataplane} external-system:read (datasource list) */
9
10
  async function listDatasources(dataplaneUrl, authConfig, options = {}) {
10
11
  const client = new ApiClient(dataplaneUrl, authConfig);
11
12
  return await client.get('/api/v1/external/', { params: options });
12
13
  }
14
+ /** @requiresPermission {Dataplane} external-system:create */
13
15
  async function createDatasource(dataplaneUrl, authConfig, datasourceData) {
14
16
  const client = new ApiClient(dataplaneUrl, authConfig);
15
17
  return await client.post('/api/v1/external/', { body: datasourceData });
16
18
  }
19
+ /** @requiresPermission {Dataplane} external-system:read */
17
20
  async function getDatasource(dataplaneUrl, sourceIdOrKey, authConfig) {
18
21
  const client = new ApiClient(dataplaneUrl, authConfig);
19
22
  return await client.get(`/api/v1/external/${sourceIdOrKey}`);
20
23
  }
24
+ /** @requiresPermission {Dataplane} external-system:update */
21
25
  async function updateDatasource(dataplaneUrl, sourceIdOrKey, authConfig, updateData) {
22
26
  const client = new ApiClient(dataplaneUrl, authConfig);
23
27
  return await client.put(`/api/v1/external/${sourceIdOrKey}`, { body: updateData });
24
28
  }
29
+ /** @requiresPermission {Dataplane} external-system:delete */
25
30
  async function deleteDatasource(dataplaneUrl, sourceIdOrKey, authConfig) {
26
31
  const client = new ApiClient(dataplaneUrl, authConfig);
27
32
  return await client.delete(`/api/v1/external/${sourceIdOrKey}`);
28
33
  }
34
+ /** @requiresPermission {Dataplane} external-system:read */
29
35
  async function getDatasourceConfig(dataplaneUrl, sourceIdOrKey, authConfig) {
30
36
  const client = new ApiClient(dataplaneUrl, authConfig);
31
37
  return await client.get(`/api/v1/external/${sourceIdOrKey}/config`);
32
38
  }
39
+ /** @requiresPermission {Dataplane} external-system:update */
33
40
  async function publishDatasource(dataplaneUrl, sourceIdOrKey, authConfig, publishData = {}) {
34
41
  const client = new ApiClient(dataplaneUrl, authConfig);
35
42
  return await client.post(`/api/v1/external/${sourceIdOrKey}/publish`, { body: publishData });
36
43
  }
44
+ /** @requiresPermission {Dataplane} external-system:update */
37
45
  async function rollbackDatasource(dataplaneUrl, sourceIdOrKey, authConfig, rollbackData) {
38
46
  const client = new ApiClient(dataplaneUrl, authConfig);
39
47
  return await client.post(`/api/v1/external/${sourceIdOrKey}/rollback`, { body: rollbackData });
40
48
  }
49
+ /** @requiresPermission {Dataplane} external-system:read */
41
50
  async function testDatasource(dataplaneUrl, sourceIdOrKey, authConfig, testData = {}) {
42
51
  const client = new ApiClient(dataplaneUrl, authConfig);
43
52
  return await client.post(`/api/v1/external/${sourceIdOrKey}/test`, { body: testData });
44
53
  }
54
+ /** @requiresPermission {Dataplane} external-system:read */
45
55
  async function listDatasourceOpenAPIEndpoints(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
46
56
  const client = new ApiClient(dataplaneUrl, authConfig);
47
57
  return await client.get(`/api/v1/external/${sourceIdOrKey}/openapi-endpoints`, { params: options });
48
58
  }
59
+ /** @requiresPermission {Dataplane} audit:read or external-system:read */
49
60
  async function listExecutionLogs(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
50
61
  const client = new ApiClient(dataplaneUrl, authConfig);
51
62
  return await client.get(`/api/v1/external/${sourceIdOrKey}/executions`, { params: options });
52
63
  }
64
+ /** @requiresPermission {Dataplane} audit:read or external-system:read */
53
65
  async function getExecutionLog(dataplaneUrl, sourceIdOrKey, executionId, authConfig) {
54
66
  const client = new ApiClient(dataplaneUrl, authConfig);
55
67
  return await client.get(`/api/v1/external/${sourceIdOrKey}/executions/${executionId}`);
56
68
  }
69
+ /** @requiresPermission {Dataplane} audit:read */
57
70
  async function listAllExecutionLogs(dataplaneUrl, authConfig, options = {}) {
58
71
  const client = new ApiClient(dataplaneUrl, authConfig);
59
72
  return await client.get('/api/v1/external/executions', { params: options });
60
73
  }
74
+ /** @requiresPermission {Dataplane} external-system:update */
61
75
  async function bulkOperation(dataplaneUrl, sourceIdOrKey, authConfig, bulkData) {
62
76
  const client = new ApiClient(dataplaneUrl, authConfig);
63
77
  return await client.post(`/api/v1/external/${sourceIdOrKey}/bulk`, { body: bulkData });
64
78
  }
79
+ /** @requiresPermission {Dataplane} external-system:read */
65
80
  async function getDatasourceStatus(dataplaneUrl, sourceIdOrKey, authConfig) {
66
81
  const client = new ApiClient(dataplaneUrl, authConfig);
67
82
  return await client.get(`/api/v1/external/${sourceIdOrKey}/status`);
@@ -1,43 +1,52 @@
1
1
  /**
2
- * @fileoverview Datasources Extended API functions (records, grants, policies, sync, documents)
2
+ * @fileoverview Datasources Extended API functions (records, grants, policies, sync, documents). All require Dataplane; scope per endpoint in dataplane OpenAPI.
3
3
  * @author AI Fabrix Team
4
4
  * @version 2.0.0
5
5
  */
6
6
 
7
7
  const { ApiClient } = require('./index');
8
8
 
9
+ /** @requiresPermission {Dataplane} external-system:read (records) */
9
10
  async function listRecords(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
10
11
  const client = new ApiClient(dataplaneUrl, authConfig);
11
12
  return await client.get(`/api/v1/external/${sourceIdOrKey}/records`, { params: options });
12
13
  }
14
+ /** @requiresPermission {Dataplane} external-system:create */
13
15
  async function createRecord(dataplaneUrl, sourceIdOrKey, authConfig, recordData) {
14
16
  const client = new ApiClient(dataplaneUrl, authConfig);
15
17
  return await client.post(`/api/v1/external/${sourceIdOrKey}/records`, { body: recordData });
16
18
  }
19
+ /** @requiresPermission {Dataplane} external-system:read */
17
20
  async function getRecord(dataplaneUrl, sourceIdOrKey, recordIdOrKey, authConfig) {
18
21
  const client = new ApiClient(dataplaneUrl, authConfig);
19
22
  return await client.get(`/api/v1/external/${sourceIdOrKey}/records/${recordIdOrKey}`);
20
23
  }
24
+ /** @requiresPermission {Dataplane} external-system:update */
21
25
  async function updateRecord(dataplaneUrl, sourceIdOrKey, recordIdOrKey, authConfig, updateData) {
22
26
  const client = new ApiClient(dataplaneUrl, authConfig);
23
27
  return await client.put(`/api/v1/external/${sourceIdOrKey}/records/${recordIdOrKey}`, { body: updateData });
24
28
  }
29
+ /** @requiresPermission {Dataplane} external-system:delete */
25
30
  async function deleteRecord(dataplaneUrl, sourceIdOrKey, recordIdOrKey, authConfig) {
26
31
  const client = new ApiClient(dataplaneUrl, authConfig);
27
32
  return await client.delete(`/api/v1/external/${sourceIdOrKey}/records/${recordIdOrKey}`);
28
33
  }
34
+ /** @requiresPermission {Dataplane} external-system:read (grants) */
29
35
  async function listGrants(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
30
36
  const client = new ApiClient(dataplaneUrl, authConfig);
31
37
  return await client.get(`/api/v1/external/${sourceIdOrKey}/grants`, { params: options });
32
38
  }
39
+ /** @requiresPermission {Dataplane} external-system:update */
33
40
  async function createGrant(dataplaneUrl, sourceIdOrKey, authConfig, grantData) {
34
41
  const client = new ApiClient(dataplaneUrl, authConfig);
35
42
  return await client.post(`/api/v1/external/${sourceIdOrKey}/grants`, { body: grantData });
36
43
  }
44
+ /** @requiresPermission {Dataplane} external-system:read */
37
45
  async function getGrant(dataplaneUrl, sourceIdOrKey, grantIdOrKey, authConfig) {
38
46
  const client = new ApiClient(dataplaneUrl, authConfig);
39
47
  return await client.get(`/api/v1/external/${sourceIdOrKey}/grants/${grantIdOrKey}`);
40
48
  }
49
+ /** @requiresPermission {Dataplane} external-system:update */
41
50
  async function updateGrant(dataplaneUrl, sourceIdOrKey, grantIdOrKey, authConfig, updateData) {
42
51
  const client = new ApiClient(dataplaneUrl, authConfig);
43
52
  return await client.put(`/api/v1/external/${sourceIdOrKey}/grants/${grantIdOrKey}`, { body: updateData });
@@ -46,10 +55,12 @@ async function deleteGrant(dataplaneUrl, sourceIdOrKey, grantIdOrKey, authConfig
46
55
  const client = new ApiClient(dataplaneUrl, authConfig);
47
56
  return await client.delete(`/api/v1/external/${sourceIdOrKey}/grants/${grantIdOrKey}`);
48
57
  }
58
+ /** @requiresPermission {Dataplane} external-system:read (policies) */
49
59
  async function listPolicies(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
50
60
  const client = new ApiClient(dataplaneUrl, authConfig);
51
61
  return await client.get(`/api/v1/external/${sourceIdOrKey}/policies`, { params: options });
52
62
  }
63
+ /** @requiresPermission {Dataplane} external-system:update */
53
64
  async function attachPolicy(dataplaneUrl, sourceIdOrKey, authConfig, policyData) {
54
65
  const client = new ApiClient(dataplaneUrl, authConfig);
55
66
  return await client.post(`/api/v1/external/${sourceIdOrKey}/policies`, { body: policyData });
@@ -58,6 +69,7 @@ async function detachPolicy(dataplaneUrl, sourceIdOrKey, policyIdOrKey, authConf
58
69
  const client = new ApiClient(dataplaneUrl, authConfig);
59
70
  return await client.delete(`/api/v1/external/${sourceIdOrKey}/policies/${policyIdOrKey}`);
60
71
  }
72
+ /** @requiresPermission {Dataplane} external-system:read (sync) */
61
73
  async function listSyncJobs(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
62
74
  const client = new ApiClient(dataplaneUrl, authConfig);
63
75
  return await client.get(`/api/v1/external/${sourceIdOrKey}/sync`, { params: options });
@@ -66,10 +78,12 @@ async function createSyncJob(dataplaneUrl, sourceIdOrKey, authConfig, syncData)
66
78
  const client = new ApiClient(dataplaneUrl, authConfig);
67
79
  return await client.post(`/api/v1/external/${sourceIdOrKey}/sync`, { body: syncData });
68
80
  }
81
+ /** @requiresPermission {Dataplane} external-system:read */
69
82
  async function getSyncJob(dataplaneUrl, sourceIdOrKey, syncJobId, authConfig) {
70
83
  const client = new ApiClient(dataplaneUrl, authConfig);
71
84
  return await client.get(`/api/v1/external/${sourceIdOrKey}/sync/${syncJobId}`);
72
85
  }
86
+ /** @requiresPermission {Dataplane} external-system:update */
73
87
  async function updateSyncJob(dataplaneUrl, sourceIdOrKey, syncJobId, authConfig, updateData) {
74
88
  const client = new ApiClient(dataplaneUrl, authConfig);
75
89
  return await client.put(`/api/v1/external/${sourceIdOrKey}/sync/${syncJobId}`, { body: updateData });
@@ -78,14 +92,17 @@ async function executeSyncJob(dataplaneUrl, sourceIdOrKey, syncJobId, authConfig
78
92
  const client = new ApiClient(dataplaneUrl, authConfig);
79
93
  return await client.post(`/api/v1/external/${sourceIdOrKey}/sync/${syncJobId}/execute`);
80
94
  }
95
+ /** @requiresPermission {Dataplane} document-record or external-system scope */
81
96
  async function validateDocuments(dataplaneUrl, sourceIdOrKey, authConfig, validateData) {
82
97
  const client = new ApiClient(dataplaneUrl, authConfig);
83
98
  return await client.post(`/api/v1/external/data-sources/${sourceIdOrKey}/documents/validate`, { body: validateData });
84
99
  }
100
+ /** @requiresPermission {Dataplane} document-record or external-system scope */
85
101
  async function bulkDocuments(dataplaneUrl, sourceIdOrKey, authConfig, bulkData) {
86
102
  const client = new ApiClient(dataplaneUrl, authConfig);
87
103
  return await client.post(`/api/v1/external/data-sources/${sourceIdOrKey}/documents/bulk`, { body: bulkData });
88
104
  }
105
+ /** @requiresPermission {Dataplane} document-record:read or external-system:read */
89
106
  async function listDocuments(dataplaneUrl, sourceIdOrKey, authConfig, options = {}) {
90
107
  const client = new ApiClient(dataplaneUrl, authConfig);
91
108
  return await client.get(`/api/v1/external/data-sources/${sourceIdOrKey}/documents`, { params: options });
@@ -9,6 +9,7 @@ const { ApiClient } = require('./index');
9
9
  /**
10
10
  * Deploy an application to an environment
11
11
  * POST /api/v1/environments/{envKey}/applications/deploy
12
+ * @requiresPermission {Controller} applications:deploy
12
13
  * @async
13
14
  * @function deployApplication
14
15
  * @param {string} controllerUrl - Controller base URL
@@ -32,6 +33,7 @@ async function deployApplication(controllerUrl, envKey, authConfig, deployData)
32
33
  /**
33
34
  * Deploy environment infrastructure
34
35
  * POST /api/v1/environments/{envKey}/deploy
36
+ * @requiresPermission {Controller} controller:deploy
35
37
  * @async
36
38
  * @function deployEnvironment
37
39
  * @param {string} controllerUrl - Controller base URL
@@ -53,6 +55,7 @@ async function deployEnvironment(controllerUrl, envKey, authConfig, deployData)
53
55
  /**
54
56
  * List deployments for an environment
55
57
  * GET /api/v1/environments/{envKey}/deployments
58
+ * @requiresPermission {Controller} deployments:read
56
59
  * @async
57
60
  * @function listDeployments
58
61
  * @param {string} controllerUrl - Controller base URL
@@ -79,6 +82,7 @@ async function listDeployments(controllerUrl, envKey, authConfig, options = {})
79
82
  /**
80
83
  * Get deployment with jobs and logs
81
84
  * GET /api/v1/environments/{envKey}/deployments/{deploymentId}
85
+ * @requiresPermission {Controller} deployments:read
82
86
  * @async
83
87
  * @function getDeployment
84
88
  * @param {string} controllerUrl - Controller base URL
@@ -96,6 +100,7 @@ async function getDeployment(controllerUrl, envKey, deploymentId, authConfig) {
96
100
  /**
97
101
  * Get deployment job logs
98
102
  * GET /api/v1/environments/{envKey}/deployments/{deploymentId}/logs
103
+ * @requiresPermission {Controller} deployments:read
99
104
  * @async
100
105
  * @function getDeploymentLogs
101
106
  * @param {string} controllerUrl - Controller base URL
@@ -116,10 +121,37 @@ async function getDeploymentLogs(controllerUrl, envKey, deploymentId, authConfig
116
121
  });
117
122
  }
118
123
 
124
+ /**
125
+ * List deployments for a single application in an environment
126
+ * GET /api/v1/environments/{envKey}/applications/{appKey}/deployments
127
+ * @requiresPermission {Controller} deployments:read
128
+ * @async
129
+ * @function listApplicationDeployments
130
+ * @param {string} controllerUrl - Controller base URL
131
+ * @param {string} envKey - Environment key
132
+ * @param {string} appKey - Application key
133
+ * @param {Object} authConfig - Authentication configuration
134
+ * @param {Object} [options] - List options
135
+ * @param {number} [options.page] - Page number
136
+ * @param {number} [options.pageSize] - Items per page (default 50)
137
+ * @param {string} [options.sort] - Sort parameter
138
+ * @param {string} [options.filter] - Filter parameter
139
+ * @returns {Promise<Object>} Paginated list of deployments for the application
140
+ * @throws {Error} If request fails
141
+ */
142
+ async function listApplicationDeployments(controllerUrl, envKey, appKey, authConfig, options = {}) {
143
+ const client = new ApiClient(controllerUrl, authConfig);
144
+ return await client.get(
145
+ `/api/v1/environments/${envKey}/applications/${appKey}/deployments`,
146
+ { params: options }
147
+ );
148
+ }
149
+
119
150
  module.exports = {
120
151
  deployApplication,
121
152
  deployEnvironment,
122
153
  listDeployments,
154
+ listApplicationDeployments,
123
155
  getDeployment,
124
156
  getDeploymentLogs
125
157
  };
@@ -9,6 +9,7 @@ const { ApiClient } = require('./index');
9
9
  /**
10
10
  * List all environments
11
11
  * GET /api/v1/environments
12
+ * @requiresPermission {Controller} environments:read
12
13
  * @async
13
14
  * @function listEnvironments
14
15
  * @param {string} controllerUrl - Controller base URL
@@ -34,6 +35,7 @@ async function listEnvironments(controllerUrl, authConfig, options = {}) {
34
35
  /**
35
36
  * Create new environment
36
37
  * POST /api/v1/environments
38
+ * @requiresPermission {Controller} environments:create
37
39
  * @async
38
40
  * @function createEnvironment
39
41
  * @param {string} controllerUrl - Controller base URL
@@ -55,6 +57,7 @@ async function createEnvironment(controllerUrl, authConfig, environmentData) {
55
57
  /**
56
58
  * Get environment by key
57
59
  * GET /api/v1/environments/{envKey}
60
+ * @requiresPermission {Controller} environments:read
58
61
  * @async
59
62
  * @function getEnvironment
60
63
  * @param {string} controllerUrl - Controller base URL
@@ -71,6 +74,7 @@ async function getEnvironment(controllerUrl, envKey, authConfig) {
71
74
  /**
72
75
  * Update environment by key
73
76
  * PATCH /api/v1/environments/{envKey}
77
+ * @requiresPermission {Controller} environments:update
74
78
  * @async
75
79
  * @function updateEnvironment
76
80
  * @param {string} controllerUrl - Controller base URL
@@ -91,6 +95,7 @@ async function updateEnvironment(controllerUrl, envKey, authConfig, updateData)
91
95
  /**
92
96
  * Get environment status
93
97
  * GET /api/v1/environments/{envKey}/status
98
+ * @requiresPermission {Controller} environments:read
94
99
  * @async
95
100
  * @function getEnvironmentStatus
96
101
  * @param {string} controllerUrl - Controller base URL
@@ -107,6 +112,7 @@ async function getEnvironmentStatus(controllerUrl, envKey, authConfig) {
107
112
  /**
108
113
  * List applications in an environment
109
114
  * GET /api/v1/environments/{envKey}/applications
115
+ * @requiresPermission {Controller} environments-applications:read
110
116
  * @async
111
117
  * @function listEnvironmentApplications
112
118
  * @param {string} controllerUrl - Controller base URL
@@ -131,6 +137,7 @@ async function listEnvironmentApplications(controllerUrl, envKey, authConfig, op
131
137
  /**
132
138
  * List deployments for environment
133
139
  * GET /api/v1/environments/{envKey}/deployments
140
+ * @requiresPermission {Controller} deployments:read
134
141
  * @async
135
142
  * @function listEnvironmentDeployments
136
143
  * @param {string} controllerUrl - Controller base URL
@@ -156,6 +163,7 @@ async function listEnvironmentDeployments(controllerUrl, envKey, authConfig, opt
156
163
  /**
157
164
  * List roles for environment
158
165
  * GET /api/v1/environments/{envKey}/roles
166
+ * @requiresPermission {Controller} environments:read
159
167
  * @async
160
168
  * @function listEnvironmentRoles
161
169
  * @param {string} controllerUrl - Controller base URL
@@ -172,6 +180,7 @@ async function listEnvironmentRoles(controllerUrl, envKey, authConfig) {
172
180
  /**
173
181
  * Map role to groups for environment
174
182
  * PATCH /api/v1/environments/{envKey}/roles/{value}/groups
183
+ * @requiresPermission {Controller} environments:update
175
184
  * @async
176
185
  * @function updateRoleGroups
177
186
  * @param {string} controllerUrl - Controller base URL
@@ -192,6 +201,7 @@ async function updateRoleGroups(controllerUrl, envKey, roleValue, authConfig, gr
192
201
  /**
193
202
  * Get application details in an environment
194
203
  * GET /api/v1/environments/{envKey}/applications/{appKey}
204
+ * @requiresPermission {Controller} environments-applications:read
195
205
  * @async
196
206
  * @function getEnvironmentApplication
197
207
  * @param {string} controllerUrl - Controller base URL
@@ -209,6 +219,7 @@ async function getEnvironmentApplication(controllerUrl, envKey, appKey, authConf
209
219
  /**
210
220
  * List datasources in an environment
211
221
  * GET /api/v1/environments/{envKey}/datasources
222
+ * @requiresPermission {Controller} environments:read (or datasources scope per controller spec)
212
223
  * @async
213
224
  * @function listEnvironmentDatasources
214
225
  * @param {string} controllerUrl - Controller base URL