@aifabrix/builder 2.11.0 → 2.20.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.
@@ -14,7 +14,7 @@ const fsSync = require('fs');
14
14
  const path = require('path');
15
15
  const yaml = require('js-yaml');
16
16
  const chalk = require('chalk');
17
- const { authenticatedApiCall } = require('./utils/api');
17
+ const { testDatasourceViaPipeline } = require('./api/pipeline.api');
18
18
  const { getDeploymentAuth } = require('./utils/token-manager');
19
19
  const { getDataplaneUrl } = require('./datasource-deploy');
20
20
  const { getConfig } = require('./config');
@@ -270,7 +270,7 @@ async function retryApiCall(fn, maxRetries = 3, backoffMs = 1000) {
270
270
  }
271
271
 
272
272
  /**
273
- * Calls pipeline test endpoint
273
+ * Calls pipeline test endpoint using centralized API client
274
274
  * @async
275
275
  * @param {string} systemKey - System key
276
276
  * @param {string} datasourceKey - Datasource key
@@ -281,17 +281,14 @@ async function retryApiCall(fn, maxRetries = 3, backoffMs = 1000) {
281
281
  * @returns {Promise<Object>} Test response
282
282
  */
283
283
  async function callPipelineTestEndpoint(systemKey, datasourceKey, payloadTemplate, dataplaneUrl, authConfig, timeout = 30000) {
284
- const endpoint = `${dataplaneUrl}/api/v1/pipeline/${systemKey}/${datasourceKey}/test`;
285
-
286
284
  const response = await retryApiCall(async() => {
287
- return await authenticatedApiCall(
288
- endpoint,
289
- {
290
- method: 'POST',
291
- body: JSON.stringify({ payloadTemplate }),
292
- timeout
293
- },
294
- authConfig.token
285
+ return await testDatasourceViaPipeline(
286
+ dataplaneUrl,
287
+ systemKey,
288
+ datasourceKey,
289
+ authConfig,
290
+ { payloadTemplate },
291
+ { timeout }
295
292
  );
296
293
  });
297
294
 
@@ -10,7 +10,7 @@
10
10
 
11
11
  const chalk = require('chalk');
12
12
  const logger = require('./logger');
13
- const { authenticatedApiCall } = require('./api');
13
+ const { registerApplication } = require('../api/applications.api');
14
14
  const { formatApiError } = require('./api-error-handler');
15
15
 
16
16
  /**
@@ -23,14 +23,9 @@ const { formatApiError } = require('./api-error-handler');
23
23
  * @returns {Promise<Object>} API response
24
24
  */
25
25
  async function callRegisterApi(apiUrl, token, environment, registrationData) {
26
- const response = await authenticatedApiCall(
27
- `${apiUrl}/api/v1/environments/${encodeURIComponent(environment)}/applications/register`,
28
- {
29
- method: 'POST',
30
- body: JSON.stringify(registrationData)
31
- },
32
- token
33
- );
26
+ // Use centralized API client
27
+ const authConfig = { type: 'bearer', token: token };
28
+ const response = await registerApplication(apiUrl, environment, authConfig, registrationData);
34
29
 
35
30
  if (!response.success) {
36
31
  const formattedError = response.formattedError || formatApiError(response);
@@ -48,7 +43,7 @@ async function callRegisterApi(apiUrl, token, environment, registrationData) {
48
43
  }
49
44
 
50
45
  // Handle API response structure:
51
- // makeApiCall returns: { success: true, data: <API response> }
46
+ // registerApplication returns: { success: true, data: <API response> }
52
47
  // API response can be:
53
48
  // 1. Direct format: { application: {...}, credentials: {...} }
54
49
  // 2. Wrapped format: { success: true, data: { application: {...}, credentials: {...} } }
@@ -18,8 +18,17 @@ const { parseErrorResponse } = require('./api-error-handler');
18
18
  * @returns {Object} Structured error information
19
19
  */
20
20
  function handleDeploymentError(error) {
21
+ if (!error) {
22
+ return {
23
+ message: 'Unknown error',
24
+ code: 'UNKNOWN',
25
+ timeout: false,
26
+ status: undefined,
27
+ data: undefined
28
+ };
29
+ }
21
30
  const safeError = {
22
- message: error.message,
31
+ message: error.message || 'Unknown error',
23
32
  code: error.code || 'UNKNOWN',
24
33
  timeout: error.code === 'ECONNABORTED',
25
34
  status: error.status || error.response?.status,
@@ -42,6 +51,38 @@ function handleDeploymentError(error) {
42
51
  * @throws {Error} User-friendly error message
43
52
  */
44
53
  async function handleDeploymentErrors(error, appName, url, alreadyLogged = false) {
54
+ // For validation errors (like URL validation), just re-throw them directly
55
+ // They already have user-friendly messages
56
+ // Handle both Error objects and strings
57
+ let errorMessage = '';
58
+ if (error instanceof Error) {
59
+ errorMessage = error.message || '';
60
+ } else if (typeof error === 'string') {
61
+ errorMessage = error;
62
+ } else if (error && typeof error === 'object' && error.message) {
63
+ errorMessage = error.message;
64
+ }
65
+
66
+ if (errorMessage && (
67
+ errorMessage.includes('Controller URL must use HTTPS') ||
68
+ errorMessage.includes('Invalid environment key') ||
69
+ errorMessage.includes('Environment key is required') ||
70
+ errorMessage.includes('Authentication configuration is required') ||
71
+ errorMessage.includes('Invalid controller URL format') ||
72
+ errorMessage.includes('Controller URL is required')
73
+ )) {
74
+ // If error is a string, convert to Error object
75
+ if (typeof error === 'string') {
76
+ throw new Error(error);
77
+ }
78
+ // If it's already an Error object, re-throw it directly
79
+ if (error instanceof Error) {
80
+ throw error;
81
+ }
82
+ // Otherwise, create a new Error with the message
83
+ throw new Error(errorMessage);
84
+ }
85
+
45
86
  // Log to audit log if not already logged
46
87
  if (!alreadyLogged) {
47
88
  try {
@@ -63,7 +104,17 @@ async function handleDeploymentErrors(error, appName, url, alreadyLogged = false
63
104
 
64
105
  // Ensure errorData is not undefined before parsing
65
106
  // If errorData is undefined, use the error message instead
66
- const errorResponse = errorData !== undefined ? errorData : safeError.message;
107
+ let errorResponse = errorData !== undefined ? errorData : safeError.message;
108
+
109
+ // Ensure errorResponse is a string or object, not an Error object
110
+ if (errorResponse instanceof Error) {
111
+ errorResponse = errorResponse.message || 'Unknown error occurred';
112
+ }
113
+
114
+ // Ensure errorResponse is not null or undefined
115
+ if (errorResponse === null || errorResponse === undefined) {
116
+ errorResponse = safeError.message || 'Unknown error occurred';
117
+ }
67
118
 
68
119
  // Determine if this is a network error
69
120
  const isNetworkError = safeError.code === 'ECONNREFUSED' ||
@@ -72,13 +123,44 @@ async function handleDeploymentErrors(error, appName, url, alreadyLogged = false
72
123
  safeError.timeout;
73
124
 
74
125
  // Parse error using error handler
75
- const parsedError = parseErrorResponse(errorResponse, safeError.status || 0, isNetworkError);
126
+ let parsedError;
127
+ try {
128
+ parsedError = parseErrorResponse(errorResponse, safeError.status || 0, isNetworkError);
129
+ // Ensure parsedError is a valid object
130
+ if (!parsedError || typeof parsedError !== 'object') {
131
+ throw new Error('parseErrorResponse returned invalid result');
132
+ }
133
+ } catch (parseErr) {
134
+ // If parsing fails, use the safe error message
135
+ parsedError = {
136
+ message: safeError.message || 'Unknown error occurred',
137
+ formatted: safeError.message || 'Unknown error occurred',
138
+ data: undefined
139
+ };
140
+ }
141
+
142
+ // Ensure parsedError is always a valid object with required properties
143
+ if (!parsedError || typeof parsedError !== 'object') {
144
+ parsedError = {
145
+ message: safeError.message || 'Unknown error occurred',
146
+ formatted: safeError.message || 'Unknown error occurred',
147
+ data: undefined
148
+ };
149
+ }
150
+
151
+ // Ensure we have a message - handle case where parsedError.message might be undefined
152
+ const finalErrorMessage = (parsedError && parsedError.message) ? parsedError.message : (safeError.message || 'Unknown error occurred');
153
+
154
+ // Validate finalErrorMessage is a string
155
+ if (typeof finalErrorMessage !== 'string') {
156
+ throw new Error(`Invalid error message type: ${typeof finalErrorMessage}. Error: ${JSON.stringify(error)}`);
157
+ }
76
158
 
77
159
  // Throw clean error message (without emoji) - CLI will format it
78
- const formattedError = new Error(parsedError.message);
79
- formattedError.formatted = parsedError.formatted;
160
+ const formattedError = new Error(finalErrorMessage);
161
+ formattedError.formatted = parsedError?.formatted || finalErrorMessage;
80
162
  formattedError.status = safeError.status;
81
- formattedError.data = parsedError.data;
163
+ formattedError.data = parsedError?.data;
82
164
  formattedError._logged = true; // Mark as logged to prevent double-logging
83
165
  throw formattedError;
84
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.11.0",
3
+ "version": "2.20.0",
4
4
  "description": "AI Fabrix Local Fabric & Deployment SDK",
5
5
  "main": "lib/index.js",
6
6
  "bin": {