@wazo/sdk 0.37.20 → 0.37.24

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 (147) hide show
  1. package/dist/wazo-sdk.js +6 -6
  2. package/esm/__tests__/api-client.test.js +91 -21
  3. package/esm/__tests__/web-rtc-client.test.js +214 -165
  4. package/esm/api/agentd.js +25 -2
  5. package/esm/api/amid.js +26 -3
  6. package/esm/api/application.js +25 -2
  7. package/esm/api/auth.js +25 -2
  8. package/esm/api/call-logd.js +34 -4
  9. package/esm/api/calld.js +35 -2
  10. package/esm/api/chatd.js +32 -2
  11. package/esm/api/confd.js +56 -9
  12. package/esm/api/ctid-ng.js +38 -5
  13. package/esm/api/dird.js +29 -3
  14. package/esm/api/webhookd.js +26 -3
  15. package/esm/api-client.js +91 -21
  16. package/esm/checker/Checker.js +241 -190
  17. package/esm/checker/checks/aor.js +91 -21
  18. package/esm/checker/checks/api.js +91 -21
  19. package/esm/checker/checks/index.js +231 -180
  20. package/esm/checker/checks/wazo-websocket.js +42 -17
  21. package/esm/checker/checks/webrtc-transport.js +214 -165
  22. package/esm/checker/checks/webrtc.js +214 -165
  23. package/esm/domain/AdHocAPIConference.js +91 -21
  24. package/esm/domain/Call.js +3 -0
  25. package/esm/domain/CallLog.js +8 -1
  26. package/esm/domain/ChatMessage.js +4 -0
  27. package/esm/domain/ChatRoom.js +3 -0
  28. package/esm/domain/Contact.js +4 -1
  29. package/esm/domain/Features.js +91 -21
  30. package/esm/domain/Meeting.js +28 -5
  31. package/esm/domain/Phone/CTIPhone.js +109 -35
  32. package/esm/domain/Phone/WebRTCPhone.js +159 -102
  33. package/esm/domain/Recording.js +3 -0
  34. package/esm/domain/Voicemail.js +3 -0
  35. package/esm/domain/__tests__/Call.test.js +3 -0
  36. package/esm/domain/__tests__/CallLog.test.js +8 -1
  37. package/esm/domain/__tests__/Contact.test.js +4 -1
  38. package/esm/domain/__tests__/Meeting.test.js +144 -0
  39. package/esm/domain/__tests__/Voicemail.test.js +3 -0
  40. package/esm/index.js +509 -414
  41. package/esm/lib/WazoSessionDescriptionHandler.js +26 -41
  42. package/esm/service/CallApi.js +91 -21
  43. package/esm/service/IssueReporter.js +26 -3
  44. package/esm/service/__tests__/IssueReporter.test.js +26 -3
  45. package/esm/service/getApiClient.js +91 -21
  46. package/esm/simple/Auth.js +499 -404
  47. package/esm/simple/Configuration.js +499 -404
  48. package/esm/simple/Directory.js +91 -21
  49. package/esm/simple/Phone.js +499 -404
  50. package/esm/simple/Websocket.js +45 -19
  51. package/esm/simple/index.js +503 -408
  52. package/esm/simple/room/LocalParticipant.js +503 -408
  53. package/esm/simple/room/Participant.js +503 -408
  54. package/esm/simple/room/RemoteParticipant.js +503 -408
  55. package/esm/simple/room/Room.js +504 -409
  56. package/esm/simple/room/SipRoom.js +503 -408
  57. package/esm/simple/room/Stream.js +503 -408
  58. package/esm/simple/room/__tests__/RemoteParticipant.test.js +503 -408
  59. package/esm/simple/utils.js +503 -408
  60. package/esm/types/WebSocketMessage.js +1 -1
  61. package/esm/utils/__tests__/api-requester.test.js +25 -2
  62. package/esm/utils/api-requester.js +25 -2
  63. package/esm/web-rtc-client.js +214 -165
  64. package/esm/websocket-client.js +43 -18
  65. package/lib/__tests__/api-client.test.js +91 -21
  66. package/lib/__tests__/web-rtc-client.test.js +214 -165
  67. package/lib/api/agentd.js +25 -2
  68. package/lib/api/amid.js +26 -3
  69. package/lib/api/application.js +25 -2
  70. package/lib/api/auth.js +25 -2
  71. package/lib/api/call-logd.js +34 -4
  72. package/lib/api/calld.js +35 -2
  73. package/lib/api/chatd.js +32 -2
  74. package/lib/api/confd.js +56 -9
  75. package/lib/api/ctid-ng.js +38 -5
  76. package/lib/api/dird.js +29 -3
  77. package/lib/api/webhookd.js +26 -3
  78. package/lib/api-client.js +91 -21
  79. package/lib/checker/Checker.js +241 -190
  80. package/lib/checker/checks/aor.js +91 -21
  81. package/lib/checker/checks/api.js +91 -21
  82. package/lib/checker/checks/index.js +231 -180
  83. package/lib/checker/checks/wazo-websocket.js +42 -17
  84. package/lib/checker/checks/webrtc-transport.js +214 -165
  85. package/lib/checker/checks/webrtc.js +214 -165
  86. package/lib/domain/AdHocAPIConference.js +91 -21
  87. package/lib/domain/Call.js +3 -0
  88. package/lib/domain/CallLog.js +8 -1
  89. package/lib/domain/ChatMessage.js +4 -0
  90. package/lib/domain/ChatRoom.js +3 -0
  91. package/lib/domain/Contact.js +4 -1
  92. package/lib/domain/Features.js +91 -21
  93. package/lib/domain/Meeting.js +32 -5
  94. package/lib/domain/Phone/CTIPhone.js +109 -35
  95. package/lib/domain/Phone/WebRTCPhone.js +159 -102
  96. package/lib/domain/Recording.js +3 -0
  97. package/lib/domain/Voicemail.js +3 -0
  98. package/lib/domain/__tests__/Call.test.js +3 -0
  99. package/lib/domain/__tests__/CallLog.test.js +8 -1
  100. package/lib/domain/__tests__/Contact.test.js +4 -1
  101. package/lib/domain/__tests__/Meeting.test.js +150 -0
  102. package/lib/domain/__tests__/Voicemail.test.js +3 -0
  103. package/lib/index.js +509 -414
  104. package/lib/lib/WazoSessionDescriptionHandler.js +26 -41
  105. package/lib/service/CallApi.js +91 -21
  106. package/lib/service/IssueReporter.js +26 -3
  107. package/lib/service/__tests__/IssueReporter.test.js +26 -3
  108. package/lib/service/getApiClient.js +91 -21
  109. package/lib/simple/Auth.js +499 -404
  110. package/lib/simple/Configuration.js +499 -404
  111. package/lib/simple/Directory.js +91 -21
  112. package/lib/simple/Phone.js +499 -404
  113. package/lib/simple/Websocket.js +45 -19
  114. package/lib/simple/index.js +503 -408
  115. package/lib/simple/room/LocalParticipant.js +503 -408
  116. package/lib/simple/room/Participant.js +503 -408
  117. package/lib/simple/room/RemoteParticipant.js +503 -408
  118. package/lib/simple/room/Room.js +504 -409
  119. package/lib/simple/room/SipRoom.js +503 -408
  120. package/lib/simple/room/Stream.js +503 -408
  121. package/lib/simple/room/__tests__/RemoteParticipant.test.js +503 -408
  122. package/lib/simple/utils.js +503 -408
  123. package/lib/types/WebSocketMessage.js +2 -0
  124. package/lib/utils/__tests__/api-requester.test.js +25 -2
  125. package/lib/utils/api-requester.js +25 -2
  126. package/lib/web-rtc-client.js +214 -165
  127. package/lib/websocket-client.js +43 -17
  128. package/package.json +1 -1
  129. package/src/api/confd.js +5 -2
  130. package/src/domain/Call.js +3 -0
  131. package/src/domain/CallLog.js +4 -0
  132. package/src/domain/ChatMessage.js +4 -0
  133. package/src/domain/ChatRoom.js +3 -0
  134. package/src/domain/Contact.js +3 -0
  135. package/src/domain/Meeting.js +28 -5
  136. package/src/domain/Phone/CTIPhone.js +4 -0
  137. package/src/domain/Phone/Phone.js +2 -0
  138. package/src/domain/Phone/WebRTCPhone.js +49 -15
  139. package/src/domain/Recording.js +3 -0
  140. package/src/domain/Voicemail.js +3 -0
  141. package/src/domain/__tests__/Meeting.test.js +50 -0
  142. package/src/lib/WazoSessionDescriptionHandler.js +1 -35
  143. package/src/service/IssueReporter.js +25 -2
  144. package/src/simple/Phone.js +5 -0
  145. package/src/types/WebSocketMessage.js +5 -1
  146. package/src/web-rtc-client.js +41 -24
  147. package/src/websocket-client.js +2 -0
@@ -82,6 +82,9 @@ class Call {
82
82
 
83
83
 
84
84
  static parseMany(plain ) {
85
+ if (!plain) {
86
+ return [];
87
+ }
85
88
  return plain.map((plainCall ) => Call.parse(plainCall));
86
89
  }
87
90
 
@@ -353,6 +356,7 @@ class IssueReporter {
353
356
 
354
357
 
355
358
 
359
+
356
360
 
357
361
  constructor() {
358
362
  addLevelsTo(this);
@@ -364,12 +368,17 @@ class IssueReporter {
364
368
  this.bufferTimeout = null;
365
369
  this._boundProcessBuffer = this._processBuffer.bind(this);
366
370
  this._boundParseLoggerBody = this._parseLoggerBody.bind(this);
371
+ this._callback = null;
367
372
  }
368
373
 
369
374
  init() {
370
375
  this._catchConsole();
371
376
  }
372
377
 
378
+ setCallback(cb ) {
379
+ this._callback = cb;
380
+ }
381
+
373
382
  configureRemoteClient(configuration = { tag: 'wazo-sdk', host: null, port: null, level: null, extra: {} }) {
374
383
  this.remoteClientConfiguration = configuration;
375
384
  }
@@ -405,6 +414,7 @@ class IssueReporter {
405
414
 
406
415
  // Handle category label
407
416
  let category = null;
417
+ let skipSendToRemote = false;
408
418
  let extra = {};
409
419
  if (args[0].indexOf(CATEGORY_PREFIX) === 0) {
410
420
  category = args[0].split('=')[1];
@@ -420,6 +430,7 @@ class IssueReporter {
420
430
  errorMessage: lastArg.message,
421
431
  errorStack: lastArg.stack,
422
432
  errorType: lastArg.constructor.name,
433
+ skipSendToRemote: lastArg.skipSendToRemote,
423
434
  };
424
435
  } else {
425
436
  extra = lastArg;
@@ -428,6 +439,11 @@ class IssueReporter {
428
439
  args.splice(1, 1);
429
440
  }
430
441
 
442
+ if (extra.skipSendToRemote) {
443
+ skipSendToRemote = true;
444
+ delete extra.skipSendToRemote;
445
+ }
446
+
431
447
  const date = moment__default['default']().format('YYYY-MM-DD HH:mm:ss.SSS');
432
448
  const message = args.join(', ');
433
449
  let consoleMessage = message;
@@ -448,7 +464,13 @@ class IssueReporter {
448
464
  const oldMethod = this.oldConsoleMethods[consoleLevel] || this.oldConsoleMethods.log;
449
465
  oldMethod.apply(oldMethod, [date, consoleMessage]);
450
466
 
451
- this._sendToRemoteLogger(level, { date, message, category, ...extra });
467
+ if (this._callback) {
468
+ this._callback(level, consoleMessage);
469
+ }
470
+
471
+ if (!skipSendToRemote) {
472
+ this._sendToRemoteLogger(level, { date, message, category, ...extra });
473
+ }
452
474
  }
453
475
 
454
476
  logRequest(url , options , response , start ) {
@@ -593,7 +615,11 @@ class IssueReporter {
593
615
  },
594
616
  // $FlowFixMe
595
617
  body,
596
- }).catch(() => {
618
+ }).catch((e ) => {
619
+ // $FlowFixMe
620
+ e.skipSendToRemote = true;
621
+ this.log('error', this._makeCategory('grafana'), 'Sending log to grafana, error', e);
622
+
597
623
  setTimeout(() => {
598
624
  if (isArray) {
599
625
  payload = payload.map(message => {
@@ -640,7 +666,7 @@ var IssueReporter$1 = new IssueReporter();
640
666
 
641
667
  const methods = ['head', 'get', 'post', 'put', 'delete'];
642
668
 
643
- const logger$1 = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
669
+ const logger = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
644
670
 
645
671
  // Use a function here to be able to mock it in tests
646
672
  const realFetch = () => {
@@ -779,7 +805,7 @@ class ApiRequester {
779
805
  };
780
806
 
781
807
  if (this.refreshTokenPromise) {
782
- logger$1.info('A token is already refreshing, waiting ...', { url });
808
+ logger.info('A token is already refreshing, waiting ...', { url });
783
809
  await this.refreshTokenPromise;
784
810
  }
785
811
 
@@ -799,7 +825,7 @@ class ApiRequester {
799
825
  return promise.then(async (err ) => {
800
826
  // Check if the token is still valid
801
827
  if (firstCall && this._checkTokenExpired(response, err)) {
802
- logger$1.warn('token expired', { error: err.reason });
828
+ logger.warn('token expired', { error: err.reason });
803
829
  // Replay the call after refreshing the token
804
830
  return this._replayWithNewToken(err, path, method, body, headers, parse);
805
831
  }
@@ -809,7 +835,7 @@ class ApiRequester {
809
835
  : exceptionClass.fromResponse(err, response.status);
810
836
 
811
837
  if (this.shouldLogErrors) {
812
- logger$1.error('API error', error);
838
+ logger.error('API error', error);
813
839
  }
814
840
 
815
841
  throw error;
@@ -819,7 +845,7 @@ class ApiRequester {
819
845
  return newParse(response, isJson);
820
846
  }).catch(error => {
821
847
  if (this.shouldLogErrors) {
822
- logger$1.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
848
+ logger.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
823
849
  }
824
850
 
825
851
  throw error;
@@ -847,13 +873,13 @@ class ApiRequester {
847
873
  ) {
848
874
  const isTokenNotFound = this._isTokenNotFound(err);
849
875
  let newPath = path;
850
- logger$1.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
876
+ logger.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
851
877
 
852
878
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
853
879
 
854
880
  return this.refreshTokenPromise.then(() => {
855
881
  this.refreshTokenPromise = null;
856
- logger$1.info('token refreshed', { isTokenNotFound });
882
+ logger.info('token refreshed', { isTokenNotFound });
857
883
  if (isTokenNotFound) {
858
884
  const pathParts = path.split('/');
859
885
  pathParts.pop();
@@ -1720,6 +1746,9 @@ class Contact {
1720
1746
  }
1721
1747
 
1722
1748
  static parseMany(response ) {
1749
+ if (!response || !response.results) {
1750
+ return [];
1751
+ }
1723
1752
  return response.results.map(r => Contact.parse(r, response.column_types));
1724
1753
  }
1725
1754
 
@@ -2797,8 +2826,9 @@ class ExternalApp {
2797
2826
 
2798
2827
 
2799
2828
 
2800
-
2829
+
2801
2830
 
2831
+
2802
2832
 
2803
2833
 
2804
2834
  class Meeting {
@@ -2809,9 +2839,10 @@ class Meeting {
2809
2839
 
2810
2840
 
2811
2841
 
2812
-
2842
+
2813
2843
 
2814
2844
 
2845
+
2815
2846
 
2816
2847
  static parse(plain ) {
2817
2848
  return new Meeting({
@@ -2821,24 +2852,43 @@ class Meeting {
2821
2852
  ownerUuids: plain.owner_uuids,
2822
2853
  port: plain.port,
2823
2854
  uuid: plain.uuid,
2824
- number: plain.number,
2855
+ extension: plain.exten,
2825
2856
  persistent: plain.persistent,
2857
+ creationTime: moment__default['default'](plain.creation_time).toDate(),
2826
2858
  });
2827
2859
  }
2828
2860
 
2861
+ static parseMany(items ) {
2862
+ if (!items) {
2863
+ return [];
2864
+ }
2865
+ return items.map(plain => Meeting.parse(plain));
2866
+ }
2867
+
2829
2868
  static newFrom(meeting ) {
2830
2869
  return newFrom(meeting, Meeting);
2831
2870
  }
2832
2871
 
2833
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2872
+ constructor({
2873
+ uuid,
2874
+ name,
2875
+ guestSipAuthorization,
2876
+ ownerUuids,
2877
+ port,
2878
+ uri,
2879
+ extension,
2880
+ persistent,
2881
+ creationTime,
2882
+ } = {}) {
2834
2883
  this.guestSipAuthorization = guestSipAuthorization;
2835
2884
  this.uri = uri;
2836
2885
  this.name = name;
2837
2886
  this.ownerUuids = ownerUuids;
2838
2887
  this.port = port;
2839
2888
  this.uuid = uuid;
2840
- this.number = number;
2889
+ this.extension = extension;
2841
2890
  this.persistent = persistent;
2891
+ this.creationTime = creationTime;
2842
2892
 
2843
2893
  // Useful to compare instead of instanceof with minified code
2844
2894
  this.type = 'Meeting';
@@ -2916,8 +2966,11 @@ var confdMethods = (client , baseUrl ) => ({
2916
2966
  }
2917
2967
  },
2918
2968
 
2919
- createMyMeeting: (name ) =>
2920
- client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
2969
+ getMyMeetings: () =>
2970
+ client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
2971
+
2972
+ createMyMeeting: (name , persistent ) =>
2973
+ client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
2921
2974
 
2922
2975
  deleteMyMeeting: (meetingUuid ) =>
2923
2976
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -3013,6 +3066,10 @@ class ChatMessage {
3013
3066
 
3014
3067
 
3015
3068
  static parseMany(plain ) {
3069
+ if (!plain || !plain.items) {
3070
+ return [];
3071
+ }
3072
+
3016
3073
  return plain.items.map(item => ChatMessage.parse(item));
3017
3074
  }
3018
3075
 
@@ -3122,6 +3179,9 @@ class Voicemail {
3122
3179
  }
3123
3180
 
3124
3181
  static parseMany(plain ) {
3182
+ if (!plain) {
3183
+ return [];
3184
+ }
3125
3185
  const plainUnread = plain.folders.filter(folder => folder.type === 'new')[0].messages;
3126
3186
  const plainRead = plain.folders.filter(folder => folder.type === 'old')[0].messages;
3127
3187
 
@@ -3197,6 +3257,9 @@ class Recording {
3197
3257
 
3198
3258
 
3199
3259
  static parseMany(recordings = []) {
3260
+ if (!recordings) {
3261
+ return [];
3262
+ }
3200
3263
  return recordings.map(item => Recording.parse(item));
3201
3264
  }
3202
3265
 
@@ -3298,6 +3361,10 @@ class CallLog {
3298
3361
  }
3299
3362
 
3300
3363
  static parseMany(plain ) {
3364
+ if (!plain || !plain.items) {
3365
+ return [];
3366
+ }
3367
+
3301
3368
  return plain.items.map(item => CallLog.parse(item));
3302
3369
  }
3303
3370
 
@@ -3519,7 +3586,7 @@ const TRANSFER_FLOW_BLIND = 'blind';
3519
3586
 
3520
3587
  // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
3521
3588
 
3522
- IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3589
+ const logger$1 = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3523
3590
 
3524
3591
  /* */
3525
3592
 
@@ -3855,6 +3922,9 @@ class ChatRoom {
3855
3922
 
3856
3923
 
3857
3924
  static parseMany(plain ) {
3925
+ if (!plain || !plain.items) {
3926
+ return [];
3927
+ }
3858
3928
  return plain.items.map(item => ChatRoom.parse(item));
3859
3929
  }
3860
3930
 
@@ -4435,7 +4505,7 @@ const AGENTD_VERSION = '1.0';
4435
4505
  const WEBHOOKD_VERSION = '1.0';
4436
4506
  const AMID_VERSION = '1.0';
4437
4507
 
4438
- const logger = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
4508
+ const logger$2 = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
4439
4509
 
4440
4510
  class ApiClient {
4441
4511
 
@@ -4487,12 +4557,12 @@ class ApiClient {
4487
4557
  }
4488
4558
 
4489
4559
  async forceRefreshToken() {
4490
- logger.info('forcing refresh token, calling callback');
4560
+ logger$2.info('forcing refresh token, calling callback');
4491
4561
  return this.refreshTokenCallback();
4492
4562
  }
4493
4563
 
4494
4564
  async refreshTokenCallback() {
4495
- logger.info('refresh token callback called', {
4565
+ logger$2.info('refresh token callback called', {
4496
4566
  refreshToken: this.refreshToken,
4497
4567
  refreshBackend: this.refreshBackend,
4498
4568
  refreshExpiration: this.refreshExpiration,
@@ -4510,7 +4580,7 @@ class ApiClient {
4510
4580
  this.isMobile,
4511
4581
  );
4512
4582
 
4513
- logger.info('token refreshed', { token: session.token });
4583
+ logger$2.info('token refreshed', { token: session.token });
4514
4584
 
4515
4585
  if (this.onRefreshToken) {
4516
4586
  this.onRefreshToken(session.token, session);
@@ -77,6 +77,9 @@ class Call {
77
77
 
78
78
 
79
79
  static parseMany(plain ) {
80
+ if (!plain) {
81
+ return [];
82
+ }
80
83
  return plain.map((plainCall ) => Call.parse(plainCall));
81
84
  }
82
85
 
@@ -32,7 +32,7 @@ BwIDAQAB
32
32
 
33
33
  //
34
34
 
35
- jsrsasign.KEYUTIL.getKey(swarmPublicKey);
35
+ const swarmKey = jsrsasign.KEYUTIL.getKey(swarmPublicKey);
36
36
 
37
37
  //
38
38
 
@@ -60,6 +60,9 @@ class Recording {
60
60
 
61
61
 
62
62
  static parseMany(recordings = []) {
63
+ if (!recordings) {
64
+ return [];
65
+ }
63
66
  return recordings.map(item => Recording.parse(item));
64
67
  }
65
68
 
@@ -161,6 +164,10 @@ class CallLog {
161
164
  }
162
165
 
163
166
  static parseMany(plain ) {
167
+ if (!plain || !plain.items) {
168
+ return [];
169
+ }
170
+
164
171
  return plain.items.map(item => CallLog.parse(item));
165
172
  }
166
173
 
@@ -58,6 +58,10 @@ class ChatMessage {
58
58
 
59
59
 
60
60
  static parseMany(plain ) {
61
+ if (!plain || !plain.items) {
62
+ return [];
63
+ }
64
+
61
65
  return plain.items.map(item => ChatMessage.parse(item));
62
66
  }
63
67
 
@@ -33,6 +33,9 @@ class ChatRoom {
33
33
 
34
34
 
35
35
  static parseMany(plain ) {
36
+ if (!plain || !plain.items) {
37
+ return [];
38
+ }
36
39
  return plain.items.map(item => ChatRoom.parse(item));
37
40
  }
38
41
 
@@ -48,7 +48,7 @@ const LINE_STATE = {
48
48
 
49
49
  //
50
50
 
51
- jsrsasign.KEYUTIL.getKey(swarmPublicKey);
51
+ const swarmKey = jsrsasign.KEYUTIL.getKey(swarmPublicKey);
52
52
 
53
53
  //
54
54
 
@@ -329,6 +329,9 @@ class Contact {
329
329
  }
330
330
 
331
331
  static parseMany(response ) {
332
+ if (!response || !response.results) {
333
+ return [];
334
+ }
332
335
  return response.results.map(r => Contact.parse(r, response.column_types));
333
336
  }
334
337