wip
This commit is contained in:
parent
512e5e8b5d
commit
dc7c0c1c6e
4 changed files with 691 additions and 509 deletions
509
package-lock.json
generated
509
package-lock.json
generated
|
|
@ -62,9 +62,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.3.tgz",
|
||||||
"integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==",
|
"integrity": "sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -79,9 +79,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz",
|
||||||
"integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==",
|
"integrity": "sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -96,9 +96,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==",
|
"integrity": "sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -113,9 +113,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz",
|
||||||
"integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==",
|
"integrity": "sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -130,9 +130,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==",
|
"integrity": "sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -147,9 +147,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz",
|
||||||
"integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==",
|
"integrity": "sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -164,9 +164,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==",
|
"integrity": "sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -181,9 +181,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz",
|
||||||
"integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==",
|
"integrity": "sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -198,9 +198,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz",
|
||||||
"integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==",
|
"integrity": "sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -215,9 +215,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz",
|
||||||
"integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==",
|
"integrity": "sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
|
@ -232,9 +232,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz",
|
||||||
"integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==",
|
"integrity": "sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
|
|
@ -249,9 +249,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz",
|
||||||
"integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==",
|
"integrity": "sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
|
|
@ -266,9 +266,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz",
|
||||||
"integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==",
|
"integrity": "sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
|
@ -283,9 +283,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz",
|
||||||
"integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==",
|
"integrity": "sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
|
@ -300,9 +300,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz",
|
||||||
"integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==",
|
"integrity": "sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
|
@ -317,9 +317,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==",
|
"integrity": "sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -334,9 +334,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==",
|
"integrity": "sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -351,9 +351,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==",
|
"integrity": "sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -368,9 +368,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==",
|
"integrity": "sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -385,9 +385,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz",
|
||||||
"integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==",
|
"integrity": "sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -402,9 +402,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz",
|
||||||
"integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==",
|
"integrity": "sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
|
@ -419,9 +419,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz",
|
||||||
"integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==",
|
"integrity": "sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -511,9 +511,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/body-parser": {
|
"node_modules/@types/body-parser": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz",
|
||||||
"integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
|
"integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/connect": "*",
|
"@types/connect": "*",
|
||||||
|
|
@ -592,15 +592,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-errors": {
|
"node_modules/@types/http-errors": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz",
|
||||||
"integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==",
|
"integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/jsonwebtoken": {
|
"node_modules/@types/jsonwebtoken": {
|
||||||
"version": "9.0.2",
|
"version": "9.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
||||||
"integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==",
|
"integrity": "sha512-b0jGiOgHtZ2jqdPgPnP6WLCXZk1T8p06A/vPGzUvxpFGgKMbjXJDjC5m52ErqBnIuWZFgGoIJyRdeG5AyreJjA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
|
|
@ -613,9 +613,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.6.0",
|
"version": "20.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz",
|
||||||
"integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg=="
|
"integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/node-cron": {
|
"node_modules/@types/node-cron": {
|
||||||
"version": "3.0.8",
|
"version": "3.0.8",
|
||||||
|
|
@ -647,20 +647,6 @@
|
||||||
"form-data": "^2.5.0"
|
"form-data": "^2.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/request/node_modules/form-data": {
|
|
||||||
"version": "2.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
|
||||||
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.6",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/send": {
|
"node_modules/@types/send": {
|
||||||
"version": "0.17.1",
|
"version": "0.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
|
||||||
|
|
@ -683,15 +669,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/tough-cookie": {
|
"node_modules/@types/tough-cookie": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz",
|
||||||
"integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
|
"integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/uuid": {
|
"node_modules/@types/uuid": {
|
||||||
"version": "9.0.3",
|
"version": "9.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz",
|
||||||
"integrity": "sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==",
|
"integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/abbrev": {
|
"node_modules/abbrev": {
|
||||||
|
|
@ -741,27 +727,6 @@
|
||||||
"node": ">= 6.0.0"
|
"node": ">= 6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/agent-base/node_modules/debug": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/agent-base/node_modules/ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
||||||
},
|
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
|
@ -856,6 +821,19 @@
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios/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/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
|
@ -913,6 +891,19 @@
|
||||||
"npm": "1.2.8000 || >= 1.4.16"
|
"npm": "1.2.8000 || >= 1.4.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/body-parser/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/body-parser/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
|
@ -1009,9 +1000,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cookie": {
|
"node_modules/cookie": {
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
|
|
@ -1028,14 +1019,6 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cookie-parser/node_modules/cookie": {
|
|
||||||
"version": "0.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
|
||||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cookie-signature": {
|
"node_modules/cookie-signature": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
|
@ -1090,11 +1073,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.0.0"
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
|
|
@ -1217,39 +1208,10 @@
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/engine.io/node_modules/cookie": {
|
|
||||||
"version": "0.4.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
|
||||||
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/engine.io/node_modules/debug": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/engine.io/node_modules/ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
||||||
},
|
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz",
|
||||||
"integrity": "sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==",
|
"integrity": "sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
|
|
@ -1260,34 +1222,34 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/android-arm": "0.19.2",
|
"@esbuild/android-arm": "0.19.3",
|
||||||
"@esbuild/android-arm64": "0.19.2",
|
"@esbuild/android-arm64": "0.19.3",
|
||||||
"@esbuild/android-x64": "0.19.2",
|
"@esbuild/android-x64": "0.19.3",
|
||||||
"@esbuild/darwin-arm64": "0.19.2",
|
"@esbuild/darwin-arm64": "0.19.3",
|
||||||
"@esbuild/darwin-x64": "0.19.2",
|
"@esbuild/darwin-x64": "0.19.3",
|
||||||
"@esbuild/freebsd-arm64": "0.19.2",
|
"@esbuild/freebsd-arm64": "0.19.3",
|
||||||
"@esbuild/freebsd-x64": "0.19.2",
|
"@esbuild/freebsd-x64": "0.19.3",
|
||||||
"@esbuild/linux-arm": "0.19.2",
|
"@esbuild/linux-arm": "0.19.3",
|
||||||
"@esbuild/linux-arm64": "0.19.2",
|
"@esbuild/linux-arm64": "0.19.3",
|
||||||
"@esbuild/linux-ia32": "0.19.2",
|
"@esbuild/linux-ia32": "0.19.3",
|
||||||
"@esbuild/linux-loong64": "0.19.2",
|
"@esbuild/linux-loong64": "0.19.3",
|
||||||
"@esbuild/linux-mips64el": "0.19.2",
|
"@esbuild/linux-mips64el": "0.19.3",
|
||||||
"@esbuild/linux-ppc64": "0.19.2",
|
"@esbuild/linux-ppc64": "0.19.3",
|
||||||
"@esbuild/linux-riscv64": "0.19.2",
|
"@esbuild/linux-riscv64": "0.19.3",
|
||||||
"@esbuild/linux-s390x": "0.19.2",
|
"@esbuild/linux-s390x": "0.19.3",
|
||||||
"@esbuild/linux-x64": "0.19.2",
|
"@esbuild/linux-x64": "0.19.3",
|
||||||
"@esbuild/netbsd-x64": "0.19.2",
|
"@esbuild/netbsd-x64": "0.19.3",
|
||||||
"@esbuild/openbsd-x64": "0.19.2",
|
"@esbuild/openbsd-x64": "0.19.3",
|
||||||
"@esbuild/sunos-x64": "0.19.2",
|
"@esbuild/sunos-x64": "0.19.3",
|
||||||
"@esbuild/win32-arm64": "0.19.2",
|
"@esbuild/win32-arm64": "0.19.3",
|
||||||
"@esbuild/win32-ia32": "0.19.2",
|
"@esbuild/win32-ia32": "0.19.3",
|
||||||
"@esbuild/win32-x64": "0.19.2"
|
"@esbuild/win32-x64": "0.19.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild-register": {
|
"node_modules/esbuild-register": {
|
||||||
"version": "3.4.2",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz",
|
||||||
"integrity": "sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==",
|
"integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
|
|
@ -1296,29 +1258,6 @@
|
||||||
"esbuild": ">=0.12 <1"
|
"esbuild": ">=0.12 <1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild-register/node_modules/debug": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/esbuild-register/node_modules/ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
|
@ -1385,6 +1324,27 @@
|
||||||
"node": ">= 8.0.0"
|
"node": ">= 8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express/node_modules/cookie": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/express/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/express/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
|
},
|
||||||
"node_modules/extend": {
|
"node_modules/extend": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||||
|
|
@ -1425,6 +1385,19 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/finalhandler/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/finalhandler/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||||
|
|
@ -1453,16 +1426,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.0",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.6",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
|
|
@ -1673,27 +1647,6 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/https-proxy-agent/node_modules/debug": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/https-proxy-agent/node_modules/ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
||||||
},
|
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
|
@ -1786,11 +1739,6 @@
|
||||||
"npm": ">=6"
|
"npm": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jsonwebtoken/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/jsprim": {
|
"node_modules/jsprim": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
||||||
|
|
@ -2007,9 +1955,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
"node_modules/negotiator": {
|
"node_modules/negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
|
|
@ -2376,6 +2324,19 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/send/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/send/node_modules/debug/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
|
},
|
||||||
"node_modules/send/node_modules/ms": {
|
"node_modules/send/node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
|
@ -2460,48 +2421,6 @@
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-parser/node_modules/debug": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/socket.io-parser/node_modules/ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
||||||
},
|
|
||||||
"node_modules/socket.io/node_modules/debug": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/socket.io/node_modules/ms": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
||||||
},
|
|
||||||
"node_modules/sshpk": {
|
"node_modules/sshpk": {
|
||||||
"version": "1.17.0",
|
"version": "1.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
|
||||||
|
|
@ -2719,9 +2638,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { Socket } from "socket.io";
|
import { Socket } from "socket.io";
|
||||||
import { io } from "../server";
|
import { io } from "../server";
|
||||||
import { Game } from "./game";
|
import { Game } from "./game";
|
||||||
import { Player, ObfuscatedPlayer } from "./player";
|
|
||||||
import { Card } from "./card";
|
|
||||||
|
|
||||||
export const handleJoinSession = (socket: Socket, sessionId: string) => {
|
export const handleJoinSession = (socket: Socket, sessionId: string) => {
|
||||||
socket.join(sessionId);
|
socket.join(sessionId);
|
||||||
|
|
@ -30,23 +28,3 @@ export const handleNewGame = (
|
||||||
console.log("Not enough players to start a game");
|
console.log("Not enough players to start a game");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const obfuscatePlayerCards = (player: Player): ObfuscatedPlayer => {
|
|
||||||
return {
|
|
||||||
id: player.id,
|
|
||||||
socketId: player.socketId,
|
|
||||||
name: player.name,
|
|
||||||
cards: player.cards.map((card: Card, index: number) => {
|
|
||||||
return {
|
|
||||||
id: card.id,
|
|
||||||
value: player.knownCardPositions[index] ? card.value : 0, // unknown cards are obfuscated to 0
|
|
||||||
name: card.name,
|
|
||||||
color: card.color,
|
|
||||||
matchColorToCardValue: card.matchColorToCardValue,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
knownCardPositions: player.knownCardPositions,
|
|
||||||
playersTurn: player.playersTurn,
|
|
||||||
cardCache: player.cardCache,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
|
||||||
621
src/game/game.ts
621
src/game/game.ts
|
|
@ -6,10 +6,20 @@ import { io } from "../server";
|
||||||
|
|
||||||
type PlayerSocketSet = Set<string>;
|
type PlayerSocketSet = Set<string>;
|
||||||
|
|
||||||
type PlayerActions = Array<
|
type PlayerActionEventName = string;
|
||||||
[string, (playerSocketId: string, data: any) => void]
|
type PlayerActionCallback = (playerSocketId: string, data: any) => void;
|
||||||
|
|
||||||
|
type ExpectedPlayerActions = Array<
|
||||||
|
[PlayerActionEventName, PlayerActionCallback]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
type PlayerAction<ActionDataType> = {
|
||||||
|
playerSocketId: string;
|
||||||
|
data: ActionDataType;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CardPosition = number;
|
||||||
|
|
||||||
// obfuscated types are used to send only necessary data to the client
|
// obfuscated types are used to send only necessary data to the client
|
||||||
export type ObfuscatedGame = {
|
export type ObfuscatedGame = {
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
|
@ -18,9 +28,11 @@ export type ObfuscatedGame = {
|
||||||
cardStack: ObfuscatedCardStack;
|
cardStack: ObfuscatedCardStack;
|
||||||
discardPile: Card[];
|
discardPile: Card[];
|
||||||
phase: string;
|
phase: string;
|
||||||
|
round: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const gamePhase = {
|
const gamePhase = {
|
||||||
|
newRound: "new round",
|
||||||
revealTwoCards: "reveal two cards",
|
revealTwoCards: "reveal two cards",
|
||||||
pickUpCard: "pick up card",
|
pickUpCard: "pick up card",
|
||||||
placeCard: "place card",
|
placeCard: "place card",
|
||||||
|
|
@ -37,6 +49,7 @@ export class Game {
|
||||||
cardStack: CardStack;
|
cardStack: CardStack;
|
||||||
discardPile: Card[];
|
discardPile: Card[];
|
||||||
phase: string;
|
phase: string;
|
||||||
|
round: number;
|
||||||
|
|
||||||
constructor(socket: Socket, sessionId: string, playerIds: PlayerSocketSet) {
|
constructor(socket: Socket, sessionId: string, playerIds: PlayerSocketSet) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
|
@ -51,6 +64,7 @@ export class Game {
|
||||||
// get the first card from the cardStack and put it in the discard pile
|
// get the first card from the cardStack and put it in the discard pile
|
||||||
this.discardPile = [this.cardStack.cards.pop()!];
|
this.discardPile = [this.cardStack.cards.pop()!];
|
||||||
this.phase = gamePhase.revealTwoCards;
|
this.phase = gamePhase.revealTwoCards;
|
||||||
|
this.round = 1;
|
||||||
|
|
||||||
console.log(`New Game created with ${this.playerCount} players!`);
|
console.log(`New Game created with ${this.playerCount} players!`);
|
||||||
this.gameLoop();
|
this.gameLoop();
|
||||||
|
|
@ -80,36 +94,52 @@ export class Game {
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeNewRound(startOver: boolean = false) {
|
||||||
|
this.round = startOver ? 1 : this.round + 1;
|
||||||
|
this.cardStack = new CardStack();
|
||||||
|
this.cardStack.shuffleCards();
|
||||||
|
this.players.forEach((player) => {
|
||||||
|
player.cards = this.cardStack.cards.splice(0, 12);
|
||||||
|
player.knownCardPositions = new Array(12).fill(false);
|
||||||
|
player.playersTurn = false;
|
||||||
|
player.cardCache = null;
|
||||||
|
player.tookDispiledCard = false;
|
||||||
|
player.roundPoints = 0;
|
||||||
|
player.totalPoints = startOver ? 0 : player.totalPoints;
|
||||||
|
player.closedRound = false;
|
||||||
|
});
|
||||||
|
this.discardPile = [this.cardStack.cards.pop()!];
|
||||||
|
this.phase = gamePhase.revealTwoCards;
|
||||||
|
}
|
||||||
|
|
||||||
async gameLoop() {
|
async gameLoop() {
|
||||||
console.log("Game started!");
|
console.log("Game started!");
|
||||||
while (this.phase !== gamePhase.gameEnded) {
|
while (this.phase !== gamePhase.gameEnded) {
|
||||||
|
this.checkForFullRevealedCards();
|
||||||
switch (this.phase) {
|
switch (this.phase) {
|
||||||
case gamePhase.revealTwoCards:
|
case gamePhase.revealTwoCards:
|
||||||
console.log("Game phase: revealTwoCards");
|
console.log("\nGame phase: revealTwoCards");
|
||||||
this.listPlayerSocketListeners();
|
|
||||||
await this.revealInitialCards();
|
await this.revealInitialCards();
|
||||||
this.phase = gamePhase.pickUpCard;
|
|
||||||
break;
|
break;
|
||||||
case gamePhase.pickUpCard:
|
case gamePhase.pickUpCard:
|
||||||
console.log("Game phase: pickUpCard");
|
console.log("\nGame phase: pickUpCard");
|
||||||
this.listPlayerSocketListeners();
|
|
||||||
await this.pickUpCard();
|
await this.pickUpCard();
|
||||||
this.phase = gamePhase.placeCard;
|
|
||||||
break;
|
break;
|
||||||
case gamePhase.placeCard:
|
case gamePhase.placeCard:
|
||||||
console.log("Game phase: placeCard");
|
console.log("\nGame phase: placeCard");
|
||||||
this.listPlayerSocketListeners();
|
|
||||||
await this.placeCard();
|
await this.placeCard();
|
||||||
break;
|
break;
|
||||||
case gamePhase.revealCard:
|
case gamePhase.revealCard:
|
||||||
console.log("Game phase: revealCard");
|
console.log("\nGame phase: revealCard");
|
||||||
this.listPlayerSocketListeners();
|
|
||||||
await this.revealCard();
|
await this.revealCard();
|
||||||
this.phase = gamePhase.pickUpCard;
|
break;
|
||||||
case gamePhase.revealedLastCard:
|
case gamePhase.revealedLastCard:
|
||||||
console.log("Game phase: revealedLastCard");
|
console.log("\nGame phase: revealedLastCard");
|
||||||
// add logic of last round
|
await this.revealedLastCard();
|
||||||
this.phase = gamePhase.gameEnded;
|
break;
|
||||||
|
case gamePhase.newRound:
|
||||||
|
console.log("\nGame phase: newRound");
|
||||||
|
await this.nextRound();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Invalid game phase: ${this.phase}`);
|
throw new Error(`Invalid game phase: ${this.phase}`);
|
||||||
|
|
@ -117,6 +147,364 @@ export class Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Game Phases
|
||||||
|
|
||||||
|
async revealInitialCards() {
|
||||||
|
this.sendMessageToAllPlayers("Reveal two cards");
|
||||||
|
while (!this.allPlayersRevealedInitialCards()) {
|
||||||
|
const playersWithRevealedInitialCards =
|
||||||
|
this.getPlayersWithRevealedInitialCards();
|
||||||
|
const playersWithUnrevealedInitialCards = this.players.filter(
|
||||||
|
(player) => !playersWithRevealedInitialCards.includes(player)
|
||||||
|
);
|
||||||
|
const playersSocketIds = playersWithUnrevealedInitialCards.map(
|
||||||
|
(player) => player.socketId
|
||||||
|
);
|
||||||
|
await this.waitForPlayerActions<CardPosition>(
|
||||||
|
[["click-card", this.revealCardAction.bind(this)]],
|
||||||
|
playersSocketIds
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.setInitialPlayersTurn();
|
||||||
|
this.phase = gamePhase.pickUpCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
async pickUpCard() {
|
||||||
|
const playerOnTurn = this.getPlayersTurn();
|
||||||
|
if (playerOnTurn.closedRound) {
|
||||||
|
this.phase = gamePhase.revealedLastCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sendMessageToAllPlayers(
|
||||||
|
`Waiting for ${playerOnTurn.name} to pick up card`
|
||||||
|
);
|
||||||
|
await this.waitForPlayerActions(
|
||||||
|
[
|
||||||
|
["draw-from-card-stack", this.drawCardAction.bind(this)],
|
||||||
|
["click-discard-pile", this.takeDiscardPileAction.bind(this)],
|
||||||
|
],
|
||||||
|
[playerOnTurn.socketId]
|
||||||
|
);
|
||||||
|
this.phase = gamePhase.placeCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
async placeCard() {
|
||||||
|
const playerOnTurn = this.getPlayersTurn();
|
||||||
|
this.sendMessageToAllPlayers(
|
||||||
|
`Waiting for ${playerOnTurn.name} to place card`
|
||||||
|
);
|
||||||
|
|
||||||
|
const expectedActions: ExpectedPlayerActions = [
|
||||||
|
["click-card", this.placeCardAction.bind(this)],
|
||||||
|
];
|
||||||
|
if (!playerOnTurn.tookDispiledCard) {
|
||||||
|
expectedActions.push([
|
||||||
|
"click-discard-pile",
|
||||||
|
this.discardCardToPileAction.bind(this),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
playerOnTurn.tookDispiledCard = false;
|
||||||
|
await this.waitForPlayerActions(expectedActions, [playerOnTurn.socketId]);
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
async revealCard() {
|
||||||
|
const playerOnTurn = this.getPlayersTurn();
|
||||||
|
this.sendMessageToAllPlayers(
|
||||||
|
`Waiting for ${playerOnTurn.name} to reveal a card`
|
||||||
|
);
|
||||||
|
|
||||||
|
const numberOfRevealedCards = playerOnTurn.getRevealedCardCount();
|
||||||
|
// ensures that the player does not select an already revealed card
|
||||||
|
while (playerOnTurn.getRevealedCardCount() <= numberOfRevealedCards) {
|
||||||
|
await this.waitForPlayerActions(
|
||||||
|
[["click-card", this.revealCardAction.bind(this)]],
|
||||||
|
[playerOnTurn.socketId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.nextPlayersTurn();
|
||||||
|
this.phase = gamePhase.pickUpCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
async revealedLastCard() {
|
||||||
|
this.revealAllCards();
|
||||||
|
this.evaluateAndSavePoints();
|
||||||
|
this.phase = gamePhase.newRound;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
this.sendMessageToAllPlayers("Waiting for next round");
|
||||||
|
}
|
||||||
|
|
||||||
|
async nextRound() {
|
||||||
|
const playerSocketIds = this.players.map((player) => player.socketId);
|
||||||
|
await this.waitForPlayerActions(
|
||||||
|
[["next-round", this.nextRoundAction.bind(this)]],
|
||||||
|
playerSocketIds
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player Action Callbacks
|
||||||
|
|
||||||
|
revealCardAction(playerSocketId: string, cardPosition: number) {
|
||||||
|
const player = this.getPlayerBySocketId(playerSocketId);
|
||||||
|
const revealedCard = player.cards[cardPosition];
|
||||||
|
console.log(`Revealed card ${revealedCard} at position ${cardPosition}`);
|
||||||
|
const playerIndex = this.players.indexOf(player!);
|
||||||
|
this.players[playerIndex].knownCardPositions[cardPosition] = true;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCardAction(playerSocketId: string, data: any) {
|
||||||
|
const player = this.getPlayerBySocketId(playerSocketId);
|
||||||
|
console.log(`Player ${player.name} drawed a card.`);
|
||||||
|
const drawnCard = this.cardStack.cards.pop()!;
|
||||||
|
player.cardCache = drawnCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
takeDiscardPileAction(playerSocketId: string, data: any) {
|
||||||
|
const player = this.getPlayerBySocketId(playerSocketId);
|
||||||
|
console.log(`Player ${player.name} took the card from discard pile.`);
|
||||||
|
const discardPileCard = this.discardPile.pop()!;
|
||||||
|
player.cardCache = discardPileCard;
|
||||||
|
player.tookDispiledCard = true;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
discardCardToPileAction(playerSocketId: string, data: any) {
|
||||||
|
const player = this.getPlayerBySocketId(playerSocketId);
|
||||||
|
console.log(`Player ${player.name} discarded a card to the pile.`);
|
||||||
|
const discardedCard = player.cardCache!;
|
||||||
|
this.discardPile.push(discardedCard);
|
||||||
|
player.cardCache = null;
|
||||||
|
this.phase = gamePhase.revealCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
placeCardAction(playerSocketId: string, cardPosition: number) {
|
||||||
|
const player = this.getPlayerBySocketId(playerSocketId);
|
||||||
|
console.log(`Player ${player.name} placed a card.`);
|
||||||
|
const placedCard = player.cardCache!;
|
||||||
|
player.cardCache = null;
|
||||||
|
const replacedCard = player.cards[cardPosition];
|
||||||
|
this.discardPile.push(replacedCard);
|
||||||
|
player.cards[cardPosition] = placedCard;
|
||||||
|
player.knownCardPositions[cardPosition] = true;
|
||||||
|
this.nextPlayersTurn();
|
||||||
|
this.phase = gamePhase.pickUpCard;
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
nextRoundAction(playerSocketId: string, data: any) {
|
||||||
|
this.initializeNewRound();
|
||||||
|
this.sendObfuscatedGameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function waits for a player to perform one of the expected actions.
|
||||||
|
* When a player performs one of the expected actions, the corresponding callback is called and further processes the player data.
|
||||||
|
* All event listeners are removed after every player defined in expectedFrom performed the expected action.
|
||||||
|
* The function also returns a promise that resolves with the data sent by the player.
|
||||||
|
* @param expectedActions
|
||||||
|
* @param expectedFrom
|
||||||
|
* @returns playerSocketId and data sent by the player
|
||||||
|
*/
|
||||||
|
waitForPlayerActions<ActionDataType>(
|
||||||
|
expectedActions: ExpectedPlayerActions,
|
||||||
|
expectedFrom: Player["socketId"][]
|
||||||
|
): Promise<PlayerAction<ActionDataType>> {
|
||||||
|
const eventListeners = new Map<string, (...args: any[]) => void>();
|
||||||
|
|
||||||
|
const addPlayerActionListeners = (
|
||||||
|
resolve: (
|
||||||
|
value:
|
||||||
|
| PlayerAction<ActionDataType>
|
||||||
|
| PromiseLike<PlayerAction<ActionDataType>>
|
||||||
|
) => void
|
||||||
|
) => {
|
||||||
|
expectedFrom.forEach((playerSocketId) => {
|
||||||
|
const playerSocket = io.sockets.sockets.get(playerSocketId);
|
||||||
|
if (playerSocket) {
|
||||||
|
expectedActions.forEach((expectedAction) => {
|
||||||
|
const [actionName, processAction] = expectedAction;
|
||||||
|
const eventListener = (data: ActionDataType) => {
|
||||||
|
console.log(`Received ${actionName} from ${playerSocketId}`);
|
||||||
|
processAction(playerSocketId, data);
|
||||||
|
// remove current and event listeners of alternative expected actions
|
||||||
|
removePlayerActionListeners();
|
||||||
|
const playerResponse = { playerSocketId, data };
|
||||||
|
resolve(playerResponse);
|
||||||
|
};
|
||||||
|
playerSocket.on(actionName, eventListener);
|
||||||
|
eventListeners.set(
|
||||||
|
`${playerSocketId}-${actionName}`,
|
||||||
|
eventListener
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removePlayerActionListeners = () => {
|
||||||
|
expectedFrom.forEach((playerSocketId) => {
|
||||||
|
const playerSocket = io.sockets.sockets.get(playerSocketId);
|
||||||
|
if (playerSocket) {
|
||||||
|
expectedActions.forEach((expectedAction) => {
|
||||||
|
const [actionName] = expectedAction;
|
||||||
|
|
||||||
|
const eventListener = eventListeners.get(
|
||||||
|
`${playerSocketId}-${actionName}`
|
||||||
|
);
|
||||||
|
if (eventListener) {
|
||||||
|
playerSocket.off(actionName, eventListener);
|
||||||
|
eventListeners.delete(`${playerSocketId}-${actionName}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise<PlayerAction<ActionDataType>>((resolve) => {
|
||||||
|
addPlayerActionListeners(resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendObfuscatedGameUpdate() {
|
||||||
|
// console.trace("sendObfuscatedGameUpdate");
|
||||||
|
this.updatePlayerRoundPoints();
|
||||||
|
const obfuscatedGame: ObfuscatedGame = {
|
||||||
|
sessionId: this.sessionId,
|
||||||
|
playerCount: this.playerCount,
|
||||||
|
phase: this.phase,
|
||||||
|
round: this.round,
|
||||||
|
discardPile: this.discardPile,
|
||||||
|
players: this.players.map(({ cards, ...player }) => {
|
||||||
|
return {
|
||||||
|
id: player.id,
|
||||||
|
socketId: player.socketId,
|
||||||
|
name: player.name,
|
||||||
|
playersTurn: player.playersTurn,
|
||||||
|
cardCache: player.cardCache,
|
||||||
|
tookDispiledCard: player.tookDispiledCard,
|
||||||
|
knownCardPositions: player.knownCardPositions,
|
||||||
|
roundPoints: player.roundPoints,
|
||||||
|
totalPoints: player.totalPoints,
|
||||||
|
closedRound: player.closedRound,
|
||||||
|
cards: cards.map((card: Card, index: number) => {
|
||||||
|
// unknown cards are obfuscated to 0
|
||||||
|
return {
|
||||||
|
id: player.knownCardPositions[index] ? card.id : 0,
|
||||||
|
value: player.knownCardPositions[index] ? card.value : "X",
|
||||||
|
name: player.knownCardPositions[index]
|
||||||
|
? card.name
|
||||||
|
: "Facedown Card",
|
||||||
|
color: player.knownCardPositions[index] ? card.color : "black",
|
||||||
|
matchColorToCardValue: card.matchColorToCardValue,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
cardStack: {
|
||||||
|
cards: this.cardStack.cards.map((card: Card) => {
|
||||||
|
// player may not see the value of the facedown cards in the cardStack
|
||||||
|
return {
|
||||||
|
id: 0,
|
||||||
|
value: "X",
|
||||||
|
name: "Facedown Card",
|
||||||
|
color: "black",
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log("Sending game update");
|
||||||
|
io.to(this.sessionId).emit("game-update", obfuscatedGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePlayerRoundPoints() {
|
||||||
|
this.players.forEach((player) => {
|
||||||
|
const revealedCardValuesSum = player.getRevealedCardsValueSum();
|
||||||
|
const threeOfAKinds = player.getThreeOfAKinds();
|
||||||
|
const threeOfAKindPoints = threeOfAKinds.reduce(
|
||||||
|
(points, threeOfAKind) => points + threeOfAKind.value * 3,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
player.roundPoints = revealedCardValuesSum - threeOfAKindPoints;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlayersWithLowestPoints(): Player[] {
|
||||||
|
this.updatePlayerRoundPoints();
|
||||||
|
const lowestScore = Math.min(
|
||||||
|
...this.players.map((player) => player.roundPoints)
|
||||||
|
);
|
||||||
|
const playersWithLowestPoints = this.players.filter(
|
||||||
|
(player) => player.roundPoints === lowestScore
|
||||||
|
);
|
||||||
|
return playersWithLowestPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluateAndSavePoints() {
|
||||||
|
const playersWithLowestPoints = this.getPlayersWithLowestPoints();
|
||||||
|
const playerClosedRound = this.getPlayerThatClosedRound();
|
||||||
|
if (
|
||||||
|
playersWithLowestPoints.includes(playerClosedRound) &&
|
||||||
|
playersWithLowestPoints.length === 1
|
||||||
|
) {
|
||||||
|
this.sendMessageToAllPlayers(`${playerClosedRound.name} won the round!`);
|
||||||
|
this.players.forEach((player) => {
|
||||||
|
player.totalPoints += player.roundPoints;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (playersWithLowestPoints.length === 1) {
|
||||||
|
this.sendMessageToAllPlayers(
|
||||||
|
`${playersWithLowestPoints[0].name} won the round!`
|
||||||
|
);
|
||||||
|
} else if (playersWithLowestPoints.length > 1) {
|
||||||
|
this.sendMessageToAllPlayers(
|
||||||
|
`${playersWithLowestPoints
|
||||||
|
.map((player) => player.name)
|
||||||
|
.join(", ")} scored equally the lowest points!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.players.forEach((player) => {
|
||||||
|
if (player.closedRound) player.totalPoints += player.roundPoints * 2;
|
||||||
|
else player.totalPoints += player.roundPoints;
|
||||||
|
});
|
||||||
|
this.sendMessageToAllPlayers(
|
||||||
|
`${playerClosedRound.name} points are doubled!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForFullRevealedCards() {
|
||||||
|
const alreadyClosedPlayers = this.players.filter(
|
||||||
|
(player) => player.closedRound
|
||||||
|
);
|
||||||
|
if (alreadyClosedPlayers) return;
|
||||||
|
|
||||||
|
const playerWithAllCardsRevealed = this.players.find((player) =>
|
||||||
|
player.knownCardPositions.every(
|
||||||
|
(knownCardPosition) => knownCardPosition === true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (playerWithAllCardsRevealed) {
|
||||||
|
playerWithAllCardsRevealed.closedRound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
revealAllCards() {
|
||||||
|
this.players.forEach((player) => {
|
||||||
|
player.knownCardPositions = player.knownCardPositions.map(
|
||||||
|
(knownCardPosition) => true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
getPlayersWithRevealedInitialCards(): Player[] {
|
getPlayersWithRevealedInitialCards(): Player[] {
|
||||||
return this.players.filter((player) => {
|
return this.players.filter((player) => {
|
||||||
return player.hasInitialCardsRevealed();
|
return player.hasInitialCardsRevealed();
|
||||||
|
|
@ -175,195 +563,35 @@ export class Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPlayersTurn() {
|
nextPlayersTurn() {
|
||||||
const playersTurn = this.players.find((player) => player.playersTurn);
|
const playerOnTurn = this.getPlayersTurn();
|
||||||
const playersTurnIndex = this.players.indexOf(playersTurn!);
|
const playersTurnIndex = this.players.indexOf(playerOnTurn);
|
||||||
const nextPlayersTurnIndex = (playersTurnIndex + 1) % this.playerCount;
|
const nextPlayersTurnIndex = (playersTurnIndex + 1) % this.playerCount;
|
||||||
this.players[playersTurnIndex].playersTurn = false;
|
this.players[playersTurnIndex].playersTurn = false;
|
||||||
this.players[nextPlayersTurnIndex].playersTurn = true;
|
this.players[nextPlayersTurnIndex].playersTurn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayerBySocketId(playerSocketId: string): Player | undefined {
|
getPlayersTurn(): Player {
|
||||||
return this.players.find((player) => player.socketId === playerSocketId);
|
const playerOnTurn = this.players.find(
|
||||||
}
|
(player) => player.playersTurn === true
|
||||||
|
|
||||||
revealCardAction(playerSocketId: string, cardPosition: number) {
|
|
||||||
const player = this.getPlayerBySocketId(playerSocketId)!; // TODO: handle player not found
|
|
||||||
const revealedCard = player.cards[cardPosition];
|
|
||||||
console.log(`Revealed card ${revealedCard} at position ${cardPosition}`);
|
|
||||||
const playerIndex = this.players.indexOf(player!);
|
|
||||||
this.players[playerIndex].knownCardPositions[cardPosition] = true;
|
|
||||||
this.sendObfuscatedGameUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
async revealInitialCards() {
|
|
||||||
while (!this.allPlayersRevealedInitialCards()) {
|
|
||||||
const playersWithRevealedInitialCards =
|
|
||||||
this.getPlayersWithRevealedInitialCards();
|
|
||||||
const playersWithUnrevealedInitialCards = this.players.filter(
|
|
||||||
(player) => !playersWithRevealedInitialCards.includes(player)
|
|
||||||
);
|
|
||||||
const playersSocketIds = playersWithUnrevealedInitialCards.map(
|
|
||||||
(player) => player.socketId
|
|
||||||
);
|
|
||||||
await this.waitForPlayerActions(
|
|
||||||
[["click-card", this.revealCardAction.bind(this)]],
|
|
||||||
playersSocketIds
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.setInitialPlayersTurn();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawCardAction(playerSocketId: string, data: any) {
|
|
||||||
const player = this.getPlayerBySocketId(playerSocketId)!; // TODO: handle player not found
|
|
||||||
console.log(`Player ${player.name} drawed a card.`);
|
|
||||||
const drawnCard = this.cardStack.cards.pop()!;
|
|
||||||
player.cardCache = drawnCard;
|
|
||||||
this.sendObfuscatedGameUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
takeDiscardPileAction(playerSocketId: string, data: any) {
|
|
||||||
const player = this.getPlayerBySocketId(playerSocketId)!; // TODO: handle player not found
|
|
||||||
console.log(`Player ${player.name} took the card from discard pile.`);
|
|
||||||
const discardPileCard = this.discardPile.pop()!;
|
|
||||||
player.cardCache = discardPileCard;
|
|
||||||
this.sendObfuscatedGameUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
discardCardToPileAction(playerSocketId: string, data: any) {
|
|
||||||
const player = this.getPlayerBySocketId(playerSocketId)!; // TODO: handle player not found
|
|
||||||
console.log(`Player ${player.name} discarded a card to the pile.`);
|
|
||||||
const discardedCard = player.cardCache!;
|
|
||||||
this.discardPile.push(discardedCard);
|
|
||||||
player.cardCache = null;
|
|
||||||
this.sendObfuscatedGameUpdate();
|
|
||||||
this.phase = gamePhase.revealCard;
|
|
||||||
}
|
|
||||||
|
|
||||||
placeCardAction(playerSocketId: string, cardPosition: number) {
|
|
||||||
const player = this.getPlayerBySocketId(playerSocketId)!; // TODO: handle player not found
|
|
||||||
console.log(`Player ${player.name} placed a card.`);
|
|
||||||
const placedCard = player.cardCache!;
|
|
||||||
player.cardCache = null;
|
|
||||||
const replacedCard = player.cards[cardPosition];
|
|
||||||
this.discardPile.push(replacedCard);
|
|
||||||
player.cards[cardPosition] = placedCard;
|
|
||||||
player.knownCardPositions[cardPosition] = true;
|
|
||||||
this.nextPlayersTurn();
|
|
||||||
this.phase = gamePhase.pickUpCard;
|
|
||||||
this.sendObfuscatedGameUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
async pickUpCard() {
|
|
||||||
const playersTurn = this.players.find((player) => player.playersTurn);
|
|
||||||
console.log(`Waiting for ${playersTurn?.name} to pick up card`);
|
|
||||||
await this.waitForPlayerActions(
|
|
||||||
[
|
|
||||||
["draw-from-card-stack", this.drawCardAction.bind(this)],
|
|
||||||
["click-discard-pile", this.takeDiscardPileAction.bind(this)],
|
|
||||||
],
|
|
||||||
[playersTurn!.socketId]
|
|
||||||
);
|
);
|
||||||
|
if (playerOnTurn) return playerOnTurn;
|
||||||
|
else throw new Error("No player on turn found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
async placeCard(tookDiscardPileCard: boolean = false) {
|
getPlayerThatClosedRound(): Player {
|
||||||
console.log("Waiting for player to place card");
|
const playerThatClosedRound = this.players.find(
|
||||||
const playersTurn = this.players.find((player) => player.playersTurn);
|
(player) => player.closedRound === true
|
||||||
const allowedActions: PlayerActions = [
|
|
||||||
["click-card", this.placeCardAction.bind(this)],
|
|
||||||
];
|
|
||||||
if (!tookDiscardPileCard) {
|
|
||||||
allowedActions.push([
|
|
||||||
"click-discard-pile",
|
|
||||||
this.discardCardToPileAction.bind(this),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
await this.waitForPlayerActions(allowedActions, [playersTurn!.socketId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async revealCard() {
|
|
||||||
console.log("Waiting for player to reveal a card");
|
|
||||||
const playersTurn = this.players.find((player) => player.playersTurn);
|
|
||||||
await this.waitForPlayerActions(
|
|
||||||
[["click-card", this.revealCardAction.bind(this)]],
|
|
||||||
[playersTurn!.socketId]
|
|
||||||
);
|
);
|
||||||
this.nextPlayersTurn();
|
if (playerThatClosedRound) return playerThatClosedRound;
|
||||||
|
else throw new Error("No player that closed the round found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForPlayerActions(
|
getPlayerBySocketId(playerSocketId: string): Player {
|
||||||
expectedActions: PlayerActions,
|
const player = this.players.find(
|
||||||
expectedFrom: Player["socketId"][]
|
(player) => player.socketId === playerSocketId
|
||||||
): Promise<void> {
|
);
|
||||||
return new Promise<void>((resolve) => {
|
if (player) return player;
|
||||||
const eventListeners: Array<(playerSocketId: string, data: any) => void> =
|
else throw new Error(`No player with socketId ${playerSocketId} found!`);
|
||||||
[];
|
|
||||||
expectedFrom.forEach((playerSocketId) => {
|
|
||||||
const playerSocket = io.sockets.sockets.get(playerSocketId);
|
|
||||||
if (playerSocket) {
|
|
||||||
expectedActions.forEach((expectedAction) => {
|
|
||||||
const [actionName, processAction] = expectedAction;
|
|
||||||
const eventListener = (data: any) => {
|
|
||||||
console.log(`Received ${actionName} from ${playerSocketId}`);
|
|
||||||
processAction(playerSocketId, data);
|
|
||||||
// remove current and event listeners of alternative expected actions
|
|
||||||
eventListeners.forEach((eventListener) => {
|
|
||||||
playerSocket.off(actionName, eventListener);
|
|
||||||
});
|
|
||||||
resolve(data);
|
|
||||||
};
|
|
||||||
playerSocket.on(actionName, eventListener);
|
|
||||||
eventListeners.push(eventListener);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// TODO: handle error
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sendObfuscatedGameUpdate() {
|
|
||||||
// console.trace("sendObfuscatedGameUpdate");
|
|
||||||
const obfuscatedGame: ObfuscatedGame = {
|
|
||||||
sessionId: this.sessionId,
|
|
||||||
playerCount: this.playerCount,
|
|
||||||
players: this.players.map((player: Player) => {
|
|
||||||
return {
|
|
||||||
id: player.id,
|
|
||||||
socketId: player.socketId,
|
|
||||||
name: player.name,
|
|
||||||
cards: player.cards.map((card: Card, index: number) => {
|
|
||||||
// unknown cards are obfuscated to 0
|
|
||||||
return {
|
|
||||||
id: player.knownCardPositions[index] ? card.id : 0,
|
|
||||||
value: player.knownCardPositions[index] ? card.value : "X",
|
|
||||||
name: player.knownCardPositions[index]
|
|
||||||
? card.name
|
|
||||||
: "Facedown Card",
|
|
||||||
color: player.knownCardPositions[index] ? card.color : "black",
|
|
||||||
matchColorToCardValue: card.matchColorToCardValue,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
knownCardPositions: player.knownCardPositions,
|
|
||||||
playersTurn: player.playersTurn,
|
|
||||||
cardCache: player.cardCache,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
cardStack: {
|
|
||||||
cards: this.cardStack.cards.map((card: Card) => {
|
|
||||||
// player may not see the value of the facedown cards in the cardStack
|
|
||||||
return {
|
|
||||||
id: 0,
|
|
||||||
value: "X",
|
|
||||||
name: "Facedown Card",
|
|
||||||
color: "black",
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
discardPile: this.discardPile,
|
|
||||||
phase: this.phase,
|
|
||||||
};
|
|
||||||
console.log("Sending game update");
|
|
||||||
io.to(this.sessionId).emit("game-update", obfuscatedGame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listPlayerSocketListeners() {
|
listPlayerSocketListeners() {
|
||||||
|
|
@ -375,4 +603,9 @@ export class Game {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendMessageToAllPlayers(message: string) {
|
||||||
|
io.to(this.sessionId).emit("message", message);
|
||||||
|
console.log(`Sent Message (Session): ${message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,26 @@ export type ObfuscatedPlayer = {
|
||||||
knownCardPositions: boolean[];
|
knownCardPositions: boolean[];
|
||||||
playersTurn: boolean;
|
playersTurn: boolean;
|
||||||
cardCache: Card | null;
|
cardCache: Card | null;
|
||||||
|
tookDispiledCard: boolean;
|
||||||
|
roundPoints: number;
|
||||||
|
totalPoints: number;
|
||||||
|
closedRound: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ColumnPosition = [number, number, number];
|
||||||
|
|
||||||
|
type ThreeOfAKind = {
|
||||||
|
position: ColumnPosition;
|
||||||
|
value: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const COLUMN_POSITIONS: ColumnPosition[] = [
|
||||||
|
[0, 4, 8],
|
||||||
|
[1, 5, 9],
|
||||||
|
[2, 6, 10],
|
||||||
|
[3, 7, 11],
|
||||||
|
];
|
||||||
|
|
||||||
export class Player {
|
export class Player {
|
||||||
id: number;
|
id: number;
|
||||||
socketId: string;
|
socketId: string;
|
||||||
|
|
@ -18,6 +36,10 @@ export class Player {
|
||||||
knownCardPositions: boolean[];
|
knownCardPositions: boolean[];
|
||||||
playersTurn: boolean;
|
playersTurn: boolean;
|
||||||
cardCache: Card | null; // this is where the card is temporarily stored when a player draws a card
|
cardCache: Card | null; // this is where the card is temporarily stored when a player draws a card
|
||||||
|
tookDispiledCard: boolean; // this is used to check if a player took a dispiled card in the current turn
|
||||||
|
roundPoints: number;
|
||||||
|
totalPoints: number;
|
||||||
|
closedRound: boolean;
|
||||||
constructor(id: number, socketId: string, name: string, cards: Card[]) {
|
constructor(id: number, socketId: string, name: string, cards: Card[]) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.socketId = socketId;
|
this.socketId = socketId;
|
||||||
|
|
@ -26,6 +48,10 @@ export class Player {
|
||||||
this.knownCardPositions = new Array(12).fill(false);
|
this.knownCardPositions = new Array(12).fill(false);
|
||||||
this.playersTurn = true;
|
this.playersTurn = true;
|
||||||
this.cardCache = null;
|
this.cardCache = null;
|
||||||
|
this.tookDispiledCard = false;
|
||||||
|
this.roundPoints = 0;
|
||||||
|
this.totalPoints = 0;
|
||||||
|
this.closedRound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasInitialCardsRevealed(): boolean {
|
hasInitialCardsRevealed(): boolean {
|
||||||
|
|
@ -40,6 +66,28 @@ export class Player {
|
||||||
return this.knownCardPositions.filter((position) => position).length;
|
return this.knownCardPositions.filter((position) => position).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getThreeOfAKinds(): ThreeOfAKind[] {
|
||||||
|
const revealedCardPositions = this.getRevealedCardPositions();
|
||||||
|
const columns: ColumnPosition[] = COLUMN_POSITIONS;
|
||||||
|
const threeOfAKinds: ThreeOfAKind[] = [];
|
||||||
|
columns.forEach((column) => {
|
||||||
|
const columnValues = column.map((position) => this.cards[position].value);
|
||||||
|
const columnHasSameValues = columnValues.every(
|
||||||
|
(value) => value === columnValues[0]
|
||||||
|
);
|
||||||
|
const columnIsRevealed = column.every((position) =>
|
||||||
|
revealedCardPositions.includes(position)
|
||||||
|
);
|
||||||
|
if (columnHasSameValues && columnIsRevealed) {
|
||||||
|
threeOfAKinds.push({
|
||||||
|
position: column,
|
||||||
|
value: columnValues[0],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return threeOfAKinds;
|
||||||
|
}
|
||||||
|
|
||||||
getRevealedCardPositions(): number[] {
|
getRevealedCardPositions(): number[] {
|
||||||
const revealedCardPositions: number[] = [];
|
const revealedCardPositions: number[] = [];
|
||||||
this.knownCardPositions.forEach((position, index) => {
|
this.knownCardPositions.forEach((position, index) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue