@ethora/chat-component-rn 26.5.21 → 26.6.11

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 (372) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +3 -3
  3. package/index.js +1 -1
  4. package/lib/commonjs/components/MainComponents/ChatHeader.js +20 -8
  5. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/ChatWrapper.js +17 -0
  7. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js +62 -0
  9. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js.map +1 -0
  10. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js +253 -0
  11. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js.map +1 -0
  12. package/lib/commonjs/components/MainComponents/MediaMessage.js +7 -1
  13. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/RoomList.js +23 -9
  15. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  16. package/lib/commonjs/components/MessageBubble/Message.js +72 -11
  17. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  18. package/lib/commonjs/components/MessageBubble/MessageTranslate.js +160 -0
  19. package/lib/commonjs/components/MessageBubble/MessageTranslate.js.map +1 -0
  20. package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js +59 -0
  21. package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
  22. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
  23. package/lib/commonjs/components/UsersList/UsersList.js +3 -1
  24. package/lib/commonjs/components/UsersList/UsersList.js.map +1 -1
  25. package/lib/commonjs/components/VideoCalls/CallButtons.js +159 -0
  26. package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -0
  27. package/lib/commonjs/components/VideoCalls/CallIcons.js +328 -0
  28. package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -0
  29. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +550 -0
  30. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -0
  31. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +636 -0
  32. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -0
  33. package/lib/commonjs/components/VideoCalls/livekitRuntime.js +91 -0
  34. package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -0
  35. package/lib/commonjs/components/VideoCalls/useCallKeep.js +215 -0
  36. package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -0
  37. package/lib/commonjs/components/styled/AudioMessage.js +91 -33
  38. package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
  39. package/lib/commonjs/components/styled/RoomListComponents/index.js +13 -1
  40. package/lib/commonjs/components/styled/RoomListComponents/index.js.map +1 -1
  41. package/lib/commonjs/components/styled/SendInput.js +83 -49
  42. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  43. package/lib/commonjs/components/styled/StyledComponents.js +9 -4
  44. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  45. package/lib/commonjs/components/styled/StyledInputComponents/Composing.js +2 -0
  46. package/lib/commonjs/components/styled/StyledInputComponents/Composing.js.map +1 -1
  47. package/lib/commonjs/components/styled/VideoMessage.js +110 -26
  48. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  49. package/lib/commonjs/context/xmppProvider.js +10 -3
  50. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  51. package/lib/commonjs/helpers/callLogMessage.js +162 -0
  52. package/lib/commonjs/helpers/callLogMessage.js.map +1 -0
  53. package/lib/commonjs/helpers/callPush.js +61 -0
  54. package/lib/commonjs/helpers/callPush.js.map +1 -0
  55. package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
  56. package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
  57. package/lib/commonjs/helpers/createUserNameFromSetUser.js +51 -2
  58. package/lib/commonjs/helpers/createUserNameFromSetUser.js.map +1 -1
  59. package/lib/commonjs/helpers/getDataFromXml.js +19 -1
  60. package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
  61. package/lib/commonjs/helpers/incomingCallFromPush.js +74 -0
  62. package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -0
  63. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +13 -1
  64. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  65. package/lib/commonjs/helpers/isUnresolvedSenderId.js +32 -0
  66. package/lib/commonjs/helpers/isUnresolvedSenderId.js.map +1 -0
  67. package/lib/commonjs/hooks/useChatSettingState.js +2 -0
  68. package/lib/commonjs/hooks/useChatSettingState.js.map +1 -1
  69. package/lib/commonjs/hooks/useMessageTranslation.js +51 -0
  70. package/lib/commonjs/hooks/useMessageTranslation.js.map +1 -0
  71. package/lib/commonjs/hooks/usePushNotifications.js +13 -3
  72. package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
  73. package/lib/commonjs/hooks/useSendMessage.js +14 -4
  74. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  75. package/lib/commonjs/i18n/strings.js +1308 -0
  76. package/lib/commonjs/i18n/strings.js.map +1 -0
  77. package/lib/commonjs/i18n/useT.js +60 -0
  78. package/lib/commonjs/i18n/useT.js.map +1 -0
  79. package/lib/commonjs/main.js +44 -0
  80. package/lib/commonjs/main.js.map +1 -1
  81. package/lib/commonjs/networking/api-requests/auth.api.js +81 -52
  82. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  83. package/lib/commonjs/networking/api-requests/push.api.js +34 -5
  84. package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
  85. package/lib/commonjs/networking/api-requests/rooms.api.js +108 -0
  86. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  87. package/lib/commonjs/networking/callTokenStanza.js +531 -0
  88. package/lib/commonjs/networking/callTokenStanza.js.map +1 -0
  89. package/lib/commonjs/networking/outboundQueue.js.map +1 -1
  90. package/lib/commonjs/networking/stanzaHandlers.js +75 -8
  91. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  92. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +47 -11
  93. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  94. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +2 -1
  95. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  96. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +42 -5
  97. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  98. package/lib/commonjs/networking/xmppClient.js +78 -16
  99. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  100. package/lib/commonjs/roomStore/callSlice.js +144 -0
  101. package/lib/commonjs/roomStore/callSlice.js.map +1 -0
  102. package/lib/commonjs/roomStore/chatSettingsSlice.js +8 -2
  103. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  104. package/lib/commonjs/roomStore/index.js +7 -1
  105. package/lib/commonjs/roomStore/index.js.map +1 -1
  106. package/lib/commonjs/roomStore/persistence.js +69 -5
  107. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  108. package/lib/commonjs/roomStore/roomsSlice.js +136 -6
  109. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  110. package/lib/commonjs/utils/translateModePolicy.js +33 -0
  111. package/lib/commonjs/utils/translateModePolicy.js.map +1 -0
  112. package/lib/module/components/MainComponents/ChatHeader.js +20 -8
  113. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  114. package/lib/module/components/MainComponents/ChatWrapper.js +17 -0
  115. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  116. package/lib/module/components/MainComponents/LanguageSelectorButton.js +57 -0
  117. package/lib/module/components/MainComponents/LanguageSelectorButton.js.map +1 -0
  118. package/lib/module/components/MainComponents/LanguageSelectorModal.js +246 -0
  119. package/lib/module/components/MainComponents/LanguageSelectorModal.js.map +1 -0
  120. package/lib/module/components/MainComponents/MediaMessage.js +7 -1
  121. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  122. package/lib/module/components/MainComponents/RoomList.js +23 -9
  123. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  124. package/lib/module/components/MessageBubble/Message.js +73 -12
  125. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  126. package/lib/module/components/MessageBubble/MessageTranslate.js +155 -0
  127. package/lib/module/components/MessageBubble/MessageTranslate.js.map +1 -0
  128. package/lib/module/components/MessageBubble/TranslatedMessageBody.js +53 -0
  129. package/lib/module/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
  130. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
  131. package/lib/module/components/UsersList/UsersList.js +3 -1
  132. package/lib/module/components/UsersList/UsersList.js.map +1 -1
  133. package/lib/module/components/VideoCalls/CallButtons.js +154 -0
  134. package/lib/module/components/VideoCalls/CallButtons.js.map +1 -0
  135. package/lib/module/components/VideoCalls/CallIcons.js +309 -0
  136. package/lib/module/components/VideoCalls/CallIcons.js.map +1 -0
  137. package/lib/module/components/VideoCalls/VideoCallOverlay.js +544 -0
  138. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -0
  139. package/lib/module/components/VideoCalls/VideoCallSession.js +630 -0
  140. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -0
  141. package/lib/module/components/VideoCalls/livekitRuntime.js +83 -0
  142. package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -0
  143. package/lib/module/components/VideoCalls/useCallKeep.js +210 -0
  144. package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -0
  145. package/lib/module/components/styled/AudioMessage.js +91 -33
  146. package/lib/module/components/styled/AudioMessage.js.map +1 -1
  147. package/lib/module/components/styled/RoomListComponents/index.js +13 -1
  148. package/lib/module/components/styled/RoomListComponents/index.js.map +1 -1
  149. package/lib/module/components/styled/SendInput.js +83 -49
  150. package/lib/module/components/styled/SendInput.js.map +1 -1
  151. package/lib/module/components/styled/StyledComponents.js +9 -4
  152. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  153. package/lib/module/components/styled/StyledInputComponents/Composing.js +2 -0
  154. package/lib/module/components/styled/StyledInputComponents/Composing.js.map +1 -1
  155. package/lib/module/components/styled/VideoMessage.js +111 -27
  156. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  157. package/lib/module/context/xmppProvider.js +11 -4
  158. package/lib/module/context/xmppProvider.js.map +1 -1
  159. package/lib/module/helpers/callLogMessage.js +152 -0
  160. package/lib/module/helpers/callLogMessage.js.map +1 -0
  161. package/lib/module/helpers/callPush.js +55 -0
  162. package/lib/module/helpers/callPush.js.map +1 -0
  163. package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
  164. package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
  165. package/lib/module/helpers/createUserNameFromSetUser.js +49 -1
  166. package/lib/module/helpers/createUserNameFromSetUser.js.map +1 -1
  167. package/lib/module/helpers/getDataFromXml.js +20 -1
  168. package/lib/module/helpers/getDataFromXml.js.map +1 -1
  169. package/lib/module/helpers/incomingCallFromPush.js +70 -0
  170. package/lib/module/helpers/incomingCallFromPush.js.map +1 -0
  171. package/lib/module/helpers/insertMessageWithDelimiter.js +13 -1
  172. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  173. package/lib/module/helpers/isUnresolvedSenderId.js +27 -0
  174. package/lib/module/helpers/isUnresolvedSenderId.js.map +1 -0
  175. package/lib/module/hooks/useChatSettingState.js +2 -0
  176. package/lib/module/hooks/useChatSettingState.js.map +1 -1
  177. package/lib/module/hooks/useMessageTranslation.js +46 -0
  178. package/lib/module/hooks/useMessageTranslation.js.map +1 -0
  179. package/lib/module/hooks/usePushNotifications.js +13 -3
  180. package/lib/module/hooks/usePushNotifications.js.map +1 -1
  181. package/lib/module/hooks/useSendMessage.js +15 -5
  182. package/lib/module/hooks/useSendMessage.js.map +1 -1
  183. package/lib/module/i18n/strings.js +1300 -0
  184. package/lib/module/i18n/strings.js.map +1 -0
  185. package/lib/module/i18n/useT.js +55 -0
  186. package/lib/module/i18n/useT.js.map +1 -0
  187. package/lib/module/main.js +7 -1
  188. package/lib/module/main.js.map +1 -1
  189. package/lib/module/networking/api-requests/auth.api.js +80 -51
  190. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  191. package/lib/module/networking/api-requests/push.api.js +35 -5
  192. package/lib/module/networking/api-requests/push.api.js.map +1 -1
  193. package/lib/module/networking/api-requests/rooms.api.js +109 -1
  194. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  195. package/lib/module/networking/callTokenStanza.js +526 -0
  196. package/lib/module/networking/callTokenStanza.js.map +1 -0
  197. package/lib/module/networking/outboundQueue.js.map +1 -1
  198. package/lib/module/networking/stanzaHandlers.js +76 -9
  199. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  200. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +48 -11
  201. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  202. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +1 -1
  203. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  204. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +43 -5
  205. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  206. package/lib/module/networking/xmppClient.js +78 -16
  207. package/lib/module/networking/xmppClient.js.map +1 -1
  208. package/lib/module/roomStore/callSlice.js +130 -0
  209. package/lib/module/roomStore/callSlice.js.map +1 -0
  210. package/lib/module/roomStore/chatSettingsSlice.js +6 -1
  211. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  212. package/lib/module/roomStore/index.js +6 -1
  213. package/lib/module/roomStore/index.js.map +1 -1
  214. package/lib/module/roomStore/persistence.js +69 -5
  215. package/lib/module/roomStore/persistence.js.map +1 -1
  216. package/lib/module/roomStore/roomsSlice.js +134 -5
  217. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  218. package/lib/module/utils/translateModePolicy.js +27 -0
  219. package/lib/module/utils/translateModePolicy.js.map +1 -0
  220. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  221. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  222. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts +12 -0
  223. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts.map +1 -0
  224. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts +31 -0
  225. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts.map +1 -0
  226. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  227. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  228. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  229. package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts +44 -0
  230. package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts.map +1 -0
  231. package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts +24 -0
  232. package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts.map +1 -0
  233. package/lib/typescript/components/UsersList/UsersList.d.ts.map +1 -1
  234. package/lib/typescript/components/VideoCalls/CallButtons.d.ts +16 -0
  235. package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -0
  236. package/lib/typescript/components/VideoCalls/CallIcons.d.ts +30 -0
  237. package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -0
  238. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts +10 -0
  239. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -0
  240. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +38 -0
  241. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -0
  242. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +52 -0
  243. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -0
  244. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +32 -0
  245. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -0
  246. package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
  247. package/lib/typescript/components/styled/RoomListComponents/index.d.ts.map +1 -1
  248. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  249. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  250. package/lib/typescript/components/styled/StyledInputComponents/Composing.d.ts.map +1 -1
  251. package/lib/typescript/components/styled/VideoMessage.d.ts +2 -0
  252. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  253. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  254. package/lib/typescript/helpers/callLogMessage.d.ts +34 -0
  255. package/lib/typescript/helpers/callLogMessage.d.ts.map +1 -0
  256. package/lib/typescript/helpers/callPush.d.ts +23 -0
  257. package/lib/typescript/helpers/callPush.d.ts.map +1 -0
  258. package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts +14 -0
  259. package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts.map +1 -1
  260. package/lib/typescript/helpers/createUserNameFromSetUser.d.ts +33 -1
  261. package/lib/typescript/helpers/createUserNameFromSetUser.d.ts.map +1 -1
  262. package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
  263. package/lib/typescript/helpers/incomingCallFromPush.d.ts +14 -0
  264. package/lib/typescript/helpers/incomingCallFromPush.d.ts.map +1 -0
  265. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  266. package/lib/typescript/helpers/isUnresolvedSenderId.d.ts +2 -0
  267. package/lib/typescript/helpers/isUnresolvedSenderId.d.ts.map +1 -0
  268. package/lib/typescript/hooks/useChatSettingState.d.ts +2 -1
  269. package/lib/typescript/hooks/useChatSettingState.d.ts.map +1 -1
  270. package/lib/typescript/hooks/useMessageTranslation.d.ts +25 -0
  271. package/lib/typescript/hooks/useMessageTranslation.d.ts.map +1 -0
  272. package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
  273. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  274. package/lib/typescript/i18n/strings.d.ts +16 -0
  275. package/lib/typescript/i18n/strings.d.ts.map +1 -0
  276. package/lib/typescript/i18n/useT.d.ts +34 -0
  277. package/lib/typescript/i18n/useT.d.ts.map +1 -0
  278. package/lib/typescript/main.d.ts +6 -1
  279. package/lib/typescript/main.d.ts.map +1 -1
  280. package/lib/typescript/networking/api-requests/auth.api.d.ts +27 -1
  281. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  282. package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
  283. package/lib/typescript/networking/api-requests/rooms.api.d.ts +3 -0
  284. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  285. package/lib/typescript/networking/callTokenStanza.d.ts +14 -0
  286. package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -0
  287. package/lib/typescript/networking/outboundQueue.d.ts +1 -0
  288. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
  289. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  290. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  291. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts +10 -0
  292. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
  293. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts +16 -1
  294. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts.map +1 -1
  295. package/lib/typescript/networking/xmppClient.d.ts +1 -1
  296. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  297. package/lib/typescript/roomStore/callSlice.d.ts +39 -0
  298. package/lib/typescript/roomStore/callSlice.d.ts.map +1 -0
  299. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +10 -1
  300. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  301. package/lib/typescript/roomStore/index.d.ts +4 -0
  302. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  303. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  304. package/lib/typescript/roomStore/roomsSlice.d.ts +6 -1
  305. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  306. package/lib/typescript/types/models/language.model.d.ts +1 -1
  307. package/lib/typescript/types/models/language.model.d.ts.map +1 -1
  308. package/lib/typescript/types/models/message.model.d.ts +7 -0
  309. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  310. package/lib/typescript/types/types.d.ts +135 -1
  311. package/lib/typescript/types/types.d.ts.map +1 -1
  312. package/lib/typescript/utils/translateModePolicy.d.ts +20 -0
  313. package/lib/typescript/utils/translateModePolicy.d.ts.map +1 -0
  314. package/package.json +20 -4
  315. package/src/components/MainComponents/ChatHeader.tsx +30 -9
  316. package/src/components/MainComponents/ChatWrapper.tsx +15 -0
  317. package/src/components/MainComponents/LanguageSelectorButton.tsx +53 -0
  318. package/src/components/MainComponents/LanguageSelectorModal.tsx +276 -0
  319. package/src/components/MainComponents/MediaMessage.tsx +5 -0
  320. package/src/components/MainComponents/RoomList.tsx +27 -9
  321. package/src/components/MessageBubble/Message.tsx +109 -17
  322. package/src/components/MessageBubble/MessageTranslate.tsx +182 -0
  323. package/src/components/MessageBubble/TranslatedMessageBody.tsx +59 -0
  324. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +3 -3
  325. package/src/components/UsersList/UsersList.tsx +3 -1
  326. package/src/components/VideoCalls/CallButtons.tsx +171 -0
  327. package/src/components/VideoCalls/CallIcons.tsx +246 -0
  328. package/src/components/VideoCalls/VideoCallOverlay.tsx +627 -0
  329. package/src/components/VideoCalls/VideoCallSession.tsx +675 -0
  330. package/src/components/VideoCalls/livekitRuntime.ts +100 -0
  331. package/src/components/VideoCalls/useCallKeep.ts +252 -0
  332. package/src/components/styled/AudioMessage.tsx +97 -37
  333. package/src/components/styled/RoomListComponents/index.tsx +15 -3
  334. package/src/components/styled/SendInput.tsx +94 -51
  335. package/src/components/styled/StyledComponents.ts +9 -6
  336. package/src/components/styled/StyledInputComponents/Composing.tsx +7 -1
  337. package/src/components/styled/VideoMessage.tsx +114 -20
  338. package/src/context/xmppProvider.tsx +14 -1
  339. package/src/helpers/callLogMessage.ts +174 -0
  340. package/src/helpers/callPush.ts +90 -0
  341. package/src/helpers/constants/LANGUAGE_OPTIONS.ts +20 -5
  342. package/src/helpers/createUserNameFromSetUser.ts +68 -2
  343. package/src/helpers/getDataFromXml.ts +40 -4
  344. package/src/helpers/incomingCallFromPush.ts +83 -0
  345. package/src/helpers/insertMessageWithDelimiter.ts +27 -9
  346. package/src/helpers/isUnresolvedSenderId.ts +25 -0
  347. package/src/hooks/useChatSettingState.tsx +4 -0
  348. package/src/hooks/useMessageTranslation.ts +70 -0
  349. package/src/hooks/usePushNotifications.ts +15 -3
  350. package/src/hooks/useSendMessage.tsx +18 -5
  351. package/src/i18n/strings.ts +1322 -0
  352. package/src/i18n/useT.ts +56 -0
  353. package/src/main.ts +18 -1
  354. package/src/networking/api-requests/auth.api.ts +79 -44
  355. package/src/networking/api-requests/push.api.ts +39 -8
  356. package/src/networking/api-requests/rooms.api.ts +109 -1
  357. package/src/networking/callTokenStanza.ts +636 -0
  358. package/src/networking/outboundQueue.ts +1 -0
  359. package/src/networking/stanzaHandlers.ts +74 -15
  360. package/src/networking/xmpp/handleStanzas.xmpp.ts +52 -11
  361. package/src/networking/xmpp/sendTextMessage.xmpp.ts +1 -1
  362. package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +41 -5
  363. package/src/networking/xmppClient.ts +97 -28
  364. package/src/roomStore/callSlice.ts +190 -0
  365. package/src/roomStore/chatSettingsSlice.ts +16 -0
  366. package/src/roomStore/index.ts +5 -0
  367. package/src/roomStore/persistence.ts +103 -3
  368. package/src/roomStore/roomsSlice.ts +149 -4
  369. package/src/types/models/language.model.ts +17 -1
  370. package/src/types/models/message.model.ts +9 -0
  371. package/src/types/types.ts +142 -2
  372. package/src/utils/translateModePolicy.ts +31 -0
@@ -0,0 +1,636 @@
1
+ import { Element } from 'ltx';
2
+ import { xml } from '@xmpp/client';
3
+ import { store } from '../roomStore';
4
+ import {
5
+ endCall,
6
+ setCallKind,
7
+ setIncomingCallToken,
8
+ setOutgoingCallToken,
9
+ } from '../roomStore/callSlice';
10
+ import { getGlobalXmppClient } from '../utils/clientRegistry';
11
+ import { callStateHasLogData } from '../helpers/callLogMessage';
12
+ import { pushLog } from '../utils/devLogger';
13
+
14
+ // Backend currently doesn't propagate `kind` on the broadcast call-token
15
+ // stanza, both ends default to video unless we tell them otherwise. We
16
+ // work around it by having the dialer send a separate `<data type=
17
+ // "call-invite" kind="..." ... />` direct-chat to the peer right before
18
+ // POST /v1/chats/call/create. The invite arrives over ~50ms direct chat,
19
+ // the call-token relays through the server in ~200-300ms, so the invite
20
+ // almost always lands first. This stash keys the kind hint by callId AND
21
+ // by room bare name (server sometimes drops callId on the token).
22
+ //
23
+ // TTL keeps the map from growing unbounded if a token never arrives.
24
+ const KIND_HINT_TTL_MS = 60_000;
25
+ const kindHints = new Map<
26
+ string,
27
+ { kind: 'audio' | 'video'; expiresAt: number }
28
+ >();
29
+
30
+ const stashKindHint = (
31
+ key: string | null | undefined,
32
+ kind: 'audio' | 'video'
33
+ ) => {
34
+ if (!key) {return;}
35
+ // Cheap cleanup pass, drop expired entries before inserting.
36
+ const now = Date.now();
37
+ for (const [k, v] of kindHints) {
38
+ if (v.expiresAt < now) {kindHints.delete(k);}
39
+ }
40
+ kindHints.set(key, { kind, expiresAt: now + KIND_HINT_TTL_MS });
41
+ };
42
+
43
+ const consumeKindHint = (
44
+ keys: Array<string | null | undefined>
45
+ ): 'audio' | 'video' | null => {
46
+ const now = Date.now();
47
+ for (const key of keys) {
48
+ if (!key) {continue;}
49
+ const hit = kindHints.get(key);
50
+ if (hit && hit.expiresAt >= now) {
51
+ kindHints.delete(key);
52
+ return hit.kind;
53
+ }
54
+ }
55
+ return null;
56
+ };
57
+
58
+ const MAX_CALL_TOKEN_AGE_MS = 5000;
59
+
60
+ // Hermes has no global `atob` and RN ships no Buffer polyfill by default,
61
+ // so the JWT payload is decoded here by hand. Only used on the ~500-byte
62
+ // middle segment of a call token, so a table-driven loop is plenty fast
63
+ // and saves pulling a base64 dependency into the SDK.
64
+ const B64_ALPHABET =
65
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
66
+
67
+ const decodeBase64 = (input: string): string => {
68
+ const clean = input.replace(/[^A-Za-z0-9+/]/g, '');
69
+ let out = '';
70
+ let buffer = 0;
71
+ let bits = 0;
72
+ for (let i = 0; i < clean.length; i++) {
73
+ const idx = B64_ALPHABET.indexOf(clean[i]);
74
+ if (idx === -1) {continue;}
75
+ buffer = (buffer << 6) | idx;
76
+ bits += 6;
77
+ if (bits >= 8) {
78
+ bits -= 8;
79
+ out += String.fromCharCode((buffer >> bits) & 0xff);
80
+ }
81
+ }
82
+ return out;
83
+ };
84
+
85
+ // A JWT payload is UTF-8, and decodeBase64 hands back one char per byte.
86
+ // Re-interpret those bytes as UTF-8 so non-ASCII caller names (accents,
87
+ // Cyrillic) survive instead of turning into mojibake on the ring screen.
88
+ const bytesToUtf8 = (binary: string): string => {
89
+ try {
90
+ return decodeURIComponent(
91
+ binary
92
+ .split('')
93
+ .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
94
+ .join('')
95
+ );
96
+ } catch {
97
+ return binary;
98
+ }
99
+ };
100
+
101
+ // Pull the JWT payload out of the call-token. We only read non-sensitive
102
+ // claims (`sub` = caller display name; `metadata.callId`, `video.room`),
103
+ // no signature verification, which is fine because the server has already
104
+ // vetted the token and LiveKit will reject anything tampered with on
105
+ // connect. Returns null when the token isn't a parseable JWT.
106
+ const decodeJwtPayload = (token: string): Record<string, any> | null => {
107
+ if (!token || typeof token !== 'string') {return null;}
108
+ const parts = token.split('.');
109
+ if (parts.length < 2) {return null;}
110
+ try {
111
+ const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
112
+ const padded = b64 + '='.repeat((4 - (b64.length % 4)) % 4);
113
+ return JSON.parse(bytesToUtf8(decodeBase64(padded))) as Record<string, any>;
114
+ } catch {
115
+ return null;
116
+ }
117
+ };
118
+
119
+ const extractCallId = (
120
+ data: Element,
121
+ jwtPayload: Record<string, any> | null
122
+ ) => {
123
+ const fromAttr = String(data.attrs?.callId || data.attrs?.callid || '').trim();
124
+ if (fromAttr) {return fromAttr;}
125
+ const metadata = jwtPayload?.metadata;
126
+ if (typeof metadata === 'string') {
127
+ try {
128
+ const parsed = JSON.parse(metadata);
129
+ if (parsed?.callId) {return String(parsed.callId);}
130
+ } catch {
131
+ // metadata isn't JSON, ignore
132
+ }
133
+ } else if (metadata && typeof metadata === 'object' && metadata.callId) {
134
+ return String(metadata.callId);
135
+ }
136
+ return null;
137
+ };
138
+
139
+ const extractCallerDisplayName = (
140
+ jwtPayload: Record<string, any> | null
141
+ ): string => {
142
+ const sub = jwtPayload?.sub;
143
+ if (typeof sub !== 'string') {return '';}
144
+ const trimmed = sub.trim();
145
+ if (!trimmed) {return '';}
146
+ // Defense: server occasionally falls back to xmppUsername / userId for
147
+ // `sub` when the caller's profile is incomplete. Those look like raw
148
+ // ID strings (long, no spaces, all alphanumeric with underscores). Skip
149
+ // them so we don't render an opaque ID as the "caller name".
150
+ const looksLikeRawId = /^[0-9a-f_-]{16,}$/i.test(trimmed);
151
+ if (looksLikeRawId) {return '';}
152
+ return trimmed;
153
+ };
154
+
155
+ // Room name format is "<userA>-<userB>" for 1:1 private chats (post
156
+ // /chats/private convention). Derive the peer xmpp localpart by removing
157
+ // the current user's xmpp localpart from the split.
158
+ const derivePeerXmppUsername = (
159
+ bareRoomName: string,
160
+ selfXmppUsername: string
161
+ ): string | null => {
162
+ if (!bareRoomName.includes('-')) {return null;}
163
+ const parts = bareRoomName.split('-');
164
+ if (parts.length !== 2) {return null;}
165
+ const selfLocal = String(selfXmppUsername || '').split('@')[0];
166
+ const peer = parts.find((p) => p && p !== selfLocal);
167
+ return peer || null;
168
+ };
169
+
170
+ // Body-text values the server may use to broadcast call signaling into a
171
+ // MUC room (so other clients without `<data>` parsing still receive the
172
+ // event in their MAM archive). These must NEVER reach `onRealtimeMessage`
173
+ // or they render as chat bubbles / new-message notifications saying
174
+ // "Deleted User: call-state".
175
+ const CALL_BODY_KEYWORDS = new Set([
176
+ 'call-token',
177
+ 'call-state',
178
+ 'call-ringing',
179
+ 'call-ended',
180
+ 'call-declined',
181
+ 'call-cancelled',
182
+ 'call-canceled',
183
+ 'call-timeout',
184
+ 'call-rejected',
185
+ ]);
186
+
187
+ const extractNumericTimestamp = (value?: string): number | null => {
188
+ const source = String(value || '').trim();
189
+ if (!source) {return null;}
190
+
191
+ const direct = Number(source);
192
+ if (Number.isFinite(direct) && direct > 0) {
193
+ return source.length > 13 ? Number(source.slice(0, 13)) : direct;
194
+ }
195
+
196
+ const match = source.match(/\d{13,}/)?.[0];
197
+ if (!match) {return null;}
198
+ return Number(match.slice(0, 13));
199
+ };
200
+
201
+ const isFreshCallToken = (stanza: Element): boolean => {
202
+ const stanzaId = stanza.getChild('stanza-id')?.attrs?.id;
203
+ const createdTs = extractNumericTimestamp(stanzaId);
204
+ if (!createdTs) {return false;}
205
+ return Math.abs(Date.now() - createdTs) <= MAX_CALL_TOKEN_AGE_MS;
206
+ };
207
+
208
+ // Match a call-token stanza's `room` attribute against the local rooms map.
209
+ // The server sends the bare room name (e.g. "${appId}_<uuid>"), but our
210
+ // store keys rooms by full JID, and IRoom.name actually holds the display
211
+ // title (see createRoomFromApi, the API's `name` is mapped onto the JID
212
+ // localpart). So lookup order is: full JID match -> JID-localpart match ->
213
+ // last-resort display-title match (only useful when the server ever decides
214
+ // to send a fully-qualified JID or a title verbatim).
215
+ const resolveRoomByStanzaRoom = (roomAttr: string) => {
216
+ const rooms = (store.getState().rooms.rooms || {}) as Record<
217
+ string,
218
+ { jid?: string; name?: string; type?: string; usersCnt?: number }
219
+ >;
220
+ const roomEntries = Object.values(rooms);
221
+
222
+ const byJid = rooms[roomAttr];
223
+ if (byJid) {return byJid;}
224
+
225
+ const byLocalpart = roomEntries.find(
226
+ (room) => (room?.jid || '').split('@')[0] === roomAttr
227
+ );
228
+ if (byLocalpart) {return byLocalpart;}
229
+
230
+ const byName = roomEntries.find((room) => room?.name === roomAttr);
231
+ if (byName) {return byName;}
232
+
233
+ return null;
234
+ };
235
+
236
+ // Mirror of handleStanzas.unwrapMucsubMessage so we can look at the real
237
+ // payload that the server pushed into the room, mucsub wraps the inner
238
+ // <message> inside <event><items><item>.
239
+ const unwrapMucsub = (stanza: Element): Element => {
240
+ // The web SDK also passes the pubsub#event xmlns here, but the ltx
241
+ // typings bundled with the RN toolchain only declare getChild(name).
242
+ // Matching on the element name alone is enough: the items > item >
243
+ // message chain below fails fast on any other <event>.
244
+ const inner = stanza
245
+ ?.getChild?.('event')
246
+ ?.getChild?.('items')
247
+ ?.getChild?.('item')
248
+ ?.getChild?.('message');
249
+ return (inner as Element) || stanza;
250
+ };
251
+
252
+ const findCallData = (stanza: Element): Element | null => {
253
+ // Direct `<data type="call-*">` on the message. Optional-called for the
254
+ // same reason as onCallTokenMessage's name check: not every stanza that
255
+ // reaches handleStanza is a real ltx Element.
256
+ const direct = stanza?.getChild?.('data');
257
+ if (direct && /^call-/i.test(String(direct.attrs?.type || ''))) {
258
+ return direct;
259
+ }
260
+ return null;
261
+ };
262
+
263
+ const getBodyText = (stanza: Element): string => {
264
+ const body = stanza?.getChild?.('body');
265
+ return String(body?.getText?.() || '').trim();
266
+ };
267
+
268
+ // Tear down the active call overlay in response to a call-state stanza.
269
+ // Two shapes arrive here:
270
+ // 1. Client signaling (sendCallStateSignal): has explicit `state`
271
+ // (cancelled / declined / ended). Terminal -> end.
272
+ // 2. Server call-log: NO `state` attr, but carries `callId` /
273
+ // `durationMs` and is broadcast into the room when the LiveKit room
274
+ // empties. For a 1:1 call that means the other side left -> end.
275
+ // `fallbackRoomAttr` is the bare room name derived from the message's
276
+ // `from` JID (server call-logs don't put `room` on the <data>).
277
+ const handleCallStateData = (
278
+ data: Element,
279
+ fallbackRoomAttr?: string
280
+ ): void => {
281
+ const state = String(
282
+ data.attrs?.state || data.attrs?.event || ''
283
+ ).toLowerCase();
284
+ const stanzaRoomAttr =
285
+ String(data.attrs?.room || '').trim() || (fallbackRoomAttr || '');
286
+ const stanzaCallId = String(
287
+ data.attrs?.callId || data.attrs?.callid || ''
288
+ ).trim();
289
+ const currentCall = store.getState().call;
290
+
291
+ if (currentCall.phase === 'idle') {return;}
292
+
293
+ const roomMatches =
294
+ !!stanzaRoomAttr &&
295
+ (currentCall.roomJid === stanzaRoomAttr ||
296
+ currentCall.roomName === stanzaRoomAttr ||
297
+ currentCall.roomBareName === stanzaRoomAttr ||
298
+ (currentCall.roomJid || '').split('@')[0] === stanzaRoomAttr);
299
+ const callIdMatches =
300
+ !!stanzaCallId &&
301
+ !!currentCall.callId &&
302
+ currentCall.callId === stanzaCallId;
303
+
304
+ const isTerminalState =
305
+ state === 'ended' ||
306
+ state === 'declined' ||
307
+ state === 'cancelled' ||
308
+ state === 'canceled' ||
309
+ state === 'timeout' ||
310
+ state === 'rejected';
311
+
312
+ // A server call-log (no explicit state, but with callId/duration) is
313
+ // itself a "session concluded" signal.
314
+ const isServerCallLog = !state && callStateHasLogData(data.attrs || {});
315
+
316
+ if ((roomMatches || callIdMatches) && (isTerminalState || isServerCallLog)) {
317
+ store.dispatch(endCall());
318
+ }
319
+ };
320
+
321
+ export const onCallTokenMessage = (stanza: Element): boolean => {
322
+ // The web SDK calls `stanza.is('message')`. Here we read `.name`
323
+ // directly: handleStanza is also fed plain stanza-shaped objects (test
324
+ // fixtures, and the mucsub inner payloads we synthesize below), and
325
+ // `.is` only exists on real ltx Elements. Name equality is what `.is`
326
+ // checks anyway for a stanza with no explicit xmlns.
327
+ if (stanza?.name !== 'message') {
328
+ return false;
329
+ }
330
+
331
+ // 1. Unwrap mucsub wrappers so server broadcasts into the MUC archive
332
+ // are inspected the same way as direct chat stanzas.
333
+ const inner = unwrapMucsub(stanza);
334
+
335
+ // 2. Anything carrying a `<data type="call-*">` element is signaling, no
336
+ // matter the message type (chat / groupchat / headline), swallow it
337
+ // before any chat / history / notification handler touches it.
338
+ const data = findCallData(inner);
339
+ if (data) {
340
+ const dataType = String(data.attrs?.type || '').toLowerCase();
341
+
342
+ if (dataType === 'call-state') {
343
+ // Surface the raw call-state attrs so we can confirm what the server
344
+ // sends for durationMs / callerXmppUsername during QA.
345
+ try {
346
+ pushLog('xmpp', '[call-state] received', {
347
+ callId: data.attrs?.callId,
348
+ durationMs: data.attrs?.durationMs,
349
+ state: data.attrs?.state,
350
+ callerXmppUsername: data.attrs?.callerXmppUsername,
351
+ from: stanza.attrs?.from,
352
+ });
353
+ } catch {
354
+ /* noop */
355
+ }
356
+
357
+ // The server call-log doesn't put `room` on the <data>; derive it
358
+ // from the message's `from` MUC JID localpart instead.
359
+ const fromRoom = String(stanza.attrs?.from || '')
360
+ .split('/')[0]
361
+ .split('@')[0]
362
+ .trim();
363
+ handleCallStateData(inner, fromRoom);
364
+
365
+ // Server call-logs (carry callerXmppUsername / durationMs) should
366
+ // flow on to onRealtimeMessage / onMessageHistory where they become
367
+ // a friendly "Outgoing call · 12 sec" entry. Bare client-side
368
+ // signaling frames (state=cancelled/declined, no log data) are
369
+ // swallowed, they exist only to tear the overlay down.
370
+ if (callStateHasLogData(data.attrs || {})) {
371
+ return false;
372
+ }
373
+ return true;
374
+ }
375
+
376
+ if (dataType === 'call-invite') {
377
+ const inviteKind = String(data.attrs?.kind || '').toLowerCase();
378
+ const normalized: 'audio' | 'video' =
379
+ inviteKind === 'audio' ? 'audio' : 'video';
380
+ const inviteRoom = String(data.attrs?.room || '').trim() || null;
381
+ const inviteCallId =
382
+ String(data.attrs?.callId || data.attrs?.callid || '').trim() || null;
383
+
384
+ // Stash for the upcoming call-token lookup AND patch any existing
385
+ // call state if the token actually arrived first (rare race).
386
+ stashKindHint(inviteRoom, normalized);
387
+ stashKindHint(inviteCallId, normalized);
388
+
389
+ const currentCall = store.getState().call;
390
+ const matchesActive =
391
+ currentCall.phase !== 'idle' &&
392
+ ((!!inviteRoom &&
393
+ (currentCall.roomBareName === inviteRoom ||
394
+ currentCall.roomJid === inviteRoom ||
395
+ (currentCall.roomJid || '').split('@')[0] === inviteRoom)) ||
396
+ (!!inviteCallId && currentCall.callId === inviteCallId));
397
+ if (matchesActive && currentCall.kind !== normalized) {
398
+ store.dispatch(setCallKind(normalized));
399
+ }
400
+ return true;
401
+ }
402
+
403
+ if (dataType === 'call-token') {
404
+ const videoCallsConfig =
405
+ store.getState().chatSettingStore.config?.videoCalls;
406
+ if (videoCallsConfig?.enabled !== true) {
407
+ return true;
408
+ }
409
+ if (!isFreshCallToken(inner)) {
410
+ return true;
411
+ }
412
+
413
+ const token = String(data.attrs?.token || '').trim();
414
+ const stanzaRoom = String(data.attrs?.room || '').trim();
415
+ const stanzaKind = String(data.attrs?.kind || '').toLowerCase();
416
+ const stanzaCallId =
417
+ String(data.attrs?.callId || data.attrs?.callid || '').trim() || null;
418
+ // Server doesn't propagate `kind` on the broadcast stanza, so first
419
+ // look for a client-side `call-invite` hint we stashed when the
420
+ // dialer signaled us directly. Falls back to whatever the server
421
+ // happens to attach, finally to video (legacy default).
422
+ const hintedKind = consumeKindHint([stanzaRoom, stanzaCallId]);
423
+ const kind: 'audio' | 'video' =
424
+ hintedKind || (stanzaKind === 'audio' ? 'audio' : 'video');
425
+ if (!token || !stanzaRoom) {
426
+ return true;
427
+ }
428
+
429
+ const resolvedRoom = resolveRoomByStanzaRoom(stanzaRoom);
430
+ const allowedRoomTypes = videoCallsConfig.allowedRoomTypes || ['private'];
431
+ const usersCnt = Number(resolvedRoom?.usersCnt || 0);
432
+ const isOneToOneLikeRoom = usersCnt > 0 && usersCnt <= 2;
433
+ const isPrivateAllowed = allowedRoomTypes.includes('private');
434
+ if (
435
+ resolvedRoom?.type &&
436
+ resolvedRoom.type !== 'private' &&
437
+ !isOneToOneLikeRoom
438
+ ) {
439
+ return true;
440
+ }
441
+ if (resolvedRoom?.type === 'private' && !isPrivateAllowed) {
442
+ return true;
443
+ }
444
+ if (
445
+ !resolvedRoom?.type &&
446
+ !stanzaRoom.includes('@') &&
447
+ !isOneToOneLikeRoom
448
+ ) {
449
+ return true;
450
+ }
451
+
452
+ const roomJid =
453
+ resolvedRoom?.jid || (stanzaRoom.includes('@') ? stanzaRoom : '');
454
+ // Prefer the JWT `sub` claim as the display name on the incoming
455
+ // ring screen, the server populates it with the caller's full name
456
+ // ("Roman Test") which is far more useful than the resolved room
457
+ // title (which for stale / deleted-peer chats reads "deleted").
458
+ const jwtPayload = decodeJwtPayload(token);
459
+ const callerName = extractCallerDisplayName(jwtPayload);
460
+ const resolvedTitle = String(resolvedRoom?.name || '').trim();
461
+ const titleLooksBad =
462
+ !resolvedTitle ||
463
+ ['deleted', 'deleted user', 'unknown', 'null'].includes(
464
+ resolvedTitle.toLowerCase()
465
+ );
466
+ const incomingRoomName =
467
+ (callerName && titleLooksBad ? callerName : resolvedTitle) ||
468
+ callerName ||
469
+ stanzaRoom;
470
+ if (!roomJid) {return true;}
471
+
472
+ const callId = extractCallId(data, jwtPayload);
473
+ const selfXmpp =
474
+ store.getState().chatSettingStore.user?.xmppUsername || '';
475
+ const peerXmppUsername = derivePeerXmppUsername(stanzaRoom, selfXmpp);
476
+
477
+ const callState = store.getState().call;
478
+ const isOutgoingRoomMatch =
479
+ callState.direction === 'outgoing' &&
480
+ (callState.roomJid === roomJid ||
481
+ callState.roomName === incomingRoomName ||
482
+ callState.roomBareName === stanzaRoom);
483
+
484
+ if (isOutgoingRoomMatch) {
485
+ store.dispatch(
486
+ setOutgoingCallToken({ roomJid, token, callId: callId || null })
487
+ );
488
+ return true;
489
+ }
490
+
491
+ store.dispatch(
492
+ setIncomingCallToken({
493
+ roomJid,
494
+ roomName: incomingRoomName,
495
+ roomBareName: stanzaRoom,
496
+ token,
497
+ kind,
498
+ callId: callId || null,
499
+ peerXmppUsername: peerXmppUsername || null,
500
+ })
501
+ );
502
+ return true;
503
+ }
504
+
505
+ // Unknown `call-*` signaling, swallow so it never lands in chat.
506
+ return true;
507
+ }
508
+
509
+ // 3. Backstop for legacy servers / clients that broadcast the signal as
510
+ // plain body text (no `<data>` element). The body literally reads
511
+ // "call-state" / "call-token" / etc. Drop these so the chat list
512
+ // and the notification toast never display them.
513
+ const bodyText = getBodyText(inner).toLowerCase();
514
+ if (bodyText && CALL_BODY_KEYWORDS.has(bodyText)) {
515
+ if (bodyText.startsWith('call-')) {
516
+ const stateFromBody = bodyText.replace(/^call-/, '');
517
+ // Treat the body-only variant as a state notification; tear down
518
+ // active call on terminal transitions, ignore otherwise.
519
+ handleCallStateData({
520
+ attrs: { state: stateFromBody, room: '' },
521
+ } as unknown as Element);
522
+ }
523
+ return true;
524
+ }
525
+
526
+ return false;
527
+ };
528
+
529
+ // Outbound counterpart of the swallow logic above. When the local user
530
+ // hangs up, cancels their own dial, or declines an incoming ring we send
531
+ // a `call-state` stanza to the peer so their UI dismisses instead of
532
+ // dangling on a phantom "incoming call" or "calling..." screen.
533
+ //
534
+ // We address the peer directly (`<message type="chat" to="<peer>@<host>">`),
535
+ // going through the room JID isn't reliable because the callee may not
536
+ // have joined the MUC yet during the ring window. The receiving client's
537
+ // onCallTokenMessage handler picks up the same `<data type="call-state">`
538
+ // it would receive from the server and dispatches `endCall()`.
539
+ export type CallSignalState = 'ended' | 'declined' | 'cancelled' | 'rejected';
540
+
541
+ export const sendCallStateSignal = (
542
+ state: CallSignalState,
543
+ options?: {
544
+ peerXmppUsername?: string | null;
545
+ callId?: string | null;
546
+ roomBareName?: string | null;
547
+ }
548
+ ): void => {
549
+ const xmppClient = getGlobalXmppClient();
550
+ if (!xmppClient) {return;}
551
+
552
+ const callState = store.getState().call;
553
+ const peer = (
554
+ options?.peerXmppUsername ||
555
+ callState.peerXmppUsername ||
556
+ ''
557
+ ).trim();
558
+ if (!peer) {return;}
559
+
560
+ const host = (xmppClient as any).host || '';
561
+ if (!host) {return;}
562
+
563
+ const callId = options?.callId || callState.callId || '';
564
+ const room =
565
+ options?.roomBareName ||
566
+ callState.roomBareName ||
567
+ (callState.roomJid || '').split('@')[0] ||
568
+ '';
569
+
570
+ try {
571
+ const stanza = xml(
572
+ 'message',
573
+ {
574
+ to: peer.includes('@') ? peer : `${peer}@${host}`,
575
+ type: 'chat',
576
+ id: `call-state-${Date.now()}`,
577
+ },
578
+ xml('data', {
579
+ type: 'call-state',
580
+ state,
581
+ callId,
582
+ room,
583
+ })
584
+ );
585
+ (xmppClient as any).client?.send?.(stanza);
586
+ } catch {
587
+ // Swallow, signaling is best-effort. The LiveKit room disconnect
588
+ // also serves as an implicit "call ended" once both sides are in.
589
+ }
590
+ };
591
+
592
+ // Tell the peer what KIND of call we're starting before the server-side
593
+ // call-token stanza reaches them, the backend currently drops the kind
594
+ // attribute on its broadcast, so without this the callee always lands on
595
+ // the video UI even when the dialer chose audio.
596
+ //
597
+ // Sent right before POST /v1/chats/call/create, addressed directly to
598
+ // the peer's bare JID. Receiver swallows it via onCallTokenMessage and
599
+ // stashes the kind hint for the upcoming call-token lookup.
600
+ export const sendCallInviteSignal = (
601
+ kind: 'audio' | 'video',
602
+ options: {
603
+ peerXmppUsername: string;
604
+ roomBareName: string;
605
+ callId?: string | null;
606
+ }
607
+ ): void => {
608
+ const xmppClient = getGlobalXmppClient();
609
+ if (!xmppClient) {return;}
610
+ const peer = String(options.peerXmppUsername || '').trim();
611
+ if (!peer) {return;}
612
+ const host = (xmppClient as any).host || '';
613
+ if (!host) {return;}
614
+
615
+ try {
616
+ const stanza = xml(
617
+ 'message',
618
+ {
619
+ to: peer.includes('@') ? peer : `${peer}@${host}`,
620
+ type: 'chat',
621
+ id: `call-invite-${Date.now()}`,
622
+ },
623
+ xml('data', {
624
+ type: 'call-invite',
625
+ kind,
626
+ room: options.roomBareName || '',
627
+ callId: options.callId || '',
628
+ })
629
+ );
630
+ (xmppClient as any).client?.send?.(stanza);
631
+ } catch {
632
+ // Best-effort: missing the hint just means the callee starts on the
633
+ // video UI and the dialer's audio publish auto-corrects once both
634
+ // join LiveKit (UI flicker, not a functional failure).
635
+ }
636
+ };
@@ -28,6 +28,7 @@
28
28
 
29
29
  export interface OutboundQueueClient {
30
30
  sendMessage: (...args: any[]) => any;
31
+ sendTextMessageWithTranslateTagStanza: (...args: any[]) => any;
31
32
  sendMediaMessageStanza: (...args: any[]) => any;
32
33
  }
33
34