@ethora/chat-component 26.9.6 → 26.10.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.
- package/README.md +45 -3
- package/dist/{ChatProfileModal-DKuxJsdM.js → ChatProfileModal-Bf5jGPBZ.js} +566 -562
- package/dist/FilePreviewModal-Bwx0RZZw.js +1763 -0
- package/dist/{ManageDataModal-Dw4dCQll.js → ManageDataModal-Dhkp0LWH.js} +20 -20
- package/dist/{MarkdownBody-xtKDMR0h.js → MarkdownBody-_sUhW2O8.js} +1 -1
- package/dist/{MessageSearchModal-BVKU6H3v.js → MessageSearchModal-rwwWrILl.js} +106 -114
- package/dist/{PublicChatsModal-CscOnVaQ.js → PublicChatsModal-Byso6_vt.js} +13 -13
- package/dist/{SideDrawer-WneDrrWG.js → SideDrawer-CQPOf0ek.js} +38 -38
- package/dist/{UserProfileModal-CMHFq1I9.js → UserProfileModal-Vj2kICvc.js} +10 -10
- package/dist/{UserSettingsModal-BoZXZ0oR.js → UserSettingsModal-CioX4ZIV.js} +5 -5
- package/dist/{VideoCallOverlay-CQNi7wp5.js → VideoCallOverlay-DodAkiam.js} +3824 -3708
- package/dist/{VisibilityModal-BPsNiMzJ.js → VisibilityModal-CIl7rkBM.js} +12 -12
- package/dist/assets/icons.d.ts +2 -3
- package/dist/components/Files/fileCategory.d.ts +4 -2
- package/dist/components/InputComponents/MentionDropdown.d.ts +2 -0
- package/dist/components/MainComponents/AlbumGrid.d.ts +22 -0
- package/dist/components/MainComponents/AttachmentList.d.ts +6 -6
- package/dist/components/MainComponents/ImageUnavailable.d.ts +21 -0
- package/dist/components/MainComponents/MediaUploadOverlay.d.ts +31 -0
- package/dist/components/MainComponents/MessageContainer.d.ts +3 -0
- package/dist/components/MainComponents/scrollAnchor.d.ts +19 -0
- package/dist/components/MainComponents/useJumpToMessage.d.ts +42 -11
- package/dist/components/MainComponents/useScrollAnchor.d.ts +29 -0
- package/dist/components/MessageBubble/MediaCaption.d.ts +9 -0
- package/dist/components/MessageBubble/MessageAvatarPhoto.d.ts +17 -0
- package/dist/components/MessageBubble/MessageReaction.d.ts +6 -0
- package/dist/components/MessageBubble/QuickReplies.d.ts +2 -0
- package/dist/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +8 -10
- package/dist/components/Modals/FilePreviewModal/ImageLightbox.d.ts +4 -0
- package/dist/components/Modals/FilePreviewModal/PdfView.d.ts +4 -0
- package/dist/components/Modals/FilePreviewModal/ViewerChrome.d.ts +64 -0
- package/dist/components/Modals/MessageSearchModal/MessageHitResults.d.ts +5 -0
- package/dist/components/Modals/styledModalComponents.d.ts +0 -8
- package/dist/components/RoomComponents/LastMessageItem.d.ts +2 -0
- package/dist/components/RoomComponents/styled/LastMessageMedia.d.ts +19 -0
- package/dist/components/RoomComponents/styled/LastTextMessage.d.ts +2 -2
- package/dist/components/RoomComponents/styled/StyledRoomComponents.d.ts +10 -3
- package/dist/components/VideoCalls/VideoCallSession.d.ts +13 -0
- package/dist/components/styled/FileCard.d.ts +20 -0
- package/dist/components/styled/MediaSurface.d.ts +50 -0
- package/dist/components/styled/MessageImage.d.ts +9 -10
- package/dist/components/styled/SendInput.d.ts +12 -2
- package/dist/components/styled/StyledComponents.d.ts +69 -2
- package/dist/components/styled/StyledInputComponents/MediaComponents.d.ts +36 -24
- package/dist/components/styled/UnsupportedType.d.ts +1 -0
- package/dist/components/styled/VideoMessage.d.ts +11 -6
- package/dist/e2ee/callKey.d.ts +32 -0
- package/dist/e2ee/fileEnvelope.d.ts +16 -5
- package/dist/e2ee/omemo.d.ts +18 -0
- package/dist/firebase-messaging-sw.js +20 -3
- package/dist/{handleCopyClick-B70vLjJD.js → handleCopyClick-DGaZhy_u.js} +1 -1
- package/dist/helpers/albumLayout.d.ts +53 -0
- package/dist/helpers/attachments.d.ts +22 -1
- package/dist/helpers/avatarImageCache.d.ts +9 -0
- package/dist/helpers/caption.d.ts +63 -0
- package/dist/helpers/checkUniqueUsers.d.ts +2 -2
- package/dist/helpers/composerFocus.d.ts +22 -0
- package/dist/helpers/createMainMessageForThread.d.ts +1 -1
- package/dist/helpers/dedupeMembers.d.ts +10 -0
- package/dist/helpers/downloadFile.d.ts +19 -0
- package/dist/helpers/fileKind.d.ts +17 -0
- package/dist/helpers/historyPreloadConfig.d.ts +25 -0
- package/dist/helpers/historyPreloadScheduler.d.ts +3 -0
- package/dist/helpers/insertMessageWithDelimiter.d.ts +1 -0
- package/dist/helpers/isMessageSearchEnabled.d.ts +9 -0
- package/dist/helpers/jumpThread.d.ts +56 -0
- package/dist/helpers/jumpWindow.d.ts +73 -0
- package/dist/helpers/lastMessagePreview.d.ts +55 -0
- package/dist/helpers/mapWithConcurrency.d.ts +8 -0
- package/dist/helpers/mediaBox.d.ts +110 -0
- package/dist/helpers/mediaBubble.d.ts +39 -0
- package/dist/helpers/mediaLabel.d.ts +10 -0
- package/dist/helpers/mediaSendRetry.d.ts +25 -0
- package/dist/helpers/messageRuns.d.ts +10 -0
- package/dist/helpers/openThreadForJump.d.ts +26 -0
- package/dist/helpers/pdf/loadPdfjs.d.ts +8 -1
- package/dist/helpers/repairFilenameEncoding.d.ts +11 -0
- package/dist/helpers/roomImageGallery.d.ts +34 -0
- package/dist/helpers/roomUserCount.d.ts +19 -0
- package/dist/helpers/safeUrl.d.ts +15 -0
- package/dist/helpers/secureFileUrl.d.ts +4 -1
- package/dist/helpers/userResolver.d.ts +57 -0
- package/dist/helpers/viewerSender.d.ts +47 -0
- package/dist/helpers/xmppIdShape.d.ts +1 -1
- package/dist/hooks/useAvatarImage.d.ts +21 -0
- package/dist/hooks/useChatWrapperInit.d.ts +6 -0
- package/dist/hooks/useIsMobileViewport.d.ts +5 -0
- package/dist/hooks/useMediaProbe.d.ts +40 -0
- package/dist/hooks/usePaneWidthVar.d.ts +11 -0
- package/dist/hooks/usePdfThumbnail.d.ts +2 -2
- package/dist/hooks/usePrefersReducedMotion.d.ts +2 -0
- package/dist/hooks/useRoomDirectory.d.ts +11 -0
- package/dist/hooks/useSendMessage.d.ts +4 -1
- package/dist/{main-rJpE4hh-.js → main-CUB_w8AZ.js} +29136 -24217
- package/dist/main.css +1 -1
- package/dist/main.js +16 -16
- package/dist/networking/api-requests/auth.api.d.ts +2 -0
- package/dist/networking/api-requests/roomMembers.api.d.ts +18 -0
- package/dist/networking/callKeyStanza.d.ts +7 -0
- package/dist/networking/ethoraEvents.d.ts +44 -0
- package/dist/networking/stanzaHandlers.d.ts +6 -4
- package/dist/networking/xmpp/allRoomPresences.xmpp.d.ts +18 -1
- package/dist/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -1
- package/dist/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +2 -0
- package/dist/networking/xmpp/sendMediaMessage.xmpp.d.ts +8 -0
- package/dist/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +2 -0
- package/dist/networking/xmppClient.d.ts +61 -2
- package/dist/roomStore/Middleware/jumpThreadMiddleware.d.ts +2 -0
- package/dist/roomStore/callSlice.d.ts +6 -1
- package/dist/roomStore/index.d.ts +22 -0
- package/dist/roomStore/roomsSlice.d.ts +51 -4
- package/dist/roomStore/safeKey.d.ts +12 -0
- package/dist/roomStore/usersSetCap.d.ts +15 -0
- package/dist/styles/motion.d.ts +22 -2
- package/dist/types/models/attachment.model.d.ts +19 -0
- package/dist/types/models/config.model.d.ts +98 -5
- package/dist/types/models/customComponents.model.d.ts +2 -0
- package/dist/types/models/message.model.d.ts +9 -0
- package/dist/types/models/modal.model.d.ts +19 -0
- package/dist/types/models/room.model.d.ts +30 -0
- package/dist/types/models/xmpp.model.d.ts +24 -1
- package/dist/utils/messageNotificationContent.d.ts +34 -0
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/public/firebase-messaging-sw.js +20 -3
- package/dist/FilePreviewModal-BcaSoO3-.js +0 -743
- package/dist/components/MainComponents/computeAnchoredScrollTop.d.ts +0 -9
- package/dist/components/Modals/NewChatModal/UpdNewChatModal.d.ts +0 -3
- package/dist/components/RoomComponents/styled/LastAudioMessage.d.ts +0 -6
- package/dist/components/RoomComponents/styled/LastMessageFile.d.ts +0 -6
- package/dist/components/RoomComponents/styled/LastMessagePhoto.d.ts +0 -6
- package/dist/components/RoomComponents/styled/LastMessageVideo.d.ts +0 -6
- package/dist/components/SortDropDown/index.d.ts +0 -8
package/dist/main.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.ethora-chat-root{font-family:var( --ethora-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif );-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ethora-chat-root code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.ethora-chat-root,.ethora-chat-root *{scrollbar-width:thin;scrollbar-color:rgba(20,20,20,.22) transparent;scrollbar-color:var( --ethora-scrollbar-thumb, color-mix(in srgb, var(--ethora-icon-color, #0052cd) 35%, transparent) ) var(--ethora-scrollbar-track, transparent)}.ethora-chat-root::-webkit-scrollbar,.ethora-chat-root ::-webkit-scrollbar{width:8px;height:8px}.ethora-chat-root::-webkit-scrollbar-thumb,.ethora-chat-root ::-webkit-scrollbar-thumb{background-color:#14141438;background-color:var( --ethora-scrollbar-thumb, color-mix(in srgb, var(--ethora-icon-color, #0052cd) 35%, transparent) );border-radius:var(--ethora-radius-full, 999px);border:2px solid transparent;background-clip:content-box}.ethora-chat-root::-webkit-scrollbar-thumb:hover,.ethora-chat-root ::-webkit-scrollbar-thumb:hover{background-color:#14141466;background-color:var( --ethora-scrollbar-thumb-hover, color-mix(in srgb, var(--ethora-icon-color, #0052cd) 60%, transparent) );background-clip:content-box}.ethora-chat-root::-webkit-scrollbar-track,.ethora-chat-root ::-webkit-scrollbar-track{background-color:var(--ethora-scrollbar-track, transparent)}.ethora-apple-emoji{font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif}.ethora-chat-root .emoji-mart{max-width:320px;max-height:360px;overflow-y:auto;border-radius:12px;box-shadow:0 4px 12px #0000001a}[data-message-id].ethora-message-highlight{animation:
|
|
1
|
+
.ethora-chat-root{font-family:var( --ethora-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif );-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ethora-chat-root code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.ethora-chat-root,.ethora-chat-root *{scrollbar-width:thin;scrollbar-color:rgba(20,20,20,.22) transparent;scrollbar-color:var( --ethora-scrollbar-thumb, color-mix(in srgb, var(--ethora-icon-color, #0052cd) 35%, transparent) ) var(--ethora-scrollbar-track, transparent)}.ethora-chat-root::-webkit-scrollbar,.ethora-chat-root ::-webkit-scrollbar{width:8px;height:8px}.ethora-chat-root::-webkit-scrollbar-thumb,.ethora-chat-root ::-webkit-scrollbar-thumb{background-color:#14141438;background-color:var( --ethora-scrollbar-thumb, color-mix(in srgb, var(--ethora-icon-color, #0052cd) 35%, transparent) );border-radius:var(--ethora-radius-full, 999px);border:2px solid transparent;background-clip:content-box}.ethora-chat-root::-webkit-scrollbar-thumb:hover,.ethora-chat-root ::-webkit-scrollbar-thumb:hover{background-color:#14141466;background-color:var( --ethora-scrollbar-thumb-hover, color-mix(in srgb, var(--ethora-icon-color, #0052cd) 60%, transparent) );background-clip:content-box}.ethora-chat-root::-webkit-scrollbar-track,.ethora-chat-root ::-webkit-scrollbar-track{background-color:var(--ethora-scrollbar-track, transparent)}.ethora-apple-emoji{font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif}.ethora-chat-root .emoji-mart{max-width:320px;max-height:360px;overflow-y:auto;border-radius:12px;box-shadow:0 4px 12px #0000001a}[data-message-id].ethora-message-highlight{animation:none;transition:none}[data-message-id].ethora-message-highlight [data-ethora-bubble]{animation:ethoraBubblePulse 1s ease-out forwards}[data-message-id].ethora-message-highlight [data-ethora-bubble]:after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:1;background-color:color-mix(in srgb,var(--ethora-color-primary, #0052cd) 22%,transparent);animation:ethoraBubbleTint 1s ease-out forwards}@keyframes ethoraBubblePulse{0%{box-shadow:0 0 color-mix(in srgb,var(--ethora-color-primary, #0052cd) 55%,transparent)}35%{box-shadow:0 0 0 3px color-mix(in srgb,var(--ethora-color-primary, #0052cd) 60%,transparent),0 0 14px 2px color-mix(in srgb,var(--ethora-color-primary, #0052cd) 35%,transparent)}to{box-shadow:0 0 0 9px color-mix(in srgb,var(--ethora-color-primary, #0052cd) 0%,transparent)}}@keyframes ethoraBubbleTint{0%{opacity:0}20%{opacity:1}to{opacity:0}}@media(prefers-reduced-motion:reduce){[data-message-id].ethora-message-highlight [data-ethora-bubble]{animation:none;box-shadow:0 0 0 2px var(--ethora-color-primary, #0052cd)}[data-message-id].ethora-message-highlight [data-ethora-bubble]:after{animation:none;display:none}}.ethora-message-highlight{animation:ethoraMessageHighlight 1s ease-out;transition:background-color .3s ease}@keyframes ethoraMessageHighlight{0%{background-color:#2196f366;transform:scale(1.02);box-shadow:0 0 0 2px #2196f333}30%{background-color:#2196f34d;box-shadow:0 0 0 2px #2196f326}60%{background-color:#2196f333;box-shadow:0 0 0 1px #2196f31a}to{background-color:transparent;transform:scale(1);box-shadow:none}}@media(max-width:768px){.ethora-message-notification-container{left:50%!important;right:auto!important;transform:translate(-50%)!important;align-items:center!important}.ethora-message-notification-container[data-position-horizontal=left],.ethora-message-notification-container[data-position-horizontal=right]{left:50%!important;right:auto!important;transform:translate(-50%)!important}}
|
package/dist/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { br as a, bs as r, bt as b, bu as o, bv as t, bw as u, bx as i, by as p, bz as h, bA as n, bB as d, i as l, bC as y, S as I, bD as T, bE as f, bF as m, bG as R, bH as g, bI as c, bJ as C, bK as A, bL as E, aq as F, ar as M, bM as Q, bN as k } from "./main-CUB_w8AZ.js";
|
|
2
2
|
export {
|
|
3
3
|
a as AuthTestIds,
|
|
4
4
|
r as Chat,
|
|
@@ -10,21 +10,21 @@ export {
|
|
|
10
10
|
p as applyTypography,
|
|
11
11
|
h as clearTypography,
|
|
12
12
|
n as formatFingerprint,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
d as handleQRChatId,
|
|
14
|
+
l as isE2eeEnabled,
|
|
15
|
+
y as isRefreshFatalError,
|
|
16
|
+
I as logoutService,
|
|
17
17
|
T as omemo,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
f as parseQuickReplies,
|
|
19
|
+
m as refreshAuthTokens,
|
|
20
|
+
R as refreshAuthTokensQuietly,
|
|
21
|
+
g as resendMessage,
|
|
22
22
|
c as useInAppNotifications,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
C as useIsUserOnline,
|
|
24
|
+
A as usePushNotifications,
|
|
25
|
+
E as useQRCodeChat,
|
|
26
|
+
F as useRoomMute,
|
|
27
|
+
M as useRoomPresence,
|
|
28
|
+
Q as useTypography,
|
|
29
|
+
k as useUnread
|
|
30
30
|
};
|
|
@@ -27,6 +27,8 @@ export interface UploadFileOptions {
|
|
|
27
27
|
* BEFORE the secure/legacy split so both routes carry it.
|
|
28
28
|
*/
|
|
29
29
|
clientEncrypted?: boolean;
|
|
30
|
+
/** Upload progress for this request, 0 to 100. */
|
|
31
|
+
onProgress?: (percent: number) => void;
|
|
30
32
|
}
|
|
31
33
|
export declare function uploadFile(formData: FormData, activeRoomJID: string, options?: UploadFileOptions): Promise<import('axios').AxiosResponse<any, any, {}>>;
|
|
32
34
|
export declare function ensureUserFromMy(user: User | null | undefined): Promise<User | null>;
|
|
@@ -1,2 +1,20 @@
|
|
|
1
1
|
import { RoomMember } from '../../types/types';
|
|
2
|
+
export type UserLookupRoute = 'auto' | 'v1' | 'v2';
|
|
3
|
+
export type UserLookupOutcome = {
|
|
4
|
+
status: 'ok';
|
|
5
|
+
user: RoomMember;
|
|
6
|
+
} | {
|
|
7
|
+
status: 'notfound' | 'forbidden' | 'error';
|
|
8
|
+
};
|
|
9
|
+
/** Module-level override of config.userLookupRoute (tests, non-React hosts). */
|
|
10
|
+
export declare const setUserLookupRoute: (route: UserLookupRoute | null) => void;
|
|
11
|
+
/** Forgets what was learned about the routes (account change, logout, tests). */
|
|
12
|
+
export declare const resetUserLookupRoute: () => void;
|
|
13
|
+
/** Visible for tests and diagnostics. */
|
|
14
|
+
export declare const isUserV1RouteUnsupported: () => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* One user by `appId_userId`, through the route chain above. Never throws.
|
|
17
|
+
* `forbidden` and `notfound` are per-user answers, `error` is transient.
|
|
18
|
+
*/
|
|
19
|
+
export declare function lookupUser(id: string, token: string): Promise<UserLookupOutcome>;
|
|
2
20
|
export declare function getUserByXmppUsername(xmppUsername: string | undefined, token: string): Promise<RoomMember | null>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Element } from 'ltx';
|
|
2
|
+
/**
|
|
3
|
+
* Claims a decrypted <call-key> signal, feeding the media key into the call
|
|
4
|
+
* slice. Returns true when it handled the stanza (so the caller stops
|
|
5
|
+
* dispatching it to the chat handlers).
|
|
6
|
+
*/
|
|
7
|
+
export declare function onCallKeyStanza(stanza: Element): boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Element } from 'ltx';
|
|
2
|
+
/**
|
|
3
|
+
* Server push `<ethora-event xmlns="urn:ethora:events:1" .../>` inside a
|
|
4
|
+
* `type="headline"` message from the server's admin account:
|
|
5
|
+
*
|
|
6
|
+
* user-profile-updated xmppUsername="<appId>_<userId>" uuid appId
|
|
7
|
+
* chat-meta-updated chatName="<appId>_<roomId>" appId
|
|
8
|
+
*
|
|
9
|
+
* The payload is a pointer only. The client re-reads the user or the room
|
|
10
|
+
* through the normal API, so nothing in the stanza is ever shown or stored.
|
|
11
|
+
* Everything in the stanza is untrusted input until proven otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export declare const ETHORA_EVENT_XMLNS = "urn:ethora:events:1";
|
|
14
|
+
export declare const ETHORA_EVENT_USER_PROFILE = "user-profile-updated";
|
|
15
|
+
export declare const ETHORA_EVENT_CHAT_META = "chat-meta-updated";
|
|
16
|
+
type HostLike = {
|
|
17
|
+
host?: string;
|
|
18
|
+
client?: {
|
|
19
|
+
jid?: {
|
|
20
|
+
getDomain?: () => string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* True when a headline came from the server and not from a user or a room.
|
|
26
|
+
* - from must be a BARE jid (a user's c2s stanza or a MUC occupant always
|
|
27
|
+
* carries a resource, and the server stamps it, so it cannot be spoofed)
|
|
28
|
+
* - its domain must be the session's own XMPP domain (not conference.*, not
|
|
29
|
+
* another server)
|
|
30
|
+
* - when config.trustedEventSenders is set, the sender must be listed
|
|
31
|
+
* The server's admin local part is deployment config (XMPP_ADMIN), so it
|
|
32
|
+
* cannot be hard-coded here.
|
|
33
|
+
*/
|
|
34
|
+
export declare const isTrustedEventSender: (stanza: Element, xmppWs: HostLike | undefined) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Handles `<ethora-event>` headlines. Returns true when the stanza carried
|
|
37
|
+
* one (trusted or not), so the caller can stop routing it. Unknown types,
|
|
38
|
+
* malformed attributes and untrusted senders are ignored silently. Never
|
|
39
|
+
* throws.
|
|
40
|
+
*/
|
|
41
|
+
export declare function onEthoraEvent(stanza: Element, xmppWs?: HostLike): boolean;
|
|
42
|
+
/** Drops timers and per-room state (tests, logout). */
|
|
43
|
+
export declare function resetEthoraEvents(): void;
|
|
44
|
+
export {};
|
|
@@ -4,9 +4,11 @@ import { default as XmppClient } from './xmppClient';
|
|
|
4
4
|
declare const onRealtimeMessage: (stanza: Element, xmppClient?: XmppClient) => Promise<IMessage>;
|
|
5
5
|
declare const onReactionMessage: (stanza: Element) => Promise<void>;
|
|
6
6
|
declare const onDeleteMessage: (stanza: Element) => Promise<void>;
|
|
7
|
+
declare const onReceivedReceipt: (stanza: Element) => Promise<void>;
|
|
8
|
+
declare const onDisplayedMarker: (stanza: Element) => Promise<void>;
|
|
7
9
|
declare const onEditMessage: (stanza: Element) => Promise<void>;
|
|
8
10
|
declare const onReactionHistory: (stanza: any) => Promise<void>;
|
|
9
|
-
declare const onMessageHistory: (stanza: any) => Promise<void>;
|
|
11
|
+
declare const onMessageHistory: (stanza: any, xmppClient?: XmppClient) => Promise<void>;
|
|
10
12
|
declare const handleComposing: (stanza: Element, currentUser: string) => Promise<void>;
|
|
11
13
|
declare const onPresenceInRoom: (stanza: Element | any) => void;
|
|
12
14
|
declare const onChatInvite: (stanza: Element, client: XmppClient) => Promise<void>;
|
|
@@ -29,6 +31,6 @@ export type XMPPErrorInfo = {
|
|
|
29
31
|
message: string;
|
|
30
32
|
};
|
|
31
33
|
export declare const handleErrorMessageStanza: (stanza: Element) => XMPPErrorInfo | null;
|
|
32
|
-
declare const onUserUpdate: (stanza: Element) => Promise<void>;
|
|
33
|
-
declare const onChatUpdate: (stanza: Element) => Promise<void>;
|
|
34
|
-
export { onRealtimeMessage, onMessageHistory, onPresenceInRoom, onReactionHistory, onGetLastMessageArchive, handleComposing, onGetChatRooms, onNewRoomCreated, onGetMembers, onGetRoomInfo, onDeleteMessage, onEditMessage, onReactionMessage, onChatInvite, onRoomKicked, onRoomMembershipChange, onMembersRefreshSignal, onMessageError, onUserUpdate, onChatUpdate, };
|
|
34
|
+
declare const onUserUpdate: (stanza: Element, xmppWs?: XmppClient) => Promise<void>;
|
|
35
|
+
declare const onChatUpdate: (stanza: Element, xmppWs?: XmppClient) => Promise<void>;
|
|
36
|
+
export { onRealtimeMessage, onMessageHistory, onPresenceInRoom, onReactionHistory, onGetLastMessageArchive, handleComposing, onGetChatRooms, onNewRoomCreated, onGetMembers, onGetRoomInfo, onDeleteMessage, onEditMessage, onReactionMessage, onReceivedReceipt, onDisplayedMarker, onChatInvite, onRoomKicked, onRoomMembershipChange, onMembersRefreshSignal, onMessageError, onUserUpdate, onChatUpdate, };
|
|
@@ -11,4 +11,21 @@ export interface AllRoomPresenceSummary {
|
|
|
11
11
|
}>;
|
|
12
12
|
}
|
|
13
13
|
export type RoomJoiner = (roomJid: string) => Promise<boolean>;
|
|
14
|
-
export
|
|
14
|
+
export interface AllRoomPresencesOptions {
|
|
15
|
+
/** Parallel joins. Default 5. */
|
|
16
|
+
concurrency?: number;
|
|
17
|
+
/** Pause after each join, per worker. Default 30 ms. */
|
|
18
|
+
pacingMs?: number;
|
|
19
|
+
/** Rooms the connection already joined: skipped, no round trip. */
|
|
20
|
+
isJoined?: (roomJid: string) => boolean;
|
|
21
|
+
/** The room the user has open: always joined next, ahead of the queue. */
|
|
22
|
+
getActiveRoomJid?: () => string | null | undefined;
|
|
23
|
+
/** Higher = joined earlier (recent activity). Default: store order. */
|
|
24
|
+
rank?: (roomJid: string) => number;
|
|
25
|
+
/** True once this sweep is obsolete (connection dropped and replaced). */
|
|
26
|
+
isCancelled?: () => boolean;
|
|
27
|
+
/** Fired once the first wave (the active room plus one pool-width of the
|
|
28
|
+
* most recent rooms) has settled, long before the rest of the sweep. */
|
|
29
|
+
onPriorityDone?: () => void;
|
|
30
|
+
}
|
|
31
|
+
export declare function allRoomPresences(client: Client, join?: RoomJoiner, options?: AllRoomPresencesOptions): Promise<AllRoomPresenceSummary>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Client } from '@xmpp/client';
|
|
2
2
|
import { Element } from '@xmpp/xml';
|
|
3
|
-
export declare const presenceInRoom: (client: Client, roomJID: string, delay?: number, timeoutMs?: number) => Promise<Element>;
|
|
3
|
+
export declare const presenceInRoom: (client: Client, roomJID: string, delay?: number, timeoutMs?: number, historyStanzas?: number) => Promise<Element>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Client } from '@xmpp/client';
|
|
2
|
+
import { IMentionSpan } from '../../types/types';
|
|
2
3
|
/**
|
|
3
4
|
* What <body> carries in an e2ee room: the key material for each sealed
|
|
4
5
|
* attachment, in the same order as `attachments` / the flat fields on <data>.
|
|
@@ -9,5 +10,12 @@ import { Client } from '@xmpp/client';
|
|
|
9
10
|
export interface E2eeMediaBody {
|
|
10
11
|
v: 1;
|
|
11
12
|
keys: string[];
|
|
13
|
+
/**
|
|
14
|
+
* The text typed with the files. It lives here, inside the envelope, and
|
|
15
|
+
* nowhere on <data>, so an e2ee caption is never readable in transit.
|
|
16
|
+
* Older readers only look at `keys` and ignore the rest.
|
|
17
|
+
*/
|
|
18
|
+
caption?: string;
|
|
19
|
+
captionMentions?: IMentionSpan[];
|
|
12
20
|
}
|
|
13
21
|
export declare function sendMediaMessage(client: Client, roomJID: string, data: any, id: string): Promise<void>;
|
|
@@ -2,6 +2,18 @@ import { Client } from '@xmpp/client';
|
|
|
2
2
|
import { Iso639_1Codes, XmppClientInterface, xmppSettingsInterface, IMessage, IMentionSpan } from '../types/types';
|
|
3
3
|
import { AllRoomPresenceSummary } from './xmpp/allRoomPresences.xmpp';
|
|
4
4
|
type HistorySource = 'active' | 'send_ack' | 'background' | 'default';
|
|
5
|
+
/** What the server's <fin> said about one windowed MAM page. */
|
|
6
|
+
export interface HistoryWindowFin {
|
|
7
|
+
complete: boolean;
|
|
8
|
+
first: number | null;
|
|
9
|
+
last: number | null;
|
|
10
|
+
}
|
|
11
|
+
/** One page of a windowed history query, returned instead of stored. */
|
|
12
|
+
export interface HistoryWindowPage extends HistoryWindowFin {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
/** Ascending by time (oldest first), whichever direction was paged. */
|
|
15
|
+
messages: IMessage[];
|
|
16
|
+
}
|
|
5
17
|
export type XmppCredentialsProvider = () => Promise<{
|
|
6
18
|
username: string;
|
|
7
19
|
password: string;
|
|
@@ -24,6 +36,12 @@ export declare class XmppClient implements XmppClientInterface {
|
|
|
24
36
|
private reconnecting;
|
|
25
37
|
private reconnectPromise;
|
|
26
38
|
presencesReady: boolean;
|
|
39
|
+
priorityPresencesReady: boolean;
|
|
40
|
+
private sweepEpoch;
|
|
41
|
+
private sweepRetryTimer;
|
|
42
|
+
private sweepRetryRunning;
|
|
43
|
+
private static readonly SWEEP_RETRY_DELAYS_MS;
|
|
44
|
+
private joinConcurrency;
|
|
27
45
|
private sendAllPresencesInFlight;
|
|
28
46
|
private connectionSteps;
|
|
29
47
|
private messageQueue;
|
|
@@ -46,11 +64,16 @@ export declare class XmppClient implements XmppClientInterface {
|
|
|
46
64
|
private historyQueueWorkerScheduled;
|
|
47
65
|
private historyQueueWorkerTimer;
|
|
48
66
|
private roomHistoryEpoch;
|
|
67
|
+
private historyReceiptAckedIds;
|
|
68
|
+
private readonly maxHistoryReceiptAckedIds;
|
|
49
69
|
private criticalSendUntil;
|
|
50
70
|
private activeRoomBoostUntil;
|
|
51
71
|
private sendStartedAtById;
|
|
72
|
+
private sessionOnlineAt;
|
|
73
|
+
private lastSentAtById;
|
|
52
74
|
private pendingSendIdsByRoom;
|
|
53
75
|
private maxInFlightHistory;
|
|
76
|
+
private joinHistoryStanzas;
|
|
54
77
|
private softPauseAfterSendMs;
|
|
55
78
|
private activeRoomBoostTtlMs;
|
|
56
79
|
private activeSendBoostMs;
|
|
@@ -183,13 +206,21 @@ export declare class XmppClient implements XmppClientInterface {
|
|
|
183
206
|
private startAdaptivePing;
|
|
184
207
|
private markActivity;
|
|
185
208
|
sendAllPresencesAndMarkReady(): Promise<void>;
|
|
209
|
+
private hasUnjoinedRooms;
|
|
186
210
|
private runAllPresencesSweep;
|
|
211
|
+
private clearSweepRetry;
|
|
212
|
+
private nextSweepRetryAt;
|
|
213
|
+
private scheduleSweepRetry;
|
|
214
|
+
private runSweepRetry;
|
|
187
215
|
reconnect(): Promise<void>;
|
|
188
|
-
allRoomPresencesStanza(): Promise<AllRoomPresenceSummary>;
|
|
216
|
+
allRoomPresencesStanza(epoch?: number): Promise<AllRoomPresenceSummary>;
|
|
189
217
|
ensureConnected(timeout?: number): Promise<void>;
|
|
190
218
|
close(): Promise<void>;
|
|
191
219
|
wrapWithConnectionCheck<T>(operation: () => Promise<T>): Promise<T>;
|
|
192
220
|
private clearMamRegistry;
|
|
221
|
+
private static readonly HISTORY_WATCHDOG_MS;
|
|
222
|
+
private historyQueueGeneration;
|
|
223
|
+
private abandonMamRequest;
|
|
193
224
|
private clearHistoryQueue;
|
|
194
225
|
private getSendLane;
|
|
195
226
|
setActiveRoomJid(roomJID: string | null): void;
|
|
@@ -210,6 +241,16 @@ export declare class XmppClient implements XmppClientInterface {
|
|
|
210
241
|
private pickNextHistoryTask;
|
|
211
242
|
private processHistoryQueue;
|
|
212
243
|
private executeHistoryTask;
|
|
244
|
+
/**
|
|
245
|
+
* Writes one archive page into the store. A LATEST page (no `before`)
|
|
246
|
+
* that is full and starts after everything the room has cached means more
|
|
247
|
+
* than a page arrived while this client was away: merging it would leave a
|
|
248
|
+
* silent hole between the cache and the page, so the cache is replaced
|
|
249
|
+
* (the same "cache reset" the startup catch-up does when its anchor is
|
|
250
|
+
* missing). Anything overlapping the cache is merged as before.
|
|
251
|
+
*/
|
|
252
|
+
private storeHistoryPage;
|
|
253
|
+
private clearPreloadError;
|
|
213
254
|
private parseMamMessages;
|
|
214
255
|
private routeMamStanza;
|
|
215
256
|
private requestMamHistory;
|
|
@@ -247,7 +288,22 @@ export declare class XmppClient implements XmppClientInterface {
|
|
|
247
288
|
coalesceRoom?: boolean;
|
|
248
289
|
skipIfPreloaded?: boolean;
|
|
249
290
|
source?: HistorySource;
|
|
250
|
-
|
|
291
|
+
reissued?: boolean;
|
|
292
|
+
}) => Promise<IMessage[] | undefined>;
|
|
293
|
+
private guardHistoryRequest;
|
|
294
|
+
/**
|
|
295
|
+
* One page of archive for a window around a message, RETURNED rather than
|
|
296
|
+
* stored: no setRoomMessages, no messageStats / historyComplete update, so
|
|
297
|
+
* the live history is untouched. Pass `before` for the page ending just
|
|
298
|
+
* before that archive id, or `after` for the page starting just after it
|
|
299
|
+
* (both exclusive; microsecond MAM ids). Messages come back oldest first.
|
|
300
|
+
*/
|
|
301
|
+
getHistoryWindow: (chatJID: string, max: number, cursor: {
|
|
302
|
+
before?: number;
|
|
303
|
+
after?: number;
|
|
304
|
+
start?: string;
|
|
305
|
+
end?: string;
|
|
306
|
+
}) => Promise<HistoryWindowPage>;
|
|
251
307
|
getLastMessageArchiveStanza(roomJID: string): void;
|
|
252
308
|
setRoomImageStanza: (roomJid: string, roomThumbnail: string, type: string, roomBackground?: string) => void;
|
|
253
309
|
getRoomInfoStanza: (roomJID: string) => void;
|
|
@@ -259,6 +315,9 @@ export declare class XmppClient implements XmppClientInterface {
|
|
|
259
315
|
deleteMessageStanza(room: string, msgId: string): void;
|
|
260
316
|
editMessageStanza(room: string, msgId: string, text: string): void;
|
|
261
317
|
sendMessageReactionStanza(messageId: string, roomJid: string, reactionsList: string[], reactionSymbol?: any): void;
|
|
318
|
+
sendReceivedReceiptStanza(messageId: string, roomJid: string): void;
|
|
319
|
+
sendDisplayedMarkerStanza(messageId: string, roomJid: string): void;
|
|
320
|
+
sendHistoryReceivedReceiptStanza(roomJid: string, messageId: string): void;
|
|
262
321
|
sendTypingRequestStanza(chatId: string, fullName: string, start: boolean): void;
|
|
263
322
|
getChatsPrivateStoreRequestStanza: () => Promise<Record<string, string | number> | null>;
|
|
264
323
|
actionSetTimestampToPrivateStoreStanza(chatId: string, timestamp: number, chats?: string[]): Promise<void>;
|
|
@@ -11,6 +11,8 @@ export interface CallState {
|
|
|
11
11
|
callId: string | null;
|
|
12
12
|
peerXmppUsername: string | null;
|
|
13
13
|
token: string | null;
|
|
14
|
+
e2eeKey: string | null;
|
|
15
|
+
e2eeKeyCallId: string | null;
|
|
14
16
|
error: string | null;
|
|
15
17
|
startedAt: number | null;
|
|
16
18
|
connectedAt: number | null;
|
|
@@ -33,6 +35,9 @@ export declare const startOutgoingCall: import('@reduxjs/toolkit').ActionCreator
|
|
|
33
35
|
roomJid: string;
|
|
34
36
|
token: string;
|
|
35
37
|
callId?: string | null;
|
|
36
|
-
}, "call/setOutgoingCallToken">, acceptIncomingCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/acceptIncomingCall">, declineIncomingCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/declineIncomingCall">, endCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/endCall">, setCallError: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<string, "call/setCallError">, setCallPhase: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<CallPhase, "call/setCallPhase">, setCallKind: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<CallKind, "call/setCallKind">,
|
|
38
|
+
}, "call/setOutgoingCallToken">, acceptIncomingCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/acceptIncomingCall">, declineIncomingCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/declineIncomingCall">, endCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/endCall">, setCallError: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<string, "call/setCallError">, setCallPhase: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<CallPhase, "call/setCallPhase">, setCallKind: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<CallKind, "call/setCallKind">, setCallE2eeKey: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
39
|
+
key: string;
|
|
40
|
+
callId: string | null;
|
|
41
|
+
}, "call/setCallE2eeKey">, resetCall: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"call/resetCall">;
|
|
37
42
|
declare const _default: import('redux').Reducer<import('immer').WritableDraft<CallState>>;
|
|
38
43
|
export default _default;
|
|
@@ -32,6 +32,28 @@ export declare const optimizePersistedRooms: (rooms: Record<string, IRoom>, char
|
|
|
32
32
|
export declare const compactUsersSetForPersist: (usersSet: Record<string, any>) => Record<string, any>;
|
|
33
33
|
/** Puts back what compactUsersSetForPersist folded into the key. */
|
|
34
34
|
export declare const restoreUsersSetForRehydrate: (usersSet: Record<string, any>) => Record<string, any>;
|
|
35
|
+
/**
|
|
36
|
+
* Per-session facts about a room that must not survive a reload. A persisted
|
|
37
|
+
* 'done' made the next page load treat the cached transcript as current:
|
|
38
|
+
* the preload sweep skipped the room and opening it returned the cache
|
|
39
|
+
* without asking the server, so anything sent while the page was closed was
|
|
40
|
+
* missing until a manual refetch. 'done'/'loading' go back to
|
|
41
|
+
* 'partial'/'idle' (the room is refetched once per session, and a page that
|
|
42
|
+
* does not overlap the cache replaces it instead of leaving a hole). The
|
|
43
|
+
* API's unread count is likewise a snapshot of that moment: the next
|
|
44
|
+
* /chats/my response re-seeds it.
|
|
45
|
+
*/
|
|
46
|
+
export declare const resetSessionRoomState: (roomsMap: Record<string, IRoom>) => Record<string, IRoom>;
|
|
47
|
+
/**
|
|
48
|
+
* A transcript cached by a build that did not persist reactions repaints every
|
|
49
|
+
* bubble without its reaction chips, and the archive will not re-deliver them
|
|
50
|
+
* for the cached middle (the latest page is merged onto the cache and the
|
|
51
|
+
* backfill resumes from the cache's oldest message). Such a cache is dropped
|
|
52
|
+
* once - the room shell stays, the transcript is refetched from MAM - exactly
|
|
53
|
+
* like the cache-budget eviction, except the paging cursors go with it: a
|
|
54
|
+
* stale first/last id would make the backfill start behind the dropped range.
|
|
55
|
+
*/
|
|
56
|
+
export declare const dropReactionlessCaches: (roomsMap: Record<string, IRoom>) => Record<string, IRoom>;
|
|
35
57
|
export declare const limitMessagesTransform: import('redux-persist').Transform<any, any, Record<string, any>, Record<string, any>>;
|
|
36
58
|
export declare const scrubSensitiveChatStateTransform: import('redux-persist').Transform<any, any, Record<string, any>, Record<string, any>>;
|
|
37
59
|
export declare const sanitizeRoomsStateTransform: import('redux-persist').Transform<any, any, Record<string, any>, Record<string, any>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AddRoomMessageAction, ApiRoom, EditAction, IMessage, IRoom, ReactionAction, RoomMember, Translation } from '../types/types';
|
|
1
|
+
import { AddRoomMessageAction, ApiRoom, EditAction, IAttachment, IMessage, IRoom, ReactionAction, RoomMember, Translation } from '../types/types';
|
|
2
2
|
import { default as XmppClient } from '../networking/xmppClient';
|
|
3
3
|
/**
|
|
4
4
|
* Draft caps. Drafts ride along in the persisted rooms slice, so they have
|
|
@@ -44,6 +44,27 @@ export interface PendingJump {
|
|
|
44
44
|
/** Epoch ms the request was made, to drop one nobody ever fulfilled. */
|
|
45
45
|
at: number;
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* A short slice of a room's archive around one message, shown INSTEAD of the
|
|
49
|
+
* live list while the reader is away from the tail (a search jump to a message
|
|
50
|
+
* far back). Separate from room.messages on purpose: it is not contiguous with
|
|
51
|
+
* the live history, so it must not touch messageStats or historyComplete.
|
|
52
|
+
*/
|
|
53
|
+
export interface JumpWindow {
|
|
54
|
+
roomJID: string;
|
|
55
|
+
/** Ascending by time, like room.messages. */
|
|
56
|
+
messages: IMessage[];
|
|
57
|
+
/** Id of the message the jump named, as it appears in `messages`. */
|
|
58
|
+
targetId: string;
|
|
59
|
+
/** RSM cursor (microseconds) to continue older paging from. */
|
|
60
|
+
olderCursor: number | null;
|
|
61
|
+
hasOlder: boolean;
|
|
62
|
+
/** RSM cursor (microseconds) to continue newer paging from. */
|
|
63
|
+
newerCursor: number | null;
|
|
64
|
+
hasNewer: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** The window is trimmed on the far side past this many messages. */
|
|
67
|
+
export declare const JUMP_WINDOW_MAX_MESSAGES = 300;
|
|
47
68
|
interface RoomMessagesState {
|
|
48
69
|
rooms: {
|
|
49
70
|
[jid: string]: IRoom;
|
|
@@ -64,6 +85,7 @@ interface RoomMessagesState {
|
|
|
64
85
|
roomsLoadError: boolean;
|
|
65
86
|
pendingJump: PendingJump | null;
|
|
66
87
|
archivedMessage: ArchivedMessage | null;
|
|
88
|
+
jumpWindow: JumpWindow | null;
|
|
67
89
|
joiningRoomJID: string | null;
|
|
68
90
|
drafts: Record<string, string>;
|
|
69
91
|
}
|
|
@@ -107,7 +129,13 @@ export declare const addRoom: import('@reduxjs/toolkit').ActionCreatorWithOption
|
|
|
107
129
|
}, "roomMessages/setMessageSendFailed">, setMessageSendRetrying: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
108
130
|
roomJID: string;
|
|
109
131
|
messageId: string;
|
|
110
|
-
}, "roomMessages/setMessageSendRetrying">,
|
|
132
|
+
}, "roomMessages/setMessageSendRetrying">, setMediaUploadState: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
133
|
+
roomJID: string;
|
|
134
|
+
messageId: string;
|
|
135
|
+
attachments?: IAttachment[];
|
|
136
|
+
pending?: boolean;
|
|
137
|
+
failed?: boolean;
|
|
138
|
+
}, "roomMessages/setMediaUploadState">, editRoomMessage: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
111
139
|
roomJID: string;
|
|
112
140
|
messageId: string;
|
|
113
141
|
text: string;
|
|
@@ -139,7 +167,17 @@ export declare const addRoom: import('@reduxjs/toolkit').ActionCreatorWithOption
|
|
|
139
167
|
createdAt?: string;
|
|
140
168
|
body?: string;
|
|
141
169
|
preview?: ArchivedMessage;
|
|
142
|
-
}, "roomMessages/requestJumpToMessage">, clearPendingJump: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"roomMessages/clearPendingJump">, showArchivedMessage: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ArchivedMessage, "roomMessages/showArchivedMessage">, clearArchivedMessage: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"roomMessages/clearArchivedMessage">,
|
|
170
|
+
}, "roomMessages/requestJumpToMessage">, clearPendingJump: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"roomMessages/clearPendingJump">, showArchivedMessage: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ArchivedMessage, "roomMessages/showArchivedMessage">, clearArchivedMessage: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"roomMessages/clearArchivedMessage">, setJumpWindow: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<JumpWindow, "roomMessages/setJumpWindow">, prependJumpWindowMessages: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
171
|
+
roomJID: string;
|
|
172
|
+
messages: IMessage[];
|
|
173
|
+
olderCursor: number | null;
|
|
174
|
+
hasOlder: boolean;
|
|
175
|
+
}, "roomMessages/prependJumpWindowMessages">, appendJumpWindowMessages: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
176
|
+
roomJID: string;
|
|
177
|
+
messages: IMessage[];
|
|
178
|
+
newerCursor: number | null;
|
|
179
|
+
hasNewer: boolean;
|
|
180
|
+
}, "roomMessages/appendJumpWindowMessages">, clearJumpWindow: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"roomMessages/clearJumpWindow">, setJoiningRoom: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<string, "roomMessages/setJoiningRoom">, clearJoiningRoom: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<string, "roomMessages/clearJoiningRoom">, setCurrentRoom: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
143
181
|
roomJID: string | null;
|
|
144
182
|
}, "roomMessages/setCurrentRoom">, setMemberOnline: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
145
183
|
roomJID: string;
|
|
@@ -150,7 +188,16 @@ export declare const addRoom: import('@reduxjs/toolkit').ActionCreatorWithOption
|
|
|
150
188
|
}, "roomMessages/setMemberOffline">, setChatUiVisible: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<boolean, "roomMessages/setChatUiVisible">, setRoomRole: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
151
189
|
chatJID: string;
|
|
152
190
|
role: string;
|
|
153
|
-
}, "roomMessages/setRoomRole">, setReactions: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ReactionAction, "roomMessages/setReactions">,
|
|
191
|
+
}, "roomMessages/setRoomRole">, setReactions: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ReactionAction, "roomMessages/setReactions">, setReceivedReceipt: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
192
|
+
roomJID: string;
|
|
193
|
+
messageId: string;
|
|
194
|
+
fromXmppUsername: string;
|
|
195
|
+
timestamp: number;
|
|
196
|
+
}, "roomMessages/setReceivedReceipt">, setDisplayedMarker: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
197
|
+
roomJID: string;
|
|
198
|
+
xmppUsername: string;
|
|
199
|
+
messageId: string;
|
|
200
|
+
}, "roomMessages/setDisplayedMarker">, setLogoutState: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"roomMessages/setLogoutState">, setActiveMessage: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
154
201
|
id: string;
|
|
155
202
|
chatJID: string;
|
|
156
203
|
}, "roomMessages/setActiveMessage">, setCloseActiveMessage: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** True when `key` is a non-empty string that is safe to use as an object key. */
|
|
2
|
+
export declare const isSafeKey: (key: unknown) => key is string;
|
|
3
|
+
/** True when `name` is a property name every object already has. */
|
|
4
|
+
export declare const isReservedName: (name: string) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* True for an `<appId>_<rest>` id that is safe to send and to store: the whole
|
|
7
|
+
* id and every underscore-separated segment after the first must not be a
|
|
8
|
+
* reserved object name, and no segment may start with `__` (which also
|
|
9
|
+
* rejects `<appId>___proto__`, where the split yields an empty segment and a
|
|
10
|
+
* `__`-prefixed one).
|
|
11
|
+
*/
|
|
12
|
+
export declare const hasSafeIdSegments: (id: string) => boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RoomMember } from '../types/types';
|
|
2
|
+
/**
|
|
3
|
+
* usersSet is persisted, and lazily resolved senders keep adding to it, so
|
|
4
|
+
* it needs a ceiling. Object key order is insertion order, so "least
|
|
5
|
+
* recently inserted" is simply the first keys.
|
|
6
|
+
*/
|
|
7
|
+
export declare const USERS_SET_CAP = 5000;
|
|
8
|
+
/** Drops the oldest-inserted entries until at most `cap` remain. */
|
|
9
|
+
export declare const capUsersSet: (usersSet: Record<string, RoomMember>, cap?: number) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Merges the members of a fresh /chats/my payload into usersSet: fresh
|
|
12
|
+
* entries win, entries fetched lazily earlier stay. A refreshed key moves to
|
|
13
|
+
* the newest position so the cap evicts genuinely stale ones first.
|
|
14
|
+
*/
|
|
15
|
+
export declare const mergeUsersSet: (usersSet: Record<string, RoomMember>, fresh: Record<string, RoomMember>, cap?: number) => void;
|
package/dist/styles/motion.d.ts
CHANGED
|
@@ -20,7 +20,17 @@ export declare const MOTION_BASE_MS = 220;
|
|
|
20
20
|
export declare const fadeIn: import('styled-components/dist/models/Keyframes').default;
|
|
21
21
|
export declare const fadeInUp: import('styled-components/dist/models/Keyframes').default;
|
|
22
22
|
export declare const scaleIn: import('styled-components/dist/models/Keyframes').default;
|
|
23
|
-
|
|
23
|
+
/** Skeleton timing: one sweep cycle, and the delay before anything shows. */
|
|
24
|
+
export declare const SHIMMER_SWEEP_MS = 2000;
|
|
25
|
+
export declare const SHIMMER_DELAY_MS = 120;
|
|
26
|
+
export declare const SHIMMER_FADE_IN_MS = 240;
|
|
27
|
+
/**
|
|
28
|
+
* The loading band drifts left to right (reading direction). Keyframes move
|
|
29
|
+
* the band's own transform, not background-position, so the browser can run
|
|
30
|
+
* it on the compositor. The band is 60% of the host wide, so -100% parks it
|
|
31
|
+
* just off the left edge and 166.67% just off the right edge.
|
|
32
|
+
*/
|
|
33
|
+
export declare const shimmerSweep: import('styled-components/dist/models/Keyframes').default;
|
|
24
34
|
/**
|
|
25
35
|
* Right-hand side drawer entrance. Travels further than `fadeInUp` (a panel
|
|
26
36
|
* sliding in from the screen edge reads as motion only if it actually
|
|
@@ -47,7 +57,17 @@ export declare const fadeInAnimation: import('styled-components').RuleSet<object
|
|
|
47
57
|
export declare const scaleInAnimation: import('styled-components').RuleSet<object>;
|
|
48
58
|
/** Convenience: side-drawer slide-in shorthand, respecting reduced motion. */
|
|
49
59
|
export declare const slideInRightAnimation: import('styled-components').RuleSet<object>;
|
|
50
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Loading skeleton: a calm, slightly tinted base with one soft band sweeping
|
|
62
|
+
* left to right every 2s. The band fades in with its own transparent edges,
|
|
63
|
+
* so there is no hard leading or trailing line. Nothing shows for the first
|
|
64
|
+
* 120ms, so an image that arrives quickly never flashes a placeholder.
|
|
65
|
+
*
|
|
66
|
+
* The host must be positioned (`position: relative` or `absolute`, set by the
|
|
67
|
+
* host itself so this helper cannot override it); the band is an ::after
|
|
68
|
+
* clipped by the host's `overflow: hidden`. Reduced motion keeps only the
|
|
69
|
+
* static base.
|
|
70
|
+
*/
|
|
51
71
|
export declare const shimmerBackground: import('styled-components').RuleSet<object>;
|
|
52
72
|
export declare const fadeOut: import('styled-components/dist/models/Keyframes').default;
|
|
53
73
|
export declare const scaleOut: import('styled-components/dist/models/Keyframes').default;
|
|
@@ -23,6 +23,9 @@ export interface IAttachment {
|
|
|
23
23
|
/** Bytes, as a string - that is how it travels on the wire. */
|
|
24
24
|
size?: string;
|
|
25
25
|
duration?: string;
|
|
26
|
+
/** Natural pixel size, when the storage recorded it. Sizes the solo preview box. */
|
|
27
|
+
width?: number;
|
|
28
|
+
height?: number;
|
|
26
29
|
ownerKey?: string;
|
|
27
30
|
userId?: string;
|
|
28
31
|
createdAt?: string;
|
|
@@ -30,4 +33,20 @@ export interface IAttachment {
|
|
|
30
33
|
expiresAt?: string;
|
|
31
34
|
isVisible?: boolean;
|
|
32
35
|
isPrivate?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Local-only state of an outgoing attachment, set by the sender while its
|
|
38
|
+
* message is still being sent. Never written to the wire.
|
|
39
|
+
* uploading - the file is going up (or every file is up and the message
|
|
40
|
+
* is waiting on its siblings); `uploadProgress` is 0 to 100.
|
|
41
|
+
* failed - this file did not upload; the message is held until it
|
|
42
|
+
* is retried.
|
|
43
|
+
*/
|
|
44
|
+
uploadStatus?: 'uploading' | 'failed';
|
|
45
|
+
uploadProgress?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Local-only `blob:` URL of the sender's own picture, so an outgoing image
|
|
48
|
+
* shows at once and stays on screen while the server copy loads. Never
|
|
49
|
+
* written to the wire.
|
|
50
|
+
*/
|
|
51
|
+
localUrl?: string;
|
|
33
52
|
}
|