@unboundcx/sdk 2.6.15 → 2.7.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/base.js CHANGED
@@ -101,6 +101,14 @@ export class BaseSDK {
101
101
  removeTransport(name) {
102
102
  this.transports.delete(name);
103
103
  }
104
+
105
+ _getJsonSafely(str, defaultValue) {
106
+ try {
107
+ return JSON.parse(str);
108
+ } catch (e) {
109
+ return defaultValue;
110
+ }
111
+ }
104
112
 
105
113
  async _getAvailableTransport(forceFetch = false) {
106
114
  if (forceFetch) {
@@ -174,9 +182,10 @@ export class BaseSDK {
174
182
 
175
183
  // Try transport plugins first
176
184
  const transport = await this._getAvailableTransport(forceFetch);
185
+ let response;
177
186
  if (transport) {
178
187
  try {
179
- const result = await transport.request(endpoint, method, params, {
188
+ response = await transport.request(endpoint, method, params, {
180
189
  namespace: this.namespace,
181
190
  token: this.token,
182
191
  callId: this.callId,
@@ -184,13 +193,7 @@ export class BaseSDK {
184
193
  baseURL: this.baseURL || this.fullUrl,
185
194
  });
186
195
 
187
- // Debug logging for transport plugins
188
- if (this.debugMode) {
189
- const status = result?.status || 200;
190
- console.log(`API :: ${transport.name} :: ${method.toUpperCase()} :: ${endpoint} :: ${status}`);
191
- }
192
196
 
193
- return result;
194
197
  } catch (err) {
195
198
  // IMPORTANT: This catch block should ONLY handle transport-level failures
196
199
  // (e.g., WebSocket disconnected, plugin unavailable, network errors)
@@ -198,22 +201,22 @@ export class BaseSDK {
198
201
  // Transport plugins should:
199
202
  // - RETURN API error responses normally (400, 500, etc.) as response objects
200
203
  // - ONLY THROW for transport mechanism failures
201
- //
202
- // This ensures API errors are passed through unchanged, just like built-in fetch
203
204
 
204
- if (this.debugMode) {
205
- console.log(`API :: Transport ${transport.name} failure :: ${method.toUpperCase()} :: ${endpoint} :: ${err.message}`);
206
- }
207
205
  console.warn(
208
206
  `Transport ${transport.name} mechanism failed, falling back to HTTP:`,
209
207
  err.message,
210
208
  );
211
- // Fall through to built-in HTTP fetch
209
+
210
+ // Built-in HTTP transport (fallback)
211
+ return this._httpRequest(endpoint, method, params);
212
212
  }
213
+ } else {
214
+ // No transport available, fallback to HTTP
215
+ return this._httpRequest(endpoint, method, params);
213
216
  }
214
217
 
215
- // Built-in HTTP transport (fallback)
216
- return this._httpRequest(endpoint, method, params);
218
+ return this._processResponse(response, transport.name, method, endpoint);
219
+
217
220
  }
218
221
 
219
222
  _isMultipartBody(body) {
@@ -306,72 +309,102 @@ export class BaseSDK {
306
309
 
307
310
  const response = await fetch(url, options);
308
311
 
312
+ return this._processResponse(response, 'https', method, endpoint);
313
+
314
+ }
315
+
316
+ async _processResponse(response, transport, method, endpoint) {
309
317
  // Check if the response indicates an HTTP error
310
318
  // These are API/configuration errors, not transport failures
311
319
  if (!response.ok) {
312
320
  let errorBody;
313
- const contentType = response.headers.get('content-type') || '';
314
-
315
- try {
316
- if (contentType.includes('application/json')) {
317
- errorBody = await response.json();
318
- } else {
319
- errorBody = await response.text();
321
+ if (response?.body) {
322
+ errorBody = response.body;
323
+ } else if (response?.headers?.['content-type']) {
324
+ const contentType = response.headers['content-type'];
325
+ try {
326
+ if (typeof response?.json === 'function' || typeof response?.text === 'function') {
327
+ if (contentType.includes('application/json')) {
328
+ errorBody = await response.json();
329
+ } else if (contentType.includes('text/')) {
330
+ errorBody = await response.text();
331
+ }
332
+ } else {
333
+ if (contentType.includes('application/json')) {
334
+ errorBody = this._getJsonSafely(response?.body, response?.body || {});
335
+ } else if (contentType.includes('text/')) {
336
+ errorBody = response?.body || '';
337
+ }
338
+ }
339
+ if (!errorBody) {
340
+ errorBody = `HTTP ${response.status} ${response.statusText}`;
341
+ }
342
+ } catch (parseError) {
343
+ errorBody = `HTTP ${response.status} ${response.statusText}`;
320
344
  }
321
- } catch (parseError) {
345
+ } else {
322
346
  errorBody = `HTTP ${response.status} ${response.statusText}`;
323
347
  }
324
348
 
325
349
  // Create a structured error for API/HTTP failures
326
- const httpError = new Error(`API :: Error :: https :: ${options.method} :: ${endpoint} :: ${response.status} :: ${response.statusText}`);
350
+ const httpError = new Error(`API :: Error :: ${transport} :: ${method.toUpperCase()} :: ${endpoint} :: ${response.status} :: ${response.statusText}`);
327
351
  httpError.status = response.status;
328
352
  httpError.statusText = response.statusText;
329
- httpError.method = options.method;
353
+ httpError.method = method;
330
354
  httpError.endpoint = endpoint;
331
355
  httpError.body = errorBody;
356
+ httpError.message = errorBody?.error || errorBody?.message || 'API Error';
332
357
 
358
+ // Debug logging for successful HTTP requests
359
+ if (this.debugMode) {
360
+ console.log(`API :: ERROR :: ${transport} :: ${method.toUpperCase()} :: ${endpoint} :: ${response?.status} :: ${responseRequestId}`, httpError);
361
+ }
362
+
333
363
  throw httpError;
334
364
  }
335
-
336
- // Check content type to determine how to parse successful response
337
- const contentType = response.headers.get('content-type') || '';
338
- let bodyResponse;
339
-
340
- if (contentType.includes('application/json')) {
341
- bodyResponse = await response.json();
342
- } else if (contentType.includes('text/')) {
343
- bodyResponse = await response.text();
365
+
366
+ let responseBody;
367
+ if (response?.body) {
368
+ responseBody = response.body;
369
+ } else if (response?.headers?.['content-type']) {
370
+ const contentType = response.headers['content-type'];
371
+ try {
372
+ if (transport === 'https') {
373
+ if (contentType.includes('application/json')) {
374
+ responseBody = await response.json();
375
+ } else if (contentType.includes('text/')) {
376
+ responseBody = await response.text();
377
+ } else {
378
+ responseBody = await response.arrayBuffer();
379
+ }
380
+ } else {
381
+ if (contentType.includes('application/json')) {
382
+ responseBody = this._getJsonSafely(response.body, response.body);
383
+ } else if (contentType.includes('text/')) {
384
+ responseBody = response?.body || '';
385
+ }
386
+ }
387
+ if (!responseBody) {
388
+ responseBody = {};
389
+ }
390
+ } catch (parseError) {
391
+ responseBody = {};
392
+ }
344
393
  } else {
345
- // For binary content (PDFs, images, etc), return as ArrayBuffer
346
- bodyResponse = await response.arrayBuffer();
394
+ responseBody = {};
347
395
  }
348
-
396
+
349
397
  const responseHeaders = response.headers;
350
398
  const responseRequestId =
351
399
  responseHeaders?.get?.('x-request-id') ||
352
400
  responseHeaders?.['x-request-id'];
353
401
 
354
- if (!response.ok) {
355
- // Debug logging for HTTP errors
356
- if (this.debugMode) {
357
- console.log(`API :: https :: ${method.toUpperCase()} :: ${endpoint} :: ${response?.status}`);
358
- }
359
-
360
- throw {
361
- name: `API :: Error :: https :: ${method} :: ${endpoint} :: ${responseRequestId} :: ${response?.status} :: ${response?.statusText}`,
362
- message: bodyResponse?.message || `API Error occured.`,
363
- method,
364
- endpoint,
365
- status: response?.status,
366
- statusText: response?.statusText,
367
- };
368
- }
369
402
 
370
403
  // Debug logging for successful HTTP requests
371
404
  if (this.debugMode) {
372
- console.log(`API :: https :: ${method.toUpperCase()} :: ${endpoint} :: ${response?.status}`);
405
+ console.log(`API :: ${transport} :: ${method.toUpperCase()} :: ${endpoint} :: ${response?.status} :: ${responseRequestId}`);
373
406
  }
374
407
 
375
- return bodyResponse;
408
+ return responseBody;
376
409
  }
377
410
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "2.6.15",
3
+ "version": "2.7.0",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -926,7 +926,7 @@ export class TenDlcBrandsService {
926
926
  * @param {Object} params - Brand parameters
927
927
  * @param {string} params.name - Brand display name (required)
928
928
  * @param {string} params.entityType - Entity type: PRIVATE_PROFIT, PUBLIC_PROFIT, NON_PROFIT (required)
929
- * @param {string} [params.cspId] - CSP ID for resellers
929
+ * @param {string} [params.cspId] - CSP ID for resellers
930
930
  * @param {string} params.companyName - Company name (required)
931
931
  * @param {string} [params.ein] - Employer Identification Number
932
932
  * @param {string} params.address1 - Street address (required)
@@ -1072,6 +1072,8 @@ export class TenDlcBrandsService {
1072
1072
  * @param {string} [params.state] - State
1073
1073
  * @param {string} [params.postalCode] - Postal code
1074
1074
  * @param {string} [params.country] - Country
1075
+ * @param {string} [params.pocFirstName] - Point of contact first name
1076
+ * @param {string} [params.pocLastName] - Point of contact last name
1075
1077
  * @param {string} [params.pocEmail] - Point of contact email
1076
1078
  * @param {string} [params.pocPhone] - Point of contact phone
1077
1079
  * @param {string} [params.stockSymbol] - Stock symbol for public companies
@@ -1082,7 +1084,7 @@ export class TenDlcBrandsService {
1082
1084
  * @param {string} [params.altBusinessIdType] - Alternative business ID type
1083
1085
  * @param {string} [params.brandRelationship] - Brand relationship
1084
1086
  * @param {string} [params.businessContactEmail] - Business contact email for 2025 compliance
1085
- * @param {string} [params.firstName] - First name for 2025 compliance
1087
+ * @param {string} [params.firstName] - First name for 2025 compliance
1086
1088
  * @param {string} [params.lastName] - Last name for 2025 compliance
1087
1089
  * @param {string} [params.mobilePhone] - Mobile phone for 2025 compliance
1088
1090
  * @returns {Promise<Object>} Updated brand details
@@ -1099,6 +1101,8 @@ export class TenDlcBrandsService {
1099
1101
  state,
1100
1102
  postalCode,
1101
1103
  country,
1104
+ pocFirstName,
1105
+ pocLastName,
1102
1106
  pocEmail,
1103
1107
  pocPhone,
1104
1108
  stockSymbol,
@@ -1128,6 +1132,8 @@ export class TenDlcBrandsService {
1128
1132
  state: { type: 'string', required: false },
1129
1133
  postalCode: { type: 'string', required: false },
1130
1134
  country: { type: 'string', required: false },
1135
+ pocFirstName: { type: 'string', required: false },
1136
+ pocLastName: { type: 'string', required: false },
1131
1137
  pocEmail: { type: 'string', required: false },
1132
1138
  pocPhone: { type: 'string', required: false },
1133
1139
  stockSymbol: { type: 'string', required: false },
@@ -1156,6 +1162,8 @@ export class TenDlcBrandsService {
1156
1162
  if (state !== undefined) updateData.state = state;
1157
1163
  if (postalCode !== undefined) updateData.postalCode = postalCode;
1158
1164
  if (country !== undefined) updateData.country = country;
1165
+ if (pocFirstName !== undefined) updateData.pocFirstName = pocFirstName;
1166
+ if (pocLastName !== undefined) updateData.pocLastName = pocLastName;
1159
1167
  if (pocEmail !== undefined) updateData.pocEmail = pocEmail;
1160
1168
  if (pocPhone !== undefined) updateData.pocPhone = pocPhone;
1161
1169
  if (stockSymbol !== undefined) updateData.stockSymbol = stockSymbol;