@ethora/chat-component-rn 26.4.1

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 (273) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +148 -0
  3. package/empty-shim.js +15 -0
  4. package/index.js +13 -0
  5. package/metro.js +72 -0
  6. package/package.json +99 -0
  7. package/src/api.config.ts +34 -0
  8. package/src/assets/BG.png +0 -0
  9. package/src/assets/BG.tsx +56 -0
  10. package/src/assets/File.svg +4 -0
  11. package/src/assets/ForzaCare.png +0 -0
  12. package/src/assets/ForzaCare.tsx +27 -0
  13. package/src/assets/icons.tsx +685 -0
  14. package/src/assets/images.tsx +41 -0
  15. package/src/assets/test.xml +243 -0
  16. package/src/components/AuthForms/Login.tsx +295 -0
  17. package/src/components/AuthForms/LoginAnonym.tsx +68 -0
  18. package/src/components/AuthForms/Register.tsx +8 -0
  19. package/src/components/ContextMenu/ContextMenuComponents.tsx +87 -0
  20. package/src/components/DropdownMenu/DropdownMenu.tsx +244 -0
  21. package/src/components/ExampleComponents/CustomMessage.tsx +92 -0
  22. package/src/components/ExampleComponents/CustomTypingIndicatorExamples.tsx +239 -0
  23. package/src/components/Header/HeaderRoomList.tsx +104 -0
  24. package/src/components/InputComponents/AudioInput.tsx +24 -0
  25. package/src/components/InputComponents/AudioRecorder.tsx +100 -0
  26. package/src/components/InputComponents/MediaInput.tsx +114 -0
  27. package/src/components/InputComponents/RecordingIndicator.tsx +77 -0
  28. package/src/components/InputComponents/Search.tsx +135 -0
  29. package/src/components/InputComponents/TextInput.tsx +66 -0
  30. package/src/components/MainComponents/ChatHeader.tsx +163 -0
  31. package/src/components/MainComponents/ChatRoom.tsx +392 -0
  32. package/src/components/MainComponents/ChatWrapper.tsx +318 -0
  33. package/src/components/MainComponents/ChooseChatMessage.tsx +44 -0
  34. package/src/components/MainComponents/ConnectionBanner.tsx +33 -0
  35. package/src/components/MainComponents/EditWrapper.tsx +72 -0
  36. package/src/components/MainComponents/LoginWrapper.tsx +134 -0
  37. package/src/components/MainComponents/MediaMessage.tsx +55 -0
  38. package/src/components/MainComponents/MessageContainer.tsx +122 -0
  39. package/src/components/MainComponents/MessageList.tsx +429 -0
  40. package/src/components/MainComponents/NoMessagesPlaceholder.tsx +49 -0
  41. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +143 -0
  42. package/src/components/MainComponents/RNStyled.tsx +34 -0
  43. package/src/components/MainComponents/ReduxWrapper.tsx +40 -0
  44. package/src/components/MainComponents/RoomList.tsx +246 -0
  45. package/src/components/MainComponents/Select.tsx +165 -0
  46. package/src/components/MainComponents/Switch.tsx +73 -0
  47. package/src/components/MainComponents/SystemMessage.tsx +42 -0
  48. package/src/components/Menu/HeaderRoomListMenu.tsx +169 -0
  49. package/src/components/MenuRoom/MenuRoom.tsx +46 -0
  50. package/src/components/MessageBubble/Avatar.tsx +84 -0
  51. package/src/components/MessageBubble/BottomReplyContainer.tsx +117 -0
  52. package/src/components/MessageBubble/CustomDivider.tsx +10 -0
  53. package/src/components/MessageBubble/DeletedMessage.tsx +36 -0
  54. package/src/components/MessageBubble/Message.tsx +400 -0
  55. package/src/components/MessageBubble/MessageInteractions.tsx +247 -0
  56. package/src/components/MessageBubble/MessageReaction.tsx +149 -0
  57. package/src/components/MessageBubble/MessageReply.tsx +50 -0
  58. package/src/components/MessageBubble/MessageTranslations.tsx +30 -0
  59. package/src/components/Modals/AddMembersModal/AddMembersModal.tsx +142 -0
  60. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +471 -0
  61. package/src/components/Modals/ChatProfileModal/DeleteChatModal.tsx +91 -0
  62. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +298 -0
  63. package/src/components/Modals/Modal/Modal.tsx +52 -0
  64. package/src/components/Modals/ModalHeaderComponent.tsx +41 -0
  65. package/src/components/Modals/ModalSelectMedia/ModalSelectMedia.tsx +285 -0
  66. package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +103 -0
  67. package/src/components/Modals/NewChatModal/ModalContent.tsx +151 -0
  68. package/src/components/Modals/NewChatModal/NewChatModal.tsx +391 -0
  69. package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +136 -0
  70. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +134 -0
  71. package/src/components/Modals/SettingsModals/BlockedUsers/BlockedUsersModal.tsx +63 -0
  72. package/src/components/Modals/SettingsModals/DocumentShares/DocumentSharesModal.tsx +115 -0
  73. package/src/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.tsx +121 -0
  74. package/src/components/Modals/SettingsModals/ManageDataModal/StyledComponents.ts +0 -0
  75. package/src/components/Modals/SettingsModals/ProfileShares/ProfileShares.tsx +65 -0
  76. package/src/components/Modals/SettingsModals/Referrals/Referrals.tsx +90 -0
  77. package/src/components/Modals/SettingsModals/SharedStyledComponents.ts +74 -0
  78. package/src/components/Modals/SettingsModals/Visibility/RadioInput.tsx +59 -0
  79. package/src/components/Modals/SettingsModals/Visibility/StyledComponents.ts +32 -0
  80. package/src/components/Modals/SettingsModals/Visibility/VisibilityModal.tsx +146 -0
  81. package/src/components/Modals/UserProfileModal/EditUserModal.tsx +163 -0
  82. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +410 -0
  83. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +85 -0
  84. package/src/components/Modals/styledModalComponents.tsx +181 -0
  85. package/src/components/OperationalModal/OperationalModal.tsx +78 -0
  86. package/src/components/RoomComponents/ChatRoomItem.tsx +219 -0
  87. package/src/components/RoomComponents/LastMessageItem.tsx +47 -0
  88. package/src/components/RoomComponents/styled/LastAudioMessage.tsx +62 -0
  89. package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +26 -0
  90. package/src/components/RoomComponents/styled/LastMessageFile.tsx +54 -0
  91. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +54 -0
  92. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +70 -0
  93. package/src/components/RoomComponents/styled/LastTextMessage.tsx +65 -0
  94. package/src/components/RoomComponents/styled/StyledRoomComponents.ts +53 -0
  95. package/src/components/SortDropDown/index.tsx +76 -0
  96. package/src/components/Thread/ThreadHeader.tsx +41 -0
  97. package/src/components/Thread/ThreadWrapper.tsx +270 -0
  98. package/src/components/Toast/Toast.tsx +128 -0
  99. package/src/components/Toast/index.ts +13 -0
  100. package/src/components/UsersList/StyledComponents.ts +30 -0
  101. package/src/components/UsersList/UsersList.tsx +112 -0
  102. package/src/components/styled/ActionButton.tsx +40 -0
  103. package/src/components/styled/AudioMessage.tsx +82 -0
  104. package/src/components/styled/Button.tsx +107 -0
  105. package/src/components/styled/ChatWrapperBox.tsx +9 -0
  106. package/src/components/styled/DateLabel.tsx +77 -0
  107. package/src/components/styled/Loader.tsx +65 -0
  108. package/src/components/styled/MediaFilePreview.tsx +42 -0
  109. package/src/components/styled/MediaModal.tsx +54 -0
  110. package/src/components/styled/MessageImage.tsx +54 -0
  111. package/src/components/styled/NewMessageLabel.tsx +50 -0
  112. package/src/components/styled/RoomListComponents/index.tsx +164 -0
  113. package/src/components/styled/SendInput.tsx +297 -0
  114. package/src/components/styled/StyledComponents.ts +320 -0
  115. package/src/components/styled/StyledInput.tsx +101 -0
  116. package/src/components/styled/StyledInputComponents/AudioComponents.tsx +1 -0
  117. package/src/components/styled/StyledInputComponents/Composing.tsx +97 -0
  118. package/src/components/styled/StyledInputComponents/CustomTypingIndicator.tsx +261 -0
  119. package/src/components/styled/StyledInputComponents/MediaComponents.tsx +90 -0
  120. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +131 -0
  121. package/src/components/styled/StyledInputComponents/VideoComponents.tsx +49 -0
  122. package/src/components/styled/TreadLabel.tsx +50 -0
  123. package/src/components/styled/UnsupportedType.tsx +95 -0
  124. package/src/components/styled/VideoMessage.tsx +68 -0
  125. package/src/context/MessageNotificationContext.tsx +335 -0
  126. package/src/context/PushNotificationProvider.tsx +78 -0
  127. package/src/context/ToastContext.tsx +63 -0
  128. package/src/context/toastProvider.tsx +0 -0
  129. package/src/context/xmppProvider.tsx +364 -0
  130. package/src/helpers/block_scroll.ts +95 -0
  131. package/src/helpers/chatAutoEnterer.ts +46 -0
  132. package/src/helpers/checkUniqueUsers.tsx +31 -0
  133. package/src/helpers/constants/CHAT_TYPES.ts +6 -0
  134. package/src/helpers/constants/LANGUAGE_OPTIONS.ts +14 -0
  135. package/src/helpers/constants/LOCAL_STORAGE.ts +3 -0
  136. package/src/helpers/constants/MESSAGE_INTERACTIONS.ts +29 -0
  137. package/src/helpers/constants/MODAL_TYPES.ts +57 -0
  138. package/src/helpers/constants/PLATFORM_CONSTANTS.ts +3 -0
  139. package/src/helpers/createMainMessageForThread.ts +23 -0
  140. package/src/helpers/createMessageFromXml.ts +118 -0
  141. package/src/helpers/createRoomFromApi.tsx +27 -0
  142. package/src/helpers/createUserNameFromSetUser.ts +15 -0
  143. package/src/helpers/dateComparison.ts +12 -0
  144. package/src/helpers/debounce.ts +10 -0
  145. package/src/helpers/ensureScopedChatCache.ts +61 -0
  146. package/src/helpers/extractUniqueMembersFromRooms.ts +45 -0
  147. package/src/helpers/formatNumberWithCommas.ts +3 -0
  148. package/src/helpers/getBooleanFromString.ts +7 -0
  149. package/src/helpers/getDataFromXml.ts +80 -0
  150. package/src/helpers/getNumberFromString.ts +5 -0
  151. package/src/helpers/getRoomsWithRetry.ts +45 -0
  152. package/src/helpers/getTintedColor.ts +28 -0
  153. package/src/helpers/getUnnamedUsers.ts +39 -0
  154. package/src/helpers/handleCopyClick.ts +3 -0
  155. package/src/helpers/handleXmppError.ts +14 -0
  156. package/src/helpers/hashcolor.ts +34 -0
  157. package/src/helpers/historyPreloadScheduler.ts +264 -0
  158. package/src/helpers/initRoomsPresence.ts +32 -0
  159. package/src/helpers/initXmppRooms.tsx +71 -0
  160. package/src/helpers/insertMessageWithDelimiter.ts +96 -0
  161. package/src/helpers/isChatIdPresentInArray.ts +54 -0
  162. package/src/helpers/localStorageUser.ts +9 -0
  163. package/src/helpers/markdownParser.tsx +295 -0
  164. package/src/helpers/nanoToMs.ts +3 -0
  165. package/src/helpers/parseMessageBody.tsx +516 -0
  166. package/src/helpers/parseUrls.tsx +42 -0
  167. package/src/helpers/resolveInitBeforeLoadUser.ts +240 -0
  168. package/src/helpers/storeConsole.ts +26 -0
  169. package/src/helpers/transformTranslatations.ts +16 -0
  170. package/src/helpers/updateMessagesTillLast.tsx +104 -0
  171. package/src/helpers/updatedChatLastTimestamps.ts +29 -0
  172. package/src/helpers/validator.ts +20 -0
  173. package/src/helpers/walletUsername.ts +12 -0
  174. package/src/hooks/hooks.ts +6 -0
  175. package/src/hooks/useChatSettingState.tsx +38 -0
  176. package/src/hooks/useChatWrapperInit.ts +266 -0
  177. package/src/hooks/useComposing.tsx +59 -0
  178. package/src/hooks/useCustomTypingIndicator.tsx +193 -0
  179. package/src/hooks/useEventHandlers.tsx +81 -0
  180. package/src/hooks/useGetNewArchRoom.tsx +57 -0
  181. package/src/hooks/useHeapSender.tsx +88 -0
  182. package/src/hooks/useLocalStorage.tsx +53 -0
  183. package/src/hooks/useLogout.tsx +31 -0
  184. package/src/hooks/useMessageHeapState.tsx +11 -0
  185. package/src/hooks/useMessageLoaderQueue.tsx +90 -0
  186. package/src/hooks/useMessageQueue.ts +146 -0
  187. package/src/hooks/usePendingNotification.ts +49 -0
  188. package/src/hooks/usePrevious.tsx +15 -0
  189. package/src/hooks/usePushNotifications.ts +106 -0
  190. package/src/hooks/useQRCodeChatHandler.ts +58 -0
  191. package/src/hooks/useRoomInitialization.tsx +160 -0
  192. package/src/hooks/useRoomState.tsx +47 -0
  193. package/src/hooks/useRoomUrl.tsx +41 -0
  194. package/src/hooks/useSendMessage.tsx +306 -0
  195. package/src/hooks/useUnreadMessagesCounter.ts +55 -0
  196. package/src/hooks/useXmppInitialization.ts +148 -0
  197. package/src/main.ts +45 -0
  198. package/src/networking/api-requests/auth.api.ts +140 -0
  199. package/src/networking/api-requests/push.api.ts +55 -0
  200. package/src/networking/api-requests/roomMembers.api.ts +20 -0
  201. package/src/networking/api-requests/rooms.api.ts +142 -0
  202. package/src/networking/api-requests/user.api.ts +65 -0
  203. package/src/networking/apiClient.ts +149 -0
  204. package/src/networking/helpers/refreshChecker.ts +13 -0
  205. package/src/networking/stanzaHandlers.ts +418 -0
  206. package/src/networking/xmpp/actionSetTimestampToPrivateStore.xmpp.ts +37 -0
  207. package/src/networking/xmpp/allRoomPresences.xmpp.ts +10 -0
  208. package/src/networking/xmpp/createPrivateRoom.xmpp.ts +26 -0
  209. package/src/networking/xmpp/createRoom.xmpp.ts +35 -0
  210. package/src/networking/xmpp/createRoomPresence.xmpp.ts +74 -0
  211. package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +15 -0
  212. package/src/networking/xmpp/deleteMessage.xmpp.ts +19 -0
  213. package/src/networking/xmpp/editMessage.xmpp.ts +46 -0
  214. package/src/networking/xmpp/getChatsPrivateStoreRequest.xmpp.ts +57 -0
  215. package/src/networking/xmpp/getHistory.xmpp.ts +140 -0
  216. package/src/networking/xmpp/getLastMessageArchive.xmpp.ts +24 -0
  217. package/src/networking/xmpp/getRoomInfo.xmpp.ts +15 -0
  218. package/src/networking/xmpp/getRoomMembers.xmpp.ts +13 -0
  219. package/src/networking/xmpp/getRooms.xmpp.ts +43 -0
  220. package/src/networking/xmpp/getRoomsPaged.xmpp.ts +59 -0
  221. package/src/networking/xmpp/handlePong.xmpp.ts +7 -0
  222. package/src/networking/xmpp/handleStanzas.xmpp.ts +55 -0
  223. package/src/networking/xmpp/inviteRoomRequest.xmpp.ts +25 -0
  224. package/src/networking/xmpp/leaveTheRoom.xmpp.ts +15 -0
  225. package/src/networking/xmpp/listenerManager.ts +116 -0
  226. package/src/networking/xmpp/presenceInRoom.xmpp.ts +57 -0
  227. package/src/networking/xmpp/roomConfig.xmpp.ts +71 -0
  228. package/src/networking/xmpp/sendMediaMessage.xmpp.ts +97 -0
  229. package/src/networking/xmpp/sendMessageReaction.xmpp.ts +41 -0
  230. package/src/networking/xmpp/sendPing.xmpp.ts +21 -0
  231. package/src/networking/xmpp/sendTextMessage.xmpp.ts +99 -0
  232. package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +44 -0
  233. package/src/networking/xmpp/sendTypingRequest.xmpp.ts +26 -0
  234. package/src/networking/xmpp/setChatsPrivateStoreRequest.xmpp.ts +48 -0
  235. package/src/networking/xmpp/setMeAsOwner.xmpp.ts +52 -0
  236. package/src/networking/xmpp/setRoomImage.xmpp.ts +26 -0
  237. package/src/networking/xmpp/setVCard.xmpp.ts +19 -0
  238. package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +75 -0
  239. package/src/networking/xmppClient.ts +603 -0
  240. package/src/roomStore/Middleware/logoutMiddleware.tsx +24 -0
  241. package/src/roomStore/Middleware/newMessageMidlleware.tsx +87 -0
  242. package/src/roomStore/Middleware/reactionsMiddleware.tsx +77 -0
  243. package/src/roomStore/Middleware/testMiddleware.tsx +20 -0
  244. package/src/roomStore/Middleware/unreadMidlleware.tsx +58 -0
  245. package/src/roomStore/chatSettingsSlice.ts +178 -0
  246. package/src/roomStore/index.ts +68 -0
  247. package/src/roomStore/persistence.ts +152 -0
  248. package/src/roomStore/roomHeapSlice.ts +37 -0
  249. package/src/roomStore/roomsSlice.ts +353 -0
  250. package/src/services/pushNotifications.ts +170 -0
  251. package/src/services/pushSubscriptionService.ts +145 -0
  252. package/src/types/messages.ts +61 -0
  253. package/src/types/models/action.model.ts +30 -0
  254. package/src/types/models/config.model.ts +16 -0
  255. package/src/types/models/customComponents.model.ts +53 -0
  256. package/src/types/models/language.model.ts +11 -0
  257. package/src/types/models/media.model.ts +5 -0
  258. package/src/types/models/message.model.ts +69 -0
  259. package/src/types/models/modal.model.ts +9 -0
  260. package/src/types/models/room.model.ts +120 -0
  261. package/src/types/models/user.model.ts +90 -0
  262. package/src/types/models/xmpp.model.ts +155 -0
  263. package/src/types/types.ts +505 -0
  264. package/src/utils/PriorityQueue.ts +47 -0
  265. package/src/utils/actionHelpers.ts +40 -0
  266. package/src/utils/actionLogger.ts +64 -0
  267. package/src/utils/clientRegistry.ts +80 -0
  268. package/src/utils/devLogger.ts +197 -0
  269. package/src/utils/messageNotificationManager.ts +108 -0
  270. package/src/utils/resendMessage.ts +87 -0
  271. package/src/utils/toastEmitter.ts +27 -0
  272. package/src/utils/xmppMemoryMonitor.ts +63 -0
  273. package/src/version.ts +1 -0
@@ -0,0 +1,80 @@
1
+ import XmppClient from '../networking/xmppClient';
2
+ import { xmppSettingsInterface } from '../types/types';
3
+
4
+ let currentClient: XmppClient | null = null;
5
+ let currentClientKey = '';
6
+ const initLocks = new Map<string, Promise<XmppClient>>();
7
+
8
+ const DEFAULT_DEV_SERVER = 'xmpp.chat.ethora.com';
9
+
10
+ export function buildXmppClientKey(
11
+ username: string,
12
+ xmppSettings?: xmppSettingsInterface
13
+ ): string {
14
+ const devServer = xmppSettings?.devServer || DEFAULT_DEV_SERVER;
15
+ const host = xmppSettings?.host || '';
16
+ const conference = xmppSettings?.conference || '';
17
+ return `${username}|${devServer}|${host}|${conference}`;
18
+ }
19
+
20
+ export function isXmppClientReusable(client: XmppClient | null): boolean {
21
+ if (!client) {return false;}
22
+ return client.status === 'online' || client.status === 'connecting';
23
+ }
24
+
25
+ export function setGlobalXmppClient(
26
+ client: XmppClient | null,
27
+ key?: string
28
+ ): void {
29
+ currentClient = client;
30
+ currentClientKey = client ? key || currentClientKey || '' : '';
31
+ }
32
+
33
+ export function getGlobalXmppClient(): XmppClient | null {
34
+ return currentClient;
35
+ }
36
+
37
+ export function getGlobalXmppClientKey(): string {
38
+ return currentClientKey;
39
+ }
40
+
41
+ export function getReusableXmppClientByKey(key: string): XmppClient | null {
42
+ if (!key || key !== currentClientKey) {return null;}
43
+ if (!isXmppClientReusable(currentClient)) {return null;}
44
+ return currentClient;
45
+ }
46
+
47
+ export async function withXmppClientInitLock(
48
+ key: string,
49
+ init: () => Promise<XmppClient>
50
+ ): Promise<XmppClient> {
51
+ const existing = initLocks.get(key);
52
+ if (existing) {return existing;}
53
+
54
+ const createdPromise = init().finally(() => {
55
+ if (initLocks.get(key) === createdPromise) {
56
+ initLocks.delete(key);
57
+ }
58
+ });
59
+
60
+ initLocks.set(key, createdPromise);
61
+ return createdPromise;
62
+ }
63
+
64
+ export function requireXmppClient(): XmppClient {
65
+ if (!currentClient) {
66
+ throw new Error('XMPP client is not initialized');
67
+ }
68
+ return currentClient;
69
+ }
70
+
71
+ export default {
72
+ buildXmppClientKey,
73
+ isXmppClientReusable,
74
+ setGlobalXmppClient,
75
+ getGlobalXmppClient,
76
+ getGlobalXmppClientKey,
77
+ getReusableXmppClientByKey,
78
+ withXmppClientInitLock,
79
+ requireXmppClient,
80
+ };
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Dev-only log bus used by the testbed `Logs` tab. Stores a bounded
3
+ * ring-buffer of entries that arrive from:
4
+ * - `console.log/info/warn/error` (patched in `installDevLogCapture`)
5
+ * - `axios` request/response interceptors (HTTP)
6
+ * - `XmppClient.attachEventListeners` (XMPP stanzas in/out)
7
+ *
8
+ * Pure module-level singleton — no React, callable from anywhere
9
+ * (reducers, services, helpers). React side reads via
10
+ * `useDevLogs()` which uses `useSyncExternalStore`.
11
+ */
12
+
13
+ export type LogKind = 'log' | 'info' | 'warn' | 'error' | 'http' | 'xmpp' | 'rn';
14
+
15
+ export interface LogEntry {
16
+ id: number;
17
+ kind: LogKind;
18
+ ts: number;
19
+ message: string;
20
+ details?: string;
21
+ }
22
+
23
+ const MAX_ENTRIES = 500;
24
+
25
+ let entries: LogEntry[] = [];
26
+ let listeners: Set<() => void> = new Set();
27
+ let nextId = 1;
28
+
29
+ export function pushLog(
30
+ kind: LogKind,
31
+ message: string,
32
+ details?: any
33
+ ): void {
34
+ const detailsStr =
35
+ details === undefined
36
+ ? undefined
37
+ : typeof details === 'string'
38
+ ? details
39
+ : safeStringify(details);
40
+ entries = [
41
+ ...entries,
42
+ { id: nextId++, kind, ts: Date.now(), message, details: detailsStr },
43
+ ];
44
+ if (entries.length > MAX_ENTRIES) {
45
+ entries = entries.slice(-MAX_ENTRIES);
46
+ }
47
+ // Defer subscriber notifications via microtask so a `pushLog` called
48
+ // during a React render (e.g. via the captured `console.log`) doesn't
49
+ // trigger a setState-during-render warning in subscribers using
50
+ // `useSyncExternalStore`.
51
+ const notify = () =>
52
+ listeners.forEach((fn) => {
53
+ try {
54
+ fn();
55
+ } catch {
56
+ /* noop */
57
+ }
58
+ });
59
+ if (typeof queueMicrotask === 'function') {
60
+ queueMicrotask(notify);
61
+ } else {
62
+ Promise.resolve().then(notify);
63
+ }
64
+ }
65
+
66
+ export function clearLogs(): void {
67
+ entries = [];
68
+ listeners.forEach((fn) => fn());
69
+ }
70
+
71
+ export function getLogs(): LogEntry[] {
72
+ return entries;
73
+ }
74
+
75
+ export function subscribeLogs(fn: () => void): () => void {
76
+ listeners.add(fn);
77
+ return () => {
78
+ listeners.delete(fn);
79
+ };
80
+ }
81
+
82
+ function safeStringify(value: any): string {
83
+ try {
84
+ return JSON.stringify(
85
+ value,
86
+ (_key, v) => {
87
+ if (typeof v === 'bigint') {return v.toString();}
88
+ if (v instanceof Error)
89
+ {return { name: v.name, message: v.message, stack: v.stack };}
90
+ return v;
91
+ },
92
+ 2
93
+ );
94
+ } catch {
95
+ try {
96
+ return String(value);
97
+ } catch {
98
+ return '[unstringifiable]';
99
+ }
100
+ }
101
+ }
102
+
103
+ // ---------------------------------------------------------------------
104
+ // console.* capture
105
+ // ---------------------------------------------------------------------
106
+ let consolePatched = false;
107
+
108
+ export function installConsoleCapture() {
109
+ if (consolePatched) {return;}
110
+ consolePatched = true;
111
+ (['log', 'info', 'warn', 'error'] as const).forEach((level) => {
112
+ const original = (console as any)[level].bind(console);
113
+ (console as any)[level] = (...args: any[]) => {
114
+ try {
115
+ const msg = args
116
+ .map((a) =>
117
+ typeof a === 'string' ? a : safeStringify(a)
118
+ )
119
+ .join(' ');
120
+ pushLog(level === 'log' ? 'log' : (level as LogKind), msg);
121
+ } catch {
122
+ /* swallow */
123
+ }
124
+ original(...args);
125
+ };
126
+ });
127
+ }
128
+
129
+ // ---------------------------------------------------------------------
130
+ // axios interceptor
131
+ // ---------------------------------------------------------------------
132
+ let axiosPatched = false;
133
+
134
+ export function installAxiosCapture(axiosInstance: any) {
135
+ if (axiosPatched || !axiosInstance?.interceptors) {return;}
136
+ axiosPatched = true;
137
+
138
+ axiosInstance.interceptors.request.use(
139
+ (config: any) => {
140
+ const method = (config.method || 'get').toUpperCase();
141
+ const url = (config.baseURL || '') + (config.url || '');
142
+ pushLog('http', `→ ${method} ${url}`, {
143
+ headers: redactHeaders(config.headers),
144
+ data: config.data,
145
+ });
146
+ return config;
147
+ },
148
+ (error: any) => {
149
+ pushLog('http', '→ request error', error?.message || String(error));
150
+ return Promise.reject(error);
151
+ }
152
+ );
153
+
154
+ axiosInstance.interceptors.response.use(
155
+ (response: any) => {
156
+ const method = (response.config?.method || 'get').toUpperCase();
157
+ const url = (response.config?.baseURL || '') + (response.config?.url || '');
158
+ pushLog(
159
+ 'http',
160
+ `← ${response.status} ${method} ${url}`,
161
+ truncateBody(response.data)
162
+ );
163
+ return response;
164
+ },
165
+ (error: any) => {
166
+ const method = (error.config?.method || '?').toUpperCase();
167
+ const url = (error.config?.baseURL || '') + (error.config?.url || '');
168
+ const status = error.response?.status || 'no-status';
169
+ pushLog('http', `← ERR ${status} ${method} ${url}`, {
170
+ data: error.response?.data,
171
+ message: error.message,
172
+ });
173
+ return Promise.reject(error);
174
+ }
175
+ );
176
+ }
177
+
178
+ function redactHeaders(headers: any) {
179
+ if (!headers || typeof headers !== 'object') {return headers;}
180
+ const out: any = {};
181
+ for (const k of Object.keys(headers)) {
182
+ const v = headers[k];
183
+ if (/^(authorization|x-custom-token|cookie)$/i.test(k)) {
184
+ out[k] = typeof v === 'string' ? v.slice(0, 16) + '…' : '[redacted]';
185
+ } else {
186
+ out[k] = v;
187
+ }
188
+ }
189
+ return out;
190
+ }
191
+
192
+ function truncateBody(body: any) {
193
+ if (body == null) {return body;}
194
+ const str = typeof body === 'string' ? body : safeStringify(body);
195
+ if (str.length <= 2000) {return str;}
196
+ return str.slice(0, 2000) + `… [+${str.length - 2000} chars]`;
197
+ }
@@ -0,0 +1,108 @@
1
+ // RN port of web messageNotificationManager — no DOM, queues pending
2
+ // notifications until a callback subscriber registers, dedupes within a
3
+ // short window.
4
+ import { IMessage } from '../types/types';
5
+
6
+ export interface MessageNotificationCallback {
7
+ (
8
+ message: IMessage,
9
+ roomName: string,
10
+ senderName: string,
11
+ roomJID: string
12
+ ): void;
13
+ }
14
+
15
+ interface PendingNotification {
16
+ message: IMessage;
17
+ roomName: string;
18
+ senderName: string;
19
+ roomJID: string;
20
+ ts: number;
21
+ }
22
+
23
+ class MessageNotificationManager {
24
+ private callbacks: Set<MessageNotificationCallback> = new Set();
25
+ private pending: PendingNotification[] = [];
26
+ private maxPending = 50;
27
+ private pendingTtlMs = 30_000;
28
+ private dedupeWindowMs = 5000;
29
+ private recentlyDelivered = new Map<string, number>();
30
+
31
+ addCallback(callback: MessageNotificationCallback): () => void {
32
+ this.callbacks.add(callback);
33
+ this.flushPending();
34
+ return () => {
35
+ this.callbacks.delete(callback);
36
+ };
37
+ }
38
+
39
+ getCallbackCount() {
40
+ return this.callbacks.size;
41
+ }
42
+
43
+ private flushPending() {
44
+ if (this.callbacks.size === 0 || this.pending.length === 0) {return;}
45
+ const now = Date.now();
46
+ const valid = this.pending.filter(
47
+ (item) => now - item.ts <= this.pendingTtlMs
48
+ );
49
+ this.pending = [];
50
+ valid.forEach((item) => {
51
+ this.callbacks.forEach((cb) =>
52
+ cb(item.message, item.roomName, item.senderName, item.roomJID)
53
+ );
54
+ });
55
+ }
56
+
57
+ private buildDedupeKey(message: IMessage, roomJID: string): string | null {
58
+ const msgId = String((message as any)?.xmppId || message?.id || '').trim();
59
+ if (msgId) {return `${roomJID}:${msgId}`;}
60
+ return null;
61
+ }
62
+
63
+ private shouldSkipDuplicate(message: IMessage, roomJID: string): boolean {
64
+ const now = Date.now();
65
+ const key = this.buildDedupeKey(message, roomJID);
66
+ if (!key) {return false;}
67
+ const prev = this.recentlyDelivered.get(key) || 0;
68
+ if (prev && now - prev < this.dedupeWindowMs) {return true;}
69
+ this.recentlyDelivered.set(key, now);
70
+ if (this.recentlyDelivered.size > 500) {
71
+ const threshold = now - this.dedupeWindowMs;
72
+ this.recentlyDelivered.forEach((ts, k) => {
73
+ if (ts < threshold) {this.recentlyDelivered.delete(k);}
74
+ });
75
+ }
76
+ return false;
77
+ }
78
+
79
+ showNotification(
80
+ message: IMessage,
81
+ roomName: string,
82
+ senderName: string,
83
+ roomJID: string
84
+ ) {
85
+ const body = typeof message?.body === 'string' ? message.body.trim() : '';
86
+ if (!body) {return;}
87
+ if (this.shouldSkipDuplicate(message, roomJID)) {return;}
88
+
89
+ if (this.callbacks.size > 0) {
90
+ this.callbacks.forEach((cb) =>
91
+ cb(message, roomName, senderName, roomJID)
92
+ );
93
+ } else {
94
+ this.pending.push({
95
+ message,
96
+ roomName,
97
+ senderName,
98
+ roomJID,
99
+ ts: Date.now(),
100
+ });
101
+ if (this.pending.length > this.maxPending) {
102
+ this.pending = this.pending.slice(-this.maxPending);
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ export const messageNotificationManager = new MessageNotificationManager();
@@ -0,0 +1,87 @@
1
+ import { requireXmppClient } from './clientRegistry';
2
+ import { store } from '../roomStore';
3
+ import { addRoomMessage } from '../roomStore/roomsSlice';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { IMessage } from '../types/types';
6
+
7
+ type ResendOptions = {
8
+ respectTranslateConfig?: boolean;
9
+ };
10
+
11
+ export async function resendMessage(
12
+ message: Pick<IMessage, 'body' | 'roomJid'> & {
13
+ isReply?: boolean;
14
+ showInChannel?: string;
15
+ mainMessage?: string;
16
+ },
17
+ options: ResendOptions = {}
18
+ ): Promise<string> {
19
+ const client = requireXmppClient();
20
+ const state = store.getState();
21
+ const user = state.chatSettingStore.user;
22
+ const config = state.chatSettingStore.config;
23
+ const activeRoomJID = message.roomJid;
24
+
25
+ const id = `resend-text-message-${uuidv4()}`;
26
+
27
+ store.dispatch(
28
+ addRoomMessage({
29
+ roomJID: activeRoomJID,
30
+ message: {
31
+ id,
32
+ user: {
33
+ ...user,
34
+ id: user.xmppUsername,
35
+ name: user.firstName + ' ' + user.lastName,
36
+ },
37
+ date: new Date().toISOString(),
38
+ body: message.body,
39
+ roomJid: activeRoomJID,
40
+ xmppFrom: `${activeRoomJID}/${user.xmppUsername}`,
41
+ pending: true,
42
+ isReply: message.isReply || false,
43
+ showInChannel: (message.showInChannel as any) || ('false' as any),
44
+ mainMessage: message.mainMessage || '',
45
+ },
46
+ })
47
+ );
48
+
49
+ const useTranslate = !!(
50
+ options.respectTranslateConfig && config?.translates?.enabled
51
+ );
52
+
53
+ if (useTranslate) {
54
+ client.sendTextMessageWithTranslateTagStanza(
55
+ activeRoomJID,
56
+ user.firstName,
57
+ user.lastName,
58
+ '',
59
+ user.walletAddress,
60
+ message.body,
61
+ '',
62
+ message.isReply || false,
63
+ message.showInChannel === 'true' || false,
64
+ message.mainMessage || '',
65
+ (state.chatSettingStore.langSource as any) || 'en',
66
+ id
67
+ );
68
+ } else {
69
+ client.sendMessage(
70
+ activeRoomJID,
71
+ user.firstName,
72
+ user.lastName,
73
+ '',
74
+ user.walletAddress,
75
+ message.body,
76
+ '',
77
+ message.isReply || false,
78
+ message.showInChannel === 'true' || false,
79
+ message.mainMessage || '',
80
+ id
81
+ );
82
+ }
83
+
84
+ return id;
85
+ }
86
+
87
+ export default resendMessage;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Tiny pub/sub used by `ToastContext` so non-React code can fire a
3
+ * toast. Replaces an out-of-tree port artifact (`../../../../utils/...`).
4
+ */
5
+ import type { ToastType } from '../components/Toast';
6
+
7
+ type Listener = (toast: ToastType) => void;
8
+
9
+ const listeners = new Set<Listener>();
10
+
11
+ export const toastEmitter = {
12
+ subscribe(fn: Listener) {
13
+ listeners.add(fn);
14
+ return () => {
15
+ listeners.delete(fn);
16
+ };
17
+ },
18
+ emit(toast: ToastType) {
19
+ listeners.forEach((fn) => {
20
+ try {
21
+ fn(toast);
22
+ } catch {
23
+ /* swallow */
24
+ }
25
+ });
26
+ },
27
+ };
@@ -0,0 +1,63 @@
1
+ import { XmppListenerManager } from '../networking/xmpp/listenerManager';
2
+
3
+ export class XmppMemoryMonitor {
4
+ private static monitoringInterval: NodeJS.Timeout | null = null;
5
+ private static warningThreshold = 10;
6
+ private static criticalThreshold = 20;
7
+
8
+ static startMonitoring(intervalMs: number = 5000): void {
9
+ if (this.monitoringInterval) {
10
+ this.stopMonitoring();
11
+ }
12
+
13
+ this.monitoringInterval = setInterval(() => {
14
+ const count = XmppListenerManager.getActiveListenerCount();
15
+
16
+ if (count >= this.criticalThreshold) {
17
+ console.warn(
18
+ `[XmppMemoryMonitor] CRITICAL: ${count} active XMPP listeners detected!`
19
+ );
20
+ XmppListenerManager.logActiveListeners();
21
+ } else if (count >= this.warningThreshold) {
22
+ console.warn(
23
+ `[XmppMemoryMonitor] WARNING: ${count} active XMPP listeners detected`
24
+ );
25
+ } else if (process.env.NODE_ENV === 'development') {
26
+ console.log(`[XmppMemoryMonitor] Active XMPP listeners: ${count}`);
27
+ }
28
+ }, intervalMs);
29
+
30
+ console.log('[XmppMemoryMonitor] Started monitoring XMPP listeners');
31
+ }
32
+
33
+ static stopMonitoring(): void {
34
+ if (this.monitoringInterval) {
35
+ clearInterval(this.monitoringInterval);
36
+ this.monitoringInterval = null;
37
+ console.log('[XmppMemoryMonitor] Stopped monitoring XMPP listeners');
38
+ }
39
+ }
40
+
41
+ static setThresholds(warning: number, critical: number): void {
42
+ this.warningThreshold = warning;
43
+ this.criticalThreshold = critical;
44
+ }
45
+
46
+ static getCurrentCount(): number {
47
+ return XmppListenerManager.getActiveListenerCount();
48
+ }
49
+
50
+ static forceCleanup(): void {
51
+ console.warn('[XmppMemoryMonitor] Force cleaning up all XMPP listeners');
52
+ XmppListenerManager.clearAllListeners();
53
+ }
54
+
55
+ static getListenerInfo(): Array<{
56
+ key: string;
57
+ eventType: string;
58
+ timestamp: number;
59
+ age: number;
60
+ }> {
61
+ return XmppListenerManager.getActiveListenersInfo();
62
+ }
63
+ }
package/src/version.ts ADDED
@@ -0,0 +1 @@
1
+ export const ETHORA_CHAT_COMPONENT_VERSION = '25.7.5';