@wazo/sdk 0.37.0-rc.5 → 0.37.2

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 (149) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +93 -16
  3. package/esm/__tests__/web-rtc-client.test.js +153 -54
  4. package/esm/api/agentd.js +24 -3
  5. package/esm/api/amid.js +7 -1
  6. package/esm/api/application.js +24 -3
  7. package/esm/api/auth.js +24 -3
  8. package/esm/api/call-logd.js +78 -20
  9. package/esm/api/calld.js +24 -20
  10. package/esm/api/chatd.js +24 -3
  11. package/esm/api/confd.js +24 -3
  12. package/esm/api/ctid-ng.js +24 -3
  13. package/esm/api/dird.js +27 -6
  14. package/esm/api/webhookd.js +7 -1
  15. package/esm/api-client.js +93 -16
  16. package/esm/checker/Checker.js +156 -54
  17. package/esm/checker/checks/aor.js +95 -16
  18. package/esm/checker/checks/api.js +94 -16
  19. package/esm/checker/checks/index.js +156 -54
  20. package/esm/checker/checks/wazo-websocket.js +7 -1
  21. package/esm/checker/checks/webrtc-transport.js +153 -54
  22. package/esm/checker/checks/webrtc.js +153 -54
  23. package/esm/domain/AdHocAPIConference.js +1717 -1640
  24. package/esm/domain/CallLog.js +71 -19
  25. package/esm/domain/CallSession.js +1 -18
  26. package/esm/domain/Contact.js +3 -3
  27. package/esm/domain/Features.js +93 -16
  28. package/esm/domain/IndirectTransfer.js +0 -17
  29. package/esm/domain/Phone/CTIPhone.js +100 -19
  30. package/esm/domain/Phone/Phone.js +0 -17
  31. package/esm/domain/Phone/WebRTCPhone.js +51 -36
  32. package/esm/domain/Recording.js +51 -0
  33. package/esm/domain/Room.js +0 -17
  34. package/esm/domain/SwitchboardCall.js +0 -17
  35. package/esm/domain/__tests__/CallLog.test.js +89 -19
  36. package/esm/domain/__tests__/CallSession.test.js +1 -18
  37. package/esm/domain/__tests__/Contact.test.js +3 -3
  38. package/esm/domain/__tests__/IndirectTransfer.test.js +1 -18
  39. package/esm/domain/__tests__/Room.test.js +1 -18
  40. package/esm/domain/__tests__/Session.test.js +7 -0
  41. package/esm/index.js +3436 -2911
  42. package/esm/lib/WazoSessionDescriptionHandler.js +28 -10
  43. package/esm/service/CallApi.js +93 -16
  44. package/esm/service/IssueReporter.js +7 -1
  45. package/esm/service/__tests__/IssueReporter.test.js +26 -2
  46. package/esm/service/getApiClient.js +93 -16
  47. package/esm/simple/Auth.js +619 -97
  48. package/esm/simple/Configuration.js +619 -97
  49. package/esm/simple/Directory.js +93 -16
  50. package/esm/simple/Phone.js +3261 -2739
  51. package/esm/simple/Websocket.js +7 -1
  52. package/esm/simple/index.js +619 -97
  53. package/esm/simple/room/LocalParticipant.js +619 -97
  54. package/esm/simple/room/Participant.js +619 -97
  55. package/esm/simple/room/RemoteParticipant.js +619 -97
  56. package/esm/simple/room/Room.js +619 -97
  57. package/esm/simple/room/Stream.js +619 -97
  58. package/esm/simple/room/__tests__/RemoteParticipant.test.js +619 -97
  59. package/esm/simple/utils.js +619 -97
  60. package/esm/utils/__tests__/api-requester.test.js +32 -6
  61. package/esm/utils/api-requester.js +24 -3
  62. package/esm/web-rtc-client.js +153 -54
  63. package/esm/websocket-client.js +7 -1
  64. package/lib/__tests__/api-client.test.js +93 -16
  65. package/lib/__tests__/web-rtc-client.test.js +154 -55
  66. package/lib/api/agentd.js +24 -3
  67. package/lib/api/amid.js +7 -1
  68. package/lib/api/application.js +24 -3
  69. package/lib/api/auth.js +24 -3
  70. package/lib/api/call-logd.js +78 -20
  71. package/lib/api/calld.js +24 -20
  72. package/lib/api/chatd.js +24 -3
  73. package/lib/api/confd.js +24 -3
  74. package/lib/api/ctid-ng.js +24 -3
  75. package/lib/api/dird.js +27 -6
  76. package/lib/api/webhookd.js +7 -1
  77. package/lib/api-client.js +93 -16
  78. package/lib/checker/Checker.js +157 -55
  79. package/lib/checker/checks/aor.js +95 -16
  80. package/lib/checker/checks/api.js +94 -16
  81. package/lib/checker/checks/index.js +157 -55
  82. package/lib/checker/checks/wazo-websocket.js +7 -1
  83. package/lib/checker/checks/webrtc-transport.js +154 -55
  84. package/lib/checker/checks/webrtc.js +154 -55
  85. package/lib/domain/AdHocAPIConference.js +1717 -1640
  86. package/lib/domain/CallLog.js +71 -19
  87. package/lib/domain/CallSession.js +1 -18
  88. package/lib/domain/Contact.js +3 -3
  89. package/lib/domain/Features.js +93 -16
  90. package/lib/domain/IndirectTransfer.js +0 -17
  91. package/lib/domain/Phone/CTIPhone.js +100 -19
  92. package/lib/domain/Phone/Phone.js +0 -16
  93. package/lib/domain/Phone/WebRTCPhone.js +51 -36
  94. package/lib/domain/Recording.js +57 -0
  95. package/lib/domain/Room.js +0 -17
  96. package/lib/domain/SwitchboardCall.js +0 -17
  97. package/lib/domain/__tests__/CallLog.test.js +89 -19
  98. package/lib/domain/__tests__/CallSession.test.js +1 -18
  99. package/lib/domain/__tests__/Contact.test.js +3 -3
  100. package/lib/domain/__tests__/IndirectTransfer.test.js +1 -18
  101. package/lib/domain/__tests__/Room.test.js +1 -18
  102. package/lib/domain/__tests__/Session.test.js +7 -0
  103. package/lib/index.js +3437 -2912
  104. package/lib/lib/WazoSessionDescriptionHandler.js +28 -10
  105. package/lib/service/CallApi.js +93 -16
  106. package/lib/service/IssueReporter.js +7 -1
  107. package/lib/service/__tests__/IssueReporter.test.js +26 -2
  108. package/lib/service/getApiClient.js +93 -16
  109. package/lib/simple/Auth.js +620 -98
  110. package/lib/simple/Configuration.js +620 -98
  111. package/lib/simple/Directory.js +93 -16
  112. package/lib/simple/Phone.js +3262 -2740
  113. package/lib/simple/Websocket.js +7 -1
  114. package/lib/simple/index.js +620 -98
  115. package/lib/simple/room/LocalParticipant.js +620 -98
  116. package/lib/simple/room/Participant.js +620 -98
  117. package/lib/simple/room/RemoteParticipant.js +620 -98
  118. package/lib/simple/room/Room.js +620 -98
  119. package/lib/simple/room/Stream.js +620 -98
  120. package/lib/simple/room/__tests__/RemoteParticipant.test.js +620 -98
  121. package/lib/simple/utils.js +620 -98
  122. package/lib/utils/__tests__/api-requester.test.js +32 -6
  123. package/lib/utils/api-requester.js +24 -3
  124. package/lib/web-rtc-client.js +154 -55
  125. package/lib/websocket-client.js +7 -1
  126. package/package.json +1 -1
  127. package/src/api-client.js +4 -0
  128. package/src/checker/checks/aor.js +2 -0
  129. package/src/checker/checks/api.js +1 -0
  130. package/src/domain/CallLog.js +18 -11
  131. package/src/domain/CallSession.js +1 -2
  132. package/src/domain/Contact.js +3 -3
  133. package/src/domain/Phone/CTIPhone.js +6 -2
  134. package/src/domain/Phone/Phone.js +2 -0
  135. package/src/domain/Phone/WebRTCPhone.js +26 -16
  136. package/src/domain/Recording.js +48 -0
  137. package/src/domain/__tests__/CallLog.test.js +19 -0
  138. package/src/domain/__tests__/Session.test.js +7 -0
  139. package/src/index.js +6 -0
  140. package/src/lib/WazoSessionDescriptionHandler.js +21 -9
  141. package/src/service/IssueReporter.js +7 -1
  142. package/src/service/__tests__/IssueReporter.test.js +20 -1
  143. package/src/simple/Phone.js +5 -1
  144. package/src/simple/index.js +6 -0
  145. package/src/simple/room/Room.js +18 -15
  146. package/src/simple/room/Stream.js +1 -4
  147. package/src/utils/__tests__/api-requester.test.js +9 -4
  148. package/src/utils/api-requester.js +17 -2
  149. package/src/web-rtc-client.js +40 -13
@@ -286,7 +286,13 @@ class IssueReporter {
286
286
  }
287
287
 
288
288
  _isLevelAbove(level1 , level2 ) {
289
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
289
+ const index1 = LOG_LEVELS.indexOf(level1);
290
+ const index2 = LOG_LEVELS.indexOf(level2);
291
+ if (index1 === -1 || index2 === -1) {
292
+ return false;
293
+ }
294
+
295
+ return index1 > index2;
290
296
  }
291
297
 
292
298
  _makeCategory(category ) {
@@ -415,6 +421,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
415
421
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
416
422
 
417
423
  const isConference = options ? !!options.conference : false;
424
+ const audioOnly = options ? !!options.audioOnly : false;
418
425
 
419
426
  // We should wait for ice when iceRestart (reinvite) or for the first invite
420
427
  // We shouldn't wait for ice when holding or resuming the call
@@ -441,16 +448,16 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
441
448
  };
442
449
 
443
450
  return this.getLocalMediaStream(options)
444
- .then(() => this.updateDirection(options, isConference))
451
+ .then(() => this.updateDirection(options, isConference, audioOnly))
445
452
  .then(() => this.createDataChannel(options))
446
453
  .then(() => {
447
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
454
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
448
455
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
449
456
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
450
457
  }
451
458
  })
452
459
  .then(() => this.createLocalOfferOrAnswer(options))
453
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
460
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
454
461
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
455
462
  .then(() => this.getLocalSessionDescription())
456
463
  .then(description => {
@@ -573,7 +580,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
573
580
  }
574
581
 
575
582
  // Overridden to send `inactive` in conference
576
- updateDirection(options , isConference = false) {
583
+ updateDirection(options , isConference = false,
584
+ audioOnly = false) {
577
585
  if (this._peerConnection === undefined) {
578
586
  return Promise.reject(new Error('Peer connection closed.'));
579
587
  }
@@ -588,14 +596,17 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
588
596
  // if we are stable, assume we are creating a local offer
589
597
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
590
598
  // determine the direction to offer given the current direction and hold state
591
- const directionToOffer = (currentDirection ) => {
599
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
592
600
  if (isConference) {
601
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
602
+ return 'sendonly';
603
+ }
593
604
  return options && options.hold ? 'sendonly' : 'sendrecv';
594
605
  }
595
606
 
596
607
  switch (currentDirection) {
597
608
  case 'inactive':
598
- return options && options.hold ? 'inactive' : 'recvonly';
609
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
599
610
  case 'recvonly':
600
611
  return options && options.hold ? 'inactive' : 'recvonly';
601
612
  case 'sendonly':
@@ -611,7 +622,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
611
622
  // set the transceiver direction to the offer direction
612
623
  this._peerConnection.getTransceivers().forEach((transceiver) => {
613
624
  if (transceiver.direction /* guarding, but should always be true */) {
614
- const offerDirection = directionToOffer(transceiver.direction);
625
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
615
626
  if (transceiver.direction !== offerDirection) {
616
627
  // eslint-disable-next-line no-param-reassign
617
628
  transceiver.direction = offerDirection;
@@ -670,6 +681,13 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
670
681
  // set the transceiver direction to the answer direction
671
682
  this._peerConnection.getTransceivers().forEach((transceiver) => {
672
683
  if (transceiver.direction /* guarding, but should always be true */) {
684
+ const { receiver } = transceiver;
685
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
686
+ // eslint-disable-next-line no-param-reassign
687
+ transceiver.direction = 'inactive';
688
+ return;
689
+ }
690
+
673
691
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
674
692
  // eslint-disable-next-line no-param-reassign
675
693
  transceiver.direction = answerDirection;
@@ -708,8 +726,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
708
726
  }
709
727
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
710
728
 
711
- // Do not reuse sender tracks in SFU
712
- if (sender && !sfu) {
729
+ // Do not reuse sender video tracks in SFU
730
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
713
731
  trackUpdates.push(
714
732
  new Promise((resolve) => {
715
733
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -1179,7 +1179,7 @@ class Contact {
1179
1179
 
1180
1180
  return new Contact({
1181
1181
  sourceId: single.id || '',
1182
- name: single.displayName,
1182
+ name: single.displayName || '',
1183
1183
  number: numbers.length ? numbers[0].number : '',
1184
1184
  numbers,
1185
1185
  emails,
@@ -1210,7 +1210,7 @@ class Contact {
1210
1210
 
1211
1211
  return new Contact({
1212
1212
  sourceId: single.id || '',
1213
- name: single.name,
1213
+ name: single.name || '',
1214
1214
  number: numbers.length ? numbers[0].number : '',
1215
1215
  numbers,
1216
1216
  emails,
@@ -1311,7 +1311,7 @@ class Contact {
1311
1311
  } = {}) {
1312
1312
  this.id = id;
1313
1313
  this.uuid = uuid;
1314
- this.name = name;
1314
+ this.name = name || '';
1315
1315
  this.number = number;
1316
1316
  this.numbers = numbers;
1317
1317
  this.email = email;
@@ -1684,17 +1684,66 @@ class Session {
1684
1684
 
1685
1685
  //
1686
1686
 
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+
1693
+
1694
+
1695
+
1696
+
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+ class Recording {
1704
+
1705
+
1706
+
1707
+
1708
+
1709
+
1710
+ static parseMany(recordings ) {
1711
+ return recordings.map(item => Recording.parse(item));
1712
+ }
1713
+
1714
+ static parse(plain ) {
1715
+ return new Recording({
1716
+ deleted: plain.deleted,
1717
+ fileName: plain.filename,
1718
+ end: plain.end_time ? moment__default['default'](plain.end_time).toDate() : null,
1719
+ start: moment__default['default'](plain.start_time).toDate(),
1720
+ uuid: plain.uuid,
1721
+ });
1722
+ }
1723
+
1724
+ constructor({ deleted, end, fileName, start, uuid } ) {
1725
+ this.deleted = deleted;
1726
+ this.end = end;
1727
+ this.fileName = fileName;
1728
+ this.start = start;
1729
+ this.uuid = uuid;
1730
+ }
1731
+ }
1732
+
1733
+ //
1734
+
1687
1735
 
1688
-
1736
+
1689
1737
 
1690
1738
 
1691
1739
 
1692
1740
 
1693
1741
 
1694
-
1742
+
1695
1743
 
1696
1744
 
1697
1745
 
1746
+
1698
1747
 
1699
1748
 
1700
1749
 
@@ -1707,7 +1756,7 @@ class Session {
1707
1756
 
1708
1757
 
1709
1758
 
1710
-
1759
+
1711
1760
 
1712
1761
 
1713
1762
 
@@ -1722,13 +1771,14 @@ class Session {
1722
1771
 
1723
1772
 
1724
1773
 
1725
-
1774
+
1775
+
1726
1776
 
1727
1777
 
1728
1778
  class CallLog {
1729
1779
 
1730
1780
 
1731
-
1781
+
1732
1782
 
1733
1783
 
1734
1784
 
@@ -1745,7 +1795,7 @@ class CallLog {
1745
1795
 
1746
1796
 
1747
1797
 
1748
-
1798
+
1749
1799
 
1750
1800
  static merge(current , toMerge ) {
1751
1801
  const onlyUnique = (value, index, self) => self.indexOf(value) === index;
@@ -1762,7 +1812,7 @@ class CallLog {
1762
1812
 
1763
1813
  static parse(plain ) {
1764
1814
  return new CallLog({
1765
- answer: moment__default['default'](plain.answer).toDate(),
1815
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
1766
1816
  answered: plain.answered,
1767
1817
  callDirection: plain.call_direction,
1768
1818
  destination: {
@@ -1776,13 +1826,14 @@ class CallLog {
1776
1826
  id: plain.id,
1777
1827
  duration: (plain.duration || 0) * 1000, // duration is in seconds
1778
1828
  start: moment__default['default'](plain.start).toDate(),
1779
- end: moment__default['default'](plain.end).toDate(),
1829
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
1830
+ recordings: Recording.parseMany(plain.recordings),
1780
1831
  });
1781
1832
  }
1782
1833
 
1783
1834
  static parseNew(plain , session ) {
1784
1835
  return new CallLog({
1785
- answer: moment__default['default'](plain.answer).toDate(),
1836
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
1786
1837
  answered: plain.answered,
1787
1838
  callDirection: plain.call_direction,
1788
1839
  destination: {
@@ -1796,7 +1847,8 @@ class CallLog {
1796
1847
  id: plain.id,
1797
1848
  duration: (plain.duration || 0) * 1000, // duration is in seconds
1798
1849
  start: moment__default['default'](plain.start).toDate(),
1799
- end: moment__default['default'](plain.end).toDate(),
1850
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
1851
+ recordings: Recording.parseMany(plain.recordings),
1800
1852
  // @TODO: FIXME add verification declined vs missed call
1801
1853
  newMissedCall: session
1802
1854
  && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
@@ -2272,7 +2324,13 @@ class IssueReporter {
2272
2324
  }
2273
2325
 
2274
2326
  _isLevelAbove(level1 , level2 ) {
2275
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
2327
+ const index1 = LOG_LEVELS.indexOf(level1);
2328
+ const index2 = LOG_LEVELS.indexOf(level2);
2329
+ if (index1 === -1 || index2 === -1) {
2330
+ return false;
2331
+ }
2332
+
2333
+ return index1 > index2;
2276
2334
  }
2277
2335
 
2278
2336
  _makeCategory(category ) {
@@ -2330,6 +2388,7 @@ class ApiRequester {
2330
2388
 
2331
2389
 
2332
2390
 
2391
+
2333
2392
 
2334
2393
 
2335
2394
 
@@ -2369,6 +2428,8 @@ class ApiRequester {
2369
2428
  this.token = token;
2370
2429
  }
2371
2430
 
2431
+ this.shouldLogErrors = true;
2432
+
2372
2433
  methods.forEach(method => {
2373
2434
  // $FlowFixMe
2374
2435
  ApiRequester.prototype[method] = function sugar(...args) {
@@ -2392,6 +2453,14 @@ class ApiRequester {
2392
2453
  this.fetchOptions = options;
2393
2454
  }
2394
2455
 
2456
+ disableErrorLogging() {
2457
+ this.shouldLogErrors = false;
2458
+ }
2459
+
2460
+ enableErrorLogging() {
2461
+ this.shouldLogErrors = true;
2462
+ }
2463
+
2395
2464
  async call(
2396
2465
  path ,
2397
2466
  method = 'get',
@@ -2452,7 +2521,9 @@ class ApiRequester {
2452
2521
  ? exceptionClass.fromText(err, response.status)
2453
2522
  : exceptionClass.fromResponse(err, response.status);
2454
2523
 
2455
- logger$1.error('API error', error);
2524
+ if (this.shouldLogErrors) {
2525
+ logger$1.error('API error', error);
2526
+ }
2456
2527
 
2457
2528
  throw error;
2458
2529
  });
@@ -2460,7 +2531,9 @@ class ApiRequester {
2460
2531
 
2461
2532
  return newParse(response, isJson);
2462
2533
  }).catch(error => {
2463
- logger$1.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2534
+ if (this.shouldLogErrors) {
2535
+ logger$1.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2536
+ }
2464
2537
 
2465
2538
  throw error;
2466
2539
  });
@@ -4327,6 +4400,10 @@ class ApiClient {
4327
4400
  this.fetchOptions = fetchOptions;
4328
4401
  this.client.setFetchOptions(fetchOptions);
4329
4402
  }
4403
+
4404
+ disableErrorLogging() {
4405
+ this.client.disableErrorLogging();
4406
+ }
4330
4407
  }
4331
4408
 
4332
4409
  /* eslint-disable dot-notation */
@@ -278,7 +278,13 @@ class IssueReporter {
278
278
  }
279
279
 
280
280
  _isLevelAbove(level1 , level2 ) {
281
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
281
+ const index1 = LOG_LEVELS.indexOf(level1);
282
+ const index2 = LOG_LEVELS.indexOf(level2);
283
+ if (index1 === -1 || index2 === -1) {
284
+ return false;
285
+ }
286
+
287
+ return index1 > index2;
282
288
  }
283
289
 
284
290
  _makeCategory(category ) {
@@ -278,7 +278,13 @@ class IssueReporter {
278
278
  }
279
279
 
280
280
  _isLevelAbove(level1 , level2 ) {
281
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
281
+ const index1 = LOG_LEVELS.indexOf(level1);
282
+ const index2 = LOG_LEVELS.indexOf(level2);
283
+ if (index1 === -1 || index2 === -1) {
284
+ return false;
285
+ }
286
+
287
+ return index1 > index2;
282
288
  }
283
289
 
284
290
  _makeCategory(category ) {
@@ -292,11 +298,22 @@ var IssueReporter$1 = new IssueReporter();
292
298
 
293
299
  jest.mock('../../utils/api-requester');
294
300
 
295
- IssueReporter$1.enable();
301
+ let oldLog;
302
+ let oldError;
296
303
 
297
304
  class MyError extends Error {}
298
305
 
299
306
  describe('IssueReporter', () => {
307
+ beforeAll(() => {
308
+ oldLog = console.log;
309
+ oldError = console.error;
310
+
311
+ console.log = () => {};
312
+ console.error = () => {};
313
+
314
+ IssueReporter$1.enable();
315
+ });
316
+
300
317
  beforeEach(() => {
301
318
  jest.resetAllMocks();
302
319
 
@@ -305,12 +322,19 @@ describe('IssueReporter', () => {
305
322
  }));
306
323
  });
307
324
 
325
+ afterAll(() => {
326
+ console.log = oldLog;
327
+ console.error = oldError;
328
+ });
329
+
308
330
  it('should compute level order', () => {
309
331
  expect(IssueReporter$1._isLevelAbove('info', 'trace')).toBeTruthy();
310
332
  expect(IssueReporter$1._isLevelAbove('trace', 'warn')).toBeFalsy();
311
333
  expect(IssueReporter$1._isLevelAbove('error', 'warn')).toBeTruthy();
312
334
  expect(IssueReporter$1._isLevelAbove('info', 'warn')).toBeFalsy();
313
335
  expect(IssueReporter$1._isLevelAbove('trace', 'trace')).toBeFalsy();
336
+ expect(IssueReporter$1._isLevelAbove('trace', 'something')).toBeFalsy();
337
+ expect(IssueReporter$1._isLevelAbove('something', 'trace')).toBeFalsy();
314
338
  });
315
339
 
316
340
  it('should send if verbosity is higher than required', () => {
@@ -317,7 +317,13 @@ class IssueReporter {
317
317
  }
318
318
 
319
319
  _isLevelAbove(level1 , level2 ) {
320
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
320
+ const index1 = LOG_LEVELS.indexOf(level1);
321
+ const index2 = LOG_LEVELS.indexOf(level2);
322
+ if (index1 === -1 || index2 === -1) {
323
+ return false;
324
+ }
325
+
326
+ return index1 > index2;
321
327
  }
322
328
 
323
329
  _makeCategory(category ) {
@@ -375,6 +381,7 @@ class ApiRequester {
375
381
 
376
382
 
377
383
 
384
+
378
385
 
379
386
 
380
387
 
@@ -414,6 +421,8 @@ class ApiRequester {
414
421
  this.token = token;
415
422
  }
416
423
 
424
+ this.shouldLogErrors = true;
425
+
417
426
  methods.forEach(method => {
418
427
  // $FlowFixMe
419
428
  ApiRequester.prototype[method] = function sugar(...args) {
@@ -437,6 +446,14 @@ class ApiRequester {
437
446
  this.fetchOptions = options;
438
447
  }
439
448
 
449
+ disableErrorLogging() {
450
+ this.shouldLogErrors = false;
451
+ }
452
+
453
+ enableErrorLogging() {
454
+ this.shouldLogErrors = true;
455
+ }
456
+
440
457
  async call(
441
458
  path ,
442
459
  method = 'get',
@@ -497,7 +514,9 @@ class ApiRequester {
497
514
  ? exceptionClass.fromText(err, response.status)
498
515
  : exceptionClass.fromResponse(err, response.status);
499
516
 
500
- logger$1.error('API error', error);
517
+ if (this.shouldLogErrors) {
518
+ logger$1.error('API error', error);
519
+ }
501
520
 
502
521
  throw error;
503
522
  });
@@ -505,7 +524,9 @@ class ApiRequester {
505
524
 
506
525
  return newParse(response, isJson);
507
526
  }).catch(error => {
508
- logger$1.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
527
+ if (this.shouldLogErrors) {
528
+ logger$1.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
529
+ }
509
530
 
510
531
  throw error;
511
532
  });
@@ -1555,7 +1576,7 @@ class Contact {
1555
1576
 
1556
1577
  return new Contact({
1557
1578
  sourceId: single.id || '',
1558
- name: single.displayName,
1579
+ name: single.displayName || '',
1559
1580
  number: numbers.length ? numbers[0].number : '',
1560
1581
  numbers,
1561
1582
  emails,
@@ -1586,7 +1607,7 @@ class Contact {
1586
1607
 
1587
1608
  return new Contact({
1588
1609
  sourceId: single.id || '',
1589
- name: single.name,
1610
+ name: single.name || '',
1590
1611
  number: numbers.length ? numbers[0].number : '',
1591
1612
  numbers,
1592
1613
  emails,
@@ -1687,7 +1708,7 @@ class Contact {
1687
1708
  } = {}) {
1688
1709
  this.id = id;
1689
1710
  this.uuid = uuid;
1690
- this.name = name;
1711
+ this.name = name || '';
1691
1712
  this.number = number;
1692
1713
  this.numbers = numbers;
1693
1714
  this.email = email;
@@ -2996,17 +3017,66 @@ var updateFrom = (instance , from ) => {
2996
3017
 
2997
3018
  //
2998
3019
 
3020
+
3021
+
3022
+
3023
+
3024
+
3025
+
3026
+
3027
+
3028
+
3029
+
3030
+
3031
+
3032
+
3033
+
3034
+
3035
+
3036
+ class Recording {
3037
+
3038
+
3039
+
3040
+
3041
+
3042
+
3043
+ static parseMany(recordings ) {
3044
+ return recordings.map(item => Recording.parse(item));
3045
+ }
3046
+
3047
+ static parse(plain ) {
3048
+ return new Recording({
3049
+ deleted: plain.deleted,
3050
+ fileName: plain.filename,
3051
+ end: plain.end_time ? moment__default['default'](plain.end_time).toDate() : null,
3052
+ start: moment__default['default'](plain.start_time).toDate(),
3053
+ uuid: plain.uuid,
3054
+ });
3055
+ }
3056
+
3057
+ constructor({ deleted, end, fileName, start, uuid } ) {
3058
+ this.deleted = deleted;
3059
+ this.end = end;
3060
+ this.fileName = fileName;
3061
+ this.start = start;
3062
+ this.uuid = uuid;
3063
+ }
3064
+ }
3065
+
3066
+ //
3067
+
2999
3068
 
3000
-
3069
+
3001
3070
 
3002
3071
 
3003
3072
 
3004
3073
 
3005
3074
 
3006
-
3075
+
3007
3076
 
3008
3077
 
3009
3078
 
3079
+
3010
3080
 
3011
3081
 
3012
3082
 
@@ -3019,7 +3089,7 @@ var updateFrom = (instance , from ) => {
3019
3089
 
3020
3090
 
3021
3091
 
3022
-
3092
+
3023
3093
 
3024
3094
 
3025
3095
 
@@ -3034,13 +3104,14 @@ var updateFrom = (instance , from ) => {
3034
3104
 
3035
3105
 
3036
3106
 
3037
-
3107
+
3108
+
3038
3109
 
3039
3110
 
3040
3111
  class CallLog {
3041
3112
 
3042
3113
 
3043
-
3114
+
3044
3115
 
3045
3116
 
3046
3117
 
@@ -3057,7 +3128,7 @@ class CallLog {
3057
3128
 
3058
3129
 
3059
3130
 
3060
-
3131
+
3061
3132
 
3062
3133
  static merge(current , toMerge ) {
3063
3134
  const onlyUnique = (value, index, self) => self.indexOf(value) === index;
@@ -3074,7 +3145,7 @@ class CallLog {
3074
3145
 
3075
3146
  static parse(plain ) {
3076
3147
  return new CallLog({
3077
- answer: moment__default['default'](plain.answer).toDate(),
3148
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3078
3149
  answered: plain.answered,
3079
3150
  callDirection: plain.call_direction,
3080
3151
  destination: {
@@ -3088,13 +3159,14 @@ class CallLog {
3088
3159
  id: plain.id,
3089
3160
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3090
3161
  start: moment__default['default'](plain.start).toDate(),
3091
- end: moment__default['default'](plain.end).toDate(),
3162
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3163
+ recordings: Recording.parseMany(plain.recordings),
3092
3164
  });
3093
3165
  }
3094
3166
 
3095
3167
  static parseNew(plain , session ) {
3096
3168
  return new CallLog({
3097
- answer: moment__default['default'](plain.answer).toDate(),
3169
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3098
3170
  answered: plain.answered,
3099
3171
  callDirection: plain.call_direction,
3100
3172
  destination: {
@@ -3108,7 +3180,8 @@ class CallLog {
3108
3180
  id: plain.id,
3109
3181
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3110
3182
  start: moment__default['default'](plain.start).toDate(),
3111
- end: moment__default['default'](plain.end).toDate(),
3183
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3184
+ recordings: Recording.parseMany(plain.recordings),
3112
3185
  // @TODO: FIXME add verification declined vs missed call
3113
3186
  newMissedCall: session
3114
3187
  && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
@@ -4329,6 +4402,10 @@ class ApiClient {
4329
4402
  this.fetchOptions = fetchOptions;
4330
4403
  this.client.setFetchOptions(fetchOptions);
4331
4404
  }
4405
+
4406
+ disableErrorLogging() {
4407
+ this.client.disableErrorLogging();
4408
+ }
4332
4409
  }
4333
4410
 
4334
4411
  /* eslint-disable dot-notation */