@ethora/chat-component-rn 26.10.1 → 26.10.3

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 (145) hide show
  1. package/lib/commonjs/components/MainComponents/ChatHeader.js +11 -10
  2. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  3. package/lib/commonjs/components/MainComponents/MessageContainer.js +10 -2
  4. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  5. package/lib/commonjs/components/MainComponents/RoomList.js +8 -18
  6. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  7. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +17 -14
  8. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  9. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +131 -17
  10. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  11. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +6 -1
  12. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  13. package/lib/commonjs/components/VideoCalls/CallButtons.js +3 -1
  14. package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -1
  15. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +123 -111
  16. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  17. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +207 -346
  18. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
  19. package/lib/commonjs/components/VideoCalls/callActions.js +61 -0
  20. package/lib/commonjs/components/VideoCalls/callActions.js.map +1 -0
  21. package/lib/commonjs/components/VideoCalls/callSessionController.js +431 -0
  22. package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -0
  23. package/lib/commonjs/components/VideoCalls/useDraggable.js +59 -0
  24. package/lib/commonjs/components/VideoCalls/useDraggable.js.map +1 -0
  25. package/lib/commonjs/helpers/createRoomFromApi.js +4 -0
  26. package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
  27. package/lib/commonjs/helpers/incomingCallFromPush.js +1 -1
  28. package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -1
  29. package/lib/commonjs/helpers/roomUserCount.js +7 -1
  30. package/lib/commonjs/helpers/roomUserCount.js.map +1 -1
  31. package/lib/commonjs/helpers/uniqueMembers.js +36 -0
  32. package/lib/commonjs/helpers/uniqueMembers.js.map +1 -0
  33. package/lib/commonjs/hooks/useLeaveRoom.js +52 -0
  34. package/lib/commonjs/hooks/useLeaveRoom.js.map +1 -0
  35. package/lib/commonjs/hooks/useLogout.js +15 -10
  36. package/lib/commonjs/hooks/useLogout.js.map +1 -1
  37. package/lib/commonjs/i18n/strings.js +18 -0
  38. package/lib/commonjs/i18n/strings.js.map +1 -1
  39. package/lib/commonjs/networking/api-requests/rooms.api.js +36 -1
  40. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  41. package/lib/commonjs/networking/callTokenStanza.js +47 -3
  42. package/lib/commonjs/networking/callTokenStanza.js.map +1 -1
  43. package/lib/commonjs/networking/xmppClient.js +9 -2
  44. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  45. package/lib/commonjs/version.js +1 -1
  46. package/lib/module/components/MainComponents/ChatHeader.js +13 -12
  47. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  48. package/lib/module/components/MainComponents/MessageContainer.js +10 -2
  49. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  50. package/lib/module/components/MainComponents/RoomList.js +8 -18
  51. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  52. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +18 -15
  53. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  54. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +132 -18
  55. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  56. package/lib/module/components/RoomComponents/ChatRoomItem.js +6 -1
  57. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  58. package/lib/module/components/VideoCalls/CallButtons.js +3 -1
  59. package/lib/module/components/VideoCalls/CallButtons.js.map +1 -1
  60. package/lib/module/components/VideoCalls/VideoCallOverlay.js +125 -113
  61. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  62. package/lib/module/components/VideoCalls/VideoCallSession.js +208 -348
  63. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
  64. package/lib/module/components/VideoCalls/callActions.js +55 -0
  65. package/lib/module/components/VideoCalls/callActions.js.map +1 -0
  66. package/lib/module/components/VideoCalls/callSessionController.js +420 -0
  67. package/lib/module/components/VideoCalls/callSessionController.js.map +1 -0
  68. package/lib/module/components/VideoCalls/useDraggable.js +55 -0
  69. package/lib/module/components/VideoCalls/useDraggable.js.map +1 -0
  70. package/lib/module/helpers/createRoomFromApi.js +4 -0
  71. package/lib/module/helpers/createRoomFromApi.js.map +1 -1
  72. package/lib/module/helpers/incomingCallFromPush.js +1 -1
  73. package/lib/module/helpers/incomingCallFromPush.js.map +1 -1
  74. package/lib/module/helpers/roomUserCount.js +7 -1
  75. package/lib/module/helpers/roomUserCount.js.map +1 -1
  76. package/lib/module/helpers/uniqueMembers.js +31 -0
  77. package/lib/module/helpers/uniqueMembers.js.map +1 -0
  78. package/lib/module/hooks/useLeaveRoom.js +48 -0
  79. package/lib/module/hooks/useLeaveRoom.js.map +1 -0
  80. package/lib/module/hooks/useLogout.js +15 -10
  81. package/lib/module/hooks/useLogout.js.map +1 -1
  82. package/lib/module/i18n/strings.js +18 -0
  83. package/lib/module/i18n/strings.js.map +1 -1
  84. package/lib/module/networking/api-requests/rooms.api.js +35 -1
  85. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  86. package/lib/module/networking/callTokenStanza.js +47 -3
  87. package/lib/module/networking/callTokenStanza.js.map +1 -1
  88. package/lib/module/networking/xmppClient.js +8 -1
  89. package/lib/module/networking/xmppClient.js.map +1 -1
  90. package/lib/module/version.js +1 -1
  91. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  92. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  93. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  94. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  95. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  96. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  97. package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -1
  98. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts +0 -6
  99. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
  100. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +9 -20
  101. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
  102. package/lib/typescript/components/VideoCalls/callActions.d.ts +15 -0
  103. package/lib/typescript/components/VideoCalls/callActions.d.ts.map +1 -0
  104. package/lib/typescript/components/VideoCalls/callSessionController.d.ts +61 -0
  105. package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -0
  106. package/lib/typescript/components/VideoCalls/useDraggable.d.ts +19 -0
  107. package/lib/typescript/components/VideoCalls/useDraggable.d.ts.map +1 -0
  108. package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
  109. package/lib/typescript/helpers/roomUserCount.d.ts +1 -0
  110. package/lib/typescript/helpers/roomUserCount.d.ts.map +1 -1
  111. package/lib/typescript/helpers/uniqueMembers.d.ts +11 -0
  112. package/lib/typescript/helpers/uniqueMembers.d.ts.map +1 -0
  113. package/lib/typescript/hooks/useLeaveRoom.d.ts +9 -0
  114. package/lib/typescript/hooks/useLeaveRoom.d.ts.map +1 -0
  115. package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
  116. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  117. package/lib/typescript/networking/api-requests/rooms.api.d.ts +8 -0
  118. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  119. package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -1
  120. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  121. package/lib/typescript/version.d.ts +1 -1
  122. package/package.json +1 -1
  123. package/src/components/MainComponents/ChatHeader.tsx +10 -8
  124. package/src/components/MainComponents/MessageContainer.tsx +14 -1
  125. package/src/components/MainComponents/RoomList.tsx +8 -14
  126. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +16 -13
  127. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +167 -36
  128. package/src/components/RoomComponents/ChatRoomItem.tsx +8 -1
  129. package/src/components/VideoCalls/CallButtons.tsx +5 -1
  130. package/src/components/VideoCalls/VideoCallOverlay.tsx +156 -163
  131. package/src/components/VideoCalls/VideoCallSession.tsx +207 -378
  132. package/src/components/VideoCalls/callActions.ts +63 -0
  133. package/src/components/VideoCalls/callSessionController.ts +421 -0
  134. package/src/components/VideoCalls/useDraggable.ts +46 -0
  135. package/src/helpers/createRoomFromApi.tsx +2 -0
  136. package/src/helpers/incomingCallFromPush.ts +2 -2
  137. package/src/helpers/roomUserCount.ts +6 -2
  138. package/src/helpers/uniqueMembers.ts +26 -0
  139. package/src/hooks/useLeaveRoom.ts +42 -0
  140. package/src/hooks/useLogout.tsx +15 -10
  141. package/src/i18n/strings.ts +18 -0
  142. package/src/networking/api-requests/rooms.api.ts +28 -1
  143. package/src/networking/callTokenStanza.ts +46 -6
  144. package/src/networking/xmppClient.ts +10 -1
  145. package/src/version.ts +1 -1
@@ -50,7 +50,18 @@ const logoutService = {
50
50
  * AFTER all the disk work has actually landed.
51
51
  */
52
52
  performLogout: async (): Promise<void> => {
53
- // 0. Flush lastViewedTimestamp to the server's private store BEFORE
53
+ // 0. Push. Release the device-token registration on the backend
54
+ // FIRST, while the access token is still valid (the token itself
55
+ // is kept so the next login re-registers it). It runs alongside
56
+ // the private-store flush below instead of after it: the flush
57
+ // can take up to 2s, and a host with a logout time budget could
58
+ // cut us off before the release went out, leaving the device
59
+ // receiving pushes for the logged-out user.
60
+ const pushRelease = releasePushRegistration().catch((e) => {
61
+ console.warn('logoutService: push release failed', e);
62
+ });
63
+
64
+ // 0a. Flush lastViewedTimestamp to the server's private store BEFORE
54
65
  // we close XMPP. Only rooms with no outstanding unread (plus the
55
66
  // visible room) get their entries updated — rooms with unread
56
67
  // keep their old marker so the next login still surfaces those
@@ -95,15 +106,9 @@ const logoutService = {
95
106
  /* non-fatal */
96
107
  }
97
108
 
98
- // 2. Push. Release the device-token registration on the backend
99
- // while the access token is still valid (the token itself is kept
100
- // so the next login re-registers it), then clear the local MucSub
101
- // room cache.
102
- try {
103
- await releasePushRegistration();
104
- } catch (e) {
105
- console.warn('logoutService: push release failed', e);
106
- }
109
+ // 2. Push. Wait for the release started in step 0, then clear the
110
+ // local MucSub room cache.
111
+ await pushRelease;
107
112
  try {
108
113
  await pushSubscriptionService.reset();
109
114
  } catch (e) {
@@ -128,6 +128,8 @@ const en: UiStringTable = {
128
128
  'call.error.deviceInUse': 'Your camera or microphone is already in use by another app.',
129
129
  'call.error.deviceGeneric': 'Could not access your camera or microphone.',
130
130
  'call.error.noAnswerTimeout': 'No answer, the call timed out',
131
+ 'call.peerMuted': '{name} is muted',
132
+ 'call.selfMuted': 'Your microphone is muted',
131
133
  'action.send': 'Send',
132
134
  'action.cancel': 'Cancel',
133
135
  'action.save': 'Save',
@@ -138,6 +140,7 @@ const en: UiStringTable = {
138
140
  'action.mute': 'Mute',
139
141
  'action.unmute': 'Unmute',
140
142
  'toast.muteFailed': 'Could not update notifications for this chat',
143
+ 'toast.leaveFailed': 'Could not leave this chat',
141
144
  'action.create': 'Create',
142
145
  'action.submit': 'Submit',
143
146
  'action.translate': 'Translate',
@@ -505,6 +508,8 @@ const fr: UiStringTable = {
505
508
  'call.error.deviceInUse': 'Votre caméra ou microphone est déjà utilisé par une autre application.',
506
509
  'call.error.deviceGeneric': 'Impossible d\'accéder à votre caméra ou microphone.',
507
510
  'call.error.noAnswerTimeout': 'Pas de réponse, l\'appel a expiré',
511
+ 'call.peerMuted': '{name} a coupé son micro',
512
+ 'call.selfMuted': 'Votre micro est coupé',
508
513
  'action.send': 'Envoyer',
509
514
  'action.cancel': 'Annuler',
510
515
  'action.save': 'Enregistrer',
@@ -515,6 +520,7 @@ const fr: UiStringTable = {
515
520
  'action.mute': 'Muet',
516
521
  'action.unmute': 'Réactiver',
517
522
  'toast.muteFailed': 'Impossible de modifier les notifications de ce chat',
523
+ 'toast.leaveFailed': 'Impossible de quitter ce chat',
518
524
  'action.create': 'Créer',
519
525
  'action.submit': 'Soumettre',
520
526
  'action.translate': 'Traduire',
@@ -882,6 +888,8 @@ const es: UiStringTable = {
882
888
  'call.error.deviceInUse': 'Tu cámara o micrófono ya está siendo usado por otra aplicación.',
883
889
  'call.error.deviceGeneric': 'No se pudo acceder a tu cámara o micrófono.',
884
890
  'call.error.noAnswerTimeout': 'Sin respuesta, la llamada expiró',
891
+ 'call.peerMuted': '{name} tiene el micrófono silenciado',
892
+ 'call.selfMuted': 'Tu micrófono está silenciado',
885
893
  'action.send': 'Enviar',
886
894
  'action.cancel': 'Cancelar',
887
895
  'action.save': 'Guardar',
@@ -892,6 +900,7 @@ const es: UiStringTable = {
892
900
  'action.mute': 'Silenciar',
893
901
  'action.unmute': 'Activar',
894
902
  'toast.muteFailed': 'No se pudieron cambiar las notificaciones de este chat',
903
+ 'toast.leaveFailed': 'No se pudo salir de este chat',
895
904
  'action.create': 'Crear',
896
905
  'action.submit': 'Enviar',
897
906
  'action.translate': 'Traducir',
@@ -1259,6 +1268,8 @@ const pt: UiStringTable = {
1259
1268
  'call.error.deviceInUse': 'A sua câmara ou microfone já está a ser utilizado por outra aplicação.',
1260
1269
  'call.error.deviceGeneric': 'Não foi possível aceder à câmara ou microfone.',
1261
1270
  'call.error.noAnswerTimeout': 'Sem resposta, a chamada expirou',
1271
+ 'call.peerMuted': '{name} está com o microfone desativado',
1272
+ 'call.selfMuted': 'Seu microfone está desativado',
1262
1273
  'action.send': 'Enviar',
1263
1274
  'action.cancel': 'Cancelar',
1264
1275
  'action.save': 'Guardar',
@@ -1269,6 +1280,7 @@ const pt: UiStringTable = {
1269
1280
  'action.mute': 'Silenciar',
1270
1281
  'action.unmute': 'Ativar som',
1271
1282
  'toast.muteFailed': 'Could not update notifications for this chat',
1283
+ 'toast.leaveFailed': 'Não foi possível sair deste chat',
1272
1284
  'action.create': 'Criar',
1273
1285
  'action.submit': 'Enviar',
1274
1286
  'action.translate': 'Traduzir',
@@ -1636,6 +1648,8 @@ const ht: UiStringTable = {
1636
1648
  'call.error.deviceInUse': 'Kamera oswa mikwofòn ou deja ap itilize pa yon lòt app.',
1637
1649
  'call.error.deviceGeneric': 'Nou pa t kapab jwenn aksè nan kamera oswa mikwofòn ou.',
1638
1650
  'call.error.noAnswerTimeout': 'Pa gen repons, apèl la fini',
1651
+ 'call.peerMuted': '{name} koupe mikwo li',
1652
+ 'call.selfMuted': 'Mikwo ou koupe',
1639
1653
  'action.send': 'Voye',
1640
1654
  'action.cancel': 'Anile',
1641
1655
  'action.save': 'Anrejistre',
@@ -1646,6 +1660,7 @@ const ht: UiStringTable = {
1646
1660
  'action.mute': 'Mete an silans',
1647
1661
  'action.unmute': 'Retire silans',
1648
1662
  'toast.muteFailed': 'Could not update notifications for this chat',
1663
+ 'toast.leaveFailed': 'Pa t kapab kite chat sa a',
1649
1664
  'action.create': 'Kreye',
1650
1665
  'action.submit': 'Soumèt',
1651
1666
  'action.translate': 'Tradui',
@@ -2013,6 +2028,8 @@ const zh: UiStringTable = {
2013
2028
  'call.error.deviceInUse': '您的摄像头或麦克风正被其他应用占用。',
2014
2029
  'call.error.deviceGeneric': '无法访问您的摄像头或麦克风。',
2015
2030
  'call.error.noAnswerTimeout': '无人接听,通话已超时',
2031
+ 'call.peerMuted': '{name} 已静音',
2032
+ 'call.selfMuted': '你的麦克风已静音',
2016
2033
  'action.send': '发送',
2017
2034
  'action.cancel': '取消',
2018
2035
  'action.save': '保存',
@@ -2023,6 +2040,7 @@ const zh: UiStringTable = {
2023
2040
  'action.mute': '静音',
2024
2041
  'action.unmute': '取消静音',
2025
2042
  'toast.muteFailed': 'Could not update notifications for this chat',
2043
+ 'toast.leaveFailed': '无法退出此聊天',
2026
2044
  'action.create': '创建',
2027
2045
  'action.submit': '提交',
2028
2046
  'action.translate': '翻译',
@@ -1,4 +1,5 @@
1
1
  import { ApiRoom, DeleteRoomMember, PostAddRoomMember, PostReportRoom, PostRoom, RoomMember } from '../../types/models/room.model';
2
+ import { uniqueMembers } from '../../helpers/uniqueMembers';
2
3
  import { store } from '../../roomStore';
3
4
  import { addRoom, mergeUsersSet, updateRoom } from '../../roomStore/roomsSlice';
4
5
  import { IRoom } from '../../types/types';
@@ -118,7 +119,7 @@ export function ownAppId(): string {
118
119
 
119
120
  const toRoomMembers = (members: any[] | undefined): RoomMember[] => {
120
121
  const known = (store.getState().rooms?.usersSet || {}) as Record<string, RoomMember>;
121
- return (members || []).map((m: any) => ({
122
+ return uniqueMembers(members).map((m: any) => ({
122
123
  firstName: m.firstName,
123
124
  lastName: m.lastName,
124
125
  profileImage:
@@ -495,6 +496,32 @@ export async function deleteRoomMember(data: DeleteRoomMember) {
495
496
  }
496
497
  }
497
498
 
499
+ /**
500
+ * Take the signed-in user out of a chat on the server (self-removal via the
501
+ * same endpoint that removes other members). The unavailable presence alone
502
+ * only leaves the MUC for this session: the backend keeps the user in
503
+ * `members` and the next /chats/my brings the chat back. A 404 means the
504
+ * server already has us out, which is what we wanted.
505
+ */
506
+ export async function leaveRoom(chatName: string): Promise<void> {
507
+ const me = (store.getState().chatSettingStore?.user?.xmppUsername || '').split('@')[0];
508
+ if (!chatName || !me) {
509
+ throw new Error('Cannot leave the chat: no chat name or user');
510
+ }
511
+ const token = store.getState().chatSettingStore.user.token || '';
512
+ invalidateRoomsCache();
513
+ try {
514
+ await http.delete('/v1/chats/users-access', {
515
+ headers: { Authorization: token },
516
+ data: { chatName, members: [me] },
517
+ });
518
+ } catch (error: any) {
519
+ if (error?.response?.status !== 404) {throw error;}
520
+ } finally {
521
+ invalidateRoomsCache();
522
+ }
523
+ }
524
+
498
525
  export async function deleteRoom(name: string) {
499
526
  const token = store.getState().chatSettingStore.user.token || '';
500
527
 
@@ -57,6 +57,15 @@ const consumeKindHint = (
57
57
 
58
58
  const MAX_CALL_TOKEN_AGE_MS = 5000;
59
59
 
60
+ // Dev-only trace of call signalling: which `<data type="call-*">` frames
61
+ // arrive and why a call-token was dropped. A dropped token is silent
62
+ // otherwise: the caller sits on "Calling..." and the callee never rings.
63
+ const callTrace = (message: string, extra?: Record<string, unknown>) => {
64
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
65
+ console.log(`[calls] ${message}`, extra ? JSON.stringify(extra) : '');
66
+ }
67
+ };
68
+
60
69
  // Hermes has no global `atob` and RN ships no Buffer polyfill by default,
61
70
  // so the JWT payload is decoded here by hand. Only used on the ~500-byte
62
71
  // middle segment of a call token, so a table-driven loop is plenty fast
@@ -215,7 +224,7 @@ const isFreshCallToken = (stanza: Element): boolean => {
215
224
  const resolveRoomByStanzaRoom = (roomAttr: string) => {
216
225
  const rooms = (store.getState().rooms.rooms || {}) as Record<
217
226
  string,
218
- { jid?: string; name?: string; type?: string; usersCnt?: number }
227
+ { jid?: string; name?: string; title?: string; type?: string; usersCnt?: number }
219
228
  >;
220
229
  const roomEntries = Object.values(rooms);
221
230
 
@@ -338,6 +347,18 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
338
347
  const data = findCallData(inner);
339
348
  if (data) {
340
349
  const dataType = String(data.attrs?.type || '').toLowerCase();
350
+ const traceStanzaId = inner.getChild?.('stanza-id')?.attrs?.id;
351
+ const traceTs = extractNumericTimestamp(traceStanzaId);
352
+ callTrace(`received ${dataType}`, {
353
+ from: stanza.attrs?.from,
354
+ type: stanza.attrs?.type,
355
+ wrapped: inner !== stanza,
356
+ room: data.attrs?.room,
357
+ callId: data.attrs?.callId || data.attrs?.callid,
358
+ hasToken: !!data.attrs?.token,
359
+ stanzaId: traceStanzaId,
360
+ ageMs: traceTs ? Date.now() - traceTs : null,
361
+ });
341
362
 
342
363
  if (dataType === 'call-state') {
343
364
  // Surface the raw call-state attrs so we can confirm what the server
@@ -404,9 +425,11 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
404
425
  const videoCallsConfig =
405
426
  store.getState().chatSettingStore.config?.videoCalls;
406
427
  if (videoCallsConfig?.enabled !== true) {
428
+ callTrace('drop call-token: calls disabled');
407
429
  return true;
408
430
  }
409
431
  if (!isFreshCallToken(inner)) {
432
+ callTrace('drop call-token: not fresh');
410
433
  return true;
411
434
  }
412
435
 
@@ -423,6 +446,7 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
423
446
  const kind: 'audio' | 'video' =
424
447
  hintedKind || (stanzaKind === 'audio' ? 'audio' : 'video');
425
448
  if (!token || !stanzaRoom) {
449
+ callTrace('drop call-token: no token or room');
426
450
  return true;
427
451
  }
428
452
 
@@ -436,9 +460,11 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
436
460
  resolvedRoom.type !== 'private' &&
437
461
  !isOneToOneLikeRoom
438
462
  ) {
463
+ callTrace('drop call-token: room type', { type: resolvedRoom.type, usersCnt });
439
464
  return true;
440
465
  }
441
466
  if (resolvedRoom?.type === 'private' && !isPrivateAllowed) {
467
+ callTrace('drop call-token: private not allowed');
442
468
  return true;
443
469
  }
444
470
  if (
@@ -446,6 +472,7 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
446
472
  !stanzaRoom.includes('@') &&
447
473
  !isOneToOneLikeRoom
448
474
  ) {
475
+ callTrace('drop call-token: room unknown', { stanzaRoom });
449
476
  return true;
450
477
  }
451
478
 
@@ -457,17 +484,25 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
457
484
  // title (which for stale / deleted-peer chats reads "deleted").
458
485
  const jwtPayload = decodeJwtPayload(token);
459
486
  const callerName = extractCallerDisplayName(jwtPayload);
460
- const resolvedTitle = String(resolvedRoom?.name || '').trim();
487
+ // `title` is the display name; on new-arch private rooms `name` is the
488
+ // bare room id ("${appId}_<a>-${appId}_<b>"), never something to show.
489
+ const resolvedTitle = String(
490
+ resolvedRoom?.title || resolvedRoom?.name || ''
491
+ ).trim();
461
492
  const titleLooksBad =
462
493
  !resolvedTitle ||
494
+ resolvedTitle === stanzaRoom ||
463
495
  ['deleted', 'deleted user', 'unknown', 'null'].includes(
464
496
  resolvedTitle.toLowerCase()
465
497
  );
498
+ // Never fall back to the room id: an empty name renders as
499
+ // "Unknown caller" on the ring screen.
466
500
  const incomingRoomName =
467
- (callerName && titleLooksBad ? callerName : resolvedTitle) ||
468
- callerName ||
469
- stanzaRoom;
470
- if (!roomJid) {return true;}
501
+ (titleLooksBad ? callerName : resolvedTitle) || callerName || '';
502
+ if (!roomJid) {
503
+ callTrace('drop call-token: no room jid', { stanzaRoom });
504
+ return true;
505
+ }
471
506
 
472
507
  const callId = extractCallId(data, jwtPayload);
473
508
  const selfXmpp =
@@ -481,6 +516,11 @@ export const onCallTokenMessage = (stanza: Element): boolean => {
481
516
  callState.roomName === incomingRoomName ||
482
517
  callState.roomBareName === stanzaRoom);
483
518
 
519
+ callTrace('accept call-token', {
520
+ outgoing: isOutgoingRoomMatch,
521
+ roomJid,
522
+ callId,
523
+ });
484
524
  if (isOutgoingRoomMatch) {
485
525
  store.dispatch(
486
526
  setOutgoingCallToken({ roomJid, token, callId: callId || null })
@@ -1,4 +1,4 @@
1
- import xmpp, { Client } from '@xmpp/client';
1
+ import xmpp, { Client, xml } from '@xmpp/client';
2
2
  import { walletToUsername } from '../helpers/walletUsername';
3
3
  import { IMessage, xmppSettingsInterface } from '../types/types';
4
4
 
@@ -765,6 +765,15 @@ export class XmppClient {
765
765
  this.authRecoveryFailures = 0;
766
766
  this.authRejectionsSinceOnline = 0;
767
767
  this.reconnectAttempts = 0;
768
+ // Initial presence, as the web client sends on 'online'. Without it
769
+ // the session is never "available" to ejabberd, which then holds
770
+ // back every `type="chat"` message addressed to the bare JID: the
771
+ // call-invite and the call-token never arrived, so the phone neither
772
+ // rang nor joined its own outgoing call. Room traffic was unaffected
773
+ // (MUC joins and mucsub don't need it), which hid the problem.
774
+ Promise.resolve()
775
+ .then(() => this.client.send(xml('presence')))
776
+ .catch((err: unknown) => console.warn('initial presence failed', err));
768
777
  this.sendAllPresencesAndMarkReady();
769
778
  try {
770
779
  devPushLog(
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // Generated by scripts/sync-version.mjs on `npm version`.
2
2
  // Edit package.json's version instead of this file.
3
- export const ETHORA_CHAT_COMPONENT_VERSION = '26.10.0';
3
+ export const ETHORA_CHAT_COMPONENT_VERSION = '26.10.3';