@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
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IMessage } from '../types/types';
|
|
2
|
+
/**
|
|
3
|
+
* Ids of the messages that end a run of one sender: the next row is another
|
|
4
|
+
* sender, a system row, or a message on the next day. A run is a block of
|
|
5
|
+
* consecutive messages from one person, which the bubbles group visually.
|
|
6
|
+
*
|
|
7
|
+
* Pass the full list, not a window of it, so the last row of a window still
|
|
8
|
+
* knows what follows it.
|
|
9
|
+
*/
|
|
10
|
+
export declare const messageRunEnds: (list: IMessage[]) => Set<string>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AppDispatch } from '../roomStore';
|
|
2
|
+
import { IMessage } from '../types/types';
|
|
3
|
+
import { HistoryWindowClient } from './jumpWindow';
|
|
4
|
+
export interface OpenThreadForJumpParams {
|
|
5
|
+
client?: HistoryWindowClient | null;
|
|
6
|
+
dispatch: AppDispatch;
|
|
7
|
+
roomJID: string;
|
|
8
|
+
/** The pending request this opens a thread for. */
|
|
9
|
+
at: number;
|
|
10
|
+
/** The reply the jump named. */
|
|
11
|
+
reply: IMessage;
|
|
12
|
+
/** The room's live messages, unfiltered. */
|
|
13
|
+
live: IMessage[];
|
|
14
|
+
/** Messages found alongside the reply (a window), unfiltered. */
|
|
15
|
+
nearby?: IMessage[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Opens the thread a reply belongs to, so a jump to the reply can highlight it
|
|
19
|
+
* there. Resolves true when the thread is open (or about to be), false when
|
|
20
|
+
* the parent could not be obtained.
|
|
21
|
+
*
|
|
22
|
+
* The parent comes from the live list (the usual thread flag), from the
|
|
23
|
+
* messages found next to the reply, or, when it is in neither, from a window
|
|
24
|
+
* around the parent fetched for the purpose.
|
|
25
|
+
*/
|
|
26
|
+
export declare function openThreadForJump({ client, dispatch, roomJID, at, reply, live, nearby, }: OpenThreadForJumpParams): Promise<boolean>;
|
|
@@ -61,4 +61,11 @@ export interface PdfjsLib {
|
|
|
61
61
|
}
|
|
62
62
|
/** Test seam - the module-level cache would otherwise leak between cases. */
|
|
63
63
|
export declare const resetPdfjsCache: () => void;
|
|
64
|
-
|
|
64
|
+
/**
|
|
65
|
+
* `libUrl`: load pdf.js from this URL (an ES module build such as
|
|
66
|
+
* `pdfjs-dist/legacy/build/pdf.min.mjs` served by the host) instead of the
|
|
67
|
+
* copy bundled with the component. For hosts that ship the component as one
|
|
68
|
+
* self-contained script (the embeddable widget), where a bundled pdf.js is
|
|
69
|
+
* 1.7 MB that every visitor downloads whether or not a PDF ever appears.
|
|
70
|
+
*/
|
|
71
|
+
export declare const loadPdfjs: (workerSrc?: string, libUrl?: string) => Promise<PdfjsLib | null>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repairs file names the backend returns as UTF-8 bytes read as Latin-1
|
|
3
|
+
* (the classic multer/busboy `originalname` problem): "Список.pdf" arrives
|
|
4
|
+
* as "СпиÑок.pdf".
|
|
5
|
+
*
|
|
6
|
+
* Pure and conservative: a name is only replaced when every character fits
|
|
7
|
+
* in one byte, the bytes decode as strict UTF-8, the result differs, holds
|
|
8
|
+
* no replacement or control characters and contains at least one letter
|
|
9
|
+
* outside basic Latin. A correct name is returned untouched.
|
|
10
|
+
*/
|
|
11
|
+
export declare const repairFilenameEncoding: (name: string) => string;
|
|
@@ -7,9 +7,27 @@ import { IMessage, ModalFile } from '../types/types';
|
|
|
7
7
|
* download action, the secure `?ft=` token treatment, the alt text - keeps
|
|
8
8
|
* reading exactly the fields it read when a single file was opened by hand.
|
|
9
9
|
*/
|
|
10
|
+
export interface GallerySender {
|
|
11
|
+
id?: string;
|
|
12
|
+
username?: string;
|
|
13
|
+
/** The message's own display name, when it has one. */
|
|
14
|
+
name?: string;
|
|
15
|
+
firstName?: string;
|
|
16
|
+
lastName?: string;
|
|
17
|
+
/** Profile photo URL, when the sender has one. */
|
|
18
|
+
photo?: string;
|
|
19
|
+
}
|
|
10
20
|
export interface GalleryImage extends ModalFile {
|
|
21
|
+
/** What the entry renders as. Images zoom; videos play. */
|
|
22
|
+
kind: 'image' | 'video';
|
|
11
23
|
/** Stable per message+slot, so two identical URLs are still two entries. */
|
|
12
24
|
key: string;
|
|
25
|
+
/** Low-resolution copy shown blurred while the full image loads. */
|
|
26
|
+
previewURL?: string;
|
|
27
|
+
/** Message timestamp (ISO), shown in the viewer's header. */
|
|
28
|
+
date?: string;
|
|
29
|
+
/** Who posted it; the viewer header shows their name and avatar. */
|
|
30
|
+
sender?: GallerySender;
|
|
13
31
|
}
|
|
14
32
|
/**
|
|
15
33
|
* The gallery the lightbox pages through.
|
|
@@ -34,7 +52,17 @@ export interface GalleryImage extends ModalFile {
|
|
|
34
52
|
* Non-images (video, PDF, audio, arbitrary files) are excluded, so opening a
|
|
35
53
|
* PDF simply produces an empty gallery and no navigation chrome.
|
|
36
54
|
*/
|
|
55
|
+
/** The sender fields the viewer header needs, or undefined for no sender. */
|
|
56
|
+
export declare const senderFromMessage: (message?: Partial<IMessage> | null) => GallerySender | undefined;
|
|
57
|
+
/** ISO date string for a message, as the viewer header wants it. */
|
|
58
|
+
export declare const isoDateFromMessage: (message?: Partial<IMessage> | null) => string | undefined;
|
|
37
59
|
export declare const collectRoomImages: (messages?: Partial<IMessage>[] | null) => GalleryImage[];
|
|
60
|
+
/**
|
|
61
|
+
* Same walk as `collectRoomImages`, but the viewer's gallery also pages
|
|
62
|
+
* through videos, so an album of photos and clips opens as one sequence.
|
|
63
|
+
* PDFs, audio and other files are still excluded.
|
|
64
|
+
*/
|
|
65
|
+
export declare const collectRoomMedia: (messages?: Partial<IMessage>[] | null, kinds?: Array<"image" | "video">) => GalleryImage[];
|
|
38
66
|
/**
|
|
39
67
|
* Position of the open file inside the gallery, or -1 when it is not part of
|
|
40
68
|
* it (a PDF, a video, a file opened from the Files panel of another room).
|
|
@@ -51,3 +79,9 @@ export declare const collectRoomImages: (messages?: Partial<IMessage>[] | null)
|
|
|
51
79
|
* were stuck.
|
|
52
80
|
*/
|
|
53
81
|
export declare const findGalleryIndex: (images: GalleryImage[], activeFile?: ModalFile | null) => number;
|
|
82
|
+
/**
|
|
83
|
+
* Builds gallery entries from the file list a caller handed over with the
|
|
84
|
+
* open request (an album grid passes all of its tiles). Items without a
|
|
85
|
+
* location, or that are neither image nor video, are dropped.
|
|
86
|
+
*/
|
|
87
|
+
export declare const galleryFromFiles: (files?: ModalFile[] | null) => GalleryImage[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IRoom } from '../types/types';
|
|
2
|
+
type CountSource = Pick<IRoom, 'members' | 'usersCnt'> | {
|
|
3
|
+
members?: unknown;
|
|
4
|
+
usersCnt?: unknown;
|
|
5
|
+
} | null | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* User count to DISPLAY for a room. /chats/my returns `usersCnt` (the true
|
|
8
|
+
* total) but at most 30 members for big public rooms, so the truncated
|
|
9
|
+
* members array must never win over usersCnt.
|
|
10
|
+
*/
|
|
11
|
+
export declare const getRoomUserCount: (room: CountSource) => number;
|
|
12
|
+
/** True when the room is known to have more users than members loaded. */
|
|
13
|
+
export declare const isRoomMembersTruncated: (room: CountSource) => boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Next usersCnt after a live join (+1) or leave (-1). Adjusts the CURRENT
|
|
16
|
+
* count instead of recomputing from the (possibly truncated) members array.
|
|
17
|
+
*/
|
|
18
|
+
export declare const adjustUsersCnt: (room: CountSource, delta: 1 | -1, nextMembersLength: number) => number;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image URLs that reach the DOM (`<img src>`, CSS `url()`) can come from
|
|
3
|
+
* user-controlled data: profile photos, message stanzas, link previews,
|
|
4
|
+
* attachment locations. Anything that is not a plain web or blob image URL is
|
|
5
|
+
* dropped here so the sink never receives an active or document-bearing URL.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Returns the trimmed input when it is a safe image URL, otherwise ''.
|
|
9
|
+
*
|
|
10
|
+
* Allowed: absolute or relative (resolved against the page origin) http:,
|
|
11
|
+
* https: and blob: URLs, and base64 data URLs of png, jpeg, gif, webp or
|
|
12
|
+
* avif images. Blocked: javascript:, vbscript:, data:text/html, data:image/svg+xml
|
|
13
|
+
* and anything that does not parse. Non-string input yields ''.
|
|
14
|
+
*/
|
|
15
|
+
export declare const safeImageUrl: (value: unknown) => string;
|
|
@@ -9,4 +9,7 @@ export declare const appendFileToken: (url: string | null | undefined, fileToken
|
|
|
9
9
|
*/
|
|
10
10
|
export declare const withoutFileToken: (url?: string | null) => string;
|
|
11
11
|
export declare const withFileToken: (url?: string | null) => string;
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const resetFileTokenRecovery: () => void;
|
|
13
|
+
export declare const requestFileTokenRecovery: (options?: {
|
|
14
|
+
force?: boolean;
|
|
15
|
+
}) => Promise<boolean>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { RoomMember } from '../types/types';
|
|
2
|
+
export type RoomDirectoryState = 'idle' | 'loading' | 'done' | 'error';
|
|
3
|
+
/** Re-render hook: called when a directory state or a negative cache entry changes. */
|
|
4
|
+
export declare const subscribeUserResolver: (listener: () => void) => (() => void);
|
|
5
|
+
/**
|
|
6
|
+
* True for an id the backend answered 404 for: the user really is gone.
|
|
7
|
+
* (An id merely not resolved yet is NOT "not found".)
|
|
8
|
+
*/
|
|
9
|
+
export declare const isUserNotFound: (rawId: string) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Where a sender's lookup stands, for the display chain:
|
|
12
|
+
* - resolved: in usersSet
|
|
13
|
+
* - pending: queued, in flight, or not requested yet (a bubble just mounted)
|
|
14
|
+
* - notfound / forbidden: the backend answered, nothing to show from it
|
|
15
|
+
* - failed: the last attempt errored (backoff), or the lookup is exhausted
|
|
16
|
+
* - unavailable: this id can never be looked up (plain handle) or there is
|
|
17
|
+
* no session token, so nothing is coming
|
|
18
|
+
*/
|
|
19
|
+
export type UserLookupStatus = 'resolved' | 'pending' | 'notfound' | 'forbidden' | 'failed' | 'unavailable';
|
|
20
|
+
export declare const getUserLookupStatus: (rawId: string) => UserLookupStatus;
|
|
21
|
+
/**
|
|
22
|
+
* Ask for the profiles of these senders. Cheap to call from anywhere (a
|
|
23
|
+
* bubble mounting, a history batch parse): known, in-flight and recently
|
|
24
|
+
* failed ids are dropped, the rest are debounced into one pass.
|
|
25
|
+
*/
|
|
26
|
+
export declare function requestUsers(ids: string[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Re-fetch one user's profile even though it is already in usersSet, because
|
|
29
|
+
* the server said it changed (ethora-event user-profile-updated). Bypasses
|
|
30
|
+
* the cache and forgets a negative-cache entry, but shares everything else
|
|
31
|
+
* with requestUsers: the same route chain (lookupUser), the same worker
|
|
32
|
+
* queue and concurrency cap, one request at a time per user. Calls for the
|
|
33
|
+
* same user within REFRESH_DEBOUNCE_MS coalesce into one fetch. The answer
|
|
34
|
+
* goes through insertUsers (display fields only), so existing bubbles are
|
|
35
|
+
* re-named. Never throws.
|
|
36
|
+
*/
|
|
37
|
+
export declare function refreshUser(rawId: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Members loaded so far by ensureRoomDirectory for this room (a new array
|
|
40
|
+
* identity after every page, a stable empty array before any).
|
|
41
|
+
*/
|
|
42
|
+
export declare const getRoomDirectoryMembers: (roomJID: string) => RoomMember[];
|
|
43
|
+
/** requestUsers for the senders of a batch of messages (history page, jump window). */
|
|
44
|
+
export declare function requestSendersOf(messages: ReadonlyArray<{
|
|
45
|
+
user?: {
|
|
46
|
+
id?: string;
|
|
47
|
+
};
|
|
48
|
+
} | null | undefined> | undefined): void;
|
|
49
|
+
export declare const getRoomDirectoryState: (roomJID: string) => RoomDirectoryState;
|
|
50
|
+
/**
|
|
51
|
+
* Loads every member of one room into usersSet, once. Pages are not
|
|
52
|
+
* guaranteed to be full, so it stops on an empty page or offset >= total,
|
|
53
|
+
* never on `items.length < limit`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function ensureRoomDirectory(roomJID: string): Promise<void>;
|
|
56
|
+
/** For tests and logout: drops every cache, timer and in-flight result. */
|
|
57
|
+
export declare function resetUserResolver(): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** What the media viewer knows about a sender, however thin. */
|
|
2
|
+
export interface ViewerSenderInput {
|
|
3
|
+
id?: string;
|
|
4
|
+
username?: string;
|
|
5
|
+
/** `message.user.name`, which carries the display name for many senders. */
|
|
6
|
+
name?: string;
|
|
7
|
+
firstName?: string;
|
|
8
|
+
lastName?: string;
|
|
9
|
+
photo?: string;
|
|
10
|
+
}
|
|
11
|
+
interface DirectoryEntry {
|
|
12
|
+
firstName?: string;
|
|
13
|
+
lastName?: string;
|
|
14
|
+
profileImage?: string;
|
|
15
|
+
}
|
|
16
|
+
interface OwnProfile extends DirectoryEntry {
|
|
17
|
+
xmppUsername?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ResolveViewerSenderOptions {
|
|
21
|
+
sender?: ViewerSenderInput | null;
|
|
22
|
+
/** `rooms.usersSet`, keyed by the xmpp username. */
|
|
23
|
+
usersSet?: Record<string, DirectoryEntry | undefined>;
|
|
24
|
+
/** The signed-in user, for their own messages. */
|
|
25
|
+
me?: OwnProfile | null;
|
|
26
|
+
/** Only used for a 1:1 room, where the room is named after the peer. */
|
|
27
|
+
peerRoomName?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ResolvedViewerSender {
|
|
30
|
+
/** Empty when nobody could be named. The header then omits the name line. */
|
|
31
|
+
name: string;
|
|
32
|
+
photo?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolves the sender shown in the viewer header. The order is the one the
|
|
36
|
+
* message bubble uses, with the signed-in user's own profile as the answer for
|
|
37
|
+
* their own messages (an own optimistic message often has no name on it):
|
|
38
|
+
*
|
|
39
|
+
* first + last on the message, the message's own `name`, the profile in
|
|
40
|
+
* `usersSet`, the signed-in user's profile (own messages), the username
|
|
41
|
+
* before the `@`, and for a 1:1 room the room's name.
|
|
42
|
+
*
|
|
43
|
+
* Never returns a placeholder: when nothing is known `name` is '' and the
|
|
44
|
+
* caller draws a neutral glyph rather than initials.
|
|
45
|
+
*/
|
|
46
|
+
export declare const resolveViewerSender: ({ sender, usersSet, me, peerRoomName, }: ResolveViewerSenderOptions) => ResolvedViewerSender;
|
|
47
|
+
export {};
|
|
@@ -2,7 +2,7 @@ export declare const toLocalPart: (value?: string) => string;
|
|
|
2
2
|
/**
|
|
3
3
|
* True when `value` (a full JID or already-bare local part) is a
|
|
4
4
|
* machine-generated Ethora id rather than anything a human would recognize
|
|
5
|
-
* as their own name - `<24 hex>_<24 hex>`
|
|
5
|
+
* as their own name - `<24 hex>_<24 hex>`, `<appId>_<uuid>` or a bare 24-hex
|
|
6
6
|
* id. Kept narrow on purpose: a handle a person actually picked is never
|
|
7
7
|
* this shape, so it is never mistaken for one.
|
|
8
8
|
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type AvatarImageStatus = 'none' | 'loading' | 'loaded' | 'failed';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves an avatar URL for rendering. Never waits on the network: the
|
|
4
|
+
* caller shows initials immediately and fades the <img> in once `status` is
|
|
5
|
+
* `loaded`.
|
|
6
|
+
*
|
|
7
|
+
* - appends the viewer's `?ft=` token for secure-files URLs synchronously
|
|
8
|
+
* from the store (no token round trip before the request starts);
|
|
9
|
+
* - reuses a URL that already loaded for the same file (see
|
|
10
|
+
* avatarImageCache) so a token rotation or a second component showing the
|
|
11
|
+
* same person does not trigger another download;
|
|
12
|
+
* - skips URLs that just failed (no repeated failing requests);
|
|
13
|
+
* - on a secure-file failure kicks the throttled fileToken recovery, whose
|
|
14
|
+
* refreshed token yields a new URL and therefore a new attempt.
|
|
15
|
+
*/
|
|
16
|
+
export declare const useAvatarImage: (rawSrc: string | null | undefined) => {
|
|
17
|
+
src: string;
|
|
18
|
+
status: AvatarImageStatus;
|
|
19
|
+
onLoad: () => void;
|
|
20
|
+
onError: () => void;
|
|
21
|
+
};
|
|
@@ -22,5 +22,11 @@ export declare const hasHostRefreshedSession: (user: {
|
|
|
22
22
|
xmppUsername?: string;
|
|
23
23
|
xmppPassword?: string;
|
|
24
24
|
}) => boolean;
|
|
25
|
+
export declare const startBackgroundJoinSweep: (client: {
|
|
26
|
+
sendAllPresencesAndMarkReady: () => Promise<unknown>;
|
|
27
|
+
}) => void;
|
|
28
|
+
export declare const loadRoomsThenJoinInBackground: <T>(client: {
|
|
29
|
+
sendAllPresencesAndMarkReady: () => Promise<unknown>;
|
|
30
|
+
}, fetchRooms: () => Promise<T>, onListReady: () => void) => Promise<T>;
|
|
25
31
|
declare const useChatWrapperInit: ({ roomJID, wasAutoSelected, config, }: useChatWrapperInitProps) => useChatWrapperInitResult;
|
|
26
32
|
export default useChatWrapperInit;
|
|
@@ -1 +1,6 @@
|
|
|
1
1
|
export declare const useIsMobileViewport: (breakpoint?: number) => boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Non-hook form of the same check, for event handlers that need the answer
|
|
4
|
+
* at the moment of the event rather than as render state.
|
|
5
|
+
*/
|
|
6
|
+
export declare const isMobileViewportNow: (breakpoint?: number) => boolean;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type MediaProbeStatus = 'idle' | 'loading' | 'recovering' | 'loaded' | 'error';
|
|
2
|
+
export interface MediaProbe {
|
|
3
|
+
status: MediaProbeStatus;
|
|
4
|
+
/**
|
|
5
|
+
* Natural size. Known once `status` is 'loaded', and usually sooner: it is
|
|
6
|
+
* read from the first decoded header while the bytes are still arriving.
|
|
7
|
+
*/
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
/**
|
|
11
|
+
* The URL whose bytes are on screen. While a picture is shown, a rotated
|
|
12
|
+
* `?ft=` token does not swap it for a fresh request: the URL that loaded
|
|
13
|
+
* stays, so a token refresh never blanks or re-downloads what is visible.
|
|
14
|
+
*/
|
|
15
|
+
url: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* No byte of the file (not even its header) arrived in this long: stop
|
|
19
|
+
* waiting and show the unavailable state with a manual retry. Once the size
|
|
20
|
+
* is known the file is on its way and is never cut off by this timer.
|
|
21
|
+
*/
|
|
22
|
+
export declare const MEDIA_STALL_MS = 8000;
|
|
23
|
+
export declare const resetMediaProbeCaches: () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Preloads one image off-DOM so the visible <img> only mounts once its bytes
|
|
26
|
+
* are cached.
|
|
27
|
+
*
|
|
28
|
+
* A failure never says anything about the file being deleted: a 404 from the
|
|
29
|
+
* storage host, an expired token, a CORS or DNS hiccup and a dead CDN edge all
|
|
30
|
+
* fail an <img> the same way, and the server's answer cannot be read across
|
|
31
|
+
* origins anyway. So the only outcome is the 'error' state, which the surface
|
|
32
|
+
* offers to `retry`. Deleting a message is driven by the server (a delete
|
|
33
|
+
* stanza) or by the sender's own Files panel action, never inferred here.
|
|
34
|
+
*
|
|
35
|
+
* A secure URL that fails gets at most one shared token refresh per token
|
|
36
|
+
* (see `requestFileTokenRecovery`); the refreshed URL re-runs this effect.
|
|
37
|
+
*/
|
|
38
|
+
export declare const useMediaProbe: (url: string | undefined) => MediaProbe & {
|
|
39
|
+
retry: () => void;
|
|
40
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Publishes the width of an element as the `--ethora-pane-w` custom property
|
|
4
|
+
* on that element, so message media can size itself to the chat pane (which
|
|
5
|
+
* may be a narrow host) instead of the viewport. Updated on every resize.
|
|
6
|
+
*
|
|
7
|
+
* The element may mount after the first render (the list shows a loader
|
|
8
|
+
* first), so every commit checks whether the ref points at a new element
|
|
9
|
+
* and re-attaches the observer if so.
|
|
10
|
+
*/
|
|
11
|
+
export declare const usePaneWidthVar: (ref: RefObject<HTMLElement | null>) => void;
|
|
@@ -9,14 +9,14 @@ interface UsePdfThumbnailParams {
|
|
|
9
9
|
maxBytes?: number;
|
|
10
10
|
sizeInBytes?: number;
|
|
11
11
|
workerSrc?: string;
|
|
12
|
+
libUrl?: string;
|
|
12
13
|
}
|
|
13
14
|
interface UsePdfThumbnailResult {
|
|
14
15
|
status: PdfThumbnailStatus;
|
|
15
16
|
/** Object URL - owned by this hook, revoked on unmount/url change. */
|
|
16
17
|
thumbnailUrl?: string;
|
|
17
|
-
pageCount?: number;
|
|
18
18
|
/** Re-runs a render that failed or was skipped for being too big. */
|
|
19
19
|
retry: () => void;
|
|
20
20
|
}
|
|
21
|
-
export declare const usePdfThumbnail: ({ url, enabled, width, maxBytes, sizeInBytes, workerSrc, }: UsePdfThumbnailParams) => UsePdfThumbnailResult;
|
|
21
|
+
export declare const usePdfThumbnail: ({ url, enabled, width, maxBytes, sizeInBytes, workerSrc, libUrl, }: UsePdfThumbnailParams) => UsePdfThumbnailResult;
|
|
22
22
|
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RoomDirectoryState } from '../helpers/userResolver';
|
|
2
|
+
import { RoomMember } from '../types/types';
|
|
3
|
+
/**
|
|
4
|
+
* Directory of a big room (usersCnt > the members the API returned).
|
|
5
|
+
* `enabled` starts the (once per room, deduplicated) load; the result grows
|
|
6
|
+
* page by page. Rooms that are not truncated never trigger a request.
|
|
7
|
+
*/
|
|
8
|
+
export declare const useRoomDirectory: (roomJid: string | undefined, enabled: boolean) => {
|
|
9
|
+
members: RoomMember[];
|
|
10
|
+
state: RoomDirectoryState;
|
|
11
|
+
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { IMentionSpan } from '../types/types';
|
|
2
|
+
import { CaptionInput } from '../helpers/caption';
|
|
3
|
+
/** Files of one message uploaded at the same time. */
|
|
4
|
+
export declare const MEDIA_UPLOAD_CONCURRENCY = 4;
|
|
2
5
|
export { shouldTagOutgoingTranslateSource } from '../utils/translateModePolicy';
|
|
3
6
|
export declare const useSendMessage: () => {
|
|
4
7
|
sendMessage: (message: string, activeRoomJID: string, isReply?: boolean, isChecked?: boolean, mainMessage?: string, mentions?: IMentionSpan[]) => Promise<void>;
|
|
5
|
-
sendMedia: (data: File | File[] | Blob, type: string, activeRoomJID: string, isReply?: boolean, isChecked?: boolean, mainMessage?: string) => Promise<
|
|
8
|
+
sendMedia: (data: File | File[] | Blob, type: string, activeRoomJID: string, isReply?: boolean, isChecked?: boolean, mainMessage?: string, caption?: CaptionInput) => Promise<boolean>;
|
|
6
9
|
sendEditMessage: (message: string) => Promise<void>;
|
|
7
10
|
isLastMessageFromUserAndProcessing: (roomJID: string) => boolean;
|
|
8
11
|
};
|