@eleven-am/pondsocket-express 0.0.36 → 0.0.38
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 +113 -450
- package/package.json +14 -14
- package/tsconfig.tsbuildinfo +1 -1
package/README.md
CHANGED
|
@@ -1,510 +1,173 @@
|
|
|
1
|
-
# PondSocket
|
|
1
|
+
# PondSocket Express Integration
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This package provides seamless integration of [PondSocket](https://www.npmjs.com/package/@eleven-am/pondsocket) with [Express](https://expressjs.com/), allowing you to add high-performance, bidirectional WebSocket endpoints to your Express applications with minimal effort.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Install the Express adapter alongside PondSocket:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install @eleven-am/pondsocket-
|
|
10
|
+
npm install @eleven-am/pondsocket @eleven-am/pondsocket-express
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Overview
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
This package exposes a function that takes your Express app and PondSocket options, and returns the app with additional methods for real-time socket communication:
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
- `createEndpoint(path, handler)`: Define a WebSocket endpoint on your Express app.
|
|
18
|
+
- `listen(...)`: Start the HTTP server and WebSocket server together.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
## Server-side Usage
|
|
20
21
|
|
|
21
|
-
```
|
|
22
|
-
import pondSocket from "@eleven-am/pondsocket-express";
|
|
22
|
+
```typescript
|
|
23
23
|
import express from "express";
|
|
24
|
+
import pondSocket from "@eleven-am/pondsocket-express";
|
|
24
25
|
|
|
25
|
-
const app =
|
|
26
|
+
const app = express();
|
|
26
27
|
|
|
27
|
-
const
|
|
28
|
-
|
|
28
|
+
const pondApp = pondSocket(app, {
|
|
29
|
+
// PondSocket options (except 'server')
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// Create a WebSocket endpoint
|
|
33
|
+
const endpoint = pondApp.createEndpoint('/api/socket', (ctx, next) => {
|
|
34
|
+
const token = ctx.request.query.token;
|
|
35
|
+
if (isValidToken(token)) {
|
|
36
|
+
ctx.accept({ role: getRoleFromToken(token) });
|
|
37
|
+
} else {
|
|
38
|
+
ctx.reject('Invalid token', 401);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
const channel = endpoint.createChannel('/channel/:id', (
|
|
38
|
-
|
|
42
|
+
// Create a channel
|
|
43
|
+
const channel = endpoint.createChannel('/channel/:id', (ctx, next) => {
|
|
44
|
+
const { role } = ctx.user.assigns;
|
|
45
|
+
const { username } = ctx.joinParams;
|
|
46
|
+
if (role === 'admin') {
|
|
47
|
+
ctx.accept({ username }).trackPresence({
|
|
48
|
+
username,
|
|
49
|
+
role,
|
|
50
|
+
status: 'online',
|
|
51
|
+
onlineSince: Date.now(),
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
ctx.decline('Insufficient permissions', 403);
|
|
55
|
+
}
|
|
39
56
|
});
|
|
57
|
+
|
|
58
|
+
// Start the server
|
|
59
|
+
pondApp.listen(3000);
|
|
40
60
|
```
|
|
41
61
|
|
|
42
62
|
## Client-side Usage
|
|
43
63
|
|
|
44
|
-
|
|
64
|
+
The client API is unchanged—use `@eleven-am/pondsocket-client` as described in the main PondSocket documentation.
|
|
45
65
|
|
|
46
|
-
```
|
|
66
|
+
```typescript
|
|
47
67
|
import PondClient from "@eleven-am/pondsocket-client";
|
|
48
68
|
|
|
49
|
-
const socket = new PondClient('/api/socket', {
|
|
69
|
+
const socket = new PondClient('ws://your-server/api/socket', {
|
|
70
|
+
token: 'your-auth-token'
|
|
71
|
+
});
|
|
50
72
|
socket.connect();
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Once connected, clients can create and join channels to engage in real-time communication with other users and the server.
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
const channel = socket.createChannel('/channel/123');
|
|
74
|
+
const channel = socket.createChannel('/channel/123', { username: 'user123' });
|
|
57
75
|
channel.join();
|
|
76
|
+
channel.broadcast('message', { text: 'Hello, PondSocket!' });
|
|
58
77
|
```
|
|
59
78
|
|
|
60
|
-
### Node Client
|
|
61
|
-
|
|
62
|
-
PondSocket also offers a Node.js client, which can be imported using:
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
import PondClient from "@eleven-am/pondsocket-client";
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
This node client allows you to turn another server into a client, enabling easy communication between different server instances.
|
|
69
|
-
|
|
70
79
|
## Key Features
|
|
71
80
|
|
|
72
|
-
- **
|
|
73
|
-
- **
|
|
74
|
-
- **
|
|
75
|
-
- **
|
|
76
|
-
- **
|
|
77
|
-
- **
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// Your username (replace with actual username)
|
|
95
|
-
const username = 'user123';
|
|
96
|
-
|
|
97
|
-
// Create a new PondClient instance
|
|
98
|
-
const socket = new PondClient(serverUrl, { token: authToken });
|
|
99
|
-
|
|
100
|
-
// Connect to the server
|
|
101
|
-
socket.connect();
|
|
102
|
-
|
|
103
|
-
// Add event listeners to handle various scenarios
|
|
104
|
-
socket.onConnectionChange((connected) => {
|
|
105
|
-
if (connected) {
|
|
106
|
-
console.log('Connected to the server.');
|
|
107
|
-
} else {
|
|
108
|
-
console.log('Disconnected from the server.');
|
|
109
|
-
}
|
|
81
|
+
- **Express Integration**: Add real-time endpoints to your existing Express app.
|
|
82
|
+
- **Simple and Efficient API**: Easy-to-use, type-safe API for WebSocket communication.
|
|
83
|
+
- **Organized Channels**: Group users and manage communication efficiently.
|
|
84
|
+
- **Assigns**: Store private information for users and channels.
|
|
85
|
+
- **Presence**: Track and broadcast user state changes.
|
|
86
|
+
- **Broadcasting**: Send messages to all or specific users.
|
|
87
|
+
- **Middleware Support**: Extensible request processing.
|
|
88
|
+
- **Distributed Support**: Built-in distributed deployment with state sync.
|
|
89
|
+
|
|
90
|
+
## Advanced Features
|
|
91
|
+
|
|
92
|
+
### Presence Management
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Server-side
|
|
96
|
+
channel.onEvent('presence', (ctx, next) => {
|
|
97
|
+
ctx.trackPresence({
|
|
98
|
+
username: ctx.user.assigns.username,
|
|
99
|
+
status: 'online',
|
|
100
|
+
lastSeen: Date.now()
|
|
101
|
+
});
|
|
110
102
|
});
|
|
111
103
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Send a message to the server
|
|
117
|
-
const message = "Hello, PondSocket!";
|
|
118
|
-
channel.broadcast('message', { text: message });
|
|
119
|
-
|
|
120
|
-
// Handle received messages
|
|
121
|
-
// Certain methods in the channel instance returns a subscription function, which can be used to unsubscribe from the event
|
|
122
|
-
const subscription = channel.onMessage((event, message) => {
|
|
123
|
-
console.log(`Received message from server: ${message.text}`);
|
|
104
|
+
// Client-side
|
|
105
|
+
channel.onPresence((presences) => {
|
|
106
|
+
console.log('Current users:', presences);
|
|
124
107
|
});
|
|
125
|
-
|
|
126
|
-
// Unsubscribe from the event
|
|
127
|
-
subscription();
|
|
128
108
|
```
|
|
129
109
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
### Server-side Example with Authentication and check for profanity before broadcasting
|
|
133
|
-
|
|
134
|
-
To create a PondSocket server that accepts authenticated connections and checks for profanity before broadcasting messages, follow the steps below:
|
|
135
|
-
|
|
136
|
-
```javascript
|
|
137
|
-
import PondSocket from "@eleven-am/pondsocket";
|
|
138
|
-
|
|
139
|
-
// Helper functions for token validation
|
|
140
|
-
function isValidToken(token) {
|
|
141
|
-
// Implement your token validation logic here
|
|
142
|
-
// Return true if the token is valid, false otherwise
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function getRoleFromToken(token) {
|
|
147
|
-
// Implement the logic to extract the user's role from the token
|
|
148
|
-
// Return the user's role
|
|
149
|
-
return 'user';
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function isTextProfane(text) {
|
|
153
|
-
// Implement your profanity check logic here
|
|
154
|
-
// Return true if the text is profane, false otherwise
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function getMessagesFromDatabase(channelId) {
|
|
159
|
-
// Implement your logic to retrieve messages from the database
|
|
160
|
-
// Return an array of messages
|
|
161
|
-
return [];
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const pond = new PondSocket();
|
|
165
|
-
|
|
166
|
-
// Create an endpoint for handling socket connections
|
|
167
|
-
const endpoint = pond.createEndpoint('/api/socket', (req, res) => {
|
|
168
|
-
// Depending if the user already has cookies set, they can be accessed from the request headers or the request address
|
|
169
|
-
const token = req.query.token; // If the token is passed as a query parameter
|
|
170
|
-
|
|
171
|
-
// Perform token validation here
|
|
172
|
-
if (isValidToken(token)) {
|
|
173
|
-
// Extract the authenticated user's username
|
|
174
|
-
const role = getRoleFromToken(token);
|
|
175
|
-
|
|
176
|
-
// Handle socket connection and authentication for valid users
|
|
177
|
-
res.accept({role}); // Assign the user's role to the socket
|
|
178
|
-
} else {
|
|
179
|
-
// Reject the connection for invalid users or without a token
|
|
180
|
-
res.reject('Invalid token', 401);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
110
|
+
### User Assigns
|
|
183
111
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// maybe retrieve the previous messages from the database
|
|
193
|
-
const messages = await getMessagesFromDatabase(id);
|
|
194
|
-
|
|
195
|
-
// Check if the user has the required role to join the channel
|
|
196
|
-
if (role === 'admin') {
|
|
197
|
-
// Accept the join request
|
|
198
|
-
res.accept({username, profanityCount: 0})
|
|
199
|
-
// optionally you can track the presence of the user in the channel
|
|
200
|
-
.trackPresence({
|
|
201
|
-
username,
|
|
202
|
-
role,
|
|
203
|
-
status: 'online',
|
|
204
|
-
onlineSince: Date.now(),
|
|
205
|
-
})
|
|
206
|
-
// and send the user the channel history
|
|
207
|
-
.sendToUsers('history', {messages}, [req.user.id]);
|
|
208
|
-
|
|
209
|
-
// Alternatively, you can also send messages to the user, NOTE that the user would be automatically subscribed to the channel.
|
|
210
|
-
// res.send('history', { messages }, { username, profanityCount: 0 })
|
|
211
|
-
// .trackPresence({
|
|
212
|
-
// username,
|
|
213
|
-
// role,
|
|
214
|
-
// status: 'online',
|
|
215
|
-
// onlineSince: Date.now(),
|
|
216
|
-
// });
|
|
217
|
-
} else {
|
|
218
|
-
// Reject the join request
|
|
219
|
-
res.decline('You do not have the required role to join this channel', 403);
|
|
220
|
-
}
|
|
112
|
+
```typescript
|
|
113
|
+
// Server-side
|
|
114
|
+
channel.onEvent('update-profile', (ctx, next) => {
|
|
115
|
+
ctx.assign({
|
|
116
|
+
...ctx.user.assigns,
|
|
117
|
+
profile: ctx.event.payload
|
|
118
|
+
});
|
|
221
119
|
});
|
|
222
120
|
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// Check for profanity
|
|
228
|
-
if (isTextProfane(text)) {
|
|
229
|
-
// Reject the message if it contains profanity
|
|
230
|
-
res.decline('Profanity is not allowed', 400, {
|
|
231
|
-
profanityCount: req.user.assigns.profanityCount + 1
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// note that profanityCount is updated so req.user.assigns.profanityCount will be updated
|
|
235
|
-
if (req.user.assigns.profanityCount >= 3) {
|
|
236
|
-
// Kick the user from the channel if they have used profanity more than 3 times
|
|
237
|
-
res.evictUser('You have been kicked from the channel for using profanity');
|
|
238
|
-
} else {
|
|
239
|
-
// you can broadcast a message to all users or In the channel that profanity is not allowed
|
|
240
|
-
res.broadcast('profanity-warning', {message: 'Profanity is not allowed'})
|
|
241
|
-
// or you can send a message to the user that profanity is not allowed
|
|
242
|
-
.sendToUsers('profanity-warning', {message: `You have used profanity ${profanityCount} times. You will be kicked from the channel if you use profanity more than 3 times.`}, [req.user.id]);
|
|
243
|
-
}
|
|
244
|
-
} else {
|
|
245
|
-
// Accept the message to allow broadcasting to other clients in the channel
|
|
246
|
-
res.accept();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// for more complete access to the channel, you can use the channel instance
|
|
250
|
-
// const channel = req.channel;
|
|
121
|
+
// Client-side
|
|
122
|
+
channel.onAssigns((assigns) => {
|
|
123
|
+
console.log('User data updated:', assigns);
|
|
251
124
|
});
|
|
125
|
+
```
|
|
252
126
|
|
|
253
|
-
|
|
254
|
-
const {presence} = req.event.params;
|
|
255
|
-
const {username} = req.user.assigns;
|
|
256
|
-
|
|
257
|
-
// Handle presence events
|
|
258
|
-
res.updatePresence({
|
|
259
|
-
username,
|
|
260
|
-
role,
|
|
261
|
-
onlineSince: Date.now(),
|
|
262
|
-
status: presence,
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
profanityChannel.onLeave((event) => {
|
|
267
|
-
const {username} = event.assigns;
|
|
268
|
-
|
|
269
|
-
// When a user leaves the channel, PondSocket will automatically remove the user from the presence list and inform other users in the channel
|
|
127
|
+
### Error Handling
|
|
270
128
|
|
|
271
|
-
|
|
129
|
+
```typescript
|
|
130
|
+
// Server-side
|
|
131
|
+
channel.onEvent('message', (ctx, next) => {
|
|
132
|
+
try {
|
|
133
|
+
ctx.accept();
|
|
134
|
+
} catch (error) {
|
|
135
|
+
ctx.decline(error.message, 400);
|
|
136
|
+
}
|
|
272
137
|
});
|
|
273
138
|
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
139
|
+
// Client-side
|
|
140
|
+
channel.onError((error) => {
|
|
141
|
+
console.error('Channel error:', error);
|
|
277
142
|
});
|
|
278
143
|
```
|
|
279
144
|
|
|
280
|
-
##
|
|
281
|
-
|
|
282
|
-
### PondSocket
|
|
283
|
-
|
|
284
|
-
The `PondSocket` class is the core class that represents the socket server.
|
|
285
|
-
|
|
286
|
-
**Constructor:**
|
|
287
|
-
|
|
288
|
-
- `constructor(server?: HTTPServer, socketServer?: WebSocketServer)`: Creates a new instance of the PondSocket with an optional HTTP server and WebSocket server.
|
|
289
|
-
|
|
290
|
-
**Methods:**
|
|
291
|
-
|
|
292
|
-
- `listen(...args: any[]): HTTPServer`: Specifies the port to listen on with the provided arguments.
|
|
293
|
-
|
|
294
|
-
- `close(callback?: () => void): HTTPServer`: Closes the server, and an optional callback can be provided.
|
|
295
|
-
|
|
296
|
-
- `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.
|
|
297
|
-
|
|
298
|
-
### ConnectionResponse
|
|
299
|
-
|
|
300
|
-
The `ConnectionResponse` class represents the response object for the incoming connection.
|
|
301
|
-
|
|
302
|
-
**Methods:**
|
|
303
|
-
|
|
304
|
-
- `accept(assigns?: PondAssigns): void`: Accepts the request and optionally assigns data to the client.
|
|
305
|
-
|
|
306
|
-
- `reject(message?: string, errorCode?: number): void`: Rejects the request with the given error message and optional error code.
|
|
307
|
-
|
|
308
|
-
- `send(event: string, payload: PondMessage, assigns?: PondAssigns): void`: Emits a direct message to the client with the specified event and payload.
|
|
309
|
-
|
|
310
|
-
### Endpoint
|
|
311
|
-
|
|
312
|
-
The `Endpoint` class represents an endpoint in the PondSocket server where channels can be created.
|
|
313
|
-
|
|
314
|
-
**Methods:**
|
|
315
|
-
|
|
316
|
-
- `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.
|
|
317
|
-
|
|
318
|
-
- `broadcast(event: string, payload: PondMessage): void`: Broadcasts a message to all clients connected to this endpoint with the specified event and payload.
|
|
319
|
-
|
|
320
|
-
- `closeConnection(clientIds: string | string[]): void`: Closes specific clients connected to this endpoint identified by the provided clientIds.
|
|
321
|
-
|
|
322
|
-
### JoinRequest
|
|
323
|
-
|
|
324
|
-
The `JoinRequest` class represents the request object when a client joins a channel.
|
|
325
|
-
|
|
326
|
-
**Properties:**
|
|
327
|
-
|
|
328
|
-
- `event: PondEvent<Path>`: The event associated with the request.
|
|
329
|
-
|
|
330
|
-
- `channelName: string`: The name of the channel.
|
|
331
|
-
|
|
332
|
-
- `assigns: UserAssigns`: The assigns data for the client.
|
|
333
|
-
|
|
334
|
-
- `presence: UserPresences`: The presence data for the client.
|
|
335
|
-
|
|
336
|
-
- `joinParams: JoinParams`: The join parameters for the client.
|
|
337
|
-
|
|
338
|
-
- `user: UserData`: The user data associated with the client.
|
|
339
|
-
|
|
340
|
-
- `channel: Channel`: The Channel instance associated with the request.
|
|
341
|
-
|
|
342
|
-
### JoinResponse
|
|
343
|
-
|
|
344
|
-
The `JoinResponse` class represents the response object for the join request.
|
|
345
|
-
|
|
346
|
-
**Methods:**
|
|
347
|
-
|
|
348
|
-
- `accept(assigns?: PondAssigns): JoinResponse`: Accepts the join request and optionally assigns data to the client.
|
|
145
|
+
## Distributed Deployment
|
|
349
146
|
|
|
350
|
-
|
|
147
|
+
PondSocket supports distributed deployment through its distributed backend system. This allows you to scale your application across multiple nodes while maintaining state synchronization.
|
|
351
148
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
- `broadcastFromUser(event: string, payload: PondMessage): JoinResponse`: Emits a message to all clients in the channel except the sender with the specified event and payload.
|
|
357
|
-
|
|
358
|
-
- `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.
|
|
359
|
-
|
|
360
|
-
- `trackPresence(presence: PondPresence): JoinResponse`: Tracks the presence of the client in the channel.
|
|
361
|
-
|
|
362
|
-
### PondChannel
|
|
363
|
-
|
|
364
|
-
The `PondChannel` class represents a Generic channel in the PondSocket server. It is used to create a channel whose path matches the provided PondPath.
|
|
365
|
-
|
|
366
|
-
**Methods:**
|
|
367
|
-
|
|
368
|
-
- `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.
|
|
369
|
-
|
|
370
|
-
- `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.
|
|
371
|
-
|
|
372
|
-
- `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.
|
|
373
|
-
|
|
374
|
-
### EventRequest
|
|
375
|
-
|
|
376
|
-
The `EventRequest` class represents the request object when an event is received from a client.
|
|
377
|
-
|
|
378
|
-
**Properties:**
|
|
379
|
-
|
|
380
|
-
- `event: PondEvent<Path>`: The event associated with the request.
|
|
381
|
-
|
|
382
|
-
- `channelName: string`: The name of the channel.
|
|
383
|
-
|
|
384
|
-
- `assigns: UserAssigns`: The assigns data for the client.
|
|
385
|
-
|
|
386
|
-
- `presence: UserPresences`: The presence data for the client.
|
|
387
|
-
|
|
388
|
-
- `user: UserData`: The user data associated with the client.
|
|
389
|
-
|
|
390
|
-
- `channel: Channel`: The Channel instance associated with the request.
|
|
391
|
-
|
|
392
|
-
### EventResponse
|
|
393
|
-
|
|
394
|
-
The `EventResponse` class represents the response object for handling events from clients.
|
|
395
|
-
|
|
396
|
-
**Methods:**
|
|
397
|
-
|
|
398
|
-
- `accept(assigns?: PondAssigns): EventResponse`: Accepts the request and optionally assigns data to the client.
|
|
399
|
-
|
|
400
|
-
- `reject(message?: string, errorCode?: number, assigns?: PondAssigns): EventResponse`: Rejects the request with the given error message, optional error code, and optional assigns data.
|
|
401
|
-
|
|
402
|
-
- `send(event: string, payload: PondMessage, assigns?: PondAssigns): void`: Emits a direct message to the client with the specified event, payload, and optional assigns data.
|
|
403
|
-
|
|
404
|
-
- `broadcast(event: string, payload: PondMessage): EventResponse`: Sends a message to all clients in the channel with the specified event and payload.
|
|
405
|
-
|
|
406
|
-
- `broadcastFromUser(event: string, payload: PondMessage): EventResponse`: Sends a message to all clients in the channel except the sender with the specified event and payload.
|
|
407
|
-
|
|
408
|
-
- `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.
|
|
409
|
-
|
|
410
|
-
- `trackPresence(presence: PondPresence, userId?: string): EventResponse`: Tracks a user's presence in the channel.
|
|
411
|
-
|
|
412
|
-
- `updatePresence(presence: PondPresence, userId?: string): EventResponse`: Updates a user's presence in the channel.
|
|
413
|
-
|
|
414
|
-
- `unTrackPresence(userId?: string): EventResponse`: Removes a user's presence from the channel.
|
|
415
|
-
|
|
416
|
-
- `evictUser(reason: string, userId?: string): void`: Evicts a user from the channel.
|
|
417
|
-
|
|
418
|
-
- `closeChannel(reason: string): void`: Closes the channel from the server-side for all clients.
|
|
419
|
-
|
|
420
|
-
### Channel
|
|
421
|
-
|
|
422
|
-
The `Channel` class represents a single Channel created by the PondSocket server. Note that a PondChannel can have multiple channels associated with it.
|
|
423
|
-
|
|
424
|
-
**Methods:**
|
|
425
|
-
|
|
426
|
-
- `name: string`: The name of the channel.
|
|
427
|
-
|
|
428
|
-
- `getAssigns: UserAssigns`: Gets the current assign data for the client.
|
|
429
|
-
|
|
430
|
-
- `getUserData(userId: string): UserData`: Gets the assign data for a specific user identified by the provided `userId`.
|
|
431
|
-
|
|
432
|
-
- `broadcastMessage(event: string, payload: PondMessage): void`: Broadcasts a message to every client in the channel with the specified event and payload.
|
|
433
|
-
|
|
434
|
-
- `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.
|
|
435
|
-
|
|
436
|
-
- `sendToUsers(userIdS: string[], event: string, payload: PondMessage): void`: Sends a message to a specific set of clients identified by the provided `userIdS`, with the specified event and payload.
|
|
437
|
-
|
|
438
|
-
- `evictUser(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.
|
|
439
|
-
|
|
440
|
-
- `trackPresence(userId: string, presence: PondPresence): void`: Tracks a user's presence in the channel identified by the provided `userId`.
|
|
441
|
-
|
|
442
|
-
- `removePresence(userId: string): void`: Removes a user's presence from the channel identified by the provided `userId`.
|
|
443
|
-
|
|
444
|
-
- `updatePresence(userId: string, presence: PondPresence): void`: Updates a user's presence in the channel identified by the provided `userId`.
|
|
445
|
-
|
|
446
|
-
### PondClient
|
|
447
|
-
|
|
448
|
-
The `PondClient` class represents a client that connects to the PondSocket server.
|
|
449
|
-
|
|
450
|
-
**Constructor:**
|
|
451
|
-
|
|
452
|
-
- `constructor(endpoint: string, params?: Record<string, any>)`: Creates a new instance of the PondClient with the provided endpoint URL and optional parameters.
|
|
453
|
-
|
|
454
|
-
**Methods:**
|
|
455
|
-
|
|
456
|
-
- `connect(backoff?: number): void`: Connects to the server with an optional backoff time.
|
|
457
|
-
|
|
458
|
-
- `getState(): boolean`: Returns the current state of the socket.
|
|
459
|
-
|
|
460
|
-
- `disconnect(): void`: Disconnects the socket.
|
|
461
|
-
|
|
462
|
-
- `createChannel(name: string, params?: JoinParams): ClientChannel`: Creates a channel with the given name and optional join parameters.
|
|
463
|
-
|
|
464
|
-
- `onConnectionChange(callback: (state: boolean) => void): Unsubscribe`: Subscribes to the connection state changes and calls the provided callback when the state changes.
|
|
465
|
-
|
|
466
|
-
### ClientChannel
|
|
467
|
-
|
|
468
|
-
The `ClientChannel` class represents a channel in the PondClient.
|
|
469
|
-
|
|
470
|
-
**Methods:**
|
|
471
|
-
|
|
472
|
-
- `join(): void`: Connects to the channel.
|
|
473
|
-
|
|
474
|
-
- `leave(): void`: Disconnects from the channel.
|
|
475
|
-
|
|
476
|
-
- `onMessage(callback: (event: string, message: PondMessage) => void): Unsubscribe`: Monitors the channel for messages and calls the provided callback when a message is received.
|
|
477
|
-
|
|
478
|
-
- `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.
|
|
479
|
-
|
|
480
|
-
- `onChannelStateChange(callback: (connected: ChannelState) => void): Unsubscribe`: Monitors the channel state of the channel and calls the provided callback when the connection state changes.
|
|
481
|
-
|
|
482
|
-
- `onJoin(callback: (presence: PondPresence) => void): Unsubscribe`: Detects when clients join the channel and calls the provided callback when a client joins the channel.
|
|
483
|
-
|
|
484
|
-
- `onLeave(callback: (presence: PondPresence) => void): Unsubscribe`: Detects when clients leave the channel and calls the provided callback when a client leaves the channel.
|
|
485
|
-
|
|
486
|
-
- `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.
|
|
487
|
-
|
|
488
|
-
- `sendMessage(event: string, payload: PondMessage, recipient: string[]): void`: Sends a message to specific clients in the channel with the specified event, payload, and recipient.
|
|
489
|
-
|
|
490
|
-
- `sendForResponse(event: string, payload: PondMessage): Promise<PondMessage>`: Sends a message to the server with the specified event, payload, and returns a promise that resolves with the response.
|
|
491
|
-
|
|
492
|
-
- `broadcastFrom(event: string, payload: PondMessage): void`: Broadcasts a message to every other client in the channel except yourself with the specified event and payload.
|
|
149
|
+
```typescript
|
|
150
|
+
import express from "express";
|
|
151
|
+
import pondSocket from "@eleven-am/pondsocket-express";
|
|
152
|
+
import { RedisBackend } from "@eleven-am/pondsocket";
|
|
493
153
|
|
|
494
|
-
|
|
154
|
+
const app = express();
|
|
495
155
|
|
|
496
|
-
|
|
156
|
+
const pondApp = pondSocket(app, {
|
|
157
|
+
backend: new RedisBackend({
|
|
158
|
+
host: 'localhost',
|
|
159
|
+
port: 6379
|
|
160
|
+
}),
|
|
161
|
+
// ...other PondSocket options
|
|
162
|
+
});
|
|
497
163
|
|
|
498
|
-
|
|
164
|
+
// Now use pondApp.createEndpoint(...) as usual
|
|
165
|
+
```
|
|
499
166
|
|
|
500
|
-
|
|
167
|
+
## Contributing
|
|
501
168
|
|
|
502
|
-
|
|
169
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
503
170
|
|
|
504
171
|
## License
|
|
505
172
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
## Conclusion
|
|
509
|
-
|
|
510
|
-
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.
|
|
173
|
+
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eleven-am/pondsocket-express",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
4
4
|
"description": "PondSocket is a fast simple socket server",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"socket",
|
|
@@ -29,26 +29,26 @@
|
|
|
29
29
|
"pipeline": "npm run lint:fix && npm run lint && npm run build && npm run push"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@eleven-am/pondsocket": "^0.1.
|
|
32
|
+
"@eleven-am/pondsocket": "^0.1.214"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@eslint/compat": "^1.
|
|
35
|
+
"@eslint/compat": "^1.4.0",
|
|
36
36
|
"@eslint/eslintrc": "^3.3.1",
|
|
37
|
-
"@eslint/js": "^9.
|
|
37
|
+
"@eslint/js": "^9.38.0",
|
|
38
38
|
"@stylistic/eslint-plugin-ts": "^4.4.1",
|
|
39
39
|
"@types/express": "^5.0.3",
|
|
40
|
-
"@types/jest": "^
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
42
|
-
"eslint": "^9.
|
|
40
|
+
"@types/jest": "^30.0.0",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.46.1",
|
|
42
|
+
"eslint": "^9.38.0",
|
|
43
43
|
"eslint-plugin-file-progress": "^3.0.2",
|
|
44
|
-
"eslint-plugin-import": "^2.
|
|
45
|
-
"globals": "^16.
|
|
46
|
-
"jest": "^30.
|
|
47
|
-
"prettier": "^3.
|
|
48
|
-
"ts-jest": "^29.
|
|
49
|
-
"ts-loader": "^9.5.
|
|
44
|
+
"eslint-plugin-import": "^2.32.0",
|
|
45
|
+
"globals": "^16.4.0",
|
|
46
|
+
"jest": "^30.2.0",
|
|
47
|
+
"prettier": "^3.6.2",
|
|
48
|
+
"ts-jest": "^29.4.5",
|
|
49
|
+
"ts-loader": "^9.5.4",
|
|
50
50
|
"ts-node": "^10.9.2",
|
|
51
|
-
"typescript": "^5.
|
|
51
|
+
"typescript": "^5.9.3"
|
|
52
52
|
},
|
|
53
53
|
"jest": {
|
|
54
54
|
"moduleFileExtensions": [
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts"],"version":"5.
|
|
1
|
+
{"root":["../src/index.ts"],"version":"5.9.3"}
|