polfan-server-js-client 0.2.56 → 0.2.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/workspace.xml +19 -2
- package/babel.config.js +1 -1
- package/build/index.cjs.js +74 -65
- package/build/index.cjs.js.map +1 -1
- package/build/index.umd.js +1 -1
- package/build/index.umd.js.map +1 -1
- package/build/types/IndexedObjectCollection.d.ts +4 -4
- package/build/types/state-tracker/TopicHistoryWindow.d.ts +18 -8
- package/package.json +2 -2
- package/src/IndexedObjectCollection.ts +4 -4
- package/src/state-tracker/TopicHistoryWindow.ts +61 -38
- package/tests/history-window.test.ts +1 -1
|
@@ -10,7 +10,7 @@ export declare class IndexedCollection<KeyT, ValueT> {
|
|
|
10
10
|
delete(...ids: KeyT[]): void;
|
|
11
11
|
deleteAll(): void;
|
|
12
12
|
findBy(field: keyof ValueT, valueToFind: any, limit?: number): IndexedCollection<KeyT, ValueT>;
|
|
13
|
-
|
|
13
|
+
createMirror(): IndexedCollection<KeyT, ValueT>;
|
|
14
14
|
}
|
|
15
15
|
export declare class IndexedObjectCollection<T> {
|
|
16
16
|
readonly id: keyof T | ((item: T) => any);
|
|
@@ -25,7 +25,7 @@ export declare class IndexedObjectCollection<T> {
|
|
|
25
25
|
delete(...ids: any[]): void;
|
|
26
26
|
deleteAll(): void;
|
|
27
27
|
findBy(field: keyof T, valueToFind: any, limit?: number): IndexedObjectCollection<T>;
|
|
28
|
-
|
|
28
|
+
createMirror(): IndexedObjectCollection<T>;
|
|
29
29
|
protected getId(item: T): any;
|
|
30
30
|
}
|
|
31
31
|
interface ObservableCollectionEvent<KeyT> {
|
|
@@ -38,7 +38,7 @@ export declare class ObservableIndexedCollection<KeyT, ValueT> extends IndexedCo
|
|
|
38
38
|
set(...items: [KeyT, ValueT][]): void;
|
|
39
39
|
delete(...ids: KeyT[]): void;
|
|
40
40
|
deleteAll(): void;
|
|
41
|
-
|
|
41
|
+
createMirror(): ObservableIndexedCollection<KeyT, ValueT>;
|
|
42
42
|
on(eventName: 'change', handler: (ev?: ObservableCollectionEvent<KeyT>) => void): this;
|
|
43
43
|
once(eventName: 'change', handler: (ev?: ObservableCollectionEvent<KeyT>) => void): this;
|
|
44
44
|
off(eventName: string, handler: (ev?: ObservableCollectionEvent<KeyT>) => void): this;
|
|
@@ -50,7 +50,7 @@ export declare class ObservableIndexedObjectCollection<T> extends IndexedObjectC
|
|
|
50
50
|
set(...items: T[]): void;
|
|
51
51
|
delete(...ids: string[]): void;
|
|
52
52
|
deleteAll(): void;
|
|
53
|
-
|
|
53
|
+
createMirror(): IndexedObjectCollection<T>;
|
|
54
54
|
on(eventName: 'change', handler: (ev?: ObservableCollectionEvent<string>) => void): this;
|
|
55
55
|
once(eventName: 'change', handler: (ev?: ObservableCollectionEvent<string>) => void): this;
|
|
56
56
|
off(eventName: string, handler: (ev?: ObservableCollectionEvent<string>) => void): this;
|
|
@@ -26,17 +26,25 @@ export declare abstract class TraversableRemoteCollection<T> extends ObservableI
|
|
|
26
26
|
* Current mode od collection window. To change mode, call one of available fetch methods.
|
|
27
27
|
*/
|
|
28
28
|
get state(): WindowState;
|
|
29
|
+
protected internalState: {
|
|
30
|
+
current: WindowState;
|
|
31
|
+
ongoing?: WindowState;
|
|
32
|
+
limit: number | null;
|
|
33
|
+
oldestId: string | null;
|
|
34
|
+
};
|
|
29
35
|
/**
|
|
30
36
|
* Maximum numer of items stored in window.
|
|
31
37
|
* Null for unlimited.
|
|
32
38
|
*/
|
|
33
|
-
limit: number | null;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
get limit(): number | null;
|
|
40
|
+
/**
|
|
41
|
+
* Maximum numer of items stored in window.
|
|
42
|
+
* Null for unlimited.
|
|
43
|
+
*/
|
|
44
|
+
set limit(value: number | null);
|
|
38
45
|
get hasLatest(): boolean;
|
|
39
46
|
get hasOldest(): boolean;
|
|
47
|
+
abstract createMirror(): IndexedObjectCollection<T>;
|
|
40
48
|
resetToLatest(): Promise<void>;
|
|
41
49
|
fetchPrevious(): Promise<void>;
|
|
42
50
|
fetchNext(): Promise<void>;
|
|
@@ -59,9 +67,11 @@ export declare class TopicHistoryWindow extends TraversableRemoteCollection<Mess
|
|
|
59
67
|
* Reexported available window modes enum.
|
|
60
68
|
*/
|
|
61
69
|
readonly WindowState: typeof WindowState;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
protected internalState: typeof TraversableRemoteCollection<Message>['prototype']['internalState'] & {
|
|
71
|
+
traverseLock: boolean;
|
|
72
|
+
};
|
|
73
|
+
constructor(roomId: string, topicId: string, tracker: ChatStateTracker, bindEvents?: boolean);
|
|
74
|
+
createMirror(): TopicHistoryWindow;
|
|
65
75
|
get isTraverseLocked(): boolean;
|
|
66
76
|
setTraverseLock(lock: boolean): Promise<void>;
|
|
67
77
|
resetToLatest(): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polfan-server-js-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.58",
|
|
4
4
|
"description": "JavaScript client library for handling communication with Polfan chat server.",
|
|
5
5
|
"author": "Jarosław Żak",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@babel/plugin-transform-typescript": "^7.20.2",
|
|
32
32
|
"@babel/polyfill": "^7.12.1",
|
|
33
33
|
"@babel/preset-env": "^7.20.2",
|
|
34
|
-
"@babel/preset-typescript": "^7.
|
|
34
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
35
35
|
"@types/jest": "^29.2.5",
|
|
36
36
|
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
37
37
|
"@typescript-eslint/parser": "^4.33.0",
|
|
@@ -53,7 +53,7 @@ export class IndexedCollection<KeyT, ValueT> {
|
|
|
53
53
|
return result;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
public
|
|
56
|
+
public createMirror(): IndexedCollection<KeyT, ValueT> {
|
|
57
57
|
const copy = new IndexedCollection<KeyT, ValueT>();
|
|
58
58
|
copy._items = this._items;
|
|
59
59
|
return copy;
|
|
@@ -116,7 +116,7 @@ export class IndexedObjectCollection<T> {
|
|
|
116
116
|
return result;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
public
|
|
119
|
+
public createMirror(): IndexedObjectCollection<T> {
|
|
120
120
|
const copy = new IndexedObjectCollection<T>(this.id);
|
|
121
121
|
copy._items = this._items;
|
|
122
122
|
return copy;
|
|
@@ -163,7 +163,7 @@ export class ObservableIndexedCollection<KeyT, ValueT> extends IndexedCollection
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
public
|
|
166
|
+
public createMirror(): ObservableIndexedCollection<KeyT, ValueT> {
|
|
167
167
|
const copy = new ObservableIndexedCollection<KeyT, ValueT>();
|
|
168
168
|
copy.eventTarget = this.eventTarget;
|
|
169
169
|
copy._items = this._items;
|
|
@@ -220,7 +220,7 @@ export class ObservableIndexedObjectCollection<T> extends IndexedObjectCollectio
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
public
|
|
223
|
+
public createMirror(): IndexedObjectCollection<T> {
|
|
224
224
|
const copy = new ObservableIndexedObjectCollection<T>(this.id);
|
|
225
225
|
copy.eventTarget = this.eventTarget;
|
|
226
226
|
copy._items = this._items;
|
|
@@ -31,63 +31,80 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
31
31
|
* Current mode od collection window. To change mode, call one of available fetch methods.
|
|
32
32
|
*/
|
|
33
33
|
public get state(): WindowState {
|
|
34
|
-
return this.
|
|
34
|
+
return this.internalState.current;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
protected internalState: {
|
|
38
|
+
current: WindowState,
|
|
39
|
+
ongoing?: WindowState,
|
|
40
|
+
limit: number | null,
|
|
41
|
+
oldestId: string | null,
|
|
42
|
+
} = {
|
|
43
|
+
current: WindowState.LIVE,
|
|
44
|
+
ongoing: undefined,
|
|
45
|
+
limit: 50,
|
|
46
|
+
oldestId: null,
|
|
47
|
+
};
|
|
48
|
+
|
|
37
49
|
/**
|
|
38
50
|
* Maximum numer of items stored in window.
|
|
39
51
|
* Null for unlimited.
|
|
40
52
|
*/
|
|
41
|
-
public limit: number | null
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
protected currentState: WindowState = WindowState.LIVE;
|
|
46
|
-
protected fetchingState: WindowState = undefined;
|
|
53
|
+
public get limit(): number | null {
|
|
54
|
+
return this.internalState.limit;
|
|
55
|
+
}
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Maximum numer of items stored in window.
|
|
59
|
+
* Null for unlimited.
|
|
60
|
+
*/
|
|
61
|
+
public set limit(value: number | null) {
|
|
62
|
+
this.internalState.limit = value;
|
|
63
|
+
}
|
|
49
64
|
|
|
50
65
|
public get hasLatest(): boolean {
|
|
51
66
|
return [WindowState.LATEST, WindowState.LIVE].includes(this.state);
|
|
52
67
|
}
|
|
53
68
|
|
|
54
69
|
public get hasOldest(): boolean {
|
|
55
|
-
return this.state === WindowState.OLDEST || this.oldestId !== null && this.has(this.oldestId);
|
|
70
|
+
return this.state === WindowState.OLDEST || this.internalState.oldestId !== null && this.has(this.internalState.oldestId);
|
|
56
71
|
}
|
|
57
72
|
|
|
73
|
+
public abstract createMirror(): IndexedObjectCollection<T>;
|
|
74
|
+
|
|
58
75
|
public async resetToLatest(): Promise<void> {
|
|
59
|
-
if (this.
|
|
76
|
+
if (this.internalState.ongoing || this.internalState.current === WindowState.LATEST) {
|
|
60
77
|
return;
|
|
61
78
|
}
|
|
62
79
|
|
|
63
|
-
this.
|
|
80
|
+
this.internalState.ongoing = WindowState.LATEST;
|
|
64
81
|
|
|
65
82
|
let result;
|
|
66
83
|
|
|
67
84
|
try {
|
|
68
85
|
result = await this.fetchLatestItems();
|
|
69
86
|
} finally {
|
|
70
|
-
this.
|
|
87
|
+
this.internalState.ongoing = undefined;
|
|
71
88
|
}
|
|
72
89
|
|
|
73
90
|
this.deleteAll();
|
|
74
91
|
this.addItems(result, 'tail');
|
|
75
|
-
this.
|
|
92
|
+
this.internalState.current = WindowState.LATEST;
|
|
76
93
|
}
|
|
77
94
|
|
|
78
95
|
public async fetchPrevious(): Promise<void> {
|
|
79
|
-
if (this.
|
|
96
|
+
if (this.internalState.ongoing || this.hasOldest) {
|
|
80
97
|
return;
|
|
81
98
|
}
|
|
82
99
|
|
|
83
|
-
this.
|
|
100
|
+
this.internalState.ongoing = WindowState.PAST;
|
|
84
101
|
|
|
85
102
|
let result;
|
|
86
103
|
|
|
87
104
|
try {
|
|
88
105
|
result = await this.fetchItemsBefore();
|
|
89
106
|
} finally {
|
|
90
|
-
this.
|
|
107
|
+
this.internalState.ongoing = undefined;
|
|
91
108
|
}
|
|
92
109
|
|
|
93
110
|
if (! result) {
|
|
@@ -96,13 +113,13 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
96
113
|
|
|
97
114
|
if (! result.length) {
|
|
98
115
|
const firstItem = this.getAt(0);
|
|
99
|
-
this.oldestId = firstItem ? this.getId(firstItem) : null;
|
|
116
|
+
this.internalState.oldestId = firstItem ? this.getId(firstItem) : null;
|
|
100
117
|
|
|
101
118
|
await this.refreshFetchedState();
|
|
102
119
|
|
|
103
120
|
// LATEST state has priority over OLDEST
|
|
104
|
-
if (this.
|
|
105
|
-
this.
|
|
121
|
+
if (this.internalState.current === WindowState.PAST) {
|
|
122
|
+
this.internalState.current = WindowState.OLDEST;
|
|
106
123
|
}
|
|
107
124
|
|
|
108
125
|
return;
|
|
@@ -113,18 +130,18 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
113
130
|
}
|
|
114
131
|
|
|
115
132
|
public async fetchNext(): Promise<void> {
|
|
116
|
-
if (this.
|
|
133
|
+
if (this.internalState.ongoing || this.hasLatest) {
|
|
117
134
|
return;
|
|
118
135
|
}
|
|
119
136
|
|
|
120
|
-
this.
|
|
137
|
+
this.internalState.ongoing = WindowState.PAST;
|
|
121
138
|
|
|
122
139
|
let result;
|
|
123
140
|
|
|
124
141
|
try {
|
|
125
142
|
result = await this.fetchItemsAfter();
|
|
126
143
|
} finally {
|
|
127
|
-
this.
|
|
144
|
+
this.internalState.ongoing = undefined;
|
|
128
145
|
}
|
|
129
146
|
|
|
130
147
|
if (! result) {
|
|
@@ -148,7 +165,7 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
148
165
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
149
166
|
|
|
150
167
|
protected async refreshFetchedState(): Promise<void> {
|
|
151
|
-
this.
|
|
168
|
+
this.internalState.current = (await this.isLatestItemLoaded()) ? WindowState.LATEST : WindowState.PAST;
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
protected addItems(newItems: T[], to: 'head' | 'tail'): void {
|
|
@@ -190,34 +207,40 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<Message> {
|
|
|
190
207
|
*/
|
|
191
208
|
public readonly WindowState: typeof WindowState = WindowState;
|
|
192
209
|
|
|
193
|
-
|
|
210
|
+
declare protected internalState: typeof TraversableRemoteCollection<Message>['prototype']['internalState'] & {
|
|
211
|
+
traverseLock: boolean,
|
|
212
|
+
};
|
|
194
213
|
|
|
195
214
|
public constructor(
|
|
196
215
|
private roomId: string,
|
|
197
216
|
private topicId: string,
|
|
198
217
|
private tracker: ChatStateTracker,
|
|
218
|
+
bindEvents: boolean = true,
|
|
199
219
|
) {
|
|
200
220
|
super('id');
|
|
201
|
-
|
|
202
|
-
this.
|
|
221
|
+
|
|
222
|
+
this.internalState.traverseLock = false;
|
|
223
|
+
|
|
224
|
+
if (bindEvents) {
|
|
225
|
+
this.tracker.client.on('Session', ev => this.handleSession(ev));
|
|
226
|
+
this.tracker.client.on('NewMessage', ev => this.handleNewMessage(ev));
|
|
227
|
+
}
|
|
203
228
|
}
|
|
204
229
|
|
|
205
|
-
public
|
|
206
|
-
const copy = new TopicHistoryWindow(this.roomId, this.topicId, this.tracker);
|
|
230
|
+
public createMirror(): TopicHistoryWindow {
|
|
231
|
+
const copy = new TopicHistoryWindow(this.roomId, this.topicId, this.tracker, false);
|
|
232
|
+
copy.eventTarget = this.eventTarget;
|
|
207
233
|
copy._items = this._items;
|
|
208
|
-
copy.
|
|
209
|
-
copy.currentState = this.currentState;
|
|
210
|
-
copy.fetchingState = this.fetchingState;
|
|
211
|
-
copy.oldestId = this.oldestId;
|
|
234
|
+
copy.internalState = this.internalState;
|
|
212
235
|
return copy;
|
|
213
236
|
}
|
|
214
237
|
|
|
215
238
|
public get isTraverseLocked(): boolean {
|
|
216
|
-
return this.traverseLock;
|
|
239
|
+
return this.internalState.traverseLock;
|
|
217
240
|
}
|
|
218
241
|
|
|
219
242
|
public async setTraverseLock(lock: boolean): Promise<void> {
|
|
220
|
-
this.traverseLock = lock;
|
|
243
|
+
this.internalState.traverseLock = lock;
|
|
221
244
|
|
|
222
245
|
if (lock && (this.state !== WindowState.LIVE && this.state !== WindowState.LATEST)) {
|
|
223
246
|
await super.resetToLatest();
|
|
@@ -225,21 +248,21 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<Message> {
|
|
|
225
248
|
}
|
|
226
249
|
|
|
227
250
|
public async resetToLatest(): Promise<void> {
|
|
228
|
-
if (this.traverseLock) {
|
|
251
|
+
if (this.internalState.traverseLock) {
|
|
229
252
|
return;
|
|
230
253
|
}
|
|
231
254
|
return super.resetToLatest();
|
|
232
255
|
}
|
|
233
256
|
|
|
234
257
|
public async fetchNext(): Promise<void> {
|
|
235
|
-
if (this.traverseLock) {
|
|
258
|
+
if (this.internalState.traverseLock) {
|
|
236
259
|
return;
|
|
237
260
|
}
|
|
238
261
|
return super.fetchNext();
|
|
239
262
|
}
|
|
240
263
|
|
|
241
264
|
public async fetchPrevious(): Promise<void> {
|
|
242
|
-
if (this.traverseLock) {
|
|
265
|
+
if (this.internalState.traverseLock) {
|
|
243
266
|
return;
|
|
244
267
|
}
|
|
245
268
|
return super.fetchPrevious();
|
|
@@ -272,7 +295,7 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<Message> {
|
|
|
272
295
|
const rooms = ev.state.rooms;
|
|
273
296
|
|
|
274
297
|
if (rooms.find(room => room.id === this.roomId)) {
|
|
275
|
-
this.resetToLatest();
|
|
298
|
+
void this.resetToLatest();
|
|
276
299
|
} else {
|
|
277
300
|
this.deleteAll();
|
|
278
301
|
}
|
|
@@ -19,7 +19,7 @@ const messages: SimpleMessage[] = [
|
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
class TestableHistoryWindow extends TraversableRemoteCollection<SimpleMessage> {
|
|
22
|
-
public
|
|
22
|
+
public createMirror(): IndexedObjectCollection<SimpleMessage> {
|
|
23
23
|
throw new Error('Method not implemented.');
|
|
24
24
|
}
|
|
25
25
|
|