diff --git a/client/Dockerfile b/client/Dockerfile
index e55360b2..297ddadf 100644
--- a/client/Dockerfile
+++ b/client/Dockerfile
@@ -1,4 +1,4 @@
-ARG NODE_VERSION=17
+ARG NODE_VERSION=18
ARG MODE=production
ARG BUILD_DATE
ARG VCS_REF
diff --git a/client/Dockerfile.dev b/client/Dockerfile.dev
index 9141fe8a..530f6d5c 100644
--- a/client/Dockerfile.dev
+++ b/client/Dockerfile.dev
@@ -1,4 +1,4 @@
-ARG NODE_VERSION=17
+ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine
diff --git a/client/package-lock.json b/client/package-lock.json
index 9fd216ce..e6652e27 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -34,18 +34,17 @@
"@types/chromecast-caf-sender": "^1.0.3",
"ajv": "^8.8.2",
"app-manifest-loader": "^2.4.1",
- "chromecast-device-emulator": "^1.2.7",
+ "chromecast-device-emulator": "^1.1.2",
"compression-webpack-plugin": "^10.0.0",
"css-hot-loader": "^1.4.4",
"css-loader": "^6.3.0",
"cssnano": "^5.0.5",
"elm": "^0.19.1-3",
"elm-analyse": "^0.16.5",
- "elm-hot-webpack-loader": "^1.1.7",
"elm-webpack-loader": "^8.0.0",
"extract-loader": "^5.1.0",
- "fibers": "^5.0.0",
"file-loader": "^6.2.0",
+ "html-loader": "^3.1.0",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^2.3.0",
"postcss-import": "^14.0.0",
@@ -59,7 +58,6 @@
"style-loader": "^3.3.0",
"terser-webpack-plugin": "^5.0.3",
"ts-loader": "^9.2.6",
- "tsickle-loader": "^0.5.0",
"typescript": "^4.1.3",
"webpack": "^5.56.1",
"webpack-cli": "^4.3.1",
@@ -4283,32 +4281,12 @@
}
},
"node_modules/chromecast-device-emulator": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/chromecast-device-emulator/-/chromecast-device-emulator-1.2.7.tgz",
- "integrity": "sha512-A93dyExP1j/Ho/n5Sqrm3uqvzFBsI5jmFrJRnqXt6nHAKDvK/mg+722R3V+OaGieWXiZmgVpi4snF6PrnNpVhw==",
- "dev": true,
- "dependencies": {
- "ajv": "^4.11.8",
- "chalk": "^2.4.1",
- "commander": "^2.15.1",
- "ws": "^5.2.0"
- },
- "bin": {
- "cde": "dist/cli/index.js",
- "chromecast-device-emulator": "dist/cli/index.js"
- },
- "engines": {
- "node": ">= 6.9.0"
- }
- },
- "node_modules/chromecast-device-emulator/node_modules/ajv": {
- "version": "4.11.8",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
- "integrity": "sha512-I/bSHSNEcFFqXLf91nchoNB9D1Kie3QKcWdchYUaoIg1+1bdWDkdfdlvdIOJbi9U8xR0y+MWc5D+won9v95WlQ==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/chromecast-device-emulator/-/chromecast-device-emulator-1.1.2.tgz",
+ "integrity": "sha512-VNaYLHsUatBtXy7uhueaQfY8yVJ87l/CUrkuGbDSrLNtAPa3DZSeurw5csfjx9Z+bgfd5WFmHM4yfcAVriM4+w==",
"dev": true,
"dependencies": {
- "co": "^4.6.0",
- "json-stable-stringify": "^1.0.1"
+ "ws": "^2.3.1"
}
},
"node_modules/clean-css": {
@@ -4346,16 +4324,6 @@
"node": ">=6"
}
},
- "node_modules/co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
- "dev": true,
- "engines": {
- "iojs": ">= 1.0.0",
- "node": ">= 0.12.0"
- }
- },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -4768,12 +4736,12 @@
}
},
"node_modules/cssnano": {
- "version": "5.1.8",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.8.tgz",
- "integrity": "sha512-5lma/yQlK+6eOHSUqNAS11b4/fbiuasoxmCHoVYxSg6lQsyX7bGGIqiLi4o3Pe2CrUTrgcD2udW7JIgzC2806g==",
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.9.tgz",
+ "integrity": "sha512-hctQHIIeDrfMjq0bQhoVmRVaSeNNOGxkvkKVOcKpJzLr09wlRrZWH4GaYudp0aszpW8wJeaO5/yBmID9n7DNCg==",
"dev": true,
"dependencies": {
- "cssnano-preset-default": "^5.2.8",
+ "cssnano-preset-default": "^5.2.9",
"lilconfig": "^2.0.3",
"yaml": "^1.10.2"
},
@@ -4789,9 +4757,9 @@
}
},
"node_modules/cssnano-preset-default": {
- "version": "5.2.8",
- "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.8.tgz",
- "integrity": "sha512-6xQXUhTAPupvib3KC0Gl0d1jIwGFcJyuWQiMcA6grprGdmIzt1cxG5z78VuZu6DRRS6qin6ETkQsH6ixxb/SQw==",
+ "version": "5.2.9",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.9.tgz",
+ "integrity": "sha512-/4qcQcAfFEg+gnXE5NxKmYJ9JcT+8S5SDuJCLYMDN8sM/ymZ+lgLXq5+ohx/7V2brUCkgW2OaoCzOdAN0zvhGw==",
"dev": true,
"dependencies": {
"css-declaration-sorter": "^6.2.2",
@@ -4803,7 +4771,7 @@
"postcss-discard-duplicates": "^5.1.0",
"postcss-discard-empty": "^5.1.1",
"postcss-discard-overridden": "^5.1.0",
- "postcss-merge-longhand": "^5.1.4",
+ "postcss-merge-longhand": "^5.1.5",
"postcss-merge-rules": "^5.1.1",
"postcss-minify-font-values": "^5.1.0",
"postcss-minify-gradients": "^5.1.1",
@@ -4938,6 +4906,8 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
+ "optional": true,
+ "peer": true,
"bin": {
"detect-libc": "bin/detect-libc.js"
},
@@ -5209,24 +5179,6 @@
"elm-format": "bin/elm-format"
}
},
- "node_modules/elm-hot": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/elm-hot/-/elm-hot-1.1.6.tgz",
- "integrity": "sha512-zYZJlfs7Gt4BdjA+D+857K+XAWzwwySJmXCgFpHW1dIEfaHSZCIPYPf7/jinZBLfKRkOAlKzI32AA84DY50g7Q==",
- "dev": true
- },
- "node_modules/elm-hot-webpack-loader": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/elm-hot-webpack-loader/-/elm-hot-webpack-loader-1.1.8.tgz",
- "integrity": "sha512-QXggtyhzeg7ioV8Ujoc6elFY+QYr49hFEb5EDcZP7976w62vjfqFX8YTa73alA+ayLT00ZsIU6eFjAzvLUzF0g==",
- "dev": true,
- "dependencies": {
- "elm-hot": "^1.1.6"
- },
- "peerDependencies": {
- "elm-webpack-loader": "^7.0.1"
- }
- },
"node_modules/elm-webpack-loader": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/elm-webpack-loader/-/elm-webpack-loader-8.0.0.tgz",
@@ -5764,6 +5716,8 @@
"integrity": "sha512-VMC7Frt87Oo0AOJ6EcPFbi+tZmkQ4tD85aatwyWL6I9cYMJmm2e+pXUJsfGZ36U7MffXtjou2XIiWJMtHriErw==",
"dev": true,
"hasInstallScript": true,
+ "optional": true,
+ "peer": true,
"dependencies": {
"detect-libc": "^1.0.3"
},
@@ -6304,6 +6258,26 @@
"integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==",
"dev": true
},
+ "node_modules/html-loader": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-3.1.0.tgz",
+ "integrity": "sha512-ycMYFRiCF7YANcLDNP72kh3Po5pTcH+bROzdDwh00iVOAY/BwvpuZ1BKPziQ35Dk9D+UD84VGX1Lu/H4HpO4fw==",
+ "dev": true,
+ "dependencies": {
+ "html-minifier-terser": "^6.0.2",
+ "parse5": "^6.0.1"
+ },
+ "engines": {
+ "node": ">= 12.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.0.0"
+ }
+ },
"node_modules/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -6840,15 +6814,6 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
- "node_modules/json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true,
- "dependencies": {
- "jsonify": "~0.0.0"
- }
- },
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -6873,15 +6838,6 @@
"graceful-fs": "^4.1.6"
}
},
- "node_modules/jsonify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
- "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
"node_modules/jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@@ -7679,6 +7635,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse5": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+ "dev": true
+ },
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -8295,9 +8257,9 @@
}
},
"node_modules/postcss-merge-longhand": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz",
- "integrity": "sha512-hbqRRqYfmXoGpzYKeW0/NCZhvNyQIlQeWVSao5iKWdyx7skLvCfQFGIUsP9NUs3dSbPac2IC4Go85/zG+7MlmA==",
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.5.tgz",
+ "integrity": "sha512-NOG1grw9wIO+60arKa2YYsrbgvP6tp+jqc7+ZD5/MalIw234ooH2C6KlR6FEn4yle7GqZoBxSK1mLBE9KPur6w==",
"dev": true,
"dependencies": {
"postcss-value-parser": "^4.2.0",
@@ -9523,9 +9485,9 @@
"dev": true
},
"node_modules/sass": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.0.tgz",
- "integrity": "sha512-6EnTglag2oVD8sNJCxUi2Jd3ICH9tJ5Mqudt/gIZNBR2uKJUBZuTpW9O1t04SkDLP7VFa76FCWTV2rwchqM8Kw==",
+ "version": "1.52.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
+ "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
@@ -10629,69 +10591,6 @@
"node": ">=8"
}
},
- "node_modules/tsickle": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.34.3.tgz",
- "integrity": "sha512-mb1v3nsr6rYaZky22xj0d6qv4ogAR40Bc6r37jwWOg3bEIO/ZppEFZiEADs/NNVLcWTPgmNmPZgaX5CfAH6oXA==",
- "dev": true,
- "dependencies": {
- "minimist": "^1.2.0",
- "mkdirp": "^0.5.1",
- "source-map": "^0.7.3"
- },
- "bin": {
- "tsickle": "src/main.js"
- },
- "peerDependencies": {
- "typescript": "~3.3.1"
- }
- },
- "node_modules/tsickle-loader": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/tsickle-loader/-/tsickle-loader-0.5.0.tgz",
- "integrity": "sha512-VzJCouScljE7JB40bQo9fOu0Rrw8pCIfj8tkTA8kdvQWbDEskdPrPyEnHTpRHyrnIo0zw+TrJnxnrSL+fH//nQ==",
- "dev": true,
- "dependencies": {
- "fs-extra": "^7.0.1",
- "tsickle": "^0.34.3"
- },
- "peerDependencies": {
- "typescript": "~3.3.1",
- "webpack": "^4.29.1"
- }
- },
- "node_modules/tsickle-loader/node_modules/fs-extra": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
- "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- },
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
- "node_modules/tsickle-loader/node_modules/jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "dev": true,
- "optionalDependencies": {
- "graceful-fs": "^4.1.6"
- }
- },
- "node_modules/tsickle/node_modules/source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
@@ -10765,15 +10664,6 @@
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
"dev": true
},
- "node_modules/universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
- "dev": true,
- "engines": {
- "node": ">= 4.0.0"
- }
- },
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -11564,14 +11454,21 @@
"dev": true
},
"node_modules/ws": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz",
- "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz",
+ "integrity": "sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=",
"dev": true,
"dependencies": {
- "async-limiter": "~1.0.0"
+ "safe-buffer": "~5.0.1",
+ "ultron": "~1.1.0"
}
},
+ "node_modules/ws/node_modules/safe-buffer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+ "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=",
+ "dev": true
+ },
"node_modules/xml-js": {
"version": "1.6.11",
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
@@ -11752,13 +11649,15 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.1.tgz",
"integrity": "sha512-f1G1WGDXEU/RN1TWAxBPQgQudtLnLQPyiWdtypkPC+mVYNKFKH/HYXSxH4MVNqwF8M0eDsoiU7HumJHCg/L/jg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@csstools/selector-specificity": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-1.0.0.tgz",
"integrity": "sha512-RkYG5KiGNX0fJ5YoI0f4Wfq2Yo74D25Hru4fxTOioYdQvHBxcrrtTTyT5Ozzh2ejcNrhFy7IEts2WyEY7yi5yw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@discoveryjs/json-ext": {
"version": "0.5.7",
@@ -14348,7 +14247,8 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz",
"integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@webpack-cli/info": {
"version": "1.4.1",
@@ -14363,7 +14263,8 @@
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz",
"integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@xtuc/ieee754": {
"version": "1.2.0",
@@ -14397,7 +14298,8 @@
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"adjust-sourcemap-loader": {
"version": "4.0.0",
@@ -15536,27 +15438,12 @@
"dev": true
},
"chromecast-device-emulator": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/chromecast-device-emulator/-/chromecast-device-emulator-1.2.7.tgz",
- "integrity": "sha512-A93dyExP1j/Ho/n5Sqrm3uqvzFBsI5jmFrJRnqXt6nHAKDvK/mg+722R3V+OaGieWXiZmgVpi4snF6PrnNpVhw==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/chromecast-device-emulator/-/chromecast-device-emulator-1.1.2.tgz",
+ "integrity": "sha512-VNaYLHsUatBtXy7uhueaQfY8yVJ87l/CUrkuGbDSrLNtAPa3DZSeurw5csfjx9Z+bgfd5WFmHM4yfcAVriM4+w==",
"dev": true,
"requires": {
- "ajv": "^4.11.8",
- "chalk": "^2.4.1",
- "commander": "^2.15.1",
- "ws": "^5.2.0"
- },
- "dependencies": {
- "ajv": {
- "version": "4.11.8",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
- "integrity": "sha512-I/bSHSNEcFFqXLf91nchoNB9D1Kie3QKcWdchYUaoIg1+1bdWDkdfdlvdIOJbi9U8xR0y+MWc5D+won9v95WlQ==",
- "dev": true,
- "requires": {
- "co": "^4.6.0",
- "json-stable-stringify": "^1.0.1"
- }
- }
+ "ws": "^2.3.1"
}
},
"clean-css": {
@@ -15587,12 +15474,6 @@
"shallow-clone": "^3.0.0"
}
},
- "co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
- "dev": true
- },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -15798,7 +15679,8 @@
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz",
"integrity": "sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"css-has-pseudo": {
"version": "3.0.4",
@@ -15840,7 +15722,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz",
"integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"css-select": {
"version": "4.3.0",
@@ -15892,20 +15775,20 @@
"dev": true
},
"cssnano": {
- "version": "5.1.8",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.8.tgz",
- "integrity": "sha512-5lma/yQlK+6eOHSUqNAS11b4/fbiuasoxmCHoVYxSg6lQsyX7bGGIqiLi4o3Pe2CrUTrgcD2udW7JIgzC2806g==",
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.9.tgz",
+ "integrity": "sha512-hctQHIIeDrfMjq0bQhoVmRVaSeNNOGxkvkKVOcKpJzLr09wlRrZWH4GaYudp0aszpW8wJeaO5/yBmID9n7DNCg==",
"dev": true,
"requires": {
- "cssnano-preset-default": "^5.2.8",
+ "cssnano-preset-default": "^5.2.9",
"lilconfig": "^2.0.3",
"yaml": "^1.10.2"
}
},
"cssnano-preset-default": {
- "version": "5.2.8",
- "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.8.tgz",
- "integrity": "sha512-6xQXUhTAPupvib3KC0Gl0d1jIwGFcJyuWQiMcA6grprGdmIzt1cxG5z78VuZu6DRRS6qin6ETkQsH6ixxb/SQw==",
+ "version": "5.2.9",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.9.tgz",
+ "integrity": "sha512-/4qcQcAfFEg+gnXE5NxKmYJ9JcT+8S5SDuJCLYMDN8sM/ymZ+lgLXq5+ohx/7V2brUCkgW2OaoCzOdAN0zvhGw==",
"dev": true,
"requires": {
"css-declaration-sorter": "^6.2.2",
@@ -15917,7 +15800,7 @@
"postcss-discard-duplicates": "^5.1.0",
"postcss-discard-empty": "^5.1.1",
"postcss-discard-overridden": "^5.1.0",
- "postcss-merge-longhand": "^5.1.4",
+ "postcss-merge-longhand": "^5.1.5",
"postcss-merge-rules": "^5.1.1",
"postcss-minify-font-values": "^5.1.0",
"postcss-minify-gradients": "^5.1.1",
@@ -15943,7 +15826,8 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
"integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"csso": {
"version": "4.2.0",
@@ -16018,7 +15902,9 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"detect-node": {
"version": "2.1.0",
@@ -16229,21 +16115,6 @@
"binwrap": "^0.2.3"
}
},
- "elm-hot": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/elm-hot/-/elm-hot-1.1.6.tgz",
- "integrity": "sha512-zYZJlfs7Gt4BdjA+D+857K+XAWzwwySJmXCgFpHW1dIEfaHSZCIPYPf7/jinZBLfKRkOAlKzI32AA84DY50g7Q==",
- "dev": true
- },
- "elm-hot-webpack-loader": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/elm-hot-webpack-loader/-/elm-hot-webpack-loader-1.1.8.tgz",
- "integrity": "sha512-QXggtyhzeg7ioV8Ujoc6elFY+QYr49hFEb5EDcZP7976w62vjfqFX8YTa73alA+ayLT00ZsIU6eFjAzvLUzF0g==",
- "dev": true,
- "requires": {
- "elm-hot": "^1.1.6"
- }
- },
"elm-webpack-loader": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/elm-webpack-loader/-/elm-webpack-loader-8.0.0.tgz",
@@ -16669,6 +16540,8 @@
"resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.1.tgz",
"integrity": "sha512-VMC7Frt87Oo0AOJ6EcPFbi+tZmkQ4tD85aatwyWL6I9cYMJmm2e+pXUJsfGZ36U7MffXtjou2XIiWJMtHriErw==",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"detect-libc": "^1.0.3"
}
@@ -16699,7 +16572,8 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -17062,6 +16936,16 @@
"integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==",
"dev": true
},
+ "html-loader": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-3.1.0.tgz",
+ "integrity": "sha512-ycMYFRiCF7YANcLDNP72kh3Po5pTcH+bROzdDwh00iVOAY/BwvpuZ1BKPziQ35Dk9D+UD84VGX1Lu/H4HpO4fw==",
+ "dev": true,
+ "requires": {
+ "html-minifier-terser": "^6.0.2",
+ "parse5": "^6.0.1"
+ }
+ },
"html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -17211,7 +17095,8 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"immutable": {
"version": "4.0.0",
@@ -17454,15 +17339,6 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
- "json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true,
- "requires": {
- "jsonify": "~0.0.0"
- }
- },
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -17484,12 +17360,6 @@
"graceful-fs": "^4.1.6"
}
},
- "jsonify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
- "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
- "dev": true
- },
"jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@@ -18107,6 +17977,12 @@
"lines-and-columns": "^1.1.6"
}
},
+ "parse5": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+ "dev": true
+ },
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -18314,7 +18190,8 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz",
"integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-custom-properties": {
"version": "12.1.7",
@@ -18347,25 +18224,29 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz",
"integrity": "sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-discard-duplicates": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
"integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-discard-empty": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
"integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-discard-overridden": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
"integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-double-position-gradients": {
"version": "3.1.1",
@@ -18408,13 +18289,15 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz",
"integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-gap-properties": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz",
"integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-image-set-function": {
"version": "4.0.6",
@@ -18440,7 +18323,8 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz",
"integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-lab-function": {
"version": "4.2.0",
@@ -18467,18 +18351,20 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz",
"integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-media-minmax": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz",
"integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-merge-longhand": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz",
- "integrity": "sha512-hbqRRqYfmXoGpzYKeW0/NCZhvNyQIlQeWVSao5iKWdyx7skLvCfQFGIUsP9NUs3dSbPac2IC4Go85/zG+7MlmA==",
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.5.tgz",
+ "integrity": "sha512-NOG1grw9wIO+60arKa2YYsrbgvP6tp+jqc7+ZD5/MalIw234ooH2C6KlR6FEn4yle7GqZoBxSK1mLBE9KPur6w==",
"dev": true,
"requires": {
"postcss-value-parser": "^4.2.0",
@@ -18571,7 +18457,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-modules-local-by-default": {
"version": "4.0.0",
@@ -18616,7 +18503,8 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
"integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-normalize-display-values": {
"version": "5.1.0",
@@ -18735,13 +18623,15 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz",
"integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-page-break": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz",
"integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-place": {
"version": "7.0.4",
@@ -18868,7 +18758,8 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz",
"integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-selector-not": {
"version": "5.0.0",
@@ -19313,9 +19204,9 @@
"dev": true
},
"sass": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.0.tgz",
- "integrity": "sha512-6EnTglag2oVD8sNJCxUi2Jd3ICH9tJ5Mqudt/gIZNBR2uKJUBZuTpW9O1t04SkDLP7VFa76FCWTV2rwchqM8Kw==",
+ "version": "1.52.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
+ "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0",
@@ -19718,7 +19609,8 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz",
"integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"stylehacks": {
"version": "5.1.0",
@@ -19940,7 +19832,8 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -20113,57 +20006,6 @@
}
}
},
- "tsickle": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.34.3.tgz",
- "integrity": "sha512-mb1v3nsr6rYaZky22xj0d6qv4ogAR40Bc6r37jwWOg3bEIO/ZppEFZiEADs/NNVLcWTPgmNmPZgaX5CfAH6oXA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.0",
- "mkdirp": "^0.5.1",
- "source-map": "^0.7.3"
- },
- "dependencies": {
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
- "dev": true
- }
- }
- },
- "tsickle-loader": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/tsickle-loader/-/tsickle-loader-0.5.0.tgz",
- "integrity": "sha512-VzJCouScljE7JB40bQo9fOu0Rrw8pCIfj8tkTA8kdvQWbDEskdPrPyEnHTpRHyrnIo0zw+TrJnxnrSL+fH//nQ==",
- "dev": true,
- "requires": {
- "fs-extra": "^7.0.1",
- "tsickle": "^0.34.3"
- },
- "dependencies": {
- "fs-extra": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
- "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- }
- },
- "jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- }
- }
- },
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
@@ -20218,12 +20060,6 @@
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
"dev": true
},
- "universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
- "dev": true
- },
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -20371,7 +20207,8 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"browserslist": {
"version": "4.20.3",
@@ -20726,7 +20563,8 @@
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz",
"integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==",
- "dev": true
+ "dev": true,
+ "requires": {}
}
}
},
@@ -20796,12 +20634,21 @@
"dev": true
},
"ws": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz",
- "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz",
+ "integrity": "sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=",
"dev": true,
"requires": {
- "async-limiter": "~1.0.0"
+ "safe-buffer": "~5.0.1",
+ "ultron": "~1.1.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+ "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=",
+ "dev": true
+ }
}
},
"xml-js": {
diff --git a/client/package.json b/client/package.json
index 0149211e..5ab5c100 100644
--- a/client/package.json
+++ b/client/package.json
@@ -47,18 +47,17 @@
"@types/chromecast-caf-sender": "^1.0.3",
"ajv": "^8.8.2",
"app-manifest-loader": "^2.4.1",
- "chromecast-device-emulator": "^1.2.7",
+ "chromecast-device-emulator": "^1.1.2",
"compression-webpack-plugin": "^10.0.0",
"css-hot-loader": "^1.4.4",
"css-loader": "^6.3.0",
"cssnano": "^5.0.5",
"elm": "^0.19.1-3",
"elm-analyse": "^0.16.5",
- "elm-hot-webpack-loader": "^1.1.7",
"elm-webpack-loader": "^8.0.0",
"extract-loader": "^5.1.0",
- "fibers": "^5.0.0",
"file-loader": "^6.2.0",
+ "html-loader": "^3.1.0",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^2.3.0",
"postcss-import": "^14.0.0",
@@ -72,7 +71,6 @@
"style-loader": "^3.3.0",
"terser-webpack-plugin": "^5.0.3",
"ts-loader": "^9.2.6",
- "tsickle-loader": "^0.5.0",
"typescript": "^4.1.3",
"webpack": "^5.56.1",
"webpack-cli": "^4.3.1",
diff --git a/client/src/html/index.html b/client/src/html/index.html
index 18918ebe..16c82974 100644
--- a/client/src/html/index.html
+++ b/client/src/html/index.html
@@ -1,20 +1,33 @@
-
+
-
-
+
+
- Massive Decks
-
+ Massive Decks
+
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/client/webpack.config.js b/client/webpack.config.js
index c2556501..385031a3 100644
--- a/client/webpack.config.js
+++ b/client/webpack.config.js
@@ -20,6 +20,7 @@ module.exports = (env, argv) => {
const dist = path.resolve(__dirname, "dist");
const src = path.resolve(__dirname, "src");
+ const assets = path.resolve(__dirname, "assets");
const version = process.env["MD_VERSION"];
const metadataFilename = `${src}/elm/MassiveDecks/Version.elm`;
@@ -76,7 +77,6 @@ module.exports = (env, argv) => {
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
use: [
- ...(production ? [] : [{ loader: "elm-hot-webpack-loader" }]),
{
loader: "elm-webpack-loader",
options: {
diff --git a/deployment/postgres/docker_compose.yml b/deployment/postgres/docker_compose.yml
index 4a509639..96e5ac38 100644
--- a/deployment/postgres/docker_compose.yml
+++ b/deployment/postgres/docker_compose.yml
@@ -14,7 +14,7 @@ volumes:
services:
storage:
- image: "postgres:13"
+ image: "postgres:14"
# See the postgres image's documentation for more on configuring it.
# https://hub.docker.com/_/postgres
environment:
diff --git a/server/.eslintrc.json b/server/.eslintrc.json
index 98069310..df0a4564 100644
--- a/server/.eslintrc.json
+++ b/server/.eslintrc.json
@@ -1,39 +1,18 @@
{
+ "root": true,
"parser": "@typescript-eslint/parser",
+ "plugins": ["@typescript-eslint", "simple-import-sort"],
"extends": [
+ "eslint:recommended",
"plugin:@typescript-eslint/recommended",
- "prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
- "parserOptions": {
- "ecmaVersion": 2018,
- "sourceType": "module"
- },
"rules": {
- "no-template-curly-in-string": "warn",
- "guard-for-in": "error",
- "no-eval": "error",
- "arrow-body-style": "error",
-
- "no-unused-vars": "off",
+ "simple-import-sort/imports": "error",
"@typescript-eslint/no-unused-vars": [
"error",
- {
- "args": "none",
- "argsIgnorePattern": "^_$",
- "varsIgnorePattern": "^_$"
- }
+ { "argsIgnorePattern": "^_", "destructuredArrayIgnorePattern": "^_" }
],
-
- "@typescript-eslint/explicit-function-return-type": [
- "error",
- {
- "allowExpressions": true,
- "allowTypedFunctionExpressions": true,
- "allowHigherOrderFunctions": true
- }
- ],
-
"@typescript-eslint/no-empty-interface": "off"
}
}
diff --git a/server/Dockerfile b/server/Dockerfile
index e4f3776e..178baed2 100644
--- a/server/Dockerfile
+++ b/server/Dockerfile
@@ -1,4 +1,4 @@
-ARG NODE_VERSION=17
+ARG NODE_VERSION=18
ARG MODE=production
ARG BUILD_DATE
ARG VCS_REF
@@ -47,4 +47,4 @@ COPY --from=build ["/md/dist", "./"]
EXPOSE 8081
USER node
-CMD ["node", "--es-module-specifier-resolution=node", "./index.js"]
+CMD ["node", "./index.js"]
diff --git a/server/Dockerfile.dev b/server/Dockerfile.dev
index cfbe4f47..b58d617a 100644
--- a/server/Dockerfile.dev
+++ b/server/Dockerfile.dev
@@ -1,4 +1,4 @@
-ARG NODE_VERSION=17
+ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine
diff --git a/server/package-lock.json b/server/package-lock.json
index adf939a7..ae7fb83f 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -48,12 +48,13 @@
"eslint": "^8.3.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
+ "eslint-plugin-simple-import-sort": "^7.0.0",
"nodemon": "^2.0.6",
"prettier": "2.6.2",
- "typescript": "^4.1.3"
+ "typescript": "^4.8.0-dev.20220520"
},
"engines": {
- "node": "18.x.x"
+ "node": ">=18.0.0 <19.0.0"
}
},
"node_modules/@colors/colors": {
@@ -75,15 +76,15 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
- "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+ "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.3.2",
- "globals": "^13.9.0",
+ "globals": "^13.15.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
@@ -377,6 +378,35 @@
}
}
},
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/typescript": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
+ "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"node_modules/@typescript-eslint/parser": {
"version": "5.25.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.25.0.tgz",
@@ -447,6 +477,35 @@
}
}
},
+ "node_modules/@typescript-eslint/type-utils/node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils/node_modules/typescript": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
+ "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"node_modules/@typescript-eslint/types": {
"version": "5.25.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.25.0.tgz",
@@ -487,6 +546,35 @@
}
}
},
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/typescript": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
+ "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"node_modules/@typescript-eslint/utils": {
"version": "5.25.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.25.0.tgz",
@@ -1292,12 +1380,12 @@
}
},
"node_modules/eslint": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
- "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz",
+ "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==",
"dev": true,
"dependencies": {
- "@eslint/eslintrc": "^1.2.3",
+ "@eslint/eslintrc": "^1.3.0",
"@humanwhocodes/config-array": "^0.9.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
@@ -1315,7 +1403,7 @@
"file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^6.0.1",
- "globals": "^13.6.0",
+ "globals": "^13.15.0",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@@ -1376,6 +1464,15 @@
}
}
},
+ "node_modules/eslint-plugin-simple-import-sort": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz",
+ "integrity": "sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": ">=5.0.0"
+ }
+ },
"node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -3778,21 +3875,6 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
- "node_modules/tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "engines": {
- "node": ">= 6"
- },
- "peerDependencies": {
- "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- }
- },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -3839,9 +3921,9 @@
}
},
"node_modules/typescript": {
- "version": "4.6.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
- "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "version": "4.8.0-dev.20220520",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.0-dev.20220520.tgz",
+ "integrity": "sha512-OLLEy7nRAUVunVn893E0QLf+pNitQQa+CBN4ZR3LpTIbK2VSPTIPX5wAFfVPZeuxXWn8mzCOammnyTAMFWpoEg==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -4130,15 +4212,15 @@
}
},
"@eslint/eslintrc": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
- "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+ "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.3.2",
- "globals": "^13.9.0",
+ "globals": "^13.15.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
@@ -4391,6 +4473,24 @@
"regexpp": "^3.2.0",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
+ },
+ "dependencies": {
+ "tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "typescript": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
+ "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "dev": true,
+ "peer": true
+ }
}
},
"@typescript-eslint/parser": {
@@ -4424,6 +4524,24 @@
"@typescript-eslint/utils": "5.25.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
+ },
+ "dependencies": {
+ "tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "typescript": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
+ "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "dev": true,
+ "peer": true
+ }
}
},
"@typescript-eslint/types": {
@@ -4445,6 +4563,24 @@
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
+ },
+ "dependencies": {
+ "tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "typescript": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
+ "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "dev": true,
+ "peer": true
+ }
}
},
"@typescript-eslint/utils": {
@@ -5064,12 +5200,12 @@
"dev": true
},
"eslint": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
- "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz",
+ "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==",
"dev": true,
"requires": {
- "@eslint/eslintrc": "^1.2.3",
+ "@eslint/eslintrc": "^1.3.0",
"@humanwhocodes/config-array": "^0.9.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
@@ -5087,7 +5223,7 @@
"file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^6.0.1",
- "globals": "^13.6.0",
+ "globals": "^13.15.0",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@@ -5158,6 +5294,13 @@
"prettier-linter-helpers": "^1.0.0"
}
},
+ "eslint-plugin-simple-import-sort": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz",
+ "integrity": "sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -6930,15 +7073,6 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "requires": {
- "tslib": "^1.8.1"
- }
- },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -6973,9 +7107,9 @@
}
},
"typescript": {
- "version": "4.6.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
- "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "version": "4.8.0-dev.20220520",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.0-dev.20220520.tgz",
+ "integrity": "sha512-OLLEy7nRAUVunVn893E0QLf+pNitQQa+CBN4ZR3LpTIbK2VSPTIPX5wAFfVPZeuxXWn8mzCOammnyTAMFWpoEg==",
"dev": true
},
"undefsafe": {
diff --git a/server/package.json b/server/package.json
index af8b38d0..b3283243 100644
--- a/server/package.json
+++ b/server/package.json
@@ -7,19 +7,23 @@
"private": true,
"repository": "github:Lattyware/massivedecks",
"engines": {
- "node": "18.x.x"
+ "node": ">=18.0.0 <19.0.0"
},
"type": "module",
- "module": "dist/index.js",
+ "exports": {
+ ".": {
+ "import": "./dist/index.js"
+ }
+ },
"scripts": {
"build": "npx tsc",
"prestart": "npm run build",
- "start": "node --es-module-specifier-resolution=node dist/index.js",
+ "start": "node dist/index.js",
"preinspect": "npm run build",
- "inspect": "node --inspect-brk --es-module-specifier-resolution=node dist/index.js",
+ "inspect": "node --inspect-brk dist/index.js",
"dev": "nodemon --exec \"npm run start\"",
"debug": "nodemon --exec \"npm run inspect\"",
- "generate-secret": "npm run prestart && node --es-module-specifier-resolution=node dist/secret.js",
+ "generate-secret": "npm run prestart && node dist/secret.js",
"docker:build": "mkdir -p \"$(pwd)/../workaround\" && ROOT_DIR=\"$(pwd)/..\" USER_ID=$(id -u ${USER}) GROUP_ID=$(id -g ${USER}) docker compose -f ../develop.yml run --rm server run build",
"docker:generate-secret": "mkdir -p \"$(pwd)/../workaround\" && ROOT_DIR=\"$(pwd)/..\" USER_ID=$(id -u ${USER}) GROUP_ID=$(id -g ${USER}) docker compose -f ../develop.yml run --rm server run generate-secret",
"docker:dev": "mkdir -p \"$(pwd)/../workaround\" && ROOT_DIR=\"$(pwd)/..\" USER_ID=$(id -u ${USER}) GROUP_ID=$(id -g ${USER}) docker compose -f ../develop.yml up --build --no-log-prefix server"
@@ -68,9 +72,10 @@
"eslint": "^8.3.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
+ "eslint-plugin-simple-import-sort": "^7.0.0",
"nodemon": "^2.0.6",
"prettier": "2.6.2",
- "typescript": "^4.1.3"
+ "typescript": "^4.8.0-dev.20220520"
},
"nodemonConfig": {
"ext": "ts,js,json,json5",
diff --git a/server/src/ts/action.ts b/server/src/ts/action.ts
index e669d512..8718efed 100644
--- a/server/src/ts/action.ts
+++ b/server/src/ts/action.ts
@@ -1,13 +1,13 @@
-import * as Actions from "./action/actions";
-import * as Authenticate from "./action/authenticate";
-import * as GameAction from "./action/game-action";
-import * as Handler from "./action/handler";
-import * as Leave from "./action/leave";
-import * as Privileged from "./action/privileged";
-import * as SetUserRole from "./action/set-user-role";
-import * as Validation from "./action/validation.validator";
-import { AlreadyAuthenticatedError } from "./errors/authentication";
-import { InvalidActionError } from "./errors/validation";
+import * as Actions from "./action/actions.js";
+import * as Authenticate from "./action/authenticate.js";
+import * as GameAction from "./action/game-action.js";
+import type * as Handler from "./action/handler.js";
+import * as Leave from "./action/leave.js";
+import * as Privileged from "./action/privileged.js";
+import * as SetUserRole from "./action/set-user-role.js";
+import * as Validation from "./action/validation.validator.js";
+import { AlreadyAuthenticatedError } from "./errors/authentication.js";
+import { InvalidActionError } from "./errors/validation.js";
/**
* An action a user takes to affect the game in some way, received via a
@@ -24,7 +24,7 @@ const allActions = new Actions.PassThroughGroup(
GameAction.actions,
Privileged.actions,
SetUserRole.actions,
- Leave.actions
+ Leave.actions,
);
const _validateAction = Validation.validate("Action");
@@ -41,7 +41,7 @@ export const handle: Handler.Handler = (
auth,
lobby,
action,
- config
+ config,
) => {
const validated = validate(action);
if (Authenticate.is(validated)) {
diff --git a/server/src/ts/action/actions.ts b/server/src/ts/action/actions.ts
index 5415d596..97140716 100644
--- a/server/src/ts/action/actions.ts
+++ b/server/src/ts/action/actions.ts
@@ -1,11 +1,12 @@
import wu from "wu";
-import { Action } from "../action";
-import { InvalidActionError } from "../errors/validation";
-import { Lobby } from "../lobby";
-import { Change } from "../lobby/change";
-import { ServerState } from "../server-state";
-import * as Token from "../user/token";
-import * as Handler from "./handler";
+
+import type { Action } from "../action.js";
+import { InvalidActionError } from "../errors/validation.js";
+import type { Lobby } from "../lobby.js";
+import type { Change } from "../lobby/change.js";
+import type { ServerState } from "../server-state.js";
+import type * as Token from "../user/token.js";
+import type * as Handler from "./handler.js";
export interface Actions {
is: (action: Action) => boolean;
@@ -14,7 +15,7 @@ export interface Actions {
auth: Token.Claims,
lobby: ParentLobby,
action: Parent,
- server: ServerState
+ server: ServerState,
) => Change | undefined;
}
@@ -22,8 +23,9 @@ export abstract class Implementation<
ParentType extends Action,
Type extends ParentType & { action: Name },
Name extends string,
- ParentLobby extends Lobby
-> implements Actions {
+ ParentLobby extends Lobby,
+> implements Actions
+{
protected abstract readonly name: Name;
// Should be Action, broken due to https://github.com/microsoft/TypeScript/pull/37195
@@ -41,7 +43,7 @@ export abstract class Implementation<
auth: Token.Claims,
lobby: ParentLobby,
action: Action,
- server: ServerState
+ server: ServerState,
): Change | undefined {
if (this.is(action)) {
return this.handle(auth, lobby, action, server);
@@ -57,8 +59,9 @@ export abstract class Group<
ParentType extends Action,
Type extends ParentType,
ParentLobby extends Lobby,
- LimitedLobby extends ParentLobby
-> implements Actions {
+ LimitedLobby extends ParentLobby,
+> implements Actions
+{
private readonly childActions: Actions[];
protected constructor(...childActions: Actions[]) {
@@ -73,14 +76,14 @@ export abstract class Group<
auth: Token.Claims,
lobby: ParentLobby,
action: Type,
- server: ServerState
+ server: ServerState,
): lobby is LimitedLobby;
tryHandle(
auth: Token.Claims,
lobby: ParentLobby,
action: Action,
- server: ServerState
+ server: ServerState,
): Change | undefined {
if (this.is(action)) {
if (this.limit(auth, lobby, action, server)) {
@@ -104,17 +107,17 @@ export abstract class Group<
*/
export class PassThroughGroup<
Type extends Action,
- ParentLobby extends Lobby
+ ParentLobby extends Lobby,
> extends Group {
constructor(...childActions: Actions[]) {
super(...childActions);
}
public limit(
- auth: Token.Claims,
+ _auth: Token.Claims,
lobby: ParentLobby,
- action: Type,
- server: ServerState
+ _action: Type,
+ _server: ServerState,
): lobby is ParentLobby {
return true;
}
diff --git a/server/src/ts/action/authenticate.ts b/server/src/ts/action/authenticate.ts
index fa23fc2a..edb8e3c9 100644
--- a/server/src/ts/action/authenticate.ts
+++ b/server/src/ts/action/authenticate.ts
@@ -1,11 +1,11 @@
-import { Action } from "../action";
-import * as Authentication from "../errors/authentication";
-import * as Event from "../event";
-import * as ConnectionChanged from "../events/lobby-event/connection-changed";
-import * as Change from "../lobby/change";
-import { GameCode } from "../lobby/game-code";
-import { ServerState } from "../server-state";
-import * as Token from "../user/token";
+import type { Action } from "../action.js";
+import * as Authentication from "../errors/authentication.js";
+import * as Event from "../event.js";
+import * as ConnectionChanged from "../events/lobby-event/connection-changed.js";
+import * as Change from "../lobby/change.js";
+import type { GameCode } from "../lobby/game-code.js";
+import type { ServerState } from "../server-state.js";
+import * as Token from "../user/token.js";
/**
* Authenticate with the game.
@@ -34,12 +34,12 @@ export const is = (action: Action): action is Authenticate =>
export async function handle(
server: ServerState,
authenticate: Authenticate,
- gameCode: GameCode
+ gameCode: GameCode,
): Promise {
const claims = Token.validate(
authenticate.token,
await server.store.id(),
- server.config.secret
+ server.config.secret,
);
if (claims.gc !== gameCode) {
throw new Authentication.InvalidAuthenticationError("wrong game code");
diff --git a/server/src/ts/action/game-action.ts b/server/src/ts/action/game-action.ts
index 27fae20e..bcbc5bbe 100644
--- a/server/src/ts/action/game-action.ts
+++ b/server/src/ts/action/game-action.ts
@@ -1,18 +1,18 @@
-import * as Action from "../action";
-import * as ActionExecutionError from "../errors/action-execution-error";
-import { GameNotStartedError } from "../errors/action-execution-error";
-import { Game } from "../games/game";
-import * as Player from "../games/player";
-import * as Lobby from "../lobby";
-import { ServerState } from "../server-state";
-import * as Token from "../user/token";
-import * as Actions from "./actions";
-import * as Czar from "./game-action/czar";
-import * as EnforceTimeLimit from "./game-action/enforce-time-limit";
-import * as PlayerAction from "./game-action/player";
-import * as Redraw from "./game-action/redraw";
-import * as SetPresence from "./game-action/set-presence";
-import * as Like from "./game-action/like";
+import type * as Action from "../action.js";
+import * as ActionExecutionError from "../errors/action-execution-error.js";
+import { GameNotStartedError } from "../errors/action-execution-error.js";
+import type { Game } from "../games/game.js";
+import * as Player from "../games/player.js";
+import * as Lobby from "../lobby.js";
+import type { ServerState } from "../server-state.js";
+import type * as Token from "../user/token.js";
+import * as Actions from "./actions.js";
+import * as Czar from "./game-action/czar.js";
+import * as EnforceTimeLimit from "./game-action/enforce-time-limit.js";
+import * as Like from "./game-action/like.js";
+import * as PlayerAction from "./game-action/player.js";
+import * as Redraw from "./game-action/redraw.js";
+import * as SetPresence from "./game-action/set-presence.js";
/**
* An action only a player can perform.
@@ -38,15 +38,15 @@ class GameActions extends Actions.Group<
Redraw.actions,
EnforceTimeLimit.actions,
SetPresence.actions,
- Like.actions
+ Like.actions,
);
}
public limit(
- auth: Token.Claims,
+ _auth: Token.Claims,
lobby: Lobby.Lobby,
action: GameAction,
- server: ServerState
+ _server: ServerState,
): lobby is Lobby.WithActiveGame {
if (!Lobby.hasActiveGame(lobby)) {
throw new GameNotStartedError(action);
@@ -61,13 +61,13 @@ export function expectRole(
auth: Token.Claims,
action: Czar.Czar,
game: Game,
- expected: "Czar"
+ expected: "Czar",
): void;
export function expectRole(
auth: Token.Claims,
action: PlayerAction.Player,
game: Game,
- expected: "Player"
+ expected: "Player",
): void;
/**
* Expect a given role.
@@ -80,14 +80,14 @@ export function expectRole(
auth: Token.Claims,
action: GameAction,
game: Game,
- expected: Player.Role
+ expected: Player.Role,
): void {
const playerRole = Player.role(auth.uid, game);
if (playerRole !== expected) {
throw new ActionExecutionError.IncorrectPlayerRoleError(
action,
playerRole,
- expected
+ expected,
);
}
}
diff --git a/server/src/ts/action/game-action/czar.ts b/server/src/ts/action/game-action/czar.ts
index b85b8ef0..e9b5e803 100644
--- a/server/src/ts/action/game-action/czar.ts
+++ b/server/src/ts/action/game-action/czar.ts
@@ -1,11 +1,11 @@
-import * as Action from "../../action";
-import * as Lobby from "../../lobby";
-import * as Token from "../../user/token";
-import * as GameAction from "../game-action";
-import * as Actions from "../actions";
-import * as Judge from "./czar/judge";
-import * as PickCall from "./czar/pick-call";
-import * as Reveal from "./czar/reveal";
+import type * as Action from "../../action.js";
+import type * as Lobby from "../../lobby.js";
+import type * as Token from "../../user/token.js";
+import * as Actions from "../actions.js";
+import * as GameAction from "../game-action.js";
+import * as Judge from "./czar/judge.js";
+import * as PickCall from "./czar/pick-call.js";
+import * as Reveal from "./czar/reveal.js";
/**
* An action only the czar can perform.
@@ -25,7 +25,7 @@ class CzarActions extends Actions.Group<
limit(
auth: Token.Claims,
lobby: Lobby.WithActiveGame,
- action: Czar
+ action: Czar,
): lobby is Lobby.WithActiveGame {
GameAction.expectRole(auth, action, lobby.game, "Czar");
return true;
diff --git a/server/src/ts/action/game-action/czar/judge.ts b/server/src/ts/action/game-action/czar/judge.ts
index 79b407a0..edaea483 100644
--- a/server/src/ts/action/game-action/czar/judge.ts
+++ b/server/src/ts/action/game-action/czar/judge.ts
@@ -1,13 +1,14 @@
-import { InvalidActionError } from "../../../errors/validation";
-import * as Event from "../../../event";
-import * as RoundFinished from "../../../events/game-event/round-finished";
-import * as Play from "../../../games/cards/play";
-import * as Round from "../../../games/game/round";
-import * as Lobby from "../../../lobby";
-import * as RoundStart from "../../../timeout/round-start";
-import * as Handler from "../../handler";
-import { Czar } from "../czar";
-import * as Actions from "./../../actions";
+import { InvalidActionError } from "../../../errors/validation.js";
+import * as Event from "../../../event.js";
+import * as RoundFinished from "../../../events/game-event/round-finished.js";
+import type * as Play from "../../../games/cards/play.js";
+import type * as Round from "../../../games/game/round.js";
+import type { Player } from "../../../games/player.js";
+import type * as Lobby from "../../../lobby.js";
+import * as RoundStart from "../../../timeout/round-start.js";
+import type * as Handler from "../../handler.js";
+import type { Czar } from "../czar.js";
+import * as Actions from "./../../actions.js";
/**
* A user declares the winning play for a round.
@@ -37,7 +38,7 @@ class JudgeAction extends Actions.Implementation<
let winningPlay = undefined;
for (const play of plays) {
if (play.likes.length > 0) {
- const player = game.players[play.playedBy];
+ const player = game.players[play.playedBy] as Player;
player.likes += play.likes.length;
}
if (play.id === action.winner) {
@@ -47,7 +48,7 @@ class JudgeAction extends Actions.Implementation<
if (winningPlay === undefined) {
throw new InvalidActionError("Given play doesn't exist.");
}
- const player = game.players[winningPlay.playedBy];
+ const player = game.players[winningPlay.playedBy] as Player;
player.score += 1;
if (game.rules.houseRules.winnersPick) {
game.rules.houseRules.winnersPick.roundWinner = winningPlay.playedBy;
diff --git a/server/src/ts/action/game-action/czar/pick-call.ts b/server/src/ts/action/game-action/czar/pick-call.ts
index 1d6bdc81..554231df 100644
--- a/server/src/ts/action/game-action/czar/pick-call.ts
+++ b/server/src/ts/action/game-action/czar/pick-call.ts
@@ -1,9 +1,9 @@
-import * as Card from "../../../games/cards/card";
-import * as Round from "../../../games/game/round";
-import * as Lobby from "../../../lobby";
-import * as Actions from "../../actions";
-import * as Handler from "../../handler";
-import { Czar } from "../czar";
+import type * as Card from "../../../games/cards/card.js";
+import type * as Round from "../../../games/game/round.js";
+import type * as Lobby from "../../../lobby.js";
+import * as Actions from "../../actions.js";
+import type * as Handler from "../../handler.js";
+import type { Czar } from "../czar.js";
/**
* A czar picks a call for a round.
@@ -26,7 +26,7 @@ class PickCallActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => {
const lobbyRound = lobby.game.round;
@@ -35,7 +35,7 @@ class PickCallActions extends Actions.Implementation<
server,
lobby.game,
action.call,
- action.fill
+ action.fill,
);
lobby.game.round = round;
return { lobby, events, timeouts };
diff --git a/server/src/ts/action/game-action/czar/reveal.ts b/server/src/ts/action/game-action/czar/reveal.ts
index 72a7e372..94dff608 100644
--- a/server/src/ts/action/game-action/czar/reveal.ts
+++ b/server/src/ts/action/game-action/czar/reveal.ts
@@ -1,15 +1,15 @@
-import { InvalidActionError } from "../../../errors/validation";
-import * as Event from "../../../event";
-import * as PlayRevealed from "../../../events/game-event/play-revealed";
-import * as Play from "../../../games/cards/play";
-import * as Round from "../../../games/game/round";
-import * as Lobby from "../../../lobby";
-import * as Handler from "../../handler";
-import { Czar } from "../czar";
-import * as Actions from "./../../actions";
-import * as StoredPlay from "../../../games/game/round/stored-play";
-import * as Util from "../../../util";
-import * as FinishedRevealing from "../../../timeout/finished-revealing";
+import { InvalidActionError } from "../../../errors/validation.js";
+import * as Event from "../../../event.js";
+import * as PlayRevealed from "../../../events/game-event/play-revealed.js";
+import type * as Play from "../../../games/cards/play.js";
+import type * as Round from "../../../games/game/round.js";
+import * as StoredPlay from "../../../games/game/round/stored-play.js";
+import type * as Lobby from "../../../lobby.js";
+import * as FinishedRevealing from "../../../timeout/finished-revealing.js";
+import * as Util from "../../../util.js";
+import type * as Handler from "../../handler.js";
+import type { Czar } from "../czar.js";
+import * as Actions from "./../../actions.js";
/**
* A user judges the winning play for a round.
@@ -30,7 +30,7 @@ class RevealAction extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
const game = lobby.game;
if (game.round.verifyStage(action, "Revealing")) {
@@ -45,7 +45,7 @@ class RevealAction extends Actions.Implementation<
const timeouts = Util.asOptionalIterable(
StoredPlay.allRevealed(game.round)
? FinishedRevealing.of(game.rules.stages)
- : undefined
+ : undefined,
);
return {
lobby,
diff --git a/server/src/ts/action/game-action/enforce-time-limit.ts b/server/src/ts/action/game-action/enforce-time-limit.ts
index ba0537db..1b775c94 100644
--- a/server/src/ts/action/game-action/enforce-time-limit.ts
+++ b/server/src/ts/action/game-action/enforce-time-limit.ts
@@ -1,11 +1,11 @@
-import { InvalidActionError } from "../../errors/validation";
-import * as round from "../../games/game/round";
-import * as Lobby from "../../lobby";
-import * as change from "../../lobby/change";
-import * as Actions from "../actions";
-import { GameAction } from "../game-action";
-import * as Handler from "../handler";
-import { dealWithLostPlayer } from "./set-presence";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as round from "../../games/game/round.js";
+import type * as Lobby from "../../lobby.js";
+import * as change from "../../lobby/change.js";
+import * as Actions from "../actions.js";
+import type { GameAction } from "../game-action.js";
+import type * as Handler from "../handler.js";
+import { dealWithLostPlayer } from "./set-presence.js";
/**
* A player asks to enforce the soft time limit for the game.
@@ -28,7 +28,7 @@ class EnforceTimeLimitAction extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => {
const game = lobby.game;
const stages = game.rules.stages;
@@ -51,7 +51,7 @@ class EnforceTimeLimitAction extends Actions.Implementation<
}
if (gameRound.timedOut) {
return change.reduce(waitingFor, lobby as Lobby.WithActiveGame, (l, p) =>
- dealWithLostPlayer(server, l, p)
+ dealWithLostPlayer(server, l, p),
);
} else {
throw new InvalidActionError("Round stage timer not done.");
diff --git a/server/src/ts/action/game-action/like.ts b/server/src/ts/action/game-action/like.ts
index 94e05bb1..0c0389e4 100644
--- a/server/src/ts/action/game-action/like.ts
+++ b/server/src/ts/action/game-action/like.ts
@@ -1,11 +1,12 @@
-import * as Play from "../../games/cards/play";
-import * as Round from "../../games/game/round";
-import * as Lobby from "../../lobby";
-import * as Actions from "../actions";
-import * as Handler from "../handler";
-import { GameAction } from "../game-action";
-import * as PlayLiked from "../../events/game-event/play-liked";
-import * as Event from "../../event";
+import * as Event from "../../event.js";
+import * as PlayLiked from "../../events/game-event/play-liked.js";
+import type * as Play from "../../games/cards/play.js";
+import type * as Round from "../../games/game/round.js";
+import type { Player } from "../../games/player.js";
+import type * as Lobby from "../../lobby.js";
+import * as Actions from "../actions.js";
+import type { GameAction } from "../game-action.js";
+import type * as Handler from "../handler.js";
/**
* A player or spectator likes a play.
@@ -26,7 +27,7 @@ class LikeActions extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
if (
lobby.game.round.isInStage<
@@ -40,7 +41,7 @@ class LikeActions extends Actions.Implementation<
target.playedBy !== auth.uid &&
target.likes.find((id) => id === auth.uid) === undefined
) {
- lobby.game.players[target.playedBy].likes += 1;
+ (lobby.game.players[target.playedBy] as Player).likes += 1;
target.likes.push(auth.uid);
const events =
lobby.game.round.stage === "Complete"
diff --git a/server/src/ts/action/game-action/player.ts b/server/src/ts/action/game-action/player.ts
index 930011ca..48126b95 100644
--- a/server/src/ts/action/game-action/player.ts
+++ b/server/src/ts/action/game-action/player.ts
@@ -1,12 +1,12 @@
-import * as Actions from "./../actions";
-import * as Submit from "./player/submit";
-import * as TakeBack from "./player/take-back";
-import * as Fill from "./player/fill";
-import * as Discard from "./player/discard";
-import * as Action from "../../action";
-import * as Lobby from "../../lobby";
-import * as Token from "../../user/token";
-import * as GameAction from "../game-action";
+import type * as Action from "../../action.js";
+import type * as Lobby from "../../lobby.js";
+import type * as Token from "../../user/token.js";
+import * as GameAction from "../game-action.js";
+import * as Actions from "./../actions.js";
+import * as Discard from "./player/discard.js";
+import * as Fill from "./player/fill.js";
+import * as Submit from "./player/submit.js";
+import * as TakeBack from "./player/take-back.js";
/**
* An action only players can perform.
@@ -30,7 +30,7 @@ class PlayerActions extends Actions.Group<
limit(
auth: Token.Claims,
lobby: Lobby.WithActiveGame,
- action: Player
+ action: Player,
): lobby is Lobby.WithActiveGame {
GameAction.expectRole(auth, action, lobby.game, "Player");
return true;
diff --git a/server/src/ts/action/game-action/player/discard.ts b/server/src/ts/action/game-action/player/discard.ts
index 94535732..a614cc18 100644
--- a/server/src/ts/action/game-action/player/discard.ts
+++ b/server/src/ts/action/game-action/player/discard.ts
@@ -1,12 +1,13 @@
-import * as Card from "../../../games/cards/card";
-import * as Actions from "../../actions";
-import { Player } from "../player";
-import * as Lobby from "../../../lobby";
-import * as Handler from "../../handler";
-import { InvalidActionError } from "../../../errors/validation";
-import * as Util from "../../../util";
-import * as Event from "../../../event";
-import * as CardDiscarded from "../../../events/game-event/card-discarded";
+import { InvalidActionError } from "../../../errors/validation.js";
+import * as Event from "../../../event.js";
+import * as CardDiscarded from "../../../events/game-event/card-discarded.js";
+import type * as Card from "../../../games/cards/card.js";
+import type { Player as PlayerModel } from "../../../games/player.js";
+import type * as Lobby from "../../../lobby.js";
+import * as Util from "../../../util.js";
+import * as Actions from "../../actions.js";
+import type * as Handler from "../../handler.js";
+import type { Player } from "../player.js";
/**
* Indicates the user is discarding their hand.
@@ -27,15 +28,15 @@ class DiscardActions extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
if (lobby.game.rules.houseRules.neverHaveIEver === undefined) {
throw new InvalidActionError(
- "The “Never Have I Ever” house rule is not enabled this game, but must be to do that."
+ "The “Never Have I Ever” house rule is not enabled this game, but must be to do that.",
);
}
const id = auth.uid;
- const player = lobby.game.players[id];
+ const player = lobby.game.players[id] as PlayerModel;
const card = player.hand.find((c) => c.id === action.card);
if (card === undefined) {
throw new InvalidActionError("Must have the card to discard it.");
@@ -45,8 +46,8 @@ class DiscardActions extends Actions.Implementation<
player.hand.push(replacement);
const events = Util.asOptionalIterable(
Event.playerSpecificAddition(CardDiscarded.of(id, card), (to) =>
- id === to ? { replacement } : {}
- )
+ id === to ? { replacement } : {},
+ ),
);
return { events };
};
diff --git a/server/src/ts/action/game-action/player/fill.ts b/server/src/ts/action/game-action/player/fill.ts
index ce4cc375..0b772afa 100644
--- a/server/src/ts/action/game-action/player/fill.ts
+++ b/server/src/ts/action/game-action/player/fill.ts
@@ -1,11 +1,12 @@
-import * as Card from "../../../games/cards/card";
-import * as Actions from "../../actions";
-import { Player } from "../player";
-import * as Lobby from "../../../lobby";
-import * as Handler from "../../handler";
-import * as Round from "../../../games/game/round";
-import { IncorrectUserRoleError } from "../../../errors/action-execution-error";
-import { InvalidActionError } from "../../../errors/validation";
+import { IncorrectUserRoleError } from "../../../errors/action-execution-error.js";
+import { InvalidActionError } from "../../../errors/validation.js";
+import * as Card from "../../../games/cards/card.js";
+import type * as Round from "../../../games/game/round.js";
+import type * as Lobby from "../../../lobby.js";
+import type { User } from "../../../user.js";
+import * as Actions from "../../actions.js";
+import type * as Handler from "../../handler.js";
+import type { Player } from "../player.js";
/**
* Indicates the user has changed the value of a blank card in their hand.
@@ -27,11 +28,11 @@ class FillActions extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
const lobbyRound = lobby.game.round;
if (lobbyRound.verifyStage(action, "Playing")) {
- const user = lobby.users[auth.uid];
+ const user = lobby.users[auth.uid] as User;
const player = lobby.game.players[auth.uid];
if (user.role !== "Player" || player === undefined) {
throw new IncorrectUserRoleError(action, user.role, "Player");
@@ -39,7 +40,7 @@ class FillActions extends Actions.Implementation<
const filled = player.hand.find((c) => c.id === action.card);
if (filled === undefined) {
throw new InvalidActionError(
- "The given card doesn't exist or isn't in the player's hand."
+ "The given card doesn't exist or isn't in the player's hand.",
);
}
if (Card.isCustom(filled)) {
diff --git a/server/src/ts/action/game-action/player/submit.ts b/server/src/ts/action/game-action/player/submit.ts
index 80ccf51c..b445fad7 100644
--- a/server/src/ts/action/game-action/player/submit.ts
+++ b/server/src/ts/action/game-action/player/submit.ts
@@ -1,16 +1,16 @@
-import { IncorrectUserRoleError } from "../../../errors/action-execution-error";
-import { InvalidActionError } from "../../../errors/validation";
-import * as Event from "../../../event";
-import * as PlaySubmitted from "../../../events/game-event/play-submitted";
-import * as Card from "../../../games/cards/card";
-import * as Play from "../../../games/cards/play";
-import * as Round from "../../../games/game/round";
-import * as Lobby from "../../../lobby";
-import * as FinishedPlaying from "../../../timeout/finished-playing";
-import * as Actions from "../../actions";
-import * as Handler from "../../handler";
-import { Player } from "../player";
-import * as Util from "../../../util";
+import { IncorrectUserRoleError } from "../../../errors/action-execution-error.js";
+import { InvalidActionError } from "../../../errors/validation.js";
+import * as Event from "../../../event.js";
+import * as PlaySubmitted from "../../../events/game-event/play-submitted.js";
+import * as Card from "../../../games/cards/card.js";
+import * as Play from "../../../games/cards/play.js";
+import type * as Round from "../../../games/game/round.js";
+import type * as Lobby from "../../../lobby.js";
+import * as FinishedPlaying from "../../../timeout/finished-playing.js";
+import * as Util from "../../../util.js";
+import * as Actions from "../../actions.js";
+import type * as Handler from "../../handler.js";
+import type { Player } from "../player.js";
/**
* A player plays a response into a round.
@@ -32,7 +32,7 @@ class SubmitActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ _server,
) => {
const lobbyRound = lobby.game.round;
@@ -47,7 +47,7 @@ class SubmitActions extends Actions.Implementation<
if (playLength !== slotCount) {
throw new InvalidActionError(
"The play must have the same number of responses as the call " +
- `has slots (expected ${slotCount}, got ${playLength}).`
+ `has slots (expected ${slotCount}, got ${playLength}).`,
);
}
const player = lobby.game.players[auth.uid];
@@ -59,7 +59,7 @@ class SubmitActions extends Actions.Implementation<
const played = player.hand.find((c) => c.id === playedCard);
if (played === undefined) {
throw new InvalidActionError(
- "The given card doesn't exist or isn't in the player's hand."
+ "The given card doesn't exist or isn't in the player's hand.",
);
}
extractedPlay.push(played);
@@ -73,7 +73,7 @@ class SubmitActions extends Actions.Implementation<
});
const events = [Event.targetAll(PlaySubmitted.of(auth.uid))];
const timeouts = Util.asOptionalIterable(
- FinishedPlaying.ifNeeded(lobby.game.rules, lobbyRound)
+ FinishedPlaying.ifNeeded(lobby.game.rules, lobbyRound),
);
return { lobby, events, timeouts };
} else {
diff --git a/server/src/ts/action/game-action/player/take-back.ts b/server/src/ts/action/game-action/player/take-back.ts
index 874d0e30..9875a59f 100644
--- a/server/src/ts/action/game-action/player/take-back.ts
+++ b/server/src/ts/action/game-action/player/take-back.ts
@@ -1,11 +1,11 @@
-import { InvalidActionError } from "../../../errors/validation";
-import * as Event from "../../../event";
-import * as PlayTakenBack from "../../../events/game-event/play-taken-back";
-import * as Round from "../../../games/game/round";
-import * as Lobby from "../../../lobby";
-import * as Actions from "../../actions";
-import * as Handler from "../../handler";
-import { Player } from "../player";
+import { InvalidActionError } from "../../../errors/validation.js";
+import * as Event from "../../../event.js";
+import * as PlayTakenBack from "../../../events/game-event/play-taken-back.js";
+import type * as Round from "../../../games/game/round.js";
+import type * as Lobby from "../../../lobby.js";
+import * as Actions from "../../actions.js";
+import type * as Handler from "../../handler.js";
+import type { Player } from "../player.js";
/**
* A player plays a white card into a round.
@@ -25,7 +25,7 @@ class TakeBackActions extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
if (lobby.game.round.verifyStage(action, "Playing")) {
const plays = lobby.game.round.plays;
diff --git a/server/src/ts/action/game-action/redraw.ts b/server/src/ts/action/game-action/redraw.ts
index df90df8b..7de2e6f1 100644
--- a/server/src/ts/action/game-action/redraw.ts
+++ b/server/src/ts/action/game-action/redraw.ts
@@ -1,11 +1,11 @@
-import { IncorrectUserRoleError } from "../../errors/action-execution-error";
-import { InvalidActionError } from "../../errors/validation";
-import * as Event from "../../event";
-import * as HandRedrawn from "../../events/game-event/hand-redrawn";
-import * as Lobby from "../../lobby";
-import * as Actions from "../actions";
-import * as GameAction from "../game-action";
-import * as Handler from "../handler";
+import { IncorrectUserRoleError } from "../../errors/action-execution-error.js";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Event from "../../event.js";
+import * as HandRedrawn from "../../events/game-event/hand-redrawn.js";
+import type * as Lobby from "../../lobby.js";
+import * as Actions from "../actions.js";
+import type * as GameAction from "../game-action.js";
+import type * as Handler from "../handler.js";
/**
* A player plays a white card into a round.
@@ -25,7 +25,7 @@ class RedrawActions extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
const game = lobby.game;
const reboot = game.rules.houseRules.reboot;
@@ -47,7 +47,7 @@ class RedrawActions extends Actions.Implementation<
events: [
Event.additionally(
HandRedrawn.of(auth.uid),
- new Map([[auth.uid, { hand: player.hand }]])
+ new Map([[auth.uid, { hand: player.hand }]]),
),
],
};
diff --git a/server/src/ts/action/game-action/set-presence.ts b/server/src/ts/action/game-action/set-presence.ts
index 5d0ba15e..521d47f4 100644
--- a/server/src/ts/action/game-action/set-presence.ts
+++ b/server/src/ts/action/game-action/set-presence.ts
@@ -1,15 +1,15 @@
-import { InvalidActionError } from "../../errors/validation";
-import * as Event from "../../event";
-import * as PlayerPresenceChanged from "../../events/game-event/player-presence-changed";
-import * as Player from "../../games/player";
-import * as Lobby from "../../lobby";
-import { ConstrainedChange } from "../../lobby/change";
-import { ServerState } from "../../server-state";
-import * as User from "../../user";
-import * as Util from "../../util";
-import * as GameAction from "../game-action";
-import * as Handler from "../handler";
-import * as Actions from "./../actions";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Event from "../../event.js";
+import * as PlayerPresenceChanged from "../../events/game-event/player-presence-changed.js";
+import type * as Player from "../../games/player.js";
+import type * as Lobby from "../../lobby.js";
+import type { ConstrainedChange } from "../../lobby/change.js";
+import type { ServerState } from "../../server-state.js";
+import type * as User from "../../user.js";
+import * as Util from "../../util.js";
+import type * as GameAction from "../game-action.js";
+import type * as Handler from "../handler.js";
+import * as Actions from "./../actions.js";
/**
* A player asks to set themself as away.
@@ -22,7 +22,7 @@ export interface SetPresence {
export const dealWithLostPlayer = (
server: ServerState,
lobby: Lobby.WithActiveGame,
- playerId: User.Id
+ playerId: User.Id,
): ConstrainedChange => {
const game = lobby.game;
@@ -70,7 +70,7 @@ class SetPresenceActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => {
const game = lobby.game;
const playerId = auth.uid;
diff --git a/server/src/ts/action/handler.ts b/server/src/ts/action/handler.ts
index f7c80b1f..fffe21a4 100644
--- a/server/src/ts/action/handler.ts
+++ b/server/src/ts/action/handler.ts
@@ -1,18 +1,18 @@
-import { Action } from "../action";
-import { Change } from "../lobby/change";
-import { Lobby } from "../lobby";
-import * as token from "../user/token";
-import { ServerState } from "../server-state";
+import type { Action } from "../action.js";
+import type { Lobby } from "../lobby.js";
+import type { Change } from "../lobby/change.js";
+import type { ServerState } from "../server-state.js";
+import type * as Token from "../user/token.js";
/**
* A handler for a given type of action where the lobby is customised.
* This can let us avoid making the same checks down the line.
*/
export type Custom = (
- auth: token.Claims,
+ auth: Token.Claims,
lobby: L,
action: A,
- server: ServerState
+ server: ServerState,
) => Change;
/**
diff --git a/server/src/ts/action/initial/check-alive.ts b/server/src/ts/action/initial/check-alive.ts
index b3baa94a..9e386d37 100644
--- a/server/src/ts/action/initial/check-alive.ts
+++ b/server/src/ts/action/initial/check-alive.ts
@@ -1,6 +1,6 @@
-import { InvalidActionError } from "../../errors/validation";
-import { Token } from "../../user/token";
-import * as Validation from "../validation.validator";
+import { InvalidActionError } from "../../errors/validation.js";
+import type { Token } from "../../user/token.js";
+import * as Validation from "../validation.validator.js";
/**
* Previously obtained tokens to check the validity of.
diff --git a/server/src/ts/action/initial/create-lobby.ts b/server/src/ts/action/initial/create-lobby.ts
index 8aca944f..d3960500 100644
--- a/server/src/ts/action/initial/create-lobby.ts
+++ b/server/src/ts/action/initial/create-lobby.ts
@@ -1,6 +1,6 @@
-import { InvalidActionError } from "../../errors/validation";
-import * as Validation from "../validation.validator";
-import { RegisterUser } from "./register-user";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Validation from "../validation.validator.js";
+import type { RegisterUser } from "./register-user.js";
/**
* The details needed to create a new lobby.
diff --git a/server/src/ts/action/initial/register-user.ts b/server/src/ts/action/initial/register-user.ts
index 494547ca..f9280a9a 100644
--- a/server/src/ts/action/initial/register-user.ts
+++ b/server/src/ts/action/initial/register-user.ts
@@ -1,6 +1,6 @@
-import { InvalidActionError } from "../../errors/validation";
-import * as User from "../../user";
-import * as Validation from "../validation.validator";
+import { InvalidActionError } from "../../errors/validation.js";
+import type * as User from "../../user.js";
+import * as Validation from "../validation.validator.js";
/**
* The details to register a new user for a lobby.
diff --git a/server/src/ts/action/leave.ts b/server/src/ts/action/leave.ts
index 8518e6b2..9f3530ae 100644
--- a/server/src/ts/action/leave.ts
+++ b/server/src/ts/action/leave.ts
@@ -1,8 +1,8 @@
-import * as Action from "../action";
-import * as Lobby from "../lobby";
-import * as Actions from "./actions";
-import * as Handler from "./handler";
-import * as Kick from "./privileged/kick";
+import type * as Action from "../action.js";
+import type * as Lobby from "../lobby.js";
+import * as Actions from "./actions.js";
+import type * as Handler from "./handler.js";
+import * as Kick from "./privileged/kick.js";
/**
* A player asks to leave the game.
@@ -23,7 +23,7 @@ class LeaveActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => Kick.removeUser(auth.uid, lobby, server, "Left");
}
diff --git a/server/src/ts/action/privileged.ts b/server/src/ts/action/privileged.ts
index b129b06e..c2710573 100644
--- a/server/src/ts/action/privileged.ts
+++ b/server/src/ts/action/privileged.ts
@@ -1,14 +1,14 @@
-import { Action } from "../action";
-import { UnprivilegedError } from "../errors/action-execution-error";
-import * as Lobby from "../lobby";
-import * as Token from "../user/token";
-import * as Actions from "./actions";
-import * as Configure from "./privileged/configure";
-import * as EndGame from "./privileged/end-game";
-import * as Kick from "./privileged/kick";
-import * as SetPlayerAway from "./privileged/set-player-away";
-import * as SetPrivilege from "./privileged/set-privilege";
-import * as StartGame from "./privileged/start-game";
+import type { Action } from "../action.js";
+import { UnprivilegedError } from "../errors/action-execution-error.js";
+import type * as Lobby from "../lobby.js";
+import type * as Token from "../user/token.js";
+import * as Actions from "./actions.js";
+import * as Configure from "./privileged/configure.js";
+import * as EndGame from "./privileged/end-game.js";
+import * as Kick from "./privileged/kick.js";
+import * as SetPlayerAway from "./privileged/set-player-away.js";
+import * as SetPrivilege from "./privileged/set-privilege.js";
+import * as StartGame from "./privileged/start-game.js";
/**
* An action only a privileged user can perform.
@@ -34,14 +34,14 @@ class PrivilegedActions extends Actions.Group<
SetPlayerAway.actions,
SetPrivilege.actions,
Kick.actions,
- EndGame.actions
+ EndGame.actions,
);
}
public limit(
auth: Token.Claims,
lobby: Lobby.Lobby,
- action: Privileged
+ action: Privileged,
): lobby is Lobby.WithActiveGame {
const user = lobby.users[auth.uid];
if (user === undefined || user.privilege !== "Privileged") {
diff --git a/server/src/ts/action/privileged/configure.ts b/server/src/ts/action/privileged/configure.ts
index 3b2439b5..2a73da92 100644
--- a/server/src/ts/action/privileged/configure.ts
+++ b/server/src/ts/action/privileged/configure.ts
@@ -1,23 +1,24 @@
import Rfc6902 from "rfc6902";
-import { ReplaceOperation, TestOperation } from "rfc6902/diff";
-import Rfc6902Patch from "rfc6902/patch";
-import * as Actions from "./../actions";
-import { ConfigEditConflictError } from "../../errors/action-execution-error";
-import { InvalidActionError } from "../../errors/validation";
-import * as Event from "../../event";
-import * as Configured from "../../events/lobby-event/configured";
-import * as Rules from "../../games/rules";
-import * as HouseRules from "../../games/rules/house-rules";
-import * as Rando from "../../games/rules/rando";
-import * as Lobby from "../../lobby";
-import * as Config from "../../lobby/config";
-import { GameCode } from "../../lobby/game-code";
-import { Task } from "../../task";
-import { LoadDeckSummary } from "../../task/load-deck-summary";
-import * as Handler from "../handler";
-import { Privileged } from "../privileged";
-import * as Validation from "../validation.validator";
-import { ServerState } from "../../server-state";
+import type { ReplaceOperation, TestOperation } from "rfc6902/diff.js";
+import Rfc6902Patch from "rfc6902/patch.js";
+
+import { ConfigEditConflictError } from "../../errors/action-execution-error.js";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Event from "../../event.js";
+import * as Configured from "../../events/lobby-event/configured.js";
+import type * as Rules from "../../games/rules.js";
+import type * as HouseRules from "../../games/rules/house-rules.js";
+import * as Rando from "../../games/rules/rando.js";
+import type * as Lobby from "../../lobby.js";
+import * as Config from "../../lobby/config.js";
+import type { GameCode } from "../../lobby/game-code.js";
+import type { ServerState } from "../../server-state.js";
+import type { Task } from "../../task.js";
+import { LoadDeckSummary } from "../../task/load-deck-summary.js";
+import type * as Handler from "../handler.js";
+import type { Privileged } from "../privileged.js";
+import * as Validation from "../validation.validator.js";
+import * as Actions from "./../actions.js";
/**
* An action to change the configuration of the lobby.
@@ -39,7 +40,7 @@ interface Result {
function applyRando(
lobby: Lobby.Lobby,
existing: Rando.Rando,
- updated?: Rando.Public
+ updated?: Rando.Public,
): Result {
const events = Rando.change(lobby, existing, updated);
return { result: existing, events, tasks: [] };
@@ -48,12 +49,12 @@ function applyRando(
function applyHouseRules(
lobby: Lobby.Lobby,
existing: HouseRules.HouseRules,
- updated: HouseRules.Public
+ updated: HouseRules.Public,
): Result {
const { result, events, tasks } = applyRando(
lobby,
existing.rando,
- updated.rando
+ updated.rando,
);
return {
result: { ...updated, rando: result },
@@ -65,12 +66,12 @@ function applyHouseRules(
function applyRules(
lobby: Lobby.Lobby,
existing: Rules.Rules,
- updated: Rules.Public
+ updated: Rules.Public,
): Result {
const { result, events, tasks } = applyHouseRules(
lobby,
existing.houseRules,
- updated.houseRules
+ updated.houseRules,
);
return {
result: { ...updated, houseRules: result },
@@ -84,12 +85,12 @@ function apply(
gameCode: GameCode,
lobby: Lobby.Lobby,
existing: Config.Config,
- updated: Config.Public
+ updated: Config.Public,
): Result {
const { result, events, tasks } = applyRules(
lobby,
existing.rules,
- updated.rules
+ updated.rules,
);
const allTasks = [...tasks];
for (const deck of updated.decks) {
@@ -119,8 +120,8 @@ const validate = (operation: Rfc6902.Operation): void => {
switch (operation.op) {
case "add":
if (
- operation.value.hasOwnProperty("summary") ||
- operation.value.hasOwnProperty("failure")
+ Object.hasOwn(operation.value, "summary") ||
+ Object.hasOwn(operation.value, "failure")
) {
throw new InvalidActionError("Can't add summaries or failures.");
}
@@ -150,7 +151,7 @@ class ConfigureActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => {
const version = lobby.config.version;
for (const op of action.change) {
@@ -176,7 +177,7 @@ class ConfigureActions extends Actions.Implementation<
auth.gc,
lobby,
lobby.config,
- validated
+ validated,
);
lobby.config = result;
const testVersion: TestOperation = {
diff --git a/server/src/ts/action/privileged/end-game.ts b/server/src/ts/action/privileged/end-game.ts
index bf593620..fed64b7e 100644
--- a/server/src/ts/action/privileged/end-game.ts
+++ b/server/src/ts/action/privileged/end-game.ts
@@ -1,9 +1,9 @@
-import * as Actions from "./../actions";
-import * as Event from "../../event";
-import * as GameEnded from "../../events/game-event/game-ended";
-import * as Lobby from "../../lobby";
-import * as Handler from "../handler";
-import { Privileged } from "../privileged";
+import * as Event from "../../event.js";
+import * as GameEnded from "../../events/game-event/game-ended.js";
+import type * as Lobby from "../../lobby.js";
+import type * as Handler from "../handler.js";
+import type { Privileged } from "../privileged.js";
+import * as Actions from "./../actions.js";
/**
* End the current game.
@@ -21,9 +21,9 @@ class EndGameActions extends Actions.Implementation<
protected readonly name = "EndGame";
protected handle: Handler.Custom = (
- auth,
+ _auth,
lobby,
- action
+ _action,
) => {
if (lobby.game === undefined || lobby.game.winner !== undefined) {
// If we are asked to end a game that isn't started or is already ended,
diff --git a/server/src/ts/action/privileged/kick.ts b/server/src/ts/action/privileged/kick.ts
index 2921f740..2f01bf74 100644
--- a/server/src/ts/action/privileged/kick.ts
+++ b/server/src/ts/action/privileged/kick.ts
@@ -1,14 +1,14 @@
-import * as Actions from "./../actions";
-import { InvalidActionError } from "../../errors/validation";
-import * as Event from "../../event";
-import * as PresenceChanged from "../../events/lobby-event/presence-changed";
-import * as Lobby from "../../lobby";
-import { Change } from "../../lobby/change";
-import { ServerState } from "../../server-state";
-import * as Timeout from "../../timeout";
-import * as User from "../../user";
-import * as Handler from "../handler";
-import { Privileged } from "../privileged";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Event from "../../event.js";
+import * as PresenceChanged from "../../events/lobby-event/presence-changed.js";
+import type * as Lobby from "../../lobby.js";
+import type { Change } from "../../lobby/change.js";
+import type { ServerState } from "../../server-state.js";
+import type * as Timeout from "../../timeout.js";
+import type * as User from "../../user.js";
+import type * as Handler from "../handler.js";
+import type { Privileged } from "../privileged.js";
+import * as Actions from "./../actions.js";
/**
* A player asks to leave the game.
@@ -22,9 +22,9 @@ export const removeUser = (
userId: User.Id,
lobby: Lobby.Lobby,
server: ServerState,
- leaveReason: PresenceChanged.LeaveReason
+ leaveReason: PresenceChanged.LeaveReason,
): Change => {
- const user = lobby.users[userId];
+ const user = lobby.users[userId] as User.User;
user.presence = "Left";
if (user.control === "Computer") {
@@ -34,7 +34,7 @@ export const removeUser = (
const allEvents = [
Event.targetAllAndPotentiallyClose(
PresenceChanged.left(userId, leaveReason),
- (id) => id === userId
+ (id) => id === userId,
),
];
const allTimeouts: Timeout.After[] = [];
@@ -57,13 +57,13 @@ export const removeUser = (
const player = game.players[userId];
if (player !== undefined) {
addResult(
- game.round.czar === userId ? game.startNewRound(server, lobby) : {}
+ game.round.czar === userId ? game.startNewRound(server, lobby) : {},
);
addResult(
game.round.players.has(userId)
? game.removeFromRound(userId, server)
- : {}
+ : {},
);
}
}
@@ -87,7 +87,7 @@ class KickActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => removeUser(action.user, lobby, server, "Kicked");
}
diff --git a/server/src/ts/action/privileged/set-player-away.ts b/server/src/ts/action/privileged/set-player-away.ts
index dd048560..b399af54 100644
--- a/server/src/ts/action/privileged/set-player-away.ts
+++ b/server/src/ts/action/privileged/set-player-away.ts
@@ -1,10 +1,10 @@
-import * as Actions from "./../actions";
-import { InvalidActionError } from "../../errors/validation";
-import * as User from "../../user";
-import * as Lobby from "../../lobby";
-import * as SetPresence from "../game-action/set-presence";
-import * as Handler from "../handler";
-import { Privileged } from "../privileged";
+import { InvalidActionError } from "../../errors/validation.js";
+import type * as Lobby from "../../lobby.js";
+import type * as User from "../../user.js";
+import * as SetPresence from "../game-action/set-presence.js";
+import type * as Handler from "../handler.js";
+import type { Privileged } from "../privileged.js";
+import * as Actions from "./../actions.js";
/**
* A privileged user asks to set a given player as away.
@@ -26,14 +26,14 @@ class SetPlayerAwayActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => {
const game = lobby.game;
if (game === undefined) {
throw new InvalidActionError("Must be in a game.");
}
- const user = lobby.users[action.player];
+ const user = lobby.users[action.player] as User.User;
if (user.control === "Computer") {
throw new InvalidActionError("Can't do this with AIs.");
}
@@ -48,7 +48,7 @@ class SetPlayerAwayActions extends Actions.Implementation<
return SetPresence.dealWithLostPlayer(
server,
lobby as Lobby.WithActiveGame,
- playerId
+ playerId,
);
} else {
return {};
diff --git a/server/src/ts/action/privileged/set-privilege.ts b/server/src/ts/action/privileged/set-privilege.ts
index 3ea2a819..81011284 100644
--- a/server/src/ts/action/privileged/set-privilege.ts
+++ b/server/src/ts/action/privileged/set-privilege.ts
@@ -1,11 +1,11 @@
-import * as Actions from "./../actions";
-import { InvalidActionError } from "../../errors/validation";
-import * as Event from "../../event";
-import * as PrivilegeChanged from "../../events/lobby-event/privilege-changed";
-import * as Lobby from "../../lobby";
-import * as User from "../../user";
-import * as Handler from "../handler";
-import { Privileged } from "../privileged";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Event from "../../event.js";
+import * as PrivilegeChanged from "../../events/lobby-event/privilege-changed.js";
+import type * as Lobby from "../../lobby.js";
+import type * as User from "../../user.js";
+import type * as Handler from "../handler.js";
+import type { Privileged } from "../privileged.js";
+import * as Actions from "./../actions.js";
/**
* A privileged user asks to change the privilege of another user.
@@ -27,9 +27,9 @@ class SetPrivilegeActions extends Actions.Implementation<
protected handle: Handler.Custom = (
auth,
lobby,
- action
+ action,
) => {
- const user = lobby.users[action.user];
+ const user = lobby.users[action.user] as User.User;
if (user.control === "Computer") {
throw new InvalidActionError("Can't do this with AIs.");
diff --git a/server/src/ts/action/privileged/start-game.ts b/server/src/ts/action/privileged/start-game.ts
index 618ba7ea..c1969cd1 100644
--- a/server/src/ts/action/privileged/start-game.ts
+++ b/server/src/ts/action/privileged/start-game.ts
@@ -1,8 +1,8 @@
-import * as Actions from "./../actions";
-import * as Lobby from "../../lobby";
-import { StartGame as StartGameTask } from "../../task/start-game";
-import * as Handler from "../handler";
-import { Privileged } from "../privileged";
+import type * as Lobby from "../../lobby.js";
+import { StartGame as StartGameTask } from "../../task/start-game.js";
+import type * as Handler from "../handler.js";
+import type { Privileged } from "../privileged.js";
+import * as Actions from "./../actions.js";
/**
* Start a game in the lobby if possible.
@@ -25,7 +25,7 @@ class StartGameActions extends Actions.Implementation<
tasks: [
new StartGameTask(
auth.gc,
- lobby.config.decks.map((s) => s.source)
+ lobby.config.decks.map((s) => s.source),
),
],
});
diff --git a/server/src/ts/action/set-user-role.ts b/server/src/ts/action/set-user-role.ts
index 0ef08086..748009e7 100644
--- a/server/src/ts/action/set-user-role.ts
+++ b/server/src/ts/action/set-user-role.ts
@@ -1,14 +1,14 @@
-import { Action } from "../action";
-import * as Event from "../event";
-import * as UserRoleChanged from "../events/lobby-event/user-role-changed";
-import * as Player from "../games/player";
-import * as Lobby from "../lobby";
-import * as Timeout from "../timeout";
-import * as User from "../user";
-import * as Actions from "./actions";
-import * as Handler from "./handler";
-import { UnprivilegedError } from "../errors/action-execution-error";
-import { Privileged } from "./privileged";
+import type { Action } from "../action.js";
+import { UnprivilegedError } from "../errors/action-execution-error.js";
+import * as Event from "../event.js";
+import * as UserRoleChanged from "../events/lobby-event/user-role-changed.js";
+import * as Player from "../games/player.js";
+import type * as Lobby from "../lobby.js";
+import type * as Timeout from "../timeout.js";
+import type * as User from "../user.js";
+import * as Actions from "./actions.js";
+import type * as Handler from "./handler.js";
+import type { Privileged } from "./privileged.js";
/**
* A player asks to leave the game.
@@ -31,10 +31,10 @@ class SetUserRoleActions extends Actions.Implementation<
auth,
lobby,
action,
- server
+ server,
) => {
const userId = action.id === undefined ? auth.uid : action.id;
- const targetUser = lobby.users[userId];
+ const targetUser = lobby.users[userId] as User.User;
const oldRole = targetUser.role;
const newRole = action.role;
const additionalMap = new Map();
@@ -56,10 +56,10 @@ class SetUserRoleActions extends Actions.Implementation<
};
if (
- lobby.users[auth.uid].privilege !== "Privileged" &&
+ lobby.users[auth.uid]?.privilege !== "Privileged" &&
(userId !== auth.uid || lobby.config.audienceMode)
) {
- throw new UnprivilegedError((action as unknown) as Privileged);
+ throw new UnprivilegedError(action as unknown as Privileged);
}
if (oldRole !== newRole) {
@@ -80,7 +80,7 @@ class SetUserRoleActions extends Actions.Implementation<
}
}
if (newRole === "Player") {
- if (!game.players.hasOwnProperty(userId)) {
+ if (!Object.hasOwn(game.players, userId)) {
const hand = game.decks.responses.draw(game.rules.handSize);
additionalMap.set(auth.uid, { hand });
game.players[userId] = Player.initial(hand);
@@ -92,7 +92,7 @@ class SetUserRoleActions extends Actions.Implementation<
events: [
Event.additionally(
UserRoleChanged.of(userId, action.role),
- additionalMap
+ additionalMap,
),
...allEvents,
],
diff --git a/server/src/ts/action/validation.ts b/server/src/ts/action/validation.ts
index 8c642c06..45770ded 100644
--- a/server/src/ts/action/validation.ts
+++ b/server/src/ts/action/validation.ts
@@ -1,8 +1,8 @@
-import { Action as ActionType } from "../action";
-import { CreateLobby as CreateLobbyType } from "../action/initial/create-lobby";
-import { RegisterUser as RegisterUserType } from "../action/initial/register-user";
-import { CheckAlive as CheckAliveType } from "../action/initial/check-alive";
-import { Public as PublicConfigType } from "../lobby/config";
+import type { Action as ActionType } from "../action.js";
+import type { CheckAlive as CheckAliveType } from "../action/initial/check-alive.js";
+import type { CreateLobby as CreateLobbyType } from "../action/initial/create-lobby.js";
+import type { RegisterUser as RegisterUserType } from "../action/initial/register-user.js";
+import type { Public as PublicConfigType } from "../lobby/config.js";
export type Action = ActionType;
export type CreateLobby = CreateLobbyType;
diff --git a/server/src/ts/action/validation.validator.ts b/server/src/ts/action/validation.validator.ts
index cb5ce178..2704b965 100644
--- a/server/src/ts/action/validation.validator.ts
+++ b/server/src/ts/action/validation.validator.ts
@@ -1,12 +1,14 @@
-import Ajv from "ajv";
-import addFormats from "ajv-formats";
-import {
- RegisterUser,
- CreateLobby,
+/* eslint-disable */
+import { default as Ajv } from "ajv";
+import { default as addFormats } from "ajv-formats";
+
+import type {
Action,
CheckAlive,
+ CreateLobby,
PublicConfig,
-} from "./validation";
+ RegisterUser,
+} from "./validation.js";
export const ajv = new Ajv({
allErrors: false,
@@ -15,9 +17,6 @@ export const ajv = new Ajv({
});
addFormats(ajv, { mode: "full" });
-import metaSchema from "ajv/lib/refs/json-schema-draft-06.json";
-ajv.addMetaSchema(metaSchema);
-
export { RegisterUser, CreateLobby, Action, CheckAlive, PublicConfig };
export const Schema = {
$schema: "http://json-schema.org/draft-07/schema#",
@@ -1122,24 +1121,24 @@ export const Schema = {
};
ajv.addSchema(Schema, "Schema");
export function validate(
- typeName: "RegisterUser"
+ typeName: "RegisterUser",
): (value: unknown) => RegisterUser;
export function validate(
- typeName: "CreateLobby"
+ typeName: "CreateLobby",
): (value: unknown) => CreateLobby;
export function validate(typeName: "Action"): (value: unknown) => Action;
export function validate(
- typeName: "CheckAlive"
+ typeName: "CheckAlive",
): (value: unknown) => CheckAlive;
export function validate(
- typeName: "PublicConfig"
+ typeName: "PublicConfig",
): (value: unknown) => PublicConfig;
export function validate(typeName: string): (value: unknown) => any {
const validator: any = ajv.getSchema(`Schema#/definitions/${typeName}`);
return (value: unknown): any => {
if (!validator) {
throw new Error(
- `No validator defined for Schema#/definitions/${typeName}`
+ `No validator defined for Schema#/definitions/${typeName}`,
);
}
@@ -1152,8 +1151,8 @@ export function validate(typeName: string): (value: unknown) => any {
": " +
ajv.errorsText(
validator.errors!.filter((e: any) => e.keyword !== "if"),
- { dataVar: typeName }
- )
+ { dataVar: typeName },
+ ),
);
}
diff --git a/server/src/ts/cache.ts b/server/src/ts/cache.ts
index 87a8438d..06a658e3 100644
--- a/server/src/ts/cache.ts
+++ b/server/src/ts/cache.ts
@@ -1,7 +1,7 @@
-import * as ServerConfig from "./config";
-import * as Decks from "./games/cards/decks";
-import * as Source from "./games/cards/source";
-import * as Logging from "./logging";
+import type * as ServerConfig from "./config.js";
+import type * as Decks from "./games/cards/decks.js";
+import type * as Source from "./games/cards/source.js";
+import * as Logging from "./logging.js";
/**
* A tag is used to check if there is a need to refresh the data in the cache.
@@ -44,14 +44,14 @@ export abstract class Cache {
Always extends Tagged,
Sometimes extends Tagged,
Resolver extends Source.Resolver,
- Result
+ Result,
>(
source: Resolver,
getCachedAlways: (source: Resolver) => Promise | undefined>,
cacheAlways: (source: Resolver, value: Always) => void,
cacheSometimes: (source: Resolver, value: Sometimes) => void,
extract: (result: Result) => [Always, Sometimes | undefined],
- miss: () => Promise
+ miss: () => Promise,
): Promise {
const cached = await getCachedAlways(source);
if (cached !== undefined && !(await this.cacheExpired(source, cached))) {
@@ -68,7 +68,7 @@ export abstract class Cache {
private async cacheExpired(
source: Source.Resolver,
- cached: Aged
+ cached: Aged,
): Promise {
if (
cached.age >= Date.now() + this.config.checkAfter &&
@@ -89,7 +89,7 @@ export abstract class Cache {
*/
public async getSummary(
source: Source.Resolver,
- miss: () => Promise
+ miss: () => Promise,
): Promise {
return this.get(
source,
@@ -97,7 +97,7 @@ export abstract class Cache {
this.cacheSummaryBackground.bind(this),
this.cacheTemplatesBackground.bind(this),
(result) => [result.summary, result.templates],
- miss
+ miss,
);
}
@@ -111,7 +111,7 @@ export abstract class Cache {
*/
public async getTemplates(
source: Source.Resolver,
- miss: () => Promise
+ miss: () => Promise,
): Promise {
return this.get(
source,
@@ -119,7 +119,7 @@ export abstract class Cache {
this.cacheTemplatesBackground.bind(this),
this.cacheSummaryBackground.bind(this),
(result) => [result.templates, result.summary],
- miss
+ miss,
);
}
@@ -127,7 +127,7 @@ export abstract class Cache {
* Get the given summary from the cache.
*/
public abstract getCachedSummary(
- source: Source.Resolver
+ source: Source.Resolver,
): Promise | undefined>;
/**
@@ -135,12 +135,12 @@ export abstract class Cache {
*/
public abstract cacheSummary(
source: Source.Resolver,
- summary: Source.Summary
+ summary: Source.Summary,
): Promise;
public cacheSummaryBackground(
source: Source.Resolver,
- summary: Source.Summary
+ summary: Source.Summary,
): void {
this.cacheSummary(source, summary).catch(Cache.logError);
}
@@ -149,7 +149,7 @@ export abstract class Cache {
* Get the given deck templates from the cache.
*/
public abstract getCachedTemplates(
- source: Source.Resolver
+ source: Source.Resolver,
): Promise | undefined>;
/**
@@ -157,12 +157,12 @@ export abstract class Cache {
*/
public abstract cacheTemplates(
source: Source.Resolver,
- templates: Decks.Templates
+ templates: Decks.Templates,
): Promise;
public cacheTemplatesBackground(
source: Source.Resolver,
- templates: Decks.Templates
+ templates: Decks.Templates,
): void {
this.cacheTemplates(source, templates).catch(Cache.logError);
}
diff --git a/server/src/ts/caches.ts b/server/src/ts/caches.ts
index 70e14468..2e6971b4 100644
--- a/server/src/ts/caches.ts
+++ b/server/src/ts/caches.ts
@@ -1,7 +1,7 @@
-import { PostgresCache } from "./caches/postgres";
-import * as ServerConfig from "./config";
-import { Cache } from "./cache";
-import { InMemoryCache } from "./caches/in-memory";
+import type { Cache } from "./cache.js";
+import { InMemoryCache } from "./caches/in-memory.js";
+import { PostgresCache } from "./caches/postgres.js";
+import type * as ServerConfig from "./config.js";
export async function from(config: ServerConfig.Cache): Promise {
switch (config.type) {
diff --git a/server/src/ts/caches/in-memory.ts b/server/src/ts/caches/in-memory.ts
index 24a593c5..3bdd4af9 100644
--- a/server/src/ts/caches/in-memory.ts
+++ b/server/src/ts/caches/in-memory.ts
@@ -1,7 +1,7 @@
-import * as Cache from "../cache";
-import * as Config from "../config";
-import * as Decks from "../games/cards/decks";
-import * as Source from "../games/cards/source";
+import * as Cache from "../cache.js";
+import type * as Config from "../config.js";
+import type * as Decks from "../games/cards/decks.js";
+import type * as Source from "../games/cards/source.js";
/**
* An in-memory cache.
@@ -23,14 +23,14 @@ export class InMemoryCache extends Cache.Cache {
}
private static key(
- source: Source.Resolver
+ source: Source.Resolver,
): [string, string] {
return [source.id(), source.deckId()];
}
public async cacheSummary(
source: Source.Resolver,
- summary: Source.Summary
+ summary: Source.Summary,
): Promise {
this.cache.summaries.set(InMemoryCache.key(source), {
cached: summary,
@@ -40,7 +40,7 @@ export class InMemoryCache extends Cache.Cache {
public async cacheTemplates(
source: Source.Resolver,
- templates: Decks.Templates
+ templates: Decks.Templates,
): Promise {
this.cache.templates.set(InMemoryCache.key(source), {
cached: templates,
@@ -49,13 +49,13 @@ export class InMemoryCache extends Cache.Cache {
}
public async getCachedSummary(
- source: Source.Resolver
+ source: Source.Resolver,
): Promise | undefined> {
return this.cache.summaries.get(InMemoryCache.key(source));
}
public async getCachedTemplates(
- source: Source.Resolver
+ source: Source.Resolver,
): Promise | undefined> {
return this.cache.templates.get(InMemoryCache.key(source));
}
diff --git a/server/src/ts/caches/postgres.ts b/server/src/ts/caches/postgres.ts
index 045f1fa8..b3c0f5e4 100644
--- a/server/src/ts/caches/postgres.ts
+++ b/server/src/ts/caches/postgres.ts
@@ -1,12 +1,13 @@
-import Pg from "pg";
-import * as Cache from "../cache";
-import * as Config from "../config";
-import * as Decks from "../games/cards/decks";
-import * as Source from "../games/cards/source";
-import * as Postgres from "../util/postgres";
-import * as Card from "../games/cards/card";
+import type Pg from "pg";
import * as uuid from "uuid";
+import * as Cache from "../cache.js";
+import type * as Config from "../config.js";
+import * as Card from "../games/cards/card.js";
+import type * as Decks from "../games/cards/decks.js";
+import type * as Source from "../games/cards/source.js";
+import * as Postgres from "../util/postgres.js";
+
class To1 extends Postgres.Upgrade<0, 1> {
public readonly to = 1;
@@ -27,7 +28,7 @@ class To0 extends Postgres.Upgrade {
public async apply(client: Pg.PoolClient): Promise<0> {
await client.query("CREATE SCHEMA mdcache;");
await client.query(
- "CREATE TABLE mdcache.meta ( version INTEGER NOT NULL );"
+ "CREATE TABLE mdcache.meta ( version INTEGER NOT NULL );",
);
await client.query(`
CREATE TABLE mdcache.decks (
@@ -101,7 +102,7 @@ export class PostgresCache extends Cache.Cache {
private readonly pg: Postgres.Postgres;
public static async create(
- config: Config.PostgreSQLCache
+ config: Config.PostgreSQLCache,
): Promise {
const pg = new Postgres.Postgres("mdcache", config.connection, upgrades);
await pg.ensureCurrent();
@@ -116,7 +117,7 @@ export class PostgresCache extends Cache.Cache {
public async cacheSummary(
source: Source.Resolver,
- summary: Source.Summary
+ summary: Source.Summary,
): Promise {
await this.pg.inTransaction(async (client) => {
await client.query(
@@ -125,7 +126,7 @@ export class PostgresCache extends Cache.Cache {
$1, $2
) ON CONFLICT (source, id) DO NOTHING;
`,
- [source.id(), source.deckId()]
+ [source.id(), source.deckId()],
);
const details = summary.details;
await client.query(
@@ -148,14 +149,14 @@ export class PostgresCache extends Cache.Cache {
summary.responses,
Date.now(),
summary.tag,
- ]
+ ],
);
});
}
public async cacheTemplates(
source: Source.Resolver,
- templates: Decks.Templates
+ templates: Decks.Templates,
): Promise {
await this.pg.inTransaction(async (client) => {
await client.query(
@@ -164,7 +165,7 @@ export class PostgresCache extends Cache.Cache {
$1, $2, $3, $4
) ON CONFLICT (source, id) DO UPDATE SET cards_updated=$3, cards_tag=$4;
`,
- [source.id(), source.deckId(), Date.now(), templates.tag]
+ [source.id(), source.deckId(), Date.now(), templates.tag],
);
for (const call of templates.calls) {
@@ -174,7 +175,7 @@ export class PostgresCache extends Cache.Cache {
$1, $2, $3
)
`,
- [source.id(), source.deckId(), JSON.stringify(call.parts)]
+ [source.id(), source.deckId(), JSON.stringify(call.parts)],
);
}
@@ -188,14 +189,14 @@ export class PostgresCache extends Cache.Cache {
$1, $2, $3
)
`,
- [source.id(), source.deckId(), response.text]
+ [source.id(), source.deckId(), response.text],
);
}
});
}
public async getCachedSummary(
- source: Source.Resolver
+ source: Source.Resolver,
): Promise | undefined> {
return await this.pg.withClient(async (client) => {
const result = await client.query(
@@ -203,7 +204,7 @@ export class PostgresCache extends Cache.Cache {
SELECT name, url, author, language, translator, calls, responses, updated
FROM mdcache.summaries WHERE source = $1 AND deck = $2
`,
- [source.id(), source.deckId()]
+ [source.id(), source.deckId()],
);
if (result.rowCount > 0) {
const row = result.rows[0];
@@ -228,14 +229,14 @@ export class PostgresCache extends Cache.Cache {
}
public async getCachedTemplates(
- source: Source.Resolver
+ source: Source.Resolver,
): Promise | undefined> {
return await this.pg.withClient(async (client) => {
const about = await client.query(
`
SELECT cards_updated, cards_tag FROM mdcache.decks WHERE source = $1 AND id = $2
`,
- [source.id(), source.deckId()]
+ [source.id(), source.deckId()],
);
if (about.rowCount > 0 && about.rows[0]["cards_updated"] !== undefined) {
const calls = new Set();
@@ -245,7 +246,7 @@ export class PostgresCache extends Cache.Cache {
`
SELECT parts FROM mdcache.calls WHERE source = $1 AND deck = $2
`,
- [source.id(), source.deckId()]
+ [source.id(), source.deckId()],
);
for (const c of callsResult.rows) {
@@ -260,7 +261,7 @@ export class PostgresCache extends Cache.Cache {
`
SELECT text FROM mdcache.responses WHERE source = $1 AND deck = $2
`,
- [source.id(), source.deckId()]
+ [source.id(), source.deckId()],
);
for (const r of responsesResult.rows) {
diff --git a/server/src/ts/config.ts b/server/src/ts/config.ts
index 1fc0424c..f8c3565b 100644
--- a/server/src/ts/config.ts
+++ b/server/src/ts/config.ts
@@ -1,6 +1,7 @@
import Moment from "moment";
-import * as Util from "./util";
-import * as LobbyConfig from "./lobby/config";
+
+import type * as LobbyConfig from "./lobby/config.js";
+import * as Util from "./util.js";
type Duration = UnparsedDuration | ParsedDuration;
type UnparsedDuration = string;
diff --git a/server/src/ts/errors/action-execution-error.ts b/server/src/ts/errors/action-execution-error.ts
index 8d5da033..f6064053 100644
--- a/server/src/ts/errors/action-execution-error.ts
+++ b/server/src/ts/errors/action-execution-error.ts
@@ -1,17 +1,16 @@
import HttpStatus from "http-status-codes";
-import { Action } from "../action";
-import { GameAction } from "../action/game-action";
-import { Privileged } from "../action/privileged";
-import * as Errors from "../errors";
-import * as Round from "../games/game/round";
-import * as Player from "../games/player";
-import * as User from "../user";
-import * as Source from "../games/cards/source";
-
-abstract class ActionExecutionError extends Errors.MassiveDecksError<
- Errors.Details
-> {
- public readonly status: number = HttpStatus.BAD_REQUEST;
+
+import type { Action } from "../action.js";
+import type { GameAction } from "../action/game-action.js";
+import type { Privileged } from "../action/privileged.js";
+import * as Errors from "../errors.js";
+import type * as Source from "../games/cards/source.js";
+import type * as Round from "../games/game/round.js";
+import type * as Player from "../games/player.js";
+import type * as User from "../user.js";
+
+abstract class ActionExecutionError extends Errors.MassiveDecksError {
+ public override readonly status: number = HttpStatus.BAD_REQUEST;
public readonly action: Action;
protected constructor(message: string, action: Action) {
@@ -26,7 +25,7 @@ export class GameNotStartedError extends ActionExecutionError {
public constructor(action: GameAction) {
super(
`The game must be started for this action:\n ${JSON.stringify(action)}`,
- action
+ action,
);
Error.captureStackTrace(this, GameNotStartedError);
}
@@ -38,13 +37,13 @@ export class GameNotStartedError extends ActionExecutionError {
// Could happen if the user has privileges removed.
export class UnprivilegedError extends ActionExecutionError {
- public readonly status = HttpStatus.FORBIDDEN;
+ public override readonly status = HttpStatus.FORBIDDEN;
public constructor(action: Privileged) {
super(
`The user does not have the privilege to perform this action:\n` +
`${JSON.stringify(action)}`,
- action
+ action,
);
Error.captureStackTrace(this, UnprivilegedError);
}
@@ -67,12 +66,12 @@ export class IncorrectPlayerRoleError extends ActionExecutionError {
public constructor(
action: Action,
role: Player.Role | null,
- expected: Player.Role
+ expected: Player.Role,
) {
super(
`For this action the player must be ${expected} but is ${role}:\n` +
`${JSON.stringify(action)}`,
- action
+ action,
);
this.role = role;
this.expected = expected;
@@ -100,7 +99,7 @@ export class IncorrectUserRoleError extends ActionExecutionError {
super(
`For this action the user must be ${expected} but is ${role}:\n` +
`${JSON.stringify(action)}`,
- action
+ action,
);
this.role = role;
this.expected = expected;
@@ -132,7 +131,7 @@ export class IncorrectRoundStageError extends ActionExecutionError {
super(
`For this action the round must be in the ${expected} stage but is in ` +
`the ${stage} stage:\n ${JSON.stringify(action)}`,
- action
+ action,
);
this.stage = stage;
this.expected = expected;
@@ -153,7 +152,7 @@ interface ConfigEditConflictDetails extends Errors.Details {
// Could happen if two users edit the configuration at the same time.
export class ConfigEditConflictError extends ActionExecutionError {
- public readonly status: number = HttpStatus.CONFLICT;
+ public override readonly status: number = HttpStatus.CONFLICT;
public readonly version: string;
public readonly expected: string;
@@ -161,7 +160,7 @@ export class ConfigEditConflictError extends ActionExecutionError {
super(
`The configuration is at version ${expected}, but the client's edit ` +
`was made to version ${version}:\n ${JSON.stringify(action)}`,
- action
+ action,
);
this.version = version;
this.expected = expected;
@@ -186,7 +185,7 @@ export class SourceNotFoundError extends ActionExecutionError {
public constructor(source: Source.External) {
super(
`The given deck (${source}) was not found at the source.`,
- (undefined as unknown) as Action
+ undefined as unknown as Action,
);
this.source = source;
Error.captureStackTrace(this, SourceNotFoundError);
@@ -205,7 +204,7 @@ export class SourceServiceError extends ActionExecutionError {
public constructor(source: Source.External) {
super(
`The given deck source (${source.source}) was not available.`,
- (undefined as unknown) as Action
+ undefined as unknown as Action,
);
this.source = source;
Error.captureStackTrace(this, SourceServiceError);
diff --git a/server/src/ts/errors/authentication.ts b/server/src/ts/errors/authentication.ts
index 53dd95d8..356ad97b 100644
--- a/server/src/ts/errors/authentication.ts
+++ b/server/src/ts/errors/authentication.ts
@@ -1,5 +1,6 @@
import HttpStatus from "http-status-codes";
-import * as Errors from "../errors";
+
+import * as Errors from "../errors.js";
export type Reason =
| "IncorrectIssuer"
@@ -14,9 +15,7 @@ export interface Details extends Errors.Details {
reason: Reason;
}
-abstract class AuthenticationFailureError extends Errors.MassiveDecksError<
- Details
-> {
+abstract class AuthenticationFailureError extends Errors.MassiveDecksError {
public readonly status = HttpStatus.FORBIDDEN;
abstract readonly reason: Reason;
@@ -38,7 +37,7 @@ export class IncorrectIssuerError extends AuthenticationFailureError {
public constructor() {
super(
"the authentication was not for this server or the server data store " +
- "has been wiped"
+ "has been wiped",
);
Error.captureStackTrace(this, IncorrectIssuerError);
}
diff --git a/server/src/ts/errors/game-state-error.ts b/server/src/ts/errors/game-state-error.ts
index 225c1cf7..3ab113c4 100644
--- a/server/src/ts/errors/game-state-error.ts
+++ b/server/src/ts/errors/game-state-error.ts
@@ -1,9 +1,8 @@
import HttpStatus from "http-status-codes";
-import * as Errors from "../errors";
-export abstract class GameStateError extends Errors.MassiveDecksError<
- Errors.Details
-> {
+import * as Errors from "../errors.js";
+
+export abstract class GameStateError extends Errors.MassiveDecksError {
public readonly status: number = HttpStatus.INTERNAL_SERVER_ERROR;
protected constructor(message: string) {
diff --git a/server/src/ts/errors/lobby.ts b/server/src/ts/errors/lobby.ts
index 89f03c46..a203466a 100644
--- a/server/src/ts/errors/lobby.ts
+++ b/server/src/ts/errors/lobby.ts
@@ -1,6 +1,7 @@
import HttpStatus from "http-status-codes";
-import * as Errors from "../errors";
-import { GameCode } from "../lobby/game-code";
+
+import * as Errors from "../errors.js";
+import type { GameCode } from "../lobby/game-code.js";
export type Reason = "Closed" | "DoesNotExist";
@@ -10,9 +11,7 @@ export interface Details extends Errors.Details {
}
// Could happen on user typo.
-export abstract class LobbyNotFoundError extends Errors.MassiveDecksError<
- Details
-> {
+export abstract class LobbyNotFoundError extends Errors.MassiveDecksError {
abstract readonly reason: Reason;
public readonly gameCode: GameCode;
diff --git a/server/src/ts/errors/registration.ts b/server/src/ts/errors/registration.ts
index 3b109032..8b0661fe 100644
--- a/server/src/ts/errors/registration.ts
+++ b/server/src/ts/errors/registration.ts
@@ -1,5 +1,6 @@
import HttpStatus from "http-status-codes";
-import * as Errors from "../errors";
+
+import * as Errors from "../errors.js";
export type Reason = "UsernameAlreadyInUse";
@@ -34,9 +35,7 @@ export interface UsernameDetails {
username: string;
}
-export class UsernameAlreadyInUseError extends RegistrationError<
- UsernameDetails
-> {
+export class UsernameAlreadyInUseError extends RegistrationError {
protected readonly reason = "UsernameAlreadyInUse";
private readonly username: string;
diff --git a/server/src/ts/errors/validation.ts b/server/src/ts/errors/validation.ts
index 85f13638..8f1ee1d8 100644
--- a/server/src/ts/errors/validation.ts
+++ b/server/src/ts/errors/validation.ts
@@ -1,5 +1,6 @@
import HttpStatus from "http-status-codes";
-import * as Errors from "../errors";
+
+import * as Errors from "../errors.js";
export interface Details extends Errors.Details {
reason: string;
diff --git a/server/src/ts/event.ts b/server/src/ts/event.ts
index 3dac8401..393f7455 100644
--- a/server/src/ts/event.ts
+++ b/server/src/ts/event.ts
@@ -1,12 +1,12 @@
-import { GameEvent } from "./events/game-event";
-import { LobbyEvent } from "./events/lobby-event";
-import { UserEvent } from "./events/user-event";
-import { Player } from "./games/player";
-import { Lobby } from "./lobby";
-import * as Logging from "./logging";
-import * as SocketManager from "./socket-manager";
-import * as User from "./user";
-import { GameCode } from "./lobby/game-code";
+import type { GameEvent } from "./events/game-event.js";
+import type { LobbyEvent } from "./events/lobby-event.js";
+import type { UserEvent } from "./events/user-event.js";
+import type { Player } from "./games/player.js";
+import type { Lobby } from "./lobby.js";
+import type { GameCode } from "./lobby/game-code.js";
+import * as Logging from "./logging.js";
+import type * as SocketManager from "./socket-manager.js";
+import type * as User from "./user.js";
/**
* An event send to clients to update them on the state of the game.
@@ -18,7 +18,7 @@ export type Event = LobbyEvent | UserEvent | GameEvent;
*/
export type Distributor = (
lobby: Lobby,
- send: (target: User.Id, payload: string, close: boolean) => void
+ send: (target: User.Id, payload: string, close: boolean) => void,
) => void;
/**
@@ -60,7 +60,7 @@ export const targetOnly =
export const additionally =
(
event: T,
- additions: Map>
+ additions: Map>,
): Distributor =>
(lobby, send) => {
const basicRendered = JSON.stringify(event);
@@ -86,7 +86,7 @@ export const conditionally =
(
event: T,
condition: (id: User.Id, user: User.User) => boolean,
- addition: Partial
+ addition: Partial,
): Distributor =>
(lobby, send) => {
const basicRendered = JSON.stringify(event);
@@ -106,7 +106,7 @@ export const conditionally =
export const playerSpecificAddition =
>(
event: T,
- addition: (id: User.Id, user: User.User, player: Player) => U
+ addition: (id: User.Id, user: User.User, player: Player) => U,
): Distributor =>
(lobby, send) => {
const basicRendered = JSON.stringify(event);
@@ -147,7 +147,7 @@ export const targetAllAndPotentiallyClose =
const sendHelper =
(
sockets: SocketManager.Sockets,
- gameCode: GameCode
+ gameCode: GameCode,
): ((user: User.Id, serializedEvent: string, close: boolean) => void) =>
(user, serializedEvent, close) => {
try {
@@ -179,7 +179,7 @@ export function send(
sockets: SocketManager.SocketManager,
gameCode: GameCode,
lobby: Lobby,
- events: Iterable
+ events: Iterable,
): void {
const sendToUser = sendHelper(sockets.sockets, gameCode);
for (const event of events) {
diff --git a/server/src/ts/events/game-event.ts b/server/src/ts/events/game-event.ts
index a4e3bb45..b22aea2d 100644
--- a/server/src/ts/events/game-event.ts
+++ b/server/src/ts/events/game-event.ts
@@ -1,19 +1,19 @@
-import { GameEnded } from "./game-event/game-ended";
-import { GameStarted } from "./game-event/game-started";
-import { HandRedrawn } from "./game-event/hand-redrawn";
-import { PauseStateChanged } from "./game-event/pause-state-changed";
-import { PlayRevealed } from "./game-event/play-revealed";
-import { PlaySubmitted } from "./game-event/play-submitted";
-import { PlayTakenBack } from "./game-event/play-taken-back";
-import { PlayerPresenceChanged } from "./game-event/player-presence-changed";
-import { RoundFinished } from "./game-event/round-finished";
-import { RoundStarted } from "./game-event/round-started";
-import { PlayingStarted } from "./game-event/playing-started";
-import { StageTimerDone } from "./game-event/stage-timer-done";
-import { StartRevealing } from "./game-event/start-revealing";
-import { StartJudging } from "./game-event/start-judging";
-import { CardDiscarded } from "./game-event/card-discarded";
-import { PlayLiked } from "./game-event/play-liked";
+import type { CardDiscarded } from "./game-event/card-discarded.js";
+import type { GameEnded } from "./game-event/game-ended.js";
+import type { GameStarted } from "./game-event/game-started.js";
+import type { HandRedrawn } from "./game-event/hand-redrawn.js";
+import type { PauseStateChanged } from "./game-event/pause-state-changed.js";
+import type { PlayLiked } from "./game-event/play-liked.js";
+import type { PlayRevealed } from "./game-event/play-revealed.js";
+import type { PlaySubmitted } from "./game-event/play-submitted.js";
+import type { PlayTakenBack } from "./game-event/play-taken-back.js";
+import type { PlayerPresenceChanged } from "./game-event/player-presence-changed.js";
+import type { PlayingStarted } from "./game-event/playing-started.js";
+import type { RoundFinished } from "./game-event/round-finished.js";
+import type { RoundStarted } from "./game-event/round-started.js";
+import type { StageTimerDone } from "./game-event/stage-timer-done.js";
+import type { StartJudging } from "./game-event/start-judging.js";
+import type { StartRevealing } from "./game-event/start-revealing.js";
export type GameEvent =
| GameStarted
diff --git a/server/src/ts/events/game-event/card-discarded.ts b/server/src/ts/events/game-event/card-discarded.ts
index d38774a9..8f3ef380 100644
--- a/server/src/ts/events/game-event/card-discarded.ts
+++ b/server/src/ts/events/game-event/card-discarded.ts
@@ -1,5 +1,5 @@
-import * as Card from "../../games/cards/card";
-import * as User from "../../user";
+import type * as Card from "../../games/cards/card.js";
+import type * as User from "../../user.js";
/**
* Indicates a player has paid to redraw their hand under the Reboot house rule.
@@ -14,7 +14,7 @@ export interface CardDiscarded {
export const of = (
player: User.Id,
card: Card.Response,
- replacement?: Card.Response
+ replacement?: Card.Response,
): CardDiscarded => ({
event: "CardDiscarded",
player,
diff --git a/server/src/ts/events/game-event/game-ended.ts b/server/src/ts/events/game-event/game-ended.ts
index b6fa7cfc..7991b973 100644
--- a/server/src/ts/events/game-event/game-ended.ts
+++ b/server/src/ts/events/game-event/game-ended.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* Indicated a game has ended.
diff --git a/server/src/ts/events/game-event/game-started.ts b/server/src/ts/events/game-event/game-started.ts
index 20dbd1e8..63f4b655 100644
--- a/server/src/ts/events/game-event/game-started.ts
+++ b/server/src/ts/events/game-event/game-started.ts
@@ -1,6 +1,6 @@
-import * as Card from "../../games/cards/card";
-import * as Round from "../../games/game/round";
-import * as PublicRound from "../../games/game/round/public";
+import type * as Card from "../../games/cards/card.js";
+import type * as Round from "../../games/game/round.js";
+import type * as PublicRound from "../../games/game/round/public.js";
/**
* Indicated a game has started in the lobby.
@@ -23,14 +23,14 @@ export interface Playing {
export type GameStarted = Base & (Starting | Playing);
export const ofPlaying = (
- startedRound: Round.Playing
+ startedRound: Round.Playing,
): GameStarted & Playing => ({
event: "GameStarted",
round: startedRound.public(),
});
export const ofStarting = (
- startedRound: Round.Starting
+ startedRound: Round.Starting,
): GameStarted & Starting => ({
event: "GameStarted",
round: startedRound.public(),
diff --git a/server/src/ts/events/game-event/hand-redrawn.ts b/server/src/ts/events/game-event/hand-redrawn.ts
index 6fd06da1..4707877f 100644
--- a/server/src/ts/events/game-event/hand-redrawn.ts
+++ b/server/src/ts/events/game-event/hand-redrawn.ts
@@ -1,5 +1,5 @@
-import * as Card from "../../games/cards/card";
-import * as User from "../../user";
+import type * as Card from "../../games/cards/card.js";
+import type * as User from "../../user.js";
/**
* Indicates a player has paid to redraw their hand under the Reboot house rule.
diff --git a/server/src/ts/events/game-event/play-liked.ts b/server/src/ts/events/game-event/play-liked.ts
index 6d801db3..e0f431d4 100644
--- a/server/src/ts/events/game-event/play-liked.ts
+++ b/server/src/ts/events/game-event/play-liked.ts
@@ -1,4 +1,4 @@
-import * as Play from "../../games/cards/play";
+import type * as Play from "../../games/cards/play.js";
/**
* Indicates a play was liked.
diff --git a/server/src/ts/events/game-event/play-revealed.ts b/server/src/ts/events/game-event/play-revealed.ts
index 2e9b6a3b..ef8238c4 100644
--- a/server/src/ts/events/game-event/play-revealed.ts
+++ b/server/src/ts/events/game-event/play-revealed.ts
@@ -1,4 +1,4 @@
-import * as Play from "../../games/cards/play";
+import type * as Play from "../../games/cards/play.js";
/**
* Indicates the czar revealed a play for the round.
diff --git a/server/src/ts/events/game-event/play-submitted.ts b/server/src/ts/events/game-event/play-submitted.ts
index c36754cc..0dbd9e1c 100644
--- a/server/src/ts/events/game-event/play-submitted.ts
+++ b/server/src/ts/events/game-event/play-submitted.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* Indicates a player has submitted a play for the round.
diff --git a/server/src/ts/events/game-event/play-taken-back.ts b/server/src/ts/events/game-event/play-taken-back.ts
index 73db111f..24ed9d3e 100644
--- a/server/src/ts/events/game-event/play-taken-back.ts
+++ b/server/src/ts/events/game-event/play-taken-back.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* Indicates a player has taken back their play for the round.
diff --git a/server/src/ts/events/game-event/player-presence-changed.ts b/server/src/ts/events/game-event/player-presence-changed.ts
index 5827718a..bdbc96bb 100644
--- a/server/src/ts/events/game-event/player-presence-changed.ts
+++ b/server/src/ts/events/game-event/player-presence-changed.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* An event for when connection state for a user changes.
diff --git a/server/src/ts/events/game-event/playing-started.ts b/server/src/ts/events/game-event/playing-started.ts
index 2e8e7c90..4c4a32f2 100644
--- a/server/src/ts/events/game-event/playing-started.ts
+++ b/server/src/ts/events/game-event/playing-started.ts
@@ -1,5 +1,5 @@
-import * as Card from "../../games/cards/card";
-import * as Round from "../../games/game/round";
+import type * as Card from "../../games/cards/card.js";
+import type * as Round from "../../games/game/round.js";
/**
* If there was a Starting phase, this is used to advance to the playing phase.
@@ -13,7 +13,7 @@ export interface PlayingStarted {
export const of = (
round: Round.Playing,
- drawn?: Card.Response[]
+ drawn?: Card.Response[],
): PlayingStarted => ({
event: "PlayingStarted",
id: round.id.toString(),
diff --git a/server/src/ts/events/game-event/round-finished.ts b/server/src/ts/events/game-event/round-finished.ts
index c2728279..860c9648 100644
--- a/server/src/ts/events/game-event/round-finished.ts
+++ b/server/src/ts/events/game-event/round-finished.ts
@@ -1,6 +1,6 @@
-import * as GameRound from "../../games/game/round";
-import * as PublicRound from "../../games/game/round/public";
-import * as User from "../../user";
+import type * as GameRound from "../../games/game/round.js";
+import type * as PublicRound from "../../games/game/round/public.js";
+import type * as User from "../../user.js";
/**
* Indicates players have finished playing into the round and now the czar
diff --git a/server/src/ts/events/game-event/round-started.ts b/server/src/ts/events/game-event/round-started.ts
index 2869da82..0ea33c4d 100644
--- a/server/src/ts/events/game-event/round-started.ts
+++ b/server/src/ts/events/game-event/round-started.ts
@@ -1,6 +1,6 @@
-import * as Card from "../../games/cards/card";
-import * as Round from "../../games/game/round";
-import * as User from "../../user";
+import type * as Card from "../../games/cards/card.js";
+import type * as Round from "../../games/game/round.js";
+import type * as User from "../../user.js";
export interface Base {
event: "RoundStarted";
@@ -19,7 +19,7 @@ export type RoundStarted = Base & Call;
export const of = (
round: Round.Round,
- drawn?: Card.Response[]
+ drawn?: Card.Response[],
): RoundStarted => ({
event: "RoundStarted",
id: round.id.toString(),
diff --git a/server/src/ts/events/game-event/stage-timer-done.ts b/server/src/ts/events/game-event/stage-timer-done.ts
index d4eedae8..30b247dc 100644
--- a/server/src/ts/events/game-event/stage-timer-done.ts
+++ b/server/src/ts/events/game-event/stage-timer-done.ts
@@ -1,4 +1,4 @@
-import * as Round from "../../games/game/round";
+import type * as Round from "../../games/game/round.js";
/**
* Indicates that the stage timer has completed.
diff --git a/server/src/ts/events/game-event/start-judging.ts b/server/src/ts/events/game-event/start-judging.ts
index a515ec2d..84810253 100644
--- a/server/src/ts/events/game-event/start-judging.ts
+++ b/server/src/ts/events/game-event/start-judging.ts
@@ -1,6 +1,6 @@
-import * as Play from "../../games/cards/play";
-import * as StartRevealing from "./start-revealing";
-import * as Card from "../../games/cards/card";
+import type * as Card from "../../games/cards/card.js";
+import type * as Play from "../../games/cards/play.js";
+import type * as StartRevealing from "./start-revealing.js";
/**
* Indicates the czar has finished revealing the plays and is now picking a winner.
@@ -17,7 +17,7 @@ export interface StartJudging extends StartRevealing.AfterPlaying {
export const of = (
plays?: Play.Revealed[],
played?: Play.Id,
- drawn?: Card.Response[]
+ drawn?: Card.Response[],
): StartJudging => ({
event: "StartJudging",
plays,
diff --git a/server/src/ts/events/game-event/start-revealing.ts b/server/src/ts/events/game-event/start-revealing.ts
index e3b30a93..d2288291 100644
--- a/server/src/ts/events/game-event/start-revealing.ts
+++ b/server/src/ts/events/game-event/start-revealing.ts
@@ -1,5 +1,5 @@
-import * as Play from "../../games/cards/play";
-import * as Card from "../../games/cards/card";
+import type * as Card from "../../games/cards/card.js";
+import type * as Play from "../../games/cards/play.js";
/**
* Indicates players have finished playing into the round and now the czar
@@ -27,7 +27,7 @@ export interface AfterPlaying {
export const of = (
plays: Play.Id[],
played?: Play.Id,
- drawn?: Card.Response[]
+ drawn?: Card.Response[],
): StartRevealing => ({
event: "StartRevealing",
plays,
diff --git a/server/src/ts/events/lobby-event.ts b/server/src/ts/events/lobby-event.ts
index 7239c0bb..244546f9 100644
--- a/server/src/ts/events/lobby-event.ts
+++ b/server/src/ts/events/lobby-event.ts
@@ -1,9 +1,9 @@
-import { Configured } from "./lobby-event/configured";
-import { ConnectionChanged } from "./lobby-event/connection-changed";
-import { ErrorEncountered } from "./lobby-event/error-encountered";
-import { PresenceChanged } from "./lobby-event/presence-changed";
-import { PrivilegeChanged } from "./lobby-event/privilege-changed";
-import { UserRoleChanged } from "./lobby-event/user-role-changed";
+import type { Configured } from "./lobby-event/configured.js";
+import type { ConnectionChanged } from "./lobby-event/connection-changed.js";
+import type { ErrorEncountered } from "./lobby-event/error-encountered.js";
+import type { PresenceChanged } from "./lobby-event/presence-changed.js";
+import type { PrivilegeChanged } from "./lobby-event/privilege-changed.js";
+import type { UserRoleChanged } from "./lobby-event/user-role-changed.js";
export type LobbyEvent =
| Configured
diff --git a/server/src/ts/events/lobby-event/configured.ts b/server/src/ts/events/lobby-event/configured.ts
index 53340225..65655aad 100644
--- a/server/src/ts/events/lobby-event/configured.ts
+++ b/server/src/ts/events/lobby-event/configured.ts
@@ -1,4 +1,4 @@
-import Rfc6902 from "rfc6902";
+import type Rfc6902 from "rfc6902";
/**
* A change was made to the configuration for the lobby.
diff --git a/server/src/ts/events/lobby-event/connection-changed.ts b/server/src/ts/events/lobby-event/connection-changed.ts
index e8779c1f..5dd35029 100644
--- a/server/src/ts/events/lobby-event/connection-changed.ts
+++ b/server/src/ts/events/lobby-event/connection-changed.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* An event for when connection state for a user changes.
diff --git a/server/src/ts/events/lobby-event/error-encountered.ts b/server/src/ts/events/lobby-event/error-encountered.ts
index 7188e89e..f5973e96 100644
--- a/server/src/ts/events/lobby-event/error-encountered.ts
+++ b/server/src/ts/events/lobby-event/error-encountered.ts
@@ -1,4 +1,4 @@
-import * as Errors from "../../errors";
+import type * as Errors from "../../errors.js";
/**
* An error occurred in the lobby.
diff --git a/server/src/ts/events/lobby-event/presence-changed.ts b/server/src/ts/events/lobby-event/presence-changed.ts
index 79fc2064..97f3244e 100644
--- a/server/src/ts/events/lobby-event/presence-changed.ts
+++ b/server/src/ts/events/lobby-event/presence-changed.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* An event for when connection state for a user changes.
diff --git a/server/src/ts/events/lobby-event/privilege-changed.ts b/server/src/ts/events/lobby-event/privilege-changed.ts
index 7e6d071e..d0a14be6 100644
--- a/server/src/ts/events/lobby-event/privilege-changed.ts
+++ b/server/src/ts/events/lobby-event/privilege-changed.ts
@@ -1,4 +1,4 @@
-import * as User from "../../user";
+import type * as User from "../../user.js";
/**
* Indicates a user's level of privilege has changed.
@@ -11,7 +11,7 @@ export interface PrivilegeChanged {
export const of = (
user: User.Id,
- privilege: User.Privilege
+ privilege: User.Privilege,
): PrivilegeChanged => ({
event: "PrivilegeChanged",
user,
diff --git a/server/src/ts/events/lobby-event/user-role-changed.ts b/server/src/ts/events/lobby-event/user-role-changed.ts
index 90550a16..59dca86d 100644
--- a/server/src/ts/events/lobby-event/user-role-changed.ts
+++ b/server/src/ts/events/lobby-event/user-role-changed.ts
@@ -1,5 +1,5 @@
-import * as Card from "../../games/cards/card";
-import * as User from "../../user";
+import type * as Card from "../../games/cards/card.js";
+import type * as User from "../../user.js";
/**
* Indicates the role for a user has changed.
diff --git a/server/src/ts/events/user-event.ts b/server/src/ts/events/user-event.ts
index a1bc99e6..b8d44d01 100644
--- a/server/src/ts/events/user-event.ts
+++ b/server/src/ts/events/user-event.ts
@@ -1,4 +1,4 @@
-import { Sync } from "./user-event/sync";
+import type { Sync } from "./user-event/sync.js";
/**
* An event that should be sent to all users.
diff --git a/server/src/ts/events/user-event/sync.ts b/server/src/ts/events/user-event/sync.ts
index 7bffaffe..9858bc8a 100644
--- a/server/src/ts/events/user-event/sync.ts
+++ b/server/src/ts/events/user-event/sync.ts
@@ -1,7 +1,7 @@
-import * as Card from "../../games/cards/card";
-import { Hand } from "../../games/cards/hand";
-import * as Lobby from "../../lobby";
-import { LikeDetail } from "../../games/game/round/public";
+import type * as Card from "../../games/cards/card.js";
+import type { Hand } from "../../games/cards/hand.js";
+import type { LikeDetail } from "../../games/game/round/public.js";
+import type * as Lobby from "../../lobby.js";
/**
* Synchronise the game state.
@@ -21,7 +21,7 @@ export const of = (
hand?: Hand,
play?: Card.Id[],
likeDetail?: LikeDetail,
- calls?: Card.Call[]
+ calls?: Card.Call[],
): Sync => ({
event: "Sync",
state,
diff --git a/server/src/ts/games/cards/card.ts b/server/src/ts/games/cards/card.ts
index 991fecac..4d66e445 100644
--- a/server/src/ts/games/cards/card.ts
+++ b/server/src/ts/games/cards/card.ts
@@ -1,7 +1,8 @@
import * as uuid from "uuid";
import wu from "wu";
-import { Source } from "./source";
-import { Custom } from "./sources/custom";
+
+import type { Source } from "./source.js";
+import type { Custom } from "./sources/custom.js";
/**
* A game card.
@@ -41,7 +42,7 @@ export type CustomCard = TCard & { source: Custom };
* If the response is a custom one, and therefore mutable.
*/
export const isCustom = (
- card: TCard
+ card: TCard,
): card is CustomCard => card.source.source == "Custom";
/** A unique id for an instance of a card.*/
@@ -65,10 +66,10 @@ export interface Styled {
}
export const isSlot = (part: Part): part is Slot =>
- typeof part !== "string" && !part.hasOwnProperty("text");
+ typeof part !== "string" && !Object.hasOwn(part, "text");
export const isStyled = (part: Part): part is Styled =>
- typeof part !== "string" && part.hasOwnProperty("text");
+ typeof part !== "string" && Object.hasOwn(part, "text");
/** Either text or a slot.*/
export type Part = string | Styled | Slot;
@@ -96,11 +97,11 @@ export const isResponse = (card: Card): card is Response =>
export const slotCount = (call: Call | Part[][]): number => {
let next = 0;
const indices = wu(
- call.hasOwnProperty("parts") ? (call as Call).parts : (call as Part[][])
+ Object.hasOwn(call, "parts") ? (call as Call).parts : (call as Part[][]),
)
.flatten(true)
.concatMap((part) =>
- isSlot(part) ? [part.index !== undefined ? part.index : next++] : []
+ isSlot(part) ? [part.index !== undefined ? part.index : next++] : [],
);
return new Set(indices).size;
};
diff --git a/server/src/ts/games/cards/decks.ts b/server/src/ts/games/cards/decks.ts
index 16c44119..b7bb09c0 100644
--- a/server/src/ts/games/cards/decks.ts
+++ b/server/src/ts/games/cards/decks.ts
@@ -1,8 +1,9 @@
import wu from "wu";
-import * as Cache from "../../cache";
-import { OutOfCardsError } from "../../errors/game-state-error";
-import * as Util from "../../util";
-import * as Card from "./card";
+
+import type * as Cache from "../../cache.js";
+import { OutOfCardsError } from "../../errors/game-state-error.js";
+import * as Util from "../../util.js";
+import * as Card from "./card.js";
const union = (sets: Iterable>): Set => {
const result = new Set();
@@ -42,6 +43,10 @@ export abstract class Deck {
this.discarded.add(card);
}
+ public draw(cards: 1): [C];
+ public draw(cards: 2): [C, C];
+ public draw(cards: 3): [C, C, C];
+ public draw(cards: number): C[];
public draw(cards: number): C[] {
const cardsLeft = this.cards.length;
const toDraw = Math.min(cardsLeft, cards);
@@ -54,6 +59,10 @@ export abstract class Deck {
}
}
+ public replace(...cards: [C]): [C];
+ public replace(...cards: [C, C]): [C, C];
+ public replace(...cards: [C, C, C]): [C, C, C];
+ public replace(...cards: C[]): C[];
public replace(...cards: C[]): C[] {
this.discard(cards);
return this.draw(cards.length);
@@ -95,7 +104,7 @@ export class Calls extends Deck {
* (in the case of custom cards).
*/
export class Responses extends Deck {
- protected discardSingle(card: Card.Response): void {
+ protected override discardSingle(card: Card.Response): void {
// We duplicate the card here so we don't damage any references to it hanging around elsewhere (e.g: history).
this.discarded.add({
...card,
@@ -105,7 +114,7 @@ export class Responses extends Deck {
}
public static fromTemplates(
- template: Iterable>
+ template: Iterable>,
): Responses {
const deck = new Responses([], union(template));
deck.reshuffle();
@@ -141,6 +150,6 @@ export interface Templates extends Cache.Tagged {
export const decks = (templates: Iterable): Decks => ({
calls: Calls.fromTemplates(wu(templates).map((template) => template.calls)),
responses: Responses.fromTemplates(
- wu(templates).map((template) => template.responses)
+ wu(templates).map((template) => template.responses),
),
});
diff --git a/server/src/ts/games/cards/hand.ts b/server/src/ts/games/cards/hand.ts
index 67fe38b9..10aa549c 100644
--- a/server/src/ts/games/cards/hand.ts
+++ b/server/src/ts/games/cards/hand.ts
@@ -1,4 +1,4 @@
-import * as Card from "./card";
+import type * as Card from "./card.js";
/**
* A hand of cards.
diff --git a/server/src/ts/games/cards/play.ts b/server/src/ts/games/cards/play.ts
index f942c544..755e2200 100644
--- a/server/src/ts/games/cards/play.ts
+++ b/server/src/ts/games/cards/play.ts
@@ -1,5 +1,6 @@
import * as uuid from "uuid";
-import { Response } from "./card";
+
+import type { Response } from "./card.js";
/** A series of cards played into a round.*/
export type Play = Response[];
diff --git a/server/src/ts/games/cards/source.ts b/server/src/ts/games/cards/source.ts
index f8851a69..54fa19da 100644
--- a/server/src/ts/games/cards/source.ts
+++ b/server/src/ts/games/cards/source.ts
@@ -1,10 +1,10 @@
-import * as Cache from "../../cache";
-import * as Decks from "./decks";
-import { Custom } from "./sources/custom";
-import { Generated } from "./sources/generated";
-import { BuiltIn } from "./sources/builtIn";
-import { ManyDecks } from "./sources/many-decks";
-import { JsonAgainstHumanity } from "./sources/json-against-humanity";
+import type * as Cache from "../../cache.js";
+import type * as Decks from "./decks.js";
+import type { BuiltIn } from "./sources/builtIn.js";
+import type { Custom } from "./sources/custom.js";
+import type { Generated } from "./sources/generated.js";
+import type { JsonAgainstHumanity } from "./sources/json-against-humanity.js";
+import type { ManyDecks } from "./sources/many-decks.js";
/**
* A source for a card or deck.
@@ -73,7 +73,7 @@ export interface AtLeastTemplates {
* A resolver that only allows access to properties that don't require store
* access.
*/
-export interface LimitedResolver {
+export interface LimitedResolver {
id: () => string;
deckId: () => string;
loadingDetails: () => Details;
@@ -83,8 +83,7 @@ export interface LimitedResolver {
/**
* Resolve information about the given source.
*/
-export abstract class Resolver
- implements LimitedResolver {
+export abstract class Resolver implements LimitedResolver {
/**
* The source in question.
*/
@@ -115,13 +114,13 @@ export abstract class Resolver
* Note that if you have a fresh summary, you should check if that has a
* tag first.
*/
- public abstract getTag(): Promise;
+ public abstract getTag(): Promise;
/**
* The summary for the source, and potentially the templates if efficient to
* return both.
*/
- public abstract atLeastSummary(): Promise;
+ public abstract atLeastSummary(): Promise;
/**
* The summary for the source.
@@ -141,7 +140,7 @@ export abstract class Resolver
* The deck templates for the source, and potentially the summary if
* efficient to return both.
*/
- public abstract atLeastTemplates(): Promise;
+ public abstract atLeastTemplates(): Promise;
/**
* The deck templates for the source.
@@ -202,7 +201,7 @@ export class CachedResolver extends Resolver {
return {
summary: await this.cache.getSummary(
this.resolver,
- async () => await this.resolver.atLeastSummary()
+ async () => await this.resolver.atLeastSummary(),
),
};
}
@@ -211,7 +210,7 @@ export class CachedResolver extends Resolver {
return {
templates: await this.cache.getTemplates(
this.resolver,
- async () => await this.resolver.atLeastTemplates()
+ async () => await this.resolver.atLeastTemplates(),
),
};
}
@@ -250,6 +249,6 @@ export interface MetaResolver {
* If the source should be cached.
*/
readonly cache: boolean;
- limitedResolver(source: S): LimitedResolver;
+ limitedResolver(source: S): LimitedResolver;
resolver(source: S): Resolver;
}
diff --git a/server/src/ts/games/cards/sources.ts b/server/src/ts/games/cards/sources.ts
index a9868352..85843efe 100644
--- a/server/src/ts/games/cards/sources.ts
+++ b/server/src/ts/games/cards/sources.ts
@@ -1,13 +1,13 @@
-import { Cache } from "../../cache";
-import * as Util from "../../util";
-import * as Source from "./source";
-import * as Player from "./sources/custom";
-import * as Config from "../../config";
-import * as BuiltIn from "./sources/builtIn";
-import { SourceNotFoundError } from "../../errors/action-execution-error";
-import * as ManyDecks from "./sources/many-decks";
-import * as JsonAgainstHumanity from "./sources/json-against-humanity";
-import * as Generated from "./sources/generated";
+import type { Cache } from "../../cache.js";
+import type * as Config from "../../config.js";
+import { SourceNotFoundError } from "../../errors/action-execution-error.js";
+import * as Util from "../../util.js";
+import * as Source from "./source.js";
+import * as BuiltIn from "./sources/builtIn.js";
+import * as Player from "./sources/custom.js";
+import * as Generated from "./sources/generated.js";
+import * as JsonAgainstHumanity from "./sources/json-against-humanity.js";
+import * as ManyDecks from "./sources/many-decks.js";
async function loadIfEnabled(
config: Config | undefined,
diff --git a/server/src/ts/games/cards/sources/builtIn.ts b/server/src/ts/games/cards/sources/builtIn.ts
index a9749e16..9bad7142 100644
--- a/server/src/ts/games/cards/sources/builtIn.ts
+++ b/server/src/ts/games/cards/sources/builtIn.ts
@@ -1,15 +1,16 @@
-import * as Source from "../source";
-import * as Decks from "../decks";
-import JSON5 from "json5";
import { promises as fs } from "fs";
-import * as Config from "../../../config";
+import JSON5 from "json5";
import * as path from "path";
-import { Part } from "../card";
-import * as Card from "../card";
+
+import type * as Config from "../../../config.js";
import {
SourceNotFoundError,
SourceServiceError,
-} from "../../../errors/action-execution-error";
+} from "../../../errors/action-execution-error.js";
+import type { Part } from "../card.js";
+import * as Card from "../card.js";
+import type * as Decks from "../decks.js";
+import * as Source from "../source.js";
const extension = ".deck.json5";
@@ -56,7 +57,7 @@ export class Resolver extends Source.Resolver {
config: Config.BuiltIn,
source: BuiltIn,
summary?: Source.Summary,
- deck?: BuiltInDeck
+ deck?: BuiltInDeck,
) {
super();
this.config = config;
@@ -143,14 +144,14 @@ export class MetaResolver implements Source.MetaResolver {
public constructor(
config: Config.BuiltIn,
summaries: Map,
- decks: Map
+ decks: Map,
) {
this.config = config;
this.summaries = summaries;
this.decks = decks;
}
- limitedResolver(source: BuiltIn): Source.LimitedResolver {
+ limitedResolver(source: BuiltIn): Source.LimitedResolver {
return this.resolver(source);
}
@@ -185,7 +186,9 @@ export async function load(config: Config.BuiltIn): Promise {
for (const id of config.decks) {
const rawDeck = JSON5.parse(
- (await fs.readFile(path.join(config.basePath, id + extension))).toString()
+ (
+ await fs.readFile(path.join(config.basePath, id + extension))
+ ).toString(),
) as BuiltInDeck;
summaries.set(id, {
details: {
diff --git a/server/src/ts/games/cards/sources/custom.ts b/server/src/ts/games/cards/sources/custom.ts
index 7c1a9c7e..6a50e13f 100644
--- a/server/src/ts/games/cards/sources/custom.ts
+++ b/server/src/ts/games/cards/sources/custom.ts
@@ -1,4 +1,4 @@
-import * as Source from "../source";
+import type * as Source from "../source.js";
/**
* A source for custom cards made during the game.
diff --git a/server/src/ts/games/cards/sources/generated.ts b/server/src/ts/games/cards/sources/generated.ts
index 0b96fb3b..1baa43fc 100644
--- a/server/src/ts/games/cards/sources/generated.ts
+++ b/server/src/ts/games/cards/sources/generated.ts
@@ -1,4 +1,4 @@
-import * as Source from "../source";
+import type * as Source from "../source.js";
/**
* A source for cards generated during the game for reasons such as house rules.
diff --git a/server/src/ts/games/cards/sources/json-against-humanity.ts b/server/src/ts/games/cards/sources/json-against-humanity.ts
index 4479f988..4867f891 100644
--- a/server/src/ts/games/cards/sources/json-against-humanity.ts
+++ b/server/src/ts/games/cards/sources/json-against-humanity.ts
@@ -1,9 +1,10 @@
-import * as Source from "../source";
-import http, { AxiosRequestConfig } from "axios";
-import * as Config from "../../../config";
-import { SourceNotFoundError } from "../../../errors/action-execution-error";
-import * as Decks from "../decks";
-import * as Card from "../card";
+import { AxiosRequestConfig, default as Axios } from "axios";
+
+import type * as Config from "../../../config.js";
+import { SourceNotFoundError } from "../../../errors/action-execution-error.js";
+import * as Card from "../card.js";
+import type * as Decks from "../decks.js";
+import * as Source from "../source.js";
/**
* From JSON Against Humanity (https://crhallberg.com/cah/)
@@ -44,7 +45,7 @@ function* introduceSlots(line: string): Iterable {
yield nextSlot;
}
yield part;
- const last = part.trimRight().substr(-1);
+ const last = part.trimEnd().slice(-1);
if (part === "" || endsSentence.has(last)) {
nextSlot = { transform: "Capitalize" };
} else {
@@ -56,7 +57,7 @@ function* introduceSlots(line: string): Iterable {
function rawDeckToSummaryAndTemplates(
raw: Packs,
pack: Pack,
- id: string
+ id: string,
): {
summary: Source.Summary;
templates: Decks.Templates;
@@ -67,7 +68,7 @@ function rawDeckToSummaryAndTemplates(
};
function call(index: number): Card.Call {
- const from = raw.black[index];
+ const from = raw.black[index] as { text: string; pick: number };
const parts = from.text.split("\n").map((t) => [...introduceSlots(t)]);
const slots = Card.slotCount(parts);
const extraSlots = Math.max(0, from.pick - slots);
@@ -79,7 +80,7 @@ function rawDeckToSummaryAndTemplates(
}
function response(index: number): Card.Response {
- const from = raw.white[index];
+ const from = raw.white[index] as string;
const stripped = from.replace("\n", "");
return {
id: Card.id(),
@@ -113,7 +114,7 @@ export class Resolver extends Source.Resolver {
source: JsonAgainstHumanity,
config: Config.JsonAgainstHumanity,
summary: Source.Summary,
- templates: Decks.Templates
+ templates: Decks.Templates,
) {
super();
this.source = source;
@@ -179,7 +180,7 @@ export class MetaResolver implements Source.MetaResolver {
const protoOrder: [string, Pack][] = [];
for (let index = 0; index < decks.packs.length; index++) {
const id = index.toString();
- const pack = decks.packs[index];
+ const pack = decks.packs[index] as Pack;
this.decks.set(id, rawDeckToSummaryAndTemplates(decks, pack, id));
protoOrder.push([id, pack]);
}
@@ -189,7 +190,7 @@ export class MetaResolver implements Source.MetaResolver {
private static compare(
[_idA, a]: [string, Pack],
- [_idB, b]: [string, Pack]
+ [_idB, b]: [string, Pack],
): number {
return MetaResolver.boolCompare(a, b, (v) => v.official);
}
@@ -227,7 +228,7 @@ export class MetaResolver implements Source.MetaResolver {
}
export const load = async (
- config: Config.JsonAgainstHumanity
+ config: Config.JsonAgainstHumanity,
): Promise => {
const httpConfig: AxiosRequestConfig = {
method: "GET",
@@ -235,6 +236,6 @@ export const load = async (
responseType: "json",
};
- const data = await http.get("", httpConfig);
+ const data = await Axios.get("", httpConfig);
return new MetaResolver(config, data.data);
};
diff --git a/server/src/ts/games/cards/sources/many-decks.ts b/server/src/ts/games/cards/sources/many-decks.ts
index 257631ec..6e1e17c9 100644
--- a/server/src/ts/games/cards/sources/many-decks.ts
+++ b/server/src/ts/games/cards/sources/many-decks.ts
@@ -1,16 +1,21 @@
-import * as Source from "../source";
+import {
+ AxiosError,
+ AxiosInstance,
+ AxiosRequestConfig,
+ default as Axios,
+} from "axios";
import genericPool from "generic-pool";
-import http, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios";
-import * as Config from "../../../config";
import HttpStatus from "http-status-codes";
+import JSON5 from "json5";
+
+import type * as Config from "../../../config.js";
import {
SourceNotFoundError,
SourceServiceError,
-} from "../../../errors/action-execution-error";
-import * as Decks from "../decks";
-import JSON5 from "json5";
-import * as Card from "../card";
-import { MassiveDecksError } from "../../../errors";
+} from "../../../errors/action-execution-error.js";
+import * as Card from "../card.js";
+import type * as Decks from "../decks.js";
+import * as Source from "../source.js";
/**
* A source that just tries to load an arbitrary URL.
@@ -32,7 +37,7 @@ export class Resolver extends Source.Resolver {
public constructor(
source: ManyDecks,
config: Config.ManyDecks,
- connectionPool: genericPool.Pool
+ connectionPool: genericPool.Pool,
) {
super();
this.source = source;
@@ -146,12 +151,12 @@ export class MetaResolver implements Source.MetaResolver {
this.connectionPool = genericPool.createPool(
{
- create: async () => http.create(httpConfig),
+ create: async () => Axios.create(httpConfig),
destroy: async (_) => {
// Do nothing.
},
},
- { max: config.simultaneousConnections }
+ { max: config.simultaneousConnections },
);
}
diff --git a/server/src/ts/games/game.ts b/server/src/ts/games/game.ts
index 87f66793..85e83c06 100644
--- a/server/src/ts/games/game.ts
+++ b/server/src/ts/games/game.ts
@@ -1,28 +1,28 @@
import wu from "wu";
-import { InvalidActionError } from "../errors/validation";
-import * as Event from "../event";
-import * as GameStarted from "../events/game-event/game-started";
-import * as PauseStateChanged from "../events/game-event/pause-state-changed";
-import * as PlaySubmitted from "../events/game-event/play-submitted";
-import * as RoundStarted from "../events/game-event/round-started";
-import * as PlayingStarted from "../events/game-event/playing-started";
-import { Lobby } from "../lobby";
-import { ServerState } from "../server-state";
-import * as Timeout from "../timeout";
-import * as FinishedPlaying from "../timeout/finished-playing";
-import * as RoundStageTimerDone from "../timeout/round-stage-timer-done";
-import * as User from "../user";
-import * as Util from "../util";
-import * as Card from "./cards/card";
-import * as Decks from "./cards/decks";
-import * as Play from "./cards/play";
-import * as Round from "./game/round";
-import * as PublicRound from "./game/round/public";
-import { StoredPlay } from "./game/round/stored-play";
-import * as Player from "./player";
-import * as Rules from "./rules";
-import * as HappyEnding from "./rules/happy-ending";
-import * as CzarChoices from "./rules/czar-choices";
+
+import { InvalidActionError } from "../errors/validation.js";
+import * as Event from "../event.js";
+import * as GameStarted from "../events/game-event/game-started.js";
+import * as PauseStateChanged from "../events/game-event/pause-state-changed.js";
+import * as PlaySubmitted from "../events/game-event/play-submitted.js";
+import * as PlayingStarted from "../events/game-event/playing-started.js";
+import * as RoundStarted from "../events/game-event/round-started.js";
+import type { Lobby } from "../lobby.js";
+import type { ServerState } from "../server-state.js";
+import type * as Timeout from "../timeout.js";
+import * as FinishedPlaying from "../timeout/finished-playing.js";
+import * as RoundStageTimerDone from "../timeout/round-stage-timer-done.js";
+import type * as User from "../user.js";
+import * as Util from "../util.js";
+import * as Card from "./cards/card.js";
+import * as Decks from "./cards/decks.js";
+import * as Play from "./cards/play.js";
+import * as Round from "./game/round.js";
+import type * as PublicRound from "./game/round/public.js";
+import type { StoredPlay } from "./game/round/stored-play.js";
+import * as Player from "./player.js";
+import * as Rules from "./rules.js";
+import * as HappyEnding from "./rules/happy-ending.js";
export interface Public {
round: PublicRound.Public;
@@ -107,7 +107,13 @@ export class Game {
);
}
- private static canBeCzar(user: User.User, player?: Player.Player): boolean {
+ private static canBeCzar(
+ user: User.User | undefined,
+ player?: Player.Player | undefined,
+ ): boolean {
+ if (user === undefined) {
+ return false;
+ }
return user.control !== "Computer" && Game.activePlayer(user, player);
}
@@ -142,14 +148,13 @@ export class Game {
nextIndex += 1;
nextIndex = nextIndex >= playerOrder.length ? 0 : nextIndex;
}
-
let triedEveryone = false;
incrementIndex();
while (!triedEveryone) {
if (nextIndex === currentIndex) {
triedEveryone = true;
}
- const potentialCzar = playerOrder[nextIndex];
+ const potentialCzar = playerOrder[nextIndex] as string;
if (Game.canBeCzar(users[potentialCzar], players[potentialCzar])) {
return potentialCzar;
}
@@ -208,7 +213,7 @@ export class Game {
}
const playersInRound = new Set(
wu(playerOrder).filter((id) =>
- Game.isPlayerInRound(czar, playerMap, id, users[id]),
+ Game.isPlayerInRound(czar, playerMap, id, users[id] as User.User),
),
);
let round: Round.Starting | Round.Playing;
@@ -292,7 +297,12 @@ export class Game {
const roundId = round.id + 1;
const playersInRound = new Set(
wu(this.playerOrder).filter((id) =>
- Game.isPlayerInRound(czar, this.players, id, lobby.users[id]),
+ Game.isPlayerInRound(
+ czar,
+ this.players,
+ id,
+ lobby.users[id] as User.User,
+ ),
),
);
if (this.rules.houseRules.happyEnding?.inFinalRound) {
@@ -317,7 +327,7 @@ export class Game {
);
}
}
- let atStart = this.startRound(server, false, this.round);
+ const atStart = this.startRound(server, false, this.round);
return {
events: [
...events,
@@ -334,7 +344,7 @@ export class Game {
*/
public removeFromRound(
toRemove: User.Id,
- server: ServerState,
+ _server: ServerState,
): { timeouts?: Iterable } {
const player = this.players[toRemove];
if (player !== undefined && this.round.stage !== "Starting") {
diff --git a/server/src/ts/games/game/round.ts b/server/src/ts/games/game/round.ts
index 9f7281a0..7740ccd6 100644
--- a/server/src/ts/games/game/round.ts
+++ b/server/src/ts/games/game/round.ts
@@ -1,24 +1,25 @@
import wu from "wu";
-import { Action } from "../../action";
-import { IncorrectRoundStageError } from "../../errors/action-execution-error";
-import * as User from "../../user";
-import * as Util from "../../util";
-import * as Card from "../cards/card";
-import * as Play from "../cards/play";
-import * as PublicRound from "./round/public";
-import * as StoredPlay from "./round/stored-play";
-import * as RoundStageTimerDone from "../../timeout/round-stage-timer-done";
-import * as Timeout from "../../timeout";
-import * as Event from "../../event";
-import * as StartJudging from "../../events/game-event/start-judging";
-import * as StartRevealing from "../../events/game-event/start-revealing";
-import * as Rules from "../rules";
-import * as Game from "../game";
-import { InvalidActionError } from "../../errors/validation";
-import { ServerState } from "../../server-state";
-import { Part } from "../cards/card";
-import * as CzarChoices from "../rules/czar-choices";
-import { Decks } from "../cards/decks";
+
+import type { Action } from "../../action.js";
+import { IncorrectRoundStageError } from "../../errors/action-execution-error.js";
+import { InvalidActionError } from "../../errors/validation.js";
+import * as Event from "../../event.js";
+import * as StartJudging from "../../events/game-event/start-judging.js";
+import * as StartRevealing from "../../events/game-event/start-revealing.js";
+import type { ServerState } from "../../server-state.js";
+import type * as Timeout from "../../timeout.js";
+import * as RoundStageTimerDone from "../../timeout/round-stage-timer-done.js";
+import type * as User from "../../user.js";
+import * as Util from "../../util.js";
+import type { Part } from "../cards/card.js";
+import * as Card from "../cards/card.js";
+import type { Decks } from "../cards/decks.js";
+import type * as Play from "../cards/play.js";
+import type * as Game from "../game.js";
+import type * as Rules from "../rules.js";
+import * as CzarChoices from "../rules/czar-choices.js";
+import type * as PublicRound from "./round/public.js";
+import * as StoredPlay from "./round/stored-play.js";
export type Round = Starting | Playing | Revealing | Judging | Complete;
@@ -78,7 +79,7 @@ export interface Timed {
export const isTimed = (
round: Base,
-): round is Base & Timed => round.hasOwnProperty("timedOut");
+): round is Base & Timed => Object.hasOwn(round, "timedOut");
export class Complete extends Base<"Complete"> {
public get stage(): "Complete" {
diff --git a/server/src/ts/games/game/round/public.ts b/server/src/ts/games/game/round/public.ts
index d9514ef3..bc7abce3 100644
--- a/server/src/ts/games/game/round/public.ts
+++ b/server/src/ts/games/game/round/public.ts
@@ -1,7 +1,7 @@
-import * as User from "../../../user";
-import * as Card from "../../cards/card";
-import * as Play from "../../cards/play";
-import * as Player from "../../player";
+import type * as User from "../../../user.js";
+import type * as Card from "../../cards/card.js";
+import type * as Play from "../../cards/play.js";
+import type * as Player from "../../player.js";
export type Public = Starting | Playing | Revealing | Judging | Complete;
diff --git a/server/src/ts/games/game/round/stored-play.ts b/server/src/ts/games/game/round/stored-play.ts
index 13181abb..32eabedb 100644
--- a/server/src/ts/games/game/round/stored-play.ts
+++ b/server/src/ts/games/game/round/stored-play.ts
@@ -1,6 +1,6 @@
-import * as User from "../../../user";
-import * as Play from "../../cards/play";
-import { Round } from "../round";
+import type * as User from "../../../user.js";
+import type * as Play from "../../cards/play.js";
+import type { Round } from "../round.js";
export interface StoredPlay {
id: Play.Id;
@@ -22,7 +22,7 @@ const isRevealed = (play: StoredPlay): play is Revealed => play.revealed;
* Checks if every stored play in a round is revealed or not.
*/
export const allRevealed = (
- round: TRound & { plays: StoredPlay[] }
+ round: TRound & { plays: StoredPlay[] },
): round is TRound & {
plays: Revealed[];
} => round.plays.every(isRevealed);
diff --git a/server/src/ts/games/player.ts b/server/src/ts/games/player.ts
index ae4b6eca..b7fd69a2 100644
--- a/server/src/ts/games/player.ts
+++ b/server/src/ts/games/player.ts
@@ -1,6 +1,6 @@
-import * as User from "../user";
-import { Hand } from "./cards/hand";
-import { Game } from "./game";
+import type * as User from "../user.js";
+import type { Hand } from "./cards/hand.js";
+import type { Game } from "./game.js";
/**
* A player containing only state all users can see.
diff --git a/server/src/ts/games/rules.ts b/server/src/ts/games/rules.ts
index eca6f840..ccd104e9 100644
--- a/server/src/ts/games/rules.ts
+++ b/server/src/ts/games/rules.ts
@@ -1,5 +1,5 @@
-import * as HouseRules from "./rules/house-rules";
-import * as Rando from "./rules/rando";
+import * as HouseRules from "./rules/house-rules.js";
+import * as Rando from "./rules/rando.js";
/** The rules for a standard game.
*/
diff --git a/server/src/ts/games/rules/czar-choices.ts b/server/src/ts/games/rules/czar-choices.ts
index 40ca5fba..dfc1b373 100644
--- a/server/src/ts/games/rules/czar-choices.ts
+++ b/server/src/ts/games/rules/czar-choices.ts
@@ -1,4 +1,4 @@
-import * as Card from "../cards/card";
+import * as Card from "../cards/card.js";
/**
* Configuration for the "Czar Choices" house rule.
diff --git a/server/src/ts/games/rules/happy-ending.ts b/server/src/ts/games/rules/happy-ending.ts
index 8463e2c2..e8b9e5bb 100644
--- a/server/src/ts/games/rules/happy-ending.ts
+++ b/server/src/ts/games/rules/happy-ending.ts
@@ -1,4 +1,4 @@
-import * as Card from "../cards/card";
+import * as Card from "../cards/card.js";
/**
* Configuration for the "Happy Ending" house rule.
diff --git a/server/src/ts/games/rules/house-rules.ts b/server/src/ts/games/rules/house-rules.ts
index b6540eb9..28de410c 100644
--- a/server/src/ts/games/rules/house-rules.ts
+++ b/server/src/ts/games/rules/house-rules.ts
@@ -1,8 +1,13 @@
-import { PackingHeat, Reboot, ComedyWriter, NeverHaveIEver } from "../rules";
-import * as Rando from "./rando";
-import * as HappyEnding from "./happy-ending";
-import * as CzarChoices from "./czar-choices";
-import * as WinnersPick from "./winners-pick";
+import type {
+ ComedyWriter,
+ NeverHaveIEver,
+ PackingHeat,
+ Reboot,
+} from "../rules.js";
+import type * as CzarChoices from "./czar-choices.js";
+import type * as HappyEnding from "./happy-ending.js";
+import * as Rando from "./rando.js";
+import type * as WinnersPick from "./winners-pick.js";
/**
* Non-standard rules that can be applied to a game.
diff --git a/server/src/ts/games/rules/rando.ts b/server/src/ts/games/rules/rando.ts
index eacbfd18..552af8b5 100644
--- a/server/src/ts/games/rules/rando.ts
+++ b/server/src/ts/games/rules/rando.ts
@@ -1,9 +1,9 @@
-import { RegisterUser } from "../../action/initial/register-user";
-import * as Event from "../../event";
-import * as PresenceChanged from "../../events/lobby-event/presence-changed";
-import * as Lobby from "../../lobby";
-import * as User from "../../user";
-import * as Util from "../../util";
+import type { RegisterUser } from "../../action/initial/register-user.js";
+import * as Event from "../../event.js";
+import * as PresenceChanged from "../../events/lobby-event/presence-changed.js";
+import * as Lobby from "../../lobby.js";
+import type * as User from "../../user.js";
+import * as Util from "../../util.js";
/**
* The maximum number of AI players allowed in a single game.
@@ -76,12 +76,16 @@ const isId = (ai: User.Id | RegisterUser): ai is User.Id =>
export const createIfNeeded = (
inLobby: Lobby.Lobby,
- ai: User.Id | RegisterUser
+ ai: User.Id | RegisterUser,
): { user: User.Id; events: Iterable } => {
if (isId(ai)) {
return {
user: ai,
- events: [Event.targetAll(PresenceChanged.joined(ai, inLobby.users[ai]))],
+ events: [
+ Event.targetAll(
+ PresenceChanged.joined(ai, inLobby.users[ai] as User.User),
+ ),
+ ],
};
} else {
return Lobby.addUser(inLobby, ai, "Player", (user) => ({
@@ -94,13 +98,13 @@ export const createIfNeeded = (
function* add(
inLobby: Lobby.Lobby,
config: Rando,
- number: number
+ number: number,
): Iterable {
const added = config.unused
.splice(0, number)
.map((ai) => createIfNeeded(inLobby, ai));
for (const { user, events } of added) {
- const userData = inLobby.users[user];
+ const userData = inLobby.users[user] as User.User;
userData.presence = "Joined";
config.current.push(user);
yield* events;
@@ -134,7 +138,7 @@ export const create = (inLobby: Lobby.Lobby, initial?: Public): Rando => {
export function* change(
inLobby: Lobby.Lobby,
config: Rando,
- changeTo?: Public
+ changeTo?: Public,
): Iterable {
const want = changeTo !== undefined ? changeTo.number : 0;
const have = config.current.length;
@@ -147,10 +151,10 @@ export function* change(
const toRemove = have - want;
const removed = config.current.splice(
config.current.length - toRemove,
- toRemove
+ toRemove,
);
for (const ai of removed) {
- const user = inLobby.users[ai];
+ const user = inLobby.users[ai] as User.User;
user.presence = "Left";
yield Event.targetAll(PresenceChanged.left(ai, "Left"));
}
diff --git a/server/src/ts/index.ts b/server/src/ts/index.ts
index e031d4ed..4542dae8 100644
--- a/server/src/ts/index.ts
+++ b/server/src/ts/index.ts
@@ -1,6 +1,7 @@
+import "express-async-errors";
+
import bodyParser from "body-parser";
import express, { NextFunction, Request, Response } from "express";
-import "express-async-errors";
import expressWinston from "express-winston";
import ws from "express-ws";
import { promises as fs } from "fs";
@@ -9,24 +10,25 @@ import HttpStatus from "http-status-codes";
import JSON5 from "json5";
import sourceMapSupport from "source-map-support";
import wu from "wu";
-import * as CheckAlive from "./action/initial/check-alive";
-import * as CreateLobby from "./action/initial/create-lobby";
-import * as RegisterUser from "./action/initial/register-user";
-import * as ServerConfig from "./config";
-import { MassiveDecksError } from "./errors";
-import { InvalidLobbyPasswordError } from "./errors/authentication";
-import { UsernameAlreadyInUseError } from "./errors/registration";
-import * as Event from "./event";
-import * as PresenceChanged from "./events/lobby-event/presence-changed";
-import * as Player from "./games/player";
-import * as Change from "./lobby/change";
-import { GameCode } from "./lobby/game-code";
-import * as Logging from "./logging";
-import * as ServerState from "./server-state";
-import * as Timeout from "./timeout";
-import * as UserDisconnect from "./timeout/user-disconnect";
-import * as User from "./user";
-import * as Token from "./user/token";
+
+import * as CheckAlive from "./action/initial/check-alive.js";
+import * as CreateLobby from "./action/initial/create-lobby.js";
+import * as RegisterUser from "./action/initial/register-user.js";
+import * as ServerConfig from "./config.js";
+import { MassiveDecksError } from "./errors.js";
+import { InvalidLobbyPasswordError } from "./errors/authentication.js";
+import { UsernameAlreadyInUseError } from "./errors/registration.js";
+import * as Event from "./event.js";
+import * as PresenceChanged from "./events/lobby-event/presence-changed.js";
+import * as Player from "./games/player.js";
+import * as Change from "./lobby/change.js";
+import type { GameCode } from "./lobby/game-code.js";
+import * as Logging from "./logging.js";
+import * as ServerState from "./server-state.js";
+import * as Timeout from "./timeout.js";
+import * as UserDisconnect from "./timeout/user-disconnect.js";
+import * as User from "./user.js";
+import * as Token from "./user/token.js";
sourceMapSupport.install();
@@ -192,7 +194,7 @@ async function main(): Promise {
});
app.ws("/api/games/:gameCode", async (socket, req) => {
- const gameCode = req.params.gameCode;
+ const gameCode = req.params["gameCode"] as string;
state.socketManager.add(state, gameCode, socket);
});
diff --git a/server/src/ts/lobby.ts b/server/src/ts/lobby.ts
index 5c9c59c5..33b22f77 100644
--- a/server/src/ts/lobby.ts
+++ b/server/src/ts/lobby.ts
@@ -1,16 +1,16 @@
-import { CreateLobby } from "./action/initial/create-lobby";
-import { RegisterUser } from "./action/initial/register-user";
-import * as Errors from "./errors";
-import * as Event from "./event";
-import * as PresenceChanged from "./events/lobby-event/presence-changed";
-import * as Game from "./games/game";
-import * as Rules from "./games/rules";
-import * as Config from "./lobby/config";
-import { GameCode } from "./lobby/game-code";
-import * as User from "./user";
-import * as Util from "./util";
-import { LoadDeckSummary } from "./task/load-deck-summary";
-import * as Rando from "./games/rules/rando";
+import type { CreateLobby } from "./action/initial/create-lobby.js";
+import type { RegisterUser } from "./action/initial/register-user.js";
+import type * as Errors from "./errors.js";
+import * as Event from "./event.js";
+import * as PresenceChanged from "./events/lobby-event/presence-changed.js";
+import * as Game from "./games/game.js";
+import * as Rules from "./games/rules.js";
+import * as Rando from "./games/rules/rando.js";
+import * as Config from "./lobby/config.js";
+import type { GameCode } from "./lobby/game-code.js";
+import { LoadDeckSummary } from "./task/load-deck-summary.js";
+import * as User from "./user.js";
+import * as Util from "./util.js";
/**
* A game lobby.
@@ -77,13 +77,13 @@ export interface Summary {
export const fromDefaults = (
gameCode: GameCode,
name: string,
- defaults: Config.Defaults
+ defaults: Config.Defaults,
): {
config: Config.Config;
tasks: LoadDeckSummary[];
} => {
const tasks = defaults.decks.map(
- (source) => new LoadDeckSummary(gameCode, source)
+ (source) => new LoadDeckSummary(gameCode, source),
);
return {
config: {
@@ -109,7 +109,7 @@ export const fromDefaults = (
export function create(
gameCode: GameCode,
creation: CreateLobby,
- defaults: Config.Defaults
+ defaults: Config.Defaults,
): {
lobby: Lobby;
tasks: LoadDeckSummary[];
@@ -125,7 +125,7 @@ export function create(
};
config.rules.houseRules.rando = Rando.create(
lobby,
- defaults.rules.houseRules.rando
+ defaults.rules.houseRules.rando,
);
return {
lobby,
@@ -175,7 +175,7 @@ export const addUser = (
lobby: Lobby,
registration: RegisterUser,
role: User.Role,
- change?: (user: User.User) => User.User
+ change?: (user: User.User) => User.User,
): {
user: User.Id;
events: Iterable;
diff --git a/server/src/ts/lobby/change.ts b/server/src/ts/lobby/change.ts
index 7b5b5616..aba0fd6f 100644
--- a/server/src/ts/lobby/change.ts
+++ b/server/src/ts/lobby/change.ts
@@ -1,11 +1,11 @@
-import { GameStateError } from "../errors/game-state-error";
-import * as Event from "../event";
-import * as ErrorEncountered from "../events/lobby-event/error-encountered";
-import { Lobby } from "../lobby";
-import { ServerState } from "../server-state";
-import { Task } from "../task";
-import * as Timeout from "../timeout";
-import { GameCode } from "./game-code";
+import { GameStateError } from "../errors/game-state-error.js";
+import * as Event from "../event.js";
+import * as ErrorEncountered from "../events/lobby-event/error-encountered.js";
+import type { Lobby } from "../lobby.js";
+import type { ServerState } from "../server-state.js";
+import type { Task } from "../task.js";
+import * as Timeout from "../timeout.js";
+import type { GameCode } from "./game-code.js";
export interface Change {
lobby?: Lobby;
@@ -17,9 +17,10 @@ export interface Change {
export type ConstrainedChange = Change & { lobby?: L };
export type Handler = (lobby: Lobby) => Change;
-export type HandlerWithReturnValue = (
- lobby: Lobby
-) => { change: Change; returnValue: T };
+export type HandlerWithReturnValue = (lobby: Lobby) => {
+ change: Change;
+ returnValue: T;
+};
/**
* Reduce a list of items to a single change by applying a function to each one
@@ -31,7 +32,7 @@ export type HandlerWithReturnValue = (
export function reduce(
items: Iterable,
lobby: L,
- toChange: (lobby: L, item: T) => ConstrainedChange
+ toChange: (lobby: L, item: T) => ConstrainedChange,
): ConstrainedChange {
let currentLobby = lobby;
let lobbyChanged = false;
@@ -66,7 +67,7 @@ function internalApply(
server: ServerState,
gameCode: GameCode,
originalLobby: Lobby,
- change: Change
+ change: Change,
): {
lobby?: Lobby;
timeouts?: Iterable;
@@ -87,7 +88,7 @@ function internalApply(
server,
gameCode,
currentLobby,
- Timeout.handler(server, timeoutAfter.timeout, gameCode, currentLobby)
+ Timeout.handler(server, timeoutAfter.timeout, gameCode, currentLobby),
);
if (chained.lobby !== undefined) {
lobbyUnchanged = false;
@@ -125,7 +126,7 @@ export async function applyAndReturn(
server: ServerState,
gameCode: GameCode,
handler: HandlerWithReturnValue,
- timeoutId?: Timeout.Id
+ timeoutId?: Timeout.Id,
): Promise {
try {
const [tasks, returnValue] = await server.store.writeAndReturn(
@@ -138,7 +139,7 @@ export async function applyAndReturn(
server.socketManager,
gameCode,
result.lobby ?? lobby,
- result.events
+ result.events,
);
}
return {
@@ -149,7 +150,7 @@ export async function applyAndReturn(
},
result: [result.tasks, returnValue],
};
- }
+ },
);
if (tasks !== undefined) {
for (const task of tasks) {
@@ -184,7 +185,7 @@ export async function apply(
server: ServerState,
gameCode: GameCode,
handler: Handler,
- timeoutId?: Timeout.Id
+ timeoutId?: Timeout.Id,
): Promise {
await applyAndReturn(
server,
@@ -193,6 +194,6 @@ export async function apply(
change: handler(lobby),
returnValue: undefined,
}),
- timeoutId
+ timeoutId,
);
}
diff --git a/server/src/ts/lobby/config.ts b/server/src/ts/lobby/config.ts
index f03c543f..b3640d61 100644
--- a/server/src/ts/lobby/config.ts
+++ b/server/src/ts/lobby/config.ts
@@ -1,5 +1,5 @@
-import * as Source from "../games/cards/source";
-import * as Rules from "../games/rules";
+import type * as Source from "../games/cards/source.js";
+import * as Rules from "../games/rules.js";
/**
* Configuration for a lobby.
@@ -72,7 +72,7 @@ export interface FailedSource {
}
export const isFailed = (source: ConfiguredSource): source is FailedSource =>
- source.hasOwnProperty("failure");
+ Object.hasOwn(source, "failure");
export const censor = (config: Config): Public => ({
version: config.version.toString(),
diff --git a/server/src/ts/lobby/game-code.ts b/server/src/ts/lobby/game-code.ts
index 7c23d454..388cf588 100644
--- a/server/src/ts/lobby/game-code.ts
+++ b/server/src/ts/lobby/game-code.ts
@@ -18,7 +18,7 @@ export type LobbyId = number;
const hashIds = new Hashids(
"massivedecks",
2,
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
);
/**
diff --git a/server/src/ts/logging.ts b/server/src/ts/logging.ts
index 053eca5b..fa54c119 100644
--- a/server/src/ts/logging.ts
+++ b/server/src/ts/logging.ts
@@ -9,7 +9,7 @@ const logFormat = winston.format.printf((info) => {
splat: undefined,
},
null,
- 2
+ 2,
);
if (stringRest !== "{}") {
@@ -24,19 +24,18 @@ export const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.colorize(),
- logFormat
+ logFormat,
),
});
const exceptionHandler = new winston.ExceptionHandler(logger);
-export const exceptionToMeta = exceptionHandler.getAllInfo.bind(
- exceptionHandler
-);
+export const exceptionToMeta =
+ exceptionHandler.getAllInfo.bind(exceptionHandler);
export const logException = (
message: string,
error: Error,
- data?: string
+ data?: string,
): void => {
const details = exceptionToMeta(error);
logger.error(message, details === undefined ? details : { details, data });
diff --git a/server/src/ts/server-state.ts b/server/src/ts/server-state.ts
index 801e5cf2..e7ab9d81 100644
--- a/server/src/ts/server-state.ts
+++ b/server/src/ts/server-state.ts
@@ -1,11 +1,11 @@
-import { Cache } from "./cache";
-import * as caches from "./caches";
-import * as Config from "./config";
-import { SocketManager } from "./socket-manager";
-import { Store } from "./store";
-import * as Stores from "./store/stores";
-import * as Tasks from "./task/tasks";
-import { Sources } from "./games/cards/sources";
+import type { Cache } from "./cache.js";
+import * as caches from "./caches.js";
+import type * as Config from "./config.js";
+import { Sources } from "./games/cards/sources.js";
+import { SocketManager } from "./socket-manager.js";
+import type { Store } from "./store.js";
+import * as Stores from "./store/stores.js";
+import * as Tasks from "./task/tasks.js";
export interface ServerState {
config: Config.Parsed;
diff --git a/server/src/ts/socket-manager.ts b/server/src/ts/socket-manager.ts
index 1ab60292..e8ae9f2a 100644
--- a/server/src/ts/socket-manager.ts
+++ b/server/src/ts/socket-manager.ts
@@ -1,19 +1,20 @@
-import WebSocket from "ws";
-import * as Action from "./action";
-import * as Authenticate from "./action/authenticate";
-import { MassiveDecksError } from "./errors";
-import { NotAuthenticatedError } from "./errors/authentication";
-import { InvalidActionError } from "./errors/validation";
-import * as Event from "./event";
-import * as Sync from "./events/user-event/sync";
-import * as Lobby from "./lobby";
-import * as Change from "./lobby/change";
-import { GameCode } from "./lobby/game-code";
-import * as Logging from "./logging";
-import { ServerState } from "./server-state";
-import * as UserDisconnect from "./timeout/user-disconnect";
-import * as User from "./user";
-import * as Token from "./user/token";
+import type WebSocket from "ws";
+
+import * as Action from "./action.js";
+import * as Authenticate from "./action/authenticate.js";
+import { MassiveDecksError } from "./errors.js";
+import { NotAuthenticatedError } from "./errors/authentication.js";
+import { InvalidActionError } from "./errors/validation.js";
+import * as Event from "./event.js";
+import * as Sync from "./events/user-event/sync.js";
+import * as Lobby from "./lobby.js";
+import * as Change from "./lobby/change.js";
+import type { GameCode } from "./lobby/game-code.js";
+import * as Logging from "./logging.js";
+import type { ServerState } from "./server-state.js";
+import * as UserDisconnect from "./timeout/user-disconnect.js";
+import type * as User from "./user.js";
+import type * as Token from "./user/token.js";
const parseJson = (raw: string): object => {
try {
@@ -95,7 +96,7 @@ export class SocketManager {
private readonly errorWSHandler =
(
socket: WebSocket,
- fn: (data: WebSocket.Data) => Promise
+ fn: (data: WebSocket.Data) => Promise,
): ((data: WebSocket.Data) => Promise) =>
async (data) => {
try {
@@ -157,7 +158,7 @@ export class SocketManager {
.filter((p) => p.likes.some((l) => l === uid))
.map((p) => p.id);
const playedCard = round.plays.find(
- (p) => p.playedBy === uid
+ (p) => p.playedBy === uid,
);
const played =
playedCard === undefined ? undefined : playedCard.id;
@@ -167,7 +168,7 @@ export class SocketManager {
calls = round.czar === uid ? round.calls : undefined;
} else {
const potentialPlay = round.plays.find(
- (play) => play.playedBy === uid
+ (play) => play.playedBy === uid,
);
if (potentialPlay !== undefined) {
play = potentialPlay.play.map((card) => card.id);
@@ -175,14 +176,14 @@ export class SocketManager {
}
}
- const user = lobby.users[uid];
+ const user = lobby.users[uid] as User.User;
user.connection = "Connected";
return {
lobby,
events: [
Event.targetOnly(
Sync.of(Lobby.censor(lobby), hand, play, likeDetail, calls),
- uid
+ uid,
),
],
};
@@ -197,14 +198,14 @@ export class SocketManager {
} else {
const claims = auth;
await Change.apply(server, auth.gc, (lobby) =>
- Action.handle(claims, lobby, validated, server)
+ Action.handle(claims, lobby, validated, server),
);
Logging.logger.info("WebSocket receive:", {
user: auth.uid,
action: validated,
});
}
- })
+ }),
);
socket.on(
"close",
@@ -225,7 +226,7 @@ export class SocketManager {
Logging.logger.info("User disconnect:", { user: auth.uid });
}
}
- })
+ }),
);
}
}
diff --git a/server/src/ts/store.ts b/server/src/ts/store.ts
index 8b434320..e4a827a1 100644
--- a/server/src/ts/store.ts
+++ b/server/src/ts/store.ts
@@ -1,11 +1,11 @@
-import { CreateLobby } from "./action/initial/create-lobby";
-import * as ServerConfig from "./config";
-import * as Lobby from "./lobby";
-import { GameCode } from "./lobby/game-code";
-import * as Timeout from "./timeout";
-import { Token } from "./user/token";
-import { Task } from "./task";
-import * as LobbyConfig from "./lobby/config";
+import type { CreateLobby } from "./action/initial/create-lobby.js";
+import type * as ServerConfig from "./config.js";
+import type * as Lobby from "./lobby.js";
+import type * as LobbyConfig from "./lobby/config.js";
+import type { GameCode } from "./lobby/game-code.js";
+import type { Task } from "./task.js";
+import type * as Timeout from "./timeout.js";
+import type { Token } from "./user/token.js";
/**
* Represents a chunk of data that should be written as a single transaction,
@@ -45,20 +45,20 @@ export abstract class Store {
* invalid, but if there is any security concern, change the application
* secret, not this. That will have the same effect securely.
*/
- public abstract id(): Promise;
+ public abstract id(): Promise;
/**
* Returns if the given lobby exists.
*/
- public abstract exists(gameCode: GameCode): Promise;
+ public abstract exists(gameCode: GameCode): Promise;
/** Create a new lobby.
* @return The game code for the new lobby and the user id for the owner.
*/
- public abstract newLobby(
+ public abstract newLobby(
creation: CreateLobby,
secret: string,
- defaults: LobbyConfig.Defaults
+ defaults: LobbyConfig.Defaults,
): Promise<{ gameCode: GameCode; token: Token; tasks: Iterable }>;
/**
@@ -68,9 +68,10 @@ export abstract class Store {
*/
public async read(
gameCode: GameCode,
- read: (
- lobby: Lobby.Lobby
- ) => { transaction: ReadOnlyTransaction; result: T }
+ read: (lobby: Lobby.Lobby) => {
+ transaction: ReadOnlyTransaction;
+ result: T;
+ },
): Promise {
return this.writeAndReturn(gameCode, read);
}
@@ -83,7 +84,7 @@ export abstract class Store {
*/
public async write(
gameCode: GameCode,
- write: (lobby: Lobby.Lobby) => Transaction
+ write: (lobby: Lobby.Lobby) => Transaction,
): Promise {
await this.writeAndReturn(gameCode, (lobby: Lobby.Lobby) => ({
transaction: write(lobby),
@@ -91,9 +92,9 @@ export abstract class Store {
}));
}
- public abstract writeAndReturn(
+ public abstract writeAndReturn(
gameCode: GameCode,
- write: (lobby: Lobby.Lobby) => { transaction: Transaction; result: T }
+ write: (lobby: Lobby.Lobby) => { transaction: Transaction; result: T },
): Promise;
/** Get a list of summaries for all the public lobbies in the store.*/
@@ -107,12 +108,12 @@ export abstract class Store {
/**
* Delete the given lobby and all associated timeouts.
*/
- public abstract delete(gameCode: GameCode): Promise;
+ public abstract delete(gameCode: GameCode): Promise;
/**
* Remove lobbies where the game is finished or everyone has been
* disconnected for some time.
* This should also clean up the cache as appropriate.
*/
- public abstract garbageCollect(): Promise;
+ public abstract garbageCollect(): Promise;
}
diff --git a/server/src/ts/store/in-memory.ts b/server/src/ts/store/in-memory.ts
index 90af7719..16451d07 100644
--- a/server/src/ts/store/in-memory.ts
+++ b/server/src/ts/store/in-memory.ts
@@ -1,24 +1,16 @@
import * as uuid from "uuid";
import wu from "wu";
-import { CreateLobby } from "../action/initial/create-lobby";
-import * as ServerConfig from "../config";
-import { LobbyClosedError, LobbyDoesNotExistError } from "../errors/lobby";
-import * as Lobby from "../lobby";
-import * as GameCode from "../lobby/game-code";
-import { Store, Transaction } from "../store";
-import * as Timeout from "../timeout";
-import * as Token from "../user/token";
-import * as LobbyConfig from "../lobby/config";
-import { Task } from "../task";
-declare module "wu" {
- // Fix incorrect types.
- // noinspection JSUnusedGlobalSymbols
- interface WuIterable {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- spreadMap(fn: (...x: any[]) => U): WuIterable;
- }
-}
+import type { CreateLobby } from "../action/initial/create-lobby.js";
+import type * as ServerConfig from "../config.js";
+import { LobbyClosedError, LobbyDoesNotExistError } from "../errors/lobby.js";
+import * as Lobby from "../lobby.js";
+import type * as LobbyConfig from "../lobby/config.js";
+import * as GameCode from "../lobby/game-code.js";
+import { Store, Transaction } from "../store.js";
+import type { Task } from "../task.js";
+import type * as Timeout from "../timeout.js";
+import * as Token from "../user/token.js";
interface TimeoutMeta {
timeout: Timeout.Timeout;
@@ -68,7 +60,7 @@ export class InMemoryStore extends Store {
public async newLobby(
creation: CreateLobby,
secret: string,
- defaults: LobbyConfig.Defaults
+ defaults: LobbyConfig.Defaults,
): Promise<{
gameCode: GameCode.GameCode;
token: Token.Token;
@@ -86,7 +78,7 @@ export class InMemoryStore extends Store {
uid: lobby.owner,
},
this._id,
- secret
+ secret,
),
tasks,
};
@@ -108,7 +100,7 @@ export class InMemoryStore extends Store {
public async writeAndReturn(
gameCode: GameCode.GameCode,
- write: (lobby: Lobby.Lobby) => { transaction: Transaction; result: T }
+ write: (lobby: Lobby.Lobby) => { transaction: Transaction; result: T },
): Promise {
const { transaction, result } = write(await this.lobby(gameCode));
if (transaction.lobby !== undefined) {
@@ -138,7 +130,7 @@ export class InMemoryStore extends Store {
if (
lastWrite + this.config.abandonedTime < Date.now() ||
wu(Object.values(lobby.users)).every(
- (u) => u.control === "Computer" || u.presence === "Left"
+ (u) => u.control === "Computer" || u.presence === "Left",
)
) {
toRemove.add(gameCode);
diff --git a/server/src/ts/store/postgres.ts b/server/src/ts/store/postgres.ts
index 9d333691..6c14d46f 100644
--- a/server/src/ts/store/postgres.ts
+++ b/server/src/ts/store/postgres.ts
@@ -1,17 +1,18 @@
-import Pg from "pg";
+import type Pg from "pg";
import * as uuid from "uuid";
-import { CreateLobby } from "../action/initial/create-lobby";
-import * as Config from "../config";
-import { LobbyClosedError } from "../errors/lobby";
-import * as Lobby from "../lobby";
-import * as GameCode from "../lobby/game-code";
-import * as Store from "../store";
-import * as Timeout from "../timeout";
-import * as Token from "../user/token";
-import * as Postgres from "../util/postgres";
-import * as LobbyConfig from "../lobby/config";
-import { LoadDeckSummary } from "../task/load-deck-summary";
-import * as Task from "../task";
+
+import type { CreateLobby } from "../action/initial/create-lobby.js";
+import type * as Config from "../config.js";
+import { LobbyClosedError } from "../errors/lobby.js";
+import * as Lobby from "../lobby.js";
+import type * as LobbyConfig from "../lobby/config.js";
+import * as GameCode from "../lobby/game-code.js";
+import * as Store from "../store.js";
+import type * as Task from "../task.js";
+import { LoadDeckSummary } from "../task/load-deck-summary.js";
+import type * as Timeout from "../timeout.js";
+import * as Token from "../user/token.js";
+import * as Postgres from "../util/postgres.js";
class To0 extends Postgres.Upgrade {
public readonly to = 0;
@@ -19,7 +20,7 @@ class To0 extends Postgres.Upgrade {
public async apply(client: Pg.PoolClient): Promise<0> {
await client.query("CREATE SCHEMA massivedecks;");
await client.query(
- "CREATE TABLE massivedecks.meta ( version INTEGER NOT NULL, id UUID NOT NULL );"
+ "CREATE TABLE massivedecks.meta ( version INTEGER NOT NULL, id UUID NOT NULL );",
);
await client.query(`
CREATE TABLE massivedecks.lobbies (
@@ -81,12 +82,12 @@ export class PostgresStore extends Store.Store {
private readonly pg: Postgres.Postgres;
public static async create(
- config: Config.PostgreSQL
+ config: Config.PostgreSQL,
): Promise {
const pg = new Postgres.Postgres(
"massivedecks",
config.connection,
- upgrades
+ upgrades,
);
await pg.ensureCurrent();
return await pg.withClient(async (client) => {
@@ -98,7 +99,7 @@ export class PostgresStore extends Store.Store {
private constructor(
id: string,
config: Config.PostgreSQL,
- pg: Postgres.Postgres
+ pg: Postgres.Postgres,
) {
super();
this.cachedId = id;
@@ -117,9 +118,9 @@ export class PostgresStore extends Store.Store {
(
await client.query(
"SELECT EXISTS (SELECT id FROM massivedecks.lobbies WHERE id = $1)",
- [lobbyId]
+ [lobbyId],
)
- ).rows[0].exists
+ ).rows[0].exists,
);
}
@@ -129,7 +130,7 @@ export class PostgresStore extends Store.Store {
async (client) =>
await client.query("DELETE FROM massivedecks.lobbies WHERE id = $1", [
lobbyId,
- ])
+ ]),
);
}
@@ -141,7 +142,7 @@ export class PostgresStore extends Store.Store {
((last_access + $1::interval ) < NOW()) OR
(SELECT bool_and(value->>'control' = 'Computer' OR value->>'presence' = 'Left') FROM jsonb_each(lobby->'users'));
`,
- [`${this.config.abandonedTime} milliseconds`]
+ [`${this.config.abandonedTime} milliseconds`],
);
return result.rowCount;
});
@@ -149,12 +150,12 @@ export class PostgresStore extends Store.Store {
public async *lobbySummaries(): AsyncIterableIterator {
yield* this.pg.withClientIterator(
- PostgresStore.lobbySummariesInternal.bind(this)
+ PostgresStore.lobbySummariesInternal.bind(this),
);
}
private static async *lobbySummariesInternal(
- client: Pg.PoolClient
+ client: Pg.PoolClient,
): AsyncIterableIterator {
const result = await client.query("SELECT * FROM massivedecks.summaries");
for (const { id, name, started, ended, users, password } of result.rows) {
@@ -174,7 +175,7 @@ export class PostgresStore extends Store.Store {
public async newLobby(
creation: CreateLobby,
secret: string,
- defaults: LobbyConfig.Defaults
+ defaults: LobbyConfig.Defaults,
): Promise<{
gameCode: GameCode.GameCode;
token: Token.Token;
@@ -184,11 +185,11 @@ export class PostgresStore extends Store.Store {
const { lobby, tasks } = Lobby.create(
"fake-game-code",
creation,
- defaults
+ defaults,
);
const result = await client.query(
"INSERT INTO massivedecks.lobbies VALUES (DEFAULT, $1) RETURNING id",
- [lobby]
+ [lobby],
);
const gameCode = GameCode.encode(result.rows[0]["id"]);
return {
@@ -199,7 +200,7 @@ export class PostgresStore extends Store.Store {
uid: lobby.owner,
},
await this.id(),
- secret
+ secret,
),
tasks: tasks.map((task) => new LoadDeckSummary(gameCode, task.source)),
};
@@ -211,11 +212,11 @@ export class PostgresStore extends Store.Store {
}
private static async *timedOutInternal(
- client: Pg.PoolClient
+ client: Pg.PoolClient,
): AsyncIterableIterator {
const result = await client.query(
"SELECT * FROM massivedecks.timeouts WHERE after < $1;",
- [Date.now()]
+ [Date.now()],
);
for (const row of result.rows) {
yield {
@@ -228,31 +229,34 @@ export class PostgresStore extends Store.Store {
public async writeAndReturn(
gameCode: string,
- write: (lobby: Lobby.Lobby) => { transaction: Store.Transaction; result: T }
+ write: (lobby: Lobby.Lobby) => {
+ transaction: Store.Transaction;
+ result: T;
+ },
): Promise {
const lobbyId = GameCode.decode(gameCode);
return await this.pg.inTransaction(async (client) => {
const get = await client.query(
"SELECT lobby FROM massivedecks.lobbies WHERE id = $1;",
- [lobbyId]
+ [lobbyId],
);
if (get.rowCount < 1) {
throw new LobbyClosedError(gameCode);
}
const { transaction, result } = write(
- Lobby.fromJSON(get.rows[0]["lobby"] as Lobby.Lobby)
+ Lobby.fromJSON(get.rows[0]["lobby"] as Lobby.Lobby),
);
if (transaction.lobby) {
await client.query(
"UPDATE massivedecks.lobbies SET lobby=$2, last_access=NOW() WHERE id = $1;",
- [lobbyId, transaction.lobby]
+ [lobbyId, transaction.lobby],
);
}
if (transaction.timeouts !== undefined) {
for (const timeout of transaction.timeouts) {
await client.query(
"INSERT INTO massivedecks.timeouts VALUES (DEFAULT, $1, $2, $3)",
- [lobbyId, Date.now() + timeout.after, timeout.timeout]
+ [lobbyId, Date.now() + timeout.after, timeout.timeout],
);
}
}
diff --git a/server/src/ts/store/stores.ts b/server/src/ts/store/stores.ts
index b4ee93a9..a885323a 100644
--- a/server/src/ts/store/stores.ts
+++ b/server/src/ts/store/stores.ts
@@ -1,7 +1,7 @@
-import * as ServerConfig from "../config";
-import { Store } from "../store";
-import { InMemoryStore } from "./in-memory";
-import { PostgresStore } from "./postgres";
+import type * as ServerConfig from "../config.js";
+import type { Store } from "../store.js";
+import { InMemoryStore } from "./in-memory.js";
+import { PostgresStore } from "./postgres.js";
export async function from(config: ServerConfig.Storage): Promise {
switch (config.type) {
diff --git a/server/src/ts/task.ts b/server/src/ts/task.ts
index c963ab4a..17c4f8ce 100644
--- a/server/src/ts/task.ts
+++ b/server/src/ts/task.ts
@@ -1,7 +1,7 @@
-import { Lobby } from "./lobby";
-import * as Change from "./lobby/change";
-import { GameCode } from "./lobby/game-code";
-import { ServerState } from "./server-state";
+import type { Lobby } from "./lobby.js";
+import * as Change from "./lobby/change.js";
+import type { GameCode } from "./lobby/game-code.js";
+import type { ServerState } from "./server-state.js";
/**
* A good base implementation of a task.
@@ -18,12 +18,12 @@ export abstract class TaskBase implements Task {
protected abstract resolve(
lobby: Lobby,
work: T,
- server: ServerState
+ server: ServerState,
): Change.Change;
protected resolveError(
- lobby: Lobby,
+ _lobby: Lobby,
error: Error,
- server: ServerState
+ _server: ServerState,
): Change.Change {
throw error;
}
@@ -35,12 +35,12 @@ export abstract class TaskBase implements Task {
} catch (e) {
const error = e as Error;
await Change.apply(server, this.gameCode, (lobby) =>
- this.resolveError(lobby, error, server)
+ this.resolveError(lobby, error, server),
);
return;
}
await Change.apply(server, this.gameCode, (lobby) =>
- this.resolve(lobby, work, server)
+ this.resolve(lobby, work, server),
);
}
}
diff --git a/server/src/ts/task/load-deck-summary.ts b/server/src/ts/task/load-deck-summary.ts
index eafd2036..678766ee 100644
--- a/server/src/ts/task/load-deck-summary.ts
+++ b/server/src/ts/task/load-deck-summary.ts
@@ -1,18 +1,19 @@
import Rfc6902 from "rfc6902";
-import * as Event from "../event";
-import * as Configured from "../events/lobby-event/configured";
-import * as Source from "../games/cards/source";
-import { Lobby } from "../lobby";
-import { Change } from "../lobby/change";
-import * as Config from "../lobby/config";
-import { GameCode } from "../lobby/game-code";
-import { ServerState } from "../server-state";
-import * as Task from "../task";
+import type { ReplaceOperation, TestOperation } from "rfc6902/diff.js";
+
import {
SourceNotFoundError,
SourceServiceError,
-} from "../errors/action-execution-error";
-import { ReplaceOperation, TestOperation } from "rfc6902/diff";
+} from "../errors/action-execution-error.js";
+import * as Event from "../event.js";
+import * as Configured from "../events/lobby-event/configured.js";
+import type * as Source from "../games/cards/source.js";
+import type { Lobby } from "../lobby.js";
+import type { Change } from "../lobby/change.js";
+import * as Config from "../lobby/config.js";
+import type { GameCode } from "../lobby/game-code.js";
+import type { ServerState } from "../server-state.js";
+import * as Task from "../task.js";
export class LoadDeckSummary extends Task.TaskBase {
public readonly source: Source.External;
@@ -34,7 +35,7 @@ export class LoadDeckSummary extends Task.TaskBase {
private resolveInternal(
lobby: Lobby,
modify: (source: Config.ConfiguredSource) => void,
- server: ServerState
+ server: ServerState,
): Change {
const lobbyConfig = lobby.config;
const oldConfig = JSON.parse(JSON.stringify(Config.censor(lobby.config)));
@@ -60,7 +61,7 @@ export class LoadDeckSummary extends Task.TaskBase {
lobby,
events: [
Event.targetAll(
- Configured.of([testVersion, ...patch, replaceVersion])
+ Configured.of([testVersion, ...patch, replaceVersion]),
),
],
};
@@ -72,7 +73,7 @@ export class LoadDeckSummary extends Task.TaskBase {
protected resolve(
lobby: Lobby,
work: Source.Summary,
- server: ServerState
+ server: ServerState,
): Change {
return this.resolveInternal(
lobby,
@@ -81,14 +82,14 @@ export class LoadDeckSummary extends Task.TaskBase {
summarised.summary = { ...work, tag: undefined };
}
},
- server
+ server,
);
}
- protected resolveError(
+ protected override resolveError(
lobby: Lobby,
error: Error,
- server: ServerState
+ server: ServerState,
): Change {
let reason: Config.FailReason;
if (error instanceof SourceNotFoundError) {
@@ -101,17 +102,17 @@ export class LoadDeckSummary extends Task.TaskBase {
return this.resolveInternal(
lobby,
(failed) => {
- if (!failed.hasOwnProperty("summary")) {
+ if (!Object.hasOwn(failed, "summary")) {
(failed as Config.FailedSource).failure = reason;
}
},
- server
+ server,
);
}
public static *discover(
gameCode: GameCode,
- lobby: Lobby
+ lobby: Lobby,
): Iterable {
for (const deck of lobby.config.decks) {
if (!Config.isFailed(deck) && deck.summary === undefined) {
diff --git a/server/src/ts/task/start-game.ts b/server/src/ts/task/start-game.ts
index c170b8e4..1d753342 100644
--- a/server/src/ts/task/start-game.ts
+++ b/server/src/ts/task/start-game.ts
@@ -1,12 +1,13 @@
import wu from "wu";
-import * as Decks from "../games/cards/decks";
-import * as Source from "../games/cards/source";
-import { Game } from "../games/game";
-import { Lobby } from "../lobby";
-import { Change } from "../lobby/change";
-import { GameCode } from "../lobby/game-code";
-import { ServerState } from "../server-state";
-import * as Task from "../task";
+
+import type * as Decks from "../games/cards/decks.js";
+import type * as Source from "../games/cards/source.js";
+import { Game } from "../games/game.js";
+import type { Lobby } from "../lobby.js";
+import type { Change } from "../lobby/change.js";
+import type { GameCode } from "../lobby/game-code.js";
+import type { ServerState } from "../server-state.js";
+import * as Task from "../task.js";
export class StartGame extends Task.TaskBase {
private readonly decks: Iterable;
@@ -19,15 +20,15 @@ export class StartGame extends Task.TaskBase {
protected async begin(server: ServerState): Promise {
return Promise.all(
wu(this.decks).map((deck) =>
- server.sources.resolver(server.cache, deck).templates()
- )
+ server.sources.resolver(server.cache, deck).templates(),
+ ),
);
}
protected resolve(
lobby: Lobby,
work: Decks.Templates[],
- server: ServerState
+ server: ServerState,
): Change {
if (lobby.game !== undefined && lobby.game.winner === undefined) {
// If we have an existing game that isn't finished, we don't try and
@@ -40,7 +41,7 @@ export class StartGame extends Task.TaskBase {
const { events, timeouts } = lobbyGame.startRound(
server,
true,
- lobbyGame.round
+ lobbyGame.round,
);
lobby.game = lobbyGame;
@@ -55,8 +56,8 @@ export class StartGame extends Task.TaskBase {
// This is super unlikely timing-wise, and if it happens, the user just has
// to click start again. They'll live.
public static *discover(
- gameCode: GameCode,
- lobby: Lobby
+ _gameCode: GameCode,
+ _lobby: Lobby,
// eslint-disable-next-line @typescript-eslint/no-empty-function
): Iterable {}
}
diff --git a/server/src/ts/task/tasks.ts b/server/src/ts/task/tasks.ts
index 3dbbb7a7..1453daaa 100644
--- a/server/src/ts/task/tasks.ts
+++ b/server/src/ts/task/tasks.ts
@@ -1,10 +1,10 @@
-import { Lobby } from "../lobby";
-import { GameCode } from "../lobby/game-code";
-import * as Logging from "../logging";
-import { ServerState } from "../server-state";
-import { Task } from "../task";
-import { LoadDeckSummary } from "./load-deck-summary";
-import { StartGame } from "./start-game";
+import type { Lobby } from "../lobby.js";
+import type { GameCode } from "../lobby/game-code.js";
+import * as Logging from "../logging.js";
+import type { ServerState } from "../server-state.js";
+import type { Task } from "../task.js";
+import { LoadDeckSummary } from "./load-deck-summary.js";
+import { StartGame } from "./start-game.js";
interface Discoverable {
discover: (gameCode: GameCode, lobby: Lobby) => Iterable;
diff --git a/server/src/ts/timeout.ts b/server/src/ts/timeout.ts
index 12edcb71..175bab96 100644
--- a/server/src/ts/timeout.ts
+++ b/server/src/ts/timeout.ts
@@ -1,13 +1,13 @@
-import { Lobby } from "./lobby";
-import * as Change from "./lobby/change";
-import { GameCode } from "./lobby/game-code";
-import { ServerState } from "./server-state";
-import * as FinishedPlaying from "./timeout/finished-playing";
-import * as RoundStageTimerDone from "./timeout/round-stage-timer-done";
-import * as RoundStart from "./timeout/round-start";
-import * as UserDisconnect from "./timeout/user-disconnect";
-import * as Logging from "./logging";
-import * as FinishedRevealing from "./timeout/finished-revealing";
+import type { Lobby } from "./lobby.js";
+import * as Change from "./lobby/change.js";
+import type { GameCode } from "./lobby/game-code.js";
+import * as Logging from "./logging.js";
+import type { ServerState } from "./server-state.js";
+import * as FinishedPlaying from "./timeout/finished-playing.js";
+import * as FinishedRevealing from "./timeout/finished-revealing.js";
+import * as RoundStageTimerDone from "./timeout/round-stage-timer-done.js";
+import * as RoundStart from "./timeout/round-start.js";
+import * as UserDisconnect from "./timeout/user-disconnect.js";
/**
* A timeout represents something that must happen after a delay in-game.
@@ -56,13 +56,13 @@ export const handler: Handler = (server, timeout, gameCode, lobby) => {
export async function handle(server: ServerState): Promise {
for await (const { id, lobby, timeout } of server.store.timedOut()) {
Logging.logger.debug(
- `Timeout executing: ${id} (${JSON.stringify(timeout)}) in ${lobby}`
+ `Timeout executing: ${id} (${JSON.stringify(timeout)}) in ${lobby}`,
);
await Change.apply(
server,
lobby,
(lobbyState) => handler(server, timeout, lobby, lobbyState),
- id
+ id,
);
}
}
@@ -71,5 +71,5 @@ export type Handler = (
server: ServerState,
timeout: T,
gameCode: GameCode,
- lobby: Lobby
+ lobby: Lobby,
) => Change.Change;
diff --git a/server/src/ts/timeout/finished-playing.ts b/server/src/ts/timeout/finished-playing.ts
index dcbc5cc9..07b22059 100644
--- a/server/src/ts/timeout/finished-playing.ts
+++ b/server/src/ts/timeout/finished-playing.ts
@@ -1,8 +1,9 @@
import wu from "wu";
-import * as Round from "../games/game/round";
-import * as Timeout from "../timeout";
-import * as Util from "../util";
-import * as Rules from "../games/rules";
+
+import type * as Round from "../games/game/round.js";
+import type * as Rules from "../games/rules.js";
+import type * as Timeout from "../timeout.js";
+import * as Util from "../util.js";
/**
* Indicates that the round should start the revealing phase if it is appropriate
diff --git a/server/src/ts/timeout/finished-revealing.ts b/server/src/ts/timeout/finished-revealing.ts
index ee4357ac..948bf54a 100644
--- a/server/src/ts/timeout/finished-revealing.ts
+++ b/server/src/ts/timeout/finished-revealing.ts
@@ -1,5 +1,5 @@
-import * as Timeout from "../timeout";
-import * as Rules from "../games/rules";
+import type * as Rules from "../games/rules.js";
+import type * as Timeout from "../timeout.js";
/**
* Indicates that the round should start the judging phase if it is appropriate
@@ -17,10 +17,10 @@ export const of = (stages: Rules.Stages): Timeout.After => ({
});
export const handle: Timeout.Handler = (
- server,
- timeout,
- gameCode,
- lobby
+ _server,
+ _timeout,
+ _gameCode,
+ lobby,
) => {
const game = lobby.game;
if (game === undefined) {
diff --git a/server/src/ts/timeout/round-stage-timer-done.ts b/server/src/ts/timeout/round-stage-timer-done.ts
index 70a44a86..b693e6c3 100644
--- a/server/src/ts/timeout/round-stage-timer-done.ts
+++ b/server/src/ts/timeout/round-stage-timer-done.ts
@@ -1,13 +1,13 @@
-import { dealWithLostPlayer } from "../action/game-action/set-presence";
-import * as Event from "../event";
-import * as StageTimerDone from "../events/game-event/stage-timer-done";
-import * as Round from "../games/game/round";
-import * as Rules from "../games/rules";
-import * as Lobby from "../lobby";
-import * as Change from "../lobby/change";
-import * as Timeout from "../timeout";
-import * as Util from "../util";
-import { Stages } from "../games/rules";
+import { dealWithLostPlayer } from "../action/game-action/set-presence.js";
+import * as Event from "../event.js";
+import * as StageTimerDone from "../events/game-event/stage-timer-done.js";
+import * as Round from "../games/game/round.js";
+import type { Stages } from "../games/rules.js";
+import type * as Rules from "../games/rules.js";
+import type * as Lobby from "../lobby.js";
+import * as Change from "../lobby/change.js";
+import type * as Timeout from "../timeout.js";
+import * as Util from "../util.js";
/**
* Indicates that the user should be marked as disconnected if they still are.
@@ -49,7 +49,7 @@ function stageDuration(stage: Round.Stage, stages: Stages): number | undefined {
*/
export const ifEnabled = (
round: Round.Round,
- stages: Rules.Stages
+ stages: Rules.Stages,
): Timeout.After | undefined => {
const afterSeconds = stageDuration(round.stage, stages);
if (afterSeconds === undefined) {
@@ -69,7 +69,7 @@ export const handle: Timeout.Handler = (
server,
timeout,
gameCode,
- lobby
+ lobby,
) => {
const game = lobby.game;
if (game === undefined) {
@@ -99,7 +99,7 @@ export const handle: Timeout.Handler = (
};
case "Hard":
return Change.reduce(waitingFor, lobby as Lobby.WithActiveGame, (l, p) =>
- dealWithLostPlayer(server, l, p)
+ dealWithLostPlayer(server, l, p),
);
default:
Util.assertNever(stages.timeLimitMode);
diff --git a/server/src/ts/timeout/round-start.ts b/server/src/ts/timeout/round-start.ts
index 999b7306..5faa9b8c 100644
--- a/server/src/ts/timeout/round-start.ts
+++ b/server/src/ts/timeout/round-start.ts
@@ -1,7 +1,7 @@
-import * as Event from "../event";
-import * as GameEnded from "../events/game-event/game-ended";
-import * as Lobby from "../lobby";
-import * as Timeout from "../timeout";
+import * as Event from "../event.js";
+import * as GameEnded from "../events/game-event/game-ended.js";
+import * as Lobby from "../lobby.js";
+import type * as Timeout from "../timeout.js";
/**
* Indicates that the round should start if it is still appropriate to do so.
@@ -18,7 +18,7 @@ export const handle: Timeout.Handler = (
server,
timeout,
gameCode,
- inLobby
+ inLobby,
) => {
if (Lobby.hasActiveGame(inLobby)) {
const lobbyGame = inLobby.game;
diff --git a/server/src/ts/timeout/user-disconnect.ts b/server/src/ts/timeout/user-disconnect.ts
index 08b26657..98d2b7a5 100644
--- a/server/src/ts/timeout/user-disconnect.ts
+++ b/server/src/ts/timeout/user-disconnect.ts
@@ -1,9 +1,10 @@
-import * as Event from "../event";
-import * as ConnectionChanged from "../events/lobby-event/connection-changed";
-import * as Timeout from "../timeout";
-import * as User from "../user";
import wu from "wu";
+import * as Event from "../event.js";
+import * as ConnectionChanged from "../events/lobby-event/connection-changed.js";
+import type * as Timeout from "../timeout.js";
+import type * as User from "../user.js";
+
/**
* Indicates that the user should be marked as disconnected if they still are.
*/
@@ -21,7 +22,7 @@ export const handle: Timeout.Handler = (
server,
timeout,
gameCode,
- lobby
+ lobby,
) => {
const id = timeout.user;
const sockets = server.socketManager.sockets.get(gameCode, id);
diff --git a/server/src/ts/user.ts b/server/src/ts/user.ts
index 6f190ce3..aad84efb 100644
--- a/server/src/ts/user.ts
+++ b/server/src/ts/user.ts
@@ -1,4 +1,4 @@
-import { RegisterUser } from "./action/initial/register-user";
+import type { RegisterUser } from "./action/initial/register-user.js";
/** A user in a lobby.*/
export interface User {
@@ -80,7 +80,7 @@ export const isSpectating: (user: User) => boolean = (user) =>
export const create = (
registration: RegisterUser,
role: Role,
- privilege: Privilege = "Unprivileged"
+ privilege: Privilege = "Unprivileged",
): User => ({
name: registration.name,
presence: "Joined",
diff --git a/server/src/ts/user/token.ts b/server/src/ts/user/token.ts
index de4b91d5..6e765ea0 100644
--- a/server/src/ts/user/token.ts
+++ b/server/src/ts/user/token.ts
@@ -1,10 +1,11 @@
import jwt from "jsonwebtoken";
+
import {
IncorrectIssuerError,
InvalidAuthenticationError,
-} from "../errors/authentication";
-import { GameCode } from "../lobby/game-code";
-import * as User from "../user";
+} from "../errors/authentication.js";
+import type { GameCode } from "../lobby/game-code.js";
+import type * as User from "../user.js";
/**
* A token that contains the encoded claims of a user.
@@ -33,7 +34,7 @@ export interface Claims {
export const create = (
tokenClaims: Claims,
issuer: string,
- secret: string
+ secret: string,
): Token =>
jwt.sign(tokenClaims, secret, { algorithm: "HS256", issuer: issuer });
@@ -52,7 +53,7 @@ export function validate(token: Token, issuer: string, secret: string): Claims {
}) as Claims;
} catch (e) {
const error = e as Error;
- if (error.hasOwnProperty("name") && error.name === "JsonWebTokenError") {
+ if (Object.hasOwn(error, "name") && error.name === "JsonWebTokenError") {
if (error.message.startsWith("jwt issuer invalid.")) {
throw new IncorrectIssuerError();
} else if (error.message.startsWith("invalid signature")) {
diff --git a/server/src/ts/util.ts b/server/src/ts/util.ts
index b16fc430..181d8782 100644
--- a/server/src/ts/util.ts
+++ b/server/src/ts/util.ts
@@ -2,13 +2,13 @@
* Check if the given value is an iterable one.
*/
export const isIterable = (
- object: T | Iterable
+ object: T | Iterable,
): object is Iterable =>
object !== null &&
typeof (object as Iterable)[Symbol.iterator] === "function";
const isSingleArgument = (
- f: ((a: A, b: B) => C) | ((b: B) => C)
+ f: ((a: A, b: B) => C) | ((b: B) => C),
): f is (b: B) => C => f.length === 1;
/**
@@ -17,7 +17,7 @@ const isSingleArgument = (
*/
export function mapObjectValues(
obj: O,
- f: ((key: string, value: V) => U) | ((value: V) => U)
+ f: ((key: string, value: V) => U) | ((value: V) => U),
): { [P in keyof O]: U } {
const newObj: { [key: string]: U } = {};
for (const [key, value] of Object.entries(obj)) {
@@ -29,9 +29,9 @@ export function mapObjectValues(
/**
* Create an object from the given entries.
*/
-export function entriesToObject(
- entries: Iterable<[string, T]>
-): { [key: string]: T } {
+export function entriesToObject(entries: Iterable<[string, T]>): {
+ [key: string]: T;
+} {
const obj: { [key: string]: T } = {};
for (const [key, value] of entries) {
obj[key] = value;
@@ -55,7 +55,7 @@ export const mapToObject = (map: Map): { [key: string]: T } =>
*/
export function counts(
iterable: Iterable,
- predicates: { [P in keyof U]: (value: T) => boolean }
+ predicates: { [P in keyof U]: (value: T) => boolean },
): { [P in keyof U]: number } {
const keys = Object.keys(predicates) as (keyof U)[];
const amounts = mapObjectValues(predicates, () => 0);
@@ -86,7 +86,7 @@ export function assertNever(value: never): never {
*/
export function findIs(
iterable: Iterable