polfan-server-js-client 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitmodules +3 -3
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_05_08_2026_17_28_[Changes]/shelved.patch +447 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_05_08_2026_17_28_[Changes]1/shelved.patch +0 -0
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_05_08_2026_17_28__Changes_.xml +4 -0
- package/.idea/workspace.xml +193 -6
- package/CODE_OF_CONDUCT.md +76 -76
- package/README.md +44 -44
- package/babel.config.js +5 -5
- package/build/index.cjs.js +392 -429
- 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/index.d.ts +2 -1
- package/build/types/state-tracker/RoomMessagesHistory.d.ts +4 -15
- package/build/types/state-tracker/TopicHistoryWindow.d.ts +0 -48
- package/build/types/types/src/index.d.ts +3 -3
- package/build/types/types/src/schemes/SessionData.d.ts +6 -0
- package/build/types/types/src/schemes/User.d.ts +15 -0
- package/build/types/types/src/schemes/UserData.d.ts +5 -0
- package/build/types/types/src/schemes/commands/SetSessionData.d.ts +9 -1
- package/build/types/types/src/schemes/commands/SetUserData.d.ts +1 -0
- package/jest.config.ts +199 -199
- package/package.json +43 -43
- package/scripts/getPackageJson.js +24 -24
- package/src/FilesClient.ts +42 -42
- package/src/index.ts +31 -29
- package/src/state-tracker/ChatStateTracker.ts +71 -71
- package/src/state-tracker/RoomMessagesHistory.ts +9 -27
- package/src/state-tracker/TopicHistoryWindow.ts +1 -133
- package/src/state-tracker/UsersManager.ts +51 -51
- package/src/state-tracker/functions.ts +28 -28
- package/src/types/src/index.ts +313 -311
- package/src/types/src/schemes/SessionData.ts +8 -1
- package/src/types/src/schemes/User.ts +17 -1
- package/src/types/src/schemes/UserData.ts +5 -0
- package/src/types/src/schemes/commands/SetSessionData.ts +11 -2
- package/src/types/src/schemes/commands/SetUserData.ts +1 -0
- package/tests/async-utils.test.ts +29 -29
- package/tests/history-window.test.ts +0 -131
- package/tests/space-roles.test.ts +42 -42
- package/tests/state-reconnect.test.ts +0 -260
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_26_07_2026_21_26_[Changes]/shelved.patch +0 -174
- package/.idea/shelf/Uncommitted_changes_before_Checkout_at_26_07_2026_21_26__Changes_.xml +0 -4
- package/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch +0 -18
- package/.idea/shelf/Uncommitted_changes_before_rebase__Changes_.xml +0 -4
package/package.json
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "polfan-server-js-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "JavaScript client library for handling communication with Polfan chat server.",
|
|
5
|
-
"author": "Jarosław Żak",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"main": "build/index.cjs.js",
|
|
8
|
-
"browser": "build/index.umd.js",
|
|
9
|
-
"types": "build/types/index.d.ts",
|
|
10
|
-
"exports": {
|
|
11
|
-
".": {
|
|
12
|
-
"types": "./build/types/index.d.ts",
|
|
13
|
-
"require": "./build/index.cjs.js",
|
|
14
|
-
"browser": "./build/index.umd.js",
|
|
15
|
-
"default": "./build/index.cjs.js"
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "npm run build:node && npm run build:browser && tsc",
|
|
20
|
-
"build:node": "webpack --config webpack.config.node.js",
|
|
21
|
-
"build:browser": "webpack --config webpack.config.browser.js",
|
|
22
|
-
"test": "jest",
|
|
23
|
-
"coverage": "npm run test -- --coverage",
|
|
24
|
-
"trypublish": "npm publish || true"
|
|
25
|
-
},
|
|
26
|
-
"devDependencies": {
|
|
27
|
-
"@babel/cli": "^7.28.3",
|
|
28
|
-
"@babel/core": "^7.28.5",
|
|
29
|
-
"@babel/preset-env": "^7.28.5",
|
|
30
|
-
"@babel/preset-typescript": "^7.28.5",
|
|
31
|
-
"@types/jest": "^29.5.14",
|
|
32
|
-
"babel-loader": "^9.2.1",
|
|
33
|
-
"file-loader": "^6.2.0",
|
|
34
|
-
"jest": "^29.7.0",
|
|
35
|
-
"ts-node": "^10.9.2",
|
|
36
|
-
"typescript": "^4.9.5",
|
|
37
|
-
"webpack": "^5.103.0",
|
|
38
|
-
"webpack-cli": "^5.1.4"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"terser-webpack-plugin": "^5.3.14"
|
|
42
|
-
}
|
|
43
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "polfan-server-js-client",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "JavaScript client library for handling communication with Polfan chat server.",
|
|
5
|
+
"author": "Jarosław Żak",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "build/index.cjs.js",
|
|
8
|
+
"browser": "build/index.umd.js",
|
|
9
|
+
"types": "build/types/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./build/types/index.d.ts",
|
|
13
|
+
"require": "./build/index.cjs.js",
|
|
14
|
+
"browser": "./build/index.umd.js",
|
|
15
|
+
"default": "./build/index.cjs.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "npm run build:node && npm run build:browser && tsc",
|
|
20
|
+
"build:node": "webpack --config webpack.config.node.js",
|
|
21
|
+
"build:browser": "webpack --config webpack.config.browser.js",
|
|
22
|
+
"test": "jest",
|
|
23
|
+
"coverage": "npm run test -- --coverage",
|
|
24
|
+
"trypublish": "npm publish || true"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@babel/cli": "^7.28.3",
|
|
28
|
+
"@babel/core": "^7.28.5",
|
|
29
|
+
"@babel/preset-env": "^7.28.5",
|
|
30
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
31
|
+
"@types/jest": "^29.5.14",
|
|
32
|
+
"babel-loader": "^9.2.1",
|
|
33
|
+
"file-loader": "^6.2.0",
|
|
34
|
+
"jest": "^29.7.0",
|
|
35
|
+
"ts-node": "^10.9.2",
|
|
36
|
+
"typescript": "^4.9.5",
|
|
37
|
+
"webpack": "^5.103.0",
|
|
38
|
+
"webpack-cli": "^5.1.4"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"terser-webpack-plugin": "^5.3.14"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A module to get package informations from package.json
|
|
6
|
-
* @module getPackageJson
|
|
7
|
-
* @param {...string} keys from package.json if no arguments passed it returns package.json content as object
|
|
8
|
-
* @returns {object} with given keys or content of package.json as object
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Returns package info
|
|
13
|
-
*/
|
|
14
|
-
const getPackageJson = function(...args) {
|
|
15
|
-
const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json')));
|
|
16
|
-
if (!args.length) {
|
|
17
|
-
return packageJSON;
|
|
18
|
-
}
|
|
19
|
-
return args.reduce((out, key) => {
|
|
20
|
-
out[key] = packageJSON[key];
|
|
21
|
-
return out;
|
|
22
|
-
}, {});
|
|
23
|
-
};
|
|
24
|
-
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A module to get package informations from package.json
|
|
6
|
+
* @module getPackageJson
|
|
7
|
+
* @param {...string} keys from package.json if no arguments passed it returns package.json content as object
|
|
8
|
+
* @returns {object} with given keys or content of package.json as object
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns package info
|
|
13
|
+
*/
|
|
14
|
+
const getPackageJson = function(...args) {
|
|
15
|
+
const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json')));
|
|
16
|
+
if (!args.length) {
|
|
17
|
+
return packageJSON;
|
|
18
|
+
}
|
|
19
|
+
return args.reduce((out, key) => {
|
|
20
|
+
out[key] = packageJSON[key];
|
|
21
|
+
return out;
|
|
22
|
+
}, {});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
25
|
module.exports = getPackageJson;
|
package/src/FilesClient.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import {AbstractRestClient, RestClientResponse} from "./AbstractRestClient";
|
|
2
|
-
|
|
3
|
-
export interface File {
|
|
4
|
-
id: string;
|
|
5
|
-
url: string;
|
|
6
|
-
name: string;
|
|
7
|
-
mime: string;
|
|
8
|
-
size: number;
|
|
9
|
-
width?: number;
|
|
10
|
-
height?: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class FilesClient extends AbstractRestClient {
|
|
14
|
-
protected defaultUrl: string = 'https://files.devana.pl';
|
|
15
|
-
|
|
16
|
-
public async uploadFile(file: globalThis.File | Blob): Promise<RestClientResponse<File>> {
|
|
17
|
-
const name = encodeURIComponent((file as globalThis.File).name ?? '');
|
|
18
|
-
let headers = {
|
|
19
|
-
...this.getAuthHeaders(),
|
|
20
|
-
Accept: 'application/json',
|
|
21
|
-
'Content-Disposition': `attachment; filename="${name}"`,
|
|
22
|
-
'Content-Length': file.size
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const response = await fetch(this.getUrl('files'), {
|
|
26
|
-
method: 'POST',
|
|
27
|
-
body: file,
|
|
28
|
-
headers
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
return this.convertFetchResponse<File>(response);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public async getFileMeta(id: string): Promise<RestClientResponse<File>> {
|
|
35
|
-
return this.send('GET', 'files/' + id);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public async getFileMetaBulk(ids: string[]): Promise<RestClientResponse<File[]>> {
|
|
39
|
-
const searchParams = new URLSearchParams();
|
|
40
|
-
ids.forEach(id => searchParams.append('id[]', id));
|
|
41
|
-
return this.send('GET', 'files?' + searchParams);
|
|
42
|
-
}
|
|
1
|
+
import {AbstractRestClient, RestClientResponse} from "./AbstractRestClient";
|
|
2
|
+
|
|
3
|
+
export interface File {
|
|
4
|
+
id: string;
|
|
5
|
+
url: string;
|
|
6
|
+
name: string;
|
|
7
|
+
mime: string;
|
|
8
|
+
size: number;
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class FilesClient extends AbstractRestClient {
|
|
14
|
+
protected defaultUrl: string = 'https://files.devana.pl';
|
|
15
|
+
|
|
16
|
+
public async uploadFile(file: globalThis.File | Blob): Promise<RestClientResponse<File>> {
|
|
17
|
+
const name = encodeURIComponent((file as globalThis.File).name ?? '');
|
|
18
|
+
let headers = {
|
|
19
|
+
...this.getAuthHeaders(),
|
|
20
|
+
Accept: 'application/json',
|
|
21
|
+
'Content-Disposition': `attachment; filename="${name}"`,
|
|
22
|
+
'Content-Length': file.size
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const response = await fetch(this.getUrl('files'), {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
body: file,
|
|
28
|
+
headers
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return this.convertFetchResponse<File>(response);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async getFileMeta(id: string): Promise<RestClientResponse<File>> {
|
|
35
|
+
return this.send('GET', 'files/' + id);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async getFileMetaBulk(ids: string[]): Promise<RestClientResponse<File[]>> {
|
|
39
|
+
const searchParams = new URLSearchParams();
|
|
40
|
+
ids.forEach(id => searchParams.append('id[]', id));
|
|
41
|
+
return this.send('GET', 'files?' + searchParams);
|
|
42
|
+
}
|
|
43
43
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
|
-
import {WebSocketChatClient} from "./WebSocketChatClient";
|
|
2
|
-
import {WebApiChatClient} from "./WebApiChatClient";
|
|
3
|
-
import {
|
|
4
|
-
IndexedCollection,
|
|
5
|
-
IndexedObjectCollection,
|
|
6
|
-
ObservableIndexedCollection,
|
|
7
|
-
ObservableIndexedObjectCollection
|
|
8
|
-
} from "./IndexedObjectCollection";
|
|
9
|
-
import {FilesClient, File} from "./FilesClient";
|
|
10
|
-
import { Permissions, PermissionDefinition, Layer } from "./Permissions";
|
|
11
|
-
import * as ChatTypes from './types/src';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
import {WebSocketChatClient} from "./WebSocketChatClient";
|
|
2
|
+
import {WebApiChatClient} from "./WebApiChatClient";
|
|
3
|
+
import {
|
|
4
|
+
IndexedCollection,
|
|
5
|
+
IndexedObjectCollection,
|
|
6
|
+
ObservableIndexedCollection,
|
|
7
|
+
ObservableIndexedObjectCollection
|
|
8
|
+
} from "./IndexedObjectCollection";
|
|
9
|
+
import {FilesClient, File} from "./FilesClient";
|
|
10
|
+
import { Permissions, PermissionDefinition, Layer } from "./Permissions";
|
|
11
|
+
import * as ChatTypes from './types/src';
|
|
12
|
+
import {UserStatus} from './types/src';
|
|
13
|
+
import {extractUserFromMember} from "./state-tracker/functions";
|
|
14
|
+
import {AbstractRestClient} from "./AbstractRestClient";
|
|
15
|
+
import {UnreadSummary} from "./state-tracker/FollowedTopicsManager";
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
IndexedCollection, ObservableIndexedCollection,
|
|
19
|
+
IndexedObjectCollection, ObservableIndexedObjectCollection,
|
|
20
|
+
Permissions, PermissionDefinition, Layer,
|
|
21
|
+
WebSocketChatClient, WebApiChatClient,
|
|
22
|
+
FilesClient,
|
|
23
|
+
AbstractRestClient,
|
|
24
|
+
extractUserFromMember,
|
|
25
|
+
UserStatus,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type {
|
|
29
|
+
ChatTypes,
|
|
30
|
+
File,
|
|
31
|
+
UnreadSummary,
|
|
30
32
|
};
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
import {WebSocketChatClient} from "../WebSocketChatClient";
|
|
2
|
-
import {Session, User} from "../types/src";
|
|
3
|
-
import {RoomsManager} from "./RoomsManager";
|
|
4
|
-
import {SpacesManager} from "./SpacesManager";
|
|
5
|
-
import {PermissionsManager} from "./PermissionsManager";
|
|
6
|
-
import {DeferredTask} from "./AsyncUtils";
|
|
7
|
-
import {EmoticonsManager} from "./EmoticonsManager";
|
|
8
|
-
import {UsersManager} from "./UsersManager";
|
|
9
|
-
import {RelationshipsManager} from "./RelationshipsManager";
|
|
10
|
-
|
|
11
|
-
export class ChatStateTracker {
|
|
12
|
-
public readonly client: WebSocketChatClient;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* State of your permissions.
|
|
16
|
-
*/
|
|
17
|
-
public readonly permissions: PermissionsManager;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* State of the rooms you are in.
|
|
21
|
-
*/
|
|
22
|
-
public readonly rooms: RoomsManager;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* State of the spaces you are in.
|
|
26
|
-
*/
|
|
27
|
-
public readonly spaces: SpacesManager;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* State of the emoticons (global and space-related).
|
|
31
|
-
*/
|
|
32
|
-
public readonly emoticons: EmoticonsManager;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Users related state.
|
|
36
|
-
*/
|
|
37
|
-
public readonly users: UsersManager;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* State of relationships with other users.
|
|
41
|
-
*/
|
|
42
|
-
public readonly relationships: RelationshipsManager;
|
|
43
|
-
|
|
44
|
-
private _me: User = null;
|
|
45
|
-
private readonly deferredSession = new DeferredTask();
|
|
46
|
-
|
|
47
|
-
public constructor(client: WebSocketChatClient) {
|
|
48
|
-
this.client = client;
|
|
49
|
-
this.client.on('Session', ev => this.handleSession(ev));
|
|
50
|
-
|
|
51
|
-
this.permissions = new PermissionsManager(this);
|
|
52
|
-
this.rooms = new RoomsManager(this);
|
|
53
|
-
this.spaces = new SpacesManager(this);
|
|
54
|
-
this.emoticons = new EmoticonsManager(this);
|
|
55
|
-
this.users = new UsersManager(this);
|
|
56
|
-
this.relationships = new RelationshipsManager(this);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public get me(): User | null {
|
|
60
|
-
return this._me;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public async getMe(): Promise<User> {
|
|
64
|
-
await this.deferredSession.promise;
|
|
65
|
-
return this._me;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private handleSession(ev: Session): void {
|
|
69
|
-
this._me = ev.user;
|
|
70
|
-
this.deferredSession.resolve();
|
|
71
|
-
}
|
|
1
|
+
import {WebSocketChatClient} from "../WebSocketChatClient";
|
|
2
|
+
import {Session, User} from "../types/src";
|
|
3
|
+
import {RoomsManager} from "./RoomsManager";
|
|
4
|
+
import {SpacesManager} from "./SpacesManager";
|
|
5
|
+
import {PermissionsManager} from "./PermissionsManager";
|
|
6
|
+
import {DeferredTask} from "./AsyncUtils";
|
|
7
|
+
import {EmoticonsManager} from "./EmoticonsManager";
|
|
8
|
+
import {UsersManager} from "./UsersManager";
|
|
9
|
+
import {RelationshipsManager} from "./RelationshipsManager";
|
|
10
|
+
|
|
11
|
+
export class ChatStateTracker {
|
|
12
|
+
public readonly client: WebSocketChatClient;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* State of your permissions.
|
|
16
|
+
*/
|
|
17
|
+
public readonly permissions: PermissionsManager;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* State of the rooms you are in.
|
|
21
|
+
*/
|
|
22
|
+
public readonly rooms: RoomsManager;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* State of the spaces you are in.
|
|
26
|
+
*/
|
|
27
|
+
public readonly spaces: SpacesManager;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* State of the emoticons (global and space-related).
|
|
31
|
+
*/
|
|
32
|
+
public readonly emoticons: EmoticonsManager;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Users related state.
|
|
36
|
+
*/
|
|
37
|
+
public readonly users: UsersManager;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* State of relationships with other users.
|
|
41
|
+
*/
|
|
42
|
+
public readonly relationships: RelationshipsManager;
|
|
43
|
+
|
|
44
|
+
private _me: User = null;
|
|
45
|
+
private readonly deferredSession = new DeferredTask();
|
|
46
|
+
|
|
47
|
+
public constructor(client: WebSocketChatClient) {
|
|
48
|
+
this.client = client;
|
|
49
|
+
this.client.on('Session', ev => this.handleSession(ev));
|
|
50
|
+
|
|
51
|
+
this.permissions = new PermissionsManager(this);
|
|
52
|
+
this.rooms = new RoomsManager(this);
|
|
53
|
+
this.spaces = new SpacesManager(this);
|
|
54
|
+
this.emoticons = new EmoticonsManager(this);
|
|
55
|
+
this.users = new UsersManager(this);
|
|
56
|
+
this.relationships = new RelationshipsManager(this);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public get me(): User | null {
|
|
60
|
+
return this._me;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public async getMe(): Promise<User> {
|
|
64
|
+
await this.deferredSession.promise;
|
|
65
|
+
return this._me;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private handleSession(ev: Session): void {
|
|
69
|
+
this._me = ev.user;
|
|
70
|
+
this.deferredSession.resolve();
|
|
71
|
+
}
|
|
72
72
|
}
|
|
@@ -6,7 +6,6 @@ import {TopicHistoryWindow, WindowState} from "./TopicHistoryWindow";
|
|
|
6
6
|
export class RoomMessagesHistory {
|
|
7
7
|
private historyWindows = new IndexedCollection<string, TopicHistoryWindow>();
|
|
8
8
|
private traverseLock: boolean = false;
|
|
9
|
-
private timeLimitedHistory: boolean = false;
|
|
10
9
|
|
|
11
10
|
public constructor(
|
|
12
11
|
private room: Room,
|
|
@@ -16,7 +15,7 @@ export class RoomMessagesHistory {
|
|
|
16
15
|
this.tracker.client.on('NewTopic', ev => this.handleNewTopic(ev));
|
|
17
16
|
this.tracker.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
|
|
18
17
|
|
|
19
|
-
this.
|
|
18
|
+
this.updateTraverseLock(this.room);
|
|
20
19
|
|
|
21
20
|
if (this.room.defaultTopic) {
|
|
22
21
|
this.createHistoryWindowForTopic(this.room.defaultTopic);
|
|
@@ -47,23 +46,13 @@ export class RoomMessagesHistory {
|
|
|
47
46
|
*
|
|
48
47
|
* The window bindings are preserved; only windows that the application had
|
|
49
48
|
* actually pulled to the latest page (state === LATEST) are refreshed, with
|
|
50
|
-
* a single
|
|
51
|
-
* were never pulled (LIVE) or belong to an ephemeral room are left
|
|
52
|
-
* so their in-memory context survives the reconnect.
|
|
53
|
-
*
|
|
54
|
-
* How a refreshed window is rebuilt depends on the room history mode: rooms
|
|
55
|
-
* keeping the full history are simply reset to the latest page (it can
|
|
56
|
-
* always be traversed back on demand), while rooms with a time-limited
|
|
57
|
-
* history (MaxAge) load the messages missed during the downtime on top of
|
|
58
|
-
* the already loaded ones, with the messages returned in both deduplicated.
|
|
59
|
-
* The maxAge retention applies to what the server serves - so that users
|
|
60
|
-
* joining later do not see the older conversation - and never to what this
|
|
61
|
-
* client already has: messages the user witnessed stay in the window until
|
|
62
|
-
* they are pushed out by its own size limit.
|
|
49
|
+
* a single resetToLatest instead of a chain of catch-up requests. Windows
|
|
50
|
+
* that were never pulled (LIVE) or belong to an ephemeral room are left
|
|
51
|
+
* untouched so their in-memory context survives the reconnect.
|
|
63
52
|
*/
|
|
64
53
|
public async resync(room: Room): Promise<void> {
|
|
65
54
|
this.room = room;
|
|
66
|
-
this.
|
|
55
|
+
this.updateTraverseLock(room);
|
|
67
56
|
|
|
68
57
|
if (this.room.defaultTopic) {
|
|
69
58
|
this.createHistoryWindowForTopic(this.room.defaultTopic);
|
|
@@ -79,13 +68,7 @@ export class RoomMessagesHistory {
|
|
|
79
68
|
continue;
|
|
80
69
|
}
|
|
81
70
|
|
|
82
|
-
if (window.state
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (this.timeLimitedHistory) {
|
|
87
|
-
await window.resyncToLatest();
|
|
88
|
-
} else {
|
|
71
|
+
if (window.state === WindowState.LATEST) {
|
|
89
72
|
await window.resetToLatest(true);
|
|
90
73
|
}
|
|
91
74
|
} catch (_e) {
|
|
@@ -100,7 +83,7 @@ export class RoomMessagesHistory {
|
|
|
100
83
|
if (this.room.id === ev.room.id) {
|
|
101
84
|
this.room = ev.room;
|
|
102
85
|
|
|
103
|
-
this.
|
|
86
|
+
this.updateTraverseLock(ev.room);
|
|
104
87
|
|
|
105
88
|
if (ev.room.defaultTopic) {
|
|
106
89
|
this.createHistoryWindowForTopic(ev.room.defaultTopic);
|
|
@@ -151,8 +134,7 @@ export class RoomMessagesHistory {
|
|
|
151
134
|
}
|
|
152
135
|
}
|
|
153
136
|
|
|
154
|
-
private
|
|
155
|
-
this.traverseLock = room.history
|
|
156
|
-
this.timeLimitedHistory = room.history?.mode === 'MaxAge';
|
|
137
|
+
private updateTraverseLock(room: Room): void {
|
|
138
|
+
this.traverseLock = room.history.mode === 'Ephemeral';
|
|
157
139
|
}
|
|
158
140
|
}
|