@antzsoft/chat-core 1.0.6 → 1.0.8

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/dist/index.d.ts CHANGED
@@ -128,7 +128,14 @@ interface Message {
128
128
  sentAt: string;
129
129
  createdAt: string;
130
130
  sender?: User;
131
- readBy?: string[];
131
+ readBy?: Array<{
132
+ userId: string;
133
+ readAt: string;
134
+ }>;
135
+ deliveredTo?: Array<{
136
+ userId: string;
137
+ deliveredAt: string;
138
+ }>;
132
139
  isEncrypted?: boolean;
133
140
  encryptionMode?: EncryptionMode;
134
141
  encryptedContent?: EncryptedContent;
@@ -225,6 +232,12 @@ interface CursorPaginatedResponse<T> {
225
232
  data: T[];
226
233
  meta: CursorPaginationMeta;
227
234
  }
235
+ type CompressionAlgorithm = 'webp' | 'jpeg' | 'gzip' | 'none';
236
+ interface CompressedFile extends UploadableFile {
237
+ originalSize: number;
238
+ compressed: boolean;
239
+ compressionAlgorithm: CompressionAlgorithm;
240
+ }
228
241
  interface PresignedUrlRequest {
229
242
  filename: string;
230
243
  mimeType: string;
@@ -322,7 +335,10 @@ interface MessageAckEvent {
322
335
  interface MessageDeliveredEvent {
323
336
  messageId: string;
324
337
  conversationId: string;
325
- deliveredAt: string;
338
+ deliveredTo: Array<{
339
+ userId: string;
340
+ deliveredAt: Date;
341
+ }>;
326
342
  }
327
343
  interface MessagesDeliveredEvent {
328
344
  conversationId: string;
@@ -338,6 +354,7 @@ interface SendMessageAttachment {
338
354
  filename: string;
339
355
  mimeType: string;
340
356
  size: number;
357
+ duration?: number;
341
358
  }
342
359
  interface OptimisticAttachment extends SendMessageAttachment {
343
360
  id: string;
@@ -415,6 +432,29 @@ interface PersistStorage {
415
432
  setItem(key: string, value: string): void | Promise<void>;
416
433
  removeItem(key: string): void | Promise<void>;
417
434
  }
435
+ /**
436
+ * Platform-provided compression function. Optional — if omitted, files are uploaded as-is.
437
+ * - Web: uses canvas (images) + CompressionStream (text/docs) — both browser-native
438
+ * - RN: uses expo-image-manipulator (images) + pako (text/docs)
439
+ * - Node: uses sharp (images) + zlib (text/docs)
440
+ */
441
+ type PlatformCompressFn = (file: UploadableFile, options: ResolvedCompressionConfig) => Promise<CompressedFile>;
442
+ interface CompressionConfig {
443
+ /** Master switch. Default: true when platformCompressFn is provided, false otherwise */
444
+ enabled?: boolean;
445
+ /** WebP quality for images, 0–1. Default: 0.85 */
446
+ imageQuality?: number;
447
+ /** Longest side cap in px before encoding. Default: 1920 */
448
+ imageMaxDimension?: number;
449
+ /** Gzip text-based documents (plain, csv, json, xml, yaml, svg). Default: true */
450
+ compressDocuments?: boolean;
451
+ }
452
+ interface ResolvedCompressionConfig {
453
+ enabled: boolean;
454
+ imageQuality: number;
455
+ imageMaxDimension: number;
456
+ compressDocuments: boolean;
457
+ }
418
458
  interface UploadConfig {
419
459
  /**
420
460
  * Per-type file size limits in MB. Can also pass a single number for all types.
@@ -469,6 +509,15 @@ interface AntzChatConfig {
469
509
  /** Must match server ENCRYPTION_MODE env var. Default: 'none' */
470
510
  encryptionMode?: 'none' | 'server';
471
511
  upload?: UploadConfig;
512
+ /**
513
+ * Optional compression config. Compression is disabled if platformCompressFn is not provided.
514
+ */
515
+ compression?: CompressionConfig;
516
+ /**
517
+ * Platform-specific compression implementation. Optional — omit to disable compression.
518
+ * Each SDK (web, RN) provides its own default; Node.js users wire in their own.
519
+ */
520
+ platformCompressFn?: PlatformCompressFn;
472
521
  /**
473
522
  * Number of messages fetched per page when loading chat history.
474
523
  * Default: 40
@@ -524,6 +573,8 @@ interface ResolvedConfig {
524
573
  onProgress?: (progress: number) => void;
525
574
  };
526
575
  platformUploadFn: PlatformUploadFn;
576
+ platformCompressFn?: PlatformCompressFn;
577
+ compression: ResolvedCompressionConfig;
527
578
  persistStorage: PersistStorage;
528
579
  messagePageSize: number;
529
580
  starredMessagePageSize: number;
@@ -531,6 +582,9 @@ interface ResolvedConfig {
531
582
  }
532
583
  declare function resolveConfig(config: AntzChatConfig): ResolvedConfig;
533
584
 
585
+ type CompressionStrategy = 'image' | 'gzip' | 'skip';
586
+ declare function getCompressionStrategy(mimeType: string, config: ResolvedCompressionConfig): CompressionStrategy;
587
+
534
588
  declare const authApi: {
535
589
  login(credentials: LoginCredentials): Promise<AuthResponse>;
536
590
  register(payload: RegisterData): Promise<AuthResponse>;
@@ -622,7 +676,7 @@ declare const conversationsApi: {
622
676
  pin(conversationId: string): Promise<void>;
623
677
  unpin(conversationId: string): Promise<void>;
624
678
  leave(conversationId: string): Promise<void>;
625
- getMembers(conversationId: string): Promise<User[]>;
679
+ getMembers(conversationId: string, filter?: "deleted" | "all"): Promise<Participant[]>;
626
680
  /**
627
681
  * Get unread message count for a single conversation.
628
682
  * Use this after app foreground or socket reconnect to refresh a specific count.
@@ -673,8 +727,11 @@ declare const storageApi: {
673
727
  * High-level batch upload.
674
728
  * The actual binary transfer is delegated to platformUploadFn so this
675
729
  * function is platform-agnostic (works on web and React Native).
730
+ * If platformCompressFn + compressionConfig are provided, each file is
731
+ * compressed before the presigned URL is requested (so the server receives
732
+ * the correct compressed size and MIME type).
676
733
  */
677
- declare function uploadBatch(files: UploadableFile[], platformUploadFn: PlatformUploadFn, conversationId?: string, onProgress?: (pct: number) => void): Promise<BatchUploadResult>;
734
+ declare function uploadBatch(files: UploadableFile[], platformUploadFn: PlatformUploadFn, conversationId?: string, onProgress?: (pct: number) => void, platformCompressFn?: PlatformCompressFn, compressionConfig?: ResolvedCompressionConfig): Promise<BatchUploadResult>;
678
735
 
679
736
  /** Shared fields for every device registration. */
680
737
  interface DeviceTokenBase {
@@ -1006,7 +1063,7 @@ declare class AntzChatClient {
1006
1063
  pin(conversationId: string): Promise<void>;
1007
1064
  unpin(conversationId: string): Promise<void>;
1008
1065
  leave(conversationId: string): Promise<void>;
1009
- getMembers(conversationId: string): Promise<User[]>;
1066
+ getMembers(conversationId: string, filter?: "deleted" | "all"): Promise<Participant[]>;
1010
1067
  getUnreadCount(conversationId: string): Promise<ConversationUnreadCount>;
1011
1068
  getUnreadSummary(): Promise<UnreadSummary>;
1012
1069
  uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
@@ -1058,4 +1115,4 @@ declare class AntzChatClient {
1058
1115
  uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
1059
1116
  }
1060
1117
 
1061
- export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type LastReadEntry, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type MessageDeletedForMeEvent, type MessageDeliveredEvent, type MessageReaction, type MessageReplyReference, type MessageUpdatedEvent, type MessagesDeliveredEvent, type MobileDeviceToken, type NewMessageEvent, type OptimisticAttachment, type PaginatedResponse, type Participant, type PersistStorage, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type QuietHours, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UnreadSummary, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserPreferences, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };
1118
+ export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type CompressedFile, type CompressionAlgorithm, type CompressionConfig, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type LastReadEntry, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type MessageDeletedForMeEvent, type MessageDeliveredEvent, type MessageReaction, type MessageReplyReference, type MessageUpdatedEvent, type MessagesDeliveredEvent, type MobileDeviceToken, type NewMessageEvent, type OptimisticAttachment, type PaginatedResponse, type Participant, type PersistStorage, type PlatformCompressFn, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type QuietHours, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedCompressionConfig, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UnreadSummary, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserPreferences, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };
package/dist/index.js CHANGED
@@ -47,6 +47,13 @@ function resolveConfig(config) {
47
47
  onProgress: config.upload?.onProgress
48
48
  },
49
49
  platformUploadFn: config.platformUploadFn,
50
+ platformCompressFn: config.platformCompressFn,
51
+ compression: {
52
+ enabled: config.compression?.enabled ?? config.platformCompressFn != null,
53
+ imageQuality: config.compression?.imageQuality ?? 0.85,
54
+ imageMaxDimension: config.compression?.imageMaxDimension ?? 1920,
55
+ compressDocuments: config.compression?.compressDocuments ?? true
56
+ },
50
57
  persistStorage: config.persistStorage,
51
58
  messagePageSize: config.messagePageSize ?? 40,
52
59
  starredMessagePageSize: config.starredMessagePageSize ?? 30,
@@ -54,6 +61,68 @@ function resolveConfig(config) {
54
61
  };
55
62
  }
56
63
 
64
+ // src/compression/compress.ts
65
+ var GZIP_MIME_TYPES = /* @__PURE__ */ new Set([
66
+ "text/plain",
67
+ "text/csv",
68
+ "text/markdown",
69
+ "text/x-markdown",
70
+ "text/xml",
71
+ "application/xml",
72
+ "text/yaml",
73
+ "text/x-yaml",
74
+ "application/x-yaml",
75
+ "application/rtf",
76
+ "text/rtf",
77
+ "application/json",
78
+ "image/svg+xml"
79
+ ]);
80
+ var IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
81
+ "image/jpeg",
82
+ "image/png",
83
+ "image/gif",
84
+ "image/webp",
85
+ "image/bmp",
86
+ "image/tiff"
87
+ ]);
88
+ var SKIP_MIME_TYPES = /* @__PURE__ */ new Set([
89
+ "video/mp4",
90
+ "video/webm",
91
+ "video/quicktime",
92
+ "audio/mpeg",
93
+ "audio/wav",
94
+ "audio/ogg",
95
+ "audio/webm",
96
+ "audio/mp4",
97
+ "application/zip",
98
+ "application/pdf",
99
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
100
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
101
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation"
102
+ ]);
103
+ function getCompressionStrategy(mimeType, config) {
104
+ if (SKIP_MIME_TYPES.has(mimeType)) return "skip";
105
+ if (IMAGE_MIME_TYPES.has(mimeType)) return "image";
106
+ if (config.compressDocuments && GZIP_MIME_TYPES.has(mimeType)) return "gzip";
107
+ return "skip";
108
+ }
109
+ async function compressFile(file, platformCompressFn, config) {
110
+ const noop = {
111
+ ...file,
112
+ originalSize: file.size,
113
+ compressed: false,
114
+ compressionAlgorithm: "none"
115
+ };
116
+ if (!config.enabled || !platformCompressFn) return noop;
117
+ const strategy = getCompressionStrategy(file.type, config);
118
+ if (strategy === "skip") return noop;
119
+ try {
120
+ return await platformCompressFn(file, config);
121
+ } catch {
122
+ return noop;
123
+ }
124
+ }
125
+
57
126
  // src/api/client.ts
58
127
  import axios from "axios";
59
128
  var _tokenStore = null;
@@ -370,8 +439,11 @@ var conversationsApi = {
370
439
  async leave(conversationId) {
371
440
  await getApiClient().delete(`/conversations/${conversationId}/leave`);
372
441
  },
373
- async getMembers(conversationId) {
374
- const { data } = await getApiClient().get(`/conversations/${conversationId}/participants`);
442
+ async getMembers(conversationId, filter) {
443
+ const { data } = await getApiClient().get(
444
+ `/conversations/${conversationId}/participants`,
445
+ filter ? { params: { filter } } : void 0
446
+ );
375
447
  return data;
376
448
  },
377
449
  /**
@@ -447,12 +519,22 @@ var storageApi = {
447
519
  return data;
448
520
  }
449
521
  };
450
- async function uploadBatch(files, platformUploadFn, conversationId, onProgress) {
451
- const requests = files.map((f) => ({
522
+ async function uploadBatch(files, platformUploadFn, conversationId, onProgress, platformCompressFn, compressionConfig) {
523
+ const compressedFiles = await Promise.all(
524
+ files.map((f) => compressFile(f, platformCompressFn, compressionConfig ?? { enabled: false, imageQuality: 0.85, imageMaxDimension: 1920, compressDocuments: true }))
525
+ );
526
+ const requests = compressedFiles.map((f) => ({
452
527
  filename: f.name,
453
528
  mimeType: f.type,
454
529
  size: f.size,
455
- conversationId
530
+ conversationId,
531
+ ...f.compressed && {
532
+ metadata: {
533
+ compressed: true,
534
+ originalSize: f.originalSize,
535
+ compressionAlgorithm: f.compressionAlgorithm
536
+ }
537
+ }
456
538
  }));
457
539
  const { urls, errors: requestErrors } = await storageApi.requestPresignedUrlBatch(requests);
458
540
  const progressMap = {};
@@ -466,7 +548,7 @@ async function uploadBatch(files, platformUploadFn, conversationId, onProgress)
466
548
  const failed = [...requestErrors];
467
549
  await Promise.all(
468
550
  urls.map(async (presigned, idx) => {
469
- const file = files[idx];
551
+ const file = compressedFiles[idx];
470
552
  progressMap[idx] = 0;
471
553
  try {
472
554
  await platformUploadFn(presigned, file, (pct) => {
@@ -858,7 +940,14 @@ var AntzChatClient = class {
858
940
  disconnectSocket();
859
941
  }
860
942
  uploadFiles(files, conversationId) {
861
- return uploadBatch(files, this._config.platformUploadFn, conversationId, this._config.upload.onProgress);
943
+ return uploadBatch(
944
+ files,
945
+ this._config.platformUploadFn,
946
+ conversationId,
947
+ this._config.upload.onProgress,
948
+ this._config.platformCompressFn,
949
+ this._config.compression
950
+ );
862
951
  }
863
952
  async uploadIcon(conversationId, file) {
864
953
  const result = await this.uploadFiles([file], conversationId);
@@ -877,6 +966,7 @@ export {
877
966
  disconnectSocket,
878
967
  getApiClient,
879
968
  getAuthStore,
969
+ getCompressionStrategy,
880
970
  getSocket,
881
971
  getSocketStatus,
882
972
  initApiClient,