stream-chat 9.52.0 → 9.52.1
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 +37 -29
- package/dist/cjs/index.browser.js.map +2 -2
- package/dist/cjs/index.node.js +37 -29
- package/dist/cjs/index.node.js.map +2 -2
- package/dist/esm/index.mjs +37 -29
- package/dist/esm/index.mjs.map +2 -2
- package/dist/types/channel.d.ts +4 -2
- package/dist/types/utils.d.ts +9 -5
- package/package.json +1 -1
- package/src/channel.ts +26 -18
- package/src/client.ts +10 -13
- package/src/messageDelivery/MessageDeliveryReporter.ts +5 -4
- package/src/utils.ts +30 -7
package/dist/types/channel.d.ts
CHANGED
|
@@ -491,14 +491,16 @@ export declare class Channel {
|
|
|
491
491
|
*/
|
|
492
492
|
markRead(data?: MarkReadOptions): Promise<EventAPIResponse | null>;
|
|
493
493
|
/**
|
|
494
|
-
* markReadRequest - Send the mark read event for this user, only works if the `read_events` setting is
|
|
494
|
+
* markReadRequest - Send the mark read event for this user, only works if the `read_events` setting is
|
|
495
|
+
* enabled and the user holds the `read-events` capability on this channel
|
|
495
496
|
*
|
|
496
497
|
* @param {MarkReadOptions} data
|
|
497
498
|
* @return {Promise<EventAPIResponse | null>} Description
|
|
498
499
|
*/
|
|
499
500
|
markAsReadRequest(data?: MarkReadOptions): Promise<EventAPIResponse | null>;
|
|
500
501
|
/**
|
|
501
|
-
* markUnread - Mark the channel as unread from messageID, only works if the `read_events` setting is
|
|
502
|
+
* markUnread - Mark the channel as unread from messageID, only works if the `read_events` setting is
|
|
503
|
+
* enabled and the user holds the `read-events` capability on this channel
|
|
502
504
|
*
|
|
503
505
|
* @param {MarkUnreadOptions} data
|
|
504
506
|
* @return {APIResponse} An API response
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -12,6 +12,15 @@ import type { AxiosRequestConfig } from 'axios';
|
|
|
12
12
|
*
|
|
13
13
|
*/
|
|
14
14
|
export declare function logChatPromiseExecution<T>(promise: Promise<T>, name: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* The default no-op client logger.
|
|
17
|
+
*/
|
|
18
|
+
export declare const noopLogger: Logger;
|
|
19
|
+
/**
|
|
20
|
+
* Invokes a single event listener in isolation, so that a faulty listener cannot
|
|
21
|
+
* abort the dispatch loop or the bookkeeping that follows it.
|
|
22
|
+
*/
|
|
23
|
+
export declare const invokeEventListener: <T>(listener: (event: T) => unknown, event: T, logger: Logger) => void;
|
|
15
24
|
export declare const sleep: (m: number) => Promise<void>;
|
|
16
25
|
export declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
|
|
17
26
|
export declare const chatCodes: {
|
|
@@ -28,11 +37,6 @@ export declare const channelHasReadEvents: (channel?: Channel) => boolean;
|
|
|
28
37
|
* channelTracksReadLocally - Whether a channel maintains a client local unread count.
|
|
29
38
|
*/
|
|
30
39
|
export declare const channelTracksReadLocally: (channel?: Channel) => boolean;
|
|
31
|
-
/**
|
|
32
|
-
* userHasReadReceipts - Whether the current user allows read receipts, per their privacy settings.
|
|
33
|
-
* Read receipts are treated as enabled unless the user has explicitly disabled them.
|
|
34
|
-
*/
|
|
35
|
-
export declare const userHasReadReceipts: (client: StreamChat) => boolean;
|
|
36
40
|
export declare function addFileToFormData(uri: string | NodeJS.ReadableStream | Buffer | File, name?: string, contentType?: string): FormData;
|
|
37
41
|
export declare function normalizeQuerySort<T extends Record<string, AscDesc | undefined>>(sort: T | T[]): {
|
|
38
42
|
direction: AscDesc;
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { MessageReceiptsTracker } from './messageDelivery';
|
|
|
6
6
|
import {
|
|
7
7
|
channelHasReadEvents,
|
|
8
8
|
generateChannelTempCid,
|
|
9
|
+
invokeEventListener,
|
|
9
10
|
logChatPromiseExecution,
|
|
10
11
|
messageSetPagination,
|
|
11
12
|
normalizeQuerySort,
|
|
@@ -1221,7 +1222,8 @@ export class Channel {
|
|
|
1221
1222
|
}
|
|
1222
1223
|
|
|
1223
1224
|
/**
|
|
1224
|
-
* markReadRequest - Send the mark read event for this user, only works if the `read_events` setting is
|
|
1225
|
+
* markReadRequest - Send the mark read event for this user, only works if the `read_events` setting is
|
|
1226
|
+
* enabled and the user holds the `read-events` capability on this channel
|
|
1225
1227
|
*
|
|
1226
1228
|
* @param {MarkReadOptions} data
|
|
1227
1229
|
* @return {Promise<EventAPIResponse | null>} Description
|
|
@@ -1229,7 +1231,13 @@ export class Channel {
|
|
|
1229
1231
|
async markAsReadRequest(data: MarkReadOptions = {}) {
|
|
1230
1232
|
this._checkInitialized();
|
|
1231
1233
|
|
|
1232
|
-
|
|
1234
|
+
// Server-side auth acts on behalf of a user with no own capabilities, so only the client-side
|
|
1235
|
+
// flow is gated. Channels the user has no `read-events` capability on do not track read state
|
|
1236
|
+
// on the backend at all - see `markReadLocally` for the client-local unread count.
|
|
1237
|
+
if (
|
|
1238
|
+
!this.getClient()._isUsingServerAuth() &&
|
|
1239
|
+
(!this.getConfig()?.read_events || !channelHasReadEvents(this))
|
|
1240
|
+
) {
|
|
1233
1241
|
return null;
|
|
1234
1242
|
}
|
|
1235
1243
|
|
|
@@ -1239,7 +1247,8 @@ export class Channel {
|
|
|
1239
1247
|
}
|
|
1240
1248
|
|
|
1241
1249
|
/**
|
|
1242
|
-
* markUnread - Mark the channel as unread from messageID, only works if the `read_events` setting is
|
|
1250
|
+
* markUnread - Mark the channel as unread from messageID, only works if the `read_events` setting is
|
|
1251
|
+
* enabled and the user holds the `read-events` capability on this channel
|
|
1243
1252
|
*
|
|
1244
1253
|
* @param {MarkUnreadOptions} data
|
|
1245
1254
|
* @return {APIResponse} An API response
|
|
@@ -1247,7 +1256,11 @@ export class Channel {
|
|
|
1247
1256
|
async markUnread(data: MarkUnreadOptions) {
|
|
1248
1257
|
this._checkInitialized();
|
|
1249
1258
|
|
|
1250
|
-
|
|
1259
|
+
// Gated the same way as `markAsReadRequest` - see the comment there.
|
|
1260
|
+
if (
|
|
1261
|
+
!this.getClient()._isUsingServerAuth() &&
|
|
1262
|
+
(!this.getConfig()?.read_events || !channelHasReadEvents(this))
|
|
1263
|
+
) {
|
|
1251
1264
|
return Promise.resolve(null);
|
|
1252
1265
|
}
|
|
1253
1266
|
|
|
@@ -2354,22 +2367,17 @@ export class Channel {
|
|
|
2354
2367
|
}
|
|
2355
2368
|
|
|
2356
2369
|
_callChannelListeners = (event: Event) => {
|
|
2357
|
-
//
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
}
|
|
2364
|
-
if (channel.listeners[event.type]) {
|
|
2365
|
-
listeners.push(...channel.listeners[event.type]);
|
|
2366
|
-
}
|
|
2370
|
+
// snapshot before dispatching: `on` pushes into these arrays in place, so a
|
|
2371
|
+
// listener that subscribes while handling an event must not be invoked for it
|
|
2372
|
+
const listeners = [
|
|
2373
|
+
...(this.listeners.all ?? []),
|
|
2374
|
+
...(this.listeners[event.type] ?? []),
|
|
2375
|
+
];
|
|
2367
2376
|
|
|
2368
|
-
|
|
2377
|
+
const { logger } = this._client;
|
|
2369
2378
|
for (const listener of listeners) {
|
|
2370
|
-
if (typeof listener
|
|
2371
|
-
|
|
2372
|
-
}
|
|
2379
|
+
if (typeof listener === 'string') continue;
|
|
2380
|
+
invokeEventListener(listener, event, logger);
|
|
2373
2381
|
}
|
|
2374
2382
|
};
|
|
2375
2383
|
|
package/src/client.ts
CHANGED
|
@@ -29,10 +29,12 @@ import {
|
|
|
29
29
|
axiosParamsSerializer,
|
|
30
30
|
chatCodes,
|
|
31
31
|
generateChannelTempCid,
|
|
32
|
+
invokeEventListener,
|
|
32
33
|
isFunction,
|
|
33
34
|
isOnline,
|
|
34
35
|
isOwnUserBaseProperty,
|
|
35
36
|
messageSetPagination,
|
|
37
|
+
noopLogger,
|
|
36
38
|
normalizeQuerySort,
|
|
37
39
|
randomId,
|
|
38
40
|
retryInterval,
|
|
@@ -575,7 +577,7 @@ export class StreamChat {
|
|
|
575
577
|
* channel: object
|
|
576
578
|
* }
|
|
577
579
|
*/
|
|
578
|
-
this.logger = isFunction(inputOptions.logger) ? inputOptions.logger :
|
|
580
|
+
this.logger = isFunction(inputOptions.logger) ? inputOptions.logger : noopLogger;
|
|
579
581
|
this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;
|
|
580
582
|
this.threads = new ThreadManager({ client: this });
|
|
581
583
|
this.polls = new PollManager({ client: this });
|
|
@@ -1700,20 +1702,15 @@ export class StreamChat {
|
|
|
1700
1702
|
}
|
|
1701
1703
|
|
|
1702
1704
|
_callClientListeners = (event: Event) => {
|
|
1703
|
-
//
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
}
|
|
1710
|
-
if (client.listeners[event.type]) {
|
|
1711
|
-
listeners.push(...client.listeners[event.type]);
|
|
1712
|
-
}
|
|
1705
|
+
// snapshot before dispatching: `on` pushes into these arrays in place, so a
|
|
1706
|
+
// listener that subscribes while handling an event must not be invoked for it
|
|
1707
|
+
const listeners = [
|
|
1708
|
+
...(this.listeners.all ?? []),
|
|
1709
|
+
...(this.listeners[event.type] ?? []),
|
|
1710
|
+
];
|
|
1713
1711
|
|
|
1714
|
-
// call the event and send it to the listeners
|
|
1715
1712
|
for (const listener of listeners) {
|
|
1716
|
-
listener
|
|
1713
|
+
invokeEventListener(listener, event, this.logger);
|
|
1717
1714
|
}
|
|
1718
1715
|
};
|
|
1719
1716
|
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
MarkReadOptions,
|
|
11
11
|
} from '../types';
|
|
12
12
|
import { type APIErrorResponse } from '../types';
|
|
13
|
-
import { throttle
|
|
13
|
+
import { throttle } from '../utils';
|
|
14
14
|
import { isAPIError, isErrorRetryable } from '../errors';
|
|
15
15
|
|
|
16
16
|
const MAX_DELIVERED_MESSAGE_COUNT_IN_PAYLOAD = 100 as const;
|
|
@@ -279,8 +279,6 @@ export class MessageDeliveryReporter {
|
|
|
279
279
|
* @param options
|
|
280
280
|
*/
|
|
281
281
|
public markRead = async (collection: Channel | Thread, options?: MarkReadOptions) => {
|
|
282
|
-
if (!userHasReadReceipts(this.client)) return null;
|
|
283
|
-
|
|
284
282
|
let result: EventAPIResponse | null = null;
|
|
285
283
|
if (isChannel(collection)) {
|
|
286
284
|
result = await collection.markAsReadRequest(options);
|
|
@@ -291,7 +289,10 @@ export class MessageDeliveryReporter {
|
|
|
291
289
|
});
|
|
292
290
|
}
|
|
293
291
|
|
|
294
|
-
|
|
292
|
+
// A read implies delivery, so the candidate is only dropped once the request actually went
|
|
293
|
+
// out. `markAsReadRequest` returns null for channels that do not track read state on the
|
|
294
|
+
// backend, and those candidates must survive for the next delivery report.
|
|
295
|
+
if (result) this.removeCandidateFor(collection);
|
|
295
296
|
return result;
|
|
296
297
|
};
|
|
297
298
|
|
package/src/utils.ts
CHANGED
|
@@ -41,6 +41,36 @@ export function logChatPromiseExecution<T>(promise: Promise<T>, name: string) {
|
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The default no-op client logger.
|
|
46
|
+
*/
|
|
47
|
+
export const noopLogger: Logger = () => null;
|
|
48
|
+
|
|
49
|
+
const logError = <T>(logger: Logger, error: unknown, event: T) => {
|
|
50
|
+
const message = 'Unhandled error in event listener';
|
|
51
|
+
logger('error', message, { error, event });
|
|
52
|
+
if (logger === noopLogger) console.error(message, error, event);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Invokes a single event listener in isolation, so that a faulty listener cannot
|
|
57
|
+
* abort the dispatch loop or the bookkeeping that follows it.
|
|
58
|
+
*/
|
|
59
|
+
export const invokeEventListener = <T>(
|
|
60
|
+
listener: (event: T) => unknown,
|
|
61
|
+
event: T,
|
|
62
|
+
logger: Logger,
|
|
63
|
+
) => {
|
|
64
|
+
try {
|
|
65
|
+
const result = listener(event);
|
|
66
|
+
if (result && typeof (result as PromiseLike<unknown>).then === 'function') {
|
|
67
|
+
Promise.resolve(result).catch((error) => logError(logger, error, event));
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
logError(logger, error, event);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
44
74
|
export const sleep = (m: number): Promise<void> => new Promise((r) => setTimeout(r, m));
|
|
45
75
|
|
|
46
76
|
export function isFunction(value: unknown): value is (...args: unknown[]) => unknown {
|
|
@@ -126,13 +156,6 @@ export const channelTracksReadLocally = (channel?: Channel) =>
|
|
|
126
156
|
!channelHasReadEvents(channel) &&
|
|
127
157
|
!!channel?.getClient().options.isLocalUnreadCountEnabled;
|
|
128
158
|
|
|
129
|
-
/**
|
|
130
|
-
* userHasReadReceipts - Whether the current user allows read receipts, per their privacy settings.
|
|
131
|
-
* Read receipts are treated as enabled unless the user has explicitly disabled them.
|
|
132
|
-
*/
|
|
133
|
-
export const userHasReadReceipts = (client: StreamChat) =>
|
|
134
|
-
client.user?.privacy_settings?.read_receipts?.enabled ?? true;
|
|
135
|
-
|
|
136
159
|
export function addFileToFormData(
|
|
137
160
|
uri: string | NodeJS.ReadableStream | Buffer | File,
|
|
138
161
|
name?: string,
|