@antzsoft/chat-core 1.2.3 → 1.2.5
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 +70 -36
- package/dist/chat.store-DLNRJ5ZT.js +7 -0
- package/dist/{chunk-GUO5QQGK.js → chunk-EOL5B7GS.js} +4 -2
- package/dist/chunk-EOL5B7GS.js.map +1 -0
- package/dist/{chunk-P7VAN6NA.js → chunk-ZNA6B2R5.js} +305 -72
- package/dist/chunk-ZNA6B2R5.js.map +1 -0
- package/dist/index.cjs +296 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +64 -142
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +68 -8
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +1 -1
- package/dist/{storage-DO8QIqKq.d.cts → storage-CctLCOnZ.d.cts} +54 -4
- package/dist/{storage-DO8QIqKq.d.ts → storage-CctLCOnZ.d.ts} +54 -4
- package/docs/integration-guide.html +209 -28
- package/package.json +1 -1
- package/dist/chat.store-JC6QYDDL.js +0 -7
- package/dist/chunk-GUO5QQGK.js.map +0 -1
- package/dist/chunk-P7VAN6NA.js.map +0 -1
- /package/dist/{chat.store-JC6QYDDL.js.map → chat.store-DLNRJ5ZT.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { R as ResolvedCompressionConfig, L as LoginCredentials, A as AuthResponse, a as RegisterData, b as AuthTokens, U as User, c as AppConfig, S as SendMessagePayload, C as CursorPaginatedResponse, M as Message, P as PaginatedResponse, d as MessageReceiptsResponse, e as ConversationListParams, f as Conversation, g as Participant, h as ConversationUnreadCount, i as UnreadSummary, j as UserPreferences, k as ResolvedConfig, l as PersistStorage, m as PresignedUrlRequest, n as PresignedUrlResponse, F as FileResponse, o as CompletedPart, p as FileType, q as AntzChatConfig, r as UploadableFile, B as BatchUploadResult } from './storage-CctLCOnZ.cjs';
|
|
2
|
+
export { s as Attachment, t as CompressedFile, u as CompressionAlgorithm, v as CompressionConfig, w as ConversationType, x as FileSizeLimits, y as LastReaction, z as MessageAckEvent, D as MessageContent, E as MessageDeletedEvent, G as MessageDeletedForMeEvent, H as MessageDeliveredEvent, I as MessageMetadata, J as MessageReaction, K as MessageReceiptEntry, N as MessageReplyReference, O as MessageUpdatedEvent, Q as MessagesDeliveredEvent, T as MultipartPartUrl, V as MultipartUploadInfo, W as NewMessageEvent, X as OptimisticAttachment, Y as PlatformCompressFn, Z as PlatformUploadFn, _ as PlatformUploadPartFn, $ as QuietHours, a0 as ReactionUpdatedEvent, a1 as ReadReceiptEvent, a2 as ReplyAttachmentSnapshot, a3 as ResolvedFileSizeLimits, a4 as SendMessageAttachment, a5 as SystemMessageMetadata, a6 as TypingIndicatorEvent, a7 as UploadConfig, a8 as UploadProgress, a9 as UserStatusEvent, aa as resolveConfig, ab as storageApi, ac as uploadBatch } from './storage-CctLCOnZ.cjs';
|
|
3
3
|
import { AxiosInstance } from 'axios';
|
|
4
4
|
import { Socket } from 'socket.io-client';
|
|
5
5
|
import * as zustand_middleware from 'zustand/middleware';
|
|
@@ -286,6 +286,35 @@ interface TransitSession {
|
|
|
286
286
|
enabled: boolean;
|
|
287
287
|
}
|
|
288
288
|
declare function setTransitSession(session: TransitSession): void;
|
|
289
|
+
declare function getSessionKey(): CryptoKey | Uint8Array | null;
|
|
290
|
+
declare function getSessionId(): string | null;
|
|
291
|
+
|
|
292
|
+
interface TransitEnvelope {
|
|
293
|
+
v: 1;
|
|
294
|
+
iv: string;
|
|
295
|
+
tag: string;
|
|
296
|
+
ct: string;
|
|
297
|
+
}
|
|
298
|
+
type AnySessionKey = CryptoKey | Uint8Array;
|
|
299
|
+
declare function encryptPayload(data: unknown, sessionKey: AnySessionKey): Promise<TransitEnvelope>;
|
|
300
|
+
declare function decryptPayload(envelope: TransitEnvelope, sessionKey: AnySessionKey): Promise<unknown>;
|
|
301
|
+
declare function isTransitEnvelope(v: unknown): v is TransitEnvelope;
|
|
302
|
+
|
|
303
|
+
interface ServerPublicKeys {
|
|
304
|
+
x25519: string;
|
|
305
|
+
p256: string;
|
|
306
|
+
enabled: boolean;
|
|
307
|
+
}
|
|
308
|
+
declare function fetchServerKeys(apiUrl: string): Promise<ServerPublicKeys>;
|
|
309
|
+
declare function generateEphemeralKey(algo: TransitAlgo, serverKeys: ServerPublicKeys): Promise<{
|
|
310
|
+
ephemeralPubB64: string;
|
|
311
|
+
deriveSessionKey: (sessionId: string) => Promise<unknown>;
|
|
312
|
+
}>;
|
|
313
|
+
declare function createRestTransitSession(apiUrl: string): Promise<{
|
|
314
|
+
sessionId: string;
|
|
315
|
+
sessionKey: CryptoKey | Uint8Array;
|
|
316
|
+
} | null>;
|
|
317
|
+
declare function performHandshake(algo: TransitAlgo, serverKeys: ServerPublicKeys, socketHandshakeAuth: Record<string, unknown>): Promise<(sessionId: string) => Promise<unknown>>;
|
|
289
318
|
|
|
290
319
|
interface AuthState {
|
|
291
320
|
user: User | null;
|
|
@@ -398,6 +427,8 @@ interface ChatState {
|
|
|
398
427
|
isSidebarOpen: boolean;
|
|
399
428
|
isGroupInfoOpen: boolean;
|
|
400
429
|
isStarredPanelOpen: boolean;
|
|
430
|
+
/** messageId currently shown in the Message Info panel, null = closed */
|
|
431
|
+
messageInfoId: string | null;
|
|
401
432
|
setActiveConversation: (id: string | null) => void;
|
|
402
433
|
setPendingTarget: (target: {
|
|
403
434
|
conversationId: string;
|
|
@@ -418,6 +449,7 @@ interface ChatState {
|
|
|
418
449
|
setGroupInfoOpen: (open: boolean) => void;
|
|
419
450
|
toggleStarredPanel: () => void;
|
|
420
451
|
setStarredPanelOpen: (open: boolean) => void;
|
|
452
|
+
setMessageInfoId: (id: string | null) => void;
|
|
421
453
|
}
|
|
422
454
|
declare const useChatStore: zustand.UseBoundStore<zustand.StoreApi<ChatState>>;
|
|
423
455
|
|
|
@@ -530,6 +562,7 @@ declare class AntzChatClient {
|
|
|
530
562
|
expiresAt: string;
|
|
531
563
|
}>;
|
|
532
564
|
deleteFile(fileId: string): Promise<void>;
|
|
565
|
+
completeMultipartUpload(fileId: string, uploadId: string, parts: CompletedPart[]): Promise<FileResponse>;
|
|
533
566
|
getConversationFiles(conversationId: string, params?: {
|
|
534
567
|
page?: number;
|
|
535
568
|
limit?: number;
|
|
@@ -562,4 +595,4 @@ declare class AntzChatClient {
|
|
|
562
595
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
563
596
|
}
|
|
564
597
|
|
|
565
|
-
export { AntzChatClient, AntzChatConfig, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, Conversation, ConversationListParams, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CursorPaginatedResponse, FileResponse, FileType, type LastReadEntry, type ListMessagesParams, LoginCredentials, Message, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
|
598
|
+
export { AntzChatClient, AntzChatConfig, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, CompletedPart, Conversation, ConversationListParams, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CursorPaginatedResponse, FileResponse, FileType, type LastReadEntry, type ListMessagesParams, LoginCredentials, Message, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, createRestTransitSession, decryptPayload, devicesApi, disconnectSocket, encryptPayload, fetchServerKeys, generateEphemeralKey, getApiClient, getAuthStore, getCompressionStrategy, getSessionId, getSessionKey, getSocket, getSocketStatus, initApiClient, initAuthStore, isTransitEnvelope, messagesApi, normalizeConversation, onSocketStatus, performHandshake, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { R as ResolvedCompressionConfig, L as LoginCredentials, A as AuthResponse, a as RegisterData, b as AuthTokens, U as User, c as AppConfig, S as SendMessagePayload, C as CursorPaginatedResponse, M as Message, P as PaginatedResponse, d as MessageReceiptsResponse, e as ConversationListParams, f as Conversation, g as Participant, h as ConversationUnreadCount, i as UnreadSummary, j as UserPreferences, k as ResolvedConfig, l as PersistStorage, m as PresignedUrlRequest, n as PresignedUrlResponse, F as FileResponse, o as CompletedPart, p as FileType, q as AntzChatConfig, r as UploadableFile, B as BatchUploadResult } from './storage-CctLCOnZ.js';
|
|
2
|
+
export { s as Attachment, t as CompressedFile, u as CompressionAlgorithm, v as CompressionConfig, w as ConversationType, x as FileSizeLimits, y as LastReaction, z as MessageAckEvent, D as MessageContent, E as MessageDeletedEvent, G as MessageDeletedForMeEvent, H as MessageDeliveredEvent, I as MessageMetadata, J as MessageReaction, K as MessageReceiptEntry, N as MessageReplyReference, O as MessageUpdatedEvent, Q as MessagesDeliveredEvent, T as MultipartPartUrl, V as MultipartUploadInfo, W as NewMessageEvent, X as OptimisticAttachment, Y as PlatformCompressFn, Z as PlatformUploadFn, _ as PlatformUploadPartFn, $ as QuietHours, a0 as ReactionUpdatedEvent, a1 as ReadReceiptEvent, a2 as ReplyAttachmentSnapshot, a3 as ResolvedFileSizeLimits, a4 as SendMessageAttachment, a5 as SystemMessageMetadata, a6 as TypingIndicatorEvent, a7 as UploadConfig, a8 as UploadProgress, a9 as UserStatusEvent, aa as resolveConfig, ab as storageApi, ac as uploadBatch } from './storage-CctLCOnZ.js';
|
|
3
3
|
import { AxiosInstance } from 'axios';
|
|
4
4
|
import { Socket } from 'socket.io-client';
|
|
5
5
|
import * as zustand_middleware from 'zustand/middleware';
|
|
@@ -286,6 +286,35 @@ interface TransitSession {
|
|
|
286
286
|
enabled: boolean;
|
|
287
287
|
}
|
|
288
288
|
declare function setTransitSession(session: TransitSession): void;
|
|
289
|
+
declare function getSessionKey(): CryptoKey | Uint8Array | null;
|
|
290
|
+
declare function getSessionId(): string | null;
|
|
291
|
+
|
|
292
|
+
interface TransitEnvelope {
|
|
293
|
+
v: 1;
|
|
294
|
+
iv: string;
|
|
295
|
+
tag: string;
|
|
296
|
+
ct: string;
|
|
297
|
+
}
|
|
298
|
+
type AnySessionKey = CryptoKey | Uint8Array;
|
|
299
|
+
declare function encryptPayload(data: unknown, sessionKey: AnySessionKey): Promise<TransitEnvelope>;
|
|
300
|
+
declare function decryptPayload(envelope: TransitEnvelope, sessionKey: AnySessionKey): Promise<unknown>;
|
|
301
|
+
declare function isTransitEnvelope(v: unknown): v is TransitEnvelope;
|
|
302
|
+
|
|
303
|
+
interface ServerPublicKeys {
|
|
304
|
+
x25519: string;
|
|
305
|
+
p256: string;
|
|
306
|
+
enabled: boolean;
|
|
307
|
+
}
|
|
308
|
+
declare function fetchServerKeys(apiUrl: string): Promise<ServerPublicKeys>;
|
|
309
|
+
declare function generateEphemeralKey(algo: TransitAlgo, serverKeys: ServerPublicKeys): Promise<{
|
|
310
|
+
ephemeralPubB64: string;
|
|
311
|
+
deriveSessionKey: (sessionId: string) => Promise<unknown>;
|
|
312
|
+
}>;
|
|
313
|
+
declare function createRestTransitSession(apiUrl: string): Promise<{
|
|
314
|
+
sessionId: string;
|
|
315
|
+
sessionKey: CryptoKey | Uint8Array;
|
|
316
|
+
} | null>;
|
|
317
|
+
declare function performHandshake(algo: TransitAlgo, serverKeys: ServerPublicKeys, socketHandshakeAuth: Record<string, unknown>): Promise<(sessionId: string) => Promise<unknown>>;
|
|
289
318
|
|
|
290
319
|
interface AuthState {
|
|
291
320
|
user: User | null;
|
|
@@ -398,6 +427,8 @@ interface ChatState {
|
|
|
398
427
|
isSidebarOpen: boolean;
|
|
399
428
|
isGroupInfoOpen: boolean;
|
|
400
429
|
isStarredPanelOpen: boolean;
|
|
430
|
+
/** messageId currently shown in the Message Info panel, null = closed */
|
|
431
|
+
messageInfoId: string | null;
|
|
401
432
|
setActiveConversation: (id: string | null) => void;
|
|
402
433
|
setPendingTarget: (target: {
|
|
403
434
|
conversationId: string;
|
|
@@ -418,6 +449,7 @@ interface ChatState {
|
|
|
418
449
|
setGroupInfoOpen: (open: boolean) => void;
|
|
419
450
|
toggleStarredPanel: () => void;
|
|
420
451
|
setStarredPanelOpen: (open: boolean) => void;
|
|
452
|
+
setMessageInfoId: (id: string | null) => void;
|
|
421
453
|
}
|
|
422
454
|
declare const useChatStore: zustand.UseBoundStore<zustand.StoreApi<ChatState>>;
|
|
423
455
|
|
|
@@ -530,6 +562,7 @@ declare class AntzChatClient {
|
|
|
530
562
|
expiresAt: string;
|
|
531
563
|
}>;
|
|
532
564
|
deleteFile(fileId: string): Promise<void>;
|
|
565
|
+
completeMultipartUpload(fileId: string, uploadId: string, parts: CompletedPart[]): Promise<FileResponse>;
|
|
533
566
|
getConversationFiles(conversationId: string, params?: {
|
|
534
567
|
page?: number;
|
|
535
568
|
limit?: number;
|
|
@@ -562,4 +595,4 @@ declare class AntzChatClient {
|
|
|
562
595
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
563
596
|
}
|
|
564
597
|
|
|
565
|
-
export { AntzChatClient, AntzChatConfig, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, Conversation, ConversationListParams, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CursorPaginatedResponse, FileResponse, FileType, type LastReadEntry, type ListMessagesParams, LoginCredentials, Message, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
|
598
|
+
export { AntzChatClient, AntzChatConfig, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, CompletedPart, Conversation, ConversationListParams, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CursorPaginatedResponse, FileResponse, FileType, type LastReadEntry, type ListMessagesParams, LoginCredentials, Message, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, createRestTransitSession, decryptPayload, devicesApi, disconnectSocket, encryptPayload, fetchServerKeys, generateEphemeralKey, getApiClient, getAuthStore, getCompressionStrategy, getSessionId, getSessionKey, getSocket, getSocketStatus, initApiClient, initAuthStore, isTransitEnvelope, messagesApi, normalizeConversation, onSocketStatus, performHandshake, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
2
|
clearTransitSession,
|
|
3
3
|
configureTransit,
|
|
4
|
+
createRestTransitSession,
|
|
4
5
|
decryptPayload,
|
|
6
|
+
detectTransitAlgo,
|
|
5
7
|
encryptPayload,
|
|
8
|
+
fetchServerKeys,
|
|
9
|
+
generateEphemeralKey,
|
|
6
10
|
getApiClient,
|
|
7
11
|
getCompressionStrategy,
|
|
12
|
+
getSessionId,
|
|
8
13
|
getSessionKey,
|
|
14
|
+
getTransitHandshakePromise,
|
|
15
|
+
getTransitSession,
|
|
9
16
|
initApiClient,
|
|
10
17
|
isTransitEnabled,
|
|
11
18
|
isTransitEnvelope,
|
|
19
|
+
performHandshake,
|
|
20
|
+
resetAlgoCache,
|
|
12
21
|
setApiClientInstance,
|
|
13
22
|
setTransitSession,
|
|
14
23
|
storageApi,
|
|
15
24
|
uploadBatch
|
|
16
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-ZNA6B2R5.js";
|
|
17
26
|
import {
|
|
18
27
|
useChatStore
|
|
19
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-EOL5B7GS.js";
|
|
20
29
|
|
|
21
30
|
// src/config/types.ts
|
|
22
31
|
function resolveConfig(config) {
|
|
@@ -63,6 +72,7 @@ function resolveConfig(config) {
|
|
|
63
72
|
onProgress: config.upload?.onProgress
|
|
64
73
|
},
|
|
65
74
|
platformUploadFn: config.platformUploadFn,
|
|
75
|
+
platformUploadPartFn: config.platformUploadPartFn,
|
|
66
76
|
platformCompressFn: config.platformCompressFn,
|
|
67
77
|
compression: {
|
|
68
78
|
enabled: config.compression?.enabled ?? config.platformCompressFn != null,
|
|
@@ -366,7 +376,7 @@ function normalizeLastMessage(lastMsg) {
|
|
|
366
376
|
id: lastMsg.messageId ?? "",
|
|
367
377
|
tenantId: "",
|
|
368
378
|
conversationId: "",
|
|
369
|
-
senderId: "",
|
|
379
|
+
senderId: lastMsg.senderId ?? "",
|
|
370
380
|
content: {
|
|
371
381
|
type: lastMsg.hasAttachments ? "attachment" : "text",
|
|
372
382
|
text: lastMsg.contentPreview
|
|
@@ -377,7 +387,8 @@ function normalizeLastMessage(lastMsg) {
|
|
|
377
387
|
isEdited: false,
|
|
378
388
|
sentAt: lastMsg.sentAt ?? "",
|
|
379
389
|
createdAt: lastMsg.sentAt ?? "",
|
|
380
|
-
...lastMsg.senderName && { senderName: lastMsg.senderName }
|
|
390
|
+
...lastMsg.senderName && { senderName: lastMsg.senderName },
|
|
391
|
+
...lastMsg.attachmentType && { attachmentType: lastMsg.attachmentType }
|
|
381
392
|
};
|
|
382
393
|
}
|
|
383
394
|
function normalizeConversation(conv) {
|
|
@@ -567,122 +578,6 @@ var usersApi = {
|
|
|
567
578
|
|
|
568
579
|
// src/socket/socket.ts
|
|
569
580
|
import { io } from "socket.io-client";
|
|
570
|
-
|
|
571
|
-
// src/crypto/detect.ts
|
|
572
|
-
var _cached = null;
|
|
573
|
-
async function detectTransitAlgo() {
|
|
574
|
-
if (_cached) return _cached;
|
|
575
|
-
try {
|
|
576
|
-
await globalThis.crypto.subtle.generateKey(
|
|
577
|
-
{ name: "X25519" },
|
|
578
|
-
false,
|
|
579
|
-
["deriveKey"]
|
|
580
|
-
);
|
|
581
|
-
_cached = "x25519";
|
|
582
|
-
} catch {
|
|
583
|
-
_cached = "p256";
|
|
584
|
-
}
|
|
585
|
-
return _cached;
|
|
586
|
-
}
|
|
587
|
-
function resetAlgoCache() {
|
|
588
|
-
_cached = null;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// src/crypto/handshake.ts
|
|
592
|
-
function hasWebCrypto() {
|
|
593
|
-
return typeof globalThis.crypto?.subtle !== "undefined";
|
|
594
|
-
}
|
|
595
|
-
async function fetchServerKeys(apiUrl) {
|
|
596
|
-
const res = await fetch(`${apiUrl}/crypto/pubkey`);
|
|
597
|
-
if (!res.ok) throw new Error(`[AntzChat] Failed to fetch server public key: ${res.status}`);
|
|
598
|
-
const body = await res.json();
|
|
599
|
-
return body?.data ?? body;
|
|
600
|
-
}
|
|
601
|
-
async function performHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
602
|
-
if (hasWebCrypto()) {
|
|
603
|
-
return performWebCryptoHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
604
|
-
}
|
|
605
|
-
return performNobleHandshake(serverKeys, socketHandshakeAuth);
|
|
606
|
-
}
|
|
607
|
-
async function performWebCryptoHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
608
|
-
const ephemeral = await globalThis.crypto.subtle.generateKey(
|
|
609
|
-
algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" },
|
|
610
|
-
false,
|
|
611
|
-
["deriveBits"]
|
|
612
|
-
);
|
|
613
|
-
const pubRaw = await globalThis.crypto.subtle.exportKey("raw", ephemeral.publicKey);
|
|
614
|
-
socketHandshakeAuth["transitEphemeralPub"] = bufToB64(pubRaw);
|
|
615
|
-
socketHandshakeAuth["transitAlgo"] = algo;
|
|
616
|
-
const ephemeralPriv = ephemeral.privateKey;
|
|
617
|
-
return (sessionId) => deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId);
|
|
618
|
-
}
|
|
619
|
-
async function deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId) {
|
|
620
|
-
const serverPubRaw = b64ToBuf(algo === "x25519" ? serverKeys.x25519 : serverKeys.p256);
|
|
621
|
-
const keyAlgoParams = algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" };
|
|
622
|
-
const serverPubKey = await globalThis.crypto.subtle.importKey("raw", serverPubRaw, keyAlgoParams, false, []);
|
|
623
|
-
const sharedBits = await globalThis.crypto.subtle.deriveBits(
|
|
624
|
-
{ name: algo === "x25519" ? "X25519" : "ECDH", public: serverPubKey },
|
|
625
|
-
ephemeralPriv,
|
|
626
|
-
256
|
|
627
|
-
);
|
|
628
|
-
const hkdfKey = await globalThis.crypto.subtle.importKey("raw", sharedBits, "HKDF", false, ["deriveKey"]);
|
|
629
|
-
const salt = new TextEncoder().encode(sessionId);
|
|
630
|
-
const info = new TextEncoder().encode("antz-transit-v1");
|
|
631
|
-
return globalThis.crypto.subtle.deriveKey(
|
|
632
|
-
{ name: "HKDF", hash: "SHA-256", salt, info },
|
|
633
|
-
hkdfKey,
|
|
634
|
-
{ name: "AES-GCM", length: 256 },
|
|
635
|
-
false,
|
|
636
|
-
["encrypt", "decrypt"]
|
|
637
|
-
);
|
|
638
|
-
}
|
|
639
|
-
async function performNobleHandshake(serverKeys, socketHandshakeAuth) {
|
|
640
|
-
const { x25519 } = await import("@noble/curves/ed25519");
|
|
641
|
-
const { hkdf } = await import("@noble/hashes/hkdf");
|
|
642
|
-
const { sha256 } = await import("@noble/hashes/sha256");
|
|
643
|
-
const { randomBytes } = await import("@noble/hashes/utils");
|
|
644
|
-
const ephemeralPriv = randomBytes(32);
|
|
645
|
-
const ephemeralPub = x25519.getPublicKey(ephemeralPriv);
|
|
646
|
-
const serverPubBytes = base64ToUint8(serverKeys.x25519);
|
|
647
|
-
socketHandshakeAuth["transitEphemeralPub"] = uint8ToBase64(ephemeralPub);
|
|
648
|
-
socketHandshakeAuth["transitAlgo"] = "x25519";
|
|
649
|
-
return (sessionId) => {
|
|
650
|
-
const sharedSecret = x25519.getSharedSecret(ephemeralPriv, serverPubBytes);
|
|
651
|
-
const salt = new TextEncoder().encode(sessionId);
|
|
652
|
-
const info = new TextEncoder().encode("antz-transit-v1");
|
|
653
|
-
const sessionKey = hkdf(sha256, sharedSecret, salt, info, 32);
|
|
654
|
-
return Promise.resolve(sessionKey);
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
|
-
function bufToB64(buf) {
|
|
658
|
-
const bytes = new Uint8Array(buf);
|
|
659
|
-
let str = "";
|
|
660
|
-
bytes.forEach((b) => {
|
|
661
|
-
str += String.fromCharCode(b);
|
|
662
|
-
});
|
|
663
|
-
return btoa(str);
|
|
664
|
-
}
|
|
665
|
-
function b64ToBuf(b64) {
|
|
666
|
-
const bin = atob(b64);
|
|
667
|
-
const buf = new Uint8Array(bin.length);
|
|
668
|
-
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
669
|
-
return buf.buffer;
|
|
670
|
-
}
|
|
671
|
-
function uint8ToBase64(bytes) {
|
|
672
|
-
let str = "";
|
|
673
|
-
bytes.forEach((b) => {
|
|
674
|
-
str += String.fromCharCode(b);
|
|
675
|
-
});
|
|
676
|
-
return btoa(str);
|
|
677
|
-
}
|
|
678
|
-
function base64ToUint8(b64) {
|
|
679
|
-
const bin = atob(b64);
|
|
680
|
-
const buf = new Uint8Array(bin.length);
|
|
681
|
-
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
682
|
-
return buf;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// src/socket/socket.ts
|
|
686
581
|
var _socket = null;
|
|
687
582
|
var _socketProxy = null;
|
|
688
583
|
var _connectingPromise = null;
|
|
@@ -779,17 +674,35 @@ async function _doConnect(config, getToken) {
|
|
|
779
674
|
};
|
|
780
675
|
let boundDeriveSessionKey = null;
|
|
781
676
|
if (config.transitEncryption) {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
677
|
+
const inFlight = getTransitHandshakePromise();
|
|
678
|
+
if (inFlight) await inFlight;
|
|
679
|
+
const existingSession = getTransitSession();
|
|
680
|
+
let httpsSession = null;
|
|
681
|
+
if (existingSession?.enabled && existingSession.sessionId) {
|
|
682
|
+
httpsSession = { sessionId: existingSession.sessionId, sessionKey: existingSession.sessionKey };
|
|
683
|
+
} else {
|
|
684
|
+
httpsSession = await createRestTransitSession(config.apiUrl);
|
|
685
|
+
if (httpsSession) {
|
|
686
|
+
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
687
|
+
setTransitSession({ sessionKey: httpsSession.sessionKey, algo, sessionId: httpsSession.sessionId, enabled: true });
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (httpsSession) {
|
|
691
|
+
socketHandshakeAuth["transitSessionId"] = httpsSession.sessionId;
|
|
692
|
+
boundDeriveSessionKey = null;
|
|
693
|
+
} else {
|
|
694
|
+
try {
|
|
695
|
+
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
696
|
+
if (!serverKeys.enabled) {
|
|
697
|
+
throw new Error(
|
|
698
|
+
"[AntzChat] Transit encryption mismatch: SDK has transitEncryption=true but server has TRANSIT_ENCRYPTION_ENABLED=false. Align the config on both sides."
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
702
|
+
boundDeriveSessionKey = await performHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
703
|
+
} catch (err) {
|
|
704
|
+
throw err;
|
|
788
705
|
}
|
|
789
|
-
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
790
|
-
boundDeriveSessionKey = await performHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
791
|
-
} catch (err) {
|
|
792
|
-
throw err;
|
|
793
706
|
}
|
|
794
707
|
} else {
|
|
795
708
|
try {
|
|
@@ -852,13 +765,13 @@ async function _doConnect(config, getToken) {
|
|
|
852
765
|
});
|
|
853
766
|
}
|
|
854
767
|
secureOn(_socket, "read_receipt", (event) => {
|
|
855
|
-
import("./chat.store-
|
|
768
|
+
import("./chat.store-DLNRJ5ZT.js").then(({ useChatStore: useChatStore2 }) => {
|
|
856
769
|
const e = event;
|
|
857
770
|
useChatStore2.getState().setLastRead(e.conversationId, e.messageId, e.readAt);
|
|
858
771
|
});
|
|
859
772
|
});
|
|
860
773
|
secureOn(_socket, "user_online", (event) => {
|
|
861
|
-
import("./chat.store-
|
|
774
|
+
import("./chat.store-DLNRJ5ZT.js").then(({ useChatStore: useChatStore2 }) => {
|
|
862
775
|
const store = useChatStore2.getState();
|
|
863
776
|
const e = event;
|
|
864
777
|
store.setUserOnline(e.userId);
|
|
@@ -866,7 +779,7 @@ async function _doConnect(config, getToken) {
|
|
|
866
779
|
});
|
|
867
780
|
});
|
|
868
781
|
secureOn(_socket, "user_offline", (event) => {
|
|
869
|
-
import("./chat.store-
|
|
782
|
+
import("./chat.store-DLNRJ5ZT.js").then(({ useChatStore: useChatStore2 }) => {
|
|
870
783
|
const e = event;
|
|
871
784
|
const store = useChatStore2.getState();
|
|
872
785
|
store.setUserOffline(e.userId);
|
|
@@ -947,11 +860,7 @@ async function drainSendQueue(conversationId) {
|
|
|
947
860
|
entry.reject(new Error("[AntzChat] Message dropped: queued too long"));
|
|
948
861
|
continue;
|
|
949
862
|
}
|
|
950
|
-
|
|
951
|
-
entry.resolve(await entry.run());
|
|
952
|
-
} catch (e) {
|
|
953
|
-
entry.reject(e);
|
|
954
|
-
}
|
|
863
|
+
entry.run().then(entry.resolve).catch(entry.reject);
|
|
955
864
|
}
|
|
956
865
|
sendQueues.delete(conversationId);
|
|
957
866
|
sendQueueRunning.delete(conversationId);
|
|
@@ -995,11 +904,13 @@ async function withAck(event, payload) {
|
|
|
995
904
|
}
|
|
996
905
|
if (!socket) return Promise.reject(new Error(`[AntzChat] Socket not connected (event: ${event})`));
|
|
997
906
|
return new Promise((resolve, reject) => {
|
|
998
|
-
|
|
907
|
+
let timer;
|
|
999
908
|
secureEmit(socket, event, payload, (response) => {
|
|
1000
909
|
clearTimeout(timer);
|
|
1001
910
|
resolve(response);
|
|
1002
|
-
})
|
|
911
|
+
}).then(() => {
|
|
912
|
+
timer = setTimeout(() => reject(new Error(`Socket ack timeout: ${event}`)), ACK_TIMEOUT);
|
|
913
|
+
}).catch(reject);
|
|
1003
914
|
});
|
|
1004
915
|
}
|
|
1005
916
|
function fireAndForget(event, payload) {
|
|
@@ -1049,7 +960,7 @@ var socketEmit = {
|
|
|
1049
960
|
const socket = tryGetSocket();
|
|
1050
961
|
if (!socket) return Promise.resolve([]);
|
|
1051
962
|
return new Promise((resolve, reject) => {
|
|
1052
|
-
|
|
963
|
+
let timer;
|
|
1053
964
|
secureEmit(socket, "get_online_users", { userIds }, (response) => {
|
|
1054
965
|
clearTimeout(timer);
|
|
1055
966
|
if (response && typeof response === "object" && "onlineStatus" in response) {
|
|
@@ -1060,7 +971,9 @@ var socketEmit = {
|
|
|
1060
971
|
} else {
|
|
1061
972
|
resolve([]);
|
|
1062
973
|
}
|
|
1063
|
-
})
|
|
974
|
+
}).then(() => {
|
|
975
|
+
timer = setTimeout(() => reject(new Error("get_online_users timeout")), ACK_TIMEOUT);
|
|
976
|
+
}).catch(reject);
|
|
1064
977
|
});
|
|
1065
978
|
},
|
|
1066
979
|
getTypingUsers(conversationId) {
|
|
@@ -1124,18 +1037,27 @@ export {
|
|
|
1124
1037
|
connectSocket,
|
|
1125
1038
|
conversationsApi,
|
|
1126
1039
|
createAuthStore,
|
|
1040
|
+
createRestTransitSession,
|
|
1041
|
+
decryptPayload,
|
|
1127
1042
|
devicesApi,
|
|
1128
1043
|
disconnectSocket,
|
|
1044
|
+
encryptPayload,
|
|
1045
|
+
fetchServerKeys,
|
|
1046
|
+
generateEphemeralKey,
|
|
1129
1047
|
getApiClient,
|
|
1130
1048
|
getAuthStore,
|
|
1131
1049
|
getCompressionStrategy,
|
|
1050
|
+
getSessionId,
|
|
1051
|
+
getSessionKey,
|
|
1132
1052
|
getSocket,
|
|
1133
1053
|
getSocketStatus,
|
|
1134
1054
|
initApiClient,
|
|
1135
1055
|
initAuthStore,
|
|
1056
|
+
isTransitEnvelope,
|
|
1136
1057
|
messagesApi,
|
|
1137
1058
|
normalizeConversation,
|
|
1138
1059
|
onSocketStatus,
|
|
1060
|
+
performHandshake,
|
|
1139
1061
|
reconnectSocket,
|
|
1140
1062
|
refreshSocketAuth,
|
|
1141
1063
|
resetAuthStore,
|