@supsis/supsis-js 1.0.0 → 1.1.1

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.
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Supsis JS SDK v1.0.0
2
+ * Supsis JS SDK v1.1.0
3
3
  * Supsis API SDK - Browser ve Node.js için omnichannel messaging, chatbot, automation, task, ticket ve voice agent entegrasyonu
4
4
  *
5
5
  * @license MIT
6
- * @author Supsis <info@supsis.com>
6
+ * @author Supsis Ai <info@softcand.com>
7
7
  * @see https://supsis.com
8
8
  */
9
9
  'use strict';
@@ -21,7 +21,7 @@ const ENVIRONMENTS = {
21
21
  /** Stage/Beta API - beta-api.supsis.live */
22
22
  stage: 'https://beta-api.supsis.live',
23
23
  /** Local development API */
24
- local: 'https://tablet-api-local.supsis.live'
24
+ local: 'https://tablet-api-local.supsis.live:50101'
25
25
  };
26
26
 
27
27
  /**
@@ -38,7 +38,9 @@ const DEFAULT_CONFIG = {
38
38
  /** Başarısız isteklerde retry sayısı */
39
39
  retryCount: 3,
40
40
  /** Retry'lar arası bekleme süresi (ms) */
41
- retryDelay: 1000
41
+ retryDelay: 1000,
42
+ /** Debug logları göster */
43
+ verbose: false
42
44
  };
43
45
 
44
46
  /**
@@ -89,12 +91,59 @@ class HttpClient {
89
91
  * @param {number} [config.timeout=30000] - İstek timeout süresi (ms)
90
92
  * @param {number} [config.retryCount=3] - Retry sayısı
91
93
  * @param {number} [config.retryDelay=1000] - Retry arası bekleme (ms)
94
+ * @param {boolean} [config.verbose=false] - Debug logları göster
92
95
  */
93
96
  constructor(config) {
97
+ config = config || {};
94
98
  this.config = Object.assign({}, DEFAULT_CONFIG, config);
95
99
  this.baseUrl = this._resolveBaseUrl();
96
100
  this.token = null;
97
- this.siteId = config.siteId || null;
101
+ this.siteId = this.config.siteId || null;
102
+ this.verbose = this.config.verbose || false;
103
+
104
+ // Debug: config değerlerini logla
105
+ if (this.verbose) {
106
+ console.log('[SupsisJS] HttpClient config:', {
107
+ timeout: this.config.timeout,
108
+ retryCount: this.config.retryCount,
109
+ env: this.config.env,
110
+ baseUrl: this.baseUrl
111
+ });
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Verbose log yazdırır
117
+ * @private
118
+ * @param {string} type - Log tipi (info, warn, error, request, response)
119
+ * @param {...any} args - Log argümanları
120
+ */
121
+ _log(type) {
122
+ if (!this.verbose) return;
123
+
124
+ var args = Array.prototype.slice.call(arguments, 1);
125
+ var prefix = '[SupsisJS]';
126
+ var timestamp = new Date().toISOString();
127
+
128
+ switch (type) {
129
+ case 'info':
130
+ console.log.apply(console, [prefix, timestamp, 'INFO:'].concat(args));
131
+ break;
132
+ case 'warn':
133
+ console.warn.apply(console, [prefix, timestamp, 'WARN:'].concat(args));
134
+ break;
135
+ case 'error':
136
+ console.error.apply(console, [prefix, timestamp, 'ERROR:'].concat(args));
137
+ break;
138
+ case 'request':
139
+ console.log.apply(console, [prefix, timestamp, '→ REQUEST:'].concat(args));
140
+ break;
141
+ case 'response':
142
+ console.log.apply(console, [prefix, timestamp, '← RESPONSE:'].concat(args));
143
+ break;
144
+ default:
145
+ console.log.apply(console, [prefix, timestamp].concat(args));
146
+ }
98
147
  }
99
148
 
100
149
  /**
@@ -153,16 +202,28 @@ class HttpClient {
153
202
  fetchOptions.body = JSON.stringify(options.body);
154
203
  }
155
204
 
205
+ this._log('request', method.toUpperCase(), url, options.body ? JSON.stringify(options.body).substring(0, 200) : '');
206
+
156
207
  let lastError;
157
208
  const retryCount = options.retryCount !== undefined ? options.retryCount : this.config.retryCount;
158
209
 
159
210
  for (let attempt = 0; attempt <= retryCount; attempt++) {
160
211
  try {
212
+ if (attempt > 0) {
213
+ this._log('info', 'Retry attempt', attempt, 'of', retryCount);
214
+ }
215
+
161
216
  const response = await this._fetchWithTimeout(url, fetchOptions);
162
- return await this._handleResponse(response);
217
+ const data = await this._handleResponse(response);
218
+
219
+ this._log('response', response.status, endpoint, typeof data === 'object' ? JSON.stringify(data).substring(0, 200) : data);
220
+
221
+ return data;
163
222
  } catch (error) {
164
223
  lastError = error;
165
224
 
225
+ this._log('error', 'Request failed:', error.message, 'Status:', error.statusCode || 'N/A');
226
+
166
227
  // Auth hatalarında retry yapma
167
228
  if (error.statusCode === HTTP_STATUS.UNAUTHORIZED ||
168
229
  error.statusCode === HTTP_STATUS.FORBIDDEN) {
@@ -171,6 +232,7 @@ class HttpClient {
171
232
 
172
233
  // Son deneme değilse bekle ve tekrar dene
173
234
  if (attempt < retryCount) {
235
+ this._log('info', 'Waiting', this.config.retryDelay * (attempt + 1), 'ms before retry...');
174
236
  await this._sleep(this.config.retryDelay * (attempt + 1));
175
237
  }
176
238
  }
@@ -184,23 +246,62 @@ class HttpClient {
184
246
  * @private
185
247
  */
186
248
  async _fetchWithTimeout(url, options) {
187
- const controller = new AbortController();
188
- const timeoutId = setTimeout(function() {
249
+ var self = this;
250
+ var timeout = this.config.timeout || 30000;
251
+ var controller = new AbortController();
252
+ var timeoutId = setTimeout(function() {
189
253
  controller.abort();
190
- }, this.config.timeout);
254
+ }, timeout);
255
+
256
+ self._log('info', 'Fetch timeout set to:', timeout, 'ms');
191
257
 
192
258
  try {
193
- const response = await fetch(url, Object.assign({}, options, {
259
+ var response = await fetch(url, Object.assign({}, options, {
194
260
  signal: controller.signal
195
261
  }));
196
262
  clearTimeout(timeoutId);
197
263
  return response;
198
264
  } catch (error) {
199
265
  clearTimeout(timeoutId);
266
+
267
+ // Detaylı hata bilgisi
268
+ self._log('error', 'Fetch error details:', {
269
+ name: error.name,
270
+ message: error.message,
271
+ code: error.code,
272
+ cause: error.cause ? String(error.cause) : undefined
273
+ });
274
+
275
+ // AbortError - gerçek timeout mu yoksa başka bir sebep mi?
200
276
  if (error.name === 'AbortError') {
201
- throw new SupsisAPIError('Request timeout', 408);
277
+ // error.cause varsa gerçek sebebi göster
278
+ var realCause = error.cause ? String(error.cause) : error.message;
279
+ throw new SupsisAPIError('Request aborted: ' + realCause, 408, {
280
+ originalError: error.message,
281
+ cause: realCause,
282
+ timeout: timeout
283
+ });
202
284
  }
203
- throw error;
285
+
286
+ // Network hataları için daha açıklayıcı hata mesajı
287
+ if (error.code === 'ECONNREFUSED') {
288
+ throw new SupsisAPIError('Connection refused: ' + url, 0, { originalError: error.message, code: error.code });
289
+ }
290
+
291
+ if (error.code === 'ENOTFOUND') {
292
+ throw new SupsisAPIError('Host not found: ' + url, 0, { originalError: error.message, code: error.code });
293
+ }
294
+
295
+ if (error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' || error.code === 'CERT_HAS_EXPIRED' || error.code === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
296
+ throw new SupsisAPIError('SSL/TLS certificate error: ' + error.message, 0, { originalError: error.message, code: error.code });
297
+ }
298
+
299
+ // Diğer hatalar için SupsisAPIError'a çevir
300
+ throw new SupsisAPIError(error.message || 'Unknown fetch error', 0, {
301
+ originalError: error.message,
302
+ code: error.code,
303
+ cause: error.cause ? String(error.cause) : undefined
304
+ });
204
305
  }
205
306
  }
206
307
 
@@ -3668,13 +3769,17 @@ class SupsisJS {
3668
3769
  /** @private */
3669
3770
  this._config = config;
3670
3771
 
3772
+ /** @private */
3773
+ this._verbose = config.verbose || false;
3774
+
3671
3775
  /** @private */
3672
3776
  this._http = new HttpClient({
3673
3777
  env: config.env || 'production',
3674
3778
  baseApiAddress: config.baseApiAddress,
3675
3779
  siteId: config.siteId,
3676
3780
  timeout: config.timeout,
3677
- retryCount: config.retryCount
3781
+ retryCount: config.retryCount,
3782
+ verbose: config.verbose
3678
3783
  });
3679
3784
 
3680
3785
  /** @private */
@@ -3688,6 +3793,38 @@ class SupsisJS {
3688
3793
 
3689
3794
  // Modülleri oluştur
3690
3795
  this._initModules();
3796
+
3797
+ this._log('info', 'SupsisJS initialized', {
3798
+ env: config.env || 'production',
3799
+ baseApiAddress: config.baseApiAddress || 'default',
3800
+ siteId: config.siteId
3801
+ });
3802
+ }
3803
+
3804
+ /**
3805
+ * Verbose log yazdırır
3806
+ * @private
3807
+ */
3808
+ _log(type) {
3809
+ if (!this._verbose) return;
3810
+
3811
+ var args = Array.prototype.slice.call(arguments, 1);
3812
+ var prefix = '[SupsisJS]';
3813
+ var timestamp = new Date().toISOString();
3814
+
3815
+ switch (type) {
3816
+ case 'info':
3817
+ console.log.apply(console, [prefix, timestamp, 'INFO:'].concat(args));
3818
+ break;
3819
+ case 'warn':
3820
+ console.warn.apply(console, [prefix, timestamp, 'WARN:'].concat(args));
3821
+ break;
3822
+ case 'error':
3823
+ console.error.apply(console, [prefix, timestamp, 'ERROR:'].concat(args));
3824
+ break;
3825
+ default:
3826
+ console.log.apply(console, [prefix, timestamp].concat(args));
3827
+ }
3691
3828
  }
3692
3829
 
3693
3830
  /**
@@ -3793,17 +3930,34 @@ class SupsisJS {
3793
3930
  * console.log('Connected as:', supsis.currentUser.fullname);
3794
3931
  */
3795
3932
  async connect() {
3933
+ var self = this;
3934
+
3796
3935
  if (this._connected) {
3936
+ this._log('info', 'Already connected');
3797
3937
  return this._user;
3798
3938
  }
3799
3939
 
3800
- const response = await this._http.post('/api/users/login', {
3801
- email: this._config.email,
3802
- password: this._config.password
3803
- }, { skipAuth: true });
3940
+ this._log('info', 'Connecting to Supsis API...');
3941
+ this._log('info', 'Base URL:', this._http.baseUrl);
3942
+
3943
+ var response;
3944
+ try {
3945
+ response = await this._http.post('/api/users/login', {
3946
+ email: this._config.email,
3947
+ password: this._config.password
3948
+ }, { skipAuth: true, retryCount: 0 });
3949
+ } catch (error) {
3950
+ self._log('error', 'Login failed:', error.message);
3951
+ throw error;
3952
+ }
3804
3953
 
3805
3954
  if (!response || !response.token) {
3806
- throw new SupsisAPIError('Login failed: No token received', 401);
3955
+ var errorMsg = 'Login failed: No token received';
3956
+ if (response && response.message) {
3957
+ errorMsg = 'Login failed: ' + response.message;
3958
+ }
3959
+ self._log('error', errorMsg);
3960
+ throw new SupsisAPIError(errorMsg, 401, response);
3807
3961
  }
3808
3962
 
3809
3963
  this._token = response.token;
@@ -3811,6 +3965,8 @@ class SupsisJS {
3811
3965
  this._http.setToken(this._token);
3812
3966
  this._connected = true;
3813
3967
 
3968
+ this._log('info', 'Connected successfully as:', this._user.fullname || this._user.email);
3969
+
3814
3970
  return this._user;
3815
3971
  }
3816
3972
 
package/dist/supsis.d.ts CHANGED
@@ -24,6 +24,8 @@ export interface SupsisConfig {
24
24
  timeout?: number;
25
25
  /** Başarısız isteklerde retry sayısı - default: 3 */
26
26
  retryCount?: number;
27
+ /** Debug logları göster - default: false */
28
+ verbose?: boolean;
27
29
  }
28
30
 
29
31
  /**
@@ -42,6 +44,8 @@ export interface ModuleAPIConfig {
42
44
  timeout?: number;
43
45
  /** Başarısız isteklerde retry sayısı */
44
46
  retryCount?: number;
47
+ /** Debug logları göster - default: false */
48
+ verbose?: boolean;
45
49
  }
46
50
 
47
51
  // ==================== RESPONSE TYPES ====================
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Supsis JS SDK v1.0.0
2
+ * Supsis JS SDK v1.1.0
3
3
  * Supsis API SDK - Browser ve Node.js için omnichannel messaging, chatbot, automation, task, ticket ve voice agent entegrasyonu
4
4
  *
5
5
  * @license MIT
6
- * @author Supsis <info@supsis.com>
6
+ * @author Supsis Ai <info@softcand.com>
7
7
  * @see https://supsis.com
8
8
  */
9
9
  /**
@@ -17,7 +17,7 @@ const ENVIRONMENTS = {
17
17
  /** Stage/Beta API - beta-api.supsis.live */
18
18
  stage: 'https://beta-api.supsis.live',
19
19
  /** Local development API */
20
- local: 'https://tablet-api-local.supsis.live'
20
+ local: 'https://tablet-api-local.supsis.live:50101'
21
21
  };
22
22
 
23
23
  /**
@@ -34,7 +34,9 @@ const DEFAULT_CONFIG = {
34
34
  /** Başarısız isteklerde retry sayısı */
35
35
  retryCount: 3,
36
36
  /** Retry'lar arası bekleme süresi (ms) */
37
- retryDelay: 1000
37
+ retryDelay: 1000,
38
+ /** Debug logları göster */
39
+ verbose: false
38
40
  };
39
41
 
40
42
  /**
@@ -85,12 +87,59 @@ class HttpClient {
85
87
  * @param {number} [config.timeout=30000] - İstek timeout süresi (ms)
86
88
  * @param {number} [config.retryCount=3] - Retry sayısı
87
89
  * @param {number} [config.retryDelay=1000] - Retry arası bekleme (ms)
90
+ * @param {boolean} [config.verbose=false] - Debug logları göster
88
91
  */
89
92
  constructor(config) {
93
+ config = config || {};
90
94
  this.config = Object.assign({}, DEFAULT_CONFIG, config);
91
95
  this.baseUrl = this._resolveBaseUrl();
92
96
  this.token = null;
93
- this.siteId = config.siteId || null;
97
+ this.siteId = this.config.siteId || null;
98
+ this.verbose = this.config.verbose || false;
99
+
100
+ // Debug: config değerlerini logla
101
+ if (this.verbose) {
102
+ console.log('[SupsisJS] HttpClient config:', {
103
+ timeout: this.config.timeout,
104
+ retryCount: this.config.retryCount,
105
+ env: this.config.env,
106
+ baseUrl: this.baseUrl
107
+ });
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Verbose log yazdırır
113
+ * @private
114
+ * @param {string} type - Log tipi (info, warn, error, request, response)
115
+ * @param {...any} args - Log argümanları
116
+ */
117
+ _log(type) {
118
+ if (!this.verbose) return;
119
+
120
+ var args = Array.prototype.slice.call(arguments, 1);
121
+ var prefix = '[SupsisJS]';
122
+ var timestamp = new Date().toISOString();
123
+
124
+ switch (type) {
125
+ case 'info':
126
+ console.log.apply(console, [prefix, timestamp, 'INFO:'].concat(args));
127
+ break;
128
+ case 'warn':
129
+ console.warn.apply(console, [prefix, timestamp, 'WARN:'].concat(args));
130
+ break;
131
+ case 'error':
132
+ console.error.apply(console, [prefix, timestamp, 'ERROR:'].concat(args));
133
+ break;
134
+ case 'request':
135
+ console.log.apply(console, [prefix, timestamp, '→ REQUEST:'].concat(args));
136
+ break;
137
+ case 'response':
138
+ console.log.apply(console, [prefix, timestamp, '← RESPONSE:'].concat(args));
139
+ break;
140
+ default:
141
+ console.log.apply(console, [prefix, timestamp].concat(args));
142
+ }
94
143
  }
95
144
 
96
145
  /**
@@ -149,16 +198,28 @@ class HttpClient {
149
198
  fetchOptions.body = JSON.stringify(options.body);
150
199
  }
151
200
 
201
+ this._log('request', method.toUpperCase(), url, options.body ? JSON.stringify(options.body).substring(0, 200) : '');
202
+
152
203
  let lastError;
153
204
  const retryCount = options.retryCount !== undefined ? options.retryCount : this.config.retryCount;
154
205
 
155
206
  for (let attempt = 0; attempt <= retryCount; attempt++) {
156
207
  try {
208
+ if (attempt > 0) {
209
+ this._log('info', 'Retry attempt', attempt, 'of', retryCount);
210
+ }
211
+
157
212
  const response = await this._fetchWithTimeout(url, fetchOptions);
158
- return await this._handleResponse(response);
213
+ const data = await this._handleResponse(response);
214
+
215
+ this._log('response', response.status, endpoint, typeof data === 'object' ? JSON.stringify(data).substring(0, 200) : data);
216
+
217
+ return data;
159
218
  } catch (error) {
160
219
  lastError = error;
161
220
 
221
+ this._log('error', 'Request failed:', error.message, 'Status:', error.statusCode || 'N/A');
222
+
162
223
  // Auth hatalarında retry yapma
163
224
  if (error.statusCode === HTTP_STATUS.UNAUTHORIZED ||
164
225
  error.statusCode === HTTP_STATUS.FORBIDDEN) {
@@ -167,6 +228,7 @@ class HttpClient {
167
228
 
168
229
  // Son deneme değilse bekle ve tekrar dene
169
230
  if (attempt < retryCount) {
231
+ this._log('info', 'Waiting', this.config.retryDelay * (attempt + 1), 'ms before retry...');
170
232
  await this._sleep(this.config.retryDelay * (attempt + 1));
171
233
  }
172
234
  }
@@ -180,23 +242,62 @@ class HttpClient {
180
242
  * @private
181
243
  */
182
244
  async _fetchWithTimeout(url, options) {
183
- const controller = new AbortController();
184
- const timeoutId = setTimeout(function() {
245
+ var self = this;
246
+ var timeout = this.config.timeout || 30000;
247
+ var controller = new AbortController();
248
+ var timeoutId = setTimeout(function() {
185
249
  controller.abort();
186
- }, this.config.timeout);
250
+ }, timeout);
251
+
252
+ self._log('info', 'Fetch timeout set to:', timeout, 'ms');
187
253
 
188
254
  try {
189
- const response = await fetch(url, Object.assign({}, options, {
255
+ var response = await fetch(url, Object.assign({}, options, {
190
256
  signal: controller.signal
191
257
  }));
192
258
  clearTimeout(timeoutId);
193
259
  return response;
194
260
  } catch (error) {
195
261
  clearTimeout(timeoutId);
262
+
263
+ // Detaylı hata bilgisi
264
+ self._log('error', 'Fetch error details:', {
265
+ name: error.name,
266
+ message: error.message,
267
+ code: error.code,
268
+ cause: error.cause ? String(error.cause) : undefined
269
+ });
270
+
271
+ // AbortError - gerçek timeout mu yoksa başka bir sebep mi?
196
272
  if (error.name === 'AbortError') {
197
- throw new SupsisAPIError('Request timeout', 408);
273
+ // error.cause varsa gerçek sebebi göster
274
+ var realCause = error.cause ? String(error.cause) : error.message;
275
+ throw new SupsisAPIError('Request aborted: ' + realCause, 408, {
276
+ originalError: error.message,
277
+ cause: realCause,
278
+ timeout: timeout
279
+ });
198
280
  }
199
- throw error;
281
+
282
+ // Network hataları için daha açıklayıcı hata mesajı
283
+ if (error.code === 'ECONNREFUSED') {
284
+ throw new SupsisAPIError('Connection refused: ' + url, 0, { originalError: error.message, code: error.code });
285
+ }
286
+
287
+ if (error.code === 'ENOTFOUND') {
288
+ throw new SupsisAPIError('Host not found: ' + url, 0, { originalError: error.message, code: error.code });
289
+ }
290
+
291
+ if (error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' || error.code === 'CERT_HAS_EXPIRED' || error.code === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
292
+ throw new SupsisAPIError('SSL/TLS certificate error: ' + error.message, 0, { originalError: error.message, code: error.code });
293
+ }
294
+
295
+ // Diğer hatalar için SupsisAPIError'a çevir
296
+ throw new SupsisAPIError(error.message || 'Unknown fetch error', 0, {
297
+ originalError: error.message,
298
+ code: error.code,
299
+ cause: error.cause ? String(error.cause) : undefined
300
+ });
200
301
  }
201
302
  }
202
303
 
@@ -3664,13 +3765,17 @@ class SupsisJS {
3664
3765
  /** @private */
3665
3766
  this._config = config;
3666
3767
 
3768
+ /** @private */
3769
+ this._verbose = config.verbose || false;
3770
+
3667
3771
  /** @private */
3668
3772
  this._http = new HttpClient({
3669
3773
  env: config.env || 'production',
3670
3774
  baseApiAddress: config.baseApiAddress,
3671
3775
  siteId: config.siteId,
3672
3776
  timeout: config.timeout,
3673
- retryCount: config.retryCount
3777
+ retryCount: config.retryCount,
3778
+ verbose: config.verbose
3674
3779
  });
3675
3780
 
3676
3781
  /** @private */
@@ -3684,6 +3789,38 @@ class SupsisJS {
3684
3789
 
3685
3790
  // Modülleri oluştur
3686
3791
  this._initModules();
3792
+
3793
+ this._log('info', 'SupsisJS initialized', {
3794
+ env: config.env || 'production',
3795
+ baseApiAddress: config.baseApiAddress || 'default',
3796
+ siteId: config.siteId
3797
+ });
3798
+ }
3799
+
3800
+ /**
3801
+ * Verbose log yazdırır
3802
+ * @private
3803
+ */
3804
+ _log(type) {
3805
+ if (!this._verbose) return;
3806
+
3807
+ var args = Array.prototype.slice.call(arguments, 1);
3808
+ var prefix = '[SupsisJS]';
3809
+ var timestamp = new Date().toISOString();
3810
+
3811
+ switch (type) {
3812
+ case 'info':
3813
+ console.log.apply(console, [prefix, timestamp, 'INFO:'].concat(args));
3814
+ break;
3815
+ case 'warn':
3816
+ console.warn.apply(console, [prefix, timestamp, 'WARN:'].concat(args));
3817
+ break;
3818
+ case 'error':
3819
+ console.error.apply(console, [prefix, timestamp, 'ERROR:'].concat(args));
3820
+ break;
3821
+ default:
3822
+ console.log.apply(console, [prefix, timestamp].concat(args));
3823
+ }
3687
3824
  }
3688
3825
 
3689
3826
  /**
@@ -3789,17 +3926,34 @@ class SupsisJS {
3789
3926
  * console.log('Connected as:', supsis.currentUser.fullname);
3790
3927
  */
3791
3928
  async connect() {
3929
+ var self = this;
3930
+
3792
3931
  if (this._connected) {
3932
+ this._log('info', 'Already connected');
3793
3933
  return this._user;
3794
3934
  }
3795
3935
 
3796
- const response = await this._http.post('/api/users/login', {
3797
- email: this._config.email,
3798
- password: this._config.password
3799
- }, { skipAuth: true });
3936
+ this._log('info', 'Connecting to Supsis API...');
3937
+ this._log('info', 'Base URL:', this._http.baseUrl);
3938
+
3939
+ var response;
3940
+ try {
3941
+ response = await this._http.post('/api/users/login', {
3942
+ email: this._config.email,
3943
+ password: this._config.password
3944
+ }, { skipAuth: true, retryCount: 0 });
3945
+ } catch (error) {
3946
+ self._log('error', 'Login failed:', error.message);
3947
+ throw error;
3948
+ }
3800
3949
 
3801
3950
  if (!response || !response.token) {
3802
- throw new SupsisAPIError('Login failed: No token received', 401);
3951
+ var errorMsg = 'Login failed: No token received';
3952
+ if (response && response.message) {
3953
+ errorMsg = 'Login failed: ' + response.message;
3954
+ }
3955
+ self._log('error', errorMsg);
3956
+ throw new SupsisAPIError(errorMsg, 401, response);
3803
3957
  }
3804
3958
 
3805
3959
  this._token = response.token;
@@ -3807,6 +3961,8 @@ class SupsisJS {
3807
3961
  this._http.setToken(this._token);
3808
3962
  this._connected = true;
3809
3963
 
3964
+ this._log('info', 'Connected successfully as:', this._user.fullname || this._user.email);
3965
+
3810
3966
  return this._user;
3811
3967
  }
3812
3968