@antzsoft/chat-core 1.2.4 → 1.2.6
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 +320 -0
- package/dist/{chunk-6NMA64BX.js → chunk-XTQYF5HU.js} +333 -65
- package/dist/chunk-XTQYF5HU.js.map +1 -0
- package/dist/index.cjs +351 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -3
- package/dist/index.d.ts +74 -3
- package/dist/index.js +92 -145
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +6 -1
- 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-Bp6fk9aM.d.cts → storage-CctLCOnZ.d.cts} +1 -1
- package/dist/{storage-Bp6fk9aM.d.ts → storage-CctLCOnZ.d.ts} +1 -1
- package/docs/integration-guide.html +835 -130
- package/package.json +1 -1
- package/dist/chunk-6NMA64BX.js.map +0 -1
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';
|
|
@@ -123,6 +123,7 @@ declare const conversationsApi: {
|
|
|
123
123
|
*/
|
|
124
124
|
uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
|
|
125
125
|
removeIcon(conversationId: string): Promise<Conversation>;
|
|
126
|
+
clearChat(conversationId: string): Promise<void>;
|
|
126
127
|
};
|
|
127
128
|
|
|
128
129
|
/** Shared fields for every device registration. */
|
|
@@ -267,6 +268,7 @@ declare const socketEmit: {
|
|
|
267
268
|
updateMessage(messageId: string, text: string): Promise<unknown>;
|
|
268
269
|
deleteMessage(messageId: string): Promise<unknown>;
|
|
269
270
|
deleteMessageForMe(messageId: string): Promise<unknown>;
|
|
271
|
+
clearChat(conversationId: string): Promise<unknown>;
|
|
270
272
|
addReaction(messageId: string, emoji: string): Promise<unknown>;
|
|
271
273
|
removeReaction(messageId: string, emoji: string): Promise<unknown>;
|
|
272
274
|
pinMessage(messageId: string): Promise<unknown>;
|
|
@@ -286,6 +288,35 @@ interface TransitSession {
|
|
|
286
288
|
enabled: boolean;
|
|
287
289
|
}
|
|
288
290
|
declare function setTransitSession(session: TransitSession): void;
|
|
291
|
+
declare function getSessionKey(): CryptoKey | Uint8Array | null;
|
|
292
|
+
declare function getSessionId(): string | null;
|
|
293
|
+
|
|
294
|
+
interface TransitEnvelope {
|
|
295
|
+
v: 1;
|
|
296
|
+
iv: string;
|
|
297
|
+
tag: string;
|
|
298
|
+
ct: string;
|
|
299
|
+
}
|
|
300
|
+
type AnySessionKey = CryptoKey | Uint8Array;
|
|
301
|
+
declare function encryptPayload(data: unknown, sessionKey: AnySessionKey): Promise<TransitEnvelope>;
|
|
302
|
+
declare function decryptPayload(envelope: TransitEnvelope, sessionKey: AnySessionKey): Promise<unknown>;
|
|
303
|
+
declare function isTransitEnvelope(v: unknown): v is TransitEnvelope;
|
|
304
|
+
|
|
305
|
+
interface ServerPublicKeys {
|
|
306
|
+
x25519: string;
|
|
307
|
+
p256: string;
|
|
308
|
+
enabled: boolean;
|
|
309
|
+
}
|
|
310
|
+
declare function fetchServerKeys(apiUrl: string): Promise<ServerPublicKeys>;
|
|
311
|
+
declare function generateEphemeralKey(algo: TransitAlgo, serverKeys: ServerPublicKeys): Promise<{
|
|
312
|
+
ephemeralPubB64: string;
|
|
313
|
+
deriveSessionKey: (sessionId: string) => Promise<unknown>;
|
|
314
|
+
}>;
|
|
315
|
+
declare function createRestTransitSession(apiUrl: string): Promise<{
|
|
316
|
+
sessionId: string;
|
|
317
|
+
sessionKey: CryptoKey | Uint8Array;
|
|
318
|
+
} | null>;
|
|
319
|
+
declare function performHandshake(algo: TransitAlgo, serverKeys: ServerPublicKeys, socketHandshakeAuth: Record<string, unknown>): Promise<(sessionId: string) => Promise<unknown>>;
|
|
289
320
|
|
|
290
321
|
interface AuthState {
|
|
291
322
|
user: User | null;
|
|
@@ -424,6 +455,45 @@ interface ChatState {
|
|
|
424
455
|
}
|
|
425
456
|
declare const useChatStore: zustand.UseBoundStore<zustand.StoreApi<ChatState>>;
|
|
426
457
|
|
|
458
|
+
declare class AntzChatError extends Error {
|
|
459
|
+
readonly code: string;
|
|
460
|
+
readonly retryable: boolean;
|
|
461
|
+
readonly context?: Record<string, unknown>;
|
|
462
|
+
constructor(code: string, message: string, retryable?: boolean, context?: Record<string, unknown>);
|
|
463
|
+
}
|
|
464
|
+
/** Thrown on 401 (after refresh also fails) or when no refresh token exists. */
|
|
465
|
+
declare class AntzChatAuthError extends AntzChatError {
|
|
466
|
+
constructor(message: string, code?: string, context?: Record<string, unknown>);
|
|
467
|
+
}
|
|
468
|
+
/** Thrown on 400 / 422 — bad input, validation failure. */
|
|
469
|
+
declare class AntzChatValidationError extends AntzChatError {
|
|
470
|
+
/** Server-returned field error array (when the server sends message as string[]). */
|
|
471
|
+
readonly fields?: string[];
|
|
472
|
+
constructor(message: string | string[], context?: Record<string, unknown>);
|
|
473
|
+
}
|
|
474
|
+
/** Thrown on network failures, timeouts, socket disconnections, and queue overflow. retryable = true. */
|
|
475
|
+
declare class AntzChatNetworkError extends AntzChatError {
|
|
476
|
+
constructor(message: string, code?: string, context?: Record<string, unknown>);
|
|
477
|
+
}
|
|
478
|
+
/** Thrown on 403 — insufficient permissions. */
|
|
479
|
+
declare class AntzChatPermissionError extends AntzChatError {
|
|
480
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
481
|
+
}
|
|
482
|
+
/** Thrown on 5xx or other unexpected server errors. retryable = true. */
|
|
483
|
+
declare class AntzChatServerError extends AntzChatError {
|
|
484
|
+
readonly httpStatus?: number;
|
|
485
|
+
constructor(message: string, httpStatus?: number, context?: Record<string, unknown>);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Converts a raw axios error (or any unknown throw) into a typed AntzChatError.
|
|
489
|
+
*
|
|
490
|
+
* Call site: client.ts response interceptor — runs AFTER transit decryption,
|
|
491
|
+
* so error.response.data is always plaintext by the time this function sees it.
|
|
492
|
+
* If decryption itself failed, error.response.data remains the raw encrypted
|
|
493
|
+
* envelope — detected via isTransitEnvelope() and noted in context.
|
|
494
|
+
*/
|
|
495
|
+
declare function normalizeAxiosError(error: unknown): AntzChatError;
|
|
496
|
+
|
|
427
497
|
/**
|
|
428
498
|
* Resolves viewer-aware display text for system messages.
|
|
429
499
|
*
|
|
@@ -515,6 +585,7 @@ declare class AntzChatClient {
|
|
|
515
585
|
getUnreadSummary(): Promise<UnreadSummary>;
|
|
516
586
|
uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
|
|
517
587
|
removeIcon(conversationId: string): Promise<Conversation>;
|
|
588
|
+
clearChat(conversationId: string): Promise<void>;
|
|
518
589
|
};
|
|
519
590
|
readonly storage: {
|
|
520
591
|
requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
|
|
@@ -566,4 +637,4 @@ declare class AntzChatClient {
|
|
|
566
637
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
567
638
|
}
|
|
568
639
|
|
|
569
|
-
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, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
|
640
|
+
export { AntzChatAuthError, AntzChatClient, AntzChatConfig, AntzChatError, AntzChatNetworkError, AntzChatPermissionError, AntzChatServerError, AntzChatValidationError, 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, normalizeAxiosError, 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';
|
|
@@ -123,6 +123,7 @@ declare const conversationsApi: {
|
|
|
123
123
|
*/
|
|
124
124
|
uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
|
|
125
125
|
removeIcon(conversationId: string): Promise<Conversation>;
|
|
126
|
+
clearChat(conversationId: string): Promise<void>;
|
|
126
127
|
};
|
|
127
128
|
|
|
128
129
|
/** Shared fields for every device registration. */
|
|
@@ -267,6 +268,7 @@ declare const socketEmit: {
|
|
|
267
268
|
updateMessage(messageId: string, text: string): Promise<unknown>;
|
|
268
269
|
deleteMessage(messageId: string): Promise<unknown>;
|
|
269
270
|
deleteMessageForMe(messageId: string): Promise<unknown>;
|
|
271
|
+
clearChat(conversationId: string): Promise<unknown>;
|
|
270
272
|
addReaction(messageId: string, emoji: string): Promise<unknown>;
|
|
271
273
|
removeReaction(messageId: string, emoji: string): Promise<unknown>;
|
|
272
274
|
pinMessage(messageId: string): Promise<unknown>;
|
|
@@ -286,6 +288,35 @@ interface TransitSession {
|
|
|
286
288
|
enabled: boolean;
|
|
287
289
|
}
|
|
288
290
|
declare function setTransitSession(session: TransitSession): void;
|
|
291
|
+
declare function getSessionKey(): CryptoKey | Uint8Array | null;
|
|
292
|
+
declare function getSessionId(): string | null;
|
|
293
|
+
|
|
294
|
+
interface TransitEnvelope {
|
|
295
|
+
v: 1;
|
|
296
|
+
iv: string;
|
|
297
|
+
tag: string;
|
|
298
|
+
ct: string;
|
|
299
|
+
}
|
|
300
|
+
type AnySessionKey = CryptoKey | Uint8Array;
|
|
301
|
+
declare function encryptPayload(data: unknown, sessionKey: AnySessionKey): Promise<TransitEnvelope>;
|
|
302
|
+
declare function decryptPayload(envelope: TransitEnvelope, sessionKey: AnySessionKey): Promise<unknown>;
|
|
303
|
+
declare function isTransitEnvelope(v: unknown): v is TransitEnvelope;
|
|
304
|
+
|
|
305
|
+
interface ServerPublicKeys {
|
|
306
|
+
x25519: string;
|
|
307
|
+
p256: string;
|
|
308
|
+
enabled: boolean;
|
|
309
|
+
}
|
|
310
|
+
declare function fetchServerKeys(apiUrl: string): Promise<ServerPublicKeys>;
|
|
311
|
+
declare function generateEphemeralKey(algo: TransitAlgo, serverKeys: ServerPublicKeys): Promise<{
|
|
312
|
+
ephemeralPubB64: string;
|
|
313
|
+
deriveSessionKey: (sessionId: string) => Promise<unknown>;
|
|
314
|
+
}>;
|
|
315
|
+
declare function createRestTransitSession(apiUrl: string): Promise<{
|
|
316
|
+
sessionId: string;
|
|
317
|
+
sessionKey: CryptoKey | Uint8Array;
|
|
318
|
+
} | null>;
|
|
319
|
+
declare function performHandshake(algo: TransitAlgo, serverKeys: ServerPublicKeys, socketHandshakeAuth: Record<string, unknown>): Promise<(sessionId: string) => Promise<unknown>>;
|
|
289
320
|
|
|
290
321
|
interface AuthState {
|
|
291
322
|
user: User | null;
|
|
@@ -424,6 +455,45 @@ interface ChatState {
|
|
|
424
455
|
}
|
|
425
456
|
declare const useChatStore: zustand.UseBoundStore<zustand.StoreApi<ChatState>>;
|
|
426
457
|
|
|
458
|
+
declare class AntzChatError extends Error {
|
|
459
|
+
readonly code: string;
|
|
460
|
+
readonly retryable: boolean;
|
|
461
|
+
readonly context?: Record<string, unknown>;
|
|
462
|
+
constructor(code: string, message: string, retryable?: boolean, context?: Record<string, unknown>);
|
|
463
|
+
}
|
|
464
|
+
/** Thrown on 401 (after refresh also fails) or when no refresh token exists. */
|
|
465
|
+
declare class AntzChatAuthError extends AntzChatError {
|
|
466
|
+
constructor(message: string, code?: string, context?: Record<string, unknown>);
|
|
467
|
+
}
|
|
468
|
+
/** Thrown on 400 / 422 — bad input, validation failure. */
|
|
469
|
+
declare class AntzChatValidationError extends AntzChatError {
|
|
470
|
+
/** Server-returned field error array (when the server sends message as string[]). */
|
|
471
|
+
readonly fields?: string[];
|
|
472
|
+
constructor(message: string | string[], context?: Record<string, unknown>);
|
|
473
|
+
}
|
|
474
|
+
/** Thrown on network failures, timeouts, socket disconnections, and queue overflow. retryable = true. */
|
|
475
|
+
declare class AntzChatNetworkError extends AntzChatError {
|
|
476
|
+
constructor(message: string, code?: string, context?: Record<string, unknown>);
|
|
477
|
+
}
|
|
478
|
+
/** Thrown on 403 — insufficient permissions. */
|
|
479
|
+
declare class AntzChatPermissionError extends AntzChatError {
|
|
480
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
481
|
+
}
|
|
482
|
+
/** Thrown on 5xx or other unexpected server errors. retryable = true. */
|
|
483
|
+
declare class AntzChatServerError extends AntzChatError {
|
|
484
|
+
readonly httpStatus?: number;
|
|
485
|
+
constructor(message: string, httpStatus?: number, context?: Record<string, unknown>);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Converts a raw axios error (or any unknown throw) into a typed AntzChatError.
|
|
489
|
+
*
|
|
490
|
+
* Call site: client.ts response interceptor — runs AFTER transit decryption,
|
|
491
|
+
* so error.response.data is always plaintext by the time this function sees it.
|
|
492
|
+
* If decryption itself failed, error.response.data remains the raw encrypted
|
|
493
|
+
* envelope — detected via isTransitEnvelope() and noted in context.
|
|
494
|
+
*/
|
|
495
|
+
declare function normalizeAxiosError(error: unknown): AntzChatError;
|
|
496
|
+
|
|
427
497
|
/**
|
|
428
498
|
* Resolves viewer-aware display text for system messages.
|
|
429
499
|
*
|
|
@@ -515,6 +585,7 @@ declare class AntzChatClient {
|
|
|
515
585
|
getUnreadSummary(): Promise<UnreadSummary>;
|
|
516
586
|
uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
|
|
517
587
|
removeIcon(conversationId: string): Promise<Conversation>;
|
|
588
|
+
clearChat(conversationId: string): Promise<void>;
|
|
518
589
|
};
|
|
519
590
|
readonly storage: {
|
|
520
591
|
requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
|
|
@@ -566,4 +637,4 @@ declare class AntzChatClient {
|
|
|
566
637
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
567
638
|
}
|
|
568
639
|
|
|
569
|
-
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, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
|
640
|
+
export { AntzChatAuthError, AntzChatClient, AntzChatConfig, AntzChatError, AntzChatNetworkError, AntzChatPermissionError, AntzChatServerError, AntzChatValidationError, 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, normalizeAxiosError, normalizeConversation, onSocketStatus, performHandshake, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveSystemMessageText, setApiClientInstance, setTransitSession, socketEmit, tryGetSocket, useChatStore, usersApi };
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AntzChatAuthError,
|
|
3
|
+
AntzChatError,
|
|
4
|
+
AntzChatNetworkError,
|
|
5
|
+
AntzChatPermissionError,
|
|
6
|
+
AntzChatServerError,
|
|
7
|
+
AntzChatValidationError,
|
|
2
8
|
clearTransitSession,
|
|
3
9
|
configureTransit,
|
|
10
|
+
createRestTransitSession,
|
|
4
11
|
decryptPayload,
|
|
12
|
+
detectTransitAlgo,
|
|
5
13
|
encryptPayload,
|
|
14
|
+
fetchServerKeys,
|
|
15
|
+
generateEphemeralKey,
|
|
6
16
|
getApiClient,
|
|
7
17
|
getCompressionStrategy,
|
|
18
|
+
getSessionId,
|
|
8
19
|
getSessionKey,
|
|
20
|
+
getTransitHandshakePromise,
|
|
21
|
+
getTransitSession,
|
|
9
22
|
initApiClient,
|
|
10
23
|
isTransitEnabled,
|
|
11
24
|
isTransitEnvelope,
|
|
25
|
+
normalizeAxiosError,
|
|
26
|
+
performHandshake,
|
|
27
|
+
resetAlgoCache,
|
|
12
28
|
setApiClientInstance,
|
|
13
29
|
setTransitSession,
|
|
14
30
|
storageApi,
|
|
15
31
|
uploadBatch
|
|
16
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-XTQYF5HU.js";
|
|
17
33
|
import {
|
|
18
34
|
useChatStore
|
|
19
35
|
} from "./chunk-EOL5B7GS.js";
|
|
@@ -378,7 +394,8 @@ function normalizeLastMessage(lastMsg) {
|
|
|
378
394
|
isEdited: false,
|
|
379
395
|
sentAt: lastMsg.sentAt ?? "",
|
|
380
396
|
createdAt: lastMsg.sentAt ?? "",
|
|
381
|
-
...lastMsg.senderName && { senderName: lastMsg.senderName }
|
|
397
|
+
...lastMsg.senderName && { senderName: lastMsg.senderName },
|
|
398
|
+
...lastMsg.attachmentType && { attachmentType: lastMsg.attachmentType }
|
|
382
399
|
};
|
|
383
400
|
}
|
|
384
401
|
function normalizeConversation(conv) {
|
|
@@ -491,6 +508,9 @@ var conversationsApi = {
|
|
|
491
508
|
async removeIcon(conversationId) {
|
|
492
509
|
const { data } = await getApiClient().post(`/conversations/${conversationId}/icon/remove`);
|
|
493
510
|
return normalizeConversation(data);
|
|
511
|
+
},
|
|
512
|
+
async clearChat(conversationId) {
|
|
513
|
+
await getApiClient().post(`/conversations/${conversationId}/clear-for-me`);
|
|
494
514
|
}
|
|
495
515
|
};
|
|
496
516
|
|
|
@@ -568,122 +588,6 @@ var usersApi = {
|
|
|
568
588
|
|
|
569
589
|
// src/socket/socket.ts
|
|
570
590
|
import { io } from "socket.io-client";
|
|
571
|
-
|
|
572
|
-
// src/crypto/detect.ts
|
|
573
|
-
var _cached = null;
|
|
574
|
-
async function detectTransitAlgo() {
|
|
575
|
-
if (_cached) return _cached;
|
|
576
|
-
try {
|
|
577
|
-
await globalThis.crypto.subtle.generateKey(
|
|
578
|
-
{ name: "X25519" },
|
|
579
|
-
false,
|
|
580
|
-
["deriveKey"]
|
|
581
|
-
);
|
|
582
|
-
_cached = "x25519";
|
|
583
|
-
} catch {
|
|
584
|
-
_cached = "p256";
|
|
585
|
-
}
|
|
586
|
-
return _cached;
|
|
587
|
-
}
|
|
588
|
-
function resetAlgoCache() {
|
|
589
|
-
_cached = null;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
// src/crypto/handshake.ts
|
|
593
|
-
function hasWebCrypto() {
|
|
594
|
-
return typeof globalThis.crypto?.subtle !== "undefined";
|
|
595
|
-
}
|
|
596
|
-
async function fetchServerKeys(apiUrl) {
|
|
597
|
-
const res = await fetch(`${apiUrl}/crypto/pubkey`);
|
|
598
|
-
if (!res.ok) throw new Error(`[AntzChat] Failed to fetch server public key: ${res.status}`);
|
|
599
|
-
const body = await res.json();
|
|
600
|
-
return body?.data ?? body;
|
|
601
|
-
}
|
|
602
|
-
async function performHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
603
|
-
if (hasWebCrypto()) {
|
|
604
|
-
return performWebCryptoHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
605
|
-
}
|
|
606
|
-
return performNobleHandshake(serverKeys, socketHandshakeAuth);
|
|
607
|
-
}
|
|
608
|
-
async function performWebCryptoHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
609
|
-
const ephemeral = await globalThis.crypto.subtle.generateKey(
|
|
610
|
-
algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" },
|
|
611
|
-
false,
|
|
612
|
-
["deriveBits"]
|
|
613
|
-
);
|
|
614
|
-
const pubRaw = await globalThis.crypto.subtle.exportKey("raw", ephemeral.publicKey);
|
|
615
|
-
socketHandshakeAuth["transitEphemeralPub"] = bufToB64(pubRaw);
|
|
616
|
-
socketHandshakeAuth["transitAlgo"] = algo;
|
|
617
|
-
const ephemeralPriv = ephemeral.privateKey;
|
|
618
|
-
return (sessionId) => deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId);
|
|
619
|
-
}
|
|
620
|
-
async function deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId) {
|
|
621
|
-
const serverPubRaw = b64ToBuf(algo === "x25519" ? serverKeys.x25519 : serverKeys.p256);
|
|
622
|
-
const keyAlgoParams = algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" };
|
|
623
|
-
const serverPubKey = await globalThis.crypto.subtle.importKey("raw", serverPubRaw, keyAlgoParams, false, []);
|
|
624
|
-
const sharedBits = await globalThis.crypto.subtle.deriveBits(
|
|
625
|
-
{ name: algo === "x25519" ? "X25519" : "ECDH", public: serverPubKey },
|
|
626
|
-
ephemeralPriv,
|
|
627
|
-
256
|
|
628
|
-
);
|
|
629
|
-
const hkdfKey = await globalThis.crypto.subtle.importKey("raw", sharedBits, "HKDF", false, ["deriveKey"]);
|
|
630
|
-
const salt = new TextEncoder().encode(sessionId);
|
|
631
|
-
const info = new TextEncoder().encode("antz-transit-v1");
|
|
632
|
-
return globalThis.crypto.subtle.deriveKey(
|
|
633
|
-
{ name: "HKDF", hash: "SHA-256", salt, info },
|
|
634
|
-
hkdfKey,
|
|
635
|
-
{ name: "AES-GCM", length: 256 },
|
|
636
|
-
false,
|
|
637
|
-
["encrypt", "decrypt"]
|
|
638
|
-
);
|
|
639
|
-
}
|
|
640
|
-
async function performNobleHandshake(serverKeys, socketHandshakeAuth) {
|
|
641
|
-
const { x25519 } = await import("@noble/curves/ed25519");
|
|
642
|
-
const { hkdf } = await import("@noble/hashes/hkdf");
|
|
643
|
-
const { sha256 } = await import("@noble/hashes/sha256");
|
|
644
|
-
const { randomBytes } = await import("@noble/hashes/utils");
|
|
645
|
-
const ephemeralPriv = randomBytes(32);
|
|
646
|
-
const ephemeralPub = x25519.getPublicKey(ephemeralPriv);
|
|
647
|
-
const serverPubBytes = base64ToUint8(serverKeys.x25519);
|
|
648
|
-
socketHandshakeAuth["transitEphemeralPub"] = uint8ToBase64(ephemeralPub);
|
|
649
|
-
socketHandshakeAuth["transitAlgo"] = "x25519";
|
|
650
|
-
return (sessionId) => {
|
|
651
|
-
const sharedSecret = x25519.getSharedSecret(ephemeralPriv, serverPubBytes);
|
|
652
|
-
const salt = new TextEncoder().encode(sessionId);
|
|
653
|
-
const info = new TextEncoder().encode("antz-transit-v1");
|
|
654
|
-
const sessionKey = hkdf(sha256, sharedSecret, salt, info, 32);
|
|
655
|
-
return Promise.resolve(sessionKey);
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
function bufToB64(buf) {
|
|
659
|
-
const bytes = new Uint8Array(buf);
|
|
660
|
-
let str = "";
|
|
661
|
-
bytes.forEach((b) => {
|
|
662
|
-
str += String.fromCharCode(b);
|
|
663
|
-
});
|
|
664
|
-
return btoa(str);
|
|
665
|
-
}
|
|
666
|
-
function b64ToBuf(b64) {
|
|
667
|
-
const bin = atob(b64);
|
|
668
|
-
const buf = new Uint8Array(bin.length);
|
|
669
|
-
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
670
|
-
return buf.buffer;
|
|
671
|
-
}
|
|
672
|
-
function uint8ToBase64(bytes) {
|
|
673
|
-
let str = "";
|
|
674
|
-
bytes.forEach((b) => {
|
|
675
|
-
str += String.fromCharCode(b);
|
|
676
|
-
});
|
|
677
|
-
return btoa(str);
|
|
678
|
-
}
|
|
679
|
-
function base64ToUint8(b64) {
|
|
680
|
-
const bin = atob(b64);
|
|
681
|
-
const buf = new Uint8Array(bin.length);
|
|
682
|
-
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
683
|
-
return buf;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
// src/socket/socket.ts
|
|
687
591
|
var _socket = null;
|
|
688
592
|
var _socketProxy = null;
|
|
689
593
|
var _connectingPromise = null;
|
|
@@ -780,28 +684,52 @@ async function _doConnect(config, getToken) {
|
|
|
780
684
|
};
|
|
781
685
|
let boundDeriveSessionKey = null;
|
|
782
686
|
if (config.transitEncryption) {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
687
|
+
const inFlight = getTransitHandshakePromise();
|
|
688
|
+
if (inFlight) await inFlight;
|
|
689
|
+
const existingSession = getTransitSession();
|
|
690
|
+
let httpsSession = null;
|
|
691
|
+
if (existingSession?.enabled && existingSession.sessionId) {
|
|
692
|
+
httpsSession = { sessionId: existingSession.sessionId, sessionKey: existingSession.sessionKey };
|
|
693
|
+
} else {
|
|
694
|
+
httpsSession = await createRestTransitSession(config.apiUrl);
|
|
695
|
+
if (httpsSession) {
|
|
696
|
+
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
697
|
+
setTransitSession({ sessionKey: httpsSession.sessionKey, algo, sessionId: httpsSession.sessionId, enabled: true });
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
if (httpsSession) {
|
|
701
|
+
socketHandshakeAuth["transitSessionId"] = httpsSession.sessionId;
|
|
702
|
+
boundDeriveSessionKey = null;
|
|
703
|
+
} else {
|
|
704
|
+
try {
|
|
705
|
+
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
706
|
+
if (!serverKeys.enabled) {
|
|
707
|
+
throw new AntzChatError(
|
|
708
|
+
"TRANSIT_MISMATCH",
|
|
709
|
+
"[AntzChat] Transit encryption mismatch: SDK has transitEncryption=true but server has TRANSIT_ENCRYPTION_ENABLED=false. Align the config on both sides.",
|
|
710
|
+
false,
|
|
711
|
+
{ sdkEnabled: true, serverEnabled: false }
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
715
|
+
boundDeriveSessionKey = await performHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
716
|
+
} catch (err) {
|
|
717
|
+
throw err;
|
|
789
718
|
}
|
|
790
|
-
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
791
|
-
boundDeriveSessionKey = await performHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
792
|
-
} catch (err) {
|
|
793
|
-
throw err;
|
|
794
719
|
}
|
|
795
720
|
} else {
|
|
796
721
|
try {
|
|
797
722
|
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
798
723
|
if (serverKeys.enabled) {
|
|
799
|
-
throw new
|
|
800
|
-
"
|
|
724
|
+
throw new AntzChatError(
|
|
725
|
+
"TRANSIT_MISMATCH",
|
|
726
|
+
"[AntzChat] Transit encryption mismatch: SDK has transitEncryption=false but server has TRANSIT_ENCRYPTION_ENABLED=true. Align the config on both sides.",
|
|
727
|
+
false,
|
|
728
|
+
{ sdkEnabled: false, serverEnabled: true }
|
|
801
729
|
);
|
|
802
730
|
}
|
|
803
731
|
} catch (err) {
|
|
804
|
-
if (err
|
|
732
|
+
if (err?.code === "TRANSIT_MISMATCH") throw err;
|
|
805
733
|
}
|
|
806
734
|
}
|
|
807
735
|
_socket = io(`${config.socketOrigin}/chat`, {
|
|
@@ -945,14 +873,10 @@ async function drainSendQueue(conversationId) {
|
|
|
945
873
|
while (queue.length > 0) {
|
|
946
874
|
const entry = queue.shift();
|
|
947
875
|
if (Date.now() - entry.enqueuedAt > QUEUE_ENTRY_TTL) {
|
|
948
|
-
entry.reject(new
|
|
876
|
+
entry.reject(new AntzChatNetworkError("Message dropped: queued too long", "MESSAGE_DROPPED"));
|
|
949
877
|
continue;
|
|
950
878
|
}
|
|
951
|
-
|
|
952
|
-
entry.resolve(await entry.run());
|
|
953
|
-
} catch (e) {
|
|
954
|
-
entry.reject(e);
|
|
955
|
-
}
|
|
879
|
+
entry.run().then(entry.resolve).catch(entry.reject);
|
|
956
880
|
}
|
|
957
881
|
sendQueues.delete(conversationId);
|
|
958
882
|
sendQueueRunning.delete(conversationId);
|
|
@@ -962,7 +886,7 @@ function queueSendMessage(payload) {
|
|
|
962
886
|
if (!sendQueues.has(conversationId)) sendQueues.set(conversationId, []);
|
|
963
887
|
const queue = sendQueues.get(conversationId);
|
|
964
888
|
if (queue.length >= QUEUE_MAX_SIZE) {
|
|
965
|
-
return Promise.reject(new
|
|
889
|
+
return Promise.reject(new AntzChatNetworkError("Send queue full: too many messages in flight", "SEND_QUEUE_FULL", { conversationId }));
|
|
966
890
|
}
|
|
967
891
|
return new Promise((resolve, reject) => {
|
|
968
892
|
queue.push({ run: () => withAck("send_message", payload), resolve, reject, enqueuedAt: Date.now() });
|
|
@@ -973,7 +897,7 @@ function waitForReconnect() {
|
|
|
973
897
|
return new Promise((resolve, reject) => {
|
|
974
898
|
const timer = setTimeout(() => {
|
|
975
899
|
unsubscribe();
|
|
976
|
-
reject(new
|
|
900
|
+
reject(new AntzChatNetworkError("Socket reconnect timeout", "SOCKET_TIMEOUT"));
|
|
977
901
|
}, RECONNECT_WAIT_TIMEOUT);
|
|
978
902
|
const unsubscribe = onSocketStatus((status) => {
|
|
979
903
|
if (status === "connected") {
|
|
@@ -983,7 +907,7 @@ function waitForReconnect() {
|
|
|
983
907
|
} else if (status === "error") {
|
|
984
908
|
clearTimeout(timer);
|
|
985
909
|
unsubscribe();
|
|
986
|
-
reject(new
|
|
910
|
+
reject(new AntzChatNetworkError("Socket reconnect failed", "SOCKET_NOT_CONNECTED"));
|
|
987
911
|
}
|
|
988
912
|
});
|
|
989
913
|
});
|
|
@@ -994,13 +918,15 @@ async function withAck(event, payload) {
|
|
|
994
918
|
await waitForReconnect();
|
|
995
919
|
socket = tryGetSocket();
|
|
996
920
|
}
|
|
997
|
-
if (!socket) return Promise.reject(new
|
|
921
|
+
if (!socket) return Promise.reject(new AntzChatNetworkError(`Socket not connected (event: ${event})`, "SOCKET_NOT_CONNECTED", { event }));
|
|
998
922
|
return new Promise((resolve, reject) => {
|
|
999
|
-
|
|
923
|
+
let timer;
|
|
1000
924
|
secureEmit(socket, event, payload, (response) => {
|
|
1001
925
|
clearTimeout(timer);
|
|
1002
926
|
resolve(response);
|
|
1003
|
-
})
|
|
927
|
+
}).then(() => {
|
|
928
|
+
timer = setTimeout(() => reject(new AntzChatNetworkError(`Socket ack timeout: ${event}`, "SOCKET_TIMEOUT", { event })), ACK_TIMEOUT);
|
|
929
|
+
}).catch(reject);
|
|
1004
930
|
});
|
|
1005
931
|
}
|
|
1006
932
|
function fireAndForget(event, payload) {
|
|
@@ -1027,6 +953,9 @@ var socketEmit = {
|
|
|
1027
953
|
deleteMessageForMe(messageId) {
|
|
1028
954
|
return withAck("delete_message_for_me", { messageId });
|
|
1029
955
|
},
|
|
956
|
+
clearChat(conversationId) {
|
|
957
|
+
return withAck("clear_chat_for_me", { conversationId });
|
|
958
|
+
},
|
|
1030
959
|
addReaction(messageId, emoji) {
|
|
1031
960
|
return withAck("add_reaction", { messageId, emoji });
|
|
1032
961
|
},
|
|
@@ -1050,7 +979,7 @@ var socketEmit = {
|
|
|
1050
979
|
const socket = tryGetSocket();
|
|
1051
980
|
if (!socket) return Promise.resolve([]);
|
|
1052
981
|
return new Promise((resolve, reject) => {
|
|
1053
|
-
|
|
982
|
+
let timer;
|
|
1054
983
|
secureEmit(socket, "get_online_users", { userIds }, (response) => {
|
|
1055
984
|
clearTimeout(timer);
|
|
1056
985
|
if (response && typeof response === "object" && "onlineStatus" in response) {
|
|
@@ -1061,7 +990,9 @@ var socketEmit = {
|
|
|
1061
990
|
} else {
|
|
1062
991
|
resolve([]);
|
|
1063
992
|
}
|
|
1064
|
-
})
|
|
993
|
+
}).then(() => {
|
|
994
|
+
timer = setTimeout(() => reject(new AntzChatNetworkError("Socket ack timeout: get_online_users", "SOCKET_TIMEOUT", { event: "get_online_users" })), ACK_TIMEOUT);
|
|
995
|
+
}).catch(reject);
|
|
1065
996
|
});
|
|
1066
997
|
},
|
|
1067
998
|
getTypingUsers(conversationId) {
|
|
@@ -1119,24 +1050,40 @@ var AntzChatClient = class {
|
|
|
1119
1050
|
}
|
|
1120
1051
|
};
|
|
1121
1052
|
export {
|
|
1053
|
+
AntzChatAuthError,
|
|
1122
1054
|
AntzChatClient,
|
|
1055
|
+
AntzChatError,
|
|
1056
|
+
AntzChatNetworkError,
|
|
1057
|
+
AntzChatPermissionError,
|
|
1058
|
+
AntzChatServerError,
|
|
1059
|
+
AntzChatValidationError,
|
|
1123
1060
|
appConfigApi,
|
|
1124
1061
|
authApi,
|
|
1125
1062
|
connectSocket,
|
|
1126
1063
|
conversationsApi,
|
|
1127
1064
|
createAuthStore,
|
|
1065
|
+
createRestTransitSession,
|
|
1066
|
+
decryptPayload,
|
|
1128
1067
|
devicesApi,
|
|
1129
1068
|
disconnectSocket,
|
|
1069
|
+
encryptPayload,
|
|
1070
|
+
fetchServerKeys,
|
|
1071
|
+
generateEphemeralKey,
|
|
1130
1072
|
getApiClient,
|
|
1131
1073
|
getAuthStore,
|
|
1132
1074
|
getCompressionStrategy,
|
|
1075
|
+
getSessionId,
|
|
1076
|
+
getSessionKey,
|
|
1133
1077
|
getSocket,
|
|
1134
1078
|
getSocketStatus,
|
|
1135
1079
|
initApiClient,
|
|
1136
1080
|
initAuthStore,
|
|
1081
|
+
isTransitEnvelope,
|
|
1137
1082
|
messagesApi,
|
|
1083
|
+
normalizeAxiosError,
|
|
1138
1084
|
normalizeConversation,
|
|
1139
1085
|
onSocketStatus,
|
|
1086
|
+
performHandshake,
|
|
1140
1087
|
reconnectSocket,
|
|
1141
1088
|
refreshSocketAuth,
|
|
1142
1089
|
resetAuthStore,
|