@abrar71/lib-jitsi-meet 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +26 -0
  3. package/dist/esm/JitsiConference.js +3692 -0
  4. package/dist/esm/JitsiConference.js.map +1 -0
  5. package/dist/esm/JitsiConferenceErrors.js +126 -0
  6. package/dist/esm/JitsiConferenceErrors.js.map +1 -0
  7. package/dist/esm/JitsiConferenceEventManager.js +424 -0
  8. package/dist/esm/JitsiConferenceEventManager.js.map +1 -0
  9. package/dist/esm/JitsiConferenceEvents.js +431 -0
  10. package/dist/esm/JitsiConferenceEvents.js.map +1 -0
  11. package/dist/esm/JitsiConnection.js +187 -0
  12. package/dist/esm/JitsiConnection.js.map +1 -0
  13. package/dist/esm/JitsiConnectionErrors.js +52 -0
  14. package/dist/esm/JitsiConnectionErrors.js.map +1 -0
  15. package/dist/esm/JitsiConnectionEvents.js +57 -0
  16. package/dist/esm/JitsiConnectionEvents.js.map +1 -0
  17. package/dist/esm/JitsiMediaDevices.js +221 -0
  18. package/dist/esm/JitsiMediaDevices.js.map +1 -0
  19. package/dist/esm/JitsiMediaDevicesEvents.js +29 -0
  20. package/dist/esm/JitsiMediaDevicesEvents.js.map +1 -0
  21. package/dist/esm/JitsiMeetJS.js +499 -0
  22. package/dist/esm/JitsiMeetJS.js.map +1 -0
  23. package/dist/esm/JitsiParticipant.js +323 -0
  24. package/dist/esm/JitsiParticipant.js.map +1 -0
  25. package/dist/esm/JitsiTrackError.js +122 -0
  26. package/dist/esm/JitsiTrackError.js.map +1 -0
  27. package/dist/esm/JitsiTrackErrors.js +91 -0
  28. package/dist/esm/JitsiTrackErrors.js.map +1 -0
  29. package/dist/esm/JitsiTrackEvents.js +60 -0
  30. package/dist/esm/JitsiTrackEvents.js.map +1 -0
  31. package/dist/esm/JitsiTranscriptionStatus.js +15 -0
  32. package/dist/esm/JitsiTranscriptionStatus.js.map +1 -0
  33. package/dist/esm/modules/RTC/BridgeChannel.js +398 -0
  34. package/dist/esm/modules/RTC/BridgeChannel.js.map +1 -0
  35. package/dist/esm/modules/RTC/JitsiLocalTrack.js +896 -0
  36. package/dist/esm/modules/RTC/JitsiLocalTrack.js.map +1 -0
  37. package/dist/esm/modules/RTC/JitsiRemoteTrack.js +427 -0
  38. package/dist/esm/modules/RTC/JitsiRemoteTrack.js.map +1 -0
  39. package/dist/esm/modules/RTC/JitsiTrack.js +453 -0
  40. package/dist/esm/modules/RTC/JitsiTrack.js.map +1 -0
  41. package/dist/esm/modules/RTC/MockClasses.js +388 -0
  42. package/dist/esm/modules/RTC/MockClasses.js.map +1 -0
  43. package/dist/esm/modules/RTC/RTC.js +658 -0
  44. package/dist/esm/modules/RTC/RTC.js.map +1 -0
  45. package/dist/esm/modules/RTC/RTCUtils.js +762 -0
  46. package/dist/esm/modules/RTC/RTCUtils.js.map +1 -0
  47. package/dist/esm/modules/RTC/ScreenObtainer.js +380 -0
  48. package/dist/esm/modules/RTC/ScreenObtainer.js.map +1 -0
  49. package/dist/esm/modules/RTC/TPCUtils.js +803 -0
  50. package/dist/esm/modules/RTC/TPCUtils.js.map +1 -0
  51. package/dist/esm/modules/RTC/TraceablePeerConnection.js +2223 -0
  52. package/dist/esm/modules/RTC/TraceablePeerConnection.js.map +1 -0
  53. package/dist/esm/modules/RTCStats/DefaulLogStorage.js +35 -0
  54. package/dist/esm/modules/RTCStats/DefaulLogStorage.js.map +1 -0
  55. package/dist/esm/modules/RTCStats/RTCStats.js +219 -0
  56. package/dist/esm/modules/RTCStats/RTCStats.js.map +1 -0
  57. package/dist/esm/modules/RTCStats/RTCStatsEvents.js +92 -0
  58. package/dist/esm/modules/RTCStats/RTCStatsEvents.js.map +1 -0
  59. package/dist/esm/modules/RTCStats/interfaces.js +2 -0
  60. package/dist/esm/modules/RTCStats/interfaces.js.map +1 -0
  61. package/dist/esm/modules/browser/BrowserCapabilities.js +345 -0
  62. package/dist/esm/modules/browser/BrowserCapabilities.js.map +1 -0
  63. package/dist/esm/modules/browser/index.js +3 -0
  64. package/dist/esm/modules/browser/index.js.map +1 -0
  65. package/dist/esm/modules/connectivity/ConnectionQuality.js +389 -0
  66. package/dist/esm/modules/connectivity/ConnectionQuality.js.map +1 -0
  67. package/dist/esm/modules/connectivity/IceFailedHandling.js +84 -0
  68. package/dist/esm/modules/connectivity/IceFailedHandling.js.map +1 -0
  69. package/dist/esm/modules/connectivity/NetworkInfo.js +49 -0
  70. package/dist/esm/modules/connectivity/NetworkInfo.js.map +1 -0
  71. package/dist/esm/modules/connectivity/TrackStreamingStatus.js +453 -0
  72. package/dist/esm/modules/connectivity/TrackStreamingStatus.js.map +1 -0
  73. package/dist/esm/modules/detection/ActiveDeviceDetector.js +79 -0
  74. package/dist/esm/modules/detection/ActiveDeviceDetector.js.map +1 -0
  75. package/dist/esm/modules/detection/DetectionEvents.js +58 -0
  76. package/dist/esm/modules/detection/DetectionEvents.js.map +1 -0
  77. package/dist/esm/modules/detection/NoAudioSignalDetection.js +127 -0
  78. package/dist/esm/modules/detection/NoAudioSignalDetection.js.map +1 -0
  79. package/dist/esm/modules/detection/P2PDominantSpeakerDetection.js +47 -0
  80. package/dist/esm/modules/detection/P2PDominantSpeakerDetection.js.map +1 -0
  81. package/dist/esm/modules/detection/TrackVADEmitter.js +190 -0
  82. package/dist/esm/modules/detection/TrackVADEmitter.js.map +1 -0
  83. package/dist/esm/modules/detection/VADAudioAnalyser.js +199 -0
  84. package/dist/esm/modules/detection/VADAudioAnalyser.js.map +1 -0
  85. package/dist/esm/modules/detection/VADNoiseDetection.js +168 -0
  86. package/dist/esm/modules/detection/VADNoiseDetection.js.map +1 -0
  87. package/dist/esm/modules/detection/VADReportingService.js +203 -0
  88. package/dist/esm/modules/detection/VADReportingService.js.map +1 -0
  89. package/dist/esm/modules/detection/VADTalkMutedDetection.js +131 -0
  90. package/dist/esm/modules/detection/VADTalkMutedDetection.js.map +1 -0
  91. package/dist/esm/modules/e2ee/Context.js +274 -0
  92. package/dist/esm/modules/e2ee/Context.js.map +1 -0
  93. package/dist/esm/modules/e2ee/E2EEContext.js +158 -0
  94. package/dist/esm/modules/e2ee/E2EEContext.js.map +1 -0
  95. package/dist/esm/modules/e2ee/E2EEErrors.js +10 -0
  96. package/dist/esm/modules/e2ee/E2EEErrors.js.map +1 -0
  97. package/dist/esm/modules/e2ee/E2EEncryption.js +87 -0
  98. package/dist/esm/modules/e2ee/E2EEncryption.js.map +1 -0
  99. package/dist/esm/modules/e2ee/ExternallyManagedKeyHandler.js +24 -0
  100. package/dist/esm/modules/e2ee/ExternallyManagedKeyHandler.js.map +1 -0
  101. package/dist/esm/modules/e2ee/KeyHandler.js +137 -0
  102. package/dist/esm/modules/e2ee/KeyHandler.js.map +1 -0
  103. package/dist/esm/modules/e2ee/ManagedKeyHandler.js +182 -0
  104. package/dist/esm/modules/e2ee/ManagedKeyHandler.js.map +1 -0
  105. package/dist/esm/modules/e2ee/OlmAdapter.js +860 -0
  106. package/dist/esm/modules/e2ee/OlmAdapter.js.map +1 -0
  107. package/dist/esm/modules/e2ee/SAS.js +128 -0
  108. package/dist/esm/modules/e2ee/SAS.js.map +1 -0
  109. package/dist/esm/modules/e2ee/Worker.js +102 -0
  110. package/dist/esm/modules/e2ee/Worker.js.map +1 -0
  111. package/dist/esm/modules/e2ee/crypto-utils.js +53 -0
  112. package/dist/esm/modules/e2ee/crypto-utils.js.map +1 -0
  113. package/dist/esm/modules/e2ee/utils.js +15 -0
  114. package/dist/esm/modules/e2ee/utils.js.map +1 -0
  115. package/dist/esm/modules/e2eping/e2eping.js +314 -0
  116. package/dist/esm/modules/e2eping/e2eping.js.map +1 -0
  117. package/dist/esm/modules/flags/FeatureFlags.js +36 -0
  118. package/dist/esm/modules/flags/FeatureFlags.js.map +1 -0
  119. package/dist/esm/modules/litemode/LiteModeContext.js +50 -0
  120. package/dist/esm/modules/litemode/LiteModeContext.js.map +1 -0
  121. package/dist/esm/modules/proxyconnection/CustomSignalingLayer.js +98 -0
  122. package/dist/esm/modules/proxyconnection/CustomSignalingLayer.js.map +1 -0
  123. package/dist/esm/modules/proxyconnection/ProxyConnectionPC.js +348 -0
  124. package/dist/esm/modules/proxyconnection/ProxyConnectionPC.js.map +1 -0
  125. package/dist/esm/modules/proxyconnection/ProxyConnectionService.js +279 -0
  126. package/dist/esm/modules/proxyconnection/ProxyConnectionService.js.map +1 -0
  127. package/dist/esm/modules/proxyconnection/constants.js +14 -0
  128. package/dist/esm/modules/proxyconnection/constants.js.map +1 -0
  129. package/dist/esm/modules/qualitycontrol/CodecSelection.js +222 -0
  130. package/dist/esm/modules/qualitycontrol/CodecSelection.js.map +1 -0
  131. package/dist/esm/modules/qualitycontrol/MockClasses.js +120 -0
  132. package/dist/esm/modules/qualitycontrol/MockClasses.js.map +1 -0
  133. package/dist/esm/modules/qualitycontrol/QualityController.js +366 -0
  134. package/dist/esm/modules/qualitycontrol/QualityController.js.map +1 -0
  135. package/dist/esm/modules/qualitycontrol/ReceiveAudioController.js +73 -0
  136. package/dist/esm/modules/qualitycontrol/ReceiveAudioController.js.map +1 -0
  137. package/dist/esm/modules/qualitycontrol/ReceiveVideoController.js +216 -0
  138. package/dist/esm/modules/qualitycontrol/ReceiveVideoController.js.map +1 -0
  139. package/dist/esm/modules/qualitycontrol/SendVideoController.js +133 -0
  140. package/dist/esm/modules/qualitycontrol/SendVideoController.js.map +1 -0
  141. package/dist/esm/modules/recording/JibriSession.js +279 -0
  142. package/dist/esm/modules/recording/JibriSession.js.map +1 -0
  143. package/dist/esm/modules/recording/RecordingManager.js +257 -0
  144. package/dist/esm/modules/recording/RecordingManager.js.map +1 -0
  145. package/dist/esm/modules/recording/recordingConstants.js +21 -0
  146. package/dist/esm/modules/recording/recordingConstants.js.map +1 -0
  147. package/dist/esm/modules/recording/recordingXMLUtils.js +69 -0
  148. package/dist/esm/modules/recording/recordingXMLUtils.js.map +1 -0
  149. package/dist/esm/modules/red/red.js +108 -0
  150. package/dist/esm/modules/red/red.js.map +1 -0
  151. package/dist/esm/modules/sdp/LocalSdpMunger.js +143 -0
  152. package/dist/esm/modules/sdp/LocalSdpMunger.js.map +1 -0
  153. package/dist/esm/modules/sdp/RtxModifier.js +179 -0
  154. package/dist/esm/modules/sdp/RtxModifier.js.map +1 -0
  155. package/dist/esm/modules/sdp/SDP.js +848 -0
  156. package/dist/esm/modules/sdp/SDP.js.map +1 -0
  157. package/dist/esm/modules/sdp/SDPDiffer.js +96 -0
  158. package/dist/esm/modules/sdp/SDPDiffer.js.map +1 -0
  159. package/dist/esm/modules/sdp/SDPUtil.js +798 -0
  160. package/dist/esm/modules/sdp/SDPUtil.js.map +1 -0
  161. package/dist/esm/modules/sdp/SampleSdpStrings.js +589 -0
  162. package/dist/esm/modules/sdp/SampleSdpStrings.js.map +1 -0
  163. package/dist/esm/modules/sdp/SdpSimulcast.js +196 -0
  164. package/dist/esm/modules/sdp/SdpSimulcast.js.map +1 -0
  165. package/dist/esm/modules/sdp/SdpTransformUtil.js +337 -0
  166. package/dist/esm/modules/sdp/SdpTransformUtil.js.map +1 -0
  167. package/dist/esm/modules/sdp/constants.js +2 -0
  168. package/dist/esm/modules/sdp/constants.js.map +1 -0
  169. package/dist/esm/modules/settings/Settings.js +95 -0
  170. package/dist/esm/modules/settings/Settings.js.map +1 -0
  171. package/dist/esm/modules/statistics/AnalyticsAdapter.js +277 -0
  172. package/dist/esm/modules/statistics/AnalyticsAdapter.js.map +1 -0
  173. package/dist/esm/modules/statistics/AvgRTPStatsReporter.js +817 -0
  174. package/dist/esm/modules/statistics/AvgRTPStatsReporter.js.map +1 -0
  175. package/dist/esm/modules/statistics/LocalStatsCollector.js +149 -0
  176. package/dist/esm/modules/statistics/LocalStatsCollector.js.map +1 -0
  177. package/dist/esm/modules/statistics/PreCallTest.js +15 -0
  178. package/dist/esm/modules/statistics/PreCallTest.js.map +1 -0
  179. package/dist/esm/modules/statistics/RTPStatsCollector.js +601 -0
  180. package/dist/esm/modules/statistics/RTPStatsCollector.js.map +1 -0
  181. package/dist/esm/modules/statistics/SpeakerStats.js +163 -0
  182. package/dist/esm/modules/statistics/SpeakerStats.js.map +1 -0
  183. package/dist/esm/modules/statistics/SpeakerStatsCollector.js +161 -0
  184. package/dist/esm/modules/statistics/SpeakerStatsCollector.js.map +1 -0
  185. package/dist/esm/modules/statistics/constants.js +7 -0
  186. package/dist/esm/modules/statistics/constants.js.map +1 -0
  187. package/dist/esm/modules/statistics/statistics.js +362 -0
  188. package/dist/esm/modules/statistics/statistics.js.map +1 -0
  189. package/dist/esm/modules/util/AsyncQueue.js +102 -0
  190. package/dist/esm/modules/util/AsyncQueue.js.map +1 -0
  191. package/dist/esm/modules/util/Deferred.js +41 -0
  192. package/dist/esm/modules/util/Deferred.js.map +1 -0
  193. package/dist/esm/modules/util/EventEmitter.js +17 -0
  194. package/dist/esm/modules/util/EventEmitter.js.map +1 -0
  195. package/dist/esm/modules/util/EventEmitterForwarder.js +52 -0
  196. package/dist/esm/modules/util/EventEmitterForwarder.js.map +1 -0
  197. package/dist/esm/modules/util/Listenable.js +106 -0
  198. package/dist/esm/modules/util/Listenable.js.map +1 -0
  199. package/dist/esm/modules/util/MathUtil.js +103 -0
  200. package/dist/esm/modules/util/MathUtil.js.map +1 -0
  201. package/dist/esm/modules/util/RandomUtil.js +66 -0
  202. package/dist/esm/modules/util/RandomUtil.js.map +1 -0
  203. package/dist/esm/modules/util/Retry.js +15 -0
  204. package/dist/esm/modules/util/Retry.js.map +1 -0
  205. package/dist/esm/modules/util/ScriptUtil.js +58 -0
  206. package/dist/esm/modules/util/ScriptUtil.js.map +1 -0
  207. package/dist/esm/modules/util/StringUtils.js +21 -0
  208. package/dist/esm/modules/util/StringUtils.js.map +1 -0
  209. package/dist/esm/modules/util/TestUtils.js +14 -0
  210. package/dist/esm/modules/util/TestUtils.js.map +1 -0
  211. package/dist/esm/modules/util/UsernameGenerator.js +436 -0
  212. package/dist/esm/modules/util/UsernameGenerator.js.map +1 -0
  213. package/dist/esm/modules/util/XMLUtils.js +135 -0
  214. package/dist/esm/modules/util/XMLUtils.js.map +1 -0
  215. package/dist/esm/modules/version/ComponentsVersions.js +52 -0
  216. package/dist/esm/modules/version/ComponentsVersions.js.map +1 -0
  217. package/dist/esm/modules/videosipgw/JitsiVideoSIPGWSession.js +137 -0
  218. package/dist/esm/modules/videosipgw/JitsiVideoSIPGWSession.js.map +1 -0
  219. package/dist/esm/modules/videosipgw/VideoSIPGW.js +102 -0
  220. package/dist/esm/modules/videosipgw/VideoSIPGW.js.map +1 -0
  221. package/dist/esm/modules/videosipgw/VideoSIPGWConstants.js +65 -0
  222. package/dist/esm/modules/videosipgw/VideoSIPGWConstants.js.map +1 -0
  223. package/dist/esm/modules/watchRTC/WatchRTC.js +69 -0
  224. package/dist/esm/modules/watchRTC/WatchRTC.js.map +1 -0
  225. package/dist/esm/modules/watchRTC/functions.js +31 -0
  226. package/dist/esm/modules/watchRTC/functions.js.map +1 -0
  227. package/dist/esm/modules/watchRTC/interfaces.js +2 -0
  228. package/dist/esm/modules/watchRTC/interfaces.js.map +1 -0
  229. package/dist/esm/modules/webaudio/AudioMixer.js +74 -0
  230. package/dist/esm/modules/webaudio/AudioMixer.js.map +1 -0
  231. package/dist/esm/modules/webaudio/WebAudioUtils.js +13 -0
  232. package/dist/esm/modules/webaudio/WebAudioUtils.js.map +1 -0
  233. package/dist/esm/modules/xmpp/AVModeration.js +156 -0
  234. package/dist/esm/modules/xmpp/AVModeration.js.map +1 -0
  235. package/dist/esm/modules/xmpp/BreakoutRooms.js +230 -0
  236. package/dist/esm/modules/xmpp/BreakoutRooms.js.map +1 -0
  237. package/dist/esm/modules/xmpp/Caps.js +223 -0
  238. package/dist/esm/modules/xmpp/Caps.js.map +1 -0
  239. package/dist/esm/modules/xmpp/ChatRoom.js +1877 -0
  240. package/dist/esm/modules/xmpp/ChatRoom.js.map +1 -0
  241. package/dist/esm/modules/xmpp/ConnectionPlugin.js +37 -0
  242. package/dist/esm/modules/xmpp/ConnectionPlugin.js.map +1 -0
  243. package/dist/esm/modules/xmpp/FileSharing.js +95 -0
  244. package/dist/esm/modules/xmpp/FileSharing.js.map +1 -0
  245. package/dist/esm/modules/xmpp/JingleHelperFunctions.js +168 -0
  246. package/dist/esm/modules/xmpp/JingleHelperFunctions.js.map +1 -0
  247. package/dist/esm/modules/xmpp/JingleSession.js +166 -0
  248. package/dist/esm/modules/xmpp/JingleSession.js.map +1 -0
  249. package/dist/esm/modules/xmpp/JingleSessionPC.js +1969 -0
  250. package/dist/esm/modules/xmpp/JingleSessionPC.js.map +1 -0
  251. package/dist/esm/modules/xmpp/JingleSessionState.js +23 -0
  252. package/dist/esm/modules/xmpp/JingleSessionState.js.map +1 -0
  253. package/dist/esm/modules/xmpp/Lobby.js +384 -0
  254. package/dist/esm/modules/xmpp/Lobby.js.map +1 -0
  255. package/dist/esm/modules/xmpp/MediaSessionEvents.js +12 -0
  256. package/dist/esm/modules/xmpp/MediaSessionEvents.js.map +1 -0
  257. package/dist/esm/modules/xmpp/MockClasses.js +77 -0
  258. package/dist/esm/modules/xmpp/MockClasses.js.map +1 -0
  259. package/dist/esm/modules/xmpp/Polls.js +87 -0
  260. package/dist/esm/modules/xmpp/Polls.js.map +1 -0
  261. package/dist/esm/modules/xmpp/ResumeTask.js +149 -0
  262. package/dist/esm/modules/xmpp/ResumeTask.js.map +1 -0
  263. package/dist/esm/modules/xmpp/RoomMetadata.js +96 -0
  264. package/dist/esm/modules/xmpp/RoomMetadata.js.map +1 -0
  265. package/dist/esm/modules/xmpp/SignalingLayerImpl.js +313 -0
  266. package/dist/esm/modules/xmpp/SignalingLayerImpl.js.map +1 -0
  267. package/dist/esm/modules/xmpp/StropheErrorHandler.js +53 -0
  268. package/dist/esm/modules/xmpp/StropheErrorHandler.js.map +1 -0
  269. package/dist/esm/modules/xmpp/StropheLastSuccess.js +52 -0
  270. package/dist/esm/modules/xmpp/StropheLastSuccess.js.map +1 -0
  271. package/dist/esm/modules/xmpp/XmppConnection.js +579 -0
  272. package/dist/esm/modules/xmpp/XmppConnection.js.map +1 -0
  273. package/dist/esm/modules/xmpp/moderator.js +524 -0
  274. package/dist/esm/modules/xmpp/moderator.js.map +1 -0
  275. package/dist/esm/modules/xmpp/sha1.js +165 -0
  276. package/dist/esm/modules/xmpp/sha1.js.map +1 -0
  277. package/dist/esm/modules/xmpp/strophe.disco.js +222 -0
  278. package/dist/esm/modules/xmpp/strophe.disco.js.map +1 -0
  279. package/dist/esm/modules/xmpp/strophe.emuc.js +206 -0
  280. package/dist/esm/modules/xmpp/strophe.emuc.js.map +1 -0
  281. package/dist/esm/modules/xmpp/strophe.jingle.js +404 -0
  282. package/dist/esm/modules/xmpp/strophe.jingle.js.map +1 -0
  283. package/dist/esm/modules/xmpp/strophe.logger.js +44 -0
  284. package/dist/esm/modules/xmpp/strophe.logger.js.map +1 -0
  285. package/dist/esm/modules/xmpp/strophe.ping.js +170 -0
  286. package/dist/esm/modules/xmpp/strophe.ping.js.map +1 -0
  287. package/dist/esm/modules/xmpp/strophe.rayo.js +117 -0
  288. package/dist/esm/modules/xmpp/strophe.rayo.js.map +1 -0
  289. package/dist/esm/modules/xmpp/strophe.stream-management.js +365 -0
  290. package/dist/esm/modules/xmpp/strophe.stream-management.js.map +1 -0
  291. package/dist/esm/modules/xmpp/strophe.util.js +116 -0
  292. package/dist/esm/modules/xmpp/strophe.util.js.map +1 -0
  293. package/dist/esm/modules/xmpp/xmpp.js +973 -0
  294. package/dist/esm/modules/xmpp/xmpp.js.map +1 -0
  295. package/dist/esm/service/RTC/BridgeVideoType.js +24 -0
  296. package/dist/esm/service/RTC/BridgeVideoType.js.map +1 -0
  297. package/dist/esm/service/RTC/CameraFacingMode.js +21 -0
  298. package/dist/esm/service/RTC/CameraFacingMode.js.map +1 -0
  299. package/dist/esm/service/RTC/CodecMimeType.js +36 -0
  300. package/dist/esm/service/RTC/CodecMimeType.js.map +1 -0
  301. package/dist/esm/service/RTC/MediaDirection.js +23 -0
  302. package/dist/esm/service/RTC/MediaDirection.js.map +1 -0
  303. package/dist/esm/service/RTC/MediaType.js +20 -0
  304. package/dist/esm/service/RTC/MediaType.js.map +1 -0
  305. package/dist/esm/service/RTC/RTCEvents.js +111 -0
  306. package/dist/esm/service/RTC/RTCEvents.js.map +1 -0
  307. package/dist/esm/service/RTC/ReceiverAudioSubscription.js +27 -0
  308. package/dist/esm/service/RTC/ReceiverAudioSubscription.js.map +1 -0
  309. package/dist/esm/service/RTC/Resolutions.js +56 -0
  310. package/dist/esm/service/RTC/Resolutions.js.map +1 -0
  311. package/dist/esm/service/RTC/SignalingEvents.js +42 -0
  312. package/dist/esm/service/RTC/SignalingEvents.js.map +1 -0
  313. package/dist/esm/service/RTC/SignalingLayer.js +153 -0
  314. package/dist/esm/service/RTC/SignalingLayer.js.map +1 -0
  315. package/dist/esm/service/RTC/StandardVideoQualitySettings.js +180 -0
  316. package/dist/esm/service/RTC/StandardVideoQualitySettings.js.map +1 -0
  317. package/dist/esm/service/RTC/VideoEncoderScalabilityMode.js +36 -0
  318. package/dist/esm/service/RTC/VideoEncoderScalabilityMode.js.map +1 -0
  319. package/dist/esm/service/RTC/VideoType.js +19 -0
  320. package/dist/esm/service/RTC/VideoType.js.map +1 -0
  321. package/dist/esm/service/authentication/AuthenticationEvents.js +13 -0
  322. package/dist/esm/service/authentication/AuthenticationEvents.js.map +1 -0
  323. package/dist/esm/service/connectivity/ConnectionQualityEvents.js +13 -0
  324. package/dist/esm/service/connectivity/ConnectionQualityEvents.js.map +1 -0
  325. package/dist/esm/service/connectivity/Constants.js +3 -0
  326. package/dist/esm/service/connectivity/Constants.js.map +1 -0
  327. package/dist/esm/service/e2eping/E2ePingEvents.js +8 -0
  328. package/dist/esm/service/e2eping/E2ePingEvents.js.map +1 -0
  329. package/dist/esm/service/statistics/AnalyticsEvents.js +521 -0
  330. package/dist/esm/service/statistics/AnalyticsEvents.js.map +1 -0
  331. package/dist/esm/service/statistics/Events.js +36 -0
  332. package/dist/esm/service/statistics/Events.js.map +1 -0
  333. package/dist/esm/service/statistics/constants.js +2 -0
  334. package/dist/esm/service/statistics/constants.js.map +1 -0
  335. package/dist/esm/service/xmpp/XMPPEvents.js +359 -0
  336. package/dist/esm/service/xmpp/XMPPEvents.js.map +1 -0
  337. package/dist/esm/service/xmpp/XMPPExtensioProtocols.js +64 -0
  338. package/dist/esm/service/xmpp/XMPPExtensioProtocols.js.map +1 -0
  339. package/dist/esm/test-setup-polyfill.js +34 -0
  340. package/dist/esm/test-setup-polyfill.js.map +1 -0
  341. package/dist/esm/tools/gen-version.js +15 -0
  342. package/dist/esm/tools/gen-version.js.map +1 -0
  343. package/dist/esm/version.js +3 -0
  344. package/dist/esm/version.js.map +1 -0
  345. package/dist/umd/lib-jitsi-meet.e2ee-worker.js +484 -0
  346. package/dist/umd/lib-jitsi-meet.min.js +3 -0
  347. package/dist/umd/lib-jitsi-meet.min.js.LICENSE.txt +18 -0
  348. package/dist/umd/lib-jitsi-meet.min.map +1 -0
  349. package/package.json +93 -0
  350. package/types/index.d.ts +16180 -0
@@ -0,0 +1,973 @@
1
+ import { safeJsonParse } from '@jitsi/js-utils/json';
2
+ import { getLogger } from '@jitsi/logger';
3
+ import { cloneDeep, unescape } from 'lodash-es';
4
+ import { $msg, Strophe } from 'strophe.js';
5
+ import * as JitsiConnectionErrors from '../../JitsiConnectionErrors';
6
+ import * as JitsiConnectionEvents from '../../JitsiConnectionEvents';
7
+ import { XMPPEvents } from '../../service/xmpp/XMPPEvents';
8
+ import { XEP } from '../../service/xmpp/XMPPExtensioProtocols';
9
+ import RTCStats from '../RTCStats/RTCStats';
10
+ import { RTCStatsEvents } from '../RTCStats/RTCStatsEvents';
11
+ import browser from '../browser';
12
+ import { E2EEncryption } from '../e2ee/E2EEncryption';
13
+ import FeatureFlags from '../flags/FeatureFlags';
14
+ import Statistics from '../statistics/statistics';
15
+ import Listenable from '../util/Listenable';
16
+ import RandomUtil from '../util/RandomUtil';
17
+ import { exists, findFirst, getText } from '../util/XMLUtils';
18
+ import Caps, { parseDiscoInfo } from './Caps';
19
+ import { IDENTITY_TYPE as FILE_SHARING_IDENTITY_TYPE } from './FileSharing';
20
+ import XmppConnection from './XmppConnection';
21
+ import Moderator from './moderator';
22
+ import './strophe.disco';
23
+ import MucConnectionPlugin from './strophe.emuc';
24
+ import JingleConnectionPlugin from './strophe.jingle';
25
+ import initStropheLogger from './strophe.logger';
26
+ import RayoConnectionPlugin from './strophe.rayo';
27
+ import initStropheUtil from './strophe.util';
28
+ const logger = getLogger('xmpp:Xmpp');
29
+ /**
30
+ * Regex to extract exact error message on jwt error.
31
+ */
32
+ const FAILURE_REGEX = /<failure.*><not-allowed\/><text>(.*)<\/text><\/failure>/gi;
33
+ /**
34
+ * Creates XMPP connection.
35
+ *
36
+ * @param {Object} options
37
+ * @param {string} [options.token] - JWT token used for authentication(JWT authentication module must be enabled in
38
+ * Prosody).
39
+ * @param {string} options.serviceUrl - The service URL for XMPP connection.
40
+ * @param {string} options.shard - The shard where XMPP connection initially landed.
41
+ * @param {string} options.enableWebsocketResume - True to enable stream resumption.
42
+ * @param {number} [options.websocketKeepAlive] - See {@link XmppConnection} constructor.
43
+ * @param {number} [options.websocketKeepAliveUrl] - See {@link XmppConnection} constructor.
44
+ * @param {Object} [options.xmppPing] - See {@link XmppConnection} constructor.
45
+ * @returns {XmppConnection}
46
+ */
47
+ function createConnection({ enableWebsocketResume, serviceUrl = '/http-bind', shard, token, websocketKeepAlive, websocketKeepAliveUrl }) {
48
+ // Append token as URL param
49
+ if (token) {
50
+ // eslint-disable-next-line no-param-reassign
51
+ serviceUrl += `${serviceUrl.indexOf('?') === -1 ? '?' : '&'}token=${token}`;
52
+ }
53
+ return new XmppConnection({
54
+ enableWebsocketResume,
55
+ serviceUrl,
56
+ shard,
57
+ websocketKeepAlive,
58
+ websocketKeepAliveUrl
59
+ });
60
+ }
61
+ /**
62
+ * Initializes Strophe plugins that need to work with Strophe.Connection directly rather than the lib-jitsi-meet's
63
+ * {@link XmppConnection} wrapper.
64
+ *
65
+ * @returns {void}
66
+ */
67
+ function initStropheNativePlugins() {
68
+ initStropheUtil();
69
+ initStropheLogger();
70
+ }
71
+ // FIXME: remove once we have a default config template. -saghul
72
+ /**
73
+ * A list of ice servers to use by default for P2P.
74
+ */
75
+ export const DEFAULT_STUN_SERVERS = [
76
+ { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }
77
+ ];
78
+ /**
79
+ * The name of the field used to recognize a chat message as carrying a JSON
80
+ * payload from another endpoint.
81
+ * If the json-message of a chat message contains a valid JSON object, and
82
+ * the JSON has this key, then it is a valid json-message to be sent.
83
+ */
84
+ export const JITSI_MEET_MUC_TYPE = 'type';
85
+ /**
86
+ * The feature used by jigasi participants.
87
+ * @type {string}
88
+ */
89
+ export const FEATURE_JIGASI = 'http://jitsi.org/protocol/jigasi';
90
+ /**
91
+ * The feature used by jibri participants.
92
+ * @type {string}
93
+ */
94
+ export const FEATURE_JIBRI = 'http://jitsi.org/protocol/jibri';
95
+ /**
96
+ * The feature used by jigasi transcriber participants.
97
+ * @type {string}
98
+ */
99
+ export const FEATURE_TRANSCRIBER = 'http://jitsi.org/protocol/transcriber';
100
+ /**
101
+ * The feature used by the lib to mark support for e2ee. We use the feature by putting it in the presence
102
+ * to avoid additional signaling (disco-info).
103
+ * @type {string}
104
+ */
105
+ export const FEATURE_E2EE = 'https://jitsi.org/meet/e2ee';
106
+ /**
107
+ * @internal
108
+ */
109
+ export default class XMPP extends Listenable {
110
+ /**
111
+ * FIXME describe all options
112
+ * @param {Object} options
113
+ * @param {String} options.serviceUrl - URL passed to the XMPP client which will be used to establish XMPP
114
+ * connection with the server.
115
+ * @param {boolean} options.enableWebsocketResume - Enables XEP-0198 stream management which will make the XMPP
116
+ * module try to resume the session in case the Websocket connection breaks.
117
+ * @param {number} [options.websocketKeepAlive] - The websocket keep alive interval. See {@link XmppConnection}
118
+ * constructor for more details.
119
+ * @param {number} [options.websocketKeepAliveUrl] - The websocket keep alive url. See {@link XmppConnection}
120
+ * constructor for more details.
121
+ * @param {Object} [options.xmppPing] - The xmpp ping settings.
122
+ * @param {Array<Object>} options.p2pStunServers see {@link JingleConnectionPlugin} for more details.
123
+ * @param token
124
+ */
125
+ constructor(options, token) {
126
+ super();
127
+ if (options.bosh && !options.serviceUrl) {
128
+ throw new Error('The "bosh" option is no longer supported, please use "serviceUrl" instead');
129
+ }
130
+ this.connection = null;
131
+ this._disconnectInProgress = false;
132
+ this.connectionTimes = {};
133
+ this.options = options;
134
+ this.token = token;
135
+ this.authenticatedUser = false;
136
+ if (!this.options.deploymentInfo) {
137
+ this.options.deploymentInfo = {};
138
+ }
139
+ // Cache of components used for certain features.
140
+ this._components = [];
141
+ // We want to track messages that are received before we process the disco-info components
142
+ // re-order of receiving we may drop some messages
143
+ this._preComponentsMsgs = [];
144
+ initStropheNativePlugins();
145
+ const xmppPing = options.xmppPing || {};
146
+ // let's ping the main domain (in case a guest one is used for the connection)
147
+ xmppPing.domain = options.hosts.domain;
148
+ this.connection = createConnection({
149
+ enableWebsocketResume: options.enableWebsocketResume,
150
+ serviceUrl: options.serviceUrl,
151
+ shard: options.deploymentInfo.shard,
152
+ token,
153
+ websocketKeepAlive: options.websocketKeepAlive,
154
+ websocketKeepAliveUrl: options.websocketKeepAliveUrl,
155
+ xmppPing
156
+ });
157
+ this.moderator = new Moderator(this);
158
+ // forwards the shard changed event
159
+ this.connection.on(XmppConnection.Events.CONN_SHARD_CHANGED, () => {
160
+ /* eslint-disable camelcase */
161
+ const details = {
162
+ shard_changed: true,
163
+ suspend_time: this.connection.ping.getPingSuspendTime(),
164
+ time_since_last_success: this.connection.getTimeSinceLastSuccess()
165
+ };
166
+ /* eslint-enable camelcase */
167
+ if (this.options.testing?.enableGracefulReconnect) {
168
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.SHARD_CHANGED_ERROR);
169
+ }
170
+ else {
171
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.OTHER_ERROR, undefined, undefined, details);
172
+ }
173
+ });
174
+ this._initStrophePlugins();
175
+ this.caps = new Caps(this.connection, /* clientNode */ 'https://jitsi.org/jitsi-meet');
176
+ // Initialize features advertised in disco-info
177
+ this.initFeaturesList();
178
+ this.connection.addHandler(this._onPrivateMessage.bind(this), null, 'message', null, null);
179
+ // Setup a disconnect on unload as a way to facilitate API consumers. It
180
+ // sounds like they would want that. A problem for them though may be if
181
+ // they wanted to utilize the connected connection in an unload handler
182
+ // of their own. However, it should be fairly easy for them to do that
183
+ // by registering their unload handler before us.
184
+ const events = `${this.options.disableBeforeUnloadHandlers ? '' : 'beforeunload '}unload`;
185
+ const handleDisconnect = ev => {
186
+ // type-checking added as disconnect returns Promise<void> | boolean
187
+ const result = this.disconnect(ev);
188
+ if (result instanceof Promise) {
189
+ result.catch(() => {
190
+ // Ignore errors in order to not break the unload.
191
+ });
192
+ }
193
+ };
194
+ for (const event of events.split(' ')) {
195
+ window.addEventListener(event, handleDisconnect);
196
+ }
197
+ }
198
+ /**
199
+ * Initializes the list of feature advertised through the disco-info
200
+ * mechanism.
201
+ */
202
+ initFeaturesList() {
203
+ // http://xmpp.org/extensions/xep-0167.html#support
204
+ // http://xmpp.org/extensions/xep-0176.html#support
205
+ this.caps.addFeature(XEP.JINGLE);
206
+ this.caps.addFeature(XEP.RTP_MEDIA);
207
+ this.caps.addFeature(XEP.ICE_UDP_TRANSPORT);
208
+ this.caps.addFeature(XEP.DTLS_SRTP);
209
+ this.caps.addFeature(XEP.SCTP_DATA_CHANNEL);
210
+ this.caps.addFeature(XEP.RTP_AUDIO);
211
+ this.caps.addFeature(XEP.RTP_VIDEO);
212
+ this.caps.addFeature('http://jitsi.org/json-encoded-sources');
213
+ if (!(this.options.disableRtx || !browser.supportsRTX())) {
214
+ this.caps.addFeature('urn:ietf:rfc:4588');
215
+ }
216
+ if (this.options.enableOpusRed === true && browser.supportsAudioRed()) {
217
+ this.caps.addFeature('http://jitsi.org/opus-red');
218
+ }
219
+ if (typeof this.options.enableRemb === 'undefined' || this.options.enableRemb) {
220
+ this.caps.addFeature('http://jitsi.org/remb');
221
+ }
222
+ // Disable TCC on Firefox 114 and older versions because of a known issue where BWE is halved on every
223
+ // renegotiation.
224
+ if (!(browser.isFirefox() && browser.isVersionLessThan(115))
225
+ && (typeof this.options.enableTcc === 'undefined' || this.options.enableTcc)) {
226
+ this.caps.addFeature('http://jitsi.org/tcc');
227
+ }
228
+ if (this.connection.rayo) {
229
+ this.caps.addFeature('urn:xmpp:rayo:client:1');
230
+ }
231
+ if (E2EEncryption.isSupported(this.options)) {
232
+ this.caps.addFeature(FEATURE_E2EE, false, true);
233
+ }
234
+ // Advertise source-name signaling when the endpoint supports it.
235
+ logger.debug('Source-name signaling is enabled');
236
+ this.caps.addFeature('http://jitsi.org/source-name');
237
+ logger.debug('Receiving multiple video streams is enabled');
238
+ this.caps.addFeature('http://jitsi.org/receive-multiple-video-streams');
239
+ // Advertise support for ssrc-rewriting.
240
+ if (FeatureFlags.isSsrcRewritingSupported()) {
241
+ this.caps.addFeature('http://jitsi.org/ssrc-rewriting-1');
242
+ }
243
+ // Use "-1" as a version that we can bump later. This should match
244
+ // the version added in moderator.js, this one here is mostly defined
245
+ // for keeping stats, since it is not made available to jocofo at
246
+ // the time of the initial conference-request.
247
+ this.caps.addFeature('http://jitsi.org/visitors-1');
248
+ // Advertise support for startMuted policy through room metadata.
249
+ this.caps.addFeature('http://jitsi.org/start-muted-room-metadata');
250
+ }
251
+ /**
252
+ * A private message is received, message that is not addressed to the muc.
253
+ * We expect private message coming from plugins component if it is
254
+ * enabled and running.
255
+ *
256
+ * @param {string} msg - The message.
257
+ */
258
+ _onPrivateMessage(msg) {
259
+ const from = msg.getAttribute('from');
260
+ if (!this._components.includes(from)) {
261
+ this._preComponentsMsgs.push(msg);
262
+ return true;
263
+ }
264
+ // Use *|xmlns to match xmlns attributes across any namespace (CSS Selectors Level 3)
265
+ const jsonMessage = getText(findFirst(msg, ':scope>json-message[*|xmlns="http://jitsi.org/jitmeet"]'));
266
+ const parsedJson = this.tryParseJSONAndVerify(jsonMessage);
267
+ if (!parsedJson || typeof parsedJson !== 'object') {
268
+ return true;
269
+ }
270
+ if (parsedJson[JITSI_MEET_MUC_TYPE] === 'speakerstats' && parsedJson.users) {
271
+ this.eventEmitter.emit(XMPPEvents.SPEAKER_STATS_RECEIVED, parsedJson.users);
272
+ }
273
+ else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'av_moderation') {
274
+ this.eventEmitter.emit(XMPPEvents.AV_MODERATION_RECEIVED, parsedJson);
275
+ }
276
+ else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'breakout_rooms') {
277
+ this.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_EVENT, parsedJson);
278
+ }
279
+ else if (parsedJson[JITSI_MEET_MUC_TYPE] === FILE_SHARING_IDENTITY_TYPE) {
280
+ this.eventEmitter.emit(XMPPEvents.FILE_SHARING_EVENT, parsedJson);
281
+ }
282
+ else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'room_metadata') {
283
+ this.eventEmitter.emit(XMPPEvents.ROOM_METADATA_EVENT, parsedJson);
284
+ }
285
+ else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'visitors') {
286
+ this.eventEmitter.emit(XMPPEvents.VISITORS_MESSAGE, parsedJson);
287
+ }
288
+ else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'polls') {
289
+ this.eventEmitter.emit(XMPPEvents.POLLS_EVENT, parsedJson);
290
+ }
291
+ return true;
292
+ }
293
+ /**
294
+ * Sends deployment info to stats if not sent already.
295
+ * We want to try sending it on failure to connect
296
+ * or when we get a sys message(from jiconop2)
297
+ * or after success or failure of disco-info
298
+ * @param force Whether to force sending without checking anything.
299
+ * @private
300
+ */
301
+ _maybeSendDeploymentInfoStat(force = false) {
302
+ const acceptedStatuses = [
303
+ Strophe.Status.ERROR,
304
+ Strophe.Status.CONNFAIL,
305
+ Strophe.Status.AUTHFAIL,
306
+ Strophe.Status.DISCONNECTED,
307
+ Strophe.Status.CONNTIMEOUT
308
+ ];
309
+ if (!force && !(acceptedStatuses.includes(this.connection.status) && this.sendDeploymentInfo)) {
310
+ return;
311
+ }
312
+ // Log deployment-specific information, if available. Defined outside
313
+ // the application by individual deployments
314
+ const aprops = this.options.deploymentInfo;
315
+ if (Object.keys(aprops ?? {}).length > 0) {
316
+ const logObject = { id: undefined };
317
+ for (const attr in aprops) {
318
+ if (aprops.hasOwnProperty(attr)) {
319
+ logObject[attr] = aprops[attr];
320
+ }
321
+ }
322
+ // Let's push to analytics any updates that may have come from the backend
323
+ Statistics.analytics.addPermanentProperties({ ...logObject });
324
+ logObject.id = 'deployment_info';
325
+ const entry = JSON.stringify(logObject);
326
+ logger.info(entry);
327
+ }
328
+ this.sendDeploymentInfo = false;
329
+ const { region, shard } = aprops;
330
+ if (region || shard) {
331
+ // avoids sending empty values
332
+ this.eventEmitter.emit(JitsiConnectionEvents.PROPERTIES_UPDATED, cloneDeep({ region, shard }));
333
+ }
334
+ }
335
+ /**
336
+ * Process received identities.
337
+ * @param {Set<String>} identities The identities to process.
338
+ * @param {Set<String>} features The features to process, optional. If missing lobby component will be queried
339
+ * for more features.
340
+ * @private
341
+ */
342
+ _processDiscoInfoIdentities(identities, features) {
343
+ // check for speakerstats
344
+ identities.forEach(identity => {
345
+ if (identity.type === 'av_moderation') {
346
+ this.avModerationComponentAddress = identity.name;
347
+ this._components.push(this.avModerationComponentAddress);
348
+ }
349
+ if (identity.type === 'end_conference') {
350
+ this.endConferenceComponentAddress = identity.name;
351
+ this._components.push(this.endConferenceComponentAddress);
352
+ }
353
+ if (identity.type === 'speakerstats') {
354
+ this.speakerStatsComponentAddress = identity.name;
355
+ this._components.push(this.speakerStatsComponentAddress);
356
+ }
357
+ if (identity.type === 'lobbyrooms') {
358
+ this.lobbySupported = true;
359
+ const processLobbyFeatures = f => {
360
+ f.forEach(fr => {
361
+ if (fr.endsWith('#displayname_required')) {
362
+ this.eventEmitter.emit(JitsiConnectionEvents.DISPLAY_NAME_REQUIRED);
363
+ }
364
+ });
365
+ };
366
+ if (features) {
367
+ processLobbyFeatures(features);
368
+ }
369
+ else {
370
+ identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)
371
+ .then(({ features: f }) => processLobbyFeatures(f))
372
+ .catch(e => logger.warn('Error getting features from lobby.', e?.message));
373
+ }
374
+ }
375
+ if (identity.type === 'shard') {
376
+ this.options.deploymentInfo.shard = this.connection.shard = identity.name;
377
+ }
378
+ if (identity.type === 'region') {
379
+ // @ts-ignore property 'region' does not exist on 'XmppConnection'
380
+ this.options.deploymentInfo.region = this.connection.region = identity.name;
381
+ }
382
+ if (identity.type === 'release') {
383
+ this.options.deploymentInfo.backendRelease = identity.name;
384
+ }
385
+ if (identity.type === 'breakout_rooms') {
386
+ this.breakoutRoomsComponentAddress = identity.name;
387
+ this._components.push(this.breakoutRoomsComponentAddress);
388
+ const processBreakoutRoomsFeatures = f => {
389
+ this.breakoutRoomsFeatures = {};
390
+ f.forEach(fr => {
391
+ if (fr.endsWith('#rename')) {
392
+ this.breakoutRoomsFeatures.rename = true;
393
+ }
394
+ });
395
+ };
396
+ if (features) {
397
+ processBreakoutRoomsFeatures(features);
398
+ }
399
+ else {
400
+ identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)
401
+ .then(({ features: f }) => processBreakoutRoomsFeatures(f))
402
+ .catch(e => logger.warn('Error getting features for breakout rooms.', e?.message));
403
+ }
404
+ }
405
+ if (identity.type === FILE_SHARING_IDENTITY_TYPE) {
406
+ this.fileSharingComponentAddress = identity.name;
407
+ this._components.push(this.fileSharingComponentAddress);
408
+ }
409
+ if (identity.type === 'room_metadata') {
410
+ this.roomMetadataComponentAddress = identity.name;
411
+ this._components.push(this.roomMetadataComponentAddress);
412
+ }
413
+ if (identity.type === 'visitors') {
414
+ this._components.push(identity.name);
415
+ }
416
+ if (identity.type === 'polls') {
417
+ this.pollsComponentAddress = identity.name;
418
+ this._components.push(this.pollsComponentAddress);
419
+ }
420
+ });
421
+ this._maybeSendDeploymentInfoStat(true);
422
+ if (this._components.length > 0) {
423
+ this._preComponentsMsgs.forEach(this._onPrivateMessage.bind(this));
424
+ }
425
+ this._preComponentsMsgs = [];
426
+ }
427
+ /**
428
+ * Parses a raw failure xmpp xml message received on auth failed.
429
+ *
430
+ * @param {string} msg - The raw failure message from xmpp.
431
+ * @returns {string|null} - The parsed message from the raw xmpp message.
432
+ */
433
+ _parseConnectionFailedMessage(msg) {
434
+ if (!msg) {
435
+ return null;
436
+ }
437
+ FAILURE_REGEX.lastIndex = 0;
438
+ const matches = FAILURE_REGEX.exec(msg);
439
+ return matches ? matches[1] : null;
440
+ }
441
+ /**
442
+ *
443
+ * @param jid
444
+ * @param password
445
+ */
446
+ _connect(jid, password) {
447
+ // connection.connect() starts the connection process.
448
+ //
449
+ // As the connection process proceeds, the user supplied callback will
450
+ // be triggered multiple times with status updates. The callback should
451
+ // take two arguments - the status code and the error condition.
452
+ //
453
+ // The status code will be one of the values in the Strophe.Status
454
+ // constants. The error condition will be one of the conditions defined
455
+ // in RFC 3920 or the condition ‘strophe-parsererror’.
456
+ //
457
+ // The Parameters wait, hold and route are optional and only relevant
458
+ // for BOSH connections. Please see XEP 124 for a more detailed
459
+ // explanation of the optional parameters.
460
+ //
461
+ // Connection status constants for use by the connection handler
462
+ // callback.
463
+ //
464
+ // Status.ERROR - An error has occurred (websockets specific)
465
+ // Status.CONNECTING - The connection is currently being made
466
+ // Status.CONNFAIL - The connection attempt failed
467
+ // Status.AUTHENTICATING - The connection is authenticating
468
+ // Status.AUTHFAIL - The authentication attempt failed
469
+ // Status.CONNECTED - The connection has succeeded
470
+ // Status.DISCONNECTED - The connection has been terminated
471
+ // Status.DISCONNECTING - The connection is currently being terminated
472
+ // Status.ATTACHED - The connection has been attached
473
+ this._resetState();
474
+ // we want to send this only on the initial connect
475
+ this.sendDiscoInfo = true;
476
+ this.sendDeploymentInfo = true;
477
+ if (this.connection._stropheConn?._addSysHandler) {
478
+ this._sysMessageHandler = this.connection._stropheConn._addSysHandler(this._onSystemMessage.bind(this), null, 'message');
479
+ }
480
+ else {
481
+ logger.warn('Cannot attach strophe system handler, jiconop cannot operate');
482
+ }
483
+ this.connection.connect(jid, password, this.connectionHandler.bind(this, {
484
+ jid,
485
+ password
486
+ }));
487
+ }
488
+ /**
489
+ * Receives system messages during the connect/login process and checks for services or
490
+ * @param msg The received message.
491
+ * @returns {void}
492
+ * @private
493
+ */
494
+ _onSystemMessage(msg) {
495
+ // proceed only if the message has any of the expected information
496
+ if (!exists(msg, ':scope>services') && !exists(msg, ':scope>query')) {
497
+ return;
498
+ }
499
+ this.sendDiscoInfo = false;
500
+ const foundIceServers = this.connection.jingle.onReceiveStunAndTurnCredentials(msg) || false;
501
+ const { features, identities } = parseDiscoInfo(msg);
502
+ this._processDiscoInfoIdentities(identities, features);
503
+ if (foundIceServers || identities.size > 0 || features.size > 0) {
504
+ this.connection._stropheConn.deleteHandler(this._sysMessageHandler);
505
+ this._sysMessageHandler = null;
506
+ }
507
+ }
508
+ /**
509
+ * The method is supposed to gracefully close the XMPP connection and the main goal is to make sure that the current
510
+ * participant will be removed from the conference XMPP MUC, so that it doesn't leave a "ghost" participant behind.
511
+ *
512
+ * @param {Object} ev - Optionally, the event which triggered the necessity to disconnect from the XMPP server
513
+ * (e.g. beforeunload, unload).
514
+ * @private
515
+ * @returns {void}
516
+ */
517
+ _cleanupXmppConnection(ev) {
518
+ // XXX Strophe is asynchronously sending by default. Unfortunately, that means that there may not be enough time
519
+ // to send an unavailable presence or disconnect at all. Switching Strophe to synchronous sending is not much of
520
+ // an option because it may lead to a noticeable delay in navigating away from the current location. As
521
+ // a compromise, we will try to increase the chances of sending an unavailable presence and/or disconnecting
522
+ // within the short time span that we have upon unloading by invoking flush() on the connection. We flush() once
523
+ // before disconnect() in order to attempt to have its unavailable presence at the top of the send queue. We
524
+ // flush() once more after disconnect() in order to attempt to have its unavailable presence sent as soon as
525
+ // possible.
526
+ !this.connection.isUsingWebSocket && this.connection.flush();
527
+ if (!this.connection.isUsingWebSocket && ev !== null && typeof ev !== 'undefined') {
528
+ const evType = ev.type;
529
+ if (evType === 'beforeunload' || evType === 'unload') {
530
+ // XXX Whatever we said above, synchronous sending is the best (known) way to properly disconnect from
531
+ // the XMPP server. Consequently, it may be fine to have the source code and comment it in or out
532
+ // depending on whether we want to run with it for some time.
533
+ this.connection.options.sync = true;
534
+ // This is needed in some browsers where sync xhr sending is disabled by default on unload.
535
+ if (this.connection.sendUnavailableBeacon()) {
536
+ return;
537
+ }
538
+ }
539
+ }
540
+ this.connection.disconnect();
541
+ this._startConnecting = false;
542
+ if (this.connection.options.sync !== true) {
543
+ this.connection.flush();
544
+ }
545
+ }
546
+ /**
547
+ *
548
+ */
549
+ _initStrophePlugins() {
550
+ const iceConfig = {
551
+ jvb: { iceServers: [] },
552
+ p2p: { iceServers: [], iceTransportPolicy: undefined }
553
+ };
554
+ const p2pStunServers = (this.options.p2p?.stunServers) || DEFAULT_STUN_SERVERS;
555
+ if (Array.isArray(p2pStunServers)) {
556
+ logger.info('P2P STUN servers: ', p2pStunServers);
557
+ iceConfig.p2p.iceServers = p2pStunServers;
558
+ }
559
+ if (this.options.p2p?.iceTransportPolicy) {
560
+ logger.info('P2P ICE transport policy: ', this.options.p2p.iceTransportPolicy);
561
+ iceConfig.p2p.iceTransportPolicy
562
+ = this.options.p2p.iceTransportPolicy;
563
+ }
564
+ this.connection.addConnectionPlugin('emuc', new MucConnectionPlugin(this));
565
+ this.connection.addConnectionPlugin('jingle', new JingleConnectionPlugin(this, this.eventEmitter, iceConfig));
566
+ this.connection.addConnectionPlugin('rayo', new RayoConnectionPlugin());
567
+ }
568
+ /**
569
+ * Returns details about connection failure. Shard change or is it after
570
+ * suspend.
571
+ * @returns { IConnectionFailedReasonDetails} contains details about a connection failure.
572
+ * @private
573
+ */
574
+ _getConnectionFailedReasonDetails() {
575
+ const details = {};
576
+ // check for moving between shard if information is available
577
+ if (this.options.deploymentInfo?.shard
578
+ && this.connection.lastResponseHeaders) {
579
+ // split headers by line
580
+ const headersArr = this.connection.lastResponseHeaders
581
+ .trim().split(/[\r\n]+/);
582
+ const headers = {};
583
+ headersArr.forEach(line => {
584
+ const parts = line.split(': ');
585
+ const header = parts.shift();
586
+ const value = parts.join(': ');
587
+ headers[header] = value;
588
+ });
589
+ /* eslint-disable camelcase */
590
+ details.shard_changed
591
+ = this.options.deploymentInfo.shard
592
+ !== headers['x-jitsi-shard'];
593
+ /* eslint-enable camelcase */
594
+ }
595
+ /* eslint-disable camelcase */
596
+ // check for possible suspend
597
+ details.suspend_time = this.connection.ping.getPingSuspendTime();
598
+ details.time_since_last_success = this.connection.getTimeSinceLastSuccess();
599
+ /* eslint-enable camelcase */
600
+ return details;
601
+ }
602
+ /**
603
+ * Resets any state/flag before starting a new connection.
604
+ * @private
605
+ */
606
+ _resetState() {
607
+ this._anonymousConnectionFailed = false;
608
+ this.connectionFailed = false;
609
+ this._lastErrorMsg = undefined;
610
+ this._disconnectInProgress = undefined;
611
+ this._wasDisconnected = false;
612
+ }
613
+ /**
614
+ * Returns the current XMPP connection instance.
615
+ */
616
+ getConnection() {
617
+ return this.connection;
618
+ }
619
+ /**
620
+ * Receive connection status changes and handles them.
621
+ *
622
+ * @param {Object} credentials
623
+ * @param {string} credentials.jid - The user's XMPP ID passed to the
624
+ * connect method. For example, 'user@xmpp.com'.
625
+ * @param {string} credentials.password - The password passed to the connect
626
+ * method.
627
+ * @param {string} status - One of Strophe's connection status strings.
628
+ * @param {string} [msg] - The connection error message provided by Strophe.
629
+ */
630
+ connectionHandler(credentials = {}, status, msg) {
631
+ const now = window.performance.now();
632
+ const statusStr = Strophe.getStatusString(status).toLowerCase();
633
+ this.connectionTimes[statusStr] = now;
634
+ logger.info(`(TIME) Strophe ${statusStr}${msg ? `[${msg}]` : ''}:\t`, now);
635
+ this.eventEmitter.emit(XMPPEvents.CONNECTION_STATUS_CHANGED, credentials, status, msg);
636
+ this._maybeSendDeploymentInfoStat();
637
+ if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
638
+ // once connected or attached we no longer need this handle, drop it if it exist
639
+ if (this._sysMessageHandler) {
640
+ this.connection._stropheConn.deleteHandler(this._sysMessageHandler);
641
+ this._sysMessageHandler = null;
642
+ }
643
+ this.sendDiscoInfo && this.connection.jingle.getStunAndTurnCredentials();
644
+ logger.info(`My Jabber ID: ${this.connection.jid}`);
645
+ this._wasDisconnected && RTCStats.sendStatsEntry(RTCStatsEvents.STROPHE_RECONNECTED_EVENT);
646
+ // XmppConnection emits CONNECTED again on reconnect - a good opportunity to clear any "last error" flags
647
+ this._resetState();
648
+ // make sure we will send the info after the features request succeeds or fails
649
+ this.sendDeploymentInfo = false;
650
+ this.sendDiscoInfo && this.caps.getFeaturesAndIdentities(this.options.hosts.domain, undefined)
651
+ .then(({ features, identities }) => {
652
+ if (!features.has(Strophe.NS.PING)) {
653
+ logger.error(`Ping NOT supported by ${this.options.hosts.domain} - please enable ping in your XMPP server config`);
654
+ }
655
+ this._processDiscoInfoIdentities(identities, undefined /* when querying we will query for features */);
656
+ })
657
+ .catch(error => {
658
+ logger.error('Feature discovery error', error);
659
+ this._maybeSendDeploymentInfoStat(true);
660
+ });
661
+ // make sure we don't query again
662
+ this.sendDiscoInfo = false;
663
+ if (credentials.password) {
664
+ this.authenticatedUser = true;
665
+ }
666
+ if (this.connection && this.connection.connected
667
+ && Strophe.getResourceFromJid(this.connection.jid)) {
668
+ // .connected is true while connecting?
669
+ // this.connection.send($pres());
670
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_ESTABLISHED, Strophe.getResourceFromJid(this.connection.jid));
671
+ }
672
+ }
673
+ else if (status === Strophe.Status.CONNFAIL) {
674
+ if (msg === 'x-strophe-bad-non-anon-jid') {
675
+ this._anonymousConnectionFailed = true;
676
+ }
677
+ else {
678
+ this.connectionFailed = true;
679
+ }
680
+ this._lastErrorMsg = msg;
681
+ if (msg === 'giving-up') {
682
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.OTHER_ERROR, msg);
683
+ }
684
+ }
685
+ else if (status === Strophe.Status.ERROR) {
686
+ this._lastErrorMsg = msg;
687
+ }
688
+ else if (status === Strophe.Status.DISCONNECTED) {
689
+ RTCStats.sendStatsEntry(RTCStatsEvents.STROPHE_DISCONNECTED_EVENT);
690
+ this._wasDisconnected = true;
691
+ // Stop ping interval
692
+ this.connection.ping.stopInterval();
693
+ const wasIntentionalDisconnect = Boolean(this._disconnectInProgress);
694
+ const errMsg = msg || this._lastErrorMsg;
695
+ if (this._anonymousConnectionFailed) {
696
+ // prompt user for username and password
697
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.PASSWORD_REQUIRED);
698
+ }
699
+ else if (this.connectionFailed) {
700
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.OTHER_ERROR, errMsg, undefined, /* credentials */ this._getConnectionFailedReasonDetails());
701
+ }
702
+ else if (wasIntentionalDisconnect) {
703
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_DISCONNECTED, errMsg);
704
+ }
705
+ else {
706
+ // XXX if Strophe drops the connection while not being asked to,
707
+ // it means that most likely some serious error has occurred.
708
+ // One currently known case is when a BOSH request fails for
709
+ // more than 4 times. The connection is dropped without
710
+ // supplying a reason(error message/event) through the API.
711
+ logger.error('XMPP connection dropped!');
712
+ // XXX if the last request error is within 5xx range it means it
713
+ // was a server failure
714
+ const lastErrorStatus = Strophe.getLastErrorStatus();
715
+ if (lastErrorStatus >= 500 && lastErrorStatus < 600) {
716
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.SERVER_ERROR, errMsg || 'server-error',
717
+ /* credentials */ undefined, this._getConnectionFailedReasonDetails());
718
+ }
719
+ else {
720
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.CONNECTION_DROPPED_ERROR, errMsg || 'connection-dropped-error',
721
+ /* credentials */ undefined, this._getConnectionFailedReasonDetails());
722
+ }
723
+ }
724
+ }
725
+ else if (status === Strophe.Status.AUTHFAIL) {
726
+ const lastFailedRawMessage = this.getConnection().getLastFailedMessage();
727
+ // wrong password or username, prompt user
728
+ this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionErrors.PASSWORD_REQUIRED, msg || this._parseConnectionFailedMessage(lastFailedRawMessage), credentials);
729
+ }
730
+ }
731
+ /**
732
+ * Attach to existing connection. Can be used for optimizations. For
733
+ * example: if the connection is created on the server we can attach to it
734
+ * and start using it.
735
+ *
736
+ * @param options {object} connecting options - rid, sid, jid and password.
737
+ */
738
+ attach(options) {
739
+ this._resetState();
740
+ // we want to send this only on the initial connect
741
+ this.sendDiscoInfo = true;
742
+ const now = this.connectionTimes.attaching = window.performance.now();
743
+ logger.info('(TIME) Strophe Attaching:\t', now);
744
+ this.connection.attach(options.jid, options.sid, (Number.parseInt(options.rid, 10) + 1).toString(), this.connectionHandler.bind(this, {
745
+ jid: options.jid,
746
+ password: options.password
747
+ }));
748
+ }
749
+ /**
750
+ *
751
+ * @param jid
752
+ * @param password
753
+ */
754
+ connect(jid, password) {
755
+ if (!jid) {
756
+ const { anonymousdomain, domain } = this.options.hosts;
757
+ let configDomain = anonymousdomain || domain;
758
+ // Force authenticated domain if room is appended with '?login=true'
759
+ // or if we're joining with the token
760
+ // FIXME Do not rely on window.location because (1) React Native
761
+ // does not have a window.location by default and (2) here we cannot
762
+ // know for sure that query/search has not be stripped from
763
+ // window.location by the time the following executes.
764
+ const { location } = window;
765
+ if (anonymousdomain) {
766
+ const search = location?.search;
767
+ if ((search && search.indexOf('login=true') !== -1)
768
+ || this.token) {
769
+ configDomain = domain;
770
+ }
771
+ }
772
+ // eslint-disable-next-line no-param-reassign
773
+ jid = configDomain || (location?.hostname);
774
+ }
775
+ this._startConnecting = true;
776
+ return this._connect(jid, password);
777
+ }
778
+ /**
779
+ * Joins or creates a muc with the provided jid, created from the passed
780
+ * in room name and muc host and onCreateResource result.
781
+ *
782
+ * @param {string} roomName - The name of the muc to join.
783
+ * @param {Object} options - Configuration for how to join the muc.
784
+ * @param {Function} [onCreateResource] - Callback to invoke when a resource
785
+ * is to be added to the jid.
786
+ * @returns {ChatRoom} Resolves with an instance of a strophe muc.
787
+ */
788
+ createRoom(roomName, options, onCreateResource) {
789
+ // Support passing the domain in a String object as part of the room name.
790
+ const domain = roomName.domain || options.customDomain;
791
+ // There are cases (when using subdomain) where muc can hold an uppercase part
792
+ let roomjid = `${this.getRoomJid(roomName, domain)}/`;
793
+ const mucNickname = onCreateResource
794
+ ? onCreateResource(this.connection.jid, this.authenticatedUser)
795
+ : RandomUtil.randomHexString(8).toLowerCase();
796
+ logger.info(`JID ${this.connection.jid} using MUC nickname ${mucNickname}`);
797
+ roomjid += mucNickname;
798
+ return this.connection.emuc?.createRoom?.(roomjid, null, options);
799
+ }
800
+ /**
801
+ * Returns the room JID based on the passed room name and domain.
802
+ *
803
+ * @param {string} roomName - The room name.
804
+ * @param {string} domain - The domain.
805
+ * @returns {string} - The room JID.
806
+ */
807
+ getRoomJid(roomName, domain) {
808
+ return `${roomName}@${domain ? domain : this.options.hosts.muc.toLowerCase()}`;
809
+ }
810
+ /**
811
+ * Check if a room with the passed JID is already created.
812
+ *
813
+ * @param {string} roomJid - The JID of the room.
814
+ * @returns {boolean}
815
+ */
816
+ isRoomCreated(roomName, domain) {
817
+ return this.connection.emuc?.isRoomCreated?.(this.getRoomJid(roomName, domain)) || false;
818
+ }
819
+ /**
820
+ * Returns the jid of the participant associated with the Strophe connection.
821
+ *
822
+ * @returns {string} The jid of the participant.
823
+ */
824
+ getJid() {
825
+ return this.connection.jid;
826
+ }
827
+ /**
828
+ * Returns the logs from strophe.jingle.
829
+ * @returns {Record<string, unknown>} - The jingle logs.
830
+ */
831
+ getJingleLog() {
832
+ const jingle = this.connection.jingle;
833
+ return jingle ? jingle.getLog() : { metadata: {} };
834
+ }
835
+ /**
836
+ * Returns the logs from strophe.
837
+ */
838
+ getXmppLog() {
839
+ return this.connection.logger?.log || null;
840
+ }
841
+ /**
842
+ *
843
+ */
844
+ dial(...args) {
845
+ return this.connection.rayo?.dial(...args);
846
+ }
847
+ /**
848
+ * Pings the server.
849
+ * @param timeout how many ms before a timeout should occur.
850
+ * @returns {Promise} resolved on ping success and reject on an error or
851
+ * a timeout.
852
+ */
853
+ ping(timeout) {
854
+ return new Promise((resolve, reject) => {
855
+ this.connection.ping.ping(this.connection.pingDomain, resolve, reject, timeout);
856
+ });
857
+ }
858
+ /**
859
+ *
860
+ */
861
+ getSessions() {
862
+ return this.connection.jingle.sessions;
863
+ }
864
+ /**
865
+ * Disconnects this from the XMPP server (if this is connected).
866
+ *
867
+ * @param {Object} ev - Optionally, the event which triggered the necessity to
868
+ * disconnect from the XMPP server (e.g. beforeunload, unload).
869
+ * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.
870
+ */
871
+ disconnect(ev = undefined) {
872
+ logger.info(`XMPP disconnect triggered by the event=${ev?.type}`);
873
+ if (this._disconnectInProgress) {
874
+ return this._disconnectInProgress;
875
+ }
876
+ else if (!this.connection || !this._startConnecting) {
877
+ // we have created a connection, but never called connect we still want to resolve on calling disconnect
878
+ // this is visitors use case when using http to send conference request.
879
+ return Promise.resolve();
880
+ }
881
+ this._disconnectInProgress = new Promise(resolve => {
882
+ const disconnectListener = (credentials, status) => {
883
+ if (status === Strophe.Status.DISCONNECTED) {
884
+ this.eventEmitter.removeListener(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);
885
+ resolve();
886
+ }
887
+ };
888
+ this.eventEmitter.on(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);
889
+ });
890
+ this._cleanupXmppConnection(ev);
891
+ return this._disconnectInProgress;
892
+ }
893
+ /**
894
+ * Notifies speaker stats component if available that we are the new
895
+ * dominant speaker in the conference.
896
+ * @param {String} roomJid - The room jid where the speaker event occurred.
897
+ * @param {boolean} silence - Whether the dominant speaker is silent or not.
898
+ */
899
+ sendDominantSpeakerEvent(roomJid, silence) {
900
+ // no speaker stats component advertised
901
+ if (!this.speakerStatsComponentAddress || !roomJid) {
902
+ return;
903
+ }
904
+ const msg = $msg({ to: this.speakerStatsComponentAddress });
905
+ msg.c('speakerstats', {
906
+ room: roomJid,
907
+ silence,
908
+ xmlns: 'http://jitsi.org/jitmeet'
909
+ }).up();
910
+ this.connection.send(msg);
911
+ }
912
+ /**
913
+ * Sends face landmarks to speaker stats component.
914
+ * @param {String} roomJid - The room jid where the speaker event occurred.
915
+ * @param {Object} payload - The expression to be sent to the speaker stats.
916
+ */
917
+ sendFaceLandmarksEvent(roomJid, payload) {
918
+ // no speaker stats component advertised
919
+ if (!this.speakerStatsComponentAddress || !roomJid) {
920
+ return;
921
+ }
922
+ const msg = $msg({ to: this.speakerStatsComponentAddress });
923
+ msg.c('faceLandmarks', {
924
+ duration: payload.duration,
925
+ faceExpression: payload.faceExpression,
926
+ room: roomJid,
927
+ timestamp: payload.timestamp,
928
+ xmlns: 'http://jitsi.org/jitmeet'
929
+ }).up();
930
+ this.connection.send(msg);
931
+ }
932
+ /**
933
+ * Check if the given argument is a valid JSON ENDPOINT_MESSAGE string by
934
+ * parsing it and checking if it has a field called 'type'.
935
+ *
936
+ * @param {string} jsonString check if this string is a valid json string
937
+ * and contains the special structure.
938
+ * @returns {boolean, object} if given object is a valid JSON string, return
939
+ * the json object. Otherwise, returns false.
940
+ */
941
+ tryParseJSONAndVerify(jsonString) {
942
+ // ignore empty strings, like message errors
943
+ if (!jsonString) {
944
+ return false;
945
+ }
946
+ try {
947
+ // Note: we use `unescape` to also convert HTML entities to UTF-8 since
948
+ // Jigasi seems to encode them like that in some circumstances.
949
+ const json = safeJsonParse(unescape(jsonString));
950
+ // Handle non-exception-throwing cases:
951
+ // Neither JSON.parse(false) or JSON.parse(1234) throw errors,
952
+ // hence the type-checking,
953
+ // but... JSON.parse(null) returns null, and
954
+ // typeof null === "object",
955
+ // so we must check for that, too.
956
+ // Thankfully, null is falsey, so this suffices:
957
+ if (json && typeof json === 'object') {
958
+ const type = json[JITSI_MEET_MUC_TYPE];
959
+ if (typeof type !== 'undefined') {
960
+ return json;
961
+ }
962
+ logger.debug('parsing valid json but does not have correct '
963
+ + 'structure', 'topic: ', type);
964
+ }
965
+ }
966
+ catch (e) {
967
+ logger.error(`Error parsing json ${jsonString}`, e);
968
+ return false;
969
+ }
970
+ return false;
971
+ }
972
+ }
973
+ //# sourceMappingURL=xmpp.js.map