polfan-server-js-client 0.2.66 → 0.2.68

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.
@@ -1,4 +1,4 @@
1
- import { Bye, GetSession, JoinSpace, Session, SpaceJoined, Error as ErrorType, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMemberUpdated, SpaceDeleted, SpaceMembers, SpaceRooms, NewRole, RoomDeleted, RoomJoined, RoomLeft, RoomMemberLeft, RoomMemberJoined, RoomMembers, NewRoom, NewTopic, TopicDeleted, NewMessage, GetPermissionOverwrites, GetComputedPermissions, LeaveSpace, CreateSpace, DeleteSpace, GetSpaceMembers, GetSpaceRooms, CreateRole, DeleteRole, AssignRole, DeassignRole, SetPermissionOverwrites, JoinRoom, LeaveRoom, CreateRoom, DeleteRoom, GetRoomMembers, CreateTopic, DeleteTopic, CreateMessage, Envelope, PermissionOverwrites, PermissionOverwritesUpdated, RoomMemberUpdated, UpdateRole, RoleUpdated, Ack, UserUpdated, UpdateRoom, RoomUpdated, UpdateSpace, SpaceUpdated, PermissionOverwriteTargets, GetPermissionOverwriteTargets, Owners, Ok, GetOwners, CreateOwner, RoleDeleted, FollowedTopicUpdated, TopicFollowed, TopicUnfollowed, FollowedTopics, FollowTopic, UnfollowTopic, GetFollowedTopics, Messages, GetMessages, Topics, GetTopics, TopicUpdated, UpdateTopic, GetDiscoverableSpaces, DiscoverableSpaces, CreateEmoticon, DeleteEmoticon, GetEmoticons, Emoticons, EmoticonDeleted, NewEmoticon, Bans, GetBans, Ban, Unban, Kick, ClientData, GetClientData, SetClientData, GetRoomSummary, GetSpaceSummary, RoomSummaryEvent, SpaceSummaryEvent, UpdateSpaceMember, Relationships, RelationshipDeleted, NewRelationship, DeleteRelationship, CreateRelationship, RoomSummaryUpdated } from "./types/src/index";
1
+ import { Bye, GetSession, JoinSpace, Session, SpaceJoined, Error as ErrorType, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMemberUpdated, SpaceDeleted, SpaceMembers, SpaceRooms, NewRole, RoomDeleted, RoomJoined, RoomLeft, RoomMemberLeft, RoomMemberJoined, RoomMembers, NewRoom, NewTopic, TopicDeleted, NewMessage, GetPermissionOverwrites, GetComputedPermissions, LeaveSpace, CreateSpace, DeleteSpace, GetSpaceMembers, GetSpaceRooms, CreateRole, DeleteRole, AssignRole, DeassignRole, SetPermissionOverwrites, JoinRoom, LeaveRoom, CreateRoom, DeleteRoom, GetRoomMembers, CreateTopic, DeleteTopic, CreateMessage, Envelope, PermissionOverwrites, PermissionOverwritesUpdated, RoomMemberUpdated, UpdateRole, RoleUpdated, Ack, UserUpdated, UpdateRoom, RoomUpdated, UpdateSpace, SpaceUpdated, PermissionOverwriteTargets, GetPermissionOverwriteTargets, Owners, Ok, GetOwners, CreateOwner, RoleDeleted, FollowedTopicUpdated, TopicFollowed, TopicUnfollowed, FollowedTopics, FollowTopic, UnfollowTopic, GetFollowedTopics, Messages, GetMessages, Topics, GetTopics, TopicUpdated, UpdateTopic, GetDiscoverableSpaces, DiscoverableSpaces, CreateEmoticon, DeleteEmoticon, GetEmoticons, Emoticons, EmoticonDeleted, NewEmoticon, Bans, GetBans, Ban, Unban, Kick, ClientData, GetClientData, SetClientData, GetRoomSummary, GetSpaceSummary, RoomSummaryEvent, SpaceSummaryEvent, UpdateSpaceMember, Relationships, RelationshipDeleted, NewRelationship, DeleteRelationship, CreateRelationship, RoomSummaryUpdated, Pong, Ping } from "./types/src/index";
2
2
  import { EventTarget } from "./EventTarget";
3
3
  import { GetRelationships } from "./types/src/schemes/commands/GetRelationships";
4
4
  import { UpdateRoomMember } from "./types/src/schemes/commands/UpdateRoomMember";
@@ -39,6 +39,7 @@ export type EventsMap = {
39
39
  NewRelationship: NewRelationship;
40
40
  RelationshipDeleted: RelationshipDeleted;
41
41
  Relationships: Relationships;
42
+ Pong: Pong;
42
43
  DiscoverableSpaces: DiscoverableSpaces;
43
44
  SpaceJoined: SpaceJoined;
44
45
  SpaceLeft: SpaceLeft;
@@ -100,6 +101,7 @@ export type CommandsMap = {
100
101
  DeleteRelationship: [DeleteRelationship, EventsMap['RelationshipDeleted']];
101
102
  CreateRelationship: [CreateRelationship, EventsMap['NewRelationship']];
102
103
  GetRelationships: [GetRelationships, EventsMap['Relationships']];
104
+ Ping: [Ping, EventsMap['Pong']];
103
105
  GetDiscoverableSpaces: [GetDiscoverableSpaces, EventsMap['DiscoverableSpaces']];
104
106
  JoinSpace: [JoinSpace, EventsMap['SpaceJoined']];
105
107
  LeaveSpace: [LeaveSpace, EventsMap['SpaceLeft']];
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { ObservableInterface } from "./EventTarget";
2
3
  import { AbstractChatClient, CommandResult, CommandsMap } from "./AbstractChatClient";
3
4
  import { ChatStateTracker } from "./state-tracker/ChatStateTracker";
@@ -9,6 +10,20 @@ export interface WebSocketClientOptions {
9
10
  awaitQueueSendDelayMs?: number;
10
11
  stateTracking?: boolean;
11
12
  queryParams?: Record<string, string>;
13
+ /**
14
+ * Ping/pong configuration, enabled by default.
15
+ */
16
+ ping?: {
17
+ enabled?: boolean;
18
+ /**
19
+ * Time without activity after which a ping will be sent. Default is 10 seconds.
20
+ */
21
+ noActivityTimeoutMs?: number;
22
+ /**
23
+ * Time to wait for a pong response before considering the connection dead. Default is 2 seconds.
24
+ */
25
+ pongBackTimeoutMs?: number;
26
+ };
12
27
  }
13
28
  declare enum WebSocketChatClientEvent {
14
29
  connect = "connect",
@@ -25,6 +40,9 @@ export declare class WebSocketChatClient extends AbstractChatClient implements O
25
40
  protected connectingTimeoutId: any;
26
41
  protected authenticated: boolean;
27
42
  protected authenticatedResolvers: [() => void, (error: Error) => void];
43
+ protected pingIntervalId?: NodeJS.Timeout;
44
+ protected lastReceivedMessageAt?: number;
45
+ protected pingInFlight: boolean;
28
46
  constructor(options: WebSocketClientOptions);
29
47
  connect(): Promise<void>;
30
48
  disconnect(): void;
@@ -37,5 +55,7 @@ export declare class WebSocketChatClient extends AbstractChatClient implements O
37
55
  private triggerConnectionTimeout;
38
56
  private isConnectingWsState;
39
57
  private isOpenWsState;
58
+ private startConnectionMonitor;
59
+ private stopConnectionMonitor;
40
60
  }
41
61
  export {};
@@ -126,4 +126,6 @@ import { Relationships } from "./schemes/events/Relationships";
126
126
  import { CreateRelationship } from "./schemes/commands/CreateRelationship";
127
127
  import { RoomSummaryUpdated } from "./schemes/events/RoomSummaryUpdated";
128
128
  import { UpdateRoomMember } from "./schemes/commands/UpdateRoomMember";
129
- export { Envelope, Message, MessageType, MessageAuthor, Role, Room, RoomFlag, RoomType, RoomStream, RoomStreamType, RoomHistory, RoomHistoryMode, RoomMember, RoomSummary, RoomSummaryExtras, Space, SpaceFlag, SpaceMember, Topic, FollowedTopic, User, UserState, PermissionOverwritesValue, ChatLocation, SpaceSummary, SpaceDiscoverable, Emoticon, PermissionOverwritesTarget, BanObject, LeaveReason, UserRelationship, UserRelationshipType, CreateTopicInitialMessage, Bye, Error, Messages, NewMessage, NewRole, NewRoom, NewTopic, TopicFollowed, TopicUnfollowed, FollowedTopics, FollowedTopicUpdated, ComputedPermissions, PermissionOverwrites, PermissionOverwritesUpdated, RoleDeleted, RoleUpdated, RoomDeleted, RoomUpdated, RoomJoined, RoomLeft, RoomMemberJoined, RoomMemberLeft, RoomMembers, RoomMemberUpdated, UserUpdated, Session, SpaceDeleted, SpaceUpdated, SpaceJoined, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMembers, SpaceMemberUpdated, SpaceRooms, TopicDeleted, TopicUpdated, PermissionOverwriteTargets, Owners, Ok, DiscoverableSpaces, Emoticons, EmoticonDeleted, NewEmoticon, Bans, ClientData, SpaceSummaryEvent, RoomSummaryEvent, NewRelationship, RelationshipDeleted, Relationships, RoomSummaryUpdated, AssignRole, GetMessages, CreateMessage, Ack, CreateRole, CreateRoom, CreateSpace, CreateTopic, FollowTopic, UnfollowTopic, GetFollowedTopics, DeassignRole, DeleteRole, DeleteRoom, DeleteSpace, DeleteTopic, SetPermissionOverwrites, GetPermissionOverwrites, GetComputedPermissions, GetRoomMembers, GetSession, GetSpaceMembers, GetSpaceRooms, JoinRoom, JoinSpace, LeaveRoom, LeaveSpace, UpdateRole, UpdateSpace, UpdateRoom, UpdateTopic, GetPermissionOverwriteTargets, CreateOwner, DeleteOwner, GetOwners, Topics, GetTopics, GetDiscoverableSpaces, GetEmoticons, CreateEmoticon, DeleteEmoticon, Ban, Unban, GetBans, Kick, GetClientData, SetClientData, GetSpaceSummary, GetRoomSummary, UpdateSpaceMember, CreateRelationship, DeleteRelationship, UpdateRoomMember, };
129
+ import { Ping } from "./schemes/commands/Ping";
130
+ import { Pong } from "./schemes/events/Pong";
131
+ export { Envelope, Message, MessageType, MessageAuthor, Role, Room, RoomFlag, RoomType, RoomStream, RoomStreamType, RoomHistory, RoomHistoryMode, RoomMember, RoomSummary, RoomSummaryExtras, Space, SpaceFlag, SpaceMember, Topic, FollowedTopic, User, UserState, PermissionOverwritesValue, ChatLocation, SpaceSummary, SpaceDiscoverable, Emoticon, PermissionOverwritesTarget, BanObject, LeaveReason, UserRelationship, UserRelationshipType, CreateTopicInitialMessage, Bye, Error, Messages, NewMessage, NewRole, NewRoom, NewTopic, TopicFollowed, TopicUnfollowed, FollowedTopics, FollowedTopicUpdated, ComputedPermissions, PermissionOverwrites, PermissionOverwritesUpdated, RoleDeleted, RoleUpdated, RoomDeleted, RoomUpdated, RoomJoined, RoomLeft, RoomMemberJoined, RoomMemberLeft, RoomMembers, RoomMemberUpdated, UserUpdated, Session, SpaceDeleted, SpaceUpdated, SpaceJoined, SpaceLeft, SpaceMemberJoined, SpaceMemberLeft, SpaceMembers, SpaceMemberUpdated, SpaceRooms, TopicDeleted, TopicUpdated, PermissionOverwriteTargets, Owners, Ok, DiscoverableSpaces, Emoticons, EmoticonDeleted, NewEmoticon, Bans, ClientData, SpaceSummaryEvent, RoomSummaryEvent, NewRelationship, RelationshipDeleted, Relationships, RoomSummaryUpdated, Pong, AssignRole, GetMessages, CreateMessage, Ack, CreateRole, CreateRoom, CreateSpace, CreateTopic, FollowTopic, UnfollowTopic, GetFollowedTopics, DeassignRole, DeleteRole, DeleteRoom, DeleteSpace, DeleteTopic, SetPermissionOverwrites, GetPermissionOverwrites, GetComputedPermissions, GetRoomMembers, GetSession, GetSpaceMembers, GetSpaceRooms, JoinRoom, JoinSpace, LeaveRoom, LeaveSpace, UpdateRole, UpdateSpace, UpdateRoom, UpdateTopic, GetPermissionOverwriteTargets, CreateOwner, DeleteOwner, GetOwners, Topics, GetTopics, GetDiscoverableSpaces, GetEmoticons, CreateEmoticon, DeleteEmoticon, Ban, Unban, GetBans, Kick, GetClientData, SetClientData, GetSpaceSummary, GetRoomSummary, UpdateSpaceMember, CreateRelationship, DeleteRelationship, UpdateRoomMember, Ping, };
@@ -0,0 +1,2 @@
1
+ export interface Ping {
2
+ }
@@ -0,0 +1,2 @@
1
+ export interface Pong {
2
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polfan-server-js-client",
3
- "version": "0.2.66",
3
+ "version": "0.2.68",
4
4
  "description": "JavaScript client library for handling communication with Polfan chat server.",
5
5
  "author": "Jarosław Żak",
6
6
  "license": "MIT",
@@ -101,7 +101,7 @@ import {
101
101
  NewRelationship,
102
102
  DeleteRelationship,
103
103
  CreateRelationship,
104
- RoomSummaryUpdated,
104
+ RoomSummaryUpdated, Pong, Ping,
105
105
  } from "./types/src/index";
106
106
  import {EventTarget} from "./EventTarget";
107
107
  import {GetRelationships} from "./types/src/schemes/commands/GetRelationships";
@@ -184,6 +184,7 @@ export type EventsMap = {
184
184
  NewRelationship: NewRelationship,
185
185
  RelationshipDeleted: RelationshipDeleted,
186
186
  Relationships: Relationships,
187
+ Pong: Pong,
187
188
  // Space events
188
189
  DiscoverableSpaces: DiscoverableSpaces,
189
190
  SpaceJoined: SpaceJoined,
@@ -250,6 +251,7 @@ export type CommandsMap = {
250
251
  DeleteRelationship: [DeleteRelationship, EventsMap['RelationshipDeleted']],
251
252
  CreateRelationship: [CreateRelationship, EventsMap['NewRelationship']],
252
253
  GetRelationships: [GetRelationships, EventsMap['Relationships']],
254
+ Ping: [Ping, EventsMap['Pong']],
253
255
  // Space commands
254
256
  GetDiscoverableSpaces: [GetDiscoverableSpaces, EventsMap['DiscoverableSpaces']],
255
257
  JoinSpace: [JoinSpace, EventsMap['SpaceJoined']],
@@ -1,5 +1,5 @@
1
1
  import {ObservableInterface} from "./EventTarget";
2
- import {AbstractChatClient, CommandResult, CommandsMap} from "./AbstractChatClient";
2
+ import {AbstractChatClient, CommandResult, CommandsMap, EventsMap} from "./AbstractChatClient";
3
3
  import {ChatStateTracker} from "./state-tracker/ChatStateTracker";
4
4
  import {Envelope} from "./types/src";
5
5
 
@@ -10,6 +10,20 @@ export interface WebSocketClientOptions {
10
10
  awaitQueueSendDelayMs?: number;
11
11
  stateTracking?: boolean;
12
12
  queryParams?: Record<string, string>;
13
+ /**
14
+ * Ping/pong configuration, enabled by default.
15
+ */
16
+ ping?: {
17
+ enabled?: boolean;
18
+ /**
19
+ * Time without activity after which a ping will be sent. Default is 10 seconds.
20
+ */
21
+ noActivityTimeoutMs?: number;
22
+ /**
23
+ * Time to wait for a pong response before considering the connection dead. Default is 2 seconds.
24
+ */
25
+ pongBackTimeoutMs?: number;
26
+ },
13
27
  }
14
28
 
15
29
  enum WebSocketChatClientEvent {
@@ -28,12 +42,20 @@ export class WebSocketChatClient extends AbstractChatClient implements Observabl
28
42
  protected connectingTimeoutId: any;
29
43
  protected authenticated: boolean;
30
44
  protected authenticatedResolvers: [() => void, (error: Error) => void];
45
+ protected pingIntervalId?: NodeJS.Timeout;
46
+ protected lastReceivedMessageAt?: number;
47
+ protected pingInFlight: boolean;
31
48
 
32
49
  public constructor(private readonly options: WebSocketClientOptions) {
33
50
  super();
34
51
  if (this.options.stateTracking ?? true) {
35
52
  this.state = new ChatStateTracker(this);
36
53
  }
54
+
55
+ options.ping ??= {};
56
+ options.ping.enabled ??= true;
57
+ options.ping.noActivityTimeoutMs ??= 15000;
58
+ options.ping.pongBackTimeoutMs ??= 5000;
37
59
  }
38
60
 
39
61
  public async connect(): Promise<void> {
@@ -52,13 +74,12 @@ export class WebSocketChatClient extends AbstractChatClient implements Observabl
52
74
  this.options.connectingTimeoutMs ?? 10000
53
75
  );
54
76
  this.authenticated = false;
55
-
56
77
  return new Promise((...args) => this.authenticatedResolvers = args);
57
78
  }
58
79
 
59
80
  public disconnect(): void {
60
81
  this.sendQueue = [];
61
- this.ws?.close();
82
+ this.ws?.close(1000); // Normal closure
62
83
  this.ws = null;
63
84
  }
64
85
 
@@ -93,6 +114,7 @@ export class WebSocketChatClient extends AbstractChatClient implements Observabl
93
114
  }
94
115
 
95
116
  private onMessage(event: MessageEvent): void {
117
+ this.lastReceivedMessageAt = Date.now();
96
118
  const envelope: Envelope = JSON.parse(event.data);
97
119
  this.handleIncomingEnvelope(envelope);
98
120
  this.emit(envelope.type, envelope.data);
@@ -103,6 +125,7 @@ export class WebSocketChatClient extends AbstractChatClient implements Observabl
103
125
  const isAuthenticated = envelope.type !== 'Bye';
104
126
  this.authenticated = isAuthenticated;
105
127
  if (isAuthenticated) {
128
+ this.startConnectionMonitor();
106
129
  this.authenticatedResolvers[0]();
107
130
  this.emit(this.Event.connect);
108
131
  this.sendFromQueue();
@@ -113,6 +136,7 @@ export class WebSocketChatClient extends AbstractChatClient implements Observabl
113
136
  }
114
137
 
115
138
  private onClose(event: CloseEvent): void {
139
+ this.stopConnectionMonitor();
116
140
  clearTimeout(this.connectingTimeoutId);
117
141
  const reconnect = event.code !== 1000; // Connection was closed because of error
118
142
  if (reconnect) {
@@ -145,4 +169,42 @@ export class WebSocketChatClient extends AbstractChatClient implements Observabl
145
169
  private isOpenWsState(): boolean {
146
170
  return this.ws && this.ws.readyState === this.ws.OPEN;
147
171
  }
172
+
173
+ private startConnectionMonitor(): void {
174
+ if (!this.options.ping!.enabled) {
175
+ return;
176
+ }
177
+
178
+ this.lastReceivedMessageAt = Date.now();
179
+
180
+ this.pingIntervalId = setInterval(async () => {
181
+ if (!this.isReady || this.pingInFlight) {
182
+ return;
183
+ }
184
+
185
+ if ((Date.now() - this.lastReceivedMessageAt) < this.options.ping!.noActivityTimeoutMs) {
186
+ return;
187
+ }
188
+
189
+ const timeout = setTimeout(() => {
190
+ this.pingInFlight = false;
191
+ this.ws.close(1012); // Service Restart (reconnect)
192
+ }, this.options.ping.pongBackTimeoutMs);
193
+
194
+ this.pingInFlight = true;
195
+
196
+ this.send('Ping', {}).then(() => {
197
+ this.pingInFlight = false;
198
+ clearTimeout(timeout);
199
+ });
200
+ }, 1000);
201
+ }
202
+
203
+ private stopConnectionMonitor(): void {
204
+ if (this.pingIntervalId) {
205
+ clearInterval(this.pingIntervalId);
206
+ this.pingIntervalId = undefined;
207
+ }
208
+ this.pingInFlight = false;
209
+ }
148
210
  }
@@ -126,6 +126,8 @@ import {Relationships} from "./schemes/events/Relationships";
126
126
  import {CreateRelationship} from "./schemes/commands/CreateRelationship";
127
127
  import {RoomSummaryUpdated} from "./schemes/events/RoomSummaryUpdated";
128
128
  import {UpdateRoomMember} from "./schemes/commands/UpdateRoomMember";
129
+ import {Ping} from "./schemes/commands/Ping";
130
+ import {Pong} from "./schemes/events/Pong";
129
131
 
130
132
  export {
131
133
  // objects
@@ -215,6 +217,7 @@ export {
215
217
  RelationshipDeleted,
216
218
  Relationships,
217
219
  RoomSummaryUpdated,
220
+ Pong,
218
221
  // commands
219
222
  AssignRole,
220
223
  GetMessages,
@@ -269,4 +272,5 @@ export {
269
272
  CreateRelationship,
270
273
  DeleteRelationship,
271
274
  UpdateRoomMember,
275
+ Ping,
272
276
  };
@@ -0,0 +1,3 @@
1
+ export interface Ping {
2
+
3
+ }
@@ -0,0 +1,3 @@
1
+ export interface Pong {
2
+
3
+ }