@eleven-am/pondsocket 0.1.125 → 0.1.127
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 +5 -15
- package/abstracts/abstractRequest.test.js +42 -0
- package/abstracts/abstractResponse.js +3 -0
- package/abstracts/middleware.test.js +70 -0
- package/channel/channel.js +22 -20
- package/channel/channel.test.js +415 -0
- package/channel/eventRequest.test.js +30 -0
- package/channel/eventResponse.js +9 -9
- package/channel/eventResponse.test.js +197 -0
- package/endpoint/endpoint.js +34 -40
- package/endpoint/endpoint.test.js +297 -0
- package/endpoint/response.js +7 -6
- package/index.d.ts +2 -0
- package/lobby/JoinRequest.test.js +40 -0
- package/lobby/JoinResponse.test.js +145 -0
- package/lobby/joinResponse.js +12 -10
- package/lobby/lobby.js +3 -3
- package/matcher/matcher.test.js +90 -0
- package/package.json +32 -13
- package/presence/presence.js +8 -8
- package/presence/presenceEngine.test.js +128 -0
- package/schema.js +13 -0
- package/server/pondSocket.js +5 -4
- package/types.d.ts +0 -496
- package/types.js +2 -0
- package/client/channel.js +0 -304
- package/client.d.ts +0 -5
- package/client.js +0 -107
- package/enums.js +0 -56
- package/express.d.ts +0 -3
- package/express.js +0 -17
- package/nest.d.ts +0 -19
- package/nest.js +0 -769
- package/node.d.ts +0 -3
- package/node.js +0 -30
- package/subjects/subject.js +0 -137
package/README.md
CHANGED
|
@@ -30,18 +30,6 @@ const endpoint = pond.createEndpoint('/api/socket', (req, res) => {
|
|
|
30
30
|
|
|
31
31
|
// Start the server
|
|
32
32
|
pond.listen(3000);
|
|
33
|
-
|
|
34
|
-
// Or alternatively, working with express
|
|
35
|
-
import pondSocket from "@eleven-am/pondsocket/express";
|
|
36
|
-
import express from "express";
|
|
37
|
-
|
|
38
|
-
const app = pondSocket(express());
|
|
39
|
-
|
|
40
|
-
const endpoint = app.upgrade('/api/socket', (req, res) => {
|
|
41
|
-
// Handle socket connection and authentication
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
app.listen(3000);
|
|
45
33
|
```
|
|
46
34
|
|
|
47
35
|
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.
|
|
@@ -57,7 +45,7 @@ const channel = endpoint.createChannel('/channel/:id', (req, res) => {
|
|
|
57
45
|
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.
|
|
58
46
|
|
|
59
47
|
```javascript
|
|
60
|
-
import PondClient from "@eleven-am/pondsocket
|
|
48
|
+
import PondClient from "@eleven-am/pondsocket-client";
|
|
61
49
|
|
|
62
50
|
const socket = new PondClient('/api/socket', {});
|
|
63
51
|
socket.connect();
|
|
@@ -75,7 +63,7 @@ channel.join();
|
|
|
75
63
|
PondSocket also offers a Node.js client, which can be imported using:
|
|
76
64
|
|
|
77
65
|
```javascript
|
|
78
|
-
import PondClient from "@eleven-am/pondsocket
|
|
66
|
+
import PondClient from "@eleven-am/pondsocket-client";
|
|
79
67
|
```
|
|
80
68
|
|
|
81
69
|
This node client allows you to turn another server into a client, enabling easy communication between different server instances.
|
|
@@ -96,7 +84,7 @@ This node client allows you to turn another server into a client, enabling easy
|
|
|
96
84
|
To connect to the PondSocket server and send messages while associating a username with the client connection, follow the steps below:
|
|
97
85
|
|
|
98
86
|
```javascript
|
|
99
|
-
import PondClient from "@eleven-am/pondsocket
|
|
87
|
+
import PondClient from "@eleven-am/pondsocket-client";
|
|
100
88
|
|
|
101
89
|
// Your server URL
|
|
102
90
|
const serverUrl = 'ws://your-server-url/api/socket';
|
|
@@ -500,6 +488,8 @@ The `ClientChannel` class represents a channel in the PondClient.
|
|
|
500
488
|
|
|
501
489
|
- `sendMessage(event: string, payload: PondMessage, recipient: string[]): void`: Sends a message to specific clients in the channel with the specified event, payload, and recipient.
|
|
502
490
|
|
|
491
|
+
- `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.
|
|
492
|
+
|
|
503
493
|
- `broadcastFrom(event: string, payload: PondMessage): void`: Broadcasts a message to every other client in the channel except yourself with the specified event and payload.
|
|
504
494
|
|
|
505
495
|
- `broadcast(event: string, payload: PondMessage): void`: Broadcasts a message to the channel, including yourself, with the specified event and payload.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const abstractRequest_1 = require("./abstractRequest");
|
|
4
|
+
const createMockChannelEngine = () => ({
|
|
5
|
+
name: 'test',
|
|
6
|
+
getAssigns: () => ({}),
|
|
7
|
+
getPresence: () => ({}),
|
|
8
|
+
});
|
|
9
|
+
describe('AbstractRequest', () => {
|
|
10
|
+
it('should be able to be instantiated', () => {
|
|
11
|
+
const request = new abstractRequest_1.AbstractRequest('/test', createMockChannelEngine(), {});
|
|
12
|
+
expect(request).toBeTruthy();
|
|
13
|
+
expect(request.channelName).toBe('test');
|
|
14
|
+
expect(request.assigns).toEqual({});
|
|
15
|
+
expect(request.presence).toEqual({});
|
|
16
|
+
});
|
|
17
|
+
it('should be able to parse queries', () => {
|
|
18
|
+
const request = new abstractRequest_1.AbstractRequest('/1234?choke=balls', createMockChannelEngine(), {});
|
|
19
|
+
expect(() => request.event).toThrowError('Event was not parsed');
|
|
20
|
+
expect(request['_parseQueries']('/:id')).toBe(true);
|
|
21
|
+
expect(request.event).toEqual({
|
|
22
|
+
event: '/1234?choke=balls',
|
|
23
|
+
params: { id: '1234' },
|
|
24
|
+
query: { choke: 'balls' },
|
|
25
|
+
payload: {},
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
it('should be return the value of the payload', () => {
|
|
29
|
+
const request = new abstractRequest_1.AbstractRequest('/test', createMockChannelEngine(), { test: 'test' });
|
|
30
|
+
expect(request['_parseQueries']('/:id')).toBe(true);
|
|
31
|
+
expect(request.event.payload).toEqual({ test: 'test' });
|
|
32
|
+
const request2 = new abstractRequest_1.AbstractRequest('/test', createMockChannelEngine(), {
|
|
33
|
+
test: 'test',
|
|
34
|
+
test2: 'test2',
|
|
35
|
+
});
|
|
36
|
+
expect(request2['_parseQueries']('/:id')).toBe(true);
|
|
37
|
+
expect(request2.event.payload).toEqual({
|
|
38
|
+
test: 'test',
|
|
39
|
+
test2: 'test2',
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const middleware_1 = require("./middleware");
|
|
13
|
+
describe('Middleware', () => {
|
|
14
|
+
it('should be able to add middleware to the stack', () => {
|
|
15
|
+
const middleware = new middleware_1.Middleware();
|
|
16
|
+
middleware.use(() => { });
|
|
17
|
+
expect(middleware.length).toBe(1);
|
|
18
|
+
});
|
|
19
|
+
it('should be able to run middleware', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
const middleware = new middleware_1.Middleware();
|
|
21
|
+
const mock = jest.fn();
|
|
22
|
+
middleware.use(mock);
|
|
23
|
+
yield middleware.run({}, {}, () => { });
|
|
24
|
+
expect(mock).toHaveBeenCalled();
|
|
25
|
+
}));
|
|
26
|
+
it('should be able to run multiple middleware', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
const middleware = new middleware_1.Middleware();
|
|
28
|
+
const mock = jest.fn();
|
|
29
|
+
middleware.use((_, __, next) => {
|
|
30
|
+
mock('first');
|
|
31
|
+
next();
|
|
32
|
+
});
|
|
33
|
+
middleware.use((_, __, next) => {
|
|
34
|
+
mock('second');
|
|
35
|
+
next();
|
|
36
|
+
});
|
|
37
|
+
yield middleware.run({}, {}, () => { });
|
|
38
|
+
expect(mock).toHaveBeenCalledTimes(2);
|
|
39
|
+
expect(mock.mock.calls[0][2]).toBe(mock.mock.calls[1][2]);
|
|
40
|
+
}));
|
|
41
|
+
it('should be merge middleware in the correct order', () => {
|
|
42
|
+
const middleware = new middleware_1.Middleware();
|
|
43
|
+
const mock = jest.fn();
|
|
44
|
+
middleware.use(mock);
|
|
45
|
+
middleware.use(mock);
|
|
46
|
+
const middleware2 = new middleware_1.Middleware(middleware);
|
|
47
|
+
expect(middleware2.length).toBe(2);
|
|
48
|
+
});
|
|
49
|
+
it('should call the final function when the middleware stack is empty', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
const middleware = new middleware_1.Middleware();
|
|
51
|
+
const mock = jest.fn();
|
|
52
|
+
yield middleware.run({}, {}, mock);
|
|
53
|
+
expect(mock).toHaveBeenCalled();
|
|
54
|
+
}));
|
|
55
|
+
it('should be able to run middleware in the correct order when using a second middleware', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
const middleware = new middleware_1.Middleware();
|
|
57
|
+
const mock = jest.fn();
|
|
58
|
+
middleware.use((_, __, next) => {
|
|
59
|
+
mock('first');
|
|
60
|
+
next();
|
|
61
|
+
});
|
|
62
|
+
middleware.use((_, __, next) => {
|
|
63
|
+
mock('second');
|
|
64
|
+
next();
|
|
65
|
+
});
|
|
66
|
+
const middleware2 = new middleware_1.Middleware(middleware);
|
|
67
|
+
yield middleware2.run({}, {}, () => { });
|
|
68
|
+
expect(mock.mock.calls[0][2]).toBe(mock.mock.calls[1][2]);
|
|
69
|
+
}));
|
|
70
|
+
});
|
package/channel/channel.js
CHANGED
|
@@ -24,12 +24,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
24
24
|
var _Channel_engine, _ChannelEngine_instances, _ChannelEngine_receiver, _ChannelEngine_presenceEngine, _ChannelEngine_users, _ChannelEngine_parentEngine, _ChannelEngine_subscribe, _ChannelEngine_getUsersFromRecipients;
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.ChannelEngine = exports.Channel = void 0;
|
|
27
|
+
const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
|
|
27
28
|
const eventRequest_1 = require("./eventRequest");
|
|
28
29
|
const eventResponse_1 = require("./eventResponse");
|
|
29
|
-
const enums_1 = require("../enums");
|
|
30
30
|
const pondError_1 = require("../errors/pondError");
|
|
31
31
|
const presence_1 = require("../presence/presence");
|
|
32
|
-
const subject_1 = require("../subjects/subject");
|
|
33
32
|
class Channel {
|
|
34
33
|
constructor(engine) {
|
|
35
34
|
_Channel_engine.set(this, void 0);
|
|
@@ -45,16 +44,16 @@ class Channel {
|
|
|
45
44
|
return __classPrivateFieldGet(this, _Channel_engine, "f").getUserData(userId);
|
|
46
45
|
}
|
|
47
46
|
broadcastMessage(event, payload) {
|
|
48
|
-
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage(
|
|
47
|
+
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage((0, pondsocket_common_1.uuid)(), pondsocket_common_1.SystemSender.CHANNEL, pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.BROADCAST, event, payload);
|
|
49
48
|
}
|
|
50
49
|
broadcastMessageFromUser(userId, event, payload) {
|
|
51
|
-
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage(userId,
|
|
50
|
+
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage((0, pondsocket_common_1.uuid)(), userId, pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER, pondsocket_common_1.ServerActions.BROADCAST, event, payload);
|
|
52
51
|
}
|
|
53
52
|
sendToUser(userId, event, payload) {
|
|
54
|
-
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage(
|
|
53
|
+
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage((0, pondsocket_common_1.uuid)(), pondsocket_common_1.SystemSender.CHANNEL, [userId], pondsocket_common_1.ServerActions.BROADCAST, event, payload);
|
|
55
54
|
}
|
|
56
55
|
sendToUsers(userIds, event, payload) {
|
|
57
|
-
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage(
|
|
56
|
+
__classPrivateFieldGet(this, _Channel_engine, "f").sendMessage((0, pondsocket_common_1.uuid)(), pondsocket_common_1.SystemSender.CHANNEL, userIds, pondsocket_common_1.ServerActions.BROADCAST, event, payload);
|
|
58
57
|
}
|
|
59
58
|
evictUser(userId, reason) {
|
|
60
59
|
__classPrivateFieldGet(this, _Channel_engine, "f").kickUser(userId, reason !== null && reason !== void 0 ? reason : 'You have been banned from the channel');
|
|
@@ -79,7 +78,7 @@ class ChannelEngine {
|
|
|
79
78
|
_ChannelEngine_users.set(this, void 0);
|
|
80
79
|
_ChannelEngine_parentEngine.set(this, void 0);
|
|
81
80
|
this.name = name;
|
|
82
|
-
__classPrivateFieldSet(this, _ChannelEngine_receiver, new
|
|
81
|
+
__classPrivateFieldSet(this, _ChannelEngine_receiver, new pondsocket_common_1.Subject(), "f");
|
|
83
82
|
__classPrivateFieldSet(this, _ChannelEngine_users, new Map(), "f");
|
|
84
83
|
__classPrivateFieldSet(this, _ChannelEngine_parentEngine, parent, "f");
|
|
85
84
|
}
|
|
@@ -132,12 +131,12 @@ class ChannelEngine {
|
|
|
132
131
|
* @param reason - The reason for kicking the user
|
|
133
132
|
*/
|
|
134
133
|
kickUser(userId, reason) {
|
|
135
|
-
this.sendMessage(
|
|
134
|
+
this.sendMessage((0, pondsocket_common_1.uuid)(), pondsocket_common_1.SystemSender.CHANNEL, [userId], pondsocket_common_1.ServerActions.SYSTEM, 'kicked_out', {
|
|
136
135
|
message: reason,
|
|
137
136
|
code: 403,
|
|
138
137
|
});
|
|
139
138
|
this.removeUser(userId);
|
|
140
|
-
this.sendMessage(
|
|
139
|
+
this.sendMessage((0, pondsocket_common_1.uuid)(), pondsocket_common_1.SystemSender.CHANNEL, pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.SYSTEM, 'kicked', {
|
|
141
140
|
userId,
|
|
142
141
|
reason,
|
|
143
142
|
});
|
|
@@ -147,7 +146,7 @@ class ChannelEngine {
|
|
|
147
146
|
* @param reason - The reason for self-destructing the channel
|
|
148
147
|
*/
|
|
149
148
|
destroy(reason) {
|
|
150
|
-
this.sendMessage(
|
|
149
|
+
this.sendMessage((0, pondsocket_common_1.uuid)(), pondsocket_common_1.SystemSender.CHANNEL, pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.ERROR, 'destroyed', {
|
|
151
150
|
message: reason !== null && reason !== void 0 ? reason : 'Channel has been destroyed',
|
|
152
151
|
});
|
|
153
152
|
__classPrivateFieldGet(this, _ChannelEngine_parentEngine, "f").destroyChannel();
|
|
@@ -195,19 +194,21 @@ class ChannelEngine {
|
|
|
195
194
|
}
|
|
196
195
|
/**
|
|
197
196
|
* @desc Sends a message to a specified set of users, from a specified sender
|
|
197
|
+
* @param requestId - The id of the request
|
|
198
198
|
* @param sender - The sender of the message
|
|
199
199
|
* @param recipient - The users to send the message to
|
|
200
200
|
* @param action - The action of the message
|
|
201
201
|
* @param event - The event name
|
|
202
202
|
* @param payload - The payload of the message
|
|
203
203
|
*/
|
|
204
|
-
sendMessage(sender, recipient, action, event, payload) {
|
|
205
|
-
if (!__classPrivateFieldGet(this, _ChannelEngine_users, "f").has(sender) && sender !==
|
|
204
|
+
sendMessage(requestId, sender, recipient, action, event, payload) {
|
|
205
|
+
if (!__classPrivateFieldGet(this, _ChannelEngine_users, "f").has(sender) && sender !== pondsocket_common_1.SystemSender.CHANNEL) {
|
|
206
206
|
throw new pondError_1.ChannelError(`ChannelEngine: User with id ${sender} does not exist in channel ${this.name}`, 404, this.name);
|
|
207
207
|
}
|
|
208
208
|
const eventMessage = {
|
|
209
209
|
recipients: __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_getUsersFromRecipients).call(this, recipient, sender),
|
|
210
210
|
channelName: this.name,
|
|
211
|
+
requestId,
|
|
211
212
|
action,
|
|
212
213
|
payload,
|
|
213
214
|
event,
|
|
@@ -227,14 +228,15 @@ class ChannelEngine {
|
|
|
227
228
|
sender: userId,
|
|
228
229
|
event: message.event,
|
|
229
230
|
payload: message.payload,
|
|
230
|
-
action:
|
|
231
|
+
action: pondsocket_common_1.ServerActions.BROADCAST,
|
|
231
232
|
channelName: this.name,
|
|
232
|
-
|
|
233
|
+
requestId: message.requestId,
|
|
234
|
+
recipients: __classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_getUsersFromRecipients).call(this, message.addresses || pondsocket_common_1.ChannelReceiver.ALL_USERS, userId),
|
|
233
235
|
};
|
|
234
236
|
const request = new eventRequest_1.EventRequest(responseEvent, this);
|
|
235
237
|
const response = new eventResponse_1.EventResponse(responseEvent, this);
|
|
236
238
|
__classPrivateFieldGet(this, _ChannelEngine_parentEngine, "f").execute(request, response, () => {
|
|
237
|
-
this.sendMessage(
|
|
239
|
+
this.sendMessage(responseEvent.requestId, pondsocket_common_1.SystemSender.CHANNEL, [userId], pondsocket_common_1.ServerActions.ERROR, pondsocket_common_1.ErrorTypes.HANDLER_NOT_FOUND, {
|
|
238
240
|
message: 'A handler did not respond to the event',
|
|
239
241
|
code: 404,
|
|
240
242
|
});
|
|
@@ -268,17 +270,17 @@ _ChannelEngine_receiver = new WeakMap(), _ChannelEngine_presenceEngine = new Wea
|
|
|
268
270
|
const allUsers = Array.from(__classPrivateFieldGet(this, _ChannelEngine_users, "f").keys());
|
|
269
271
|
let users;
|
|
270
272
|
switch (recipients) {
|
|
271
|
-
case
|
|
273
|
+
case pondsocket_common_1.ChannelReceiver.ALL_USERS:
|
|
272
274
|
users = allUsers;
|
|
273
275
|
break;
|
|
274
|
-
case
|
|
275
|
-
if (sender ===
|
|
276
|
-
throw new pondError_1.ChannelError(`ChannelEngine: Cannot use ${
|
|
276
|
+
case pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER:
|
|
277
|
+
if (sender === pondsocket_common_1.SystemSender.CHANNEL) {
|
|
278
|
+
throw new pondError_1.ChannelError(`ChannelEngine: Cannot use ${pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER} with ${pondsocket_common_1.SystemSender.CHANNEL}`, 500, this.name);
|
|
277
279
|
}
|
|
278
280
|
users = allUsers.filter((user) => user !== sender);
|
|
279
281
|
break;
|
|
280
282
|
default:
|
|
281
|
-
if (!Array.isArray(recipients)
|
|
283
|
+
if (!Array.isArray(recipients)) {
|
|
282
284
|
throw new pondError_1.ChannelError(`ChannelEngine: Invalid recipients ${recipients}`, 500, this.name);
|
|
283
285
|
}
|
|
284
286
|
if (recipients.some((user) => !allUsers.includes(user))) {
|