mongo-realtime 1.0.1 → 1.0.3

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 (4) hide show
  1. package/README.md +49 -18
  2. package/index.js +27 -0
  3. package/logo.png +0 -0
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A Node.js package that combines Socket.IO and MongoDB Change Streams to deliver real-time database updates to your WebSocket clients.
4
4
 
5
+ ![Banner](logo.png)
6
+
5
7
  ## 🚀 Features
6
8
 
7
9
  - **Real-time updates**: Automatically detects changes in MongoDB and broadcasts them via Socket.IO
@@ -69,6 +71,8 @@ Initializes the socket system and MongoDB Change Streams.
69
71
  |-----------|------|-------------|
70
72
  | `options.connection` | `mongoose.Connection`* | Active Mongoose connection |
71
73
  | `options.server` | `http.Server`* | HTTP server to attach Socket.IO |
74
+ | `options.authentify` | `Function` | Function to authenticate socket connections. Should return true if authenticated |
75
+ | `options.middlewares` | `Array[Function]` | Array of Socket.IO middlewares |
72
76
  | `options.onSocket` | `Function` | Callback on socket connection |
73
77
  | `options.offSocket` | `Function` | Callback on socket disconnection |
74
78
  | `options.watch` | `Array[String]` | Collections to only watch. Listen to all when is empty |
@@ -95,6 +99,35 @@ The package automatically emits six types of events for each database change:
95
99
  | `db:change:{collection}:{id}` | Specific document | `db:change:users:507f1f77bcf86cd799439011` |
96
100
  | `db:{type}:{collection}:{id}` | Type + document | `db:insert:users:507f1f77bcf86cd799439011` |
97
101
 
102
+ ### Event listeners
103
+
104
+ You can add serverside listeners to those db events to trigger specific actions on the server:
105
+
106
+ ```js
107
+ function sendNotification(change){
108
+ const userId = change.docId; // or change.documentKey._id
109
+ NotificationService.send(userId,"Welcome to DB");
110
+ }
111
+
112
+ MongoRealtime.listen("db:insert:users",sendNotification);
113
+ ```
114
+
115
+ #### Adding many callback to one event
116
+
117
+ ```js
118
+ MongoRealtime.listen("db:insert:users",anotherAction);
119
+ MongoRealtime.listen("db:insert:users",anotherAction2);
120
+ ```
121
+
122
+ #### Removing event listeners
123
+
124
+ ```js
125
+ MongoRealtime.removeListener("db:insert:users",sendNotification); // remove this specific action from this event
126
+ MongoRealtime.removeListener("db:insert:users"); // remove all actions from this event
127
+ MongoRealtime.removeAllListeners(); // remove all listeners
128
+
129
+ ```
130
+
98
131
  ### Event Payload Structure
99
132
 
100
133
  Each event contains the full MongoDB change object:
@@ -102,6 +135,8 @@ Each event contains the full MongoDB change object:
102
135
  ```javascript
103
136
  {
104
137
  "_id": {...},
138
+ "col":"users", // same as ns.coll
139
+ "docId":"...", // same as documentKey._id
105
140
  "operationType": "insert|update|delete|replace",
106
141
  "documentKey": { "_id": "..." },
107
142
  "ns": { "db": "mydb", "coll": "users" },
@@ -186,29 +221,25 @@ MongoRealtime.init({
186
221
  ### Socket Authentication
187
222
 
188
223
  ```javascript
189
- function authenticateSocket(socket){
190
- socket.on('authenticate', (token) => {
191
- if (isValidToken(token)) {
192
- socket.authenticated = true;
193
- socket.emit('authenticated');
194
- } else {
195
- socket.disconnect();
196
- }
197
- });
198
-
199
- socket.use((packet, next) => {
200
- if (socket.authenticated) {
201
- next();
202
- } else {
203
- next(new Error('Unauthenticated'));
204
- }
205
- });
224
+ function authenticateSocket(token, socket){
225
+ const verify = AuthService.verifyToken(token);
226
+ if(verify){
227
+ socket.user = verify.user; // attach user info to socket
228
+ return true; // should return true to accept the connection
229
+ }
230
+ return false;
206
231
  }
207
232
 
208
233
  MongoRealtime.init({
209
234
  connection: mongoose.connection,
210
235
  server: server,
211
- onSocket: authenticateSocket,
236
+ authentify: authenticateSocket,
237
+ middlewares: [
238
+ (socket, next) => {
239
+ console.log(`User is authenticated: ${socket.user.email}`);
240
+ next();
241
+ }
242
+ ],
212
243
  offSocket: (socket, reason) => {
213
244
  console.log(`Socket ${socket.id} disconnected: ${reason}`);
214
245
  }
package/index.js CHANGED
@@ -12,6 +12,8 @@ class MongoRealtime {
12
12
  *
13
13
  * @param {Object} options
14
14
  * @param {import("mongoose").Connection} options.connection - Active Mongoose connection
15
+ * @param {(token:String, socket: import("socket.io").Socket) => boolean | Promise<boolean>} options.authentify - Auth function that should return true if `token` is valid
16
+ * @param {[( socket: import("socket.io").Socket, next: (err?: ExtendedError) => void) => void]} options.middlewares - Register mmiddlewares on incoming socket
15
17
  * @param {(socket: import("socket.io").Socket) => void} options.onSocket - Callback triggered when a socket connects
16
18
  * @param {(socket: import("socket.io").Socket, reason: import("socket.io").DisconnectReason) => void} options.offSocket - Callback triggered when a socket disconnects
17
19
  * @param {import("http").Server} options.server - HTTP server to attach Socket.IO to
@@ -22,6 +24,8 @@ class MongoRealtime {
22
24
  static init({
23
25
  connection,
24
26
  server,
27
+ authentify,
28
+ middlewares=[],
25
29
  onSocket,
26
30
  offSocket,
27
31
  watch = [],
@@ -37,6 +41,29 @@ class MongoRealtime {
37
41
  watch = watch.map((s) => s.toLowerCase());
38
42
  ignore = ignore.map((s) => s.toLowerCase());
39
43
 
44
+ this.io.use(async (socket, next) => {
45
+ if (!!authentify) {
46
+ try {
47
+ const token = socket.handshake.auth.token;
48
+ if (!token) return next(new Error("No token provided"));
49
+
50
+ const authorized =await authentify(token, socket);
51
+ if (authorized===true) return next(); // exactly returns true
52
+
53
+ return next(new Error("Unauthorized"));
54
+ } catch (error) {
55
+ return next(new Error("Authentication error"));
56
+ }
57
+ } else {
58
+ return next();
59
+ }
60
+
61
+ });
62
+
63
+ for (let middleware of middlewares) {
64
+ this.io.use(middleware);
65
+ }
66
+
40
67
  this.io.on("connection", (socket) => {
41
68
  this.sockets = [...this.io.sockets.sockets.values()];
42
69
  if (onSocket) onSocket(socket);
package/logo.png ADDED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongo-realtime",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "main": "index.js",
5
5
  "scripts": {},
6
6
  "keywords": [