diff --git a/server/.gitignore b/server/.gitignore index 94bce9f5b..901f64f49 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -30,7 +30,7 @@ local-cdn test-cdn # Weird Redis Dumps -dump.rdb +*.rdb scripts/quick-insert/insert.ts scripts/bpi-poyashi-data/output.json diff --git a/server/package.json b/server/package.json index 98b5fb553..b016a828c 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "tachi-server", - "version": "2.0.1", + "version": "2.0.2", "description": "A score tracking server.", "main": "js/index.js", "private": true, @@ -51,6 +51,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.41.0", + "@aws-sdk/signature-v4-crt": "^3.41.0", "@types/mocha": "^9.0.0", "@valuabletouch/winston-seq": "^1.2.0", "bcryptjs": "^2.4.3", @@ -82,7 +83,7 @@ "rimraf": "3.0.2", "safe-json-stringify": "1.2.0", "seq-logging": "^1.1.1", - "tachi-common": "0.3.10", + "tachi-common": "0.3.13", "ts-node": "10.0.0", "typescript": "4.3.4", "winston": "3.3.3", diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml index 18f6b6765..ad124496d 100644 --- a/server/pnpm-lock.yaml +++ b/server/pnpm-lock.yaml @@ -2,6 +2,7 @@ lockfileVersion: 5.3 specifiers: '@aws-sdk/client-s3': ^3.41.0 + '@aws-sdk/signature-v4-crt': ^3.41.0 '@types/bcrypt': 5.0.0 '@types/bcryptjs': ^2.4.2 '@types/bunyan': ^1.8.7 @@ -62,7 +63,7 @@ specifiers: safe-json-stringify: 1.2.0 seq-logging: ^1.1.1 supertest: 6.1.3 - tachi-common: 0.3.10 + tachi-common: 0.3.13 tap: 15.0.9 ts-node: 10.0.0 tsconfig-paths: 3.10.1 @@ -73,7 +74,8 @@ specifiers: winston-transport: ^4.4.0 dependencies: - '@aws-sdk/client-s3': 3.41.0 + '@aws-sdk/client-s3': 3.41.0_@aws-sdk+signature-v4-crt@3.41.0 + '@aws-sdk/signature-v4-crt': 3.41.0 '@types/mocha': 9.0.0 '@valuabletouch/winston-seq': 1.2.0 bcryptjs: 2.4.3 @@ -105,7 +107,7 @@ dependencies: rimraf: 3.0.2 safe-json-stringify: 1.2.0 seq-logging: 1.1.1 - tachi-common: 0.3.10 + tachi-common: 0.3.13 ts-node: 10.0.0_83f53b0a0c5616d3fa00ed4e30b9ce1b typescript: 4.3.4 winston: 3.3.3 @@ -218,7 +220,7 @@ packages: tslib: 2.3.1 dev: false - /@aws-sdk/client-s3/3.41.0: + /@aws-sdk/client-s3/3.41.0_@aws-sdk+signature-v4-crt@3.41.0: resolution: {integrity: sha512-PGPy7MbyjkpQECPR02NOxucqJWJEah9IcQcUMyRB1vZBg6irBI1d4GTuWafegr3xKQ+7ZTraupDtUSJ9oRqKOg==} engines: {node: '>=10.0.0'} dependencies: @@ -244,7 +246,7 @@ packages: '@aws-sdk/middleware-location-constraint': 3.40.0 '@aws-sdk/middleware-logger': 3.40.0 '@aws-sdk/middleware-retry': 3.40.0 - '@aws-sdk/middleware-sdk-s3': 3.41.0 + '@aws-sdk/middleware-sdk-s3': 3.41.0_@aws-sdk+signature-v4-crt@3.41.0 '@aws-sdk/middleware-serde': 3.40.0 '@aws-sdk/middleware-signing': 3.40.0 '@aws-sdk/middleware-ssec': 3.40.0 @@ -630,7 +632,7 @@ packages: uuid: 8.3.2 dev: false - /@aws-sdk/middleware-sdk-s3/3.41.0: + /@aws-sdk/middleware-sdk-s3/3.41.0_@aws-sdk+signature-v4-crt@3.41.0: resolution: {integrity: sha512-B7JOpmIpm1zxERQEMwZCWj3FisTvwfUgpfQglYdqrB6VpIoCM8fk2pmi5KzU/JDeNBlhTouj6mwnhJL/z5jopA==} engines: {node: '>= 10.0.0'} peerDependencies: @@ -638,6 +640,7 @@ packages: dependencies: '@aws-sdk/protocol-http': 3.40.0 '@aws-sdk/signature-v4': 3.40.0 + '@aws-sdk/signature-v4-crt': 3.41.0 '@aws-sdk/types': 3.40.0 '@aws-sdk/util-arn-parser': 3.37.0 tslib: 2.3.1 @@ -764,6 +767,24 @@ packages: tslib: 2.3.1 dev: false + /@aws-sdk/signature-v4-crt/3.41.0: + resolution: {integrity: sha512-qqFPptnVz62s4CCGv7z5scrjZ2YW65LJw8UcZIugr2Z+KKeDSlwwFkyagigTzp67rewuI4PYtTCD1vETAcVERg==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.37.0 + '@aws-sdk/querystring-parser': 3.40.0 + '@aws-sdk/signature-v4': 3.40.0 + '@aws-sdk/util-hex-encoding': 3.37.0 + '@aws-sdk/util-uri-escape': 3.37.0 + aws-crt: 1.10.4 + tslib: 2.3.1 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: false + /@aws-sdk/signature-v4/3.40.0: resolution: {integrity: sha512-Q1GNZJRCS3W2qsRtDsX/b6EOSfMXfr6TW46N3LnLTGYZ3KAN2SOSJ1DsW59AuGpEZyRmOhJ9L/Q5U403+bZMXQ==} engines: {node: '>= 10.0.0'} @@ -1669,7 +1690,6 @@ packages: /ansi-regex/2.1.1: resolution: {integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=} engines: {node: '>=0.10.0'} - dev: true /ansi-regex/3.0.0: resolution: {integrity: sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=} @@ -1695,6 +1715,10 @@ packages: color-convert: 2.0.1 dev: true + /ansi/0.3.1: + resolution: {integrity: sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=} + dev: false + /anymatch/3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} engines: {node: '>= 8'} @@ -1718,6 +1742,13 @@ packages: resolution: {integrity: sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=} dev: true + /are-we-there-yet/1.0.6: + resolution: {integrity: sha1-otKMkxAqpsyWJFomy5VN4G7FPww=} + dependencies: + delegates: 1.0.0 + readable-stream: 2.3.7 + dev: false + /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} dev: false @@ -1786,6 +1817,24 @@ packages: resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} dev: true + /aws-crt/1.10.4: + resolution: {integrity: sha512-5JzT7Wku8Q97Sm+MEAf6703cThj3Hi4NWc139gGvmfsk5Le5H7SDmkW8CThAcyyqHVXWw68LEtDL936Asz0Srw==} + requiresBuild: true + dependencies: + axios: 0.21.4 + cmake-js: 6.3.0 + crypto-js: 4.1.1 + fastestsmallesttextencoderdecoder: 1.0.22 + mqtt: 4.2.8 + tar: 6.1.11 + ws: 7.5.6 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: false + /aws-sign2/0.7.0: resolution: {integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=} dev: true @@ -1794,9 +1843,29 @@ packages: resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} dev: true + /axios/0.21.4: + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + dependencies: + follow-redirects: 1.14.5 + transitivePeerDependencies: + - debug + dev: false + + /axios/0.21.4_debug@4.3.2: + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + dependencies: + follow-redirects: 1.14.5_debug@4.3.2 + transitivePeerDependencies: + - debug + dev: false + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + /bcrypt-pbkdf/1.0.2: resolution: {integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=} dependencies: @@ -1807,11 +1876,23 @@ packages: resolution: {integrity: sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=} dev: false + /big-integer/1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: false + /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} dev: true + /binary/0.3.0: + resolution: {integrity: sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=} + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + dev: false + /bind-obj-methods/3.0.0: resolution: {integrity: sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==} engines: {node: '>=10'} @@ -1824,6 +1905,18 @@ packages: safe-buffer: 5.2.1 dev: false + /bl/4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: false + + /bluebird/3.4.7: + resolution: {integrity: sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=} + dev: false + /body-parser/1.19.0: resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==} engines: {node: '>= 0.8'} @@ -1877,6 +1970,27 @@ packages: /buffer-from/1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer-indexof-polyfill/1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + dev: false + + /buffer-shims/1.0.0: + resolution: {integrity: sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=} + dev: false + + /buffer/5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /buffers/0.1.1: + resolution: {integrity: sha1-skV5w77U1tOWru5tmorn9Ugqt7s=} + engines: {node: '>=0.2.0'} + dev: false + /bullmq/1.54.4: resolution: {integrity: sha512-F6bHmbQi5pHwhC4GAUyi3/USKCx8+tCefFEYyNhRMUpis+bA7Y5Ot7cfqXa+k/IeLsr/+4ld+LcL2Q0lPFf++Q==} dependencies: @@ -1956,6 +2070,11 @@ packages: engines: {node: '>=6'} dev: true + /camelcase/2.1.1: + resolution: {integrity: sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=} + engines: {node: '>=0.10.0'} + dev: false + /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -1969,6 +2088,12 @@ packages: resolution: {integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=} dev: true + /chainsaw/0.1.0: + resolution: {integrity: sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=} + dependencies: + traverse: 0.3.9 + dev: false + /chalk/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2001,11 +2126,28 @@ packages: fsevents: 2.3.2 dev: true + /chownr/1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + + /chownr/2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: false + /clean-stack/2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} dev: true + /cliui/3.2.0: + resolution: {integrity: sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=} + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi: 2.1.0 + dev: false + /cliui/4.1.0: resolution: {integrity: sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==} dependencies: @@ -2037,10 +2179,33 @@ packages: engines: {node: '>=0.10.0'} dev: false + /cmake-js/6.3.0: + resolution: {integrity: sha512-1uqTOmFt6BIqKlrX+39/aewU/JVhyZWDqwAL+6psToUwxj3yWPJiwxiZFmV0XdcoWmqGs7peZTxTbJtAcH8hxw==} + engines: {node: '>= 10.0.0'} + hasBin: true + dependencies: + axios: 0.21.4_debug@4.3.2 + debug: 4.3.2 + fs-extra: 5.0.0 + is-iojs: 1.1.0 + lodash: 4.17.21 + memory-stream: 0.0.3 + npmlog: 1.2.1 + rc: 1.2.8 + semver: 5.7.1 + splitargs: 0.0.7 + tar: 4.4.19 + unzipper: 0.8.14 + url-join: 0.0.1 + which: 1.3.1 + yargs: 3.32.0 + transitivePeerDependencies: + - supports-color + dev: false + /code-point-at/1.1.0: resolution: {integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=} engines: {node: '>=0.10.0'} - dev: true /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -2107,6 +2272,13 @@ packages: engines: {node: '>= 10'} dev: false + /commist/1.1.0: + resolution: {integrity: sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==} + dependencies: + leven: 2.1.0 + minimist: 1.2.5 + dev: false + /commondir/1.0.1: resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} dev: true @@ -2128,6 +2300,16 @@ packages: typedarray: 0.0.6 dev: false + /concat-stream/2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.0 + typedarray: 0.0.6 + dev: false + /connect-redis/6.0.0: resolution: {integrity: sha512-6eGEAAPHYvcfbRNCMmPzBIjrqRWLw7at9lCUH4G6NQ8gwWDJelaUmFNOqPIhehbw941euVmIuqWsaWiKXfb+5g==} engines: {node: '>=12'} @@ -2205,6 +2387,10 @@ packages: which: 2.0.2 dev: true + /crypto-js/4.1.1: + resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} + dev: false + /csv-parse/4.16.0: resolution: {integrity: sha512-Zb4tGPANH4SW0LgC9+s9Mnequs9aqn7N3/pCqNbVjs2XhEF6yWNU2Vm4OGl1v2Go9nw8rXt87Cm2QN/o6Vpqgg==} dev: false @@ -2241,7 +2427,11 @@ packages: /decamelize/1.2.0: resolution: {integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=} engines: {node: '>=0.10.0'} - dev: true + + /deep-extend/0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false /deep-is/0.1.3: resolution: {integrity: sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=} @@ -2276,6 +2466,10 @@ packages: engines: {node: '>=0.4.0'} dev: true + /delegates/1.0.0: + resolution: {integrity: sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=} + dev: false + /denque/1.5.0: resolution: {integrity: sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==} engines: {node: '>=0.10'} @@ -2341,6 +2535,21 @@ packages: dev: false optional: true + /duplexer2/0.1.4: + resolution: {integrity: sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=} + dependencies: + readable-stream: 2.3.7 + dev: false + + /duplexify/4.1.2: + resolution: {integrity: sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.0 + stream-shift: 1.0.1 + dev: false + /ecc-jsbn/0.1.2: resolution: {integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=} dependencies: @@ -2369,6 +2578,12 @@ packages: engines: {node: '>= 0.8'} dev: false + /end-of-stream/1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + /enquirer/2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} @@ -2763,6 +2978,10 @@ packages: hasBin: true dev: false + /fastestsmallesttextencoderdecoder/1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + dev: false + /fastq/1.11.1: resolution: {integrity: sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==} dependencies: @@ -2850,6 +3069,28 @@ packages: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} dev: false + /follow-redirects/1.14.5: + resolution: {integrity: sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /follow-redirects/1.14.5_debug@4.3.2: + resolution: {integrity: sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.2 + dev: false + /foreground-child/2.0.0: resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} engines: {node: '>=8.0.0'} @@ -2901,6 +3142,27 @@ packages: resolution: {integrity: sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=} dev: true + /fs-extra/5.0.0: + resolution: {integrity: sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==} + dependencies: + graceful-fs: 4.2.8 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /fs-minipass/1.2.7: + resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} + dependencies: + minipass: 2.9.0 + dev: false + + /fs-minipass/2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.1.3 + dev: false + /fs.realpath/1.0.0: resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} @@ -2912,6 +3174,16 @@ packages: dev: true optional: true + /fstream/1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + dependencies: + graceful-fs: 4.2.8 + inherits: 2.0.4 + mkdirp: 0.5.5 + rimraf: 2.4.5 + dev: false + /function-bind/1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} @@ -2923,6 +3195,16 @@ packages: resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=} dev: true + /gauge/1.2.7: + resolution: {integrity: sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=} + dependencies: + ansi: 0.3.1 + has-unicode: 2.0.1 + lodash.pad: 4.5.1 + lodash.padend: 4.6.1 + lodash.padstart: 4.6.1 + dev: false + /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -2972,7 +3254,6 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 dev: false - optional: true /glob/7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} @@ -3010,7 +3291,6 @@ packages: /graceful-fs/4.2.8: resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==} - dev: true /har-schema/2.0.0: resolution: {integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=} @@ -3051,6 +3331,10 @@ packages: has-symbols: 1.0.2 dev: true + /has-unicode/2.0.1: + resolution: {integrity: sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=} + dev: false + /has/1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -3070,6 +3354,13 @@ packages: engines: {node: '>=10.0.0'} dev: false + /help-me/3.0.0: + resolution: {integrity: sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==} + dependencies: + glob: 7.1.7 + readable-stream: 3.6.0 + dev: false + /hosted-git-info/2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -3116,6 +3407,10 @@ packages: safer-buffer: 2.1.2 dev: false + /ieee754/1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + /ignore/4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} engines: {node: '>= 4'} @@ -3174,6 +3469,10 @@ packages: /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + /internal-slot/1.0.3: resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} engines: {node: '>= 0.4'} @@ -3183,6 +3482,11 @@ packages: side-channel: 1.0.4 dev: true + /invert-kv/1.0.0: + resolution: {integrity: sha1-EEqOSqym09jNFXqO+L+rLXo//bY=} + engines: {node: '>=0.10.0'} + dev: false + /ioredis/4.28.1: resolution: {integrity: sha512-7gcrUJEcPHWy+eEyq6wIZpXtfHt8crhbc5+z0sqrnHUkwBblXinygfamj+/jx83Qo+2LW3q87Nj2VsuH6BF2BA==} engines: {node: '>=6'} @@ -3264,7 +3568,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: number-is-nan: 1.0.1 - dev: true /is-fullwidth-code-point/2.0.0: resolution: {integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=} @@ -3283,6 +3586,10 @@ packages: is-extglob: 2.1.1 dev: true + /is-iojs/1.1.0: + resolution: {integrity: sha1-TBEDO11dlNbqs3dd7cm+fQCDJfE=} + dev: false + /is-nan/1.3.2: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} @@ -3353,7 +3660,6 @@ packages: /isexe/2.0.0: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} - dev: true /isstream/0.1.2: resolution: {integrity: sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=} @@ -3484,6 +3790,12 @@ packages: dependencies: minimist: 1.2.5 + /jsonfile/4.0.0: + resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=} + optionalDependencies: + graceful-fs: 4.2.8 + dev: false + /jsprim/1.4.1: resolution: {integrity: sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=} engines: {'0': node >=0.6.0} @@ -3498,11 +3810,23 @@ packages: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} dev: false + /lcid/1.0.0: + resolution: {integrity: sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=} + engines: {node: '>=0.10.0'} + dependencies: + invert-kv: 1.0.0 + dev: false + /lcov-parse/1.0.0: resolution: {integrity: sha1-6w1GtUER68VhrLTECO+TY73I9+A=} hasBin: true dev: true + /leven/2.1.0: + resolution: {integrity: sha1-wuep93IJTe6dNCAq6KzORoeHVYA=} + engines: {node: '>=0.10.0'} + dev: false + /levn/0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -3531,6 +3855,10 @@ packages: yapool: 1.0.0 dev: true + /listenercount/1.0.1: + resolution: {integrity: sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=} + dev: false + /load-json-file/4.0.0: resolution: {integrity: sha1-L19Fq5HjMhYjT9U62rZo607AmTs=} engines: {node: '>=4'} @@ -3580,6 +3908,18 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.pad/4.5.1: + resolution: {integrity: sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=} + dev: false + + /lodash.padend/4.6.1: + resolution: {integrity: sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=} + dev: false + + /lodash.padstart/4.6.1: + resolution: {integrity: sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=} + dev: false + /lodash.truncate/4.4.2: resolution: {integrity: sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=} dev: true @@ -3637,6 +3977,12 @@ packages: dev: false optional: true + /memory-stream/0.0.3: + resolution: {integrity: sha1-6+jdHDuLw4wOeUHp3dWuvmtN6D8=} + dependencies: + readable-stream: 1.0.34 + dev: false + /merge-descriptors/1.0.1: resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=} @@ -3686,12 +4032,32 @@ packages: /minimist/1.2.5: resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} + /minipass/2.9.0: + resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} + dependencies: + safe-buffer: 5.2.1 + yallist: 3.1.1 + dev: false + /minipass/3.1.3: resolution: {integrity: sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==} engines: {node: '>=8'} dependencies: yallist: 4.0.0 - dev: true + + /minizlib/1.3.3: + resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} + dependencies: + minipass: 2.9.0 + dev: false + + /minizlib/2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.1.3 + yallist: 4.0.0 + dev: false /mkdirp/0.5.5: resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==} @@ -3795,6 +4161,41 @@ packages: - supports-color dev: false + /mqtt-packet/6.10.0: + resolution: {integrity: sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==} + dependencies: + bl: 4.1.0 + debug: 4.3.2 + process-nextick-args: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /mqtt/4.2.8: + resolution: {integrity: sha512-DJYjlXODVXtSDecN8jnNzi6ItX3+ufGsEs9OB3YV24HtkRrh7kpx8L5M1LuyF0KzaiGtWr2PzDcMGAY60KGOSA==} + engines: {node: '>=10.0.0'} + hasBin: true + dependencies: + commist: 1.1.0 + concat-stream: 2.0.0 + debug: 4.3.2 + duplexify: 4.1.2 + help-me: 3.0.0 + inherits: 2.0.4 + minimist: 1.2.5 + mqtt-packet: 6.10.0 + pump: 3.0.0 + readable-stream: 3.6.0 + reinterval: 1.1.0 + split2: 3.2.2 + ws: 7.5.6 + xtend: 4.0.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /ms/2.0.0: resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} @@ -3930,10 +4331,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /npmlog/1.2.1: + resolution: {integrity: sha1-KOe+YZYJtT960d0wChDWTXFiaLY=} + dependencies: + ansi: 0.3.1 + are-we-there-yet: 1.0.6 + gauge: 1.2.7 + dev: false + /number-is-nan/1.0.1: resolution: {integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=} engines: {node: '>=0.10.0'} - dev: true /nyc/15.1.0: resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} @@ -4051,6 +4459,13 @@ packages: word-wrap: 1.2.3 dev: true + /os-locale/1.4.0: + resolution: {integrity: sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=} + engines: {node: '>=0.10.0'} + dependencies: + lcid: 1.0.0 + dev: false + /own-or-env/1.0.1: resolution: {integrity: sha512-y8qULRbRAlL6x2+M0vIe7jJbJx/kmUTzYonRAa2ayesR2qWLswninkVyeJe4x3IEXhdgoNodzjQRKAoEs6Fmrw==} dependencies: @@ -4232,6 +4647,10 @@ packages: hasBin: true dev: true + /process-nextick-args/1.0.7: + resolution: {integrity: sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=} + dev: false + /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: false @@ -4272,6 +4691,13 @@ packages: resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==} dev: true + /pump/3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -4324,6 +4750,16 @@ packages: unpipe: 1.0.0 dev: false + /rc/1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.5 + strip-json-comments: 2.0.1 + dev: false + /react-is/16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: true @@ -4354,6 +4790,15 @@ packages: path-type: 3.0.0 dev: true + /readable-stream/1.0.34: + resolution: {integrity: sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=} + dependencies: + core-util-is: 1.0.2 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: false + /readable-stream/1.1.14: resolution: {integrity: sha1-fPTFTvZI44EwhMY23SB54WbAgdk=} dependencies: @@ -4363,6 +4808,18 @@ packages: string_decoder: 0.10.31 dev: false + /readable-stream/2.1.5: + resolution: {integrity: sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=} + dependencies: + buffer-shims: 1.0.0 + core-util-is: 1.0.2 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 1.0.7 + string_decoder: 0.10.31 + util-deprecate: 1.0.2 + dev: false + /readable-stream/2.3.7: resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} dependencies: @@ -4421,6 +4878,10 @@ packages: engines: {node: '>=8'} dev: true + /reinterval/1.1.0: + resolution: {integrity: sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=} + dev: false + /release-zalgo/1.0.0: resolution: {integrity: sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=} engines: {node: '>=4'} @@ -4514,7 +4975,6 @@ packages: dependencies: glob: 6.0.4 dev: false - optional: true /rimraf/3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -4603,6 +5063,10 @@ packages: resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=} dev: true + /setimmediate/1.0.5: + resolution: {integrity: sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=} + dev: false + /setprototypeof/1.1.1: resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} dev: false @@ -4711,6 +5175,16 @@ packages: resolution: {integrity: sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==} dev: true + /split2/3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + dependencies: + readable-stream: 3.6.0 + dev: false + + /splitargs/0.0.7: + resolution: {integrity: sha1-/p965lc3GzOxDLgNoUPPgknPazs=} + dev: false + /sprintf-js/1.0.3: resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} dev: true @@ -4755,6 +5229,10 @@ packages: engines: {node: '>= 0.6'} dev: false + /stream-shift/1.0.1: + resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} + dev: false + /streamsearch/0.1.2: resolution: {integrity: sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=} engines: {node: '>=0.8.0'} @@ -4767,7 +5245,6 @@ packages: code-point-at: 1.1.0 is-fullwidth-code-point: 1.0.0 strip-ansi: 3.0.1 - dev: true /string-width/2.1.1: resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} @@ -4820,7 +5297,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: ansi-regex: 2.1.1 - dev: true /strip-ansi/4.0.0: resolution: {integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=} @@ -4846,6 +5322,11 @@ packages: engines: {node: '>=8'} dev: true + /strip-json-comments/2.0.1: + resolution: {integrity: sha1-PFMZQukIwml8DsNEhYwobHygpgo=} + engines: {node: '>=0.10.0'} + dev: false + /strip-json-comments/3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4906,8 +5387,8 @@ packages: strip-ansi: 6.0.0 dev: true - /tachi-common/0.3.10: - resolution: {integrity: sha512-OiEnRz8b7ix+m/W5bFwaN+0fgupmbYHKhsn4/IaFb8f2rCEHY/i3t8TGuYAx212Uo2hOsDSX5/yxVOrgcxZ1AA==} + /tachi-common/0.3.13: + resolution: {integrity: sha512-nelJPWufn30Q2Mn+6mD+aTlIsWXxdSug1+wkWcT6TCynVEG+peY2WWGkpNUfMenRM9OBIImY6VoC4AvHZ4qI6Q==} dependencies: monk: 7.3.4 transitivePeerDependencies: @@ -5003,6 +5484,31 @@ packages: - treport - '@types/react' + /tar/4.4.19: + resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} + engines: {node: '>=4.5'} + dependencies: + chownr: 1.1.4 + fs-minipass: 1.2.7 + minipass: 2.9.0 + minizlib: 1.3.3 + mkdirp: 0.5.5 + safe-buffer: 5.2.1 + yallist: 3.1.1 + dev: false + + /tar/6.1.11: + resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==} + engines: {node: '>= 10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 3.1.3 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: false + /tcompare/5.0.6: resolution: {integrity: sha512-OvO7omN/wkdsKzmOqr3sQFfLbghs/2X5mwSkcfgRiXZshfPnTsAs3IRf1RixR/Pff26qG/r9ogcZMpV0YdeGXg==} engines: {node: '>=10'} @@ -5052,6 +5558,10 @@ packages: punycode: 2.1.1 dev: true + /traverse/0.3.9: + resolution: {integrity: sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=} + dev: false + /triple-beam/1.3.0: resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==} dev: false @@ -5187,17 +5697,40 @@ packages: strip-ansi: 3.0.1 dev: true + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + /unpipe/1.0.0: resolution: {integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=} engines: {node: '>= 0.8'} dev: false + /unzipper/0.8.14: + resolution: {integrity: sha512-8rFtE7EP5ssOwGpN2dt1Q4njl0N1hUXJ7sSPz0leU2hRdq6+pra57z4YPBlVqm40vcgv6ooKZEAx48fMTv9x4w==} + dependencies: + big-integer: 1.6.51 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + listenercount: 1.0.1 + readable-stream: 2.1.5 + setimmediate: 1.0.5 + dev: false + /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.1.1 dev: true + /url-join/0.0.1: + resolution: {integrity: sha1-HbSK1CLTQCRpqH99l73r/k+x48g=} + dev: false + /util-deprecate/1.0.2: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} @@ -5256,6 +5789,13 @@ packages: resolution: {integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=} dev: true + /which/1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -5273,6 +5813,12 @@ packages: stackback: 0.0.2 dev: true + /window-size/0.1.4: + resolution: {integrity: sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=} + engines: {node: '>= 0.10.0'} + hasBin: true + dev: false + /winston-daily-rotate-file/4.5.5_winston@3.3.3: resolution: {integrity: sha512-ds0WahIjiDhKCiMXmY799pDBW+58ByqIBtUcsqr4oDoXrAI3Zn+hbgFdUxzMfqA93OG0mPLYVMiotqTgE/WeWQ==} engines: {node: '>=8'} @@ -5320,7 +5866,6 @@ packages: dependencies: string-width: 1.0.2 strip-ansi: 3.0.1 - dev: true /wrap-ansi/6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} @@ -5343,18 +5888,38 @@ packages: typedarray-to-buffer: 3.1.5 dev: true + /ws/7.5.6: + resolution: {integrity: sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /xtend/4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} dev: false + /y18n/3.2.2: + resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} + dev: false + /y18n/4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true + /yallist/3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: false + /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true /yaml/1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} @@ -5390,6 +5955,18 @@ packages: yargs-parser: 18.1.3 dev: true + /yargs/3.32.0: + resolution: {integrity: sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=} + dependencies: + camelcase: 2.1.1 + cliui: 3.2.0 + decamelize: 1.2.0 + os-locale: 1.4.0 + string-width: 1.0.2 + window-size: 0.1.4 + y18n: 3.2.2 + dev: false + /yn/3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} diff --git a/server/src/external/mongo/schemas.ts b/server/src/external/mongo/schemas.ts index dfbf27036..d1b7fbb40 100644 --- a/server/src/external/mongo/schemas.ts +++ b/server/src/external/mongo/schemas.ts @@ -209,7 +209,7 @@ const GetScoreMeta = (game: Game, playtype: Playtypes[Game]): PrudenceSchema => } else if (game === "usc") { return { noteMod: optNull(p.isIn("NORMAL", "MIRROR", "RANDOM", "MIR-RAN")), - gaugeMod: optNull(p.isIn("NORMAL", "HARD")), + gaugeMod: optNull(p.isIn("NORMAL", "HARD", "PERMISSIVE")), }; } else if (game === "bms" && playtype === "7K") { return { @@ -771,7 +771,7 @@ export const DatabaseSchemas: Record = { return prSchemaify( PR_ChartDocument("iidx", playtype, { notecount: p.isPositiveNonZeroInteger, - inGameID: p.isPositiveNonZeroInteger, + inGameID: p.or(p.isPositiveNonZeroInteger, [p.isPositiveNonZeroInteger]), arcChartID: "?string", hashSHA256: "?string", "2dxtraSet": "?string", diff --git a/server/src/lib/constants/ea3id.ts b/server/src/lib/constants/ea3id.ts index 552649b71..365564215 100644 --- a/server/src/lib/constants/ea3id.ts +++ b/server/src/lib/constants/ea3id.ts @@ -6,6 +6,7 @@ export const MODEL_IIDX_LIGHTNING = "TDJ"; export const REV_2DXTRA = "E"; export const REV_2DXBMS = "Z"; export const REV_OMNIMIX = "X"; +export const REV_NORMAL = "A"; export const EXT_HEROIC_VERSE = "2020092900"; export const EXT_BISTROVER = "2021091500"; diff --git a/server/src/lib/constants/version.ts b/server/src/lib/constants/version.ts index e88649b3a..e4287014c 100644 --- a/server/src/lib/constants/version.ts +++ b/server/src/lib/constants/version.ts @@ -4,7 +4,7 @@ const MAJOR = 2; const MINOR = 0; -const PATCH = 1; +const PATCH = 2; // As is with all front-facing zkldi projects, the version names for tachi-server // are from an album I like. In this case, the album is Portishead - Dummy. diff --git a/server/src/lib/orphan-queue/orphan-queue.ts b/server/src/lib/orphan-queue/orphan-queue.ts index 50fb1a6a3..38e155927 100644 --- a/server/src/lib/orphan-queue/orphan-queue.ts +++ b/server/src/lib/orphan-queue/orphan-queue.ts @@ -10,6 +10,7 @@ import { SongDocument, } from "tachi-common"; import { GetNextCounterValue } from "utils/db"; +import { DedupeArr } from "utils/misc"; const logger = CreateLogCtx(__filename); @@ -35,7 +36,7 @@ export async function HandleOrphanQueue( userID: integer, chartName: string ) { - logger.debug(`received orphanqueue request for ${chartName}.`); + logger.debug(`Received orphanqueue request for ${chartName}.`); const orphanChart = await db["orphan-chart-queue"].findOne( Object.assign({ idString }, orphanMatchCriteria), @@ -45,7 +46,7 @@ export async function HandleOrphanQueue( ); if (!orphanChart) { - logger.verbose(`received unknown chart ${chartName}, orphaning.`); + logger.verbose(`Received unknown chart ${chartName}, orphaning.`); await db["orphan-chart-queue"].insert({ idString, @@ -59,7 +60,7 @@ export async function HandleOrphanQueue( orphanChart.userIDs.push(userID); - const uniqueUsersArr = [...new Set(orphanChart.userIDs)]; + const uniqueUsersArr = DedupeArr(orphanChart.userIDs); const playcount = uniqueUsersArr.length; // If N or more people have played this chart while orphaned, unorphan diff --git a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts index 2988907fc..17627caaf 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts @@ -45,7 +45,7 @@ export async function CreateKaiIIDXClassHandler( return {}; } - if (iidxDan === null) { + if (iidxDan === null || iidxDan === undefined) { return {}; } diff --git a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts index a637de914..5871422b5 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts @@ -36,7 +36,7 @@ export async function CreateKaiSDVXClassHandler( const sdvxDan: number | null = json.skill_level - 1; - if (sdvxDan === null || sdvxDan === undefined) { + if (json.skill_level === null || json.skill_level === undefined) { return {}; } diff --git a/server/src/lib/score-import/import-types/common/batch-manual/parser.ts b/server/src/lib/score-import/import-types/common/batch-manual/parser.ts index 90e8fdb5a..9be2d4a36 100644 --- a/server/src/lib/score-import/import-types/common/batch-manual/parser.ts +++ b/server/src/lib/score-import/import-types/common/batch-manual/parser.ts @@ -65,7 +65,7 @@ const PR_ScoreMeta = (game: Game, playtype: Playtypes[Game]): PrudenceSchema => } else if (game === "usc") { return { noteMod: optNull(p.isIn("NORMAL", "MIRROR", "RANDOM", "MIR-RAN")), - gaugeMod: optNull(p.isIn("NORMAL", "HARD")), + gaugeMod: optNull(p.isIn("NORMAL", "HARD", "PERMISSIVE")), }; } else if (game === "sdvx") { return { diff --git a/server/src/lib/score-import/import-types/common/types.ts b/server/src/lib/score-import/import-types/common/types.ts index 7ce93f495..05a085e5b 100644 --- a/server/src/lib/score-import/import-types/common/types.ts +++ b/server/src/lib/score-import/import-types/common/types.ts @@ -16,11 +16,11 @@ import { ClassHandler } from "../../framework/user-game-stats/types"; import { SDVXEamusementCSVData } from "../file/eamusement-sdvx-csv/types"; import { MerScore } from "../file/mer-iidx/types"; import { S3Score } from "../file/solid-state-squad/types"; -import { BarbatosScore } from "../ir/barbatos/types"; +import { BarbatosContext, BarbatosScore } from "../ir/barbatos/types"; import { BeatorajaContext, BeatorajaScore } from "../ir/beatoraja/types"; import { FervidexStaticContext, FervidexStaticScore } from "../ir/fervidex-static/types"; import { FervidexContext, FervidexScore } from "../ir/fervidex/types"; -import { KsHookSV3CScore } from "../ir/kshook-sv3c/types"; +import { KsHookSV3CContext, KsHookSV3CScore } from "../ir/kshook-sv3c/types"; import { IRUSCContext } from "../ir/usc/types"; import { KaiContext } from "./api-kai/types"; import { BatchManualContext } from "./batch-manual/types"; @@ -62,12 +62,12 @@ export interface ImportTypeContextMap { "file/pli-iidx-csv": IIDXEamusementCSVContext; "ir/direct-manual": BatchManualContext; - "ir/barbatos": EmptyObject; + "ir/barbatos": BarbatosContext; "ir/fervidex": FervidexContext; "ir/fervidex-static": FervidexStaticContext; "ir/beatoraja": BeatorajaContext; "ir/usc": IRUSCContext; - "ir/kshook-sv3c": EmptyObject; + "ir/kshook-sv3c": KsHookSV3CContext; "api/arc-iidx": EmptyObject; "api/arc-sdvx": EmptyObject; diff --git a/server/src/lib/score-import/import-types/file/solid-state-squad/parser.ts b/server/src/lib/score-import/import-types/file/solid-state-squad/parser.ts index 82d239b99..60db0329f 100644 --- a/server/src/lib/score-import/import-types/file/solid-state-squad/parser.ts +++ b/server/src/lib/score-import/import-types/file/solid-state-squad/parser.ts @@ -66,7 +66,6 @@ export function ParseSolidStateXML( } if (!parsedXML?.s3data?.scoredata?.song) { - logger.crit("foo", { data: fileData.buffer }); throw new ScoreImportFatalError(400, `Invalid S3 XML, no s3data -> scoredata -> song?`); } diff --git a/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts b/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts index 0a1ac0632..1c651489d 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts @@ -40,7 +40,12 @@ t.test("#ConverterIRBarbatos", (t) => { }; t.test("Should convert a BarbatosScore into a Dry Score", async (t) => { - const res = await ConverterIRBarbatos(barbScore, {}, "ir/barbatos", logger); + const res = await ConverterIRBarbatos( + barbScore, + { timeReceived: 10 }, + "ir/barbatos", + logger + ); t.hasStrict(res, { song: albidaSong, @@ -82,7 +87,7 @@ t.test("#ConverterIRBarbatos", (t) => { () => ConverterIRBarbatos( deepmerge(barbScore, { song_id: 1000 }) as BarbatosScore, - {}, + { timeReceived: 10 }, "ir/barbatos", logger ), @@ -97,9 +102,12 @@ t.test("#ConverterIRBarbatos", (t) => { t.test("Should throw InternalFailure if song-chart desync.", async (t) => { await db.songs.sdvx.remove({ id: 1 }); // force a song-chart desync - t.rejects(() => ConverterIRBarbatos(barbScore, {}, "ir/barbatos", logger), { - message: /Song 1 \(sdvx\) has no parent song/u, - }); + t.rejects( + () => ConverterIRBarbatos(barbScore, { timeReceived: 10 }, "ir/barbatos", logger), + { + message: /Song 1 \(sdvx\) has no parent song/u, + } + ); t.end(); }); diff --git a/server/src/lib/score-import/import-types/ir/barbatos/converter.ts b/server/src/lib/score-import/import-types/ir/barbatos/converter.ts index 64f1d0e6b..37310b466 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/converter.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/converter.ts @@ -1,7 +1,6 @@ import { Lamps } from "tachi-common"; import { FindSDVXChartOnInGameID } from "utils/queries/charts"; import { FindSongOnID } from "utils/queries/songs"; -import { EmptyObject } from "utils/types"; import { InternalFailure, KTDataNotFoundFailure, @@ -9,7 +8,7 @@ import { import { GenericGetGradeAndPercent } from "../../../framework/common/score-utils"; import { DryScore } from "../../../framework/common/types"; import { ConverterFunction } from "../../common/types"; -import { BarbatosScore } from "./types"; +import { BarbatosContext, BarbatosScore } from "./types"; const LAMP_LOOKUP = { 1: "FAILED", @@ -27,7 +26,7 @@ const DIFFICULTY_LOOKUP = { 4: "MXM", }; -export const ConverterIRBarbatos: ConverterFunction = async ( +export const ConverterIRBarbatos: ConverterFunction = async ( data, context, importType, @@ -65,7 +64,7 @@ export const ConverterIRBarbatos: ConverterFunction service: "Barbatos", comment: null, importType: "ir/barbatos", - timeAchieved: Date.now(), + timeAchieved: context.timeReceived, scoreData: { score: data.score, percent, @@ -84,7 +83,7 @@ export const ConverterIRBarbatos: ConverterFunction }, }, scoreMeta: { - inSkillAnalyser: data.is_skill_analyser, + inSkillAnalyser: data.is_skill_analyzer, }, }; diff --git a/server/src/lib/score-import/import-types/ir/barbatos/parser.ts b/server/src/lib/score-import/import-types/ir/barbatos/parser.ts index 8293c360f..0aa50b744 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/parser.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/parser.ts @@ -21,7 +21,7 @@ const PR_Barbatos = { did_fail: "boolean", clear_type: p.isIn(1, 2, 3, 4, 5), gauge_type: p.isIn(0, 1, 2, 3), - is_skill_analyser: "boolean", + is_skill_analyzer: "boolean", }; export function ParseBarbatosSingle( diff --git a/server/src/lib/score-import/import-types/ir/barbatos/types.ts b/server/src/lib/score-import/import-types/ir/barbatos/types.ts index d57506670..9a3ad9956 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/types.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/types.ts @@ -15,5 +15,9 @@ export interface BarbatosScore { did_fail: boolean; clear_type: 1 | 2 | 3 | 4 | 5; gauge_type: 1 | 2; - is_skill_analyser: boolean; + is_skill_analyzer: boolean; +} + +export interface BarbatosContext { + timeReceived: number; } diff --git a/server/src/lib/score-import/import-types/ir/beatoraja/converter.ts b/server/src/lib/score-import/import-types/ir/beatoraja/converter.ts index 1c9323cf5..a3ccd606d 100644 --- a/server/src/lib/score-import/import-types/ir/beatoraja/converter.ts +++ b/server/src/lib/score-import/import-types/ir/beatoraja/converter.ts @@ -182,7 +182,7 @@ export const ConverterIRBeatoraja: ConverterFunction { t.test("Should convert a valid fervidex score into a dry score.", async (t) => { const res = await ConverterIRFervidex( baseFervidexScore, - { version: "27" }, + { version: "27", timeReceived: 10 }, "ir/fervidex", logger ); @@ -159,7 +159,7 @@ t.test("#ConverterIRFervidex", (t) => { const res = await ConverterIRFervidex( deepmerge(baseFervidexScore, { option: { style_2p: "R_RANDOM" }, chart: "dpa" }), - { version: "27" }, + { version: "27", timeReceived: 10 }, "ir/fervidex", logger ); @@ -182,7 +182,7 @@ t.test("#ConverterIRFervidex", (t) => { t.test("Should null BP if the user died pre-emptively.", async (t) => { const res = await ConverterIRFervidex( deepmerge(baseFervidexScore, { dead: { measure: 1, note: 10 } }), - { version: "27" }, + { version: "27", timeReceived: 10 }, "ir/fervidex", logger ); @@ -204,7 +204,7 @@ t.test("#ConverterIRFervidex", (t) => { t.rejects( ConverterIRFervidex( deepmerge(baseFervidexScore, { chart: "spl" }), - { version: "27" }, + { version: "27", timeReceived: 10 }, "ir/fervidex", logger ), @@ -218,7 +218,12 @@ t.test("#ConverterIRFervidex", (t) => { await db.songs.iidx.remove({}); // this forces desync t.rejects( - ConverterIRFervidex(baseFervidexScore, { version: "27" }, "ir/fervidex", logger), + ConverterIRFervidex( + baseFervidexScore, + { version: "27", timeReceived: 10 }, + "ir/fervidex", + logger + ), { message: /Song 1 \(iidx\) has no parent song/giu } ); @@ -258,7 +263,7 @@ t.test("#ConverterIRFervidex", (t) => { t.test("Should convert undeflow gauge to null.", async (t) => { const res = await ConverterIRFervidex( deepmerge(baseFervidexScore, { gauge: [10, 5, 249, 248] }), - { version: "27" }, + { version: "27", timeReceived: 10 }, "ir/fervidex", logger ); diff --git a/server/src/lib/score-import/import-types/ir/fervidex/converter.ts b/server/src/lib/score-import/import-types/ir/fervidex/converter.ts index f4291e1cb..2a82affb8 100644 --- a/server/src/lib/score-import/import-types/ir/fervidex/converter.ts +++ b/server/src/lib/score-import/import-types/ir/fervidex/converter.ts @@ -23,7 +23,7 @@ export const FERVIDEX_LAMP_LOOKUP = { }; export function TachifyAssist( - assist: FervidexScore["option"]["assist"] + assist: Required["option"]["assist"] ): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["assist"] { switch (assist) { case "FULL_ASSIST": @@ -40,7 +40,7 @@ export function TachifyAssist( } export function TachifyGauge( - gauge: FervidexScore["option"]["gauge"] + gauge: Required["option"]["gauge"] ): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["gauge"] { switch (gauge) { case "ASSISTED_EASY": @@ -58,7 +58,7 @@ export function TachifyGauge( } export function TachifyRange( - gauge: FervidexScore["option"]["range"] + gauge: Required["option"]["range"] ): DryScore<"iidx:SP" | "iidx:DP">["scoreMeta"]["range"] { switch (gauge) { case "HIDDEN_PLUS": @@ -77,7 +77,7 @@ export function TachifyRange( } } -export function TachifyRandom(gauge: FervidexScore["option"]["style"]) { +export function TachifyRandom(gauge: Required["option"]["style"]) { switch (gauge) { case "RANDOM": return "RANDOM"; @@ -186,7 +186,7 @@ export const ConverterIRFervidex: ConverterFunction { + const f = (sid: string) => SoftwareIDToVersion(sid, logger); + + t.throws(() => f("a"), {}, "Should throw on invalid string."); + t.throws(() => f("LDJ:J:B:Q:2020092900"), {}, "Should throw on unknown HV revision."); + t.throws(() => f("LDJ:J:B:Q:2021091500"), {}, "Should throw on unknown BST revision."); + t.throws(() => f("XDJ:J:B:A:2020092900"), {}, "Should throw on unknown model."); + t.throws(() => f("LDJ:J:B:A:2099092900"), {}, "Should throw on unknown ext."); + + t.equal(f("LDJ:J:B:A:2020092900"), "27"); + t.equal(f("LDJ:J:B:X:2020092900"), "27-omni"); + t.equal(f("LDJ:J:B:E:2020092900"), "27-2dxtra"); + t.equal(f("LDJ:J:B:A:2021091500"), "28"); + t.equal(f("LDJ:J:B:X:2021091500"), "28-omni"); + t.equal(f("LDJ:J:B:E:2021091500"), "28-2dxtra"); + + t.equal(f("TDJ:J:B:A:2020092900"), "27"); + t.equal(f("TDJ:J:B:X:2020092900"), "27-omni"); + t.equal(f("TDJ:J:B:E:2020092900"), "27-2dxtra"); + t.equal(f("TDJ:J:B:A:2021091500"), "28"); + t.equal(f("TDJ:J:B:X:2021091500"), "28-omni"); + t.equal(f("TDJ:J:B:E:2021091500"), "28-2dxtra"); + + t.equal(f("P2D:J:B:A:2020092900"), "inf"); + + t.end(); +}); diff --git a/server/src/lib/score-import/import-types/ir/fervidex/parser.ts b/server/src/lib/score-import/import-types/ir/fervidex/parser.ts index 04488585e..3e0569dd1 100644 --- a/server/src/lib/score-import/import-types/ir/fervidex/parser.ts +++ b/server/src/lib/score-import/import-types/ir/fervidex/parser.ts @@ -2,8 +2,10 @@ import { EXT_BISTROVER, EXT_HEROIC_VERSE, MODEL_IIDX, + MODEL_IIDX_LIGHTNING, MODEL_INFINITAS_2, REV_2DXTRA, + REV_NORMAL, REV_OMNIMIX, } from "lib/constants/ea3id"; import { KtLogger } from "lib/logger/logger"; @@ -42,7 +44,7 @@ const PR_Fervidex: PrudenceSchema = { note: optNull(p.isPositiveInteger), } as unknown as ValidSchemaValue), - option: { + option: p.optional({ gauge: optNull(p.isIn("ASSISTED_EASY", "EASY", "HARD", "EX_HARD")), range: optNull( p.isIn("SUDDEN_PLUS", "HIDDEN_PLUS", "SUD_PLUS_HID_PLUS", "LIFT", "LIFT_SUD_PLUS") @@ -50,7 +52,7 @@ const PR_Fervidex: PrudenceSchema = { style: optNull(p.isIn("RANDOM", "R_RANDOM", "S_RANDOM", "MIRROR")), style_2p: optNull(p.isIn("RANDOM", "R_RANDOM", "S_RANDOM", "MIRROR")), assist: optNull(p.isIn("AUTO_SCRATCH", "LEGACY_NOTE", "ASCR_LEGACY", "FULL_ASSIST")), - }, + }), // we dont use it and we dont care. pacemaker: p.any, @@ -73,24 +75,25 @@ export function SoftwareIDToVersion(model: string, logger: KtLogger) { if (data.model === MODEL_INFINITAS_2) { return "inf"; - } else if (data.model === MODEL_IIDX) { - // only HV. everything else is disabled deliberately. + } else if (data.model === MODEL_IIDX || data.model === MODEL_IIDX_LIGHTNING) { + // pretty icky yandere-dev tier if statements, but hey + // that's just how it works... if (data.ext === EXT_HEROIC_VERSE) { if (data.rev === REV_OMNIMIX) { return "27-omni"; - } - - if (data.rev === REV_2DXTRA) { + } else if (data.rev === REV_2DXTRA) { return "27-2dxtra"; + } else if (data.rev === REV_NORMAL) { + return "27"; } - - return "27"; } else if (data.ext === EXT_BISTROVER) { if (data.rev === REV_OMNIMIX) { return "28-omni"; + } else if (data.rev === REV_2DXTRA) { + return "28-2dxtra"; + } else if (data.rev === REV_NORMAL) { + return "28"; } - - return "28"; } } @@ -122,7 +125,7 @@ export function ParseFervidexSingle( // asserted using prudence. return { - context: { version }, + context: { version, timeReceived: Date.now() }, game: "iidx", iterable: [body] as unknown as FervidexScore[], classHandler: null, diff --git a/server/src/lib/score-import/import-types/ir/fervidex/types.ts b/server/src/lib/score-import/import-types/ir/fervidex/types.ts index 3ce953002..d8b4f9e65 100644 --- a/server/src/lib/score-import/import-types/ir/fervidex/types.ts +++ b/server/src/lib/score-import/import-types/ir/fervidex/types.ts @@ -30,7 +30,7 @@ export interface FervidexScore { note?: integer | null; }; - option: { + option?: { gauge?: "ASSISTED_EASY" | "EASY" | "HARD" | "EX_HARD" | null; range?: | "SUDDEN_PLUS" @@ -60,4 +60,5 @@ export interface FervidexScore { export interface FervidexContext { version: GPTSupportedVersions["iidx:SP" | "iidx:DP"]; + timeReceived: number; } diff --git a/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.test.ts b/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.test.ts index 496af0aa4..be6ff13f7 100644 --- a/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.test.ts +++ b/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.test.ts @@ -12,7 +12,7 @@ t.test("#ConverterIRKsHookSV3C", (t) => { t.test("Should match a score with its song and chart.", async (t) => { const res = await ConverterIRKsHookSV3C( TestingKsHookSV3CScore, - {}, + { timeReceived: 10 }, "ir/kshook-sv3c", logger ); @@ -57,7 +57,7 @@ t.test("#ConverterIRKsHookSV3C", (t) => { () => ConverterIRKsHookSV3C( Object.assign({}, TestingKsHookSV3CScore, { music_id: 10000 }), - {}, + { timeReceived: 10 }, "ir/kshook-sv3c", logger ), diff --git a/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.ts b/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.ts index 9f64ffc4b..8c8994d41 100644 --- a/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.ts +++ b/server/src/lib/score-import/import-types/ir/kshook-sv3c/converter.ts @@ -7,11 +7,10 @@ import { DryScore } from "lib/score-import/framework/common/types"; import { Lamps } from "tachi-common"; import { FindSDVXChartOnInGameIDVersion } from "utils/queries/charts"; import { FindSongOnID } from "utils/queries/songs"; -import { EmptyObject } from "utils/types"; import { ConverterFunction } from "../../common/types"; -import { KsHookSV3CScore } from "./types"; +import { KsHookSV3CContext, KsHookSV3CScore } from "./types"; -export const ConverterIRKsHookSV3C: ConverterFunction = async ( +export const ConverterIRKsHookSV3C: ConverterFunction = async ( data, context, importType, @@ -44,7 +43,7 @@ export const ConverterIRKsHookSV3C: ConverterFunction { const res = ParseKsHookSV3C(data, logger); t.equal(res.game, "sdvx"); - t.strictSame(res.context, {}); + t.type(res.context.timeReceived, "number"); t.ok(Array.isArray(res.iterable)); t.type(res.classHandler, "function"); } catch (err) { diff --git a/server/src/lib/score-import/import-types/ir/kshook-sv3c/parser.ts b/server/src/lib/score-import/import-types/ir/kshook-sv3c/parser.ts index 6ce5ceaa1..1fa5d3d9b 100644 --- a/server/src/lib/score-import/import-types/ir/kshook-sv3c/parser.ts +++ b/server/src/lib/score-import/import-types/ir/kshook-sv3c/parser.ts @@ -3,9 +3,8 @@ import { KtLogger } from "lib/logger/logger"; import ScoreImportFatalError from "lib/score-import/framework/score-importing/score-import-error"; import p, { PrudenceSchema } from "prudence"; import { FormatPrError } from "utils/prudence"; -import { EmptyObject } from "utils/types"; import { ParserFunctionReturns } from "../../common/types"; -import { KsHookSV3CScore } from "./types"; +import { KsHookSV3CContext, KsHookSV3CScore } from "./types"; const PR_KsHookSV3C: PrudenceSchema = { appeal_id: p.isPositiveInteger, @@ -75,7 +74,7 @@ const PR_KsHookSV3C: PrudenceSchema = { export function ParseKsHookSV3C( body: Record, logger: KtLogger -): ParserFunctionReturns { +): ParserFunctionReturns { // Ignore excess keys, as SV3C might add more features in the future. const err = p(body, PR_KsHookSV3C, undefined, { allowExcessKeys: true }); @@ -88,7 +87,9 @@ export function ParseKsHookSV3C( return { game: "sdvx", iterable: [score], - context: {}, + context: { + timeReceived: Date.now(), + }, classHandler: () => { const skillLevel = ConvertSkillLevel(score.skill_level); diff --git a/server/src/lib/score-import/import-types/ir/kshook-sv3c/types.ts b/server/src/lib/score-import/import-types/ir/kshook-sv3c/types.ts index 0b7f4e331..ea97d81a1 100644 --- a/server/src/lib/score-import/import-types/ir/kshook-sv3c/types.ts +++ b/server/src/lib/score-import/import-types/ir/kshook-sv3c/types.ts @@ -56,3 +56,7 @@ export interface KsHookSV3CScore { skill_name: integer; track_no: integer; } + +export interface KsHookSV3CContext { + timeReceived: number; +} diff --git a/server/src/lib/score-import/import-types/ir/usc/converter.test.ts b/server/src/lib/score-import/import-types/ir/usc/converter.test.ts index e0fba6455..ed59e4350 100644 --- a/server/src/lib/score-import/import-types/ir/usc/converter.test.ts +++ b/server/src/lib/score-import/import-types/ir/usc/converter.test.ts @@ -16,6 +16,17 @@ t.test("#DeriveLamp", (t) => { t.equal(DeriveLamp(d(uscScore, { options: { gaugeType: 0 }, gauge: 0.7 }), logger), "CLEAR"); + t.equal(DeriveLamp(d(uscScore, { options: { gaugeType: 2 }, gauge: 1 }), logger), "FAILED"); + t.equal(DeriveLamp(d(uscScore, { options: { gaugeType: 2 }, gauge: 0 }), logger), "FAILED"); + t.equal( + DeriveLamp(d(uscScore, { options: { gaugeType: 2 }, gauge: 1, score: 10_000_000 }), logger), + "PERFECT ULTIMATE CHAIN" + ); + t.equal( + DeriveLamp(d(uscScore, { options: { gaugeType: 2 }, gauge: 1, error: 0 }), logger), + "ULTIMATE CHAIN" + ); + t.equal( DeriveLamp(d(uscScore, { options: { gaugeType: 1 }, gauge: 0.1 }), logger), "EXCESSIVE CLEAR" @@ -58,7 +69,7 @@ t.test("#DeriveLamp", (t) => { "ULTIMATE CHAIN" ); - t.throws(() => DeriveLamp(d(uscScore, { options: { gaugeType: 2 } }), logger)); + t.throws(() => DeriveLamp(d(uscScore, { options: { gaugeType: 3 } }), logger)); t.end(); }); @@ -77,7 +88,7 @@ t.test("#DeriveNoteMod", (t) => { const dm = (p: Partial) => ConverterIRUSC( d(uscScore, p), - { chartHash: uscChart.data.hashSHA1 as string, playtype: "Controller" }, + { chartHash: uscChart.data.hashSHA1 as string, playtype: "Controller", timeReceived: 10 }, "ir/usc", logger ); diff --git a/server/src/lib/score-import/import-types/ir/usc/converter.ts b/server/src/lib/score-import/import-types/ir/usc/converter.ts index 7070876bb..82b4e7204 100644 --- a/server/src/lib/score-import/import-types/ir/usc/converter.ts +++ b/server/src/lib/score-import/import-types/ir/usc/converter.ts @@ -50,6 +50,8 @@ export function DeriveLamp( return scoreDoc.gauge >= 0.7 ? "CLEAR" : "FAILED"; } else if (scoreDoc.options.gaugeType === 1) { return scoreDoc.gauge > 0 ? "EXCESSIVE CLEAR" : "FAILED"; + } else if (scoreDoc.options.gaugeType === 2) { + return "FAILED"; } logger.error(`Could not derive Lamp from Score Document`, { scoreDoc }); @@ -106,7 +108,7 @@ export const ConverterIRUSC: ConverterFunction = a comment: null, game: "usc", importType, - timeAchieved: Date.now(), + timeAchieved: context.timeReceived, service: "USC-IR", scoreData: { grade, @@ -126,7 +128,12 @@ export const ConverterIRUSC: ConverterFunction = a }, }, scoreMeta: { - gaugeMod: data.options.gaugeType === 0 ? "NORMAL" : "HARD", + gaugeMod: + data.options.gaugeType === 0 + ? "NORMAL" + : data.options.gaugeType === 1 + ? "HARD" + : "PERMISSIVE", noteMod: DeriveNoteMod(data), }, }; diff --git a/server/src/lib/score-import/import-types/ir/usc/parser.ts b/server/src/lib/score-import/import-types/ir/usc/parser.ts index 1b46c783b..74df7ad84 100644 --- a/server/src/lib/score-import/import-types/ir/usc/parser.ts +++ b/server/src/lib/score-import/import-types/ir/usc/parser.ts @@ -18,7 +18,7 @@ const PR_USCIRScore: PrudenceSchema = { late: p.optional(p.isPositiveInteger), combo: p.optional(p.isPositiveInteger), options: { - gaugeType: p.isIn(0, 1), + gaugeType: p.isIn(0, 1, 2), mirror: "boolean", random: "boolean", autoFlags: p.isInteger, @@ -62,6 +62,7 @@ export function ParseIRUSC( context: { chartHash, playtype, + timeReceived: Date.now(), }, game: "usc", iterable: [score] as USCClientScore[], diff --git a/server/src/lib/score-import/import-types/ir/usc/types.ts b/server/src/lib/score-import/import-types/ir/usc/types.ts index badada65d..e9283d56c 100644 --- a/server/src/lib/score-import/import-types/ir/usc/types.ts +++ b/server/src/lib/score-import/import-types/ir/usc/types.ts @@ -3,4 +3,5 @@ import { Playtypes } from "tachi-common"; export interface IRUSCContext { chartHash: string; playtype: Playtypes["usc"]; + timeReceived: number; } diff --git a/server/src/server/router/api/v1/admin/router.ts b/server/src/server/router/api/v1/admin/router.ts index 54d12f143..5537a2872 100644 --- a/server/src/server/router/api/v1/admin/router.ts +++ b/server/src/server/router/api/v1/admin/router.ts @@ -12,6 +12,7 @@ import { Game, UserAuthLevels } from "tachi-common"; import db from "external/mongo/db"; import { DeleteScore } from "lib/delete-scores/delete-scores"; import { UpdateAllPBs } from "utils/calculations/recalc-scores"; +import DestroyUserGamePlaytypeData from "utils/reset-state/destroy-ugpt"; const logger = CreateLogCtx(__filename); @@ -260,6 +261,44 @@ router.post("/delete-score", prValidate({ scoreID: "string" }), async (req, res) }); }); +/** + * Destroys a users UGPT profile and forces a site recalc. + * + * @POST /api/v1/admin/destroy-ugpt + */ +router.post( + "/destroy-ugpt", + prValidate({ + userID: p.isInteger, + game: p.isIn(TachiConfig.GAMES), + playtype: "string", // lazy + }), + async (req, res) => { + const { userID, game, playtype } = req.body; + + const ugpt = await db["game-stats"].findOne({ + userID, + game, + playtype, + }); + + if (!ugpt) { + return res.status(404).json({ + success: false, + description: `No stats for ${userID} (${game} ${playtype}) exist.`, + }); + } + + await DestroyUserGamePlaytypeData(userID, game, playtype); + + return res.status(200).json({ + success: true, + description: `Completely destroyed UGPT for ${userID} (${game} ${playtype}).`, + body: {}, + }); + } +); + /** * Destroy a chart and all of its scores (and sessions). * diff --git a/server/src/server/router/ir/fervidex/router.test.ts b/server/src/server/router/ir/fervidex/router.test.ts index da8f511d5..f9351d856 100644 --- a/server/src/server/router/ir/fervidex/router.test.ts +++ b/server/src/server/router/ir/fervidex/router.test.ts @@ -5,6 +5,7 @@ import mockApi from "test-utils/mock-api"; import ResetDBState from "test-utils/resets"; import { GetKTDataJSON } from "test-utils/test-data"; import { Sleep } from "utils/misc"; +import deepmerge from "deepmerge"; // eslint-disable-next-line @typescript-eslint/no-explicit-any function TestHeaders(url: string, data: any) { @@ -301,6 +302,27 @@ t.test("POST /ir/fervidex/score/submit", (t) => { t.end(); }); + t.test("Should import a valid score with undefined options", async (t) => { + const res = await mockApi + .post("/ir/fervidex/score/submit") + .set("Authorization", "Bearer mock_token") + .set("User-Agent", "fervidex/1.3.0") + .set("X-Software-Model", "LDJ:J:B:A:2020092900") + .send(deepmerge(GetKTDataJSON("./fervidex/base.json"), { option: undefined })); + + t.equal(res.body.success, true, "Should be successful"); + + t.equal(res.body.body.errors.length, 0, "Should have 0 failed scores."); + + const scores = await db.scores.count({ + service: "Fervidex", + }); + + t.equal(scores, 1, "Should import 1 score."); + + t.end(); + }); + t.test("Should import a valid score with 2dx-gsm", async (t) => { const res = await mockApi .post("/ir/fervidex/score/submit") diff --git a/server/src/server/router/ir/fervidex/router.ts b/server/src/server/router/ir/fervidex/router.ts index 2cbfc3aeb..fa81417b8 100644 --- a/server/src/server/router/ir/fervidex/router.ts +++ b/server/src/server/router/ir/fervidex/router.ts @@ -60,7 +60,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => { // version.minor if (versions[1] < 3) { logger.debug( - `Rejected outdated fervidex client from user ${req[SYMBOL_TachiAPIAuth].userID!}.` + `Rejected outdated fervidex client from user ${req[SYMBOL_TachiAPIAuth].userID}.` ); return res.status(400).json({ success: false, diff --git a/server/src/server/router/ir/usc/_playtype/router.test.ts b/server/src/server/router/ir/usc/_playtype/router.test.ts index 2296737b1..2b279d756 100644 --- a/server/src/server/router/ir/usc/_playtype/router.test.ts +++ b/server/src/server/router/ir/usc/_playtype/router.test.ts @@ -582,6 +582,12 @@ t.test("POST /scores", (t) => { t.equal(res.body.statusCode, 22); + t.match( + res.body.description, + "(1/3)", + "Should contain (required/outOf) in the response description." + ); + const dbScore = await db.scores.findOne({ game: "usc", }); diff --git a/server/src/server/router/ir/usc/_playtype/router.ts b/server/src/server/router/ir/usc/_playtype/router.ts index 2bac60cff..f930c7ab3 100644 --- a/server/src/server/router/ir/usc/_playtype/router.ts +++ b/server/src/server/router/ir/usc/_playtype/router.ts @@ -21,6 +21,7 @@ import { Playtypes, SuccessfulAPIResponse, } from "tachi-common"; +import { DedupeArr } from "utils/misc"; import { FormatPrError } from "utils/prudence"; import { GetBlacklist } from "utils/queries/blacklist"; import { AssignToReqTachiData } from "utils/req-tachi-data"; @@ -319,6 +320,7 @@ router.post("/scores", RequirePermissions("submit_score"), async (req, res) => { song, { "chartDoc.data.hashSHA1": uscChart.chartHash, + "chartDoc.playtype": playtype, }, ServerConfig.USC_QUEUE_SIZE, req[SYMBOL_TachiAPIAuth].userID!, @@ -332,9 +334,12 @@ router.post("/scores", RequirePermissions("submit_score"), async (req, res) => { "context.playtype": playtype, }); - await Promise.all( - scoresToDeorphan.map((score) => ReprocessOrphan(score, blacklist, logger)) - ); + for (const score of scoresToDeorphan) { + // Has to be like this to avoid race conditions where two + // orphans resolve to the same scoreID and collide in mid-air! + // eslint-disable-next-line no-await-in-loop + await ReprocessOrphan(score, blacklist, logger); + } } } @@ -346,16 +351,6 @@ router.post("/scores", RequirePermissions("submit_score"), async (req, res) => { playtype, ]); - // If this was an orphan chart request, return ACCEPTED, - // since it may be unorphaned in the future - if (!chartDoc) { - return res.status(200).json({ - statusCode: STATUS_CODES.ACCEPTED, - description: - "This score has been accepted, but is waiting for more players before its parent chart is accepted.", - }); - } - if (importRes.statusCode === 500) { return res.status(200).json({ statusCode: STATUS_CODES.SERVER_ERROR, @@ -370,6 +365,71 @@ router.post("/scores", RequirePermissions("submit_score"), async (req, res) => { const importDoc = (importRes.body as SuccessfulAPIResponse).body as ImportDocument; + // If the import failed, AND the import failure WAS NOT that the chart didnt exist + // report that error instead. + if (importDoc.errors[0]?.type && importDoc.errors[0].type !== "KTDataNotFound") { + logger.info(`USC Import Failed ${importDoc.errors[0].message}`, { + importDoc, + userID, + }); + + return res.status(200).json({ + statusCode: STATUS_CODES.BAD_REQ, + description: `${importDoc.errors[0].type} ${importDoc.errors[0].message}`, + }); + } + + // If this was an orphan chart request, return ACCEPTED, + // since it may be unorphaned in the future + if (!chartDoc) { + const orphanChart = await db["orphan-chart-queue"].findOne({ + "chartDoc.data.hashSHA1": uscChart.chartHash, + "chartDoc.playtype": playtype, + }); + + if (!orphanChart) { + logger.severe( + `No orphan chart for USC ${uscChart.chartHash} (${playtype})? One was expected.`, + { uscChart, playtype } + ); + return res.status(200).json({ + statusCode: STATUS_CODES.SERVER_ERROR, + description: `An internal server error has occured.`, + }); + } + + const players = DedupeArr([...orphanChart.userIDs, userID]); + + return res.status(200).json({ + statusCode: STATUS_CODES.ACCEPTED, + description: `This score has been accepted, but is waiting for more players before its parent chart is accepted. (${players.length}/${ServerConfig.USC_QUEUE_SIZE})`, + }); + } + + // If the chartDoc exists, any error is a failure here. + if (importDoc.errors[0]) { + logger.info(`USC Import Failed ${importDoc.errors[0].message}`, { + importDoc, + userID, + }); + + return res.status(200).json({ + statusCode: STATUS_CODES.BAD_REQ, + description: `${importDoc.errors[0].type} ${importDoc.errors[0].message}`, + }); + } + + if (!importDoc.scoreIDs[0]) { + logger.warn(`No scoreID, but import was successful?`, { + importDoc, + userID, + }); + return res.status(200).json({ + statusCode: STATUS_CODES.BAD_REQ, + description: "No score was imported.", + }); + } + if (importDoc.errors[0]) { logger.info(`USC Import Failed ${importDoc.errors[0].message}`, { importDoc, diff --git a/server/src/server/router/ir/usc/_playtype/types.ts b/server/src/server/router/ir/usc/_playtype/types.ts index 887242eb0..861c67df0 100644 --- a/server/src/server/router/ir/usc/_playtype/types.ts +++ b/server/src/server/router/ir/usc/_playtype/types.ts @@ -8,7 +8,7 @@ export interface USCServerScore { near: integer; error: integer; ranking: integer; - gaugeMod: "NORMAL" | "HARD"; + gaugeMod: "NORMAL" | "HARD" | "PERMISSIVE"; noteMod: "NORMAL" | "MIRROR" | "RANDOM" | "MIR-RAN"; username: string; } @@ -24,7 +24,7 @@ export interface USCClientScore { late: integer | null; combo: integer | null; options: { - gaugeType: 0 | 1; + gaugeType: 0 | 1 | 2; gaugeOpt: integer; mirror: boolean; random: boolean; diff --git a/server/src/test-utils/test-data.ts b/server/src/test-utils/test-data.ts index 0f040ab26..abeb8b1b9 100644 --- a/server/src/test-utils/test-data.ts +++ b/server/src/test-utils/test-data.ts @@ -195,7 +195,7 @@ export const barbScore: BarbatosScore = { near_fast: 40, near_slow: 10, gauge_type: 1, - is_skill_analyser: false, + is_skill_analyzer: false, level: 10, max_chain: 100, percent: 90, diff --git a/server/src/test-utils/test-data/barbatos/base.json b/server/src/test-utils/test-data/barbatos/base.json index 145b5f9b9..cfeb37b8b 100644 --- a/server/src/test-utils/test-data/barbatos/base.json +++ b/server/src/test-utils/test-data/barbatos/base.json @@ -13,5 +13,5 @@ "did_fail": false, "clear_type": 2, "gauge_type": 0, - "is_skill_analyser": false + "is_skill_analyzer": false } \ No newline at end of file diff --git a/server/src/utils/folder.ts b/server/src/utils/folder.ts index b7fb9f829..73fc6904a 100644 --- a/server/src/utils/folder.ts +++ b/server/src/utils/folder.ts @@ -59,7 +59,7 @@ export async function ResolveFolderToCharts( const folderDataTransposed: Record = {}; for (const key in folder.data) { - folderDataTransposed[key.replace(/¬/gu, ".").replace("~", "$")] = folder.data[key]; + folderDataTransposed[key.replace(/¬/gu, ".").replace(/~/gu, "$")] = folder.data[key]; } const fx = deepmerge.all([filter, { playtype: folder.playtype }, folderDataTransposed]); diff --git a/server/src/utils/reset-state/destroy-ugpt.ts b/server/src/utils/reset-state/destroy-ugpt.ts new file mode 100644 index 000000000..6b0b40a40 --- /dev/null +++ b/server/src/utils/reset-state/destroy-ugpt.ts @@ -0,0 +1,94 @@ +import db from "external/mongo/db"; +import { integer, Game, Playtypes } from "tachi-common"; +import { UpdateAllPBs } from "utils/calculations/recalc-scores"; + +/** + * Completely resets a UGPT profile. + * + * This function is dangerous! Should only be ran by admins. + */ +export default async function DestroyUserGamePlaytypeData( + userID: integer, + game: Game, + playtype: Playtypes[Game] +) { + await db["game-stats-snapshots"].remove({ + userID, + game, + playtype, + }); + + await db.scores.remove({ + userID, + game, + playtype, + }); + + const chartIDs = ( + await db["personal-bests"].find( + { + userID, + game, + playtype, + }, + { + projection: { + chartID: 1, + }, + } + ) + ).map((e) => e.chartID); + + await db["personal-bests"].remove({ + userID, + game, + playtype, + }); + + await UpdateAllPBs(undefined, { + chartID: { $in: chartIDs }, + }); + + const sessionIDs = ( + await db.sessions.find( + { + userID, + game, + playtype, + }, + { + projection: { + sessionID: 1, + }, + } + ) + ).map((e) => e.sessionID); + + await db["session-view-cache"].remove({ + sessionID: { $in: sessionIDs }, + }); + + await db.sessions.remove({ + userID, + game, + playtype, + }); + + await db.imports.remove({ + userID, + game, + playtype, + }); + + await db["game-settings"].remove({ + userID, + game, + playtype, + }); + + await db["game-stats"].remove({ + userID, + game, + playtype, + }); +}