polfan-server-js-client 0.1.99940 → 0.2.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.
@@ -0,0 +1,2252 @@
1
+ /******/ (() => { // webpackBootstrap
2
+ /******/ "use strict";
3
+ /******/ // The require scope
4
+ /******/ var __webpack_require__ = {};
5
+ /******/
6
+ /************************************************************************/
7
+ /******/ /* webpack/runtime/define property getters */
8
+ /******/ (() => {
9
+ /******/ // define getter functions for harmony exports
10
+ /******/ __webpack_require__.d = (exports, definition) => {
11
+ /******/ for(var key in definition) {
12
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14
+ /******/ }
15
+ /******/ }
16
+ /******/ };
17
+ /******/ })();
18
+ /******/
19
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
20
+ /******/ (() => {
21
+ /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
22
+ /******/ })();
23
+ /******/
24
+ /******/ /* webpack/runtime/make namespace object */
25
+ /******/ (() => {
26
+ /******/ // define __esModule on exports
27
+ /******/ __webpack_require__.r = (exports) => {
28
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
29
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30
+ /******/ }
31
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
32
+ /******/ };
33
+ /******/ })();
34
+ /******/
35
+ /************************************************************************/
36
+ var __webpack_exports__ = {};
37
+ // ESM COMPAT FLAG
38
+ __webpack_require__.r(__webpack_exports__);
39
+
40
+ // EXPORTS
41
+ __webpack_require__.d(__webpack_exports__, {
42
+ "AuthClient": () => (/* reexport */ AuthClient),
43
+ "FilesClient": () => (/* reexport */ FilesClient),
44
+ "IndexedCollection": () => (/* reexport */ IndexedCollection),
45
+ "IndexedObjectCollection": () => (/* reexport */ IndexedObjectCollection),
46
+ "Layer": () => (/* reexport */ Layer),
47
+ "ObservableIndexedCollection": () => (/* reexport */ ObservableIndexedCollection),
48
+ "ObservableIndexedObjectCollection": () => (/* reexport */ ObservableIndexedObjectCollection),
49
+ "PermissionDefinition": () => (/* reexport */ PermissionDefinition),
50
+ "Permissions": () => (/* reexport */ Permissions),
51
+ "WebApiChatClient": () => (/* reexport */ WebApiChatClient),
52
+ "WebSocketChatClient": () => (/* reexport */ WebSocketChatClient),
53
+ "extractUserFromMember": () => (/* reexport */ extractUserFromMember)
54
+ });
55
+
56
+ ;// CONCATENATED MODULE: ./src/EventTarget.ts
57
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
58
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
59
+ function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
60
+ class EventTarget {
61
+ constructor() {
62
+ _defineProperty(this, "events", new Map());
63
+ _defineProperty(this, "onceEvents", new Map());
64
+ }
65
+ on(eventName, handler) {
66
+ this.addHandler(this.events, eventName, handler);
67
+ return this;
68
+ }
69
+ once(eventName, handler) {
70
+ this.addHandler(this.onceEvents, eventName, handler);
71
+ return this;
72
+ }
73
+ off(eventName, handler) {
74
+ const index = this.events.get(eventName)?.indexOf(handler);
75
+ if (!index || index < 0) {
76
+ return this;
77
+ }
78
+ this.events.get(eventName).splice(index, 1);
79
+ return this;
80
+ }
81
+ emit(eventName, event) {
82
+ this.callHandlers(this.events, eventName, event);
83
+ this.callHandlers(this.onceEvents, eventName, event);
84
+ this.onceEvents.delete(eventName);
85
+ return this;
86
+ }
87
+ addHandler(map, eventName, handler) {
88
+ const handlers = map.get(eventName) ?? [];
89
+ handlers.push(handler);
90
+ map.set(eventName, handlers);
91
+ }
92
+ callHandlers(map, eventName, event) {
93
+ map.get(eventName)?.forEach(callback => callback(event));
94
+ }
95
+ }
96
+ ;// CONCATENATED MODULE: ./src/AbstractChatClient.ts
97
+ function AbstractChatClient_defineProperty(obj, key, value) { key = AbstractChatClient_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
98
+ function AbstractChatClient_toPropertyKey(arg) { var key = AbstractChatClient_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
99
+ function AbstractChatClient_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
100
+
101
+ class AbstractChatClient extends EventTarget {
102
+ constructor(...args) {
103
+ super(...args);
104
+ AbstractChatClient_defineProperty(this, "awaitingResponse", new Map());
105
+ AbstractChatClient_defineProperty(this, "sentCounter", 0);
106
+ }
107
+ on(eventName, handler) {
108
+ return super.on(eventName, handler);
109
+ }
110
+ once(eventName, handler) {
111
+ return super.once(eventName, handler);
112
+ }
113
+ createEnvelope(type, data) {
114
+ return {
115
+ type,
116
+ data,
117
+ ref: (++this.sentCounter).toString()
118
+ };
119
+ }
120
+ createPromiseFromCommandEnvelope(envelope) {
121
+ return new Promise((...args) => this.awaitingResponse.set(envelope.ref, args));
122
+ }
123
+ handleIncomingEnvelope(envelope) {
124
+ if (!this.awaitingResponse.has(envelope.ref)) {
125
+ return;
126
+ }
127
+ const isError = envelope.type === 'Error';
128
+ this.awaitingResponse.get(envelope.ref)[0]({
129
+ data: isError ? null : envelope.data,
130
+ error: isError ? envelope.data : null
131
+ });
132
+ this.awaitingResponse.delete(envelope.ref);
133
+ }
134
+ handleEnvelopeSendError(envelope, error) {
135
+ if (!this.awaitingResponse.has(envelope.ref)) {
136
+ return;
137
+ }
138
+ this.awaitingResponse.get(envelope.ref)[0](error);
139
+ this.awaitingResponse.delete(envelope.ref);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Map of incoming events.
145
+ */
146
+
147
+ /**
148
+ * Map of commands and their corresponding events.
149
+ */
150
+ ;// CONCATENATED MODULE: ./src/IndexedObjectCollection.ts
151
+ function IndexedObjectCollection_defineProperty(obj, key, value) { key = IndexedObjectCollection_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
152
+ function IndexedObjectCollection_toPropertyKey(arg) { var key = IndexedObjectCollection_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
153
+ function IndexedObjectCollection_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
154
+
155
+ class IndexedCollection {
156
+ constructor(items = []) {
157
+ IndexedObjectCollection_defineProperty(this, "_items", new Map());
158
+ IndexedObjectCollection_defineProperty(this, "_mutationCounter", 0);
159
+ this.set(...items);
160
+ }
161
+ get mutationCounter() {
162
+ return this._mutationCounter;
163
+ }
164
+ get items() {
165
+ return this._items;
166
+ }
167
+ get length() {
168
+ return this._items.size;
169
+ }
170
+ set(...items) {
171
+ this._mutationCounter++;
172
+ for (const item of items) {
173
+ this._items.set(item[0], item[1]);
174
+ }
175
+ }
176
+ get(id) {
177
+ return this.items.get(id);
178
+ }
179
+ has(id) {
180
+ return this.items.has(id);
181
+ }
182
+ delete(...ids) {
183
+ for (const id of ids) {
184
+ this.items.delete(id);
185
+ }
186
+ }
187
+ deleteAll() {
188
+ this.items.clear();
189
+ }
190
+ findBy(field, valueToFind, limit = null) {
191
+ const result = new IndexedCollection();
192
+ let item;
193
+ while (!(item = this.items.entries().next().value).done) {
194
+ if (limit && result.length === limit) {
195
+ break;
196
+ }
197
+ if (item[1][field] === valueToFind) {
198
+ result.set(item);
199
+ }
200
+ }
201
+ return result;
202
+ }
203
+ }
204
+ class IndexedObjectCollection {
205
+ constructor(id, items = []) {
206
+ this.id = id;
207
+ IndexedObjectCollection_defineProperty(this, "_items", void 0);
208
+ this._items = new IndexedCollection();
209
+ this.set(...items);
210
+ }
211
+ get items() {
212
+ return Array.from(this._items.items.values());
213
+ }
214
+ get length() {
215
+ return this._items.length;
216
+ }
217
+ get mutationCounter() {
218
+ return this._items.mutationCounter;
219
+ }
220
+ set(...items) {
221
+ this._items.set(...items.map(item => [this.getId(item), item]));
222
+ }
223
+ get(id) {
224
+ return this._items.get(id);
225
+ }
226
+ getAt(index) {
227
+ return this.items[index];
228
+ }
229
+ has(id) {
230
+ return this._items.has(id);
231
+ }
232
+ delete(...ids) {
233
+ this._items.delete(...ids);
234
+ }
235
+ deleteAll() {
236
+ this._items.deleteAll();
237
+ }
238
+ findBy(field, valueToFind, limit = null) {
239
+ const result = new IndexedObjectCollection(this.id);
240
+ for (const value of this.items) {
241
+ if (limit && result.length === limit) {
242
+ break;
243
+ }
244
+ if (value[field] === valueToFind) {
245
+ result.set(value);
246
+ }
247
+ }
248
+ return result;
249
+ }
250
+ getId(item) {
251
+ return typeof this.id === 'function' ? this.id(item) : item[this.id];
252
+ }
253
+ }
254
+ class ObservableIndexedCollection extends IndexedCollection {
255
+ constructor(items = []) {
256
+ super();
257
+ IndexedObjectCollection_defineProperty(this, "eventTarget", void 0);
258
+ this.eventTarget = new EventTarget();
259
+ this.set(...items);
260
+ }
261
+ set(...items) {
262
+ if (items.length) {
263
+ super.set(...items);
264
+ this.eventTarget.emit('change', {
265
+ setItems: items.map(item => item[0])
266
+ });
267
+ }
268
+ }
269
+ delete(...ids) {
270
+ if (ids.length) {
271
+ super.delete(...ids);
272
+ this.eventTarget.emit('change', {
273
+ deletedItems: ids
274
+ });
275
+ }
276
+ }
277
+ deleteAll() {
278
+ if (this.length) {
279
+ const ids = this._items.keys();
280
+ super.deleteAll();
281
+ this.eventTarget.emit('change', {
282
+ deletedItems: Array.from(ids)
283
+ });
284
+ }
285
+ }
286
+ on(eventName, handler) {
287
+ this.eventTarget.on(eventName, handler);
288
+ return this;
289
+ }
290
+ once(eventName, handler) {
291
+ this.eventTarget.once(eventName, handler);
292
+ return this;
293
+ }
294
+ off(eventName, handler) {
295
+ this.eventTarget.off(eventName, handler);
296
+ return this;
297
+ }
298
+ }
299
+ class ObservableIndexedObjectCollection extends IndexedObjectCollection {
300
+ constructor(id, items = []) {
301
+ super(id);
302
+ this.id = id;
303
+ IndexedObjectCollection_defineProperty(this, "eventTarget", void 0);
304
+ this.eventTarget = new EventTarget();
305
+ this.set(...items);
306
+ }
307
+ set(...items) {
308
+ if (items.length) {
309
+ super.set(...items);
310
+ this.eventTarget.emit('change', {
311
+ setItems: items.map(item => this.getId(item))
312
+ });
313
+ }
314
+ }
315
+ delete(...ids) {
316
+ if (ids.length) {
317
+ super.delete(...ids);
318
+ this.eventTarget.emit('change', {
319
+ deletedItems: ids
320
+ });
321
+ }
322
+ }
323
+ deleteAll() {
324
+ if (this.length) {
325
+ const ids = this._items.items.keys();
326
+ super.deleteAll();
327
+ this.eventTarget.emit('change', {
328
+ deletedItems: Array.from(ids)
329
+ });
330
+ }
331
+ }
332
+ on(eventName, handler) {
333
+ this.eventTarget.on(eventName, handler);
334
+ return this;
335
+ }
336
+ once(eventName, handler) {
337
+ this.eventTarget.once(eventName, handler);
338
+ return this;
339
+ }
340
+ off(eventName, handler) {
341
+ this.eventTarget.off(eventName, handler);
342
+ return this;
343
+ }
344
+ }
345
+ ;// CONCATENATED MODULE: ./src/state-tracker/AsyncUtils.ts
346
+ function AsyncUtils_defineProperty(obj, key, value) { key = AsyncUtils_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
347
+ function AsyncUtils_toPropertyKey(arg) { var key = AsyncUtils_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
348
+ function AsyncUtils_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
349
+
350
+ class DeferredTask {
351
+ constructor() {
352
+ AsyncUtils_defineProperty(this, "promise", void 0);
353
+ AsyncUtils_defineProperty(this, "resolve", void 0);
354
+ this.promise = new Promise(resolve => this.resolve = resolve);
355
+ }
356
+ }
357
+ class PromiseRegistry {
358
+ constructor() {
359
+ AsyncUtils_defineProperty(this, "promises", new IndexedCollection());
360
+ }
361
+ register(promise, key) {
362
+ this.promises.set([key, promise]);
363
+ }
364
+ registerByFunction(fn, key) {
365
+ this.register(fn(), key);
366
+ }
367
+ get(key) {
368
+ return this.promises.get(key);
369
+ }
370
+ has(key) {
371
+ return this.promises.has(key);
372
+ }
373
+ notExist(key) {
374
+ return !this.has(key);
375
+ }
376
+ forget(...keys) {
377
+ this.promises.delete(...keys);
378
+ }
379
+ forgetAll() {
380
+ this.promises.deleteAll();
381
+ }
382
+ }
383
+ ;// CONCATENATED MODULE: ./src/state-tracker/TopicHistoryWindow.ts
384
+ function TopicHistoryWindow_defineProperty(obj, key, value) { key = TopicHistoryWindow_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
385
+ function TopicHistoryWindow_toPropertyKey(arg) { var key = TopicHistoryWindow_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
386
+ function TopicHistoryWindow_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
387
+
388
+ let WindowState = /*#__PURE__*/function (WindowState) {
389
+ /**
390
+ * The latest messages (those received live) are available in the history window, history has not been fetched.
391
+ */
392
+ WindowState[WindowState["LIVE"] = 0] = "LIVE";
393
+ /**
394
+ * The latest messages has been fetched and are available in the history window.
395
+ */
396
+ WindowState[WindowState["LATEST"] = 1] = "LATEST";
397
+ /**
398
+ * The historical messages have been fetched and are available in the history window.
399
+ * Latest messages are not available and will not be available.
400
+ */
401
+ WindowState[WindowState["PAST"] = 2] = "PAST";
402
+ /**
403
+ * The oldest messages have been fetched and are available in the history window.
404
+ * Next attempts to fetch previous messages will result with no-op.
405
+ */
406
+ WindowState[WindowState["OLDEST"] = 3] = "OLDEST";
407
+ return WindowState;
408
+ }({});
409
+ class TraversableRemoteCollection extends ObservableIndexedObjectCollection {
410
+ constructor(...args) {
411
+ super(...args);
412
+ /**
413
+ * Maximum numer of items stored in window.
414
+ * Null for unlimited.
415
+ */
416
+ TopicHistoryWindow_defineProperty(this, "limit", 50);
417
+ TopicHistoryWindow_defineProperty(this, "currentState", WindowState.LIVE);
418
+ TopicHistoryWindow_defineProperty(this, "fetchingState", undefined);
419
+ TopicHistoryWindow_defineProperty(this, "oldestId", null);
420
+ }
421
+ /**
422
+ * Current mode od collection window. To change mode, call one of available fetch methods.
423
+ */
424
+ get state() {
425
+ return this.currentState;
426
+ }
427
+ get hasLatest() {
428
+ return [WindowState.LATEST, WindowState.LIVE].includes(this.state);
429
+ }
430
+ get hasOldest() {
431
+ return this.state === WindowState.OLDEST || this.oldestId !== null && this.has(this.oldestId);
432
+ }
433
+ async resetToLatest() {
434
+ if (this.fetchingState || this.currentState === WindowState.LATEST) {
435
+ return;
436
+ }
437
+ this.fetchingState = WindowState.LATEST;
438
+ let result;
439
+ try {
440
+ result = await this.fetchLatestItems();
441
+ } finally {
442
+ this.fetchingState = undefined;
443
+ }
444
+ this.deleteAll();
445
+ this.addItems(result, 'tail');
446
+ this.currentState = WindowState.LATEST;
447
+ }
448
+ async fetchPrevious() {
449
+ if (this.fetchingState || this.hasOldest) {
450
+ return;
451
+ }
452
+ this.fetchingState = WindowState.PAST;
453
+ let result;
454
+ try {
455
+ result = await this.fetchItemsBefore();
456
+ } finally {
457
+ this.fetchingState = undefined;
458
+ }
459
+ if (!result) {
460
+ return this.resetToLatest();
461
+ }
462
+ if (!result.length) {
463
+ const firstItem = this.getAt(0);
464
+ this.oldestId = firstItem ? this.getId(firstItem) : null;
465
+ await this.refreshFetchedState();
466
+
467
+ // LATEST state has priority over OLDEST
468
+ if (this.currentState === WindowState.PAST) {
469
+ this.currentState = WindowState.OLDEST;
470
+ }
471
+ return;
472
+ }
473
+ this.addItems(result, 'head');
474
+ await this.refreshFetchedState();
475
+ }
476
+ async fetchNext() {
477
+ if (this.fetchingState || this.hasLatest) {
478
+ return;
479
+ }
480
+ this.fetchingState = WindowState.PAST;
481
+ let result;
482
+ try {
483
+ result = await this.fetchItemsAfter();
484
+ } finally {
485
+ this.fetchingState = undefined;
486
+ }
487
+ if (!result) {
488
+ await this.resetToLatest();
489
+ return;
490
+ }
491
+ if (result.length) {
492
+ this.addItems(result, 'tail');
493
+ await this.refreshFetchedState();
494
+ return;
495
+ }
496
+ }
497
+ async refreshFetchedState() {
498
+ this.currentState = (await this.isLatestItemLoaded()) ? WindowState.LATEST : WindowState.PAST;
499
+ }
500
+ addItems(newItems, to) {
501
+ let result;
502
+ if (to === 'head') {
503
+ result = this.trimItemsArrayToLimit([...newItems, ...this.items], 'tail');
504
+ }
505
+ if (to === 'tail') {
506
+ result = this.trimItemsArrayToLimit([...this.items, ...newItems], 'head');
507
+ }
508
+ this.deleteAll();
509
+ this.set(...result);
510
+ }
511
+
512
+ /**
513
+ * Return array with messages of count that matching limit.
514
+ */
515
+ trimItemsArrayToLimit(items, from) {
516
+ if (this.limit === null) {
517
+ return items;
518
+ }
519
+ if (from === 'head') {
520
+ return items.slice(-this.limit);
521
+ }
522
+ if (from === 'tail') {
523
+ return items.slice(0, this.limit);
524
+ }
525
+ }
526
+ }
527
+ class TopicHistoryWindow extends TraversableRemoteCollection {
528
+ constructor(roomId, topicId, tracker) {
529
+ super('id');
530
+ this.roomId = roomId;
531
+ this.topicId = topicId;
532
+ this.tracker = tracker;
533
+ /**
534
+ * Reexported available window modes enum.
535
+ */
536
+ TopicHistoryWindow_defineProperty(this, "WindowState", WindowState);
537
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
538
+ this.tracker.client.on('NewMessage', ev => this.handleNewMessage(ev));
539
+ }
540
+
541
+ /**
542
+ * For internal use.
543
+ * @internal
544
+ */
545
+ _updateMessageReference(refTopic) {
546
+ const refMessage = this.get(refTopic.refMessage.id);
547
+ if (refMessage) {
548
+ // Update referenced topic ID in message
549
+ this.set({
550
+ ...refMessage,
551
+ topicRef: refTopic.id
552
+ });
553
+ }
554
+ }
555
+ async handleNewMessage(ev) {
556
+ if ([WindowState.LATEST, WindowState.LIVE].includes(this.state) && ev.message.location.roomId === this.roomId && ev.message.location.topicId === this.topicId) {
557
+ this.addItems([ev.message], 'tail');
558
+ }
559
+ }
560
+ handleSession(ev) {
561
+ const rooms = ev.state.rooms;
562
+ if (rooms.find(room => room.id === this.roomId)) {
563
+ this.resetToLatest();
564
+ } else {
565
+ this.deleteAll();
566
+ }
567
+ }
568
+ async fetchItemsAfter() {
569
+ const afterId = this.getAt(this.length - 1)?.id;
570
+ if (!afterId) {
571
+ // If there is no message to refer, fetch latest
572
+ return null;
573
+ }
574
+ const result = await this.tracker.client.send('GetMessages', {
575
+ location: {
576
+ roomId: this.roomId,
577
+ topicId: this.topicId
578
+ },
579
+ after: afterId
580
+ });
581
+ if (result.error) {
582
+ throw new Error(`Cannot fetch messages: ${result.error.message}`);
583
+ }
584
+ return result.data.messages;
585
+ }
586
+ async fetchItemsBefore() {
587
+ const beforeId = this.getAt(0)?.id;
588
+ if (!beforeId) {
589
+ // If there is no message to refer, fetch latest
590
+ return null;
591
+ }
592
+ const result = await this.tracker.client.send('GetMessages', {
593
+ location: {
594
+ roomId: this.roomId,
595
+ topicId: this.topicId
596
+ },
597
+ before: beforeId
598
+ });
599
+ if (result.error) {
600
+ throw new Error(`Cannot fetch messages: ${result.error.message}`);
601
+ }
602
+ return result.data.messages;
603
+ }
604
+ async fetchLatestItems() {
605
+ const result = await this.tracker.client.send('GetMessages', {
606
+ location: {
607
+ roomId: this.roomId,
608
+ topicId: this.topicId
609
+ }
610
+ });
611
+ if (result.error) {
612
+ throw new Error(`Cannot fetch messages: ${result.error.message}`);
613
+ }
614
+ return result.data.messages;
615
+ }
616
+ async getTopic() {
617
+ return (await this.tracker.rooms.getTopics(this.roomId, [this.topicId])).get(this.topicId);
618
+ }
619
+ async getLatestMessageId() {
620
+ return (await this.getTopic())?.lastMessage?.id;
621
+ }
622
+ async isLatestItemLoaded() {
623
+ const lastMessageId = await this.getLatestMessageId();
624
+ return lastMessageId ? this.has(lastMessageId) : true;
625
+ }
626
+ }
627
+ ;// CONCATENATED MODULE: ./src/state-tracker/RoomMessagesHistory.ts
628
+ function RoomMessagesHistory_defineProperty(obj, key, value) { key = RoomMessagesHistory_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
629
+ function RoomMessagesHistory_toPropertyKey(arg) { var key = RoomMessagesHistory_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
630
+ function RoomMessagesHistory_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
631
+
632
+
633
+ class RoomMessagesHistory {
634
+ constructor(room, tracker) {
635
+ this.room = room;
636
+ this.tracker = tracker;
637
+ RoomMessagesHistory_defineProperty(this, "historyWindows", new IndexedCollection());
638
+ this.tracker.client.on('RoomUpdated', ev => this.handleRoomUpdated(ev));
639
+ this.tracker.client.on('NewTopic', ev => this.handleNewTopic(ev));
640
+ this.tracker.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
641
+ if (this.room.defaultTopic) {
642
+ this.createHistoryWindowForTopic(this.room.defaultTopic);
643
+ }
644
+ }
645
+
646
+ /**
647
+ * Returns a history window object for the given topic ID, allowing you to view message history.
648
+ */
649
+ async getMessagesWindow(topicId) {
650
+ let historyWindow = this.historyWindows.get(topicId);
651
+ if (!historyWindow) {
652
+ const topic = (await this.tracker.rooms.getTopics(this.room.id, [topicId])).get(topicId);
653
+ if (topic) {
654
+ this.createHistoryWindowForTopic(topic);
655
+ }
656
+ }
657
+ return this.historyWindows.get(topicId);
658
+ }
659
+ handleRoomUpdated(ev) {
660
+ if (this.room.id === ev.room.id) {
661
+ this.room = ev.room;
662
+ if (ev.room.defaultTopic) {
663
+ this.createHistoryWindowForTopic(ev.room.defaultTopic);
664
+ }
665
+ }
666
+ }
667
+ handleNewTopic(ev) {
668
+ if (this.room.id === ev.roomId) {
669
+ this.createHistoryWindowForTopic(ev.topic);
670
+ }
671
+ }
672
+ handleTopicDeleted(ev) {
673
+ if (this.room.id === ev.location.roomId) {
674
+ this.historyWindows.delete(ev.location.topicId);
675
+ }
676
+ }
677
+ createHistoryWindowForTopic(topic) {
678
+ if (this.historyWindows.has(topic.id)) {
679
+ return;
680
+ }
681
+ this.historyWindows.set([topic.id, new TopicHistoryWindow(this.room.id, topic.id, this.tracker)]);
682
+
683
+ // If new topic refers to some message from this room, update other structures
684
+ if (topic.refMessage) {
685
+ const refHistoryWindow = this.historyWindows.get(topic.refMessage.location.topicId);
686
+ refHistoryWindow?._updateMessageReference(topic);
687
+ }
688
+ }
689
+ }
690
+ ;// CONCATENATED MODULE: ./src/state-tracker/MessagesManager.ts
691
+ function MessagesManager_defineProperty(obj, key, value) { key = MessagesManager_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
692
+ function MessagesManager_toPropertyKey(arg) { var key = MessagesManager_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
693
+ function MessagesManager_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
694
+
695
+
696
+
697
+ class MessagesManager {
698
+ constructor(tracker) {
699
+ this.tracker = tracker;
700
+ MessagesManager_defineProperty(this, "roomHistories", new IndexedCollection());
701
+ MessagesManager_defineProperty(this, "followedTopics", new IndexedCollection());
702
+ MessagesManager_defineProperty(this, "followedTopicsPromises", new PromiseRegistry());
703
+ MessagesManager_defineProperty(this, "deferredSession", new DeferredTask());
704
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
705
+ this.tracker.client.on('RoomJoined', ev => this.handleRoomJoin(ev));
706
+ this.tracker.client.on('NewTopic', ev => this.handleNewTopic(ev));
707
+ this.tracker.client.on('FollowedTopicUpdated', ev => this.handleFollowedTopicUpdated(ev));
708
+ this.tracker.client.on('TopicFollowed', ev => this.handleTopicFollowed(ev));
709
+ this.tracker.client.on('TopicUnfollowed', ev => this.handleTopicUnfollowed(ev));
710
+ this.tracker.client.on('NewMessage', ev => this.handleNewMessage(ev));
711
+ this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
712
+ this.tracker.client.on('RoomLeft', ev => this.handleRoomLeft(ev));
713
+ this.tracker.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
714
+ }
715
+
716
+ /**
717
+ * Get history manager for given room ID.
718
+ */
719
+ async getRoomHistory(roomId) {
720
+ await this.deferredSession.promise;
721
+ return this.roomHistories.get(roomId);
722
+ }
723
+
724
+ /**
725
+ * Cache followed topics for all joined rooms in a space and fetch them in bulk if necessary.
726
+ * Then you can get them using getRoomFollowedTopics().
727
+ * @see getRoomFollowedTopics
728
+ */
729
+ async cacheSpaceFollowedTopics(spaceId) {
730
+ if (spaceId && !(await this.tracker.spaces.get()).has(spaceId)) {
731
+ throw new Error(`You are not in space ${spaceId}`);
732
+ }
733
+ const roomIds = (await this.tracker.rooms.get()).findBy('spaceId', spaceId).items.map(room => room.id);
734
+ if (!roomIds.length) {
735
+ // We don't need to ping server for followed topics for this space, if user has no joined rooms
736
+ return;
737
+ }
738
+ const resultPromise = this.tracker.client.send('GetFollowedTopics', {
739
+ location: {
740
+ spaceId
741
+ }
742
+ });
743
+ roomIds.forEach(roomId => this.followedTopicsPromises.register(resultPromise, roomId));
744
+ const result = await resultPromise;
745
+ if (result.error) {
746
+ throw result.error;
747
+ }
748
+ this.setFollowedTopicsArray(roomIds, result.data.followedTopics);
749
+ }
750
+
751
+ /**
752
+ * Get followed topics for the given room.
753
+ * @return Undefined if you are not in the room, collection otherwise.
754
+ */
755
+ async getRoomFollowedTopics(roomId) {
756
+ if (!(await this.tracker.rooms.get()).has(roomId)) {
757
+ return undefined;
758
+ }
759
+ if (!this.followedTopics.has(roomId)) {
760
+ if (this.followedTopicsPromises.notExist(roomId)) {
761
+ this.followedTopicsPromises.registerByFunction(async () => {
762
+ const result = await this.tracker.client.send('GetFollowedTopics', {
763
+ location: {
764
+ roomId
765
+ }
766
+ });
767
+ if (result.error) {
768
+ throw result.error;
769
+ }
770
+ this.setFollowedTopicsArray([roomId], result.data.followedTopics);
771
+ }, roomId);
772
+ }
773
+ await this.followedTopicsPromises.get(roomId);
774
+ }
775
+ return this.followedTopics.get(roomId);
776
+ }
777
+
778
+ /**
779
+ * Batch acknowledge all missed messages from any topics in given room.
780
+ */
781
+ async ackRoomFollowedTopics(roomId) {
782
+ const collection = await this.getRoomFollowedTopics(roomId);
783
+ if (!collection) {
784
+ return;
785
+ }
786
+ for (const followedTopic of collection.items) {
787
+ if (followedTopic.missed) {
788
+ await this.tracker.client.send('Ack', {
789
+ location: followedTopic.location
790
+ });
791
+ }
792
+ }
793
+ }
794
+
795
+ /**
796
+ * Calculate missed messages from any topic in given room.
797
+ * @return Undefined if you are not in room.
798
+ */
799
+ async calculateRoomMissedMessages(roomId) {
800
+ const collection = await this.getRoomFollowedTopics(roomId);
801
+ if (collection) {
802
+ return collection.items.reduce((previousValue, currentValue) => previousValue + (currentValue.missed ?? 0), 0);
803
+ }
804
+ return undefined;
805
+ }
806
+
807
+ /**
808
+ * For internal use. If you want to delete the message, execute a proper command on client object.
809
+ * @internal
810
+ */
811
+ _deleteByTopicIds(roomId, ...topicIds) {
812
+ this.followedTopics.get(roomId)?.delete(...topicIds);
813
+ }
814
+ createHistoryForNewRoom(room) {
815
+ this.roomHistories.set([room.id, new RoomMessagesHistory(room, this.tracker)]);
816
+ }
817
+ handleNewMessage(ev) {
818
+ this.updateLocallyFollowedTopicOnNewMessage(ev);
819
+ }
820
+ handleFollowedTopicUpdated(ev) {
821
+ this.followedTopics.get(ev.followedTopic.location.roomId)?.set(ev.followedTopic);
822
+ }
823
+ handleTopicFollowed(ev) {
824
+ this.setFollowedTopicsArray([ev.followedTopic.location.roomId], [ev.followedTopic]);
825
+ }
826
+ handleTopicUnfollowed(ev) {
827
+ this.followedTopics.get(ev.location.roomId)?.delete(ev.location.topicId);
828
+ }
829
+ handleRoomDeleted(ev) {
830
+ this.roomHistories.delete(ev.id);
831
+ this.clearRoomFollowedTopicsStructures(ev.id);
832
+ }
833
+ handleRoomJoin(ev) {
834
+ this.createHistoryForNewRoom(ev.room);
835
+ this.clearRoomFollowedTopicsStructures(ev.room.id);
836
+ }
837
+ handleRoomLeft(ev) {
838
+ this.roomHistories.delete(ev.id);
839
+ this.clearRoomFollowedTopicsStructures(ev.id);
840
+ }
841
+ async handleNewTopic(ev) {
842
+ if (this.followedTopics.has(ev.roomId)) {
843
+ // Check if the new topic is followed by user
844
+ // only if client asked for followed topics list before for this room
845
+ const result = await this.tracker.client.send('GetFollowedTopics', {
846
+ location: {
847
+ roomId: ev.roomId,
848
+ topicId: ev.topic.id
849
+ }
850
+ });
851
+ const followedTopic = result.data.followedTopics[0];
852
+ if (followedTopic) {
853
+ this.followedTopics.get(ev.roomId).set(followedTopic);
854
+ }
855
+ }
856
+ }
857
+ handleTopicDeleted(ev) {
858
+ this.followedTopics.get(ev.location.roomId)?.delete(ev.location.topicId);
859
+ }
860
+ handleSession(ev) {
861
+ this.followedTopics.deleteAll();
862
+ this.followedTopicsPromises.forgetAll();
863
+ this.roomHistories.deleteAll();
864
+ ev.state.rooms.forEach(room => this.createHistoryForNewRoom(room));
865
+ this.deferredSession.resolve();
866
+ }
867
+ updateLocallyFollowedTopicOnNewMessage(ev) {
868
+ const roomFollowedTopics = this.followedTopics.get(ev.message.location.roomId);
869
+ const followedTopic = roomFollowedTopics?.get(ev.message.location.topicId);
870
+ if (!roomFollowedTopics || !followedTopic) {
871
+ // Skip if we don't follow this room or targeted topic
872
+ return;
873
+ }
874
+ const isMe = ev.message.author.user.id === this.tracker.me?.id;
875
+ let update;
876
+ if (isMe) {
877
+ // Reset missed messages count if new message is authored by me
878
+ update = {
879
+ missed: 0,
880
+ lastAckMessageId: ev.message.id
881
+ };
882
+ } else {
883
+ // ...add 1 otherwise
884
+ update = {
885
+ missed: followedTopic.missed === null ? null : followedTopic.missed + 1
886
+ };
887
+ }
888
+ roomFollowedTopics.set({
889
+ ...followedTopic,
890
+ ...update
891
+ });
892
+ }
893
+ setFollowedTopicsArray(roomIds, followedTopics) {
894
+ const roomToTopics = {};
895
+
896
+ // Reassign followed topics to limit collection change event emit
897
+ followedTopics.forEach(followedTopic => {
898
+ roomToTopics[followedTopic.location.roomId] ??= [];
899
+ roomToTopics[followedTopic.location.roomId].push(followedTopic);
900
+ });
901
+ roomIds.forEach(roomId => {
902
+ if (!this.followedTopics.has(roomId)) {
903
+ this.followedTopics.set([roomId, new ObservableIndexedObjectCollection(followedTopic => followedTopic.location.topicId)]);
904
+ }
905
+ if (roomToTopics[roomId]) {
906
+ this.followedTopics.get(roomId).set(...roomToTopics[roomId]);
907
+ }
908
+ });
909
+ }
910
+ clearRoomFollowedTopicsStructures(roomId) {
911
+ this.followedTopics.delete(roomId);
912
+ this.followedTopicsPromises.forget(roomId);
913
+ }
914
+ }
915
+ ;// CONCATENATED MODULE: ./src/state-tracker/RoomsManager.ts
916
+ function RoomsManager_defineProperty(obj, key, value) { key = RoomsManager_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
917
+ function RoomsManager_toPropertyKey(arg) { var key = RoomsManager_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
918
+ function RoomsManager_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
919
+
920
+
921
+
922
+ class RoomsManager {
923
+ constructor(tracker) {
924
+ this.tracker = tracker;
925
+ RoomsManager_defineProperty(this, "messages", void 0);
926
+ RoomsManager_defineProperty(this, "list", new ObservableIndexedObjectCollection('id'));
927
+ RoomsManager_defineProperty(this, "topics", new IndexedCollection());
928
+ RoomsManager_defineProperty(this, "members", new IndexedCollection());
929
+ RoomsManager_defineProperty(this, "deferredSession", new DeferredTask());
930
+ RoomsManager_defineProperty(this, "membersPromises", new PromiseRegistry());
931
+ RoomsManager_defineProperty(this, "topicsPromises", new PromiseRegistry());
932
+ this.messages = new MessagesManager(tracker);
933
+ this.tracker.client.on('NewMessage', ev => this.handleNewMessage(ev));
934
+ this.tracker.client.on('NewTopic', ev => this.handleNewTopic(ev));
935
+ this.tracker.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
936
+ this.tracker.client.on('RoomJoined', ev => this.handleRoomJoined(ev));
937
+ this.tracker.client.on('RoomLeft', ev => this.handleRoomLeft(ev));
938
+ this.tracker.client.on('RoomUpdated', ev => this.handleRoomUpdated(ev));
939
+ this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
940
+ this.tracker.client.on('TopicUpdated', ev => this.handleTopicUpdated(ev));
941
+ this.tracker.client.on('RoomMemberJoined', ev => this.handleRoomMemberJoined(ev));
942
+ this.tracker.client.on('RoomMemberLeft', ev => this.handleRoomMemberLeft(ev));
943
+ this.tracker.client.on('RoomMembers', ev => this.handleRoomMembers(ev));
944
+ this.tracker.client.on('RoomMemberUpdated', ev => this.handleRoomMemberUpdated(ev));
945
+ this.tracker.client.on('SpaceMemberLeft', ev => this.handleSpaceMemberLeft(ev));
946
+ this.tracker.client.on('SpaceMemberUpdated', ev => this.handleSpaceMemberUpdated(ev));
947
+ this.tracker.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
948
+ this.tracker.client.on('SpaceLeft', ev => this.handleSpaceDeleted(ev));
949
+ this.tracker.client.on('UserUpdated', ev => this.handleUserUpdated(ev));
950
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
951
+ }
952
+
953
+ /**
954
+ * Get collection of room members.
955
+ */
956
+ async getMembers(roomId) {
957
+ if (this.membersPromises.notExist(roomId)) {
958
+ this.membersPromises.registerByFunction(async () => {
959
+ const result = await this.tracker.client.send('GetRoomMembers', {
960
+ id: roomId
961
+ });
962
+ if (result.error) {
963
+ throw result.error;
964
+ }
965
+ this.handleRoomMembers(result.data);
966
+ }, roomId);
967
+ }
968
+ await this.membersPromises.get(roomId);
969
+ return this.members.get(roomId);
970
+ }
971
+
972
+ /**
973
+ * Get a room member representing the current user.
974
+ */
975
+ async getMe(roomId) {
976
+ const userId = (await this.tracker.getMe()).id;
977
+ if (!this.list.has(roomId)) {
978
+ // User is not in passed room.
979
+ return undefined;
980
+ }
981
+ const members = await this.getMembers(roomId);
982
+ return members?.items.find(member => (member.user?.id ?? member.spaceMember.user.id) === userId);
983
+ }
984
+
985
+ /**
986
+ * Get collection of all the rooms you are in.
987
+ */
988
+ async get() {
989
+ await this.deferredSession.promise;
990
+ return this.list;
991
+ }
992
+
993
+ /**
994
+ * Get a collection of locally cached Topic objects for given room.
995
+ * You can pass topic ids as second argument, to try to fetch them from the server.
996
+ */
997
+ async getTopics(roomId, tryToFetchTopicIds) {
998
+ await this.deferredSession.promise;
999
+ if (tryToFetchTopicIds?.length) {
1000
+ // Topic can be fetched if it isn't already cached and fetch is not already in progress
1001
+ const canFetch = topicId => !this.topics.get(roomId)?.has(topicId) && !this.topicsPromises.has(roomId + topicId);
1002
+ const idsToFetch = tryToFetchTopicIds.filter(canFetch);
1003
+ if (idsToFetch.length) {
1004
+ const promise = this.tracker.client.send('GetTopics', {
1005
+ roomId,
1006
+ topicIds: idsToFetch
1007
+ }).then(result => this.topics.get(result.data.location.roomId)?.set(...result.data.topics));
1008
+ idsToFetch.forEach(topicId => this.topicsPromises.register(promise, roomId + topicId));
1009
+ }
1010
+ for (const topicId of tryToFetchTopicIds) {
1011
+ await this.topicsPromises.get(roomId + topicId);
1012
+ }
1013
+ }
1014
+ return this.topics.get(roomId);
1015
+ }
1016
+ deleteRoom(...roomIds) {
1017
+ this.list.delete(...roomIds);
1018
+ this.members.delete(...roomIds);
1019
+ this.membersPromises.forget(...roomIds);
1020
+ for (const roomId of roomIds) {
1021
+ const topicIds = this.topics.get(roomId)?.items.map(topic => topic.id) ?? [];
1022
+ this.messages._deleteByTopicIds(roomId, ...topicIds);
1023
+ }
1024
+ this.topics.delete(...roomIds);
1025
+ }
1026
+ deleteRoomsBySpaceId(spaceId) {
1027
+ this.deleteRoom(...this.list.findBy('spaceId', spaceId).items.map(room => room.id));
1028
+ }
1029
+ handleSpaceMemberUpdated(ev) {
1030
+ // Update members of rooms related to this space
1031
+ for (const room of this.list.findBy('spaceId', ev.spaceId).items) {
1032
+ const roomMembers = this.members.get(room.id);
1033
+ if (!roomMembers || !roomMembers.has(ev.userId)) {
1034
+ // Skip update if member list for this room is not loaded
1035
+ // or user is not in room
1036
+ continue;
1037
+ }
1038
+ const roomMember = roomMembers.get(ev.userId);
1039
+ const user = roomMember.spaceMember.user;
1040
+
1041
+ // Update space member but first fill user object (it's null in event object)
1042
+ roomMember.spaceMember = {
1043
+ ...ev.member,
1044
+ user
1045
+ };
1046
+ roomMembers.set(roomMember);
1047
+ }
1048
+ }
1049
+ handleSpaceMemberLeft(ev) {
1050
+ this.list.findBy('spaceId', ev.spaceId).items.forEach(room => this.members.get(room.id)?.delete(ev.userId));
1051
+ }
1052
+ handleRoomMemberUpdated(ev) {
1053
+ if (!this.members.has(ev.roomId)) {
1054
+ // We do not track member list for this room.
1055
+ return;
1056
+ }
1057
+ const members = this.members.get(ev.roomId);
1058
+ const member = members.get(ev.userId);
1059
+ const newMember = ev.member;
1060
+ const user = member.spaceMember?.user ?? member.user;
1061
+ if (newMember.spaceMember) {
1062
+ newMember.spaceMember.user = user;
1063
+ } else {
1064
+ newMember.user = user;
1065
+ }
1066
+ members.set(newMember);
1067
+ }
1068
+ handleSpaceDeleted(ev) {
1069
+ this.deleteRoomsBySpaceId(ev.id);
1070
+ }
1071
+ handleTopicDeleted(ev) {
1072
+ const collection = this.topics.get(ev.location.roomId);
1073
+ collection.delete(ev.location.topicId);
1074
+ const room = this.list.get(ev.location.roomId);
1075
+ if (room.defaultTopic?.id === ev.location.topicId) {
1076
+ this.list.set({
1077
+ ...room,
1078
+ defaultTopic: null
1079
+ });
1080
+ }
1081
+ }
1082
+ handleNewTopic(ev) {
1083
+ this.addJoinedRoomTopics(ev.roomId, ev.topic);
1084
+ }
1085
+ addJoinedRoomTopics(roomId, ...topics) {
1086
+ if (this.topics.has(roomId)) {
1087
+ this.topics.get(roomId).set(...topics);
1088
+ } else {
1089
+ this.topics.set([roomId, new ObservableIndexedObjectCollection('id', topics)]);
1090
+ }
1091
+ }
1092
+ handleRoomJoined(ev) {
1093
+ this.addJoinedRooms(ev.room);
1094
+ }
1095
+ handleRoomUpdated(ev) {
1096
+ this.list.set(ev.room);
1097
+ }
1098
+ handleRoomDeleted(ev) {
1099
+ this.deleteRoom(ev.id);
1100
+ }
1101
+ handleTopicUpdated(ev) {
1102
+ const room = this.list.get(ev.location.roomId);
1103
+ if (this.topics.get(ev.location.roomId)?.has(ev.topic.id)) {
1104
+ this.topics.get(ev.location.roomId).set(ev.topic);
1105
+ }
1106
+ if (room.defaultTopic.id === ev.topic.id) {
1107
+ room.defaultTopic = ev.topic;
1108
+ this.list.set(room);
1109
+ }
1110
+ }
1111
+ addJoinedRooms(...rooms) {
1112
+ for (const room of rooms) {
1113
+ if (room.defaultTopic) {
1114
+ this.addJoinedRoomTopics(room.id, room.defaultTopic);
1115
+ }
1116
+ if (room.type === 'Pm' && room.recipients) {
1117
+ // Treat PM recipients as normal room members.
1118
+ // We are registering fake promise in `memberPromises`
1119
+ // because GetMembers are not supported for PM rooms.
1120
+ this.handleRoomMembers({
1121
+ id: room.id,
1122
+ members: room.recipients.map(user => ({
1123
+ user,
1124
+ spaceMember: null,
1125
+ roles: null
1126
+ }))
1127
+ });
1128
+ this.membersPromises.register(Promise.resolve(), room.id);
1129
+ }
1130
+ }
1131
+ this.list.set(...rooms);
1132
+ }
1133
+ handleRoomLeft(ev) {
1134
+ this.deleteRoom(ev.id);
1135
+ }
1136
+ handleRoomMemberJoined(ev) {
1137
+ if (this.members.has(ev.roomId)) {
1138
+ this.members.get(ev.roomId).set(ev.member);
1139
+ }
1140
+ }
1141
+ handleRoomMemberLeft(ev) {
1142
+ if (this.members.has(ev.roomId)) {
1143
+ this.members.get(ev.roomId).delete(ev.userId);
1144
+ }
1145
+ }
1146
+ handleRoomMembers(ev) {
1147
+ if (!this.members.has(ev.id)) {
1148
+ this.members.set([ev.id, new ObservableIndexedObjectCollection(member => member.user?.id ?? member.spaceMember.user.id, ev.members)]);
1149
+ }
1150
+ }
1151
+ handleSession(ev) {
1152
+ this.list.deleteAll();
1153
+ this.topics.deleteAll();
1154
+ this.topicsPromises.forgetAll();
1155
+ this.members.deleteAll();
1156
+ this.membersPromises.forgetAll();
1157
+ this.addJoinedRooms(...ev.state.rooms);
1158
+ this.deferredSession.resolve();
1159
+ }
1160
+ handleUserUpdated(ev) {
1161
+ this.members.items.forEach(members => {
1162
+ const member = members.get(ev.user.id);
1163
+ if (!member) {
1164
+ // Skip room; updated user is not here
1165
+ return;
1166
+ }
1167
+ const newMember = {
1168
+ ...member
1169
+ };
1170
+ if (member.user) {
1171
+ newMember.user = ev.user;
1172
+ } else {
1173
+ newMember.spaceMember.user = ev.user;
1174
+ }
1175
+ members.set(newMember);
1176
+ });
1177
+ }
1178
+ handleNewMessage(ev) {
1179
+ const topics = this.topics.get(ev.message.location.roomId);
1180
+ const topic = topics?.get(ev.message.location.topicId);
1181
+ if (topic) {
1182
+ topics.set({
1183
+ ...topic,
1184
+ messageCount: topic.messageCount + 1,
1185
+ lastMessage: ev.message
1186
+ });
1187
+ }
1188
+ }
1189
+ }
1190
+ ;// CONCATENATED MODULE: ./src/state-tracker/functions.ts
1191
+ function reorderRolesOnPriorityUpdate(allRoles, oldRole, updatedRole) {
1192
+ // If the priority has changed, adjust the rest of roles
1193
+ const increased = updatedRole.priority - oldRole.priority > 0;
1194
+ const decreased = !increased;
1195
+ const changedRoles = [];
1196
+ allRoles.forEach(role => {
1197
+ if (role.id === updatedRole.id) {
1198
+ // Skip the updated role
1199
+ return;
1200
+ }
1201
+ if (increased && oldRole.priority <= role.priority) {
1202
+ role.priority--;
1203
+ changedRoles.push(role);
1204
+ }
1205
+ if (decreased && updatedRole.priority <= role.priority) {
1206
+ role.priority++;
1207
+ changedRoles.push(role);
1208
+ }
1209
+ });
1210
+ return changedRoles;
1211
+ }
1212
+ function extractUserFromMember(member) {
1213
+ return member.user ?? member.spaceMember?.user;
1214
+ }
1215
+ ;// CONCATENATED MODULE: ./src/state-tracker/SpacesManager.ts
1216
+ function SpacesManager_defineProperty(obj, key, value) { key = SpacesManager_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1217
+ function SpacesManager_toPropertyKey(arg) { var key = SpacesManager_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1218
+ function SpacesManager_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1219
+
1220
+
1221
+
1222
+ class SpacesManager {
1223
+ constructor(tracker) {
1224
+ this.tracker = tracker;
1225
+ SpacesManager_defineProperty(this, "list", new ObservableIndexedObjectCollection('id'));
1226
+ SpacesManager_defineProperty(this, "roles", new IndexedCollection());
1227
+ SpacesManager_defineProperty(this, "rooms", new IndexedCollection());
1228
+ SpacesManager_defineProperty(this, "roomIdToSpaceId", new IndexedCollection());
1229
+ SpacesManager_defineProperty(this, "members", new IndexedCollection());
1230
+ SpacesManager_defineProperty(this, "deferredSession", new DeferredTask());
1231
+ SpacesManager_defineProperty(this, "roomsPromises", new PromiseRegistry());
1232
+ SpacesManager_defineProperty(this, "membersPromises", new PromiseRegistry());
1233
+ this.tracker.client.on('NewRoom', ev => this.handleNewRoom(ev));
1234
+ this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
1235
+ this.tracker.client.on('RoomUpdated', ev => this.handleRoomUpdated(ev));
1236
+ this.tracker.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
1237
+ this.tracker.client.on('SpaceUpdated', ev => this.handleSpaceUpdated(ev));
1238
+ this.tracker.client.on('SpaceJoined', ev => this.handleSpaceJoined(ev));
1239
+ this.tracker.client.on('SpaceLeft', ev => this.handleSpaceDeleted(ev));
1240
+ this.tracker.client.on('SpaceMemberJoined', ev => this.handleSpaceMemberJoined(ev));
1241
+ this.tracker.client.on('SpaceMemberLeft', ev => this.handleSpaceMemberLeft(ev));
1242
+ this.tracker.client.on('SpaceMembers', ev => this.handleSpaceMembers(ev));
1243
+ this.tracker.client.on('SpaceRooms', ev => this.handleSpaceRooms(ev));
1244
+ this.tracker.client.on('SpaceMemberUpdated', ev => this.handleSpaceMemberUpdated(ev));
1245
+ this.tracker.client.on('UserUpdated', ev => this.handleUserUpdated(ev));
1246
+ this.tracker.client.on('NewRole', ev => this.handleNewRole(ev));
1247
+ this.tracker.client.on('RoleDeleted', ev => this.handleRoleDeleted(ev));
1248
+ this.tracker.client.on('RoleUpdated', ev => this.handleRoleUpdated(ev));
1249
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
1250
+ }
1251
+
1252
+ /**
1253
+ * Get collection of all the spaces you are in.
1254
+ */
1255
+ async get() {
1256
+ await this.deferredSession.promise;
1257
+ return this.list;
1258
+ }
1259
+
1260
+ /**
1261
+ * Get collection of space roles.
1262
+ */
1263
+ async getRoles(spaceId) {
1264
+ await this.deferredSession.promise;
1265
+ return this.roles.get(spaceId);
1266
+ }
1267
+
1268
+ /**
1269
+ * Get collection of the all available rooms inside given space.
1270
+ */
1271
+ async getRooms(spaceId) {
1272
+ if (this.roomsPromises.notExist(spaceId)) {
1273
+ this.roomsPromises.registerByFunction(async () => {
1274
+ const result = await this.tracker.client.send('GetSpaceRooms', {
1275
+ id: spaceId
1276
+ });
1277
+ if (result.error) {
1278
+ throw result.error;
1279
+ }
1280
+ this.handleSpaceRooms(result.data);
1281
+ }, spaceId);
1282
+ }
1283
+ await this.roomsPromises.get(spaceId);
1284
+ return this.rooms.get(spaceId);
1285
+ }
1286
+
1287
+ /**
1288
+ * Get collection of space members.
1289
+ */
1290
+ async getMembers(spaceId) {
1291
+ if (this.membersPromises.notExist(spaceId)) {
1292
+ this.membersPromises.registerByFunction(async () => {
1293
+ const result = await this.tracker.client.send('GetSpaceMembers', {
1294
+ id: spaceId
1295
+ });
1296
+ if (result.error) {
1297
+ throw result.error;
1298
+ }
1299
+ this.handleSpaceMembers(result.data);
1300
+ }, spaceId);
1301
+ }
1302
+ await this.membersPromises.get(spaceId);
1303
+ return this.members.get(spaceId);
1304
+ }
1305
+
1306
+ /**
1307
+ * Get a space member representing the current user.
1308
+ */
1309
+ async getMe(spaceId) {
1310
+ const userId = (await this.tracker.getMe()).id;
1311
+ if (!this.list.has(spaceId)) {
1312
+ // User is not in passed space.
1313
+ return undefined;
1314
+ }
1315
+ const members = await this.getMembers(spaceId);
1316
+ return members?.items.find(member => member.user.id === userId);
1317
+ }
1318
+ handleNewRole(ev) {
1319
+ const collection = this.roles.get(ev.spaceId);
1320
+ collection.set(ev.role);
1321
+ this.list.get(ev.spaceId).roles = collection.items;
1322
+ }
1323
+ handleNewRoom(ev) {
1324
+ this.rooms.get(ev.spaceId)?.set(ev.summary);
1325
+ this.roomIdToSpaceId.set([ev.summary.id, ev.spaceId]);
1326
+ }
1327
+ handleRoomUpdated(ev) {
1328
+ if (ev.room.spaceId && this.rooms.has(ev.room.spaceId)) {
1329
+ const rooms = this.rooms.get(ev.room.spaceId);
1330
+ rooms.set({
1331
+ ...rooms.get(ev.room.id),
1332
+ name: ev.room.name,
1333
+ description: ev.room.description
1334
+ });
1335
+ }
1336
+ }
1337
+ async handleRoomDeleted(ev) {
1338
+ const spaceId = this.roomIdToSpaceId.get(ev.id);
1339
+ this.roomIdToSpaceId.delete(ev.id);
1340
+ if (!spaceId) {
1341
+ return;
1342
+ }
1343
+ const space = this.list.get(spaceId);
1344
+ let spaceChanged = false;
1345
+ this.rooms.get(spaceId)?.delete(ev.id);
1346
+ if (space.systemRoom === ev.id) {
1347
+ space.systemRoom = null;
1348
+ spaceChanged = true;
1349
+ }
1350
+ if (space.defaultRooms.includes(ev.id)) {
1351
+ space.defaultRooms = space.defaultRooms.filter(roomId => roomId !== ev.id);
1352
+ spaceChanged = true;
1353
+ }
1354
+ if (spaceChanged) {
1355
+ this.list.set(space);
1356
+ }
1357
+ }
1358
+ handleRoleDeleted(ev) {
1359
+ const collection = this.roles.get(ev.spaceId);
1360
+ collection.delete(ev.id);
1361
+ this.list.get(ev.spaceId).roles = collection.items;
1362
+ }
1363
+ handleSpaceUpdated(ev) {
1364
+ this.list.set(ev.space);
1365
+ }
1366
+ handleSpaceDeleted(ev) {
1367
+ const roomIds = this.rooms.get(ev.id)?.items.map(item => item.id) ?? [];
1368
+ this.roomIdToSpaceId.delete(...roomIds);
1369
+ this.roles.delete(ev.id);
1370
+ this.members.delete(ev.id);
1371
+ this.membersPromises.forget(ev.id);
1372
+ this.rooms.delete(ev.id);
1373
+ this.roomsPromises.forget(ev.id);
1374
+ this.list.delete(ev.id);
1375
+ }
1376
+ handleSpaceJoined(ev) {
1377
+ this.addJoinedSpaces(ev.space);
1378
+ }
1379
+ addJoinedSpaces(...spaces) {
1380
+ this.roles.set(...spaces.map(space => [space.id, new ObservableIndexedObjectCollection('id', space.roles)]));
1381
+ this.list.set(...spaces);
1382
+ }
1383
+ handleSpaceMemberJoined(ev) {
1384
+ if (this.members.has(ev.spaceId)) {
1385
+ this.members.get(ev.spaceId).set(ev.member);
1386
+ }
1387
+ }
1388
+ handleSpaceMemberLeft(ev) {
1389
+ if (this.members.has(ev.spaceId)) {
1390
+ this.members.get(ev.spaceId).delete(ev.userId);
1391
+ }
1392
+ }
1393
+ handleSpaceMembers(ev) {
1394
+ if (!this.members.has(ev.id)) {
1395
+ this.members.set([ev.id, new ObservableIndexedObjectCollection(member => member?.user.id, ev.members)]);
1396
+ }
1397
+ }
1398
+ handleSpaceRooms(ev) {
1399
+ if (!this.rooms.has(ev.id)) {
1400
+ this.rooms.set([ev.id, new ObservableIndexedObjectCollection('id', ev.summaries)]);
1401
+ ev.summaries.forEach(summary => this.roomIdToSpaceId.set([summary.id, ev.id]));
1402
+ }
1403
+ }
1404
+ handleSpaceMemberUpdated(ev) {
1405
+ if (this.members.has(ev.spaceId)) {
1406
+ const members = this.members.get(ev.spaceId);
1407
+ const member = members.get(ev.userId);
1408
+ members.set({
1409
+ ...ev.member,
1410
+ user: member.user
1411
+ });
1412
+ }
1413
+ }
1414
+ handleRoleUpdated(ev) {
1415
+ const roles = this.roles.get(ev.spaceId);
1416
+ const oldRole = roles.get(ev.role.id);
1417
+ const newRole = ev.role;
1418
+ const rolesToUpdate = [newRole];
1419
+ if (oldRole.priority !== newRole.priority) {
1420
+ rolesToUpdate.push(...reorderRolesOnPriorityUpdate(roles.items, oldRole, newRole));
1421
+ }
1422
+ this.roles.get(ev.spaceId).set(...rolesToUpdate);
1423
+ }
1424
+ handleSession(ev) {
1425
+ this.list.deleteAll();
1426
+ this.roles.deleteAll();
1427
+ this.rooms.deleteAll();
1428
+ this.roomsPromises.forgetAll();
1429
+ this.members.deleteAll();
1430
+ this.membersPromises.forgetAll();
1431
+ this.roomIdToSpaceId.deleteAll();
1432
+ this.addJoinedSpaces(...ev.state.spaces);
1433
+ this.deferredSession.resolve();
1434
+ }
1435
+ handleUserUpdated(ev) {
1436
+ this.members.items.forEach(members => {
1437
+ const member = members.get(ev.user.id);
1438
+ if (!member) {
1439
+ // Skip space; updated user is not here
1440
+ return;
1441
+ }
1442
+ members.set({
1443
+ ...member,
1444
+ user: ev.user
1445
+ });
1446
+ });
1447
+ }
1448
+ }
1449
+ ;// CONCATENATED MODULE: ./src/Permissions.ts
1450
+ function Permissions_defineProperty(obj, key, value) { key = Permissions_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1451
+ function Permissions_toPropertyKey(arg) { var key = Permissions_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1452
+ function Permissions_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1453
+ let Layer = /*#__PURE__*/function (Layer) {
1454
+ Layer[Layer["Global"] = 0] = "Global";
1455
+ Layer[Layer["Space"] = 1] = "Space";
1456
+ Layer[Layer["Room"] = 2] = "Room";
1457
+ Layer[Layer["Topic"] = 3] = "Topic";
1458
+ return Layer;
1459
+ }({});
1460
+ class PermissionDefinition {
1461
+ constructor() {
1462
+ Permissions_defineProperty(this, "value", void 0);
1463
+ Permissions_defineProperty(this, "maxLayer", void 0);
1464
+ }
1465
+ }
1466
+ class Permissions {
1467
+ static getNames() {
1468
+ return Object.keys(this.list);
1469
+ }
1470
+ static getByName(name) {
1471
+ return this.list[name];
1472
+ }
1473
+ static canBeDefinedOnLayer(permissionName, layer) {
1474
+ const def = this.getByName(permissionName);
1475
+ if (!def) {
1476
+ throw new Error(`Invalid permission name: ${permissionName}`);
1477
+ }
1478
+ return layer <= this.getByName(permissionName).maxLayer;
1479
+ }
1480
+ }
1481
+ Permissions_defineProperty(Permissions, "list", {
1482
+ Root: {
1483
+ value: 1 << 0,
1484
+ maxLayer: Layer.Room
1485
+ },
1486
+ CreateSpaces: {
1487
+ value: 1 << 1,
1488
+ maxLayer: Layer.Global
1489
+ },
1490
+ ManageSpace: {
1491
+ value: 1 << 2,
1492
+ maxLayer: Layer.Space
1493
+ },
1494
+ ManageSpaceRoles: {
1495
+ value: 1 << 3,
1496
+ maxLayer: Layer.Space
1497
+ },
1498
+ ManageRoom: {
1499
+ value: 1 << 4,
1500
+ maxLayer: Layer.Room
1501
+ },
1502
+ CreateTopics: {
1503
+ value: 1 << 5,
1504
+ maxLayer: Layer.Room
1505
+ },
1506
+ ManageTopic: {
1507
+ value: 1 << 6,
1508
+ maxLayer: Layer.Topic
1509
+ },
1510
+ ManageSpaceMembers: {
1511
+ value: 1 << 7,
1512
+ maxLayer: Layer.Space
1513
+ },
1514
+ ManageRoomMembers: {
1515
+ value: 1 << 8,
1516
+ maxLayer: Layer.Room
1517
+ },
1518
+ CreateMessages: {
1519
+ value: 1 << 9,
1520
+ maxLayer: Layer.Topic
1521
+ },
1522
+ ManagePermissions: {
1523
+ value: 1 << 10,
1524
+ maxLayer: Layer.Topic
1525
+ },
1526
+ CreateSpaceRooms: {
1527
+ value: 1 << 11,
1528
+ maxLayer: Layer.Space
1529
+ },
1530
+ ManageSpaceRooms: {
1531
+ value: 1 << 12,
1532
+ maxLayer: Layer.Space
1533
+ },
1534
+ CreateEmoticons: {
1535
+ value: 1 << 13,
1536
+ maxLayer: Layer.Space
1537
+ },
1538
+ ManageEmoticon: {
1539
+ value: 1 << 14,
1540
+ maxLayer: Layer.Space
1541
+ },
1542
+ ManageBan: {
1543
+ value: 1 << 15,
1544
+ maxLayer: Layer.Room
1545
+ },
1546
+ Kick: {
1547
+ value: 1 << 16,
1548
+ maxLayer: Layer.Room
1549
+ },
1550
+ ChangeOwnNick: {
1551
+ value: 1 << 17,
1552
+ maxLayer: Layer.Space
1553
+ }
1554
+ });
1555
+ ;// CONCATENATED MODULE: ./src/state-tracker/PermissionsManager.ts
1556
+ function PermissionsManager_defineProperty(obj, key, value) { key = PermissionsManager_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1557
+ function PermissionsManager_toPropertyKey(arg) { var key = PermissionsManager_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1558
+ function PermissionsManager_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1559
+
1560
+
1561
+
1562
+
1563
+ const getOvId = (location, target) => [location.spaceId, location.roomId, location.topicId, target?.type, target?.userId, target?.roleId].filter(Boolean).join('/');
1564
+ const getOvIdByObject = overwrites => getOvId(overwrites.location, overwrites.target);
1565
+ class PermissionsManager extends EventTarget {
1566
+ constructor(tracker) {
1567
+ super();
1568
+ this.tracker = tracker;
1569
+ PermissionsManager_defineProperty(this, "overwrites", new IndexedCollection());
1570
+ PermissionsManager_defineProperty(this, "overwritesPromises", new PromiseRegistry());
1571
+ this.tracker.client.on('PermissionOverwrites', ev => this.handlePermissionOverwrites(ev));
1572
+ this.tracker.client.on('PermissionOverwritesUpdated', ev => this.handlePermissionOverwrites(ev));
1573
+ this.tracker.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
1574
+ this.tracker.client.on('SpaceLeft', ev => this.handleSpaceDeleted(ev));
1575
+ this.tracker.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
1576
+ this.tracker.client.on('RoomLeft', ev => this.handleRoomDeleted(ev));
1577
+ this.tracker.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
1578
+ this.tracker.client.on('RoleDeleted', ev => this.handleRoleDeleted(ev));
1579
+ this.tracker.client.on('SpaceMemberUpdated', ev => this.handleSpaceMemberUpdated(ev));
1580
+ this.tracker.client.on('RoomMemberUpdated', ev => this.handleRoomMemberUpdated(ev));
1581
+ this.tracker.client.on('Session', ev => this.handleSession(ev));
1582
+ }
1583
+ async getOverwrites(location, target) {
1584
+ this.validateLocation(location);
1585
+ const id = getOvId(location, target);
1586
+ if (this.overwritesPromises.notExist(id)) {
1587
+ this.overwritesPromises.registerByFunction(async () => {
1588
+ const result = await this.tracker.client.send('GetPermissionOverwrites', {
1589
+ location,
1590
+ target
1591
+ });
1592
+ if (result.error) {
1593
+ throw result.error;
1594
+ }
1595
+ this.handlePermissionOverwrites(result.data);
1596
+ }, id);
1597
+ }
1598
+ await this.overwritesPromises.get(id);
1599
+ return this.overwrites.get(id);
1600
+ }
1601
+ on(eventName, handler) {
1602
+ return super.on(eventName, handler);
1603
+ }
1604
+ async check(permissionNames, location) {
1605
+ if (!permissionNames.length) {
1606
+ throw new Error('Permission names array cannot be empty');
1607
+ }
1608
+ const ownedPermissions = await this.calculatePermissions(location);
1609
+ const missing = [];
1610
+ permissionNames.forEach(name => {
1611
+ if (~ownedPermissions & Permissions.getByName(name).value) {
1612
+ missing.push(name);
1613
+ }
1614
+ });
1615
+ return {
1616
+ ok: missing.length === 0,
1617
+ hasAll: missing.length === 0,
1618
+ hasAny: missing.length < permissionNames.length,
1619
+ missing
1620
+ };
1621
+ }
1622
+ async calculatePermissions(location) {
1623
+ this.validateLocation(location);
1624
+ const userId = (await this.tracker.getMe()).id;
1625
+ const [spaceMember, roomMember] = await this.fetchMembersOrFail(location);
1626
+ const userRoles = [...(spaceMember?.roles ?? []), ...(roomMember?.roles ?? [])];
1627
+ const promises = [
1628
+ // Global user overwrites
1629
+ this.getOverwrites({}, {
1630
+ type: 'User',
1631
+ userId
1632
+ }).then(v => v.overwrites)];
1633
+ if (location.spaceId && (await this.tracker.spaces.get())?.has(location.spaceId)) {
1634
+ const filterLocation = {
1635
+ spaceId: location.spaceId
1636
+ };
1637
+ promises.push(this.collectRoleOverwrites(filterLocation, userRoles));
1638
+ promises.push(this.getOverwrites(filterLocation, {
1639
+ type: 'User',
1640
+ userId
1641
+ }).then(v => v.overwrites));
1642
+ }
1643
+ if (location.roomId && (await this.tracker.rooms.get())?.has(location.roomId)) {
1644
+ const filterLocation = {
1645
+ spaceId: location.spaceId,
1646
+ roomId: location.roomId
1647
+ };
1648
+ if (userRoles.length) {
1649
+ promises.push(this.collectRoleOverwrites(filterLocation, userRoles));
1650
+ }
1651
+ promises.push(this.getOverwrites(filterLocation, {
1652
+ type: 'User',
1653
+ userId
1654
+ }).then(v => v.overwrites));
1655
+ }
1656
+ if (location.topicId && (await this.tracker.rooms.getTopics(location.roomId))?.has(location.topicId)) {
1657
+ if (userRoles.length) {
1658
+ promises.push(this.collectRoleOverwrites(location, userRoles));
1659
+ }
1660
+ promises.push(this.getOverwrites(location, {
1661
+ type: 'User',
1662
+ userId
1663
+ }).then(v => v.overwrites));
1664
+ }
1665
+ return this.resolveOverwritesHierarchy(await Promise.all(promises));
1666
+ }
1667
+ handlePermissionOverwrites(ev) {
1668
+ this.overwrites.set([getOvIdByObject(ev), ev]);
1669
+ this.emit('change');
1670
+ }
1671
+ handleSpaceDeleted(ev) {
1672
+ const ids = this.deleteOverwritesByIdPrefix(getOvId({
1673
+ spaceId: ev.id
1674
+ }));
1675
+ this.overwritesPromises.forget(...ids);
1676
+ }
1677
+ async handleRoomDeleted(ev) {
1678
+ const room = (await this.tracker.rooms.get()).get(ev.id);
1679
+ if (room) {
1680
+ const ids = this.deleteOverwritesByIdPrefix(getOvId({
1681
+ spaceId: room.spaceId,
1682
+ roomId: room.id
1683
+ }));
1684
+ this.overwritesPromises.forget(...ids);
1685
+ }
1686
+ }
1687
+ handleTopicDeleted(ev) {
1688
+ const ids = this.deleteOverwritesByIdPrefix(getOvId(ev.location));
1689
+ this.overwritesPromises.forget(...ids);
1690
+ }
1691
+ handleRoleDeleted(ev) {
1692
+ const ids = this.deleteOverwritesByIdPrefix(getOvId({
1693
+ spaceId: ev.spaceId
1694
+ }, {
1695
+ type: 'Role',
1696
+ roleId: ev.id
1697
+ }));
1698
+ this.overwritesPromises.forget(...ids);
1699
+ }
1700
+ handleSpaceMemberUpdated(ev) {
1701
+ if (ev.userId === this.tracker.me?.id) {
1702
+ // User roles in space could potentially have changed
1703
+ this.emit('change');
1704
+ }
1705
+ }
1706
+ handleRoomMemberUpdated(ev) {
1707
+ if (ev.userId === this.tracker.me?.id) {
1708
+ // User roles in room could potentially have changed
1709
+ this.emit('change');
1710
+ }
1711
+ }
1712
+
1713
+ /**
1714
+ * @return Matched and deleted ids
1715
+ */
1716
+ deleteOverwritesByIdPrefix(prefix) {
1717
+ const ids = [];
1718
+ this.overwrites.items.forEach(overwrites => {
1719
+ const id = getOvIdByObject(overwrites);
1720
+ if (id.startsWith(prefix)) {
1721
+ ids.push(id);
1722
+ this.overwrites.delete(id);
1723
+ }
1724
+ });
1725
+ return ids;
1726
+ }
1727
+ async collectRoleOverwrites(location, userRoles) {
1728
+ const roleOverwrites = await Promise.all(userRoles.map(roleId => this.getOverwrites(location, {
1729
+ type: 'Role',
1730
+ roleId
1731
+ })));
1732
+ return this.resolveOverwritesFromRolesByOrder(location.spaceId, roleOverwrites);
1733
+ }
1734
+ async resolveOverwritesFromRolesByOrder(spaceId, overwrites) {
1735
+ let allows = 0,
1736
+ denies = 0;
1737
+ const roles = await this.tracker.spaces.getRoles(spaceId);
1738
+ const sortedOverwrites = overwrites.sort((a, b) => roles.get(a.target.roleId).priority - roles.get(b.target.roleId).priority);
1739
+
1740
+ // Max length of bit word
1741
+ const permissionsLength = overwrites.reduce((previousValue, currentValue) => Math.max(previousValue, currentValue.overwrites.allow?.toString(2).length ?? 0, currentValue.overwrites.deny?.toString(2).length ?? 0), 0);
1742
+ sortedOverwrites.forEach(overwriteEvent => {
1743
+ const overwrites = overwriteEvent.overwrites;
1744
+ const revDecDenies = overwrites.deny?.toString(2).split('').reverse().join('') ?? '';
1745
+ const revDecAllows = overwrites.allow?.toString(2).split('').reverse().join('') ?? '';
1746
+ for (let i = 0; i < permissionsLength; i++) {
1747
+ const deny = parseInt(revDecDenies[i] ?? '0');
1748
+ const allow = parseInt(revDecAllows[i] ?? '0');
1749
+ if (deny) {
1750
+ denies |= 1 << i;
1751
+ }
1752
+ if (allow) {
1753
+ allows |= 1 << i;
1754
+ }
1755
+ }
1756
+ });
1757
+ return {
1758
+ allow: allows,
1759
+ deny: denies
1760
+ };
1761
+ }
1762
+ resolveOverwritesHierarchy(permissionOverwritesValues) {
1763
+ let result = 0;
1764
+ for (const value of permissionOverwritesValues) {
1765
+ if (value.allow & Permissions.getByName('Root').value) {
1766
+ return this.getRootAccessValue();
1767
+ }
1768
+ result = result & ~value.deny | value.allow;
1769
+ }
1770
+ return result;
1771
+ }
1772
+ getRootAccessValue() {
1773
+ let result = 0;
1774
+ for (const name of Permissions.getNames()) {
1775
+ result |= Permissions.getByName(name).value;
1776
+ }
1777
+ return result;
1778
+ }
1779
+ async fetchMembersOrFail(location) {
1780
+ const results = await Promise.all([location.spaceId ? this.tracker.spaces.getMe(location.spaceId) : null, location.roomId ? this.tracker.rooms.getMe(location.roomId) : null]);
1781
+ const spaceFail = location.spaceId && !results[0];
1782
+ const roomFail = location.roomId && !results[1];
1783
+ if (spaceFail || roomFail) {
1784
+ const layer = spaceFail ? `space (${location.spaceId})` : `room (${location.roomId})`;
1785
+ throw new Error(`Attempting to calculate permissions for a ${layer} that the user does not belong to`);
1786
+ }
1787
+ return results;
1788
+ }
1789
+ validateLocation(location) {
1790
+ if (location.topicId && !location.roomId) {
1791
+ throw new Error('Corrupted arguments hierarchy');
1792
+ }
1793
+ }
1794
+ handleSession(ev) {
1795
+ this.overwrites.deleteAll();
1796
+ this.overwritesPromises.forgetAll();
1797
+ }
1798
+ }
1799
+ ;// CONCATENATED MODULE: ./src/state-tracker/EmoticonsManager.ts
1800
+ function EmoticonsManager_defineProperty(obj, key, value) { key = EmoticonsManager_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1801
+ function EmoticonsManager_toPropertyKey(arg) { var key = EmoticonsManager_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1802
+ function EmoticonsManager_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1803
+
1804
+
1805
+ const GLOBAL_KEY = 'global';
1806
+ class EmoticonsManager {
1807
+ constructor(tracker) {
1808
+ this.tracker = tracker;
1809
+ EmoticonsManager_defineProperty(this, "list", new IndexedCollection());
1810
+ EmoticonsManager_defineProperty(this, "emoticonsPromises", new PromiseRegistry());
1811
+ this.tracker.client.on('Emoticons', ev => this.handleEmoticons(ev));
1812
+ this.tracker.client.on('NewEmoticon', ev => this.handleNewEmoticon(ev));
1813
+ this.tracker.client.on('EmoticonDeleted', ev => this.handleEmoticonDeleted(ev));
1814
+ this.tracker.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
1815
+ this.tracker.client.on('Session', () => this.handleSession());
1816
+ }
1817
+ async get(spaceId) {
1818
+ if (this.emoticonsPromises.notExist(spaceId)) {
1819
+ this.emoticonsPromises.registerByFunction(async () => {
1820
+ const result = await this.tracker.client.send('GetEmoticons', {
1821
+ spaceId
1822
+ });
1823
+ if (result.error) {
1824
+ throw result.error;
1825
+ }
1826
+ this.handleEmoticons(result.data);
1827
+ }, spaceId ?? GLOBAL_KEY);
1828
+ }
1829
+ await this.emoticonsPromises.get(spaceId);
1830
+ return this.list.get(spaceId);
1831
+ }
1832
+ handleEmoticons(event) {
1833
+ const spaceId = event.location.spaceId ?? GLOBAL_KEY;
1834
+ if (!this.list.has(spaceId)) {
1835
+ this.list.set([spaceId, new ObservableIndexedObjectCollection('id')]);
1836
+ }
1837
+ const collection = this.list.get(spaceId);
1838
+ collection.set(...event.emoticons);
1839
+ }
1840
+ handleNewEmoticon(ev) {
1841
+ const collection = this.list.get(ev.emoticon.spaceId ?? GLOBAL_KEY);
1842
+ collection?.set(ev.emoticon);
1843
+ }
1844
+ handleEmoticonDeleted(ev) {
1845
+ const collection = this.list.get(ev.spaceId ?? GLOBAL_KEY);
1846
+ collection?.delete(ev.emoticonId);
1847
+ }
1848
+ handleSpaceDeleted(event) {
1849
+ this.list.delete(event.id);
1850
+ }
1851
+ handleSession() {
1852
+ this.list.deleteAll();
1853
+ this.emoticonsPromises.forgetAll();
1854
+ }
1855
+ }
1856
+ ;// CONCATENATED MODULE: ./src/state-tracker/UsersManager.ts
1857
+ function UsersManager_defineProperty(obj, key, value) { key = UsersManager_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1858
+ function UsersManager_toPropertyKey(arg) { var key = UsersManager_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1859
+ function UsersManager_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1860
+
1861
+
1862
+ class UsersManager {
1863
+ constructor(tracker) {
1864
+ this.tracker = tracker;
1865
+ UsersManager_defineProperty(this, "users", new ObservableIndexedObjectCollection('id'));
1866
+ // RoomMemberUpdated & SpaceMemberUpdated events are not contains user object
1867
+ tracker.client.on('UserUpdated', event => this.handleUsers([event.user]));
1868
+ tracker.client.on('RoomMemberJoined', event => this.handleMembers([event.member]));
1869
+ tracker.client.on('SpaceMemberJoined', event => this.handleMembers([event.member]));
1870
+ tracker.client.on('SpaceMembers', event => this.handleMembers(event.members));
1871
+ tracker.client.on('RoomMembers', event => this.handleMembers(event.members));
1872
+ tracker.client.on('Messages', event => this.handleUsers(event.messages.map(message => message.author.user)));
1873
+ tracker.client.on('NewMessage', event => this.handleUsers([event.message.author.user]));
1874
+ tracker.client.on('Session', event => this.handleSession(event));
1875
+ }
1876
+
1877
+ /**
1878
+ * Get all available (cached) user objects at once.
1879
+ */
1880
+ async getAvailable() {
1881
+ return this.users;
1882
+ }
1883
+ handleMembers(members) {
1884
+ this.users.set(...members.map(extractUserFromMember));
1885
+ }
1886
+ handleUsers(users) {
1887
+ this.users.set(...users);
1888
+ }
1889
+ handleSession(session) {
1890
+ this.users.deleteAll();
1891
+ this.users.set(session.user);
1892
+ }
1893
+ }
1894
+ ;// CONCATENATED MODULE: ./src/state-tracker/ChatStateTracker.ts
1895
+ function ChatStateTracker_defineProperty(obj, key, value) { key = ChatStateTracker_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1896
+ function ChatStateTracker_toPropertyKey(arg) { var key = ChatStateTracker_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1897
+ function ChatStateTracker_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1898
+
1899
+
1900
+
1901
+
1902
+
1903
+
1904
+ class ChatStateTracker {
1905
+ constructor(client) {
1906
+ this.client = client;
1907
+ /**
1908
+ * State of your permissions.
1909
+ */
1910
+ ChatStateTracker_defineProperty(this, "permissions", new PermissionsManager(this));
1911
+ /**
1912
+ * State of the rooms you are in.
1913
+ */
1914
+ ChatStateTracker_defineProperty(this, "rooms", new RoomsManager(this));
1915
+ /**
1916
+ * State of the spaces you are in.
1917
+ */
1918
+ ChatStateTracker_defineProperty(this, "spaces", new SpacesManager(this));
1919
+ /**
1920
+ * State of the emoticons (global and space-related).
1921
+ */
1922
+ ChatStateTracker_defineProperty(this, "emoticons", new EmoticonsManager(this));
1923
+ /**
1924
+ * Users related state.
1925
+ */
1926
+ ChatStateTracker_defineProperty(this, "users", new UsersManager(this));
1927
+ ChatStateTracker_defineProperty(this, "_me", null);
1928
+ ChatStateTracker_defineProperty(this, "deferredSession", new DeferredTask());
1929
+ this.client.on('Session', ev => this.handleSession(ev));
1930
+ }
1931
+ get me() {
1932
+ return this._me;
1933
+ }
1934
+ async getMe() {
1935
+ await this.deferredSession.promise;
1936
+ return this._me;
1937
+ }
1938
+ handleSession(ev) {
1939
+ this._me = ev.user;
1940
+ this.deferredSession.resolve();
1941
+ }
1942
+ }
1943
+ ;// CONCATENATED MODULE: ./src/WebSocketChatClient.ts
1944
+ function WebSocketChatClient_defineProperty(obj, key, value) { key = WebSocketChatClient_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1945
+ function WebSocketChatClient_toPropertyKey(arg) { var key = WebSocketChatClient_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
1946
+ function WebSocketChatClient_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1947
+
1948
+
1949
+ var WebSocketChatClientEvent = /*#__PURE__*/function (WebSocketChatClientEvent) {
1950
+ WebSocketChatClientEvent["connect"] = "connect";
1951
+ WebSocketChatClientEvent["disconnect"] = "disconnect";
1952
+ WebSocketChatClientEvent["message"] = "message";
1953
+ WebSocketChatClientEvent["error"] = "error";
1954
+ return WebSocketChatClientEvent;
1955
+ }(WebSocketChatClientEvent || {});
1956
+ class WebSocketChatClient extends AbstractChatClient {
1957
+ constructor(options) {
1958
+ super();
1959
+ this.options = options;
1960
+ WebSocketChatClient_defineProperty(this, "Event", WebSocketChatClientEvent);
1961
+ WebSocketChatClient_defineProperty(this, "state", void 0);
1962
+ WebSocketChatClient_defineProperty(this, "ws", null);
1963
+ WebSocketChatClient_defineProperty(this, "sendQueue", []);
1964
+ WebSocketChatClient_defineProperty(this, "connectingTimeoutId", void 0);
1965
+ WebSocketChatClient_defineProperty(this, "authenticated", void 0);
1966
+ WebSocketChatClient_defineProperty(this, "authenticatedResolvers", void 0);
1967
+ if (this.options.stateTracking ?? true) {
1968
+ this.state = new ChatStateTracker(this);
1969
+ }
1970
+ }
1971
+ async connect() {
1972
+ const params = new URLSearchParams(this.options.queryParams ?? {});
1973
+ params.set('token', this.options.token);
1974
+ this.ws = new WebSocket(`${this.options.url}?${params}`);
1975
+ this.ws.onclose = ev => this.onClose(ev);
1976
+ this.ws.onmessage = ev => this.onMessage(ev);
1977
+ this.connectingTimeoutId = setTimeout(() => this.triggerConnectionTimeout(), this.options.connectingTimeoutMs ?? 10000);
1978
+ this.authenticated = false;
1979
+ return new Promise((...args) => this.authenticatedResolvers = args);
1980
+ }
1981
+ disconnect() {
1982
+ this.sendQueue = [];
1983
+ this.ws?.close();
1984
+ this.ws = null;
1985
+ }
1986
+ async send(commandType, commandData) {
1987
+ if (!this.ws || [this.ws.CLOSED, this.ws.CLOSING].includes(this.ws.readyState)) {
1988
+ throw new Error('Cannot send; close or closing connection state');
1989
+ }
1990
+ const envelope = this.createEnvelope(commandType, commandData);
1991
+ const promise = this.createPromiseFromCommandEnvelope(envelope);
1992
+ if (this.ws.readyState === this.ws.CONNECTING || !this.authenticated) {
1993
+ this.sendQueue.push(envelope);
1994
+ return promise;
1995
+ }
1996
+ if (this.ws.readyState !== this.ws.OPEN) {
1997
+ throw new Error(`Invalid websocket state=${this.ws.readyState}`);
1998
+ }
1999
+ this.sendEnvelope(envelope);
2000
+ return promise;
2001
+ }
2002
+ sendEnvelope(envelope) {
2003
+ this.ws.send(JSON.stringify(envelope));
2004
+ }
2005
+ onMessage(event) {
2006
+ const envelope = JSON.parse(event.data);
2007
+ this.handleIncomingEnvelope(envelope);
2008
+ this.emit(envelope.type, envelope.data);
2009
+ this.emit(this.Event.message, envelope);
2010
+
2011
+ // Login successfully
2012
+ if (!this.authenticated) {
2013
+ const isAuthenticated = envelope.type !== 'Bye';
2014
+ this.authenticated = isAuthenticated;
2015
+ if (isAuthenticated) {
2016
+ this.authenticatedResolvers[0]();
2017
+ this.emit(this.Event.connect);
2018
+ this.sendFromQueue();
2019
+ } else {
2020
+ this.authenticatedResolvers[1](envelope.data);
2021
+ }
2022
+ }
2023
+ }
2024
+ onClose(event) {
2025
+ clearTimeout(this.connectingTimeoutId);
2026
+ const reconnect = event.code !== 1000; // Connection was closed because of error
2027
+ if (reconnect) {
2028
+ this.connect();
2029
+ }
2030
+ this.emit(this.Event.disconnect, reconnect);
2031
+ }
2032
+ sendFromQueue() {
2033
+ // Send awaiting data to server
2034
+ let lastDelay = 0;
2035
+ for (const dataIndex in this.sendQueue) {
2036
+ const envelope = this.sendQueue[dataIndex];
2037
+ setTimeout(() => this.sendEnvelope(envelope), lastDelay);
2038
+ lastDelay += this.options.awaitQueueSendDelayMs ?? 500;
2039
+ }
2040
+ this.sendQueue = [];
2041
+ clearTimeout(this.connectingTimeoutId);
2042
+ }
2043
+ triggerConnectionTimeout() {
2044
+ this.disconnect();
2045
+ this.emit(this.Event.error, new Error('Connection timeout'));
2046
+ }
2047
+ }
2048
+ ;// CONCATENATED MODULE: ./src/WebApiChatClient.ts
2049
+ function WebApiChatClient_defineProperty(obj, key, value) { key = WebApiChatClient_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2050
+ function WebApiChatClient_toPropertyKey(arg) { var key = WebApiChatClient_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
2051
+ function WebApiChatClient_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
2052
+
2053
+ var WebApiChatClientEvent = /*#__PURE__*/function (WebApiChatClientEvent) {
2054
+ WebApiChatClientEvent["message"] = "message";
2055
+ WebApiChatClientEvent["error"] = "error";
2056
+ WebApiChatClientEvent["destroy"] = "destroy";
2057
+ return WebApiChatClientEvent;
2058
+ }(WebApiChatClientEvent || {});
2059
+ class WebApiChatClient extends AbstractChatClient {
2060
+ constructor(options) {
2061
+ super();
2062
+ this.options = options;
2063
+ WebApiChatClient_defineProperty(this, "Event", WebApiChatClientEvent);
2064
+ WebApiChatClient_defineProperty(this, "sendStack", void 0);
2065
+ }
2066
+ async send(commandType, commandData) {
2067
+ const envelope = this.createEnvelope(commandType, commandData);
2068
+ this.sendStack.push({
2069
+ data: envelope,
2070
+ attempts: 0,
2071
+ lastTimeoutId: null
2072
+ });
2073
+ this.makeApiCall(this.sendStack.length - 1);
2074
+ return this.createPromiseFromCommandEnvelope(envelope);
2075
+ }
2076
+ destroy() {
2077
+ // Cancel all awaiting requests
2078
+ this.sendStack.forEach(item => {
2079
+ if (item.lastTimeoutId) {
2080
+ clearTimeout(item.lastTimeoutId);
2081
+ }
2082
+ this.awaitingResponse.delete(item.data.ref);
2083
+ });
2084
+ this.sendStack = [];
2085
+ this.emit(this.Event.destroy, false);
2086
+ }
2087
+ async onMessage(reqId, response) {
2088
+ this.sendStack.splice(reqId, 1);
2089
+ const envelope = await response.json();
2090
+ this.handleIncomingEnvelope(envelope);
2091
+ this.emit(envelope.type, envelope.data);
2092
+ this.emit(this.Event.message, envelope);
2093
+ }
2094
+ onError(reqId, body) {
2095
+ if (this.sendStack[reqId].attempts >= (this.options.attemptsToSend ?? 10)) {
2096
+ this.sendStack.splice(reqId, 1);
2097
+ this.handleEnvelopeSendError(this.sendStack[reqId].data, new Error(`Cannot send ${body}; aborting after reaching the maximum connection errors`));
2098
+ return;
2099
+ }
2100
+ this.sendStack[reqId].lastTimeoutId = setTimeout(() => this.makeApiCall(reqId), this.options.attemptDelayMs ?? 3000);
2101
+ }
2102
+ makeApiCall(reqId) {
2103
+ this.sendStack[reqId].attempts++;
2104
+ const bodyJson = JSON.stringify(this.sendStack[reqId].data);
2105
+ const headers = {
2106
+ 'Content-Type': 'application/json',
2107
+ Accept: 'application/json'
2108
+ };
2109
+ headers.Authorization = `Bearer ${this.options.token}`;
2110
+ const params = new URLSearchParams(this.options.queryParams ?? {});
2111
+ const url = `${this.options.url}${params ? '?' + params : ''}`;
2112
+ fetch(url, {
2113
+ headers,
2114
+ body: bodyJson,
2115
+ method: 'POST'
2116
+ }).then(response => this.onMessage(reqId, response)).catch(() => this.onError(reqId, bodyJson));
2117
+ }
2118
+ }
2119
+ ;// CONCATENATED MODULE: ./src/AbstractRestClient.ts
2120
+ function AbstractRestClient_defineProperty(obj, key, value) { key = AbstractRestClient_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2121
+ function AbstractRestClient_toPropertyKey(arg) { var key = AbstractRestClient_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
2122
+ function AbstractRestClient_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
2123
+ class AbstractRestClient {
2124
+ constructor(options) {
2125
+ this.options = options;
2126
+ AbstractRestClient_defineProperty(this, "defaultUrl", void 0);
2127
+ }
2128
+ async send(method, uri, data = undefined) {
2129
+ let url = this.getUrl(uri);
2130
+ let body = undefined;
2131
+ if (data) {
2132
+ if (['GET', 'DELETE'].includes(method)) {
2133
+ url += new URLSearchParams(data).toString();
2134
+ } else {
2135
+ body = JSON.stringify(data);
2136
+ }
2137
+ }
2138
+ const headers = {
2139
+ 'Content-Type': 'application/json',
2140
+ Accept: 'application/json',
2141
+ ...this.getAuthHeaders()
2142
+ };
2143
+ const result = await fetch(url, {
2144
+ method,
2145
+ body,
2146
+ headers
2147
+ });
2148
+ return this.convertFetchResponse(result);
2149
+ }
2150
+ getAuthHeaders() {
2151
+ const headers = {};
2152
+ if (this.options.token) {
2153
+ headers.Authorization = `Bearer ${this.options.token}`;
2154
+ }
2155
+ return headers;
2156
+ }
2157
+ getUrl(uri) {
2158
+ return this.removeEndingSlash(this.options.url ?? this.defaultUrl) + '/' + this.removeStartingSlash(uri);
2159
+ }
2160
+ async convertFetchResponse(result) {
2161
+ return {
2162
+ ok: result.ok,
2163
+ status: result.status,
2164
+ data: result.headers.get('content-type')?.includes('json') ? await result.json() : await result.text()
2165
+ };
2166
+ }
2167
+ removeStartingSlash(text) {
2168
+ return text.replace(/^\/+/, '');
2169
+ }
2170
+ removeEndingSlash(text) {
2171
+ return text.replace(/\/+$/, '');
2172
+ }
2173
+ }
2174
+ ;// CONCATENATED MODULE: ./src/AuthClient.ts
2175
+ function AuthClient_defineProperty(obj, key, value) { key = AuthClient_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2176
+ function AuthClient_toPropertyKey(arg) { var key = AuthClient_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
2177
+ function AuthClient_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
2178
+
2179
+ class AuthClient extends AbstractRestClient {
2180
+ constructor(...args) {
2181
+ super(...args);
2182
+ AuthClient_defineProperty(this, "defaultUrl", 'https://polfan.pl/webservice/api');
2183
+ }
2184
+ static async createToken(login, password, clientName = 'pserv-js-client') {
2185
+ const response = await new AuthClient({
2186
+ token: null
2187
+ }).send('POST', 'auth/tokens', {
2188
+ login,
2189
+ password,
2190
+ client_name: clientName
2191
+ });
2192
+ if (response.ok) {
2193
+ return response.data;
2194
+ }
2195
+ throw new Error(`Cannot create user token: ${response.data.errors[0]}`);
2196
+ }
2197
+ async deleteToken(token) {
2198
+ const response = await this.send('DELETE', `auth/tokens/${token}`);
2199
+ if (!response.ok) {
2200
+ throw new Error(`Cannot delete access token: ${response.data.errors[0]}`);
2201
+ }
2202
+ }
2203
+ async getMe() {
2204
+ const response = await this.send('GET', 'auth/me');
2205
+ if (response.ok) {
2206
+ response.data.id = response.data.id.toString();
2207
+ return response.data;
2208
+ }
2209
+ throw new Error(`Cannot get current user account: ${response.data.errors[0]}`);
2210
+ }
2211
+ }
2212
+ ;// CONCATENATED MODULE: ./src/FilesClient.ts
2213
+ function FilesClient_defineProperty(obj, key, value) { key = FilesClient_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2214
+ function FilesClient_toPropertyKey(arg) { var key = FilesClient_toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
2215
+ function FilesClient_toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
2216
+
2217
+ class FilesClient extends AbstractRestClient {
2218
+ constructor(...args) {
2219
+ super(...args);
2220
+ FilesClient_defineProperty(this, "defaultUrl", 'https://polfan.pl/webservice/api/files');
2221
+ }
2222
+ async uploadFile(file) {
2223
+ const formData = new FormData();
2224
+ formData.append('file', file);
2225
+ let headers = {
2226
+ ...this.getAuthHeaders(),
2227
+ Accept: 'application/json'
2228
+ };
2229
+ const response = await fetch(this.defaultUrl, {
2230
+ method: 'POST',
2231
+ body: formData,
2232
+ headers
2233
+ });
2234
+ return this.convertFetchResponse(response);
2235
+ }
2236
+ async getFileMetadata(id) {
2237
+ return this.send('GET', '/' + id);
2238
+ }
2239
+ }
2240
+ ;// CONCATENATED MODULE: ./src/index.ts
2241
+
2242
+
2243
+
2244
+
2245
+
2246
+
2247
+
2248
+
2249
+ module.exports = __webpack_exports__;
2250
+ /******/ })()
2251
+ ;
2252
+ //# sourceMappingURL=index.cjs.js.map