@eleven-am/pondsocket-nest 0.0.130 → 0.0.131

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.
Files changed (2) hide show
  1. package/README.md +255 -228
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # PondSocket NestJS Integration
2
2
 
3
- This package provides a NestJS integration layer for PondSocket, making it easy to use PondSocket's real-time WebSocket functionality within NestJS applications.
3
+ This package provides a NestJS integration layer for PondSocket, making it easy to use PondSocket's real-time WebSocket
4
+ functionality within NestJS applications.
4
5
 
5
6
  ## Installation
6
7
 
@@ -10,7 +11,9 @@ npm install @eleven-am/pondsocket-nest
10
11
 
11
12
  ## Overview
12
13
 
13
- This package integrates PondSocket's powerful WebSocket capabilities with NestJS's architecture and dependency injection system. It provides decorators and services that make it natural to use WebSocket functionality in a NestJS application while maintaining all of PondSocket's features.
14
+ This package integrates PondSocket's powerful WebSocket capabilities with NestJS's architecture and dependency injection
15
+ system. It provides decorators and services that make it natural to use WebSocket functionality in a NestJS application
16
+ while maintaining all of PondSocket's features.
14
17
 
15
18
  ## Key Features
16
19
 
@@ -27,17 +30,17 @@ This package integrates PondSocket's powerful WebSocket capabilities with NestJS
27
30
  ### Module Setup
28
31
 
29
32
  ```typescript
30
- import { Module } from '@nestjs/common';
31
- import { PondSocketModule } from '@eleven-am/pondsocket-nest';
32
-
33
- @Module({
34
- imports: [
35
- PondSocketModule.forRoot({
36
- guards: [AuthGuard], // Optional: Global guards
37
- pipes: [ValidationPipe], // Optional: Global pipes
38
- isGlobal: true, // Optional: Make the module global
39
- })
40
- ]
33
+ import {Module} from '@nestjs/common';
34
+ import {PondSocketModule} from '@eleven-am/pondsocket-nest';
35
+
36
+ @Module ({
37
+ imports: [
38
+ PondSocketModule.forRoot ({
39
+ guards: [AuthGuard], // Optional: Global guards
40
+ pipes: [ValidationPipe], // Optional: Global pipes
41
+ isGlobal: true, // Optional: Make the module global
42
+ })
43
+ ]
41
44
  })
42
45
  export class AppModule {}
43
46
  ```
@@ -45,75 +48,75 @@ export class AppModule {}
45
48
  ### Creating WebSocket Endpoints
46
49
 
47
50
  ```typescript
48
- import { Controller } from '@nestjs/common';
49
- import { PondSocketEndpoint, PondSocketConnection, Context } from '@eleven-am/pondsocket-nest';
51
+ import {Controller} from '@nestjs/common';
52
+ import {PondSocketEndpoint, PondSocketConnection, Context} from '@eleven-am/pondsocket-nest';
50
53
 
51
- @PondSocketEndpoint('/api/socket')
54
+ @Endpoint('/api/socket')
52
55
  export class SocketController {
53
- @PondSocketConnection()
54
- async handleConnection(ctx: Context) {
55
- const token = ctx.request.query.token;
56
-
57
- if (isValidToken(token)) {
58
- const role = getRoleFromToken(token);
59
- ctx.accept({ role });
60
- } else {
61
- ctx.reject('Invalid token', 401);
62
- }
63
- }
56
+ @OnConnection()
57
+ async handleConnection (ctx: Context) {
58
+ const token = ctx.request.query.token;
59
+
60
+ if (isValidToken (token)) {
61
+ const role = getRoleFromToken (token);
62
+ ctx.accept ({role});
63
+ } else {
64
+ ctx.reject ('Invalid token', 401);
65
+ }
66
+ }
64
67
  }
65
68
  ```
66
69
 
67
70
  ### Creating Channels
68
71
 
69
72
  ```typescript
70
- import { Controller } from '@nestjs/common';
71
- import { PondSocketChannel, PondSocketJoin, Context } from '@eleven-am/pondsocket-nest';
73
+ import {Controller} from '@nestjs/common';
74
+ import {PondSocketChannel, PondSocketJoin, Context} from '@eleven-am/pondsocket-nest';
72
75
 
73
- @PondSocketChannel('/channel/:id')
76
+ @Channel('/channel/:id')
74
77
  export class ChannelController {
75
- @PondSocketJoin()
76
- async handleJoin(ctx: Context) {
77
- const { role } = ctx.user.assigns;
78
- const { username } = ctx.joinParams;
79
- const { id } = ctx.event.params;
80
-
81
- if (role === 'admin') {
82
- ctx.accept({ username })
83
- .trackPresence({
84
- username,
85
- role,
86
- status: 'online',
87
- onlineSince: Date.now(),
88
- });
89
- } else {
90
- ctx.decline('Insufficient permissions', 403);
91
- }
92
- }
78
+ @OnJoin()
79
+ async handleJoin (ctx: Context) {
80
+ const {role} = ctx.user.assigns;
81
+ const {username} = ctx.joinParams;
82
+ const {id} = ctx.event.params;
83
+
84
+ if (role === 'admin') {
85
+ ctx.accept({username})
86
+ .trackPresence({
87
+ username,
88
+ role,
89
+ status: 'online',
90
+ onlineSince: Date.now (),
91
+ });
92
+ } else {
93
+ ctx.decline('Insufficient permissions', 403);
94
+ }
95
+ }
93
96
  }
94
97
  ```
95
98
 
96
99
  ### Handling Channel Events
97
100
 
98
101
  ```typescript
99
- import { Controller } from '@nestjs/common';
100
- import { PondSocketEvent, Context } from '@eleven-am/pondsocket-nest';
102
+ import {Controller} from '@nestjs/common';
103
+ import {PondSocketEvent, Context} from '@eleven-am/pondsocket-nest';
101
104
 
102
- @PondSocketChannel('/channel/:id')
105
+ @Channel('/channel/:id')
103
106
  export class ChannelController {
104
- @PondSocketEvent('message')
105
- async handleMessage(ctx: Context) {
106
- const { text } = ctx.event.payload;
107
-
108
- // Broadcast to all users in the channel
109
- ctx.broadcast('message', { text });
110
-
111
- // Broadcast to specific users
112
- ctx.broadcastTo(['user1', 'user2'], 'message', { text });
113
-
114
- // Broadcast to all except sender
115
- ctx.broadcastFrom('message', { text });
116
- }
107
+ @OnEvent('message')
108
+ async handleMessage (ctx: Context) {
109
+ const {text} = ctx.event.payload;
110
+
111
+ // Broadcast to all users in the channel
112
+ ctx.broadcast('message', {text});
113
+
114
+ // Broadcast to specific users
115
+ ctx.broadcastTo(['user1', 'user2'], 'message', {text});
116
+
117
+ // Broadcast to all except sender
118
+ ctx.broadcastFrom('message', {text});
119
+ }
117
120
  }
118
121
  ```
119
122
 
@@ -122,48 +125,56 @@ export class ChannelController {
122
125
  ### Presence Management
123
126
 
124
127
  ```typescript
125
- @PondSocketChannel('/channel/:id')
128
+
129
+ @Channel ('/channel/:id')
126
130
  export class ChannelController {
127
- @PondSocketEvent('presence')
128
- async handlePresence(ctx: Context) {
129
- ctx.trackPresence({
130
- username: ctx.user.assigns.username,
131
- status: 'online',
132
- lastSeen: Date.now()
133
- });
134
- }
131
+ @OnEvent ('presence')
132
+ async handlePresence (ctx: Context) {
133
+ ctx.trackPresence ({
134
+ username: ctx.user.assigns.username,
135
+ status: 'online',
136
+ lastSeen: Date.now ()
137
+ });
138
+ }
135
139
  }
136
140
  ```
137
141
 
138
142
  ### User Assigns
139
143
 
140
144
  ```typescript
141
- @PondSocketChannel('/channel/:id')
145
+
146
+ @Channel ('/channel/:id')
142
147
  export class ChannelController {
143
- @PondSocketEvent('update-profile')
144
- async handleProfileUpdate(ctx: Context) {
145
- ctx.assign({
146
- ...ctx.user.assigns,
147
- profile: ctx.event.payload
148
- });
149
- }
148
+ @OnEvent ('update-profile')
149
+ async handleProfileUpdate (ctx: Context) {
150
+ ctx.assign ({
151
+ ...ctx.user.assigns,
152
+ profile: ctx.event.payload
153
+ });
154
+ }
150
155
  }
151
156
  ```
152
157
 
153
158
  ### Error Handling
154
159
 
155
160
  ```typescript
156
- @PondSocketChannel('/channel/:id')
161
+ import {PondChannel} from "@eleven-am/pondsocket/types";
162
+ import {ChannelInstance} from "@eleven-am/pondsocke-nest";
163
+
164
+ @Channel ('/channel/:id')
157
165
  export class ChannelController {
158
- @PondSocketEvent('message')
159
- async handleMessage(ctx: Context) {
160
- try {
161
- // Your logic here
162
- ctx.accept();
163
- } catch (error) {
164
- ctx.decline(error.message, 400);
165
- }
166
- }
166
+ @ChannelInstance()
167
+ instancd: PondChannel // Instance of the channel
168
+
169
+ @OnEvent ('message')
170
+ async handleMessage (ctx: Context) {
171
+ try {
172
+ // Your logic here
173
+ ctx.accept();
174
+ } catch (error) {
175
+ ctx.decline (error.message, 400);
176
+ }
177
+ }
167
178
  }
168
179
  ```
169
180
 
@@ -172,36 +183,38 @@ export class ChannelController {
172
183
  The package maintains PondSocket's distributed deployment capabilities:
173
184
 
174
185
  ```typescript
175
- import { Module } from '@nestjs/common';
176
- import { PondSocketModule } from '@eleven-am/pondsocket-nest';
177
- import { RedisBackend } from '@eleven-am/pondsocket';
186
+ import {Module} from '@nestjs/common';
187
+ import {PondSocketModule} from '@eleven-am/pondsocket-nest';
188
+ import {RedisBackend} from '@eleven-am/pondsocket';
178
189
 
179
190
  @Module({
180
- imports: [
181
- PondSocketModule.forRoot({
182
- backend: new RedisBackend({
183
- host: 'localhost',
184
- port: 6379
185
- })
186
- })
187
- ]
191
+ imports: [
192
+ PondSocketModule.forRoot({
193
+ backend: new RedisBackend({
194
+ host: 'localhost',
195
+ port: 6379
196
+ })
197
+ })
198
+ ]
188
199
  })
189
- export class AppModule {}
200
+ export class AppModule {
201
+ }
190
202
  ```
191
203
 
192
204
  ### Distributed Mode Features
193
205
 
194
- The distributed mode enables you to scale your WebSocket application across multiple server instances while maintaining state synchronization. Here are the key features:
206
+ The distributed mode enables you to scale your WebSocket application across multiple server instances while maintaining
207
+ state synchronization. Here are the key features:
195
208
 
196
209
  1. **State Synchronization**
197
- - Channel presence is synchronized across all instances
198
- - User assigns are shared between instances
199
- - Channel events are broadcasted to all instances
210
+ - Channel presence is synchronized across all instances
211
+ - User assigns are shared between instances
212
+ - Channel events are broadcasted to all instances
200
213
 
201
214
  2. **Load Balancing**
202
- - Multiple server instances can handle WebSocket connections
203
- - Connections are distributed across available instances
204
- - Automatic failover if an instance goes down
215
+ - Multiple server instances can handle WebSocket connections
216
+ - Connections are distributed across available instances
217
+ - Automatic failover if an instance goes down
205
218
 
206
219
  3. **Backend Options**
207
220
  ```typescript
@@ -245,9 +258,9 @@ The distributed mode enables you to scale your WebSocket application across mult
245
258
 
246
259
  5. **Error Handling**
247
260
  ```typescript
248
- @PondSocketChannel('/channel/:id')
261
+ @Channel('/channel/:id')
249
262
  export class ChannelController {
250
- @PondSocketEvent('message')
263
+ @OnEvent('message')
251
264
  async handleMessage(ctx: Context) {
252
265
  try {
253
266
  // Your logic here
@@ -285,20 +298,20 @@ The distributed mode enables you to scale your WebSocket application across mult
285
298
  ```
286
299
 
287
300
  7. **Best Practices**
288
- - Use Redis backend in production environments
289
- - Implement proper error handling for distributed operations
290
- - Monitor backend connection health
291
- - Use appropriate Redis configuration for your scale
292
- - Consider using Redis Cluster for high availability
293
- - Implement proper logging for distributed operations
301
+ - Use Redis backend in production environments
302
+ - Implement proper error handling for distributed operations
303
+ - Monitor backend connection health
304
+ - Use appropriate Redis configuration for your scale
305
+ - Consider using Redis Cluster for high availability
306
+ - Implement proper logging for distributed operations
294
307
 
295
308
  8. **Scaling Considerations**
296
- - Monitor Redis memory usage
297
- - Implement proper cleanup of stale data
298
- - Consider using Redis Cluster for larger deployments
299
- - Implement proper error handling and retry mechanisms
300
- - Monitor network latency between instances
301
- - Implement proper logging and monitoring
309
+ - Monitor Redis memory usage
310
+ - Implement proper cleanup of stale data
311
+ - Consider using Redis Cluster for larger deployments
312
+ - Implement proper error handling and retry mechanisms
313
+ - Monitor network latency between instances
314
+ - Implement proper logging and monitoring
302
315
 
303
316
  ## Configuration Options
304
317
 
@@ -306,14 +319,14 @@ The `PondSocketModule.forRoot()` method accepts the following options:
306
319
 
307
320
  ```typescript
308
321
  interface PondSocketOptions {
309
- guards?: any[]; // Global guards
310
- pipes?: any[]; // Global pipes
311
- providers?: any[]; // Additional providers
312
- imports?: any[]; // Additional imports
313
- exports?: any[]; // Additional exports
314
- isGlobal?: boolean; // Make the module global
315
- isExclusiveSocketServer?: boolean; // Use exclusive socket server
316
- backend?: IDistributedBackend; // Distributed backend
322
+ guards?: any[]; // Global guards
323
+ pipes?: any[]; // Global pipes
324
+ providers?: any[]; // Additional providers
325
+ imports?: any[]; // Additional imports
326
+ exports?: any[]; // Additional exports
327
+ isGlobal?: boolean; // Make the module global
328
+ isExclusiveSocketServer?: boolean; // Use exclusive socket server
329
+ backend?: IDistributedBackend; // Distributed backend
317
330
  }
318
331
  ```
319
332
 
@@ -325,22 +338,22 @@ The client-side usage remains the same as the core PondSocket package:
325
338
  import PondClient from "@eleven-am/pondsocket-client";
326
339
 
327
340
  const socket = new PondClient('ws://your-server/api/socket', {
328
- token: 'your-auth-token'
341
+ token: 'your-auth-token'
329
342
  });
330
343
 
331
- socket.connect();
344
+ socket.connect ();
332
345
 
333
346
  const channel = socket.createChannel('/channel/123', {
334
- username: 'user123'
347
+ username: 'user123'
335
348
  });
336
349
 
337
- channel.join();
350
+ channel.join ();
338
351
 
339
352
  channel.onMessage((event, message) => {
340
- console.log(`Received message: ${message.text}`);
353
+ console.log (`Received message: ${message.text}`);
341
354
  });
342
355
 
343
- channel.broadcast('message', { text: 'Hello, PondSocket!' });
356
+ channel.broadcast('message', {text: 'Hello, PondSocket!'});
344
357
  ```
345
358
 
346
359
  ## Contributing
@@ -353,27 +366,31 @@ This project is licensed under the GPL-3.0 License - see the LICENSE file for de
353
366
 
354
367
  ## Return Type Functionality
355
368
 
356
- The NestJS integration provides a powerful return type system that allows you to declaratively specify actions to be taken when handling WebSocket events. Instead of using the context object directly, you can return an object with specific properties to trigger various actions.
369
+ The NestJS integration provides a powerful return type system that allows you to declaratively specify actions to be
370
+ taken when handling WebSocket events. Instead of using the context object directly, you can return an object with
371
+ specific properties to trigger various actions.
357
372
 
358
373
  ### Return Type Interface
359
374
 
360
375
  ```typescript
361
- type NestFuncType<Event extends string, Payload extends PondMessage, Presence extends PondPresence, Assigns extends PondAssigns = PondAssigns> = {
362
- // Send an event to the user
363
- event?: Event;
364
-
365
- // Broadcast to all users in the channel
366
- broadcast?: Event;
367
-
368
- // Broadcast to all users except the sender
369
- broadcastFrom?: Event;
370
-
371
- // Update user assigns
372
- assigns?: Partial<Assigns>;
373
-
374
- // Update user presence
375
- presence?: Presence;
376
- } & Payload;
376
+ type NestFuncType<Event extends string, Payload extends PondMessage, Presence extends PondPresence, Assigns extends PondAssigns = PondAssigns> =
377
+ {
378
+ // Send an event to the user
379
+ event?: Event;
380
+
381
+ // Broadcast to all users in the channel
382
+ broadcast?: Event;
383
+
384
+ // Broadcast to all users except the sender
385
+ broadcastFrom?: Event;
386
+
387
+ // Update user assigns
388
+ assigns?: Partial<Assigns>;
389
+
390
+ // Update user presence
391
+ presence?: Presence;
392
+ }
393
+ & Payload;
377
394
  ```
378
395
 
379
396
  ### Usage Examples
@@ -381,103 +398,110 @@ type NestFuncType<Event extends string, Payload extends PondMessage, Presence ex
381
398
  #### Channel Join with Multiple Actions
382
399
 
383
400
  ```typescript
401
+
384
402
  @PondSocketChannel('/chat/:roomId')
385
403
  export class ChatController {
386
- @PondSocketJoin()
387
- async handleJoin(ctx: Context) {
388
- const { username } = ctx.joinParams;
389
-
390
- return {
391
- // Send welcome message to the joining user
392
- event: 'welcome',
393
- message: 'Welcome to the chat!',
394
-
395
- // Broadcast join notification to all users
396
- broadcast: 'user_joined',
397
- username,
398
- timestamp: Date.now(),
399
-
400
- // Update user's assigns
401
- assigns: {
402
- username,
403
- joinedAt: Date.now(),
404
- role: 'member'
405
- },
406
-
407
- // Update user's presence
408
- presence: {
409
- username,
410
- status: 'online',
411
- lastSeen: Date.now()
412
- }
413
- };
414
- }
404
+ @PondSocketJoin()
405
+ async handleJoin (ctx: Context) {
406
+ const {username} = ctx.joinParams;
407
+
408
+ return {
409
+ // Send welcome message to the joining user
410
+ event: 'welcome',
411
+ message: 'Welcome to the chat!',
412
+
413
+ // Broadcast join notification to all users
414
+ broadcast: 'user_joined',
415
+ username,
416
+ timestamp: Date.now(),
417
+
418
+ // Update user's assigns
419
+ assigns: {
420
+ username,
421
+ joinedAt: Date.now(),
422
+ role: 'member'
423
+ },
424
+
425
+ // Update user's presence
426
+ presence: {
427
+ username,
428
+ status: 'online',
429
+ lastSeen: Date.now()
430
+ }
431
+ };
432
+ }
415
433
  }
416
434
  ```
417
435
 
418
436
  #### Message Handling
419
437
 
420
438
  ```typescript
439
+
421
440
  @PondSocketChannel('/chat/:roomId')
422
441
  export class ChatController {
423
- @PondSocketEvent('message')
424
- async handleMessage(ctx: Context) {
425
- const { text } = ctx.event.payload;
426
- const { username } = ctx.user.assigns;
427
-
428
- return {
429
- // Broadcast the message to all users
430
- broadcast: 'message',
431
- text,
432
- username,
433
- timestamp: Date.now(),
434
-
435
- // Update user's last message timestamp
436
- assigns: {
437
- lastMessageAt: Date.now()
438
- }
439
- };
440
- }
442
+ @PondSocketEvent('message')
443
+ async handleMessage(ctx: Context) {
444
+ const {text} = ctx.event.payload;
445
+ const {username} = ctx.user.assigns;
446
+
447
+ return {
448
+ // Broadcast the message to all users
449
+ broadcast: 'message',
450
+ text,
451
+ username,
452
+ timestamp: Date.now(),
453
+
454
+ // Update user's last message timestamp
455
+ assigns: {
456
+ lastMessageAt: Date.now()
457
+ }
458
+ };
459
+ }
441
460
  }
442
461
  ```
443
462
 
444
463
  #### Presence Updates
445
464
 
446
465
  ```typescript
447
- @PondSocketChannel('/chat/:roomId')
466
+
467
+ @PondSocketChannel ('/chat/:roomId')
448
468
  export class ChatController {
449
- @PondSocketEvent('status')
450
- async handleStatus(ctx: Context) {
451
- const { status } = ctx.event.payload;
452
-
453
- return {
454
- // Update user's presence
455
- presence: {
456
- status,
457
- lastSeen: Date.now()
458
- },
459
-
460
- // Notify others about the status change
461
- broadcastFrom: 'status_change',
462
- username: ctx.user.assigns.username,
463
- status,
464
- timestamp: Date.now()
465
- };
466
- }
469
+ @PondSocketEvent('status')
470
+ async handleStatus(ctx: Context) {
471
+ const {status} = ctx.event.payload;
472
+
473
+ return {
474
+ // Update user's presence
475
+ presence: {
476
+ status,
477
+ lastSeen: Date.now()
478
+ },
479
+
480
+ // Notify others about the status change
481
+ broadcastFrom: 'status_change',
482
+ username: ctx.user.assigns.username,
483
+ status,
484
+ timestamp: Date.now()
485
+ };
486
+ }
467
487
  }
468
488
  ```
469
489
 
470
490
  ### Benefits
471
491
 
472
- 1. **Declarative Code**: Actions are clearly specified in the return object, making the code more readable and maintainable.
492
+ 1. **Declarative Code**: Actions are clearly specified in the return object, making the code more readable and
493
+ maintainable.
473
494
 
474
495
  2. **Type Safety**: The return type is fully typed, providing excellent TypeScript support and IDE autocompletion.
475
496
 
476
- 3. **Reduced Boilerplate**: No need to call multiple context methods; all actions are specified in a single return statement.
497
+ 3. **Reduced Boilerplate**: No need to call multiple context methods; all actions are specified in a single return
498
+ statement.
477
499
 
478
- 4. **Flexible Combinations**: You can combine multiple actions in a single return statement, making it easy to handle complex scenarios.
500
+ 4. **Flexible Combinations**: You can combine multiple actions in a single return statement, making it easy to handle
501
+ complex scenarios.
479
502
 
480
- 5. **Automatic Handling**: The framework automatically processes the returned object and executes the specified actions in the correct order.
503
+ 5. **Automatic Handling**: The framework automatically processes the returned object and executes the specified actions
504
+ in the correct order.
481
505
 
482
506
  ### Best Practices
483
507
 
@@ -495,8 +519,11 @@ export class ChatController {
495
519
  }
496
520
  ```
497
521
 
498
- 2. **Keep It Simple**: While you can combine multiple actions, try to keep the return object focused on a single responsibility when possible.
522
+ 2. **Keep It Simple**: While you can combine multiple actions, try to keep the return object focused on a single
523
+ responsibility when possible.
499
524
 
500
- 3. **Use TypeScript**: Take advantage of TypeScript's type system to ensure your return objects are correctly structured.
525
+ 3. **Use TypeScript**: Take advantage of TypeScript's type system to ensure your return objects are correctly
526
+ structured.
501
527
 
502
- 4. **Handle Errors**: Remember that you can still use `ctx.decline()` for error cases where returning an object isn't appropriate.
528
+ 4. **Handle Errors**: Remember that you can still use `ctx.decline()` for error cases where returning an object isn't
529
+ appropriate.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eleven-am/pondsocket-nest",
3
- "version": "0.0.130",
3
+ "version": "0.0.131",
4
4
  "description": "PondSocket is a fast simple socket server",
5
5
  "keywords": [
6
6
  "socket",