@eleven-am/pondsocket 0.1.141 → 0.1.142

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.
@@ -6,8 +6,13 @@ const channel_1 = require("./channel");
6
6
  const channel_test_1 = require("./channel.test");
7
7
  const eventResponse_1 = require("./eventResponse");
8
8
  const createChannelEngine = () => {
9
- const parentEngine = (0, channel_test_1.createParentEngine)();
10
- return new channel_1.ChannelEngine('test', parentEngine);
9
+ const { parentEngine, socket } = (0, channel_test_1.createParentEngine)();
10
+ const channelEngine = new channel_1.ChannelEngine('test', parentEngine);
11
+ return {
12
+ channelEngine,
13
+ parentEngine,
14
+ socket,
15
+ };
11
16
  };
12
17
  exports.createChannelEngine = createChannelEngine;
13
18
  const createChannelEvent = (name) => {
@@ -18,7 +23,6 @@ const createChannelEvent = (name) => {
18
23
  },
19
24
  sender: 'sender',
20
25
  action: pondsocket_common_1.ServerActions.BROADCAST,
21
- recipients: ['recipient'],
22
26
  channelName: name,
23
27
  requestId: 'requestId',
24
28
  };
@@ -26,10 +30,11 @@ const createChannelEvent = (name) => {
26
30
  };
27
31
  exports.createChannelEvent = createChannelEvent;
28
32
  const createChannelResponse = () => {
29
- const channelEngine = (0, exports.createChannelEngine)();
33
+ const { channelEngine, socket } = (0, exports.createChannelEngine)();
30
34
  const event = (0, exports.createChannelEvent)(channelEngine.name);
31
- channelEngine.addUser(event.sender, { assign: 'assign' }, () => { });
32
- channelEngine.addUser(event.recipients[0], { assign: 'assign' }, () => { });
35
+ const unsub = channelEngine.addUser(event.sender, { assign: 'assign' }, () => { });
36
+ socket.subscriptions.set(channelEngine.name, unsub);
37
+ channelEngine.addUser('tester', { assign: 'assign' }, () => { });
33
38
  const response = new eventResponse_1.EventResponse(event, channelEngine);
34
39
  return {
35
40
  channelEngine,
@@ -42,52 +47,36 @@ describe('ChannelResponse', () => {
42
47
  const { response } = createChannelResponse();
43
48
  expect(response).toBeDefined();
44
49
  });
45
- it('should accept the request', () => {
46
- const { response, channelEngine } = createChannelResponse();
47
- jest.spyOn(channelEngine, 'sendMessage');
48
- response.accept();
49
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', ['recipient'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
50
- });
51
- it('should reject the request', () => {
52
- const { response, channelEngine, event } = createChannelResponse();
53
- jest.spyOn(channelEngine, 'sendMessage');
54
- response.reject();
55
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', pondsocket_common_1.SystemSender.CHANNEL, [event.sender], pondsocket_common_1.ServerActions.ERROR, pondsocket_common_1.ErrorTypes.UNAUTHORIZED_BROADCAST, {
56
- message: 'Unauthorized request',
57
- code: 403,
58
- });
59
- });
60
50
  it('should send a direct message', () => {
61
51
  const { response, channelEngine, event } = createChannelResponse();
62
52
  jest.spyOn(channelEngine, 'sendMessage');
63
- response.send('event', { payload: 'payload' });
64
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', pondsocket_common_1.SystemSender.CHANNEL, [event.sender], pondsocket_common_1.ServerActions.SYSTEM, 'event', { payload: 'payload' });
53
+ response.reply('event', { payload: 'payload' });
54
+ expect(channelEngine.sendMessage).toHaveBeenCalledWith(pondsocket_common_1.SystemSender.CHANNEL, [event.sender], pondsocket_common_1.ServerActions.SYSTEM, 'event', { payload: 'payload' }, 'requestId');
65
55
  });
66
56
  it('should broadcast a message', () => {
67
57
  const { response, channelEngine } = createChannelResponse();
68
58
  jest.spyOn(channelEngine, 'sendMessage');
69
59
  response.broadcast('event', { payload: 'payload' });
70
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
60
+ expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', pondsocket_common_1.ChannelReceiver.ALL_USERS, pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
71
61
  });
72
62
  it('should broadcastFromUser a message', () => {
73
63
  const { response, channelEngine } = createChannelResponse();
74
64
  jest.spyOn(channelEngine, 'sendMessage');
75
- response.broadcastFromUser('event', { payload: 'payload' });
76
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER, pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
65
+ response.broadcastFrom('event', { payload: 'payload' });
66
+ expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', pondsocket_common_1.ChannelReceiver.ALL_EXCEPT_SENDER, pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
77
67
  });
78
68
  it('should sendToUsers a message', () => {
79
69
  const { response, channelEngine } = createChannelResponse();
80
70
  jest.spyOn(channelEngine, 'sendMessage');
81
- response.sendToUsers('event', { payload: 'payload' }, ['recipient']);
82
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', ['recipient'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
71
+ response.broadcastTo('event', { payload: 'payload' }, 'tester');
72
+ expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', ['tester'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
73
+ channelEngine.sendMessage.mockClear();
74
+ response.broadcastTo('event', { payload: 'payload' }, ['tester', 'sender']);
75
+ expect(channelEngine.sendMessage).toHaveBeenCalledWith('sender', ['tester', 'sender'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' }, 'requestId');
83
76
  });
84
77
  it('should fail to send to non existing users', () => {
85
- const { event, response, channelEngine } = createChannelResponse();
86
- jest.spyOn(channelEngine, 'sendMessage');
87
- event.recipients = ['non_existing_user'];
88
- expect(() => response.accept()).toThrow('ChannelEngine: Invalid recipients non_existing_user some users do not exist in channel test');
89
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', event.sender, ['non_existing_user'], pondsocket_common_1.ServerActions.BROADCAST, event.event, event.payload);
90
- expect(() => response.sendToUsers('event', { payload: 'payload' }, ['non_existing_user']))
78
+ const { response } = createChannelResponse();
79
+ expect(() => response.broadcastTo('event', { payload: 'payload' }, ['non_existing_user']))
91
80
  .toThrow('ChannelEngine: Invalid recipients non_existing_user some users do not exist in channel test');
92
81
  });
93
82
  it('should track a trackPresence', () => {
@@ -99,7 +88,7 @@ describe('ChannelResponse', () => {
99
88
  it('should update a users assign data', () => {
100
89
  const { response, channelEngine } = createChannelResponse();
101
90
  jest.spyOn(channelEngine, 'updateAssigns');
102
- response.accept({ assign: 'updated' });
91
+ response.assign({ assign: 'updated' });
103
92
  expect(channelEngine.updateAssigns).toHaveBeenCalledWith('sender', { assign: 'updated' });
104
93
  });
105
94
  it('should evict a user', () => {
@@ -109,7 +98,11 @@ describe('ChannelResponse', () => {
109
98
  expect(channelEngine.kickUser).toHaveBeenCalledWith('sender', 'recipient');
110
99
  });
111
100
  it('should destroy the channel', () => {
112
- const { response, channelEngine } = createChannelResponse();
101
+ const { channelEngine, socket } = (0, exports.createChannelEngine)();
102
+ const event = (0, exports.createChannelEvent)(channelEngine.name);
103
+ const unsub = channelEngine.addUser(event.sender, { assign: 'assign' }, () => { });
104
+ socket.subscriptions.set(channelEngine.name, unsub);
105
+ const response = new eventResponse_1.EventResponse(event, channelEngine);
113
106
  jest.spyOn(channelEngine, 'destroy');
114
107
  response.closeChannel('recipient');
115
108
  expect(channelEngine.destroy).toHaveBeenCalledWith('recipient');
@@ -118,7 +111,6 @@ describe('ChannelResponse', () => {
118
111
  const { response, channelEngine } = createChannelResponse();
119
112
  jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
120
113
  expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
121
- response.accept();
122
114
  response.trackPresence({ status: 'online' });
123
115
  expect(channelEngine.presenceEngine.trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
124
116
  });
@@ -126,7 +118,6 @@ describe('ChannelResponse', () => {
126
118
  const { response, channelEngine } = createChannelResponse();
127
119
  jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
128
120
  expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
129
- response.accept();
130
121
  response.trackPresence({ status: 'online' });
131
122
  expect(channelEngine.presenceEngine.trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
132
123
  expect(() => response.trackPresence({ status: 'online' })).toThrow('PresenceEngine: Presence with key sender already exists');
@@ -135,7 +126,6 @@ describe('ChannelResponse', () => {
135
126
  const { response, channelEngine } = createChannelResponse();
136
127
  jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
137
128
  expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
138
- response.accept();
139
129
  expect(() => response.trackPresence({ status: 'online' }, 'non_existent_user'))
140
130
  .toThrow('ChannelEngine: Invalid recipients non_existent_user some users do not exist in channel test');
141
131
  });
@@ -144,7 +134,6 @@ describe('ChannelResponse', () => {
144
134
  const { response, channelEngine } = createChannelResponse();
145
135
  jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
146
136
  expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
147
- response.accept();
148
137
  response.trackPresence({ status: 'online' });
149
138
  expect(channelEngine.presenceEngine.trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
150
139
  expect((_a = channelEngine.presenceEngine) === null || _a === void 0 ? void 0 : _a.getPresence()).toEqual({
@@ -159,7 +148,6 @@ describe('ChannelResponse', () => {
159
148
  const { response, channelEngine } = createChannelResponse();
160
149
  jest.spyOn(channelEngine.presenceEngine, 'trackPresence');
161
150
  expect(channelEngine.presenceEngine.trackPresence).not.toHaveBeenCalled();
162
- response.accept();
163
151
  response.trackPresence({ status: 'online' });
164
152
  expect(() => response.updatePresence({ status: 'online' }, 'non_existent_user'))
165
153
  .toThrow('PresenceEngine: Presence with key non_existent_user does not exist');
@@ -171,7 +159,7 @@ describe('ChannelResponse', () => {
171
159
  expect((_a = channelEngine.presenceEngine) === null || _a === void 0 ? void 0 : _a.getPresence()).toEqual({
172
160
  sender: { status: 'online' },
173
161
  });
174
- response.unTrackPresence();
162
+ response.removePresence();
175
163
  expect((_b = channelEngine.presenceEngine) === null || _b === void 0 ? void 0 : _b.getPresence()).toEqual({});
176
164
  });
177
165
  it('should throw an error if unTrackPresence is called for a non existing user', () => {
@@ -181,17 +169,7 @@ describe('ChannelResponse', () => {
181
169
  expect((_a = channelEngine.presenceEngine) === null || _a === void 0 ? void 0 : _a.getPresence()).toEqual({
182
170
  sender: { status: 'online' },
183
171
  });
184
- expect(() => response.unTrackPresence('non_existent_user'))
172
+ expect(() => response.removePresence('non_existent_user'))
185
173
  .toThrow('PresenceEngine: Presence with key non_existent_user does not exist');
186
174
  });
187
- it('should throw an error if accept, reject / send is called more than once', () => {
188
- const { response, channelEngine } = createChannelResponse();
189
- jest.spyOn(channelEngine, 'sendMessage');
190
- expect(channelEngine.sendMessage).not.toHaveBeenCalled();
191
- response.accept();
192
- expect(channelEngine.sendMessage).toHaveBeenCalledWith('requestId', 'sender', ['recipient'], pondsocket_common_1.ServerActions.BROADCAST, 'event', { payload: 'payload' });
193
- expect(() => response.accept()).toThrow('Event response has already been executed');
194
- expect(() => response.reject()).toThrow('Event response has already been executed');
195
- expect(() => response.send('event', { payload: 'payload' })).toThrow('Event response has already been executed');
196
- });
197
175
  });
@@ -12,19 +12,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createEndpointEngine = void 0;
15
16
  const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
16
17
  const superwstest_1 = __importDefault(require("superwstest"));
17
18
  const pondSocket_1 = require("../server/pondSocket");
18
19
  /* eslint-disable line-comment-position, no-inline-comments */
20
+ const createEndpointEngine = (socket) => ({
21
+ createChannel: jest.fn(),
22
+ listConnections: jest.fn(),
23
+ getClients: jest.fn(),
24
+ broadcast: jest.fn(),
25
+ closeConnection: jest.fn(),
26
+ manageSocket: jest.fn(),
27
+ getUser: () => socket,
28
+ subscribeTo: jest.fn(),
29
+ unsubscribeFrom: jest.fn(),
30
+ });
31
+ exports.createEndpointEngine = createEndpointEngine;
19
32
  describe('endpoint', () => {
20
33
  let socket;
21
34
  let server;
22
35
  beforeEach((done) => {
23
36
  socket = new pondSocket_1.PondSocket();
24
- server = socket.listen(3000, 'localhost', done);
37
+ server = socket.listen(3000, 'localhost', () => {
38
+ done();
39
+ });
25
40
  });
26
41
  afterEach((done) => {
27
- server.close(done);
42
+ server.close(() => {
43
+ done();
44
+ });
28
45
  });
29
46
  it('should be able to close a single socket', () => __awaiter(void 0, void 0, void 0, function* () {
30
47
  let count = 0;
@@ -37,7 +54,7 @@ describe('endpoint', () => {
37
54
  }, 1000);
38
55
  }
39
56
  else {
40
- res.reject();
57
+ res.decline();
41
58
  }
42
59
  });
43
60
  yield (0, superwstest_1.default)(server)
@@ -51,11 +68,11 @@ describe('endpoint', () => {
51
68
  const endpoint = socket.createEndpoint('/api/:room', (req, res) => {
52
69
  if (req.params.room === 'socket') {
53
70
  res.accept();
54
- const connections = endpoint.listConnections();
71
+ const connections = endpoint.getClients();
55
72
  expect(connections).toHaveLength(1);
56
73
  }
57
74
  else {
58
- res.reject();
75
+ res.decline();
59
76
  }
60
77
  });
61
78
  yield (0, superwstest_1.default)(server)
@@ -67,7 +84,7 @@ describe('endpoint', () => {
67
84
  socket.createEndpoint('/api/:path', (req, res) => {
68
85
  count++;
69
86
  expect(req.params.path).toBe('socket');
70
- res.reject();
87
+ res.decline();
71
88
  });
72
89
  yield (0, superwstest_1.default)(server)
73
90
  .ws('/api/socket')
@@ -88,12 +105,12 @@ describe('endpoint', () => {
88
105
  const endpoint = socket.createEndpoint('/api/:room', (req, res) => {
89
106
  if (req.params.room === 'socket') {
90
107
  res.accept();
91
- const connections = endpoint.listConnections();
108
+ const connections = endpoint.getClients();
92
109
  expect(connections).toHaveLength(1);
93
110
  endpoint.broadcast('TEST', { test: 'test' });
94
111
  }
95
112
  else {
96
- res.reject();
113
+ res.decline();
97
114
  }
98
115
  });
99
116
  yield (0, superwstest_1.default)(server)
@@ -120,12 +137,12 @@ describe('endpoint', () => {
120
137
  res.accept();
121
138
  }
122
139
  else {
123
- res.reject();
140
+ res.decline();
124
141
  }
125
142
  });
126
143
  endpoint.createChannel('/test/:room', (req, res) => {
127
144
  expect(req.event.params.room).toBeDefined();
128
- res.accept({
145
+ res.accept().assign({
129
146
  assigns: {
130
147
  status: 'online',
131
148
  },
@@ -162,7 +179,7 @@ describe('endpoint', () => {
162
179
  });
163
180
  endpoint.createChannel('/test/:room', (req, res) => {
164
181
  expect(req.event.params.room).toBeDefined();
165
- res.reject('Something went wrong');
182
+ res.decline('Something went wrong');
166
183
  });
167
184
  yield (0, superwstest_1.default)(server)
168
185
  .ws('/api/socket')
@@ -212,7 +229,7 @@ describe('endpoint', () => {
212
229
  }));
213
230
  it('should throw an error if accept, reject / send is called more than once', () => __awaiter(void 0, void 0, void 0, function* () {
214
231
  socket.createEndpoint('/api/:room', (_, res) => {
215
- res.send('hello', {
232
+ res.reply('hello', {
216
233
  test: 'test',
217
234
  });
218
235
  expect(() => res.accept()).toThrowError('Cannot execute response more than once');
@@ -244,7 +261,7 @@ describe('endpoint', () => {
244
261
  res.accept();
245
262
  });
246
263
  channel.onEvent('echo', (req, res) => {
247
- res.send('echo', req.event.payload);
264
+ res.reply('echo', req.event.payload);
248
265
  });
249
266
  channel.onEvent('broadcast', (req) => {
250
267
  channel.broadcast('broadcast', Object.assign(Object.assign({}, req.event.payload), { broadcast: true }));
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _EndpointEngine_instances, _EndpointEngine_middleware, _EndpointEngine_channels, _EndpointEngine_sockets, _EndpointEngine_parentEngine, _EndpointEngine_sendMessage, _EndpointEngine_joinChannel, _EndpointEngine_execute, _EndpointEngine_retrieveChannel, _EndpointEngine_handleMessage, _EndpointEngine_readMessage, _EndpointEngine_buildError, _EndpointEngine_leaveChannel, _Endpoint_engine;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.Endpoint = exports.EndpointEngine = void 0;
16
+ const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
17
+ const zod_1 = require("zod");
18
+ const middleware_1 = require("../abstracts/middleware");
19
+ const pondError_1 = require("../errors/pondError");
20
+ const joinRequest_1 = require("../lobby/joinRequest");
21
+ const joinResponse_1 = require("../lobby/joinResponse");
22
+ const lobby_1 = require("../lobby/lobby");
23
+ const matcher_1 = require("../matcher/matcher");
24
+ const schema_1 = require("../schema");
25
+ class EndpointEngine {
26
+ constructor(parent) {
27
+ _EndpointEngine_instances.add(this);
28
+ _EndpointEngine_middleware.set(this, void 0);
29
+ _EndpointEngine_channels.set(this, void 0);
30
+ _EndpointEngine_sockets.set(this, void 0);
31
+ _EndpointEngine_parentEngine.set(this, void 0);
32
+ __classPrivateFieldSet(this, _EndpointEngine_sockets, new Map(), "f");
33
+ __classPrivateFieldSet(this, _EndpointEngine_middleware, new middleware_1.Middleware(), "f");
34
+ __classPrivateFieldSet(this, _EndpointEngine_channels, new Set(), "f");
35
+ __classPrivateFieldSet(this, _EndpointEngine_parentEngine, parent, "f");
36
+ }
37
+ get parent() {
38
+ return __classPrivateFieldGet(this, _EndpointEngine_parentEngine, "f");
39
+ }
40
+ /**
41
+ * @desc Adds a new PondChannel to this path on this endpoint
42
+ * @param path - The path to add the channel to
43
+ * @param handler - The handler to use to authenticate the client
44
+ *
45
+ * @example
46
+ * const channel = endpoint.createChannel('/chat', (request, response) => {
47
+ * if (request.user.assigns.admin)
48
+ * response.accept();
49
+ *
50
+ * else
51
+ * response.reject('You are not an admin', 403);
52
+ * });
53
+ */
54
+ createChannel(path, handler) {
55
+ const pondChannel = new lobby_1.LobbyEngine(this);
56
+ __classPrivateFieldGet(this, _EndpointEngine_middleware, "f").use((user, joinParams, next) => {
57
+ const event = (0, matcher_1.parseAddress)(path, user.channelName);
58
+ if (event) {
59
+ const newChannel = pondChannel.getChannel(user.channelName) || pondChannel.createChannel(user.channelName);
60
+ const request = new joinRequest_1.JoinRequest(user, joinParams, newChannel);
61
+ const response = new joinResponse_1.JoinResponse(user, newChannel);
62
+ if (request._parseQueries(path)) {
63
+ return handler(request, response);
64
+ }
65
+ }
66
+ next();
67
+ });
68
+ __classPrivateFieldGet(this, _EndpointEngine_channels, "f").add(pondChannel);
69
+ return new lobby_1.PondChannel(pondChannel);
70
+ }
71
+ /**
72
+ * @desc Gets all clients connected to this endpoint
73
+ */
74
+ getClients() {
75
+ return [...__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").values()];
76
+ }
77
+ /**
78
+ * @desc Broadcasts a message to all clients connected to this endpoint
79
+ * @param event - The event to broadcast
80
+ * @param payload - The payload to broadcast
81
+ */
82
+ broadcast(event, payload) {
83
+ __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").forEach(({ socket }) => {
84
+ const message = {
85
+ event,
86
+ payload,
87
+ requestId: (0, pondsocket_common_1.uuid)(),
88
+ action: pondsocket_common_1.ServerActions.BROADCAST,
89
+ channelName: pondsocket_common_1.SystemSender.ENDPOINT,
90
+ };
91
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_sendMessage).call(this, socket, message);
92
+ });
93
+ }
94
+ /**
95
+ * @desc Closes specific clients connected to this endpoint
96
+ * @param clientIds - The id for the client / clients to close
97
+ */
98
+ closeConnection(clientIds) {
99
+ const clients = typeof clientIds === 'string' ? [clientIds] : clientIds;
100
+ this.getClients()
101
+ .forEach(({ clientId, socket }) => {
102
+ if (clients.includes(clientId)) {
103
+ socket.close();
104
+ }
105
+ });
106
+ }
107
+ /**
108
+ * @desc Manages a new socket connection
109
+ * @param cache - The socket cache
110
+ */
111
+ manageSocket(cache) {
112
+ __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").set(cache.clientId, cache);
113
+ const socket = cache.socket;
114
+ socket.addEventListener('message', (message) => {
115
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_readMessage).call(this, cache, message.data);
116
+ });
117
+ socket.addEventListener('close', () => {
118
+ cache.subscriptions.forEach((unsubscribe) => unsubscribe());
119
+ });
120
+ socket.addEventListener('error', () => {
121
+ cache.subscriptions.forEach((unsubscribe) => unsubscribe());
122
+ });
123
+ }
124
+ /**
125
+ * @desc Retrieves a user from the endpoint
126
+ * @param clientId - The id of the user to retrieve
127
+ * @private
128
+ */
129
+ getUser(clientId) {
130
+ const user = __classPrivateFieldGet(this, _EndpointEngine_sockets, "f").get(clientId);
131
+ if (!user) {
132
+ throw new pondError_1.EndpointError(`GatewayEngine: User ${clientId} does not exist`, 404);
133
+ }
134
+ return user;
135
+ }
136
+ /**
137
+ * @desc Subscribes a user to a channel, Will join the channel if it exists or add to pending subscriptions
138
+ * @param userId - The id of the user to subscribe
139
+ * @param channel - The name of the channel to subscribe to
140
+ */
141
+ subscribeTo(userId, channel) {
142
+ const user = this.getUser(userId);
143
+ const channelEngine = __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_retrieveChannel).call(this, channel);
144
+ if (!channelEngine) {
145
+ user.pendingSubscriptions.add(channel);
146
+ }
147
+ else {
148
+ user.subscriptions.set(channel, channelEngine.addUser(userId, user.assigns, (event) => {
149
+ user.socket.send(JSON.stringify(event));
150
+ }));
151
+ }
152
+ }
153
+ /**
154
+ * @desc Unsubscribes a user from a channel
155
+ * @param userId - The id of the user to unsubscribe
156
+ * @param channel - The name of the channel to unsubscribe from
157
+ */
158
+ unsubscribeFrom(userId, channel) {
159
+ const user = this.getUser(userId);
160
+ const unsubscribe = user.subscriptions.get(channel);
161
+ if (unsubscribe) {
162
+ unsubscribe();
163
+ user.subscriptions.delete(channel);
164
+ }
165
+ else if (user.pendingSubscriptions.has(channel)) {
166
+ user.pendingSubscriptions.delete(channel);
167
+ }
168
+ else {
169
+ throw new pondError_1.EndpointError(`GatewayEngine: User ${userId} is not subscribed to ${channel}`, 404);
170
+ }
171
+ }
172
+ subscribePendingUsers(channel) {
173
+ const users = [...__classPrivateFieldGet(this, _EndpointEngine_sockets, "f").values()]
174
+ .filter(({ pendingSubscriptions }) => pendingSubscriptions.has(channel.name));
175
+ users.forEach(({ clientId, pendingSubscriptions, subscriptions, socket, assigns }) => {
176
+ const unsubscribe = channel.addUser(clientId, assigns, (event) => {
177
+ socket.send(JSON.stringify(event));
178
+ });
179
+ subscriptions.set(channel.name, unsubscribe);
180
+ pendingSubscriptions.delete(channel.name);
181
+ });
182
+ }
183
+ }
184
+ exports.EndpointEngine = EndpointEngine;
185
+ _EndpointEngine_middleware = new WeakMap(), _EndpointEngine_channels = new WeakMap(), _EndpointEngine_sockets = new WeakMap(), _EndpointEngine_parentEngine = new WeakMap(), _EndpointEngine_instances = new WeakSet(), _EndpointEngine_sendMessage = function _EndpointEngine_sendMessage(socket, message) {
186
+ socket.send(JSON.stringify(message));
187
+ }, _EndpointEngine_joinChannel = function _EndpointEngine_joinChannel(channel, socket, joinParams, requestId) {
188
+ const cache = Object.assign(Object.assign({}, socket), { requestId, channelName: channel });
189
+ __classPrivateFieldGet(this, _EndpointEngine_middleware, "f").run(cache, joinParams, () => {
190
+ throw new pondError_1.EndpointError(`GatewayEngine: Channel ${channel} does not exist`, 404);
191
+ });
192
+ }, _EndpointEngine_execute = function _EndpointEngine_execute(channel, handler) {
193
+ for (const manager of __classPrivateFieldGet(this, _EndpointEngine_channels, "f")) {
194
+ const isPresent = manager.listChannels()
195
+ .includes(channel);
196
+ if (isPresent) {
197
+ return manager.execute(channel, handler);
198
+ }
199
+ }
200
+ throw new Error(`GatewayEngine: Channel ${channel} does not exist`);
201
+ }, _EndpointEngine_retrieveChannel = function _EndpointEngine_retrieveChannel(channel) {
202
+ for (const manager of __classPrivateFieldGet(this, _EndpointEngine_channels, "f")) {
203
+ const isPresent = manager.listChannels()
204
+ .includes(channel);
205
+ if (isPresent) {
206
+ return manager.getChannel(channel);
207
+ }
208
+ }
209
+ }, _EndpointEngine_handleMessage = function _EndpointEngine_handleMessage(cache, message) {
210
+ switch (message.action) {
211
+ case pondsocket_common_1.ClientActions.JOIN_CHANNEL:
212
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_joinChannel).call(this, message.channelName, cache, message.payload, message.requestId);
213
+ break;
214
+ case pondsocket_common_1.ClientActions.LEAVE_CHANNEL:
215
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_leaveChannel).call(this, message.channelName, cache);
216
+ break;
217
+ case pondsocket_common_1.ClientActions.BROADCAST:
218
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_execute).call(this, message.channelName, (channel) => {
219
+ channel.broadcastMessage(cache.clientId, message);
220
+ });
221
+ break;
222
+ default:
223
+ throw new Error(`GatewayEngine: Action ${message.action} does not exist`);
224
+ }
225
+ }, _EndpointEngine_readMessage = function _EndpointEngine_readMessage(cache, message) {
226
+ try {
227
+ const data = JSON.parse(message);
228
+ const result = schema_1.clientMessageSchema.parse(data);
229
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_handleMessage).call(this, cache, result);
230
+ }
231
+ catch (e) {
232
+ __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_sendMessage).call(this, cache.socket, __classPrivateFieldGet(this, _EndpointEngine_instances, "m", _EndpointEngine_buildError).call(this, e));
233
+ }
234
+ }, _EndpointEngine_buildError = function _EndpointEngine_buildError(error) {
235
+ const event = {
236
+ event: pondsocket_common_1.ErrorTypes.INVALID_MESSAGE,
237
+ action: pondsocket_common_1.ServerActions.ERROR,
238
+ channelName: pondsocket_common_1.SystemSender.ENDPOINT,
239
+ requestId: (0, pondsocket_common_1.uuid)(),
240
+ payload: {},
241
+ };
242
+ if (error instanceof SyntaxError) {
243
+ event.payload = {
244
+ message: 'Invalid JSON',
245
+ };
246
+ }
247
+ else if (error instanceof Error) {
248
+ event.event = pondsocket_common_1.ErrorTypes.INTERNAL_SERVER_ERROR;
249
+ event.payload = {
250
+ message: error.message,
251
+ };
252
+ }
253
+ else if (error instanceof pondError_1.PresenceError) {
254
+ event.event = pondsocket_common_1.ErrorTypes.PRESENCE_ERROR;
255
+ event.channelName = error.channel;
256
+ event.payload = {
257
+ message: error.message,
258
+ code: error.code,
259
+ action: error.event,
260
+ };
261
+ }
262
+ else if (error instanceof pondError_1.ChannelError) {
263
+ event.event = pondsocket_common_1.ErrorTypes.CHANNEL_ERROR;
264
+ event.channelName = error.channel;
265
+ event.payload = {
266
+ message: error.message,
267
+ code: error.code,
268
+ };
269
+ }
270
+ else if (error instanceof pondError_1.EndpointError) {
271
+ event.event = pondsocket_common_1.ErrorTypes.ENDPOINT_ERROR;
272
+ event.payload = {
273
+ message: error.message,
274
+ code: error.code,
275
+ };
276
+ }
277
+ else if (error instanceof zod_1.ZodError) {
278
+ const message = error.errors.map((error) => {
279
+ if ('expected' in error && 'received' in error) {
280
+ return `Expected ${error.path.join('.')} to be ${error.expected}, but received ${error.received}`;
281
+ }
282
+ return `${error.path.join('.')} ${error.message}`;
283
+ }).join(', ');
284
+ event.payload = {
285
+ message,
286
+ code: 400,
287
+ };
288
+ }
289
+ else {
290
+ event.payload = {
291
+ message: 'Unknown error',
292
+ };
293
+ }
294
+ return event;
295
+ }, _EndpointEngine_leaveChannel = function _EndpointEngine_leaveChannel(channel, socket) {
296
+ const unsubscribe = socket.subscriptions.get(channel);
297
+ if (!unsubscribe) {
298
+ throw new pondError_1.EndpointError(`GatewayEngine: Channel ${channel} does not exist`, 404);
299
+ }
300
+ unsubscribe();
301
+ };
302
+ class Endpoint {
303
+ constructor(engine) {
304
+ _Endpoint_engine.set(this, void 0);
305
+ __classPrivateFieldSet(this, _Endpoint_engine, engine, "f");
306
+ }
307
+ createChannel(path, handler) {
308
+ return __classPrivateFieldGet(this, _Endpoint_engine, "f").createChannel(path, handler);
309
+ }
310
+ broadcast(event, payload) {
311
+ __classPrivateFieldGet(this, _Endpoint_engine, "f").broadcast(event, payload);
312
+ }
313
+ closeConnection(clientIds) {
314
+ __classPrivateFieldGet(this, _Endpoint_engine, "f").closeConnection(clientIds);
315
+ }
316
+ getClients() {
317
+ return __classPrivateFieldGet(this, _Endpoint_engine, "f").getClients().map(({ socket }) => socket);
318
+ }
319
+ }
320
+ exports.Endpoint = Endpoint;
321
+ _Endpoint_engine = new WeakMap();