@wazo/sdk 0.37.2 → 0.37.6

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 (99) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +84 -22
  3. package/esm/__tests__/web-rtc-client.test.js +156 -55
  4. package/esm/api/call-logd.js +10 -22
  5. package/esm/api/calld.js +3 -0
  6. package/esm/api/confd.js +71 -0
  7. package/esm/api-client.js +84 -22
  8. package/esm/checker/Checker.js +160 -55
  9. package/esm/checker/checks/aor.js +84 -22
  10. package/esm/checker/checks/api.js +84 -22
  11. package/esm/checker/checks/index.js +160 -55
  12. package/esm/checker/checks/wazo-websocket.js +4 -0
  13. package/esm/checker/checks/webrtc-transport.js +156 -55
  14. package/esm/checker/checks/webrtc.js +156 -55
  15. package/esm/domain/AdHocAPIConference.js +84 -22
  16. package/esm/domain/CallLog.js +10 -22
  17. package/esm/domain/Features.js +84 -22
  18. package/esm/domain/Meeting.js +71 -0
  19. package/esm/domain/Phone/CTIPhone.js +84 -22
  20. package/esm/domain/Phone/WebRTCPhone.js +22 -8
  21. package/esm/domain/__tests__/CallLog.test.js +10 -22
  22. package/esm/index.js +726 -371
  23. package/esm/lib/WazoSessionDescriptionHandler.js +17 -9
  24. package/esm/service/CallApi.js +84 -22
  25. package/esm/service/getApiClient.js +84 -22
  26. package/esm/simple/Auth.js +717 -363
  27. package/esm/simple/Configuration.js +717 -363
  28. package/esm/simple/Directory.js +84 -22
  29. package/esm/simple/Phone.js +709 -355
  30. package/esm/simple/Websocket.js +6 -0
  31. package/esm/simple/index.js +719 -365
  32. package/esm/simple/room/LocalParticipant.js +689 -335
  33. package/esm/simple/room/Participant.js +689 -335
  34. package/esm/simple/room/RemoteParticipant.js +689 -335
  35. package/esm/simple/room/Room.js +689 -335
  36. package/esm/simple/room/SipRoom.js +13001 -0
  37. package/esm/simple/room/Stream.js +719 -365
  38. package/esm/simple/room/__tests__/RemoteParticipant.test.js +4130 -3774
  39. package/esm/simple/utils.js +719 -365
  40. package/esm/web-rtc-client.js +156 -55
  41. package/esm/websocket-client.js +5 -1
  42. package/lib/__tests__/api-client.test.js +84 -22
  43. package/lib/__tests__/web-rtc-client.test.js +156 -55
  44. package/lib/api/call-logd.js +10 -22
  45. package/lib/api/calld.js +3 -0
  46. package/lib/api/confd.js +71 -0
  47. package/lib/api-client.js +84 -22
  48. package/lib/checker/Checker.js +160 -55
  49. package/lib/checker/checks/aor.js +84 -22
  50. package/lib/checker/checks/api.js +84 -22
  51. package/lib/checker/checks/index.js +160 -55
  52. package/lib/checker/checks/wazo-websocket.js +4 -0
  53. package/lib/checker/checks/webrtc-transport.js +156 -55
  54. package/lib/checker/checks/webrtc.js +156 -55
  55. package/lib/domain/AdHocAPIConference.js +84 -22
  56. package/lib/domain/CallLog.js +10 -22
  57. package/lib/domain/Features.js +84 -22
  58. package/lib/domain/Meeting.js +73 -0
  59. package/lib/domain/Phone/CTIPhone.js +84 -22
  60. package/lib/domain/Phone/WebRTCPhone.js +22 -8
  61. package/lib/domain/__tests__/CallLog.test.js +10 -22
  62. package/lib/index.js +726 -371
  63. package/lib/lib/WazoSessionDescriptionHandler.js +17 -9
  64. package/lib/service/CallApi.js +84 -22
  65. package/lib/service/getApiClient.js +84 -22
  66. package/lib/simple/Auth.js +717 -363
  67. package/lib/simple/Configuration.js +717 -363
  68. package/lib/simple/Directory.js +84 -22
  69. package/lib/simple/Phone.js +709 -355
  70. package/lib/simple/Websocket.js +6 -0
  71. package/lib/simple/index.js +719 -365
  72. package/lib/simple/room/LocalParticipant.js +689 -335
  73. package/lib/simple/room/Participant.js +689 -335
  74. package/lib/simple/room/RemoteParticipant.js +689 -335
  75. package/lib/simple/room/Room.js +689 -335
  76. package/lib/simple/room/SipRoom.js +13011 -0
  77. package/lib/simple/room/Stream.js +719 -365
  78. package/lib/simple/room/__tests__/RemoteParticipant.test.js +4131 -3775
  79. package/lib/simple/utils.js +719 -365
  80. package/lib/web-rtc-client.js +156 -55
  81. package/lib/websocket-client.js +6 -0
  82. package/package.json +1 -1
  83. package/src/api/calld.js +3 -0
  84. package/src/api/confd.js +13 -0
  85. package/src/domain/CallLog.js +10 -22
  86. package/src/domain/Meeting.js +59 -0
  87. package/src/domain/Phone/WebRTCPhone.js +22 -8
  88. package/src/index.js +2 -0
  89. package/src/lib/WazoSessionDescriptionHandler.js +17 -9
  90. package/src/simple/Phone.js +13 -4
  91. package/src/simple/index.js +4 -0
  92. package/src/simple/room/Participant.js +7 -0
  93. package/src/simple/room/Room.js +158 -79
  94. package/src/simple/room/SipRoom.js +147 -0
  95. package/src/simple/room/Stream.js +1 -3
  96. package/src/simple/room/__tests__/RemoteParticipant.test.js +3 -2
  97. package/src/types/WebSocketMessage.js +21 -0
  98. package/src/web-rtc-client.js +55 -24
  99. package/src/websocket-client.js +4 -0
@@ -2493,6 +2493,65 @@ class ExternalApp {
2493
2493
  }
2494
2494
  }
2495
2495
 
2496
+ //
2497
+
2498
+
2499
+
2500
+
2501
+
2502
+
2503
+
2504
+
2505
+
2506
+
2507
+
2508
+ class Meeting {
2509
+
2510
+
2511
+
2512
+
2513
+
2514
+
2515
+
2516
+
2517
+
2518
+
2519
+ static parse(plain ) {
2520
+ return new Meeting({
2521
+ guestSipAuthorization: plain.guest_sip_authorization,
2522
+ hostname: plain.hostname,
2523
+ name: plain.name,
2524
+ ownerUuids: plain.owner_uuids,
2525
+ port: plain.port,
2526
+ uuid: plain.uuid,
2527
+ number: plain.number,
2528
+ });
2529
+ }
2530
+
2531
+ static newFrom(meeting ) {
2532
+ return newFrom(meeting, Meeting);
2533
+ }
2534
+
2535
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
2536
+ this.guestSipAuthorization = guestSipAuthorization;
2537
+ this.hostname = hostname;
2538
+ this.name = name;
2539
+ this.ownerUuids = ownerUuids;
2540
+ this.port = port;
2541
+ this.uuid = uuid;
2542
+ this.number = number;
2543
+
2544
+ // Useful to compare instead of instanceof with minified code
2545
+ this.type = 'Meeting';
2546
+ }
2547
+
2548
+ getGuestSipCredentials() {
2549
+ // eslint-disable-next-line no-undef
2550
+ const [username, secret] = atob(this.guestSipAuthorization).split(':');
2551
+ return { username, secret };
2552
+ }
2553
+ }
2554
+
2496
2555
  /* */
2497
2556
 
2498
2557
  var confdMethods = (client , baseUrl ) => ({
@@ -2557,6 +2616,18 @@ var confdMethods = (client , baseUrl ) => ({
2557
2616
  return null;
2558
2617
  }
2559
2618
  },
2619
+
2620
+ createMyMeeting: (name ) =>
2621
+ client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
2622
+
2623
+ deleteMyMeeting: (meetingUuid ) =>
2624
+ client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
2625
+
2626
+ getMeeting: (meetingUuid ) =>
2627
+ client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2628
+
2629
+ guestGetMeeting: (meetingUuid ) =>
2630
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2560
2631
  });
2561
2632
 
2562
2633
  //
@@ -3141,7 +3212,11 @@ class CallLog {
3141
3212
  answered: plain.answered,
3142
3213
  callDirection: plain.call_direction,
3143
3214
  destination: {
3144
- extension: plain.requested_extension || plain.destination_extension,
3215
+ // @TEMP: Temporarily assuming empty numbers are meetings
3216
+ // which is admittedly a very dangerous assumption. Did i mention it was temporary?
3217
+ extension: plain.requested_extension
3218
+ || plain.destination_extension
3219
+ || `meeting-${plain.requested_name || plain.destination_name || ''}`,
3145
3220
  name: plain.requested_name || plain.destination_name || '',
3146
3221
  },
3147
3222
  source: {
@@ -3157,27 +3232,11 @@ class CallLog {
3157
3232
  }
3158
3233
 
3159
3234
  static parseNew(plain , session ) {
3160
- return new CallLog({
3161
- answer: plain.answer ? moment(plain.answer).toDate() : null,
3162
- answered: plain.answered,
3163
- callDirection: plain.call_direction,
3164
- destination: {
3165
- extension: plain.requested_extension || plain.destination_extension,
3166
- name: plain.requested_name || plain.destination_name || '',
3167
- },
3168
- source: {
3169
- extension: plain.source_extension,
3170
- name: plain.source_name,
3171
- },
3172
- id: plain.id,
3173
- duration: (plain.duration || 0) * 1000, // duration is in seconds
3174
- start: moment(plain.start).toDate(),
3175
- end: plain.end ? moment(plain.end).toDate() : null,
3176
- recordings: Recording.parseMany(plain.recordings),
3177
- // @TODO: FIXME add verification declined vs missed call
3178
- newMissedCall: session
3179
- && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
3180
- });
3235
+ const callLog = CallLog.parse(plain);
3236
+ // @TODO: FIXME add verification declined vs missed call
3237
+ callLog.newMissedCall = session
3238
+ && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
3239
+ return callLog;
3181
3240
  }
3182
3241
 
3183
3242
  static newFrom(profile ) {
@@ -3919,6 +3978,9 @@ var calldMethods = (client , baseUrl ) => ({
3919
3978
  getConferenceParticipantsAsUser: async (conferenceId ) =>
3920
3979
  client.get(`${baseUrl}/users/me/conferences/${conferenceId}/participants`),
3921
3980
 
3981
+ getMeetingParticipantsAsUser: async (meetingUuid ) =>
3982
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
3983
+
3922
3984
  listTrunks: () => client.get(`${baseUrl}/trunks`),
3923
3985
 
3924
3986
  mute: (callId ) =>
@@ -0,0 +1,71 @@
1
+ //
2
+
3
+ var newFrom = (instance , ToClass ) => {
4
+ const args = {};
5
+ Object.getOwnPropertyNames(instance).forEach(prop => {
6
+ args[prop] = instance[prop];
7
+ });
8
+
9
+ return new ToClass(args);
10
+ };
11
+
12
+ //
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+ class Meeting {
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+ static parse(plain ) {
36
+ return new Meeting({
37
+ guestSipAuthorization: plain.guest_sip_authorization,
38
+ hostname: plain.hostname,
39
+ name: plain.name,
40
+ ownerUuids: plain.owner_uuids,
41
+ port: plain.port,
42
+ uuid: plain.uuid,
43
+ number: plain.number,
44
+ });
45
+ }
46
+
47
+ static newFrom(meeting ) {
48
+ return newFrom(meeting, Meeting);
49
+ }
50
+
51
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
52
+ this.guestSipAuthorization = guestSipAuthorization;
53
+ this.hostname = hostname;
54
+ this.name = name;
55
+ this.ownerUuids = ownerUuids;
56
+ this.port = port;
57
+ this.uuid = uuid;
58
+ this.number = number;
59
+
60
+ // Useful to compare instead of instanceof with minified code
61
+ this.type = 'Meeting';
62
+ }
63
+
64
+ getGuestSipCredentials() {
65
+ // eslint-disable-next-line no-undef
66
+ const [username, secret] = atob(this.guestSipAuthorization).split(':');
67
+ return { username, secret };
68
+ }
69
+ }
70
+
71
+ export default Meeting;
@@ -2184,7 +2184,11 @@ class CallLog {
2184
2184
  answered: plain.answered,
2185
2185
  callDirection: plain.call_direction,
2186
2186
  destination: {
2187
- extension: plain.requested_extension || plain.destination_extension,
2187
+ // @TEMP: Temporarily assuming empty numbers are meetings
2188
+ // which is admittedly a very dangerous assumption. Did i mention it was temporary?
2189
+ extension: plain.requested_extension
2190
+ || plain.destination_extension
2191
+ || `meeting-${plain.requested_name || plain.destination_name || ''}`,
2188
2192
  name: plain.requested_name || plain.destination_name || '',
2189
2193
  },
2190
2194
  source: {
@@ -2200,27 +2204,11 @@ class CallLog {
2200
2204
  }
2201
2205
 
2202
2206
  static parseNew(plain , session ) {
2203
- return new CallLog({
2204
- answer: plain.answer ? moment(plain.answer).toDate() : null,
2205
- answered: plain.answered,
2206
- callDirection: plain.call_direction,
2207
- destination: {
2208
- extension: plain.requested_extension || plain.destination_extension,
2209
- name: plain.requested_name || plain.destination_name || '',
2210
- },
2211
- source: {
2212
- extension: plain.source_extension,
2213
- name: plain.source_name,
2214
- },
2215
- id: plain.id,
2216
- duration: (plain.duration || 0) * 1000, // duration is in seconds
2217
- start: moment(plain.start).toDate(),
2218
- end: plain.end ? moment(plain.end).toDate() : null,
2219
- recordings: Recording.parseMany(plain.recordings),
2220
- // @TODO: FIXME add verification declined vs missed call
2221
- newMissedCall: session
2222
- && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
2223
- });
2207
+ const callLog = CallLog.parse(plain);
2208
+ // @TODO: FIXME add verification declined vs missed call
2209
+ callLog.newMissedCall = session
2210
+ && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
2211
+ return callLog;
2224
2212
  }
2225
2213
 
2226
2214
  static newFrom(profile ) {
@@ -3379,6 +3367,65 @@ class ExternalApp {
3379
3367
  }
3380
3368
  }
3381
3369
 
3370
+ //
3371
+
3372
+
3373
+
3374
+
3375
+
3376
+
3377
+
3378
+
3379
+
3380
+
3381
+
3382
+ class Meeting {
3383
+
3384
+
3385
+
3386
+
3387
+
3388
+
3389
+
3390
+
3391
+
3392
+
3393
+ static parse(plain ) {
3394
+ return new Meeting({
3395
+ guestSipAuthorization: plain.guest_sip_authorization,
3396
+ hostname: plain.hostname,
3397
+ name: plain.name,
3398
+ ownerUuids: plain.owner_uuids,
3399
+ port: plain.port,
3400
+ uuid: plain.uuid,
3401
+ number: plain.number,
3402
+ });
3403
+ }
3404
+
3405
+ static newFrom(meeting ) {
3406
+ return newFrom(meeting, Meeting);
3407
+ }
3408
+
3409
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
3410
+ this.guestSipAuthorization = guestSipAuthorization;
3411
+ this.hostname = hostname;
3412
+ this.name = name;
3413
+ this.ownerUuids = ownerUuids;
3414
+ this.port = port;
3415
+ this.uuid = uuid;
3416
+ this.number = number;
3417
+
3418
+ // Useful to compare instead of instanceof with minified code
3419
+ this.type = 'Meeting';
3420
+ }
3421
+
3422
+ getGuestSipCredentials() {
3423
+ // eslint-disable-next-line no-undef
3424
+ const [username, secret] = atob(this.guestSipAuthorization).split(':');
3425
+ return { username, secret };
3426
+ }
3427
+ }
3428
+
3382
3429
  /* */
3383
3430
 
3384
3431
  var confdMethods = (client , baseUrl ) => ({
@@ -3443,6 +3490,18 @@ var confdMethods = (client , baseUrl ) => ({
3443
3490
  return null;
3444
3491
  }
3445
3492
  },
3493
+
3494
+ createMyMeeting: (name ) =>
3495
+ client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
3496
+
3497
+ deleteMyMeeting: (meetingUuid ) =>
3498
+ client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
3499
+
3500
+ getMeeting: (meetingUuid ) =>
3501
+ client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
3502
+
3503
+ guestGetMeeting: (meetingUuid ) =>
3504
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
3446
3505
  });
3447
3506
 
3448
3507
  //
@@ -4270,6 +4329,9 @@ var calldMethods = (client , baseUrl ) => ({
4270
4329
  getConferenceParticipantsAsUser: async (conferenceId ) =>
4271
4330
  client.get(`${baseUrl}/users/me/conferences/${conferenceId}/participants`),
4272
4331
 
4332
+ getMeetingParticipantsAsUser: async (meetingUuid ) =>
4333
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
4334
+
4273
4335
  listTrunks: () => client.get(`${baseUrl}/trunks`),
4274
4336
 
4275
4337
  mute: (callId ) =>
@@ -951,7 +951,7 @@ class WebRTCPhone extends Emitter {
951
951
  });
952
952
 
953
953
  if (!sipSession) {
954
- return null;
954
+ return false;
955
955
  }
956
956
 
957
957
  // $FlowFixMe
@@ -961,19 +961,17 @@ class WebRTCPhone extends Emitter {
961
961
  // Downgrade
962
962
  if (constraints && !isUpgrade) {
963
963
  // No reinvite needed
964
- return this._downgradeToAudio(callSession);
964
+ this._downgradeToAudio(callSession);
965
+ return false;
965
966
  }
966
967
 
967
968
  if (isUpgrade) {
968
969
  const shouldReinvite = await this._upgradeToVideo(callSession, constraints, conference);
969
970
  if (!shouldReinvite) {
970
- return;
971
+ return false;
971
972
  }
972
973
  }
973
974
 
974
- // Force reinvite in SDH
975
- sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
976
-
977
975
  return this.client.reinvite(sipSession, constraints, conference, audioOnly);
978
976
  }
979
977
 
@@ -1046,7 +1044,7 @@ class WebRTCPhone extends Emitter {
1046
1044
  _downgradeToAudio(callSession ) {
1047
1045
  const sipSession = this.findSipSession(callSession);
1048
1046
  if (!sipSession) {
1049
- return;
1047
+ return false;
1050
1048
  }
1051
1049
 
1052
1050
  // Release local video stream when downgrading to audio
@@ -1248,6 +1246,10 @@ class WebRTCPhone extends Emitter {
1248
1246
  localStream.removeTrack(videoTrack);
1249
1247
  }
1250
1248
 
1249
+ if (localStream) {
1250
+ localStream.addTrack(screenTrack);
1251
+ }
1252
+
1251
1253
  if (sender) {
1252
1254
  sender.replaceTrack(screenTrack);
1253
1255
  }
@@ -1263,6 +1265,7 @@ class WebRTCPhone extends Emitter {
1263
1265
  }
1264
1266
 
1265
1267
  logger.info('WebRTC phone - stop screen sharing');
1268
+ let reinvited = false;
1266
1269
 
1267
1270
  try {
1268
1271
  if (this.currentScreenShare.stream) {
@@ -1277,7 +1280,8 @@ class WebRTCPhone extends Emitter {
1277
1280
  // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
1278
1281
  // We have to downgrade to audio.
1279
1282
  const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
1280
- await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
1283
+ const constraints = { audio: false, video: screenshareStopped };
1284
+ reinvited = await this.sendReinvite(targetCallSession, constraints, conference);
1281
1285
  }
1282
1286
  } catch (e) {
1283
1287
  console.warn(e);
@@ -1291,6 +1295,8 @@ class WebRTCPhone extends Emitter {
1291
1295
  );
1292
1296
 
1293
1297
  this.currentScreenShare = null;
1298
+
1299
+ return reinvited;
1294
1300
  }
1295
1301
 
1296
1302
  async _getStreamFromConstraints(constraints , conference = false) {
@@ -1351,6 +1357,10 @@ class WebRTCPhone extends Emitter {
1351
1357
  this.client.changeAudioOutputDevice(id);
1352
1358
  }
1353
1359
 
1360
+ createAudioElementFor(sessionId ) {
1361
+ return this.client.createAudioElementFor(sessionId);
1362
+ }
1363
+
1354
1364
  changeRingDevice(id ) {
1355
1365
  this.audioRingDeviceId = id;
1356
1366
  }
@@ -1998,6 +2008,10 @@ class WebRTCPhone extends Emitter {
1998
2008
  return callSession ? this.client.hasLocalVideo(callSession.sipCallId) : null;
1999
2009
  }
2000
2010
 
2011
+ hasALocalVideoTrack(callSession ) {
2012
+ return callSession ? this.client.hasALocalVideoTrack(callSession.sipCallId) : null;
2013
+ }
2014
+
2001
2015
  getRemoteStream(callSession ) {
2002
2016
  return callSession ? this.client.getRemoteStream(callSession.sipCallId) : null;
2003
2017
  }
@@ -162,7 +162,11 @@ class CallLog {
162
162
  answered: plain.answered,
163
163
  callDirection: plain.call_direction,
164
164
  destination: {
165
- extension: plain.requested_extension || plain.destination_extension,
165
+ // @TEMP: Temporarily assuming empty numbers are meetings
166
+ // which is admittedly a very dangerous assumption. Did i mention it was temporary?
167
+ extension: plain.requested_extension
168
+ || plain.destination_extension
169
+ || `meeting-${plain.requested_name || plain.destination_name || ''}`,
166
170
  name: plain.requested_name || plain.destination_name || '',
167
171
  },
168
172
  source: {
@@ -178,27 +182,11 @@ class CallLog {
178
182
  }
179
183
 
180
184
  static parseNew(plain , session ) {
181
- return new CallLog({
182
- answer: plain.answer ? moment(plain.answer).toDate() : null,
183
- answered: plain.answered,
184
- callDirection: plain.call_direction,
185
- destination: {
186
- extension: plain.requested_extension || plain.destination_extension,
187
- name: plain.requested_name || plain.destination_name || '',
188
- },
189
- source: {
190
- extension: plain.source_extension,
191
- name: plain.source_name,
192
- },
193
- id: plain.id,
194
- duration: (plain.duration || 0) * 1000, // duration is in seconds
195
- start: moment(plain.start).toDate(),
196
- end: plain.end ? moment(plain.end).toDate() : null,
197
- recordings: Recording.parseMany(plain.recordings),
198
- // @TODO: FIXME add verification declined vs missed call
199
- newMissedCall: session
200
- && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
201
- });
185
+ const callLog = CallLog.parse(plain);
186
+ // @TODO: FIXME add verification declined vs missed call
187
+ callLog.newMissedCall = session
188
+ && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
189
+ return callLog;
202
190
  }
203
191
 
204
192
  static newFrom(profile ) {