@antzsoft/chat-core 1.0.7 → 1.0.9
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 +182 -0
- package/dist/index.cjs +119 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -2
- package/dist/index.d.ts +49 -2
- package/dist/index.js +118 -7
- package/dist/index.js.map +1 -1
- package/docs/integration-guide.html +456 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -232,6 +232,12 @@ interface CursorPaginatedResponse<T> {
|
|
|
232
232
|
data: T[];
|
|
233
233
|
meta: CursorPaginationMeta;
|
|
234
234
|
}
|
|
235
|
+
type CompressionAlgorithm = 'webp' | 'jpeg' | 'gzip' | 'none';
|
|
236
|
+
interface CompressedFile extends UploadableFile {
|
|
237
|
+
originalSize: number;
|
|
238
|
+
compressed: boolean;
|
|
239
|
+
compressionAlgorithm: CompressionAlgorithm;
|
|
240
|
+
}
|
|
235
241
|
interface PresignedUrlRequest {
|
|
236
242
|
filename: string;
|
|
237
243
|
mimeType: string;
|
|
@@ -348,6 +354,7 @@ interface SendMessageAttachment {
|
|
|
348
354
|
filename: string;
|
|
349
355
|
mimeType: string;
|
|
350
356
|
size: number;
|
|
357
|
+
duration?: number;
|
|
351
358
|
}
|
|
352
359
|
interface OptimisticAttachment extends SendMessageAttachment {
|
|
353
360
|
id: string;
|
|
@@ -425,6 +432,29 @@ interface PersistStorage {
|
|
|
425
432
|
setItem(key: string, value: string): void | Promise<void>;
|
|
426
433
|
removeItem(key: string): void | Promise<void>;
|
|
427
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
|
+
}
|
|
428
458
|
interface UploadConfig {
|
|
429
459
|
/**
|
|
430
460
|
* Per-type file size limits in MB. Can also pass a single number for all types.
|
|
@@ -479,6 +509,15 @@ interface AntzChatConfig {
|
|
|
479
509
|
/** Must match server ENCRYPTION_MODE env var. Default: 'none' */
|
|
480
510
|
encryptionMode?: 'none' | 'server';
|
|
481
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;
|
|
482
521
|
/**
|
|
483
522
|
* Number of messages fetched per page when loading chat history.
|
|
484
523
|
* Default: 40
|
|
@@ -534,6 +573,8 @@ interface ResolvedConfig {
|
|
|
534
573
|
onProgress?: (progress: number) => void;
|
|
535
574
|
};
|
|
536
575
|
platformUploadFn: PlatformUploadFn;
|
|
576
|
+
platformCompressFn?: PlatformCompressFn;
|
|
577
|
+
compression: ResolvedCompressionConfig;
|
|
537
578
|
persistStorage: PersistStorage;
|
|
538
579
|
messagePageSize: number;
|
|
539
580
|
starredMessagePageSize: number;
|
|
@@ -541,6 +582,9 @@ interface ResolvedConfig {
|
|
|
541
582
|
}
|
|
542
583
|
declare function resolveConfig(config: AntzChatConfig): ResolvedConfig;
|
|
543
584
|
|
|
585
|
+
type CompressionStrategy = 'image' | 'gzip' | 'skip';
|
|
586
|
+
declare function getCompressionStrategy(mimeType: string, config: ResolvedCompressionConfig): CompressionStrategy;
|
|
587
|
+
|
|
544
588
|
declare const authApi: {
|
|
545
589
|
login(credentials: LoginCredentials): Promise<AuthResponse>;
|
|
546
590
|
register(payload: RegisterData): Promise<AuthResponse>;
|
|
@@ -683,8 +727,11 @@ declare const storageApi: {
|
|
|
683
727
|
* High-level batch upload.
|
|
684
728
|
* The actual binary transfer is delegated to platformUploadFn so this
|
|
685
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).
|
|
686
733
|
*/
|
|
687
|
-
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>;
|
|
688
735
|
|
|
689
736
|
/** Shared fields for every device registration. */
|
|
690
737
|
interface DeviceTokenBase {
|
|
@@ -1068,4 +1115,4 @@ declare class AntzChatClient {
|
|
|
1068
1115
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
1069
1116
|
}
|
|
1070
1117
|
|
|
1071
|
-
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;
|
|
@@ -450,12 +519,22 @@ var storageApi = {
|
|
|
450
519
|
return data;
|
|
451
520
|
}
|
|
452
521
|
};
|
|
453
|
-
async function uploadBatch(files, platformUploadFn, conversationId, onProgress) {
|
|
454
|
-
const
|
|
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) => ({
|
|
455
527
|
filename: f.name,
|
|
456
528
|
mimeType: f.type,
|
|
457
529
|
size: f.size,
|
|
458
|
-
conversationId
|
|
530
|
+
conversationId,
|
|
531
|
+
...f.compressed && {
|
|
532
|
+
metadata: {
|
|
533
|
+
compressed: true,
|
|
534
|
+
originalSize: f.originalSize,
|
|
535
|
+
compressionAlgorithm: f.compressionAlgorithm
|
|
536
|
+
}
|
|
537
|
+
}
|
|
459
538
|
}));
|
|
460
539
|
const { urls, errors: requestErrors } = await storageApi.requestPresignedUrlBatch(requests);
|
|
461
540
|
const progressMap = {};
|
|
@@ -469,7 +548,7 @@ async function uploadBatch(files, platformUploadFn, conversationId, onProgress)
|
|
|
469
548
|
const failed = [...requestErrors];
|
|
470
549
|
await Promise.all(
|
|
471
550
|
urls.map(async (presigned, idx) => {
|
|
472
|
-
const file =
|
|
551
|
+
const file = compressedFiles[idx];
|
|
473
552
|
progressMap[idx] = 0;
|
|
474
553
|
try {
|
|
475
554
|
await platformUploadFn(presigned, file, (pct) => {
|
|
@@ -664,8 +743,32 @@ function refreshSocketAuth() {
|
|
|
664
743
|
|
|
665
744
|
// src/socket/emitters.ts
|
|
666
745
|
var ACK_TIMEOUT = 5e3;
|
|
667
|
-
|
|
668
|
-
|
|
746
|
+
var RECONNECT_WAIT_TIMEOUT = 15e3;
|
|
747
|
+
function waitForReconnect() {
|
|
748
|
+
return new Promise((resolve, reject) => {
|
|
749
|
+
const timer = setTimeout(() => {
|
|
750
|
+
unsubscribe();
|
|
751
|
+
reject(new Error("[AntzChat] Socket reconnect timeout"));
|
|
752
|
+
}, RECONNECT_WAIT_TIMEOUT);
|
|
753
|
+
const unsubscribe = onSocketStatus((status) => {
|
|
754
|
+
if (status === "connected") {
|
|
755
|
+
clearTimeout(timer);
|
|
756
|
+
unsubscribe();
|
|
757
|
+
resolve();
|
|
758
|
+
} else if (status === "error") {
|
|
759
|
+
clearTimeout(timer);
|
|
760
|
+
unsubscribe();
|
|
761
|
+
reject(new Error("[AntzChat] Socket reconnect failed"));
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
async function withAck(event, payload) {
|
|
767
|
+
let socket = tryGetSocket();
|
|
768
|
+
if (!socket) {
|
|
769
|
+
await waitForReconnect();
|
|
770
|
+
socket = tryGetSocket();
|
|
771
|
+
}
|
|
669
772
|
if (!socket) return Promise.reject(new Error(`[AntzChat] Socket not connected (event: ${event})`));
|
|
670
773
|
return new Promise((resolve, reject) => {
|
|
671
774
|
const timer = setTimeout(() => reject(new Error(`Socket ack timeout: ${event}`)), ACK_TIMEOUT);
|
|
@@ -861,7 +964,14 @@ var AntzChatClient = class {
|
|
|
861
964
|
disconnectSocket();
|
|
862
965
|
}
|
|
863
966
|
uploadFiles(files, conversationId) {
|
|
864
|
-
return uploadBatch(
|
|
967
|
+
return uploadBatch(
|
|
968
|
+
files,
|
|
969
|
+
this._config.platformUploadFn,
|
|
970
|
+
conversationId,
|
|
971
|
+
this._config.upload.onProgress,
|
|
972
|
+
this._config.platformCompressFn,
|
|
973
|
+
this._config.compression
|
|
974
|
+
);
|
|
865
975
|
}
|
|
866
976
|
async uploadIcon(conversationId, file) {
|
|
867
977
|
const result = await this.uploadFiles([file], conversationId);
|
|
@@ -880,6 +990,7 @@ export {
|
|
|
880
990
|
disconnectSocket,
|
|
881
991
|
getApiClient,
|
|
882
992
|
getAuthStore,
|
|
993
|
+
getCompressionStrategy,
|
|
883
994
|
getSocket,
|
|
884
995
|
getSocketStatus,
|
|
885
996
|
initApiClient,
|