stream-chat 6.2.0 → 6.3.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/browser.es.js +526 -87
- package/dist/browser.es.js.map +1 -1
- package/dist/browser.full-bundle.min.js +1 -1
- package/dist/browser.full-bundle.min.js.map +1 -1
- package/dist/browser.js +526 -87
- package/dist/browser.js.map +1 -1
- package/dist/index.es.js +526 -87
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +526 -87
- package/dist/index.js.map +1 -1
- package/dist/types/channel.d.ts +6 -5
- package/dist/types/channel.d.ts.map +1 -1
- package/dist/types/channel_state.d.ts +36 -5
- package/dist/types/channel_state.d.ts.map +1 -1
- package/dist/types/client.d.ts +29 -1
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/types.d.ts +45 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/channel.ts +24 -16
- package/src/channel_state.ts +238 -49
- package/src/client.ts +45 -2
- package/src/types.ts +59 -0
package/src/channel_state.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
Event,
|
|
7
7
|
ExtendableGenerics,
|
|
8
8
|
DefaultGenerics,
|
|
9
|
+
MessageSetType,
|
|
9
10
|
MessageResponse,
|
|
10
11
|
ReactionResponse,
|
|
11
12
|
UserResponse,
|
|
@@ -24,7 +25,6 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
24
25
|
watcher_count: number;
|
|
25
26
|
typing: Record<string, Event<StreamChatGenerics>>;
|
|
26
27
|
read: ChannelReadStatus<StreamChatGenerics>;
|
|
27
|
-
messages: Array<ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>>;
|
|
28
28
|
pinnedMessages: Array<ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>>;
|
|
29
29
|
threads: Record<string, Array<ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>>>;
|
|
30
30
|
mutedUsers: Array<UserResponse<StreamChatGenerics>>;
|
|
@@ -40,12 +40,23 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
40
40
|
* be pushed on to message list.
|
|
41
41
|
*/
|
|
42
42
|
isUpToDate: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Disjoint lists of messages
|
|
45
|
+
* Users can jump in the message list (with searching) and this can result in disjoint lists of messages
|
|
46
|
+
* The state manages these lists and merges them when lists overlap
|
|
47
|
+
* The messages array contains the currently active set
|
|
48
|
+
*/
|
|
49
|
+
messageSets: {
|
|
50
|
+
isCurrent: boolean;
|
|
51
|
+
isLatest: boolean;
|
|
52
|
+
messages: Array<ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>>;
|
|
53
|
+
}[] = [];
|
|
43
54
|
constructor(channel: Channel<StreamChatGenerics>) {
|
|
44
55
|
this._channel = channel;
|
|
45
56
|
this.watcher_count = 0;
|
|
46
57
|
this.typing = {};
|
|
47
58
|
this.read = {};
|
|
48
|
-
this.
|
|
59
|
+
this.initMessages();
|
|
49
60
|
this.pinnedMessages = [];
|
|
50
61
|
this.threads = {};
|
|
51
62
|
// a list of users to hide messages from
|
|
@@ -64,20 +75,49 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
64
75
|
this.last_message_at = channel?.state?.last_message_at != null ? new Date(channel.state.last_message_at) : null;
|
|
65
76
|
}
|
|
66
77
|
|
|
78
|
+
get messages() {
|
|
79
|
+
return this.messageSets.find((s) => s.isCurrent)?.messages || [];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
set messages(messages: Array<ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>>) {
|
|
83
|
+
const index = this.messageSets.findIndex((s) => s.isCurrent);
|
|
84
|
+
this.messageSets[index].messages = messages;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The list of latest messages
|
|
89
|
+
* The messages array not always contains the latest messages (for example if a user searched for an earlier message, that is in a different message set)
|
|
90
|
+
*/
|
|
91
|
+
get latestMessages() {
|
|
92
|
+
return this.messageSets.find((s) => s.isLatest)?.messages || [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
set latestMessages(messages: Array<ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>>) {
|
|
96
|
+
const index = this.messageSets.findIndex((s) => s.isLatest);
|
|
97
|
+
this.messageSets[index].messages = messages;
|
|
98
|
+
}
|
|
99
|
+
|
|
67
100
|
/**
|
|
68
101
|
* addMessageSorted - Add a message to the state
|
|
69
102
|
*
|
|
70
103
|
* @param {MessageResponse<StreamChatGenerics>} newMessage A new message
|
|
71
104
|
* @param {boolean} timestampChanged Whether updating a message with changed created_at value.
|
|
72
105
|
* @param {boolean} addIfDoesNotExist Add message if it is not in the list, used to prevent out of order updated messages from being added.
|
|
73
|
-
*
|
|
106
|
+
* @param {MessageSetType} messageSetToAddToIfDoesNotExist Which message set to add to if message is not in the list (only used if addIfDoesNotExist is true)
|
|
74
107
|
*/
|
|
75
108
|
addMessageSorted(
|
|
76
109
|
newMessage: MessageResponse<StreamChatGenerics>,
|
|
77
110
|
timestampChanged = false,
|
|
78
111
|
addIfDoesNotExist = true,
|
|
112
|
+
messageSetToAddToIfDoesNotExist: MessageSetType = 'latest',
|
|
79
113
|
) {
|
|
80
|
-
return this.addMessagesSorted(
|
|
114
|
+
return this.addMessagesSorted(
|
|
115
|
+
[newMessage],
|
|
116
|
+
timestampChanged,
|
|
117
|
+
false,
|
|
118
|
+
addIfDoesNotExist,
|
|
119
|
+
messageSetToAddToIfDoesNotExist,
|
|
120
|
+
);
|
|
81
121
|
}
|
|
82
122
|
|
|
83
123
|
/**
|
|
@@ -109,6 +149,7 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
109
149
|
* @param {boolean} timestampChanged Whether updating messages with changed created_at value.
|
|
110
150
|
* @param {boolean} initializing Whether channel is being initialized.
|
|
111
151
|
* @param {boolean} addIfDoesNotExist Add message if it is not in the list, used to prevent out of order updated messages from being added.
|
|
152
|
+
* @param {MessageSetType} messageSetToAddToIfDoesNotExist Which message set to add to if messages are not in the list (only used if addIfDoesNotExist is true)
|
|
112
153
|
*
|
|
113
154
|
*/
|
|
114
155
|
addMessagesSorted(
|
|
@@ -116,46 +157,59 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
116
157
|
timestampChanged = false,
|
|
117
158
|
initializing = false,
|
|
118
159
|
addIfDoesNotExist = true,
|
|
160
|
+
messageSetToAddToIfDoesNotExist: MessageSetType = 'current',
|
|
119
161
|
) {
|
|
120
|
-
|
|
121
|
-
|
|
162
|
+
const { messagesToAdd, targetMessageSetIndex } = this.findTargetMessageSet(
|
|
163
|
+
newMessages,
|
|
164
|
+
addIfDoesNotExist,
|
|
165
|
+
messageSetToAddToIfDoesNotExist,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
for (let i = 0; i < messagesToAdd.length; i += 1) {
|
|
169
|
+
const isFromShadowBannedUser = messagesToAdd[i].shadowed;
|
|
122
170
|
if (isFromShadowBannedUser) {
|
|
123
171
|
continue;
|
|
124
172
|
}
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
173
|
+
const isMerging = messagesToAdd[i].created_at instanceof Date;
|
|
174
|
+
let message: ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>;
|
|
175
|
+
if (isMerging) {
|
|
176
|
+
message = messagesToAdd[i] as ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>;
|
|
177
|
+
} else {
|
|
178
|
+
message = this.formatMessage(messagesToAdd[i] as MessageResponse<StreamChatGenerics>);
|
|
179
|
+
|
|
180
|
+
if (message.user && this._channel?.cid) {
|
|
181
|
+
/**
|
|
182
|
+
* Store the reference to user for this channel, so that when we have to
|
|
183
|
+
* handle updates to user, we can use the reference map, to determine which
|
|
184
|
+
* channels need to be updated with updated user object.
|
|
185
|
+
*/
|
|
186
|
+
this._channel.getClient().state.updateUserReference(message.user, this._channel.cid);
|
|
187
|
+
}
|
|
135
188
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
189
|
+
if (initializing && message.id && this.threads[message.id]) {
|
|
190
|
+
// If we are initializing the state of channel (e.g., in case of connection recovery),
|
|
191
|
+
// then in that case we remove thread related to this message from threads object.
|
|
192
|
+
// This way we can ensure that we don't have any stale data in thread object
|
|
193
|
+
// and consumer can refetch the replies.
|
|
194
|
+
delete this.threads[message.id];
|
|
195
|
+
}
|
|
143
196
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
197
|
+
if (!this.last_message_at) {
|
|
198
|
+
this.last_message_at = new Date(message.created_at.getTime());
|
|
199
|
+
}
|
|
147
200
|
|
|
148
|
-
|
|
149
|
-
|
|
201
|
+
if (message.created_at.getTime() > this.last_message_at.getTime()) {
|
|
202
|
+
this.last_message_at = new Date(message.created_at.getTime());
|
|
203
|
+
}
|
|
150
204
|
}
|
|
151
205
|
|
|
152
206
|
// update or append the messages...
|
|
153
207
|
const parentID = message.parent_id;
|
|
154
208
|
|
|
155
|
-
// add to the
|
|
156
|
-
if (!parentID || message.show_in_channel) {
|
|
157
|
-
this.messages = this._addToMessageList(
|
|
158
|
-
this.messages,
|
|
209
|
+
// add to the given message set
|
|
210
|
+
if ((!parentID || message.show_in_channel) && targetMessageSetIndex !== -1) {
|
|
211
|
+
this.messageSets[targetMessageSetIndex].messages = this._addToMessageList(
|
|
212
|
+
this.messageSets[targetMessageSetIndex].messages,
|
|
159
213
|
message,
|
|
160
214
|
timestampChanged,
|
|
161
215
|
'created_at',
|
|
@@ -172,7 +226,7 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
172
226
|
* message is "oldest" message, and newer messages are therefore not loaded.
|
|
173
227
|
* This can also occur if an old thread message is updated.
|
|
174
228
|
*/
|
|
175
|
-
if (parentID && !initializing) {
|
|
229
|
+
if (parentID && !initializing && !isMerging) {
|
|
176
230
|
const thread = this.threads[parentID] || [];
|
|
177
231
|
const threadMessages = this._addToMessageList(
|
|
178
232
|
thread,
|
|
@@ -286,12 +340,14 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
286
340
|
updated_at: m.updated_at?.toString(),
|
|
287
341
|
} as unknown) as MessageResponse<StreamChatGenerics>);
|
|
288
342
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
343
|
+
this.messageSets.forEach((set) => {
|
|
344
|
+
const updatedMessages = set.messages
|
|
345
|
+
.filter((msg) => msg.quoted_message_id === message.id)
|
|
346
|
+
.map(parseMessage)
|
|
347
|
+
.map((msg) => ({ ...msg, quoted_message: { ...message, attachments: [] } }));
|
|
293
348
|
|
|
294
|
-
|
|
349
|
+
this.addMessagesSorted(updatedMessages, true);
|
|
350
|
+
});
|
|
295
351
|
}
|
|
296
352
|
|
|
297
353
|
/**
|
|
@@ -322,9 +378,14 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
322
378
|
}
|
|
323
379
|
|
|
324
380
|
if ((!show_in_channel && !parent_id) || show_in_channel) {
|
|
325
|
-
const
|
|
326
|
-
if (
|
|
327
|
-
|
|
381
|
+
const messageSetIndex = this.findMessageSetIndex(message);
|
|
382
|
+
if (messageSetIndex !== -1) {
|
|
383
|
+
const msgIndex = this.messageSets[messageSetIndex].messages.findIndex((msg) => msg.id === message.id);
|
|
384
|
+
if (msgIndex !== -1) {
|
|
385
|
+
this.messageSets[messageSetIndex].messages[msgIndex] = updateFunc(
|
|
386
|
+
this.messageSets[messageSetIndex].messages[msgIndex],
|
|
387
|
+
);
|
|
388
|
+
}
|
|
328
389
|
}
|
|
329
390
|
}
|
|
330
391
|
|
|
@@ -442,9 +503,15 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
442
503
|
this.threads[messageToRemove.parent_id] = threadMessages;
|
|
443
504
|
isRemoved = removed;
|
|
444
505
|
} else {
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
506
|
+
const messageSetIndex = this.findMessageSetIndex(messageToRemove);
|
|
507
|
+
if (messageSetIndex !== -1) {
|
|
508
|
+
const { removed, result: messages } = this.removeMessageFromArray(
|
|
509
|
+
this.messageSets[messageSetIndex].messages,
|
|
510
|
+
messageToRemove,
|
|
511
|
+
);
|
|
512
|
+
this.messageSets[messageSetIndex].messages = messages;
|
|
513
|
+
isRemoved = removed;
|
|
514
|
+
}
|
|
448
515
|
}
|
|
449
516
|
|
|
450
517
|
return isRemoved;
|
|
@@ -477,7 +544,7 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
477
544
|
}
|
|
478
545
|
};
|
|
479
546
|
|
|
480
|
-
_updateUserMessages(
|
|
547
|
+
this.messageSets.forEach((set) => _updateUserMessages(set.messages, user));
|
|
481
548
|
|
|
482
549
|
for (const parentId in this.threads) {
|
|
483
550
|
_updateUserMessages(this.threads[parentId], user);
|
|
@@ -535,7 +602,7 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
535
602
|
}
|
|
536
603
|
};
|
|
537
604
|
|
|
538
|
-
_deleteUserMessages(
|
|
605
|
+
this.messageSets.forEach((set) => _deleteUserMessages(set.messages, user, hardDelete));
|
|
539
606
|
|
|
540
607
|
for (const parentId in this.threads) {
|
|
541
608
|
_deleteUserMessages(this.threads[parentId], user, hardDelete);
|
|
@@ -549,9 +616,9 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
549
616
|
*
|
|
550
617
|
*/
|
|
551
618
|
filterErrorMessages() {
|
|
552
|
-
const filteredMessages = this.
|
|
619
|
+
const filteredMessages = this.latestMessages.filter((message) => message.type !== 'error');
|
|
553
620
|
|
|
554
|
-
this.
|
|
621
|
+
this.latestMessages = filteredMessages;
|
|
555
622
|
}
|
|
556
623
|
|
|
557
624
|
/**
|
|
@@ -577,7 +644,129 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
|
|
|
577
644
|
}
|
|
578
645
|
|
|
579
646
|
clearMessages() {
|
|
580
|
-
this.
|
|
647
|
+
this.initMessages();
|
|
581
648
|
this.pinnedMessages = [];
|
|
582
649
|
}
|
|
650
|
+
|
|
651
|
+
initMessages() {
|
|
652
|
+
this.messageSets = [{ messages: [], isLatest: true, isCurrent: true }];
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* loadMessageIntoState - Loads a given message (and messages around it) into the state
|
|
657
|
+
*
|
|
658
|
+
* @param {string} messageId The id of the message, or 'latest' to indicate switching to the latest messages
|
|
659
|
+
* @param {string} parentMessageId The id of the parent message, if we want load a thread reply
|
|
660
|
+
*/
|
|
661
|
+
async loadMessageIntoState(messageId: string | 'latest', parentMessageId?: string) {
|
|
662
|
+
let messageSetIndex: number;
|
|
663
|
+
let switchedToMessageSet = false;
|
|
664
|
+
let loadedMessageThread = false;
|
|
665
|
+
const messageIdToFind = parentMessageId || messageId;
|
|
666
|
+
if (messageId === 'latest') {
|
|
667
|
+
if (this.messages === this.latestMessages) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
messageSetIndex = this.messageSets.findIndex((s) => s.isLatest);
|
|
671
|
+
} else {
|
|
672
|
+
messageSetIndex = this.findMessageSetIndex({ id: messageIdToFind });
|
|
673
|
+
}
|
|
674
|
+
if (messageSetIndex !== -1) {
|
|
675
|
+
this.switchToMessageSet(messageSetIndex);
|
|
676
|
+
switchedToMessageSet = true;
|
|
677
|
+
}
|
|
678
|
+
loadedMessageThread = !parentMessageId || !!this.threads[parentMessageId]?.find((m) => m.id === messageId);
|
|
679
|
+
if (switchedToMessageSet && loadedMessageThread) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (!switchedToMessageSet) {
|
|
683
|
+
await this._channel.query({ messages: { id_around: messageIdToFind, limit: 25 } }, 'new');
|
|
684
|
+
}
|
|
685
|
+
if (!loadedMessageThread && parentMessageId) {
|
|
686
|
+
await this._channel.getReplies(parentMessageId, { id_around: messageId, limit: 25 });
|
|
687
|
+
}
|
|
688
|
+
messageSetIndex = this.findMessageSetIndex({ id: messageIdToFind });
|
|
689
|
+
if (messageSetIndex !== -1) {
|
|
690
|
+
this.switchToMessageSet(messageSetIndex);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
private switchToMessageSet(index: number) {
|
|
695
|
+
const currentMessages = this.messageSets.find((s) => s.isCurrent);
|
|
696
|
+
if (!currentMessages) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
currentMessages.isCurrent = false;
|
|
700
|
+
this.messageSets[index].isCurrent = true;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
private areMessageSetsOverlap(messages1: Array<{ id: string }>, messages2: Array<{ id: string }>) {
|
|
704
|
+
return messages1.some((m1) => messages2.find((m2) => m1.id === m2.id));
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
private findMessageSetIndex(message: { id?: string }) {
|
|
708
|
+
return this.messageSets.findIndex((set) => !!set.messages.find((m) => m.id === message.id));
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
private findTargetMessageSet(
|
|
712
|
+
newMessages: MessageResponse<StreamChatGenerics>[],
|
|
713
|
+
addIfDoesNotExist = true,
|
|
714
|
+
messageSetToAddToIfDoesNotExist: MessageSetType = 'current',
|
|
715
|
+
) {
|
|
716
|
+
let messagesToAdd: (
|
|
717
|
+
| MessageResponse<StreamChatGenerics>
|
|
718
|
+
| ReturnType<ChannelState<StreamChatGenerics>['formatMessage']>
|
|
719
|
+
)[] = newMessages;
|
|
720
|
+
let targetMessageSetIndex!: number;
|
|
721
|
+
if (addIfDoesNotExist) {
|
|
722
|
+
const overlappingMessageSetIndices = this.messageSets
|
|
723
|
+
.map((_, i) => i)
|
|
724
|
+
.filter((i) => this.areMessageSetsOverlap(this.messageSets[i].messages, newMessages));
|
|
725
|
+
switch (messageSetToAddToIfDoesNotExist) {
|
|
726
|
+
case 'new':
|
|
727
|
+
if (overlappingMessageSetIndices.length > 0) {
|
|
728
|
+
targetMessageSetIndex = overlappingMessageSetIndices[0];
|
|
729
|
+
// No new message set is created if newMessages only contains thread replies
|
|
730
|
+
} else if (newMessages.some((m) => !m.parent_id)) {
|
|
731
|
+
this.messageSets.push({ messages: [], isCurrent: false, isLatest: false });
|
|
732
|
+
targetMessageSetIndex = this.messageSets.length - 1;
|
|
733
|
+
}
|
|
734
|
+
break;
|
|
735
|
+
case 'current':
|
|
736
|
+
targetMessageSetIndex = this.messageSets.findIndex((s) => s.isCurrent);
|
|
737
|
+
break;
|
|
738
|
+
case 'latest':
|
|
739
|
+
targetMessageSetIndex = this.messageSets.findIndex((s) => s.isLatest);
|
|
740
|
+
break;
|
|
741
|
+
default:
|
|
742
|
+
targetMessageSetIndex = -1;
|
|
743
|
+
}
|
|
744
|
+
// when merging the target set will be the first one from the overlapping message sets
|
|
745
|
+
const mergeTargetMessageSetIndex = overlappingMessageSetIndices.splice(0, 1)[0];
|
|
746
|
+
const mergeSourceMessageSetIndices = [...overlappingMessageSetIndices];
|
|
747
|
+
if (mergeTargetMessageSetIndex !== undefined && mergeTargetMessageSetIndex !== targetMessageSetIndex) {
|
|
748
|
+
mergeSourceMessageSetIndices.push(targetMessageSetIndex);
|
|
749
|
+
}
|
|
750
|
+
// merge message sets
|
|
751
|
+
if (mergeSourceMessageSetIndices.length > 0) {
|
|
752
|
+
const target = this.messageSets[mergeTargetMessageSetIndex];
|
|
753
|
+
const sources = this.messageSets.filter((_, i) => mergeSourceMessageSetIndices.indexOf(i) !== -1);
|
|
754
|
+
sources.forEach((messageSet) => {
|
|
755
|
+
target.isLatest = target.isLatest || messageSet.isLatest;
|
|
756
|
+
target.isCurrent = target.isCurrent || messageSet.isCurrent;
|
|
757
|
+
messagesToAdd = [...messagesToAdd, ...messageSet.messages];
|
|
758
|
+
});
|
|
759
|
+
sources.forEach((s) => this.messageSets.splice(this.messageSets.indexOf(s), 1));
|
|
760
|
+
const overlappingMessageSetIndex = this.messageSets.findIndex((s) =>
|
|
761
|
+
this.areMessageSetsOverlap(s.messages, newMessages),
|
|
762
|
+
);
|
|
763
|
+
targetMessageSetIndex = overlappingMessageSetIndex;
|
|
764
|
+
}
|
|
765
|
+
} else {
|
|
766
|
+
// assumes that all new messages belong to the same set
|
|
767
|
+
targetMessageSetIndex = this.findMessageSetIndex(newMessages[0]);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return { targetMessageSetIndex, messagesToAdd };
|
|
771
|
+
}
|
|
583
772
|
}
|
package/src/client.ts
CHANGED
|
@@ -86,6 +86,10 @@ import {
|
|
|
86
86
|
PermissionAPIResponse,
|
|
87
87
|
PermissionsAPIResponse,
|
|
88
88
|
PushProvider,
|
|
89
|
+
PushProviderID,
|
|
90
|
+
PushProviderConfig,
|
|
91
|
+
PushProviderUpsertResponse,
|
|
92
|
+
PushProviderListResponse,
|
|
89
93
|
ReactionResponse,
|
|
90
94
|
SearchOptions,
|
|
91
95
|
SearchPayload,
|
|
@@ -1473,10 +1477,10 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
|
|
|
1473
1477
|
c.initialized = true;
|
|
1474
1478
|
|
|
1475
1479
|
if (skipInitialization === undefined) {
|
|
1476
|
-
c._initializeState(channelState);
|
|
1480
|
+
c._initializeState(channelState, 'latest');
|
|
1477
1481
|
} else if (!skipInitialization.includes(channelState.channel.id)) {
|
|
1478
1482
|
c.state.clearMessages();
|
|
1479
|
-
c._initializeState(channelState);
|
|
1483
|
+
c._initializeState(channelState, 'latest');
|
|
1480
1484
|
}
|
|
1481
1485
|
|
|
1482
1486
|
channels.push(c);
|
|
@@ -2900,4 +2904,43 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
|
|
|
2900
2904
|
async _listImports(options: ListImportsPaginationOptions) {
|
|
2901
2905
|
return await this.get<APIResponse & ListImportsResponse>(this.baseURL + `/imports`, options);
|
|
2902
2906
|
}
|
|
2907
|
+
|
|
2908
|
+
/**
|
|
2909
|
+
* upsertPushProvider - Create or Update a push provider
|
|
2910
|
+
*
|
|
2911
|
+
* Note: Works only for v2 push version is enabled on app settings.
|
|
2912
|
+
*
|
|
2913
|
+
* @param {PushProviderConfig} configuration of the provider you want to create or update
|
|
2914
|
+
*
|
|
2915
|
+
* @return {APIResponse & PushProviderUpsertResponse} A push provider
|
|
2916
|
+
*/
|
|
2917
|
+
async upsertPushProvider(pushProvider: PushProviderConfig) {
|
|
2918
|
+
return await this.post<APIResponse & PushProviderUpsertResponse>(this.baseURL + `/push_providers`, {
|
|
2919
|
+
push_provider: pushProvider,
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2923
|
+
/**
|
|
2924
|
+
* deletePushProvider - Delete a push provider
|
|
2925
|
+
*
|
|
2926
|
+
* Note: Works only for v2 push version is enabled on app settings.
|
|
2927
|
+
*
|
|
2928
|
+
* @param {PushProviderID} type and foreign id of the push provider to be deleted
|
|
2929
|
+
*
|
|
2930
|
+
* @return {APIResponse} An API response
|
|
2931
|
+
*/
|
|
2932
|
+
async deletePushProvider({ type, name }: PushProviderID) {
|
|
2933
|
+
return await this.delete<APIResponse>(this.baseURL + `/push_providers/${type}/${name}`);
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* listPushProviders - Get all push providers in the app
|
|
2938
|
+
*
|
|
2939
|
+
* Note: Works only for v2 push version is enabled on app settings.
|
|
2940
|
+
*
|
|
2941
|
+
* @return {APIResponse & PushProviderListResponse} A push provider
|
|
2942
|
+
*/
|
|
2943
|
+
async listPushProviders() {
|
|
2944
|
+
return await this.get<APIResponse & PushProviderListResponse>(this.baseURL + `/push_providers`);
|
|
2945
|
+
}
|
|
2903
2946
|
}
|
package/src/types.ts
CHANGED
|
@@ -120,6 +120,7 @@ export type AppSettingsAPIResponse<StreamChatGenerics extends ExtendableGenerics
|
|
|
120
120
|
apn?: APNConfig;
|
|
121
121
|
firebase?: FirebaseConfig;
|
|
122
122
|
huawei?: HuaweiConfig;
|
|
123
|
+
providers?: PushProviderConfig[];
|
|
123
124
|
xiaomi?: XiaomiConfig;
|
|
124
125
|
};
|
|
125
126
|
revoke_tokens_issued_before?: string | null;
|
|
@@ -1610,6 +1611,54 @@ export type CheckPushInput<StreamChatGenerics extends ExtendableGenerics = Defau
|
|
|
1610
1611
|
|
|
1611
1612
|
export type PushProvider = 'apn' | 'firebase' | 'huawei' | 'xiaomi';
|
|
1612
1613
|
|
|
1614
|
+
export type PushProviderConfig = PushProviderCommon &
|
|
1615
|
+
PushProviderAPN &
|
|
1616
|
+
PushProviderFirebase &
|
|
1617
|
+
PushProviderHuawei &
|
|
1618
|
+
PushProviderXiaomi;
|
|
1619
|
+
|
|
1620
|
+
export type PushProviderID = {
|
|
1621
|
+
name: string;
|
|
1622
|
+
type: PushProvider;
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
export type PushProviderCommon = {
|
|
1626
|
+
created_at: string;
|
|
1627
|
+
updated_at: string;
|
|
1628
|
+
description?: string;
|
|
1629
|
+
disabled_at?: string;
|
|
1630
|
+
disabled_reason?: string;
|
|
1631
|
+
};
|
|
1632
|
+
|
|
1633
|
+
export type PushProviderAPN = {
|
|
1634
|
+
apn_auth_key?: string;
|
|
1635
|
+
apn_auth_type?: 'token' | 'certificate';
|
|
1636
|
+
apn_development?: boolean;
|
|
1637
|
+
apn_host?: string;
|
|
1638
|
+
apn_key_id?: string;
|
|
1639
|
+
apn_notification_template?: string;
|
|
1640
|
+
apn_p12_cert?: string;
|
|
1641
|
+
apn_team_id?: string;
|
|
1642
|
+
apn_topic?: string;
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
export type PushProviderFirebase = {
|
|
1646
|
+
firebase_credentials?: string;
|
|
1647
|
+
firebase_data_template?: string;
|
|
1648
|
+
firebase_notification_template?: string;
|
|
1649
|
+
firebase_server_key?: string;
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
export type PushProviderHuawei = {
|
|
1653
|
+
huawei_app_id?: string;
|
|
1654
|
+
huawei_app_secret?: string;
|
|
1655
|
+
};
|
|
1656
|
+
|
|
1657
|
+
export type PushProviderXiaomi = {
|
|
1658
|
+
xiaomi_package_name?: string;
|
|
1659
|
+
xiaomi_secret?: string;
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1613
1662
|
export type CommandVariants<StreamChatGenerics extends ExtendableGenerics = DefaultGenerics> =
|
|
1614
1663
|
| 'all'
|
|
1615
1664
|
| 'ban'
|
|
@@ -2195,3 +2244,13 @@ export type ImportTask = {
|
|
|
2195
2244
|
result?: UR;
|
|
2196
2245
|
size?: number;
|
|
2197
2246
|
};
|
|
2247
|
+
|
|
2248
|
+
export type MessageSetType = 'latest' | 'current' | 'new';
|
|
2249
|
+
|
|
2250
|
+
export type PushProviderUpsertResponse = {
|
|
2251
|
+
push_provider: PushProvider;
|
|
2252
|
+
};
|
|
2253
|
+
|
|
2254
|
+
export type PushProviderListResponse = {
|
|
2255
|
+
push_providers: PushProvider[];
|
|
2256
|
+
};
|