playsocketjs 1.1.9 → 1.1.10

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.
@@ -2333,7 +2333,8 @@ class PlaySocket {
2333
2333
  * @private
2334
2334
  */
2335
2335
  async #attemptReconnect() {
2336
- if (this.#reconnectCount++ >= 3) {
2336
+ this.#reconnectCount++;
2337
+ if (this.#reconnectCount > 9) {
2337
2338
  this.#triggerEvent("error", "Disconnected from server.");
2338
2339
  return this.destroy();
2339
2340
  }
@@ -2226,6 +2226,7 @@ function requireServer () {
2226
2226
 
2227
2227
  // Set up ws event handlers
2228
2228
  this.#wss.on('connection', ws => {
2229
+ ws.connectionId = crypto.randomUUID();
2229
2230
  ws.isAlive = true;
2230
2231
  ws.on('pong', () => { ws.isAlive = true; });
2231
2232
  ws.on('message', msg => this.#handleMessage(ws, msg));
@@ -2258,9 +2259,14 @@ function requireServer () {
2258
2259
  try {
2259
2260
  const data = decode(message);
2260
2261
 
2261
- // Apply rate limiting after client is registered
2262
- if (ws.clientId && !this.#checkRateLimit(ws.clientId, data.type)) {
2263
- return console.error(`Client ${ws.clientId} rate limit exceeded.`);
2262
+ // Apply rate limiting to all connections (including unregistered)
2263
+ if (!this.#checkRateLimit(ws.connectionId, data.type)) {
2264
+ ws.rateLimitViolations = (ws.rateLimitViolations || 0) + 1;
2265
+ if (ws.rateLimitViolations > 5) {
2266
+ ws.terminate();
2267
+ return console.error(`Connection ${ws.connectionId} terminated due to repeated rate limit violations.`);
2268
+ }
2269
+ return console.error(`Connection ${ws.connectionId} rate limit exceeded.`);
2264
2270
  }
2265
2271
 
2266
2272
  switch (data.type) {
@@ -2465,24 +2471,24 @@ function requireServer () {
2465
2471
  * Check rate limit using token bucket algorithm
2466
2472
  * @private
2467
2473
  */
2468
- #checkRateLimit(clientId, operationType) {
2469
- const MAX_POINTS = 100;
2474
+ #checkRateLimit(connectionId, operationType) {
2475
+ const MAX_POINTS = 20;
2470
2476
  const now = Date.now();
2471
2477
 
2472
- if (!this.#rateLimits.has(clientId)) {
2473
- this.#rateLimits.set(clientId, { points: MAX_POINTS, lastReset: now });
2478
+ if (!this.#rateLimits.has(connectionId)) {
2479
+ this.#rateLimits.set(connectionId, { points: MAX_POINTS, lastReset: now });
2474
2480
  return true;
2475
2481
  }
2476
2482
 
2477
- const limit = this.#rateLimits.get(clientId);
2483
+ const limit = this.#rateLimits.get(connectionId);
2478
2484
 
2479
- // Reset points if interval has passed (5s)
2480
- if (now - limit.lastReset > 5000) {
2485
+ // Reset points if interval has passed (1s)
2486
+ if (now - limit.lastReset > 1000) {
2481
2487
  limit.points = MAX_POINTS;
2482
2488
  limit.lastReset = now;
2483
2489
  }
2484
2490
 
2485
- const pointCost = ['create_room', 'join_room'].includes(operationType) ? 20 : 1;
2491
+ const pointCost = ['create_room', 'join_room'].includes(operationType) ? 5 : 1;
2486
2492
  if (limit.points < pointCost) return false;
2487
2493
 
2488
2494
  limit.points -= pointCost;
@@ -2494,22 +2500,25 @@ function requireServer () {
2494
2500
  * @private
2495
2501
  */
2496
2502
  #handleDisconnection(ws) {
2497
- if (!ws.clientId) return;
2498
- this.#clients.delete(ws.clientId); // Immediately remove from active clients (otherwise, server would try to message this client)
2503
+ this.#rateLimits.delete(ws.connectionId);
2499
2504
 
2500
- // If client was in a room, check if they were the host & migrate
2501
- const roomId = this.#clientRooms.get(ws.clientId);
2502
- if (roomId != null) this.#changeHostIfDisconnected(roomId, ws.clientId);
2505
+ if (ws.clientId) {
2506
+ this.#clients.delete(ws.clientId); // Immediately remove from active clients (otherwise, server would try to message this client)
2503
2507
 
2504
- if (ws.willfulDisconnect) {
2505
- this.#disconnectClient(ws); // Immediate disconnection
2506
- } else {
2507
- // Pending complete disconnection with 2s grace period to allow for reconnections
2508
- this.#pendingDisconnects.set(ws.clientId, {
2509
- timeout: setTimeout(() => {
2510
- this.#disconnectClient(ws);
2511
- }, 2000)
2512
- });
2508
+ // If client was in a room, check if they were the host & migrate
2509
+ const roomId = this.#clientRooms.get(ws.clientId);
2510
+ if (roomId != null) this.#changeHostIfDisconnected(roomId, ws.clientId);
2511
+
2512
+ if (ws.willfulDisconnect) {
2513
+ this.#disconnectClient(ws); // Immediate disconnection
2514
+ } else {
2515
+ // Pending complete disconnection with 5s grace period to allow for reconnections
2516
+ this.#pendingDisconnects.set(ws.clientId, {
2517
+ timeout: setTimeout(() => {
2518
+ this.#disconnectClient(ws);
2519
+ }, 5000)
2520
+ });
2521
+ }
2513
2522
  }
2514
2523
  }
2515
2524
 
@@ -2520,7 +2529,6 @@ function requireServer () {
2520
2529
  */
2521
2530
  #disconnectClient(ws) {
2522
2531
  this.#pendingDisconnects.delete(ws.clientId);
2523
- this.#rateLimits.delete(ws.clientId);
2524
2532
  this.#clientTokens.delete(ws.clientId);
2525
2533
  const roomId = this.#clientRooms.get(ws.clientId);
2526
2534
  const room = this.#rooms[roomId];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playsocketjs",
3
- "version": "1.1.9",
3
+ "version": "1.1.10",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "module": "dist/playsocket-client.js",
6
6
  "exports": {