polfan-server-js-client 0.2.92 → 0.2.94
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/.idea/workspace.xml +70 -48
- package/build/index.cjs.js +234 -131
- package/build/index.cjs.js.map +1 -1
- package/build/index.umd.js +1 -1
- package/build/index.umd.js.map +1 -1
- package/build/types/AbstractChatClient.d.ts +2 -3
- package/build/types/state-tracker/MessagesManager.d.ts +13 -5
- package/build/types/state-tracker/TopicHistoryWindow.d.ts +4 -0
- package/build/types/types/src/index.d.ts +3 -4
- package/build/types/types/src/schemes/FollowedTopic.d.ts +4 -0
- package/build/types/types/src/schemes/commands/GetMessages.d.ts +1 -0
- package/build/types/types/src/schemes/commands/UpdateFollowedTopic.d.ts +6 -0
- package/package.json +1 -1
- package/src/AbstractChatClient.ts +2 -4
- package/src/state-tracker/MessagesManager.ts +141 -22
- package/src/state-tracker/TopicHistoryWindow.ts +50 -1
- package/src/types/src/index.ts +4 -5
- package/src/types/src/schemes/FollowedTopic.ts +5 -0
- package/src/types/src/schemes/commands/GetMessages.ts +1 -0
- package/src/types/src/schemes/commands/UpdateFollowedTopic.ts +7 -0
- package/tests/history-window.test.ts +84 -1
- package/tsconfig.json +16 -16
- package/src/types/src/schemes/commands/UnfollowTopic.ts +0 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bye, GetSession, JoinSpace, Session, SpaceJoined, Error as ErrorType, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMemberUpdated, SpaceDeleted, SpaceMembers, SpaceRooms, NewRole, RoomDeleted, RoomJoined, RoomLeft, RoomMemberLeft, RoomMemberJoined, RoomMembers, NewRoom, NewTopic, TopicDeleted, NewMessage, GetPermissionOverwrites, GetComputedPermissions, LeaveSpace, CreateSpace, DeleteSpace, GetSpaceMembers, GetSpaceRooms, CreateRole, DeleteRole, AssignRole, DeassignRole, SetPermissionOverwrites, JoinRoom, LeaveRoom, CreateRoom, DeleteRoom, GetRoomMembers, CreateTopic, DeleteTopic, CreateMessage, Envelope, PermissionOverwrites, PermissionOverwritesUpdated, RoomMemberUpdated, UpdateRole, RoleUpdated, Ack, UserUpdated, UpdateRoom, RoomUpdated, UpdateSpace, SpaceUpdated, PermissionOverwriteTargets, GetPermissionOverwriteTargets, Owners, Ok, GetOwners, CreateOwner, RoleDeleted, FollowedTopicUpdated, TopicFollowed,
|
|
1
|
+
import { Bye, GetSession, JoinSpace, Session, SpaceJoined, Error as ErrorType, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMemberUpdated, SpaceDeleted, SpaceMembers, SpaceRooms, NewRole, RoomDeleted, RoomJoined, RoomLeft, RoomMemberLeft, RoomMemberJoined, RoomMembers, NewRoom, NewTopic, TopicDeleted, NewMessage, GetPermissionOverwrites, GetComputedPermissions, LeaveSpace, CreateSpace, DeleteSpace, GetSpaceMembers, GetSpaceRooms, CreateRole, DeleteRole, AssignRole, DeassignRole, SetPermissionOverwrites, JoinRoom, LeaveRoom, CreateRoom, DeleteRoom, GetRoomMembers, CreateTopic, DeleteTopic, CreateMessage, Envelope, PermissionOverwrites, PermissionOverwritesUpdated, RoomMemberUpdated, UpdateRole, RoleUpdated, Ack, UserUpdated, UpdateRoom, RoomUpdated, UpdateSpace, SpaceUpdated, PermissionOverwriteTargets, GetPermissionOverwriteTargets, Owners, Ok, GetOwners, CreateOwner, RoleDeleted, FollowedTopicUpdated, TopicFollowed, FollowedTopics, FollowTopic, UpdateFollowedTopic, GetFollowedTopics, Messages, GetMessages, Topics, GetTopics, TopicUpdated, UpdateTopic, GetDiscoverableSpaces, DiscoverableSpaces, CreateEmoticon, DeleteEmoticon, GetEmoticons, Emoticons, EmoticonDeleted, NewEmoticon, Bans, GetBans, Ban, Unban, Kick, ClientData, GetClientData, SetClientData, GetRoomSummary, GetSpaceSummary, RoomSummaryEvent, SpaceSummaryEvent, UpdateSpaceMember, Relationships, RelationshipDeleted, NewRelationship, DeleteRelationship, CreateRelationship, RoomSummaryUpdated, Pong, Ping, RedactMessages, MessagesRedacted, ReportAbuse, UpdateRoomMember, GetRelationships, GetUserInfo, UserInfo } from "./types/src";
|
|
2
2
|
import { EventTarget } from "./EventTarget";
|
|
3
3
|
type ArrayOfPromiseResolvers = [(value: any) => void, (reason?: any) => void];
|
|
4
4
|
type ExtraEventMap = Record<string, any>;
|
|
@@ -74,7 +74,6 @@ export type EventsMap = {
|
|
|
74
74
|
NewMessage: NewMessage;
|
|
75
75
|
UserUpdated: UserUpdated;
|
|
76
76
|
TopicFollowed: TopicFollowed;
|
|
77
|
-
TopicUnfollowed: TopicUnfollowed;
|
|
78
77
|
FollowedTopics: FollowedTopics;
|
|
79
78
|
FollowedTopicUpdated: FollowedTopicUpdated;
|
|
80
79
|
Messages: Messages;
|
|
@@ -137,7 +136,7 @@ export type CommandsMap = {
|
|
|
137
136
|
CreateMessage: CommandDefinition<CreateMessage, EventsMap['NewMessage']>;
|
|
138
137
|
Ack: CommandDefinition<Ack, EventsMap['FollowedTopicUpdated'] | EventsMap['Ok']>;
|
|
139
138
|
FollowTopic: CommandDefinition<FollowTopic, EventsMap['TopicFollowed']>;
|
|
140
|
-
|
|
139
|
+
UpdateFollowedTopic: CommandDefinition<UpdateFollowedTopic, EventsMap['FollowedTopicUpdated']>;
|
|
141
140
|
GetFollowedTopics: CommandDefinition<GetFollowedTopics, EventsMap['FollowedTopics']>;
|
|
142
141
|
GetMessages: CommandDefinition<GetMessages, EventsMap['Messages']>;
|
|
143
142
|
GetTopics: CommandDefinition<GetTopics, EventsMap['Topics']>;
|
|
@@ -8,6 +8,7 @@ export declare class MessagesManager {
|
|
|
8
8
|
private readonly followedTopics;
|
|
9
9
|
private readonly followedTopicsPromises;
|
|
10
10
|
private readonly deferredSession;
|
|
11
|
+
private readonly unreadSummariesCache;
|
|
11
12
|
constructor(tracker: ChatStateTracker);
|
|
12
13
|
/**
|
|
13
14
|
* Get history manager for given room ID.
|
|
@@ -25,14 +26,17 @@ export declare class MessagesManager {
|
|
|
25
26
|
*/
|
|
26
27
|
getRoomFollowedTopics(roomId: string): Promise<ObservableIndexedObjectCollection<FollowedTopic> | undefined>;
|
|
27
28
|
/**
|
|
28
|
-
* Batch acknowledge all
|
|
29
|
+
* Batch acknowledge all messages for given room.
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
+
ackRoom(roomId: string): Promise<void>;
|
|
31
32
|
/**
|
|
32
|
-
* Calculate missed messages from any topic in given room.
|
|
33
|
+
* Calculate missed messages with mentions from any topic in given room.
|
|
33
34
|
* @return Undefined if you are not in room.
|
|
34
35
|
*/
|
|
35
|
-
|
|
36
|
+
summarizeUnreadMessages(location: ChatLocation): Promise<{
|
|
37
|
+
mentionCount: number;
|
|
38
|
+
isUnread: boolean;
|
|
39
|
+
}>;
|
|
36
40
|
/**
|
|
37
41
|
* For internal use. If you want to delete the message, execute a proper command on client object.
|
|
38
42
|
* @internal
|
|
@@ -43,11 +47,15 @@ export declare class MessagesManager {
|
|
|
43
47
|
* @internal
|
|
44
48
|
*/
|
|
45
49
|
_resolveLastMessage(location: ChatLocation): Promise<Message | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Wyczyść cache celowo, tylko dla lokalizacji których dotyczy zmiana.
|
|
52
|
+
*/
|
|
53
|
+
private invalidateUnreadSummaries;
|
|
54
|
+
private invalidateUnreadSummariesForRooms;
|
|
46
55
|
private createHistoryForNewRoom;
|
|
47
56
|
private handleNewMessage;
|
|
48
57
|
private handleFollowedTopicUpdated;
|
|
49
58
|
private handleTopicFollowed;
|
|
50
|
-
private handleTopicUnfollowed;
|
|
51
59
|
private handleRoomDeleted;
|
|
52
60
|
private handleRoomJoin;
|
|
53
61
|
private handleRoomLeft;
|
|
@@ -67,9 +67,11 @@ export declare abstract class TraversableRemoteCollection<ItemT, EventMapT exten
|
|
|
67
67
|
resetToLatest(): Promise<void>;
|
|
68
68
|
fetchPrevious(): Promise<void>;
|
|
69
69
|
fetchNext(): Promise<void>;
|
|
70
|
+
jumpTo(id: string): Promise<void>;
|
|
70
71
|
protected abstract fetchLatestItems(): Promise<ItemT[]>;
|
|
71
72
|
protected abstract fetchItemsBefore(): Promise<ItemT[] | null>;
|
|
72
73
|
protected abstract fetchItemsAfter(): Promise<ItemT[] | null>;
|
|
74
|
+
protected abstract fetchItemsAround(id: string): Promise<ItemT[] | null>;
|
|
73
75
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
74
76
|
protected refreshFetchedState(): Promise<void>;
|
|
75
77
|
protected addItems(newItems: ItemT[], to: 'head' | 'tail'): void;
|
|
@@ -100,12 +102,14 @@ export declare class TopicHistoryWindow extends TraversableRemoteCollection<Mess
|
|
|
100
102
|
resetToLatest(): Promise<void>;
|
|
101
103
|
fetchNext(): Promise<void>;
|
|
102
104
|
fetchPrevious(): Promise<void>;
|
|
105
|
+
jumpTo(id: string): Promise<void>;
|
|
103
106
|
/**
|
|
104
107
|
* For internal use.
|
|
105
108
|
* @internal
|
|
106
109
|
*/
|
|
107
110
|
_updateMessageReference(refTopic: Topic): void;
|
|
108
111
|
protected fetchItemsAfter(): Promise<Message[] | null>;
|
|
112
|
+
protected fetchItemsAround(id: string): Promise<Message[] | null>;
|
|
109
113
|
protected fetchItemsBefore(): Promise<Message[] | null>;
|
|
110
114
|
protected fetchLatestItems(): Promise<Message[]>;
|
|
111
115
|
private getTopic;
|
|
@@ -77,9 +77,8 @@ import { Owners } from "./schemes/events/Owners";
|
|
|
77
77
|
import { Ok } from "./schemes/events/Ok";
|
|
78
78
|
import { FollowTopic } from "./schemes/commands/FollowTopic";
|
|
79
79
|
import { FollowedTopics } from "./schemes/events/FollowedTopics";
|
|
80
|
-
import { FollowedTopic } from "./schemes/FollowedTopic";
|
|
81
|
-
import {
|
|
82
|
-
import { TopicUnfollowed } from "./schemes/events/TopicUnfollowed";
|
|
80
|
+
import { FollowedTopic, NotificationLevel } from "./schemes/FollowedTopic";
|
|
81
|
+
import { UpdateFollowedTopic } from "./schemes/commands/UpdateFollowedTopic";
|
|
83
82
|
import { TopicFollowed } from "./schemes/events/TopicFollowed";
|
|
84
83
|
import { GetFollowedTopics } from "./schemes/commands/GetFollowedTopics";
|
|
85
84
|
import { FollowedTopicUpdated } from "./schemes/events/FollowedTopicUpdated";
|
|
@@ -134,4 +133,4 @@ import { GetRelationships } from "./schemes/commands/GetRelationships";
|
|
|
134
133
|
import { GetUserInfo } from "./schemes/commands/GetUserInfo";
|
|
135
134
|
import { UserInfo } from "./schemes/events/UserInfo";
|
|
136
135
|
import { UserInformation } from "./schemes/UserInformation";
|
|
137
|
-
export { Envelope, Message, MessageType, MessageAuthor, Role, Room, RoomType, RoomStream, RoomStreamType, RoomHistory, RoomHistoryMode, RoomMember, RoomSummary, RoomSummaryExtras, Space, SpaceMember, Topic, FollowedTopic, User, UserState, PermissionOverwritesValue, ChatLocation, SpaceSummary, SpaceDiscoverable, Emoticon, PermissionOverwritesTarget, BanObject, LeaveReason, UserRelationship, UserRelationshipType, CreateTopicInitialMessage, UserInformation, Bye, Error, Messages, NewMessage, NewRole, NewRoom, NewTopic, TopicFollowed,
|
|
136
|
+
export { Envelope, Message, MessageType, MessageAuthor, Role, Room, RoomType, RoomStream, RoomStreamType, RoomHistory, RoomHistoryMode, RoomMember, RoomSummary, RoomSummaryExtras, Space, SpaceMember, Topic, FollowedTopic, NotificationLevel, User, UserState, PermissionOverwritesValue, ChatLocation, SpaceSummary, SpaceDiscoverable, Emoticon, PermissionOverwritesTarget, BanObject, LeaveReason, UserRelationship, UserRelationshipType, CreateTopicInitialMessage, UserInformation, Bye, Error, Messages, NewMessage, NewRole, NewRoom, NewTopic, TopicFollowed, FollowedTopics, FollowedTopicUpdated, ComputedPermissions, PermissionOverwrites, PermissionOverwritesUpdated, RoleDeleted, RoleUpdated, RoomDeleted, RoomUpdated, RoomJoined, RoomLeft, RoomMemberJoined, RoomMemberLeft, RoomMembers, RoomMemberUpdated, UserUpdated, Session, SpaceDeleted, SpaceUpdated, SpaceJoined, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMembers, SpaceMemberUpdated, SpaceRooms, TopicDeleted, TopicUpdated, PermissionOverwriteTargets, Owners, Ok, DiscoverableSpaces, Emoticons, EmoticonDeleted, NewEmoticon, Bans, ClientData, SpaceSummaryEvent, RoomSummaryEvent, NewRelationship, RelationshipDeleted, Relationships, RoomSummaryUpdated, Pong, MessagesRedacted, UserInfo, AssignRole, GetMessages, CreateMessage, Ack, CreateRole, CreateRoom, CreateSpace, CreateTopic, FollowTopic, UpdateFollowedTopic, GetFollowedTopics, DeassignRole, DeleteRole, DeleteRoom, DeleteSpace, DeleteTopic, SetPermissionOverwrites, GetPermissionOverwrites, GetComputedPermissions, GetRoomMembers, GetSession, GetSpaceMembers, GetSpaceRooms, JoinRoom, JoinSpace, LeaveRoom, LeaveSpace, UpdateRole, UpdateSpace, UpdateRoom, UpdateTopic, GetPermissionOverwriteTargets, CreateOwner, DeleteOwner, GetOwners, Topics, GetTopics, GetDiscoverableSpaces, GetEmoticons, CreateEmoticon, DeleteEmoticon, Ban, Unban, GetBans, Kick, GetClientData, SetClientData, GetSpaceSummary, GetRoomSummary, UpdateSpaceMember, CreateRelationship, DeleteRelationship, GetRelationships, UpdateRoomMember, Ping, ReportAbuse, RedactMessages, GetUserInfo, };
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ChatLocation } from "./ChatLocation";
|
|
2
|
+
export type NotificationLevel = 'All' | 'Mentions' | 'None';
|
|
2
3
|
export interface FollowedTopic {
|
|
3
4
|
location: ChatLocation;
|
|
4
5
|
lastAckMessageId: string | null;
|
|
6
|
+
notificationLevel: NotificationLevel;
|
|
5
7
|
missed: number | null;
|
|
8
|
+
isUnread: boolean;
|
|
9
|
+
mentionCount: number;
|
|
6
10
|
}
|
package/package.json
CHANGED
|
@@ -64,10 +64,9 @@ import {
|
|
|
64
64
|
RoleDeleted,
|
|
65
65
|
FollowedTopicUpdated,
|
|
66
66
|
TopicFollowed,
|
|
67
|
-
TopicUnfollowed,
|
|
68
67
|
FollowedTopics,
|
|
69
68
|
FollowTopic,
|
|
70
|
-
|
|
69
|
+
UpdateFollowedTopic,
|
|
71
70
|
GetFollowedTopics,
|
|
72
71
|
Messages,
|
|
73
72
|
GetMessages,
|
|
@@ -224,7 +223,6 @@ export type CommandResponse<CommandType extends keyof CommandsMap> = CommandsMap
|
|
|
224
223
|
NewMessage: NewMessage,
|
|
225
224
|
UserUpdated: UserUpdated,
|
|
226
225
|
TopicFollowed: TopicFollowed,
|
|
227
|
-
TopicUnfollowed: TopicUnfollowed,
|
|
228
226
|
FollowedTopics: FollowedTopics,
|
|
229
227
|
FollowedTopicUpdated: FollowedTopicUpdated,
|
|
230
228
|
Messages: Messages,
|
|
@@ -292,7 +290,7 @@ export type CommandsMap = {
|
|
|
292
290
|
CreateMessage: CommandDefinition<CreateMessage, EventsMap['NewMessage']>,
|
|
293
291
|
Ack: CommandDefinition<Ack, EventsMap['FollowedTopicUpdated'] | EventsMap['Ok']>,
|
|
294
292
|
FollowTopic: CommandDefinition<FollowTopic, EventsMap['TopicFollowed']>,
|
|
295
|
-
|
|
293
|
+
UpdateFollowedTopic: CommandDefinition<UpdateFollowedTopic, EventsMap['FollowedTopicUpdated']>,
|
|
296
294
|
GetFollowedTopics: CommandDefinition<GetFollowedTopics, EventsMap['FollowedTopics']>,
|
|
297
295
|
GetMessages: CommandDefinition<GetMessages, EventsMap['Messages']>,
|
|
298
296
|
GetTopics: CommandDefinition<GetTopics, EventsMap['Topics']>,
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
NewMessage,
|
|
4
4
|
FollowedTopic,
|
|
5
5
|
TopicFollowed,
|
|
6
|
-
TopicUnfollowed,
|
|
7
6
|
RoomDeleted,
|
|
8
7
|
RoomLeft,
|
|
9
8
|
TopicDeleted,
|
|
@@ -26,6 +25,7 @@ export class MessagesManager {
|
|
|
26
25
|
private readonly followedTopics = new IndexedCollection<string, ObservableIndexedObjectCollection<FollowedTopic>>();
|
|
27
26
|
private readonly followedTopicsPromises = new PromiseRegistry();
|
|
28
27
|
private readonly deferredSession = new DeferredTask();
|
|
28
|
+
private readonly unreadSummariesCache = new Map<string, { mentionCount: number, isUnread: boolean }>();
|
|
29
29
|
|
|
30
30
|
public constructor(private tracker: ChatStateTracker) {
|
|
31
31
|
this.tracker.client.on('Session', ev => this.handleSession(ev));
|
|
@@ -33,7 +33,6 @@ export class MessagesManager {
|
|
|
33
33
|
this.tracker.client.on('NewTopic', ev => this.handleNewTopic(ev));
|
|
34
34
|
this.tracker.client.on('FollowedTopicUpdated', ev => this.handleFollowedTopicUpdated(ev));
|
|
35
35
|
this.tracker.client.on('TopicFollowed', ev => this.handleTopicFollowed(ev));
|
|
36
|
-
this.tracker.client.on('TopicUnfollowed', ev => this.handleTopicUnfollowed(ev));
|
|
37
36
|
this.tracker.client.on('NewMessage', ev => this.handleNewMessage(ev));
|
|
38
37
|
this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
|
|
39
38
|
this.tracker.client.on('RoomLeft', ev => this.handleRoomLeft(ev));
|
|
@@ -107,9 +106,9 @@ export class MessagesManager {
|
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
/**
|
|
110
|
-
* Batch acknowledge all
|
|
109
|
+
* Batch acknowledge all messages for given room.
|
|
111
110
|
*/
|
|
112
|
-
public async
|
|
111
|
+
public async ackRoom(roomId: string): Promise<void> {
|
|
113
112
|
const collection = await this.getRoomFollowedTopics(roomId);
|
|
114
113
|
|
|
115
114
|
if (! collection) {
|
|
@@ -117,27 +116,75 @@ export class MessagesManager {
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
for (const followedTopic of collection.items) {
|
|
120
|
-
if (followedTopic.
|
|
119
|
+
if (followedTopic.isUnread) {
|
|
121
120
|
await this.tracker.client.send('Ack', {location: followedTopic.location});
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
/**
|
|
127
|
-
* Calculate missed messages from any topic in given room.
|
|
126
|
+
* Calculate missed messages with mentions from any topic in given room.
|
|
128
127
|
* @return Undefined if you are not in room.
|
|
129
128
|
*/
|
|
130
|
-
public async
|
|
131
|
-
const
|
|
129
|
+
public async summarizeUnreadMessages(location: ChatLocation): Promise<{ mentionCount: number, isUnread: boolean }> {
|
|
130
|
+
const cacheKey = location.topicId
|
|
131
|
+
? `topic:${location.roomId}:${location.topicId}`
|
|
132
|
+
: location.roomId
|
|
133
|
+
? `room:${location.roomId}`
|
|
134
|
+
: location.spaceId
|
|
135
|
+
? `space:${location.spaceId}`
|
|
136
|
+
: 'spaceless';
|
|
137
|
+
|
|
138
|
+
if (this.unreadSummariesCache.has(cacheKey)) {
|
|
139
|
+
return this.unreadSummariesCache.get(cacheKey)!;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let roomIds: string[] = [];
|
|
143
|
+
let targetTopicId: string | undefined;
|
|
144
|
+
const rooms = await this.tracker.rooms.get();
|
|
132
145
|
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
146
|
+
if (location.topicId) {
|
|
147
|
+
if (!location.roomId) {
|
|
148
|
+
throw new Error("roomId is required when querying by topicId");
|
|
149
|
+
}
|
|
150
|
+
roomIds = [location.roomId];
|
|
151
|
+
targetTopicId = location.topicId;
|
|
152
|
+
} else if (location.roomId) {
|
|
153
|
+
roomIds = [location.roomId];
|
|
154
|
+
} else if (location.spaceId) {
|
|
155
|
+
await this.cacheSpaceFollowedTopics(location.spaceId);
|
|
156
|
+
roomIds = rooms.findBy('spaceId', location.spaceId).items.map(r => r.id);
|
|
157
|
+
} else {
|
|
158
|
+
roomIds = rooms.items.filter(r => !r.spaceId).map(r => r.id);
|
|
138
159
|
}
|
|
139
160
|
|
|
140
|
-
|
|
161
|
+
let mentionCount = 0;
|
|
162
|
+
let isUnread = false;
|
|
163
|
+
|
|
164
|
+
for (const roomId of roomIds) {
|
|
165
|
+
const collection = await this.getRoomFollowedTopics(roomId);
|
|
166
|
+
|
|
167
|
+
if (!collection) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const topic of collection.items) {
|
|
172
|
+
if (targetTopicId && topic.location.topicId !== targetTopicId) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (topic.isUnread) {
|
|
177
|
+
isUnread = true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
mentionCount += (topic.mentionCount ?? 0);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const result = { mentionCount, isUnread };
|
|
185
|
+
this.unreadSummariesCache.set(cacheKey, result);
|
|
186
|
+
|
|
187
|
+
return result;
|
|
141
188
|
}
|
|
142
189
|
|
|
143
190
|
/**
|
|
@@ -146,6 +193,7 @@ export class MessagesManager {
|
|
|
146
193
|
*/
|
|
147
194
|
public _deleteByTopicIds(roomId: string, ...topicIds: string[]): void {
|
|
148
195
|
this.followedTopics.get(roomId)?.delete(...topicIds);
|
|
196
|
+
topicIds.forEach(topicId => this.invalidateUnreadSummaries(roomId, topicId));
|
|
149
197
|
}
|
|
150
198
|
|
|
151
199
|
/**
|
|
@@ -172,24 +220,70 @@ export class MessagesManager {
|
|
|
172
220
|
return message || null;
|
|
173
221
|
}
|
|
174
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Wyczyść cache celowo, tylko dla lokalizacji których dotyczy zmiana.
|
|
225
|
+
*/
|
|
226
|
+
private invalidateUnreadSummaries(roomId?: string, topicId?: string): void {
|
|
227
|
+
if (!roomId) {
|
|
228
|
+
this.unreadSummariesCache.clear();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.unreadSummariesCache.delete(`room:${roomId}`);
|
|
233
|
+
|
|
234
|
+
if (topicId) {
|
|
235
|
+
this.unreadSummariesCache.delete(`topic:${roomId}:${topicId}`);
|
|
236
|
+
} else {
|
|
237
|
+
for (const key of this.unreadSummariesCache.keys()) {
|
|
238
|
+
if (key.startsWith(`topic:${roomId}:`)) {
|
|
239
|
+
this.unreadSummariesCache.delete(key);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for (const key of this.unreadSummariesCache.keys()) {
|
|
245
|
+
if (key.startsWith('space:') || key === 'spaceless') {
|
|
246
|
+
this.unreadSummariesCache.delete(key);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private invalidateUnreadSummariesForRooms(roomIds: string[]): void {
|
|
252
|
+
const roomIdsSet = new Set(roomIds);
|
|
253
|
+
roomIds.forEach(roomId => {
|
|
254
|
+
this.unreadSummariesCache.delete(`room:${roomId}`);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
for (const key of this.unreadSummariesCache.keys()) {
|
|
258
|
+
if (key.startsWith('space:') || key === 'spaceless') {
|
|
259
|
+
this.unreadSummariesCache.delete(key);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (key.startsWith('topic:')) {
|
|
263
|
+
const parts = key.split(':');
|
|
264
|
+
if (parts.length >= 2 && roomIdsSet.has(parts[1])) {
|
|
265
|
+
this.unreadSummariesCache.delete(key);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
175
271
|
private createHistoryForNewRoom(room: Room): void {
|
|
176
272
|
this.roomHistories.set([room.id, new RoomMessagesHistory(room, this.tracker)]);
|
|
177
273
|
}
|
|
178
274
|
|
|
179
275
|
private handleNewMessage(ev: NewMessage): void {
|
|
180
|
-
this.updateLocallyFollowedTopicOnNewMessage(ev);
|
|
276
|
+
void this.updateLocallyFollowedTopicOnNewMessage(ev);
|
|
181
277
|
}
|
|
182
278
|
|
|
183
279
|
private handleFollowedTopicUpdated(ev: FollowedTopicUpdated): void {
|
|
184
280
|
this.followedTopics.get(ev.followedTopic.location.roomId)?.set(ev.followedTopic);
|
|
281
|
+
this.invalidateUnreadSummaries(ev.followedTopic.location.roomId, ev.followedTopic.location.topicId);
|
|
185
282
|
}
|
|
186
283
|
|
|
187
284
|
private handleTopicFollowed(ev: TopicFollowed): void {
|
|
188
285
|
this.setFollowedTopicsArray([ev.followedTopic.location.roomId], [ev.followedTopic]);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
private handleTopicUnfollowed(ev: TopicUnfollowed): void {
|
|
192
|
-
this.followedTopics.get(ev.location.roomId)?.delete(ev.location.topicId);
|
|
286
|
+
this.invalidateUnreadSummaries(ev.followedTopic.location.roomId, ev.followedTopic.location.topicId);
|
|
193
287
|
}
|
|
194
288
|
|
|
195
289
|
private handleRoomDeleted(ev: RoomDeleted): void {
|
|
@@ -218,23 +312,26 @@ export class MessagesManager {
|
|
|
218
312
|
const followedTopic = result.data.followedTopics[0];
|
|
219
313
|
if (followedTopic) {
|
|
220
314
|
this.followedTopics.get(ev.roomId).set(followedTopic);
|
|
315
|
+
this.invalidateUnreadSummaries(ev.roomId, ev.topic.id);
|
|
221
316
|
}
|
|
222
317
|
}
|
|
223
318
|
}
|
|
224
319
|
|
|
225
320
|
private handleTopicDeleted(ev: TopicDeleted): void {
|
|
226
321
|
this.followedTopics.get(ev.location.roomId)?.delete(ev.location.topicId);
|
|
322
|
+
this.invalidateUnreadSummaries(ev.location.roomId, ev.location.topicId);
|
|
227
323
|
}
|
|
228
324
|
|
|
229
325
|
private handleSession(ev: Session): void {
|
|
230
326
|
this.followedTopics.deleteAll();
|
|
231
327
|
this.followedTopicsPromises.forgetAll();
|
|
328
|
+
this.invalidateUnreadSummaries();
|
|
232
329
|
this.roomHistories.deleteAll();
|
|
233
330
|
ev.state.rooms.forEach(room => this.createHistoryForNewRoom(room));
|
|
234
331
|
this.deferredSession.resolve();
|
|
235
332
|
}
|
|
236
333
|
|
|
237
|
-
private updateLocallyFollowedTopicOnNewMessage(ev: NewMessage): void {
|
|
334
|
+
private async updateLocallyFollowedTopicOnNewMessage(ev: NewMessage): Promise<void> {
|
|
238
335
|
const roomFollowedTopics = this.followedTopics.get(ev.message.location.roomId);
|
|
239
336
|
const followedTopic = roomFollowedTopics?.get(ev.message.location.topicId);
|
|
240
337
|
|
|
@@ -250,12 +347,31 @@ export class MessagesManager {
|
|
|
250
347
|
if (isMe) {
|
|
251
348
|
// Reset missed messages count if new message is authored by me
|
|
252
349
|
update = {missed: 0, lastAckMessageId: ev.message.id};
|
|
350
|
+
} else if (ev.message.type === 'Text') {
|
|
351
|
+
// ...check for mentions if it's text message...
|
|
352
|
+
const member = await this.tracker.rooms.getMe(ev.message.location.roomId);
|
|
353
|
+
const roleIds = [...(member.spaceMember?.roles ?? []), ...member.roles];
|
|
354
|
+
const mentionHandlers = [
|
|
355
|
+
...roleIds.map(id => `<@&${id}>`),
|
|
356
|
+
`<@${ev.message.author.user.id}>`,
|
|
357
|
+
];
|
|
358
|
+
const mentionExists = mentionHandlers.some(handler => ev.message.content.includes(handler));
|
|
359
|
+
|
|
360
|
+
update = {
|
|
361
|
+
missed: followedTopic.missed === null ? null : followedTopic.missed + 1,
|
|
362
|
+
isUnread: true,
|
|
363
|
+
mentionCount: followedTopic.mentionCount + (mentionExists ? 1 : 0),
|
|
364
|
+
};
|
|
253
365
|
} else {
|
|
254
|
-
// ...
|
|
255
|
-
update = {
|
|
366
|
+
// ...or just mark as unread.
|
|
367
|
+
update = {
|
|
368
|
+
missed: followedTopic.missed === null ? null : followedTopic.missed + 1,
|
|
369
|
+
isUnread: true,
|
|
370
|
+
};
|
|
256
371
|
}
|
|
257
372
|
|
|
258
373
|
roomFollowedTopics.set({...followedTopic, ...update});
|
|
374
|
+
this.invalidateUnreadSummaries(ev.message.location.roomId, ev.message.location.topicId);
|
|
259
375
|
}
|
|
260
376
|
|
|
261
377
|
private setFollowedTopicsArray(roomIds: string[], followedTopics: FollowedTopic[]): void {
|
|
@@ -278,10 +394,13 @@ export class MessagesManager {
|
|
|
278
394
|
this.followedTopics.get(roomId).set(...roomToTopics[roomId]);
|
|
279
395
|
}
|
|
280
396
|
});
|
|
397
|
+
|
|
398
|
+
this.invalidateUnreadSummariesForRooms(roomIds);
|
|
281
399
|
}
|
|
282
400
|
|
|
283
401
|
private clearRoomFollowedTopicsStructures(roomId: string): void {
|
|
284
402
|
this.followedTopics.delete(roomId);
|
|
285
403
|
this.followedTopicsPromises.forget(roomId);
|
|
404
|
+
this.invalidateUnreadSummaries(roomId);
|
|
286
405
|
}
|
|
287
406
|
}
|
|
@@ -202,12 +202,40 @@ export abstract class TraversableRemoteCollection<
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
public async jumpTo(id: string): Promise<void> {
|
|
206
|
+
if (this.internalState.ongoing || this._items.has(id)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let result: ItemT[] | null;
|
|
211
|
+
const originalState = this.state;
|
|
212
|
+
this.internalState.ongoing = WindowState.PAST;
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
result = await this.fetchItemsAround(id);
|
|
216
|
+
this.internalState.lastFetchCount = result ? result.length : 0;
|
|
217
|
+
} finally {
|
|
218
|
+
this.internalState.ongoing = undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!result) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
this._items.deleteAll(); // Directly call deleteAll to prevent event emit.
|
|
226
|
+
this.addItems(result, 'tail');
|
|
227
|
+
this.internalState.current = WindowState.PAST;
|
|
228
|
+
this.emitChangeWithDiff(true, originalState);
|
|
229
|
+
}
|
|
230
|
+
|
|
205
231
|
protected abstract fetchLatestItems(): Promise<ItemT[]>;
|
|
206
232
|
|
|
207
233
|
protected abstract fetchItemsBefore(): Promise<ItemT[] | null>;
|
|
208
234
|
|
|
209
235
|
protected abstract fetchItemsAfter(): Promise<ItemT[] | null>;
|
|
210
236
|
|
|
237
|
+
protected abstract fetchItemsAround(id: string): Promise<ItemT[] | null>;
|
|
238
|
+
|
|
211
239
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
212
240
|
|
|
213
241
|
protected async refreshFetchedState(): Promise<void> {
|
|
@@ -334,6 +362,13 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
334
362
|
return super.fetchPrevious();
|
|
335
363
|
}
|
|
336
364
|
|
|
365
|
+
public async jumpTo(id: string): Promise<void> {
|
|
366
|
+
if (this.internalState.traverseLock) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
return super.jumpTo(id);
|
|
370
|
+
}
|
|
371
|
+
|
|
337
372
|
/**
|
|
338
373
|
* For internal use.
|
|
339
374
|
* @internal
|
|
@@ -368,6 +403,20 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
368
403
|
return result.data.messages;
|
|
369
404
|
}
|
|
370
405
|
|
|
406
|
+
protected async fetchItemsAround(id: string): Promise<Message[] | null> {
|
|
407
|
+
const result = await this.tracker.client.send('GetMessages', {
|
|
408
|
+
location: {roomId: this.roomId, topicId: this.topicId},
|
|
409
|
+
around: id,
|
|
410
|
+
limit: this.internalState.fetchLimit,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
if (result.error) {
|
|
414
|
+
throw new Error(`Cannot fetch messages: ${result.error.message}`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return result.data.messages;
|
|
418
|
+
}
|
|
419
|
+
|
|
371
420
|
protected async fetchItemsBefore(): Promise<Message[] | null> {
|
|
372
421
|
const beforeId = this.getAt(0)?.id;
|
|
373
422
|
|
|
@@ -446,4 +495,4 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
446
495
|
this.eventTarget.emit('reftopicsdeleted', refTopicIds);
|
|
447
496
|
}
|
|
448
497
|
}
|
|
449
|
-
}
|
|
498
|
+
}
|
package/src/types/src/index.ts
CHANGED
|
@@ -77,9 +77,8 @@ import { Owners } from "./schemes/events/Owners";
|
|
|
77
77
|
import { Ok } from "./schemes/events/Ok";
|
|
78
78
|
import {FollowTopic} from "./schemes/commands/FollowTopic";
|
|
79
79
|
import {FollowedTopics} from "./schemes/events/FollowedTopics";
|
|
80
|
-
import {FollowedTopic} from "./schemes/FollowedTopic";
|
|
81
|
-
import {
|
|
82
|
-
import {TopicUnfollowed} from "./schemes/events/TopicUnfollowed";
|
|
80
|
+
import {FollowedTopic, NotificationLevel} from "./schemes/FollowedTopic";
|
|
81
|
+
import {UpdateFollowedTopic} from "./schemes/commands/UpdateFollowedTopic";
|
|
83
82
|
import {TopicFollowed} from "./schemes/events/TopicFollowed";
|
|
84
83
|
import {GetFollowedTopics} from "./schemes/commands/GetFollowedTopics";
|
|
85
84
|
import {FollowedTopicUpdated} from "./schemes/events/FollowedTopicUpdated";
|
|
@@ -155,6 +154,7 @@ export {
|
|
|
155
154
|
SpaceMember,
|
|
156
155
|
Topic,
|
|
157
156
|
FollowedTopic,
|
|
157
|
+
NotificationLevel,
|
|
158
158
|
User,
|
|
159
159
|
UserState,
|
|
160
160
|
PermissionOverwritesValue,
|
|
@@ -178,7 +178,6 @@ export {
|
|
|
178
178
|
NewRoom,
|
|
179
179
|
NewTopic,
|
|
180
180
|
TopicFollowed,
|
|
181
|
-
TopicUnfollowed,
|
|
182
181
|
FollowedTopics,
|
|
183
182
|
FollowedTopicUpdated,
|
|
184
183
|
ComputedPermissions,
|
|
@@ -235,7 +234,7 @@ export {
|
|
|
235
234
|
CreateSpace,
|
|
236
235
|
CreateTopic,
|
|
237
236
|
FollowTopic,
|
|
238
|
-
|
|
237
|
+
UpdateFollowedTopic,
|
|
239
238
|
GetFollowedTopics,
|
|
240
239
|
DeassignRole,
|
|
241
240
|
DeleteRole,
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import {ChatLocation} from "./ChatLocation";
|
|
2
2
|
|
|
3
|
+
export type NotificationLevel = 'All' | 'Mentions' | 'None';
|
|
4
|
+
|
|
3
5
|
export interface FollowedTopic {
|
|
4
6
|
location: ChatLocation;
|
|
5
7
|
lastAckMessageId: string | null;
|
|
8
|
+
notificationLevel: NotificationLevel;
|
|
6
9
|
missed: number | null;
|
|
10
|
+
isUnread: boolean;
|
|
11
|
+
mentionCount: number;
|
|
7
12
|
}
|