@ethora/chat-component-rn 26.6.11 → 26.6.13
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.
- package/CHANGELOG.md +24 -0
- package/README.md +2 -2
- package/lib/commonjs/components/AuthForms/Login.js +2 -1
- package/lib/commonjs/components/AuthForms/Login.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +4 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +14 -13
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/LoginWrapper.js +2 -1
- package/lib/commonjs/components/MainComponents/LoginWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +18 -7
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/InteractionsOverlay.js +1 -1
- package/lib/commonjs/components/MessageBubble/InteractionsOverlay.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +4 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +15 -11
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/GViewWebView.js +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/GViewWebView.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +2 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +5 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +10 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +4 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +4 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +6 -3
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/commonjs/components/styled/AudioMessage.js +2 -1
- package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
- package/lib/commonjs/components/styled/MediaFilePreview.js +1 -1
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +34 -8
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +36 -64
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +44 -18
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/initXmppRooms.js +5 -1
- package/lib/commonjs/helpers/initXmppRooms.js.map +1 -1
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js +126 -12
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/commonjs/helpers/secureFileUrl.js +101 -0
- package/lib/commonjs/helpers/secureFileUrl.js.map +1 -0
- package/lib/commonjs/hooks/useChatWrapperInit.js +3 -3
- package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/commonjs/hooks/useFileToken.js +10 -0
- package/lib/commonjs/hooks/useFileToken.js.map +1 -0
- package/lib/commonjs/hooks/useSendMessage.js +23 -13
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/main.js +25 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +99 -54
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/roomMembers.api.js +1 -1
- package/lib/commonjs/networking/api-requests/roomMembers.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/rooms.api.js +9 -9
- package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/user.api.js +9 -9
- package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
- package/lib/commonjs/networking/apiClient.js +62 -112
- package/lib/commonjs/networking/apiClient.js.map +1 -1
- package/lib/commonjs/networking/authRefresh.js +323 -0
- package/lib/commonjs/networking/authRefresh.js.map +1 -0
- package/lib/commonjs/networking/xmppClient.js +33 -5
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/chatSettingsSlice.js +20 -2
- package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/module/components/AuthForms/Login.js +2 -1
- package/lib/module/components/AuthForms/Login.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +4 -1
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +14 -13
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/LoginWrapper.js +2 -1
- package/lib/module/components/MainComponents/LoginWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +18 -7
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MessageBubble/InteractionsOverlay.js +1 -1
- package/lib/module/components/MessageBubble/InteractionsOverlay.js.map +1 -1
- package/lib/module/components/MessageBubble/Message.js +1 -1
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +4 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +15 -11
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/GViewWebView.js +1 -1
- package/lib/module/components/Modals/FilePreviewModal/GViewWebView.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js +2 -1
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js +5 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js +10 -2
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +4 -1
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +4 -1
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallSession.js +6 -3
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/module/components/styled/AudioMessage.js +2 -1
- package/lib/module/components/styled/AudioMessage.js.map +1 -1
- package/lib/module/components/styled/MediaFilePreview.js +1 -1
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +34 -8
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +36 -64
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/xmppProvider.js +43 -18
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/initXmppRooms.js +5 -1
- package/lib/module/helpers/initXmppRooms.js.map +1 -1
- package/lib/module/helpers/resolveInitBeforeLoadUser.js +126 -11
- package/lib/module/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/module/helpers/secureFileUrl.js +91 -0
- package/lib/module/helpers/secureFileUrl.js.map +1 -0
- package/lib/module/hooks/useChatWrapperInit.js +3 -3
- package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/module/hooks/useFileToken.js +5 -0
- package/lib/module/hooks/useFileToken.js.map +1 -0
- package/lib/module/hooks/useSendMessage.js +24 -14
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/main.js +12 -1
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +96 -53
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/api-requests/roomMembers.api.js +1 -1
- package/lib/module/networking/api-requests/roomMembers.api.js.map +1 -1
- package/lib/module/networking/api-requests/rooms.api.js +9 -9
- package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/module/networking/api-requests/user.api.js +8 -7
- package/lib/module/networking/api-requests/user.api.js.map +1 -1
- package/lib/module/networking/apiClient.js +61 -113
- package/lib/module/networking/apiClient.js.map +1 -1
- package/lib/module/networking/authRefresh.js +312 -0
- package/lib/module/networking/authRefresh.js.map +1 -0
- package/lib/module/networking/xmppClient.js +33 -5
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/chatSettingsSlice.js +20 -2
- package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/typescript/components/AuthForms/Login.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/LoginWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
- package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts +8 -0
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/initXmppRooms.d.ts.map +1 -1
- package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts.map +1 -1
- package/lib/typescript/helpers/secureFileUrl.d.ts +7 -0
- package/lib/typescript/helpers/secureFileUrl.d.ts.map +1 -0
- package/lib/typescript/hooks/useCustomTypingIndicator.d.ts +16 -4
- package/lib/typescript/hooks/useCustomTypingIndicator.d.ts.map +1 -1
- package/lib/typescript/hooks/useFileToken.d.ts +2 -0
- package/lib/typescript/hooks/useFileToken.d.ts.map +1 -0
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +6 -1
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -27
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
- package/lib/typescript/networking/apiClient.d.ts +12 -6
- package/lib/typescript/networking/apiClient.d.ts.map +1 -1
- package/lib/typescript/networking/authRefresh.d.ts +92 -0
- package/lib/typescript/networking/authRefresh.d.ts.map +1 -0
- package/lib/typescript/networking/xmppClient.d.ts +6 -0
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts +16 -0
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +17 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/package.json +29 -28
- package/src/components/AuthForms/Login.tsx +1 -0
- package/src/components/MainComponents/ChatHeader.tsx +4 -1
- package/src/components/MainComponents/ChatWrapper.tsx +14 -19
- package/src/components/MainComponents/LoginWrapper.tsx +1 -0
- package/src/components/MainComponents/MediaMessage.tsx +15 -5
- package/src/components/MessageBubble/InteractionsOverlay.tsx +1 -1
- package/src/components/MessageBubble/Message.tsx +1 -1
- package/src/components/MessageBubble/MessageInteractions.tsx +1 -1
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +4 -1
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +14 -10
- package/src/components/Modals/FilePreviewModal/GViewWebView.tsx +1 -1
- package/src/components/Modals/FilePreviewModal/PdfView.tsx +2 -1
- package/src/components/RoomComponents/ChatRoomItem.tsx +9 -1
- package/src/components/RoomComponents/styled/LastMessageFile.tsx +14 -2
- package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +4 -1
- package/src/components/RoomComponents/styled/LastMessageVideo.tsx +4 -1
- package/src/components/VideoCalls/VideoCallSession.tsx +8 -3
- package/src/components/styled/AudioMessage.tsx +2 -1
- package/src/components/styled/MediaFilePreview.tsx +1 -1
- package/src/components/styled/MessageImage.tsx +45 -6
- package/src/components/styled/VideoMessage.tsx +36 -60
- package/src/context/xmppProvider.tsx +45 -20
- package/src/helpers/initXmppRooms.tsx +5 -1
- package/src/helpers/resolveInitBeforeLoadUser.ts +123 -11
- package/src/helpers/secureFileUrl.ts +103 -0
- package/src/hooks/useChatWrapperInit.ts +3 -3
- package/src/hooks/useFileToken.ts +7 -0
- package/src/hooks/useSendMessage.tsx +28 -13
- package/src/main.ts +22 -1
- package/src/networking/api-requests/auth.api.ts +125 -52
- package/src/networking/api-requests/roomMembers.api.ts +1 -1
- package/src/networking/api-requests/rooms.api.ts +9 -9
- package/src/networking/api-requests/user.api.ts +8 -7
- package/src/networking/apiClient.ts +68 -123
- package/src/networking/authRefresh.ts +435 -0
- package/src/networking/xmppClient.ts +37 -5
- package/src/roomStore/chatSettingsSlice.ts +28 -3
- package/src/types/types.ts +17 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { store } from '../roomStore';
|
|
2
|
+
import { getCurrentBaseURL } from '../networking/apiClient';
|
|
3
|
+
import { refreshAuthTokens } from '../networking/authRefresh';
|
|
4
|
+
|
|
5
|
+
const SECURE_FILES_HOST_PREFIX = 'secure-files.';
|
|
6
|
+
const SECURE_MEDIA_PATH_PREFIX = '/secure-media/';
|
|
7
|
+
|
|
8
|
+
const FILE_TOKEN_PARAM = 'ft';
|
|
9
|
+
|
|
10
|
+
export const resolveFileUrl = (url?: string | null): string => {
|
|
11
|
+
if (!url) {return '';}
|
|
12
|
+
// Any scheme at all — http(s), data, file, content, blob.
|
|
13
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {return url;}
|
|
14
|
+
if (!url.startsWith('/')) {return url;}
|
|
15
|
+
|
|
16
|
+
const base = getCurrentBaseURL().replace(/\/+$/, '');
|
|
17
|
+
return base ? `${base}${url}` : url;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const isSecureFileUrl = (url?: string | null): boolean => {
|
|
21
|
+
if (!url) {return false;}
|
|
22
|
+
|
|
23
|
+
const path = url.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]*/i, '');
|
|
24
|
+
if (path.startsWith(SECURE_MEDIA_PATH_PREFIX)) {return true;}
|
|
25
|
+
|
|
26
|
+
const match = /^https?:\/\/(?:[^@/]+@)?([^:/?#]+)/i.exec(url);
|
|
27
|
+
if (!match) {return false;}
|
|
28
|
+
return match[1].toLowerCase().startsWith(SECURE_FILES_HOST_PREFIX);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const appendFileToken = (
|
|
32
|
+
url: string | null | undefined,
|
|
33
|
+
fileToken: string | null | undefined
|
|
34
|
+
): string => {
|
|
35
|
+
if (!url) {return '';}
|
|
36
|
+
|
|
37
|
+
const resolved = resolveFileUrl(url);
|
|
38
|
+
if (!fileToken || !isSecureFileUrl(resolved)) {return resolved;}
|
|
39
|
+
url = resolved;
|
|
40
|
+
|
|
41
|
+
const hashIndex = url.indexOf('#');
|
|
42
|
+
const hash = hashIndex === -1 ? '' : url.slice(hashIndex);
|
|
43
|
+
const withoutHash = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
44
|
+
|
|
45
|
+
const queryIndex = withoutHash.indexOf('?');
|
|
46
|
+
const base = queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);
|
|
47
|
+
const query = queryIndex === -1 ? '' : withoutHash.slice(queryIndex + 1);
|
|
48
|
+
|
|
49
|
+
const params = query
|
|
50
|
+
.split('&')
|
|
51
|
+
.filter(Boolean)
|
|
52
|
+
.filter((pair) => pair.split('=')[0] !== FILE_TOKEN_PARAM);
|
|
53
|
+
|
|
54
|
+
params.push(`${FILE_TOKEN_PARAM}=${encodeURIComponent(fileToken)}`);
|
|
55
|
+
|
|
56
|
+
return `${base}?${params.join('&')}${hash}`;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const withFileToken = (url?: string | null): string =>
|
|
60
|
+
appendFileToken(
|
|
61
|
+
url,
|
|
62
|
+
store.getState().chatSettingStore?.user?.fileToken || ''
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const RECOVERY_COOLDOWN_MS = 30_000;
|
|
66
|
+
let recoveryInFlight: Promise<boolean> | null = null;
|
|
67
|
+
let lastRecoveryAt = 0;
|
|
68
|
+
|
|
69
|
+
export const requestFileTokenRecovery = (): Promise<boolean> => {
|
|
70
|
+
if (recoveryInFlight) {return recoveryInFlight;}
|
|
71
|
+
|
|
72
|
+
const now = Date.now();
|
|
73
|
+
if (now - lastRecoveryAt < RECOVERY_COOLDOWN_MS) {
|
|
74
|
+
return Promise.resolve(false);
|
|
75
|
+
}
|
|
76
|
+
lastRecoveryAt = now;
|
|
77
|
+
|
|
78
|
+
const state = store.getState();
|
|
79
|
+
const refreshConfig = state.chatSettingStore?.config?.refreshTokens;
|
|
80
|
+
const user = state.chatSettingStore?.user;
|
|
81
|
+
|
|
82
|
+
if (!refreshConfig?.enabled) {return Promise.resolve(false);}
|
|
83
|
+
|
|
84
|
+
const run = async (): Promise<boolean> => {
|
|
85
|
+
if (!refreshConfig.refreshFunction && !user?.refreshToken) {return false;}
|
|
86
|
+
|
|
87
|
+
const tokens = await refreshAuthTokens();
|
|
88
|
+
return Boolean(tokens.fileToken);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
recoveryInFlight = run()
|
|
92
|
+
.catch(() => false)
|
|
93
|
+
.finally(() => {
|
|
94
|
+
recoveryInFlight = null;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return recoveryInFlight;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const __resetFileTokenRecoveryForTests = (): void => {
|
|
101
|
+
recoveryInFlight = null;
|
|
102
|
+
lastRecoveryAt = 0;
|
|
103
|
+
};
|
|
@@ -10,7 +10,7 @@ import { chatAutoEnterer } from '../helpers/chatAutoEnterer';
|
|
|
10
10
|
import { initRoomsPresence } from '../helpers/initRoomsPresence';
|
|
11
11
|
import { updatedChatLastTimestamps } from '../helpers/updatedChatLastTimestamps';
|
|
12
12
|
import { updateMessagesTillLast } from '../helpers/updateMessagesTillLast';
|
|
13
|
-
import {
|
|
13
|
+
import { refreshAuthTokensQuietly } from '../networking/authRefresh';
|
|
14
14
|
import { setLangSource, setConfig } from '../roomStore/chatSettingsSlice';
|
|
15
15
|
import { setIsLoading } from '../roomStore/roomsSlice';
|
|
16
16
|
import { useRoomState } from './useRoomState';
|
|
@@ -179,7 +179,7 @@ const useChatWrapperInit = ({
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
{
|
|
182
|
-
config?.refreshTokens?.enabled &&
|
|
182
|
+
config?.refreshTokens?.enabled && refreshAuthTokensQuietly();
|
|
183
183
|
}
|
|
184
184
|
} catch (error) {
|
|
185
185
|
console.error(' Error during initialization', error);
|
|
@@ -233,7 +233,7 @@ const useChatWrapperInit = ({
|
|
|
233
233
|
setConnectionLost(false);
|
|
234
234
|
}
|
|
235
235
|
{
|
|
236
|
-
config?.refreshTokens?.enabled &&
|
|
236
|
+
config?.refreshTokens?.enabled && refreshAuthTokensQuietly();
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
clearMessageFailure,
|
|
10
10
|
markMessageFailed,
|
|
11
11
|
} from '../roomStore/roomHeapSlice';
|
|
12
|
-
import {
|
|
12
|
+
import { uploadFileV2 } from '../networking/api-requests/auth.api';
|
|
13
13
|
import { enqueueOutboundSend } from '../networking/outboundQueue';
|
|
14
14
|
import { RootState, store } from '../roomStore';
|
|
15
15
|
import { getGlobalXmppClient } from '../utils/clientRegistry';
|
|
@@ -182,13 +182,34 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
182
182
|
// PENDING_WATCHDOG_MS, flip the bubble to "failed → tap to
|
|
183
183
|
// retry". We check at fire-time whether the message is still
|
|
184
184
|
// pending and not already marked failed by the catch path.
|
|
185
|
-
|
|
185
|
+
// One-shot extension for the case below. Declared outside the
|
|
186
|
+
// timer so the rescheduled run can't extend again.
|
|
187
|
+
let watchdogExtended = false;
|
|
188
|
+
const runWatchdog = () => {
|
|
186
189
|
const state = reduxStore.getState();
|
|
187
190
|
const roomMsgs = state.rooms?.rooms?.[activeRoomJID]?.messages || [];
|
|
188
191
|
const stillPending = roomMsgs.find(
|
|
189
192
|
(m: any) => m.id === optimisticId && m.pending
|
|
190
193
|
);
|
|
191
194
|
const alreadyFailed = state.roomHeapSlice?.failedMessages?.[optimisticId];
|
|
195
|
+
|
|
196
|
+
// Don't call it a failure while the stream is still coming back.
|
|
197
|
+
// A reconnect tears the old client down and builds a new one, and
|
|
198
|
+
// any echo in flight during that window is simply lost — the
|
|
199
|
+
// message may well have been delivered (it has been observed
|
|
200
|
+
// arriving twice on the receiving side). Failing it here shows a
|
|
201
|
+
// red "tap to retry" under a message that actually went through.
|
|
202
|
+
// Give the reconnect one more window to produce an echo, once.
|
|
203
|
+
const streamOnline = getGlobalXmppClient()?.status === 'online';
|
|
204
|
+
if (stillPending && !alreadyFailed && !streamOnline && !watchdogExtended) {
|
|
205
|
+
watchdogExtended = true;
|
|
206
|
+
console.warn(
|
|
207
|
+
`Send watchdog — ${optimisticId} still pending but the stream is not online; extending one window`
|
|
208
|
+
);
|
|
209
|
+
watchdogTimer = setTimeout(runWatchdog, PENDING_WATCHDOG_MS);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
192
213
|
if (stillPending && !alreadyFailed) {
|
|
193
214
|
console.warn(
|
|
194
215
|
`Send watchdog fired — message ${optimisticId} stuck pending > ${PENDING_WATCHDOG_MS}ms; marking failed`
|
|
@@ -211,7 +232,9 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
211
232
|
messageType: 'text',
|
|
212
233
|
});
|
|
213
234
|
}
|
|
214
|
-
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
let watchdogTimer = setTimeout(runWatchdog, PENDING_WATCHDOG_MS);
|
|
215
238
|
|
|
216
239
|
try {
|
|
217
240
|
// The single send closure, used both for the immediate send and for
|
|
@@ -467,19 +490,11 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
467
490
|
name: data?.name || data?.fileName || `media_${Date.now()}`,
|
|
468
491
|
};
|
|
469
492
|
|
|
470
|
-
// Mirror the web client: a single multipart POST to /files/ with
|
|
471
|
-
// the file under the plural "files" field. We send it via fetch
|
|
472
|
-
// (not axios) because RN's fetch sets the multipart boundary on the
|
|
473
|
-
// Content-Type header correctly. The previous axios fallback omitted
|
|
474
|
-
// a valid boundary, so the server mis-parsed one file as many and
|
|
475
|
-
// rejected the request with HTTP 413 "TOO_MANY_FILES". The only
|
|
476
|
-
// retry is the documented singular-"file" fallback for deployments
|
|
477
|
-
// that 500 on the plural field (bug #10).
|
|
478
493
|
const tryUpload = async () => {
|
|
479
494
|
const fd = new FormData();
|
|
480
495
|
fd.append('files', fileBlob as any);
|
|
481
496
|
try {
|
|
482
|
-
return await
|
|
497
|
+
return await uploadFileV2(fd, activeRoomJID);
|
|
483
498
|
} catch (err: any) {
|
|
484
499
|
if (err?.response?.status === 500) {
|
|
485
500
|
console.warn(
|
|
@@ -488,7 +503,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
488
503
|
);
|
|
489
504
|
const fd2 = new FormData();
|
|
490
505
|
fd2.append('file', fileBlob as any);
|
|
491
|
-
return await
|
|
506
|
+
return await uploadFileV2(fd2, activeRoomJID);
|
|
492
507
|
}
|
|
493
508
|
throw err;
|
|
494
509
|
}
|
package/src/main.ts
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
*
|
|
8
8
|
* <Chat
|
|
9
9
|
* config={{
|
|
10
|
-
*
|
|
10
|
+
* // The API ROOT — the SDK versions every path itself
|
|
11
|
+
* // (`/v1/...`, `/v2/...`). A legacy `.../v1` is accepted and
|
|
12
|
+
* // normalised, so existing integrations keep working.
|
|
13
|
+
* baseUrl: 'https://api.chat.ethora.com',
|
|
11
14
|
* xmppSettings: { host: 'xmpp.chat.ethora.com' },
|
|
12
15
|
* jwtLogin: { enabled: true, token: '<paste JWT>' },
|
|
13
16
|
* initBeforeLoad: true,
|
|
@@ -66,3 +69,21 @@ export type {
|
|
|
66
69
|
} from './types/types';
|
|
67
70
|
export type { Iso639_1Codes } from './types/models/language.model';
|
|
68
71
|
export type { TranslateMode } from './utils/translateModePolicy';
|
|
72
|
+
|
|
73
|
+
// Auth-token rotation. Exposed so hosts can drive a refresh themselves
|
|
74
|
+
// (it is deduped and shares the SDK's lock) and, more importantly, so
|
|
75
|
+
// they can tell a dead session from a transient failure: only
|
|
76
|
+
// `RefreshFatalError` means "log the user out". Every other rejection —
|
|
77
|
+
// network, 5xx, a lost REFRESH_IN_PROGRESS race — must leave the
|
|
78
|
+
// session alone.
|
|
79
|
+
export {
|
|
80
|
+
refreshAuthTokens,
|
|
81
|
+
refreshAuthTokensQuietly,
|
|
82
|
+
RefreshFatalError,
|
|
83
|
+
isRefreshFatalError,
|
|
84
|
+
} from './networking/authRefresh';
|
|
85
|
+
export type {
|
|
86
|
+
RefreshErrorCode,
|
|
87
|
+
RefreshResult,
|
|
88
|
+
RefreshOptions,
|
|
89
|
+
} from './networking/authRefresh';
|
|
@@ -18,8 +18,9 @@ export async function loginEmail(email: string, password: string) {
|
|
|
18
18
|
user: User;
|
|
19
19
|
refreshToken: string;
|
|
20
20
|
token: string;
|
|
21
|
+
fileToken?: string;
|
|
21
22
|
}>(
|
|
22
|
-
'/users/login-with-email',
|
|
23
|
+
'/v1/users/login-with-email',
|
|
23
24
|
{
|
|
24
25
|
email,
|
|
25
26
|
password,
|
|
@@ -29,6 +30,16 @@ export async function loginEmail(email: string, password: string) {
|
|
|
29
30
|
|
|
30
31
|
console.log('loginEmail res', res.data);
|
|
31
32
|
|
|
33
|
+
// The fileToken arrives at the TOP level of the login response, next to
|
|
34
|
+
// token/refreshToken — not inside `user`. Folding it in here is what
|
|
35
|
+
// makes secure media (`secure-files.*`, uploaded via /v2/files/secure)
|
|
36
|
+
// render at all: without it every such image 403s and the bubble comes
|
|
37
|
+
// up blank.
|
|
38
|
+
res.data.user = {
|
|
39
|
+
...res.data.user,
|
|
40
|
+
fileToken: res.data.fileToken || '',
|
|
41
|
+
};
|
|
42
|
+
|
|
32
43
|
return res;
|
|
33
44
|
}
|
|
34
45
|
|
|
@@ -39,7 +50,7 @@ export function loginSocial(
|
|
|
39
50
|
authToken: string = 'authToken'
|
|
40
51
|
) {
|
|
41
52
|
return http.post<any>(
|
|
42
|
-
'/users/login',
|
|
53
|
+
'/v1/users/login',
|
|
43
54
|
{
|
|
44
55
|
idToken,
|
|
45
56
|
accessToken,
|
|
@@ -58,7 +69,7 @@ export function registerSocial(
|
|
|
58
69
|
signUpPlan?: string
|
|
59
70
|
) {
|
|
60
71
|
return http.post(
|
|
61
|
-
'/users',
|
|
72
|
+
'/v1/users',
|
|
62
73
|
{
|
|
63
74
|
idToken,
|
|
64
75
|
accessToken,
|
|
@@ -72,7 +83,7 @@ export function registerSocial(
|
|
|
72
83
|
|
|
73
84
|
export function checkEmailExist(email: string) {
|
|
74
85
|
return http.get(
|
|
75
|
-
'/users/checkEmail/' + email,
|
|
86
|
+
'/v1/users/checkEmail/' + email,
|
|
76
87
|
|
|
77
88
|
{ headers: { Authorization: getCurrentAppToken() } }
|
|
78
89
|
);
|
|
@@ -84,7 +95,8 @@ export async function loginViaJwt(clientToken: string): Promise<User> {
|
|
|
84
95
|
user: User;
|
|
85
96
|
refreshToken: string;
|
|
86
97
|
token: string;
|
|
87
|
-
|
|
98
|
+
fileToken?: string;
|
|
99
|
+
}>('/v1/users/client', null, { headers: { 'x-custom-token': clientToken } });
|
|
88
100
|
|
|
89
101
|
console.log('✅ loginViaJwt: Received response', {
|
|
90
102
|
hasUser: !!response.data.user,
|
|
@@ -103,6 +115,8 @@ export async function loginViaJwt(clientToken: string): Promise<User> {
|
|
|
103
115
|
...response.data.user,
|
|
104
116
|
refreshToken: response.data.refreshToken,
|
|
105
117
|
token: response.data.token,
|
|
118
|
+
// Top-level, same as loginEmail — see the note there.
|
|
119
|
+
fileToken: response.data.fileToken || '',
|
|
106
120
|
};
|
|
107
121
|
|
|
108
122
|
return user;
|
|
@@ -131,7 +145,7 @@ export async function loginViaJwt(clientToken: string): Promise<User> {
|
|
|
131
145
|
|
|
132
146
|
export function uploadFile(formData: FormData) {
|
|
133
147
|
const token = store.getState().chatSettingStore?.user?.token ?? '';
|
|
134
|
-
return http.post('/files/', formData, {
|
|
148
|
+
return http.post('/v1/files/', formData, {
|
|
135
149
|
headers: {
|
|
136
150
|
Authorization: token,
|
|
137
151
|
Accept: '*/*',
|
|
@@ -144,79 +158,91 @@ export function uploadFile(formData: FormData) {
|
|
|
144
158
|
});
|
|
145
159
|
}
|
|
146
160
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
161
|
+
const SECURE_UPLOAD_PATH = '/v2/files/secure';
|
|
162
|
+
const LEGACY_UPLOAD_PATH = '/v1/files/';
|
|
163
|
+
|
|
164
|
+
const cloneFormData = (formData: FormData): FormData => {
|
|
165
|
+
const copy = new FormData();
|
|
166
|
+
const source = formData as any;
|
|
167
|
+
|
|
168
|
+
if (Array.isArray(source?._parts)) {
|
|
169
|
+
for (const [key, value] of source._parts) {
|
|
170
|
+
copy.append(key, value);
|
|
171
|
+
}
|
|
172
|
+
return copy;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (typeof source?.forEach === 'function') {
|
|
176
|
+
source.forEach((value: any, key: string) => copy.append(key, value));
|
|
177
|
+
return copy;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (typeof source?.getParts === 'function') {
|
|
181
|
+
for (const part of source.getParts()) {
|
|
182
|
+
// `headers` is derived by getParts() and must not be copied back —
|
|
183
|
+
// RN regenerates it from the value.
|
|
184
|
+
const { fieldName, string, headers: _headers, ...file } = part;
|
|
185
|
+
copy.append(fieldName, string !== undefined ? string : file);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return copy;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
function postMultipart(
|
|
193
|
+
url: string,
|
|
194
|
+
body: FormData,
|
|
195
|
+
path: string
|
|
196
|
+
): Promise<{ data: any }> {
|
|
176
197
|
const token = store.getState().chatSettingStore?.user?.token ?? '';
|
|
177
|
-
const baseUrl = getCurrentBaseURL();
|
|
178
|
-
const url = `${baseUrl.replace(/\/$/, '')}${UPLOAD_PATH}`;
|
|
179
198
|
|
|
180
199
|
pushLog('http', `→ POST ${url} (xhr)`, {
|
|
181
|
-
|
|
200
|
+
path,
|
|
201
|
+
baseUrl: getCurrentBaseURL() || '[empty]',
|
|
202
|
+
headers: {
|
|
203
|
+
Authorization: token ? token.slice(0, 16) + '…' : '[empty]',
|
|
204
|
+
Accept: '*/*',
|
|
205
|
+
},
|
|
182
206
|
});
|
|
183
207
|
|
|
184
208
|
return new Promise((resolve, reject) => {
|
|
185
209
|
const xhr = new XMLHttpRequest();
|
|
186
210
|
|
|
187
211
|
const failNetwork = (reason: string) => {
|
|
188
|
-
pushLog('http', `← ERR xhr ${
|
|
212
|
+
pushLog('http', `← ERR xhr ${path}`, { reason, url });
|
|
189
213
|
const err: any = new Error(reason);
|
|
190
214
|
err.code = 'ERR_NETWORK';
|
|
191
|
-
err.config = { url:
|
|
215
|
+
err.config = { url: path };
|
|
192
216
|
reject(err);
|
|
193
217
|
};
|
|
194
218
|
|
|
195
219
|
xhr.onload = () => {
|
|
196
220
|
const status = xhr.status;
|
|
197
|
-
let
|
|
221
|
+
let responseBody: any = null;
|
|
198
222
|
try {
|
|
199
|
-
|
|
223
|
+
responseBody = JSON.parse(xhr.responseText);
|
|
200
224
|
} catch {
|
|
201
|
-
|
|
225
|
+
responseBody = xhr.responseText || null;
|
|
202
226
|
}
|
|
203
227
|
|
|
204
228
|
if (status < 200 || status >= 300) {
|
|
205
|
-
pushLog('http', `← ${status} POST ${
|
|
229
|
+
pushLog('http', `← ${status} POST ${path} (xhr)`, responseBody);
|
|
206
230
|
const err: any = new Error(`Upload failed: ${status}`);
|
|
207
231
|
// Shaped like an axios error so callers' `err.response.status`
|
|
208
232
|
// checks keep working — notably useSendMessage's retry with the
|
|
209
233
|
// singular "file" field on 500.
|
|
210
|
-
err.response = { status, statusText: xhr.statusText, data:
|
|
211
|
-
err.config = { url:
|
|
234
|
+
err.response = { status, statusText: xhr.statusText, data: responseBody };
|
|
235
|
+
err.config = { url: path };
|
|
212
236
|
reject(err);
|
|
213
237
|
return;
|
|
214
238
|
}
|
|
215
239
|
|
|
216
|
-
pushLog('http', `← ${status} POST ${
|
|
217
|
-
resultsCount: Array.isArray(
|
|
240
|
+
pushLog('http', `← ${status} POST ${path} (xhr)`, {
|
|
241
|
+
resultsCount: Array.isArray(responseBody?.results)
|
|
242
|
+
? responseBody.results.length
|
|
243
|
+
: 'n/a',
|
|
218
244
|
});
|
|
219
|
-
resolve({ data:
|
|
245
|
+
resolve({ data: responseBody });
|
|
220
246
|
};
|
|
221
247
|
|
|
222
248
|
xhr.onerror = () => failNetwork('Network request failed');
|
|
@@ -226,8 +252,55 @@ export function uploadFileMultipart(formData: FormData): Promise<{ data: any }>
|
|
|
226
252
|
xhr.open('POST', url);
|
|
227
253
|
xhr.setRequestHeader('Authorization', token);
|
|
228
254
|
xhr.setRequestHeader('Accept', '*/*');
|
|
229
|
-
// Deliberately no Content-Type — see the note above
|
|
230
|
-
|
|
231
|
-
xhr.send(formData as any);
|
|
255
|
+
// Deliberately no Content-Type — see the note above.
|
|
256
|
+
xhr.send(body as any);
|
|
232
257
|
});
|
|
233
258
|
}
|
|
259
|
+
|
|
260
|
+
const canFallBackToLegacyUpload = (error: unknown): boolean => {
|
|
261
|
+
const status = (error as { response?: { status?: number } })?.response
|
|
262
|
+
?.status;
|
|
263
|
+
if (typeof status !== 'number') {return true;}
|
|
264
|
+
return status !== 401 && status !== 413;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
let secureUploadUnavailable = false;
|
|
268
|
+
|
|
269
|
+
export async function uploadFileV2(
|
|
270
|
+
formData: FormData,
|
|
271
|
+
activeRoomJID: string
|
|
272
|
+
): Promise<{ data: any }> {
|
|
273
|
+
const chatName = (activeRoomJID || '').split('@')[0];
|
|
274
|
+
const apiRoot = getCurrentBaseURL().replace(/\/$/, '');
|
|
275
|
+
|
|
276
|
+
if (!secureUploadUnavailable && chatName) {
|
|
277
|
+
const body = cloneFormData(formData);
|
|
278
|
+
body.append('chatName', chatName);
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
return await postMultipart(
|
|
282
|
+
`${apiRoot}${SECURE_UPLOAD_PATH}`,
|
|
283
|
+
body,
|
|
284
|
+
SECURE_UPLOAD_PATH
|
|
285
|
+
);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (!canFallBackToLegacyUpload(error)) {throw error;}
|
|
288
|
+
|
|
289
|
+
secureUploadUnavailable = true;
|
|
290
|
+
console.warn(
|
|
291
|
+
`[chat] ${SECURE_UPLOAD_PATH} unreachable, falling back to ${LEGACY_UPLOAD_PATH} for this session`,
|
|
292
|
+
error
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return postMultipart(
|
|
298
|
+
`${apiRoot}${LEGACY_UPLOAD_PATH}`,
|
|
299
|
+
formData,
|
|
300
|
+
LEGACY_UPLOAD_PATH
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export const __resetSecureUploadLatchForTests = (): void => {
|
|
305
|
+
secureUploadUnavailable = false;
|
|
306
|
+
};
|
|
@@ -181,7 +181,7 @@ export async function getRooms(): Promise<{ items: ApiRoom[] }> {
|
|
|
181
181
|
|
|
182
182
|
getRoomsInFlightToken = token;
|
|
183
183
|
getRoomsInFlight = (async () => {
|
|
184
|
-
const response = await http.get('/chats/my', {
|
|
184
|
+
const response = await http.get('/v1/chats/my', {
|
|
185
185
|
headers: { Authorization: token },
|
|
186
186
|
});
|
|
187
187
|
lastGetRoomsResponse = response.data;
|
|
@@ -206,7 +206,7 @@ export async function getRoomByName(chatName: string): Promise<ApiRoom> {
|
|
|
206
206
|
const token = store.getState().chatSettingStore.user.token || '';
|
|
207
207
|
|
|
208
208
|
try {
|
|
209
|
-
const response = await http.get(`/chats/my/${chatName}`, {
|
|
209
|
+
const response = await http.get(`/v1/chats/my/${chatName}`, {
|
|
210
210
|
headers: {
|
|
211
211
|
Authorization: token,
|
|
212
212
|
},
|
|
@@ -221,7 +221,7 @@ export async function postRoom(data: PostRoom) {
|
|
|
221
221
|
const token = store.getState().chatSettingStore.user.token || '';
|
|
222
222
|
|
|
223
223
|
try {
|
|
224
|
-
const response = await http.post('/chats', data, {
|
|
224
|
+
const response = await http.post('/v1/chats', data, {
|
|
225
225
|
headers: {
|
|
226
226
|
Authorization: token,
|
|
227
227
|
},
|
|
@@ -240,7 +240,7 @@ export async function postPrivateRoom(
|
|
|
240
240
|
|
|
241
241
|
try {
|
|
242
242
|
const response = await http.post(
|
|
243
|
-
'/chats/private',
|
|
243
|
+
'/v1/chats/private',
|
|
244
244
|
{ username },
|
|
245
245
|
{
|
|
246
246
|
headers: {
|
|
@@ -260,7 +260,7 @@ export async function postReportRoom(data: PostReportRoom) {
|
|
|
260
260
|
|
|
261
261
|
try {
|
|
262
262
|
const response = await http.post(
|
|
263
|
-
`/chats/reports/${chatName}`,
|
|
263
|
+
`/v1/chats/reports/${chatName}`,
|
|
264
264
|
{ category, text },
|
|
265
265
|
{
|
|
266
266
|
headers: {
|
|
@@ -282,7 +282,7 @@ export async function postAddRoomMember(
|
|
|
282
282
|
|
|
283
283
|
try {
|
|
284
284
|
const response = await http.post(
|
|
285
|
-
`/chats/users-access`,
|
|
285
|
+
`/v1/chats/users-access`,
|
|
286
286
|
{ chatName, members },
|
|
287
287
|
{
|
|
288
288
|
headers: {
|
|
@@ -301,7 +301,7 @@ export async function deleteRoomMember(data: DeleteRoomMember) {
|
|
|
301
301
|
const token = store.getState().chatSettingStore.user.token || '';
|
|
302
302
|
|
|
303
303
|
try {
|
|
304
|
-
const response = await http.delete(`/chats/users-access`, {
|
|
304
|
+
const response = await http.delete(`/v1/chats/users-access`, {
|
|
305
305
|
headers: {
|
|
306
306
|
Authorization: token,
|
|
307
307
|
},
|
|
@@ -320,7 +320,7 @@ export async function deleteRoom(name: string) {
|
|
|
320
320
|
const token = store.getState().chatSettingStore.user.token || '';
|
|
321
321
|
|
|
322
322
|
try {
|
|
323
|
-
const response = await http.delete('/chats', {
|
|
323
|
+
const response = await http.delete('/v1/chats', {
|
|
324
324
|
headers: {
|
|
325
325
|
Authorization: token,
|
|
326
326
|
},
|
|
@@ -360,7 +360,7 @@ export async function createChatCall(
|
|
|
360
360
|
|
|
361
361
|
try {
|
|
362
362
|
await http.post(
|
|
363
|
-
`/chats/call/create/${chatName}`,
|
|
363
|
+
`/v1/chats/call/create/${chatName}`,
|
|
364
364
|
{ kind },
|
|
365
365
|
{
|
|
366
366
|
headers: {
|