@superblocksteam/sabs-client 0.258.0 → 0.260.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.
package/dist/sabs.js CHANGED
@@ -6,29 +6,53 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SabsClient = void 0;
7
7
  const sabs_types_1 = require("@superblocksteam/sabs-types");
8
8
  const axios_1 = __importDefault(require("axios"));
9
+ const errors_1 = require("./errors");
10
+ /**
11
+ * SABS (Superblocks Application Build System) TypeScript Client
12
+ *
13
+ * Provides methods to interact with the SABS API for building and managing applications.
14
+ *
15
+ * All error types inherit from the standard `HttpError` class that extends the standard `Error` class,
16
+ * ensuring backward compatibility with existing error handling code that catches generic `Error` instances
17
+ * used in earlier versions of the client library.
18
+ */
9
19
  class SabsClient {
10
20
  baseUrl;
11
21
  constructor(baseUrl) {
12
22
  this.baseUrl = baseUrl;
13
23
  }
24
+ /**
25
+ * Start a new build for an application
26
+ *
27
+ * @param params - Build parameters
28
+ * @param params.directoryHash - Hash of the application directory to build
29
+ * @param params.meta - Application metadata (ID and organization ID)
30
+ * @param params.buildKey - Secret build key for authentication
31
+ * @param params.accessToken - JWT access token for authorization
32
+ * @returns Promise resolving to build information including build ID
33
+ * @throws BadRequestError if the directory hash, application metadata, application ID, organization ID, build key, or access token are empty or invalid
34
+ * @throws ForbiddenError if the access token is invalid or missing the required scopes
35
+ * @throws InternalServerError if the service has an unexpected error while performing this request
36
+ * @throws HttpError if the request fails for an unknown reason
37
+ */
14
38
  async build({ directoryHash, meta, buildKey, accessToken }) {
15
39
  if (!directoryHash || directoryHash.length === 0) {
16
- throw new Error('Directory hash is required');
40
+ throw (0, errors_1.createClientError)('Directory hash is required');
17
41
  }
18
42
  if (!meta) {
19
- throw new Error('Application metadata is required');
43
+ throw (0, errors_1.createClientError)('Application metadata is required');
20
44
  }
21
45
  if (!meta.id || meta.id.length === 0) {
22
- throw new Error('Application ID is required');
46
+ throw (0, errors_1.createClientError)('Application ID is required');
23
47
  }
24
48
  if (!meta.organizationId || meta.organizationId.length === 0) {
25
- throw new Error('Organization ID is required');
49
+ throw (0, errors_1.createClientError)('Organization ID is required');
26
50
  }
27
51
  if (!buildKey || buildKey.length === 0) {
28
- throw new Error('Build key is required');
52
+ throw (0, errors_1.createClientError)('Build key is required');
29
53
  }
30
54
  if (!accessToken || accessToken.length === 0) {
31
- throw new Error('Access token is required');
55
+ throw (0, errors_1.createClientError)('Access token is required');
32
56
  }
33
57
  const data = new sabs_types_1.BuildRequest({
34
58
  directoryHash: directoryHash,
@@ -41,30 +65,58 @@ class SabsClient {
41
65
  data
42
66
  }, accessToken);
43
67
  }
68
+ /**
69
+ * Get the status of a build
70
+ *
71
+ * @param params - Status query parameters
72
+ * @param params.buildId - ID of the build to check
73
+ * @param params.accessToken - JWT access token for authorization
74
+ * @returns Promise resolving to build status information
75
+ * @throws BadRequestError if the build ID or access token is empty or invalid
76
+ * @throws UnauthorizedError if the access token is invalid or missing the required scopes
77
+ * @throws NotFoundError if the build ID is invalid
78
+ * @throws InternalServerError if the service has an unexpected error while performing this request
79
+ * @throws HttpError if the request fails for an unknown reason
80
+ */
44
81
  async status({ buildId, accessToken }) {
45
82
  if (!buildId || buildId.length === 0) {
46
- throw new Error('Build ID is required');
83
+ throw (0, errors_1.createClientError)('Build ID is required');
47
84
  }
48
85
  if (!accessToken || accessToken.length === 0) {
49
- throw new Error('Access token is required');
86
+ throw (0, errors_1.createClientError)('Access token is required');
50
87
  }
51
88
  return this.executeRequest({
52
89
  method: 'GET',
53
90
  url: `${this.baseUrl}/v1/builds/${buildId}`
54
91
  }, accessToken);
55
92
  }
93
+ /**
94
+ * Get the status of multiple builds at once
95
+ *
96
+ * @param params - Bulk status query parameters
97
+ * @param params.organizationId - Organization ID
98
+ * @param params.applicationId - Application ID
99
+ * @param params.directoryHashes - Array of directory hashes to check
100
+ * @param params.accessToken - JWT access token for authorization
101
+ * @returns Promise resolving to multiple build status information
102
+ * @throws BadRequestError if the organization ID, application ID, directory hashes, or access token are empty or invalid
103
+ * @throws UnauthorizedError if the access token is invalid or missing the required scopes
104
+ * @throws NotFoundError if the organization ID or application ID is invalid
105
+ * @throws InternalServerError if the service has an unexpected error while performing this request
106
+ * @throws HttpError if the request fails for an unknown reason
107
+ */
56
108
  async bulkStatus({ organizationId, applicationId, directoryHashes, accessToken }) {
57
109
  if (!organizationId || organizationId.length === 0) {
58
- throw new Error('Organization ID is required');
110
+ throw (0, errors_1.createClientError)('Organization ID is required');
59
111
  }
60
112
  if (!applicationId || applicationId.length === 0) {
61
- throw new Error('Application ID is required');
113
+ throw (0, errors_1.createClientError)('Application ID is required');
62
114
  }
63
115
  if (!directoryHashes || directoryHashes.length === 0) {
64
- throw new Error('Directory hashes are required');
116
+ throw (0, errors_1.createClientError)('Directory hashes are required');
65
117
  }
66
118
  if (!accessToken || accessToken.length === 0) {
67
- throw new Error('Access token is required');
119
+ throw (0, errors_1.createClientError)('Access token is required');
68
120
  }
69
121
  const data = new sabs_types_1.BulkStatusRequest({
70
122
  organizationId,
@@ -77,18 +129,33 @@ class SabsClient {
77
129
  data
78
130
  }, accessToken);
79
131
  }
132
+ /**
133
+ * List all builds for a specific application and directory
134
+ *
135
+ * @param params - List query parameters
136
+ * @param params.organizationId - Organization ID
137
+ * @param params.applicationId - Application ID
138
+ * @param params.directoryHash - Hash of the application directory
139
+ * @param params.accessToken - JWT access token for authorization
140
+ * @returns Promise resolving to list of builds
141
+ * @throws BadRequestError if the organization ID, application ID, directory hash, or access token are empty or invalid
142
+ * @throws UnauthorizedError if the access token is invalid or missing the required scopes
143
+ * @throws NotFoundError if the organization ID or application ID is invalid
144
+ * @throws InternalServerError if the service has an unexpected error while performing this request
145
+ * @throws HttpError if the request fails for an unknown reason
146
+ */
80
147
  async list({ organizationId, applicationId, directoryHash, accessToken }) {
81
148
  if (!organizationId || organizationId.length === 0) {
82
- throw new Error('Organization ID is required');
149
+ throw (0, errors_1.createClientError)('Organization ID is required');
83
150
  }
84
151
  if (!applicationId || applicationId.length === 0) {
85
- throw new Error('Application ID is required');
152
+ throw (0, errors_1.createClientError)('Application ID is required');
86
153
  }
87
154
  if (!directoryHash || directoryHash.length === 0) {
88
- throw new Error('Directory hash is required');
155
+ throw (0, errors_1.createClientError)('Directory hash is required');
89
156
  }
90
157
  if (!accessToken || accessToken.length === 0) {
91
- throw new Error('Access token is required');
158
+ throw (0, errors_1.createClientError)('Access token is required');
92
159
  }
93
160
  const data = new sabs_types_1.ListRequest({
94
161
  organizationId,
@@ -101,18 +168,34 @@ class SabsClient {
101
168
  params: data
102
169
  }, accessToken);
103
170
  }
171
+ /**
172
+ * Terminate a running build with a final status
173
+ *
174
+ * @param params - Termination parameters
175
+ * @param params.buildId - ID of the build to terminate
176
+ * @param params.status - Final status of the build
177
+ * @param params.buildKey - Secret build key for authentication
178
+ * @param params.error - Optional error message if build failed
179
+ * @param params.accessToken - JWT access token for authorization
180
+ * @returns Promise resolving to termination confirmation
181
+ * @throws BadRequestError if the build ID, build status, build key, or access token are empty or invalid
182
+ * @throws UnauthorizedError if the access token is invalid or missing the required scopes
183
+ * @throws NotFoundError if the build ID is invalid
184
+ * @throws InternalServerError if the service has an unexpected error while performing this request
185
+ * @throws HttpError if the request fails for an unknown reason
186
+ */
104
187
  async terminate({ buildId, status, buildKey, error, accessToken }) {
105
188
  if (!buildId || buildId.length === 0) {
106
- throw new Error('Build ID is required');
189
+ throw (0, errors_1.createClientError)('Build ID is required');
107
190
  }
108
191
  if (!status) {
109
- throw new Error('Build status is required');
192
+ throw (0, errors_1.createClientError)('Build status is required');
110
193
  }
111
194
  if (!buildKey || buildKey.length === 0) {
112
- throw new Error('Build key is required');
195
+ throw (0, errors_1.createClientError)('Build key is required');
113
196
  }
114
197
  if (!accessToken || accessToken.length === 0) {
115
- throw new Error('Access token is required');
198
+ throw (0, errors_1.createClientError)('Access token is required');
116
199
  }
117
200
  const data = new sabs_types_1.TerminateRequest({
118
201
  buildId,
@@ -126,18 +209,36 @@ class SabsClient {
126
209
  data
127
210
  }, accessToken);
128
211
  }
212
+ /**
213
+ * Create a new live edit session for real-time development
214
+ *
215
+ * @param params - Live edit creation parameters
216
+ * @param params.applicationId - Application ID
217
+ * @param params.organizationId - Organization ID
218
+ * @param params.branch - Git branch name
219
+ * @param params.expiresIn - Session duration in seconds
220
+ * @param params.accessToken - JWT access token for authorization
221
+ * @returns Promise resolving to live edit session information
222
+ * @throws BadRequestError if the application ID, organization ID, branch, or access token are empty or invalid, or expiresIn is not greater than 0
223
+ * @throws UnauthorizedError if the access token is invalid or missing the required scopes
224
+ * @throws InternalServerError if the service has an unexpected error while performing this request
225
+ * @throws HttpError if the request fails for an unknown reason
226
+ */
129
227
  async createLiveEdit({ applicationId, organizationId, branch, expiresIn, accessToken }) {
130
228
  if (!applicationId || applicationId.length === 0) {
131
- throw new Error('Application ID is required');
229
+ throw (0, errors_1.createClientError)('Application ID is required');
132
230
  }
133
231
  if (!organizationId || organizationId.length === 0) {
134
- throw new Error('Organization ID is required');
232
+ throw (0, errors_1.createClientError)('Organization ID is required');
135
233
  }
136
234
  if (!branch || branch.length === 0) {
137
- throw new Error('Branch is required');
235
+ throw (0, errors_1.createClientError)('Branch is required');
138
236
  }
139
237
  if (!accessToken || accessToken.length === 0) {
140
- throw new Error('Access token is required');
238
+ throw (0, errors_1.createClientError)('Access token is required');
239
+ }
240
+ if (!expiresIn || expiresIn <= 0) {
241
+ throw (0, errors_1.createClientError)('Expires in is required and must be greater than 0');
141
242
  }
142
243
  const data = new sabs_types_1.CreateLiveEditRequest({
143
244
  application: {
@@ -154,12 +255,25 @@ class SabsClient {
154
255
  data
155
256
  }, accessToken);
156
257
  }
258
+ /**
259
+ * Terminate an active live edit session
260
+ *
261
+ * @param params - Live edit termination parameters
262
+ * @param params.liveEditId - ID of the live edit session to terminate
263
+ * @param params.accessToken - JWT access token for authorization
264
+ * @returns Promise resolving to termination confirmation
265
+ * @throws BadRequestError if the live edit ID or access token are empty or invalid
266
+ * @throws UnauthorizedError if the access token is invalid or missing the required scopes
267
+ * @throws NotFoundError if the live edit ID is invalid
268
+ * @throws InternalServerError if the service has an unexpected error while performing this request
269
+ * @throws HttpError if the request fails for an unknown reason
270
+ */
157
271
  async terminateLiveEdit({ liveEditId, accessToken }) {
158
272
  if (!liveEditId || liveEditId.length === 0) {
159
- throw new Error('Live edit ID is required');
273
+ throw (0, errors_1.createClientError)('Live edit ID is required');
160
274
  }
161
275
  if (!accessToken || accessToken.length === 0) {
162
- throw new Error('Access token is required');
276
+ throw (0, errors_1.createClientError)('Access token is required');
163
277
  }
164
278
  const data = new sabs_types_1.TerminateLiveEditRequest({
165
279
  liveEditId
@@ -186,11 +300,27 @@ class SabsClient {
186
300
  return response.data;
187
301
  }
188
302
  catch (error) {
189
- let errMsg = `sabs service request failed: ${error.message}`;
190
303
  if (axios_1.default.isAxiosError(error)) {
191
- errMsg += `\n[${error.response?.status}] ${error.response?.statusText}: ${JSON.stringify(error.response?.data)}`;
304
+ const statusCode = error.response?.status ?? 500;
305
+ const statusText = error.response?.statusText ?? 'Unknown Error';
306
+ const responseData = error.response?.data;
307
+ let message;
308
+ if (responseData && typeof responseData === 'object' && responseData.message) {
309
+ message = responseData.message;
310
+ }
311
+ else if (responseData && typeof responseData === 'string') {
312
+ message = responseData;
313
+ }
314
+ else {
315
+ message = `${statusText} (${statusCode})`;
316
+ }
317
+ throw (0, errors_1.createErrorFromStatusCode)(statusCode, message);
318
+ }
319
+ else {
320
+ // Network error or other non-HTTP error
321
+ const message = error instanceof Error ? error.message : 'Unknown error occurred';
322
+ throw (0, errors_1.createNetworkError)(message, error instanceof Error ? error : undefined);
192
323
  }
193
- throw new Error(errMsg);
194
324
  }
195
325
  }
196
326
  }
package/dist/sabs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sabs.js","sourceRoot":"","sources":["../src/sabs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sabs.js","sourceRoot":"","sources":["../src/sabs.ts"],"names":[],"mappings":";;;;;;AAAA,4DAgBqC;AACrC,kDAA0E;AAE1E,qCAA4F;AAE5F;;;;;;;;GAQG;AACH,MAAa,UAAU;IACJ,OAAO,CAAS;IAEjC,YAAmB,OAAe;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;;;;;;;;;;OAaG;IACI,KAAK,CAAC,KAAK,CAAC,EACjB,aAAa,EACb,IAAI,EACJ,QAAQ,EACR,WAAW,EAMZ;QACC,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAA,0BAAiB,EAAC,4BAA4B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAA,0BAAiB,EAAC,kCAAkC,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAA,0BAAiB,EAAC,4BAA4B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAA,0BAAiB,EAAC,6BAA6B,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,IAAA,0BAAiB,EAAC,uBAAuB,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,yBAAY,CAAC;YAC5B,aAAa,EAAE,aAAa;YAC5B,mBAAmB,EAAE,IAAI;YACzB,QAAQ;SACT,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,YAAY;YAChC,IAAI;SACL,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,WAAW,EAA6C;QACrF,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAA,0BAAiB,EAAC,sBAAsB,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,KAAK;YACb,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,cAAc,OAAO,EAAE;SAC5C,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACI,KAAK,CAAC,UAAU,CAAC,EACtB,cAAc,EACd,aAAa,EACb,eAAe,EACf,WAAW,EAMZ;QACC,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,IAAA,0BAAiB,EAAC,6BAA6B,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAA,0BAAiB,EAAC,4BAA4B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrD,MAAM,IAAA,0BAAiB,EAAC,+BAA+B,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,8BAAiB,CAAC;YACjC,cAAc;YACd,aAAa;YACb,eAAe;SAChB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,cAAc,cAAc,IAAI,aAAa,cAAc;YAC/E,IAAI;SACL,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACI,KAAK,CAAC,IAAI,CAAC,EAChB,cAAc,EACd,aAAa,EACb,aAAa,EACb,WAAW,EAMZ;QACC,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,IAAA,0BAAiB,EAAC,6BAA6B,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAA,0BAAiB,EAAC,4BAA4B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAA,0BAAiB,EAAC,4BAA4B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,wBAAW,CAAC;YAC3B,cAAc;YACd,aAAa;YACb,aAAa;SACd,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,KAAK;YACb,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,WAAW;YAC/B,MAAM,EAAE,IAAI;SACb,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACI,KAAK,CAAC,SAAS,CAAC,EACrB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,KAAK,EACL,WAAW,EAOZ;QACC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAA,0BAAiB,EAAC,sBAAsB,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,IAAA,0BAAiB,EAAC,uBAAuB,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,6BAAgB,CAAC;YAChC,OAAO;YACP,MAAM;YACN,KAAK;YACL,QAAQ;SACT,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,cAAc,OAAO,YAAY;YACrD,IAAI;SACL,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACI,KAAK,CAAC,cAAc,CAAC,EAC1B,aAAa,EACb,cAAc,EACd,MAAM,EACN,SAAS,EACT,WAAW,EAOZ;QACC,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAA,0BAAiB,EAAC,4BAA4B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,IAAA,0BAAiB,EAAC,6BAA6B,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAA,0BAAiB,EAAC,oBAAoB,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,IAAA,0BAAiB,EAAC,mDAAmD,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,kCAAqB,CAAC;YACrC,WAAW,EAAE;gBACX,aAAa;gBACb,cAAc,EAAE,cAAc;gBAC9B,MAAM,EAAE,MAAM;aACf;YACD,UAAU,EAAE,WAAW;YACvB,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;SAC7B,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,eAAe;YACnC,IAAI;SACL,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,KAAK,CAAC,iBAAiB,CAAC,EAC7B,UAAU,EACV,WAAW,EAIZ;QACC,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAA,0BAAiB,EAAC,0BAA0B,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,qCAAwB,CAAC;YACxC,UAAU;SACX,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CACxB;YACE,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,iBAAiB,UAAU,YAAY;YAC3D,IAAI;SACL,EACD,WAAW,CACZ,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,cAAc,CAAI,MAA0B,EAAE,WAAoB;QAC9E,IAAI,OAA2C,CAAC;QAChD,IAAI,WAAW,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAClC,OAAO,GAAG;gBACR,GAAG,MAAM,CAAC,OAAO;gBACjB,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,UAAU,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;aACjE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,OAAO,CAAI;gBACtC,GAAG,MAAM;gBACT,OAAO;aACR,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,eAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAC;gBACjD,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,EAAE,UAAU,IAAI,eAAe,CAAC;gBACjE,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC;gBAE1C,IAAI,OAAe,CAAC;gBACpB,IAAI,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;oBAC7E,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;gBACjC,CAAC;qBAAM,IAAI,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;oBAC5D,OAAO,GAAG,YAAY,CAAC;gBACzB,CAAC;qBAAM,CAAC;oBACN,OAAO,GAAG,GAAG,UAAU,KAAK,UAAU,GAAG,CAAC;gBAC5C,CAAC;gBAED,MAAM,IAAA,kCAAyB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACN,wCAAwC;gBACxC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;gBAClF,MAAM,IAAA,2BAAkB,EAAC,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAzZD,gCAyZC"}
package/dist/sabs.test.js CHANGED
@@ -695,17 +695,258 @@ describe('sabs service', () => {
695
695
  data: 'failed to process request'
696
696
  }));
697
697
  const anyBuildId = 'anyBuildId';
698
- const expectedError = 'sabs service request failed: request failed\n[500] internal server error: "failed to process request"';
699
698
  const sabs = new sabs_1.SabsClient('http://localhost:3000');
700
- await expect(sabs.status({ buildId: anyBuildId, accessToken: anyAccessToken })).rejects.toThrow(expectedError);
699
+ await expect(sabs.status({ buildId: anyBuildId, accessToken: anyAccessToken })).rejects.toThrow();
701
700
  });
702
701
  test('re-raises error when error is not axios error', async () => {
703
702
  const mockAxios = jest.spyOn(axios_1.default, 'request');
704
703
  mockAxios.mockRejectedValue(new Error('unexpected error'));
705
704
  const anyBuildId = 'anyBuildId';
706
- const expectedError = 'sabs service request failed: unexpected error';
707
705
  const sabs = new sabs_1.SabsClient('http://localhost:3000');
708
- await expect(sabs.status({ buildId: anyBuildId, accessToken: anyAccessToken })).rejects.toThrow(expectedError);
706
+ await expect(sabs.status({ buildId: anyBuildId, accessToken: anyAccessToken })).rejects.toThrow();
707
+ });
708
+ });
709
+ describe('backward compatibility', () => {
710
+ test('errors can be caught as generic Error instances (backward compatibility)', async () => {
711
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
712
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Service unavailable', 'ECONNREFUSED', undefined, undefined, {
713
+ headers: {},
714
+ config: {
715
+ headers: new axios_1.AxiosHeaders()
716
+ },
717
+ status: 503,
718
+ statusText: 'Service Unavailable',
719
+ data: { message: 'Server temporarily unavailable' }
720
+ }));
721
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
722
+ const applicationId = 'test-app';
723
+ const organizationId = 'test-org';
724
+ const directoryHash = 'abc123';
725
+ // This simulates how existing applications might handle errors
726
+ try {
727
+ const result = await sabs.build({
728
+ directoryHash,
729
+ meta: new sabs_types_1.ApplicationMetadata({
730
+ id: applicationId,
731
+ organizationId
732
+ }),
733
+ buildKey: anyBuildKey,
734
+ accessToken: anyAccessToken
735
+ });
736
+ // Should not reach here
737
+ expect(result).toBeUndefined();
738
+ }
739
+ catch (error) {
740
+ // Legacy error handling - should still work with new error types
741
+ expect(error).toBeInstanceOf(Error);
742
+ expect(error.message).toContain('SABS API Error (503)');
743
+ // Verify we can still access basic Error properties
744
+ expect(typeof error.message).toBe('string');
745
+ expect(error.name).toBeDefined();
746
+ // This is how existing code might log and re-throw
747
+ const loggedError = {
748
+ error,
749
+ applicationId,
750
+ organizationId,
751
+ directoryHash,
752
+ message: error.message
753
+ };
754
+ expect(loggedError.error).toBe(error);
755
+ expect(loggedError.message).toBe(error.message);
756
+ // Re-throwing as generic Error should work
757
+ expect(() => {
758
+ throw new Error('Unable to launch build');
759
+ }).toThrow('Unable to launch build');
760
+ }
761
+ });
762
+ test('new error types provide additional functionality when accessed', async () => {
763
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
764
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Unauthorized', 'UNAUTHORIZED', undefined, undefined, {
765
+ headers: {},
766
+ config: {
767
+ headers: new axios_1.AxiosHeaders()
768
+ },
769
+ status: 401,
770
+ statusText: 'Unauthorized',
771
+ data: { message: 'Invalid token' }
772
+ }));
773
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
774
+ try {
775
+ await sabs.status({ buildId: 'test-build', accessToken: 'invalid-token' });
776
+ }
777
+ catch (error) {
778
+ // Backward compatible - can still catch as Error
779
+ expect(error).toBeInstanceOf(Error);
780
+ // But applications can now also check for specific error types
781
+ const { UnauthorizedError } = await Promise.resolve().then(() => __importStar(require('./errors')));
782
+ expect(error).toBeInstanceOf(UnauthorizedError);
783
+ // And access the status code if needed
784
+ if ('status' in error) {
785
+ expect(error.status).toBe(401);
786
+ }
787
+ }
788
+ });
789
+ describe('response data handling', () => {
790
+ test('handles responseData with message property', async () => {
791
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
792
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Bad Request', 'BAD_REQUEST', undefined, undefined, {
793
+ headers: {},
794
+ config: {
795
+ headers: new axios_1.AxiosHeaders()
796
+ },
797
+ status: 400,
798
+ statusText: 'Bad Request',
799
+ data: { message: 'Directory hash is required' }
800
+ }));
801
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
802
+ try {
803
+ await sabs.build({
804
+ directoryHash: 'test', // Use non-empty value to avoid client-side validation
805
+ meta: new sabs_types_1.ApplicationMetadata({ id: 'test', organizationId: 'test' }),
806
+ buildKey: 'test',
807
+ accessToken: 'test'
808
+ });
809
+ }
810
+ catch (error) {
811
+ expect(error).toBeInstanceOf(Error);
812
+ expect(error.message).toBe('SABS API Error (400): Directory hash is required');
813
+ }
814
+ });
815
+ test('handles responseData as string', async () => {
816
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
817
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Internal Server Error', 'INTERNAL_SERVER_ERROR', undefined, undefined, {
818
+ headers: {},
819
+ config: {
820
+ headers: new axios_1.AxiosHeaders()
821
+ },
822
+ status: 500,
823
+ statusText: 'Internal Server Error',
824
+ data: 'Database connection failed'
825
+ }));
826
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
827
+ try {
828
+ await sabs.build({
829
+ directoryHash: 'test',
830
+ meta: new sabs_types_1.ApplicationMetadata({ id: 'test', organizationId: 'test' }),
831
+ buildKey: 'test',
832
+ accessToken: 'test'
833
+ });
834
+ }
835
+ catch (error) {
836
+ expect(error).toBeInstanceOf(Error);
837
+ expect(error.message).toBe('SABS API Error (500): Database connection failed');
838
+ }
839
+ });
840
+ test('handles null responseData', async () => {
841
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
842
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Service Unavailable', 'SERVICE_UNAVAILABLE', undefined, undefined, {
843
+ headers: {},
844
+ config: {
845
+ headers: new axios_1.AxiosHeaders()
846
+ },
847
+ status: 503,
848
+ statusText: 'Service Unavailable',
849
+ data: null
850
+ }));
851
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
852
+ try {
853
+ await sabs.build({
854
+ directoryHash: 'test',
855
+ meta: new sabs_types_1.ApplicationMetadata({ id: 'test', organizationId: 'test' }),
856
+ buildKey: 'test',
857
+ accessToken: 'test'
858
+ });
859
+ }
860
+ catch (error) {
861
+ expect(error).toBeInstanceOf(Error);
862
+ expect(error.message).toBe('SABS API Error (503): Service Unavailable (503)');
863
+ }
864
+ });
865
+ test('handles undefined responseData', async () => {
866
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
867
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Gateway Timeout', 'GATEWAY_TIMEOUT', undefined, undefined, {
868
+ headers: {},
869
+ config: {
870
+ headers: new axios_1.AxiosHeaders()
871
+ },
872
+ status: 504,
873
+ statusText: 'Gateway Timeout',
874
+ data: undefined
875
+ }));
876
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
877
+ try {
878
+ await sabs.build({
879
+ directoryHash: 'test',
880
+ meta: new sabs_types_1.ApplicationMetadata({ id: 'test', organizationId: 'test' }),
881
+ buildKey: 'test',
882
+ accessToken: 'test'
883
+ });
884
+ }
885
+ catch (error) {
886
+ expect(error).toBeInstanceOf(Error);
887
+ expect(error.message).toBe('SABS API Error (504): Gateway Timeout (504)');
888
+ }
889
+ });
890
+ test('handles responseData object without message property', async () => {
891
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
892
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Bad Request', 'BAD_REQUEST', undefined, undefined, {
893
+ headers: {},
894
+ config: {
895
+ headers: new axios_1.AxiosHeaders()
896
+ },
897
+ status: 400,
898
+ statusText: 'Bad Request',
899
+ data: { error: 'validation_failed', details: ['field is required'] }
900
+ }));
901
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
902
+ try {
903
+ await sabs.build({
904
+ directoryHash: 'test',
905
+ meta: new sabs_types_1.ApplicationMetadata({ id: 'test', organizationId: 'test' }),
906
+ buildKey: 'test',
907
+ accessToken: 'test'
908
+ });
909
+ }
910
+ catch (error) {
911
+ expect(error).toBeInstanceOf(Error);
912
+ expect(error.message).toBe('SABS API Error (400): Bad Request (400)');
913
+ }
914
+ });
915
+ test('all errors have consistent HttpError interface', async () => {
916
+ const responseData = { code: 'TIMEOUT', retryAfter: 30 };
917
+ const mockAxios = jest.spyOn(axios_1.default, 'request');
918
+ mockAxios.mockRejectedValue(new axios_1.AxiosError('Request timeout', 'TIMEOUT', undefined, undefined, {
919
+ headers: {},
920
+ config: {
921
+ headers: new axios_1.AxiosHeaders()
922
+ },
923
+ status: 500,
924
+ statusText: 'Internal Server Error',
925
+ data: responseData
926
+ }));
927
+ const sabs = new sabs_1.SabsClient('http://localhost:3000');
928
+ try {
929
+ await sabs.build({
930
+ directoryHash: 'test',
931
+ meta: new sabs_types_1.ApplicationMetadata({ id: 'test', organizationId: 'test' }),
932
+ buildKey: 'test',
933
+ accessToken: 'test'
934
+ });
935
+ }
936
+ catch (error) {
937
+ expect(error).toBeInstanceOf(Error);
938
+ expect(error.message).toBe('SABS API Error (500): Internal Server Error (500)');
939
+ // All error types now have consistent HttpError interface
940
+ expect('status' in error).toBe(true);
941
+ expect('title' in error).toBe(true);
942
+ if ('status' in error) {
943
+ expect(error.status).toBe(500);
944
+ }
945
+ if ('title' in error) {
946
+ expect(error.title).toBe('Internal server error');
947
+ }
948
+ }
949
+ });
709
950
  });
710
951
  });
711
952
  });