diff --git a/client/package-lock.json b/client/package-lock.json index 296828d..5d65687 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -6,7 +6,7 @@ "": { "dependencies": { "@hathora/client-sdk": "^1.0.0", - "@hathora/cloud-sdk-typescript": "^2.2.8", + "@hathora/cloud-sdk-typescript": "^2.3.0", "@heroicons/react": "^2.0.17", "@react-oauth/google": "^0.10.0", "dayjs": "^1.11.7", @@ -2055,18 +2055,18 @@ } }, "node_modules/@hathora/client-sdk": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@hathora/client-sdk/-/client-sdk-1.0.0.tgz", - "integrity": "sha512-/WVolBvARssfXYdA3NXssQoA2O17xPpiu5/j12+/fdnD+S3LjlRRNYi4QGdltFWbUYechHtB2hT7MzBT6pgHKQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@hathora/client-sdk/-/client-sdk-1.3.1.tgz", + "integrity": "sha512-RGZ+tgJL/RbkikcNMMcNLNIE+gfdTOoN4qHOhjDQuW7O641mRhj+AElW3I0wlFsEDzLXbkMV+zcPkN/QDtS5LA==", "dependencies": { "isomorphic-ws": "^5.0.0", "jwt-decode": "^3.1.2" } }, "node_modules/@hathora/cloud-sdk-typescript": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.8.tgz", - "integrity": "sha512-RyCwTAQ2t6nWiiajKJKbp4IrAulXEXeRQVaaRDA2V/iVt+Vilg7iLGQNqrEBgoUcZIY07VR5Ew/RNYjpiHdiUA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.3.0.tgz", + "integrity": "sha512-lfcd0f23xTk5vKFuX1/YnPcgAVSoccF1ZyxeutQ52vKn5mt7gCE9ljHDAZaC8mXDJMz0LLFnlt/raRi/g0kZJA==", "peerDependencies": { "zod": ">= 3" } @@ -8041,16 +8041,16 @@ "dev": true }, "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "peer": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -9504,18 +9504,18 @@ "dev": true }, "@hathora/client-sdk": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@hathora/client-sdk/-/client-sdk-1.0.0.tgz", - "integrity": "sha512-/WVolBvARssfXYdA3NXssQoA2O17xPpiu5/j12+/fdnD+S3LjlRRNYi4QGdltFWbUYechHtB2hT7MzBT6pgHKQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@hathora/client-sdk/-/client-sdk-1.3.1.tgz", + "integrity": "sha512-RGZ+tgJL/RbkikcNMMcNLNIE+gfdTOoN4qHOhjDQuW7O641mRhj+AElW3I0wlFsEDzLXbkMV+zcPkN/QDtS5LA==", "requires": { "isomorphic-ws": "^5.0.0", "jwt-decode": "^3.1.2" } }, "@hathora/cloud-sdk-typescript": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.8.tgz", - "integrity": "sha512-RyCwTAQ2t6nWiiajKJKbp4IrAulXEXeRQVaaRDA2V/iVt+Vilg7iLGQNqrEBgoUcZIY07VR5Ew/RNYjpiHdiUA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.3.0.tgz", + "integrity": "sha512-lfcd0f23xTk5vKFuX1/YnPcgAVSoccF1ZyxeutQ52vKn5mt7gCE9ljHDAZaC8mXDJMz0LLFnlt/raRi/g0kZJA==", "requires": {} }, "@heroicons/react": { @@ -13800,9 +13800,9 @@ "dev": true }, "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "peer": true, "requires": {} }, diff --git a/client/package.json b/client/package.json index 9ccc107..3633ba8 100644 --- a/client/package.json +++ b/client/package.json @@ -7,7 +7,7 @@ }, "dependencies": { "@hathora/client-sdk": "^1.0.0", - "@hathora/cloud-sdk-typescript": "^2.2.8", + "@hathora/cloud-sdk-typescript": "^2.3.0", "@heroicons/react": "^2.0.17", "@react-oauth/google": "^0.10.0", "dayjs": "^1.11.7", diff --git a/client/src/app.tsx b/client/src/app.tsx index 6633b58..8044d82 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -61,7 +61,7 @@ function App() { const connect = new HathoraConnection(roomIdFromUrl, connectionInfo); connect.onClose(async () => { // If game has ended, we want updated lobby state - const updatedLobbyInfo = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomIdFromUrl); + const updatedLobbyInfo = await hathoraSdk.lobbiesV3.getLobbyInfoByRoomId(roomIdFromUrl); const updatedRoomConfig = JSON.parse(updatedLobbyInfo.roomConfig ?? "") as RoomConfig; setSessionMetadata({ serverUrl: `${connectionInfo.host}:${connectionInfo.port}`, @@ -72,7 +72,7 @@ function App() { isGameEnd: updatedRoomConfig.isGameEnd, winningPlayerId: updatedRoomConfig.winningPlayerId, playerNicknameMap: updatedRoomConfig.playerNicknameMap, - creatorId: updatedLobbyInfo.createdBy, + creatorId: updatedLobbyInfo.createdBy + "", }); setFailedToConnect(true); }); @@ -87,7 +87,7 @@ function App() { isGameEnd: roomConfig.isGameEnd, winningPlayerId: roomConfig.winningPlayerId, playerNicknameMap: roomConfig.playerNicknameMap, - creatorId: lobbyInfo.createdBy, + creatorId: lobbyInfo.createdBy + "", }); } catch (e) { setRoomIdNotFound(roomIdFromUrl); diff --git a/client/src/components/lobby/GameCreator.tsx b/client/src/components/lobby/GameCreator.tsx index f94af0d..da2ba85 100644 --- a/client/src/components/lobby/GameCreator.tsx +++ b/client/src/components/lobby/GameCreator.tsx @@ -83,13 +83,13 @@ export function GameCreator(props: GameCreatorProps) { playerNicknameMap: {}, isGameEnd: false, }; - const lobbyV3 = await hathoraSdk.lobbyV3.createLobby( + const lobbyV3 = await hathoraSdk.lobbiesV3.createLobby( { playerAuth: playerToken.value }, { region, visibility: visibility as LobbyVisibility, roomConfig: JSON.stringify(roomConfig), - } + }, ); // Wait until lobby connection details are ready before redirect player to match await isReadyForConnect(appId, lobbyV3.roomId, hathoraSdk); diff --git a/client/src/components/lobby/PublicLobbyList.tsx b/client/src/components/lobby/PublicLobbyList.tsx index 1f04f22..42d1fd7 100644 --- a/client/src/components/lobby/PublicLobbyList.tsx +++ b/client/src/components/lobby/PublicLobbyList.tsx @@ -6,7 +6,7 @@ import dayjs from "dayjs"; dayjs.extend(relativeTime); import { ClockIcon, TrophyIcon, UserIcon, UsersIcon } from "@heroicons/react/24/outline"; -import { LobbyV3, Region } from "@hathora/cloud-sdk-typescript/dist/sdk/models/shared"; +import { LobbyV3, Region } from "@hathora/cloud-sdk-typescript/models/components"; import { getHathoraSdk, isReadyForConnect } from "../../utils"; import { RoomConfig } from "../../../../common/types"; @@ -25,9 +25,9 @@ export function PublicLobbyList(props: PublicLobbyListProps) { const [readyRooms, setReadyRooms] = React.useState>(new Set()); useEffect(() => { - lobbies.forEach(async (l) => { + lobbies.forEach(async (lobby) => { // Ensure that lobby is ready for connections before adding to visible lobby list - await isReadyForConnect(appId, l.roomId, hathoraSdk); + await isReadyForConnect(appId, lobby.roomId, hathoraSdk); setReadyRooms((prev) => { return new Set([...prev, l.roomId]); }); @@ -54,10 +54,10 @@ export function PublicLobbyList(props: PublicLobbyListProps) { > {lobbies.length > 0 ? ( lobbies - .filter((l) => readyRooms.has(l.roomId)) + .filter((lobby) => readyRooms.has(lobby.roomId)) .sort((a, b) => (new Date(b.createdAt).getTime() || 0) - (new Date(a.createdAt).getTime() || 0)) .map((lobby, index) => { - const roomConfig = JSON.parse(lobby.roomConfig) as RoomConfig; + const roomConfig = JSON.parse(lobby.roomConfig ?? "{}") as RoomConfig; return ( {`${dayjs( - lobby.createdAt + lobby.createdAt, ).fromNow()}`}
@@ -148,18 +148,18 @@ function useLobbies(appId: string): LobbyV3[] { const [lobbies, setLobbies] = React.useState([]); React.useEffect(() => { if (appId) { - hathoraSdk.lobbyV3.listActivePublicLobbies().then(({ classes }) => { - if (classes != null) { - setLobbies(classes); + hathoraSdk.lobbiesV3.listActivePublicLobbies().then((lobbies) => { + if (lobbies != null) { + setLobbies(lobbies); } }); } }, [appId]); useInterval(() => { if (appId) { - hathoraSdk.lobbyV3.listActivePublicLobbies().then(({ classes }) => { - if (classes != null) { - setLobbies(classes); + hathoraSdk.lobbiesV3.listActivePublicLobbies().then((lobbies) => { + if (lobbies != null) { + setLobbies(lobbies); } }); } @@ -178,4 +178,6 @@ export const FLAG_TABLE: Record = { Sydney: "πŸ‡¦πŸ‡Ί", Washington_DC: "πŸ‡ΊπŸ‡Έ", Sao_Paulo: "πŸ‡§πŸ‡·", + Dallas: "πŸ‡ΊπŸ‡Έ", + Los_Angeles: "πŸ‡ΊπŸ‡Έ", }; diff --git a/client/src/components/website/ExplanationText.tsx b/client/src/components/website/ExplanationText.tsx index 3c99f1b..6fb9551 100644 --- a/client/src/components/website/ExplanationText.tsx +++ b/client/src/components/website/ExplanationText.tsx @@ -293,7 +293,7 @@ const hathoraSdk = new HathoraCloud({ appId: env_variable.HATHORA_APP_ID });`}

Authenticated players (via client) can create lobbies

- {`const { lobbyV3 } = await hathoraSdk.lobbyV3.createLobby( + {`const { lobbyV3 } = await hathoraSdk.lobbiesV3.createLobby( { createLobbyV3Params: { region: Region.Seattle, @@ -328,7 +328,7 @@ const hathoraSdk = new HathoraCloud({ appId: env_variable.HATHORA_APP_ID }); playerNicknameMap: {}, isGameEnd: false, }; - const { lobbyV3 } = await hathoraSdk.lobbyV3.createLobby( + const { lobbyV3 } = await hathoraSdk.lobbiesV3.createLobby( { createLobbyV3Params: { region, @@ -390,7 +390,7 @@ const hathoraSdk = new HathoraCloud({ appId: env_variable.HATHORA_APP_ID }); {`import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; const hathoraSdk = new HathoraCloud({ appId: env_variable.HATHORA_APP_ID }); -const publicLobbies = hathoraSdk.lobbyV3.listActivePublicLobbies();`} +const publicLobbies = hathoraSdk.lobbiesV3.listActivePublicLobbies();`}
{`import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; @@ -400,18 +400,18 @@ function useLobbies(appId: string): LobbyV3[] { const [lobbies, setLobbies] = React.useState([]); React.useEffect(() => { if (appId) { - hathoraSdk.lobbyV3.listActivePublicLobbies().then(({ classes }) => { - if (classes != null) { - setLobbies(classes); + hathoraSdk.lobbiesV3.listActivePublicLobbies().then((lobbies) => { + if (lobbies != null) { + setLobbies(lobbies); } }); } }, [appId]); useInterval(() => { if (appId) { - hathoraSdk.lobbyV3.listActivePublicLobbies().then(({ classes }) => { - if (classes != null) { - setLobbies(classes); + hathoraSdk.lobbiesV3.listActivePublicLobbies().then((lobbies) => { + if (lobbies != null) { + setLobbies(lobbies); } }); } @@ -477,12 +477,12 @@ const hathoraSdk = new HathoraCloud({ appId: env_variable.HATHORA_APP_ID });`}

{`// This step is only needed if you want to validate RoomConfig before connecting a player -const lobbyInfo = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomId); +const lobbyInfo = await hathoraSdk.lobbiesV3.getLobbyInfoByRoomId(roomId); // lobbyInfo will contain details like region and roomConfig`}

Get connection info (host and port) to route your player

- {`const { connectionInfoV2 } = await hathoraSdk.roomV2.getConnectionInfo(roomId); + {`const { connectionInfoV2 } = await hathoraSdk.roomsV2.getConnectionInfo(roomId); // Use your network transport of choice (using Hathora BuildKits here) import { HathoraConnection } from "@hathora/client-sdk"; @@ -515,7 +515,7 @@ if ( roomIdFromUrl != null ) { const connect = new HathoraConnection(roomIdFromUrl, connectionInfo); connect.onClose(async () => { // If game has ended, we want updated lobby info - const updatedLobbyInfo = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomIdFromUrl); + const updatedLobbyInfo = await hathoraSdk.lobbiesV3.getLobbyInfoByRoomId(roomIdFromUrl); const updatedRoomConfig = JSON.parse(updatedLobbyInfo.roomConfig) as RoomConfig | undefined; setFailedToConnect(true); }); @@ -541,10 +541,10 @@ if ( roomIdFromUrl != null ) { const MAX_CONNECT_ATTEMPTS = 50; const TRY_CONNECT_INTERVAL_MS = 1000; - const lobbyInfo = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomIdFromUrl); + const lobbyInfo = await hathoraSdk.lobbiesV3.getLobbyInfoByRoomId(roomIdFromUrl); for (let i = 0; i < MAX_CONNECT_ATTEMPTS; i++) { - const res = await hathoraSdk.roomV2.getConnectionInfo(roomId); + const res = await hathoraSdk.roomsV2.getConnectionInfo(roomId); if (res.connectionInfoV2?.status === ConnectionInfoV2Status.Active) { return { lobbyInfo, connectionInfo: res.connectionInfoV2 }; } @@ -563,7 +563,7 @@ const hathoraSdk = new HathoraCloud({ appId: env_variable.HATHORA_APP_ID }); async subscribeUser(roomId: RoomId, userId: string): Promise { console.log("subscribeUser", roomId, userId); try { - const lobbyInfo = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomId); + const lobbyInfo = await hathoraSdk.lobbiesV3.getLobbyInfoByRoomId(roomId); const roomConfig = JSON.parse(lobbyInfo.roomConfig) as RoomConfig | undefined; if (!rooms.has(roomId)) { @@ -642,7 +642,7 @@ const hathoraSdk = new HathoraCloud({ // RoomConfig is meant to hold custom objects let myCustomRoomConfig = { isGameEnd: true, winningPlayerId: myGameData.winningPlayerId,} -const res = await hathoraSdk.roomV2.updateRoomConfig({ +const res = await hathoraSdk.roomsV2.updateRoomConfig({ roomConfig: JSON.stringify(myCustomRoomConfig) }, roomId);`}
@@ -662,7 +662,7 @@ async function updateRoomConfig(game: InternalState, roomId: string) { isGameEnd: game.isGameEnd, winningPlayerId: game.winningPlayerId, }; - return await hathoraSdk.roomV2.updateRoomConfig({ roomConfig: JSON.stringify(roomConfig) }, roomId); + return await hathoraSdk.roomsV2.updateRoomConfig({ roomConfig: JSON.stringify(roomConfig) }, roomId); }`} +const lobby = hathoraSdk.roomsV2.destroyRoom(roomId);`}
{`import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; @@ -722,7 +722,7 @@ async function endGameCleanup(roomId: string, game: InternalState, winningPlayer server.closeConnection(roomId, playerId, "game has ended, disconnecting players"); }); console.log("destroying room: ", roomId); - hathoraSdk.roomV2.destroyRoom(roomId); + hathoraSdk.roomsV2.destroyRoom(roomId); }, 10000); }`} { const MAX_CONNECT_ATTEMPTS = 50; const TRY_CONNECT_INTERVAL_MS = 1000; try { - const lobbyInfo = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomId); + const lobbyInfo = await hathoraSdk.lobbiesV3.getLobbyInfoByRoomId(roomId); if (lobbyInfo.visibility === "local") { return new Promise<{ lobbyInfo: LobbyV3; connectionInfo: ConnectionDetails }>((resolve) => - resolve({ lobbyInfo, connectionInfo: LOCAL_CONNECTION_DETAILS }) + resolve({ lobbyInfo, connectionInfo: LOCAL_CONNECTION_DETAILS }), ); } for (let i = 0; i < MAX_CONNECT_ATTEMPTS; i++) { - const connectionInfoV2 = await hathoraSdk.roomV2.getConnectionInfo(roomId); + const connectionInfoV2 = await hathoraSdk.roomsV2.getConnectionInfo(roomId); if (connectionInfoV2.exposedPort !== undefined) { - return { lobbyInfo, connectionInfo: connectionInfoV2.exposedPort }; + return { + lobbyInfo, + connectionInfo: { + ...connectionInfoV2.exposedPort, + transportType: isRecognized(TransportType, connectionInfoV2.exposedPort.transportType) + ? connectionInfoV2.exposedPort.transportType + : "tcp", + }, + }; } await new Promise((resolve) => setTimeout(resolve, TRY_CONNECT_INTERVAL_MS)); } @@ -60,3 +68,12 @@ export async function isReadyForConnect( export function getHathoraSdk(appId: string | undefined): HathoraCloud { return new HathoraCloud({ appId }); } + +function isRecognized(mapping: { [k: string]: U }, candidate: unknown): candidate is U { + for (const [, member] of Object.entries(mapping)) { + if (member === candidate) { + return true; + } + } + return false; +} diff --git a/common/package-lock.json b/common/package-lock.json index ec4857e..79e54ec 100644 --- a/common/package-lock.json +++ b/common/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@hathora/cloud-sdk-typescript": "^2.2.8" + "@hathora/cloud-sdk-typescript": "^2.3.0" }, "devDependencies": { "typescript": "^4.8.3" @@ -20,9 +20,9 @@ } }, "node_modules/@hathora/cloud-sdk-typescript": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.8.tgz", - "integrity": "sha512-RyCwTAQ2t6nWiiajKJKbp4IrAulXEXeRQVaaRDA2V/iVt+Vilg7iLGQNqrEBgoUcZIY07VR5Ew/RNYjpiHdiUA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.3.0.tgz", + "integrity": "sha512-lfcd0f23xTk5vKFuX1/YnPcgAVSoccF1ZyxeutQ52vKn5mt7gCE9ljHDAZaC8mXDJMz0LLFnlt/raRi/g0kZJA==", "peerDependencies": { "zod": ">= 3" } diff --git a/common/package.json b/common/package.json index c35cacc..b1f9a2d 100644 --- a/common/package.json +++ b/common/package.json @@ -1,7 +1,7 @@ { "type": "module", "dependencies": { - "@hathora/cloud-sdk-typescript": "^2.2.8" + "@hathora/cloud-sdk-typescript": "^2.3.0" }, "devDependencies": { "typescript": "^4.8.3" diff --git a/common/types.ts b/common/types.ts index 7dfb597..62d7549 100644 --- a/common/types.ts +++ b/common/types.ts @@ -1,4 +1,4 @@ -import {Region} from "@hathora/cloud-sdk-typescript/models/components"; +import { Region } from "@hathora/cloud-sdk-typescript/models/components"; export type Direction = { x: number; diff --git a/server/package-lock.json b/server/package-lock.json index 877d88f..4454190 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@hathora/cloud-sdk-typescript": "^2.2.8", + "@hathora/cloud-sdk-typescript": "^2.3.0", "@hathora/server-sdk": "^1.0.0", "detect-collisions": "^6.4.2", "dotenv": "^16.0.2" @@ -29,17 +29,17 @@ } }, "node_modules/@hathora/cloud-sdk-typescript": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.8.tgz", - "integrity": "sha512-RyCwTAQ2t6nWiiajKJKbp4IrAulXEXeRQVaaRDA2V/iVt+Vilg7iLGQNqrEBgoUcZIY07VR5Ew/RNYjpiHdiUA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.3.0.tgz", + "integrity": "sha512-lfcd0f23xTk5vKFuX1/YnPcgAVSoccF1ZyxeutQ52vKn5mt7gCE9ljHDAZaC8mXDJMz0LLFnlt/raRi/g0kZJA==", "peerDependencies": { "zod": ">= 3" } }, "node_modules/@hathora/server-sdk": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@hathora/server-sdk/-/server-sdk-1.0.0.tgz", - "integrity": "sha512-nR9FTJmpLzJt7HiLg0Wx4QKVdQJgsDaQxXUzp9ZLR9PuINS4QfkGZL5rdJU2aLZmTr9zgzwUCxMwk5MOYDeJiw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@hathora/server-sdk/-/server-sdk-1.1.0.tgz", + "integrity": "sha512-p8HbxomYvY2byAaepnKA7JRnt42t9TRBgFLEWS3Yo4YFmu3kDaYtU7er2mpftRcdd3/EoyzTypKDYeyVTEYJ6w==", "dependencies": { "jsonwebtoken": "^9.0.0", "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.19.0" @@ -186,14 +186,20 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "dependencies": { "jws": "^3.2.2", - "lodash": "^4.17.21", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { "node": ">=12", @@ -219,21 +225,40 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, "node_modules/make-error": { "version": "1.3.6", @@ -292,12 +317,9 @@ "integrity": "sha512-mxdv5RZJO4tdMnUURGU3gAMcnDUEwcNJwE+lPO0/V+rBeDvFLH3wEZEOR0fH7cTN0zQaNxBEbHnyQL9DzupwQQ==" }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -371,11 +393,6 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -406,15 +423,15 @@ } }, "@hathora/cloud-sdk-typescript": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.8.tgz", - "integrity": "sha512-RyCwTAQ2t6nWiiajKJKbp4IrAulXEXeRQVaaRDA2V/iVt+Vilg7iLGQNqrEBgoUcZIY07VR5Ew/RNYjpiHdiUA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.3.0.tgz", + "integrity": "sha512-lfcd0f23xTk5vKFuX1/YnPcgAVSoccF1ZyxeutQ52vKn5mt7gCE9ljHDAZaC8mXDJMz0LLFnlt/raRi/g0kZJA==", "requires": {} }, "@hathora/server-sdk": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@hathora/server-sdk/-/server-sdk-1.0.0.tgz", - "integrity": "sha512-nR9FTJmpLzJt7HiLg0Wx4QKVdQJgsDaQxXUzp9ZLR9PuINS4QfkGZL5rdJU2aLZmTr9zgzwUCxMwk5MOYDeJiw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@hathora/server-sdk/-/server-sdk-1.1.0.tgz", + "integrity": "sha512-p8HbxomYvY2byAaepnKA7JRnt42t9TRBgFLEWS3Yo4YFmu3kDaYtU7er2mpftRcdd3/EoyzTypKDYeyVTEYJ6w==", "requires": { "jsonwebtoken": "^9.0.0", "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.19.0" @@ -543,14 +560,20 @@ } }, "jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "requires": { "jws": "^3.2.2", - "lodash": "^4.17.21", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^7.3.8" + "semver": "^7.5.4" } }, "jwa": { @@ -572,18 +595,40 @@ "safe-buffer": "^5.0.1" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, "make-error": { "version": "1.3.6", @@ -625,12 +670,9 @@ "integrity": "sha512-mxdv5RZJO4tdMnUURGU3gAMcnDUEwcNJwE+lPO0/V+rBeDvFLH3wEZEOR0fH7cTN0zQaNxBEbHnyQL9DzupwQQ==" }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" }, "ts-node": { "version": "10.9.1", @@ -669,11 +711,6 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/server/package.json b/server/package.json index 8eee6cb..4d0a701 100644 --- a/server/package.json +++ b/server/package.json @@ -4,7 +4,7 @@ "start": "npx ts-node-esm --experimental-specifier-resolution=node server.ts" }, "dependencies": { - "@hathora/cloud-sdk-typescript": "^2.2.8", + "@hathora/cloud-sdk-typescript": "^2.3.0", "@hathora/server-sdk": "^1.0.0", "detect-collisions": "^6.4.2", "dotenv": "^16.0.2" diff --git a/server/server.ts b/server/server.ts index 7f44c6f..17a0a14 100644 --- a/server/server.ts +++ b/server/server.ts @@ -143,7 +143,7 @@ const rooms: Map = new Map(); // Create an object to represent our Store const store: Application = { - verifyToken(token: string): UserId | undefined { + async verifyToken(token: string): Promise { const userId = verifyJwt(token, process.env.HATHORA_APP_SECRET!); if (userId === undefined) { console.error("Failed to verify token", token); @@ -155,7 +155,7 @@ const store: Application = { async subscribeUser(roomId: RoomId, userId: string): Promise { console.log("subscribeUser", roomId, userId); try { - const roomInfo = await hathoraSdk.roomV2.getRoomInfo(roomId); + const roomInfo = await hathoraSdk.roomsV2.getRoomInfo(roomId); const roomConfig = JSON.parse(roomInfo.roomConfig!) as RoomConfig; if (!rooms.has(roomId)) { @@ -218,7 +218,7 @@ const store: Application = { }, // onMessage is an integral part of your game's server. It is responsible for reading messages sent from the clients and handling them accordingly, this is where your game's event-based logic should live - onMessage(roomId: RoomId, userId: string, data: ArrayBuffer): void { + async onMessage(roomId: RoomId, userId: string, data: ArrayBuffer): Promise { if (!rooms.has(roomId)) { return; } @@ -467,7 +467,7 @@ async function endGameCleanup(roomId: string, game: InternalState, winningPlayer server.closeConnection(roomId, playerId, "game has ended, disconnecting players"); }); console.log("destroying room: ", roomId); - hathoraSdk.roomV2.destroyRoom(roomId); + hathoraSdk.roomsV2.destroyRoom(roomId); }, 10000); } @@ -475,15 +475,17 @@ async function updateRoomConfig(game: InternalState, roomId: string, playerNewNi const roomConfig: RoomConfig = { capacity: 0, winningScore: game.winningScore, - playerNicknameMap: Object.fromEntries(game.players.map((player) => { - if (playerNewNickname && player.id == playerNewNickname.id) { - return [player.id, playerNewNickname.nickname ?? player.id]; - } else { - return [player.id, player.nickname ?? player.id]; - } - })), + playerNicknameMap: Object.fromEntries( + game.players.map((player) => { + if (playerNewNickname && player.id == playerNewNickname.id) { + return [player.id, playerNewNickname.nickname ?? player.id]; + } else { + return [player.id, player.nickname ?? player.id]; + } + }), + ), isGameEnd: game.isGameEnd, winningPlayerId: game.winningPlayerId, }; - return await hathoraSdk.roomV2.updateRoomConfig(roomId, { roomConfig: JSON.stringify(roomConfig) } ); + return await hathoraSdk.roomsV2.updateRoomConfig(roomId, { roomConfig: JSON.stringify(roomConfig) }); }