From 16d06164d56332bd00fb22acc5b2b2997b942d73 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Mon, 24 May 2021 15:34:03 +0200
Subject: [PATCH] Small fix + attempt to improve socket messages reliability...

---
 client/package-lock.json     | 283 +++++++++++++++++------------------
 client/src/views/Game.vue    |  51 ++++---
 client/src/views/Hall.vue    | 100 +++++++------
 client/src/views/MyGames.vue |  38 ++---
 server/sockets.js            |  19 +++
 5 files changed, 264 insertions(+), 227 deletions(-)

diff --git a/client/package-lock.json b/client/package-lock.json
index 670ba11c..bd08ac46 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -44,12 +44,12 @@
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.1.tgz",
-      "integrity": "sha512-TMGhsXMXCP/O1WtQmZjpEYDhCYC9vFhayWZPJSZCGkPJgUqX0rF0wwtrYvnzVxIjcF80tkUertXVk5cwqi5cAQ==",
+      "version": "7.14.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz",
+      "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.14.1",
+        "@babel/types": "^7.14.2",
         "jsesc": "^2.5.1",
         "source-map": "^0.5.0"
       }
@@ -64,14 +64,14 @@
       }
     },
     "node_modules/@babel/helper-function-name": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz",
-      "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==",
+      "version": "7.14.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz",
+      "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==",
       "dev": true,
       "dependencies": {
         "@babel/helper-get-function-arity": "^7.12.13",
         "@babel/template": "^7.12.13",
-        "@babel/types": "^7.12.13"
+        "@babel/types": "^7.14.2"
       }
     },
     "node_modules/@babel/helper-get-function-arity": {
@@ -110,9 +110,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.1.tgz",
-      "integrity": "sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q==",
+      "version": "7.14.3",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz",
+      "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==",
       "dev": true,
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -133,25 +133,25 @@
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.14.0",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.0.tgz",
-      "integrity": "sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA==",
+      "version": "7.14.2",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz",
+      "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==",
       "dev": true,
       "dependencies": {
         "@babel/code-frame": "^7.12.13",
-        "@babel/generator": "^7.14.0",
-        "@babel/helper-function-name": "^7.12.13",
+        "@babel/generator": "^7.14.2",
+        "@babel/helper-function-name": "^7.14.2",
         "@babel/helper-split-export-declaration": "^7.12.13",
-        "@babel/parser": "^7.14.0",
-        "@babel/types": "^7.14.0",
+        "@babel/parser": "^7.14.2",
+        "@babel/types": "^7.14.2",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.1.tgz",
-      "integrity": "sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA==",
+      "version": "7.14.2",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz",
+      "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==",
       "dev": true,
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.14.0",
@@ -279,9 +279,9 @@
       "dev": true
     },
     "node_modules/@types/node": {
-      "version": "15.0.2",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz",
-      "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==",
+      "version": "15.6.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.0.tgz",
+      "integrity": "sha512-gCYSfQpy+LYhOFTKAeE8BkyGqaxmlFxe+n4DKM6DR0wzw/HISUE/hAmkC/KT8Sw5PCJblqg062b3z9gucv3k0A==",
       "dev": true
     },
     "node_modules/@types/normalize-package-data": {
@@ -1852,16 +1852,12 @@
       }
     },
     "node_modules/camelcase": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
-      "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
       "dev": true,
-      "peer": true,
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=6"
       }
     },
     "node_modules/caniuse-api": {
@@ -2814,16 +2810,15 @@
       }
     },
     "node_modules/css-loader": {
-      "version": "5.2.4",
-      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.4.tgz",
-      "integrity": "sha512-OFYGyINCKkdQsTrSYxzGSFnGS4gNjcXkKkQgWxK138jgnPt+lepxdjSZNc8sHAl5vP3DhsJUxufWIjOwI8PMMw==",
+      "version": "5.2.5",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.5.tgz",
+      "integrity": "sha512-bH6QQacvSRtLX0lycAOs43S173n+lfXxB5cx4FjVkTLw5tAEwk5bxNLbkt5K1iETd5KxazRx70GpqOxsuwKiFA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "camelcase": "^6.2.0",
         "icss-utils": "^5.1.0",
         "loader-utils": "^2.0.0",
-        "postcss": "^8.2.10",
+        "postcss": "^8.2.15",
         "postcss-modules-extract-imports": "^3.0.0",
         "postcss-modules-local-by-default": "^4.0.0",
         "postcss-modules-scope": "^3.0.0",
@@ -2901,15 +2896,15 @@
       }
     },
     "node_modules/css-loader/node_modules/postcss": {
-      "version": "8.2.14",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.14.tgz",
-      "integrity": "sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w==",
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz",
+      "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "colorette": "^1.2.2",
-        "nanoid": "^3.1.22",
-        "source-map": "^0.6.1"
+        "nanoid": "^3.1.23",
+        "source-map-js": "^0.6.2"
       },
       "engines": {
         "node": "^10 || ^12 || >=14"
@@ -3576,9 +3571,9 @@
       "dev": true
     },
     "node_modules/detect-node": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz",
-      "integrity": "sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
+      "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
       "dev": true
     },
     "node_modules/diffie-hellman": {
@@ -3809,9 +3804,9 @@
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.3.727",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz",
-      "integrity": "sha512-Mfz4FIB4FSvEwBpDfdipRIrwd6uo8gUDoRDF4QEYb4h4tSuI3ov594OrjU6on042UlFHouIJpClDODGkPcBSbg==",
+      "version": "1.3.736",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz",
+      "integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig==",
       "dev": true
     },
     "node_modules/elliptic": {
@@ -8290,9 +8285,9 @@
       "dev": true
     },
     "node_modules/node-releases": {
-      "version": "1.1.71",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz",
-      "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==",
+      "version": "1.1.72",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz",
+      "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==",
       "dev": true
     },
     "node_modules/normalize-package-data": {
@@ -9099,9 +9094,9 @@
       "dev": true
     },
     "node_modules/picomatch": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
-      "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+      "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
       "dev": true,
       "engines": {
         "node": ">=8.6"
@@ -9822,9 +9817,9 @@
       "dev": true
     },
     "node_modules/postcss-selector-parser": {
-      "version": "6.0.5",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.5.tgz",
-      "integrity": "sha512-aFYPoYmXbZ1V6HZaSvat08M97A8HqO6Pjz+PiNpw/DhuRrC72XWAdp3hL6wusDCN31sSmcZyMGa2hZEuX+Xfhg==",
+      "version": "6.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
+      "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
       "dev": true,
       "dependencies": {
         "cssesc": "^3.0.0",
@@ -10792,9 +10787,9 @@
       "dev": true
     },
     "node_modules/sass": {
-      "version": "1.32.12",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz",
-      "integrity": "sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==",
+      "version": "1.34.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.0.tgz",
+      "integrity": "sha512-rHEN0BscqjUYuomUEaqq3BMgsXqQfkcMVR7UhscsAVub0/spUrZGBMxQXFS2kfiDsPLZw5yuU9iJEFNC2x38Qw==",
       "dev": true,
       "dependencies": {
         "chokidar": ">=3.0.0 <4.0.0"
@@ -11540,6 +11535,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/source-map-js": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
+      "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/source-map-resolve": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -11596,9 +11601,9 @@
       }
     },
     "node_modules/spdx-license-ids": {
-      "version": "3.0.7",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
-      "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz",
+      "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==",
       "dev": true
     },
     "node_modules/spdy": {
@@ -13096,9 +13101,9 @@
       "dev": true
     },
     "node_modules/vue-loader": {
-      "version": "15.9.6",
-      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz",
-      "integrity": "sha512-j0cqiLzwbeImIC6nVIby2o/ABAWhlppyL/m5oJ67R5MloP0hj/DtFgb0Zmq3J9CG7AJ+AXIvHVnJAPBvrLyuDg==",
+      "version": "15.9.7",
+      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.7.tgz",
+      "integrity": "sha512-qzlsbLV1HKEMf19IqCJqdNvFJRCI58WNbS6XbPqK13MrLz65es75w392MSQ5TsARAfIjUw+ATm3vlCXUJSOH9Q==",
       "dev": true,
       "dependencies": {
         "@vue/component-compiler-utils": "^3.1.0",
@@ -13645,15 +13650,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/webpack-dev-server/node_modules/camelcase": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/webpack-dev-server/node_modules/chokidar": {
       "version": "2.1.8",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@@ -14499,12 +14495,12 @@
       }
     },
     "@babel/generator": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.1.tgz",
-      "integrity": "sha512-TMGhsXMXCP/O1WtQmZjpEYDhCYC9vFhayWZPJSZCGkPJgUqX0rF0wwtrYvnzVxIjcF80tkUertXVk5cwqi5cAQ==",
+      "version": "7.14.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz",
+      "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.14.1",
+        "@babel/types": "^7.14.2",
         "jsesc": "^2.5.1",
         "source-map": "^0.5.0"
       },
@@ -14518,14 +14514,14 @@
       }
     },
     "@babel/helper-function-name": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz",
-      "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==",
+      "version": "7.14.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz",
+      "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==",
       "dev": true,
       "requires": {
         "@babel/helper-get-function-arity": "^7.12.13",
         "@babel/template": "^7.12.13",
-        "@babel/types": "^7.12.13"
+        "@babel/types": "^7.14.2"
       }
     },
     "@babel/helper-get-function-arity": {
@@ -14564,9 +14560,9 @@
       }
     },
     "@babel/parser": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.1.tgz",
-      "integrity": "sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q==",
+      "version": "7.14.3",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz",
+      "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==",
       "dev": true
     },
     "@babel/template": {
@@ -14581,25 +14577,25 @@
       }
     },
     "@babel/traverse": {
-      "version": "7.14.0",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.0.tgz",
-      "integrity": "sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA==",
+      "version": "7.14.2",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz",
+      "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.12.13",
-        "@babel/generator": "^7.14.0",
-        "@babel/helper-function-name": "^7.12.13",
+        "@babel/generator": "^7.14.2",
+        "@babel/helper-function-name": "^7.14.2",
         "@babel/helper-split-export-declaration": "^7.12.13",
-        "@babel/parser": "^7.14.0",
-        "@babel/types": "^7.14.0",
+        "@babel/parser": "^7.14.2",
+        "@babel/types": "^7.14.2",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       }
     },
     "@babel/types": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.1.tgz",
-      "integrity": "sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA==",
+      "version": "7.14.2",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz",
+      "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==",
       "dev": true,
       "requires": {
         "@babel/helper-validator-identifier": "^7.14.0",
@@ -14707,9 +14703,9 @@
       "dev": true
     },
     "@types/node": {
-      "version": "15.0.2",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz",
-      "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==",
+      "version": "15.6.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.0.tgz",
+      "integrity": "sha512-gCYSfQpy+LYhOFTKAeE8BkyGqaxmlFxe+n4DKM6DR0wzw/HISUE/hAmkC/KT8Sw5PCJblqg062b3z9gucv3k0A==",
       "dev": true
     },
     "@types/normalize-package-data": {
@@ -16043,11 +16039,10 @@
       }
     },
     "camelcase": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
-      "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
-      "dev": true,
-      "peer": true
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true
     },
     "caniuse-api": {
       "version": "3.0.0",
@@ -16835,16 +16830,15 @@
       }
     },
     "css-loader": {
-      "version": "5.2.4",
-      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.4.tgz",
-      "integrity": "sha512-OFYGyINCKkdQsTrSYxzGSFnGS4gNjcXkKkQgWxK138jgnPt+lepxdjSZNc8sHAl5vP3DhsJUxufWIjOwI8PMMw==",
+      "version": "5.2.5",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.5.tgz",
+      "integrity": "sha512-bH6QQacvSRtLX0lycAOs43S173n+lfXxB5cx4FjVkTLw5tAEwk5bxNLbkt5K1iETd5KxazRx70GpqOxsuwKiFA==",
       "dev": true,
       "peer": true,
       "requires": {
-        "camelcase": "^6.2.0",
         "icss-utils": "^5.1.0",
         "loader-utils": "^2.0.0",
-        "postcss": "^8.2.10",
+        "postcss": "^8.2.15",
         "postcss-modules-extract-imports": "^3.0.0",
         "postcss-modules-local-by-default": "^4.0.0",
         "postcss-modules-scope": "^3.0.0",
@@ -16895,15 +16889,15 @@
           }
         },
         "postcss": {
-          "version": "8.2.14",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.14.tgz",
-          "integrity": "sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w==",
+          "version": "8.3.0",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz",
+          "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==",
           "dev": true,
           "peer": true,
           "requires": {
             "colorette": "^1.2.2",
-            "nanoid": "^3.1.22",
-            "source-map": "^0.6.1"
+            "nanoid": "^3.1.23",
+            "source-map-js": "^0.6.2"
           }
         },
         "postcss-modules-extract-imports": {
@@ -17412,9 +17406,9 @@
       "dev": true
     },
     "detect-node": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz",
-      "integrity": "sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
+      "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
       "dev": true
     },
     "diffie-hellman": {
@@ -17619,9 +17613,9 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.727",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz",
-      "integrity": "sha512-Mfz4FIB4FSvEwBpDfdipRIrwd6uo8gUDoRDF4QEYb4h4tSuI3ov594OrjU6on042UlFHouIJpClDODGkPcBSbg==",
+      "version": "1.3.736",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz",
+      "integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig==",
       "dev": true
     },
     "elliptic": {
@@ -21137,9 +21131,9 @@
       }
     },
     "node-releases": {
-      "version": "1.1.71",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz",
-      "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==",
+      "version": "1.1.72",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz",
+      "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==",
       "dev": true
     },
     "normalize-package-data": {
@@ -21778,9 +21772,9 @@
       "dev": true
     },
     "picomatch": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
-      "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+      "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
       "dev": true
     },
     "pify": {
@@ -22424,9 +22418,9 @@
       }
     },
     "postcss-selector-parser": {
-      "version": "6.0.5",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.5.tgz",
-      "integrity": "sha512-aFYPoYmXbZ1V6HZaSvat08M97A8HqO6Pjz+PiNpw/DhuRrC72XWAdp3hL6wusDCN31sSmcZyMGa2hZEuX+Xfhg==",
+      "version": "6.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
+      "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
       "dev": true,
       "requires": {
         "cssesc": "^3.0.0",
@@ -23221,9 +23215,9 @@
       "dev": true
     },
     "sass": {
-      "version": "1.32.12",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz",
-      "integrity": "sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==",
+      "version": "1.34.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.0.tgz",
+      "integrity": "sha512-rHEN0BscqjUYuomUEaqq3BMgsXqQfkcMVR7UhscsAVub0/spUrZGBMxQXFS2kfiDsPLZw5yuU9iJEFNC2x38Qw==",
       "dev": true,
       "requires": {
         "chokidar": ">=3.0.0 <4.0.0"
@@ -23832,6 +23826,13 @@
       "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
       "dev": true
     },
+    "source-map-js": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
+      "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
+      "dev": true,
+      "peer": true
+    },
     "source-map-resolve": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -23888,9 +23889,9 @@
       }
     },
     "spdx-license-ids": {
-      "version": "3.0.7",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
-      "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz",
+      "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==",
       "dev": true
     },
     "spdy": {
@@ -25113,9 +25114,9 @@
       "dev": true
     },
     "vue-loader": {
-      "version": "15.9.6",
-      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz",
-      "integrity": "sha512-j0cqiLzwbeImIC6nVIby2o/ABAWhlppyL/m5oJ67R5MloP0hj/DtFgb0Zmq3J9CG7AJ+AXIvHVnJAPBvrLyuDg==",
+      "version": "15.9.7",
+      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.7.tgz",
+      "integrity": "sha512-qzlsbLV1HKEMf19IqCJqdNvFJRCI58WNbS6XbPqK13MrLz65es75w392MSQ5TsARAfIjUw+ATm3vlCXUJSOH9Q==",
       "dev": true,
       "requires": {
         "@vue/component-compiler-utils": "^3.1.0",
@@ -25564,12 +25565,6 @@
             "to-regex": "^3.0.1"
           }
         },
-        "camelcase": {
-          "version": "5.3.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-          "dev": true
-        },
         "chokidar": {
           "version": "2.1.8",
           "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue
index 6e9768af..c3f21198 100644
--- a/client/src/views/Game.vue
+++ b/client/src/views/Game.vue
@@ -236,7 +236,8 @@ export default {
       // If newmove got no pingback, send again:
       opponentGotMove: false,
       connexionString: "",
-      socketCloseListener: 0,
+      reopenTimeout: 0,
+      reconnectTimeout: 0,
       // Incomplete info games: show move played
       moveNotation: "",
       // Intervals from setInterval():
@@ -289,14 +290,13 @@ export default {
   },
   methods: {
     cleanBeforeDestroy: function() {
-      clearInterval(this.socketCloseListener);
       document.removeEventListener('visibilitychange', this.visibilityChange);
       window.removeEventListener('focus', this.onFocus);
       window.removeEventListener('blur', this.onBlur);
       if (!!this.askLastate) clearInterval(this.askLastate);
       if (!!this.retrySendmove) clearInterval(this.retrySendmove);
       if (!!this.clockUpdate) clearInterval(this.clockUpdate);
-      this.conn.removeEventListener("message", this.socketMessageListener);
+      clearTimeout(this.reopenTimeout);
       this.send("disconnect");
       this.conn = null;
     },
@@ -374,7 +374,7 @@ export default {
           id: my.id,
           name: my.name,
           tmpIds: {
-            tmpId: { focus: true }
+            [tmpId]: { focus: true }
           }
         }
       );
@@ -409,30 +409,41 @@ export default {
         "&page=" +
         // Discard potential "/?next=[...]" for page indication:
         encodeURIComponent(this.$route.path.match(/\/game\/[a-zA-Z0-9]+/)[0]);
+      openConnection();
+    },
+    openConnection: function() {
       this.conn = new WebSocket(this.connexionString);
-      this.conn.addEventListener("message", this.socketMessageListener);
-      this.socketCloseListener = setInterval(
-        () => {
-          if (this.conn.readyState == 3) {
-            this.conn.removeEventListener(
-              "message", this.socketMessageListener);
-            this.conn = new WebSocket(this.connexionString);
-            this.conn.addEventListener("message", this.socketMessageListener);
-            const oppSid = this.getOppsid();
-            if (!!oppSid) this.requestLastate(oppSid); //in case of
-          }
-        },
-        1000
-      );
+      const onOpen = () => {
+        this.reconnectTimeout = 250;
+        const oppSid = this.getOppsid();
+        if (!!oppSid) this.requestLastate(oppSid); //in case of
+      };
+      this.conn.onopen = onOpen;
+      this.conn.onmessage = this.socketMessageListener;
+      const closeConnection = () => {
+        this.reopenTimeout = setTimeout(
+          () => {
+            this.openConnection();
+            this.reconnectTimeout = Math.min(2*this.reconnectTimeout, 30000);
+          },
+          this.reconnectTimeout
+        );
+      };
+      this.conn.onerror = closeConnection;
+      this.conn.onclose = closeConnection;
       // Socket init required before loading remote game:
       const socketInit = callback => {
         if (this.conn.readyState == 1)
           // 1 == OPEN state
           callback();
-        else
+        else {
           // Socket not ready yet (initial loading)
           // NOTE: first arg is Websocket object, unused here:
-          this.conn.onopen = () => callback();
+          this.conn.onopen = () => {
+            onOpen();
+            callback();
+          };
+        }
       };
       this.fetchGame((game) => {
         if (!!game) {
diff --git a/client/src/views/Hall.vue b/client/src/views/Hall.vue
index b7199a7b..4f27f794 100644
--- a/client/src/views/Hall.vue
+++ b/client/src/views/Hall.vue
@@ -282,7 +282,8 @@ export default {
       presetChalls: JSON.parse(localStorage.getItem("presetChalls") || "[]"),
       conn: null,
       connexionString: "",
-      socketCloseListener: 0,
+      reopenTimeout: 0,
+      reconnectTimeout: 0,
       // Related to (killing of) self multi-connects:
       newConnect: {}
     };
@@ -317,39 +318,35 @@ export default {
         id: my.id,
         name: my.name,
         tmpIds: {
-          tmpId: { page: "/", focus: true }
+          [tmpId]: { page: "/", focus: true }
         }
       }
     );
-    const connectAndPoll = () => {
-      this.send("connect");
-      this.send("pollclientsandgamers");
-      if (!!this.$route.query["challenge"]) {
-        // Automatic challenge sending, for tournaments
-        this.loadNewchallVariant(
-          () => {
-            Object.assign(
-              this.newchallenge,
-              {
-                fen: "",
-                vid:
-                  this.st.variants
-                  .find(v => v.name == this.$route.query["variant"])
-                  .id,
-                to: this.$route.query["challenge"],
-                color: this.$route.query["color"] || '',
-                cadence: this.$route.query["cadence"],
-                options: {},
-                memorize: false
-              }
-            );
-            window.doClick("modalNewgame");
-          },
-          this.$route.query["variant"]
-        );
-      }
-    };
-    // Initialize connection
+    if (!!this.$route.query["challenge"]) {
+      // Automatic challenge sending, for tournaments
+      this.loadNewchallVariant(
+        () => {
+          Object.assign(
+            this.newchallenge,
+            {
+              fen: "",
+              vid:
+                this.st.variants
+                .find(v => v.name == this.$route.query["variant"])
+                .id,
+              to: this.$route.query["challenge"],
+              color: this.$route.query["color"] || '',
+              cadence: this.$route.query["cadence"],
+              options: {},
+              memorize: false
+            }
+          );
+          window.doClick("modalNewgame");
+        },
+        this.$route.query["variant"]
+      );
+    }
+    // Connexion string won't change if disconnect/reconnect
     this.connexionString =
       params.socketUrl +
       "/?sid=" + this.st.user.sid +
@@ -358,19 +355,7 @@ export default {
       "&page=" +
       // Hall: path is "/" (TODO: could be hard-coded as well)
       encodeURIComponent(this.$route.path);
-    this.conn = new WebSocket(this.connexionString);
-    this.conn.onopen = connectAndPoll;
-    this.conn.addEventListener("message", this.socketMessageListener);
-    this.socketCloseListener = setInterval(
-      () => {
-        if (this.conn.readyState == 3) {
-          this.conn.removeEventListener("message", this.socketMessageListener);
-          this.conn = new WebSocket(this.connexionString);
-          this.conn.addEventListener("message", this.socketMessageListener);
-        }
-      },
-      1000
-    );
+    this.openConnection();
   },
   mounted: function() {
     document.getElementById("peopleWrap")
@@ -466,13 +451,36 @@ export default {
     this.cleanBeforeDestroy();
   },
   methods: {
+    openConnection: function() {
+      const connectAndPoll = () => {
+        this.send("connect");
+        this.send("pollclientsandgamers");
+      };
+      // Initialize connection
+      this.conn = new WebSocket(this.connexionString);
+      this.conn.onopen = () => {
+        this.reconnectTimeout = 250;
+        connectAndPoll();
+      };
+      this.conn.onmessage = this.socketMessageListener;
+      const closeConnection = () => {
+        this.reopenTimeout = setTimeout(
+          () => {
+            this.openConnection();
+            this.reconnectTimeout = Math.min(2*this.reconnectTimeout, 30000);
+          },
+          this.reconnectTimeout
+        );
+      };
+      this.conn.onerror = closeConnection;
+      this.conn.onclose = closeConnection;
+    },
     cleanBeforeDestroy: function() {
-      clearInterval(this.socketCloseListener);
       document.removeEventListener('visibilitychange', this.visibilityChange);
       window.removeEventListener('focus', this.onFocus);
       window.removeEventListener('blur', this.onBlur);
       window.removeEventListener("beforeunload", this.cleanBeforeDestroy);
-      this.conn.removeEventListener("message", this.socketMessageListener);
+      clearTimeout(this.reopenTimeout);
       this.send("disconnect");
       this.conn = null;
     },
diff --git a/client/src/views/MyGames.vue b/client/src/views/MyGames.vue
index d12fff48..ad330aec 100644
--- a/client/src/views/MyGames.vue
+++ b/client/src/views/MyGames.vue
@@ -78,7 +78,8 @@ export default {
       },
       conn: null,
       connexionString: "",
-      socketCloseListener: 0
+      reopenTimeout: 0,
+      reconnectTimeout: 0
     };
   },
   watch: {
@@ -96,7 +97,6 @@ export default {
   },
   created: function() {
     window.addEventListener("beforeunload", this.cleanBeforeDestroy);
-    // Initialize connection
     this.connexionString =
       params.socketUrl +
       "/?sid=" + this.st.user.sid +
@@ -104,19 +104,7 @@ export default {
       "&tmpId=" + getRandString() +
       "&page=" +
       encodeURIComponent(this.$route.path);
-    this.conn = new WebSocket(this.connexionString);
-    this.conn.onmessage = this.socketMessageListener;
-    this.socketCloseListener = setInterval(
-      () => {
-        if (this.conn.readyState == 3) {
-          // Connexion is closed: re-open
-          this.conn.removeEventListener("message", this.socketMessageListener);
-          this.conn = new WebSocket(this.connexionString);
-          this.conn.addEventListener("message", this.socketMessageListener);
-        }
-      },
-      1000
-    );
+    this.openConnection();
   },
   mounted: function() {
     const adjustAndSetDisplay = () => {
@@ -182,10 +170,26 @@ export default {
     this.cleanBeforeDestroy();
   },
   methods: {
+    openConnection: function() {
+      // Initialize connection
+      this.conn = new WebSocket(this.connexionString);
+      this.conn.onopen = () => { this.reconnectTimeout = 250; };
+      this.conn.onmessage = this.socketMessageListener;
+      const closeConnection = () => {
+        this.reopenTimeout = setTimeout(
+          () => {
+            this.openConnection();
+            this.reconnectTimeout = Math.min(2*this.reconnectTimeout, 30000);
+          },
+          this.reconnectTimeout
+        );
+      };
+      this.conn.onerror = closeConnection;
+      this.conn.onclose = closeConnection;
+    },
     cleanBeforeDestroy: function() {
-      clearInterval(this.socketCloseListener);
       window.removeEventListener("beforeunload", this.cleanBeforeDestroy);
-      this.conn.removeEventListener("message", this.socketMessageListener);
+      clearTimeout(this.reopenTimeout);
       this.conn.send(JSON.stringify({code: "disconnect"}));
       this.conn = null;
     },
diff --git a/server/sockets.js b/server/sockets.js
index c2b41e88..520b8b70 100644
--- a/server/sockets.js
+++ b/server/sockets.js
@@ -18,6 +18,12 @@ function send(socket, message) {
     socket.send(JSON.stringify(message));
 }
 
+// https://www.npmjs.com/package/ws - detect lost connections...
+function noop() {}
+function heartbeat() {
+  this.isAlive = true;
+}
+
 module.exports = function(wss) {
   // Associative array page --> sid --> tmpId --> socket
   // "page" is either "/" for hall or "/game/some_gid" for Game,
@@ -36,6 +42,8 @@ module.exports = function(wss) {
     });
   }
   wss.on("connection", (socket, req) => {
+    socket.isAlive = true;
+    socket.on('pong', heartbeat);
     const query = getJsonFromUrl(req.url);
     const sid = query["sid"];
     const id = query["id"];
@@ -368,4 +376,15 @@ module.exports = function(wss) {
     socket.on("message", messageListener);
     socket.on("close", closeListener);
   });
+  const interval = setInterval(
+    () => {
+      wss.clients.forEach(ws => {
+        if (ws.isAlive === false) return ws.terminate();
+        ws.isAlive = false;
+        ws.ping(noop);
+      });
+    },
+    30000
+  );
+  wss.on('close', () => clearInterval(interval));
 }
-- 
2.44.0