diff --git a/client/package-lock.json b/client/package-lock.json index 2b3534b..224c401 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -6,7 +6,7 @@ "": { "dependencies": { "@hathora/client-sdk": "^1.0.0", - "@hathora/hathora-cloud-sdk": "^0.0.3", + "@hathora/cloud-sdk-typescript": "^2.2.0", "@heroicons/react": "^2.0.17", "@react-oauth/google": "^0.10.0", "dayjs": "^1.11.7", @@ -2063,10 +2063,17 @@ "jwt-decode": "^3.1.2" } }, - "node_modules/@hathora/hathora-cloud-sdk": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@hathora/hathora-cloud-sdk/-/hathora-cloud-sdk-0.0.3.tgz", - "integrity": "sha512-ZpiOTRbawUTnEc6/8Z+gTDGYQcQRegoR20Bcmfd4ecr0tUzVu4j97iX+05CiSiMZySjWpzzlWJdCGarW4eAi2g==" + "node_modules/@hathora/cloud-sdk-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.0.tgz", + "integrity": "sha512-cSL6cdGSmQiC3hNWe7zd/xse1a0Egm9T1TrxifGDoZBFuOPhQBwTDkl7MCwFHz+vYplxgMemUAQBFHakJXiU8w==", + "dependencies": { + "axios": "^1.1.3", + "class-transformer": "^0.5.1", + "form-data": "^4.0.0", + "jsonpath": "^1.1.1", + "reflect-metadata": "^0.1.13" + } }, "node_modules/@heroicons/react": { "version": "2.0.17", @@ -3140,6 +3147,11 @@ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -3161,6 +3173,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", @@ -3497,6 +3519,11 @@ "node": ">=6.0" } }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3515,6 +3542,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", @@ -3688,8 +3726,7 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/define-properties": { "version": "1.2.0", @@ -3707,6 +3744,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -4270,6 +4315,94 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint": { "version": "8.38.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", @@ -4735,6 +4868,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", @@ -4772,7 +4917,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4841,8 +4985,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fastq": { "version": "1.15.0", @@ -4924,6 +5067,25 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -4933,6 +5095,19 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", @@ -5816,6 +5991,16 @@ "node": ">=6" } }, + "node_modules/jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "dependencies": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -5984,8 +6169,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "peer": true, "engines": { "node": ">= 0.6" } @@ -5994,8 +6177,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6622,6 +6803,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -6737,6 +6923,11 @@ "node": ">=8.10.0" } }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "node_modules/refractor": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", @@ -7112,8 +7303,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -7147,6 +7337,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/static-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "dependencies": { + "escodegen": "^1.8.1" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -7703,6 +7901,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -8026,7 +8229,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9500,10 +9702,17 @@ "jwt-decode": "^3.1.2" } }, - "@hathora/hathora-cloud-sdk": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@hathora/hathora-cloud-sdk/-/hathora-cloud-sdk-0.0.3.tgz", - "integrity": "sha512-ZpiOTRbawUTnEc6/8Z+gTDGYQcQRegoR20Bcmfd4ecr0tUzVu4j97iX+05CiSiMZySjWpzzlWJdCGarW4eAi2g==" + "@hathora/cloud-sdk-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.0.tgz", + "integrity": "sha512-cSL6cdGSmQiC3hNWe7zd/xse1a0Egm9T1TrxifGDoZBFuOPhQBwTDkl7MCwFHz+vYplxgMemUAQBFHakJXiU8w==", + "requires": { + "axios": "^1.1.3", + "class-transformer": "^0.5.1", + "form-data": "^4.0.0", + "jsonpath": "^1.1.1", + "reflect-metadata": "^0.1.13" + } }, "@heroicons/react": { "version": "2.0.17", @@ -10354,6 +10563,11 @@ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -10366,6 +10580,16 @@ "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", "dev": true }, + "axios": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "axobject-query": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", @@ -10605,6 +10829,11 @@ "dev": true, "peer": true }, + "class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -10620,6 +10849,14 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "comma-separated-tokens": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", @@ -10756,8 +10993,7 @@ "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "define-properties": { "version": "1.2.0", @@ -10769,6 +11005,11 @@ "object-keys": "^1.1.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -11109,6 +11350,65 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, "eslint": { "version": "8.38.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", @@ -11439,6 +11739,11 @@ "eslint-visitor-keys": "^3.4.0" } }, + "esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==" + }, "esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", @@ -11466,8 +11771,7 @@ "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, "eventemitter3": { "version": "4.0.7", @@ -11526,8 +11830,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "fastq": { "version": "1.15.0", @@ -11590,6 +11893,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -11599,6 +11907,16 @@ "is-callable": "^1.1.3" } }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", @@ -12216,6 +12534,16 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "requires": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -12352,16 +12680,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "peer": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "peer": true, "requires": { "mime-db": "1.52.0" } @@ -12790,6 +13114,11 @@ "xtend": "^4.0.0" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -12870,6 +13199,11 @@ "picomatch": "^2.2.1" } }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "refractor": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", @@ -13138,8 +13472,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true + "devOptional": true }, "source-map-js": { "version": "1.0.2", @@ -13163,6 +13496,14 @@ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==" }, + "static-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "requires": { + "escodegen": "^1.8.1" + } + }, "stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -13563,6 +13904,11 @@ "which-boxed-primitive": "^1.0.2" } }, + "underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -13777,8 +14123,7 @@ "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, "wrappy": { "version": "1.0.2", diff --git a/client/package.json b/client/package.json index 0f0463c..5204272 100644 --- a/client/package.json +++ b/client/package.json @@ -7,7 +7,7 @@ }, "dependencies": { "@hathora/client-sdk": "^1.0.0", - "@hathora/hathora-cloud-sdk": "^0.0.3", + "@hathora/cloud-sdk-typescript": "^2.2.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 2069853..a1fa1d2 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -1,10 +1,10 @@ import ReactDOM from "react-dom/client"; import React, { useEffect, useState } from "react"; import { GoogleOAuthProvider } from "@react-oauth/google"; -import { AuthV1Api, LobbyV2Api, RoomV1Api } from "@hathora/hathora-cloud-sdk"; +import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; import { HathoraConnection } from "@hathora/client-sdk"; -import { SessionMetadata, LobbyState, InitialConfig } from "../../common/types"; +import { SessionMetadata, RoomConfig } from "../../common/types"; import { isReadyForConnect, Token } from "./utils"; import { Socials } from "./components/website/Socials"; @@ -18,14 +18,12 @@ import { LobbySelector } from "./components/lobby/LobbySelector"; import { BulletButton } from "./components/lobby/BulletButton"; import { GameComponent, GameConfig } from "./components/GameComponent"; -const authClient = new AuthV1Api(); -const lobbyClient = new LobbyV2Api(); -const roomClient = new RoomV1Api(); +const appId = process.env.HATHORA_APP_ID; +const hathoraSdk = new HathoraCloud({ appId }); function App() { - const appId = process.env.HATHORA_APP_ID; const [googleIdToken, setGoogleIdToken] = useState(); - const token = useAuthToken(appId, googleIdToken); + const token = useAuthToken(googleIdToken); const [connection, setConnection] = useState(); const [sessionMetadata, setSessionMetadata] = useState(undefined); const [failedToConnect, setFailedToConnect] = useState(false); @@ -50,7 +48,7 @@ function App() { !sessionMetadata?.isGameEnd ) { // Once we parse roomId from the URL, get connection details to connect player to the server - isReadyForConnect(appId, roomClient, lobbyClient, roomIdFromUrl) + isReadyForConnect(appId, roomIdFromUrl, hathoraSdk) .then(async ({ connectionInfo, lobbyInfo }) => { setRoomIdNotFound(undefined); if (connection != null) { @@ -58,25 +56,26 @@ function App() { } try { - const lobbyState = lobbyInfo.state as LobbyState | undefined; - const lobbyInitialConfig = lobbyInfo.initialConfig as InitialConfig | undefined; + const roomConfig = JSON.parse(lobbyInfo.roomConfig) as RoomConfig; - if (!lobbyState || !lobbyState.isGameEnd) { + if (!roomConfig.isGameEnd) { const connect = new HathoraConnection(roomIdFromUrl, connectionInfo); connect.onClose(async () => { // If game has ended, we want updated lobby state - const updatedLobbyInfo = await lobbyClient.getLobbyInfo(appId, roomIdFromUrl); - const updatedLobbyState = updatedLobbyInfo.state as LobbyState | undefined; - const updatedLobbyInitialConfig = updatedLobbyInfo.initialConfig as InitialConfig | undefined; + const { lobbyV3: updatedLobbyInfo } = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomIdFromUrl); + if (updatedLobbyInfo == null) { + return; + } + const updatedRoomConfig = JSON.parse(updatedLobbyInfo.roomConfig) as RoomConfig; setSessionMetadata({ serverUrl: `${connectionInfo.host}:${connectionInfo.port}`, region: updatedLobbyInfo.region, roomId: updatedLobbyInfo.roomId, - capacity: updatedLobbyInitialConfig?.capacity ?? 0, - winningScore: updatedLobbyInitialConfig?.winningScore ?? 99, - isGameEnd: !!updatedLobbyState?.isGameEnd, - winningPlayerId: updatedLobbyState?.winningPlayerId, - playerNicknameMap: updatedLobbyState?.playerNicknameMap || {}, + capacity: updatedRoomConfig.capacity, + winningScore: updatedRoomConfig.winningScore, + isGameEnd: !!updatedRoomConfig.isGameEnd, + winningPlayerId: updatedRoomConfig.winningPlayerId, + playerNicknameMap: updatedRoomConfig.playerNicknameMap, creatorId: updatedLobbyInfo.createdBy, }); setFailedToConnect(true); @@ -87,11 +86,11 @@ function App() { serverUrl: `${connectionInfo.host}:${connectionInfo.port}`, region: lobbyInfo.region, roomId: lobbyInfo.roomId, - capacity: lobbyInitialConfig?.capacity ?? 0, - winningScore: lobbyInitialConfig?.winningScore ?? 99, - isGameEnd: lobbyState?.isGameEnd ?? false, - winningPlayerId: lobbyState?.winningPlayerId, - playerNicknameMap: lobbyState?.playerNicknameMap || {}, + capacity: roomConfig.capacity, + winningScore: roomConfig.winningScore, + isGameEnd: roomConfig.isGameEnd, + winningPlayerId: roomConfig.winningPlayerId, + playerNicknameMap: roomConfig.playerNicknameMap, creatorId: lobbyInfo.createdBy, }); } catch (e) { @@ -202,20 +201,20 @@ const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement) root.render(); // Custom hook to access auth token -function useAuthToken(appId: string | undefined, googleIdToken: string | undefined): Token | undefined { +function useAuthToken(googleIdToken: string | undefined): Token | undefined { const [token, setToken] = React.useState(); useEffect(() => { if (appId != null) { - getToken(appId, authClient, googleIdToken).then(setToken); + getToken(googleIdToken).then(setToken); } - }, [appId, googleIdToken]); + }, [googleIdToken]); return token; } // 1. Check sessionStorage for existing token // 2. If googleIdToken passed, use it for auth and store token // 3. If none above, then use anonymous auth -async function getToken(appId: string, client: AuthV1Api, googleIdToken: string | undefined): Promise { +async function getToken(googleIdToken: string | undefined): Promise { const maybeToken = sessionStorage.getItem("bullet-mania-token"); const maybeTokenType = sessionStorage.getItem("bullet-mania-token-type"); if (maybeToken !== null && maybeTokenType != null) { @@ -225,13 +224,19 @@ async function getToken(appId: string, client: AuthV1Api, googleIdToken: string } as Token; } if (googleIdToken == null) { - const { token } = await client.loginAnonymous(appId); - return { value: token, type: "anonymous" }; + const { loginResponse } = await hathoraSdk.authV1.loginAnonymous(); + if (loginResponse == null) { + throw new Error("Failed to login anonymously"); + } + return { value: loginResponse.token, type: "anonymous" }; + } + const { loginResponse } = await hathoraSdk.authV1.loginGoogle({ idToken: googleIdToken }); + if (loginResponse == null) { + throw new Error("Failed to login with google"); } - const { token } = await client.loginGoogle(appId, { idToken: googleIdToken }); - sessionStorage.setItem("bullet-mania-token", token); + sessionStorage.setItem("bullet-mania-token", loginResponse.token); sessionStorage.setItem("bullet-mania-token-type", "google"); - return { value: token, type: "google" }; + return { value: loginResponse.token, type: "google" }; } function getRoomIdFromUrl(): string | undefined { diff --git a/client/src/components/lobby/GameCreator.tsx b/client/src/components/lobby/GameCreator.tsx index 4939a53..52b0e55 100644 --- a/client/src/components/lobby/GameCreator.tsx +++ b/client/src/components/lobby/GameCreator.tsx @@ -1,9 +1,10 @@ import React from "react"; import { GoogleLogin } from "@react-oauth/google"; -import { LobbyV2Api, RoomV1Api, Region } from "@hathora/hathora-cloud-sdk"; +import { LobbyVisibility, Region } from "@hathora/cloud-sdk-typescript/dist/sdk/models/shared"; +import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; import { isReadyForConnect, Token } from "../../utils"; -import { InitialConfig } from "../../../../common/types"; +import { RoomConfig } from "../../../../common/types"; import { MultiSelect } from "./MultiSelect"; import { LobbyPageCard } from "./LobbyPageCard"; @@ -11,9 +12,6 @@ import { Header } from "./Header"; import { Dropdown } from "./Dropdown"; import { BulletButton } from "./BulletButton"; -const lobbyClient = new LobbyV2Api(); -const roomClient = new RoomV1Api(); - interface GameCreatorProps { appId: string; playerToken: Token; @@ -28,7 +26,8 @@ export function GameCreator(props: GameCreatorProps) { const [isLoading, setIsLoading] = React.useState(false); const [error, setError] = React.useState(""); - const initialConfig: InitialConfig = { capacity, winningScore }; + const hathoraSdk = new HathoraCloud({ appId }); + return (
Create Game
@@ -78,14 +77,28 @@ export function GameCreator(props: GameCreatorProps) { } setIsLoading(true); try { - const lobby = await lobbyClient.createLobby(appId, playerToken.value, { - visibility, - region, - initialConfig, - }); + const roomConfig: RoomConfig = { + capacity, + winningScore, + playerNicknameMap: {}, + isGameEnd: false, + }; + const { lobbyV3 } = await hathoraSdk.lobbyV3.createLobby( + { + createLobbyV3Params: { + region, + visibility: visibility as LobbyVisibility, + roomConfig: JSON.stringify(roomConfig), + }, + }, + { playerAuth: playerToken.value } + ); + if (lobbyV3 == null) { + throw new Error("Failed to create lobby"); + } // Wait until lobby connection details are ready before redirect player to match - await isReadyForConnect(appId, roomClient, lobbyClient, lobby.roomId); - window.location.href = `/${lobby.roomId}`; //update url + await isReadyForConnect(appId, lobbyV3.roomId, hathoraSdk); + window.location.href = `/${lobbyV3.roomId}`; //update url } catch (e) { setError(e instanceof Error ? e.toString() : typeof e === "string" ? e : "Unknown error"); } finally { diff --git a/client/src/components/lobby/PublicLobbyList.tsx b/client/src/components/lobby/PublicLobbyList.tsx index a4bd575..cc36a41 100644 --- a/client/src/components/lobby/PublicLobbyList.tsx +++ b/client/src/components/lobby/PublicLobbyList.tsx @@ -6,17 +6,17 @@ import dayjs from "dayjs"; dayjs.extend(relativeTime); import { ClockIcon, TrophyIcon, UserIcon, UsersIcon } from "@heroicons/react/24/outline"; -import { LobbyV2Api, RoomV1Api, Region, Lobby } from "@hathora/hathora-cloud-sdk"; +import { LobbyV3, Region } from "@hathora/cloud-sdk-typescript/dist/sdk/models/shared"; +import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; import { isReadyForConnect } from "../../utils"; -import { InitialConfig, LobbyState } from "../../../../common/types"; +import { RoomConfig } from "../../../../common/types"; import { LobbyPageCard } from "./LobbyPageCard"; import { Header } from "./Header"; import { BulletButton } from "./BulletButton"; -const lobbyClient = new LobbyV2Api(); -const roomClient = new RoomV1Api(); +const hathoraSdk = new HathoraCloud({ appId: process.env.HATHORA_APP_ID }); interface PublicLobbyListProps { appId: string; @@ -25,15 +25,17 @@ export function PublicLobbyList(props: PublicLobbyListProps) { const { appId } = props; const lobbies = useLobbies(appId); const [readyRooms, setReadyRooms] = React.useState>(new Set()); + useEffect(() => { lobbies.forEach(async (l) => { // Ensure that lobby is ready for connections before adding to visible lobby list - await isReadyForConnect(appId, roomClient, lobbyClient, l.roomId); + await isReadyForConnect(appId, l.roomId, hathoraSdk); setReadyRooms((prev) => { return new Set([...prev, l.roomId]); }); }); - }, [lobbies]); + }, [lobbies, appId]); + return (
Join Public Game
@@ -57,8 +59,7 @@ export function PublicLobbyList(props: PublicLobbyListProps) { .filter((l) => readyRooms.has(l.roomId)) .sort((a, b) => (new Date(b.createdAt).getTime() || 0) - (new Date(a.createdAt).getTime() || 0)) .map((lobby, index) => { - const lobbyState = lobby.state as LobbyState | undefined; - const lobbyInitialConfig = lobby.initialConfig as InitialConfig | undefined; + const roomConfig = JSON.parse(lobby.roomConfig) as RoomConfig; return (
- {`${lobbyState?.playerNicknameMap ? Object.keys(lobbyState.playerNicknameMap).length : 0}/${ - lobbyInitialConfig?.capacity ?? "n/a" - }`} + {`${Object.keys(roomConfig.playerNicknameMap).length}/${roomConfig.capacity}`}
- {lobbyState && lobbyState.playerNicknameMap[lobby.createdBy] ? ( - `${lobbyState.playerNicknameMap[lobby.createdBy]}` + {roomConfig.playerNicknameMap[lobby.createdBy] ? ( + `${roomConfig.playerNicknameMap[lobby.createdBy]}` ) : ( creator left )}
- {`${lobbyInitialConfig?.winningScore ?? "n/a"} kills to win`} + {`${roomConfig.winningScore} kills to win`}
- {lobbyState?.isGameEnd ? ( + {roomConfig.isGameEnd ? (
GAME ENDED
@@ -119,19 +118,13 @@ export function PublicLobbyList(props: PublicLobbyListProps) { @@ -153,16 +146,24 @@ export function PublicLobbyList(props: PublicLobbyListProps) { ); } -function useLobbies(appId: string): Lobby[] { - const [lobbies, setLobbies] = React.useState([]); +function useLobbies(appId: string): LobbyV3[] { + const [lobbies, setLobbies] = React.useState([]); React.useEffect(() => { if (appId) { - lobbyClient.listActivePublicLobbies(appId).then(setLobbies); + hathoraSdk.lobbyV3.listActivePublicLobbies().then(({ classes }) => { + if (classes != null) { + setLobbies(classes); + } + }); } }, [appId]); useInterval(() => { if (appId) { - lobbyClient.listActivePublicLobbies(appId).then(setLobbies); + hathoraSdk.lobbyV3.listActivePublicLobbies().then(({ classes }) => { + if (classes != null) { + setLobbies(classes); + } + }); } }, 2000); return lobbies; diff --git a/client/src/utils.ts b/client/src/utils.ts index 5cff367..83cc30a 100644 --- a/client/src/utils.ts +++ b/client/src/utils.ts @@ -1,5 +1,5 @@ -import { Lobby } from "@hathora/hathora-cloud-sdk/src/models/index"; -import { LobbyV2Api, RoomV1Api } from "@hathora/hathora-cloud-sdk"; +import { LobbyV3 } from "@hathora/cloud-sdk-typescript/dist/sdk/models/shared"; +import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; import { ConnectionDetails } from "@hathora/client-sdk"; export const LOCAL_CONNECTION_DETAILS: ConnectionDetails = { @@ -30,25 +30,27 @@ export const Token = { export async function isReadyForConnect( appId: string, - roomClient: RoomV1Api, - lobbyClient: LobbyV2Api, - roomId: string -): Promise<{ lobbyInfo: Lobby; connectionInfo: ConnectionDetails }> { + roomId: string, + hathoraSdk: HathoraCloud +): Promise<{ lobbyInfo: LobbyV3; connectionInfo: ConnectionDetails }> { const MAX_CONNECT_ATTEMPTS = 50; const TRY_CONNECT_INTERVAL_MS = 1000; - const lobbyInfo = await lobbyClient.getLobbyInfo(appId, roomId); + const { lobbyV3: lobbyInfo } = await hathoraSdk.lobbyV3.getLobbyInfoByRoomId(roomId); + if (lobbyInfo === undefined) { + throw new Error("Lobby not found: " + roomId); + } if (lobbyInfo.visibility === "local") { - return new Promise<{ lobbyInfo: Lobby; connectionInfo: ConnectionDetails }>((resolve) => + return new Promise<{ lobbyInfo: LobbyV3; connectionInfo: ConnectionDetails }>((resolve) => resolve({ lobbyInfo, connectionInfo: LOCAL_CONNECTION_DETAILS }) ); } for (let i = 0; i < MAX_CONNECT_ATTEMPTS; i++) { - const res = await roomClient.getConnectionInfo(appId, roomId); - if (res.status === "active") { - return { lobbyInfo, connectionInfo: res }; + const { connectionInfoV2 } = await hathoraSdk.roomV2.getConnectionInfo(roomId); + if (connectionInfoV2?.exposedPort !== undefined) { + return { lobbyInfo, connectionInfo: connectionInfoV2.exposedPort }; } await new Promise((resolve) => setTimeout(resolve, TRY_CONNECT_INTERVAL_MS)); } diff --git a/common/types.ts b/common/types.ts index 688849b..2d20a7a 100644 --- a/common/types.ts +++ b/common/types.ts @@ -33,15 +33,12 @@ export type GameState = { bullets: Bullet[]; }; -export type LobbyState = { - playerNicknameMap: { [playerId: string]: string }; - isGameEnd?: boolean; - winningPlayerId?: string; -}; - -export type InitialConfig = { +export type RoomConfig = { capacity: number; winningScore: number; + playerNicknameMap: { [playerId: string]: string }; + isGameEnd: boolean; + winningPlayerId?: string; }; export type SessionMetadata = { diff --git a/server/package-lock.json b/server/package-lock.json index 80a1556..a34fb93 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@hathora/hathora-cloud-sdk": "^0.0.3", + "@hathora/cloud-sdk-typescript": "^2.2.0", "@hathora/server-sdk": "^1.0.0", "detect-collisions": "^6.4.2", "dotenv": "^16.0.2" @@ -28,10 +28,17 @@ "node": ">=12" } }, - "node_modules/@hathora/hathora-cloud-sdk": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@hathora/hathora-cloud-sdk/-/hathora-cloud-sdk-0.0.3.tgz", - "integrity": "sha512-ZpiOTRbawUTnEc6/8Z+gTDGYQcQRegoR20Bcmfd4ecr0tUzVu4j97iX+05CiSiMZySjWpzzlWJdCGarW4eAi2g==" + "node_modules/@hathora/cloud-sdk-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.0.tgz", + "integrity": "sha512-cSL6cdGSmQiC3hNWe7zd/xse1a0Egm9T1TrxifGDoZBFuOPhQBwTDkl7MCwFHz+vYplxgMemUAQBFHakJXiU8w==", + "dependencies": { + "axios": "^1.1.3", + "class-transformer": "^0.5.1", + "form-data": "^4.0.0", + "jsonpath": "^1.1.1", + "reflect-metadata": "^0.1.13" + } }, "node_modules/@hathora/server-sdk": { "version": "1.0.0", @@ -134,17 +141,61 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-collisions": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/detect-collisions/-/detect-collisions-6.4.2.tgz", @@ -182,6 +233,114 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "dependencies": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", @@ -216,6 +375,18 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -238,11 +409,46 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/poly-decomp": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/poly-decomp/-/poly-decomp-0.3.0.tgz", @@ -251,6 +457,19 @@ "node": "*" } }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/quickselect": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", @@ -264,6 +483,11 @@ "quickselect": "^2.0.0" } }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -302,6 +526,23 @@ "node": ">=10" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "dependencies": { + "escodegen": "^1.8.1" + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -345,6 +586,17 @@ } } }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/typescript": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", @@ -358,6 +610,11 @@ "node": ">=4.2.0" } }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "node_modules/uWebSockets.js": { "version": "20.19.0", "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#42c9c0d5d31f46ca4115dc75672b0037ec970f28" @@ -368,6 +625,14 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -393,10 +658,17 @@ "@jridgewell/trace-mapping": "0.3.9" } }, - "@hathora/hathora-cloud-sdk": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@hathora/hathora-cloud-sdk/-/hathora-cloud-sdk-0.0.3.tgz", - "integrity": "sha512-ZpiOTRbawUTnEc6/8Z+gTDGYQcQRegoR20Bcmfd4ecr0tUzVu4j97iX+05CiSiMZySjWpzzlWJdCGarW4eAi2g==" + "@hathora/cloud-sdk-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@hathora/cloud-sdk-typescript/-/cloud-sdk-typescript-2.2.0.tgz", + "integrity": "sha512-cSL6cdGSmQiC3hNWe7zd/xse1a0Egm9T1TrxifGDoZBFuOPhQBwTDkl7MCwFHz+vYplxgMemUAQBFHakJXiU8w==", + "requires": { + "axios": "^1.1.3", + "class-transformer": "^0.5.1", + "form-data": "^4.0.0", + "jsonpath": "^1.1.1", + "reflect-metadata": "^0.1.13" + } }, "@hathora/server-sdk": { "version": "1.0.0", @@ -487,17 +759,55 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "detect-collisions": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/detect-collisions/-/detect-collisions-6.4.2.tgz", @@ -529,6 +839,70 @@ "safe-buffer": "^5.0.1" } }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } + }, + "esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==" + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "requires": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, "jsonwebtoken": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", @@ -559,6 +933,15 @@ "safe-buffer": "^5.0.1" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -578,16 +961,52 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "poly-decomp": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/poly-decomp/-/poly-decomp-0.3.0.tgz", "integrity": "sha512-hWeBxGzPYiybmI4548Fca7Up/0k1qS5+79cVHI9+H33dKya5YNb9hxl0ZnDaDgvrZSuYFBhkCK/HOnqN7gefkQ==" }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "quickselect": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", @@ -601,6 +1020,11 @@ "quickselect": "^2.0.0" } }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -619,6 +1043,20 @@ "lru-cache": "^6.0.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "static-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "requires": { + "escodegen": "^1.8.1" + } + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -640,12 +1078,25 @@ "yn": "3.1.1" } }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "requires": { + "prelude-ls": "~1.1.2" + } + }, "typescript": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "dev": true }, + "underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "uWebSockets.js": { "version": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#42c9c0d5d31f46ca4115dc75672b0037ec970f28", "from": "uWebSockets.js@github:uNetworking/uWebSockets.js#v20.19.0" @@ -656,6 +1107,11 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/server/package.json b/server/package.json index 6a12814..8464439 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/hathora-cloud-sdk": "^0.0.3", + "@hathora/cloud-sdk-typescript": "^2.2.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 a241e10..d6ec95e 100644 --- a/server/server.ts +++ b/server/server.ts @@ -4,14 +4,16 @@ import { fileURLToPath } from "url"; import { UserId, RoomId, Application, startServer, verifyJwt } from "@hathora/server-sdk"; import dotenv from "dotenv"; import { Box, Body, System } from "detect-collisions"; -import { Direction, GameState, InitialConfig, LobbyState } from "../common/types"; +import { Direction, GameState, RoomConfig } from "../common/types"; import { ClientMessage, ClientMessageType, ServerMessage, ServerMessageType } from "../common/messages"; import map from "../common/map.json" assert { type: "json" }; -import { LobbyV2Api, RoomV1Api } from "@hathora/hathora-cloud-sdk"; +import { HathoraCloud } from "@hathora/cloud-sdk-typescript"; -const lobbyClient = new LobbyV2Api(); -const roomClient = new RoomV1Api(); +const hathoraSdk = new HathoraCloud({ + appId: process.env.HATHORA_APP_ID!, + security: { hathoraDevToken: process.env.DEVELOPER_TOKEN! }, +}); // The millisecond tick rate const TICK_INTERVAL_MS = 50; @@ -129,6 +131,7 @@ type InternalState = { physics: System; players: InternalPlayer[]; bullets: InternalBullet[]; + capacity: number; winningScore: number; isGameEnd: boolean; winningPlayerId?: UserId; @@ -151,16 +154,15 @@ const store: Application = { async subscribeUser(roomId: RoomId, userId: string): Promise { console.log("subscribeUser", roomId, userId); try { - const lobbyInfo = await lobbyClient.getLobbyInfo(process.env.HATHORA_APP_ID!, roomId); - const lobbyState = lobbyInfo.state as LobbyState | undefined; - const lobbyInitialConfig = lobbyInfo.initialConfig as InitialConfig | undefined; + const roomInfo = await hathoraSdk.roomV2.getRoomInfo(roomId); + const roomConfig = JSON.parse(roomInfo.room!.roomConfig) as RoomConfig; if (!rooms.has(roomId)) { - rooms.set(roomId, initializeRoom(lobbyInitialConfig?.winningScore ?? 10, lobbyState?.isGameEnd || false)); + rooms.set(roomId, initializeRoom(roomConfig.capacity, roomConfig.winningScore, roomConfig.isGameEnd)); } const game = rooms.get(roomId)!; - if (game.players.length === lobbyInitialConfig?.capacity) { + if (game.players.length === roomConfig.capacity) { throw new Error("room is full"); } if (game.isGameEnd) { @@ -412,7 +414,7 @@ function broadcastStateUpdate(roomId: RoomId) { server.broadcastMessage(roomId, Buffer.from(JSON.stringify(msg), "utf8")); } -function initializeRoom(winningScore: number, isGameEnd: boolean) { +function initializeRoom(capacity: number, winningScore: number, isGameEnd: boolean): InternalState { const physics = new System(); const tileSize = map.tileSize; const top = map.top * tileSize; @@ -434,13 +436,7 @@ function initializeRoom(winningScore: number, isGameEnd: boolean) { physics.insert(wallBody(left, bottom, right - left, BOUNDARY_WIDTH)); // bottom physics.insert(wallBody(right, top, BOUNDARY_WIDTH, bottom - top)); // right - return { - physics, - players: [], - bullets: [], - winningScore, - isGameEnd, - }; + return { physics, players: [], bullets: [], capacity, winningScore, isGameEnd }; } function wallBody(x: number, y: number, width: number, height: number): PhysicsBody { @@ -470,23 +466,17 @@ async function endGameCleanup(roomId: string, game: InternalState, winningPlayer server.closeConnection(roomId, playerId, "game has ended, disconnecting players"); }); console.log("destroying room: ", roomId); - roomClient.destroyRoom( - process.env.HATHORA_APP_ID!, - roomId, - { headers: { Authorization: `Bearer ${getDeveloperToken()}`, "Content-Type": "application/json" } } - ); + hathoraSdk.roomV2.destroyRoom(roomId); }, 10000); } async function updateLobbyState(game: InternalState, roomId: string) { - const lobbyState: LobbyState = { + const roomConfig: RoomConfig = { + capacity: 0, + winningScore: game.winningScore, playerNicknameMap: Object.fromEntries(game.players.map((player) => [player.id, player.nickname ?? player.id])), isGameEnd: game.isGameEnd, winningPlayerId: game.winningPlayerId, }; - return await lobbyClient.setLobbyState(process.env.HATHORA_APP_ID!, - roomId, - { state:lobbyState }, - { headers: { Authorization: `Bearer ${getDeveloperToken()}`, "Content-Type": "application/json" } } - ); + return await hathoraSdk.roomV2.updateRoomConfig({ roomConfig: JSON.stringify(roomConfig) }, roomId); }