@eleven-am/pondsocket 0.1.64 → 0.1.66

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/README.md CHANGED
@@ -1,139 +1,477 @@
1
-
2
1
  # PondSocket
3
2
 
4
- PondSocket is a fast, minimalist and bidirectional socket framework for NodeJS. Pond allows you to think of each action during a sockets lifetime as a request instead of a huge callback that exists inside the connection event.
5
- ## Documentation
3
+ PondSocket is a high-performance, minimalist, and bidirectional socket framework designed for Node.js. It provides a seamless way to handle real-time communication between server and client applications, making it an ideal choice for building WebSocket-based projects.
4
+
5
+ ## Installation
6
6
 
7
- This is a Node.js module available through the npm registry.
7
+ To integrate PondSocket into your Node.js project, simply install it via npm:
8
8
 
9
9
  ```bash
10
- npm install @eleven-am/pondsocket
10
+ npm install @eleven-am/pondsocket
11
11
  ```
12
12
 
13
- PondSocket usage depends on the environment in which it is being used.
14
-
15
- #### On the server
16
-
17
- When using PondSocket, an endpoint is created. The endpoint is the gateway by which sockets actually connect to the server.
18
- Multiple endpoints can be created but every endpoint is independent of the other, ie sockets on one endpoint cannot communicate with sockets on another endpoint.
19
-
20
- ```js
21
- import { PondSocket } from "@eleven-am/pondsocket";
22
-
23
- const pond = new PondSocket();
24
-
25
- const endpoint = pond.createEndpoint('/api/socket', (req, res, _endpoint) => {
26
- const token = req.query.token;
27
- if (!token)
28
- return res.reject('No token provided');
29
- res.accept({
30
- assign: {
31
- token
32
- }
33
- });
34
- })
13
+ ## Overview
14
+
15
+ PondSocket simplifies the complexity of handling WebSocket connections by abstracting the communication process into individual requests rather than dealing with intricate callbacks within the connection event. It offers a lightweight yet powerful solution for managing bidirectional communication channels, enabling real-time updates and collaboration between server and client components.
16
+
17
+ ## Server-side Usage
18
+
19
+ When setting up the server, PondSocket allows you to create multiple endpoints, each serving as a gateway for sockets to connect and communicate. Each endpoint operates independently, ensuring that sockets from one endpoint cannot interact with sockets from another. This isolation enhances security and simplifies resource management.
20
+
21
+ ```javascript
22
+ import PondSocket from "@eleven-am/pondsocket";
23
+
24
+ const pond = new PondSocket();
25
+
26
+ // Create an endpoint for handling socket connections
27
+ const endpoint = pond.createEndpoint('/api/socket', (req, res) => {
28
+ // Handle socket connection and authentication
29
+ });
35
30
  ```
36
31
 
37
- While sockets connect through the endpoint, communication between sockets cannot occur on the endpoint level. Sockets have to join a channel to communicate
38
- between themselves.
39
-
40
- ```js
41
- const channel = endpoint.createChannel(/^channel(.*?)/, (req, res, channel) => {
42
- const isAdmin = req.clientAssigns.admin;
43
- if (!isAdmin)
44
- return res.reject('You are not an admin');
45
-
46
- res.accept({
47
- assign: {
48
- admin: true,
49
- joinedDate: new Date()
50
- },
51
- presence: {
52
- state: 'online'
53
- },
54
- channelData: {
55
- locked: true,
56
- numberOfUsers: channel.presence.length
57
- }
58
- });
59
- });
32
+ Within each endpoint, sockets interact through channels. Channels provide an organized way to group users and manage efficient communication among them. When users join a channel, they can participate in real-time events and exchange information with other users in the same channel.
33
+
34
+ ```javascript
35
+ const channel = endpoint.createChannel('/channel/:id', (req, res) => {
36
+ // Handle the join request, which is sent when a user attempts to join the channel
37
+ });
60
38
  ```
61
39
 
62
- A user goes through the createChannel function to join a channel.
63
- When a user joins a channel, some private information can be assigned to the user. This assign could be viewed as a cookie that is only available serverside.
64
- The presence is the current state of the user. When you reassign a new presence information to a user, all other users connected to the same channel are informed of the change.
65
- This could be used as *user is typing*, *user is away*, etc. The channelData is information that is stored on the channel and accessible from anywhere the channel is available.
66
- It can be anything from a boolean to an instance of a class. This data cannot be accessed from another channel as it is private to the channel.
67
-
68
- ```js
69
- channel.on('hello', (req, res, channel) => {
70
- const users = channel.presence;
71
- res.assign({
72
- assign: {
73
- pingDate: new Date(),
74
- users: users.length
75
- }
76
- });
77
-
78
- // res.reject('curse words are not allowed on a child friendly channel')
79
- // channel.closeFromChannel(req.client.clientId);
80
- })
40
+ ## Client-side Usage
41
+
42
+ On the client-side, PondSocket provides the PondClient class to establish connections with the server. Clients can easily initiate connections, join channels, and participate in real-time interactions.
43
+
44
+ ```javascript
45
+ import PondClient from "@eleven-am/pondsocket/client";
46
+
47
+ const socket = new PondClient('/api/socket', {});
48
+ socket.connect();
81
49
  ```
82
50
 
83
- When a message is sent on a channel by a user, an event is triggered. The *on* function can be used to listen for these events. If the function is specified, it is called when the message is received.
84
- You can choose to decline the message being sent, or you can allow the message to be sent as usual. You can also do all the normal assigns to the channel, or user.
85
- In case there is no *on* function, the message will be sent without any action being taken.
51
+ Once connected, clients can create and join channels to engage in real-time communication with other users and the server.
86
52
 
87
- #### On the browser
53
+ ```javascript
54
+ const channel = socket.createChannel('/channel/123');
55
+ channel.join();
56
+ ```
88
57
 
89
- ```js
90
- import { PondClient } from "@eleven-am/pondsocket/client";
58
+ ### Node Client
91
59
 
92
- export const socket = new PondClient('/api/socket', {});
93
- socket.connect();
60
+ PondSocket also offers a Node.js client, which can be imported using:
61
+
62
+ ```javascript
63
+ import PondClient from "@eleven-am/pondsocket/node";
94
64
  ```
95
65
 
96
- The browser compatible package can be imported from @eleven-am/pondsocket/client.
97
- AN url string is provided to the class along with other url params, like token.
66
+ This node client allows you to turn another server into a client, enabling easy communication between different server instances.
67
+
68
+ ## Key Features
69
+
70
+ - **Simple and Efficient API**: PondSocket offers an easy-to-use API, making WebSocket communication straightforward and hassle-free.
71
+ - **Organized Channels**: Channels provide a structured approach for grouping users and facilitating efficient communication.
72
+ - **Assigns**: PondSocket allows the storage of private information for users and channels, enhancing data security.
73
+ - **Presence**: The presence feature keeps track of users' current states and notifies other users about any changes.
74
+ - **Broadcasting**: PondSocket enables broadcasting messages to all users or specific groups within a channel, facilitating real-time updates.
75
+ - **Typed and Well-documented**: The codebase is thoroughly documented and typed, providing a seamless development experience with improved IDE suggestions.
76
+
77
+ ## Examples
78
+
79
+ ### Client-side Example with Authentication
80
+
81
+ To connect to the PondSocket server and send messages while associating a username with the client connection, follow the steps below:
82
+
83
+ ```javascript
84
+ import PondClient from "@eleven-am/pondsocket/client";
98
85
 
99
- Multiple classes can be created, but it is advised to use a single class throughout the application.
100
- You can just create multiple channels and maintain the single socket connection.
86
+ // Your server URL
87
+ const serverUrl = 'ws://your-server-url/api/socket';
101
88
 
102
- ```js
103
- const channelTopic = 'channel:one';
104
- const options = {
105
- username: 'eleven-am'
89
+ // Your authenticated user's username (replace with actual username)
90
+ const authToken = 'your-auth-token';
91
+
92
+ // Your username (replace with actual username)
93
+ const username = 'user123';
94
+
95
+ // Create a new PondClient instance
96
+ const socket = new PondClient(serverUrl, { token: authToken });
97
+
98
+ // Connect to the server
99
+ socket.connect();
100
+
101
+ // Add event listeners to handle various scenarios
102
+ socket.onConnectionChange((connected) => {
103
+ if (connected) {
104
+ console.log('Connected to the server.');
105
+ } else {
106
+ console.log('Disconnected from the server.');
106
107
  }
108
+ });
109
+
110
+ // Create a channel and join it
111
+ const channel = socket.createChannel('/channel/123', { username });
112
+ channel.join();
107
113
 
108
- export const channel = socket.createChannel(channelTopic, options);
109
- channel.join();
114
+ // Send a message to the server
115
+ const message = "Hello, PondSocket!";
116
+ channel.broadcast('message', { text: message });
117
+
118
+ // Handle received messages
119
+ channel.onMessage((event, message) => {
120
+ console.log(`Received message from server: ${message.text}`);
121
+ });
110
122
  ```
111
123
 
112
- When connected to the channel you can subscribe to the events from the channel.
124
+ The client will now connect to the server, and the server will receive the necessary headers automatically, including any authentication tokens or cookies, as required by the browser.
113
125
 
114
- ```js
115
- const subscriptionPresence = channel.onPresenceUpdate(presence => {
116
- // handle the presence changes of the channel
117
- });
126
+ ### Server-side Example with Authentication and check for profanity before broadcasting
127
+
128
+ To create a PondSocket server that accepts authenticated connections and checks for profanity before broadcasting messages, follow the steps below:
129
+
130
+ ```javascript
131
+ import PondSocket from "@eleven-am/pondsocket";
132
+ import Filter from "bad-words";
133
+
134
+ // Helper functions for token validation
135
+ function isValidToken(token) {
136
+ // Implement your token validation logic here
137
+ // Return true if the token is valid, false otherwise
138
+ return true;
139
+ }
140
+
141
+ function getRoleFromToken(token) {
142
+ // Implement the logic to extract the user's role from the token
143
+ // Return the user's role
144
+ return 'user';
145
+ }
146
+
147
+ // Create a PondChannel with profanity check
148
+ const profanityFilter = new Filter();
149
+
150
+ const pond = new PondSocket();
151
+
152
+ // Create an endpoint for handling socket connections
153
+ const endpoint = pond.createEndpoint('/api/socket', (req, res) => {
154
+ // Depending if the user already has cookies set, they can be accessed from the request headers or the request address
155
+ const token = req.query.token; // If the token is passed as a query parameter
156
+
157
+ // Perform token validation here
158
+ if (isValidToken(token)) {
159
+ // Extract the authenticated user's username
160
+ const role = getUsernameFromToken(token);
161
+
162
+ // Handle socket connection and authentication for valid users
163
+ res.accept({ role }); // Assign the user's role to the socket
164
+ } else {
165
+ // Reject the connection for invalid users or without a token
166
+ res.reject('Invalid token', 401);
167
+ }
168
+ });
169
+
170
+ const profanityChannel = endpoint.createChannel('/channel/:id', (req, res) => {
171
+ // When joining the channel, any joinParams passed from the client will be available in the request payload
172
+ // Also any previous assigns on the socket will be available in the request payload as well
173
+ const { role } = req.user.assigns;
174
+ const { username } = req.joinParams;
175
+
176
+ // Check if the user has the required role to join the channel
177
+ if (role === 'admin') {
178
+ // Accept the join request
179
+ res.accept({ username, profanityCount: 0 })
180
+ // optionally you can track the presence of the user in the channel
181
+ .trackPresence({
182
+ username,
183
+ role,
184
+ status: 'online',
185
+ onlineSince: Date.now(),
186
+ });
187
+ } else {
188
+ // Reject the join request
189
+ res.reject('You do not have the required role to join this channel', 403);
190
+ }
191
+ });
118
192
 
119
- const subscriptionMessage = channel.onMessage((event, data) => {
120
- // handle the message being received
193
+ // Attach message event listener to the profanityChannel
194
+ profanityChannel.onEvent('message', (req, res) => {
195
+ const { text } = req.event.payload;
196
+
197
+ // Check for profanity
198
+ if (profanityFilter.isProfane(text)) {
199
+ const profanityCount = req.user.assigns.profanityCount + 1
200
+ // Reject the message if it contains profanity
201
+ res.reject('Profanity is not allowed', 400, {
202
+ profanityCount,
203
+ });
204
+
205
+ if (profanityCount >= 3) {
206
+ // Kick the user from the channel if they have used profanity more than 3 times
207
+ res.evictUser('You have been kicked from the channel for using profanity');
208
+ } else {
209
+ // you can broadcast a message to all users or In the channel that profanity is not allowed
210
+ res.broadcast('profanity-warning', { message: 'Profanity is not allowed' })
211
+ // or you can send a message to the user that profanity is not allowed
212
+ .send('profanity-warning', { message: `You have used profanity ${profanityCount} times. You will be kicked from the channel if you use profanity more than 3 times.` });
213
+ }
214
+ } else {
215
+ // Accept the message to allow broadcasting to other clients in the channel
216
+ res.accept();
217
+ }
218
+
219
+ // for more complete access to the channel, you can use the client object
220
+ // const channel = req.client;
221
+ });
222
+
223
+ profanityChannel.onEvent('presence/:presence', (req, res) => {
224
+ const { presence } = req.event.params;
225
+ const { username } = req.user.assigns;
226
+
227
+ // Handle presence events
228
+ res.updatePresence({
229
+ username,
230
+ role,
231
+ onlineSince: Date.now(),
232
+ status: presence,
121
233
  });
234
+ });
235
+
236
+ profanityChannel.onLeave((req, res) => {
237
+ const { username } = req.user.assigns;
238
+
239
+ // When a user leaves the channel, PondSocket will automatically remove the user from the presence list and inform other users in the channel
240
+
241
+ // perform a cleanup operation here
242
+ });
243
+
122
244
 
123
- // When done with the channel remember to unsubscribe from these listeners
124
- subscriptionPresence.unsubscribe();
125
- subscriptionMessage.unsubscribe();
245
+ // Start the server
246
+ pond.listen(3000, () => {
247
+ console.log('PondSocket server listening on port 3000');
248
+ });
126
249
  ```
127
250
 
128
- There are many other features available on the channel object. Since the application is completely typed,
129
- suggestions should be provided by your IDE.
251
+ ## API Documentation
130
252
 
131
- ```js
132
- channel.broadcast('hello', {
133
- name: 'eleven-am',
134
- message: 'I am the man, man'
135
- })
253
+ Apologies for the confusion. Let me remove "Class" from the title of each section:
136
254
 
137
- // channel.broadcastFrom broadcasts a message to everyone but the client that emitted the message
138
- // channel.sendMessage sends a message to clients specified in the function
139
- ```
255
+ ### PondSocket
256
+
257
+ The `PondSocket` class is the core class that represents the socket server.
258
+
259
+ **Constructor:**
260
+
261
+ - `constructor(server?: HTTPServer, socketServer?: WebSocketServer)`: Creates a new instance of the PondSocket with an optional HTTP server and WebSocket server.
262
+
263
+ **Methods:**
264
+
265
+ - `listen(...args: any[]): HTTPServer`: Specifies the port to listen on with the provided arguments.
266
+
267
+ - `close(callback?: () => void): HTTPServer`: Closes the server, and an optional callback can be provided.
268
+
269
+ - `createEndpoint<Path extends string>(path: PondPath<Path>, handler: (request: IncomingConnection<Path>, response: ConnectionResponse) => void | Promise<void>): Endpoint`: Accepts a new socket upgrade request on the provided endpoint using the handler function to authenticate the socket.
270
+
271
+ ### ConnectionResponse
272
+
273
+ The `ConnectionResponse` class represents the response object for the incoming connection.
274
+
275
+ **Methods:**
276
+
277
+ - `accept(assigns?: PondAssigns): void`: Accepts the request and optionally assigns data to the client.
278
+
279
+ - `reject(message?: string, errorCode?: number): void`: Rejects the request with the given error message and optional error code.
280
+
281
+ - `send(event: string, payload: PondMessage, assigns?: PondAssigns): void`: Emits a direct message to the client with the specified event and payload.
282
+
283
+ ### Endpoint
284
+
285
+ The `Endpoint` class represents an endpoint in the PondSocket server where channels can be created.
286
+
287
+ **Methods:**
288
+
289
+ - `createChannel<Path extends string>(path: PondPath<Path>, handler: (request: JoinRequest<Path>, response: JoinResponse) => void | Promise<void>): PondChannel`: Adds a new PondChannel to this path on this endpoint with the provided handler function to authenticate the client.
290
+
291
+ - `broadcast(event: string, payload: PondMessage): void`: Broadcasts a message to all clients connected to this endpoint with the specified event and payload.
292
+
293
+ - `closeConnection(clientIds: string | string[]): void`: Closes specific clients connected to this endpoint identified by the provided clientIds.
294
+
295
+ ### JoinRequest
296
+
297
+ The `JoinRequest` class represents the request object when a client joins a channel.
298
+
299
+ **Properties:**
300
+
301
+ - `event: PondEvent<Path>`: The event associated with the request.
302
+
303
+ - `channelName: string`: The name of the channel.
304
+
305
+ - `assigns: UserAssigns`: The assigns data for the client.
306
+
307
+ - `presence: UserPresences`: The presence data for the client.
308
+
309
+ - `joinParams: JoinParams`: The join parameters for the client.
310
+
311
+ - `user: UserData`: The user data associated with the client.
312
+
313
+ - `client: Client`: The Client instance associated with the request.
314
+
315
+ ### JoinResponse
316
+
317
+ The `JoinResponse` class represents the response object for the join request.
318
+
319
+ **Methods:**
320
+
321
+ - `accept(assigns?: PondAssigns): JoinResponse`: Accepts the join request and optionally assigns data to the client.
322
+
323
+ - `reject(message?: string, errorCode?: number): JoinResponse`: Rejects the join request with the given error message and optional error code.
324
+
325
+ - `send(event: string, payload: PondMessage, assigns?: PondAssigns): JoinResponse`: Emits a direct message to the client with the specified event, payload, and optional assigns data.
326
+
327
+ - `broadcast(event: string, payload: PondMessage): JoinResponse`: Emits a message to all clients in the channel with the specified event and payload.
328
+
329
+ - `broadcastFromUser(event: string, payload: PondMessage): JoinResponse`: Emits a message to all clients in the channel except the sender with the specified event and payload.
330
+
331
+ - `sendToUsers(event: string, payload: PondMessage, userIds: string[]): JoinResponse`: Emits a message to a specific set of clients identified by the provided userIds with the specified event and payload.
332
+
333
+ - `trackPresence(presence: PondPresence): JoinResponse`: Tracks the presence of the client in the channel.
334
+
335
+ ### PondChannel
336
+
337
+ The `PondChannel` class represents a Generic channel in the PondSocket server. It is used to create a channel whose path matches the provided PondPath.
338
+
339
+ **Methods:**
340
+
341
+ - `onEvent<Event extends string>(event: PondPath<Event>, handler: (request: EventRequest<Event>, response: EventResponse) => void | Promise<void>): void`: Handles an event request made by a user for the specified event with the provided handler function.
342
+
343
+ - `broadcast(event: string, payload: PondMessage, channelName?: string): void`: Broadcasts a message to all users in the channel with the specified event and payload. Optionally, a specific channel name can be provided to broadcast the message only to users in that channel.
344
+
345
+ - `onLeave(handler: (event: LeaveEvent) => void | Promise<void>): void`: Handles a leave event for the channel with the provided handler function when a user leaves the channel.
346
+
347
+ ### EventRequest
348
+
349
+ The `EventRequest` class represents the request object when an event is received from a client.
350
+
351
+ **Properties:**
352
+
353
+ - `event: PondEvent<Path>`: The event associated with the request.
354
+
355
+ - `channelName: string`: The name of the channel.
356
+
357
+ - `assigns: UserAssigns`: The assigns data for the client.
358
+
359
+ - `presence: UserPresences`: The presence data for the client.
360
+
361
+ - `user: UserData`: The user data associated with the client.
362
+
363
+ - `client: Client`: The Client instance associated with the request.
364
+
365
+ ### EventResponse
366
+
367
+ The `EventResponse` class represents the response object for handling events from clients.
368
+
369
+ **Methods:**
370
+
371
+ - `accept(assigns?: PondAssigns): EventResponse`: Accepts the request and optionally assigns data to the client.
372
+
373
+ - `reject(message?: string, errorCode?: number, assigns?: PondAssigns): EventResponse`: Rejects the request with the given error message, optional error code, and optional assigns data.
374
+
375
+ - `send(event: string, payload: PondMessage, assigns?: PondAssigns): void`: Emits a direct message to the client with the specified event, payload, and optional assigns data.
376
+
377
+ - `broadcast(event: string, payload: PondMessage): EventResponse`: Sends a message to all clients in the channel with the specified event and payload.
378
+
379
+ - `broadcastFromUser(event: string, payload: PondMessage): EventResponse`: Sends a message to all clients in the channel except the sender with the specified event and payload.
380
+
381
+ - `sendToUsers(event: string, payload: PondMessage, userIds: string[]): EventResponse`: Sends a message to a specific set of clients identified by the provided userIds with the specified event and payload.
382
+
383
+ - `trackPresence(presence: PondPresence, userId?: string): EventResponse`: Tracks a user's presence in the channel.
384
+
385
+ - `updatePresence(presence: PondPresence, userId?: string): EventResponse`: Updates a user's presence in the channel.
386
+
387
+ - `unTrackPresence(userId?: string): EventResponse`: Removes a user's presence from the channel.
388
+
389
+ - `evictUser(reason: string, userId?: string): void`: Evicts a user from the channel.
390
+
391
+ - `closeChannel(reason: string): void`: Closes the channel from the server-side for all clients.
392
+
393
+ ### Client
394
+
395
+ The `Client` class represents a single Channel created by the PondSocket server. Note that a PondChannel can have multiple clients.
396
+
397
+ **Methods:**
398
+
399
+ - `getAssigns: UserAssigns`: Gets the current assign data for the client.
400
+
401
+ - `getUserData(userId: string): UserData`: Gets the assign data for a specific user identified by the provided `userId`.
402
+
403
+ - `broadcastMessage(event: string, payload: PondMessage): void`: Broadcasts a message to every client in the channel with the specified event and payload.
404
+
405
+ - `sendToUser(userId: string, event: string, payload: PondMessage): void`: Sends a message to a specific client in the channel identified by the provided `userId`, with the specified event and payload.
406
+
407
+ - `banUser(userId: string, reason?: string): void`: Bans a user from the channel identified by the provided `userId`. Optionally, you can provide a `reason` for the ban.
408
+
409
+ - `trackPresence(userId: string, presence: PondPresence): void`: Tracks a user's presence in the channel identified by the provided `userId`.
410
+
411
+ - `removePresence(userId: string): void`: Removes a user's presence from the channel identified by the provided `userId`.
412
+
413
+ - `updatePresence(userId: string, presence: PondPresence): void`: Updates a user's presence in the channel identified by the provided `userId`.
414
+
415
+ ### PondClient
416
+
417
+ The `PondClient` class represents a client that connects to the PondSocket server.
418
+
419
+ **Constructor:**
420
+
421
+ - `constructor(endpoint: string, params?: Record<string, any>)`: Creates a new instance of the PondClient with the provided endpoint URL and optional parameters.
422
+
423
+ **Methods:**
424
+
425
+ - `connect(backoff?: number): void`: Connects to the server with an optional backoff time.
426
+
427
+ - `getState(): boolean`: Returns the current state of the socket.
428
+
429
+ - `disconnect(): void`: Disconnects the socket.
430
+
431
+ - `createChannel(name: string, params?: JoinParams): Channel`: Creates a channel with the given name and optional join parameters.
432
+
433
+ - `onConnectionChange(callback: (state: boolean) => void): Unsubscribe`: Subscribes to the connection state changes and calls the provided callback when the state changes.
434
+
435
+ ### Channel
436
+
437
+ The `Channel` class represents a channel in the PondClient.
438
+
439
+ **Methods:**
440
+
441
+ - `join(): void`: Connects to the channel.
442
+
443
+ - `leave(): void`: Disconnects from the channel.
444
+
445
+ - `onMessage(callback: (event: string, message: PondMessage) => void): Unsubscribe`: Monitors the channel for messages and calls the provided callback when a message is received.
446
+
447
+ - `onMessageEvent(event: string, callback: (message: PondMessage) => void): Unsubscribe`: Monitors the channel for messages with the specified event and calls the provided callback when a message is received.
448
+
449
+ - `onChannelStateChange(callback: (connected: ChannelState) => void): Unsubscribe`: Monitors the channel state of the channel and calls the provided callback when the connection state changes.
450
+
451
+ - `onJoin(callback: (presence: PondPresence) => void): Unsubscribe`: Detects when clients join the channel and calls the provided callback when a client joins the channel.
452
+
453
+ - `onLeave(callback: (presence: PondPresence) => void): Unsubscribe`: Detects when clients leave the channel and calls the provided callback when a client leaves the channel.
454
+
455
+ - `onPresenceChange(callback: (presence: PresencePayload) => void): Unsubscribe`: Detects when clients change their presence in the channel and calls the provided callback when a client changes their presence in the channel.
456
+
457
+ - `sendMessage(event: string, payload: PondMessage, recipient: string[]): void`: Sends a message to specific clients in the channel with the specified event, payload, and recipient.
458
+
459
+ - `broadcastFrom(event: string, payload: PondMessage): void`: Broadcasts a message to every other client in the channel except yourself with the specified event and payload.
460
+
461
+ - `broadcast(event: string, payload: PondMessage): void`: Broadcasts a message to the channel, including yourself, with the specified event and payload.
462
+
463
+ - `getPresence(): PondPresence[]`: Gets the current presence of the channel.
464
+
465
+ - `onUsersChange(callback: (users: PondPresence[]) => void): Unsubscribe`: Monitors the presence of the channel and calls the provided callback when the presence changes.
466
+
467
+ - `isConnected(): boolean`: Gets the current connection state of the channel.
468
+
469
+ - `onConnectionChange(callback: (connected: boolean) => void): Unsubscribe`: Monitors the connection state of the channel and calls the provided callback when the connection state changes.
470
+
471
+ ## License
472
+
473
+ PondSocket is released under the GPL-3.0 License. Please refer to the `LICENSE` file for detailed licensing information.
474
+
475
+ ## Conclusion
476
+
477
+ PondSocket is a powerful and versatile solution for building real-time applications that require efficient bidirectional communication between server and client components. Its minimalist design and comprehensive feature set make it an excellent choice for WebSocket-based projects, providing developers with a straightforward and reliable tool for building real-time communication systems. With the Node.js client, it also allows for easy communication between multiple server instances, expanding its capabilities even further.
package/client.js CHANGED
@@ -95,7 +95,6 @@ class PondClient {
95
95
  return this._connectionState.subscribe(callback);
96
96
  }
97
97
  }
98
- exports.default = PondClient;
99
98
  _PondClient_channels = new WeakMap(), _PondClient_instances = new WeakSet(), _PondClient_createPublisher = function _PondClient_createPublisher() {
100
99
  return (message) => {
101
100
  if (this._connectionState.value) {
@@ -103,3 +102,4 @@ _PondClient_channels = new WeakMap(), _PondClient_instances = new WeakSet(), _Po
103
102
  }
104
103
  };
105
104
  };
105
+ exports.default = PondClient;
package/enums.js CHANGED
@@ -6,20 +6,20 @@ var PresenceEventTypes;
6
6
  PresenceEventTypes["JOIN"] = "JOIN";
7
7
  PresenceEventTypes["LEAVE"] = "LEAVE";
8
8
  PresenceEventTypes["UPDATE"] = "UPDATE";
9
- })(PresenceEventTypes = exports.PresenceEventTypes || (exports.PresenceEventTypes = {}));
9
+ })(PresenceEventTypes || (exports.PresenceEventTypes = PresenceEventTypes = {}));
10
10
  var ServerActions;
11
11
  (function (ServerActions) {
12
12
  ServerActions["PRESENCE"] = "PRESENCE";
13
13
  ServerActions["SYSTEM"] = "SYSTEM";
14
14
  ServerActions["BROADCAST"] = "BROADCAST";
15
15
  ServerActions["ERROR"] = "ERROR";
16
- })(ServerActions = exports.ServerActions || (exports.ServerActions = {}));
16
+ })(ServerActions || (exports.ServerActions = ServerActions = {}));
17
17
  var ClientActions;
18
18
  (function (ClientActions) {
19
19
  ClientActions["JOIN_CHANNEL"] = "JOIN_CHANNEL";
20
20
  ClientActions["LEAVE_CHANNEL"] = "LEAVE_CHANNEL";
21
21
  ClientActions["BROADCAST"] = "BROADCAST";
22
- })(ClientActions = exports.ClientActions || (exports.ClientActions = {}));
22
+ })(ClientActions || (exports.ClientActions = ClientActions = {}));
23
23
  var ChannelState;
24
24
  (function (ChannelState) {
25
25
  ChannelState["IDLE"] = "IDLE";
@@ -27,7 +27,7 @@ var ChannelState;
27
27
  ChannelState["JOINED"] = "JOINED";
28
28
  ChannelState["STALLED"] = "STALLED";
29
29
  ChannelState["CLOSED"] = "CLOSED";
30
- })(ChannelState = exports.ChannelState || (exports.ChannelState = {}));
30
+ })(ChannelState || (exports.ChannelState = ChannelState = {}));
31
31
  var ErrorTypes;
32
32
  (function (ErrorTypes) {
33
33
  ErrorTypes["UNAUTHORIZED_CONNECTION"] = "UNAUTHORIZED_CONNECTION";
@@ -39,18 +39,18 @@ var ErrorTypes;
39
39
  ErrorTypes["CHANNEL_ERROR"] = "CHANNEL_ERROR";
40
40
  ErrorTypes["ENDPOINT_ERROR"] = "ENDPOINT_ERROR";
41
41
  ErrorTypes["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
42
- })(ErrorTypes = exports.ErrorTypes || (exports.ErrorTypes = {}));
42
+ })(ErrorTypes || (exports.ErrorTypes = ErrorTypes = {}));
43
43
  var SystemSender;
44
44
  (function (SystemSender) {
45
45
  SystemSender["ENDPOINT"] = "ENDPOINT";
46
46
  SystemSender["CHANNEL"] = "CHANNEL";
47
- })(SystemSender = exports.SystemSender || (exports.SystemSender = {}));
47
+ })(SystemSender || (exports.SystemSender = SystemSender = {}));
48
48
  var ChannelReceiver;
49
49
  (function (ChannelReceiver) {
50
50
  ChannelReceiver["ALL_USERS"] = "ALL_USERS";
51
51
  ChannelReceiver["ALL_EXCEPT_SENDER"] = "ALL_EXCEPT_SENDER";
52
- })(ChannelReceiver = exports.ChannelReceiver || (exports.ChannelReceiver = {}));
52
+ })(ChannelReceiver || (exports.ChannelReceiver = ChannelReceiver = {}));
53
53
  var Events;
54
54
  (function (Events) {
55
55
  Events["ACKNOWLEDGE"] = "ACKNOWLEDGE";
56
- })(Events = exports.Events || (exports.Events = {}));
56
+ })(Events || (exports.Events = Events = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eleven-am/pondsocket",
3
- "version": "0.1.64",
3
+ "version": "0.1.66",
4
4
  "description": "PondSocket is a fast simple socket server",
5
5
  "keywords": [
6
6
  "socket",
@@ -22,30 +22,30 @@
22
22
  },
23
23
  "author": "Roy OSSAI",
24
24
  "license": "GPL-3.0",
25
- "main": "index.js",
26
- "types": "index.d.ts",
25
+ "main": "dist/index.js",
26
+ "types": "dist/index.d.ts",
27
27
  "repository": {
28
28
  "type": "git",
29
29
  "url": "git+https://github.com/Eleven-am/pondSocket.git"
30
30
  },
31
31
  "dependencies": {
32
32
  "websocket": "^1.0.34",
33
- "ws": "^8.12.0"
33
+ "ws": "^8.13.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@types/express": "^4.17.14",
37
- "@types/jest": "^29.5.0",
38
- "@types/node": "^16.10.3",
36
+ "@types/express": "^4.17.17",
37
+ "@types/jest": "^29.5.3",
38
+ "@types/node": "^20.4.4",
39
39
  "@types/websocket": "^1.0.5",
40
- "@types/ws": "^8.5.3",
41
- "@typescript-eslint/eslint-plugin": "^5.58.0",
42
- "eslint": "^8.38.0",
40
+ "@types/ws": "^8.5.5",
41
+ "@typescript-eslint/eslint-plugin": "^6.1.0",
42
+ "eslint": "^8.45.0",
43
43
  "eslint-plugin-file-progress": "^1.3.0",
44
44
  "eslint-plugin-import": "^2.27.5",
45
- "jest": "^29.0.1",
45
+ "jest": "^29.6.1",
46
46
  "superwstest": "^2.0.3",
47
- "ts-jest": "^29.1.0",
47
+ "ts-jest": "^29.1.1",
48
48
  "ts-node": "^10.9.1",
49
- "typescript": "^4.9.4"
49
+ "typescript": "^5.1.6"
50
50
  }
51
51
  }
package/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { Express } from 'express';
2
1
  import { Server as HTTPServer, IncomingHttpHeaders } from 'http';
2
+
3
+ import type { Express } from 'express';
3
4
  import { WebSocketServer } from 'ws';
4
5
 
5
6
  type Unsubscribe = () => void;
@@ -524,6 +525,8 @@ declare class PondSocket {
524
525
  createEndpoint<Path extends string> (path: PondPath<Path>, handler: (request: IncomingConnection<Path>, response: ConnectionResponse) => void | Promise<void>): Endpoint;
525
526
  }
526
527
 
528
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
529
+ // @ts-ignore
527
530
  interface PondSocketExpressApp extends Express {
528
531
 
529
532
  /**