@ethora/chat-component 26.8.1 → 26.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{ChatProfileModal-DZVi2WRb.js → ChatProfileModal-DJcii-VO.js} +3 -3
  2. package/dist/{FilePreviewModal-BelSYN5e.js → FilePreviewModal-CZtgkIHl.js} +37 -37
  3. package/dist/{ManageDataModal-Bs_0SHBL.js → ManageDataModal-aOWxvxSs.js} +2 -2
  4. package/dist/{MarkdownBody-BYUK4GVM.js → MarkdownBody-neDkIgJl.js} +1 -1
  5. package/dist/{SideDrawer-C_nWZRwH.js → SideDrawer-mSCnYOgy.js} +11 -11
  6. package/dist/UserProfileModal-a_O8hh1O.js +594 -0
  7. package/dist/{UserSettingsModal-J7uJfki1.js → UserSettingsModal-92nP1add.js} +2 -2
  8. package/dist/{VideoCallOverlay-BXHNEhdX.js → VideoCallOverlay-DYd3pFuD.js} +1 -1
  9. package/dist/{VisibilityModal-4QJnWpAL.js → VisibilityModal-BKI5XKir.js} +2 -2
  10. package/dist/assets/icons.d.ts +8 -0
  11. package/dist/components/MainComponents/AttachmentList.d.ts +5 -0
  12. package/dist/components/styled/MessageImage.d.ts +10 -0
  13. package/dist/e2ee/crypto.d.ts +32 -0
  14. package/dist/e2ee/index.d.ts +53 -0
  15. package/dist/e2ee/omemo.d.ts +130 -0
  16. package/dist/e2ee/protobuf.d.ts +25 -0
  17. package/dist/e2ee/ratchet.d.ts +54 -0
  18. package/dist/e2ee/stanza.d.ts +24 -0
  19. package/dist/e2ee/store.d.ts +12 -0
  20. package/dist/{handleCopyClick-Bj2V_brV.js → handleCopyClick-tizCFAb8.js} +1 -1
  21. package/dist/helpers/findMessagesForFile.d.ts +25 -0
  22. package/dist/helpers/xmppIdShape.d.ts +9 -0
  23. package/dist/helpers/xmppUsername.d.ts +1 -1
  24. package/dist/hooks/useChatWrapperInit.d.ts +5 -1
  25. package/dist/{main-DmtEeYji.js → main-DkokKp7d.js} +19687 -16224
  26. package/dist/main.d.ts +2 -0
  27. package/dist/main.js +23 -20
  28. package/dist/networking/api-requests/rooms.api.d.ts +1 -1
  29. package/dist/networking/authRefresh.d.ts +6 -0
  30. package/dist/networking/xmpp/sendTextMessage.xmpp.d.ts +1 -1
  31. package/dist/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts +1 -1
  32. package/dist/networking/xmppClient.d.ts +39 -0
  33. package/dist/roomStore/storage.d.ts +2 -1
  34. package/dist/types/models/config.model.d.ts +14 -0
  35. package/dist/types/models/message.model.d.ts +10 -0
  36. package/dist/types/models/room.model.d.ts +10 -0
  37. package/package.json +4 -1
  38. package/dist/UserProfileModal-CD2IB5SD.js +0 -574
package/dist/main.d.ts CHANGED
@@ -32,3 +32,5 @@ export type { Iso639_1Codes, Language, LanguageOptions, } from './types/models/l
32
32
  export type { CustomComponentsContextValue, CustomScrollableAreaProps, DaySeparatorProps, NewMessageLabelProps, DecoratedMessage, ScrollControllerApi, } from './types/models/customComponents.model';
33
33
  export type { SendInputProps } from './components/styled/SendInput';
34
34
  export type { xmppSettingsInterface, XmppClientInterface, MediaUploadData, } from './types/models/xmpp.model';
35
+ export { omemo, isE2eeEnabled, formatFingerprint } from './e2ee';
36
+ export type { DeviceInfo, Trust } from './e2ee';
package/dist/main.js CHANGED
@@ -1,27 +1,30 @@
1
- import { b2 as a, b3 as r, b4 as b, b5 as o, b6 as t, b7 as h, b8 as u, b9 as i, ba as p, bb as n, bc as d, J as l, bd as T, be as f, bf as y, bg as I, bh as R, bi as c, bj as g, bk as m, ah as C, ai as k, bl as A, bm as Q } from "./main-DmtEeYji.js";
1
+ import { b3 as a, b4 as r, b5 as b, b6 as o, b7 as t, b8 as i, b9 as p, ba as u, bb as h, bc as n, bd as d, be as l, bf as f, J as m, bg as T, bh as g, bi as y, bj as I, bk as R, bl as c, bm as C, bn as k, bo as A, ai as E, aj as Q, bp as F, bq as M } from "./main-DkokKp7d.js";
2
2
  export {
3
3
  a as AuthTestIds,
4
4
  r as Chat,
5
5
  b as ChatInputTestIds,
6
6
  o as MessageBubbleTestIds,
7
7
  t as RefreshFatalError,
8
- h as RoomListTestIds,
9
- u as XmppProvider,
10
- i as applyTypography,
11
- p as clearTypography,
12
- n as handleQRChatId,
13
- d as isRefreshFatalError,
14
- l as logoutService,
15
- T as parseQuickReplies,
16
- f as refreshAuthTokens,
17
- y as refreshAuthTokensQuietly,
18
- I as resendMessage,
19
- R as useInAppNotifications,
20
- c as useIsUserOnline,
21
- g as usePushNotifications,
22
- m as useQRCodeChat,
23
- C as useRoomMute,
24
- k as useRoomPresence,
25
- A as useTypography,
26
- Q as useUnread
8
+ i as RoomListTestIds,
9
+ p as XmppProvider,
10
+ u as applyTypography,
11
+ h as clearTypography,
12
+ n as formatFingerprint,
13
+ d as handleQRChatId,
14
+ l as isE2eeEnabled,
15
+ f as isRefreshFatalError,
16
+ m as logoutService,
17
+ T as omemo,
18
+ g as parseQuickReplies,
19
+ y as refreshAuthTokens,
20
+ I as refreshAuthTokensQuietly,
21
+ R as resendMessage,
22
+ c as useInAppNotifications,
23
+ C as useIsUserOnline,
24
+ k as usePushNotifications,
25
+ A as useQRCodeChat,
26
+ E as useRoomMute,
27
+ Q as useRoomPresence,
28
+ F as useTypography,
29
+ M as useUnread
27
30
  };
@@ -15,7 +15,7 @@ export declare function unmuteRoom(chatName: string): Promise<{
15
15
  muted: boolean;
16
16
  } | undefined>;
17
17
  export declare function postRoom(data: PostRoom): Promise<any>;
18
- export declare function postPrivateRoom(username: string, title?: string): Promise<ApiRoom>;
18
+ export declare function postPrivateRoom(username: string, e2ee?: boolean): Promise<ApiRoom>;
19
19
  export declare function postReportRoom(data: PostReportRoom): Promise<any>;
20
20
  export declare function postAddRoomMember(data: PostAddRoomMember): Promise<RoomMember[]>;
21
21
  export declare function deleteRoomMember(data: DeleteRoomMember): Promise<any>;
@@ -103,6 +103,12 @@ type CredentialLike = Partial<Pick<User, 'xmppUsername' | 'refreshToken' | 'toke
103
103
  export declare function markCurrentSessionDead(): void;
104
104
  export declare function isSessionDead(candidate: CredentialLike): boolean;
105
105
  export declare function clearDeadSessionLatch(): void;
106
+ /**
107
+ * Single-flight wrapper: several requests can fail with the same dead
108
+ * refresh token at once (a burst of 401s right after the token dies), and
109
+ * without this each would call the host's `loginFunction` independently.
110
+ */
111
+ export declare function attemptHostRecovery(): Promise<boolean>;
106
112
  /** Test seam: drops any shared in-flight promise between cases. */
107
113
  export declare function __resetAuthRefreshStateForTests(): void;
108
114
  export {};
@@ -1,3 +1,3 @@
1
1
  import { Client } from '@xmpp/client';
2
2
  import { IMentionSpan } from '../../types/types';
3
- export declare const sendTextMessage: (client: Client, roomJID: string, firstName: string, lastName: string, photo: string, walletAddress: string, userMessage: string, notDisplayedValue?: string, isReply?: boolean, showInChannel?: boolean, mainMessage?: string, devServer?: string, customId?: string, mentions?: IMentionSpan[]) => boolean;
3
+ export declare const sendTextMessage: (client: Client, roomJID: string, firstName: string, lastName: string, photo: string, walletAddress: string, userMessage: string, notDisplayedValue?: string, isReply?: boolean, showInChannel?: boolean, mainMessage?: string, devServer?: string, customId?: string, mentions?: IMentionSpan[]) => Promise<boolean>;
@@ -13,4 +13,4 @@ export declare const sendTextMessageWithTranslateTag: (client: Client, stanzaMes
13
13
  mainMessage?: string;
14
14
  devServer?: string;
15
15
  mentions?: IMentionSpan[];
16
- }, source: Iso639_1Codes, customId?: string) => boolean;
16
+ }, source: Iso639_1Codes, customId?: string) => Promise<boolean>;
@@ -109,6 +109,45 @@ export declare class XmppClient implements XmppClientInterface {
109
109
  */
110
110
  private authRecoveryAttempts;
111
111
  private maxAuthRecoveryAttempts;
112
+ /**
113
+ * True for the whole span of a bounded, self-healing credential
114
+ * refresh - from the moment `recoverFromAuthFailure` commits to trying
115
+ * again through to it either reconnecting online or giving up. While
116
+ * this is true, `status` cycles through 'auth_failed' -> 'offline' ->
117
+ * 'connecting' purely as a side effect of the refresh-and-reconnect
118
+ * dance, not because anything is actually wrong with the network - see
119
+ * `isRecoveringAuth` and its use in useChatWrapperInit's
120
+ * `isStatusConnectionLost`.
121
+ */
122
+ private authRecoveryActive;
123
+ /**
124
+ * Whether a bounded, provider-backed credential recovery is currently
125
+ * in flight (see `authRecoveryActive` above). Consumers use this to
126
+ * avoid painting a "Connection lost" banner for a recoverable, expected
127
+ * token refresh - only a status change that happens OUTSIDE this window
128
+ * (a real socket/network drop, or a recovery that has already given up)
129
+ * should read as a genuine connection loss.
130
+ */
131
+ get isRecoveringAuth(): boolean;
132
+ /**
133
+ * Bug C, part 2: a client that has never once reached 'online' is
134
+ * mid-FIRST-connect, not "lost" - the WS handshake + SASL bind for a
135
+ * brand new session routinely spends a second or two sitting in
136
+ * 'connecting'/'offline' before its first 'online', and
137
+ * isStatusConnectionLost used to paint that identically to a real
138
+ * dropped connection, flashing "Connection lost. Retrying..." on every
139
+ * cold start (measured live: ~2s, samples 4-13 of a 200ms poll) even
140
+ * though nothing had ever been connected in the first place.
141
+ *
142
+ * Set once, on the first 'online' event, and deliberately never reset -
143
+ * a later real drop (offline/error) or auth-triggered reconnect must
144
+ * still read as connection-lost once this session has actually been
145
+ * online before. `authFailureDetected`/`authRecoveryAttempts` reset on
146
+ * every reconnect; this one is a one-way latch for the life of the
147
+ * client instance.
148
+ */
149
+ private everOnline;
150
+ get hasEverBeenOnline(): boolean;
112
151
  /**
113
152
  * Inject (or replace) the callback used to fetch fresh XMPP
114
153
  * credentials after a SASL `not-authorized`. The provider refreshes
@@ -1,4 +1,5 @@
1
- import { default as createWebStorage } from 'redux-persist/lib/storage/createWebStorage';
1
+ import { default as createWebStorageImport } from 'redux-persist/lib/storage/createWebStorage';
2
+ declare const createWebStorage: typeof createWebStorageImport;
2
3
  export declare const isQuotaExceededError: (error: unknown) => boolean;
3
4
  export declare const withQuotaHandling: (engine: ReturnType<typeof createWebStorage>) => ReturnType<typeof createWebStorage>;
4
5
  declare const storage: {
@@ -135,6 +135,20 @@ export type ChatErrorFallbackRenderer = (context: ChatErrorInfo & {
135
135
  }) => React.ReactNode;
136
136
  export interface IConfig {
137
137
  appId?: string;
138
+ /**
139
+ * End-to-end encryption (OMEMO 2, XEP-0384).
140
+ *
141
+ * Off by default, and off means nothing changes: no keys are generated, no
142
+ * PEP node is touched, and stanzas are built exactly as before. With it on,
143
+ * the SDK publishes this device's keys after connecting and encrypts
144
+ * messages in rooms the backend marked `e2ee` - other rooms stay plain.
145
+ *
146
+ * Requires a backend that reports `e2ee` per chat and an XMPP server that
147
+ * lets members read each other's OMEMO PEP nodes (`access_model: open`).
148
+ */
149
+ e2ee?: {
150
+ enabled: boolean;
151
+ };
138
152
  disableHeader?: boolean;
139
153
  disableMedia?: boolean;
140
154
  /** Composer attachment limits. Applies to the built-in SendInput. */
@@ -17,8 +17,18 @@ export interface IMessage {
17
17
  locationPreview?: string;
18
18
  mimetype?: string;
19
19
  location?: string;
20
+ attachmentId?: string;
20
21
  pending?: boolean;
21
22
  failed?: boolean;
23
+ /**
24
+ * Sent in clear in a room that is supposed to be end-to-end encrypted.
25
+ *
26
+ * Derived locally, never trusted from the sender: in an `e2ee` room any
27
+ * message that did not arrive inside an OMEMO payload is unprotected,
28
+ * whatever it claims about itself. The bubble marks these so nobody
29
+ * mistakes the room's badge for a guarantee about this message.
30
+ */
31
+ unencrypted?: boolean;
22
32
  timestamp?: number;
23
33
  showInChannel?: string;
24
34
  activeMessage?: boolean;
@@ -27,6 +27,14 @@ export interface IRoom {
27
27
  roomBg: string;
28
28
  members?: RoomMember[];
29
29
  type?: 'public' | 'group' | 'private';
30
+ /**
31
+ * End-to-end encrypted room (OMEMO 2), as the backend reports it on
32
+ * `GET /v1/chats/my`. Set once when the room is created and never changed:
33
+ * flipping it would either leak plaintext into a room the other side reads
34
+ * as encrypted, or drop encryption the other side relies on. The SDK only
35
+ * runs its OMEMO path for rooms carrying this flag.
36
+ */
37
+ e2ee?: boolean;
30
38
  creteadAt?: string;
31
39
  appId?: string;
32
40
  createdAt?: string;
@@ -95,6 +103,8 @@ export interface ApiRoomLastMessage {
95
103
  export interface ApiRoom {
96
104
  name: string;
97
105
  type: 'public' | 'group' | 'private';
106
+ /** See IRoom.e2ee. Passed straight through by createRoomFromApi. */
107
+ e2ee?: boolean;
98
108
  title?: string;
99
109
  description?: string;
100
110
  picture?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethora/chat-component",
3
- "version": "26.8.1",
3
+ "version": "26.8.2",
4
4
  "type": "module",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",
@@ -49,6 +49,9 @@
49
49
  "@emoji-mart/react": "^1.1.1",
50
50
  "@livekit/components-react": "^2.9.20",
51
51
  "@livekit/components-styles": "^1.2.0",
52
+ "@noble/ciphers": "^2.4.0",
53
+ "@noble/curves": "^2.4.0",
54
+ "@noble/hashes": "^2.4.0",
52
55
  "@reduxjs/toolkit": "^2.8.2",
53
56
  "@types/styled-components": "^5.1.34",
54
57
  "@xmpp/client": "^0.13.6",