stream-chat 9.25.0 → 9.26.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 +80 -19
- package/dist/cjs/index.browser.js.map +2 -2
- package/dist/cjs/index.node.js +86 -19
- package/dist/cjs/index.node.js.map +2 -2
- package/dist/esm/index.mjs +80 -19
- package/dist/esm/index.mjs.map +2 -2
- package/dist/types/channel.d.ts +18 -0
- package/dist/types/client.d.ts +10 -42
- package/dist/types/messageComposer/attachmentManager.d.ts +4 -2
- package/dist/types/messageComposer/middleware/index.d.ts +1 -0
- package/dist/types/messageDelivery/MessageDeliveryReporter.d.ts +5 -0
- package/dist/types/types.d.ts +54 -4
- package/package.json +5 -3
- package/src/channel.ts +41 -0
- package/src/channel_state.ts +9 -5
- package/src/client.ts +5 -10
- package/src/messageComposer/middleware/index.ts +1 -0
- package/src/messageDelivery/MessageDeliveryReporter.ts +55 -13
- package/src/types.ts +54 -5
- package/src/utils.ts +1 -0
|
@@ -3,16 +3,20 @@ import { Channel } from '../channel';
|
|
|
3
3
|
import type { ThreadUserReadState } from '../thread';
|
|
4
4
|
import { Thread } from '../thread';
|
|
5
5
|
import type {
|
|
6
|
+
ErrorFromResponse,
|
|
6
7
|
EventAPIResponse,
|
|
7
8
|
LocalMessage,
|
|
8
9
|
MarkDeliveredOptions,
|
|
9
10
|
MarkReadOptions,
|
|
10
11
|
} from '../types';
|
|
12
|
+
import { type APIErrorResponse } from '../types';
|
|
11
13
|
import { throttle } from '../utils';
|
|
14
|
+
import { isAPIError, isErrorRetryable } from '../errors';
|
|
12
15
|
|
|
13
16
|
const MAX_DELIVERED_MESSAGE_COUNT_IN_PAYLOAD = 100 as const;
|
|
14
17
|
const MARK_AS_DELIVERED_BUFFER_TIMEOUT = 1000 as const;
|
|
15
18
|
const MARK_AS_READ_THROTTLE_TIMEOUT = 1000 as const;
|
|
19
|
+
const RETRY_COUNT_LIMIT_FOR_TIMEOUT_INCREASE = 3 as const;
|
|
16
20
|
|
|
17
21
|
const isChannel = (item: Channel | Thread): item is Channel => item instanceof Channel;
|
|
18
22
|
const isThread = (item: Channel | Thread): item is Thread => item instanceof Thread;
|
|
@@ -40,6 +44,10 @@ export class MessageDeliveryReporter {
|
|
|
40
44
|
protected markDeliveredRequestPromise: Promise<EventAPIResponse | void> | null = null;
|
|
41
45
|
protected markDeliveredTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
42
46
|
|
|
47
|
+
protected requestTimeoutMs: number = MARK_AS_DELIVERED_BUFFER_TIMEOUT;
|
|
48
|
+
// increased up to RETRY_COUNT_LIMIT_FOR_TIMEOUT_INCREASE
|
|
49
|
+
protected requestRetryCount: number = 0;
|
|
50
|
+
|
|
43
51
|
constructor({ client }: MessageDeliveryReporterOptions) {
|
|
44
52
|
this.client = client;
|
|
45
53
|
}
|
|
@@ -47,18 +55,35 @@ export class MessageDeliveryReporter {
|
|
|
47
55
|
private get markDeliveredRequestInFlight() {
|
|
48
56
|
return this.markDeliveredRequestPromise !== null;
|
|
49
57
|
}
|
|
58
|
+
|
|
50
59
|
private get hasTimer() {
|
|
51
60
|
return this.markDeliveredTimeout !== null;
|
|
52
61
|
}
|
|
62
|
+
|
|
53
63
|
private get hasDeliveryCandidates() {
|
|
54
64
|
return this.deliveryReportCandidates.size > 0;
|
|
55
65
|
}
|
|
56
66
|
|
|
67
|
+
private get canExecuteRequest() {
|
|
68
|
+
return !this.markDeliveredRequestInFlight && this.hasDeliveryCandidates;
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
private static hasPermissionToReportDeliveryFor(collection: Channel | Thread) {
|
|
58
72
|
if (isChannel(collection)) return !!collection.getConfig()?.delivery_events;
|
|
59
73
|
if (isThread(collection)) return !!collection.channel.getConfig()?.delivery_events;
|
|
60
74
|
}
|
|
61
75
|
|
|
76
|
+
private increaseBackOff() {
|
|
77
|
+
if (this.requestRetryCount >= RETRY_COUNT_LIMIT_FOR_TIMEOUT_INCREASE) return;
|
|
78
|
+
this.requestRetryCount = this.requestRetryCount + 1;
|
|
79
|
+
this.requestTimeoutMs = this.requestTimeoutMs * 2;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private resetBackOff() {
|
|
83
|
+
this.requestTimeoutMs = MARK_AS_DELIVERED_BUFFER_TIMEOUT;
|
|
84
|
+
this.requestRetryCount = 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
62
87
|
/**
|
|
63
88
|
* Build latest_delivered_messages payload from an arbitrary buffer (deliveryReportCandidates / nextDeliveryReportCandidates)
|
|
64
89
|
*/
|
|
@@ -186,7 +211,7 @@ export class MessageDeliveryReporter {
|
|
|
186
211
|
* @param options
|
|
187
212
|
*/
|
|
188
213
|
public announceDelivery = (options?: AnnounceDeliveryOptions) => {
|
|
189
|
-
if (
|
|
214
|
+
if (!this.canExecuteRequest) return;
|
|
190
215
|
|
|
191
216
|
const { latest_delivered_messages, sendBuffer } =
|
|
192
217
|
this.confirmationsFromDeliveryReportCandidates();
|
|
@@ -194,7 +219,9 @@ export class MessageDeliveryReporter {
|
|
|
194
219
|
|
|
195
220
|
const payload = { ...options, latest_delivered_messages };
|
|
196
221
|
|
|
197
|
-
const postFlightReconcile = (
|
|
222
|
+
const postFlightReconcile = ({
|
|
223
|
+
preventSchedulingRetry,
|
|
224
|
+
}: { preventSchedulingRetry?: boolean } = {}) => {
|
|
198
225
|
this.markDeliveredRequestPromise = null;
|
|
199
226
|
|
|
200
227
|
// promote anything that arrived during request
|
|
@@ -203,32 +230,47 @@ export class MessageDeliveryReporter {
|
|
|
203
230
|
}
|
|
204
231
|
this.nextDeliveryReportCandidates = new Map();
|
|
205
232
|
|
|
233
|
+
if (preventSchedulingRetry) return;
|
|
206
234
|
// checks internally whether there are candidates to announce
|
|
207
235
|
this.announceDeliveryBuffered(options);
|
|
208
236
|
};
|
|
209
237
|
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
for (const [k, v] of Object.entries(sendBuffer)) {
|
|
213
|
-
if (!this.deliveryReportCandidates.has(k)) {
|
|
214
|
-
this.deliveryReportCandidates.set(k, v);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
238
|
+
const handleSuccess = () => {
|
|
239
|
+
this.resetBackOff();
|
|
217
240
|
postFlightReconcile();
|
|
218
241
|
};
|
|
219
242
|
|
|
243
|
+
const handleError = (error: ErrorFromResponse<APIErrorResponse> | Error) => {
|
|
244
|
+
// re-populate relevant candidates for the next report
|
|
245
|
+
// but make sure to keep the items that failed to be reported the first next time
|
|
246
|
+
const newDeliveryReportCandidates = new Map(sendBuffer);
|
|
247
|
+
for (const [k, v] of this.deliveryReportCandidates.entries()) {
|
|
248
|
+
newDeliveryReportCandidates.set(k, v);
|
|
249
|
+
}
|
|
250
|
+
this.deliveryReportCandidates = newDeliveryReportCandidates;
|
|
251
|
+
|
|
252
|
+
if (
|
|
253
|
+
(isAPIError(error) && isErrorRetryable(error)) ||
|
|
254
|
+
(error as ErrorFromResponse<APIErrorResponse>).status >= 500
|
|
255
|
+
) {
|
|
256
|
+
this.increaseBackOff();
|
|
257
|
+
postFlightReconcile();
|
|
258
|
+
} else {
|
|
259
|
+
postFlightReconcile({ preventSchedulingRetry: true });
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
220
263
|
this.markDeliveredRequestPromise = this.client
|
|
221
264
|
.markChannelsDelivered(payload)
|
|
222
|
-
.then(
|
|
265
|
+
.then(handleSuccess, handleError);
|
|
223
266
|
};
|
|
224
267
|
|
|
225
268
|
public announceDeliveryBuffered = (options?: AnnounceDeliveryOptions) => {
|
|
226
|
-
if (this.hasTimer ||
|
|
227
|
-
return;
|
|
269
|
+
if (this.hasTimer || !this.canExecuteRequest) return;
|
|
228
270
|
this.markDeliveredTimeout = setTimeout(() => {
|
|
229
271
|
this.markDeliveredTimeout = null;
|
|
230
272
|
this.announceDelivery(options);
|
|
231
|
-
},
|
|
273
|
+
}, this.requestTimeoutMs);
|
|
232
274
|
};
|
|
233
275
|
|
|
234
276
|
/**
|
package/src/types.ts
CHANGED
|
@@ -71,6 +71,7 @@ export type Unpacked<T> = T extends (infer U)[]
|
|
|
71
71
|
|
|
72
72
|
export type APIResponse = {
|
|
73
73
|
duration: string;
|
|
74
|
+
blocklist?: BlockListResponse;
|
|
74
75
|
};
|
|
75
76
|
|
|
76
77
|
export type TranslateResponse = {
|
|
@@ -80,6 +81,8 @@ export type TranslateResponse = {
|
|
|
80
81
|
|
|
81
82
|
export type AppSettingsAPIResponse = APIResponse & {
|
|
82
83
|
app?: {
|
|
84
|
+
id?: string | number;
|
|
85
|
+
allow_multi_user_devices?: boolean;
|
|
83
86
|
// TODO
|
|
84
87
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
88
|
call_types: any;
|
|
@@ -108,6 +111,9 @@ export type AppSettingsAPIResponse = APIResponse & {
|
|
|
108
111
|
read_events?: boolean;
|
|
109
112
|
replies?: boolean;
|
|
110
113
|
search?: boolean;
|
|
114
|
+
shared_locations?: boolean;
|
|
115
|
+
skip_last_msg_update_for_system_msgs?: boolean;
|
|
116
|
+
count_messages?: boolean;
|
|
111
117
|
typing_events?: boolean;
|
|
112
118
|
updated_at?: string;
|
|
113
119
|
uploads?: boolean;
|
|
@@ -140,12 +146,28 @@ export type AppSettingsAPIResponse = APIResponse & {
|
|
|
140
146
|
type: string;
|
|
141
147
|
}>;
|
|
142
148
|
grants?: Record<string, string[]>;
|
|
149
|
+
guest_user_creation_disabled?: boolean;
|
|
143
150
|
image_moderation_enabled?: boolean;
|
|
151
|
+
image_moderation_labels?: string[];
|
|
144
152
|
image_upload_config?: FileUploadConfig;
|
|
153
|
+
allowed_flag_reasons?: string[];
|
|
154
|
+
max_aggregated_activities_length?: number;
|
|
155
|
+
moderation_bulk_submit_action_enabled?: boolean;
|
|
156
|
+
moderation_dashboard_preferences?: Record<string, unknown> | null;
|
|
157
|
+
moderation_enabled?: boolean;
|
|
158
|
+
moderation_llm_configurability_enabled?: boolean;
|
|
159
|
+
moderation_multitenant_blocklist_enabled?: boolean;
|
|
160
|
+
moderation_webhook_url?: string;
|
|
145
161
|
multi_tenant_enabled?: boolean;
|
|
146
162
|
name?: string;
|
|
147
163
|
organization?: string;
|
|
148
164
|
permission_version?: string;
|
|
165
|
+
/**
|
|
166
|
+
* The placement of the app in the form of `${region}.${shard}`.
|
|
167
|
+
* Examples: "us-east.c1", "dublin.c3", "singapore.c2"
|
|
168
|
+
* Note: The backend may add/remove regions or shards occasionally.
|
|
169
|
+
*/
|
|
170
|
+
placement?: string;
|
|
149
171
|
policies?: Record<string, Policy[]>;
|
|
150
172
|
poll_enabled?: boolean;
|
|
151
173
|
push_notifications?: {
|
|
@@ -167,6 +189,8 @@ export type AppSettingsAPIResponse = APIResponse & {
|
|
|
167
189
|
sqs_url?: string;
|
|
168
190
|
suspended?: boolean;
|
|
169
191
|
suspended_explanation?: string;
|
|
192
|
+
use_hook_v2?: boolean;
|
|
193
|
+
user_response_time_enabled?: boolean;
|
|
170
194
|
user_search_disallowed_roles?: string[] | null;
|
|
171
195
|
video_provider?: string;
|
|
172
196
|
webhook_events?: Array<string>;
|
|
@@ -282,6 +306,7 @@ export type ChannelResponse = CustomChannelData & {
|
|
|
282
306
|
created_by?: UserResponse | null;
|
|
283
307
|
created_by_id?: string;
|
|
284
308
|
deleted_at?: string;
|
|
309
|
+
filter_tags?: string[];
|
|
285
310
|
hidden?: boolean;
|
|
286
311
|
invites?: string[];
|
|
287
312
|
joined?: boolean;
|
|
@@ -331,6 +356,7 @@ export type ChannelAPIResponse = {
|
|
|
331
356
|
|
|
332
357
|
export type ChannelUpdateOptions = {
|
|
333
358
|
hide_history?: boolean;
|
|
359
|
+
hide_history_before?: string | Date;
|
|
334
360
|
skip_push?: boolean;
|
|
335
361
|
};
|
|
336
362
|
|
|
@@ -786,6 +812,7 @@ export type OwnUserBase = {
|
|
|
786
812
|
privacy_settings?: PrivacySettings;
|
|
787
813
|
push_preferences?: PushPreference;
|
|
788
814
|
roles?: string[];
|
|
815
|
+
total_unread_count_by_team?: Record<string, number> | null;
|
|
789
816
|
};
|
|
790
817
|
|
|
791
818
|
export type OwnUserResponse = UserResponse & OwnUserBase;
|
|
@@ -882,10 +909,12 @@ export type UpdateMessageAPIResponse = APIResponse & {
|
|
|
882
909
|
|
|
883
910
|
export type UsersAPIResponse = APIResponse & {
|
|
884
911
|
users: Array<UserResponse>;
|
|
912
|
+
membership_deletion_task_id?: string;
|
|
885
913
|
};
|
|
886
914
|
|
|
887
915
|
export type UpdateUsersAPIResponse = APIResponse & {
|
|
888
916
|
users: { [key: string]: UserResponse };
|
|
917
|
+
membership_deletion_task_id?: string;
|
|
889
918
|
};
|
|
890
919
|
|
|
891
920
|
export type UserResponse = CustomUserData & {
|
|
@@ -908,7 +937,7 @@ export type UserResponse = CustomUserData & {
|
|
|
908
937
|
role?: string;
|
|
909
938
|
shadow_banned?: boolean;
|
|
910
939
|
teams?: string[];
|
|
911
|
-
teams_role?: TeamsRole;
|
|
940
|
+
teams_role?: TeamsRole | null;
|
|
912
941
|
updated_at?: string;
|
|
913
942
|
username?: string;
|
|
914
943
|
avg_response_time?: number;
|
|
@@ -1032,11 +1061,13 @@ export type CreateChannelOptions = {
|
|
|
1032
1061
|
reminders?: boolean;
|
|
1033
1062
|
replies?: boolean;
|
|
1034
1063
|
search?: boolean;
|
|
1064
|
+
shared_locations?: boolean;
|
|
1035
1065
|
skip_last_msg_update_for_system_msgs?: boolean;
|
|
1036
1066
|
typing_events?: boolean;
|
|
1037
1067
|
uploads?: boolean;
|
|
1038
1068
|
url_enrichment?: boolean;
|
|
1039
1069
|
user_message_reminders?: boolean;
|
|
1070
|
+
count_messages?: boolean;
|
|
1040
1071
|
};
|
|
1041
1072
|
|
|
1042
1073
|
export type CreateCommandOptions = {
|
|
@@ -1064,9 +1095,8 @@ export type DeactivateUsersOptions = {
|
|
|
1064
1095
|
export type NewMemberPayload = CustomMemberData &
|
|
1065
1096
|
Pick<ChannelMemberResponse, 'user_id' | 'channel_role'>;
|
|
1066
1097
|
|
|
1067
|
-
export type Thresholds =
|
|
1068
|
-
'explicit' | 'spam' | 'toxic',
|
|
1069
|
-
Partial<{ block: number; flag: number }>
|
|
1098
|
+
export type Thresholds = Partial<
|
|
1099
|
+
Record<'explicit' | 'spam' | 'toxic', Partial<{ block: number; flag: number }>>
|
|
1070
1100
|
>;
|
|
1071
1101
|
|
|
1072
1102
|
export type BlockListOptions = {
|
|
@@ -1170,6 +1200,7 @@ export type UpdateChannelTypeResponse = {
|
|
|
1170
1200
|
reminders: boolean;
|
|
1171
1201
|
replies: boolean;
|
|
1172
1202
|
search: boolean;
|
|
1203
|
+
shared_locations: boolean;
|
|
1173
1204
|
skip_last_msg_update_for_system_msgs: boolean;
|
|
1174
1205
|
typing_events: boolean;
|
|
1175
1206
|
updated_at: string;
|
|
@@ -1180,9 +1211,11 @@ export type UpdateChannelTypeResponse = {
|
|
|
1180
1211
|
blocklist?: string;
|
|
1181
1212
|
blocklist_behavior?: BlocklistBehavior;
|
|
1182
1213
|
blocklists?: BlockListOptions[];
|
|
1214
|
+
message_retention?: string;
|
|
1183
1215
|
partition_size?: number;
|
|
1184
1216
|
partition_ttl?: string;
|
|
1185
1217
|
count_messages?: boolean;
|
|
1218
|
+
user_message_reminders?: boolean;
|
|
1186
1219
|
};
|
|
1187
1220
|
|
|
1188
1221
|
export type GetChannelTypeResponse = {
|
|
@@ -1208,6 +1241,7 @@ export type GetChannelTypeResponse = {
|
|
|
1208
1241
|
reminders: boolean;
|
|
1209
1242
|
replies: boolean;
|
|
1210
1243
|
search: boolean;
|
|
1244
|
+
shared_locations: boolean;
|
|
1211
1245
|
skip_last_msg_update_for_system_msgs: boolean;
|
|
1212
1246
|
typing_events: boolean;
|
|
1213
1247
|
updated_at: string;
|
|
@@ -1218,9 +1252,11 @@ export type GetChannelTypeResponse = {
|
|
|
1218
1252
|
blocklist?: string;
|
|
1219
1253
|
blocklist_behavior?: BlocklistBehavior;
|
|
1220
1254
|
blocklists?: BlockListOptions[];
|
|
1255
|
+
message_retention?: string;
|
|
1221
1256
|
partition_size?: number;
|
|
1222
1257
|
partition_ttl?: string;
|
|
1223
1258
|
count_messages?: boolean;
|
|
1259
|
+
user_message_reminders?: boolean;
|
|
1224
1260
|
};
|
|
1225
1261
|
|
|
1226
1262
|
export type UpdateChannelOptions = Partial<{
|
|
@@ -1260,6 +1296,7 @@ export type MarkUnreadOptions = {
|
|
|
1260
1296
|
connection_id?: string;
|
|
1261
1297
|
message_id?: string;
|
|
1262
1298
|
thread_id?: string;
|
|
1299
|
+
message_timestamp?: string | Date;
|
|
1263
1300
|
user?: UserResponse;
|
|
1264
1301
|
user_id?: string;
|
|
1265
1302
|
};
|
|
@@ -1751,6 +1788,8 @@ export type ReactionFilters = QueryFilters<
|
|
|
1751
1788
|
|
|
1752
1789
|
export type ChannelFilters = QueryFilters<
|
|
1753
1790
|
ContainsOperator<Omit<CustomChannelData, 'name'>> & {
|
|
1791
|
+
app_banned?: 'only' | 'excluded';
|
|
1792
|
+
has_unread?: boolean;
|
|
1754
1793
|
archived?: boolean;
|
|
1755
1794
|
'member.user.name'?:
|
|
1756
1795
|
| RequireOnlyOne<{
|
|
@@ -2044,7 +2083,7 @@ export type UserFilters = QueryFilters<
|
|
|
2044
2083
|
}
|
|
2045
2084
|
>;
|
|
2046
2085
|
|
|
2047
|
-
export type InviteStatus = 'pending' | 'accepted' | 'rejected';
|
|
2086
|
+
export type InviteStatus = 'pending' | 'accepted' | 'rejected' | 'member';
|
|
2048
2087
|
|
|
2049
2088
|
// https://getstream.io/chat/docs/react/channel_member/#update-channel-members
|
|
2050
2089
|
export type MemberFilters = QueryFilters<
|
|
@@ -2368,6 +2407,8 @@ export type BlockList = {
|
|
|
2368
2407
|
team?: string;
|
|
2369
2408
|
type?: string;
|
|
2370
2409
|
validate?: boolean;
|
|
2410
|
+
is_leet_check_enabled?: boolean;
|
|
2411
|
+
is_plural_check_enabled?: boolean;
|
|
2371
2412
|
};
|
|
2372
2413
|
|
|
2373
2414
|
export type ChannelConfig = ChannelConfigFields &
|
|
@@ -2403,6 +2444,7 @@ export type ChannelConfigFields = {
|
|
|
2403
2444
|
replies?: boolean;
|
|
2404
2445
|
search?: boolean;
|
|
2405
2446
|
shared_locations?: boolean;
|
|
2447
|
+
skip_last_msg_update_for_system_msgs?: boolean;
|
|
2406
2448
|
count_messages?: boolean;
|
|
2407
2449
|
typing_events?: boolean;
|
|
2408
2450
|
uploads?: boolean;
|
|
@@ -2423,6 +2465,7 @@ export type ChannelData = CustomChannelData &
|
|
|
2423
2465
|
members: string[] | Array<NewMemberPayload>;
|
|
2424
2466
|
blocklist_behavior: AutomodBehavior;
|
|
2425
2467
|
automod: Automod;
|
|
2468
|
+
filter_tags: string[];
|
|
2426
2469
|
}>;
|
|
2427
2470
|
|
|
2428
2471
|
export type ChannelMute = {
|
|
@@ -3153,6 +3196,11 @@ export type CampaignData = {
|
|
|
3153
3196
|
custom?: {};
|
|
3154
3197
|
id?: string;
|
|
3155
3198
|
members?: string[];
|
|
3199
|
+
members_template?: Array<{
|
|
3200
|
+
user_id: string;
|
|
3201
|
+
channel_role?: string;
|
|
3202
|
+
custom?: Record<string, unknown>;
|
|
3203
|
+
}>;
|
|
3156
3204
|
team?: string;
|
|
3157
3205
|
};
|
|
3158
3206
|
create_channels?: boolean;
|
|
@@ -4435,6 +4483,7 @@ export type EventHook = {
|
|
|
4435
4483
|
sns_key?: string;
|
|
4436
4484
|
sns_secret?: string;
|
|
4437
4485
|
sns_role_arn?: string;
|
|
4486
|
+
should_send_custom_events?: boolean;
|
|
4438
4487
|
|
|
4439
4488
|
// pending message config
|
|
4440
4489
|
timeout_ms?: number;
|
package/src/utils.ts
CHANGED