diff --git a/clients/solid/package.json b/clients/solid/package.json
index a3a425e..35bd636 100644
--- a/clients/solid/package.json
+++ b/clients/solid/package.json
@@ -27,6 +27,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"corvu": "^0.7.1",
+ "joi": "^17.13.3",
"solid-js": "^1.9.2",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7"
diff --git a/clients/solid/pnpm-lock.yaml b/clients/solid/pnpm-lock.yaml
index fb134bc..8af2b16 100644
--- a/clients/solid/pnpm-lock.yaml
+++ b/clients/solid/pnpm-lock.yaml
@@ -26,6 +26,9 @@ importers:
corvu:
specifier: ^0.7.1
version: 0.7.1(solid-js@1.9.2)
+ joi:
+ specifier: ^17.13.3
+ version: 17.13.3
solid-js:
specifier: ^1.9.2
version: 1.9.2
@@ -364,6 +367,12 @@ packages:
'@floating-ui/utils@0.2.8':
resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==}
+ '@hapi/hoek@9.3.0':
+ resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
+
+ '@hapi/topo@5.1.0':
+ resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+
'@internationalized/date@3.5.6':
resolution: {integrity: sha512-jLxQjefH9VI5P9UQuqB6qNKnvFt1Ky1TPIzHGsIlCi7sZZoMR8SdYbBGRvM0y+Jtb+ez4ieBzmiAUcpmPYpyOw==}
@@ -505,6 +514,15 @@ packages:
cpu: [x64]
os: [win32]
+ '@sideway/address@4.1.5':
+ resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
+
+ '@sideway/formula@3.0.1':
+ resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
+
+ '@sideway/pinpoint@2.0.0':
+ resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
+
'@sinclair/typebox@0.27.8':
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
@@ -713,8 +731,8 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- caniuse-lite@1.0.30001668:
- resolution: {integrity: sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==}
+ caniuse-lite@1.0.30001669:
+ resolution: {integrity: sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==}
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
@@ -798,8 +816,8 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- electron-to-chromium@1.5.38:
- resolution: {integrity: sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg==}
+ electron-to-chromium@1.5.39:
+ resolution: {integrity: sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -931,6 +949,9 @@ packages:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
+ joi@17.13.3:
+ resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1028,8 +1049,8 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
- picocolors@1.1.0:
- resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
@@ -1366,7 +1387,7 @@ snapshots:
'@babel/code-frame@7.25.7':
dependencies:
'@babel/highlight': 7.25.7
- picocolors: 1.1.0
+ picocolors: 1.1.1
'@babel/compat-data@7.25.8': {}
@@ -1451,7 +1472,7 @@ snapshots:
'@babel/helper-validator-identifier': 7.25.7
chalk: 2.4.2
js-tokens: 4.0.0
- picocolors: 1.1.0
+ picocolors: 1.1.1
'@babel/parser@7.25.8':
dependencies:
@@ -1640,6 +1661,12 @@ snapshots:
'@floating-ui/utils@0.2.8': {}
+ '@hapi/hoek@9.3.0': {}
+
+ '@hapi/topo@5.1.0':
+ dependencies:
+ '@hapi/hoek': 9.3.0
+
'@internationalized/date@3.5.6':
dependencies:
'@swc/helpers': 0.5.13
@@ -1766,6 +1793,14 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.24.0':
optional: true
+ '@sideway/address@4.1.5':
+ dependencies:
+ '@hapi/hoek': 9.3.0
+
+ '@sideway/formula@3.0.1': {}
+
+ '@sideway/pinpoint@2.0.0': {}
+
'@sinclair/typebox@0.27.8': {}
'@solid-devtools/debugger@0.23.4(solid-js@1.9.2)':
@@ -1965,10 +2000,10 @@ snapshots:
autoprefixer@10.4.20(postcss@8.4.47):
dependencies:
browserslist: 4.24.0
- caniuse-lite: 1.0.30001668
+ caniuse-lite: 1.0.30001669
fraction.js: 4.3.7
normalize-range: 0.1.2
- picocolors: 1.1.0
+ picocolors: 1.1.1
postcss: 8.4.47
postcss-value-parser: 4.2.0
@@ -2002,14 +2037,14 @@ snapshots:
browserslist@4.24.0:
dependencies:
- caniuse-lite: 1.0.30001668
- electron-to-chromium: 1.5.38
+ caniuse-lite: 1.0.30001669
+ electron-to-chromium: 1.5.39
node-releases: 2.0.18
update-browserslist-db: 1.1.1(browserslist@4.24.0)
camelcase-css@2.0.1: {}
- caniuse-lite@1.0.30001668: {}
+ caniuse-lite@1.0.30001669: {}
chalk@2.4.2:
dependencies:
@@ -2092,7 +2127,7 @@ snapshots:
eastasianwidth@0.2.0: {}
- electron-to-chromium@1.5.38: {}
+ electron-to-chromium@1.5.39: {}
emoji-regex@8.0.0: {}
@@ -2228,6 +2263,14 @@ snapshots:
jiti@1.21.6: {}
+ joi@17.13.3:
+ dependencies:
+ '@hapi/hoek': 9.3.0
+ '@hapi/topo': 5.1.0
+ '@sideway/address': 4.1.5
+ '@sideway/formula': 3.0.1
+ '@sideway/pinpoint': 2.0.0
+
js-tokens@4.0.0: {}
jsesc@3.0.2: {}
@@ -2298,7 +2341,7 @@ snapshots:
lru-cache: 10.4.3
minipass: 7.1.2
- picocolors@1.1.0: {}
+ picocolors@1.1.1: {}
picomatch@2.3.1: {}
@@ -2340,7 +2383,7 @@ snapshots:
postcss@8.4.47:
dependencies:
nanoid: 3.3.7
- picocolors: 1.1.0
+ picocolors: 1.1.1
source-map-js: 1.2.1
pretty-format@29.7.0:
@@ -2532,7 +2575,7 @@ snapshots:
micromatch: 4.0.8
normalize-path: 3.0.0
object-hash: 3.0.0
- picocolors: 1.1.0
+ picocolors: 1.1.1
postcss: 8.4.47
postcss-import: 15.1.0(postcss@8.4.47)
postcss-js: 4.0.1(postcss@8.4.47)
@@ -2570,7 +2613,7 @@ snapshots:
dependencies:
browserslist: 4.24.0
escalade: 3.2.0
- picocolors: 1.1.0
+ picocolors: 1.1.1
util-deprecate@1.0.2: {}
diff --git a/clients/solid/src/App.tsx b/clients/solid/src/App.tsx
index c56f39d..3389c59 100644
--- a/clients/solid/src/App.tsx
+++ b/clients/solid/src/App.tsx
@@ -10,6 +10,7 @@ import {
} from "@/components/ui/tabs";
import Home from "@/pages/Home";
import Footer from "@/components/Footer";
+import { Websocket } from "./components/Websocket";
const Browser = lazy(() => import("@/pages/Browser"));
const Game = lazy(() => import("@/pages/Game"));
@@ -25,6 +26,7 @@ export default function App(): JSXElement {
Cards For Humanity
+
Home
diff --git a/clients/solid/src/components/Websocket.tsx b/clients/solid/src/components/Websocket.tsx
new file mode 100644
index 0000000..d0330b7
--- /dev/null
+++ b/clients/solid/src/components/Websocket.tsx
@@ -0,0 +1,96 @@
+import Joi from "joi";
+import { JSXElement } from "solid-js";
+import { onCleanup } from "solid-js";
+
+export function Websocket(): JSXElement {
+ const UserUpdate = Joi.object({
+ username: Joi.string(),
+ });
+
+ const ChatMessage = Joi.object({
+ text: Joi.string(),
+ });
+
+ const ServerOnlineUsers = Joi.object({
+ online_users: Joi.number(),
+ });
+
+ const ServerActiveGames = Joi.object({
+ active_games: Joi.number(),
+ });
+
+ const ChatUpdate = Joi.object({
+ room: Joi.string(),
+ users: Joi.number(),
+ });
+
+ const GamesUpdate = Joi.object({
+ games: Joi.array(),
+ });
+
+ const CardPacksMeta = Joi.object({
+ official_meta: Joi.array(),
+ unofficial_meta: Joi.array(),
+ });
+
+ const socket = new WebSocket("ws://127.0.0.1:3030/websocket");
+
+ const handleMessage = (event: MessageEvent) => {
+ let json = JSON.parse(event.data);
+
+ // TODO: This is ridiculous but it works
+ try {
+ Joi.attempt(json, UserUpdate);
+ console.log("UserUpdate! Name is: ", json);
+ } catch {}
+
+ try {
+ Joi.attempt(json, ChatMessage);
+ console.log("Chat Message: ", json);
+ } catch {}
+
+ try {
+ Joi.attempt(json, ServerOnlineUsers);
+ console.log("Online Users: ", json);
+ } catch {}
+
+ try {
+ Joi.attempt(json, ServerActiveGames);
+ console.log("Active Games: ", json);
+ } catch {}
+
+ try {
+ Joi.attempt(json, ChatUpdate);
+ console.log("Chat Update: ", json);
+ } catch {}
+
+ try {
+ Joi.attempt(json, GamesUpdate);
+ console.log("GamesUpdate: ", json);
+ } catch {}
+
+ try {
+ Joi.attempt(json, CardPacksMeta);
+ console.log("Card Packs: ", json);
+ } catch {}
+ };
+ socket.addEventListener("message", handleMessage);
+
+ const handleClose = (event: CloseEvent) => {
+ console.log(
+ "The connection has been closed successfully.",
+ event.code,
+ event.reason,
+ );
+ };
+
+ socket.addEventListener("close", handleClose);
+
+ onCleanup(() => {
+ socket.removeEventListener("message", handleMessage);
+ socket.removeEventListener("close", handleClose);
+ socket.close();
+ });
+
+ return <>SockEt>;
+}