polfan-server-js-client 0.1.1 → 0.1.6

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.
Files changed (211) hide show
  1. package/.gitmodules +3 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  3. package/.idea/polfan-server-js-client.iml +3 -1
  4. package/.idea/vcs.xml +1 -1
  5. package/README.md +17 -17
  6. package/build/index.js +3282 -1
  7. package/build/index.js.map +1 -1
  8. package/build/types/AbstractChatClient.d.ts +26 -9
  9. package/build/types/AbstractRestClient.d.ts +1 -1
  10. package/build/types/EventTarget.d.ts +2 -0
  11. package/build/types/IndexedObjectCollection.d.ts +6 -3
  12. package/build/types/Permissions.d.ts +65 -0
  13. package/build/types/WebSocketChatClient.d.ts +1 -1
  14. package/build/types/index.d.ts +4 -1
  15. package/build/types/state-tracker/AsyncUtils.d.ts +14 -0
  16. package/build/types/state-tracker/ChatStateTracker.d.ts +26 -0
  17. package/build/types/state-tracker/MessagesManager.d.ts +39 -0
  18. package/build/types/state-tracker/PermissionsManager.d.ts +41 -0
  19. package/build/types/state-tracker/RoomsManager.d.ts +49 -0
  20. package/build/types/state-tracker/SpacesManager.d.ts +52 -0
  21. package/build/types/state-tracker/functions.d.ts +2 -0
  22. package/build/types/types/src/index.d.ts +82 -0
  23. package/build/types/types/src/schemes/AckReport.d.ts +7 -0
  24. package/build/types/types/src/schemes/ChatLocation.d.ts +5 -0
  25. package/build/types/types/src/schemes/Envelope.d.ts +5 -0
  26. package/build/types/types/src/schemes/Message.d.ts +7 -0
  27. package/build/types/types/src/schemes/PermissionOverwritesValue.d.ts +4 -0
  28. package/build/types/types/src/schemes/Role.d.ts +6 -0
  29. package/build/types/types/src/schemes/Room.d.ts +10 -0
  30. package/build/types/types/src/schemes/RoomMember.d.ts +7 -0
  31. package/build/types/types/src/schemes/RoomSummary.d.ts +5 -0
  32. package/build/types/types/src/schemes/Space.d.ts +6 -0
  33. package/build/types/types/src/schemes/SpaceMember.d.ts +5 -0
  34. package/build/types/types/src/schemes/Topic.d.ts +5 -0
  35. package/build/types/types/src/schemes/User.d.ts +8 -0
  36. package/build/types/types/src/schemes/UserState.d.ts +6 -0
  37. package/build/types/types/src/schemes/commands/Ack.d.ts +5 -0
  38. package/build/types/types/src/schemes/commands/AssignRole.d.ts +6 -0
  39. package/build/types/types/src/schemes/commands/CreateMessage.d.ts +5 -0
  40. package/build/types/types/src/schemes/commands/CreateOwner.d.ts +5 -0
  41. package/build/types/types/src/schemes/commands/CreateRole.d.ts +5 -0
  42. package/build/types/types/src/schemes/commands/CreateRoom.d.ts +7 -0
  43. package/build/types/types/src/schemes/commands/CreateSpace.d.ts +3 -0
  44. package/build/types/types/src/schemes/commands/CreateTopic.d.ts +12 -0
  45. package/build/types/types/src/schemes/commands/DeassignRole.d.ts +6 -0
  46. package/build/types/types/src/schemes/commands/DeleteOwner.d.ts +5 -0
  47. package/build/types/types/src/schemes/commands/DeleteRole.d.ts +4 -0
  48. package/build/types/types/src/schemes/commands/DeleteRoom.d.ts +3 -0
  49. package/build/types/types/src/schemes/commands/DeleteSpace.d.ts +3 -0
  50. package/build/types/types/src/schemes/commands/DeleteTopic.d.ts +4 -0
  51. package/build/types/types/src/schemes/commands/GetAckReports.d.ts +4 -0
  52. package/build/types/types/src/schemes/commands/GetComputedPermissions.d.ts +4 -0
  53. package/build/types/types/src/schemes/commands/GetOwners.d.ts +4 -0
  54. package/build/types/types/src/schemes/commands/GetPermissionOverwriteTargets.d.ts +4 -0
  55. package/build/types/types/src/schemes/commands/GetPermissionOverwrites.d.ts +6 -0
  56. package/build/types/types/src/schemes/commands/GetRoomMembers.d.ts +3 -0
  57. package/build/types/types/src/schemes/commands/GetSession.d.ts +2 -0
  58. package/build/types/types/src/schemes/commands/GetSpaceMembers.d.ts +3 -0
  59. package/build/types/types/src/schemes/commands/GetSpaceRooms.d.ts +3 -0
  60. package/build/types/types/src/schemes/commands/JoinRoom.d.ts +3 -0
  61. package/build/types/types/src/schemes/commands/JoinSpace.d.ts +3 -0
  62. package/build/types/types/src/schemes/commands/LeaveRoom.d.ts +3 -0
  63. package/build/types/types/src/schemes/commands/LeaveSpace.d.ts +3 -0
  64. package/build/types/types/src/schemes/commands/SetPermissionOverwrites.d.ts +8 -0
  65. package/build/types/types/src/schemes/commands/UpdateRole.d.ts +7 -0
  66. package/build/types/types/src/schemes/commands/UpdateRoom.d.ts +5 -0
  67. package/build/types/types/src/schemes/commands/UpdateSpace.d.ts +4 -0
  68. package/build/types/types/src/schemes/events/AckReports.d.ts +4 -0
  69. package/build/types/types/src/schemes/events/Bye.d.ts +3 -0
  70. package/build/types/types/src/schemes/events/ComputedPermissions.d.ts +5 -0
  71. package/build/types/types/src/schemes/events/Error.d.ts +4 -0
  72. package/build/types/types/src/schemes/events/NewMessage.d.ts +6 -0
  73. package/build/types/types/src/schemes/events/NewRole.d.ts +5 -0
  74. package/build/types/types/src/schemes/events/NewRoom.d.ts +5 -0
  75. package/build/types/types/src/schemes/events/NewTopic.d.ts +5 -0
  76. package/build/types/types/src/schemes/events/Ok.d.ts +2 -0
  77. package/build/types/types/src/schemes/events/Owners.d.ts +8 -0
  78. package/build/types/types/src/schemes/events/PermissionOverwriteTargets.d.ts +10 -0
  79. package/build/types/types/src/schemes/events/PermissionOverwrites.d.ts +8 -0
  80. package/build/types/types/src/schemes/events/PermissionOverwritesUpdated.d.ts +8 -0
  81. package/build/types/types/src/schemes/events/RoleDeleted.d.ts +4 -0
  82. package/build/types/types/src/schemes/events/RoleUpdated.d.ts +5 -0
  83. package/build/types/types/src/schemes/events/RoomDeleted.d.ts +3 -0
  84. package/build/types/types/src/schemes/events/RoomJoined.d.ts +4 -0
  85. package/build/types/types/src/schemes/events/RoomLeft.d.ts +3 -0
  86. package/build/types/types/src/schemes/events/RoomMemberJoined.d.ts +5 -0
  87. package/build/types/types/src/schemes/events/RoomMemberLeft.d.ts +4 -0
  88. package/build/types/types/src/schemes/events/RoomMemberUpdated.d.ts +6 -0
  89. package/build/types/types/src/schemes/events/RoomMembers.d.ts +5 -0
  90. package/build/types/types/src/schemes/events/RoomUpdated.d.ts +4 -0
  91. package/build/types/types/src/schemes/events/Session.d.ts +7 -0
  92. package/build/types/types/src/schemes/events/SpaceDeleted.d.ts +3 -0
  93. package/build/types/types/src/schemes/events/SpaceJoined.d.ts +4 -0
  94. package/build/types/types/src/schemes/events/SpaceLeft.d.ts +3 -0
  95. package/build/types/types/src/schemes/events/SpaceMemberJoined.d.ts +5 -0
  96. package/build/types/types/src/schemes/events/SpaceMemberLeft.d.ts +4 -0
  97. package/build/types/types/src/schemes/events/SpaceMemberUpdated.d.ts +6 -0
  98. package/build/types/types/src/schemes/events/SpaceMembers.d.ts +5 -0
  99. package/build/types/types/src/schemes/events/SpaceRooms.d.ts +5 -0
  100. package/build/types/types/src/schemes/events/SpaceUpdated.d.ts +4 -0
  101. package/build/types/types/src/schemes/events/TopicDeleted.d.ts +4 -0
  102. package/build/types/types/src/schemes/events/UserUpdated.d.ts +4 -0
  103. package/jest.config.ts +199 -0
  104. package/package.json +4 -22
  105. package/src/AbstractChatClient.ts +50 -16
  106. package/src/AbstractRestClient.ts +65 -65
  107. package/src/AuthClient.ts +1 -1
  108. package/src/EventTarget.ts +9 -0
  109. package/src/IndexedObjectCollection.ts +21 -4
  110. package/src/Permissions.ts +46 -0
  111. package/src/WebApiChatClient.ts +2 -2
  112. package/src/WebSocketChatClient.ts +6 -5
  113. package/src/index.ts +7 -2
  114. package/src/state-tracker/AsyncUtils.ts +38 -0
  115. package/src/state-tracker/ChatStateTracker.ts +42 -0
  116. package/src/state-tracker/MessagesManager.ts +154 -0
  117. package/src/state-tracker/PermissionsManager.ts +306 -0
  118. package/src/state-tracker/RoomsManager.ts +272 -0
  119. package/src/state-tracker/SpacesManager.ts +267 -0
  120. package/src/state-tracker/functions.ts +25 -0
  121. package/src/types/README.md +2 -0
  122. package/src/types/package-lock.json +31 -0
  123. package/src/types/package.json +16 -0
  124. package/src/types/src/index.ts +168 -0
  125. package/src/types/src/schemes/AckReport.ts +7 -0
  126. package/src/types/src/schemes/ChatLocation.ts +5 -0
  127. package/src/types/src/schemes/Envelope.ts +5 -0
  128. package/src/types/src/schemes/Message.ts +8 -0
  129. package/src/types/src/schemes/PermissionOverwritesValue.ts +4 -0
  130. package/src/types/src/schemes/Role.ts +6 -0
  131. package/src/types/src/schemes/Room.ts +12 -0
  132. package/src/types/src/schemes/RoomMember.ts +8 -0
  133. package/src/types/src/schemes/RoomSummary.ts +5 -0
  134. package/src/types/src/schemes/Space.ts +7 -0
  135. package/src/types/src/schemes/SpaceMember.ts +6 -0
  136. package/src/types/src/schemes/Topic.ts +5 -0
  137. package/src/types/src/schemes/User.ts +9 -0
  138. package/src/types/src/schemes/UserState.ts +7 -0
  139. package/src/types/src/schemes/commands/Ack.ts +6 -0
  140. package/src/types/src/schemes/commands/AssignRole.ts +7 -0
  141. package/src/types/src/schemes/commands/CreateMessage.ts +6 -0
  142. package/src/types/src/schemes/commands/CreateOwner.ts +6 -0
  143. package/src/types/src/schemes/commands/CreateRole.ts +5 -0
  144. package/src/types/src/schemes/commands/CreateRoom.ts +8 -0
  145. package/src/types/src/schemes/commands/CreateSpace.ts +3 -0
  146. package/src/types/src/schemes/commands/CreateTopic.ts +14 -0
  147. package/src/types/src/schemes/commands/DeassignRole.ts +7 -0
  148. package/src/types/src/schemes/commands/DeleteOwner.ts +6 -0
  149. package/src/types/src/schemes/commands/DeleteRole.ts +4 -0
  150. package/src/types/src/schemes/commands/DeleteRoom.ts +3 -0
  151. package/src/types/src/schemes/commands/DeleteSpace.ts +3 -0
  152. package/src/types/src/schemes/commands/DeleteTopic.ts +5 -0
  153. package/src/types/src/schemes/commands/GetAckReports.ts +5 -0
  154. package/src/types/src/schemes/commands/GetComputedPermissions.ts +5 -0
  155. package/src/types/src/schemes/commands/GetOwners.ts +5 -0
  156. package/src/types/src/schemes/commands/GetPermissionOverwriteTargets.ts +5 -0
  157. package/src/types/src/schemes/commands/GetPermissionOverwrites.ts +7 -0
  158. package/src/types/src/schemes/commands/GetRoomMembers.ts +3 -0
  159. package/src/types/src/schemes/commands/GetSession.ts +2 -0
  160. package/src/types/src/schemes/commands/GetSpaceMembers.ts +3 -0
  161. package/src/types/src/schemes/commands/GetSpaceRooms.ts +3 -0
  162. package/src/types/src/schemes/commands/JoinRoom.ts +3 -0
  163. package/src/types/src/schemes/commands/JoinSpace.ts +3 -0
  164. package/src/types/src/schemes/commands/LeaveRoom.ts +3 -0
  165. package/src/types/src/schemes/commands/LeaveSpace.ts +3 -0
  166. package/src/types/src/schemes/commands/SetPermissionOverwrites.ts +9 -0
  167. package/src/types/src/schemes/commands/UpdateRole.ts +7 -0
  168. package/src/types/src/schemes/commands/UpdateRoom.ts +5 -0
  169. package/src/types/src/schemes/commands/UpdateSpace.ts +4 -0
  170. package/src/types/src/schemes/events/AckReports.ts +5 -0
  171. package/src/types/src/schemes/events/Bye.ts +3 -0
  172. package/src/types/src/schemes/events/ComputedPermissions.ts +6 -0
  173. package/src/types/src/schemes/events/Error.ts +4 -0
  174. package/src/types/src/schemes/events/NewMessage.ts +7 -0
  175. package/src/types/src/schemes/events/NewRole.ts +6 -0
  176. package/src/types/src/schemes/events/NewRoom.ts +6 -0
  177. package/src/types/src/schemes/events/NewTopic.ts +6 -0
  178. package/src/types/src/schemes/events/Ok.ts +3 -0
  179. package/src/types/src/schemes/events/Owners.ts +9 -0
  180. package/src/types/src/schemes/events/PermissionOverwriteTargets.ts +11 -0
  181. package/src/types/src/schemes/events/PermissionOverwrites.ts +9 -0
  182. package/src/types/src/schemes/events/PermissionOverwritesUpdated.ts +9 -0
  183. package/src/types/src/schemes/events/RoleDeleted.ts +4 -0
  184. package/src/types/src/schemes/events/RoleUpdated.ts +6 -0
  185. package/src/types/src/schemes/events/RoomDeleted.ts +3 -0
  186. package/src/types/src/schemes/events/RoomJoined.ts +5 -0
  187. package/src/types/src/schemes/events/RoomLeft.ts +3 -0
  188. package/src/types/src/schemes/events/RoomMemberJoined.ts +6 -0
  189. package/src/types/src/schemes/events/RoomMemberLeft.ts +4 -0
  190. package/src/types/src/schemes/events/RoomMemberUpdated.ts +7 -0
  191. package/src/types/src/schemes/events/RoomMembers.ts +6 -0
  192. package/src/types/src/schemes/events/RoomUpdated.ts +5 -0
  193. package/src/types/src/schemes/events/Session.ts +8 -0
  194. package/src/types/src/schemes/events/SpaceDeleted.ts +3 -0
  195. package/src/types/src/schemes/events/SpaceJoined.ts +5 -0
  196. package/src/types/src/schemes/events/SpaceLeft.ts +3 -0
  197. package/src/types/src/schemes/events/SpaceMemberJoined.ts +6 -0
  198. package/src/types/src/schemes/events/SpaceMemberLeft.ts +4 -0
  199. package/src/types/src/schemes/events/SpaceMemberUpdated.ts +7 -0
  200. package/src/types/src/schemes/events/SpaceMembers.ts +6 -0
  201. package/src/types/src/schemes/events/SpaceRooms.ts +6 -0
  202. package/src/types/src/schemes/events/SpaceUpdated.ts +5 -0
  203. package/src/types/src/schemes/events/TopicDeleted.ts +5 -0
  204. package/src/types/src/schemes/events/UserUpdated.ts +5 -0
  205. package/src/types/tsconfig.json +75 -0
  206. package/tests/async-utils.test.ts +30 -0
  207. package/tests/permissions.test.ts +14 -0
  208. package/tests/space-roles.test.ts +43 -0
  209. package/webpack.config.js +1 -1
  210. package/build/types/ChatStateTracker.d.ts +0 -54
  211. package/src/ChatStateTracker.ts +0 -326
@@ -0,0 +1,272 @@
1
+ import {IndexedCollection, ObservableIndexedObjectCollection} from "../IndexedObjectCollection";
2
+ import {
3
+ NewTopic,
4
+ Room, RoomDeleted,
5
+ RoomJoined, RoomLeft,
6
+ RoomMember, RoomMemberJoined, RoomMemberLeft, RoomMembers,
7
+ RoomMemberUpdated, RoomUpdated, Session, SpaceDeleted, SpaceLeft, SpaceMemberLeft,
8
+ SpaceMemberUpdated,
9
+ Topic,
10
+ TopicDeleted,
11
+ UserUpdated,
12
+ } from "../types/src";
13
+ import {ChatStateTracker} from "./ChatStateTracker";
14
+ import {DeferredTask, PromiseRegistry} from "./AsyncUtils";
15
+ import {MessagesManager} from "./MessagesManager";
16
+
17
+ export class RoomsManager {
18
+ public readonly messages: MessagesManager;
19
+
20
+ private readonly list = new ObservableIndexedObjectCollection<Room>('id');
21
+ private readonly topics = new IndexedCollection<string, ObservableIndexedObjectCollection<Topic>>();
22
+ private readonly members = new IndexedCollection<string, ObservableIndexedObjectCollection<RoomMember>>();
23
+ private readonly deferredSession = new DeferredTask();
24
+ private readonly membersPromises = new PromiseRegistry();
25
+
26
+ public constructor(private tracker: ChatStateTracker) {
27
+ this.messages = new MessagesManager(tracker);
28
+
29
+ this.tracker.client.on('NewTopic', ev => this.handleNewTopic(ev));
30
+ this.tracker.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
31
+ this.tracker.client.on('RoomJoined', ev => this.handleRoomJoined(ev));
32
+ this.tracker.client.on('RoomLeft', ev => this.handleRoomLeft(ev));
33
+ this.tracker.client.on('RoomUpdated', ev => this.handleRoomUpdated(ev));
34
+ this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
35
+ this.tracker.client.on('RoomMemberJoined', ev => this.handleRoomMemberJoined(ev));
36
+ this.tracker.client.on('RoomMemberLeft', ev => this.handleRoomMemberLeft(ev));
37
+ this.tracker.client.on('RoomMembers', ev => this.handleRoomMembers(ev));
38
+ this.tracker.client.on('RoomMemberUpdated', ev => this.handleRoomMemberUpdated(ev));
39
+ this.tracker.client.on('SpaceMemberLeft', ev => this.handleSpaceMemberLeft(ev));
40
+ this.tracker.client.on('SpaceMemberUpdated', ev => this.handleSpaceMemberUpdated(ev));
41
+ this.tracker.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
42
+ this.tracker.client.on('SpaceLeft', ev => this.handleSpaceDeleted(ev));
43
+ this.tracker.client.on('UserUpdated', ev => this.handleUserUpdated(ev));
44
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
45
+ }
46
+
47
+ /**
48
+ * Get collection of room members.
49
+ */
50
+ public async getMembers(roomId: string): Promise<ObservableIndexedObjectCollection<RoomMember> | undefined> {
51
+ if (this.membersPromises.notExist(roomId)) {
52
+ this.membersPromises.registerByFunction(async () => {
53
+ const result = await this.tracker.client.send('GetRoomMembers', {id: roomId});
54
+ if (result.error) {
55
+ throw result.error;
56
+ }
57
+ this.handleRoomMembers(result.data);
58
+ }, roomId);
59
+ }
60
+
61
+ await this.membersPromises.get(roomId);
62
+ return this.members.get(roomId);
63
+ }
64
+
65
+ /**
66
+ * Get a room member representing the current user.
67
+ */
68
+ public async getMe(roomId: string): Promise<RoomMember | undefined> {
69
+ const userId = (await this.tracker.getMe()).id;
70
+
71
+ if (! this.list.has(roomId)) {
72
+ // User is not in passed room.
73
+ return undefined;
74
+ }
75
+
76
+ const members = await this.getMembers(roomId);
77
+ return members.items.find(member => (member.user?.id ?? member.spaceMember.user.id) === userId);
78
+ }
79
+
80
+ /**
81
+ * Get collection of all the rooms you are in.
82
+ */
83
+ public async get(): Promise<ObservableIndexedObjectCollection<Room>> {
84
+ await this.deferredSession.promise;
85
+ return this.list;
86
+ }
87
+
88
+ /**
89
+ * Get collection of room topics.
90
+ */
91
+ public async getTopics(roomId: string): Promise<ObservableIndexedObjectCollection<Topic> | undefined> {
92
+ await this.deferredSession.promise;
93
+ return this.topics.get(roomId);
94
+ }
95
+
96
+ private deleteRoom(...roomIds: string[]): void {
97
+ this.list.delete(...roomIds);
98
+ this.members.delete(...roomIds);
99
+ this.membersPromises.forget(...roomIds);
100
+
101
+ for (const roomId of roomIds) {
102
+ const topicIds: string[] = this.topics.get(roomId)?.map(topic => topic.id) ?? [];
103
+ this.messages._deleteByTopicIds(roomId, ...topicIds);
104
+ }
105
+
106
+ this.topics.delete(...roomIds);
107
+ }
108
+
109
+ private deleteRoomsBySpaceId(spaceId: string): void {
110
+ this.deleteRoom(
111
+ ...this.list.findBy('spaceId', spaceId).map(room => room.id)
112
+ );
113
+ }
114
+
115
+ private handleSpaceMemberUpdated(ev: SpaceMemberUpdated): void {
116
+ // Update members of rooms related to this space
117
+ for (const room of this.list.findBy('spaceId', ev.spaceId).items) {
118
+ const roomMembers = this.members.get(room.id);
119
+
120
+ if (! roomMembers || ! roomMembers.has(ev.userId)) {
121
+ // Skip update if member list for this room is not loaded
122
+ // or user is not in room
123
+ continue;
124
+ }
125
+
126
+ const roomMember = roomMembers.get(ev.userId);
127
+ const user = roomMember.spaceMember.user;
128
+
129
+ // Update space member but first fill user object (it's null in event object)
130
+ roomMember.spaceMember = {...ev.member, user};
131
+ roomMembers.set(roomMember);
132
+ }
133
+ }
134
+
135
+ private handleSpaceMemberLeft(ev: SpaceMemberLeft): void {
136
+ this.list
137
+ .findBy('spaceId', ev.spaceId).items
138
+ .forEach(room => this.members.get(room.id)?.delete(ev.userId));
139
+ }
140
+
141
+ private handleRoomMemberUpdated(ev: RoomMemberUpdated): void {
142
+ if (! this.members.has(ev.roomId)) {
143
+ // We do not track member list for this room.
144
+ return;
145
+ }
146
+
147
+ const members = this.members.get(ev.roomId);
148
+ const member = members.get(ev.userId);
149
+ const newMember = ev.member;
150
+ const user = member.spaceMember?.user ?? member.user;
151
+
152
+ if (newMember.spaceMember) {
153
+ newMember.spaceMember.user = user;
154
+ } else {
155
+ newMember.user = user;
156
+ }
157
+
158
+ members.set(newMember);
159
+ }
160
+
161
+ private handleSpaceDeleted(ev: SpaceDeleted | SpaceLeft): void {
162
+ this.deleteRoomsBySpaceId(ev.id);
163
+ }
164
+
165
+ private handleTopicDeleted(ev: TopicDeleted): void {
166
+ const collection = this.topics.get(ev.location.roomId);
167
+ collection.delete(ev.location.topicId);
168
+
169
+ const room = this.list.get(ev.location.roomId);
170
+ if (room.defaultTopic?.id === ev.location.topicId) {
171
+ this.list.set({...room, defaultTopic: null});
172
+ }
173
+ }
174
+
175
+ private handleNewTopic(ev: NewTopic): void {
176
+ this.addJoinedRoomTopics(ev.roomId, ev.topic);
177
+ }
178
+
179
+ private addJoinedRoomTopics(roomId: string, ...topics: Topic[]): void {
180
+ if (this.topics.has(roomId)) {
181
+ this.topics.get(roomId).set(...topics);
182
+ } else {
183
+ this.topics.set([roomId, new ObservableIndexedObjectCollection<Topic>('id', topics)]);
184
+ }
185
+
186
+ this.messages._handleNewTopics(roomId, ...topics);
187
+ }
188
+
189
+ private handleRoomJoined(ev: RoomJoined): void {
190
+ this.addJoinedRooms(ev.room);
191
+ }
192
+
193
+ private handleRoomUpdated(ev: RoomUpdated): void {
194
+ this.list.set({
195
+ ...this.list.get(ev.room.id),
196
+ name: ev.room.name,
197
+ description: ev.room.description,
198
+ } as Room);
199
+ }
200
+
201
+ private handleRoomDeleted(ev: RoomDeleted): void {
202
+ this.deleteRoom(ev.id);
203
+ }
204
+
205
+ private addJoinedRooms(...rooms: Room[]): void {
206
+ for (const room of rooms) {
207
+ if (room.defaultTopic) {
208
+ this.addJoinedRoomTopics(room.id, room.defaultTopic);
209
+ }
210
+ }
211
+ this.list.set(...rooms);
212
+ }
213
+
214
+ private handleRoomLeft(ev: RoomLeft): void {
215
+ this.deleteRoom(ev.id);
216
+ }
217
+
218
+ private handleRoomMemberJoined(ev: RoomMemberJoined): void {
219
+ if (this.members.has(ev.roomId)) {
220
+ this.members.get(ev.roomId).set(ev.member);
221
+ }
222
+ }
223
+
224
+ private handleRoomMemberLeft(ev: RoomMemberLeft): void {
225
+ if (this.members.has(ev.roomId)) {
226
+ this.members.get(ev.roomId).delete(ev.userId);
227
+ }
228
+ }
229
+
230
+ private handleRoomMembers(ev: RoomMembers): void {
231
+ if (! this.members.has(ev.id)) {
232
+ this.members.set([
233
+ ev.id,
234
+ new ObservableIndexedObjectCollection(
235
+ member => member.user?.id ?? member.spaceMember.user.id,
236
+ ev.members,
237
+ )
238
+ ]);
239
+ }
240
+ }
241
+
242
+ private handleSession(ev: Session): void {
243
+ this.list.deleteAll();
244
+ this.topics.deleteAll();
245
+ this.members.deleteAll();
246
+
247
+ this.addJoinedRooms(...ev.state.rooms);
248
+
249
+ this.deferredSession.resolve();
250
+ }
251
+
252
+ private handleUserUpdated(ev: UserUpdated): void {
253
+ this.members.items.forEach((members) => {
254
+ const member = members.get(ev.user.id);
255
+
256
+ if (! member) {
257
+ // Skip room; updated user is not here
258
+ return;
259
+ }
260
+
261
+ const newMember: RoomMember = {...member};
262
+
263
+ if (member.user) {
264
+ newMember.user = ev.user;
265
+ } else {
266
+ newMember.spaceMember.user = ev.user;
267
+ }
268
+
269
+ members.set(newMember);
270
+ });
271
+ }
272
+ }
@@ -0,0 +1,267 @@
1
+ import {ChatStateTracker} from "./ChatStateTracker";
2
+ import {IndexedCollection, ObservableIndexedObjectCollection} from "../IndexedObjectCollection";
3
+ import {
4
+ NewRole,
5
+ NewRoom,
6
+ Role,
7
+ RoleDeleted,
8
+ RoleUpdated,
9
+ RoomDeleted,
10
+ RoomSummary,
11
+ RoomUpdated,
12
+ Session,
13
+ Space,
14
+ SpaceDeleted,
15
+ SpaceJoined,
16
+ SpaceLeft,
17
+ SpaceMember,
18
+ SpaceMemberJoined,
19
+ SpaceMemberLeft,
20
+ SpaceMembers,
21
+ SpaceMemberUpdated,
22
+ SpaceRooms,
23
+ SpaceUpdated,
24
+ UserUpdated
25
+ } from "../types/src";
26
+ import {DeferredTask, PromiseRegistry} from "./AsyncUtils";
27
+ import {reorderRolesOnPriorityUpdate} from "./functions";
28
+
29
+ export class SpacesManager {
30
+ private readonly list = new ObservableIndexedObjectCollection<Space>('id');
31
+ private readonly roles = new IndexedCollection<string, ObservableIndexedObjectCollection<Role>>();
32
+ private readonly rooms = new IndexedCollection<string, ObservableIndexedObjectCollection<RoomSummary>>();
33
+ private readonly roomIdToSpaceId = new IndexedCollection<string, string>();
34
+ private readonly members = new IndexedCollection<string, ObservableIndexedObjectCollection<SpaceMember>>();
35
+ private readonly deferredSession = new DeferredTask();
36
+ private readonly roomsPromises = new PromiseRegistry();
37
+ private readonly membersPromises = new PromiseRegistry();
38
+
39
+ public constructor(private tracker: ChatStateTracker) {
40
+ this.tracker.client.on('NewRoom', ev => this.handleNewRoom(ev));
41
+ this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
42
+ this.tracker.client.on('RoomUpdated', ev => this.handleRoomUpdated(ev));
43
+ this.tracker.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
44
+ this.tracker.client.on('SpaceUpdated', ev => this.handleSpaceUpdated(ev));
45
+ this.tracker.client.on('SpaceJoined', ev => this.handleSpaceJoined(ev));
46
+ this.tracker.client.on('SpaceLeft', ev => this.handleSpaceDeleted(ev));
47
+ this.tracker.client.on('SpaceMemberJoined', ev => this.handleSpaceMemberJoined(ev));
48
+ this.tracker.client.on('SpaceMemberLeft', ev => this.handleSpaceMemberLeft(ev));
49
+ this.tracker.client.on('SpaceMembers', ev => this.handleSpaceMembers(ev));
50
+ this.tracker.client.on('SpaceRooms', ev => this.handleSpaceRooms(ev));
51
+ this.tracker.client.on('SpaceMemberUpdated', ev => this.handleSpaceMemberUpdated(ev));
52
+ this.tracker.client.on('UserUpdated', ev => this.handleUserUpdated(ev));
53
+ this.tracker.client.on('NewRole', ev => this.handleNewRole(ev));
54
+ this.tracker.client.on('RoleDeleted', ev => this.handleRoleDeleted(ev));
55
+ this.tracker.client.on('RoleUpdated', ev => this.handleRoleUpdated(ev));
56
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
57
+ }
58
+
59
+ /**
60
+ * Get collection of all the spaces you are in.
61
+ */
62
+ public async get(): Promise<ObservableIndexedObjectCollection<Space>> {
63
+ await this.deferredSession.promise;
64
+ return this.list;
65
+ }
66
+
67
+ /**
68
+ * Get collection of space roles.
69
+ */
70
+ public async getRoles(spaceId: string): Promise<ObservableIndexedObjectCollection<Role> | undefined> {
71
+ await this.deferredSession.promise;
72
+ return this.roles.get(spaceId);
73
+ }
74
+
75
+ /**
76
+ * Get collection of the all available rooms inside given space.
77
+ */
78
+ public async getRooms(spaceId: string): Promise<ObservableIndexedObjectCollection<RoomSummary> | undefined> {
79
+ if (this.roomsPromises.notExist(spaceId)) {
80
+ this.roomsPromises.registerByFunction(async () => {
81
+ const result = await this.tracker.client.send('GetSpaceRooms', {id: spaceId});
82
+ if (result.error) {
83
+ throw result.error;
84
+ }
85
+ this.handleSpaceRooms(result.data);
86
+ }, spaceId);
87
+ }
88
+
89
+ await this.roomsPromises.get(spaceId);
90
+ return this.rooms.get(spaceId);
91
+ }
92
+
93
+ /**
94
+ * Get collection of space members.
95
+ */
96
+ public async getMembers(spaceId: string): Promise<ObservableIndexedObjectCollection<SpaceMember> | undefined> {
97
+ if (this.membersPromises.notExist(spaceId)) {
98
+ this.membersPromises.registerByFunction(async () => {
99
+ const result = await this.tracker.client.send('GetSpaceMembers', {id: spaceId});
100
+ if (result.error) {
101
+ throw result.error;
102
+ }
103
+ this.handleSpaceMembers(result.data);
104
+ }, spaceId);
105
+ }
106
+
107
+ await this.membersPromises.get(spaceId);
108
+ return this.members.get(spaceId);
109
+ }
110
+
111
+ /**
112
+ * Get a space member representing the current user.
113
+ */
114
+ public async getMe(spaceId: string): Promise<SpaceMember | undefined> {
115
+ const userId = (await this.tracker.getMe()).id;
116
+
117
+ if (! this.list.has(spaceId)) {
118
+ // User is not in passed space.
119
+ return undefined;
120
+ }
121
+
122
+ const members = await this.getMembers(spaceId);
123
+ return members.items.find(member => member.user.id === userId);
124
+ }
125
+
126
+ private handleNewRole(ev: NewRole): void {
127
+ const collection = this.roles.get(ev.spaceId);
128
+ collection.set(ev.role);
129
+ this.list.get(ev.spaceId).roles = collection.items;
130
+ }
131
+
132
+ private handleNewRoom(ev: NewRoom): void {
133
+ this.rooms.get(ev.spaceId)?.set(ev.summary);
134
+ this.roomIdToSpaceId.set([ev.summary.id, ev.spaceId]);
135
+ }
136
+
137
+ private handleRoomUpdated(ev: RoomUpdated): void {
138
+ if (ev.room.spaceId && this.rooms.has(ev.room.spaceId)) {
139
+ const rooms = this.rooms.get(ev.room.spaceId);
140
+ rooms.set({
141
+ ...rooms.get(ev.room.id),
142
+ name: ev.room.name,
143
+ description: ev.room.description,
144
+ } as RoomSummary);
145
+ }
146
+ }
147
+
148
+ private async handleRoomDeleted(ev: RoomDeleted): Promise<void> {
149
+ const spaceId = this.roomIdToSpaceId.get(ev.id);
150
+
151
+ if (spaceId && this.rooms.has(spaceId)) {
152
+ this.rooms.get(spaceId).delete(ev.id);
153
+ }
154
+ }
155
+
156
+ private handleRoleDeleted(ev: RoleDeleted): void {
157
+ const collection = this.roles.get(ev.spaceId);
158
+ collection.delete(ev.id);
159
+ this.list.get(ev.spaceId).roles = collection.items;
160
+ }
161
+
162
+ private handleSpaceUpdated(ev: SpaceUpdated): void {
163
+ this.list.set({
164
+ ...this.list.get(ev.space.id),
165
+ name: ev.space.name,
166
+ } as Space);
167
+ }
168
+
169
+ private handleSpaceDeleted(ev: SpaceDeleted | SpaceLeft): void {
170
+ const roomIds = this.rooms.get(ev.id)?.map(item => item.id) ?? [];
171
+ this.roomIdToSpaceId.delete(...roomIds);
172
+
173
+ this.roles.delete(ev.id);
174
+ this.members.delete(ev.id);
175
+ this.membersPromises.forget(ev.id);
176
+ this.rooms.delete(ev.id);
177
+ this.roomsPromises.forget(ev.id);
178
+ this.list.delete(ev.id);
179
+ }
180
+
181
+ private handleSpaceJoined(ev: SpaceJoined): void {
182
+ this.addJoinedSpaces(ev.space);
183
+ }
184
+
185
+ private addJoinedSpaces(...spaces: Space[]): void {
186
+ this.roles.set(...(spaces.map(space => [
187
+ space.id,
188
+ new ObservableIndexedObjectCollection<Role>('id', space.roles)
189
+ ]) as [string, ObservableIndexedObjectCollection<Role>][]));
190
+ this.list.set(...spaces);
191
+ }
192
+
193
+ private handleSpaceMemberJoined(ev: SpaceMemberJoined): void {
194
+ if (this.members.has(ev.spaceId)) {
195
+ this.members.get(ev.spaceId).set(ev.member);
196
+ }
197
+ }
198
+
199
+ private handleSpaceMemberLeft(ev: SpaceMemberLeft): void {
200
+ if (this.members.has(ev.spaceId)) {
201
+ this.members.get(ev.spaceId).delete(ev.userId);
202
+ }
203
+ }
204
+
205
+ private handleSpaceMembers(ev: SpaceMembers): void {
206
+ if (! this.members.has(ev.id)) {
207
+ this.members.set([
208
+ ev.id,
209
+ new ObservableIndexedObjectCollection(member => member?.user.id, ev.members)
210
+ ]);
211
+ }
212
+ }
213
+
214
+ private handleSpaceRooms(ev: SpaceRooms): void {
215
+ if (! this.rooms.has(ev.id)) {
216
+ this.rooms.set([ev.id, new ObservableIndexedObjectCollection('id', ev.summaries)]);
217
+ }
218
+ }
219
+
220
+ private handleSpaceMemberUpdated(ev: SpaceMemberUpdated): void {
221
+ if (this.members.has(ev.spaceId)) {
222
+ const members = this.members.get(ev.spaceId);
223
+ const member = members.get(ev.userId);
224
+ members.set({...ev.member, user: member.user});
225
+ }
226
+ }
227
+
228
+ private handleRoleUpdated(ev: RoleUpdated): void {
229
+ const roles = this.roles.get(ev.spaceId);
230
+ const oldRole = roles.get(ev.role.id);
231
+ const newRole = ev.role;
232
+ const rolesToUpdate = [newRole];
233
+
234
+ if (oldRole.priority !== newRole.priority) {
235
+ rolesToUpdate.push(
236
+ ...reorderRolesOnPriorityUpdate(roles.items, oldRole, newRole)
237
+ );
238
+ }
239
+
240
+ this.roles.get(ev.spaceId).set(...rolesToUpdate);
241
+ }
242
+
243
+ private handleSession(ev: Session): void {
244
+ this.list.deleteAll();
245
+ this.roles.deleteAll();
246
+ this.rooms.deleteAll();
247
+ this.members.deleteAll();
248
+ this.roomIdToSpaceId.deleteAll();
249
+
250
+ this.addJoinedSpaces(...ev.state.spaces);
251
+
252
+ this.deferredSession.resolve();
253
+ }
254
+
255
+ private handleUserUpdated(ev: UserUpdated): void {
256
+ this.members.items.forEach((members) => {
257
+ const member = members.get(ev.user.id);
258
+
259
+ if (! member) {
260
+ // Skip space; updated user is not here
261
+ return;
262
+ }
263
+
264
+ members.set({...member, user: ev.user});
265
+ });
266
+ }
267
+ }
@@ -0,0 +1,25 @@
1
+ import {Role} from "../types/src";
2
+
3
+ export function reorderRolesOnPriorityUpdate(allRoles: Role[], oldRole: Role, updatedRole: Role): Role[] {
4
+ // If the priority has changed, adjust the rest of roles
5
+ const increased = (updatedRole.priority - oldRole.priority) > 0;
6
+ const decreased = ! increased;
7
+ const changedRoles: Role[] = [];
8
+
9
+ allRoles.forEach(role => {
10
+ if (role.id === updatedRole.id) {
11
+ // Skip the updated role
12
+ return;
13
+ }
14
+ if (increased && oldRole.priority <= role.priority) {
15
+ role.priority--;
16
+ changedRoles.push(role);
17
+ }
18
+ if (decreased && updatedRole.priority <= role.priority) {
19
+ role.priority++;
20
+ changedRoles.push(role);
21
+ }
22
+ });
23
+
24
+ return changedRoles;
25
+ }
@@ -0,0 +1,2 @@
1
+ # pserv-ts-types
2
+ TypeScript type definitions for PServ APIs protocol.
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "pserv-ts-types",
3
+ "lockfileVersion": 2,
4
+ "requires": true,
5
+ "packages": {
6
+ "": {
7
+ "dependencies": {
8
+ "typescript": "^5.0.2"
9
+ }
10
+ },
11
+ "node_modules/typescript": {
12
+ "version": "5.0.2",
13
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
14
+ "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
15
+ "bin": {
16
+ "tsc": "bin/tsc",
17
+ "tsserver": "bin/tsserver"
18
+ },
19
+ "engines": {
20
+ "node": ">=12.20"
21
+ }
22
+ }
23
+ },
24
+ "dependencies": {
25
+ "typescript": {
26
+ "version": "5.0.2",
27
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
28
+ "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw=="
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "pserv-ts-types",
3
+ "version": "0.0.30",
4
+ "description": "TypeScript type definitions for PServ APIs protocol.",
5
+ "author": "Jarosław Żak",
6
+ "license": "MIT",
7
+ "types": "dist/index.d.ts",
8
+ "main": "dist/index.js",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "prepare": "npm run build"
12
+ },
13
+ "devDependencies": {
14
+ "typescript": "^5.0.2"
15
+ }
16
+ }