From aa0069a0a324c5a750fcc8c2bf13ce11a37d8087 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Mon, 26 Jun 2023 15:05:05 +0000 Subject: [PATCH 01/29] feat: server --- .github/workflows/host.yml | 2 +- package.json | 12 +- scripts/build.js | 18 +- src/{index.ts => bot.ts} | 0 src/commands/debug.ts | 2 +- src/commands/help.ts | 2 +- src/core/blitz/wargamingError.ts | 2 +- src/core/blitzstars/blitzStarsError.ts | 2 +- src/events/error.ts | 2 +- src/server.ts | 7 + yarn.lock | 476 ++++++++++++++++++++++++- 11 files changed, 504 insertions(+), 21 deletions(-) rename src/{index.ts => bot.ts} (100%) create mode 100644 src/server.ts diff --git a/.github/workflows/host.yml b/.github/workflows/host.yml index d637da4f6..b4bc3c4bd 100644 --- a/.github/workflows/host.yml +++ b/.github/workflows/host.yml @@ -35,4 +35,4 @@ jobs: unzip dist.zip - name: Run index.cjs - run: NODE_ENV=production DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ secrets.WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings index.cjs + run: NODE_ENV=production DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ secrets.WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings bot.cjs diff --git a/package.json b/package.json index 22972cbae..feb01e488 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "blitzkrieg", - "version": "1.7.7", + "version": "1.9.0", "description": "", "main": "src/index.ts", "type": "module", "scripts": { - "dev": "yarn build:raw --dev && yarn start --dev", - "start": "node --enable-source-maps --trace-warnings dist/index.cjs", + "dev:bot": "yarn build:bot --dev && yarn start --dev", + "start": "node --enable-source-maps --trace-warnings dist/bot.cjs", "zip": "zip -r dist.zip dist", - "build:raw": "node scripts/build", - "build": "yarn lint && yarn build:raw", + "build:bot": "node scripts/build --bot", + "build": "yarn lint && yarn build:bot", "lint": "tsc" }, "license": "MIT", @@ -19,6 +19,7 @@ "bepaint": "^0.1.0-beta.3", "discord.js": "^14.9.0", "escape-html": "^1.0.3", + "express": "^4.18.2", "fuzzysort": "^2.0.4", "lodash": "^4.17.21", "markdown-escape": "^2.0.0", @@ -28,6 +29,7 @@ "devDependencies": { "@total-typescript/ts-reset": "^0.4.2", "@types/escape-html": "^1.0.2", + "@types/express": "^4.17.17", "@types/lodash": "^4.14.195", "@types/markdown-escape": "^1.1.0", "@types/node": "^20.2.1", diff --git a/scripts/build.js b/scripts/build.js index afeb9b893..575ad8c1b 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -2,17 +2,15 @@ import { build } from 'esbuild'; import { rmSync } from 'fs'; import { argv } from 'process'; -const isDev = argv.includes('--dev'); -const isProd = !isDev; +const isProd = !argv.includes('--dev'); +const buildAll = argv.includes('--build=all'); +const buildBot = argv.includes('--build=bot') | buildAll; +const buildServer = argv.includes('--build=server') | buildAll; console.log('Removing dist...'); rmSync('dist', { recursive: true, force: true }); -console.log('Building...'); -build({ - entryPoints: ['src/index.ts'], - outfile: 'dist/index.cjs', - +const commonOptions = { platform: 'node', loader: { '.node': 'copy', @@ -26,4 +24,10 @@ build({ minifyWhitespace: isProd, logLevel: isProd ? 'info' : 'silent', +}; + +console.log('Building...'); +build({ + entryPoints: ['src/bot.ts'], + outfile: 'dist/bot.cjs', }); diff --git a/src/index.ts b/src/bot.ts similarity index 100% rename from src/index.ts rename to src/bot.ts diff --git a/src/commands/debug.ts b/src/commands/debug.ts index 32a7ba4a2..f32d66ff9 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -1,12 +1,12 @@ import { SlashCommandBuilder } from 'discord.js'; import packageJSON from '../../package.json' assert { type: 'json' }; +import { client } from '../bot.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cleanTable from '../core/interaction/cleanTable.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; import getClientId from '../core/process/getClientId.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; -import { client } from '../index.js'; const executionStart = new Date().getTime(); diff --git a/src/commands/help.ts b/src/commands/help.ts index cecaa41f8..08ba3ca10 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,12 +1,12 @@ import { SlashCommandBuilder } from 'discord.js'; import discord from '../../discord.json' assert { type: 'json' }; +import { client } from '../bot.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; import { CommandRegistry, guildCommands, publicCommands, } from '../events/interactionCreate/index.js'; -import { client } from '../index.js'; export default { inProduction: true, diff --git a/src/core/blitz/wargamingError.ts b/src/core/blitz/wargamingError.ts index e9e8258aa..f27b0092e 100644 --- a/src/core/blitz/wargamingError.ts +++ b/src/core/blitz/wargamingError.ts @@ -3,9 +3,9 @@ import { ChatInputCommandInteraction, EmbedBuilder, } from 'discord.js'; +import { client } from '../../bot.js'; import { NEGATIVE_COLOR } from '../../constants/colors.js'; import { handleError } from '../../events/error.js'; -import { client } from '../../index.js'; export default async function wargamingError( interaction: ChatInputCommandInteraction, diff --git a/src/core/blitzstars/blitzStarsError.ts b/src/core/blitzstars/blitzStarsError.ts index 9f2b8443c..113f4947f 100644 --- a/src/core/blitzstars/blitzStarsError.ts +++ b/src/core/blitzstars/blitzStarsError.ts @@ -3,9 +3,9 @@ import { ChatInputCommandInteraction, EmbedBuilder, } from 'discord.js'; +import { client } from '../../bot.js'; import { NEGATIVE_COLOR } from '../../constants/colors.js'; import { handleError } from '../../events/error.js'; -import { client } from '../../index.js'; export default async function blitzStarsError( interaction: ChatInputCommandInteraction, diff --git a/src/events/error.ts b/src/events/error.ts index 117182ded..ee73d6fdc 100644 --- a/src/events/error.ts +++ b/src/events/error.ts @@ -1,8 +1,8 @@ import { EmbedBuilder, TextChannel } from 'discord.js'; import discord from '../../discord.json' assert { type: 'json' }; +import { client } from '../bot.js'; import { NEGATIVE_COLOR } from '../constants/colors.js'; import isDev from '../core/process/isDev.js'; -import { client } from '../index.js'; const PROCESS_ERROR_EVENTS = ['uncaughtException']; const CLIENT_ERROR_EVENTS = ['error']; diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 000000000..f442940f6 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,7 @@ +import express from 'express'; + +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!'); +}); diff --git a/yarn.lock b/yarn.lock index 630e9a2cd..a3fc8053d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -290,11 +290,51 @@ resolved "https://registry.yarnpkg.com/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz#c564c173ba09973968e1046c93965b7a257878a4" integrity sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A== +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + "@types/escape-html@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.2.tgz#072b7b13784fb3cee9c2450c22f36405983f5e3c" integrity sha512-gaBLT8pdcexFztLSPRtriHeXY/Kn4907uOCZ4Q3lncFBkheAWOuNt53ypsF8szgxbEJ513UeBzcf4utN0EzEwA== +"@types/express-serve-static-core@^4.17.33": + version "4.17.35" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^4.17.17": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-errors@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" + integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== + "@types/lodash@^4.14.195": version "4.14.195" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" @@ -305,6 +345,16 @@ resolved "https://registry.yarnpkg.com/@types/markdown-escape/-/markdown-escape-1.1.0.tgz#8bd940d6701880eb7229467542c029bc05a7b22f" integrity sha512-bJZh73L6fSt8MmTON/btR8hiKRipoIoPfLO41lxr6l65QXdG1rwUjR8Hu5xU7XYHBwKHiJZ+sTQ8L2TKkQrBpw== +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/node@*", "@types/node@^20.2.1": version "20.3.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.0.tgz#719498898d5defab83c3560f45d8498f58d11938" @@ -315,6 +365,16 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + "@types/react@^18.2.7": version "18.2.11" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.11.tgz#168f7dbb421ed214fcf8c5fe8e587765a3e02fd1" @@ -329,6 +389,23 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== +"@types/send@*": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" + integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== + dependencies: + "@types/http-errors" "*" + "@types/mime" "*" + "@types/node" "*" + "@types/ws@^8.5.4": version "8.5.5" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" @@ -341,6 +418,19 @@ resolved "https://registry.yarnpkg.com/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz#84c5a3f8d648842cec5cc649b88df599af32ed88" integrity sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ== +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + base64-js@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" @@ -351,6 +441,24 @@ bepaint@^0.1.0-beta.3: resolved "https://registry.yarnpkg.com/bepaint/-/bepaint-0.1.0-beta.3.tgz#fe8f0d20e35da075a6ed69f42d61156d985da584" integrity sha512-rybuEo674bEal5QUm/qO9jok3TptyRH2bdHDheFO25fw+HCBic5Oiy+ZWnOFnROCGZQy2Zcw7po4KrKSxz02Pg== +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + busboy@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -358,6 +466,19 @@ busboy@^1.6.0: dependencies: streamsearch "^1.1.0" +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + camelize@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" @@ -368,6 +489,28 @@ color-name@^1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + css-background-parser@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/css-background-parser/-/css-background-parser-0.1.0.tgz#48a17f7fe6d4d4f1bca3177ddf16c5617950741b" @@ -397,6 +540,23 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + discord-api-types@^0.37.41: version "0.37.43" resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.43.tgz#94ae2b949e3aa092f5e93b0f3cf8e6620583749c" @@ -422,11 +582,21 @@ discord.js@^14.9.0: undici "^5.22.0" ws "^8.13.0" +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + emoji-regex@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f" integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA== +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + esbuild@^0.17.19: version "0.17.19" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955" @@ -455,11 +625,53 @@ esbuild@^0.17.19: "@esbuild/win32-ia32" "0.17.19" "@esbuild/win32-x64" "0.17.19" -escape-html@^1.0.3: +escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express@^4.18.2: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -479,26 +691,104 @@ file-type@^18.3.0: strtok3 "^7.0.0" token-types "^5.0.1" +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + fuzzysort@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-2.0.4.tgz#a21d1ce8947eaf2797dc3b7c28c36db9d1165f84" integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw== +get-intrinsic@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hex-rgb@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776" integrity sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -inherits@^2.0.3: +inherits@2.0.4, inherits@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -534,6 +824,65 @@ markdown-escape@^2.0.0: resolved "https://registry.yarnpkg.com/markdown-escape/-/markdown-escape-2.0.0.tgz#44484d30d7845b91575c77fd8898f23a0a6f890c" integrity sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A== +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + pako@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" @@ -547,6 +896,16 @@ parse-css-color@^0.2.1: color-name "^1.1.4" hex-rgb "^4.1.0" +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + peek-readable@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec" @@ -557,6 +916,36 @@ postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -580,11 +969,16 @@ readable-web-to-node-stream@^3.0.2: dependencies: readable-stream "^3.6.0" -safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + satori@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/satori/-/satori-0.9.1.tgz#59380f59be44ff825e58b5e2c8d0598240e15365" @@ -600,6 +994,54 @@ satori@^0.9.1: postcss-value-parser "^4.2.0" yoga-wasm-web "^0.3.3" +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" @@ -630,6 +1072,11 @@ tiny-inflate@^1.0.0: resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + token-types@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4" @@ -648,6 +1095,14 @@ tslib@^2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + typescript@^5.0.4: version "5.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" @@ -668,11 +1123,26 @@ unicode-trie@^2.0.0: pako "^0.2.5" tiny-inflate "^1.0.0" +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + ws@^8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" From 8dd0ca9d10ca2899193f9b84576208ac697b9137 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Mon, 26 Jun 2023 17:25:28 +0000 Subject: [PATCH 02/29] feat: svg responses --- .vscode/settings.json | 1 + package.json | 11 +++++---- scripts/build.js | 21 ++++++++++++++---- src/core/ui/jsxToSvg.ts | 42 +++++++++++++++++++++++++++++++++++ src/core/ui/render.tsx | 49 +++++------------------------------------ src/core/ui/svgToPng.ts | 5 +++++ src/server.ts | 15 +++++++++++-- 7 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 src/core/ui/jsxToSvg.ts create mode 100644 src/core/ui/svgToPng.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index de2d6290e..f17372342 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "playerachievements", "playerinfo", "Resvg", + "roboto", "searchclans", "searchplayers", "searchtanks", diff --git a/package.json b/package.json index feb01e488..ee84e10c7 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,14 @@ "main": "src/index.ts", "type": "module", "scripts": { - "dev:bot": "yarn build:bot --dev && yarn start --dev", - "start": "node --enable-source-maps --trace-warnings dist/bot.cjs", - "zip": "zip -r dist.zip dist", - "build:bot": "node scripts/build --bot", + "build:bot": "node scripts/build --build=bot", + "build:server": "node scripts/build --build=server", "build": "yarn lint && yarn build:bot", + "dev:bot": "yarn build:bot --dev && yarn start:bot --dev", + "dev:server": "yarn build:server --dev && yarn start:server --dev", + "start:bot": "node --enable-source-maps --trace-warnings dist/bot.cjs", + "start:server": "node --enable-source-maps --trace-warnings dist/server.cjs", + "zip": "zip -r dist.zip dist", "lint": "tsc" }, "license": "MIT", diff --git a/scripts/build.js b/scripts/build.js index 575ad8c1b..d2161ac2e 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -27,7 +27,20 @@ const commonOptions = { }; console.log('Building...'); -build({ - entryPoints: ['src/bot.ts'], - outfile: 'dist/bot.cjs', -}); +if (buildBot) { + build({ + ...commonOptions, + + entryPoints: ['src/bot.ts'], + outfile: 'dist/bot.cjs', + }); +} + +if (buildServer) { + build({ + ...commonOptions, + + entryPoints: ['src/server.ts'], + outfile: 'dist/server.cjs', + }); +} diff --git a/src/core/ui/jsxToSvg.ts b/src/core/ui/jsxToSvg.ts new file mode 100644 index 000000000..5c6aa1290 --- /dev/null +++ b/src/core/ui/jsxToSvg.ts @@ -0,0 +1,42 @@ +import { readFile } from 'fs'; +import { join } from 'path'; +import satori from 'satori'; +import robotoBlackFile from '../../assets/fonts/Roboto-Black.ttf'; +import robotoBoldFile from '../../assets/fonts/Roboto-Bold.ttf'; +import robotoFile from '../../assets/fonts/Roboto.ttf'; + +const FONT_NAME = 'Roboto'; +const FONT_FILES = [robotoFile, robotoBoldFile, robotoBlackFile]; + +let roboto: Buffer; +let robotoBold: Buffer; +let robotoBlack: Buffer; + +console.log('Importing fonts...'); +Promise.all( + FONT_FILES.map( + (file) => + new Promise((resolve, reject) => { + const path = join(__dirname, file); + + readFile(path, (error, data) => { + if (error) reject(error); + resolve(data); + }); + }), + ), +).then((data) => { + [roboto, robotoBold, robotoBlack] = data; + console.log('Fonts imported'); +}); + +export default async function jsxToSvg(jsx: JSX.Element) { + return await satori(jsx, { + width: 640, + fonts: [ + { data: roboto, name: FONT_NAME, weight: 400 }, + { data: robotoBold, name: FONT_NAME, weight: 700 }, + { data: robotoBlack, name: FONT_NAME, weight: 900 }, + ], + }); +} diff --git a/src/core/ui/render.tsx b/src/core/ui/render.tsx index 19ba744b1..ae00848bc 100644 --- a/src/core/ui/render.tsx +++ b/src/core/ui/render.tsx @@ -1,48 +1,9 @@ -import { Resvg } from '@resvg/resvg-js'; -import { readFile } from 'fs'; -import { join } from 'path'; -import { ReactNode } from 'react'; -import satori from 'satori'; -import robotoBlackFile from '../../assets/fonts/Roboto-Black.ttf'; -import robotoBoldFile from '../../assets/fonts/Roboto-Bold.ttf'; -import robotoFile from '../../assets/fonts/Roboto.ttf'; +import jsxToSvg from './jsxToSvg.js'; +import svgToPng from './svgToPng.js'; -const FONT_NAME = 'Roboto'; -const FONT_FILES = [robotoFile, robotoBoldFile, robotoBlackFile]; - -let roboto: Buffer; -let robotoBold: Buffer; -let robotoBlack: Buffer; - -console.log('Importing fonts...'); -Promise.all( - FONT_FILES.map( - (file) => - new Promise((resolve, reject) => { - const path = join(__dirname, file); - - readFile(path, (error, data) => { - if (error) reject(error); - resolve(data); - }); - }), - ), -).then((data) => { - [roboto, robotoBold, robotoBlack] = data; - console.log('Fonts imported'); -}); - -export default async function render(element: ReactNode) { - const svg = await satori(element, { - width: 640, - fonts: [ - { data: roboto, name: FONT_NAME, weight: 400 }, - { data: robotoBold, name: FONT_NAME, weight: 700 }, - { data: robotoBlack, name: FONT_NAME, weight: 900 }, - ], - }); - - const png = new Resvg(svg).render().asPng(); +export default async function render(jsx: JSX.Element) { + const svg = await jsxToSvg(jsx); + const png = svgToPng(svg); return png; } diff --git a/src/core/ui/svgToPng.ts b/src/core/ui/svgToPng.ts new file mode 100644 index 000000000..3a221097d --- /dev/null +++ b/src/core/ui/svgToPng.ts @@ -0,0 +1,5 @@ +import { Resvg } from "@resvg/resvg-js"; + +export default function svgToPng(svg: string) { + return new Resvg(svg).render().asPng() +} \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index f442940f6..857cc4937 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,7 +1,18 @@ import express from 'express'; +import jsxToSvg from './core/ui/jsxToSvg.js'; +import today from './renderers/today.js'; const app = express(); -app.get('/', (req, res) => { - res.send('Hello World!'); +app.get('/', async (req, res) => { + const jsx = await today({ server: 'com', id: 1028700193 }); + const svg = await jsxToSvg(jsx); + + res.writeHead(200, { + 'Content-Type': 'image/svg+xml', + 'Content-Length': svg.length, + }); + res.end(svg); }); + +app.listen(process.env.PORT || 3000); From 79343438f0d157ce1de8fdba5b766fde30d09d8e Mon Sep 17 00:00:00 2001 From: tresabhi Date: Mon, 26 Jun 2023 17:36:43 +0000 Subject: [PATCH 03/29] feat: cleaned up build proccess --- package.json | 6 +++--- src/core/options/resolvePeriod.ts | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ee84e10c7..cc3539319 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "main": "src/index.ts", "type": "module", "scripts": { - "build:bot": "node scripts/build --build=bot", - "build:server": "node scripts/build --build=server", - "build": "yarn lint && yarn build:bot", + "build:bot": "yarn lint && node scripts/build --build=bot", + "build:server": "yarn lint && node scripts/build --build=server", + "build": "yarn lint && node scripts/build --build=all", "dev:bot": "yarn build:bot --dev && yarn start:bot --dev", "dev:server": "yarn build:server --dev && yarn start:server --dev", "start:bot": "node --enable-source-maps --trace-warnings dist/bot.cjs", diff --git a/src/core/options/resolvePeriod.ts b/src/core/options/resolvePeriod.ts index 18045401b..b8a2c5c4d 100644 --- a/src/core/options/resolvePeriod.ts +++ b/src/core/options/resolvePeriod.ts @@ -43,6 +43,16 @@ export default function resolvePeriod( let evolutionName: string; let start: number; let end: number; + let url: URL; + let period: Period; + + if (interaction instanceof ChatInputCommandInteraction) { + period = interaction.options.getSubcommand() as Period; + } else { + url = new URL(`${CYCLIC_API}/${interaction.customId}`); + const path = url.pathname.split('/').filter(Boolean); + period = path[path.length - 1] as Period; + } if (period === 'custom') { const startRaw = From 0f46f333b5dd3018294d1c27a5148ce9c2eb05ad Mon Sep 17 00:00:00 2001 From: tresabhi Date: Mon, 26 Jun 2023 18:08:07 +0000 Subject: [PATCH 04/29] feat: cache tankopedia and tankaverages during build --- .vscode/settings.json | 1 + package.json | 4 +-- scripts/build.js | 42 ++++++++++++++++++++++++++--- src/core/blitz/tankopedia.ts | 36 ++++++++----------------- src/core/blitzstars/tankAverages.ts | 16 +++++------ src/core/process/isDev.ts | 2 -- src/server.ts | 2 +- 7 files changed, 59 insertions(+), 44 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f17372342..68ad53f7a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,6 +21,7 @@ "Smri", "startcase", "strvk", + "tankaverages", "tankopedia", "tankstats", "Unicum", diff --git a/package.json b/package.json index cc3539319..fcafaa25d 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "src/index.ts", "type": "module", "scripts": { - "build:bot": "yarn lint && node scripts/build --build=bot", - "build:server": "yarn lint && node scripts/build --build=server", + "build:bot": "node scripts/build --build=bot", + "build:server": "node scripts/build --build=server", "build": "yarn lint && node scripts/build --build=all", "dev:bot": "yarn build:bot --dev && yarn start:bot --dev", "dev:server": "yarn build:server --dev && yarn start:server --dev", diff --git a/scripts/build.js b/scripts/build.js index d2161ac2e..9f56eafc5 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,5 +1,5 @@ import { build } from 'esbuild'; -import { rmSync } from 'fs'; +import { mkdirSync, rmSync, writeFileSync } from 'fs'; import { argv } from 'process'; const isProd = !argv.includes('--dev'); @@ -7,8 +7,37 @@ const buildAll = argv.includes('--build=all'); const buildBot = argv.includes('--build=bot') | buildAll; const buildServer = argv.includes('--build=server') | buildAll; -console.log('Removing dist...'); -rmSync('dist', { recursive: true, force: true }); +if (isProd) { + // only remove in production to ensure no time is wasted in dev + console.log('Removing dist...'); + rmSync('dist', { recursive: true, force: true }); + + console.log('Creating dist...'); + mkdirSync('dist'); + + console.log('Caching tankopedia...'); + fetch('https://www.blitzstars.com/bs-tankopedia.json') + .then((response) => response.text()) + .then((tankopedia) => { + writeFileSync('./dist/tankopedia.json', tankopedia); + console.log('Tankopedia cached'); + }); + + console.log('Caching tank averages...'); + fetch('https://www.blitzstars.com/api/tankaverages.json') + .then((response) => response.json()) + .then((individualTankAverages) => { + const tankAverages = {}; + + individualTankAverages.forEach((individualTankAverage) => { + tankAverages[individualTankAverage.tank_id] = individualTankAverage; + }); + + writeFileSync('./dist/tankaverages.json', JSON.stringify(tankAverages)); + + console.log('Tank averages cached'); + }); +} const commonOptions = { platform: 'node', @@ -26,21 +55,26 @@ const commonOptions = { logLevel: isProd ? 'info' : 'silent', }; -console.log('Building...'); if (buildBot) { + console.log('Building bot...'); build({ ...commonOptions, entryPoints: ['src/bot.ts'], outfile: 'dist/bot.cjs', + }).then(() => { + console.log('Bot built'); }); } if (buildServer) { + console.log('Building server...'); build({ ...commonOptions, entryPoints: ['src/server.ts'], outfile: 'dist/server.cjs', + }).then(() => { + console.log('Server built'); }); } diff --git a/src/core/blitz/tankopedia.ts b/src/core/blitz/tankopedia.ts index a79aa6411..6e0b2678e 100644 --- a/src/core/blitz/tankopedia.ts +++ b/src/core/blitz/tankopedia.ts @@ -1,4 +1,5 @@ -import { WargamingResponse } from '../../types/wargamingResponse.js'; +import { readFileSync } from 'fs'; +import { join } from 'path'; export type TankType = 'AT-SPG' | 'lightTank' | 'mediumTank' | 'heavyTank'; @@ -18,30 +19,15 @@ export interface Tankopedia { [id: number]: TankopediaEntry; } -export const tankopedia: Tankopedia = {}; -export const TANK_IDS: number[] = []; -export const TANKS: TankopediaEntry[] = []; -export const TANK_NAMES: string[] = []; - -console.log('Caching tankopedia...'); -fetch('https://www.blitzstars.com/bs-tankopedia.json') - .then( - (response) => - response.json() as Promise< - WargamingResponse & { status: 'ok' } - >, - ) - .then((wargamingResponse) => { - Object.assign(tankopedia, wargamingResponse.data); - Object.entries(tankopedia).forEach(([idString, entry]) => { - const id = Number(idString); - - TANK_IDS.push(id); - TANKS.push(entry); - TANK_NAMES.push(entry.name); - }), - console.log('Cached tankopedia'); - }); +export const tankopedia = ( + JSON.parse( + readFileSync(join(__dirname, 'tankopedia.json')) as unknown as string, + ) as { data: Tankopedia } +).data; +const entries = Object.entries(tankopedia); +export const TANK_IDS = entries.map(([, { tank_id }]) => tank_id as number); +export const TANKS = entries.map(([, entry]) => entry as TankopediaEntry); +export const TANK_NAMES = entries.map(([, { name }]) => name); export const TANK_ICONS: Record = { 'AT-SPG': 'https://i.imgur.com/BIHSEH0.png', diff --git a/src/core/blitzstars/tankAverages.ts b/src/core/blitzstars/tankAverages.ts index 747f5a449..b5858a13b 100644 --- a/src/core/blitzstars/tankAverages.ts +++ b/src/core/blitzstars/tankAverages.ts @@ -1,3 +1,5 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; import { AllStats } from '../../types/accountInfo.js'; export interface SpecialStats { @@ -78,14 +80,8 @@ export interface IndividualTankAverage { last_update: number; } -export const tankAverages: Record = {}; +export type TankAverages = Record; -console.log('Caching tank averages...'); -fetch('https://www.blitzstars.com/api/tankaverages.json') - .then((response) => response.json() as Promise) - .then((individualTankAverages) => { - individualTankAverages.forEach((individualTankAverage) => { - tankAverages[individualTankAverage.tank_id] = individualTankAverage; - }); - console.log('Tank averages cached'); - }); +export const tankAverages = JSON.parse( + readFileSync(join(__dirname, 'tankaverages.json')) as unknown as string, +) as TankAverages; diff --git a/src/core/process/isDev.ts b/src/core/process/isDev.ts index 71a694792..3a6db04c9 100644 --- a/src/core/process/isDev.ts +++ b/src/core/process/isDev.ts @@ -3,5 +3,3 @@ const isDevBoolean = process.env.NODE_ENV === 'development'; export default function isDev() { return isDevBoolean; } - -console.log(process.env.NODE_ENV); diff --git a/src/server.ts b/src/server.ts index 857cc4937..099ce5b56 100644 --- a/src/server.ts +++ b/src/server.ts @@ -15,4 +15,4 @@ app.get('/', async (req, res) => { res.end(svg); }); -app.listen(process.env.PORT || 3000); +app.listen(process.env.PORT ?? 3000); From f2ae6984380ee2e50f9af9252b9eb7e881a4defa Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 01:43:30 +0000 Subject: [PATCH 05/29] feat: express responses --- src/bot.ts | 2 +- src/commands/debug.ts | 4 +- src/commands/eligible.ts | 4 +- src/commands/evolution.tsx | 6 +-- src/commands/help.ts | 2 +- src/commands/inactive.tsx | 4 +- src/commands/ownedtanks.tsx | 4 +- src/commands/ping.ts | 2 +- src/commands/playerachievements.ts | 4 +- src/commands/playerinfo.ts | 4 +- src/commands/searchclans.ts | 4 +- src/commands/searchplayers.ts | 4 +- src/commands/searchtanks.ts | 2 +- src/commands/stats.tsx | 8 ++-- src/commands/today.tsx | 2 +- src/commands/verify.ts | 4 +- src/components/GenericAllStats.tsx | 2 +- src/components/TitleBar.tsx | 2 +- src/core/blitz/getBlitzClan.ts | 2 +- src/core/blitz/getTankStats.ts | 4 +- src/core/blitz/getWargamingResponse.ts | 2 +- src/core/blitz/listAccountsPanServer.ts | 2 +- src/core/blitz/listClansPanServer.ts | 2 +- src/core/blitz/resolveTankId.ts | 2 +- src/core/blitzstars/getPlayerHistories.ts | 2 +- .../express/normalizeResponderReturnable.ts | 11 +++++ .../resolvePeriodFromCommand.ts} | 28 ++++++++----- src/core/{process => node}/args.ts | 0 src/core/{process => node}/errorWithCause.ts | 0 src/core/{process => node}/getClientId.ts | 0 src/core/{process => node}/isDev.ts | 0 src/core/{process => node}/isNumber.ts | 0 src/core/{process => node}/psa.ts | 0 src/core/options/addPeriodSubCommands.ts | 2 +- src/core/options/resolvePlayer.ts | 2 +- src/events/error.ts | 2 +- .../handlers/chatInputCommand.ts | 10 ++--- src/events/interactionCreate/index.ts | 31 +++++++------- src/events/ready.ts | 2 +- src/renderers/evolution.tsx | 4 +- src/renderers/stats.tsx | 4 +- src/renderers/today.tsx | 2 +- src/responders/stats.tsx | 24 +++++++++++ src/server.ts | 42 ++++++++++++++----- tsconfig.json | 2 +- 45 files changed, 153 insertions(+), 93 deletions(-) create mode 100644 src/core/express/normalizeResponderReturnable.ts rename src/core/{options/resolvePeriod.ts => interaction/resolvePeriodFromCommand.ts} (75%) rename src/core/{process => node}/args.ts (100%) rename src/core/{process => node}/errorWithCause.ts (100%) rename src/core/{process => node}/getClientId.ts (100%) rename src/core/{process => node}/isDev.ts (100%) rename src/core/{process => node}/isNumber.ts (100%) rename src/core/{process => node}/psa.ts (100%) create mode 100644 src/responders/stats.tsx diff --git a/src/bot.ts b/src/bot.ts index 823467025..a8a7c9cca 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,5 +1,5 @@ import { Client, GatewayIntentBits } from 'discord.js'; -import { DISCORD_TOKEN } from './core/process/args.js'; +import { DISCORD_TOKEN } from './core/node/args.js'; import { registerErrorHandlers } from './events/error.js'; import guildMemberAdd from './events/guildMemberAdd.js'; import interactionCreate from './events/interactionCreate/index.js'; diff --git a/src/commands/debug.ts b/src/commands/debug.ts index f32d66ff9..ff8d654c0 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -5,7 +5,7 @@ import { tankopedia } from '../core/blitz/tankopedia.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cleanTable from '../core/interaction/cleanTable.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; -import getClientId from '../core/process/getClientId.js'; +import getClientId from '../core/node/getClientId.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; const executionStart = new Date().getTime(); @@ -19,7 +19,7 @@ export default { .setName('debug') .setDescription('Debug information about the bot'), - execute(interaction) { + handler(interaction) { const currentTime = new Date().getTime(); const uptime = currentTime - executionStart; diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index bd038a85a..0a65fa1e0 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -10,9 +10,9 @@ import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cleanTable, { TableInput } from '../core/interaction/cleanTable.js'; import negativeEmbed from '../core/interaction/negativeEmbed.js'; import positiveEmbed from '../core/interaction/positiveEmbed.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -46,7 +46,7 @@ export default { ) .addStringOption(addUsernameOption), - async execute(interaction) { + async handler(interaction) { const clan = interaction.options.getString('clan') as SkilledClan; const { id, server } = await resolvePlayer(interaction); const accountInfo = await getWargamingResponse( diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 318cf28d3..3d94f5883 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -2,8 +2,8 @@ import { SlashCommandBuilder } from 'discord.js'; import tanksAutocomplete from '../core/autocomplete/tanks.js'; import usernameAutocomplete from '../core/autocomplete/username.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; +import resolvePeriodFromCommand from '../core/interaction/resolvePeriodFromCommand.js'; import addStatsSubCommandGroups from '../core/options/addStatsSubCommandGroups.js'; -import resolvePeriod from '../core/options/resolvePeriod.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import evolution from '../renderers/evolution.js'; @@ -20,12 +20,12 @@ export default { .setDescription('Evolution of statistics'), ), - async execute(interaction) { + async handler(interaction) { const commandGroup = interaction.options.getSubcommandGroup( true, ) as StatType; const player = await resolvePlayer(interaction); - const period = resolvePeriod(interaction); + const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; diff --git a/src/commands/help.ts b/src/commands/help.ts index 08ba3ca10..0b178aa8d 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -17,7 +17,7 @@ export default { .setName('help') .setDescription('All the help you need about the bot'), - execute(interaction) { + handler(interaction) { return infoEmbed( `${client.user?.username} help`, `**About**\n${ diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index 4a45dc54a..36ce1fe63 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -8,8 +8,8 @@ import { BLITZ_SERVERS } from '../constants/servers.js'; import clanAutocomplete from '../core/autocomplete/clan.js'; import getBlitzClan from '../core/blitz/getBlitzClan.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addClanChoices from '../core/options/addClanChoices.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { ClanInfo } from '../types/clanInfo.js'; @@ -34,7 +34,7 @@ export default { .setMinValue(0), ), - async execute(interaction) { + async handler(interaction) { const clanName = interaction.options.getString('clan')!; const { server, id } = await getBlitzClan(interaction, clanName); const threshold = diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedtanks.tsx index 14b0dfc52..ff41e146a 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedtanks.tsx @@ -13,9 +13,9 @@ import { Tier, tankopedia, } from '../core/blitz/tankopedia.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; @@ -69,7 +69,7 @@ export default { ) .addStringOption(addUsernameOption), - async execute(interaction) { + async handler(interaction) { const tier = Number(interaction.options.getString('tier')); const account = await resolvePlayer(interaction); const { id, server } = account; diff --git a/src/commands/ping.ts b/src/commands/ping.ts index dd0b41471..6c99eda61 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -17,7 +17,7 @@ export default { option.setName('blitz').setDescription('Ping Blitz'), ), - async execute(interaction) { + async handler(interaction) { const subcommand = interaction.options.getSubcommand(); const executionStart = Date.now(); diff --git a/src/commands/playerachievements.ts b/src/commands/playerachievements.ts index 43b888103..258fd6f23 100644 --- a/src/commands/playerachievements.ts +++ b/src/commands/playerachievements.ts @@ -5,9 +5,9 @@ import usernameAutocomplete from '../core/autocomplete/username.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import cleanTable, { TableInputEntry } from '../core/interaction/cleanTable.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountAchievements } from '../types/accountAchievements.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -33,7 +33,7 @@ export default { ), ), - async execute(interaction) { + async handler(interaction) { const sortBy = (interaction.options.getString('sort') ?? 'name') as SortBy; const account = await resolvePlayer(interaction); const { id, server } = account; diff --git a/src/commands/playerinfo.ts b/src/commands/playerinfo.ts index f7dfde492..287e17d15 100644 --- a/src/commands/playerinfo.ts +++ b/src/commands/playerinfo.ts @@ -4,9 +4,9 @@ import usernameAutocomplete from '../core/autocomplete/username.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import cleanTable from '../core/interaction/cleanTable.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -20,7 +20,7 @@ export default { .setDescription('Basic information about a player') .addStringOption(addUsernameOption), - async execute(interaction) { + async handler(interaction) { const account = await resolvePlayer(interaction); const { id, server } = account; const accounts = await getWargamingResponse( diff --git a/src/commands/searchclans.ts b/src/commands/searchclans.ts index 5e005d6f1..bb5f2cf39 100644 --- a/src/commands/searchclans.ts +++ b/src/commands/searchclans.ts @@ -3,9 +3,9 @@ import markdownEscape from 'markdown-escape'; import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addClanChoices from '../core/options/addClanChoices.js'; import addServerChoices from '../core/options/addServerChoices.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { ClanList } from '../types/clanList.js'; @@ -27,7 +27,7 @@ export default { .setMaxValue(100), ), - async execute(interaction) { + async handler(interaction) { const server = interaction.options.getString('server') as BlitzServer; const clan = interaction.options.getString('clan')!; const limit = interaction.options.getInteger('limit') ?? 25; diff --git a/src/commands/searchplayers.ts b/src/commands/searchplayers.ts index d9b1ea2c7..4852d4b8d 100644 --- a/src/commands/searchplayers.ts +++ b/src/commands/searchplayers.ts @@ -4,9 +4,9 @@ import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import { usernamePattern } from '../core/blitz/listAccountsPanServer.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addServerChoices from '../core/options/addServerChoices.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountList } from '../types/accountList.js'; @@ -30,7 +30,7 @@ export default { .setMaxValue(100), ), - async execute(interaction) { + async handler(interaction) { const server = interaction.options.getString('server') as BlitzServer; const name = interaction.options.getString('username')!; const limit = interaction.options.getInteger('limit') ?? 25; diff --git a/src/commands/searchtanks.ts b/src/commands/searchtanks.ts index bb4260b88..38c2c0d93 100644 --- a/src/commands/searchtanks.ts +++ b/src/commands/searchtanks.ts @@ -23,7 +23,7 @@ export default { .setMaxValue(100), ), - async execute(interaction) { + async handler(interaction) { const tank = interaction.options.getString('tank')!; const limit = interaction.options.getInteger('limit') ?? 25; const results = go(tank, TANK_NAMES, { limit }).map( diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index f036f0239..9c04f5370 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -6,9 +6,9 @@ import resolveTankId from '../core/blitz/resolveTankId.js'; import interactionToURL from '../core/interaction/interactionToURL.js'; import linkButton from '../core/interaction/linkButton.js'; import primaryButton from '../core/interaction/primaryButton.js'; +import resolvePeriodFromCommand from '../core/interaction/resolvePeriodFromCommand.js'; import { Period } from '../core/options/addPeriodSubCommands.js'; import addStatsSubCommandGroups from '../core/options/addStatsSubCommandGroups.js'; -import resolvePeriod from '../core/options/resolvePeriod.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import stats, { StatType } from '../renderers/stats.js'; @@ -24,13 +24,13 @@ export default { .setDescription('In-game statistics'), ), - async execute(interaction) { + async handler(interaction) { const commandGroup = interaction.options.getSubcommandGroup( true, ) as StatType; const subcommand = interaction.options.getSubcommand() as Period; const player = await resolvePlayer(interaction); - const period = resolvePeriod(interaction); + const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; const start = interaction.options.getInteger('start'); @@ -57,7 +57,7 @@ export default { const url = new URL(`${CYCLIC_API}/${interaction.customId}`); const path = url.pathname.split('/').filter(Boolean); const commandGroup = path[1] as StatType; - const period = resolvePeriod(interaction); + const period = resolvePeriodFromCommand(interaction); const player = await resolvePlayer(interaction); return await stats( diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 41988e021..2d6c1040a 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -15,7 +15,7 @@ export default { .setDescription('A general daily breakdown of your performance') .addStringOption(addUsernameOption), - async execute(interaction) { + async handler(interaction) { const player = await resolvePlayer(interaction); return await today(player); diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 6d923e032..1ac4e466d 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -5,9 +5,9 @@ import usernameAutocomplete from '../core/autocomplete/username.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import negativeEmbed from '../core/interaction/negativeEmbed.js'; import positiveEmbed from '../core/interaction/positiveEmbed.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; import resolvePlayer from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; @@ -22,7 +22,7 @@ export default { .setDescription("Set's the user's username to their in-game name") .addStringOption((option) => addUsernameOption(option).setRequired(true)), - async execute(interaction) { + async handler(interaction) { const blitzAccount = await resolvePlayer(interaction); const { id, server } = blitzAccount; const accountInfo = await getWargamingResponse( diff --git a/src/components/GenericAllStats.tsx b/src/components/GenericAllStats.tsx index 5374a0801..7fcc64f27 100644 --- a/src/components/GenericAllStats.tsx +++ b/src/components/GenericAllStats.tsx @@ -1,5 +1,5 @@ import getWN8Percentile from '../core/blitz/getWN8Percentile.js'; -import isNumber from '../core/process/isNumber.js'; +import isNumber from '../core/node/isNumber.js'; import { AllStats, SupplementaryStats } from '../types/accountInfo.js'; import GenericStats from './GenericStats/index.js'; diff --git a/src/components/TitleBar.tsx b/src/components/TitleBar.tsx index ead666fa2..0366b4fb1 100644 --- a/src/components/TitleBar.tsx +++ b/src/components/TitleBar.tsx @@ -1,4 +1,4 @@ -import isDev from '../core/process/isDev.js'; +import isDev from '../core/node/isDev.js'; import { theme } from '../stitches.config.js'; export interface TitleBarProps { diff --git a/src/core/blitz/getBlitzClan.ts b/src/core/blitz/getBlitzClan.ts index d511584fc..206aff2fc 100644 --- a/src/core/blitz/getBlitzClan.ts +++ b/src/core/blitz/getBlitzClan.ts @@ -1,7 +1,7 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import { BlitzServer } from '../../constants/servers.js'; +import errorWithCause from '../node/errorWithCause.js'; import { serverAndIdPattern } from '../options/resolvePlayer.js'; -import errorWithCause from '../process/errorWithCause.js'; import listClansPanServer from './listClansPanServer.js'; export default async function getBlitzClan( diff --git a/src/core/blitz/getTankStats.ts b/src/core/blitz/getTankStats.ts index 66d1091d5..5579400bb 100644 --- a/src/core/blitz/getTankStats.ts +++ b/src/core/blitz/getTankStats.ts @@ -1,7 +1,7 @@ import { BLITZ_SERVERS, BlitzServer } from '../../constants/servers.js'; import { TanksStats } from '../../types/tanksStats.js'; -import { WARGAMING_APPLICATION_ID } from '../process/args.js'; -import errorWithCause from '../process/errorWithCause.js'; +import { WARGAMING_APPLICATION_ID } from '../node/args.js'; +import errorWithCause from '../node/errorWithCause.js'; import getWargamingResponse from './getWargamingResponse.js'; export default async function getTankStats(server: BlitzServer, id: number) { diff --git a/src/core/blitz/getWargamingResponse.ts b/src/core/blitz/getWargamingResponse.ts index 59d30f9d5..3d13701ab 100644 --- a/src/core/blitz/getWargamingResponse.ts +++ b/src/core/blitz/getWargamingResponse.ts @@ -1,5 +1,5 @@ import { WargamingResponse } from '../../types/wargamingResponse.js'; -import errorWithCause from '../process/errorWithCause.js'; +import errorWithCause from '../node/errorWithCause.js'; export default async function getWargamingResponse( url: string, diff --git a/src/core/blitz/listAccountsPanServer.ts b/src/core/blitz/listAccountsPanServer.ts index f09069ba7..e608ed77a 100644 --- a/src/core/blitz/listAccountsPanServer.ts +++ b/src/core/blitz/listAccountsPanServer.ts @@ -1,6 +1,6 @@ import { BlitzServer } from '../../constants/servers.js'; import { Account, AccountList } from '../../types/accountList.js'; -import { WARGAMING_APPLICATION_ID } from '../process/args.js'; +import { WARGAMING_APPLICATION_ID } from '../node/args.js'; import getWargamingResponse from './getWargamingResponse.js'; export type AccountListWithServer = (Account & { diff --git a/src/core/blitz/listClansPanServer.ts b/src/core/blitz/listClansPanServer.ts index 2d5fc148c..eb435d1b4 100644 --- a/src/core/blitz/listClansPanServer.ts +++ b/src/core/blitz/listClansPanServer.ts @@ -1,6 +1,6 @@ import { BlitzServer } from '../../constants/servers.js'; import { Clan, ClanList } from '../../types/clanList.js'; -import { WARGAMING_APPLICATION_ID } from '../process/args.js'; +import { WARGAMING_APPLICATION_ID } from '../node/args.js'; import getWargamingResponse from './getWargamingResponse.js'; export type ClanListWithServer = (Clan & { diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index 1364c35c1..6931996ed 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -1,5 +1,5 @@ import { go } from 'fuzzysort'; -import errorWithCause from '../process/errorWithCause.js'; +import errorWithCause from '../node/errorWithCause.js'; import { TANKS, tankopedia } from './tankopedia.js'; export default function resolveTankId(tank: string) { diff --git a/src/core/blitzstars/getPlayerHistories.ts b/src/core/blitzstars/getPlayerHistories.ts index d52cfd151..a99e1d10d 100644 --- a/src/core/blitzstars/getPlayerHistories.ts +++ b/src/core/blitzstars/getPlayerHistories.ts @@ -7,7 +7,7 @@ import { getHistoriesDefaultOptions, } from '../../types/histories.js'; import getWargamingResponse from '../blitz/getWargamingResponse.js'; -import { WARGAMING_APPLICATION_ID } from '../process/args.js'; +import { WARGAMING_APPLICATION_ID } from '../node/args.js'; import { emptyAllStats } from './getTankStatsOverTime.js'; export interface PlayerHistoryRaw { diff --git a/src/core/express/normalizeResponderReturnable.ts b/src/core/express/normalizeResponderReturnable.ts new file mode 100644 index 000000000..d0ffeadab --- /dev/null +++ b/src/core/express/normalizeResponderReturnable.ts @@ -0,0 +1,11 @@ +import { ResponderReturnable } from '../../server.js'; +import jsxToSvg from '../ui/jsxToSvg.js'; + +export default async function normalizeResponderReturnable( + returnable: ResponderReturnable, +) { + const awaitedReturnable = await returnable; + const svg = await jsxToSvg(awaitedReturnable); + + return svg; +} diff --git a/src/core/options/resolvePeriod.ts b/src/core/interaction/resolvePeriodFromCommand.ts similarity index 75% rename from src/core/options/resolvePeriod.ts rename to src/core/interaction/resolvePeriodFromCommand.ts index b8a2c5c4d..2eb25c58e 100644 --- a/src/core/options/resolvePeriod.ts +++ b/src/core/interaction/resolvePeriodFromCommand.ts @@ -3,11 +3,12 @@ import { CacheType, ChatInputCommandInteraction, } from 'discord.js'; +import { Request } from 'express'; import { CYCLIC_API } from '../../constants/cyclic.js'; import getPeriodNow from '../blitzstars/getPeriodNow.js'; import getPeriodStart from '../blitzstars/getPeriodStart.js'; import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo.js'; -import { Period } from './addPeriodSubCommands.js'; +import { Period } from '../options/addPeriodSubCommands.js'; export const PERIOD_NAMES: Record = { today: "Today's statistics", @@ -34,10 +35,11 @@ export interface ResolvedPeriod { end: number; } -export default function resolvePeriod( - interaction: +export default function resolvePeriodFromCommand( + input: | ChatInputCommandInteraction - | ButtonInteraction, + | ButtonInteraction + | Request, ) { let statsName: string; let evolutionName: string; @@ -46,22 +48,26 @@ export default function resolvePeriod( let url: URL; let period: Period; - if (interaction instanceof ChatInputCommandInteraction) { - period = interaction.options.getSubcommand() as Period; + if (input instanceof ChatInputCommandInteraction) { + period = input.options.getSubcommand() as Period; } else { - url = new URL(`${CYCLIC_API}/${interaction.customId}`); + url = new URL( + `${CYCLIC_API}${ + input instanceof ButtonInteraction ? `/${input.customId}` : input.path + }`, + ); const path = url.pathname.split('/').filter(Boolean); period = path[path.length - 1] as Period; } if (period === 'custom') { const startRaw = - interaction instanceof ChatInputCommandInteraction - ? interaction.options.getInteger('start')! + input instanceof ChatInputCommandInteraction + ? input.options.getInteger('start')! : parseInt(url!.searchParams.get('start')!); const endRaw = - interaction instanceof ChatInputCommandInteraction - ? interaction.options.getInteger('end')! + input instanceof ChatInputCommandInteraction + ? input.options.getInteger('end')! : parseInt(url!.searchParams.get('end')!); const startMin = Math.min(startRaw, endRaw); const endMax = Math.max(startRaw, endRaw); diff --git a/src/core/process/args.ts b/src/core/node/args.ts similarity index 100% rename from src/core/process/args.ts rename to src/core/node/args.ts diff --git a/src/core/process/errorWithCause.ts b/src/core/node/errorWithCause.ts similarity index 100% rename from src/core/process/errorWithCause.ts rename to src/core/node/errorWithCause.ts diff --git a/src/core/process/getClientId.ts b/src/core/node/getClientId.ts similarity index 100% rename from src/core/process/getClientId.ts rename to src/core/node/getClientId.ts diff --git a/src/core/process/isDev.ts b/src/core/node/isDev.ts similarity index 100% rename from src/core/process/isDev.ts rename to src/core/node/isDev.ts diff --git a/src/core/process/isNumber.ts b/src/core/node/isNumber.ts similarity index 100% rename from src/core/process/isNumber.ts rename to src/core/node/isNumber.ts diff --git a/src/core/process/psa.ts b/src/core/node/psa.ts similarity index 100% rename from src/core/process/psa.ts rename to src/core/node/psa.ts diff --git a/src/core/options/addPeriodSubCommands.ts b/src/core/options/addPeriodSubCommands.ts index d8d28f2e9..450ea5c69 100644 --- a/src/core/options/addPeriodSubCommands.ts +++ b/src/core/options/addPeriodSubCommands.ts @@ -2,7 +2,7 @@ import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, } from 'discord.js'; -import { PERIOD_NAMES } from './resolvePeriod.js'; +import { PERIOD_NAMES } from '../interaction/resolvePeriodFromCommand.js'; export type Period = 'today' | '30' | '60' | '90' | 'career' | 'custom'; diff --git a/src/core/options/resolvePlayer.ts b/src/core/options/resolvePlayer.ts index 4e2d344d3..003a49e6c 100644 --- a/src/core/options/resolvePlayer.ts +++ b/src/core/options/resolvePlayer.ts @@ -8,7 +8,7 @@ import { BlitzServer } from '../../constants/servers.js'; import listAccountsPanServer, { usernamePatternWithoutPosition, } from '../blitz/listAccountsPanServer.js'; -import errorWithCause from '../process/errorWithCause.js'; +import errorWithCause from '../node/errorWithCause.js'; export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; diff --git a/src/events/error.ts b/src/events/error.ts index ee73d6fdc..8dec386de 100644 --- a/src/events/error.ts +++ b/src/events/error.ts @@ -2,7 +2,7 @@ import { EmbedBuilder, TextChannel } from 'discord.js'; import discord from '../../discord.json' assert { type: 'json' }; import { client } from '../bot.js'; import { NEGATIVE_COLOR } from '../constants/colors.js'; -import isDev from '../core/process/isDev.js'; +import isDev from '../core/node/isDev.js'; const PROCESS_ERROR_EVENTS = ['uncaughtException']; const CLIENT_ERROR_EVENTS = ['error']; diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index 6907bf516..471c1d709 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -8,24 +8,24 @@ import { import negativeEmbed from '../../../core/interaction/negativeEmbed.js'; import normalizeInteractionReturnable from '../../../core/interaction/normalizeInteractionReturnable.js'; import warningEmbed from '../../../core/interaction/warningEmbed.js'; -import { psa } from '../../../core/process/psa.js'; +import { psa } from '../../../core/node/psa.js'; import { handleError } from '../../error.js'; import { commands } from '../index.js'; export default async function handleChatInputCommand( interaction: ChatInputCommandInteraction, ) { - const command = commands[interaction.commandName]; + const registry = commands[interaction.commandName]; console.log(interaction.toString()); await interaction.deferReply(); try { - const returnable = await command.execute(interaction); + const returnable = await registry.handler(interaction); - if (command.handlesInteraction) return; + if (registry.handlesInteraction) return; - const reply = await normalizeInteractionReturnable(returnable!); + const reply = await normalizeInteractionReturnable(returnable); if (psa.data) { if (!reply.embeds) reply.embeds = []; diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index 2b3d35c04..1594357df 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -28,9 +28,9 @@ import searchtanks from '../../commands/searchtanks.js'; import stats from '../../commands/stats.js'; import today from '../../commands/today.js'; import verify from '../../commands/verify.js'; -import { DISCORD_TOKEN } from '../../core/process/args.js'; -import getClientId from '../../core/process/getClientId.js'; -import isDev from '../../core/process/isDev.js'; +import { DISCORD_TOKEN } from '../../core/node/args.js'; +import getClientId from '../../core/node/getClientId.js'; +import isDev from '../../core/node/isDev.js'; import handleAutocomplete from './handlers/autocomplete.js'; import handleButton from './handlers/button.js'; import handleChatInputCommand from './handlers/chatInputCommand.js'; @@ -46,29 +46,26 @@ export type InteractionReturnable = | InteractionIterableReturnable | Promise; -export type CommandRegistry = { +export interface Registry { inDevelopment: boolean; inProduction: boolean; - inPublic: boolean; +} +export interface CommandRegistry + extends Registry { + inPublic: boolean; + handlesInteraction?: HandlesInteraction; command: | SlashCommandBuilder | SlashCommandSubcommandsOnlyBuilder | Omit; + + handler: ( + interaction: ChatInputCommandInteraction, + ) => HandlesInteraction extends true ? void : InteractionReturnable; autocomplete?: (interaction: AutocompleteInteraction) => void; button?: (interaction: ButtonInteraction) => InteractionReturnable; -} & ( - | { - handlesInteraction?: false; - execute: ( - interaction: ChatInputCommandInteraction, - ) => InteractionReturnable; - } - | { - handlesInteraction: true; - execute: (interaction: ChatInputCommandInteraction) => void; - } -); +} const rest = new REST().setToken(DISCORD_TOKEN); diff --git a/src/events/ready.ts b/src/events/ready.ts index 9fd2c068f..e84016295 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,5 +1,5 @@ import { Client } from 'discord.js'; -import isDev from '../core/process/isDev.js'; +import isDev from '../core/node/isDev.js'; export default function ready(client: Client) { console.log( diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index a4276b935..3a307585e 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -9,9 +9,9 @@ import resolveTankName from '../core/blitz/resolveTankName.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import getPlayerHistories from '../core/blitzstars/getPlayerHistories.js'; import getTankHistories from '../core/blitzstars/getTankHistories.js'; -import { ResolvedPeriod } from '../core/options/resolvePeriod.js'; +import { ResolvedPeriod } from '../core/interaction/resolvePeriodFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { ResolvedPlayer } from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { AccountInfo } from '../types/accountInfo.js'; import { Histories } from '../types/histories.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index cf7d3b9f9..1e5327f9c 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -12,9 +12,9 @@ import sumStats from '../core/blitz/sumStats.js'; import { Tier, tankopedia } from '../core/blitz/tankopedia.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import { ResolvedPeriod } from '../core/options/resolvePeriod.js'; +import { ResolvedPeriod } from '../core/interaction/resolvePeriodFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { ResolvedPlayer } from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { AccountInfo, AllStats, diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index 77650cb6b..385725b03 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -14,8 +14,8 @@ import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { ResolvedPlayer } from '../core/options/resolvePlayer.js'; -import { WARGAMING_APPLICATION_ID } from '../core/process/args.js'; import { AccountInfo, AllStats } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/responders/stats.tsx b/src/responders/stats.tsx new file mode 100644 index 000000000..ac5cba514 --- /dev/null +++ b/src/responders/stats.tsx @@ -0,0 +1,24 @@ +import { BlitzServer } from '../constants/servers.js'; +import resolvePeriodFromCommand from '../core/interaction/resolvePeriodFromCommand.js'; +import stats, { StatType } from '../renderers/stats.js'; +import { ResponderRegistry } from '../server.js'; + +export default { + route: '/stats/:type/:period', + inProduction: true, + inDevelopment: true, + + async handler(req) { + console.log('yeah'); + + return await stats( + req.params.type as StatType, + resolvePeriodFromCommand(req), + { + server: req.query.server as BlitzServer, + id: parseInt(req.query.id as string), + }, + parseInt(req.query.tank as string), + ); + }, +} satisfies ResponderRegistry; diff --git a/src/server.ts b/src/server.ts index 099ce5b56..0c2cf6462 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,18 +1,40 @@ -import express from 'express'; -import jsxToSvg from './core/ui/jsxToSvg.js'; -import today from './renderers/today.js'; +import express, { Request, Response } from 'express'; +import normalizeResponderReturnable from './core/express/normalizeResponderReturnable.js'; +import isDev from './core/node/isDev.js'; +import { Registry } from './events/interactionCreate/index.js'; +import stats from './responders/stats.js'; + +export type ResponderReturnable = JSX.Element | Promise; + +export interface ResponderRegistry + extends Registry { + route: string; + handlesInteraction?: HandlesInteraction; + + handler: ( + req: Request, + res: Response, + ) => HandlesInteraction extends true ? void : ResponderReturnable; +} const app = express(); -app.get('/', async (req, res) => { - const jsx = await today({ server: 'com', id: 1028700193 }); - const svg = await jsxToSvg(jsx); +([stats] as ResponderRegistry[]).forEach((registry) => { + if (!(isDev() ? registry.inDevelopment : registry.inProduction)) return; - res.writeHead(200, { - 'Content-Type': 'image/svg+xml', - 'Content-Length': svg.length, + app.get(registry.route, async (req, res) => { + const returnable = registry.handler(req, res); + + if (registry.handlesInteraction) return; + + const response = await normalizeResponderReturnable(returnable); + + res.writeHead(200, { + 'Content-Type': 'image/svg+xml', + 'Content-Length': response.length, + }); + res.end(response); }); - res.end(svg); }); app.listen(process.env.PORT ?? 3000); diff --git a/tsconfig.json b/tsconfig.json index 8ca930d1c..61fa9c597 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,5 @@ "resolveJsonModule": true, "jsx": "react-jsx" }, - "include": ["src/**/*.ts", "src/renderers/stats.tsx", "src/events/interactionCreate/handlers/button.tsx"] + "include": ["src/**/*.ts", "src/renderers/stats.tsx", "src/events/interactionCreate/handlers/button.tsx", "src/responders/stats.tsx"] } From 7dd3913ae83d9f5d4b38e3380b852d353489394e Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 01:46:08 +0000 Subject: [PATCH 06/29] feat: organized files --- src/commands/debug.ts | 4 ++-- src/commands/eligible.ts | 10 +++++----- src/commands/evolution.tsx | 10 +++++----- src/commands/help.ts | 2 +- src/commands/inactive.tsx | 4 ++-- src/commands/ownedtanks.tsx | 6 +++--- src/commands/playerachievements.ts | 10 +++++----- src/commands/playerinfo.ts | 10 +++++----- src/commands/searchclans.ts | 6 +++--- src/commands/searchplayers.ts | 6 +++--- src/commands/searchtanks.ts | 4 ++-- src/commands/stats.tsx | 18 +++++++++--------- src/commands/today.tsx | 6 +++--- src/commands/verify.ts | 10 +++++----- src/core/blitz/getBlitzClan.ts | 2 +- src/core/blitzstars/getPeriodStart.ts | 2 +- .../{options => discord}/addClanChoices.ts | 0 .../addPeriodSubCommands.ts | 2 +- .../{options => discord}/addServerChoices.ts | 0 .../addStatsSubCommandGroups.ts | 0 .../{options => discord}/addTankChoices.ts | 0 .../{options => discord}/addUsernameOption.ts | 0 .../clan.ts => discord/clanAutocomplete.ts} | 0 .../{interaction => discord}/cleanTable.ts | 0 .../fullBlitzStarsStats.ts | 0 .../generateCustomId.ts | 0 src/core/{interaction => discord}/infoEmbed.ts | 0 .../interactionToURL.ts | 0 .../{interaction => discord}/linkButton.ts | 0 .../{interaction => discord}/negativeEmbed.ts | 0 src/core/{interaction => discord}/noMember.ts | 0 .../normalizeInteractionReturnable.ts | 0 .../notTrackedByBlitzStars.ts | 0 .../{interaction => discord}/positiveEmbed.ts | 0 .../{interaction => discord}/primaryButton.ts | 0 .../resolvePeriodFromCommand.ts | 2 +- src/core/{options => discord}/resolvePlayer.ts | 0 .../supportBlitzStars.ts | 0 .../tanks.ts => discord/tanksAutocomplete.ts} | 0 .../usernameAutocomplete.ts} | 0 .../{interaction => discord}/warningEmbed.ts | 0 .../express/normalizeResponderReturnable.ts | 2 +- src/core/{ui => node}/jsxToSvg.ts | 0 src/core/{ui => node}/render.tsx | 0 src/core/{ui => node}/svgToPng.ts | 0 .../interactionCreate/handlers/button.tsx | 2 +- .../handlers/chatInputCommand.ts | 6 +++--- src/renderers/evolution.tsx | 4 ++-- src/renderers/stats.tsx | 4 ++-- src/renderers/today.tsx | 2 +- src/responders/stats.tsx | 2 +- 51 files changed, 68 insertions(+), 68 deletions(-) rename src/core/{options => discord}/addClanChoices.ts (100%) rename src/core/{options => discord}/addPeriodSubCommands.ts (95%) rename src/core/{options => discord}/addServerChoices.ts (100%) rename src/core/{options => discord}/addStatsSubCommandGroups.ts (100%) rename src/core/{options => discord}/addTankChoices.ts (100%) rename src/core/{options => discord}/addUsernameOption.ts (100%) rename src/core/{autocomplete/clan.ts => discord/clanAutocomplete.ts} (100%) rename src/core/{interaction => discord}/cleanTable.ts (100%) rename src/core/{interaction => discord}/fullBlitzStarsStats.ts (100%) rename src/core/{interaction => discord}/generateCustomId.ts (100%) rename src/core/{interaction => discord}/infoEmbed.ts (100%) rename src/core/{interaction => discord}/interactionToURL.ts (100%) rename src/core/{interaction => discord}/linkButton.ts (100%) rename src/core/{interaction => discord}/negativeEmbed.ts (100%) rename src/core/{interaction => discord}/noMember.ts (100%) rename src/core/{interaction => discord}/normalizeInteractionReturnable.ts (100%) rename src/core/{interaction => discord}/notTrackedByBlitzStars.ts (100%) rename src/core/{interaction => discord}/positiveEmbed.ts (100%) rename src/core/{interaction => discord}/primaryButton.ts (100%) rename src/core/{interaction => discord}/resolvePeriodFromCommand.ts (97%) rename src/core/{options => discord}/resolvePlayer.ts (100%) rename src/core/{interaction => discord}/supportBlitzStars.ts (100%) rename src/core/{autocomplete/tanks.ts => discord/tanksAutocomplete.ts} (100%) rename src/core/{autocomplete/username.ts => discord/usernameAutocomplete.ts} (100%) rename src/core/{interaction => discord}/warningEmbed.ts (100%) rename src/core/{ui => node}/jsxToSvg.ts (100%) rename src/core/{ui => node}/render.tsx (100%) rename src/core/{ui => node}/svgToPng.ts (100%) diff --git a/src/commands/debug.ts b/src/commands/debug.ts index ff8d654c0..bb669e193 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -3,8 +3,8 @@ import packageJSON from '../../package.json' assert { type: 'json' }; import { client } from '../bot.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import cleanTable from '../core/interaction/cleanTable.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; +import cleanTable from '../core/discord/cleanTable.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; import getClientId from '../core/node/getClientId.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 0a65fa1e0..404c962c6 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -7,12 +7,12 @@ import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getPeriodStart from '../core/blitzstars/getPeriodStart.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import cleanTable, { TableInput } from '../core/interaction/cleanTable.js'; -import negativeEmbed from '../core/interaction/negativeEmbed.js'; -import positiveEmbed from '../core/interaction/positiveEmbed.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import cleanTable, { TableInput } from '../core/discord/cleanTable.js'; +import negativeEmbed from '../core/discord/negativeEmbed.js'; +import positiveEmbed from '../core/discord/positiveEmbed.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 3d94f5883..e62cc92de 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -1,10 +1,10 @@ import { SlashCommandBuilder } from 'discord.js'; -import tanksAutocomplete from '../core/autocomplete/tanks.js'; -import usernameAutocomplete from '../core/autocomplete/username.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; -import resolvePeriodFromCommand from '../core/interaction/resolvePeriodFromCommand.js'; -import addStatsSubCommandGroups from '../core/options/addStatsSubCommandGroups.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; +import addStatsSubCommandGroups from '../core/discord/addStatsSubCommandGroups.js'; +import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import evolution from '../renderers/evolution.js'; import { StatType } from '../renderers/stats.js'; diff --git a/src/commands/help.ts b/src/commands/help.ts index 0b178aa8d..a65c18293 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; import discord from '../../discord.json' assert { type: 'json' }; import { client } from '../bot.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; import { CommandRegistry, guildCommands, diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index 36ce1fe63..6e9dd397b 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -5,11 +5,11 @@ import PoweredByWargaming from '../components/PoweredByWargaming.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; -import clanAutocomplete from '../core/autocomplete/clan.js'; import getBlitzClan from '../core/blitz/getBlitzClan.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; +import addClanChoices from '../core/discord/addClanChoices.js'; +import clanAutocomplete from '../core/discord/clanAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addClanChoices from '../core/options/addClanChoices.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { ClanInfo } from '../types/clanInfo.js'; diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedtanks.tsx index ff41e146a..14815e287 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedtanks.tsx @@ -5,7 +5,6 @@ import * as Tanks from '../components/Tanks/index.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; -import usernameAutocomplete from '../core/autocomplete/username.js'; import getTankStats from '../core/blitz/getTankStats.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import { @@ -13,9 +12,10 @@ import { Tier, tankopedia, } from '../core/blitz/tankopedia.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/commands/playerachievements.ts b/src/commands/playerachievements.ts index 258fd6f23..c2fbcb471 100644 --- a/src/commands/playerachievements.ts +++ b/src/commands/playerachievements.ts @@ -1,13 +1,13 @@ import { SlashCommandBuilder } from 'discord.js'; import { startCase } from 'lodash'; import markdownEscape from 'markdown-escape'; -import usernameAutocomplete from '../core/autocomplete/username.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import cleanTable, { TableInputEntry } from '../core/interaction/cleanTable.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import cleanTable, { TableInputEntry } from '../core/discord/cleanTable.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountAchievements } from '../types/accountAchievements.js'; import { AccountInfo } from '../types/accountInfo.js'; diff --git a/src/commands/playerinfo.ts b/src/commands/playerinfo.ts index 287e17d15..7e07d56c4 100644 --- a/src/commands/playerinfo.ts +++ b/src/commands/playerinfo.ts @@ -1,12 +1,12 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; -import usernameAutocomplete from '../core/autocomplete/username.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import cleanTable from '../core/interaction/cleanTable.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import cleanTable from '../core/discord/cleanTable.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; diff --git a/src/commands/searchclans.ts b/src/commands/searchclans.ts index bb5f2cf39..674b18c8a 100644 --- a/src/commands/searchclans.ts +++ b/src/commands/searchclans.ts @@ -2,10 +2,10 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; +import addClanChoices from '../core/discord/addClanChoices.js'; +import addServerChoices from '../core/discord/addServerChoices.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addClanChoices from '../core/options/addClanChoices.js'; -import addServerChoices from '../core/options/addServerChoices.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { ClanList } from '../types/clanList.js'; diff --git a/src/commands/searchplayers.ts b/src/commands/searchplayers.ts index 4852d4b8d..afb67450f 100644 --- a/src/commands/searchplayers.ts +++ b/src/commands/searchplayers.ts @@ -3,10 +3,10 @@ import markdownEscape from 'markdown-escape'; import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import { usernamePattern } from '../core/blitz/listAccountsPanServer.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; +import addServerChoices from '../core/discord/addServerChoices.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addServerChoices from '../core/options/addServerChoices.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountList } from '../types/accountList.js'; diff --git a/src/commands/searchtanks.ts b/src/commands/searchtanks.ts index 38c2c0d93..dd320f77b 100644 --- a/src/commands/searchtanks.ts +++ b/src/commands/searchtanks.ts @@ -2,8 +2,8 @@ import { SlashCommandBuilder } from 'discord.js'; import { go } from 'fuzzysort'; import markdownEscape from 'markdown-escape'; import { TANK_NAMES } from '../core/blitz/tankopedia.js'; -import infoEmbed from '../core/interaction/infoEmbed.js'; -import addTankChoices from '../core/options/addTankChoices.js'; +import addTankChoices from '../core/discord/addTankChoices.js'; +import infoEmbed from '../core/discord/infoEmbed.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; export default { diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 9c04f5370..c35a0d7c7 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -1,15 +1,15 @@ import { SlashCommandBuilder } from 'discord.js'; import { CYCLIC_API } from '../constants/cyclic.js'; -import tanksAutocomplete from '../core/autocomplete/tanks.js'; -import usernameAutocomplete from '../core/autocomplete/username.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; -import interactionToURL from '../core/interaction/interactionToURL.js'; -import linkButton from '../core/interaction/linkButton.js'; -import primaryButton from '../core/interaction/primaryButton.js'; -import resolvePeriodFromCommand from '../core/interaction/resolvePeriodFromCommand.js'; -import { Period } from '../core/options/addPeriodSubCommands.js'; -import addStatsSubCommandGroups from '../core/options/addStatsSubCommandGroups.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; +import { Period } from '../core/discord/addPeriodSubCommands.js'; +import addStatsSubCommandGroups from '../core/discord/addStatsSubCommandGroups.js'; +import interactionToURL from '../core/discord/interactionToURL.js'; +import linkButton from '../core/discord/linkButton.js'; +import primaryButton from '../core/discord/primaryButton.js'; +import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import stats, { StatType } from '../renderers/stats.js'; diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 2d6c1040a..a1b46d234 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; -import usernameAutocomplete from '../core/autocomplete/username.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import today from '../renderers/today.js'; diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 1ac4e466d..b3cef4b84 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -1,13 +1,13 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; import discord from '../../discord.json' assert { type: 'json' }; -import usernameAutocomplete from '../core/autocomplete/username.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import negativeEmbed from '../core/interaction/negativeEmbed.js'; -import positiveEmbed from '../core/interaction/positiveEmbed.js'; +import addUsernameOption from '../core/discord/addUsernameOption.js'; +import negativeEmbed from '../core/discord/negativeEmbed.js'; +import positiveEmbed from '../core/discord/positiveEmbed.js'; +import resolvePlayer from '../core/discord/resolvePlayer.js'; +import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import addUsernameOption from '../core/options/addUsernameOption.js'; -import resolvePlayer from '../core/options/resolvePlayer.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/core/blitz/getBlitzClan.ts b/src/core/blitz/getBlitzClan.ts index 206aff2fc..91a6aaf63 100644 --- a/src/core/blitz/getBlitzClan.ts +++ b/src/core/blitz/getBlitzClan.ts @@ -1,7 +1,7 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import { BlitzServer } from '../../constants/servers.js'; +import { serverAndIdPattern } from '../discord/resolvePlayer.js'; import errorWithCause from '../node/errorWithCause.js'; -import { serverAndIdPattern } from '../options/resolvePlayer.js'; import listClansPanServer from './listClansPanServer.js'; export default async function getBlitzClan( diff --git a/src/core/blitzstars/getPeriodStart.ts b/src/core/blitzstars/getPeriodStart.ts index abff335a7..ec955af34 100644 --- a/src/core/blitzstars/getPeriodStart.ts +++ b/src/core/blitzstars/getPeriodStart.ts @@ -1,4 +1,4 @@ -import { Period } from '../options/addPeriodSubCommands.js'; +import { Period } from '../discord/addPeriodSubCommands.js'; import getTimeDaysAgo from './getTimeDaysAgo.js'; export default function getPeriodStart(period: Exclude) { diff --git a/src/core/options/addClanChoices.ts b/src/core/discord/addClanChoices.ts similarity index 100% rename from src/core/options/addClanChoices.ts rename to src/core/discord/addClanChoices.ts diff --git a/src/core/options/addPeriodSubCommands.ts b/src/core/discord/addPeriodSubCommands.ts similarity index 95% rename from src/core/options/addPeriodSubCommands.ts rename to src/core/discord/addPeriodSubCommands.ts index 450ea5c69..74fd61087 100644 --- a/src/core/options/addPeriodSubCommands.ts +++ b/src/core/discord/addPeriodSubCommands.ts @@ -2,7 +2,7 @@ import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, } from 'discord.js'; -import { PERIOD_NAMES } from '../interaction/resolvePeriodFromCommand.js'; +import { PERIOD_NAMES } from '../discord/resolvePeriodFromCommand.js'; export type Period = 'today' | '30' | '60' | '90' | 'career' | 'custom'; diff --git a/src/core/options/addServerChoices.ts b/src/core/discord/addServerChoices.ts similarity index 100% rename from src/core/options/addServerChoices.ts rename to src/core/discord/addServerChoices.ts diff --git a/src/core/options/addStatsSubCommandGroups.ts b/src/core/discord/addStatsSubCommandGroups.ts similarity index 100% rename from src/core/options/addStatsSubCommandGroups.ts rename to src/core/discord/addStatsSubCommandGroups.ts diff --git a/src/core/options/addTankChoices.ts b/src/core/discord/addTankChoices.ts similarity index 100% rename from src/core/options/addTankChoices.ts rename to src/core/discord/addTankChoices.ts diff --git a/src/core/options/addUsernameOption.ts b/src/core/discord/addUsernameOption.ts similarity index 100% rename from src/core/options/addUsernameOption.ts rename to src/core/discord/addUsernameOption.ts diff --git a/src/core/autocomplete/clan.ts b/src/core/discord/clanAutocomplete.ts similarity index 100% rename from src/core/autocomplete/clan.ts rename to src/core/discord/clanAutocomplete.ts diff --git a/src/core/interaction/cleanTable.ts b/src/core/discord/cleanTable.ts similarity index 100% rename from src/core/interaction/cleanTable.ts rename to src/core/discord/cleanTable.ts diff --git a/src/core/interaction/fullBlitzStarsStats.ts b/src/core/discord/fullBlitzStarsStats.ts similarity index 100% rename from src/core/interaction/fullBlitzStarsStats.ts rename to src/core/discord/fullBlitzStarsStats.ts diff --git a/src/core/interaction/generateCustomId.ts b/src/core/discord/generateCustomId.ts similarity index 100% rename from src/core/interaction/generateCustomId.ts rename to src/core/discord/generateCustomId.ts diff --git a/src/core/interaction/infoEmbed.ts b/src/core/discord/infoEmbed.ts similarity index 100% rename from src/core/interaction/infoEmbed.ts rename to src/core/discord/infoEmbed.ts diff --git a/src/core/interaction/interactionToURL.ts b/src/core/discord/interactionToURL.ts similarity index 100% rename from src/core/interaction/interactionToURL.ts rename to src/core/discord/interactionToURL.ts diff --git a/src/core/interaction/linkButton.ts b/src/core/discord/linkButton.ts similarity index 100% rename from src/core/interaction/linkButton.ts rename to src/core/discord/linkButton.ts diff --git a/src/core/interaction/negativeEmbed.ts b/src/core/discord/negativeEmbed.ts similarity index 100% rename from src/core/interaction/negativeEmbed.ts rename to src/core/discord/negativeEmbed.ts diff --git a/src/core/interaction/noMember.ts b/src/core/discord/noMember.ts similarity index 100% rename from src/core/interaction/noMember.ts rename to src/core/discord/noMember.ts diff --git a/src/core/interaction/normalizeInteractionReturnable.ts b/src/core/discord/normalizeInteractionReturnable.ts similarity index 100% rename from src/core/interaction/normalizeInteractionReturnable.ts rename to src/core/discord/normalizeInteractionReturnable.ts diff --git a/src/core/interaction/notTrackedByBlitzStars.ts b/src/core/discord/notTrackedByBlitzStars.ts similarity index 100% rename from src/core/interaction/notTrackedByBlitzStars.ts rename to src/core/discord/notTrackedByBlitzStars.ts diff --git a/src/core/interaction/positiveEmbed.ts b/src/core/discord/positiveEmbed.ts similarity index 100% rename from src/core/interaction/positiveEmbed.ts rename to src/core/discord/positiveEmbed.ts diff --git a/src/core/interaction/primaryButton.ts b/src/core/discord/primaryButton.ts similarity index 100% rename from src/core/interaction/primaryButton.ts rename to src/core/discord/primaryButton.ts diff --git a/src/core/interaction/resolvePeriodFromCommand.ts b/src/core/discord/resolvePeriodFromCommand.ts similarity index 97% rename from src/core/interaction/resolvePeriodFromCommand.ts rename to src/core/discord/resolvePeriodFromCommand.ts index 2eb25c58e..fe71e4861 100644 --- a/src/core/interaction/resolvePeriodFromCommand.ts +++ b/src/core/discord/resolvePeriodFromCommand.ts @@ -8,7 +8,7 @@ import { CYCLIC_API } from '../../constants/cyclic.js'; import getPeriodNow from '../blitzstars/getPeriodNow.js'; import getPeriodStart from '../blitzstars/getPeriodStart.js'; import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo.js'; -import { Period } from '../options/addPeriodSubCommands.js'; +import { Period } from '../discord/addPeriodSubCommands.js'; export const PERIOD_NAMES: Record = { today: "Today's statistics", diff --git a/src/core/options/resolvePlayer.ts b/src/core/discord/resolvePlayer.ts similarity index 100% rename from src/core/options/resolvePlayer.ts rename to src/core/discord/resolvePlayer.ts diff --git a/src/core/interaction/supportBlitzStars.ts b/src/core/discord/supportBlitzStars.ts similarity index 100% rename from src/core/interaction/supportBlitzStars.ts rename to src/core/discord/supportBlitzStars.ts diff --git a/src/core/autocomplete/tanks.ts b/src/core/discord/tanksAutocomplete.ts similarity index 100% rename from src/core/autocomplete/tanks.ts rename to src/core/discord/tanksAutocomplete.ts diff --git a/src/core/autocomplete/username.ts b/src/core/discord/usernameAutocomplete.ts similarity index 100% rename from src/core/autocomplete/username.ts rename to src/core/discord/usernameAutocomplete.ts diff --git a/src/core/interaction/warningEmbed.ts b/src/core/discord/warningEmbed.ts similarity index 100% rename from src/core/interaction/warningEmbed.ts rename to src/core/discord/warningEmbed.ts diff --git a/src/core/express/normalizeResponderReturnable.ts b/src/core/express/normalizeResponderReturnable.ts index d0ffeadab..4b9eb100b 100644 --- a/src/core/express/normalizeResponderReturnable.ts +++ b/src/core/express/normalizeResponderReturnable.ts @@ -1,5 +1,5 @@ import { ResponderReturnable } from '../../server.js'; -import jsxToSvg from '../ui/jsxToSvg.js'; +import jsxToSvg from '../node/jsxToSvg.js'; export default async function normalizeResponderReturnable( returnable: ResponderReturnable, diff --git a/src/core/ui/jsxToSvg.ts b/src/core/node/jsxToSvg.ts similarity index 100% rename from src/core/ui/jsxToSvg.ts rename to src/core/node/jsxToSvg.ts diff --git a/src/core/ui/render.tsx b/src/core/node/render.tsx similarity index 100% rename from src/core/ui/render.tsx rename to src/core/node/render.tsx diff --git a/src/core/ui/svgToPng.ts b/src/core/node/svgToPng.ts similarity index 100% rename from src/core/ui/svgToPng.ts rename to src/core/node/svgToPng.ts diff --git a/src/events/interactionCreate/handlers/button.tsx b/src/events/interactionCreate/handlers/button.tsx index 7f2a87014..82a33f013 100644 --- a/src/events/interactionCreate/handlers/button.tsx +++ b/src/events/interactionCreate/handlers/button.tsx @@ -1,5 +1,5 @@ import { ButtonInteraction, CacheType } from 'discord.js'; -import normalizeInteractionReturnable from '../../../core/interaction/normalizeInteractionReturnable.js'; +import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; import { commands } from '../index.js'; export default async function handleButton( diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index 471c1d709..818cf1895 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -5,9 +5,9 @@ import { CacheType, ChatInputCommandInteraction, } from 'discord.js'; -import negativeEmbed from '../../../core/interaction/negativeEmbed.js'; -import normalizeInteractionReturnable from '../../../core/interaction/normalizeInteractionReturnable.js'; -import warningEmbed from '../../../core/interaction/warningEmbed.js'; +import negativeEmbed from '../../../core/discord/negativeEmbed.js'; +import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; +import warningEmbed from '../../../core/discord/warningEmbed.js'; import { psa } from '../../../core/node/psa.js'; import { handleError } from '../../error.js'; import { commands } from '../index.js'; diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 3a307585e..28d9dde9f 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -9,9 +9,9 @@ import resolveTankName from '../core/blitz/resolveTankName.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import getPlayerHistories from '../core/blitzstars/getPlayerHistories.js'; import getTankHistories from '../core/blitzstars/getTankHistories.js'; -import { ResolvedPeriod } from '../core/interaction/resolvePeriodFromCommand.js'; +import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayer.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import { ResolvedPlayer } from '../core/options/resolvePlayer.js'; import { AccountInfo } from '../types/accountInfo.js'; import { Histories } from '../types/histories.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index 1e5327f9c..d61c51a23 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -12,9 +12,9 @@ import sumStats from '../core/blitz/sumStats.js'; import { Tier, tankopedia } from '../core/blitz/tankopedia.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import { ResolvedPeriod } from '../core/interaction/resolvePeriodFromCommand.js'; +import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayer.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import { ResolvedPlayer } from '../core/options/resolvePlayer.js'; import { AccountInfo, AllStats, diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index 385725b03..81ad56736 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -14,8 +14,8 @@ import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayer.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; -import { ResolvedPlayer } from '../core/options/resolvePlayer.js'; import { AccountInfo, AllStats } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/responders/stats.tsx b/src/responders/stats.tsx index ac5cba514..c3b92d327 100644 --- a/src/responders/stats.tsx +++ b/src/responders/stats.tsx @@ -1,5 +1,5 @@ import { BlitzServer } from '../constants/servers.js'; -import resolvePeriodFromCommand from '../core/interaction/resolvePeriodFromCommand.js'; +import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import stats, { StatType } from '../renderers/stats.js'; import { ResponderRegistry } from '../server.js'; From abcb75f06efe180cc5e6f289dd129729e042a918 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 01:48:26 +0000 Subject: [PATCH 07/29] fix: type issues --- src/commands/ping.ts | 2 +- src/core/discord/normalizeInteractionReturnable.ts | 4 ++-- src/core/node/{render.tsx => jsxToPng.ts} | 2 +- src/events/interactionCreate/index.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/core/node/{render.tsx => jsxToPng.ts} (72%) diff --git a/src/commands/ping.ts b/src/commands/ping.ts index 6c99eda61..bcff65f19 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -30,4 +30,4 @@ export default { const executionTime = Date.now() - executionStart; interaction.editReply(`Pong 🏓 - ${executionTime}ms`); }, -} satisfies CommandRegistry; +} satisfies CommandRegistry; diff --git a/src/core/discord/normalizeInteractionReturnable.ts b/src/core/discord/normalizeInteractionReturnable.ts index 9303aec47..d935763a3 100644 --- a/src/core/discord/normalizeInteractionReturnable.ts +++ b/src/core/discord/normalizeInteractionReturnable.ts @@ -5,7 +5,7 @@ import { InteractionEditReplyOptions, } from 'discord.js'; import { InteractionReturnable } from '../../events/interactionCreate/index.js'; -import render from '../ui/render.js'; +import jsxToPng from '../node/jsxToPng.js'; export default async function normalizeInteractionReturnable( returnable: InteractionReturnable, @@ -29,7 +29,7 @@ export default async function normalizeInteractionReturnable( item, ); } else { - const image = await render(item); + const image = await jsxToPng(item); if (!reply.files) reply.files = []; reply.files.push(image); } diff --git a/src/core/node/render.tsx b/src/core/node/jsxToPng.ts similarity index 72% rename from src/core/node/render.tsx rename to src/core/node/jsxToPng.ts index ae00848bc..e48d3b1f5 100644 --- a/src/core/node/render.tsx +++ b/src/core/node/jsxToPng.ts @@ -1,7 +1,7 @@ import jsxToSvg from './jsxToSvg.js'; import svgToPng from './svgToPng.js'; -export default async function render(jsx: JSX.Element) { +export default async function jsxToPng(jsx: JSX.Element) { const svg = await jsxToSvg(jsx); const png = svgToPng(svg); diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index 1594357df..4a7ef7b29 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -51,7 +51,7 @@ export interface Registry { inProduction: boolean; } -export interface CommandRegistry +export interface CommandRegistry extends Registry { inPublic: boolean; handlesInteraction?: HandlesInteraction; From c221c06511a44eea377c2fee887a62c01a564a1b Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 02:02:00 +0000 Subject: [PATCH 08/29] feat: split resolvePeriod --- src/commands/evolution.tsx | 1 + src/commands/stats.tsx | 3 +- src/core/discord/resolvePeriodFromButton.ts | 9 ++++ src/core/discord/resolvePeriodFromCommand.ts | 38 +++------------- src/core/express/resolvePeriodFromRequest.ts | 7 +++ src/core/express/resolvePeriodFromURL.ts | 43 +++++++++++++++++++ .../handlers/chatInputCommand.ts | 2 +- src/responders/stats.tsx | 9 ++-- 8 files changed, 73 insertions(+), 39 deletions(-) create mode 100644 src/core/discord/resolvePeriodFromButton.ts create mode 100644 src/core/express/resolvePeriodFromRequest.ts create mode 100644 src/core/express/resolvePeriodFromURL.ts diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index e62cc92de..f1ee55b12 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -31,6 +31,7 @@ export default { return await evolution(commandGroup, period, player, tankId); + // TODO: implement this // new ButtonBuilder() // .setStyle(ButtonStyle.Link) // .setLabel('View on BlitzStars') diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index c35a0d7c7..4458b99da 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -6,6 +6,7 @@ import addStatsSubCommandGroups from '../core/discord/addStatsSubCommandGroups.j import interactionToURL from '../core/discord/interactionToURL.js'; import linkButton from '../core/discord/linkButton.js'; import primaryButton from '../core/discord/primaryButton.js'; +import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePlayer from '../core/discord/resolvePlayer.js'; import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; @@ -57,7 +58,7 @@ export default { const url = new URL(`${CYCLIC_API}/${interaction.customId}`); const path = url.pathname.split('/').filter(Boolean); const commandGroup = path[1] as StatType; - const period = resolvePeriodFromCommand(interaction); + const period = resolvePeriodFromButton(interaction); const player = await resolvePlayer(interaction); return await stats( diff --git a/src/core/discord/resolvePeriodFromButton.ts b/src/core/discord/resolvePeriodFromButton.ts new file mode 100644 index 000000000..cda3c11ca --- /dev/null +++ b/src/core/discord/resolvePeriodFromButton.ts @@ -0,0 +1,9 @@ +import { ButtonInteraction, CacheType } from 'discord.js'; +import { CYCLIC_API } from '../../constants/cyclic.js'; +import resolvePeriodFromURL from '../express/resolvePeriodFromURL.js'; + +export default function resolvePeriodFromButton( + interaction: ButtonInteraction, +) { + return resolvePeriodFromURL(`${CYCLIC_API}/${interaction.customId}`); +} diff --git a/src/core/discord/resolvePeriodFromCommand.ts b/src/core/discord/resolvePeriodFromCommand.ts index fe71e4861..6c5a6bfe5 100644 --- a/src/core/discord/resolvePeriodFromCommand.ts +++ b/src/core/discord/resolvePeriodFromCommand.ts @@ -1,10 +1,4 @@ -import { - ButtonInteraction, - CacheType, - ChatInputCommandInteraction, -} from 'discord.js'; -import { Request } from 'express'; -import { CYCLIC_API } from '../../constants/cyclic.js'; +import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import getPeriodNow from '../blitzstars/getPeriodNow.js'; import getPeriodStart from '../blitzstars/getPeriodStart.js'; import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo.js'; @@ -36,39 +30,17 @@ export interface ResolvedPeriod { } export default function resolvePeriodFromCommand( - input: - | ChatInputCommandInteraction - | ButtonInteraction - | Request, + interaction: ChatInputCommandInteraction, ) { let statsName: string; let evolutionName: string; let start: number; let end: number; - let url: URL; - let period: Period; - - if (input instanceof ChatInputCommandInteraction) { - period = input.options.getSubcommand() as Period; - } else { - url = new URL( - `${CYCLIC_API}${ - input instanceof ButtonInteraction ? `/${input.customId}` : input.path - }`, - ); - const path = url.pathname.split('/').filter(Boolean); - period = path[path.length - 1] as Period; - } + const period = interaction.options.getSubcommand() as Period; if (period === 'custom') { - const startRaw = - input instanceof ChatInputCommandInteraction - ? input.options.getInteger('start')! - : parseInt(url!.searchParams.get('start')!); - const endRaw = - input instanceof ChatInputCommandInteraction - ? input.options.getInteger('end')! - : parseInt(url!.searchParams.get('end')!); + const startRaw = interaction.options.getInteger('start')!; + const endRaw = interaction.options.getInteger('end')!; const startMin = Math.min(startRaw, endRaw); const endMax = Math.max(startRaw, endRaw); diff --git a/src/core/express/resolvePeriodFromRequest.ts b/src/core/express/resolvePeriodFromRequest.ts new file mode 100644 index 000000000..8695d79a0 --- /dev/null +++ b/src/core/express/resolvePeriodFromRequest.ts @@ -0,0 +1,7 @@ +import { Request } from 'express'; +import { CYCLIC_API } from '../../constants/cyclic.js'; +import resolvePeriodFromURL from './resolvePeriodFromURL.js'; + +export default function resolvePeriodFromRequest(request: Request) { + return resolvePeriodFromURL(`${CYCLIC_API}${request.path}`); +} diff --git a/src/core/express/resolvePeriodFromURL.ts b/src/core/express/resolvePeriodFromURL.ts new file mode 100644 index 000000000..2799f2f39 --- /dev/null +++ b/src/core/express/resolvePeriodFromURL.ts @@ -0,0 +1,43 @@ +import getPeriodNow from '../blitzstars/getPeriodNow.js'; +import getPeriodStart from '../blitzstars/getPeriodStart.js'; +import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo.js'; +import { Period } from '../discord/addPeriodSubCommands.js'; +import { + EVOLUTION_PERIOD_NAMES, + PERIOD_NAMES, + ResolvedPeriod, +} from '../discord/resolvePeriodFromCommand.js'; + +export default function resolvePeriodFromURL(urlString: string) { + let statsName: string; + let evolutionName: string; + let start: number; + let end: number; + const url = new URL(urlString); + const path = url.pathname.split('/').filter(Boolean); + const period = path[path.length - 1] as Period; + + if (period === 'custom') { + const startRaw = parseInt(url!.searchParams.get('start')!); + const endRaw = parseInt(url!.searchParams.get('end')!); + const startMin = Math.min(startRaw, endRaw); + const endMax = Math.max(startRaw, endRaw); + + statsName = `${startMin} to ${endMax} days' statistics`; + evolutionName = `${startMin} to ${endMax} days' evolution`; + start = getTimeDaysAgo(startMin); + end = getTimeDaysAgo(endMax); + } else { + statsName = PERIOD_NAMES[period]; + evolutionName = EVOLUTION_PERIOD_NAMES[period]; + start = getPeriodStart(period); + end = getPeriodNow(); + } + + return { + statsName, + evolutionName, + start, + end, + } satisfies ResolvedPeriod; +} diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index 818cf1895..0944dbdb5 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -25,7 +25,7 @@ export default async function handleChatInputCommand( if (registry.handlesInteraction) return; - const reply = await normalizeInteractionReturnable(returnable); + const reply = await normalizeInteractionReturnable(returnable!); if (psa.data) { if (!reply.embeds) reply.embeds = []; diff --git a/src/responders/stats.tsx b/src/responders/stats.tsx index c3b92d327..bab1e5c5f 100644 --- a/src/responders/stats.tsx +++ b/src/responders/stats.tsx @@ -1,5 +1,5 @@ import { BlitzServer } from '../constants/servers.js'; -import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; +import resolvePeriodFromRequest from '../core/express/resolvePeriodFromRequest.js'; import stats, { StatType } from '../renderers/stats.js'; import { ResponderRegistry } from '../server.js'; @@ -9,11 +9,12 @@ export default { inDevelopment: true, async handler(req) { - console.log('yeah'); + const type = req.params.type as StatType; + const period = resolvePeriodFromRequest(req); return await stats( - req.params.type as StatType, - resolvePeriodFromCommand(req), + type, + period, { server: req.query.server as BlitzServer, id: parseInt(req.query.id as string), From a67d1700fc475e3f737febeb4365f85436af8067 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 02:07:14 +0000 Subject: [PATCH 09/29] feat: split resolvePlayer --- src/commands/eligible.ts | 4 +- src/commands/evolution.tsx | 4 +- src/commands/ownedtanks.tsx | 4 +- src/commands/playerachievements.ts | 4 +- src/commands/playerinfo.ts | 4 +- src/commands/stats.tsx | 7 +- src/commands/today.tsx | 4 +- src/commands/verify.ts | 4 +- src/core/blitz/getBlitzClan.ts | 2 +- src/core/discord/resolvePlayer.ts | 67 -------------------- src/core/discord/resolvePlayerFromButton.ts | 9 +++ src/core/discord/resolvePlayerFromCommand.ts | 52 +++++++++++++++ src/core/express/resolvePlayerFromRequest.ts | 7 ++ src/core/express/resolvePlayerFromURL.ts | 11 ++++ src/renderers/evolution.tsx | 2 +- src/renderers/stats.tsx | 2 +- src/renderers/today.tsx | 2 +- 17 files changed, 101 insertions(+), 88 deletions(-) delete mode 100644 src/core/discord/resolvePlayer.ts create mode 100644 src/core/discord/resolvePlayerFromButton.ts create mode 100644 src/core/discord/resolvePlayerFromCommand.ts create mode 100644 src/core/express/resolvePlayerFromRequest.ts create mode 100644 src/core/express/resolvePlayerFromURL.ts diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 404c962c6..d4dd2a2c2 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -11,7 +11,7 @@ import addUsernameOption from '../core/discord/addUsernameOption.js'; import cleanTable, { TableInput } from '../core/discord/cleanTable.js'; import negativeEmbed from '../core/discord/negativeEmbed.js'; import positiveEmbed from '../core/discord/positiveEmbed.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -48,7 +48,7 @@ export default { async handler(interaction) { const clan = interaction.options.getString('clan') as SkilledClan; - const { id, server } = await resolvePlayer(interaction); + const { id, server } = await resolvePlayerFromCommand(interaction); const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index f1ee55b12..d389e7ed7 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -2,7 +2,7 @@ import { SlashCommandBuilder } from 'discord.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; import addStatsSubCommandGroups from '../core/discord/addStatsSubCommandGroups.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -24,7 +24,7 @@ export default { const commandGroup = interaction.options.getSubcommandGroup( true, ) as StatType; - const player = await resolvePlayer(interaction); + const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedtanks.tsx index 14815e287..7fb28c870 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedtanks.tsx @@ -13,7 +13,7 @@ import { tankopedia, } from '../core/blitz/tankopedia.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -71,7 +71,7 @@ export default { async handler(interaction) { const tier = Number(interaction.options.getString('tier')); - const account = await resolvePlayer(interaction); + const account = await resolvePlayerFromCommand(interaction); const { id, server } = account; const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, diff --git a/src/commands/playerachievements.ts b/src/commands/playerachievements.ts index c2fbcb471..b8f9872a4 100644 --- a/src/commands/playerachievements.ts +++ b/src/commands/playerachievements.ts @@ -5,7 +5,7 @@ import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; import cleanTable, { TableInputEntry } from '../core/discord/cleanTable.js'; import infoEmbed from '../core/discord/infoEmbed.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -35,7 +35,7 @@ export default { async handler(interaction) { const sortBy = (interaction.options.getString('sort') ?? 'name') as SortBy; - const account = await resolvePlayer(interaction); + const account = await resolvePlayerFromCommand(interaction); const { id, server } = account; const accounts = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, diff --git a/src/commands/playerinfo.ts b/src/commands/playerinfo.ts index 7e07d56c4..b7349f0a8 100644 --- a/src/commands/playerinfo.ts +++ b/src/commands/playerinfo.ts @@ -4,7 +4,7 @@ import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; import cleanTable from '../core/discord/cleanTable.js'; import infoEmbed from '../core/discord/infoEmbed.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -21,7 +21,7 @@ export default { .addStringOption(addUsernameOption), async handler(interaction) { - const account = await resolvePlayer(interaction); + const account = await resolvePlayerFromCommand(interaction); const { id, server } = account; const accounts = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 4458b99da..f2d99b0b8 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -8,7 +8,8 @@ import linkButton from '../core/discord/linkButton.js'; import primaryButton from '../core/discord/primaryButton.js'; import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -30,7 +31,7 @@ export default { true, ) as StatType; const subcommand = interaction.options.getSubcommand() as Period; - const player = await resolvePlayer(interaction); + const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; @@ -59,7 +60,7 @@ export default { const path = url.pathname.split('/').filter(Boolean); const commandGroup = path[1] as StatType; const period = resolvePeriodFromButton(interaction); - const player = await resolvePlayer(interaction); + const player = await resolvePlayerFromButton(interaction); return await stats( commandGroup, diff --git a/src/commands/today.tsx b/src/commands/today.tsx index a1b46d234..786148753 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -1,6 +1,6 @@ import { SlashCommandBuilder } from 'discord.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import today from '../renderers/today.js'; @@ -16,7 +16,7 @@ export default { .addStringOption(addUsernameOption), async handler(interaction) { - const player = await resolvePlayer(interaction); + const player = await resolvePlayerFromCommand(interaction); return await today(player); }, diff --git a/src/commands/verify.ts b/src/commands/verify.ts index b3cef4b84..6888a7455 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -5,7 +5,7 @@ import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; import negativeEmbed from '../core/discord/negativeEmbed.js'; import positiveEmbed from '../core/discord/positiveEmbed.js'; -import resolvePlayer from '../core/discord/resolvePlayer.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -23,7 +23,7 @@ export default { .addStringOption((option) => addUsernameOption(option).setRequired(true)), async handler(interaction) { - const blitzAccount = await resolvePlayer(interaction); + const blitzAccount = await resolvePlayerFromCommand(interaction); const { id, server } = blitzAccount; const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, diff --git a/src/core/blitz/getBlitzClan.ts b/src/core/blitz/getBlitzClan.ts index 91a6aaf63..908950824 100644 --- a/src/core/blitz/getBlitzClan.ts +++ b/src/core/blitz/getBlitzClan.ts @@ -1,6 +1,6 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import { BlitzServer } from '../../constants/servers.js'; -import { serverAndIdPattern } from '../discord/resolvePlayer.js'; +import { serverAndIdPattern } from '../discord/resolvePlayerFromCommand.js'; import errorWithCause from '../node/errorWithCause.js'; import listClansPanServer from './listClansPanServer.js'; diff --git a/src/core/discord/resolvePlayer.ts b/src/core/discord/resolvePlayer.ts deleted file mode 100644 index 003a49e6c..000000000 --- a/src/core/discord/resolvePlayer.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - ButtonInteraction, - CacheType, - ChatInputCommandInteraction, -} from 'discord.js'; -import { CYCLIC_API } from '../../constants/cyclic.js'; -import { BlitzServer } from '../../constants/servers.js'; -import listAccountsPanServer, { - usernamePatternWithoutPosition, -} from '../blitz/listAccountsPanServer.js'; -import errorWithCause from '../node/errorWithCause.js'; - -export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; - -export interface ResolvedPlayer { - server: BlitzServer; - id: number; -} - -export default async function resolvePlayer( - interaction: - | ChatInputCommandInteraction - | ButtonInteraction, -) { - if (interaction instanceof ChatInputCommandInteraction) { - const commandUsername = interaction.options.getString('username'); - const displayName = interaction.guild?.members.cache - .get(interaction.user.id) - ?.displayName.match(usernamePatternWithoutPosition)?.[0]; - const username = commandUsername ?? displayName; - - if (username === undefined) { - throw errorWithCause( - 'Username could not be inferred', - "You didn't provide me a username in the command nor was I able to infer your Blitz username from your Discord nickname. Try providing a username manually in the command or using the `/verify` command to set your Discord nickname to your Blitz username.", - ); - } - - if (serverAndIdPattern.test(username)) { - const [server, accountId] = username.split('/'); - return { - server: server as BlitzServer, - id: Number(accountId), - } satisfies ResolvedPlayer; - } else { - const accounts = await listAccountsPanServer(username); - - if (accounts[0]) { - return { - server: accounts[0].server, - id: accounts[0].account_id, - } satisfies ResolvedPlayer; - } else { - throw errorWithCause( - 'Could not find user', - `I couldn't find user \`${username}\`. Try providing a valid username manually or using the \`/verify\` command to set your Discord nickname to your Blitz username.`, - ); - } - } - } else { - const url = new URL(`${CYCLIC_API}/${interaction.customId}`); - return { - id: parseInt(url.searchParams.get('id')!), - server: url.searchParams.get('server') as BlitzServer, - } satisfies ResolvedPlayer; - } -} diff --git a/src/core/discord/resolvePlayerFromButton.ts b/src/core/discord/resolvePlayerFromButton.ts new file mode 100644 index 000000000..c6b956359 --- /dev/null +++ b/src/core/discord/resolvePlayerFromButton.ts @@ -0,0 +1,9 @@ +import { ButtonInteraction, CacheType } from 'discord.js'; +import { CYCLIC_API } from '../../constants/cyclic.js'; +import resolvePlayerFromURL from '../express/resolvePlayerFromURL.js'; + +export default async function resolvePlayerFromButton( + interaction: ButtonInteraction, +) { + return resolvePlayerFromURL(`${CYCLIC_API}/${interaction.customId}`); +} diff --git a/src/core/discord/resolvePlayerFromCommand.ts b/src/core/discord/resolvePlayerFromCommand.ts new file mode 100644 index 000000000..1707ad7c3 --- /dev/null +++ b/src/core/discord/resolvePlayerFromCommand.ts @@ -0,0 +1,52 @@ +import { CacheType, ChatInputCommandInteraction } from 'discord.js'; +import { BlitzServer } from '../../constants/servers.js'; +import listAccountsPanServer, { + usernamePatternWithoutPosition, +} from '../blitz/listAccountsPanServer.js'; +import errorWithCause from '../node/errorWithCause.js'; + +export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; + +export interface ResolvedPlayer { + server: BlitzServer; + id: number; +} + +export default async function resolvePlayerFromCommand( + interaction: ChatInputCommandInteraction, +) { + const commandUsername = interaction.options.getString('username'); + const displayName = interaction.guild?.members.cache + .get(interaction.user.id) + ?.displayName.match(usernamePatternWithoutPosition)?.[0]; + const username = commandUsername ?? displayName; + + if (username === undefined) { + throw errorWithCause( + 'Username could not be inferred', + "You didn't provide me a username in the command nor was I able to infer your Blitz username from your Discord nickname. Try providing a username manually in the command or using the `/verify` command to set your Discord nickname to your Blitz username.", + ); + } + + if (serverAndIdPattern.test(username)) { + const [server, accountId] = username.split('/'); + return { + server: server as BlitzServer, + id: Number(accountId), + } satisfies ResolvedPlayer; + } else { + const accounts = await listAccountsPanServer(username); + + if (accounts[0]) { + return { + server: accounts[0].server, + id: accounts[0].account_id, + } satisfies ResolvedPlayer; + } else { + throw errorWithCause( + 'Could not find user', + `I couldn't find user \`${username}\`. Try providing a valid username manually or using the \`/verify\` command to set your Discord nickname to your Blitz username.`, + ); + } + } +} diff --git a/src/core/express/resolvePlayerFromRequest.ts b/src/core/express/resolvePlayerFromRequest.ts new file mode 100644 index 000000000..81f34fb2d --- /dev/null +++ b/src/core/express/resolvePlayerFromRequest.ts @@ -0,0 +1,7 @@ +import { Request } from 'express'; +import { CYCLIC_API } from '../../constants/cyclic.js'; +import resolvePlayerFromURL from './resolvePlayerFromURL.js'; + +export default async function resolvePlayerFromRequest(request: Request) { + return resolvePlayerFromURL(`${CYCLIC_API}${request.path}`); +} diff --git a/src/core/express/resolvePlayerFromURL.ts b/src/core/express/resolvePlayerFromURL.ts new file mode 100644 index 000000000..1c9e4f2ff --- /dev/null +++ b/src/core/express/resolvePlayerFromURL.ts @@ -0,0 +1,11 @@ +import { BlitzServer } from '../../constants/servers.js'; +import { ResolvedPlayer } from '../discord/resolvePlayerFromCommand.js'; + +export default async function resolvePlayerFromURL(urlString: string) { + const url = new URL(urlString); + + return { + id: parseInt(url.searchParams.get('id')!), + server: url.searchParams.get('server') as BlitzServer, + } satisfies ResolvedPlayer; +} diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 28d9dde9f..9b1af6974 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -10,7 +10,7 @@ import { tankopedia } from '../core/blitz/tankopedia.js'; import getPlayerHistories from '../core/blitzstars/getPlayerHistories.js'; import getTankHistories from '../core/blitzstars/getTankHistories.js'; import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; -import { ResolvedPlayer } from '../core/discord/resolvePlayer.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { AccountInfo } from '../types/accountInfo.js'; import { Histories } from '../types/histories.js'; diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index d61c51a23..c999673b1 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -13,7 +13,7 @@ import { Tier, tankopedia } from '../core/blitz/tankopedia.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; -import { ResolvedPlayer } from '../core/discord/resolvePlayer.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { AccountInfo, diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index 81ad56736..f84c76bdc 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -14,7 +14,7 @@ import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import { ResolvedPlayer } from '../core/discord/resolvePlayer.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { AccountInfo, AllStats } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; From 9dc48c91256ecac21006af1d0d2a910b6cea78f3 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 02:13:07 +0000 Subject: [PATCH 10/29] feat: switched to parseInt --- src/core/blitz/resolveTankId.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index 6931996ed..2beee53dd 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -3,7 +3,7 @@ import errorWithCause from '../node/errorWithCause.js'; import { TANKS, tankopedia } from './tankopedia.js'; export default function resolveTankId(tank: string) { - const number = Number(tank); + const number = parseInt(tank); if (Number.isNaN(number)) { const searchResult = go(tank, TANKS, { keys: ['name'], limit: 1 }); From c7821d03d2d42bb11a6d255574cf74bfbed52d5b Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 02:13:57 +0000 Subject: [PATCH 11/29] feat: cleaned blitz --- src/commands/eligible.ts | 4 +-- src/commands/inactive.tsx | 2 +- src/commands/searchplayers.ts | 2 +- src/core/blitz/{getWN8.ts => calculateWN8.ts} | 2 +- src/core/blitz/getBlitzClan.ts | 10 +++---- src/core/blitz/getWargamingResponse.ts | 11 +++++++- .../{listClansPanServer.ts => listClans.ts} | 2 +- ...istAccountsPanServer.ts => listPlayers.ts} | 2 +- src/core/blitz/wargamingError.ts | 26 ------------------- src/core/discord/clanAutocomplete.ts | 4 +-- src/core/discord/resolvePlayerFromCommand.ts | 6 ++--- src/core/discord/usernameAutocomplete.ts | 4 +-- src/renderers/stats.tsx | 6 ++--- src/renderers/today.tsx | 9 ++++--- src/types/wargamingResponse.ts | 14 ---------- 15 files changed, 36 insertions(+), 68 deletions(-) rename src/core/blitz/{getWN8.ts => calculateWN8.ts} (94%) rename src/core/blitz/{listClansPanServer.ts => listClans.ts} (95%) rename src/core/blitz/{listAccountsPanServer.ts => listPlayers.ts} (95%) delete mode 100644 src/core/blitz/wargamingError.ts delete mode 100644 src/types/wargamingResponse.ts diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index d4dd2a2c2..5438362e2 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -1,5 +1,5 @@ import { SlashCommandBuilder } from 'discord.js'; -import getWN8 from '../core/blitz/getWN8.js'; +import calculateWN8 from '../core/blitz/calculateWN8.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import sumStats from '../core/blitz/sumStats.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; @@ -79,7 +79,7 @@ export default { // edge case where new tanks don't have averages if (tankAverages[tankId]) { - const tankWN8 = getWN8(tankAverages[tankId].all, stats); + const tankWN8 = calculateWN8(tankAverages[tankId].all, stats); if (isNaN(tankWN8)) return accumulator; return accumulator + tankWN8 * stats.battles; diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index 6e9dd397b..dc52d8163 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -36,7 +36,7 @@ export default { async handler(interaction) { const clanName = interaction.options.getString('clan')!; - const { server, id } = await getBlitzClan(interaction, clanName); + const { server, id } = await getBlitzClan(clanName); const threshold = interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD; const time = new Date().getTime() / 1000; diff --git a/src/commands/searchplayers.ts b/src/commands/searchplayers.ts index afb67450f..f0d6a13ce 100644 --- a/src/commands/searchplayers.ts +++ b/src/commands/searchplayers.ts @@ -2,7 +2,7 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import { usernamePattern } from '../core/blitz/listAccountsPanServer.js'; +import { usernamePattern } from '../core/blitz/listPlayers.js'; import addServerChoices from '../core/discord/addServerChoices.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; import infoEmbed from '../core/discord/infoEmbed.js'; diff --git a/src/core/blitz/getWN8.ts b/src/core/blitz/calculateWN8.ts similarity index 94% rename from src/core/blitz/getWN8.ts rename to src/core/blitz/calculateWN8.ts index 86da436f9..850c2f6ea 100644 --- a/src/core/blitz/getWN8.ts +++ b/src/core/blitz/calculateWN8.ts @@ -3,7 +3,7 @@ import { AllStats } from '../../types/accountInfo.js'; /** * Formula from https://web.archive.org/web/20190105064817/http://wiki.wnefficiency.net/pages/WN8 */ -export default function getWN8(expected: AllStats, average: AllStats) { +export default function calculateWN8(expected: AllStats, average: AllStats) { const avgDmg = average.damage_dealt / average.battles; const avgSpot = average.spotted / average.battles; const avgFrag = average.frags / average.battles; diff --git a/src/core/blitz/getBlitzClan.ts b/src/core/blitz/getBlitzClan.ts index 908950824..3e1cf5b62 100644 --- a/src/core/blitz/getBlitzClan.ts +++ b/src/core/blitz/getBlitzClan.ts @@ -1,18 +1,14 @@ -import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import { BlitzServer } from '../../constants/servers.js'; import { serverAndIdPattern } from '../discord/resolvePlayerFromCommand.js'; import errorWithCause from '../node/errorWithCause.js'; -import listClansPanServer from './listClansPanServer.js'; +import listClans from './listClans.js'; -export default async function getBlitzClan( - interaction: ChatInputCommandInteraction, - clan: string, -) { +export default async function getBlitzClan(clan: string) { if (serverAndIdPattern.test(clan)) { const [server, accountId] = clan.split('/'); return { server: server as BlitzServer, id: Number(accountId) }; } else { - const accounts = await listClansPanServer(clan); + const accounts = await listClans(clan); if (accounts[0]) { return { server: accounts[0].server, id: accounts[0].clan_id }; diff --git a/src/core/blitz/getWargamingResponse.ts b/src/core/blitz/getWargamingResponse.ts index 3d13701ab..76b012190 100644 --- a/src/core/blitz/getWargamingResponse.ts +++ b/src/core/blitz/getWargamingResponse.ts @@ -1,6 +1,15 @@ -import { WargamingResponse } from '../../types/wargamingResponse.js'; import errorWithCause from '../node/errorWithCause.js'; +export type WargamingResponse = + | { + status: 'error'; + error: { field: string; message: string; code: 402; value: null }; + } + | { + status: 'ok'; + data: Data; + }; + export default async function getWargamingResponse( url: string, ) { diff --git a/src/core/blitz/listClansPanServer.ts b/src/core/blitz/listClans.ts similarity index 95% rename from src/core/blitz/listClansPanServer.ts rename to src/core/blitz/listClans.ts index eb435d1b4..f4b8a3364 100644 --- a/src/core/blitz/listClansPanServer.ts +++ b/src/core/blitz/listClans.ts @@ -7,7 +7,7 @@ export type ClanListWithServer = (Clan & { server: 'com' | 'eu' | 'asia'; })[]; -export default async function listClansPanServer(search: string, limit = 9) { +export default async function listClans(search: string, limit = 9) { const trimmed = search.trim(); if (trimmed.length < 3 && trimmed.length > 100) return []; const normalizedLimit = Math.round(limit / 3); diff --git a/src/core/blitz/listAccountsPanServer.ts b/src/core/blitz/listPlayers.ts similarity index 95% rename from src/core/blitz/listAccountsPanServer.ts rename to src/core/blitz/listPlayers.ts index e608ed77a..64e4faf28 100644 --- a/src/core/blitz/listAccountsPanServer.ts +++ b/src/core/blitz/listPlayers.ts @@ -10,7 +10,7 @@ export type AccountListWithServer = (Account & { export const usernamePattern = /^[a-zA-Z0-9_]{3,24}$/; export const usernamePatternWithoutPosition = /[a-zA-Z0-9_]{3,24}/; -export default async function listAccountsPanServer(search: string, limit = 9) { +export default async function listPlayers(search: string, limit = 9) { const trimmedSearch = search.trim(); const normalizedLimit = Math.round(limit / 3); const encodedSearch = encodeURIComponent(trimmedSearch); diff --git a/src/core/blitz/wargamingError.ts b/src/core/blitz/wargamingError.ts deleted file mode 100644 index f27b0092e..000000000 --- a/src/core/blitz/wargamingError.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - CacheType, - ChatInputCommandInteraction, - EmbedBuilder, -} from 'discord.js'; -import { client } from '../../bot.js'; -import { NEGATIVE_COLOR } from '../../constants/colors.js'; -import { handleError } from '../../events/error.js'; - -export default async function wargamingError( - interaction: ChatInputCommandInteraction, - error: Error, - command: string, -) { - await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setColor(NEGATIVE_COLOR) - .setTitle(`${client.user?.username} ran into an issue`) - .setDescription('Wargaming returned an error. Please try again later.'), - ], - }); - - console.log(`Wargaming returned an error`); - handleError(error, command); -} diff --git a/src/core/discord/clanAutocomplete.ts b/src/core/discord/clanAutocomplete.ts index 307665bf3..4f375e749 100644 --- a/src/core/discord/clanAutocomplete.ts +++ b/src/core/discord/clanAutocomplete.ts @@ -4,14 +4,14 @@ import { CacheType, } from 'discord.js'; import { BLITZ_SERVERS } from '../../constants/servers.js'; -import listClansPanServer from '../blitz/listClansPanServer.js'; +import listClans from '../blitz/listClans.js'; export default async function clanAutocomplete( interaction: AutocompleteInteraction, ) { const focusedOption = interaction.options.getFocused(true); if (focusedOption.name !== 'clan') return; - const players = await listClansPanServer(focusedOption.value); + const players = await listClans(focusedOption.value); await interaction.respond( players diff --git a/src/core/discord/resolvePlayerFromCommand.ts b/src/core/discord/resolvePlayerFromCommand.ts index 1707ad7c3..3ed7cb396 100644 --- a/src/core/discord/resolvePlayerFromCommand.ts +++ b/src/core/discord/resolvePlayerFromCommand.ts @@ -1,8 +1,8 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import { BlitzServer } from '../../constants/servers.js'; -import listAccountsPanServer, { +import listPlayers, { usernamePatternWithoutPosition, -} from '../blitz/listAccountsPanServer.js'; +} from '../blitz/listPlayers.js'; import errorWithCause from '../node/errorWithCause.js'; export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; @@ -35,7 +35,7 @@ export default async function resolvePlayerFromCommand( id: Number(accountId), } satisfies ResolvedPlayer; } else { - const accounts = await listAccountsPanServer(username); + const accounts = await listPlayers(username); if (accounts[0]) { return { diff --git a/src/core/discord/usernameAutocomplete.ts b/src/core/discord/usernameAutocomplete.ts index e303e1a56..6b3e8d283 100644 --- a/src/core/discord/usernameAutocomplete.ts +++ b/src/core/discord/usernameAutocomplete.ts @@ -4,14 +4,14 @@ import { CacheType, } from 'discord.js'; import { BLITZ_SERVERS } from '../../constants/servers.js'; -import listAccountsPanServer from '../blitz/listAccountsPanServer.js'; +import listPlayers from '../blitz/listPlayers.js'; export default async function usernameAutocomplete( interaction: AutocompleteInteraction, ) { const focusedOption = interaction.options.getFocused(true); if (focusedOption.name !== 'username') return; - const players = await listAccountsPanServer(focusedOption.value); + const players = await listPlayers(focusedOption.value); try { await interaction.respond( diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index c999673b1..04ad0f87c 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -5,7 +5,7 @@ import TierWeights, { TierWeightsRecord } from '../components/TierWeights.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; -import getWN8 from '../core/blitz/getWN8.js'; +import calculateWN8 from '../core/blitz/calculateWN8.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankName from '../core/blitz/resolveTankName.js'; import sumStats from '../core/blitz/sumStats.js'; @@ -83,7 +83,7 @@ export default async function stats( const tankAverage = tankAverages[tankId]; return tankAverage - ? accumulator + getWN8(tankAverage.all, stats) * stats.battles + ? accumulator + calculateWN8(tankAverage.all, stats) * stats.battles : accumulator; }, 0) / battlesOfTanksWithAverages, tier: @@ -115,7 +115,7 @@ export default async function stats( stats = tankStats[tankId]; supplementaryStats = { - WN8: getWN8(tankAverages[tankId].all, tankStats[tankId]), + WN8: calculateWN8(tankAverages[tankId].all, tankStats[tankId]), tier: tankopedia[tankId].tier, }; } diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index f84c76bdc..ff2736f75 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -4,8 +4,8 @@ import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; +import calculateWN8 from '../core/blitz/calculateWN8.js'; import getTankStats from '../core/blitz/getTankStats.js'; -import getWN8 from '../core/blitz/getWN8.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankName from '../core/blitz/resolveTankName.js'; import sumStats from '../core/blitz/sumStats.js'; @@ -60,7 +60,7 @@ export default async function today({ server, id }: ResolvedPlayer) { ? accumulator : { ...accumulator, - [tankId]: getWN8(tankAverages[tankId].all, tankStats), + [tankId]: calculateWN8(tankAverages[tankId].all, tankStats), }; }, {}, @@ -71,7 +71,10 @@ export default async function today({ server, id }: ResolvedPlayer) { ? accumulator : { ...accumulator, - [tank_id]: getWN8(tankAverages[tank_id].all, careerStats[tank_id]), + [tank_id]: calculateWN8( + tankAverages[tank_id].all, + careerStats[tank_id], + ), }; }, {}, diff --git a/src/types/wargamingResponse.ts b/src/types/wargamingResponse.ts deleted file mode 100644 index 99dbf8a27..000000000 --- a/src/types/wargamingResponse.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type WargamingResponse = - | { - status: 'error'; - error: { - field: string; - message: string; - code: 402; - value: null; - }; - } - | { - status: 'ok'; - data: Data; - }; From 169588a2115b9aa109d8cef406d25e8a9f01fb27 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 02:16:30 +0000 Subject: [PATCH 12/29] feat: cleaned blitzstars --- src/commands/eligible.ts | 4 +-- src/core/blitz/sumStats.ts | 2 +- src/core/blitzstars/blitzStarsError.ts | 28 ------------------- src/core/blitzstars/blitzStarsLinks.ts | 5 ---- src/core/blitzstars/getPlayerHistories.ts | 2 +- src/core/blitzstars/getTankHistories.ts | 2 +- ...StatsOverTime.ts => getTankStatsDiffed.ts} | 2 +- src/core/blitzstars/getTimeDaysAgo.ts | 4 +-- src/core/blitzstars/last5AM.ts | 11 -------- src/core/blitzstars/playerAverage.ts | 2 +- src/core/blitzstars/poweredByBlitzStars.ts | 8 ------ src/renderers/stats.tsx | 4 +-- src/renderers/today.tsx | 4 +-- 13 files changed, 13 insertions(+), 65 deletions(-) delete mode 100644 src/core/blitzstars/blitzStarsError.ts delete mode 100644 src/core/blitzstars/blitzStarsLinks.ts rename src/core/blitzstars/{getTankStatsOverTime.ts => getTankStatsDiffed.ts} (98%) delete mode 100644 src/core/blitzstars/last5AM.ts delete mode 100644 src/core/blitzstars/poweredByBlitzStars.ts diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 5438362e2..adae55419 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -5,7 +5,7 @@ import sumStats from '../core/blitz/sumStats.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getPeriodStart from '../core/blitzstars/getPeriodStart.js'; -import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; +import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import addUsernameOption from '../core/discord/addUsernameOption.js'; import cleanTable, { TableInput } from '../core/discord/cleanTable.js'; @@ -58,7 +58,7 @@ export default { let body = ''; if (clan === 'SKLLD') { - const tankStatsOverTime = await getTankStatsOverTime( + const tankStatsOverTime = await getTankStatsDiffed( server, id, getPeriodStart('30'), diff --git a/src/core/blitz/sumStats.ts b/src/core/blitz/sumStats.ts index 7d990f44c..10b2095a0 100644 --- a/src/core/blitz/sumStats.ts +++ b/src/core/blitz/sumStats.ts @@ -1,5 +1,5 @@ import { AllStats } from '../../types/accountInfo.js'; -import { emptyAllStats } from '../blitzstars/getTankStatsOverTime.js'; +import { emptyAllStats } from '../blitzstars/getTankStatsDiffed.js'; export default function sumStats(allStatsCollection: AllStats[]) { return allStatsCollection.reduce((accumulated, current) => { diff --git a/src/core/blitzstars/blitzStarsError.ts b/src/core/blitzstars/blitzStarsError.ts deleted file mode 100644 index 113f4947f..000000000 --- a/src/core/blitzstars/blitzStarsError.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - CacheType, - ChatInputCommandInteraction, - EmbedBuilder, -} from 'discord.js'; -import { client } from '../../bot.js'; -import { NEGATIVE_COLOR } from '../../constants/colors.js'; -import { handleError } from '../../events/error.js'; - -export default async function blitzStarsError( - interaction: ChatInputCommandInteraction, - error: Error, - command: string, -) { - await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setColor(NEGATIVE_COLOR) - .setTitle(`${client.user?.username} ran into an issue`) - .setDescription( - 'BlitzStars returned an error. Please try again later.', - ), - ], - }); - - console.log(`BlitzStars returned an error`); - handleError(error, command); -} diff --git a/src/core/blitzstars/blitzStarsLinks.ts b/src/core/blitzstars/blitzStarsLinks.ts deleted file mode 100644 index 619da67ea..000000000 --- a/src/core/blitzstars/blitzStarsLinks.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { BlitzServer } from '../../constants/servers.js'; - -export default function blitzStarsLinks(server: BlitzServer, nickname: string) { - return `[View full stats](https://www.blitzstars.com/player/${server}/${nickname}) • [Support BlitzStars](https://www.blitzstars.com/supporters)`; -} diff --git a/src/core/blitzstars/getPlayerHistories.ts b/src/core/blitzstars/getPlayerHistories.ts index a99e1d10d..aed5d135b 100644 --- a/src/core/blitzstars/getPlayerHistories.ts +++ b/src/core/blitzstars/getPlayerHistories.ts @@ -8,7 +8,7 @@ import { } from '../../types/histories.js'; import getWargamingResponse from '../blitz/getWargamingResponse.js'; import { WARGAMING_APPLICATION_ID } from '../node/args.js'; -import { emptyAllStats } from './getTankStatsOverTime.js'; +import { emptyAllStats } from './getTankStatsDiffed.js'; export interface PlayerHistoryRaw { clan: { clan_id: number; name: string; tag: string }; diff --git a/src/core/blitzstars/getTankHistories.ts b/src/core/blitzstars/getTankHistories.ts index 21c324974..4e69e198c 100644 --- a/src/core/blitzstars/getTankHistories.ts +++ b/src/core/blitzstars/getTankHistories.ts @@ -6,7 +6,7 @@ import { getHistoriesDefaultOptions, } from '../../types/histories.js'; import getTankStats from '../blitz/getTankStats.js'; -import { emptyAllStats } from './getTankStatsOverTime.js'; +import { emptyAllStats } from './getTankStatsDiffed.js'; export interface TankHistory extends History { tank_id: number; diff --git a/src/core/blitzstars/getTankStatsOverTime.ts b/src/core/blitzstars/getTankStatsDiffed.ts similarity index 98% rename from src/core/blitzstars/getTankStatsOverTime.ts rename to src/core/blitzstars/getTankStatsDiffed.ts index c1c789822..513f7f21c 100644 --- a/src/core/blitzstars/getTankStatsOverTime.ts +++ b/src/core/blitzstars/getTankStatsDiffed.ts @@ -34,7 +34,7 @@ export const emptyTankHistoryNode: TankHistoryRaw = { all: emptyAllStats, }; -export default async function getTankStatsOverTime( +export default async function getTankStatsDiffed( server: BlitzServer, id: number, start: number, diff --git a/src/core/blitzstars/getTimeDaysAgo.ts b/src/core/blitzstars/getTimeDaysAgo.ts index fc66a9171..86a3512ea 100644 --- a/src/core/blitzstars/getTimeDaysAgo.ts +++ b/src/core/blitzstars/getTimeDaysAgo.ts @@ -1,4 +1,4 @@ -export default function getTimeDaysAgo(period: number) { +export default function getTimeDaysAgo(daysAgo: number) { const now = new Date(); now.setHours(5, 0, 0, 0); @@ -6,7 +6,7 @@ export default function getTimeDaysAgo(period: number) { if (now.getTime() > Date.now()) now.setDate(now.getDate() - 1); // subtract the period number of days from now - now.setDate(now.getDate() - period); + now.setDate(now.getDate() - daysAgo); return now.getTime() / 1000; } diff --git a/src/core/blitzstars/last5AM.ts b/src/core/blitzstars/last5AM.ts deleted file mode 100644 index ba923acc9..000000000 --- a/src/core/blitzstars/last5AM.ts +++ /dev/null @@ -1,11 +0,0 @@ -export default function last5AM() { - const fiveAM = new Date(); - fiveAM.setHours(5, 0, 0, 0); // Set the time to 5:00 AM today - - if (fiveAM > new Date()) { - // If it's now before 5:00 AM, go back one day - fiveAM.setDate(fiveAM.getDate() - 1); - } - - return fiveAM; -} diff --git a/src/core/blitzstars/playerAverage.ts b/src/core/blitzstars/playerAverage.ts index 346298fcf..a2315adb1 100644 --- a/src/core/blitzstars/playerAverage.ts +++ b/src/core/blitzstars/playerAverage.ts @@ -1,5 +1,5 @@ import sumStats from '../blitz/sumStats.js'; -import { emptyAllStats } from './getTankStatsOverTime.js'; +import { emptyAllStats } from './getTankStatsDiffed.js'; import { tankAverages } from './tankAverages.js'; console.log('Calculating player average...'); diff --git a/src/core/blitzstars/poweredByBlitzStars.ts b/src/core/blitzstars/poweredByBlitzStars.ts deleted file mode 100644 index 4967e0461..000000000 --- a/src/core/blitzstars/poweredByBlitzStars.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { EmbedBuilder } from 'discord.js'; - -export default function poweredByBlitzStars(embed: EmbedBuilder) { - return embed.setTimestamp().setFooter({ - text: 'Powered by BlitzStars', - iconURL: 'https://www.blitzstars.com/assets/images/TankyMcPewpew.png', - }); -} diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index 04ad0f87c..b8257dd38 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -10,7 +10,7 @@ import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankName from '../core/blitz/resolveTankName.js'; import sumStats from '../core/blitz/sumStats.js'; import { Tier, tankopedia } from '../core/blitz/tankopedia.js'; -import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; +import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; @@ -49,7 +49,7 @@ export default async function stats( image = tankopedia[tankId].images.normal; } - const tankStats = await getTankStatsOverTime(server, id, start, end); + const tankStats = await getTankStatsDiffed(server, id, start, end); let stats: AllStats; let supplementaryStats: SupplementaryStats; let tierWeights: TierWeightsRecord; diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index ff2736f75..b224921dc 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -11,7 +11,7 @@ import resolveTankName from '../core/blitz/resolveTankName.js'; import sumStats from '../core/blitz/sumStats.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; -import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; +import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; @@ -20,7 +20,7 @@ import { AccountInfo, AllStats } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; export default async function today({ server, id }: ResolvedPlayer) { - const tankStatsOverTime = await getTankStatsOverTime( + const tankStatsOverTime = await getTankStatsDiffed( server, id, getTimeDaysAgo(0), From 01ed20941d2a39053a359e94ce9e935fc903a047 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 02:22:28 +0000 Subject: [PATCH 13/29] feat: cleaned discord --- src/commands/debug.ts | 8 +++---- src/commands/eligible.ts | 16 +++++++------- src/commands/evolution.tsx | 12 +++++----- src/commands/help.ts | 4 ++-- src/commands/inactive.tsx | 4 ++-- src/commands/ownedtanks.tsx | 8 +++---- src/commands/playerachievements.ts | 18 ++++++++------- src/commands/playerinfo.ts | 16 +++++++------- src/commands/searchclans.ts | 4 ++-- src/commands/searchplayers.ts | 8 +++---- src/commands/searchtanks.ts | 4 ++-- src/commands/stats.tsx | 12 +++++----- src/commands/today.tsx | 8 +++---- src/commands/verify.ts | 22 +++++++++---------- ...oups.ts => addStatTypeSubCommandGroups.ts} | 10 +++++---- ...sernameOption.ts => addUsernameChoices.ts} | 2 +- ...lanAutocomplete.ts => autocompleteClan.ts} | 2 +- ...ksAutocomplete.ts => autocompleteTanks.ts} | 2 +- ...utocomplete.ts => autocompleteUsername.ts} | 2 +- .../discord/{infoEmbed.ts => embedInfo.ts} | 2 +- .../{negativeEmbed.ts => embedNegative.ts} | 2 +- .../{positiveEmbed.ts => embedPositive.ts} | 2 +- .../{warningEmbed.ts => embedWarning.ts} | 2 +- src/core/discord/fullBlitzStarsStats.ts | 12 ---------- src/core/discord/generateCustomId.ts | 9 -------- .../{cleanTable.ts => markdownTable.ts} | 2 +- src/core/discord/noMember.ts | 6 ----- src/core/discord/notTrackedByBlitzStars.ts | 6 ----- src/core/discord/supportBlitzStars.ts | 1 + .../handlers/chatInputCommand.ts | 8 +++---- 30 files changed, 93 insertions(+), 121 deletions(-) rename src/core/discord/{addStatsSubCommandGroups.ts => addStatTypeSubCommandGroups.ts} (70%) rename src/core/discord/{addUsernameOption.ts => addUsernameChoices.ts} (75%) rename src/core/discord/{clanAutocomplete.ts => autocompleteClan.ts} (94%) rename src/core/discord/{tanksAutocomplete.ts => autocompleteTanks.ts} (94%) rename src/core/discord/{usernameAutocomplete.ts => autocompleteUsername.ts} (95%) rename src/core/discord/{infoEmbed.ts => embedInfo.ts} (77%) rename src/core/discord/{negativeEmbed.ts => embedNegative.ts} (78%) rename src/core/discord/{positiveEmbed.ts => embedPositive.ts} (78%) rename src/core/discord/{warningEmbed.ts => embedWarning.ts} (78%) delete mode 100644 src/core/discord/fullBlitzStarsStats.ts delete mode 100644 src/core/discord/generateCustomId.ts rename src/core/discord/{cleanTable.ts => markdownTable.ts} (81%) delete mode 100644 src/core/discord/noMember.ts delete mode 100644 src/core/discord/notTrackedByBlitzStars.ts diff --git a/src/commands/debug.ts b/src/commands/debug.ts index bb669e193..9cfb93357 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -3,8 +3,8 @@ import packageJSON from '../../package.json' assert { type: 'json' }; import { client } from '../bot.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import cleanTable from '../core/discord/cleanTable.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import embedInfo from '../core/discord/embedInfo.js'; +import markdownTable from '../core/discord/markdownTable.js'; import getClientId from '../core/node/getClientId.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -23,9 +23,9 @@ export default { const currentTime = new Date().getTime(); const uptime = currentTime - executionStart; - return infoEmbed( + return embedInfo( `${client.user?.username} debug information`, - cleanTable([ + markdownTable([ ['Version', packageJSON.version], ['Client ID', getClientId()], ['Tag', interaction.client.user.tag], diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index adae55419..faa00c9e7 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -7,10 +7,10 @@ import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getPeriodStart from '../core/blitzstars/getPeriodStart.js'; import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; -import cleanTable, { TableInput } from '../core/discord/cleanTable.js'; -import negativeEmbed from '../core/discord/negativeEmbed.js'; -import positiveEmbed from '../core/discord/positiveEmbed.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import embedNegative from '../core/discord/embedNegative.js'; +import embedPositive from '../core/discord/embedPositive.js'; +import markdownTable, { TableInput } from '../core/discord/markdownTable.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; @@ -44,7 +44,7 @@ export default { ) .setRequired(true), ) - .addStringOption(addUsernameOption), + .addStringOption(addUsernameChoices), async handler(interaction) { const clan = interaction.options.getString('clan') as SkilledClan; @@ -137,7 +137,7 @@ export default { isEligible = problems.length === 0; body = isEligible ? 'Player is fully eligible.' - : `Player is not eligible. Shortcomings in 30-day statistics:\n\n${cleanTable( + : `Player is not eligible. Shortcomings in 30-day statistics:\n\n${markdownTable( problems, )}`; } else if (clan === 'SMRI') { @@ -162,11 +162,11 @@ export default { isEligible = problems.length === 0; body = isEligible ? 'Player is fully eligible.' - : `Player is not eligible. Shortcomings in career statistics:\n\n${cleanTable( + : `Player is not eligible. Shortcomings in career statistics:\n\n${markdownTable( problems, )}`; } - return (isEligible ? positiveEmbed : negativeEmbed)(title, body); + return (isEligible ? embedPositive : embedNegative)(title, body); }, } satisfies CommandRegistry; diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index d389e7ed7..165fe79bc 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -1,10 +1,10 @@ import { SlashCommandBuilder } from 'discord.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; -import addStatsSubCommandGroups from '../core/discord/addStatsSubCommandGroups.js'; +import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; +import autocompleteTanks from '../core/discord/autocompleteTanks.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import evolution from '../renderers/evolution.js'; import { StatType } from '../renderers/stats.js'; @@ -14,7 +14,7 @@ export default { inDevelopment: true, inPublic: true, - command: addStatsSubCommandGroups( + command: addStatTypeSubCommandGroups( new SlashCommandBuilder() .setName('evolution') .setDescription('Evolution of statistics'), @@ -45,7 +45,7 @@ export default { }, autocomplete: (interaction) => { - usernameAutocomplete(interaction); - tanksAutocomplete(interaction); + autocompleteUsername(interaction); + autocompleteTanks(interaction); }, } satisfies CommandRegistry; diff --git a/src/commands/help.ts b/src/commands/help.ts index a65c18293..2ce447da2 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; import discord from '../../discord.json' assert { type: 'json' }; import { client } from '../bot.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import embedInfo from '../core/discord/embedInfo.js'; import { CommandRegistry, guildCommands, @@ -18,7 +18,7 @@ export default { .setDescription('All the help you need about the bot'), handler(interaction) { - return infoEmbed( + return embedInfo( `${client.user?.username} help`, `**About**\n${ client.user?.username diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index dc52d8163..d47a52278 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -8,7 +8,7 @@ import { BLITZ_SERVERS } from '../constants/servers.js'; import getBlitzClan from '../core/blitz/getBlitzClan.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addClanChoices from '../core/discord/addClanChoices.js'; -import clanAutocomplete from '../core/discord/clanAutocomplete.js'; +import autocompleteClan from '../core/discord/autocompleteClan.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -84,5 +84,5 @@ export default { ); }, - autocomplete: clanAutocomplete, + autocomplete: autocompleteClan, } satisfies CommandRegistry; diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedtanks.tsx index 7fb28c870..5dd529765 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedtanks.tsx @@ -12,9 +12,9 @@ import { Tier, tankopedia, } from '../core/blitz/tankopedia.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -67,7 +67,7 @@ export default { ) .setRequired(true), ) - .addStringOption(addUsernameOption), + .addStringOption(addUsernameChoices), async handler(interaction) { const tier = Number(interaction.options.getString('tier')); @@ -120,5 +120,5 @@ export default { ); }, - autocomplete: usernameAutocomplete, + autocomplete: autocompleteUsername, } satisfies CommandRegistry; diff --git a/src/commands/playerachievements.ts b/src/commands/playerachievements.ts index b8f9872a4..0f566c6db 100644 --- a/src/commands/playerachievements.ts +++ b/src/commands/playerachievements.ts @@ -2,11 +2,13 @@ import { SlashCommandBuilder } from 'discord.js'; import { startCase } from 'lodash'; import markdownEscape from 'markdown-escape'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; -import cleanTable, { TableInputEntry } from '../core/discord/cleanTable.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import embedInfo from '../core/discord/embedInfo.js'; +import markdownTable, { + TableInputEntry, +} from '../core/discord/markdownTable.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountAchievements } from '../types/accountAchievements.js'; @@ -22,7 +24,7 @@ export default { command: new SlashCommandBuilder() .setName('playerachievements') .setDescription("All the player's achievements") - .addStringOption(addUsernameOption) + .addStringOption(addUsernameChoices) .addStringOption((option) => option .setName('sort') @@ -50,10 +52,10 @@ export default { ...accountAchievements.max_series, }; - return infoEmbed( + return embedInfo( `${markdownEscape(accounts[id].nickname)}'s information`, - cleanTable( + markdownTable( Object.keys(compound) .filter((achievement) => compound[achievement] > 0) .sort( @@ -72,5 +74,5 @@ export default { ); }, - autocomplete: usernameAutocomplete, + autocomplete: autocompleteUsername, } satisfies CommandRegistry; diff --git a/src/commands/playerinfo.ts b/src/commands/playerinfo.ts index b7349f0a8..1066e7e60 100644 --- a/src/commands/playerinfo.ts +++ b/src/commands/playerinfo.ts @@ -1,11 +1,11 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; -import cleanTable from '../core/discord/cleanTable.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import embedInfo from '../core/discord/embedInfo.js'; +import markdownTable from '../core/discord/markdownTable.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -18,7 +18,7 @@ export default { command: new SlashCommandBuilder() .setName('playerinfo') .setDescription('Basic information about a player') - .addStringOption(addUsernameOption), + .addStringOption(addUsernameChoices), async handler(interaction) { const account = await resolvePlayerFromCommand(interaction); @@ -28,10 +28,10 @@ export default { ); const accountInfo = accounts[id]; - return infoEmbed( + return embedInfo( `${markdownEscape(accountInfo.nickname)}'s information`, - cleanTable([ + markdownTable([ ['Nickname', `${accountInfo.nickname}`], ['Battles', `${accountInfo.statistics.all.battles}`], [ @@ -56,5 +56,5 @@ export default { ); }, - autocomplete: usernameAutocomplete, + autocomplete: autocompleteUsername, } satisfies CommandRegistry; diff --git a/src/commands/searchclans.ts b/src/commands/searchclans.ts index 674b18c8a..d29675fe7 100644 --- a/src/commands/searchclans.ts +++ b/src/commands/searchclans.ts @@ -4,7 +4,7 @@ import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addClanChoices from '../core/discord/addClanChoices.js'; import addServerChoices from '../core/discord/addServerChoices.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import embedInfo from '../core/discord/embedInfo.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { ClanList } from '../types/clanList.js'; @@ -35,7 +35,7 @@ export default { `https://api.wotblitz.${server}/wotb/clans/list/?application_id=${WARGAMING_APPLICATION_ID}&search=${clan}&limit=${limit}`, ); - return infoEmbed( + return embedInfo( `Clan search for "${markdownEscape(clan)}" in ${BLITZ_SERVERS[server]}`, clanList.length === 0 ? 'No clans found.' diff --git a/src/commands/searchplayers.ts b/src/commands/searchplayers.ts index f0d6a13ce..aad73abc1 100644 --- a/src/commands/searchplayers.ts +++ b/src/commands/searchplayers.ts @@ -4,8 +4,8 @@ import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import { usernamePattern } from '../core/blitz/listPlayers.js'; import addServerChoices from '../core/discord/addServerChoices.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import embedInfo from '../core/discord/embedInfo.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountList } from '../types/accountList.js'; @@ -20,7 +20,7 @@ export default { .setDescription('Search players in a Blitz server') .addStringOption(addServerChoices) .addStringOption((option) => - addUsernameOption(option).setAutocomplete(false).setRequired(true), + addUsernameChoices(option).setAutocomplete(false).setRequired(true), ) .addIntegerOption((option) => option @@ -43,7 +43,7 @@ export default { ) : []; - return infoEmbed( + return embedInfo( `Player search for "${markdownEscape(name)}" in ${BLITZ_SERVERS[server]}`, `\`\`\`${ players.length === 0 diff --git a/src/commands/searchtanks.ts b/src/commands/searchtanks.ts index dd320f77b..76e4157c3 100644 --- a/src/commands/searchtanks.ts +++ b/src/commands/searchtanks.ts @@ -3,7 +3,7 @@ import { go } from 'fuzzysort'; import markdownEscape from 'markdown-escape'; import { TANK_NAMES } from '../core/blitz/tankopedia.js'; import addTankChoices from '../core/discord/addTankChoices.js'; -import infoEmbed from '../core/discord/infoEmbed.js'; +import embedInfo from '../core/discord/embedInfo.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; export default { @@ -30,7 +30,7 @@ export default { (result) => result.target, ); - return infoEmbed( + return embedInfo( `Tank search for "${markdownEscape(tank)}"`, results.length === 0 ? 'No tanks found.' diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index f2d99b0b8..8194b7db2 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -2,7 +2,9 @@ import { SlashCommandBuilder } from 'discord.js'; import { CYCLIC_API } from '../constants/cyclic.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; import { Period } from '../core/discord/addPeriodSubCommands.js'; -import addStatsSubCommandGroups from '../core/discord/addStatsSubCommandGroups.js'; +import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; +import autocompleteTanks from '../core/discord/autocompleteTanks.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import interactionToURL from '../core/discord/interactionToURL.js'; import linkButton from '../core/discord/linkButton.js'; import primaryButton from '../core/discord/primaryButton.js'; @@ -10,8 +12,6 @@ import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js' import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import tanksAutocomplete from '../core/discord/tanksAutocomplete.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import stats, { StatType } from '../renderers/stats.js'; @@ -20,7 +20,7 @@ export default { inDevelopment: false, inPublic: true, - command: addStatsSubCommandGroups( + command: addStatTypeSubCommandGroups( new SlashCommandBuilder() .setName('stats') .setDescription('In-game statistics'), @@ -51,8 +51,8 @@ export default { }, autocomplete: (interaction) => { - usernameAutocomplete(interaction); - tanksAutocomplete(interaction); + autocompleteUsername(interaction); + autocompleteTanks(interaction); }, async button(interaction) { diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 786148753..e7f29d0e0 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import today from '../renderers/today.js'; @@ -13,7 +13,7 @@ export default { command: new SlashCommandBuilder() .setName('today') .setDescription('A general daily breakdown of your performance') - .addStringOption(addUsernameOption), + .addStringOption(addUsernameChoices), async handler(interaction) { const player = await resolvePlayerFromCommand(interaction); @@ -21,5 +21,5 @@ export default { return await today(player); }, - autocomplete: usernameAutocomplete, + autocomplete: autocompleteUsername, } satisfies CommandRegistry; diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 6888a7455..8ea2582c9 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -2,11 +2,11 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; import discord from '../../discord.json' assert { type: 'json' }; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import addUsernameOption from '../core/discord/addUsernameOption.js'; -import negativeEmbed from '../core/discord/negativeEmbed.js'; -import positiveEmbed from '../core/discord/positiveEmbed.js'; +import addUsernameChoices from '../core/discord/addUsernameChoices.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import embedNegative from '../core/discord/embedNegative.js'; +import embedPositive from '../core/discord/embedPositive.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import usernameAutocomplete from '../core/discord/usernameAutocomplete.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; @@ -20,7 +20,7 @@ export default { command: new SlashCommandBuilder() .setName('verify') .setDescription("Set's the user's username to their in-game name") - .addStringOption((option) => addUsernameOption(option).setRequired(true)), + .addStringOption((option) => addUsernameChoices(option).setRequired(true)), async handler(interaction) { const blitzAccount = await resolvePlayerFromCommand(interaction); @@ -38,13 +38,13 @@ export default { interaction.guild?.members.cache.get(interaction.member?.user.id); if (!interaction.guild?.members.me?.permissions.has('ManageNicknames')) { - return negativeEmbed( + return embedNegative( `${markdownEscape(interaction.user.username)} failed to verify`, "I don't have the permission to change your nickname.", ); } if (!interaction.member || !member) { - return negativeEmbed( + return embedNegative( `${interaction.user.username} is not in this server`, "I couldn't find this person in this server. Did they leave?", ); @@ -55,7 +55,7 @@ export default { if (interaction.guildId === discord.sklld_guild_id) { if (!interaction.guild?.members.me?.permissions.has('ManageRoles')) { - return negativeEmbed( + return embedNegative( `${markdownEscape(interaction.user.username)} failed to verify`, "I don't have the permission to change your manage roles.", ); @@ -65,19 +65,19 @@ export default { await member.roles.add(discord.sklld_peasant_role); } - return positiveEmbed( + return embedPositive( `${interaction.user.username} is verified`, `The user is now verified as ${markdownEscape( accountInfo[id].nickname, )}${markdownEscape(clanTag)}`, ); } catch (error) { - return negativeEmbed( + return embedNegative( `${interaction.user.username} failed to verify`, "I can't change your nickname because you have higher permissions than me. Try setting your nickname to your Blitz username manually.", ); } }, - autocomplete: usernameAutocomplete, + autocomplete: autocompleteUsername, } satisfies CommandRegistry; diff --git a/src/core/discord/addStatsSubCommandGroups.ts b/src/core/discord/addStatTypeSubCommandGroups.ts similarity index 70% rename from src/core/discord/addStatsSubCommandGroups.ts rename to src/core/discord/addStatTypeSubCommandGroups.ts index f24315784..a5657db10 100644 --- a/src/core/discord/addStatsSubCommandGroups.ts +++ b/src/core/discord/addStatTypeSubCommandGroups.ts @@ -1,13 +1,15 @@ import { SlashCommandBuilder } from 'discord.js'; import addPeriodSubCommands from './addPeriodSubCommands.js'; import addTankChoices from './addTankChoices.js'; -import addUsernameOption from './addUsernameOption.js'; +import addUsernameChoices from './addUsernameChoices.js'; -export default function addStatsSubCommandGroups(option: SlashCommandBuilder) { +export default function addStatTypeSubCommandGroups( + option: SlashCommandBuilder, +) { return option .addSubcommandGroup((option) => addPeriodSubCommands(option, (option) => - option.addStringOption(addUsernameOption), + option.addStringOption(addUsernameChoices), ) .setName('player') .setDescription("Player's statistics"), @@ -16,7 +18,7 @@ export default function addStatsSubCommandGroups(option: SlashCommandBuilder) { addPeriodSubCommands(option, (option) => option .addStringOption(addTankChoices) - .addStringOption(addUsernameOption), + .addStringOption(addUsernameChoices), ) .setName('tank') .setDescription("Tank's statistics"), diff --git a/src/core/discord/addUsernameOption.ts b/src/core/discord/addUsernameChoices.ts similarity index 75% rename from src/core/discord/addUsernameOption.ts rename to src/core/discord/addUsernameChoices.ts index c5da50df8..cc089f368 100644 --- a/src/core/discord/addUsernameOption.ts +++ b/src/core/discord/addUsernameChoices.ts @@ -1,6 +1,6 @@ import { SlashCommandStringOption } from 'discord.js'; -export default function addUsernameOption(option: SlashCommandStringOption) { +export default function addUsernameChoices(option: SlashCommandStringOption) { return option .setName('username') .setDescription( diff --git a/src/core/discord/clanAutocomplete.ts b/src/core/discord/autocompleteClan.ts similarity index 94% rename from src/core/discord/clanAutocomplete.ts rename to src/core/discord/autocompleteClan.ts index 4f375e749..78c7df143 100644 --- a/src/core/discord/clanAutocomplete.ts +++ b/src/core/discord/autocompleteClan.ts @@ -6,7 +6,7 @@ import { import { BLITZ_SERVERS } from '../../constants/servers.js'; import listClans from '../blitz/listClans.js'; -export default async function clanAutocomplete( +export default async function autocompleteClan( interaction: AutocompleteInteraction, ) { const focusedOption = interaction.options.getFocused(true); diff --git a/src/core/discord/tanksAutocomplete.ts b/src/core/discord/autocompleteTanks.ts similarity index 94% rename from src/core/discord/tanksAutocomplete.ts rename to src/core/discord/autocompleteTanks.ts index 7d5776f7d..8b45d8022 100644 --- a/src/core/discord/tanksAutocomplete.ts +++ b/src/core/discord/autocompleteTanks.ts @@ -7,7 +7,7 @@ import { go } from 'fuzzysort'; import resolveTankName from '../blitz/resolveTankName.js'; import { TANKS } from '../blitz/tankopedia.js'; -export default async function tanksAutocomplete( +export default async function autocompleteTanks( interaction: AutocompleteInteraction, ) { const focusedOption = interaction.options.getFocused(true); diff --git a/src/core/discord/usernameAutocomplete.ts b/src/core/discord/autocompleteUsername.ts similarity index 95% rename from src/core/discord/usernameAutocomplete.ts rename to src/core/discord/autocompleteUsername.ts index 6b3e8d283..871f424f2 100644 --- a/src/core/discord/usernameAutocomplete.ts +++ b/src/core/discord/autocompleteUsername.ts @@ -6,7 +6,7 @@ import { import { BLITZ_SERVERS } from '../../constants/servers.js'; import listPlayers from '../blitz/listPlayers.js'; -export default async function usernameAutocomplete( +export default async function autocompleteUsername( interaction: AutocompleteInteraction, ) { const focusedOption = interaction.options.getFocused(true); diff --git a/src/core/discord/infoEmbed.ts b/src/core/discord/embedInfo.ts similarity index 77% rename from src/core/discord/infoEmbed.ts rename to src/core/discord/embedInfo.ts index 21976cd95..4c591e1f6 100644 --- a/src/core/discord/infoEmbed.ts +++ b/src/core/discord/embedInfo.ts @@ -1,7 +1,7 @@ import { EmbedBuilder } from 'discord.js'; import { ACCENT_COLOR } from '../../constants/colors.js'; -export default function infoEmbed(title: string, description: string) { +export default function embedInfo(title: string, description: string) { return new EmbedBuilder() .setColor(ACCENT_COLOR) .setTitle(title) diff --git a/src/core/discord/negativeEmbed.ts b/src/core/discord/embedNegative.ts similarity index 78% rename from src/core/discord/negativeEmbed.ts rename to src/core/discord/embedNegative.ts index f01024c82..54e11ab8b 100644 --- a/src/core/discord/negativeEmbed.ts +++ b/src/core/discord/embedNegative.ts @@ -1,7 +1,7 @@ import { EmbedBuilder } from 'discord.js'; import { NEGATIVE_COLOR } from '../../constants/colors.js'; -export default function negativeEmbed(title: string, description: string) { +export default function embedNegative(title: string, description: string) { return new EmbedBuilder() .setColor(NEGATIVE_COLOR) .setTitle(title) diff --git a/src/core/discord/positiveEmbed.ts b/src/core/discord/embedPositive.ts similarity index 78% rename from src/core/discord/positiveEmbed.ts rename to src/core/discord/embedPositive.ts index 29a86adc5..c9067d818 100644 --- a/src/core/discord/positiveEmbed.ts +++ b/src/core/discord/embedPositive.ts @@ -1,7 +1,7 @@ import { EmbedBuilder } from 'discord.js'; import { POSITIVE_COLOR } from '../../constants/colors.js'; -export default function positiveEmbed(title: string, description: string) { +export default function embedPositive(title: string, description: string) { return new EmbedBuilder() .setColor(POSITIVE_COLOR) .setTitle(title) diff --git a/src/core/discord/warningEmbed.ts b/src/core/discord/embedWarning.ts similarity index 78% rename from src/core/discord/warningEmbed.ts rename to src/core/discord/embedWarning.ts index b8006d1c2..45ee01909 100644 --- a/src/core/discord/warningEmbed.ts +++ b/src/core/discord/embedWarning.ts @@ -1,7 +1,7 @@ import { EmbedBuilder } from 'discord.js'; import { WARNING_COLOR } from '../../constants/colors.js'; -export default function warningEmbed(title: string, description: string) { +export default function embedWarning(title: string, description: string) { return new EmbedBuilder() .setColor(WARNING_COLOR) .setTitle(title) diff --git a/src/core/discord/fullBlitzStarsStats.ts b/src/core/discord/fullBlitzStarsStats.ts deleted file mode 100644 index 362e202c5..000000000 --- a/src/core/discord/fullBlitzStarsStats.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ButtonBuilder, ButtonStyle } from 'discord.js'; -import { BlitzServer } from '../../constants/servers.js'; - -export default function fullBlitzStarsStats( - server: BlitzServer, - username: string, -) { - return new ButtonBuilder() - .setLabel('View on BlitzStars') - .setURL(`https://www.blitzstars.com/player/${server}/${username}`) - .setStyle(ButtonStyle.Link); -} diff --git a/src/core/discord/generateCustomId.ts b/src/core/discord/generateCustomId.ts deleted file mode 100644 index 380573365..000000000 --- a/src/core/discord/generateCustomId.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { CacheType, ChatInputCommandInteraction } from 'discord.js'; - -export default function generateCustomId( - interaction: ChatInputCommandInteraction, -) { - return `${interaction.commandName}/${ - interaction.options.getSubcommandGroup() ?? '' - }/${interaction.options.getSubcommand() ?? ''}`; -} diff --git a/src/core/discord/cleanTable.ts b/src/core/discord/markdownTable.ts similarity index 81% rename from src/core/discord/cleanTable.ts rename to src/core/discord/markdownTable.ts index 45961433c..af2f3a475 100644 --- a/src/core/discord/cleanTable.ts +++ b/src/core/discord/markdownTable.ts @@ -1,7 +1,7 @@ export type TableInputEntry = [string, string | number] | []; export type TableInput = TableInputEntry[]; -export default function cleanTable(input: TableInput) { +export default function markdownTable(input: TableInput) { return input .filter((array) => array[1] !== undefined) .map((array) => (array.length === 0 ? '' : `**${array[0]}**: ${array[1]}`)) diff --git a/src/core/discord/noMember.ts b/src/core/discord/noMember.ts deleted file mode 100644 index 6b2071220..000000000 --- a/src/core/discord/noMember.ts +++ /dev/null @@ -1,6 +0,0 @@ -import negativeEmbed from './negativeEmbed.js'; - -export const noMember = negativeEmbed( - 'User of command is not a member', - 'Discord claims that the user of this command does not have an account... strange!', -); diff --git a/src/core/discord/notTrackedByBlitzStars.ts b/src/core/discord/notTrackedByBlitzStars.ts deleted file mode 100644 index 566551cf3..000000000 --- a/src/core/discord/notTrackedByBlitzStars.ts +++ /dev/null @@ -1,6 +0,0 @@ -import negativeEmbed from './negativeEmbed.js'; - -export const notTrackedByBlitzStars = negativeEmbed( - 'No data to display', - 'Player is not tracked by BlitzStars.', -); diff --git a/src/core/discord/supportBlitzStars.ts b/src/core/discord/supportBlitzStars.ts index f7d40c6ee..9953dd818 100644 --- a/src/core/discord/supportBlitzStars.ts +++ b/src/core/discord/supportBlitzStars.ts @@ -1,5 +1,6 @@ import { ButtonBuilder, ButtonStyle } from 'discord.js'; +// TODO: ADD THIS AGAIN IMMEDIATELY export const supportBlitzStars = new ButtonBuilder() .setLabel('Support BlitzStars') .setURL('https://www.blitzstars.com/supporters') diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index 0944dbdb5..090af20b7 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -5,9 +5,9 @@ import { CacheType, ChatInputCommandInteraction, } from 'discord.js'; -import negativeEmbed from '../../../core/discord/negativeEmbed.js'; +import embedNegative from '../../../core/discord/embedNegative.js'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; -import warningEmbed from '../../../core/discord/warningEmbed.js'; +import embedWarning from '../../../core/discord/embedWarning.js'; import { psa } from '../../../core/node/psa.js'; import { handleError } from '../../error.js'; import { commands } from '../index.js'; @@ -29,7 +29,7 @@ export default async function handleChatInputCommand( if (psa.data) { if (!reply.embeds) reply.embeds = []; - reply.embeds.push(warningEmbed(psa.data.title, psa.data.description)); + reply.embeds.push(embedWarning(psa.data.title, psa.data.description)); } await interaction.editReply(reply); @@ -43,7 +43,7 @@ export default async function handleChatInputCommand( await interaction.editReply({ embeds: [ - negativeEmbed( + embedNegative( (error as Error).message, `${(error as Error).cause ?? 'No further information is available.'}`, ), From ab5061ba998a9ae1208a9c507b8ffdbb5d556b8a Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 17:22:27 +0000 Subject: [PATCH 14/29] feat: cleaned node --- src/bot.ts | 2 +- src/commands/eligible.ts | 2 +- src/commands/inactive.tsx | 2 +- src/commands/ownedtanks.tsx | 2 +- src/commands/playerachievements.ts | 2 +- src/commands/playerinfo.ts | 2 +- src/commands/searchclans.ts | 2 +- src/commands/searchplayers.ts | 2 +- src/commands/verify.ts | 2 +- src/core/blitz/getBlitzClan.ts | 4 ++-- src/core/blitz/getTankStats.ts | 6 +++--- src/core/blitz/getWargamingResponse.ts | 4 ++-- src/core/blitz/listClans.ts | 2 +- src/core/blitz/listPlayers.ts | 2 +- src/core/blitz/resolveTankId.ts | 6 +++--- src/core/blitzstars/getPlayerHistories.ts | 2 +- src/core/{node => discord}/psa.ts | 0 src/core/discord/resolvePlayerFromCommand.ts | 6 +++--- src/core/node/{args.ts => arguments.ts} | 0 src/core/node/errorWithCause.ts | 3 --- src/core/node/isDev.ts | 4 +--- src/core/node/isNumber.ts | 2 +- src/core/node/throwError.ts | 3 +++ src/events/interactionCreate/handlers/chatInputCommand.ts | 2 +- src/events/interactionCreate/index.ts | 2 +- src/renderers/evolution.tsx | 2 +- src/renderers/stats.tsx | 2 +- src/renderers/today.tsx | 2 +- 28 files changed, 35 insertions(+), 37 deletions(-) rename src/core/{node => discord}/psa.ts (100%) rename src/core/node/{args.ts => arguments.ts} (100%) delete mode 100644 src/core/node/errorWithCause.ts create mode 100644 src/core/node/throwError.ts diff --git a/src/bot.ts b/src/bot.ts index a8a7c9cca..8d66081c8 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,5 +1,5 @@ import { Client, GatewayIntentBits } from 'discord.js'; -import { DISCORD_TOKEN } from './core/node/args.js'; +import { DISCORD_TOKEN } from './core/node/arguments.js'; import { registerErrorHandlers } from './events/error.js'; import guildMemberAdd from './events/guildMemberAdd.js'; import interactionCreate from './events/interactionCreate/index.js'; diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index faa00c9e7..30ec318cf 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -12,7 +12,7 @@ import embedNegative from '../core/discord/embedNegative.js'; import embedPositive from '../core/discord/embedPositive.js'; import markdownTable, { TableInput } from '../core/discord/markdownTable.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index d47a52278..89bcb0d42 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -9,7 +9,7 @@ import getBlitzClan from '../core/blitz/getBlitzClan.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addClanChoices from '../core/discord/addClanChoices.js'; import autocompleteClan from '../core/discord/autocompleteClan.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { ClanInfo } from '../types/clanInfo.js'; diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedtanks.tsx index 5dd529765..843eafa08 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedtanks.tsx @@ -15,7 +15,7 @@ import { import addUsernameChoices from '../core/discord/addUsernameChoices.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/commands/playerachievements.ts b/src/commands/playerachievements.ts index 0f566c6db..242826988 100644 --- a/src/commands/playerachievements.ts +++ b/src/commands/playerachievements.ts @@ -9,7 +9,7 @@ import markdownTable, { TableInputEntry, } from '../core/discord/markdownTable.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountAchievements } from '../types/accountAchievements.js'; import { AccountInfo } from '../types/accountInfo.js'; diff --git a/src/commands/playerinfo.ts b/src/commands/playerinfo.ts index 1066e7e60..7e34552e3 100644 --- a/src/commands/playerinfo.ts +++ b/src/commands/playerinfo.ts @@ -6,7 +6,7 @@ import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import embedInfo from '../core/discord/embedInfo.js'; import markdownTable from '../core/discord/markdownTable.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; diff --git a/src/commands/searchclans.ts b/src/commands/searchclans.ts index d29675fe7..56244b025 100644 --- a/src/commands/searchclans.ts +++ b/src/commands/searchclans.ts @@ -5,7 +5,7 @@ import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addClanChoices from '../core/discord/addClanChoices.js'; import addServerChoices from '../core/discord/addServerChoices.js'; import embedInfo from '../core/discord/embedInfo.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { ClanList } from '../types/clanList.js'; diff --git a/src/commands/searchplayers.ts b/src/commands/searchplayers.ts index aad73abc1..fba77980e 100644 --- a/src/commands/searchplayers.ts +++ b/src/commands/searchplayers.ts @@ -6,7 +6,7 @@ import { usernamePattern } from '../core/blitz/listPlayers.js'; import addServerChoices from '../core/discord/addServerChoices.js'; import addUsernameChoices from '../core/discord/addUsernameChoices.js'; import embedInfo from '../core/discord/embedInfo.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountList } from '../types/accountList.js'; diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 8ea2582c9..5a3e3402c 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -7,7 +7,7 @@ import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import embedNegative from '../core/discord/embedNegative.js'; import embedPositive from '../core/discord/embedPositive.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/core/blitz/getBlitzClan.ts b/src/core/blitz/getBlitzClan.ts index 3e1cf5b62..d8e7c5311 100644 --- a/src/core/blitz/getBlitzClan.ts +++ b/src/core/blitz/getBlitzClan.ts @@ -1,6 +1,6 @@ import { BlitzServer } from '../../constants/servers.js'; import { serverAndIdPattern } from '../discord/resolvePlayerFromCommand.js'; -import errorWithCause from '../node/errorWithCause.js'; +import throwError from '../node/throwError.js'; import listClans from './listClans.js'; export default async function getBlitzClan(clan: string) { @@ -13,7 +13,7 @@ export default async function getBlitzClan(clan: string) { if (accounts[0]) { return { server: accounts[0].server, id: accounts[0].clan_id }; } else { - throw errorWithCause( + throw throwError( 'Could not find clan', `I couldn't find clan \`${clan}\`. Try selecting a username from the search result.`, ); diff --git a/src/core/blitz/getTankStats.ts b/src/core/blitz/getTankStats.ts index 5579400bb..2f75efd05 100644 --- a/src/core/blitz/getTankStats.ts +++ b/src/core/blitz/getTankStats.ts @@ -1,7 +1,7 @@ import { BLITZ_SERVERS, BlitzServer } from '../../constants/servers.js'; import { TanksStats } from '../../types/tanksStats.js'; -import { WARGAMING_APPLICATION_ID } from '../node/args.js'; -import errorWithCause from '../node/errorWithCause.js'; +import { WARGAMING_APPLICATION_ID } from '../node/arguments.js'; +import throwError from '../node/throwError.js'; import getWargamingResponse from './getWargamingResponse.js'; export default async function getTankStats(server: BlitzServer, id: number) { @@ -10,7 +10,7 @@ export default async function getTankStats(server: BlitzServer, id: number) { ); if (tankStats[id] === null) { - throw errorWithCause( + throw throwError( 'No tank stats available', `Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${BLITZ_SERVERS[server]} server.`, ); diff --git a/src/core/blitz/getWargamingResponse.ts b/src/core/blitz/getWargamingResponse.ts index 76b012190..78edbaa93 100644 --- a/src/core/blitz/getWargamingResponse.ts +++ b/src/core/blitz/getWargamingResponse.ts @@ -1,4 +1,4 @@ -import errorWithCause from '../node/errorWithCause.js'; +import throwError from '../node/throwError.js'; export type WargamingResponse = | { @@ -21,7 +21,7 @@ export default async function getWargamingResponse( if (parsed.status === 'ok') { return parsed.data; } else { - throw errorWithCause( + throw throwError( `Wargaming response error status:"${parsed.status}"`, `Message: "${parsed.error.message}"\nURL: "${url}"`, ); diff --git a/src/core/blitz/listClans.ts b/src/core/blitz/listClans.ts index f4b8a3364..d751e2de7 100644 --- a/src/core/blitz/listClans.ts +++ b/src/core/blitz/listClans.ts @@ -1,6 +1,6 @@ import { BlitzServer } from '../../constants/servers.js'; import { Clan, ClanList } from '../../types/clanList.js'; -import { WARGAMING_APPLICATION_ID } from '../node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../node/arguments.js'; import getWargamingResponse from './getWargamingResponse.js'; export type ClanListWithServer = (Clan & { diff --git a/src/core/blitz/listPlayers.ts b/src/core/blitz/listPlayers.ts index 64e4faf28..5820e59d5 100644 --- a/src/core/blitz/listPlayers.ts +++ b/src/core/blitz/listPlayers.ts @@ -1,6 +1,6 @@ import { BlitzServer } from '../../constants/servers.js'; import { Account, AccountList } from '../../types/accountList.js'; -import { WARGAMING_APPLICATION_ID } from '../node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../node/arguments.js'; import getWargamingResponse from './getWargamingResponse.js'; export type AccountListWithServer = (Account & { diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index 2beee53dd..89da65c1d 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -1,5 +1,5 @@ import { go } from 'fuzzysort'; -import errorWithCause from '../node/errorWithCause.js'; +import throwError from '../node/throwError.js'; import { TANKS, tankopedia } from './tankopedia.js'; export default function resolveTankId(tank: string) { @@ -9,7 +9,7 @@ export default function resolveTankId(tank: string) { const searchResult = go(tank, TANKS, { keys: ['name'], limit: 1 }); if (searchResult.length === 0) { - throw errorWithCause( + throw throwError( 'Tank not found', `Could not find tank by the name "${tank}".`, ); @@ -20,7 +20,7 @@ export default function resolveTankId(tank: string) { if (tankopedia[number]) { return number; } else { - throw errorWithCause( + throw throwError( 'Tank not found', `Could not find tank by the ID "${number}".`, ); diff --git a/src/core/blitzstars/getPlayerHistories.ts b/src/core/blitzstars/getPlayerHistories.ts index aed5d135b..72e6aa852 100644 --- a/src/core/blitzstars/getPlayerHistories.ts +++ b/src/core/blitzstars/getPlayerHistories.ts @@ -7,7 +7,7 @@ import { getHistoriesDefaultOptions, } from '../../types/histories.js'; import getWargamingResponse from '../blitz/getWargamingResponse.js'; -import { WARGAMING_APPLICATION_ID } from '../node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../node/arguments.js'; import { emptyAllStats } from './getTankStatsDiffed.js'; export interface PlayerHistoryRaw { diff --git a/src/core/node/psa.ts b/src/core/discord/psa.ts similarity index 100% rename from src/core/node/psa.ts rename to src/core/discord/psa.ts diff --git a/src/core/discord/resolvePlayerFromCommand.ts b/src/core/discord/resolvePlayerFromCommand.ts index 3ed7cb396..084b8c52f 100644 --- a/src/core/discord/resolvePlayerFromCommand.ts +++ b/src/core/discord/resolvePlayerFromCommand.ts @@ -3,7 +3,7 @@ import { BlitzServer } from '../../constants/servers.js'; import listPlayers, { usernamePatternWithoutPosition, } from '../blitz/listPlayers.js'; -import errorWithCause from '../node/errorWithCause.js'; +import throwError from '../node/throwError.js'; export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; @@ -22,7 +22,7 @@ export default async function resolvePlayerFromCommand( const username = commandUsername ?? displayName; if (username === undefined) { - throw errorWithCause( + throw throwError( 'Username could not be inferred', "You didn't provide me a username in the command nor was I able to infer your Blitz username from your Discord nickname. Try providing a username manually in the command or using the `/verify` command to set your Discord nickname to your Blitz username.", ); @@ -43,7 +43,7 @@ export default async function resolvePlayerFromCommand( id: accounts[0].account_id, } satisfies ResolvedPlayer; } else { - throw errorWithCause( + throw throwError( 'Could not find user', `I couldn't find user \`${username}\`. Try providing a valid username manually or using the \`/verify\` command to set your Discord nickname to your Blitz username.`, ); diff --git a/src/core/node/args.ts b/src/core/node/arguments.ts similarity index 100% rename from src/core/node/args.ts rename to src/core/node/arguments.ts diff --git a/src/core/node/errorWithCause.ts b/src/core/node/errorWithCause.ts deleted file mode 100644 index 0e2ef81c7..000000000 --- a/src/core/node/errorWithCause.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default function errorWithCause(message: string, cause: string) { - return new Error(message, { cause }); -} diff --git a/src/core/node/isDev.ts b/src/core/node/isDev.ts index 3a6db04c9..9167667ba 100644 --- a/src/core/node/isDev.ts +++ b/src/core/node/isDev.ts @@ -1,5 +1,3 @@ -const isDevBoolean = process.env.NODE_ENV === 'development'; - export default function isDev() { - return isDevBoolean; + return process.env.NODE_ENV === 'development'; } diff --git a/src/core/node/isNumber.ts b/src/core/node/isNumber.ts index 930922ecb..3ad11be0a 100644 --- a/src/core/node/isNumber.ts +++ b/src/core/node/isNumber.ts @@ -1,3 +1,3 @@ export default function isNumber(value: any) { - return typeof value === 'number' && !isNaN(value) && isFinite(value); + return typeof value === 'number' && isFinite(value); } diff --git a/src/core/node/throwError.ts b/src/core/node/throwError.ts new file mode 100644 index 000000000..2aa57dec7 --- /dev/null +++ b/src/core/node/throwError.ts @@ -0,0 +1,3 @@ +export default function throwError(message: string, cause: string) { + return new Error(message, { cause }); +} diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index 090af20b7..3422b8121 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -8,7 +8,7 @@ import { import embedNegative from '../../../core/discord/embedNegative.js'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; import embedWarning from '../../../core/discord/embedWarning.js'; -import { psa } from '../../../core/node/psa.js'; +import { psa } from '../../../core/discord/psa.js'; import { handleError } from '../../error.js'; import { commands } from '../index.js'; diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index 4a7ef7b29..b70b6da24 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -28,7 +28,7 @@ import searchtanks from '../../commands/searchtanks.js'; import stats from '../../commands/stats.js'; import today from '../../commands/today.js'; import verify from '../../commands/verify.js'; -import { DISCORD_TOKEN } from '../../core/node/args.js'; +import { DISCORD_TOKEN } from '../../core/node/arguments.js'; import getClientId from '../../core/node/getClientId.js'; import isDev from '../../core/node/isDev.js'; import handleAutocomplete from './handlers/autocomplete.js'; diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 9b1af6974..cff891b6c 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -11,7 +11,7 @@ import getPlayerHistories from '../core/blitzstars/getPlayerHistories.js'; import getTankHistories from '../core/blitzstars/getTankHistories.js'; import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { AccountInfo } from '../types/accountInfo.js'; import { Histories } from '../types/histories.js'; import { PlayerClanData } from '../types/playerClanData.js'; diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index b8257dd38..13e5a6235 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -14,7 +14,7 @@ import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { AccountInfo, AllStats, diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index b224921dc..a880edffc 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -15,7 +15,7 @@ import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo.js'; import { tankAverages } from '../core/blitzstars/tankAverages.js'; import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; -import { WARGAMING_APPLICATION_ID } from '../core/node/args.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { AccountInfo, AllStats } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; From a0ba60a3fb1c794b32287cc1e5d9260a3fdf6b7c Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 17:23:57 +0000 Subject: [PATCH 15/29] feat: cleaned constants --- src/constants/servers.ts | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/constants/servers.ts b/src/constants/servers.ts index d8ce0cd67..593125389 100644 --- a/src/constants/servers.ts +++ b/src/constants/servers.ts @@ -1,19 +1,7 @@ -export const BLITZ_SERVERS = { +export type BlitzServer = 'com' | 'eu' | 'asia'; + +export const BLITZ_SERVERS: Record = { com: 'North America', eu: 'Europe', asia: 'Asia', }; - -export const BLITZ_SERVERS_SHORT = { - com: 'NA', - eu: 'EU', - asia: 'ASIA', -}; - -export const BLITZ_SERVERS_SHORT_INVERSE = { - NA: 'com', - EU: 'eu', - ASIA: 'asia', -}; - -export type BlitzServer = keyof typeof BLITZ_SERVERS; From f8f95af215a9429aeebf1d15f06e370b93ddd56b Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 17:44:15 +0000 Subject: [PATCH 16/29] feat: rename to routers --- package.json | 4 ++-- ...rReturnable.ts => normalizeRouterReturnable.ts} | 6 +++--- src/{responders => routers}/stats.tsx | 4 ++-- src/server.ts | 14 +++++++------- tsconfig.json | 7 ++++++- 5 files changed, 20 insertions(+), 15 deletions(-) rename src/core/express/{normalizeResponderReturnable.ts => normalizeRouterReturnable.ts} (51%) rename src/{responders => routers}/stats.tsx (88%) diff --git a/package.json b/package.json index fcafaa25d..a5129d404 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "build:bot": "node scripts/build --build=bot", "build:server": "node scripts/build --build=server", "build": "yarn lint && node scripts/build --build=all", - "dev:bot": "yarn build:bot --dev && yarn start:bot --dev", - "dev:server": "yarn build:server --dev && yarn start:server --dev", + "dev:bot": "yarn build:bot --dev && yarn start:bot", + "dev:server": "yarn build:server --dev && yarn start:server", "start:bot": "node --enable-source-maps --trace-warnings dist/bot.cjs", "start:server": "node --enable-source-maps --trace-warnings dist/server.cjs", "zip": "zip -r dist.zip dist", diff --git a/src/core/express/normalizeResponderReturnable.ts b/src/core/express/normalizeRouterReturnable.ts similarity index 51% rename from src/core/express/normalizeResponderReturnable.ts rename to src/core/express/normalizeRouterReturnable.ts index 4b9eb100b..5e775e089 100644 --- a/src/core/express/normalizeResponderReturnable.ts +++ b/src/core/express/normalizeRouterReturnable.ts @@ -1,8 +1,8 @@ -import { ResponderReturnable } from '../../server.js'; +import { RouterReturnable } from '../../server.js'; import jsxToSvg from '../node/jsxToSvg.js'; -export default async function normalizeResponderReturnable( - returnable: ResponderReturnable, +export default async function normalizeRouterReturnable( + returnable: RouterReturnable, ) { const awaitedReturnable = await returnable; const svg = await jsxToSvg(awaitedReturnable); diff --git a/src/responders/stats.tsx b/src/routers/stats.tsx similarity index 88% rename from src/responders/stats.tsx rename to src/routers/stats.tsx index bab1e5c5f..a47213a14 100644 --- a/src/responders/stats.tsx +++ b/src/routers/stats.tsx @@ -1,7 +1,7 @@ import { BlitzServer } from '../constants/servers.js'; import resolvePeriodFromRequest from '../core/express/resolvePeriodFromRequest.js'; import stats, { StatType } from '../renderers/stats.js'; -import { ResponderRegistry } from '../server.js'; +import { RouterRegistry } from '../server.js'; export default { route: '/stats/:type/:period', @@ -22,4 +22,4 @@ export default { parseInt(req.query.tank as string), ); }, -} satisfies ResponderRegistry; +} satisfies RouterRegistry; diff --git a/src/server.ts b/src/server.ts index 0c2cf6462..1c4c1ea9d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,12 +1,12 @@ import express, { Request, Response } from 'express'; -import normalizeResponderReturnable from './core/express/normalizeResponderReturnable.js'; +import normalizeRouterReturnable from './core/express/normalizeRouterReturnable.js'; import isDev from './core/node/isDev.js'; import { Registry } from './events/interactionCreate/index.js'; -import stats from './responders/stats.js'; +import stats from './routers/stats.js'; -export type ResponderReturnable = JSX.Element | Promise; +export type RouterReturnable = JSX.Element | Promise; -export interface ResponderRegistry +export interface RouterRegistry extends Registry { route: string; handlesInteraction?: HandlesInteraction; @@ -14,12 +14,12 @@ export interface ResponderRegistry handler: ( req: Request, res: Response, - ) => HandlesInteraction extends true ? void : ResponderReturnable; + ) => HandlesInteraction extends true ? void : RouterReturnable; } const app = express(); -([stats] as ResponderRegistry[]).forEach((registry) => { +([stats] as RouterRegistry[]).forEach((registry) => { if (!(isDev() ? registry.inDevelopment : registry.inProduction)) return; app.get(registry.route, async (req, res) => { @@ -27,7 +27,7 @@ const app = express(); if (registry.handlesInteraction) return; - const response = await normalizeResponderReturnable(returnable); + const response = await normalizeRouterReturnable(returnable); res.writeHead(200, { 'Content-Type': 'image/svg+xml', diff --git a/tsconfig.json b/tsconfig.json index 61fa9c597..f4fceb5f4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,10 @@ "resolveJsonModule": true, "jsx": "react-jsx" }, - "include": ["src/**/*.ts", "src/renderers/stats.tsx", "src/events/interactionCreate/handlers/button.tsx", "src/responders/stats.tsx"] + "include": [ + "src/**/*.ts", + "src/renderers/stats.tsx", + "src/events/interactionCreate/handlers/button.tsx", + "src/routers/stats.tsx" + ] } From da950ad42f8daa676e4cfe20975ae5af4c566e90 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 17:46:54 +0000 Subject: [PATCH 17/29] feat: implemented resolvePlayerFromRequest --- src/core/express/resolvePlayerFromRequest.ts | 2 +- src/core/express/resolvePlayerFromURL.ts | 2 +- src/routers/stats.tsx | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/core/express/resolvePlayerFromRequest.ts b/src/core/express/resolvePlayerFromRequest.ts index 81f34fb2d..e012942c4 100644 --- a/src/core/express/resolvePlayerFromRequest.ts +++ b/src/core/express/resolvePlayerFromRequest.ts @@ -2,6 +2,6 @@ import { Request } from 'express'; import { CYCLIC_API } from '../../constants/cyclic.js'; import resolvePlayerFromURL from './resolvePlayerFromURL.js'; -export default async function resolvePlayerFromRequest(request: Request) { +export default function resolvePlayerFromRequest(request: Request) { return resolvePlayerFromURL(`${CYCLIC_API}${request.path}`); } diff --git a/src/core/express/resolvePlayerFromURL.ts b/src/core/express/resolvePlayerFromURL.ts index 1c9e4f2ff..81608ab13 100644 --- a/src/core/express/resolvePlayerFromURL.ts +++ b/src/core/express/resolvePlayerFromURL.ts @@ -1,7 +1,7 @@ import { BlitzServer } from '../../constants/servers.js'; import { ResolvedPlayer } from '../discord/resolvePlayerFromCommand.js'; -export default async function resolvePlayerFromURL(urlString: string) { +export default function resolvePlayerFromURL(urlString: string) { const url = new URL(urlString); return { diff --git a/src/routers/stats.tsx b/src/routers/stats.tsx index a47213a14..521dbf9a5 100644 --- a/src/routers/stats.tsx +++ b/src/routers/stats.tsx @@ -1,5 +1,5 @@ -import { BlitzServer } from '../constants/servers.js'; import resolvePeriodFromRequest from '../core/express/resolvePeriodFromRequest.js'; +import resolvePlayerFromRequest from '../core/express/resolvePlayerFromRequest.js'; import stats, { StatType } from '../renderers/stats.js'; import { RouterRegistry } from '../server.js'; @@ -11,14 +11,12 @@ export default { async handler(req) { const type = req.params.type as StatType; const period = resolvePeriodFromRequest(req); + const player = resolvePlayerFromRequest(req); return await stats( type, period, - { - server: req.query.server as BlitzServer, - id: parseInt(req.query.id as string), - }, + player, parseInt(req.query.tank as string), ); }, From 8bf803015767682ba644a10fcf0e76550cf56475 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 19:09:01 +0000 Subject: [PATCH 18/29] feat: disabled normies from using dev commands --- src/events/interactionCreate/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index b70b6da24..b4f48ad9e 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -25,7 +25,7 @@ import playerinfo from '../../commands/playerinfo.js'; import searchclans from '../../commands/searchclans.js'; import searchplayers from '../../commands/searchplayers.js'; import searchtanks from '../../commands/searchtanks.js'; -import stats from '../../commands/stats.js'; +import statsfull from '../../commands/statsfull.js'; import today from '../../commands/today.js'; import verify from '../../commands/verify.js'; import { DISCORD_TOKEN } from '../../core/node/arguments.js'; @@ -81,14 +81,14 @@ export const commands: Record = ( searchclans, searchplayers, searchtanks, - stats, + statsfull, today, verify, ping, evolution, ] as CommandRegistry[] ).reduce((accumulator, registry) => { - // if (isDev()) registry.command.setName(`${registry.command.name}dev`); + if (isDev()) registry.command.setDefaultMemberPermissions(0); return { ...accumulator, [registry.command.name]: registry }; }, {}); From 5fb36352d2ba6191f9886f4a41e82d2d50bc8387 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Tue, 27 Jun 2023 19:10:12 +0000 Subject: [PATCH 19/29] feat: renamed stats to statsfull --- .vscode/settings.json | 1 + src/commands/evolution.tsx | 2 +- src/commands/{stats.tsx => statsfull.tsx} | 14 +++++++------- src/renderers/evolution.tsx | 2 +- src/renderers/{stats.tsx => statsfull.tsx} | 2 +- src/routers/stats.tsx | 4 ++-- tsconfig.json | 7 +------ 7 files changed, 14 insertions(+), 18 deletions(-) rename src/commands/{stats.tsx => statsfull.tsx} (88%) rename src/renderers/{stats.tsx => statsfull.tsx} (98%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 68ad53f7a..bc8e18f0c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,6 +20,7 @@ "SKLLD", "Smri", "startcase", + "statsfull", "strvk", "tankaverages", "tankopedia", diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 165fe79bc..3dc6d6ddb 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -7,7 +7,7 @@ import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.j import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import evolution from '../renderers/evolution.js'; -import { StatType } from '../renderers/stats.js'; +import { StatType } from '../renderers/statsfull.js'; export default { inProduction: true, diff --git a/src/commands/stats.tsx b/src/commands/statsfull.tsx similarity index 88% rename from src/commands/stats.tsx rename to src/commands/statsfull.tsx index 8194b7db2..92a1341c2 100644 --- a/src/commands/stats.tsx +++ b/src/commands/statsfull.tsx @@ -13,17 +13,17 @@ import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.j import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; -import stats, { StatType } from '../renderers/stats.js'; +import statsfull, { StatType } from '../renderers/statsfull.js'; export default { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( new SlashCommandBuilder() - .setName('stats') - .setDescription('In-game statistics'), + .setName('statsfull') + .setDescription('Full in-game statistics'), ), async handler(interaction) { @@ -37,14 +37,14 @@ export default { const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); - const path = `stats/${commandGroup}/${subcommand}?server=${ + const path = `statsfull/${commandGroup}/${subcommand}?server=${ player.server }&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; interactionToURL(interaction); return [ - await stats(commandGroup, period, player, tankId), + await statsfull(commandGroup, period, player, tankId), primaryButton(path, 'Refresh'), linkButton(path, 'Embed'), ]; @@ -62,7 +62,7 @@ export default { const period = resolvePeriodFromButton(interaction); const player = await resolvePlayerFromButton(interaction); - return await stats( + return await statsfull( commandGroup, period, player, diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index cff891b6c..7048ed115 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -15,7 +15,7 @@ import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { AccountInfo } from '../types/accountInfo.js'; import { Histories } from '../types/histories.js'; import { PlayerClanData } from '../types/playerClanData.js'; -import { StatType } from './stats.js'; +import { StatType } from './statsfull.js'; export default async function evolution( type: Type, diff --git a/src/renderers/stats.tsx b/src/renderers/statsfull.tsx similarity index 98% rename from src/renderers/stats.tsx rename to src/renderers/statsfull.tsx index 13e5a6235..33fa798de 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/statsfull.tsx @@ -24,7 +24,7 @@ import { PlayerClanData } from '../types/playerClanData.js'; export type StatType = 'player' | 'tank'; -export default async function stats( +export default async function statsfull( type: Type, { start, end, statsName }: ResolvedPeriod, { server, id }: ResolvedPlayer, diff --git a/src/routers/stats.tsx b/src/routers/stats.tsx index 521dbf9a5..cdaea9824 100644 --- a/src/routers/stats.tsx +++ b/src/routers/stats.tsx @@ -1,6 +1,6 @@ import resolvePeriodFromRequest from '../core/express/resolvePeriodFromRequest.js'; import resolvePlayerFromRequest from '../core/express/resolvePlayerFromRequest.js'; -import stats, { StatType } from '../renderers/stats.js'; +import statsfull, { StatType } from '../renderers/statsfull.js'; import { RouterRegistry } from '../server.js'; export default { @@ -13,7 +13,7 @@ export default { const period = resolvePeriodFromRequest(req); const player = resolvePlayerFromRequest(req); - return await stats( + return await statsfull( type, period, player, diff --git a/tsconfig.json b/tsconfig.json index f4fceb5f4..8d1a8a7e4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,10 +11,5 @@ "resolveJsonModule": true, "jsx": "react-jsx" }, - "include": [ - "src/**/*.ts", - "src/renderers/stats.tsx", - "src/events/interactionCreate/handlers/button.tsx", - "src/routers/stats.tsx" - ] + "include": ["src/**/*.ts"] } From 64fd15c0a5a8ee34fbea6d25d0f2c023c21bf526 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 28 Jun 2023 17:58:36 +0000 Subject: [PATCH 20/29] feat: new /stats --- src/commands/evolution.tsx | 2 +- src/commands/stats.tsx | 73 +++++++++ .../components/WN8Display/components/Glow.tsx | 39 +++++ .../components/WN8Display/index.tsx | 77 +++++++++ .../components/WN8SurroundingStat.tsx | 47 ++++++ src/components/AllStatsOverview/index.tsx | 97 ++++++++++++ src/core/node/hslToHex.ts | 22 +++ src/events/interactionCreate/index.ts | 2 + src/renderers/stats.tsx | 149 ++++++++++++++++++ src/routers/stats.tsx | 2 +- tsconfig.json | 3 +- 11 files changed, 510 insertions(+), 3 deletions(-) create mode 100644 src/commands/stats.tsx create mode 100644 src/components/AllStatsOverview/components/WN8Display/components/Glow.tsx create mode 100644 src/components/AllStatsOverview/components/WN8Display/index.tsx create mode 100644 src/components/AllStatsOverview/components/WN8SurroundingStat.tsx create mode 100644 src/components/AllStatsOverview/index.tsx create mode 100644 src/core/node/hslToHex.ts create mode 100644 src/renderers/stats.tsx diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 3dc6d6ddb..5b4b8b1db 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -11,7 +11,7 @@ import { StatType } from '../renderers/statsfull.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx new file mode 100644 index 000000000..e0f85a615 --- /dev/null +++ b/src/commands/stats.tsx @@ -0,0 +1,73 @@ +import { SlashCommandBuilder } from 'discord.js'; +import { CYCLIC_API } from '../constants/cyclic.js'; +import resolveTankId from '../core/blitz/resolveTankId.js'; +import { Period } from '../core/discord/addPeriodSubCommands.js'; +import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; +import autocompleteTanks from '../core/discord/autocompleteTanks.js'; +import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import interactionToURL from '../core/discord/interactionToURL.js'; +import linkButton from '../core/discord/linkButton.js'; +import primaryButton from '../core/discord/primaryButton.js'; +import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; +import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; +import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; +import { CommandRegistry } from '../events/interactionCreate/index.js'; +import stats from '../renderers/stats.js'; +import statsfull, { StatType } from '../renderers/statsfull.js'; + +export default { + inProduction: true, + inDevelopment: true, + inPublic: true, + + command: addStatTypeSubCommandGroups( + new SlashCommandBuilder() + .setName('stats') + .setDescription('In-game statistics'), + ), + + async handler(interaction) { + const commandGroup = interaction.options.getSubcommandGroup( + true, + ) as StatType; + const subcommand = interaction.options.getSubcommand() as Period; + const player = await resolvePlayerFromCommand(interaction); + const period = resolvePeriodFromCommand(interaction); + const tankIdRaw = interaction.options.getString('tank')!; + const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; + const start = interaction.options.getInteger('start'); + const end = interaction.options.getInteger('end'); + const path = `stats/${commandGroup}/${subcommand}?server=${ + player.server + }&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; + + interactionToURL(interaction); + + return [ + await stats(commandGroup, period, player, tankId), + primaryButton(path, 'Refresh'), + linkButton(path, 'Embed'), + ]; + }, + + autocomplete: (interaction) => { + autocompleteUsername(interaction); + autocompleteTanks(interaction); + }, + + async button(interaction) { + const url = new URL(`${CYCLIC_API}/${interaction.customId}`); + const path = url.pathname.split('/').filter(Boolean); + const commandGroup = path[1] as StatType; + const period = resolvePeriodFromButton(interaction); + const player = await resolvePlayerFromButton(interaction); + + return await statsfull( + commandGroup, + period, + player, + parseInt(url.searchParams.get('tankId')!), + ); + }, +} satisfies CommandRegistry; diff --git a/src/components/AllStatsOverview/components/WN8Display/components/Glow.tsx b/src/components/AllStatsOverview/components/WN8Display/components/Glow.tsx new file mode 100644 index 000000000..7c5d2f93e --- /dev/null +++ b/src/components/AllStatsOverview/components/WN8Display/components/Glow.tsx @@ -0,0 +1,39 @@ +import { Percentile } from '../../../../../constants/percentiles.js'; +import hslToHex from '../../../../../core/node/hslToHex.js'; +import { PERCENTILE_COLORS } from '../../../../PercentileIndicator.js'; + +export enum GlowSide { + Top, + Bottom, +} + +export interface GlowProps { + percentile: Percentile; + side: GlowSide; +} + +export function Glow({ percentile, side }: GlowProps) { + const color = PERCENTILE_COLORS[percentile]; + const color1 = hslToHex(color); + const color2 = `${color1}00`; + + const background = `linear-gradient(${ + side === GlowSide.Top ? 0 : 180 + }deg, ${color1} 0%, ${color2} 100%)`; + + return ( +
+
+
+
+
+
+
+ ); +} diff --git a/src/components/AllStatsOverview/components/WN8Display/index.tsx b/src/components/AllStatsOverview/components/WN8Display/index.tsx new file mode 100644 index 000000000..08f257fe2 --- /dev/null +++ b/src/components/AllStatsOverview/components/WN8Display/index.tsx @@ -0,0 +1,77 @@ +import { Percentile } from '../../../../constants/percentiles.js'; +import getWN8Percentile from '../../../../core/blitz/getWN8Percentile.js'; +import { theme } from '../../../../stitches.config.js'; +import { PERCENTILE_COLORS } from '../../../PercentileIndicator.js'; +import { Glow, GlowSide } from './components/Glow.js'; + +export interface WN8DisplayProps { + WN8?: number; +} + +export const PERCENTILE_NAMES = { + [Percentile.VeryBad]: 'Very Bad', + [Percentile.Bad]: 'Bad', + [Percentile.BelowAverage]: 'Below Average', + [Percentile.Average]: 'Average', + [Percentile.AboveAverage]: 'Above Average', + [Percentile.Good]: 'Good', + [Percentile.VeryGood]: 'Very Good', + [Percentile.Great]: 'Great', + [Percentile.Unicum]: 'Unicum', + [Percentile.SuperUnicum]: 'Super Unicum', +}; + +export function WN8Display({ WN8 }: WN8DisplayProps) { + const percentile = + WN8 === undefined ? Percentile.VeryBad : getWN8Percentile(WN8); + const color = PERCENTILE_COLORS[percentile]; + + return ( +
+ + +
+ + {WN8 === undefined ? '--' : WN8.toFixed(0)} + + + {PERCENTILE_NAMES[percentile]} + +
+ + +
+ ); +} diff --git a/src/components/AllStatsOverview/components/WN8SurroundingStat.tsx b/src/components/AllStatsOverview/components/WN8SurroundingStat.tsx new file mode 100644 index 000000000..4c48d00fa --- /dev/null +++ b/src/components/AllStatsOverview/components/WN8SurroundingStat.tsx @@ -0,0 +1,47 @@ +import { theme } from '../../../stitches.config.js'; + +export enum WN8SurroundingStatAlign { + Left, + Right, +} + +export interface WN8SurroundingStatProps { + label: string; + value: string | number; + align?: WN8SurroundingStatAlign; + padded?: boolean; +} + +export function WN8SurroundingStat({ + label, + value, + align = WN8SurroundingStatAlign.Left, + padded = false, +}: WN8SurroundingStatProps) { + return ( +
+ + {value} + + + {label} + +
+ ); +} diff --git a/src/components/AllStatsOverview/index.tsx b/src/components/AllStatsOverview/index.tsx new file mode 100644 index 000000000..0571520e7 --- /dev/null +++ b/src/components/AllStatsOverview/index.tsx @@ -0,0 +1,97 @@ +import { AllStats, SupplementaryStats } from '../../types/accountInfo.js'; +import { WN8Display } from './components/WN8Display/index.js'; +import { + WN8SurroundingStat, + WN8SurroundingStatAlign, +} from './components/WN8SurroundingStat.js'; + +export interface AllStatsOverviewProps { + stats: AllStats; + supplementaryStats: SupplementaryStats; +} + +export default function AllStatsOverview({ + stats, + supplementaryStats, +}: AllStatsOverviewProps) { + return ( +
+
+ + + + +
+ + + +
+ + + + +
+
+ ); +} diff --git a/src/core/node/hslToHex.ts b/src/core/node/hslToHex.ts new file mode 100644 index 000000000..304ed774d --- /dev/null +++ b/src/core/node/hslToHex.ts @@ -0,0 +1,22 @@ +const numberRegex = /\d+(\.\d+)?/g; + +/** + * Thanks to icl7126! + * https://stackoverflow.com/a/44134328/12294756 + */ +export default function hslToHex(hsl: string) { + let [h, s, l] = Array.from(hsl.matchAll(numberRegex)).map((m) => + parseFloat(m[0]), + ); + + l /= 100; + const a = (s * Math.min(l, 1 - l)) / 100; + const f = (n: number) => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return Math.round(255 * color) + .toString(16) + .padStart(2, '0'); // convert to Hex and prefix "0" if needed + }; + return `#${f(0)}${f(8)}${f(4)}`; +} diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index b4f48ad9e..92e145979 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -25,6 +25,7 @@ import playerinfo from '../../commands/playerinfo.js'; import searchclans from '../../commands/searchclans.js'; import searchplayers from '../../commands/searchplayers.js'; import searchtanks from '../../commands/searchtanks.js'; +import stats from '../../commands/stats.js'; import statsfull from '../../commands/statsfull.js'; import today from '../../commands/today.js'; import verify from '../../commands/verify.js'; @@ -86,6 +87,7 @@ export const commands: Record = ( verify, ping, evolution, + stats, ] as CommandRegistry[] ).reduce((accumulator, registry) => { if (isDev()) registry.command.setDefaultMemberPermissions(0); diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx new file mode 100644 index 000000000..aec9de200 --- /dev/null +++ b/src/renderers/stats.tsx @@ -0,0 +1,149 @@ +import AllStatsOverview from '../components/AllStatsOverview/index.js'; +import NoData, { NoDataType } from '../components/NoData.js'; +import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; +import { TierWeightsRecord } from '../components/TierWeights.js'; +import TitleBar from '../components/TitleBar.js'; +import Wrapper from '../components/Wrapper.js'; +import { BLITZ_SERVERS } from '../constants/servers.js'; +import calculateWN8 from '../core/blitz/calculateWN8.js'; +import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; +import resolveTankName from '../core/blitz/resolveTankName.js'; +import sumStats from '../core/blitz/sumStats.js'; +import { Tier, tankopedia } from '../core/blitz/tankopedia.js'; +import getTankStatsDiffed from '../core/blitzstars/getTankStatsDiffed.js'; +import { tankAverages } from '../core/blitzstars/tankAverages.js'; +import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; +import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; +import { + AccountInfo, + AllStats, + SupplementaryStats, +} from '../types/accountInfo.js'; +import { PlayerClanData } from '../types/playerClanData.js'; + +export type StatType = 'player' | 'tank'; + +export default async function stats( + type: Type, + { start, end, statsName }: ResolvedPeriod, + { server, id }: ResolvedPlayer, + tankId: Type extends 'tank' ? number : never, +) { + let nameDiscriminator: string | undefined; + let image: string | undefined; + + if (type === 'player') { + const clan = ( + await getWargamingResponse( + `https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`, + ) + )[id]?.clan; + + if (clan) nameDiscriminator = `[${clan.tag}]`; + image = clan + ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` + : undefined; + } else if (type === 'tank') { + nameDiscriminator = `(${resolveTankName(tankId)})`; + image = tankopedia[tankId].images.normal; + } + + const tankStats = await getTankStatsDiffed(server, id, start, end); + let stats: AllStats; + let supplementaryStats: SupplementaryStats; + let tierWeights: TierWeightsRecord; + + if (type === 'player') { + const entries = Object.entries(tankStats); + stats = sumStats(entries.map(([, stats]) => stats)); + const battlesOfTanksWithAverages = entries.reduce( + (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankAverage = tankAverages[tankId]; + + return tankAverage ? accumulator + stats.battles : accumulator; + }, + 0, + ); + const battlesOfTanksWithTankopediaEntry = entries.reduce( + (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankopediaEntry = tankopedia[tankId]; + + return tankopediaEntry ? accumulator + stats.battles : accumulator; + }, + 0, + ); + + supplementaryStats = { + WN8: + entries.reduce((accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankAverage = tankAverages[tankId]; + + return tankAverage + ? accumulator + calculateWN8(tankAverage.all, stats) * stats.battles + : accumulator; + }, 0) / battlesOfTanksWithAverages, + tier: + entries.reduce((accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankopediaEntry = tankopedia[tankId]; + + return tankopediaEntry + ? accumulator + tankopediaEntry.tier * stats.battles + : accumulator; + }, 0) / battlesOfTanksWithTankopediaEntry, + }; + tierWeights = entries.reduce( + (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tier = tankopedia[tankId].tier as Tier; + + if (accumulator[tier]) { + accumulator[tier]! += stats.battles; + } else { + accumulator[tier] = stats.battles; + } + + return accumulator; + }, + {}, + ); + } else { + stats = tankStats[tankId]; + + supplementaryStats = { + WN8: calculateWN8(tankAverages[tankId].all, tankStats[tankId]), + tier: tankopedia[tankId].tier, + }; + } + + const accountInfo = await getWargamingResponse( + `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, + ); + + return ( + + + + {stats.battles === 0 && } + {stats.battles > 0 && ( + + )} + + + + ); +} diff --git a/src/routers/stats.tsx b/src/routers/stats.tsx index cdaea9824..861933cfe 100644 --- a/src/routers/stats.tsx +++ b/src/routers/stats.tsx @@ -6,7 +6,7 @@ import { RouterRegistry } from '../server.js'; export default { route: '/stats/:type/:period', inProduction: true, - inDevelopment: true, + inDevelopment: false, async handler(req) { const type = req.params.type as StatType; diff --git a/tsconfig.json b/tsconfig.json index 8d1a8a7e4..d47b9a960 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "target": "ESNext", "module": "ESNext", + // "moduleResolution": "Node", TODO: implement Node module resolution "moduleResolution": "nodenext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, @@ -11,5 +12,5 @@ "resolveJsonModule": true, "jsx": "react-jsx" }, - "include": ["src/**/*.ts"] + "include": ["src/**/*.ts", "src/components/AllStatsOverview/components/WN8SurroundingStat.tsx"] } From dd39563d6d6d43848451f734de7d2cac4cce878b Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 28 Jun 2023 18:07:49 +0000 Subject: [PATCH 21/29] feat: merged powered by --- src/commands/inactive.tsx | 4 +-- src/commands/ownedtanks.tsx | 4 +-- src/commands/stats.tsx | 7 ++--- src/components/PoweredBy.tsx | 38 ++++++++++++++++++++++++++ src/components/PoweredByBlitzStars.tsx | 15 ---------- src/components/PoweredByWargaming.tsx | 15 ---------- src/renderers/evolution.tsx | 4 +-- src/renderers/stats.tsx | 4 +-- src/renderers/statsfull.tsx | 4 +-- src/renderers/today.tsx | 4 +-- 10 files changed, 53 insertions(+), 46 deletions(-) create mode 100644 src/components/PoweredBy.tsx delete mode 100644 src/components/PoweredByBlitzStars.tsx delete mode 100644 src/components/PoweredByWargaming.tsx diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index 89bcb0d42..b5687f3b6 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; import GenericStats from '../components/GenericStats/index.js'; import NoData, { NoDataType } from '../components/NoData.js'; -import PoweredByWargaming from '../components/PoweredByWargaming.js'; +import PoweredBy, { PoweredByType } from '../components/PoweredBy.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; @@ -79,7 +79,7 @@ export default { {!hasInactiveMembers && } {hasInactiveMembers && } - + ); }, diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedtanks.tsx index 843eafa08..a7d9ffd59 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedtanks.tsx @@ -1,6 +1,6 @@ import { SlashCommandBuilder } from 'discord.js'; import NoData, { NoDataType } from '../components/NoData.js'; -import PoweredByWargaming from '../components/PoweredByWargaming.js'; +import PoweredBy, { PoweredByType } from '../components/PoweredBy.js'; import * as Tanks from '../components/Tanks/index.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; @@ -115,7 +115,7 @@ export default { )} - + ); }, diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index e0f85a615..2bff4e4e7 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -5,7 +5,6 @@ import { Period } from '../core/discord/addPeriodSubCommands.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; -import interactionToURL from '../core/discord/interactionToURL.js'; import linkButton from '../core/discord/linkButton.js'; import primaryButton from '../core/discord/primaryButton.js'; import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; @@ -14,7 +13,7 @@ import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js' import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import stats from '../renderers/stats.js'; -import statsfull, { StatType } from '../renderers/statsfull.js'; +import { StatType } from '../renderers/statsfull.js'; export default { inProduction: true, @@ -42,7 +41,7 @@ export default { player.server }&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; - interactionToURL(interaction); + // interactionToURL(interaction); return [ await stats(commandGroup, period, player, tankId), @@ -63,7 +62,7 @@ export default { const period = resolvePeriodFromButton(interaction); const player = await resolvePlayerFromButton(interaction); - return await statsfull( + return await stats( commandGroup, period, player, diff --git a/src/components/PoweredBy.tsx b/src/components/PoweredBy.tsx new file mode 100644 index 000000000..aeedde2b6 --- /dev/null +++ b/src/components/PoweredBy.tsx @@ -0,0 +1,38 @@ +import { ReactNode } from 'react'; +import { theme } from '../stitches.config.js'; + +export enum PoweredByType { + BlitzStars, + Wargaming, +} + +export interface PoweredByProps { + type: PoweredByType; + footer?: ReactNode; +} + +const POWERED_BY_IMAGES: Record = { + [PoweredByType.BlitzStars]: + 'https://www.blitzstars.com/assets/images/4b4cb591.TankyMcPewpew.png', + [PoweredByType.Wargaming]: 'https://i.imgur.com/jADGWm0.png', +}; + +const POWERED_BY_NAMES: Record = { + [PoweredByType.BlitzStars]: 'BlitzStars', + [PoweredByType.Wargaming]: 'Wargaming', +}; + +export default function PoweredBy({ type, footer }: PoweredByProps) { + return ( +
+
{footer}
+ +
+ + + Powered by {POWERED_BY_NAMES[type]} + +
+
+ ); +} diff --git a/src/components/PoweredByBlitzStars.tsx b/src/components/PoweredByBlitzStars.tsx deleted file mode 100644 index a1bc33308..000000000 --- a/src/components/PoweredByBlitzStars.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { theme } from '../stitches.config.js'; - -export default function PoweredByBlitzStars() { - return ( -
- - - Powered by BlitzStars - -
- ); -} diff --git a/src/components/PoweredByWargaming.tsx b/src/components/PoweredByWargaming.tsx deleted file mode 100644 index e18ad7e7f..000000000 --- a/src/components/PoweredByWargaming.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { theme } from '../stitches.config.js'; - -export default function PoweredByWargaming() { - return ( -
- - - Powered by Wargaming - -
- ); -} diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 7048ed115..e89f218b5 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -1,6 +1,6 @@ import * as Graph from '../components/Graph/index.js'; import NoData, { NoDataType } from '../components/NoData.js'; -import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; +import PoweredBy, { PoweredByType } from '../components/PoweredBy.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; @@ -128,7 +128,7 @@ export default async function evolution( )} - + ); } diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index aec9de200..c09056f69 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -1,6 +1,6 @@ import AllStatsOverview from '../components/AllStatsOverview/index.js'; import NoData, { NoDataType } from '../components/NoData.js'; -import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; +import PoweredBy, { PoweredByType } from '../components/PoweredBy.js'; import { TierWeightsRecord } from '../components/TierWeights.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; @@ -143,7 +143,7 @@ export default async function stats( /> )} - + ); } diff --git a/src/renderers/statsfull.tsx b/src/renderers/statsfull.tsx index 33fa798de..68c77fba6 100644 --- a/src/renderers/statsfull.tsx +++ b/src/renderers/statsfull.tsx @@ -1,6 +1,6 @@ import GenericAllStats from '../components/GenericAllStats.js'; import NoData, { NoDataType } from '../components/NoData.js'; -import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; +import PoweredBy, { PoweredByType } from '../components/PoweredBy.js'; import TierWeights, { TierWeightsRecord } from '../components/TierWeights.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; @@ -146,7 +146,7 @@ export default async function statsfull( /> )} - + ); } diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index a880edffc..021274e04 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -1,6 +1,6 @@ import * as Breakdown from '../components/Breakdown/index.js'; import NoData, { NoDataType } from '../components/NoData.js'; -import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; +import PoweredBy, { PoweredByType } from '../components/PoweredBy.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; @@ -156,7 +156,7 @@ export default async function today({ server, id }: ResolvedPlayer) { {rows.length === 0 && } {rows.length > 0 && {rows}} - + ); } From d1d8aad6c7bf9dd1cdd26c0d8fb4683d6a57e1e4 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 28 Jun 2023 18:45:14 +0000 Subject: [PATCH 22/29] feat: added all buttons to dynamic commands --- src/commands/evolution.tsx | 65 ++++++++++++++----- src/commands/stats.tsx | 30 ++++++--- src/commands/statsfull.tsx | 27 +++++--- src/commands/today.tsx | 32 ++++++++- src/core/discord/interactionToURL.ts | 31 ++++++--- src/core/discord/linkButton.ts | 5 +- .../interactionCreate/handlers/button.tsx | 4 +- src/renderers/evolution.tsx | 8 +-- src/renderers/stats.tsx | 12 ++-- 9 files changed, 157 insertions(+), 57 deletions(-) diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 5b4b8b1db..f7e65edf6 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -1,17 +1,26 @@ import { SlashCommandBuilder } from 'discord.js'; +import { CYCLIC_API } from '../constants/cyclic.js'; +import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import interactionToURL from '../core/discord/interactionToURL.js'; +import linkButton from '../core/discord/linkButton.js'; +import primaryButton from '../core/discord/primaryButton.js'; +import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; +import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import evolution from '../renderers/evolution.js'; import { StatType } from '../renderers/statsfull.js'; +import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( @@ -27,25 +36,51 @@ export default { const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; - const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; + const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null; + const start = interaction.options.getInteger('start'); + const end = interaction.options.getInteger('end'); + const { nickname } = ( + await getWargamingResponse( + `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + ) + )[player.id]; + const path = interactionToURL(interaction, { + ...player, + tankId, + start, + end, + }); - return await evolution(commandGroup, period, player, tankId); - - // TODO: implement this - // new ButtonBuilder() - // .setStyle(ButtonStyle.Link) - // .setLabel('View on BlitzStars') - // .setURL( - // commandGroup === 'tank' - // ? `https://www.blitzstars.com/player/com/${ - // accountInfo[id].nickname - // }/tank/${tankId!}` - // : `https://www.blitzstars.com/player/com/${accountInfo[id].nickname}`, - // ); + return [ + await evolution(commandGroup, period, player, tankId), + primaryButton(path, 'Refresh'), + linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + linkButton( + `https://www.blitzstars.com/player/${player.server}/${nickname}${ + commandGroup === 'tank' ? `/tank/${tankId!}` : '' + }`, + 'BlitzStars', + ), + ]; }, autocomplete: (interaction) => { autocompleteUsername(interaction); autocompleteTanks(interaction); }, + + async button(interaction) { + const url = new URL(`${CYCLIC_API}/${interaction.customId}`); + const path = url.pathname.split('/').filter(Boolean); + const commandGroup = path[1] as StatType; + const period = resolvePeriodFromButton(interaction); + const player = await resolvePlayerFromButton(interaction); + + return await evolution( + commandGroup, + period, + player, + parseInt(url.searchParams.get('tankId')!), + ); + }, } satisfies CommandRegistry; diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 2bff4e4e7..4f29fbda2 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -1,19 +1,22 @@ import { SlashCommandBuilder } from 'discord.js'; import { CYCLIC_API } from '../constants/cyclic.js'; +import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; -import { Period } from '../core/discord/addPeriodSubCommands.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import interactionToURL from '../core/discord/interactionToURL.js'; import linkButton from '../core/discord/linkButton.js'; import primaryButton from '../core/discord/primaryButton.js'; import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import stats from '../renderers/stats.js'; import { StatType } from '../renderers/statsfull.js'; +import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, @@ -30,23 +33,32 @@ export default { const commandGroup = interaction.options.getSubcommandGroup( true, ) as StatType; - const subcommand = interaction.options.getSubcommand() as Period; const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; - const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; + const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); - const path = `stats/${commandGroup}/${subcommand}?server=${ - player.server - }&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; - - // interactionToURL(interaction); + const path = interactionToURL(interaction, { + ...player, + tankId, + start, + end, + }); + const { nickname } = ( + await getWargamingResponse( + `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + ) + )[player.id]; return [ await stats(commandGroup, period, player, tankId), primaryButton(path, 'Refresh'), - linkButton(path, 'Embed'), + linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + linkButton( + `https://www.blitzstars.com/player/${player.server}/${nickname}`, + 'BlitzStars', + ), ]; }, diff --git a/src/commands/statsfull.tsx b/src/commands/statsfull.tsx index 92a1341c2..2e8a23e4b 100644 --- a/src/commands/statsfull.tsx +++ b/src/commands/statsfull.tsx @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; import { CYCLIC_API } from '../constants/cyclic.js'; +import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankId from '../core/blitz/resolveTankId.js'; -import { Period } from '../core/discord/addPeriodSubCommands.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; @@ -12,8 +12,10 @@ import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js' import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import statsfull, { StatType } from '../renderers/statsfull.js'; +import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, @@ -30,23 +32,32 @@ export default { const commandGroup = interaction.options.getSubcommandGroup( true, ) as StatType; - const subcommand = interaction.options.getSubcommand() as Period; const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); - const path = `statsfull/${commandGroup}/${subcommand}?server=${ - player.server - }&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; - - interactionToURL(interaction); + const path = interactionToURL(interaction, { + ...player, + tankId, + start, + end, + }); + const { nickname } = ( + await getWargamingResponse( + `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + ) + )[player.id]; return [ await statsfull(commandGroup, period, player, tankId), primaryButton(path, 'Refresh'), - linkButton(path, 'Embed'), + linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + linkButton( + `https://www.blitzstars.com/player/${player.server}/${nickname}`, + 'BlitzStars', + ), ]; }, diff --git a/src/commands/today.tsx b/src/commands/today.tsx index e7f29d0e0..324c92b77 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -1,13 +1,21 @@ import { SlashCommandBuilder } from 'discord.js'; +import { CYCLIC_API } from '../constants/cyclic.js'; +import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addUsernameChoices from '../core/discord/addUsernameChoices.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; +import interactionToURL from '../core/discord/interactionToURL.js'; +import linkButton from '../core/discord/linkButton.js'; +import primaryButton from '../core/discord/primaryButton.js'; +import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; +import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import today from '../renderers/today.js'; +import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() @@ -17,9 +25,29 @@ export default { async handler(interaction) { const player = await resolvePlayerFromCommand(interaction); + const { nickname } = ( + await getWargamingResponse( + `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + ) + )[player.id]; + const path = interactionToURL(interaction, player); - return await today(player); + return [ + await today(player), + primaryButton(path, 'Refresh'), + linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + linkButton( + `https://www.blitzstars.com/player/${player.server}/${nickname}`, + 'BlitzStars', + ), + ]; }, autocomplete: autocompleteUsername, + + async button(interaction) { + const player = await resolvePlayerFromButton(interaction); + + return await today(player); + }, } satisfies CommandRegistry; diff --git a/src/core/discord/interactionToURL.ts b/src/core/discord/interactionToURL.ts index 1dc5041a4..25e903f5d 100644 --- a/src/core/discord/interactionToURL.ts +++ b/src/core/discord/interactionToURL.ts @@ -1,20 +1,33 @@ -import { CacheType, ChatInputCommandInteraction } from 'discord.js'; +import { + CacheType, + ChatInputCommandInteraction, + CommandInteractionOption, +} from 'discord.js'; + +export interface Parameters { + [key: string]: CommandInteractionOption['value'] | undefined | null; +} export default function interactionToURL( interaction: ChatInputCommandInteraction, + parameters?: Parameters, ) { const pathname = [ interaction.commandName, - interaction.options.getSubcommandGroup(), - interaction.options.getSubcommand(), + interaction.options.getSubcommandGroup(false), + interaction.options.getSubcommand(false), ] .filter(Boolean) .join('/'); - const urlSearchParams = new URLSearchParams(); + const params = [ + ...interaction.options.data.map( + (option) => [option.name, option.value] as const, + ), + ...Object.entries(parameters ?? {}), + ] + .filter(([, value]) => value !== undefined && value !== null) + .map(([key, value]) => `${key}=${value}`) + .join('&'); - interaction.options.data.forEach((option) => { - if (option.value) urlSearchParams.set(option.name, `${option.value}`); - }); - - console.log(`${urlSearchParams}`); + return `${pathname}${params.length > 0 ? `?${params}` : ''}`; } diff --git a/src/core/discord/linkButton.ts b/src/core/discord/linkButton.ts index 1215518a2..c553b009b 100644 --- a/src/core/discord/linkButton.ts +++ b/src/core/discord/linkButton.ts @@ -3,16 +3,15 @@ import { ButtonStyle, ComponentEmojiResolvable, } from 'discord.js'; -import { CYCLIC_API } from '../../constants/cyclic.js'; export default function linkButton( - id: string, + url: string, label: string, emoji?: ComponentEmojiResolvable, ) { const button = new ButtonBuilder() .setStyle(ButtonStyle.Link) - .setURL(`${CYCLIC_API}/${id}`) + .setURL(url) .setLabel(label); if (emoji) button.setEmoji(emoji); diff --git a/src/events/interactionCreate/handlers/button.tsx b/src/events/interactionCreate/handlers/button.tsx index 82a33f013..4bf3d0251 100644 --- a/src/events/interactionCreate/handlers/button.tsx +++ b/src/events/interactionCreate/handlers/button.tsx @@ -1,11 +1,13 @@ import { ButtonInteraction, CacheType } from 'discord.js'; +import { CYCLIC_API } from '../../../constants/cyclic.js'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; import { commands } from '../index.js'; export default async function handleButton( interaction: ButtonInteraction, ) { - const commandName = interaction.customId.split('/')[0]; + const url = new URL(`${CYCLIC_API}/${interaction.customId}`); + const commandName = url.pathname.split('/')[1]; const button = commands[commandName]?.button; if (!button) { diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index e89f218b5..1cce51f92 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -21,7 +21,7 @@ export default async function evolution( type: Type, { start, end, evolutionName }: ResolvedPeriod, { server, id }: ResolvedPlayer, - tankId: Type extends 'tank' ? number : never, + tankId: Type extends 'tank' ? number : null, ) { let nameDiscriminator: string | undefined; let image: string | undefined; @@ -38,8 +38,8 @@ export default async function evolution( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else { - nameDiscriminator = `(${resolveTankName(tankId)})`; - image = tankopedia[tankId].images.normal; + nameDiscriminator = `(${resolveTankName(tankId!)})`; + image = tankopedia[tankId!].images.normal; } let histories: Histories; @@ -53,7 +53,7 @@ export default async function evolution( }); } else { histories = await getTankHistories(server, id, { - tankId, + tankId: tankId!, start, end, includeLatestHistories: true, diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index c09056f69..c2d6401fa 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -28,7 +28,7 @@ export default async function stats( type: Type, { start, end, statsName }: ResolvedPeriod, { server, id }: ResolvedPlayer, - tankId: Type extends 'tank' ? number : never, + tankId: Type extends 'tank' ? number : null, ) { let nameDiscriminator: string | undefined; let image: string | undefined; @@ -45,8 +45,8 @@ export default async function stats( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else if (type === 'tank') { - nameDiscriminator = `(${resolveTankName(tankId)})`; - image = tankopedia[tankId].images.normal; + nameDiscriminator = `(${resolveTankName(tankId!)})`; + image = tankopedia[tankId!].images.normal; } const tankStats = await getTankStatsDiffed(server, id, start, end); @@ -112,11 +112,11 @@ export default async function stats( {}, ); } else { - stats = tankStats[tankId]; + stats = tankStats[tankId!]; supplementaryStats = { - WN8: calculateWN8(tankAverages[tankId].all, tankStats[tankId]), - tier: tankopedia[tankId].tier, + WN8: calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]), + tier: tankopedia[tankId!].tier, }; } From c2d2d076f0a27208ac7f9739069297be8ef1d3db Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 28 Jun 2023 18:48:10 +0000 Subject: [PATCH 23/29] fix: /statsfull now uses null tankId when not available --- src/commands/statsfull.tsx | 2 +- src/renderers/statsfull.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commands/statsfull.tsx b/src/commands/statsfull.tsx index 2e8a23e4b..023466552 100644 --- a/src/commands/statsfull.tsx +++ b/src/commands/statsfull.tsx @@ -35,7 +35,7 @@ export default { const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; - const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; + const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); const path = interactionToURL(interaction, { diff --git a/src/renderers/statsfull.tsx b/src/renderers/statsfull.tsx index 68c77fba6..a5617a208 100644 --- a/src/renderers/statsfull.tsx +++ b/src/renderers/statsfull.tsx @@ -28,7 +28,7 @@ export default async function statsfull( type: Type, { start, end, statsName }: ResolvedPeriod, { server, id }: ResolvedPlayer, - tankId: Type extends 'tank' ? number : never, + tankId: Type extends 'tank' ? number : null, ) { let nameDiscriminator: string | undefined; let image: string | undefined; @@ -45,8 +45,8 @@ export default async function statsfull( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else if (type === 'tank') { - nameDiscriminator = `(${resolveTankName(tankId)})`; - image = tankopedia[tankId].images.normal; + nameDiscriminator = `(${resolveTankName(tankId!)})`; + image = tankopedia[tankId!].images.normal; } const tankStats = await getTankStatsDiffed(server, id, start, end); @@ -112,11 +112,11 @@ export default async function statsfull( {}, ); } else { - stats = tankStats[tankId]; + stats = tankStats[tankId!]; supplementaryStats = { - WN8: calculateWN8(tankAverages[tankId].all, tankStats[tankId]), - tier: tankopedia[tankId].tier, + WN8: calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]), + tier: tankopedia[tankId!].tier, }; } From 4c9715988d8831e41f548abc194cf89579539547 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 28 Jun 2023 19:27:47 +0000 Subject: [PATCH 24/29] feat: disabled embeds for non-routed commands --- src/commands/evolution.tsx | 2 +- src/commands/statsfull.tsx | 2 +- src/commands/today.tsx | 3 +-- src/components/AllStatsOverview/index.tsx | 3 +-- src/core/express/resolvePlayerFromRequest.ts | 2 +- src/renderers/stats.tsx | 15 ++++++++------- src/routers/stats.tsx | 9 +++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index f7e65edf6..020c60fd5 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -54,7 +54,7 @@ export default { return [ await evolution(commandGroup, period, player, tankId), primaryButton(path, 'Refresh'), - linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + // linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( `https://www.blitzstars.com/player/${player.server}/${nickname}${ commandGroup === 'tank' ? `/tank/${tankId!}` : '' diff --git a/src/commands/statsfull.tsx b/src/commands/statsfull.tsx index 023466552..2eedd49b5 100644 --- a/src/commands/statsfull.tsx +++ b/src/commands/statsfull.tsx @@ -53,7 +53,7 @@ export default { return [ await statsfull(commandGroup, period, player, tankId), primaryButton(path, 'Refresh'), - linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + // linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( `https://www.blitzstars.com/player/${player.server}/${nickname}`, 'BlitzStars', diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 324c92b77..86587df48 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -1,5 +1,4 @@ import { SlashCommandBuilder } from 'discord.js'; -import { CYCLIC_API } from '../constants/cyclic.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import addUsernameChoices from '../core/discord/addUsernameChoices.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js'; @@ -35,7 +34,7 @@ export default { return [ await today(player), primaryButton(path, 'Refresh'), - linkButton(`${CYCLIC_API}/${path}`, 'Embed'), + // linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( `https://www.blitzstars.com/player/${player.server}/${nickname}`, 'BlitzStars', diff --git a/src/components/AllStatsOverview/index.tsx b/src/components/AllStatsOverview/index.tsx index 0571520e7..3a2834d73 100644 --- a/src/components/AllStatsOverview/index.tsx +++ b/src/components/AllStatsOverview/index.tsx @@ -19,8 +19,7 @@ export default function AllStatsOverview({ style={{ display: 'flex', gap: -64, - // alignItems: 'center', - // justifyContent: 'center', + width: '100%', }} >
( { start, end, statsName }: ResolvedPeriod, { server, id }: ResolvedPlayer, tankId: Type extends 'tank' ? number : null, + naked = false, ) { let nameDiscriminator: string | undefined; let image: string | undefined; @@ -123,8 +124,13 @@ export default async function stats( const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); + const overview = ( + + ); - return ( + return naked ? ( + overview + ) : ( ( /> {stats.battles === 0 && } - {stats.battles > 0 && ( - - )} + {stats.battles > 0 && overview} diff --git a/src/routers/stats.tsx b/src/routers/stats.tsx index 861933cfe..dc8c5c661 100644 --- a/src/routers/stats.tsx +++ b/src/routers/stats.tsx @@ -1,23 +1,24 @@ import resolvePeriodFromRequest from '../core/express/resolvePeriodFromRequest.js'; import resolvePlayerFromRequest from '../core/express/resolvePlayerFromRequest.js'; -import statsfull, { StatType } from '../renderers/statsfull.js'; +import stats, { StatType } from '../renderers/stats.js'; import { RouterRegistry } from '../server.js'; export default { route: '/stats/:type/:period', inProduction: true, - inDevelopment: false, + inDevelopment: true, async handler(req) { const type = req.params.type as StatType; const period = resolvePeriodFromRequest(req); const player = resolvePlayerFromRequest(req); - return await statsfull( + return await stats( type, period, player, - parseInt(req.query.tank as string), + parseInt(req.query.tankId as string), + true, ); }, } satisfies RouterRegistry; From e81c0cbc1e1dd52b6bf3c56880f9ad2e45e3fe31 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 28 Jun 2023 19:34:35 +0000 Subject: [PATCH 25/29] feat: footer for stats --- src/commands/evolution.tsx | 2 +- src/commands/stats.tsx | 2 +- src/commands/statsfull.tsx | 2 +- src/commands/today.tsx | 2 +- src/components/PoweredBy.tsx | 2 +- src/renderers/stats.tsx | 15 ++++++++++++++- src/routers/stats.tsx | 2 +- 7 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 020c60fd5..62123fa81 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 4f29fbda2..2c92ae620 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/commands/statsfull.tsx b/src/commands/statsfull.tsx index 2eedd49b5..1683abb8d 100644 --- a/src/commands/statsfull.tsx +++ b/src/commands/statsfull.tsx @@ -19,7 +19,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 86587df48..950297142 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -14,7 +14,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/components/PoweredBy.tsx b/src/components/PoweredBy.tsx index aeedde2b6..fc376f057 100644 --- a/src/components/PoweredBy.tsx +++ b/src/components/PoweredBy.tsx @@ -25,7 +25,7 @@ const POWERED_BY_NAMES: Record = { export default function PoweredBy({ type, footer }: PoweredByProps) { return (
-
{footer}
+
{footer}
diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index 60f40e567..bbcfb9629 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -15,6 +15,7 @@ import { tankAverages } from '../core/blitzstars/tankAverages.js'; import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand.js'; import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; +import { theme } from '../stitches.config.js'; import { AccountInfo, AllStats, @@ -127,6 +128,18 @@ export default async function stats( const overview = ( ); + const footer = ( + + /statsfull for all statistics + + ); return naked ? ( overview @@ -144,7 +157,7 @@ export default async function stats( {stats.battles === 0 && } {stats.battles > 0 && overview} - + ); } diff --git a/src/routers/stats.tsx b/src/routers/stats.tsx index dc8c5c661..c6e5c30f0 100644 --- a/src/routers/stats.tsx +++ b/src/routers/stats.tsx @@ -6,7 +6,7 @@ import { RouterRegistry } from '../server.js'; export default { route: '/stats/:type/:period', inProduction: true, - inDevelopment: true, + inDevelopment: false, async handler(req) { const type = req.params.type as StatType; From 3fd90588a38a1075ef6489746c43ca0418c69ac3 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Thu, 29 Jun 2023 01:34:02 +0000 Subject: [PATCH 26/29] feat: renamed routers to routes --- src/commands/stats.tsx | 2 +- ...erReturnable.ts => normalizeRouteReturnable.ts} | 6 +++--- src/{routers => routes}/stats.tsx | 4 ++-- src/server.ts | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) rename src/core/express/{normalizeRouterReturnable.ts => normalizeRouteReturnable.ts} (53%) rename src/{routers => routes}/stats.tsx (89%) diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 2c92ae620..4f29fbda2 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/core/express/normalizeRouterReturnable.ts b/src/core/express/normalizeRouteReturnable.ts similarity index 53% rename from src/core/express/normalizeRouterReturnable.ts rename to src/core/express/normalizeRouteReturnable.ts index 5e775e089..f630232da 100644 --- a/src/core/express/normalizeRouterReturnable.ts +++ b/src/core/express/normalizeRouteReturnable.ts @@ -1,8 +1,8 @@ -import { RouterReturnable } from '../../server.js'; +import { RouteReturnable } from '../../server.js'; import jsxToSvg from '../node/jsxToSvg.js'; -export default async function normalizeRouterReturnable( - returnable: RouterReturnable, +export default async function normalizeRouteReturnable( + returnable: RouteReturnable, ) { const awaitedReturnable = await returnable; const svg = await jsxToSvg(awaitedReturnable); diff --git a/src/routers/stats.tsx b/src/routes/stats.tsx similarity index 89% rename from src/routers/stats.tsx rename to src/routes/stats.tsx index c6e5c30f0..3ce638a67 100644 --- a/src/routers/stats.tsx +++ b/src/routes/stats.tsx @@ -1,7 +1,7 @@ import resolvePeriodFromRequest from '../core/express/resolvePeriodFromRequest.js'; import resolvePlayerFromRequest from '../core/express/resolvePlayerFromRequest.js'; import stats, { StatType } from '../renderers/stats.js'; -import { RouterRegistry } from '../server.js'; +import { RouteRegistry } from '../server.js'; export default { route: '/stats/:type/:period', @@ -21,4 +21,4 @@ export default { true, ); }, -} satisfies RouterRegistry; +} satisfies RouteRegistry; diff --git a/src/server.ts b/src/server.ts index 1c4c1ea9d..8048bb0fb 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,12 +1,12 @@ import express, { Request, Response } from 'express'; -import normalizeRouterReturnable from './core/express/normalizeRouterReturnable.js'; +import normalizeRouteReturnable from './core/express/normalizeRouteReturnable.js'; import isDev from './core/node/isDev.js'; import { Registry } from './events/interactionCreate/index.js'; -import stats from './routers/stats.js'; +import stats from './routes/stats.js'; -export type RouterReturnable = JSX.Element | Promise; +export type RouteReturnable = JSX.Element | Promise; -export interface RouterRegistry +export interface RouteRegistry extends Registry { route: string; handlesInteraction?: HandlesInteraction; @@ -14,12 +14,12 @@ export interface RouterRegistry handler: ( req: Request, res: Response, - ) => HandlesInteraction extends true ? void : RouterReturnable; + ) => HandlesInteraction extends true ? void : RouteReturnable; } const app = express(); -([stats] as RouterRegistry[]).forEach((registry) => { +([stats] as RouteRegistry[]).forEach((registry) => { if (!(isDev() ? registry.inDevelopment : registry.inProduction)) return; app.get(registry.route, async (req, res) => { @@ -27,7 +27,7 @@ const app = express(); if (registry.handlesInteraction) return; - const response = await normalizeRouterReturnable(returnable); + const response = await normalizeRouteReturnable(returnable); res.writeHead(200, { 'Content-Type': 'image/svg+xml', From 90d4b76b31c55546fb9ef620a5ddb903daf0711d Mon Sep 17 00:00:00 2001 From: tresabhi Date: Thu, 29 Jun 2023 01:43:59 +0000 Subject: [PATCH 27/29] feat: added auto refresh --- src/core/express/withAutoRefresh.ts | 23 +++++++++++++++++++++++ src/routes/stats.tsx | 2 +- src/server.ts | 14 ++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 src/core/express/withAutoRefresh.ts diff --git a/src/core/express/withAutoRefresh.ts b/src/core/express/withAutoRefresh.ts new file mode 100644 index 000000000..e29b780cf --- /dev/null +++ b/src/core/express/withAutoRefresh.ts @@ -0,0 +1,23 @@ +export default function withAutoRefresh(svg: string, refreshAfter: number) { + return ` + + + + + + + + + ${svg} + + + `; +} diff --git a/src/routes/stats.tsx b/src/routes/stats.tsx index 3ce638a67..ccc329a80 100644 --- a/src/routes/stats.tsx +++ b/src/routes/stats.tsx @@ -6,7 +6,7 @@ import { RouteRegistry } from '../server.js'; export default { route: '/stats/:type/:period', inProduction: true, - inDevelopment: false, + inDevelopment: true, async handler(req) { const type = req.params.type as StatType; diff --git a/src/server.ts b/src/server.ts index 8048bb0fb..660710863 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,5 +1,6 @@ import express, { Request, Response } from 'express'; import normalizeRouteReturnable from './core/express/normalizeRouteReturnable.js'; +import withAutoRefresh from './core/express/withAutoRefresh.js'; import isDev from './core/node/isDev.js'; import { Registry } from './events/interactionCreate/index.js'; import stats from './routes/stats.js'; @@ -23,17 +24,14 @@ const app = express(); if (!(isDev() ? registry.inDevelopment : registry.inProduction)) return; app.get(registry.route, async (req, res) => { - const returnable = registry.handler(req, res); + console.log(req.originalUrl); + const returnable = registry.handler(req, res); if (registry.handlesInteraction) return; - const response = await normalizeRouteReturnable(returnable); - - res.writeHead(200, { - 'Content-Type': 'image/svg+xml', - 'Content-Length': response.length, - }); - res.end(response); + res.send( + withAutoRefresh(await normalizeRouteReturnable(returnable), 60 * 1000), + ); }); }); From e34a6c6e4b05841caabc096fc361cb7c41d513ef Mon Sep 17 00:00:00 2001 From: tresabhi Date: Thu, 29 Jun 2023 18:39:59 +0000 Subject: [PATCH 28/29] feat: easier to read evolution --- src/commands/evolution.tsx | 2 +- src/commands/stats.tsx | 2 +- src/components/Graph/components/Line.tsx | 4 +- .../{VerticalMargin.tsx => Margin.tsx} | 30 ++++---- src/components/Graph/components/Root.tsx | 73 +++++++++---------- src/components/Graph/index.ts | 2 +- src/renderers/evolution.tsx | 60 +++++++-------- src/routes/stats.tsx | 2 +- 8 files changed, 85 insertions(+), 90 deletions(-) rename src/components/Graph/components/{VerticalMargin.tsx => Margin.tsx} (54%) diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 62123fa81..020c60fd5 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 4f29fbda2..2c92ae620 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/components/Graph/components/Line.tsx b/src/components/Graph/components/Line.tsx index f4b527769..3c170eead 100644 --- a/src/components/Graph/components/Line.tsx +++ b/src/components/Graph/components/Line.tsx @@ -1,16 +1,18 @@ -import { blue, green, red } from '@radix-ui/colors'; +import { blue, green, red, slateDark } from '@radix-ui/colors'; import { GRAPH_HEIGHT, GRAPH_WIDTH } from './Root.js'; export enum LineColor { Red, Green, Blue, + White, } const LINE_COLORS = { [LineColor.Red]: red.red9, [LineColor.Green]: green.green9, [LineColor.Blue]: blue.blue9, + [LineColor.White]: slateDark.slate11, }; export enum LineStyle { diff --git a/src/components/Graph/components/VerticalMargin.tsx b/src/components/Graph/components/Margin.tsx similarity index 54% rename from src/components/Graph/components/VerticalMargin.tsx rename to src/components/Graph/components/Margin.tsx index 6edd08837..f27275550 100644 --- a/src/components/Graph/components/VerticalMargin.tsx +++ b/src/components/Graph/components/Margin.tsx @@ -1,32 +1,34 @@ import { times } from 'lodash'; import { theme } from '../../../stitches.config.js'; -import { MarginProps } from './Root.js'; +import { MarginProps as RootMarginProps } from './Root.js'; -export enum VerticalMarginAlign { - Left, - Right, +export enum MarginOrientation { + Vertical, + Horizontal, } -export interface VerticalMarginProps extends MarginProps { +export interface MarginProps extends RootMarginProps { verticalSeparations: number; - align?: VerticalMarginAlign; + orientation?: MarginOrientation; } -export function VerticalMargin({ +export function Margin({ verticalSeparations, max, min, suffix, - align = VerticalMarginAlign.Left, -}: VerticalMarginProps) { + precision = 0, + orientation = MarginOrientation.Vertical, +}: MarginProps) { + const isVertical = orientation === MarginOrientation.Vertical; + return (
@@ -43,7 +45,7 @@ export function VerticalMargin({ ((verticalSeparations - (index + 1)) / (verticalSeparations - 1)) + min - ).toFixed(0)}${suffix ?? ''}`} + ).toFixed(precision)}${suffix ?? ''}`} ))}
diff --git a/src/components/Graph/components/Root.tsx b/src/components/Graph/components/Root.tsx index dc68b133e..a8761d905 100644 --- a/src/components/Graph/components/Root.tsx +++ b/src/components/Graph/components/Root.tsx @@ -1,42 +1,55 @@ import { times } from 'lodash'; import { ReactNode } from 'react'; import { theme } from '../../../stitches.config.js'; -import { VerticalMargin, VerticalMarginAlign } from './VerticalMargin.js'; +import { Margin, MarginOrientation } from './Margin.js'; -export const GRAPH_WIDTH = 512; +export const GRAPH_WIDTH = 544; export const GRAPH_HEIGHT = 320; export interface MarginProps { min: number; max: number; suffix?: string; + precision?: number; } export interface RootProps { children: ReactNode; - leftVerticalMargin?: MarginProps; - rightVerticalMargin?: MarginProps; - verticalSeparations?: number; + verticalMargin?: MarginProps; + horizontalMargin?: MarginProps; + separations?: number; xMinLabel: string; xMaxLabel: string; } export function Root({ children, - leftVerticalMargin, - rightVerticalMargin, - verticalSeparations = 5, + verticalMargin, + horizontalMargin, + separations = 5, xMinLabel, xMaxLabel, }: RootProps) { return (
+
+ + {xMinLabel} + + + {xMaxLabel} + +
+
- {leftVerticalMargin && ( - + {verticalMargin && ( + )} - {times(verticalSeparations - 2, (index) => { - const y = GRAPH_HEIGHT * ((index + 1) / (verticalSeparations - 1)); + {times(separations - 2, (index) => { + const y = GRAPH_HEIGHT * ((index + 1) / (separations - 1)); return ( - - {rightVerticalMargin && ( - - )}
-
- - {xMinLabel} - - - {xMaxLabel} - -
+ {horizontalMargin && ( + + )}
); } diff --git a/src/components/Graph/index.ts b/src/components/Graph/index.ts index bdb4bf3f9..eceb36006 100644 --- a/src/components/Graph/index.ts +++ b/src/components/Graph/index.ts @@ -1,3 +1,3 @@ export * from './components/Line.js'; +export * from './components/Margin.js'; export * from './components/Root.js'; -export * from './components/VerticalMargin.js'; diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 1cce51f92..0ccac742f 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -61,24 +61,22 @@ export default async function evolution( }); } - const careerWinrate = histories.map( + const plot = histories.map( (history) => [ - history.last_battle_time, + history.all.battles, (history.all.wins / history.all.battles) * 100, ] as Graph.PlotItem, ); - const careerBattles = histories.map( - (history) => - [history.last_battle_time, history.all.battles] as Graph.PlotItem, - ); - const winrateYs = careerWinrate.map(([, y]) => y); - const maxWinrate = Math.max(...winrateYs); - const minWinrate = Math.min(...winrateYs); - const battleYs = careerBattles.map(([, y]) => y); - const maxBattle = Math.max(...battleYs); - const minBattle = Math.min(...battleYs); - const minTime = Math.min(...careerBattles.map(([x]) => x)); + const times = histories.map((history) => history.last_battle_time); + const minTime = Math.min(...times); + const maxTime = Math.max(...times); + const ys = plot.map(([, y]) => y); + const xs = plot.map(([x]) => x); + const maxY = Math.max(...ys); + const minY = Math.min(...ys); + const maxX = Math.max(...xs); + const minX = Math.min(...xs); const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, @@ -96,37 +94,33 @@ export default async function evolution( /> {/* goofy ahh bug forces me to call them as functions */} - {careerWinrate.length > 0 && ( + {plot.length > 0 && ( - {Graph.Line({ - // total battles - plot: careerBattles!, - color: Graph.LineColor.Blue, - })} {Graph.Line({ // career winrate - plot: careerWinrate!, - minY: minWinrate, - maxY: maxWinrate, + color: Graph.LineColor.Red, + plot: plot, + minY, + maxY, })} )} - {careerWinrate.length === 0 && ( - - )} + {plot.length === 0 && } diff --git a/src/routes/stats.tsx b/src/routes/stats.tsx index ccc329a80..3ce638a67 100644 --- a/src/routes/stats.tsx +++ b/src/routes/stats.tsx @@ -6,7 +6,7 @@ import { RouteRegistry } from '../server.js'; export default { route: '/stats/:type/:period', inProduction: true, - inDevelopment: true, + inDevelopment: false, async handler(req) { const type = req.params.type as StatType; From 4c2b0253def3cc294622af69ce7e83bf55d7b20e Mon Sep 17 00:00:00 2001 From: tresabhi Date: Fri, 30 Jun 2023 17:38:44 +0000 Subject: [PATCH 29/29] feat: implemented dist package.json --- package.dist.json | 4 +- scripts/build.js | 43 +++++++++++-------- src/commands/stats.tsx | 2 +- src/components/Graph/components/Margin.tsx | 4 +- src/components/Graph/components/Root.tsx | 6 +-- src/core/node/throwError.ts | 2 +- .../interactionCreate/handlers/button.tsx | 14 +++++- 7 files changed, 46 insertions(+), 29 deletions(-) diff --git a/package.dist.json b/package.dist.json index 5a2dc478b..8c2a9203f 100644 --- a/package.dist.json +++ b/package.dist.json @@ -1,6 +1,6 @@ { - "main": "server.js", + "main": "server.cjs", "scripts": { - "start": "node --enable-source-maps server.cjs" + "start": "node --enable-source-maps --trace-warnings server.cjs" } } diff --git a/scripts/build.js b/scripts/build.js index 9f56eafc5..49774e78b 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,5 +1,5 @@ import { build } from 'esbuild'; -import { mkdirSync, rmSync, writeFileSync } from 'fs'; +import { copyFile, mkdir, rm, writeFile } from 'fs/promises'; import { argv } from 'process'; const isProd = !argv.includes('--dev'); @@ -9,21 +9,21 @@ const buildServer = argv.includes('--build=server') | buildAll; if (isProd) { // only remove in production to ensure no time is wasted in dev - console.log('Removing dist...'); - rmSync('dist', { recursive: true, force: true }); + console.log('🟡 Removing dist...'); + await rm('dist', { recursive: true, force: true }); + console.log('✅ Dist removed'); - console.log('Creating dist...'); - mkdirSync('dist'); + console.log('🟡 Creating dist...'); + await mkdir('dist'); + console.log('✅ Dist created'); - console.log('Caching tankopedia...'); + console.log('🟡 Caching tankopedia...'); fetch('https://www.blitzstars.com/bs-tankopedia.json') .then((response) => response.text()) - .then((tankopedia) => { - writeFileSync('./dist/tankopedia.json', tankopedia); - console.log('Tankopedia cached'); - }); + .then((tankopedia) => writeFile('./dist/tankopedia.json', tankopedia)) + .then(() => console.log('✅ Tankopedia cached')); - console.log('Caching tank averages...'); + console.log('🟡 Caching tank averages...'); fetch('https://www.blitzstars.com/api/tankaverages.json') .then((response) => response.json()) .then((individualTankAverages) => { @@ -33,10 +33,17 @@ if (isProd) { tankAverages[individualTankAverage.tank_id] = individualTankAverage; }); - writeFileSync('./dist/tankaverages.json', JSON.stringify(tankAverages)); + return writeFile( + './dist/tankaverages.json', + JSON.stringify(tankAverages), + ); + }) + .then(() => console.log('✅ Tank averages cached')); - console.log('Tank averages cached'); - }); + console.log('🟡 Copying package.json...'); + copyFile('package.dist.json', 'dist/package.json').then(() => + console.log('✅ package.json copied'), + ); } const commonOptions = { @@ -56,25 +63,25 @@ const commonOptions = { }; if (buildBot) { - console.log('Building bot...'); + console.log('🟡 Building bot...'); build({ ...commonOptions, entryPoints: ['src/bot.ts'], outfile: 'dist/bot.cjs', }).then(() => { - console.log('Bot built'); + console.log('✅ Bot built'); }); } if (buildServer) { - console.log('Building server...'); + console.log('🟡 Building server...'); build({ ...commonOptions, entryPoints: ['src/server.ts'], outfile: 'dist/server.cjs', }).then(() => { - console.log('Server built'); + console.log('✅ Server built'); }); } diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 2c92ae620..4f29fbda2 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export default { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/components/Graph/components/Margin.tsx b/src/components/Graph/components/Margin.tsx index f27275550..144a7904a 100644 --- a/src/components/Graph/components/Margin.tsx +++ b/src/components/Graph/components/Margin.tsx @@ -1,13 +1,13 @@ import { times } from 'lodash'; import { theme } from '../../../stitches.config.js'; -import { MarginProps as RootMarginProps } from './Root.js'; +import { MarginInputProps } from './Root.js'; export enum MarginOrientation { Vertical, Horizontal, } -export interface MarginProps extends RootMarginProps { +export interface MarginProps extends MarginInputProps { verticalSeparations: number; orientation?: MarginOrientation; } diff --git a/src/components/Graph/components/Root.tsx b/src/components/Graph/components/Root.tsx index a8761d905..5bc56b5db 100644 --- a/src/components/Graph/components/Root.tsx +++ b/src/components/Graph/components/Root.tsx @@ -6,7 +6,7 @@ import { Margin, MarginOrientation } from './Margin.js'; export const GRAPH_WIDTH = 544; export const GRAPH_HEIGHT = 320; -export interface MarginProps { +export interface MarginInputProps { min: number; max: number; suffix?: string; @@ -15,8 +15,8 @@ export interface MarginProps { export interface RootProps { children: ReactNode; - verticalMargin?: MarginProps; - horizontalMargin?: MarginProps; + verticalMargin?: MarginInputProps; + horizontalMargin?: MarginInputProps; separations?: number; xMinLabel: string; xMaxLabel: string; diff --git a/src/core/node/throwError.ts b/src/core/node/throwError.ts index 2aa57dec7..2a8a8585f 100644 --- a/src/core/node/throwError.ts +++ b/src/core/node/throwError.ts @@ -1,3 +1,3 @@ -export default function throwError(message: string, cause: string) { +export default function throwError(message: string, cause?: string) { return new Error(message, { cause }); } diff --git a/src/events/interactionCreate/handlers/button.tsx b/src/events/interactionCreate/handlers/button.tsx index 4bf3d0251..657a0bcc8 100644 --- a/src/events/interactionCreate/handlers/button.tsx +++ b/src/events/interactionCreate/handlers/button.tsx @@ -1,21 +1,31 @@ import { ButtonInteraction, CacheType } from 'discord.js'; import { CYCLIC_API } from '../../../constants/cyclic.js'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; +import throwError from '../../../core/node/throwError.js'; import { commands } from '../index.js'; export default async function handleButton( interaction: ButtonInteraction, ) { + await interaction.deferUpdate(); + const url = new URL(`${CYCLIC_API}/${interaction.customId}`); const commandName = url.pathname.split('/')[1]; const button = commands[commandName]?.button; if (!button) { - console.error(`Button handler not found for "${commandName}"`); + throwError(`Button handler not found for "${commandName}"`); + return; + } + + if (interaction.message.interaction?.user.id !== interaction.user.id) { + interaction.followUp({ + ephemeral: true, + content: 'You are not the author of this command.', + }); return; } - await interaction.deferUpdate(); await interaction.message.edit( await normalizeInteractionReturnable(button(interaction)), );