@eleven-am/pondsocket 0.1.200 → 0.1.201

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eleven-am/pondsocket",
3
- "version": "0.1.200",
3
+ "version": "0.1.201",
4
4
  "description": "PondSocket is a fast simple socket server",
5
5
  "keywords": [
6
6
  "socket",
@@ -23,7 +23,7 @@
23
23
  "remove": "rm -r dist/tests && rm dist/distIndex.js",
24
24
  "copy": "cp src/types.d.ts dist/types.d.ts && cp src/distIndex.ts dist/index.d.ts && cp package.json dist && cp README.md dist && cp LICENSE dist",
25
25
  "push": "npm version patch && npm run copy && cd dist && npm publish && cd ..",
26
- "pipeline": "npm run lint && npm run test && npm run build && npm run push"
26
+ "pipeline": "npm run lint:fix && npm run lint && npm run test && npm run build && npm run push"
27
27
  },
28
28
  "author": "Roy OSSAI",
29
29
  "license": "GPL-3.0",
@@ -35,31 +35,31 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@eleven-am/pondsocket-common": "^0.0.26",
38
- "ioredis": "^5.6.1",
39
- "ws": "^8.18.1"
38
+ "redis": "^5.5.6",
39
+ "ws": "^8.18.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@eslint/compat": "^1.2.8",
42
+ "@eslint/compat": "^1.2.9",
43
43
  "@eslint/eslintrc": "^3.3.1",
44
- "@eslint/js": "^9.25.1",
45
- "@stylistic/eslint-plugin-ts": "^4.2.0",
44
+ "@eslint/js": "^9.28.0",
45
+ "@stylistic/eslint-plugin-ts": "^4.4.1",
46
46
  "@types/jest": "^29.5.14",
47
- "@types/node": "^22.15.3",
47
+ "@types/node": "^22.15.30",
48
48
  "@types/ws": "^8.18.1",
49
- "@typescript-eslint/eslint-plugin": "^8.31.1",
50
- "@typescript-eslint/parser": "^8.31.1",
51
- "eslint": "^9.25.1",
52
- "eslint-config-prettier": "^10.1.2",
49
+ "@typescript-eslint/eslint-plugin": "^8.33.1",
50
+ "@typescript-eslint/parser": "^8.33.1",
51
+ "eslint": "^9.28.0",
52
+ "eslint-config-prettier": "^10.1.5",
53
53
  "eslint-import-resolver-node": "^0.3.9",
54
54
  "eslint-plugin-file-progress": "^3.0.2",
55
55
  "eslint-plugin-import": "^2.31.0",
56
- "eslint-plugin-prettier": "^5.2.6",
57
- "globals": "^16.0.0",
56
+ "eslint-plugin-prettier": "^5.4.1",
57
+ "globals": "^16.2.0",
58
58
  "jest": "^29.7.0",
59
59
  "prettier": "^3.5.3",
60
60
  "source-map-support": "^0.5.21",
61
- "supertest": "^7.1.0",
62
- "ts-jest": "^29.3.2",
61
+ "supertest": "^7.1.1",
62
+ "ts-jest": "^29.3.4",
63
63
  "ts-loader": "^9.5.2",
64
64
  "ts-node": "^10.9.2",
65
65
  "tsconfig-paths": "^4.2.0",
package/server/server.js CHANGED
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
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
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _PondSocket_instances, _PondSocket_exclusiveServer, _PondSocket_server, _PondSocket_socketServer, _PondSocket_middleware, _PondSocket_manageHeartbeat, _PondSocket_init, _PondSocket_getCookies;
13
+ var _PondSocket_instances, _PondSocket_server, _PondSocket_exclusiveServer, _PondSocket_socketServer, _PondSocket_backend, _PondSocket_middleware, _PondSocket_handleUpgrade, _PondSocket_manageHeartbeat, _PondSocket_init, _PondSocket_getCookies;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.PondSocket = void 0;
16
16
  const http_1 = require("http");
@@ -22,15 +22,17 @@ const endpointEngine_1 = require("../engines/endpointEngine");
22
22
  const matcher_1 = require("../matcher/matcher");
23
23
  const endpoint_1 = require("../wrappers/endpoint");
24
24
  class PondSocket {
25
- constructor({ server, socketServer, exclusiveServer = true, } = {}) {
25
+ constructor({ server, socketServer, exclusiveServer = true, distributedBackend, } = {}) {
26
26
  _PondSocket_instances.add(this);
27
- _PondSocket_exclusiveServer.set(this, void 0);
28
27
  _PondSocket_server.set(this, void 0);
28
+ _PondSocket_exclusiveServer.set(this, void 0);
29
29
  _PondSocket_socketServer.set(this, void 0);
30
+ _PondSocket_backend.set(this, void 0);
30
31
  _PondSocket_middleware.set(this, void 0);
31
32
  __classPrivateFieldSet(this, _PondSocket_middleware, new middleware_1.Middleware(), "f");
32
33
  __classPrivateFieldSet(this, _PondSocket_exclusiveServer, exclusiveServer, "f");
33
34
  __classPrivateFieldSet(this, _PondSocket_server, server !== null && server !== void 0 ? server : new http_1.Server(), "f");
35
+ __classPrivateFieldSet(this, _PondSocket_backend, distributedBackend !== null && distributedBackend !== void 0 ? distributedBackend : null, "f");
34
36
  __classPrivateFieldSet(this, _PondSocket_socketServer, socketServer !== null && socketServer !== void 0 ? socketServer : new ws_1.WebSocketServer({ noServer: true }), "f");
35
37
  __classPrivateFieldGet(this, _PondSocket_instances, "m", _PondSocket_init).call(this);
36
38
  }
@@ -50,7 +52,7 @@ class PondSocket {
50
52
  * Create a new endpoint
51
53
  */
52
54
  createEndpoint(path, handler) {
53
- const endpoint = new endpointEngine_1.EndpointEngine();
55
+ const endpoint = new endpointEngine_1.EndpointEngine(String(path), __classPrivateFieldGet(this, _PondSocket_backend, "f"));
54
56
  __classPrivateFieldGet(this, _PondSocket_middleware, "f").use((req, params, next) => {
55
57
  const event = (0, matcher_1.parseAddress)(path, req.address);
56
58
  if (!event) {
@@ -67,38 +69,34 @@ class PondSocket {
67
69
  });
68
70
  return new endpoint_1.Endpoint(endpoint);
69
71
  }
70
- /**
71
- * Handle WebSocket upgrade requests
72
- */
73
- handleUpgrade(req, socket, head) {
74
- const clientId = req.headers['sec-websocket-key'];
75
- const request = {
76
- id: clientId,
77
- headers: req.headers,
78
- address: req.url || '',
79
- };
80
- const params = {
81
- head,
82
- socket,
83
- request: req,
84
- requestId: (0, pondsocket_common_1.uuid)(),
85
- };
86
- __classPrivateFieldGet(this, _PondSocket_middleware, "f").run(request, params, (error) => {
87
- if (error) {
88
- const code = (error === null || error === void 0 ? void 0 : error.statusCode) || 400;
89
- const message = (error === null || error === void 0 ? void 0 : error.message) || 'Unauthorized connection';
90
- socket.write(`HTTP/1.1 ${code} ${message}\r\n\r\n`);
91
- socket.destroy();
92
- }
93
- else if (__classPrivateFieldGet(this, _PondSocket_exclusiveServer, "f")) {
94
- socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
95
- socket.destroy();
96
- }
97
- });
98
- }
99
72
  }
100
73
  exports.PondSocket = PondSocket;
101
- _PondSocket_exclusiveServer = new WeakMap(), _PondSocket_server = new WeakMap(), _PondSocket_socketServer = new WeakMap(), _PondSocket_middleware = new WeakMap(), _PondSocket_instances = new WeakSet(), _PondSocket_manageHeartbeat = function _PondSocket_manageHeartbeat() {
74
+ _PondSocket_server = new WeakMap(), _PondSocket_exclusiveServer = new WeakMap(), _PondSocket_socketServer = new WeakMap(), _PondSocket_backend = new WeakMap(), _PondSocket_middleware = new WeakMap(), _PondSocket_instances = new WeakSet(), _PondSocket_handleUpgrade = function _PondSocket_handleUpgrade(req, socket, head) {
75
+ const clientId = req.headers['sec-websocket-key'];
76
+ const request = {
77
+ id: clientId,
78
+ headers: req.headers,
79
+ address: req.url || '',
80
+ };
81
+ const params = {
82
+ head,
83
+ socket,
84
+ request: req,
85
+ requestId: (0, pondsocket_common_1.uuid)(),
86
+ };
87
+ __classPrivateFieldGet(this, _PondSocket_middleware, "f").run(request, params, (error) => {
88
+ if (error) {
89
+ const code = (error === null || error === void 0 ? void 0 : error.statusCode) || 400;
90
+ const message = (error === null || error === void 0 ? void 0 : error.message) || 'Unauthorized connection';
91
+ socket.write(`HTTP/1.1 ${code} ${message}\r\n\r\n`);
92
+ socket.destroy();
93
+ }
94
+ else if (__classPrivateFieldGet(this, _PondSocket_exclusiveServer, "f")) {
95
+ socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
96
+ socket.destroy();
97
+ }
98
+ });
99
+ }, _PondSocket_manageHeartbeat = function _PondSocket_manageHeartbeat() {
102
100
  __classPrivateFieldGet(this, _PondSocket_socketServer, "f").on('connection', (socket) => {
103
101
  socket.on('pong', () => {
104
102
  socket.isAlive = true;
@@ -122,7 +120,7 @@ _PondSocket_exclusiveServer = new WeakMap(), _PondSocket_server = new WeakMap(),
122
120
  __classPrivateFieldGet(this, _PondSocket_server, "f").on('close', () => {
123
121
  clearInterval(timeout);
124
122
  });
125
- __classPrivateFieldGet(this, _PondSocket_server, "f").on('upgrade', this.handleUpgrade.bind(this));
123
+ __classPrivateFieldGet(this, _PondSocket_server, "f").on('upgrade', __classPrivateFieldGet(this, _PondSocket_instances, "m", _PondSocket_handleUpgrade).bind(this));
126
124
  }, _PondSocket_getCookies = function _PondSocket_getCookies(headers) {
127
125
  const cookieHeader = headers.cookie;
128
126
  if (!cookieHeader) {
package/types.d.ts CHANGED
@@ -1,19 +1,20 @@
1
- import { Server, ServerResponse, IncomingMessage, IncomingHttpHeaders } from 'http';
1
+ import { IncomingHttpHeaders, IncomingMessage, Server as HTTPServer, Server, ServerResponse } from 'http';
2
2
 
3
3
  import {
4
+ EventParams,
4
5
  IncomingConnection,
6
+ JoinParams,
7
+ Params,
5
8
  PondAssigns,
6
9
  PondEvent,
7
10
  PondEventMap,
8
11
  PondMessage,
9
12
  PondPath,
10
13
  PondPresence,
14
+ Unsubscribe,
15
+ UserAssigns,
11
16
  UserData,
12
17
  UserPresences,
13
- UserAssigns,
14
- JoinParams,
15
- EventParams,
16
- Params,
17
18
  } from '@eleven-am/pondsocket-common';
18
19
  import { WebSocket, WebSocketServer } from 'ws';
19
20
 
@@ -24,22 +25,117 @@ export interface LeaveEvent<EventTypes extends PondEventMap = PondEventMap, Pres
24
25
  channel: Channel<EventTypes, PresenceType, AssignType>;
25
26
  }
26
27
 
27
- export interface OutgoingEvent<Event extends string, EventTypes extends PondEventMap = PondEventMap, PresenceType extends PondPresence = PondPresence, AssignType extends PondAssigns = PondAssigns> {
28
- payload: PondMessage;
29
- event: EventParams<Event>;
30
- channel: Channel<EventTypes, PresenceType, AssignType>;
31
- }
32
-
33
28
  export type LeaveCallback<EventTypes extends PondEventMap = PondEventMap, PresenceType extends PondPresence = PondPresence, AssignType extends PondAssigns = PondAssigns> = (event: LeaveEvent<EventTypes, PresenceType, AssignType>) => void;
34
29
 
35
- export type OutgoingHandler<Event extends string, EventTypes extends PondEventMap = PondEventMap, PresenceType extends PondPresence = PondPresence, AssignType extends PondAssigns = PondAssigns> = (event: OutgoingEvent<Event, EventTypes, PresenceType, AssignType>) => PondMessage | Promise<PondMessage> | void | Promise<void>;
36
-
37
30
  export type RequestHandler<Request> = (request: Request) => void | Promise<void>;
38
31
 
39
32
  export interface PondSocketOptions {
40
- server?: Server;
41
- exclusiveServer?: boolean;
33
+ server?: HTTPServer;
42
34
  socketServer?: WebSocketServer;
35
+ exclusiveServer?: boolean;
36
+ distributedBackend?: IDistributedBackend;
37
+ }
38
+
39
+ export enum DistributedMessageType {
40
+ STATE_REQUEST = 'STATE_REQUEST',
41
+ STATE_RESPONSE = 'STATE_RESPONSE',
42
+ USER_JOINED = 'USER_JOINED',
43
+ USER_LEFT = 'USER_LEFT',
44
+ USER_MESSAGE = 'USER_MESSAGE',
45
+ PRESENCE_UPDATE = 'PRESENCE_UPDATE',
46
+ PRESENCE_REMOVED = 'PRESENCE_REMOVED',
47
+ ASSIGNS_UPDATE = 'ASSIGNS_UPDATE',
48
+ ASSIGNS_REMOVED = 'ASSIGNS_REMOVED',
49
+ EVICT_USER = 'EVICT_USER'
50
+ }
51
+
52
+ export interface DistributedMessage {
53
+ type: DistributedMessageType;
54
+ endpointName: string;
55
+ channelName: string;
56
+ timestamp?: number;
57
+ }
58
+
59
+ export interface StateRequest extends DistributedMessage {
60
+ type: DistributedMessageType.STATE_REQUEST;
61
+ fromNode: string;
62
+ }
63
+
64
+ export interface StateResponse extends DistributedMessage {
65
+ type: DistributedMessageType.STATE_RESPONSE;
66
+ users: Array<{
67
+ id: string;
68
+ presence: PondPresence;
69
+ assigns: PondAssigns;
70
+ }>;
71
+ }
72
+
73
+ export interface UserJoined extends DistributedMessage {
74
+ type: DistributedMessageType.USER_JOINED;
75
+ userId: string;
76
+ presence: PondPresence;
77
+ assigns: PondAssigns;
78
+ }
79
+
80
+ export interface UserLeft extends DistributedMessage {
81
+ type: DistributedMessageType.USER_LEFT;
82
+ userId: string;
83
+ }
84
+
85
+ export interface UserMessage extends DistributedMessage {
86
+ type: DistributedMessageType.USER_MESSAGE;
87
+ fromUserId: string;
88
+ event: string;
89
+ payload: PondMessage;
90
+ requestId: string;
91
+ recipients: string[];
92
+ }
93
+
94
+ export interface PresenceUpdate extends DistributedMessage {
95
+ type: DistributedMessageType.PRESENCE_UPDATE;
96
+ userId: string;
97
+ presence: PondPresence;
98
+ }
99
+
100
+ export interface PresenceRemoved extends DistributedMessage {
101
+ type: DistributedMessageType.PRESENCE_REMOVED;
102
+ userId: string;
103
+ }
104
+
105
+ export interface AssignsUpdate extends DistributedMessage {
106
+ type: DistributedMessageType.ASSIGNS_UPDATE;
107
+ userId: string;
108
+ assigns: PondAssigns;
109
+ }
110
+
111
+ export interface AssignsRemoved extends DistributedMessage {
112
+ type: DistributedMessageType.ASSIGNS_REMOVED;
113
+ userId: string;
114
+ }
115
+
116
+ export interface EvictUser extends DistributedMessage {
117
+ type: DistributedMessageType.EVICT_USER;
118
+ userId: string;
119
+ reason: string;
120
+ fromNode?: string;
121
+ }
122
+
123
+ export type DistributedChannelMessage =
124
+ | StateRequest
125
+ | StateResponse
126
+ | UserJoined
127
+ | UserLeft
128
+ | UserMessage
129
+ | PresenceUpdate
130
+ | PresenceRemoved
131
+ | AssignsUpdate
132
+ | AssignsRemoved
133
+ | EvictUser;
134
+
135
+ export interface IDistributedBackend {
136
+ broadcast(endpointName: string, channelName: string, message: DistributedChannelMessage): Promise<void>;
137
+ subscribe(endpointName: string, channelName: string, handler: (message: DistributedChannelMessage) => void): Unsubscribe;
138
+ cleanup(): Promise<void>;
43
139
  }
44
140
 
45
141
  export declare class PondSocket {
@@ -130,15 +226,15 @@ export declare class PondChannel<EventType extends PondEventMap = PondEventMap,
130
226
  /**
131
227
  * @desc Handles an outgoing event, this is useful for modifying the event before it is sent to the client
132
228
  * @param {PondPath<string>} event - The event to handle
133
- * @param {OutgoingHandler} handler - The handler to execute when the event is sent
229
+ * @param {RequestHandler} handler - The handler to execute when the event is sent
134
230
  * @example
135
- * pond.onOutgoing('echo', (event) => {
231
+ * pond.handleOutgoingEvent('echo', (event) => {
136
232
  * return {
137
233
  * message: 'Hello, world!'
138
234
  * };
139
235
  * });
140
236
  */
141
- onOutgoing<Event extends string> (event: PondPath<Event>, handler: OutgoingHandler<Event, EventType, PresenceType, AssignType>): void;
237
+ handleOutgoingEvent<Event extends string> (event: PondPath<Event>, handler: RequestHandler<OutgoingContext<Event, PresenceType, AssignType>>): void;
142
238
 
143
239
  /**
144
240
  * @desc Gets a channel by name
@@ -360,7 +456,7 @@ export declare class ConnectionContext<Path extends string> {
360
456
  reply(event: string, payload: PondMessage): ConnectionContext<Path>;
361
457
  }
362
458
 
363
- export declare class JoinContext<Path extends string, EventType extends PondEventMap = PondEventMap, PresenceType extends PondPresence = PondPresence, AssignType extends PondAssigns = PondAssigns> {
459
+ export declare class BaseContext<Path extends string, PresenceType extends PondPresence = PondPresence, AssignType extends PondAssigns = PondAssigns> {
364
460
  /**
365
461
  * @desc Get the event information.
366
462
  */
@@ -376,11 +472,6 @@ export declare class JoinContext<Path extends string, EventType extends PondEven
376
472
  */
377
473
  get channel(): Channel;
378
474
 
379
- /**
380
- * @desc Get the join parameters.
381
- */
382
- get joinParams(): JoinParams;
383
-
384
475
  /**
385
476
  * @desc Get all current presences in the channel.
386
477
  */
@@ -392,9 +483,21 @@ export declare class JoinContext<Path extends string, EventType extends PondEven
392
483
  get assigns(): UserAssigns;
393
484
 
394
485
  /**
395
- * @desc Get the user data.
486
+ * @desc Get the user who sent the request.
396
487
  */
397
488
  get user(): UserData<PresenceType, AssignType>;
489
+ }
490
+
491
+ export declare class JoinContext<
492
+ Path extends string,
493
+ EventType extends PondEventMap = PondEventMap,
494
+ PresenceType extends PondPresence = PondPresence,
495
+ AssignType extends PondAssigns = PondAssigns
496
+ > extends BaseContext<Path, PresenceType, AssignType> {
497
+ /**
498
+ * @desc Get the join parameters.
499
+ */
500
+ get joinParams(): JoinParams;
398
501
 
399
502
  /**
400
503
  * @desc Checks if the server has responded to the join request.
@@ -456,37 +559,12 @@ export declare class JoinContext<Path extends string, EventType extends PondEven
456
559
  trackPresence(presence: PresenceType): JoinContext<Path, PresenceType, AssignType>;
457
560
  }
458
561
 
459
- export declare class EventContext<Path extends string, EventType extends PondEventMap = PondEventMap, PresenceType extends PondPresence = PondPresence, AssignType extends PondAssigns = PondAssigns> {
460
- /**
461
- * @desc Get the event information.
462
- */
463
- get event(): PondEvent<Path>;
464
-
465
- /**
466
- * @desc Get the channel name.
467
- */
468
- get channelName(): string;
469
-
470
- /**
471
- * @desc Get the channel instance.
472
- */
473
- get channel(): Channel;
474
-
475
- /**
476
- * @desc Get all current presences in the channel.
477
- */
478
- get presences(): UserPresences;
479
-
480
- /**
481
- * @desc Get all current assigns in the channel.
482
- */
483
- get assigns(): UserAssigns;
484
-
485
- /**
486
- * @desc Get the user who sent the request.
487
- */
488
- get user(): UserData<PresenceType, AssignType>;
489
-
562
+ export declare class EventContext<
563
+ Path extends string,
564
+ EventType extends PondEventMap = PondEventMap,
565
+ PresenceType extends PondPresence = PondPresence,
566
+ AssignType extends PondAssigns = PondAssigns
567
+ > extends BaseContext<Path, PresenceType, AssignType> {
490
568
  /**
491
569
  * @desc Assigns data to the client.
492
570
  * @param {PondAssigns} assigns - The data to assign to the client.
@@ -558,3 +636,25 @@ export declare class EventContext<Path extends string, EventType extends PondEve
558
636
  */
559
637
  evictUser(reason: string, userId?: string): EventContext<Path, EventType, PresenceType, AssignType>;
560
638
  }
639
+
640
+ export class OutgoingContext<
641
+ Path extends string,
642
+ PresenceType extends PondPresence = PondPresence,
643
+ AssignType extends PondAssigns = PondAssigns
644
+ > extends BaseContext<Path, PresenceType, AssignType> {
645
+ /**
646
+ * @desc Get the join parameters.
647
+ */
648
+ get payload(): PondMessage;
649
+
650
+ /**
651
+ * @desc Blocks the outgoing context, preventing further processing of the event.
652
+ */
653
+ block(): OutgoingContext<Path, PresenceType, AssignType>;
654
+
655
+ /**
656
+ * desc Transforms the outgoing context with a new payload.
657
+ * @param payload - The new payload to set for the context.
658
+ */
659
+ transform(payload: PondMessage): OutgoingContext<Path, PresenceType, AssignType>;
660
+ }
@@ -28,7 +28,7 @@ class PondChannel {
28
28
  __classPrivateFieldGet(this, _PondChannel_lobby, "f").onLeave(callback);
29
29
  return this;
30
30
  }
31
- onOutgoing(event, handler) {
31
+ handleOutgoingEvent(event, handler) {
32
32
  __classPrivateFieldGet(this, _PondChannel_lobby, "f").handleOutgoingEvent(event, handler);
33
33
  return this;
34
34
  }