stream-chat 9.39.0 → 9.41.0
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/cjs/index.browser.js +236 -33
- package/dist/cjs/index.browser.js.map +3 -3
- package/dist/cjs/index.node.js +236 -33
- package/dist/cjs/index.node.js.map +3 -3
- package/dist/esm/index.mjs +236 -33
- package/dist/esm/index.mjs.map +3 -3
- package/dist/types/channel.d.ts +23 -2
- package/dist/types/client.d.ts +8 -3
- package/dist/types/messageComposer/attachmentManager.d.ts +3 -3
- package/dist/types/messageComposer/configuration/types.d.ts +11 -1
- package/dist/types/messageComposer/types.d.ts +2 -0
- package/dist/types/offline-support/offline_support_api.d.ts +22 -0
- package/dist/types/offline-support/types.d.ts +14 -0
- package/dist/types/offline-support/util.d.ts +11 -0
- package/package.json +1 -1
- package/src/channel.ts +25 -0
- package/src/client.ts +55 -2
- package/src/messageComposer/attachmentManager.ts +83 -16
- package/src/messageComposer/configuration/configuration.ts +1 -0
- package/src/messageComposer/configuration/types.ts +12 -0
- package/src/messageComposer/types.ts +2 -0
- package/src/offline-support/offline_support_api.ts +124 -3
- package/src/offline-support/types.ts +18 -0
- package/src/offline-support/util.ts +32 -0
package/dist/types/channel.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AxiosRequestConfig } from 'axios';
|
|
1
2
|
import { ChannelState } from './channel_state';
|
|
2
3
|
import { CooldownTimer } from './CooldownTimer';
|
|
3
4
|
import { MessageComposer } from './messageComposer';
|
|
@@ -81,8 +82,28 @@ export declare class Channel {
|
|
|
81
82
|
*/
|
|
82
83
|
_sendMessage(message: Message, options?: SendMessageOptions): Promise<SendMessageAPIResponse>;
|
|
83
84
|
sendMessage(message: Message, options?: SendMessageOptions): Promise<SendMessageAPIResponse>;
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Upload a file to this channel’s file endpoint (multipart). Forwards to the client’s `sendFile` implementation.
|
|
87
|
+
*
|
|
88
|
+
* @param uri File source: URL string, `File`, `Buffer`, or readable stream (Node).
|
|
89
|
+
* @param name File name sent in the multipart body.
|
|
90
|
+
* @param contentType MIME type; defaults are applied when omitted.
|
|
91
|
+
* @param user Optional user payload appended to the form as JSON.
|
|
92
|
+
* @param axiosRequestConfig Optional Axios per-request config, merged after upload defaults (e.g. `onUploadProgress`, `signal` from `AbortController`).
|
|
93
|
+
* @return Promise resolving to `{ file: string, ... }` with the CDN URL.
|
|
94
|
+
*/
|
|
95
|
+
sendFile(uri: string | NodeJS.ReadableStream | Buffer | File, name?: string, contentType?: string, user?: UserResponse, axiosRequestConfig?: AxiosRequestConfig): Promise<import("./types").SendFileAPIResponse>;
|
|
96
|
+
/**
|
|
97
|
+
* Upload an image to this channel’s image endpoint (multipart). Uses the same transport as `sendFile`.
|
|
98
|
+
*
|
|
99
|
+
* @param uri Image source: URL string, `File`, or readable stream (Node). For `Buffer` uploads, use `sendFile` toward the channel file endpoint instead.
|
|
100
|
+
* @param name File name sent in the multipart body.
|
|
101
|
+
* @param contentType MIME type.
|
|
102
|
+
* @param user Optional user payload appended to the form as JSON.
|
|
103
|
+
* @param axiosRequestConfig Optional Axios per-request config, merged after upload defaults (e.g. `onUploadProgress`, `signal`).
|
|
104
|
+
* @return Promise resolving to `{ file: string, ... }` with the CDN URL.
|
|
105
|
+
*/
|
|
106
|
+
sendImage(uri: string | NodeJS.ReadableStream | File, name?: string, contentType?: string, user?: UserResponse, axiosRequestConfig?: AxiosRequestConfig): Promise<import("./types").SendFileAPIResponse>;
|
|
86
107
|
deleteFile(url: string): Promise<APIResponse>;
|
|
87
108
|
deleteImage(url: string): Promise<APIResponse>;
|
|
88
109
|
/**
|
package/dist/types/client.d.ts
CHANGED
|
@@ -400,7 +400,7 @@ export declare class StreamChat {
|
|
|
400
400
|
post<T>(url: string, data?: unknown): Promise<T>;
|
|
401
401
|
patch<T>(url: string, data?: unknown): Promise<T>;
|
|
402
402
|
delete<T>(url: string, params?: AxiosRequestConfig['params']): Promise<T>;
|
|
403
|
-
sendFile(url: string, uri: string | NodeJS.ReadableStream | Buffer | File, name?: string, contentType?: string, user?: UserResponse): Promise<SendFileAPIResponse>;
|
|
403
|
+
sendFile(url: string, uri: string | NodeJS.ReadableStream | Buffer | File, name?: string, contentType?: string, user?: UserResponse, axiosRequestConfig?: AxiosRequestConfig): Promise<SendFileAPIResponse>;
|
|
404
404
|
errorFromResponse(response: AxiosResponse<APIErrorResponse>): ErrorFromResponse<APIErrorResponse>;
|
|
405
405
|
handleResponse<T>(response: AxiosResponse<T>): T;
|
|
406
406
|
dispatchEvent: (event: Event) => void;
|
|
@@ -1113,6 +1113,9 @@ export declare class StreamChat {
|
|
|
1113
1113
|
updateMessage(message: LocalMessage | Partial<MessageResponse>, partialUserOrUserId?: string | {
|
|
1114
1114
|
id: string;
|
|
1115
1115
|
}, options?: UpdateMessageOptions): Promise<UpdateMessageAPIResponse>;
|
|
1116
|
+
_updateMessage(message: LocalMessage | Partial<MessageResponse>, partialUserOrUserId?: string | {
|
|
1117
|
+
id: string;
|
|
1118
|
+
}, options?: UpdateMessageOptions): Promise<UpdateMessageAPIResponse>;
|
|
1116
1119
|
/**
|
|
1117
1120
|
* partialUpdateMessage - Update the given message id while retaining additional properties
|
|
1118
1121
|
*
|
|
@@ -1972,10 +1975,11 @@ export declare class StreamChat {
|
|
|
1972
1975
|
* @param {string} [name] The name of the file
|
|
1973
1976
|
* @param {string} [contentType] The content type of the file
|
|
1974
1977
|
* @param {UserResponse} [user] Optional user information
|
|
1978
|
+
* @param {AxiosRequestConfig} [axiosRequestConfig] Optional axios config (e.g. onUploadProgress for progress tracking)
|
|
1975
1979
|
*
|
|
1976
1980
|
* @return {Promise<SendFileAPIResponse>} Response containing the file URL
|
|
1977
1981
|
*/
|
|
1978
|
-
uploadFile(uri: string | NodeJS.ReadableStream | Buffer | File, name?: string, contentType?: string, user?: UserResponse): Promise<SendFileAPIResponse>;
|
|
1982
|
+
uploadFile(uri: string | NodeJS.ReadableStream | Buffer | File, name?: string, contentType?: string, user?: UserResponse, axiosRequestConfig?: AxiosRequestConfig): Promise<SendFileAPIResponse>;
|
|
1979
1983
|
/**
|
|
1980
1984
|
* uploadImage - Uploads an image to the configured storage (defaults to Stream CDN)
|
|
1981
1985
|
*
|
|
@@ -1983,10 +1987,11 @@ export declare class StreamChat {
|
|
|
1983
1987
|
* @param {string} [name] The name of the image
|
|
1984
1988
|
* @param {string} [contentType] The content type of the image
|
|
1985
1989
|
* @param {UserResponse} [user] Optional user information
|
|
1990
|
+
* @param {AxiosRequestConfig} [axiosRequestConfig] Optional axios config (e.g. onUploadProgress for progress tracking)
|
|
1986
1991
|
*
|
|
1987
1992
|
* @return {Promise<SendFileAPIResponse>} Response containing the image URL
|
|
1988
1993
|
*/
|
|
1989
|
-
uploadImage(uri: string | NodeJS.ReadableStream | File, name?: string, contentType?: string, user?: UserResponse): Promise<SendFileAPIResponse>;
|
|
1994
|
+
uploadImage(uri: string | NodeJS.ReadableStream | File, name?: string, contentType?: string, user?: UserResponse, axiosRequestConfig?: AxiosRequestConfig): Promise<SendFileAPIResponse>;
|
|
1990
1995
|
/**
|
|
1991
1996
|
* deleteFile - Deletes a file from the configured storage
|
|
1992
1997
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AttachmentManagerConfig, MinimumUploadRequestResult, UploadRequestFn } from './configuration';
|
|
1
|
+
import type { AttachmentManagerConfig, MinimumUploadRequestResult, UploadRequestFn, UploadRequestOptions } from './configuration';
|
|
2
2
|
import { AttachmentPostUploadMiddlewareExecutor, AttachmentPreUploadMiddlewareExecutor } from './middleware/attachmentManager';
|
|
3
3
|
import { StateStore } from '../store';
|
|
4
4
|
import type { AttachmentLoadingState, FileLike, FileReference, LocalAttachment, LocalUploadAttachment, UploadPermissionCheckResult } from './types';
|
|
@@ -57,7 +57,7 @@ export declare class AttachmentManager {
|
|
|
57
57
|
* Method to perform the default upload behavior without checking for custom upload functions
|
|
58
58
|
* to prevent recursive calls
|
|
59
59
|
*/
|
|
60
|
-
doDefaultUploadRequest: (fileLike: FileReference | FileLike) => Promise<{
|
|
60
|
+
doDefaultUploadRequest: (fileLike: FileReference | FileLike, options?: UploadRequestOptions) => Promise<{
|
|
61
61
|
blocklist?: import("..").BlockListResponse;
|
|
62
62
|
file: string;
|
|
63
63
|
thumb_url?: string;
|
|
@@ -65,7 +65,7 @@ export declare class AttachmentManager {
|
|
|
65
65
|
/**
|
|
66
66
|
* todo: docs how to customize the image and file upload by overriding do
|
|
67
67
|
*/
|
|
68
|
-
doUploadRequest: (fileLike: FileReference | FileLike) => Promise<MinimumUploadRequestResult | {
|
|
68
|
+
doUploadRequest: (fileLike: FileReference | FileLike, options?: UploadRequestOptions) => Promise<MinimumUploadRequestResult | {
|
|
69
69
|
blocklist?: import("..").BlockListResponse;
|
|
70
70
|
file: string;
|
|
71
71
|
thumb_url?: string;
|
|
@@ -5,7 +5,11 @@ export type MinimumUploadRequestResult = {
|
|
|
5
5
|
file: string;
|
|
6
6
|
thumb_url?: string;
|
|
7
7
|
} & Partial<Record<string, unknown>>;
|
|
8
|
-
|
|
8
|
+
/** Optional second argument to `UploadRequestFn`; integrators may call `onProgress` to report 0–100 or `undefined` when indeterminate. */
|
|
9
|
+
export type UploadRequestOptions = {
|
|
10
|
+
onProgress?: (percent: number | undefined) => void;
|
|
11
|
+
};
|
|
12
|
+
export type UploadRequestFn = (fileLike: FileReference | FileLike, options?: UploadRequestOptions) => Promise<MinimumUploadRequestResult>;
|
|
9
13
|
export type DraftsConfiguration = {
|
|
10
14
|
enabled: boolean;
|
|
11
15
|
};
|
|
@@ -36,6 +40,12 @@ export type AttachmentManagerConfig = {
|
|
|
36
40
|
acceptedFiles: string[];
|
|
37
41
|
/** Function that allows to customize the upload request. */
|
|
38
42
|
doUploadRequest?: UploadRequestFn;
|
|
43
|
+
/**
|
|
44
|
+
* When true, the attachment manager sets `localMetadata.uploadProgress` and passes `options.onProgress`
|
|
45
|
+
* to `doUploadRequest` (built-in and custom). Set to false to disable progress tracking.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
trackUploadProgress: boolean;
|
|
39
49
|
};
|
|
40
50
|
export type LinkPreviewsManagerConfig = {
|
|
41
51
|
/** Number of milliseconds to debounce firing the URL enrichment queries when typing. The default value is 1500(ms). */
|
|
@@ -69,6 +69,8 @@ export type LocalAttachmentUploadMetadata = {
|
|
|
69
69
|
previewUri?: string;
|
|
70
70
|
uploadState: AttachmentLoadingState;
|
|
71
71
|
uploadPermissionCheck?: UploadPermissionCheckResult;
|
|
72
|
+
/** 0–100 while uploading when progress tracking is enabled; undefined otherwise or when indeterminate */
|
|
73
|
+
uploadProgress?: number;
|
|
72
74
|
};
|
|
73
75
|
export type LocalImageAttachmentUploadMetadata = LocalAttachmentUploadMetadata & {
|
|
74
76
|
/**
|
|
@@ -271,6 +271,15 @@ export declare abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
271
271
|
* @returns {Promise<() => Promise<void>>}
|
|
272
272
|
*/
|
|
273
273
|
abstract addPendingTask: OfflineDBApi['addPendingTask'];
|
|
274
|
+
/**
|
|
275
|
+
* @abstract
|
|
276
|
+
* Updates a pending task in the DB, given its ID.
|
|
277
|
+
* Will return the prepared queries for delayed execution (even if they are
|
|
278
|
+
* already executed).
|
|
279
|
+
* @param {DBUpdatePendingTaskType} options
|
|
280
|
+
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
281
|
+
*/
|
|
282
|
+
abstract updatePendingTask: OfflineDBApi['updatePendingTask'];
|
|
274
283
|
/**
|
|
275
284
|
* @abstract
|
|
276
285
|
* Deletes a pending task from the DB, given its ID.
|
|
@@ -572,13 +581,26 @@ export declare abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
572
581
|
* @param error
|
|
573
582
|
*/
|
|
574
583
|
private shouldSkipQueueingTask;
|
|
584
|
+
private mergeFailedMessageUpdateIntoPendingSendMessage;
|
|
585
|
+
private isPendingSendMessageTask;
|
|
586
|
+
private handleOfflineFailedUpdateMessagePendingTask;
|
|
587
|
+
/**
|
|
588
|
+
* Central ingress for persisting pending tasks. It either stores the task as-is
|
|
589
|
+
* or rewrites an existing pending `send-message` task for offline edits of failed messages.
|
|
590
|
+
*/
|
|
591
|
+
handleAddPendingTask: ({ task }: {
|
|
592
|
+
task: PendingTask;
|
|
593
|
+
}) => Promise<void>;
|
|
575
594
|
/**
|
|
576
595
|
* Executes a task from the list of supported pending tasks. Currently supported pending tasks
|
|
577
596
|
* are:
|
|
597
|
+
* - Updating a message
|
|
578
598
|
* - Deleting a message
|
|
579
599
|
* - Sending a reaction
|
|
580
600
|
* - Removing a reaction
|
|
581
601
|
* - Sending a message
|
|
602
|
+
* - Creating a draft
|
|
603
|
+
* - Deleting a draft
|
|
582
604
|
* It will throw if we try to execute a pending task that is not supported.
|
|
583
605
|
* @param task - The task we want to execute
|
|
584
606
|
* @param isPendingTask - a control value telling us if it's an actual pending task being executed
|
|
@@ -189,6 +189,15 @@ export type DBDeletePendingTaskType = {
|
|
|
189
189
|
/** ID of the pending task. */
|
|
190
190
|
id: number;
|
|
191
191
|
};
|
|
192
|
+
/**
|
|
193
|
+
* Update a pending task by ID.
|
|
194
|
+
*/
|
|
195
|
+
export type DBUpdatePendingTaskType = {
|
|
196
|
+
/** ID of the pending task. */
|
|
197
|
+
id: number;
|
|
198
|
+
/** The next task payload to persist. */
|
|
199
|
+
task: PendingTask;
|
|
200
|
+
};
|
|
192
201
|
/**
|
|
193
202
|
* Options to delete a reaction from a message.
|
|
194
203
|
*/
|
|
@@ -309,6 +318,7 @@ export interface OfflineDBApi {
|
|
|
309
318
|
addPendingTask: (task: PendingTask) => Promise<() => Promise<void>>;
|
|
310
319
|
getPendingTasks: (conditions?: DBGetPendingTasksType) => Promise<PendingTask[]>;
|
|
311
320
|
deleteDraft: (options: DBDeleteDraftType) => Promise<ExecuteBatchDBQueriesType>;
|
|
321
|
+
updatePendingTask: (options: DBUpdatePendingTaskType) => Promise<ExecuteBatchDBQueriesType>;
|
|
312
322
|
deletePendingTask: (options: DBDeletePendingTaskType) => Promise<ExecuteBatchDBQueriesType>;
|
|
313
323
|
deleteReaction: (options: DBDeleteReactionType) => Promise<ExecuteBatchDBQueriesType>;
|
|
314
324
|
deleteMember: (options: DBDeleteMemberType) => Promise<ExecuteBatchDBQueriesType>;
|
|
@@ -326,6 +336,7 @@ export type OfflineDBState = {
|
|
|
326
336
|
userId?: string;
|
|
327
337
|
};
|
|
328
338
|
export type PendingTaskTypes = {
|
|
339
|
+
updateMessage: 'update-message';
|
|
329
340
|
deleteMessage: 'delete-message';
|
|
330
341
|
deleteReaction: 'delete-reaction';
|
|
331
342
|
sendReaction: 'send-reaction';
|
|
@@ -342,6 +353,9 @@ export type PendingTask = {
|
|
|
342
353
|
} & ({
|
|
343
354
|
payload: Parameters<Channel['sendReaction']>;
|
|
344
355
|
type: PendingTaskTypes['sendReaction'];
|
|
356
|
+
} | {
|
|
357
|
+
payload: Parameters<StreamChat['updateMessage']>;
|
|
358
|
+
type: PendingTaskTypes['updateMessage'];
|
|
345
359
|
} | {
|
|
346
360
|
payload: Parameters<StreamChat['deleteMessage']>;
|
|
347
361
|
type: PendingTaskTypes['deleteMessage'];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Attachment, LocalMessage, MessageResponse } from '../types';
|
|
2
|
+
export declare const isLocalUrl: (value: string | undefined) => boolean;
|
|
3
|
+
export declare const isAttachmentReplayable: (attachment: Attachment) => boolean;
|
|
4
|
+
export declare const isMessageUpdateReplayable: (message: LocalMessage | Partial<MessageResponse>) => boolean;
|
|
5
|
+
export declare const getPendingTaskChannelData: (cid?: string) => {
|
|
6
|
+
channelId?: undefined;
|
|
7
|
+
channelType?: undefined;
|
|
8
|
+
} | {
|
|
9
|
+
channelId: string;
|
|
10
|
+
channelType: string;
|
|
11
|
+
};
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AxiosRequestConfig } from 'axios';
|
|
1
2
|
import { ChannelState } from './channel_state';
|
|
2
3
|
import { CooldownTimer } from './CooldownTimer';
|
|
3
4
|
import { MessageComposer } from './messageComposer';
|
|
@@ -245,11 +246,22 @@ export class Channel {
|
|
|
245
246
|
return await this._sendMessage(message, options);
|
|
246
247
|
}
|
|
247
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Upload a file to this channel’s file endpoint (multipart). Forwards to the client’s `sendFile` implementation.
|
|
251
|
+
*
|
|
252
|
+
* @param uri File source: URL string, `File`, `Buffer`, or readable stream (Node).
|
|
253
|
+
* @param name File name sent in the multipart body.
|
|
254
|
+
* @param contentType MIME type; defaults are applied when omitted.
|
|
255
|
+
* @param user Optional user payload appended to the form as JSON.
|
|
256
|
+
* @param axiosRequestConfig Optional Axios per-request config, merged after upload defaults (e.g. `onUploadProgress`, `signal` from `AbortController`).
|
|
257
|
+
* @return Promise resolving to `{ file: string, ... }` with the CDN URL.
|
|
258
|
+
*/
|
|
248
259
|
sendFile(
|
|
249
260
|
uri: string | NodeJS.ReadableStream | Buffer | File,
|
|
250
261
|
name?: string,
|
|
251
262
|
contentType?: string,
|
|
252
263
|
user?: UserResponse,
|
|
264
|
+
axiosRequestConfig?: AxiosRequestConfig,
|
|
253
265
|
) {
|
|
254
266
|
return this.getClient().sendFile(
|
|
255
267
|
`${this._channelURL()}/file`,
|
|
@@ -257,14 +269,26 @@ export class Channel {
|
|
|
257
269
|
name,
|
|
258
270
|
contentType,
|
|
259
271
|
user,
|
|
272
|
+
axiosRequestConfig,
|
|
260
273
|
);
|
|
261
274
|
}
|
|
262
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Upload an image to this channel’s image endpoint (multipart). Uses the same transport as `sendFile`.
|
|
278
|
+
*
|
|
279
|
+
* @param uri Image source: URL string, `File`, or readable stream (Node). For `Buffer` uploads, use `sendFile` toward the channel file endpoint instead.
|
|
280
|
+
* @param name File name sent in the multipart body.
|
|
281
|
+
* @param contentType MIME type.
|
|
282
|
+
* @param user Optional user payload appended to the form as JSON.
|
|
283
|
+
* @param axiosRequestConfig Optional Axios per-request config, merged after upload defaults (e.g. `onUploadProgress`, `signal`).
|
|
284
|
+
* @return Promise resolving to `{ file: string, ... }` with the CDN URL.
|
|
285
|
+
*/
|
|
263
286
|
sendImage(
|
|
264
287
|
uri: string | NodeJS.ReadableStream | File,
|
|
265
288
|
name?: string,
|
|
266
289
|
contentType?: string,
|
|
267
290
|
user?: UserResponse,
|
|
291
|
+
axiosRequestConfig?: AxiosRequestConfig,
|
|
268
292
|
) {
|
|
269
293
|
return this.getClient().sendFile(
|
|
270
294
|
`${this._channelURL()}/image`,
|
|
@@ -272,6 +296,7 @@ export class Channel {
|
|
|
272
296
|
name,
|
|
273
297
|
contentType,
|
|
274
298
|
user,
|
|
299
|
+
axiosRequestConfig,
|
|
275
300
|
);
|
|
276
301
|
}
|
|
277
302
|
|
package/src/client.ts
CHANGED
|
@@ -265,6 +265,7 @@ import { ReminderManager } from './reminders';
|
|
|
265
265
|
import { StateStore } from './store';
|
|
266
266
|
import type { MessageComposer } from './messageComposer';
|
|
267
267
|
import type { AbstractOfflineDB } from './offline-support';
|
|
268
|
+
import { getPendingTaskChannelData } from './offline-support/util';
|
|
268
269
|
|
|
269
270
|
function isString(x: unknown): x is string {
|
|
270
271
|
return typeof x === 'string' || x instanceof String;
|
|
@@ -1310,6 +1311,7 @@ export class StreamChat {
|
|
|
1310
1311
|
name?: string,
|
|
1311
1312
|
contentType?: string,
|
|
1312
1313
|
user?: UserResponse,
|
|
1314
|
+
axiosRequestConfig?: AxiosRequestConfig,
|
|
1313
1315
|
) {
|
|
1314
1316
|
const data = addFileToFormData(uri, name, contentType || 'multipart/form-data');
|
|
1315
1317
|
if (user != null) data.append('user', JSON.stringify(user));
|
|
@@ -1320,6 +1322,7 @@ export class StreamChat {
|
|
|
1320
1322
|
timeout: 0,
|
|
1321
1323
|
maxContentLength: Infinity,
|
|
1322
1324
|
maxBodyLength: Infinity,
|
|
1325
|
+
...axiosRequestConfig,
|
|
1323
1326
|
},
|
|
1324
1327
|
});
|
|
1325
1328
|
}
|
|
@@ -3114,6 +3117,38 @@ export class StreamChat {
|
|
|
3114
3117
|
throw Error('Please specify the message.id when calling updateMessage');
|
|
3115
3118
|
}
|
|
3116
3119
|
|
|
3120
|
+
const messageId = message.id as string;
|
|
3121
|
+
|
|
3122
|
+
try {
|
|
3123
|
+
if (this.offlineDb) {
|
|
3124
|
+
return await this.offlineDb.queueTask<UpdateMessageAPIResponse>({
|
|
3125
|
+
task: {
|
|
3126
|
+
...getPendingTaskChannelData(message.cid),
|
|
3127
|
+
messageId,
|
|
3128
|
+
payload: [message, partialUserOrUserId, options],
|
|
3129
|
+
type: 'update-message',
|
|
3130
|
+
},
|
|
3131
|
+
});
|
|
3132
|
+
}
|
|
3133
|
+
} catch (error) {
|
|
3134
|
+
this.logger('error', `offlineDb:updateMessage`, {
|
|
3135
|
+
tags: ['channel', 'offlineDb'],
|
|
3136
|
+
error,
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
return await this._updateMessage(message, partialUserOrUserId, options);
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
async _updateMessage(
|
|
3144
|
+
message: LocalMessage | Partial<MessageResponse>,
|
|
3145
|
+
partialUserOrUserId?: string | { id: string },
|
|
3146
|
+
options?: UpdateMessageOptions,
|
|
3147
|
+
) {
|
|
3148
|
+
if (!message.id) {
|
|
3149
|
+
throw Error('Please specify the message.id when calling updateMessage');
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3117
3152
|
// should not include user object
|
|
3118
3153
|
const payload = toUpdatedMessagePayload(message);
|
|
3119
3154
|
|
|
@@ -4833,6 +4868,7 @@ export class StreamChat {
|
|
|
4833
4868
|
* @param {string} [name] The name of the file
|
|
4834
4869
|
* @param {string} [contentType] The content type of the file
|
|
4835
4870
|
* @param {UserResponse} [user] Optional user information
|
|
4871
|
+
* @param {AxiosRequestConfig} [axiosRequestConfig] Optional axios config (e.g. onUploadProgress for progress tracking)
|
|
4836
4872
|
*
|
|
4837
4873
|
* @return {Promise<SendFileAPIResponse>} Response containing the file URL
|
|
4838
4874
|
*/
|
|
@@ -4841,8 +4877,16 @@ export class StreamChat {
|
|
|
4841
4877
|
name?: string,
|
|
4842
4878
|
contentType?: string,
|
|
4843
4879
|
user?: UserResponse,
|
|
4880
|
+
axiosRequestConfig?: AxiosRequestConfig,
|
|
4844
4881
|
) {
|
|
4845
|
-
return this.sendFile(
|
|
4882
|
+
return this.sendFile(
|
|
4883
|
+
`${this.baseURL}/uploads/file`,
|
|
4884
|
+
uri,
|
|
4885
|
+
name,
|
|
4886
|
+
contentType,
|
|
4887
|
+
user,
|
|
4888
|
+
axiosRequestConfig,
|
|
4889
|
+
);
|
|
4846
4890
|
}
|
|
4847
4891
|
|
|
4848
4892
|
/**
|
|
@@ -4852,6 +4896,7 @@ export class StreamChat {
|
|
|
4852
4896
|
* @param {string} [name] The name of the image
|
|
4853
4897
|
* @param {string} [contentType] The content type of the image
|
|
4854
4898
|
* @param {UserResponse} [user] Optional user information
|
|
4899
|
+
* @param {AxiosRequestConfig} [axiosRequestConfig] Optional axios config (e.g. onUploadProgress for progress tracking)
|
|
4855
4900
|
*
|
|
4856
4901
|
* @return {Promise<SendFileAPIResponse>} Response containing the image URL
|
|
4857
4902
|
*/
|
|
@@ -4860,8 +4905,16 @@ export class StreamChat {
|
|
|
4860
4905
|
name?: string,
|
|
4861
4906
|
contentType?: string,
|
|
4862
4907
|
user?: UserResponse,
|
|
4908
|
+
axiosRequestConfig?: AxiosRequestConfig,
|
|
4863
4909
|
) {
|
|
4864
|
-
return this.sendFile(
|
|
4910
|
+
return this.sendFile(
|
|
4911
|
+
`${this.baseURL}/uploads/image`,
|
|
4912
|
+
uri,
|
|
4913
|
+
name,
|
|
4914
|
+
contentType,
|
|
4915
|
+
user,
|
|
4916
|
+
axiosRequestConfig,
|
|
4917
|
+
);
|
|
4865
4918
|
}
|
|
4866
4919
|
|
|
4867
4920
|
/**
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AttachmentManagerConfig,
|
|
3
3
|
MinimumUploadRequestResult,
|
|
4
4
|
UploadRequestFn,
|
|
5
|
+
UploadRequestOptions,
|
|
5
6
|
} from './configuration';
|
|
6
7
|
import { isLocalImageAttachment, isUploadedAttachment } from './attachmentIdentity';
|
|
7
8
|
import {
|
|
@@ -445,12 +446,31 @@ export class AttachmentManager {
|
|
|
445
446
|
* Method to perform the default upload behavior without checking for custom upload functions
|
|
446
447
|
* to prevent recursive calls
|
|
447
448
|
*/
|
|
448
|
-
doDefaultUploadRequest = async (
|
|
449
|
+
doDefaultUploadRequest = async (
|
|
450
|
+
fileLike: FileReference | FileLike,
|
|
451
|
+
options?: UploadRequestOptions,
|
|
452
|
+
) => {
|
|
453
|
+
const progressHandler = options?.onProgress
|
|
454
|
+
? (progressEvent: {
|
|
455
|
+
loaded: number;
|
|
456
|
+
total?: number;
|
|
457
|
+
lengthComputable?: boolean;
|
|
458
|
+
}) => {
|
|
459
|
+
const percent =
|
|
460
|
+
progressEvent.lengthComputable && progressEvent.total
|
|
461
|
+
? Math.round((progressEvent.loaded * 100) / progressEvent.total)
|
|
462
|
+
: undefined;
|
|
463
|
+
options.onProgress?.(percent);
|
|
464
|
+
}
|
|
465
|
+
: undefined;
|
|
466
|
+
|
|
449
467
|
if (isFileReference(fileLike)) {
|
|
450
468
|
return this.channel[isImageFile(fileLike) ? 'sendImage' : 'sendFile'](
|
|
451
469
|
fileLike.uri,
|
|
452
470
|
fileLike.name,
|
|
453
471
|
fileLike.type,
|
|
472
|
+
undefined,
|
|
473
|
+
progressHandler ? { onUploadProgress: progressHandler } : undefined,
|
|
454
474
|
);
|
|
455
475
|
}
|
|
456
476
|
|
|
@@ -463,8 +483,15 @@ export class AttachmentManager {
|
|
|
463
483
|
});
|
|
464
484
|
|
|
465
485
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
466
|
-
const { duration, ...result } =
|
|
467
|
-
|
|
486
|
+
const { duration, ...result } = await this.channel[
|
|
487
|
+
isImageFile(fileLike) ? 'sendImage' : 'sendFile'
|
|
488
|
+
](
|
|
489
|
+
file,
|
|
490
|
+
undefined,
|
|
491
|
+
undefined,
|
|
492
|
+
undefined,
|
|
493
|
+
progressHandler ? { onUploadProgress: progressHandler } : undefined,
|
|
494
|
+
);
|
|
468
495
|
return result;
|
|
469
496
|
};
|
|
470
497
|
|
|
@@ -472,13 +499,16 @@ export class AttachmentManager {
|
|
|
472
499
|
* todo: docs how to customize the image and file upload by overriding do
|
|
473
500
|
*/
|
|
474
501
|
|
|
475
|
-
doUploadRequest = async (
|
|
502
|
+
doUploadRequest = async (
|
|
503
|
+
fileLike: FileReference | FileLike,
|
|
504
|
+
options?: UploadRequestOptions,
|
|
505
|
+
) => {
|
|
476
506
|
const customUploadFn = this.config.doUploadRequest;
|
|
477
507
|
if (customUploadFn) {
|
|
478
|
-
return await customUploadFn(fileLike);
|
|
508
|
+
return await customUploadFn(fileLike, options);
|
|
479
509
|
}
|
|
480
510
|
|
|
481
|
-
return this.doDefaultUploadRequest(fileLike);
|
|
511
|
+
return this.doDefaultUploadRequest(fileLike, options);
|
|
482
512
|
};
|
|
483
513
|
|
|
484
514
|
// @deprecated use attachmentManager.uploadFile(file)
|
|
@@ -507,19 +537,37 @@ export class AttachmentManager {
|
|
|
507
537
|
return localAttachment;
|
|
508
538
|
}
|
|
509
539
|
|
|
510
|
-
this.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
},
|
|
540
|
+
const shouldTrackProgress = this.config.trackUploadProgress;
|
|
541
|
+
const uploadingAttachment: LocalUploadAttachment = {
|
|
542
|
+
...attachment,
|
|
543
|
+
localMetadata: {
|
|
544
|
+
...attachment.localMetadata,
|
|
545
|
+
uploadState: 'uploading',
|
|
546
|
+
...(shouldTrackProgress && { uploadProgress: 0 }),
|
|
517
547
|
},
|
|
518
|
-
|
|
548
|
+
};
|
|
549
|
+
this.upsertAttachments([uploadingAttachment]);
|
|
550
|
+
|
|
551
|
+
const uploadOptions = shouldTrackProgress
|
|
552
|
+
? {
|
|
553
|
+
onProgress: (percent: number | undefined) => {
|
|
554
|
+
this.updateAttachment({
|
|
555
|
+
...uploadingAttachment,
|
|
556
|
+
localMetadata: {
|
|
557
|
+
...uploadingAttachment.localMetadata,
|
|
558
|
+
uploadProgress: percent,
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
},
|
|
562
|
+
}
|
|
563
|
+
: undefined;
|
|
519
564
|
|
|
520
565
|
let response: MinimumUploadRequestResult;
|
|
521
566
|
try {
|
|
522
|
-
response = await this.doUploadRequest(
|
|
567
|
+
response = await this.doUploadRequest(
|
|
568
|
+
localAttachment.localMetadata.file,
|
|
569
|
+
uploadOptions,
|
|
570
|
+
);
|
|
523
571
|
} catch (error) {
|
|
524
572
|
const reason = error instanceof Error ? error.message : 'unknown error';
|
|
525
573
|
const failedAttachment: LocalUploadAttachment = {
|
|
@@ -527,6 +575,7 @@ export class AttachmentManager {
|
|
|
527
575
|
localMetadata: {
|
|
528
576
|
...attachment.localMetadata,
|
|
529
577
|
uploadState: 'failed',
|
|
578
|
+
uploadProgress: undefined,
|
|
530
579
|
},
|
|
531
580
|
};
|
|
532
581
|
|
|
@@ -561,6 +610,7 @@ export class AttachmentManager {
|
|
|
561
610
|
localMetadata: {
|
|
562
611
|
...attachment.localMetadata,
|
|
563
612
|
uploadState: 'finished',
|
|
613
|
+
uploadProgress: undefined,
|
|
564
614
|
},
|
|
565
615
|
};
|
|
566
616
|
|
|
@@ -605,19 +655,35 @@ export class AttachmentManager {
|
|
|
605
655
|
return preUpload.state.attachment;
|
|
606
656
|
}
|
|
607
657
|
|
|
658
|
+
const shouldTrackProgress = this.config.trackUploadProgress;
|
|
608
659
|
attachment = {
|
|
609
660
|
...attachment,
|
|
610
661
|
localMetadata: {
|
|
611
662
|
...attachment.localMetadata,
|
|
612
663
|
uploadState: 'uploading',
|
|
664
|
+
...(shouldTrackProgress && { uploadProgress: 0 }),
|
|
613
665
|
},
|
|
614
666
|
};
|
|
615
667
|
this.upsertAttachments([attachment]);
|
|
616
668
|
|
|
669
|
+
const uploadOptions = shouldTrackProgress
|
|
670
|
+
? {
|
|
671
|
+
onProgress: (percent: number | undefined) => {
|
|
672
|
+
this.updateAttachment({
|
|
673
|
+
...attachment,
|
|
674
|
+
localMetadata: {
|
|
675
|
+
...attachment.localMetadata,
|
|
676
|
+
uploadProgress: percent,
|
|
677
|
+
},
|
|
678
|
+
});
|
|
679
|
+
},
|
|
680
|
+
}
|
|
681
|
+
: undefined;
|
|
682
|
+
|
|
617
683
|
let response: MinimumUploadRequestResult | undefined;
|
|
618
684
|
let error: Error | undefined;
|
|
619
685
|
try {
|
|
620
|
-
response = await this.doUploadRequest(file);
|
|
686
|
+
response = await this.doUploadRequest(file, uploadOptions);
|
|
621
687
|
} catch (err) {
|
|
622
688
|
error = err instanceof Error ? err : undefined;
|
|
623
689
|
}
|
|
@@ -630,6 +696,7 @@ export class AttachmentManager {
|
|
|
630
696
|
localMetadata: {
|
|
631
697
|
...attachment.localMetadata,
|
|
632
698
|
uploadState: error ? 'failed' : 'finished',
|
|
699
|
+
uploadProgress: undefined,
|
|
633
700
|
},
|
|
634
701
|
},
|
|
635
702
|
error,
|
|
@@ -31,6 +31,7 @@ export const DEFAULT_ATTACHMENT_MANAGER_CONFIG: AttachmentManagerConfig = {
|
|
|
31
31
|
acceptedFiles: [], // an empty array means all files are accepted
|
|
32
32
|
fileUploadFilter: () => true,
|
|
33
33
|
maxNumberOfFilesPerMessage: API_MAX_FILES_ALLOWED_PER_MESSAGE,
|
|
34
|
+
trackUploadProgress: true,
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export const DEFAULT_TEXT_COMPOSER_CONFIG: TextComposerConfig = {
|
|
@@ -6,8 +6,14 @@ export type MinimumUploadRequestResult = { file: string; thumb_url?: string } &
|
|
|
6
6
|
Record<string, unknown>
|
|
7
7
|
>;
|
|
8
8
|
|
|
9
|
+
/** Optional second argument to `UploadRequestFn`; integrators may call `onProgress` to report 0–100 or `undefined` when indeterminate. */
|
|
10
|
+
export type UploadRequestOptions = {
|
|
11
|
+
onProgress?: (percent: number | undefined) => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
9
14
|
export type UploadRequestFn = (
|
|
10
15
|
fileLike: FileReference | FileLike,
|
|
16
|
+
options?: UploadRequestOptions,
|
|
11
17
|
) => Promise<MinimumUploadRequestResult>;
|
|
12
18
|
|
|
13
19
|
export type DraftsConfiguration = {
|
|
@@ -43,6 +49,12 @@ export type AttachmentManagerConfig = {
|
|
|
43
49
|
acceptedFiles: string[];
|
|
44
50
|
/** Function that allows to customize the upload request. */
|
|
45
51
|
doUploadRequest?: UploadRequestFn;
|
|
52
|
+
/**
|
|
53
|
+
* When true, the attachment manager sets `localMetadata.uploadProgress` and passes `options.onProgress`
|
|
54
|
+
* to `doUploadRequest` (built-in and custom). Set to false to disable progress tracking.
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
trackUploadProgress: boolean;
|
|
46
58
|
};
|
|
47
59
|
|
|
48
60
|
export type LinkPreviewsManagerConfig = {
|
|
@@ -120,6 +120,8 @@ export type LocalAttachmentUploadMetadata = {
|
|
|
120
120
|
previewUri?: string;
|
|
121
121
|
uploadState: AttachmentLoadingState;
|
|
122
122
|
uploadPermissionCheck?: UploadPermissionCheckResult; // added new
|
|
123
|
+
/** 0–100 while uploading when progress tracking is enabled; undefined otherwise or when indeterminate */
|
|
124
|
+
uploadProgress?: number;
|
|
123
125
|
};
|
|
124
126
|
|
|
125
127
|
export type LocalImageAttachmentUploadMetadata = LocalAttachmentUploadMetadata & {
|