polfan-server-js-client 0.1.0 → 0.1.2
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/build/index.js +1776 -1
- package/build/index.js.map +1 -1
- package/build/types/{AbstractClient.d.ts → AbstractChatClient.d.ts} +1 -1
- package/build/types/AbstractRestClient.d.ts +19 -0
- package/build/types/AuthClient.d.ts +16 -0
- package/build/types/{WebSocketStateTracker.d.ts → ChatStateTracker.d.ts} +3 -3
- package/build/types/EventTarget.d.ts +2 -0
- package/build/types/IndexedObjectCollection.d.ts +3 -0
- package/build/types/{WebApiClient.d.ts → WebApiChatClient.d.ts} +6 -6
- package/build/types/{WebSocketClient.d.ts → WebSocketChatClient.d.ts} +6 -6
- package/build/types/index.d.ts +4 -3
- package/index.html +8 -0
- package/package.json +1 -1
- package/src/{AbstractClient.ts → AbstractChatClient.ts} +1 -1
- package/src/AbstractRestClient.ts +66 -0
- package/src/AuthClient.ts +46 -0
- package/src/{WebSocketStateTracker.ts → ChatStateTracker.ts} +15 -5
- package/src/EventTarget.ts +9 -0
- package/src/IndexedObjectCollection.ts +18 -1
- package/src/{WebApiClient.ts → WebApiChatClient.ts} +7 -7
- package/src/{WebSocketClient.ts → WebSocketChatClient.ts} +11 -10
- package/src/index.ts +5 -3
- package/webpack.config.js +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {AbstractRestClient} from "./AbstractRestClient";
|
|
2
|
+
|
|
3
|
+
export interface TokenInterface {
|
|
4
|
+
token: string,
|
|
5
|
+
expiration: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface MyAccountInterface {
|
|
9
|
+
id: string;
|
|
10
|
+
nick: string;
|
|
11
|
+
avatar: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class AuthClient extends AbstractRestClient {
|
|
15
|
+
protected defaultUrl: string = 'https://polfan.pl/webservice/api';
|
|
16
|
+
|
|
17
|
+
public static async createToken(
|
|
18
|
+
login: string,
|
|
19
|
+
password: string,
|
|
20
|
+
clientName: string = 'pserv-js-client'
|
|
21
|
+
): Promise<TokenInterface> {
|
|
22
|
+
const response = await new AuthClient({token: null}).send('POST', 'auth/tokens', {
|
|
23
|
+
login, password, client_name: clientName
|
|
24
|
+
});
|
|
25
|
+
if (response.ok) {
|
|
26
|
+
return response.data;
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`Cannot create user token: ${response.data.errors[0]}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async deleteToken(token: string): Promise<void> {
|
|
32
|
+
const response = await this.send('DELETE', `auth/tokens/${token}`);
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(`Cannot delete access token: ${response.data.errors[0]}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async getMe(): Promise<MyAccountInterface> {
|
|
39
|
+
const response = await this.send('GET', 'auth/me');
|
|
40
|
+
if (response.ok) {
|
|
41
|
+
response.data.id = response.data.id.toString();
|
|
42
|
+
return response.data;
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`Cannot get current user account: ${response.data.errors[0]}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {WebSocketChatClient} from "./WebSocketChatClient";
|
|
2
2
|
import {IndexedCollection, ObservableIndexedObjectCollection} from "./IndexedObjectCollection";
|
|
3
3
|
import {
|
|
4
4
|
Message,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
|
|
30
30
|
type Deferred = {resolver: () => void, promise: Promise<void>};
|
|
31
31
|
|
|
32
|
-
export class
|
|
32
|
+
export class ChatStateTracker {
|
|
33
33
|
private readonly joinedSpaces = new ObservableIndexedObjectCollection<Space>('id');
|
|
34
34
|
private readonly joinedRooms = new ObservableIndexedObjectCollection<Room>('id');
|
|
35
35
|
private readonly spacesRoles = new IndexedCollection<string, ObservableIndexedObjectCollection<Role>>();
|
|
@@ -46,7 +46,8 @@ export class WebSocketStateTracker {
|
|
|
46
46
|
private reconnecting: boolean = false;
|
|
47
47
|
private me: User = null;
|
|
48
48
|
|
|
49
|
-
public constructor(private readonly client:
|
|
49
|
+
public constructor(private readonly client: WebSocketChatClient) {
|
|
50
|
+
this.createDeferredGetter('session');
|
|
50
51
|
this.bind();
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -200,6 +201,16 @@ export class WebSocketStateTracker {
|
|
|
200
201
|
room.id,
|
|
201
202
|
new ObservableIndexedObjectCollection<Topic>('id', room.topics)
|
|
202
203
|
]));
|
|
204
|
+
|
|
205
|
+
const topicsMessages: [string, ObservableIndexedObjectCollection<Message>][] = [];
|
|
206
|
+
for (const room of rooms) {
|
|
207
|
+
topicsMessages.push(...room.topics.map<[string, ObservableIndexedObjectCollection<Message>]>(topic => [
|
|
208
|
+
topic.id,
|
|
209
|
+
new ObservableIndexedObjectCollection<Message>('id')
|
|
210
|
+
]));
|
|
211
|
+
}
|
|
212
|
+
this.topicsMessages.set(...topicsMessages);
|
|
213
|
+
|
|
203
214
|
this.joinedRooms.set(...rooms);
|
|
204
215
|
}
|
|
205
216
|
|
|
@@ -235,12 +246,11 @@ export class WebSocketStateTracker {
|
|
|
235
246
|
}
|
|
236
247
|
|
|
237
248
|
private handleSession(ev: Session): void {
|
|
238
|
-
this.me = ev.user;
|
|
239
|
-
|
|
240
249
|
if (this.me && !this.reconnecting) {
|
|
241
250
|
return;
|
|
242
251
|
}
|
|
243
252
|
|
|
253
|
+
this.me = ev.user;
|
|
244
254
|
this.reconnecting = false;
|
|
245
255
|
|
|
246
256
|
this.joinedRooms.deleteAll();
|
package/src/EventTarget.ts
CHANGED
|
@@ -4,6 +4,7 @@ type HandlersMap<EventT> = Map<string, EventHandler<EventT>[]>;
|
|
|
4
4
|
export interface ObservableInterface<EventT = any> {
|
|
5
5
|
on(eventName: string, handler: EventHandler<EventT>): this;
|
|
6
6
|
once(eventName: string, handler: EventHandler<EventT>): this;
|
|
7
|
+
off(eventName: string, handler: EventHandler<EventT>): this;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export class EventTarget<EventT = any> implements ObservableInterface<EventT> {
|
|
@@ -20,6 +21,14 @@ export class EventTarget<EventT = any> implements ObservableInterface<EventT> {
|
|
|
20
21
|
return this;
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
public off(eventName: string, handler: EventHandler<EventT>): this {
|
|
25
|
+
const index = this.events.get(eventName)?.indexOf(handler);
|
|
26
|
+
if (!index || index < 0) {
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
this.events.get(eventName).splice(index, 1);
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
public emit(eventName: string, event?: EventT): this {
|
|
24
33
|
this.callHandlers(this.events, eventName, event);
|
|
25
34
|
this.callHandlers(this.onceEvents, eventName, event);
|
|
@@ -131,6 +131,12 @@ interface ObservableCollectionEvent<KeyT> {
|
|
|
131
131
|
export class ObservableIndexedCollection<KeyT, ValueT> extends IndexedCollection<KeyT, ValueT> implements ObservableInterface {
|
|
132
132
|
protected eventTarget: EventTarget<ObservableCollectionEvent<KeyT>>;
|
|
133
133
|
|
|
134
|
+
public constructor(items: [key: KeyT, value: ValueT][] = []) {
|
|
135
|
+
super();
|
|
136
|
+
this.eventTarget = new EventTarget<ObservableCollectionEvent<KeyT>>();
|
|
137
|
+
this.set(...items);
|
|
138
|
+
}
|
|
139
|
+
|
|
134
140
|
public set(...items: [KeyT, ValueT][]) {
|
|
135
141
|
if (items.length) {
|
|
136
142
|
super.set(...items);
|
|
@@ -162,6 +168,11 @@ export class ObservableIndexedCollection<KeyT, ValueT> extends IndexedCollection
|
|
|
162
168
|
this.eventTarget.once(eventName, handler);
|
|
163
169
|
return this;
|
|
164
170
|
}
|
|
171
|
+
|
|
172
|
+
public off(eventName: string, handler: (ev?: ObservableCollectionEvent<KeyT>) => void): this {
|
|
173
|
+
this.eventTarget.off(eventName, handler);
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
165
176
|
}
|
|
166
177
|
|
|
167
178
|
export class ObservableIndexedObjectCollection<T> extends IndexedObjectCollection<T> implements ObservableInterface {
|
|
@@ -171,8 +182,9 @@ export class ObservableIndexedObjectCollection<T> extends IndexedObjectCollectio
|
|
|
171
182
|
public readonly id: keyof T | ((item: T) => string),
|
|
172
183
|
items: T[] = [],
|
|
173
184
|
) {
|
|
174
|
-
super(id
|
|
185
|
+
super(id);
|
|
175
186
|
this.eventTarget = new EventTarget();
|
|
187
|
+
this.set(...items);
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
public set(...items: T[]) {
|
|
@@ -206,4 +218,9 @@ export class ObservableIndexedObjectCollection<T> extends IndexedObjectCollectio
|
|
|
206
218
|
this.eventTarget.once(eventName, handler);
|
|
207
219
|
return this;
|
|
208
220
|
}
|
|
221
|
+
|
|
222
|
+
public off(eventName: string, handler: (ev?: ObservableCollectionEvent<string>) => void): this {
|
|
223
|
+
this.eventTarget.off(eventName, handler);
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
209
226
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {AbstractChatClient, CommandResult, CommandsMap} from "./AbstractChatClient";
|
|
2
2
|
import {ObservableInterface} from "./EventTarget";
|
|
3
3
|
import {Envelope} from "pserv-ts-types";
|
|
4
4
|
|
|
5
|
-
export interface
|
|
5
|
+
export interface WebApiChatClientOptions {
|
|
6
6
|
url: string;
|
|
7
7
|
token?: string;
|
|
8
8
|
temporaryNick?: string;
|
|
@@ -10,18 +10,18 @@ export interface WebApiClientOptions {
|
|
|
10
10
|
attemptDelayMs?: number;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
enum
|
|
13
|
+
enum WebApiChatClientEvent {
|
|
14
14
|
message = 'message',
|
|
15
15
|
error = 'error',
|
|
16
16
|
destroy = 'destroy',
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export class
|
|
20
|
-
public readonly Event =
|
|
19
|
+
export class WebApiChatClient extends AbstractChatClient implements ObservableInterface {
|
|
20
|
+
public readonly Event = WebApiChatClientEvent;
|
|
21
21
|
|
|
22
22
|
protected sendStack: {data: any, attempts: number, lastTimeoutId: any}[];
|
|
23
23
|
|
|
24
|
-
public constructor(private readonly options:
|
|
24
|
+
public constructor(private readonly options: WebApiChatClientOptions) {
|
|
25
25
|
super();
|
|
26
26
|
if (!this.options.token && !this.options.temporaryNick) {
|
|
27
27
|
throw new Error('Token or temporary nick is required');
|
|
@@ -52,7 +52,7 @@ export class WebApiClient extends AbstractClient implements ObservableInterface
|
|
|
52
52
|
this.sendStack.splice(reqId, 1);
|
|
53
53
|
const envelope: Envelope = await response.json();
|
|
54
54
|
this.handleIncomingEnvelope(envelope);
|
|
55
|
-
this.emit(envelope.type, envelope);
|
|
55
|
+
this.emit(envelope.type, envelope.data);
|
|
56
56
|
this.emit(this.Event.message, envelope);
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {ObservableInterface} from "./EventTarget";
|
|
2
|
-
import {
|
|
2
|
+
import {AbstractChatClient, CommandResult, CommandsMap} from "./AbstractChatClient";
|
|
3
3
|
import {Envelope} from "pserv-ts-types";
|
|
4
|
-
import {
|
|
4
|
+
import {ChatStateTracker} from "./ChatStateTracker";
|
|
5
5
|
|
|
6
6
|
export interface WebSocketClientOptions {
|
|
7
7
|
url: string;
|
|
@@ -12,16 +12,16 @@ export interface WebSocketClientOptions {
|
|
|
12
12
|
stateTracking?: boolean;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
enum
|
|
15
|
+
enum WebSocketChatClientEvent {
|
|
16
16
|
connect = 'connect',
|
|
17
17
|
disconnect = 'disconnect',
|
|
18
18
|
message = 'message',
|
|
19
19
|
error = 'error',
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export class
|
|
23
|
-
public readonly Event =
|
|
24
|
-
public readonly state?:
|
|
22
|
+
export class WebSocketChatClient extends AbstractChatClient implements ObservableInterface {
|
|
23
|
+
public readonly Event = WebSocketChatClientEvent;
|
|
24
|
+
public readonly state?: ChatStateTracker;
|
|
25
25
|
|
|
26
26
|
protected ws: WebSocket|null = null;
|
|
27
27
|
protected sendQueue: [commandType: keyof CommandsMap, commandData: any][] = [];
|
|
@@ -35,7 +35,7 @@ export class WebSocketClient extends AbstractClient implements ObservableInterfa
|
|
|
35
35
|
throw new Error('Token or temporary nick is required');
|
|
36
36
|
}
|
|
37
37
|
if (this.options.stateTracking ?? true) {
|
|
38
|
-
this.state = new
|
|
38
|
+
this.state = new ChatStateTracker(this);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -80,6 +80,10 @@ export class WebSocketClient extends AbstractClient implements ObservableInterfa
|
|
|
80
80
|
|
|
81
81
|
private onMessage(event: MessageEvent): void {
|
|
82
82
|
const envelope: Envelope = JSON.parse(event.data);
|
|
83
|
+
this.handleIncomingEnvelope(envelope);
|
|
84
|
+
this.emit(envelope.type, envelope.data);
|
|
85
|
+
this.emit(this.Event.message, envelope);
|
|
86
|
+
|
|
83
87
|
// Login successfully
|
|
84
88
|
if (!this.authenticated) {
|
|
85
89
|
const isAuthenticated = envelope.type !== 'Error';
|
|
@@ -92,9 +96,6 @@ export class WebSocketClient extends AbstractClient implements ObservableInterfa
|
|
|
92
96
|
this.authenticatedResolvers[1](envelope.data);
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
|
-
this.handleIncomingEnvelope(envelope);
|
|
96
|
-
this.emit(envelope.type, envelope);
|
|
97
|
-
this.emit(this.Event.message, envelope);
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
private onClose(event: CloseEvent): void {
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {WebSocketChatClient} from "./WebSocketChatClient";
|
|
2
|
+
import {WebApiChatClient} from "./WebApiChatClient";
|
|
3
3
|
import {
|
|
4
4
|
IndexedCollection,
|
|
5
5
|
IndexedObjectCollection,
|
|
6
6
|
ObservableIndexedCollection,
|
|
7
7
|
ObservableIndexedObjectCollection
|
|
8
8
|
} from "./IndexedObjectCollection";
|
|
9
|
+
import { AuthClient } from "./AuthClient";
|
|
9
10
|
|
|
10
11
|
export {
|
|
11
12
|
IndexedCollection, ObservableIndexedCollection,
|
|
12
13
|
IndexedObjectCollection, ObservableIndexedObjectCollection,
|
|
13
|
-
|
|
14
|
+
WebSocketChatClient, WebApiChatClient,
|
|
15
|
+
AuthClient
|
|
14
16
|
};
|