@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/README.md +200 -3
- package/dist/index.cjs +98 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +97 -7
- package/dist/index.js.map +1 -1
- package/docs/integration-guide.html +456 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1122,6 +1122,166 @@ result.failed.forEach((f) => console.error('Failed:', f.filename, f.error));
|
|
|
1122
1122
|
|
|
1123
1123
|
---
|
|
1124
1124
|
|
|
1125
|
+
## File Compression
|
|
1126
|
+
|
|
1127
|
+
Compression is optional and fully backward compatible. It runs entirely client-side before the upload starts — the server receives the already-compressed file with the correct size and MIME type.
|
|
1128
|
+
|
|
1129
|
+
### How it works
|
|
1130
|
+
|
|
1131
|
+
When `platformCompressFn` is provided and `compression.enabled` is `true` (the default when a compressor is supplied), `uploadBatch` compresses each file before requesting a presigned URL:
|
|
1132
|
+
|
|
1133
|
+
1. Determine strategy per file (`image` → WebP/JPEG resize+encode, `gzip` → text/doc compression, `skip` → no-op)
|
|
1134
|
+
2. Run `platformCompressFn(file, compressionConfig)` — returns a `CompressedFile`
|
|
1135
|
+
3. If compressed result is **larger** than the original, the original is used instead (automatic fallback)
|
|
1136
|
+
4. Request presigned URL with the compressed size and MIME type
|
|
1137
|
+
5. Upload the compressed bytes
|
|
1138
|
+
6. Store `metadata.compressed`, `metadata.originalSize`, `metadata.compressionAlgorithm` on the file record
|
|
1139
|
+
|
|
1140
|
+
### Strategy by file type
|
|
1141
|
+
|
|
1142
|
+
| File type | Strategy | Algorithm | Notes |
|
|
1143
|
+
|-----------|----------|-----------|-------|
|
|
1144
|
+
| `image/jpeg`, `image/png`, `image/gif`, `image/bmp`, `image/tiff` | `image` | `webp` (web) / `jpeg` (RN) | Resize to `imageMaxDimension` first |
|
|
1145
|
+
| `image/webp` | `image` | `webp` | Re-encode at target quality |
|
|
1146
|
+
| `image/svg+xml` | `gzip` | `gzip` | SVG is XML text |
|
|
1147
|
+
| `text/plain`, `text/csv`, `text/markdown`, `application/json`, `text/xml`, `application/xml`, `text/yaml`, `application/rtf` | `gzip` | `gzip` | Only when `compressDocuments: true` |
|
|
1148
|
+
| `video/*`, `audio/*`, `application/pdf`, `application/zip`, Office formats (`.docx`, `.xlsx`, `.pptx`) | `skip` | `none` | Already compressed |
|
|
1149
|
+
|
|
1150
|
+
### Configuration
|
|
1151
|
+
|
|
1152
|
+
Pass `compression` and `platformCompressFn` in the config:
|
|
1153
|
+
|
|
1154
|
+
```typescript
|
|
1155
|
+
import { AntzChatClient } from '@antzsoft/chat-core';
|
|
1156
|
+
|
|
1157
|
+
const client = new AntzChatClient({
|
|
1158
|
+
apiUrl: 'https://api.yourapp.com/api/v1',
|
|
1159
|
+
authToken: 'your-token',
|
|
1160
|
+
platformUploadFn: myUploadFn,
|
|
1161
|
+
persistStorage: myStorage,
|
|
1162
|
+
|
|
1163
|
+
// Optional — omit to disable compression entirely
|
|
1164
|
+
platformCompressFn: myCompressFn,
|
|
1165
|
+
compression: {
|
|
1166
|
+
enabled: true, // default: true when platformCompressFn is provided
|
|
1167
|
+
imageQuality: 0.85, // 0–1, default: 0.85
|
|
1168
|
+
imageMaxDimension: 1920, // longest side cap in px, default: 1920
|
|
1169
|
+
compressDocuments: true, // gzip text/json/csv/xml/yaml, default: true
|
|
1170
|
+
},
|
|
1171
|
+
});
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
### Opt out completely
|
|
1175
|
+
|
|
1176
|
+
```typescript
|
|
1177
|
+
// Disable compression — files upload as-is
|
|
1178
|
+
const client = new AntzChatClient({
|
|
1179
|
+
...
|
|
1180
|
+
compression: { enabled: false },
|
|
1181
|
+
});
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
### Implementing `platformCompressFn` for Node.js
|
|
1185
|
+
|
|
1186
|
+
The web and RN SDKs provide their own compressors automatically. For Node.js / `AntzChatClient` direct usage, implement it with `sharp` and `zlib`:
|
|
1187
|
+
|
|
1188
|
+
```typescript
|
|
1189
|
+
import sharp from 'sharp';
|
|
1190
|
+
import zlib from 'zlib';
|
|
1191
|
+
import { promisify } from 'util';
|
|
1192
|
+
import type { PlatformCompressFn } from '@antzsoft/chat-core';
|
|
1193
|
+
import { getCompressionStrategy } from '@antzsoft/chat-core';
|
|
1194
|
+
import * as fs from 'fs/promises';
|
|
1195
|
+
import * as path from 'path';
|
|
1196
|
+
import * as os from 'os';
|
|
1197
|
+
|
|
1198
|
+
const gzip = promisify(zlib.gzip);
|
|
1199
|
+
|
|
1200
|
+
export const nodeCompressFn: PlatformCompressFn = async (file, options) => {
|
|
1201
|
+
const strategy = getCompressionStrategy(file.type, options);
|
|
1202
|
+
const noop = { ...file, originalSize: file.size, compressed: false, compressionAlgorithm: 'none' as const };
|
|
1203
|
+
|
|
1204
|
+
if (strategy === 'image') {
|
|
1205
|
+
try {
|
|
1206
|
+
const buffer = await sharp(file.uri)
|
|
1207
|
+
.resize({ width: options.imageMaxDimension, height: options.imageMaxDimension, fit: 'inside', withoutEnlargement: true })
|
|
1208
|
+
.jpeg({ quality: Math.round(options.imageQuality * 100) })
|
|
1209
|
+
.toBuffer();
|
|
1210
|
+
|
|
1211
|
+
if (buffer.length >= file.size) return noop;
|
|
1212
|
+
|
|
1213
|
+
const tmpPath = path.join(os.tmpdir(), `${Date.now()}.jpg`);
|
|
1214
|
+
await fs.writeFile(tmpPath, buffer);
|
|
1215
|
+
|
|
1216
|
+
return {
|
|
1217
|
+
uri: tmpPath,
|
|
1218
|
+
name: file.name.replace(/\.[^.]+$/, '.jpg'),
|
|
1219
|
+
type: 'image/jpeg',
|
|
1220
|
+
size: buffer.length,
|
|
1221
|
+
originalSize: file.size,
|
|
1222
|
+
compressed: true,
|
|
1223
|
+
compressionAlgorithm: 'jpeg' as const,
|
|
1224
|
+
};
|
|
1225
|
+
} catch {
|
|
1226
|
+
return noop;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
if (strategy === 'gzip') {
|
|
1231
|
+
try {
|
|
1232
|
+
const input = await fs.readFile(file.uri);
|
|
1233
|
+
const compressed = await gzip(input);
|
|
1234
|
+
|
|
1235
|
+
if (compressed.length >= file.size) return noop;
|
|
1236
|
+
|
|
1237
|
+
const tmpPath = path.join(os.tmpdir(), `${Date.now()}.gz`);
|
|
1238
|
+
await fs.writeFile(tmpPath, compressed);
|
|
1239
|
+
|
|
1240
|
+
return {
|
|
1241
|
+
uri: tmpPath,
|
|
1242
|
+
name: file.name + '.gz',
|
|
1243
|
+
type: file.type,
|
|
1244
|
+
size: compressed.length,
|
|
1245
|
+
originalSize: file.size,
|
|
1246
|
+
compressed: true,
|
|
1247
|
+
compressionAlgorithm: 'gzip' as const,
|
|
1248
|
+
};
|
|
1249
|
+
} catch {
|
|
1250
|
+
return noop;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
return noop;
|
|
1255
|
+
};
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
Then pass it to the client:
|
|
1259
|
+
|
|
1260
|
+
```typescript
|
|
1261
|
+
const client = new AntzChatClient({
|
|
1262
|
+
apiUrl: 'https://api.yourapp.com/api/v1',
|
|
1263
|
+
authToken: process.env.AUTH_TOKEN,
|
|
1264
|
+
platformUploadFn: myUploadFn,
|
|
1265
|
+
persistStorage: myStorage,
|
|
1266
|
+
platformCompressFn: nodeCompressFn,
|
|
1267
|
+
compression: { imageQuality: 0.85, imageMaxDimension: 1920 },
|
|
1268
|
+
});
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
### `CompressedFile` type
|
|
1272
|
+
|
|
1273
|
+
```typescript
|
|
1274
|
+
interface CompressedFile extends UploadableFile {
|
|
1275
|
+
originalSize: number;
|
|
1276
|
+
compressed: boolean;
|
|
1277
|
+
compressionAlgorithm: 'webp' | 'jpeg' | 'gzip' | 'none';
|
|
1278
|
+
}
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
The `CompressedFile` extends `UploadableFile` — it is a drop-in replacement everywhere `UploadableFile` is accepted.
|
|
1282
|
+
|
|
1283
|
+
---
|
|
1284
|
+
|
|
1125
1285
|
### Devices API (`devicesApi`)
|
|
1126
1286
|
|
|
1127
1287
|
Used for push notification token registration. The SDK does not call this automatically — the host app is responsible for obtaining the device token from the OS and registering it.
|
|
@@ -1559,7 +1719,7 @@ Subscribe using `client.socket.on(event, handler)` (headless) or directly on the
|
|
|
1559
1719
|
| `read_receipt` | `ReadReceiptEvent` | A user read messages in a conversation. | **Chat detail screen** (to update tick marks) + **app root** (to clear your own unread count when read on another device). |
|
|
1560
1720
|
| `unread_count_changed` | `{ conversationId: string; unreadCount: number; userId: string }` | Your unread count changed for a conversation (fired to your personal room on all devices). | **App root / conversation list screen** — keep alive as long as the list is rendered. |
|
|
1561
1721
|
| `message_ack` | `MessageAckEvent` | Server confirmation for a message you sent via socket (maps tempId to the real messageId). | **Chat detail screen** — add on mount, remove on unmount. |
|
|
1562
|
-
| `message_delivered` | `
|
|
1722
|
+
| `message_delivered` | `MessageDeliveredEvent` | A single message you sent was delivered to all active recipients. | **Chat detail screen** — add on mount, remove on unmount. |
|
|
1563
1723
|
| `messages_delivered` | `MessagesDeliveredEvent` | Batch delivery catch-up — fired when a recipient comes online and your pending messages are delivered. | **Chat detail screen** — add on mount, remove on unmount. |
|
|
1564
1724
|
| `conversation_created` | `Conversation` | A new conversation was created (or you were added to one). | **App root** — call `joinRoom` here for the new conversation. Keep for full session. |
|
|
1565
1725
|
| `conversation_updated` | `Conversation` | A conversation's last message or metadata changed — use this to update the conversation list. | **App root** — keep for full session. The server emits this for every message across all conversations; a global listener keeps the in-memory conversation list and unread badge always in sync. |
|
|
@@ -1854,7 +2014,8 @@ interface Message {
|
|
|
1854
2014
|
sentAt: string;
|
|
1855
2015
|
createdAt: string;
|
|
1856
2016
|
sender?: User;
|
|
1857
|
-
readBy?: string
|
|
2017
|
+
readBy?: Array<{ userId: string; readAt: string }>;
|
|
2018
|
+
deliveredTo?: Array<{ userId: string; deliveredAt: string }>;
|
|
1858
2019
|
isEncrypted?: boolean;
|
|
1859
2020
|
encryptionMode?: 'none' | 'server' | 'e2ee';
|
|
1860
2021
|
encryptedContent?: EncryptedContent;
|
|
@@ -1992,6 +2153,7 @@ interface SendMessageAttachment {
|
|
|
1992
2153
|
filename: string;
|
|
1993
2154
|
mimeType: string;
|
|
1994
2155
|
size: number;
|
|
2156
|
+
duration?: number; // seconds — required for audio/video so receivers can render a player UI
|
|
1995
2157
|
}
|
|
1996
2158
|
```
|
|
1997
2159
|
|
|
@@ -2053,10 +2215,16 @@ interface MessageAckEvent {
|
|
|
2053
2215
|
status: MessageStatus;
|
|
2054
2216
|
}
|
|
2055
2217
|
|
|
2218
|
+
interface MessageDeliveredEvent {
|
|
2219
|
+
messageId: string;
|
|
2220
|
+
conversationId: string;
|
|
2221
|
+
deliveredTo: Array<{ userId: string; deliveredAt: string }>;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2056
2224
|
interface MessagesDeliveredEvent {
|
|
2057
2225
|
conversationId: string;
|
|
2058
2226
|
messageIds: string[];
|
|
2059
|
-
deliveredTo: string;
|
|
2227
|
+
deliveredTo: string; // single userId (batch catch-up per recipient)
|
|
2060
2228
|
deliveredAt: string;
|
|
2061
2229
|
}
|
|
2062
2230
|
```
|
|
@@ -2180,6 +2348,35 @@ document.querySelectorAll('[data-conv-id]').forEach((el) => {
|
|
|
2180
2348
|
|
|
2181
2349
|
---
|
|
2182
2350
|
|
|
2351
|
+
## Changelog
|
|
2352
|
+
|
|
2353
|
+
### v1.0.8
|
|
2354
|
+
- **`duration` field in `SendMessageAttachment`** — Pass `duration` (seconds) when sending audio or video. Server now stores and returns it in `new_message` and message list responses. **Action required (RN):** Omitting it on React Native can crash native audio player libraries on the receiver side; always pass it for audio/video. Web is unaffected.
|
|
2355
|
+
- **File compression** — `uploadBatch` now accepts optional `platformCompressFn` + `compressionConfig` args. Fully backward compatible — existing callers unchanged. Web/RN SDKs wire this in automatically; Node.js users can supply `nodeCompressFn` manually. No action required unless opting in on Node.
|
|
2356
|
+
- **Removed members keep read-only access** — Server behavior change. Removed participants stay in their conversation list and can read history but cannot write. Socket room membership ends immediately on removal. **No SDK change required.**
|
|
2357
|
+
- **Admin delete is hide-only** — Server behavior change. Deleting a conversation sets `isHidden` for the requester only; other participants are unaffected. **No SDK change required.**
|
|
2358
|
+
- **Fix: `lastMessage.status` stuck as `deleted`** — Server now explicitly resets `status: 'active'` on both REST and WebSocket paths when a new message is sent. **No client action required.**
|
|
2359
|
+
- **Fix: `duration` stored from sender payload** — `SendMessageAttachment.duration` is now persisted and echoed back. The `SendMessageAttachment` interface in this package is unchanged (field was already present as optional).
|
|
2360
|
+
|
|
2361
|
+
### v1.0.7
|
|
2362
|
+
- **`deliveredTo` per-user delivery timestamps** — All message responses now include `deliveredTo: Array<{ userId, deliveredAt }>` alongside `readBy`. The `Message` type updated: `readBy` changed from `string[]` to `Array<{ userId, readAt }>`. The `message_delivered` socket event payload changed from `{ deliveredTo: string[], deliveredAt }` to `{ deliveredTo: Array<{ userId, deliveredAt }> }`.
|
|
2363
|
+
- **Audio support for `.m4a` / `audio/x-m4a`** — `audio/m4a` and `audio/x-m4a` MIME types are now accepted for audio attachments.
|
|
2364
|
+
- **Participant filter on `getMembers`** — `getMembers(conversationId, { filter: 'active' | 'deleted' | 'all' })` defaults to `'active'`. Use `'all'` to include removed participants, `'deleted'` to list only removed ones.
|
|
2365
|
+
- **Message character limit: 10,000** — Text messages are capped at 10,000 characters. Sending beyond this returns a `400` validation error.
|
|
2366
|
+
|
|
2367
|
+
### v1.0.6
|
|
2368
|
+
- `externalId` on all user responses
|
|
2369
|
+
- Single unified User List API (`usersApi.list()`)
|
|
2370
|
+
- Single unified Conversation List API (`conversationsApi.list()`)
|
|
2371
|
+
- Fix: attachment last-message content preview
|
|
2372
|
+
- Fix: avatar upload via `AntzChatClient`
|
|
2373
|
+
- Fix: `client.connect()` on React Native
|
|
2374
|
+
- Group icon — create & update
|
|
2375
|
+
- Scroll to first unread message
|
|
2376
|
+
- Push notifications — device token registration (RN & Web)
|
|
2377
|
+
|
|
2378
|
+
---
|
|
2379
|
+
|
|
2183
2380
|
## License
|
|
2184
2381
|
|
|
2185
2382
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -102,6 +102,7 @@ __export(src_exports, {
|
|
|
102
102
|
disconnectSocket: () => disconnectSocket,
|
|
103
103
|
getApiClient: () => getApiClient,
|
|
104
104
|
getAuthStore: () => getAuthStore,
|
|
105
|
+
getCompressionStrategy: () => getCompressionStrategy,
|
|
105
106
|
getSocket: () => getSocket,
|
|
106
107
|
getSocketStatus: () => getSocketStatus,
|
|
107
108
|
initApiClient: () => initApiClient,
|
|
@@ -168,6 +169,13 @@ function resolveConfig(config) {
|
|
|
168
169
|
onProgress: config.upload?.onProgress
|
|
169
170
|
},
|
|
170
171
|
platformUploadFn: config.platformUploadFn,
|
|
172
|
+
platformCompressFn: config.platformCompressFn,
|
|
173
|
+
compression: {
|
|
174
|
+
enabled: config.compression?.enabled ?? config.platformCompressFn != null,
|
|
175
|
+
imageQuality: config.compression?.imageQuality ?? 0.85,
|
|
176
|
+
imageMaxDimension: config.compression?.imageMaxDimension ?? 1920,
|
|
177
|
+
compressDocuments: config.compression?.compressDocuments ?? true
|
|
178
|
+
},
|
|
171
179
|
persistStorage: config.persistStorage,
|
|
172
180
|
messagePageSize: config.messagePageSize ?? 40,
|
|
173
181
|
starredMessagePageSize: config.starredMessagePageSize ?? 30,
|
|
@@ -175,6 +183,68 @@ function resolveConfig(config) {
|
|
|
175
183
|
};
|
|
176
184
|
}
|
|
177
185
|
|
|
186
|
+
// src/compression/compress.ts
|
|
187
|
+
var GZIP_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
188
|
+
"text/plain",
|
|
189
|
+
"text/csv",
|
|
190
|
+
"text/markdown",
|
|
191
|
+
"text/x-markdown",
|
|
192
|
+
"text/xml",
|
|
193
|
+
"application/xml",
|
|
194
|
+
"text/yaml",
|
|
195
|
+
"text/x-yaml",
|
|
196
|
+
"application/x-yaml",
|
|
197
|
+
"application/rtf",
|
|
198
|
+
"text/rtf",
|
|
199
|
+
"application/json",
|
|
200
|
+
"image/svg+xml"
|
|
201
|
+
]);
|
|
202
|
+
var IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
203
|
+
"image/jpeg",
|
|
204
|
+
"image/png",
|
|
205
|
+
"image/gif",
|
|
206
|
+
"image/webp",
|
|
207
|
+
"image/bmp",
|
|
208
|
+
"image/tiff"
|
|
209
|
+
]);
|
|
210
|
+
var SKIP_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
211
|
+
"video/mp4",
|
|
212
|
+
"video/webm",
|
|
213
|
+
"video/quicktime",
|
|
214
|
+
"audio/mpeg",
|
|
215
|
+
"audio/wav",
|
|
216
|
+
"audio/ogg",
|
|
217
|
+
"audio/webm",
|
|
218
|
+
"audio/mp4",
|
|
219
|
+
"application/zip",
|
|
220
|
+
"application/pdf",
|
|
221
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
222
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
223
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
224
|
+
]);
|
|
225
|
+
function getCompressionStrategy(mimeType, config) {
|
|
226
|
+
if (SKIP_MIME_TYPES.has(mimeType)) return "skip";
|
|
227
|
+
if (IMAGE_MIME_TYPES.has(mimeType)) return "image";
|
|
228
|
+
if (config.compressDocuments && GZIP_MIME_TYPES.has(mimeType)) return "gzip";
|
|
229
|
+
return "skip";
|
|
230
|
+
}
|
|
231
|
+
async function compressFile(file, platformCompressFn, config) {
|
|
232
|
+
const noop = {
|
|
233
|
+
...file,
|
|
234
|
+
originalSize: file.size,
|
|
235
|
+
compressed: false,
|
|
236
|
+
compressionAlgorithm: "none"
|
|
237
|
+
};
|
|
238
|
+
if (!config.enabled || !platformCompressFn) return noop;
|
|
239
|
+
const strategy = getCompressionStrategy(file.type, config);
|
|
240
|
+
if (strategy === "skip") return noop;
|
|
241
|
+
try {
|
|
242
|
+
return await platformCompressFn(file, config);
|
|
243
|
+
} catch {
|
|
244
|
+
return noop;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
178
248
|
// src/api/client.ts
|
|
179
249
|
var import_axios = __toESM(require("axios"), 1);
|
|
180
250
|
var _tokenStore = null;
|
|
@@ -491,8 +561,11 @@ var conversationsApi = {
|
|
|
491
561
|
async leave(conversationId) {
|
|
492
562
|
await getApiClient().delete(`/conversations/${conversationId}/leave`);
|
|
493
563
|
},
|
|
494
|
-
async getMembers(conversationId) {
|
|
495
|
-
const { data } = await getApiClient().get(
|
|
564
|
+
async getMembers(conversationId, filter) {
|
|
565
|
+
const { data } = await getApiClient().get(
|
|
566
|
+
`/conversations/${conversationId}/participants`,
|
|
567
|
+
filter ? { params: { filter } } : void 0
|
|
568
|
+
);
|
|
496
569
|
return data;
|
|
497
570
|
},
|
|
498
571
|
/**
|
|
@@ -568,12 +641,22 @@ var storageApi = {
|
|
|
568
641
|
return data;
|
|
569
642
|
}
|
|
570
643
|
};
|
|
571
|
-
async function uploadBatch(files, platformUploadFn, conversationId, onProgress) {
|
|
572
|
-
const
|
|
644
|
+
async function uploadBatch(files, platformUploadFn, conversationId, onProgress, platformCompressFn, compressionConfig) {
|
|
645
|
+
const compressedFiles = await Promise.all(
|
|
646
|
+
files.map((f) => compressFile(f, platformCompressFn, compressionConfig ?? { enabled: false, imageQuality: 0.85, imageMaxDimension: 1920, compressDocuments: true }))
|
|
647
|
+
);
|
|
648
|
+
const requests = compressedFiles.map((f) => ({
|
|
573
649
|
filename: f.name,
|
|
574
650
|
mimeType: f.type,
|
|
575
651
|
size: f.size,
|
|
576
|
-
conversationId
|
|
652
|
+
conversationId,
|
|
653
|
+
...f.compressed && {
|
|
654
|
+
metadata: {
|
|
655
|
+
compressed: true,
|
|
656
|
+
originalSize: f.originalSize,
|
|
657
|
+
compressionAlgorithm: f.compressionAlgorithm
|
|
658
|
+
}
|
|
659
|
+
}
|
|
577
660
|
}));
|
|
578
661
|
const { urls, errors: requestErrors } = await storageApi.requestPresignedUrlBatch(requests);
|
|
579
662
|
const progressMap = {};
|
|
@@ -587,7 +670,7 @@ async function uploadBatch(files, platformUploadFn, conversationId, onProgress)
|
|
|
587
670
|
const failed = [...requestErrors];
|
|
588
671
|
await Promise.all(
|
|
589
672
|
urls.map(async (presigned, idx) => {
|
|
590
|
-
const file =
|
|
673
|
+
const file = compressedFiles[idx];
|
|
591
674
|
progressMap[idx] = 0;
|
|
592
675
|
try {
|
|
593
676
|
await platformUploadFn(presigned, file, (pct) => {
|
|
@@ -982,7 +1065,14 @@ var AntzChatClient = class {
|
|
|
982
1065
|
disconnectSocket();
|
|
983
1066
|
}
|
|
984
1067
|
uploadFiles(files, conversationId) {
|
|
985
|
-
return uploadBatch(
|
|
1068
|
+
return uploadBatch(
|
|
1069
|
+
files,
|
|
1070
|
+
this._config.platformUploadFn,
|
|
1071
|
+
conversationId,
|
|
1072
|
+
this._config.upload.onProgress,
|
|
1073
|
+
this._config.platformCompressFn,
|
|
1074
|
+
this._config.compression
|
|
1075
|
+
);
|
|
986
1076
|
}
|
|
987
1077
|
async uploadIcon(conversationId, file) {
|
|
988
1078
|
const result = await this.uploadFiles([file], conversationId);
|
|
@@ -1002,6 +1092,7 @@ var AntzChatClient = class {
|
|
|
1002
1092
|
disconnectSocket,
|
|
1003
1093
|
getApiClient,
|
|
1004
1094
|
getAuthStore,
|
|
1095
|
+
getCompressionStrategy,
|
|
1005
1096
|
getSocket,
|
|
1006
1097
|
getSocketStatus,
|
|
1007
1098
|
initApiClient,
|