From 84ddf8785006c360df0fa496e2ab4e243df09bfb Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sat, 16 May 2026 16:06:39 +0200 Subject: [PATCH 01/50] feat: nodify people to put role at top --- apps/bot/package.json | 22 +- apps/bot/src/commands/utility/setup.ts | 5 +- package.json | 4 +- pnpm-lock.yaml | 1192 ++++++++++++------------ 4 files changed, 614 insertions(+), 609 deletions(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index b8c7ef9..ed4e1e4 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -15,26 +15,26 @@ "db:generate": "prisma generate" }, "dependencies": { - "@discordjs/core": "^2.3.0", - "@prisma/adapter-pg": "^7.7.0", - "@prisma/client": "^7.7.0", + "@discordjs/core": "^2.4.0", + "@prisma/adapter-pg": "^7.8.0", + "@prisma/client": "^7.8.0", "@sapphire/framework": "^5.5.0", "@types/ms": "^2.1.0", - "discord.js": "^14.24.0", + "discord.js": "^14.26.4", "dotenv": "^17.4.2", "ms": "^2.1.3", - "prisma": "^7.7.0", - "zod": "^4.3.6" + "prisma": "^7.8.0", + "zod": "^4.4.3" }, "devDependencies": { - "@sapphire/ts-config": "^5.0.1", - "@types/node": "^22.18.8", + "@sapphire/ts-config": "^5.0.3", + "@types/node": "^22.19.19", "concurrently": "^9.2.1", "eslint": "^9.39.4", - "eslint-config-neon": "^0.2.7", + "eslint-config-neon": "^0.2.9", "eslint-formatter-compact": "^8.40.0", - "eslint-formatter-pretty": "^7.0.0", - "prettier": "^3.6.2", + "eslint-formatter-pretty": "^7.1.0", + "prettier": "^3.8.3", "rimraf": "^6.1.3", "typescript": "~5.9.3" }, diff --git a/apps/bot/src/commands/utility/setup.ts b/apps/bot/src/commands/utility/setup.ts index 90c7a25..63bb690 100644 --- a/apps/bot/src/commands/utility/setup.ts +++ b/apps/bot/src/commands/utility/setup.ts @@ -113,7 +113,8 @@ export class SetupCommand extends Command { content: [ `**Server Setup**`, `${emojis.rightArrow1} This wizard will walk you through configuring the bot's features.`, - `${emojis.rightArrow1} You can adjust anything later with \`/settings\`.` + `${emojis.rightArrow1} You can adjust anything later with \`/settings\`.`, + `**Please put the newly created Quest role at the top of the role list!**` ].join('\n'), components: [ new ActionRowBuilder().addComponents( @@ -615,7 +616,7 @@ export class SetupCommand extends Command { `${emojis.rightArrow1} Here's what was configured:`, ...summary, '', - `${emojis.rightArrow1} **What's next?**`, + `**What's next?**`, `${emojis.rightArrow1} Use \`/automod add\` to block words in your server.`, `${emojis.rightArrow1} Use \`/autorole add\` to assign roles to new members automatically.`, `${emojis.rightArrow1} Use \`/settings\` to adjust any of these at any time.` diff --git a/package.json b/package.json index f507b00..8744e86 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "clean": "turbo run build --force && rm -rf node_modules apps/*/node_modules dist .turbo" }, "dependencies": { - "discord.js": "^14.26.3" + "discord.js": "^14.26.4" }, "engines": { "node": ">=22.12.0" }, "devDependencies": { - "turbo": "^2.9.10" + "turbo": "^2.9.14" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3d0ca5..2ebc0df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,24 +9,24 @@ importers: .: dependencies: discord.js: - specifier: ^14.26.3 - version: 14.26.3 + specifier: ^14.26.4 + version: 14.26.4 devDependencies: turbo: - specifier: ^2.9.10 - version: 2.9.10 + specifier: ^2.9.14 + version: 2.9.14 apps/bot: dependencies: '@discordjs/core': - specifier: ^2.3.0 + specifier: ^2.4.0 version: 2.4.0 '@prisma/adapter-pg': - specifier: ^7.7.0 - version: 7.7.0 + specifier: ^7.8.0 + version: 7.8.0 '@prisma/client': - specifier: ^7.7.0 - version: 7.7.0(prisma@7.7.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3) + specifier: ^7.8.0 + version: 7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3) '@sapphire/framework': specifier: ^5.5.0 version: 5.5.0 @@ -34,8 +34,8 @@ importers: specifier: ^2.1.0 version: 2.1.0 discord.js: - specifier: ^14.24.0 - version: 14.26.3 + specifier: ^14.26.4 + version: 14.26.4 dotenv: specifier: ^17.4.2 version: 17.4.2 @@ -43,35 +43,35 @@ importers: specifier: ^2.1.3 version: 2.1.3 prisma: - specifier: ^7.7.0 - version: 7.7.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + specifier: ^7.8.0 + version: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) zod: - specifier: ^4.3.6 - version: 4.3.6 + specifier: ^4.4.3 + version: 4.4.3 devDependencies: '@sapphire/ts-config': - specifier: ^5.0.1 + specifier: ^5.0.3 version: 5.0.3 '@types/node': - specifier: ^22.18.8 - version: 22.19.17 + specifier: ^22.19.19 + version: 22.19.19 concurrently: specifier: ^9.2.1 version: 9.2.1 eslint: specifier: ^9.39.4 - version: 9.39.4(jiti@2.6.1) + version: 9.39.4(jiti@2.7.0) eslint-config-neon: - specifier: ^0.2.7 - version: 0.2.9(@typescript-eslint/types@8.58.2)(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(svelte@3.59.2)(typescript@5.9.3) + specifier: ^0.2.9 + version: 0.2.9(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2)(typescript@5.9.3) eslint-formatter-compact: specifier: ^8.40.0 version: 8.40.0 eslint-formatter-pretty: - specifier: ^7.0.0 + specifier: ^7.1.0 version: 7.1.0 prettier: - specifier: ^3.6.2 + specifier: ^3.8.3 version: 3.8.3 rimraf: specifier: ^6.1.3 @@ -121,8 +121,8 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + '@babel/compat-data@7.29.3': + resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} engines: {node: '>=6.9.0'} '@babel/core@7.29.0': @@ -167,8 +167,8 @@ packages: resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} engines: {node: '>=6.0.0'} hasBin: true @@ -312,12 +312,16 @@ packages: peerDependencies: hono: ^4 - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -368,8 +372,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/eslint-plugin-next@15.5.15': - resolution: {integrity: sha512-ExQoBfyKMjAUQ2nuF39ryQsG26H374ZfH13dlOZqf6TaE9ycRbIm+qUbUFCliU4BtQhiqtS7cnGA1yWfPMQ+jA==} + '@next/eslint-plugin-next@15.5.18': + resolution: {integrity: sha512-w4MYq8M26a8PNrfto0JosLf5/3ssln1rsyP96g2DkC8uFVymStM5DLSz5ElxxrPRg2XnTMnFo3kREFlhYvxhWw==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -418,14 +422,14 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@prisma/adapter-pg@7.7.0': - resolution: {integrity: sha512-q33Ta8sKbgzEpAy0lx45tAq//yMv0qcb+8nj+TCA3P4wiAY+OBFEFk/NDkZncAfHaNJeGo5WJpJdpbL+ijYx8g==} + '@prisma/adapter-pg@7.8.0': + resolution: {integrity: sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==} - '@prisma/client-runtime-utils@7.7.0': - resolution: {integrity: sha512-BLyd0UpFYOtyJFTHm7jS9vesHW7P83abibodQMiIofqjBKzDHQ1VAsQkdfvXyYDkPlONPfOTz7/rv3x/+CQqvQ==} + '@prisma/client-runtime-utils@7.8.0': + resolution: {integrity: sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==} - '@prisma/client@7.7.0': - resolution: {integrity: sha512-5Ar4OsZpJ54s21sy5oDNNW9gQtd4NuxCaiM7+JDTOU07D6VvlpLjYzAVCMB1+JzokN+08dAVomlx+b7bhJd3ww==} + '@prisma/client@7.8.0': + resolution: {integrity: sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==} engines: {node: ^20.19 || ^22.12 || >=24.0} peerDependencies: prisma: '*' @@ -436,35 +440,35 @@ packages: typescript: optional: true - '@prisma/config@7.7.0': - resolution: {integrity: sha512-hmPI3tKLO2aP0Y5vugbjcnA9qqlfJndiT6ds4tw28U5hNHLWg+mHJEWAhjsSPgxjtmxhJ/EDIeIlyh+3Us0OPg==} + '@prisma/config@7.8.0': + resolution: {integrity: sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==} '@prisma/debug@7.2.0': resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} - '@prisma/debug@7.7.0': - resolution: {integrity: sha512-12J62XdqCmpiwJHhHdQxZeY3ckVCWIFmcJP8hg5dPTceeiQ0wiojXGFYTluKqFQfu46fRLgb/rLALZMAx3+dTA==} + '@prisma/debug@7.8.0': + resolution: {integrity: sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==} '@prisma/dev@0.24.3': resolution: {integrity: sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==} - '@prisma/driver-adapter-utils@7.7.0': - resolution: {integrity: sha512-gZXREeu6mOk7zXfGFJgh86p7Vhj0sXNKp+4Cg1tWYo7V2dfncP2qxS2BiTmbIIha8xPqItkl0WSw38RuSq1HoQ==} + '@prisma/driver-adapter-utils@7.8.0': + resolution: {integrity: sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==} - '@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': - resolution: {integrity: sha512-r51DLcJ8bDRSrBEJF3J4cinoWyGA7rfP2mG6lD90VqIbGNOkbfcLcXalSVjq5Y6brQS3vcjrq4GbyUb1Cb7vkw==} + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': + resolution: {integrity: sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==} - '@prisma/engines@7.7.0': - resolution: {integrity: sha512-7fmcbT7HHXBq/b+3h/dO1JI3fd8l8q7erf7xP7pRprh58hmSSnG8mg9K3yjW3h9WaHWUwngVFpSxxxivaitQ2w==} + '@prisma/engines@7.8.0': + resolution: {integrity: sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==} - '@prisma/fetch-engine@7.7.0': - resolution: {integrity: sha512-TfyzveBQoK4xALzsTpVhB/0KG1N8zOK0ap+RnBMkzGUu3f98fnQ4QtXa2wlKPhsO2X8a3N5ugFQgcKNoHGmDfw==} + '@prisma/fetch-engine@7.8.0': + resolution: {integrity: sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==} '@prisma/get-platform@7.2.0': resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} - '@prisma/get-platform@7.7.0': - resolution: {integrity: sha512-MEUNzvKxvYnJ7kgvd6oNRnMmmiGNS9TYLB2weMeIXplnHdL/UWEGnvavYGnN7KLJ2n0iI4dDAyzSkHI3c7AscQ==} + '@prisma/get-platform@7.8.0': + resolution: {integrity: sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==} '@prisma/query-plan-executor@7.2.0': resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} @@ -644,38 +648,38 @@ packages: peerDependencies: eslint: ^9.0.0 || ^10.0.0 - '@turbo/darwin-64@2.9.10': - resolution: {integrity: sha512-5BVJnes8/zMPydF8ktfBBWqCCpUeWVxwZ6avYHRqLzk2PuTAsLz0TlaKdDe1nk1cz3/o0c+7CEf6zqNXdB2N7Q==} + '@turbo/darwin-64@2.9.14': + resolution: {integrity: sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.10': - resolution: {integrity: sha512-MwaJl+vsxlkkDJYWN87GWKYD64kOvZFFlrDtGmCDeEx/488Kola5TVgS0VQkEUwnbDPjaDIB7kBMIzdzJRElbg==} + '@turbo/darwin-arm64@2.9.14': + resolution: {integrity: sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.10': - resolution: {integrity: sha512-HWrCKR+kUicEf4awj1EVRh5LI2hiDncpWZSXqhVj+wQT3SolBSXqXiSPYHgdh6hkmyfvz75Ex/+axXGcgQGdeA==} + '@turbo/linux-64@2.9.14': + resolution: {integrity: sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.10': - resolution: {integrity: sha512-edJINoZcDn4g1zkOZHFrGtLX0EWTryoNJSlZK5SEVux4hITT6hTCzugVGtOUmdI+PuJ/xRRL3jKGa+JgjSoq5A==} + '@turbo/linux-arm64@2.9.14': + resolution: {integrity: sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.10': - resolution: {integrity: sha512-rkASn89ATUtSyKvhGaWSyqVHBwtqFEUV1rFNKCtthSoix0T/kUHLJDKpepE/Wh6CtSnhxAfsY8cODtevD/hR7A==} + '@turbo/windows-64@2.9.14': + resolution: {integrity: sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.10': - resolution: {integrity: sha512-cblXqub7uABXKNMzvPB1IyOuSQpeMo7zZHSREB2C0mtIVn4lUSd2CfaGBtOrDqmkC9dsan3itxY4IejChQvfpg==} + '@turbo/windows-arm64@2.9.14': + resolution: {integrity: sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g==} cpu: [arm64] os: [win32] - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/concat-stream@2.0.3': resolution: {integrity: sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ==} @@ -692,8 +696,8 @@ packages: '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -716,8 +720,11 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@22.19.17': - resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} + '@types/node@22.19.19': + resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} + + '@types/node@25.8.0': + resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} '@types/pg@8.20.0': resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} @@ -746,11 +753,11 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.58.2': - resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} + '@typescript-eslint/eslint-plugin@8.59.3': + resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.2 + '@typescript-eslint/parser': ^8.59.3 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' @@ -760,15 +767,15 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/parser@8.58.2': - resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} + '@typescript-eslint/parser@8.59.3': + resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.2': - resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} + '@typescript-eslint/project-service@8.59.3': + resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -777,18 +784,18 @@ packages: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@8.58.2': - resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} + '@typescript-eslint/scope-manager@8.59.3': + resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.2': - resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} + '@typescript-eslint/tsconfig-utils@8.59.3': + resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.2': - resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} + '@typescript-eslint/type-utils@8.59.3': + resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -798,8 +805,8 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@8.58.2': - resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} + '@typescript-eslint/types@8.59.3': + resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -811,8 +818,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.58.2': - resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} + '@typescript-eslint/typescript-estree@8.59.3': + resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -823,8 +830,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@8.58.2': - resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} + '@typescript-eslint/utils@8.59.3': + resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -834,8 +841,8 @@ packages: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@8.58.2': - resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} + '@typescript-eslint/visitor-keys@8.59.3': + resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -959,12 +966,15 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-escapes@7.3.0: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} @@ -1053,8 +1063,8 @@ packages: resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} engines: {node: '>= 6.0.0'} - axe-core@4.11.3: - resolution: {integrity: sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg==} + axe-core@4.11.4: + resolution: {integrity: sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==} engines: {node: '>=4'} axobject-query@4.1.0: @@ -1071,16 +1081,16 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.19: - resolution: {integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==} + baseline-browser-mapping@2.10.29: + resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} engines: {node: '>=6.0.0'} hasBin: true bent@7.3.12: resolution: {integrity: sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==} - better-result@2.8.2: - resolution: {integrity: sha512-YOf0VSj5nUPI27doTtXF+BBnsiRq3qY7avHqfIWnppxTLGyvkLq1QV2RTxkwoZwJ60ywLfZ0raFF4J/G886i7A==} + better-result@2.9.2: + resolution: {integrity: sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==} boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1091,8 +1101,8 @@ packages: brace-expansion@2.1.0: resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -1111,8 +1121,8 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} - builtin-modules@5.1.0: - resolution: {integrity: sha512-c5JxaDrzwRjq3WyJkI1AGR5xy6Gr6udlt7sQPbl09+3ckB+Zo2qqQ2KhCTBr7Q8dHB43bENGYEk4xddrFH/b7A==} + builtin-modules@5.2.0: + resolution: {integrity: sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==} engines: {node: '>=18.20'} bytes@3.1.2: @@ -1122,10 +1132,10 @@ packages: bytesish@0.4.4: resolution: {integrity: sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==} - c12@3.1.0: - resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: - magicast: ^0.3.5 + magicast: '*' peerDependenciesMeta: magicast: optional: true @@ -1146,8 +1156,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001788: - resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} + caniuse-lite@1.0.30001792: + resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -1182,20 +1192,14 @@ packages: resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} engines: {pnpm: '>=8'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} ci-info@4.4.0: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - - citty@0.2.2: - resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} - clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -1238,10 +1242,6 @@ packages: confbox@0.2.4: resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1330,18 +1330,14 @@ packages: discord-api-types@0.38.47: resolution: {integrity: sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==} - discord.js@14.26.3: - resolution: {integrity: sha512-XEKtYn28YFsiJ5l4fLRyikdbo6RD5oFyqfVHQlvXz2104JhH/E8slN28dbky05w3DCrJcNVWvhVvcJCTSl/KIg==} + discord.js@14.26.4: + resolution: {integrity: sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==} engines: {node: '>=18'} doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - dotenv@17.4.2: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} @@ -1356,8 +1352,8 @@ packages: effect@3.20.0: resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==} - electron-to-chromium@1.5.340: - resolution: {integrity: sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==} + electron-to-chromium@1.5.357: + resolution: {integrity: sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -1372,8 +1368,8 @@ packages: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} - enhanced-resolve@5.20.1: - resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + enhanced-resolve@5.21.3: + resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} engines: {node: '>=10.13.0'} entities@7.0.1: @@ -1560,14 +1556,14 @@ packages: peerDependencies: eslint: '>=8.23.0' - eslint-plugin-promise@7.2.1: - resolution: {integrity: sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==} + eslint-plugin-promise@7.3.0: + resolution: {integrity: sha512-6uGiOR0INuujr6PEQmeSSP7GbIMJ/ebEXXiEzb/nOj68LknH5Pxzb/AbZivmr6VE6TkTE8rTjRK9zhKpK6HsRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 - eslint-plugin-react-hooks@7.1.0: - resolution: {integrity: sha512-LDicyhrRFrIaheDYryeM2W8gWyZXnAs4zIr2WVPiOSeTmIu2RjR4x/9N0xLaRWZ+9hssBDGo3AadcohuzAvSvg==} + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} engines: {node: '>=18'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 @@ -1623,14 +1619,14 @@ packages: peerDependencies: eslint: '>=9.29.0' - eslint-plugin-vue@10.8.0: - resolution: {integrity: sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==} + eslint-plugin-vue@10.9.1: + resolution: {integrity: sha512-cHB0Tf4Duvzwecwd/AqWzZvF/QszE13BhjVUpVXWCy9AeMR5GjkAjP3i85vqgLgOuTmkHR1OJ5oMeqLHtuw8zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-eslint-parser: ^10.0.0 + vue-eslint-parser: ^10.3.0 peerDependenciesMeta: '@stylistic/eslint-plugin': optional: true @@ -1735,6 +1731,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -1809,8 +1808,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.5.0: - resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -1831,8 +1830,8 @@ packages: get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} - giget@2.0.0: - resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + giget@3.2.0: + resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} hasBin: true glob-parent@5.1.2: @@ -1919,8 +1918,8 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} hermes-estree@0.25.1: @@ -1929,8 +1928,8 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - hono@4.12.14: - resolution: {integrity: sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==} + hono@4.12.19: + resolution: {integrity: sha512-xa3eYXYXx68XTT4hZ7dRzsXBhaq85ToSrlUJNoR0gwz/1Ap/CNwX47wfvV7pc/xWhjKVVkLT7zBJy8chhNguqQ==} engines: {node: '>=16.9.0'} hosted-git-info@7.0.2: @@ -2029,8 +2028,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} is-data-view@1.0.2: @@ -2154,8 +2153,8 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true jju@1.4.0: @@ -2269,8 +2268,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.3.5: - resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} + lru-cache@11.3.6: + resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -2433,8 +2432,8 @@ packages: resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} engines: {node: '>=8.0.0'} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2453,11 +2452,8 @@ packages: resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} engines: {node: '>= 0.4'} - node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - - node-releases@2.0.37: - resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} + node-releases@2.0.44: + resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} nopt@7.2.1: resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} @@ -2487,11 +2483,6 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nypm@0.6.5: - resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} - engines: {node: '>=18'} - hasBin: true - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2595,8 +2586,8 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -2643,8 +2634,8 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} plur@5.1.0: resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} @@ -2662,8 +2653,8 @@ packages: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -2699,8 +2690,8 @@ packages: engines: {node: '>=14'} hasBin: true - prisma@7.7.0: - resolution: {integrity: sha512-HlgwRBt1uEFB9LStHL4HLYDvoi4BNu1rYA0hPG0zCAEyK9SaZBqp7E5Rjpc3Qh8Lex/ye/svoHZ0OWoFNhWxuQ==} + prisma@7.8.0: + resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} engines: {node: ^20.19 || ^22.12 || >=24.0} hasBin: true peerDependencies: @@ -2748,8 +2739,8 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} react-dom@19.2.5: resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} @@ -2771,9 +2762,9 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} @@ -2839,8 +2830,8 @@ packages: engines: {node: '>= 0.4'} hasBin: true - resolve@2.0.0-next.6: - resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==} + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} engines: {node: '>= 0.4'} hasBin: true @@ -2867,8 +2858,8 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} safe-buffer@5.2.1: @@ -2901,6 +2892,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} @@ -3008,8 +3004,8 @@ packages: resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} engines: {node: '>=16'} - string-width@8.2.0: - resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} engines: {node: '>=20'} string.prototype.includes@2.0.1: @@ -3089,14 +3085,10 @@ packages: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} - tapable@2.3.2: - resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tinyexec@1.1.1: - resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} - engines: {node: '>=18'} - tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -3149,8 +3141,8 @@ packages: peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - turbo@2.9.10: - resolution: {integrity: sha512-YBLeNT0wLoysGgQEkvBWE2GA1liGGZ1j13wa7xHTwELJx4ZhM+c2szeXj6wUOUGO86BmyhY0Q/ELWwU3WDXzZA==} + turbo@2.9.14: + resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} hasBin: true type-check@0.4.0: @@ -3180,8 +3172,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.58.2: - resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} + typescript-eslint@8.59.3: + resolution: {integrity: sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3204,6 +3196,9 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici@6.24.1: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} @@ -3339,6 +3334,18 @@ packages: utf-8-validate: optional: true + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} @@ -3354,8 +3361,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} hasBin: true @@ -3384,8 +3391,8 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -3394,39 +3401,39 @@ snapshots: '@angular-eslint/bundled-angular-compiler@20.7.0': {} - '@angular-eslint/eslint-plugin-template@20.7.0(@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/types@8.58.2)(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@angular-eslint/eslint-plugin-template@20.7.0(@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 20.7.0 - '@angular-eslint/template-parser': 20.7.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@angular-eslint/utils': 20.7.0(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/template-parser': 20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@angular-eslint/utils': 20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) aria-query: 5.3.2 axobject-query: 4.1.0 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 - '@angular-eslint/eslint-plugin@20.7.0(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@angular-eslint/eslint-plugin@20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 20.7.0 - '@angular-eslint/utils': 20.7.0(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@angular-eslint/utils': 20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 - '@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 20.7.0 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-scope: 9.1.2 typescript: 5.9.3 - '@angular-eslint/utils@20.7.0(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@angular-eslint/utils@20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 20.7.0 - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 '@astrojs/compiler@3.0.1': {} @@ -3437,7 +3444,7 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} + '@babel/compat-data@7.29.3': {} '@babel/core@7.29.0': dependencies: @@ -3446,7 +3453,7 @@ snapshots: '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 @@ -3461,7 +3468,7 @@ snapshots: '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 @@ -3469,7 +3476,7 @@ snapshots: '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.29.0 + '@babel/compat-data': 7.29.3 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.2 lru-cache: 5.1.1 @@ -3504,14 +3511,14 @@ snapshots: '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@babel/parser@7.29.2': + '@babel/parser@7.29.3': dependencies: '@babel/types': 7.29.0 '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@babel/traverse@7.29.0': @@ -3519,7 +3526,7 @@ snapshots: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/types': 7.29.0 debug: 4.4.3 @@ -3602,7 +3609,7 @@ snapshots: '@vladfrangu/async_event_emitter': 2.4.7 discord-api-types: 0.38.47 tslib: 2.8.1 - ws: 8.20.0 + ws: 8.20.1 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -3635,26 +3642,26 @@ snapshots: '@es-joy/jsdoccomment@0.78.0': dependencies: - '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.58.2 + '@types/estree': 1.0.9 + '@typescript-eslint/types': 8.59.3 comment-parser: 1.4.1 esquery: 1.7.0 jsdoc-type-pratt-parser: 7.0.0 '@es-joy/resolve.exports@1.2.0': {} - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@9.39.4(jiti@2.6.1))': + '@eslint/compat@1.4.1(eslint@9.39.4(jiti@2.7.0))': dependencies: '@eslint/core': 0.17.0 optionalDependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) '@eslint/config-array@0.21.2': dependencies: @@ -3678,7 +3685,7 @@ snapshots: '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.14.0 + ajv: 6.15.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 @@ -3704,17 +3711,22 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@hono/node-server@1.19.11(hono@4.12.14)': + '@hono/node-server@1.19.11(hono@4.12.19)': dependencies: - hono: 4.12.14 + hono: 4.12.19 - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -3768,10 +3780,10 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.2 optional: true - '@next/eslint-plugin-next@15.5.15': + '@next/eslint-plugin-next@15.5.18': dependencies: fast-glob: 3.3.1 @@ -3795,7 +3807,7 @@ snapshots: ini: 4.1.3 nopt: 7.2.1 proc-log: 4.2.0 - semver: 7.7.4 + semver: 7.8.0 walk-up-path: 3.0.1 transitivePeerDependencies: - bluebird @@ -3809,7 +3821,7 @@ snapshots: proc-log: 4.2.0 promise-inflight: 1.0.1 promise-retry: 2.0.1 - semver: 7.7.4 + semver: 7.8.0 which: 4.0.0 transitivePeerDependencies: - bluebird @@ -3831,7 +3843,7 @@ snapshots: json-parse-even-better-errors: 3.0.2 normalize-package-data: 6.0.2 proc-log: 4.2.0 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - bluebird @@ -3846,27 +3858,27 @@ snapshots: '@pkgr/core@0.2.9': {} - '@prisma/adapter-pg@7.7.0': + '@prisma/adapter-pg@7.8.0': dependencies: - '@prisma/driver-adapter-utils': 7.7.0 + '@prisma/driver-adapter-utils': 7.8.0 '@types/pg': 8.20.0 pg: 8.20.0 postgres-array: 3.0.4 transitivePeerDependencies: - pg-native - '@prisma/client-runtime-utils@7.7.0': {} + '@prisma/client-runtime-utils@7.8.0': {} - '@prisma/client@7.7.0(prisma@7.7.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@prisma/client-runtime-utils': 7.7.0 + '@prisma/client-runtime-utils': 7.8.0 optionalDependencies: - prisma: 7.7.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + prisma: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) typescript: 5.9.3 - '@prisma/config@7.7.0': + '@prisma/config@7.8.0': dependencies: - c12: 3.1.0 + c12: 3.3.4 deepmerge-ts: 7.1.5 effect: 3.20.0 empathic: 2.0.0 @@ -3875,20 +3887,20 @@ snapshots: '@prisma/debug@7.2.0': {} - '@prisma/debug@7.7.0': {} + '@prisma/debug@7.8.0': {} '@prisma/dev@0.24.3(typescript@5.9.3)': dependencies: '@electric-sql/pglite': 0.4.1 '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) - '@hono/node-server': 1.19.11(hono@4.12.14) + '@hono/node-server': 1.19.11(hono@4.12.19) '@prisma/get-platform': 7.2.0 '@prisma/query-plan-executor': 7.2.0 '@prisma/streams-local': 0.1.2 foreground-child: 3.3.1 get-port-please: 3.2.0 - hono: 4.12.14 + hono: 4.12.19 http-status-codes: 2.3.0 pathe: 2.0.3 proper-lockfile: 4.1.2 @@ -3899,39 +3911,39 @@ snapshots: transitivePeerDependencies: - typescript - '@prisma/driver-adapter-utils@7.7.0': + '@prisma/driver-adapter-utils@7.8.0': dependencies: - '@prisma/debug': 7.7.0 + '@prisma/debug': 7.8.0 - '@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': {} + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} - '@prisma/engines@7.7.0': + '@prisma/engines@7.8.0': dependencies: - '@prisma/debug': 7.7.0 - '@prisma/engines-version': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711 - '@prisma/fetch-engine': 7.7.0 - '@prisma/get-platform': 7.7.0 + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/fetch-engine': 7.8.0 + '@prisma/get-platform': 7.8.0 - '@prisma/fetch-engine@7.7.0': + '@prisma/fetch-engine@7.8.0': dependencies: - '@prisma/debug': 7.7.0 - '@prisma/engines-version': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711 - '@prisma/get-platform': 7.7.0 + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/get-platform': 7.8.0 '@prisma/get-platform@7.2.0': dependencies: '@prisma/debug': 7.2.0 - '@prisma/get-platform@7.7.0': + '@prisma/get-platform@7.8.0': dependencies: - '@prisma/debug': 7.7.0 + '@prisma/debug': 7.8.0 '@prisma/query-plan-executor@7.2.0': {} '@prisma/streams-local@0.1.2': dependencies: - ajv: 8.12.0 - better-result: 2.8.2 + ajv: 8.20.0 + better-result: 2.9.2 env-paths: 3.0.0 proper-lockfile: 4.1.2 @@ -4068,60 +4080,60 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@stylistic/eslint-plugin-jsx@4.4.1(eslint@9.39.4(jiti@2.6.1))': + '@stylistic/eslint-plugin-jsx@4.4.1(eslint@9.39.4(jiti@2.7.0))': dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.4 - '@stylistic/eslint-plugin-ts@4.4.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@stylistic/eslint-plugin-ts@4.4.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 transitivePeerDependencies: - supports-color - typescript - '@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.6.1))': + '@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.7.0))': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) - '@typescript-eslint/types': 8.58.2 - eslint: 9.39.4(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/types': 8.59.3 + eslint: 9.39.4(jiti@2.7.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.4 - '@turbo/darwin-64@2.9.10': + '@turbo/darwin-64@2.9.14': optional: true - '@turbo/darwin-arm64@2.9.10': + '@turbo/darwin-arm64@2.9.14': optional: true - '@turbo/linux-64@2.9.10': + '@turbo/linux-64@2.9.14': optional: true - '@turbo/linux-arm64@2.9.10': + '@turbo/linux-arm64@2.9.14': optional: true - '@turbo/windows-64@2.9.10': + '@turbo/windows-64@2.9.14': optional: true - '@turbo/windows-arm64@2.9.10': + '@turbo/windows-arm64@2.9.14': optional: true - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true '@types/concat-stream@2.0.3': dependencies: - '@types/node': 22.19.17 + '@types/node': 22.19.19 '@types/debug@4.1.13': dependencies: @@ -4129,16 +4141,16 @@ snapshots: '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@types/esrecurse@4.3.1': {} '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/hast@3.0.4': dependencies: @@ -4160,13 +4172,17 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@22.19.17': + '@types/node@22.19.19': dependencies: undici-types: 6.21.0 + '@types/node@25.8.0': + dependencies: + undici-types: 7.24.6 + '@types/pg@8.20.0': dependencies: - '@types/node': 22.19.17 + '@types/node': 22.19.19 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -4184,7 +4200,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 22.19.17 + '@types/node': 25.8.0 '@types/yargs-parser@21.0.3': {} @@ -4192,15 +4208,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/type-utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.2 - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/type-utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.3 + eslint: 9.39.4(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -4208,30 +4224,30 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/experimental-utils@5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.3 debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.2(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.3(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -4242,22 +4258,22 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@8.58.2': + '@typescript-eslint/scope-manager@8.59.3': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/visitor-keys': 8.59.3 - '@typescript-eslint/tsconfig-utils@8.58.2(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -4265,7 +4281,7 @@ snapshots: '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@8.58.2': {} + '@typescript-eslint/types@8.59.3': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': dependencies: @@ -4274,50 +4290,50 @@ snapshots: debug: 4.4.3 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.7.4 + semver: 7.8.0 tsutils: 3.21.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.58.2(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.3(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.58.2(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/project-service': 8.59.3(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/visitor-keys': 8.59.3 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.7.4 + semver: 7.8.0 tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@types/json-schema': 7.0.15 '@types/semver': 7.7.1 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-scope: 5.1.1 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -4327,9 +4343,9 @@ snapshots: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.58.2': + '@typescript-eslint/visitor-keys@8.59.3': dependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.3 eslint-visitor-keys: 5.0.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -4401,7 +4417,7 @@ snapshots: acorn@8.16.0: {} - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -4415,6 +4431,13 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-escapes@7.3.0: dependencies: environment: 1.1.0 @@ -4499,8 +4522,8 @@ snapshots: astro-eslint-parser@1.4.0: dependencies: '@astrojs/compiler': 3.0.1 - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 astrojs-compiler-sync: 1.1.1(@astrojs/compiler@3.0.1) debug: 4.4.3 entities: 7.0.1 @@ -4509,7 +4532,7 @@ snapshots: espree: 10.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color @@ -4526,7 +4549,7 @@ snapshots: aws-ssl-profiles@1.1.2: {} - axe-core@4.11.3: {} + axe-core@4.11.4: {} axobject-query@4.1.0: {} @@ -4536,7 +4559,7 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.19: {} + baseline-browser-mapping@2.10.29: {} bent@7.3.12: dependencies: @@ -4544,7 +4567,7 @@ snapshots: caseless: 0.12.0 is-stream: 2.0.1 - better-result@2.8.2: {} + better-result@2.9.2: {} boolbase@1.0.0: {} @@ -4557,7 +4580,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.5: + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -4567,36 +4590,36 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.19 - caniuse-lite: 1.0.30001788 - electron-to-chromium: 1.5.340 - node-releases: 2.0.37 + baseline-browser-mapping: 2.10.29 + caniuse-lite: 1.0.30001792 + electron-to-chromium: 1.5.357 + node-releases: 2.0.44 update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-from@1.1.2: {} builtin-modules@3.3.0: {} - builtin-modules@5.1.0: {} + builtin-modules@5.2.0: {} bytes@3.1.2: {} bytesish@0.4.4: {} - c12@3.1.0: + c12@3.3.4: dependencies: - chokidar: 4.0.3 + chokidar: 5.0.0 confbox: 0.2.4 defu: 6.1.7 - dotenv: 16.6.1 + dotenv: 17.4.2 exsolve: 1.0.8 - giget: 2.0.0 - jiti: 2.6.1 + giget: 3.2.0 + jiti: 2.7.0 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 1.0.0 - pkg-types: 2.3.0 - rc9: 2.1.2 + perfect-debounce: 2.1.0 + pkg-types: 2.3.1 + rc9: 3.0.1 call-bind-apply-helpers@1.0.2: dependencies: @@ -4617,7 +4640,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001788: {} + caniuse-lite@1.0.30001792: {} caseless@0.12.0: {} @@ -4644,18 +4667,12 @@ snapshots: dependencies: '@kurkle/color': 0.3.4 - chokidar@4.0.3: + chokidar@5.0.0: dependencies: - readdirp: 4.1.2 + readdirp: 5.0.0 ci-info@4.4.0: {} - citty@0.1.6: - dependencies: - consola: 3.4.2 - - citty@0.2.2: {} - clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -4698,8 +4715,6 @@ snapshots: confbox@0.2.4: {} - consola@3.4.2: {} - convert-source-map@2.0.0: {} core-js-compat@3.49.0: @@ -4780,7 +4795,7 @@ snapshots: discord-api-types@0.38.47: {} - discord.js@14.26.3: + discord.js@14.26.4: dependencies: '@discordjs/builders': 1.14.1 '@discordjs/collection': 1.5.3 @@ -4803,8 +4818,6 @@ snapshots: dependencies: esutils: 2.0.3 - dotenv@16.6.1: {} - dotenv@17.4.2: {} dunder-proto@1.0.1: @@ -4820,7 +4833,7 @@ snapshots: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 - electron-to-chromium@1.5.340: {} + electron-to-chromium@1.5.357: {} emoji-regex@10.6.0: {} @@ -4830,10 +4843,10 @@ snapshots: empathic@2.0.0: {} - enhanced-resolve@5.20.1: + enhanced-resolve@5.21.3: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.2 + tapable: 2.3.3 entities@7.0.1: {} @@ -4871,7 +4884,7 @@ snapshots: has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 internal-slot: 1.1.0 is-array-buffer: 3.0.5 is-callable: 1.2.7 @@ -4889,7 +4902,7 @@ snapshots: object.assign: 4.1.7 own-keys: 1.0.1 regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 + safe-array-concat: 1.1.4 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 @@ -4936,11 +4949,11 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 es-shim-unscopables@1.1.0: dependencies: - hasown: 2.0.2 + hasown: 2.0.3 es-to-primitive@1.3.0: dependencies: @@ -4954,56 +4967,56 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-compat-utils@0.5.1(eslint@9.39.4(jiti@2.6.1)): + eslint-compat-utils@0.5.1(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.6.1) - semver: 7.7.4 + eslint: 9.39.4(jiti@2.7.0) + semver: 7.8.0 - eslint-compat-utils@0.6.5(eslint@9.39.4(jiti@2.6.1)): + eslint-compat-utils@0.6.5(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.6.1) - semver: 7.7.4 + eslint: 9.39.4(jiti@2.7.0) + semver: 7.8.0 - eslint-config-neon@0.2.9(@typescript-eslint/types@8.58.2)(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(svelte@3.59.2)(typescript@5.9.3): + eslint-config-neon@0.2.9(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2)(typescript@5.9.3): dependencies: - '@angular-eslint/eslint-plugin': 20.7.0(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@angular-eslint/eslint-plugin-template': 20.7.0(@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/types@8.58.2)(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@angular-eslint/template-parser': 20.7.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@eslint/compat': 1.4.1(eslint@9.39.4(jiti@2.6.1)) - '@next/eslint-plugin-next': 15.5.15 - '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4(jiti@2.6.1)) - '@stylistic/eslint-plugin-jsx': 4.4.1(eslint@9.39.4(jiti@2.6.1)) - '@stylistic/eslint-plugin-ts': 4.4.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/eslint-plugin': 20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@angular-eslint/eslint-plugin-template': 20.7.0(@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@angular-eslint/template-parser': 20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@eslint/compat': 1.4.1(eslint@9.39.4(jiti@2.7.0)) + '@next/eslint-plugin-next': 15.5.18 + '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4(jiti@2.7.0)) + '@stylistic/eslint-plugin-jsx': 4.4.1(eslint@9.39.4(jiti@2.7.0)) + '@stylistic/eslint-plugin-ts': 4.4.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) '@types/lodash.merge': 4.6.9 - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) astro-eslint-parser: 1.4.0 - eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@2.6.1)) - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) - eslint-mdx: 3.7.0(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-astro: 1.7.0(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-cypress: 5.3.0(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-jsdoc: 61.7.1(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-mdx: 3.7.0(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-n: 17.24.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-promise: 7.2.1(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-react-hooks: 7.1.0(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-react-refresh: 0.4.26(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-rxjs: 5.0.3(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-rxjs-angular: 2.0.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-sonarjs: 3.0.7(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-svelte3: 4.0.0(eslint@9.39.4(jiti@2.6.1))(svelte@3.59.2) + eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) + eslint-mdx: 3.7.0(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-astro: 1.7.0(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-cypress: 5.3.0(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsdoc: 61.7.1(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-mdx: 3.7.0(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-n: 17.24.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint-plugin-promise: 7.3.0(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-refresh: 0.4.26(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-rxjs: 5.0.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint-plugin-rxjs-angular: 2.0.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint-plugin-sonarjs: 3.0.7(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-svelte3: 4.0.0(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2) eslint-plugin-tsdoc: 0.4.0 - eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-unicorn: 61.0.2(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-vue: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.6.1)))(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.6.1))) + eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint-plugin-unicorn: 61.0.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-vue: 10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.7.0)))(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.7.0))) globals: 16.5.0 lodash.merge: 4.6.2 - typescript-eslint: 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.6.1)) + typescript-eslint: 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - '@typescript-eslint/types' - '@typescript-eslint/utils' @@ -5016,14 +5029,14 @@ snapshots: - svelte - typescript - eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) - eslint-etc@5.2.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-etc@5.2.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) tsutils: 3.21.0(typescript@5.9.3) tsutils-etc: 1.4.2(tsutils@3.21.0(typescript@5.9.3))(typescript@5.9.3) typescript: 5.9.3 @@ -5040,7 +5053,7 @@ snapshots: eslint-rule-docs: 1.1.235 log-symbols: 7.0.1 plur: 5.1.0 - string-width: 8.2.0 + string-width: 8.2.1 supports-hyperlinks: 4.4.0 eslint-import-context@0.1.9(unrs-resolver@1.11.1): @@ -5050,10 +5063,10 @@ snapshots: optionalDependencies: unrs-resolver: 1.11.1 - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) get-tsconfig: 4.14.0 is-bun-module: 2.0.0 @@ -5061,15 +5074,15 @@ snapshots: tinyglobby: 0.2.16 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-mdx@3.7.0(eslint@9.39.4(jiti@2.6.1)): + eslint-mdx@3.7.0(eslint@9.39.4(jiti@2.7.0)): dependencies: acorn: 8.16.0 acorn-jsx: 5.3.2(acorn@8.16.0) - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) espree: 10.4.0 estree-util-visit: 2.0.0 remark-mdx: 3.1.1 @@ -5084,51 +5097,51 @@ snapshots: - bluebird - supports-color - eslint-plugin-astro@1.7.0(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-astro@1.7.0(eslint@9.39.4(jiti@2.7.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.3 astro-eslint-parser: 1.4.0 - eslint: 9.39.4(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.4(jiti@2.6.1)) + eslint: 9.39.4(jiti@2.7.0) + eslint-compat-utils: 0.6.5(eslint@9.39.4(jiti@2.7.0)) globals: 16.5.0 - postcss: 8.5.10 + postcss: 8.5.14 postcss-selector-parser: 7.1.1 transitivePeerDependencies: - supports-color - eslint-plugin-cypress@5.3.0(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-cypress@5.3.0(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) globals: 16.5.0 - eslint-plugin-es-x@7.8.0(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-es-x@7.8.0(eslint@9.39.4(jiti@2.7.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - eslint: 9.39.4(jiti@2.6.1) - eslint-compat-utils: 0.5.1(eslint@9.39.4(jiti@2.6.1)) + eslint: 9.39.4(jiti@2.7.0) + eslint-compat-utils: 0.5.1(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)): dependencies: '@package-json/types': 0.0.12 - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.3 comment-parser: 1.4.6 debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.2.5 - semver: 7.7.4 + semver: 7.8.0 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-jsdoc@61.7.1(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-jsdoc@61.7.1(eslint@9.39.4(jiti@2.7.0)): dependencies: '@es-joy/jsdoccomment': 0.78.0 '@es-joy/resolve.exports': 1.2.0 @@ -5136,30 +5149,30 @@ snapshots: comment-parser: 1.4.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) espree: 11.2.0 esquery: 1.7.0 html-entities: 2.6.0 object-deep-merge: 2.0.0 parse-imports-exports: 0.2.4 - semver: 7.7.4 + semver: 7.8.0 spdx-expression-parse: 4.0.0 to-valid-identifier: 1.0.0 transitivePeerDependencies: - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 array.prototype.flatmap: 1.3.3 ast-types-flow: 0.0.8 - axe-core: 4.11.3 + axe-core: 4.11.4 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.39.4(jiti@2.6.1) - hasown: 2.0.2 + eslint: 9.39.4(jiti@2.7.0) + hasown: 2.0.3 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.5 @@ -5167,10 +5180,10 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-mdx@3.7.0(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-mdx@3.7.0(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.6.1) - eslint-mdx: 3.7.0(eslint@9.39.4(jiti@2.6.1)) + eslint: 9.39.4(jiti@2.7.0) + eslint-mdx: 3.7.0(eslint@9.39.4(jiti@2.7.0)) mdast-util-from-markdown: 2.0.3 mdast-util-mdx: 3.0.0 micromark-extension-mdxjs: 3.0.0 @@ -5185,42 +5198,42 @@ snapshots: - remark-lint-file-extension - supports-color - eslint-plugin-n@17.24.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-n@17.24.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) - enhanced-resolve: 5.20.1 - eslint: 9.39.4(jiti@2.6.1) - eslint-plugin-es-x: 7.8.0(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + enhanced-resolve: 5.21.3 + eslint: 9.39.4(jiti@2.7.0) + eslint-plugin-es-x: 7.8.0(eslint@9.39.4(jiti@2.7.0)) get-tsconfig: 4.14.0 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 - semver: 7.7.4 + semver: 7.8.0 ts-declaration-location: 1.0.7(typescript@5.9.3) transitivePeerDependencies: - typescript - eslint-plugin-promise@7.2.1(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-promise@7.3.0(eslint@9.39.4(jiti@2.7.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) - eslint: 9.39.4(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + eslint: 9.39.4(jiti@2.7.0) - eslint-plugin-react-hooks@7.1.0(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 - eslint: 9.39.4(jiti@2.6.1) + '@babel/parser': 7.29.3 + eslint: 9.39.4(jiti@2.7.0) hermes-parser: 0.25.1 - zod: 4.3.6 - zod-validation-error: 4.0.2(zod@4.3.6) + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) transitivePeerDependencies: - supports-color - eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) - eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -5228,39 +5241,39 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.3.2 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) estraverse: 5.3.0 - hasown: 2.0.2 + hasown: 2.0.3 jsx-ast-utils: 3.3.5 minimatch: 3.1.5 object.entries: 1.1.9 object.fromentries: 2.0.8 object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.6 + resolve: 2.0.0-next.7 semver: 6.3.1 string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-rxjs-angular@2.0.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-rxjs-angular@2.0.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) common-tags: 1.8.2 - eslint: 9.39.4(jiti@2.6.1) - eslint-etc: 5.2.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + eslint-etc: 5.2.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) requireindex: 1.2.0 tslib: 2.8.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-rxjs@5.0.3(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-rxjs@5.0.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) common-tags: 1.8.2 decamelize: 5.0.1 - eslint: 9.39.4(jiti@2.6.1) - eslint-etc: 5.2.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + eslint-etc: 5.2.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) requireindex: 1.2.0 rxjs-report-usage: 1.0.6 tslib: 2.8.1 @@ -5270,12 +5283,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-sonarjs@3.0.7(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-sonarjs@3.0.7(eslint@9.39.4(jiti@2.7.0)): dependencies: '@eslint-community/regexpp': 4.12.2 builtin-modules: 3.3.0 bytes: 3.1.2 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) functional-red-black-tree: 1.0.1 jsx-ast-utils-x: 0.1.0 lodash.merge: 4.6.2 @@ -5284,9 +5297,9 @@ snapshots: semver: 7.7.4 typescript: 5.9.3 - eslint-plugin-svelte3@4.0.0(eslint@9.39.4(jiti@2.6.1))(svelte@3.59.2): + eslint-plugin-svelte3@4.0.0(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2): dependencies: - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) svelte: 3.59.2 eslint-plugin-tsdoc@0.4.0: @@ -5294,27 +5307,27 @@ snapshots: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) json-schema: 0.4.0 natural-compare-lite: 1.4.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-unicorn@61.0.2(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-unicorn@61.0.2(eslint@9.39.4(jiti@2.7.0)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@eslint/plugin-kit': 0.3.5 change-case: 5.4.4 ci-info: 4.4.0 clean-regexp: 1.0.0 core-js-compat: 3.49.0 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) esquery: 1.7.0 find-up-simple: 1.0.1 globals: 16.5.0 @@ -5324,22 +5337,22 @@ snapshots: pluralize: 8.0.0 regexp-tree: 0.1.27 regjsparser: 0.12.0 - semver: 7.7.4 + semver: 7.8.0 strip-indent: 4.1.1 - eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.6.1)))(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.6.1))): + eslint-plugin-vue@10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.7.0)))(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.7.0))): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) - eslint: 9.39.4(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + eslint: 9.39.4(jiti@2.7.0) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.1 - semver: 7.7.4 - vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.6.1)) + semver: 7.8.0 + vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.7.0)) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4(jiti@2.6.1)) - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) eslint-rule-docs@1.1.235: {} @@ -5356,7 +5369,7 @@ snapshots: eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -5366,9 +5379,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.4(jiti@2.6.1): + eslint@9.39.4(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 @@ -5376,11 +5389,11 @@ snapshots: '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 + '@types/estree': 1.0.9 + ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -5403,7 +5416,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -5470,6 +5483,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-uri@3.1.2: {} + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -5519,7 +5534,7 @@ snapshots: call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 - hasown: 2.0.2 + hasown: 2.0.3 is-callable: 1.2.7 functional-red-black-tree@1.0.1: {} @@ -5536,7 +5551,7 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.5.0: {} + get-east-asian-width@1.6.0: {} get-intrinsic@1.3.0: dependencies: @@ -5548,7 +5563,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 math-intrinsics: 1.1.0 get-port-please@3.2.0: {} @@ -5568,14 +5583,7 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - giget@2.0.0: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - defu: 6.1.7 - node-fetch-native: 1.6.7 - nypm: 0.6.5 - pathe: 2.0.3 + giget@3.2.0: {} glob-parent@5.1.2: dependencies: @@ -5659,7 +5667,7 @@ snapshots: dependencies: has-symbols: 1.1.0 - hasown@2.0.2: + hasown@2.0.3: dependencies: function-bind: 1.1.2 @@ -5669,7 +5677,7 @@ snapshots: dependencies: hermes-estree: 0.25.1 - hono@4.12.14: {} + hono@4.12.19: {} hosted-git-info@7.0.2: dependencies: @@ -5712,7 +5720,7 @@ snapshots: internal-slot@1.1.0: dependencies: es-errors: 1.3.0 - hasown: 2.0.2 + hasown: 2.0.3 side-channel: 1.1.0 irregular-plurals@3.5.0: {} @@ -5751,17 +5759,17 @@ snapshots: is-builtin-module@5.0.0: dependencies: - builtin-modules: 5.1.0 + builtin-modules: 5.2.0 is-bun-module@2.0.0: dependencies: - semver: 7.7.4 + semver: 7.8.0 is-callable@1.2.7: {} - is-core-module@2.16.1: + is-core-module@2.16.2: dependencies: - hasown: 2.0.2 + hasown: 2.0.3 is-data-view@1.0.2: dependencies: @@ -5820,7 +5828,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 is-set@2.0.3: {} @@ -5879,7 +5887,7 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jiti@2.6.1: {} + jiti@2.7.0: {} jju@1.4.0: {} @@ -5969,7 +5977,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.3.5: {} + lru-cache@11.3.6: {} lru-cache@5.1.1: dependencies: @@ -6091,7 +6099,7 @@ snapshots: micromark-extension-mdx-expression@3.0.1: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.3 micromark-factory-space: 2.0.1 @@ -6102,7 +6110,7 @@ snapshots: micromark-extension-mdx-jsx@3.0.2: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.3 @@ -6119,7 +6127,7 @@ snapshots: micromark-extension-mdxjs-esm@3.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-util-character: 2.1.1 @@ -6155,7 +6163,7 @@ snapshots: micromark-factory-mdx-expression@2.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 @@ -6219,7 +6227,7 @@ snapshots: micromark-util-events-to-acorn@2.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/unist': 3.0.3 devlop: 1.1.0 estree-util-visit: 2.0.0 @@ -6287,7 +6295,7 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.6 minimatch@3.1.5: dependencies: @@ -6317,7 +6325,7 @@ snapshots: dependencies: lru.min: 1.1.4 - nanoid@3.3.11: {} + nanoid@3.3.12: {} napi-postinstall@0.3.4: {} @@ -6332,9 +6340,7 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 - node-fetch-native@1.6.7: {} - - node-releases@2.0.37: {} + node-releases@2.0.44: {} nopt@7.2.1: dependencies: @@ -6343,12 +6349,12 @@ snapshots: normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 - semver: 7.7.4 + semver: 7.8.0 validate-npm-package-license: 3.0.4 npm-install-checks@6.3.0: dependencies: - semver: 7.7.4 + semver: 7.8.0 npm-normalize-package-bin@3.0.1: {} @@ -6356,7 +6362,7 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 4.2.0 - semver: 7.7.4 + semver: 7.8.0 validate-npm-package-name: 5.0.1 npm-pick-manifest@9.1.0: @@ -6364,18 +6370,12 @@ snapshots: npm-install-checks: 6.3.0 npm-normalize-package-bin: 3.0.1 npm-package-arg: 11.0.3 - semver: 7.7.4 + semver: 7.8.0 nth-check@2.1.1: dependencies: boolbase: 1.0.0 - nypm@0.6.5: - dependencies: - citty: 0.2.2 - pathe: 2.0.3 - tinyexec: 1.1.1 - object-assign@4.1.1: {} object-deep-merge@2.0.0: {} @@ -6488,14 +6488,14 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.3.5 + lru-cache: 11.3.6 minipass: 7.1.3 path-type@4.0.0: {} pathe@2.0.3: {} - perfect-debounce@1.0.0: {} + perfect-debounce@2.1.0: {} pg-cloudflare@1.3.0: optional: true @@ -6538,7 +6538,7 @@ snapshots: picomatch@4.0.4: {} - pkg-types@2.3.0: + pkg-types@2.3.1: dependencies: confbox: 0.2.4 exsolve: 1.0.8 @@ -6557,9 +6557,9 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.5.10: + postcss@8.5.14: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -6581,11 +6581,11 @@ snapshots: prettier@3.8.3: {} - prisma@7.7.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: - '@prisma/config': 7.7.0 + '@prisma/config': 7.8.0 '@prisma/dev': 0.24.3(typescript@5.9.3) - '@prisma/engines': 7.7.0 + '@prisma/engines': 7.8.0 '@prisma/studio-core': 0.27.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) mysql2: 3.15.3 postgres: 3.4.7 @@ -6630,7 +6630,7 @@ snapshots: queue-microtask@1.2.3: {} - rc9@2.1.2: + rc9@3.0.1: dependencies: defu: 6.1.7 destr: 2.0.5 @@ -6655,7 +6655,7 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@4.1.2: {} + readdirp@5.0.0: {} refa@0.12.1: dependencies: @@ -6731,14 +6731,14 @@ snapshots: resolve@1.22.12: dependencies: es-errors: 1.3.0 - is-core-module: 2.16.1 + is-core-module: 2.16.2 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.6: + resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 - is-core-module: 2.16.1 + is-core-module: 2.16.2 node-exports-info: 1.6.0 object-keys: 1.1.1 path-parse: 1.0.7 @@ -6759,7 +6759,7 @@ snapshots: rxjs-report-usage@1.0.6: dependencies: - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.3 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 bent: 7.3.12 @@ -6773,7 +6773,7 @@ snapshots: dependencies: tslib: 2.8.1 - safe-array-concat@1.1.3: + safe-array-concat@1.1.4: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -6808,6 +6808,8 @@ snapshots: semver@7.7.4: {} + semver@7.8.0: {} + seq-queue@0.0.5: {} set-function-length@1.2.2: @@ -6928,9 +6930,9 @@ snapshots: emoji-regex: 10.6.0 strip-ansi: 7.2.0 - string-width@8.2.0: + string-width@8.2.1: dependencies: - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 string.prototype.includes@2.0.1: @@ -7029,9 +7031,7 @@ snapshots: dependencies: '@pkgr/core': 0.2.9 - tapable@2.3.2: {} - - tinyexec@1.1.1: {} + tapable@2.3.3: {} tinyglobby@0.2.16: dependencies: @@ -7078,14 +7078,14 @@ snapshots: tslib: 1.14.1 typescript: 5.9.3 - turbo@2.9.10: + turbo@2.9.14: optionalDependencies: - '@turbo/darwin-64': 2.9.10 - '@turbo/darwin-arm64': 2.9.10 - '@turbo/linux-64': 2.9.10 - '@turbo/linux-arm64': 2.9.10 - '@turbo/windows-64': 2.9.10 - '@turbo/windows-arm64': 2.9.10 + '@turbo/darwin-64': 2.9.14 + '@turbo/darwin-arm64': 2.9.14 + '@turbo/linux-64': 2.9.14 + '@turbo/linux-arm64': 2.9.14 + '@turbo/windows-64': 2.9.14 + '@turbo/windows-arm64': 2.9.14 type-check@0.4.0: dependencies: @@ -7128,13 +7128,13 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -7152,6 +7152,8 @@ snapshots: undici-types@6.21.0: {} + undici-types@7.24.6: {} + undici@6.24.1: {} unified-engine@11.2.2: @@ -7159,7 +7161,7 @@ snapshots: '@types/concat-stream': 2.0.3 '@types/debug': 4.1.13 '@types/is-empty': 1.2.3 - '@types/node': 22.19.17 + '@types/node': 22.19.19 '@types/unist': 3.0.3 concat-stream: 2.0.0 debug: 4.4.3 @@ -7176,7 +7178,7 @@ snapshots: vfile-message: 4.0.3 vfile-reporter: 8.1.1 vfile-statistics: 3.0.0 - yaml: 2.8.3 + yaml: 2.9.0 transitivePeerDependencies: - bluebird - supports-color @@ -7296,15 +7298,15 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.6.1)): + vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 4.4.3 - eslint: 9.39.4(jiti@2.6.1) + eslint: 9.39.4(jiti@2.7.0) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 espree: 11.2.0 esquery: 1.7.0 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color @@ -7377,6 +7379,8 @@ snapshots: ws@8.20.0: {} + ws@8.20.1: {} + xml-name-validator@4.0.0: {} xtend@4.0.2: {} @@ -7385,7 +7389,7 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.3: {} + yaml@2.9.0: {} yargs-parser@21.1.1: {} @@ -7408,10 +7412,10 @@ snapshots: grammex: 3.1.12 graphmatch: 1.1.1 - zod-validation-error@4.0.2(zod@4.3.6): + zod-validation-error@4.0.2(zod@4.4.3): dependencies: - zod: 4.3.6 + zod: 4.4.3 - zod@4.3.6: {} + zod@4.4.3: {} zwitch@2.0.4: {} From 95c0b1a65927ab06a9512d381673f0eb76fce062 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sat, 16 May 2026 16:12:01 +0200 Subject: [PATCH 02/50] style(setup): small change on the setup summary --- apps/bot/src/commands/utility/setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/src/commands/utility/setup.ts b/apps/bot/src/commands/utility/setup.ts index 63bb690..139f62a 100644 --- a/apps/bot/src/commands/utility/setup.ts +++ b/apps/bot/src/commands/utility/setup.ts @@ -613,7 +613,7 @@ export class SetupCommand extends Command { await safeEditReply({ content: [ - `${emojis.rightArrow1} Here's what was configured:`, + `**Here's what was configured:**`, ...summary, '', `**What's next?**`, From 807b58e1c52fbaed97bde64b23e1422e636efc84 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sat, 16 May 2026 16:24:47 +0200 Subject: [PATCH 03/50] refactor(heartbeat): improve kuma push monitor --- apps/bot/src/util/heartbeat.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/bot/src/util/heartbeat.ts b/apps/bot/src/util/heartbeat.ts index b4150cc..ddaf2a7 100644 --- a/apps/bot/src/util/heartbeat.ts +++ b/apps/bot/src/util/heartbeat.ts @@ -1,24 +1,30 @@ import type { Client } from 'discord.js'; export function heartbeat(client: Client) { - const pushURLs = process.env['KUMA_PUSH_URL']?.split(',').map((url) => url.trim()).filter(Boolean) ?? []; + const pushURLs = process.env.KUMA_PUSH_URL?.split(',').map((u) => u.trim()).filter(Boolean) ?? []; const shardId = client.shard?.ids?.[0] ?? 0; - const pushURL = pushURLs[shardId] ?? pushURLs[0]; - - if (!pushURL) return; + const pushURL = pushURLs[shardId]; const push = async () => { if (!client.isReady()) return; try { const url = new URL(pushURL); - url.searchParams.set('ping', String(client.ws.ping)); - await fetch(url); + url.searchParams.set('ping', String(Math.max(0, client.ws.ping))); + url.searchParams.set('status', 'up'); + + const response = await fetch(url, { signal: AbortSignal.timeout(10_000) }); + if (!response.ok) { + console.error(`[heartbeat] Shard ${shardId} push failed: ${response.status}`); + } } catch (err) { - console.error('Push failed:', err); + console.error(`[heartbeat] Shard ${shardId} push error:`, err); } }; - void push(); - setInterval(push, 60_000); -} + const loop = async () => { + await push(); + setTimeout(loop, 60_000); + }; + void loop(); +} \ No newline at end of file From b9a33c4a3ffb024acb6394c321aaad5a9ff58160 Mon Sep 17 00:00:00 2001 From: UnbraveChimp <129645851+UnbraveChimp@users.noreply.github.com> Date: Sat, 16 May 2026 19:11:11 +0200 Subject: [PATCH 04/50] Update GitHub Sponsors usernames in FUNDING.yml Signed-off-by: UnbraveChimp <129645851+UnbraveChimp@users.noreply.github.com> --- .github/FUNDING.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..f3d79b9 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,15 @@ +# These are supported funding model platforms + +github: duck-organization, UnbraveChimp +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +thanks_dev: # Replace with a single thanks.dev username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From b6612e8a9655885ec5e9b156b5da2a2f4bc8e7d3 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 19:45:24 +0200 Subject: [PATCH 05/50] style: from arrow 1 to arrow 2 --- apps/bot/src/commands/utility/setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/src/commands/utility/setup.ts b/apps/bot/src/commands/utility/setup.ts index 139f62a..eb8c90f 100644 --- a/apps/bot/src/commands/utility/setup.ts +++ b/apps/bot/src/commands/utility/setup.ts @@ -436,7 +436,7 @@ export class SetupCommand extends Command { await panelChoice.deferUpdate(); } } else { - summary.push(`${emojis.rightArrow1} **Tickets** skipped`); + summary.push(`${emojis.rightArrow2} **Tickets** skipped`); } } else { await ticketsFeatureChoice.deferUpdate(); From 5293fad9fbc111bad1fdbf9e2fa2b9eb733d10df Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 17:49:27 +0000 Subject: [PATCH 06/50] Initial plan From 72875339ed0a4936f41b7ed82e646e67d0474ded Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 17:49:51 +0000 Subject: [PATCH 07/50] Initial plan From cb48f27cc06f3673f4064d4796cf63a4d716c02e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 17:51:16 +0000 Subject: [PATCH 08/50] fix: correct wording and spelling in CONTRIBUTING guide Agent-Logs-Url: https://github.com/duck-organization/quest-bot/sessions/ff94c8c1-830c-41ab-ba3c-faecdadd001e Co-authored-by: UnbraveChimp <129645851+UnbraveChimp@users.noreply.github.com> --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e5673ee..a1935a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,16 @@ # Contributing to Quest Bot -Contributing to Quest Bot requires basic knowledge of Typescript, Discord.JS and prisma. +Contributing to Quest Bot requires basic knowledge of TypeScript, Discord.JS and prisma. ## AI Rules -Please refrain from using AI to create new features. Using AI to help you *understand* how to make something is fine but you can't have it vibecode or make features for you. This is especially important for HackClub events. You can use AI to help *draft* a feature. +Please refrain from using AI to create new features. Using AI to help you *understand* how to make something is fine but you can't have it write code or make features for you. This is especially important for HackClub events. You can use AI to help *draft* a feature. -When commiting code you take *full* responsibility for what you are commiting. +When committing code you take *full* responsibility for what you are committing. ## Pull requests -Please submit pull requests to the `dev` branch, unless this is a feature which requires a seperate branch. +Please submit pull requests to the `dev` branch, unless this is a feature which requires a separate branch. Make sure to test the code you have made before creating a pull request. Format for commit messages, fix|upd|chore|dockerfile: (change made). From a3c0d0ae75632358ea66c40ed327940207dd7c14 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 20:55:30 +0200 Subject: [PATCH 09/50] fix: security vuln --- apps/bot/package.json | 2 + apps/bot/src/commands/moderation/automod.ts | 10 +- apps/bot/src/commands/utility/setup.ts | 8 +- apps/bot/src/util/heartbeat.ts | 2 +- pnpm-lock.yaml | 304 ++++++++++++++++++++ pnpm-workspace.yaml | 1 + 6 files changed, 321 insertions(+), 6 deletions(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index ed4e1e4..2667c72 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -24,11 +24,13 @@ "dotenv": "^17.4.2", "ms": "^2.1.3", "prisma": "^7.8.0", + "sharp": "^0.34.5", "zod": "^4.4.3" }, "devDependencies": { "@sapphire/ts-config": "^5.0.3", "@types/node": "^22.19.19", + "@types/sharp": "^0.32.0", "concurrently": "^9.2.1", "eslint": "^9.39.4", "eslint-config-neon": "^0.2.9", diff --git a/apps/bot/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts index 0156e1d..02f1a14 100644 --- a/apps/bot/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -1,5 +1,5 @@ import { Command } from '@sapphire/framework'; -import { MessageFlags } from 'discord.js'; +import { MessageFlags, PermissionsBitField } from 'discord.js'; import { createAutoMod, DuplicateAutoModError, getAutoMod, getAutoMods, removeAutoMod } from '#lib/automod.js'; import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js'; import { emojis } from '#utils/emoji.js'; @@ -73,6 +73,14 @@ export class AutoModCommand extends Command { return; } + if (!interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to manage automod.`, + flags: MessageFlags.Ephemeral + }); + return; + } + const subcommand = interaction.options.getSubcommand(); if (subcommand === 'add') { diff --git a/apps/bot/src/commands/utility/setup.ts b/apps/bot/src/commands/utility/setup.ts index eb8c90f..cc5f278 100644 --- a/apps/bot/src/commands/utility/setup.ts +++ b/apps/bot/src/commands/utility/setup.ts @@ -222,11 +222,11 @@ export class SetupCommand extends Command { }); summary.push(`${emojis.rightArrow2} **Welcome Messages** enabled in <#${welcomeChannelId}>`); } else { - summary.push(`${emojis.rightArrow1} **Welcome Messages** skipped`); + summary.push(`${emojis.rightArrow2} **Welcome Messages** skipped`); } } else { await welcomeFeatureChoice.deferUpdate(); - summary.push(`${emojis.rightArrow1} **Welcome Messages** skipped`); + summary.push(`${emojis.rightArrow2} **Welcome Messages** skipped`); } // 2: tickets @@ -604,11 +604,11 @@ export class SetupCommand extends Command { }); summary.push(`${emojis.rightArrow2} **Confessions** enabled in <#${confessionChannelId}>`); } else { - summary.push(`${emojis.rightArrow1} **Confessions** skipped`); + summary.push(`${emojis.rightArrow2} **Confessions** skipped`); } } else { await confessionsFeatureChoice.deferUpdate(); - summary.push(`${emojis.rightArrow1} **Confessions** skipped`); + summary.push(`${emojis.rightArrow2} **Confessions** skipped`); } await safeEditReply({ diff --git a/apps/bot/src/util/heartbeat.ts b/apps/bot/src/util/heartbeat.ts index ddaf2a7..76ebe54 100644 --- a/apps/bot/src/util/heartbeat.ts +++ b/apps/bot/src/util/heartbeat.ts @@ -6,7 +6,7 @@ export function heartbeat(client: Client) { const pushURL = pushURLs[shardId]; const push = async () => { - if (!client.isReady()) return; + if (!pushURL || !client.isReady()) return; try { const url = new URL(pushURL); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ebc0df..850f204 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,9 @@ importers: prisma: specifier: ^7.8.0 version: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + sharp: + specifier: ^0.34.5 + version: 0.34.5 zod: specifier: ^4.4.3 version: 4.4.3 @@ -55,6 +58,9 @@ importers: '@types/node': specifier: ^22.19.19 version: 22.19.19 + '@types/sharp': + specifier: ^0.32.0 + version: 0.32.0 concurrently: specifier: ^9.2.1 version: 9.2.1 @@ -332,6 +338,159 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -735,6 +894,10 @@ packages: '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + '@types/sharp@0.32.0': + resolution: {integrity: sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==} + deprecated: This is a stub types definition. sharp provides its own type definitions, so you do not need this installed. + '@types/supports-color@8.1.3': resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==} @@ -1320,6 +1483,10 @@ packages: destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2912,6 +3079,10 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3731,6 +3902,102 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.1': @@ -4192,6 +4459,10 @@ snapshots: '@types/semver@7.7.1': {} + '@types/sharp@0.32.0': + dependencies: + sharp: 0.34.5 + '@types/supports-color@8.1.3': {} '@types/unist@2.0.11': {} @@ -4785,6 +5056,8 @@ snapshots: destr@2.0.5: {} + detect-libc@2.1.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -6834,6 +7107,37 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.0 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cc85114..6c8a7a9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,4 +11,5 @@ allowBuilds: '@prisma/engines': true esbuild: true prisma: true + sharp: true unrs-resolver: true From a5fb3f84ed957df930f0c970e7ae7e3a779086e1 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 21:18:28 +0200 Subject: [PATCH 10/50] chore: replace eslint with prettier and reformat codebase --- .eslintrc.json | 12 - apps/bot/.prettierignore | 1 + apps/bot/package.json | 8 +- apps/bot/prisma.config.ts | 18 +- .../globalModeration/confessionBlacklist.ts | 150 +- apps/bot/src/commands/moderation/automod.ts | 318 +- .../commands/moderation/autorole/autorole.ts | 315 +- apps/bot/src/commands/moderation/ban/ban.ts | 308 +- apps/bot/src/commands/moderation/ban/unban.ts | 236 +- apps/bot/src/commands/moderation/kick.ts | 278 +- apps/bot/src/commands/moderation/mute/mute.ts | 312 +- .../src/commands/moderation/mute/unmute.ts | 247 +- apps/bot/src/commands/moderation/nick.ts | 138 +- apps/bot/src/commands/moderation/purge.ts | 220 +- apps/bot/src/commands/moderation/slowmode.ts | 144 +- .../src/commands/moderation/warn/unwarn.ts | 238 +- apps/bot/src/commands/moderation/warn/warn.ts | 370 +- .../bot/src/commands/moderation/warn/warns.ts | 116 +- apps/bot/src/commands/ping.ts | 36 +- apps/bot/src/commands/promotion/bot.ts | 24 +- apps/bot/src/commands/promotion/discord.ts | 24 +- apps/bot/src/commands/promotion/invite.ts | 24 +- apps/bot/src/commands/promotion/unlimited.ts | 32 +- apps/bot/src/commands/utility/confess.ts | 246 +- apps/bot/src/commands/utility/help.ts | 57 +- .../src/commands/utility/reminder/reminder.ts | 248 +- .../commands/utility/reminder/reminders.ts | 58 +- apps/bot/src/commands/utility/settings.ts | 719 +- apps/bot/src/commands/utility/setup.ts | 1168 ++- apps/bot/src/commands/utility/setupTickets.ts | 80 +- apps/bot/src/commands/utility/user.ts | 26 +- apps/bot/src/index.ts | 36 +- .../confession/confessionHandler.ts | 780 +- .../ticket/createTicketHandler.ts | 299 +- .../ticket/removeTicketHandler.ts | 300 +- apps/bot/src/lib/automod.ts | 100 +- apps/bot/src/lib/autorole.ts | 86 +- apps/bot/src/lib/bans.ts | 115 +- apps/bot/src/lib/confessions.ts | 97 +- apps/bot/src/lib/limits.ts | 47 +- apps/bot/src/lib/logging.ts | 55 +- apps/bot/src/lib/mutes.ts | 87 +- apps/bot/src/lib/prisma.ts | 16 +- apps/bot/src/lib/reminderEvent.ts | 86 +- apps/bot/src/lib/reminders.ts | 76 +- apps/bot/src/lib/settings.ts | 82 +- apps/bot/src/lib/tickets.ts | 93 +- apps/bot/src/lib/warns.ts | 64 +- apps/bot/src/lib/welcomeModule.ts | 56 +- apps/bot/src/listeners/channelCreate.ts | 68 +- apps/bot/src/listeners/channelDelete.ts | 70 +- apps/bot/src/listeners/chatInputDenied.ts | 28 +- apps/bot/src/listeners/contextMenuDenied.ts | 28 +- apps/bot/src/listeners/guildBanAdd.ts | 50 +- apps/bot/src/listeners/guildCreate.ts | 32 +- apps/bot/src/listeners/guildDelete.ts | 28 +- apps/bot/src/listeners/guildEmojisUpdate.ts | 40 +- apps/bot/src/listeners/guildMemberAdd.ts | 58 +- apps/bot/src/listeners/guildMemberRemove.ts | 54 +- apps/bot/src/listeners/guildMemberUpdate.ts | 88 +- .../bot/src/listeners/messageCommandDenied.ts | 14 +- apps/bot/src/listeners/messageCreate.ts | 84 +- apps/bot/src/listeners/messageDelete.ts | 43 +- apps/bot/src/listeners/messageDeleteBulk.ts | 40 +- apps/bot/src/listeners/messageUpdate.ts | 50 +- apps/bot/src/listeners/ready.ts | 85 +- apps/bot/src/preconditions/devMode.ts | 48 +- apps/bot/src/preconditions/globalModerator.ts | 36 +- apps/bot/src/sharder.ts | 2 +- apps/bot/src/util/collectors.ts | 42 +- apps/bot/src/util/emoji.ts | 12 +- apps/bot/src/util/heartbeat.ts | 49 +- apps/bot/tsconfig.eslint.json | 8 - pnpm-lock.yaml | 7379 ++--------------- 74 files changed, 5619 insertions(+), 11463 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 apps/bot/.prettierignore delete mode 100644 apps/bot/tsconfig.eslint.json diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 7db8224..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/eslintrc.json", - "root": true, - "extends": ["neon/common", "neon/node", "neon/typescript", "neon/prettier"], - "parserOptions": { - "project": ["./tsconfig.eslint.json"] - }, - "ignorePatterns": ["**/dist/*"], - "rules": { - "import/extensions": 0 - } -} diff --git a/apps/bot/.prettierignore b/apps/bot/.prettierignore new file mode 100644 index 0000000..849ddff --- /dev/null +++ b/apps/bot/.prettierignore @@ -0,0 +1 @@ +dist/ diff --git a/apps/bot/package.json b/apps/bot/package.json index 2667c72..32b4c41 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -6,8 +6,8 @@ "type": "module", "scripts": { "build": "rimraf dist && prisma generate && tsc", - "lint": "prettier --check . && eslint --ext .ts --format=pretty src", - "format": "prettier --write . && eslint --ext .ts --fix --format=pretty src", + "lint": "prettier --check .", + "format": "prettier --write .", "predev": "pnpm build", "start": "node --env-file-if-exists=../../.env dist/sharder.js", "dev": "concurrently \"tsc --watch\" \"node --watch --env-file-if-exists=../../.env dist/index.js\"", @@ -32,10 +32,6 @@ "@types/node": "^22.19.19", "@types/sharp": "^0.32.0", "concurrently": "^9.2.1", - "eslint": "^9.39.4", - "eslint-config-neon": "^0.2.9", - "eslint-formatter-compact": "^8.40.0", - "eslint-formatter-pretty": "^7.1.0", "prettier": "^3.8.3", "rimraf": "^6.1.3", "typescript": "~5.9.3" diff --git a/apps/bot/prisma.config.ts b/apps/bot/prisma.config.ts index 831a20f..b60c396 100644 --- a/apps/bot/prisma.config.ts +++ b/apps/bot/prisma.config.ts @@ -1,14 +1,14 @@ // This file was generated by Prisma, and assumes you have installed the following: // npm install --save-dev prisma dotenv -import "dotenv/config"; -import { defineConfig } from "prisma/config"; +import 'dotenv/config'; +import { defineConfig } from 'prisma/config'; export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - }, - datasource: { - url: process.env["DATABASE_URL"], - }, + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: process.env['DATABASE_URL'], + }, }); diff --git a/apps/bot/src/commands/globalModeration/confessionBlacklist.ts b/apps/bot/src/commands/globalModeration/confessionBlacklist.ts index 21141d5..a2cace6 100644 --- a/apps/bot/src/commands/globalModeration/confessionBlacklist.ts +++ b/apps/bot/src/commands/globalModeration/confessionBlacklist.ts @@ -1,91 +1,79 @@ import { Command } from '@sapphire/framework'; import { MessageFlags } from 'discord.js'; -import { - addConfessionBlacklist, - removeConfessionBlacklist, - isConfessionBlacklisted, -} from '#lib/confessions.js'; +import { addConfessionBlacklist, removeConfessionBlacklist, isConfessionBlacklisted } from '#lib/confessions.js'; import { emojis } from '#utils/emoji.js'; export class ConfessionBlacklistCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['globalModerator'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['globalModerator'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('confessionblacklist') - .setDescription('Manage the confession blacklist') - .setDefaultMemberPermissions(0n) - .setDMPermission(false) - .addSubcommand((sub: any) => - sub - .setName('add') - .setDescription('Blacklist a user from making confessions') - .addUserOption((opt: any) => - opt.setName('user').setDescription('User to blacklist').setRequired(true) - ) - .addStringOption((opt: any) => - opt.setName('reason').setDescription('Reason').setRequired(false) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('remove') - .setDescription('Remove a user from the confession blacklist') - .addUserOption((opt: any) => - opt.setName('user').setDescription('User to unblacklist').setRequired(true) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('check') - .setDescription('Check if a user is blacklisted from confessions') - .addUserOption((opt: any) => - opt.setName('user').setDescription('User to check').setRequired(true) - ) - ) - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('confessionblacklist') + .setDescription('Manage the confession blacklist') + .setDefaultMemberPermissions(0n) + .setDMPermission(false) + .addSubcommand((sub: any) => + sub + .setName('add') + .setDescription('Blacklist a user from making confessions') + .addUserOption((opt: any) => opt.setName('user').setDescription('User to blacklist').setRequired(true)) + .addStringOption((opt: any) => opt.setName('reason').setDescription('Reason').setRequired(false)), + ) + .addSubcommand((sub: any) => + sub + .setName('remove') + .setDescription('Remove a user from the confession blacklist') + .addUserOption((opt: any) => opt.setName('user').setDescription('User to unblacklist').setRequired(true)), + ) + .addSubcommand((sub: any) => + sub + .setName('check') + .setDescription('Check if a user is blacklisted from confessions') + .addUserOption((opt: any) => opt.setName('user').setDescription('User to check').setRequired(true)), + ), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const subcommand = interaction.options.getSubcommand(); - const user = interaction.options.getUser('user', true); + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const subcommand = interaction.options.getSubcommand(); + const user = interaction.options.getUser('user', true); - if (subcommand === 'add') { - const reason = interaction.options.getString('reason') ?? undefined; - try { - await addConfessionBlacklist(user.id, interaction.user.id, reason); - await interaction.reply({ - content: `${emojis.rightArrow2} Blacklisted ${user} from confessions${reason ? ` (reason: ${reason})` : ''}.`, - flags: MessageFlags.Ephemeral - }); - } catch (err) { - console.error(err); - await interaction.reply({ - content: `${emojis.rightArrow2} Failed to blacklist that user.`, - flags: MessageFlags.Ephemeral - }); - } - } + if (subcommand === 'add') { + const reason = interaction.options.getString('reason') ?? undefined; + try { + await addConfessionBlacklist(user.id, interaction.user.id, reason); + await interaction.reply({ + content: `${emojis.rightArrow2} Blacklisted ${user} from confessions${reason ? ` (reason: ${reason})` : ''}.`, + flags: MessageFlags.Ephemeral, + }); + } catch (err) { + console.error(err); + await interaction.reply({ + content: `${emojis.rightArrow2} Failed to blacklist that user.`, + flags: MessageFlags.Ephemeral, + }); + } + } - if (subcommand === 'remove') { - await removeConfessionBlacklist(user.id); - await interaction.reply({ - content: `${emojis.rightArrow2} Removed ${user} from the confession blacklist.`, - flags: MessageFlags.Ephemeral - }); - } + if (subcommand === 'remove') { + await removeConfessionBlacklist(user.id); + await interaction.reply({ + content: `${emojis.rightArrow2} Removed ${user} from the confession blacklist.`, + flags: MessageFlags.Ephemeral, + }); + } - if (subcommand === 'check') { - const blacklisted = await isConfessionBlacklisted(user.id); - await interaction.reply({ - content: blacklisted - ? `${emojis.rightArrow2} ${user} is blacklisted from confessions.` - : `${emojis.rightArrow2} ${user} is not blacklisted.`, - flags: MessageFlags.Ephemeral - }); - } - } -} \ No newline at end of file + if (subcommand === 'check') { + const blacklisted = await isConfessionBlacklisted(user.id); + await interaction.reply({ + content: blacklisted + ? `${emojis.rightArrow2} ${user} is blacklisted from confessions.` + : `${emojis.rightArrow2} ${user} is not blacklisted.`, + flags: MessageFlags.Ephemeral, + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts index 02f1a14..11b0996 100644 --- a/apps/bot/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -5,166 +5,158 @@ import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js' import { emojis } from '#utils/emoji.js'; export class AutoModCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('automod') - .setDescription('Block words from being said!') - .addSubcommand((sub: any) => - sub - .setName('add') - .setDescription('Create a new automod rule.') - .addStringOption((option: any) => - option.setName('word').setDescription('The word to block').setRequired(true) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('remove') - .setDescription('Remove words from the automod list.') - .addStringOption((option: any) => - option - .setName('word') - .setDescription('The word to remove') - .setAutocomplete(true) - .setRequired(true) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('list') - .setDescription('List all blocked words.') - ) - ); - } - - public override async autocompleteRun(interaction: Command.AutocompleteInteraction) { - if (!interaction.guildId) { - await interaction.respond([]); - return; - } - - const focusedOption = interaction.options.getFocused(true); - - if (interaction.options.getSubcommand() !== 'remove' || focusedOption.name !== 'word') { - await interaction.respond([]); - return; - } - - const autoMods = await getAutoMods(interaction.guildId); - const choices = autoMods.slice(0, 25).map((autoMod) => ({ - name: autoMod.word, - value: autoMod.id - })); - - await interaction.respond(choices); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage automod.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const subcommand = interaction.options.getSubcommand(); - - if (subcommand === 'add') { - const word = interaction.options.getString('word', true).trim().toLowerCase(); - try { - await createAutoMod( - interaction.guildId, - interaction.guild.name, - word, - interaction.client.application.entitlements - ); - await interaction.reply({ - content: `${emojis.rightArrow2} The word '${word}' has been added to the automod list.`, - flags: MessageFlags.Ephemeral - }); - } catch (err) { - if (err instanceof LimitError) { - if (err.showQuestUnlimitedPrompt) { - await interaction.reply({ - content: `${emojis.questUnlimited2} ${err.message} Unlock unlimited automod rules with QuestUnlimited.`, - components: getQuestUnlimitedPurchaseComponents(interaction.client.application.id), - flags: MessageFlags.Ephemeral - }); - return; - } - - await interaction.reply({ - content: `${emojis.rightArrow2} ${err.message}`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (err instanceof DuplicateAutoModError) { - await interaction.reply({ - content: `${emojis.rightArrow2} ${err.message}`, - flags: MessageFlags.Ephemeral - }); - return; - } - - console.error(err); - - await interaction.reply({ - content: `${emojis.rightArrow2} That word is already blocked in this server.`, - flags: MessageFlags.Ephemeral - }); - } - } - - if (subcommand === 'list') { - const autoMods = await getAutoMods(interaction.guildId); - if (autoMods.length === 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} There are no words in the automod list.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const wordList = autoMods.map((autoMod) => `${emojis.rightArrow1} ${autoMod.word}`).join('\n'); - await interaction.reply({ - content: `**Blocked Words:**\n${wordList}`, - flags: MessageFlags.Ephemeral - }); - } - - if (subcommand === 'remove') { - const autoModId = interaction.options.getString('word', true); - const autoMod = await getAutoMod(autoModId); - - if (!autoMod) { - await interaction.reply({ - content: `${emojis.rightArrow2} That blocked word doesn't exist.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - await removeAutoMod(autoMod.id); - await interaction.reply({ - content: `${emojis.rightArrow2} The word '${autoMod.word}' has been removed from the automod list.`, - flags: MessageFlags.Ephemeral - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('automod') + .setDescription('Block words from being said!') + .addSubcommand((sub: any) => + sub + .setName('add') + .setDescription('Create a new automod rule.') + .addStringOption((option: any) => + option.setName('word').setDescription('The word to block').setRequired(true), + ), + ) + .addSubcommand((sub: any) => + sub + .setName('remove') + .setDescription('Remove words from the automod list.') + .addStringOption((option: any) => + option.setName('word').setDescription('The word to remove').setAutocomplete(true).setRequired(true), + ), + ) + .addSubcommand((sub: any) => sub.setName('list').setDescription('List all blocked words.')), + ); + } + + public override async autocompleteRun(interaction: Command.AutocompleteInteraction) { + if (!interaction.guildId) { + await interaction.respond([]); + return; + } + + const focusedOption = interaction.options.getFocused(true); + + if (interaction.options.getSubcommand() !== 'remove' || focusedOption.name !== 'word') { + await interaction.respond([]); + return; + } + + const autoMods = await getAutoMods(interaction.guildId); + const choices = autoMods.slice(0, 25).map((autoMod) => ({ + name: autoMod.word, + value: autoMod.id, + })); + + await interaction.respond(choices); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to manage automod.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const subcommand = interaction.options.getSubcommand(); + + if (subcommand === 'add') { + const word = interaction.options.getString('word', true).trim().toLowerCase(); + try { + await createAutoMod( + interaction.guildId, + interaction.guild.name, + word, + interaction.client.application.entitlements, + ); + await interaction.reply({ + content: `${emojis.rightArrow2} The word '${word}' has been added to the automod list.`, + flags: MessageFlags.Ephemeral, + }); + } catch (err) { + if (err instanceof LimitError) { + if (err.showQuestUnlimitedPrompt) { + await interaction.reply({ + content: `${emojis.questUnlimited2} ${err.message} Unlock unlimited automod rules with QuestUnlimited.`, + components: getQuestUnlimitedPurchaseComponents(interaction.client.application.id), + flags: MessageFlags.Ephemeral, + }); + return; + } + + await interaction.reply({ + content: `${emojis.rightArrow2} ${err.message}`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (err instanceof DuplicateAutoModError) { + await interaction.reply({ + content: `${emojis.rightArrow2} ${err.message}`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + console.error(err); + + await interaction.reply({ + content: `${emojis.rightArrow2} That word is already blocked in this server.`, + flags: MessageFlags.Ephemeral, + }); + } + } + + if (subcommand === 'list') { + const autoMods = await getAutoMods(interaction.guildId); + if (autoMods.length === 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} There are no words in the automod list.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const wordList = autoMods.map((autoMod) => `${emojis.rightArrow1} ${autoMod.word}`).join('\n'); + await interaction.reply({ + content: `**Blocked Words:**\n${wordList}`, + flags: MessageFlags.Ephemeral, + }); + } + + if (subcommand === 'remove') { + const autoModId = interaction.options.getString('word', true); + const autoMod = await getAutoMod(autoModId); + + if (!autoMod) { + await interaction.reply({ + content: `${emojis.rightArrow2} That blocked word doesn't exist.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + await removeAutoMod(autoMod.id); + await interaction.reply({ + content: `${emojis.rightArrow2} The word '${autoMod.word}' has been removed from the automod list.`, + flags: MessageFlags.Ephemeral, + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/autorole/autorole.ts b/apps/bot/src/commands/moderation/autorole/autorole.ts index 8525dc6..022fec8 100644 --- a/apps/bot/src/commands/moderation/autorole/autorole.ts +++ b/apps/bot/src/commands/moderation/autorole/autorole.ts @@ -5,162 +5,159 @@ import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js' import { emojis } from '#utils/emoji.js'; export class AutoRoleCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('autorole') - .setDescription('Automatically assign roles to new members!') - .addSubcommand((sub: any) => - sub - .setName('add') - .setDescription('Create a new auto role.') - .addRoleOption((option: any) => - option.setName('role').setDescription('The role to assign to new members').setRequired(true) - ) - .addBooleanOption((option: any) => - option.setName('bot_role').setDescription('Whether this role should be assigned to bots').setRequired(true) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('remove') - .setDescription('Remove an auto role.') - .addStringOption((option: any) => - option - .setName('role') - .setDescription('The auto role to remove') - .setAutocomplete(true) - .setRequired(true) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('list') - .setDescription('List all auto roles.') - ) - ); - } - - public override async autocompleteRun(interaction: Command.AutocompleteInteraction) { - if (!interaction.guildId) { - await interaction.respond([]); - return; - } - - const focusedOption = interaction.options.getFocused(true); - - if (interaction.options.getSubcommand() !== 'remove' || focusedOption.name !== 'role') { - await interaction.respond([]); - return; - } - - const autoRoles = await getAutoRoles(interaction.guildId); - const choices = autoRoles.slice(0, 25).map((autoRole) => ({ - name: interaction.guild?.roles.cache.get(autoRole.roleId)?.name ?? autoRole.roleId, - value: autoRole.id - })); - - await interaction.respond(choices); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const subcommand = interaction.options.getSubcommand(); - - if (subcommand === 'add') { - const role = interaction.options.getRole('role', true); - const botRole = interaction.options.getBoolean('bot_role', true); - - try { - await createAutoRole( - interaction.guildId, - interaction.guild.name, - role.id, - botRole, - interaction.client.application.entitlements - ); - await interaction.reply({ - content: `${emojis.rightArrow2} Added auto role ${role} (Bot Role: ${botRole}).`, - flags: MessageFlags.Ephemeral - }); - } catch (err) { - if (err instanceof LimitError) { - if (err.showQuestUnlimitedPrompt) { - await interaction.reply({ - content: `${emojis.questUnlimited2} ${err.message} Unlock unlimited auto roles with QuestUnlimited.`, - components: getQuestUnlimitedPurchaseComponents(interaction.client.application.id), - flags: MessageFlags.Ephemeral - }); - return; - } - - await interaction.reply({ - content: `${emojis.rightArrow2} ${err.message}`, - flags: MessageFlags.Ephemeral - }); - return; - } - - console.error(err); - - await interaction.reply({ - content: `${emojis.rightArrow2} That role is already an auto role in this server.`, - flags: MessageFlags.Ephemeral - }); - } - } - - if (subcommand === 'remove') { - const autoRoleId = interaction.options.getString('role', true); - const autoRole = await getAutoRole(autoRoleId); - - if (!autoRole) { - await interaction.reply({ - content: `${emojis.rightArrow2} That auto role no longer exists.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - await removeAutoRole(autoRole.id); - await interaction.reply({ - content: `${emojis.rightArrow2} Removed auto role for <@&${autoRole.roleId}>.`, - flags: MessageFlags.Ephemeral - }); - } - - if (subcommand === 'list') { - const autoRoles = await getAutoRoles(interaction.guildId); - if (autoRoles.length === 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} There are no auto roles set up in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const autoRoleList = autoRoles.map(autoRole => { - const role = interaction.guild?.roles.cache.get(autoRole.roleId); - const roleName = role ? `<@&${role.id}>` : `Unknown Role (${autoRole.roleId})`; - const botRoleText = autoRole.botRole ? ' (Bot Role)' : ''; - return `${emojis.rightArrow1} ${roleName}${botRoleText}`; - }).join('\n'); - - await interaction.reply({ - content: `**Auto Roles:**\n${autoRoleList}`, - flags: MessageFlags.Ephemeral - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('autorole') + .setDescription('Automatically assign roles to new members!') + .addSubcommand((sub: any) => + sub + .setName('add') + .setDescription('Create a new auto role.') + .addRoleOption((option: any) => + option.setName('role').setDescription('The role to assign to new members').setRequired(true), + ) + .addBooleanOption((option: any) => + option + .setName('bot_role') + .setDescription('Whether this role should be assigned to bots') + .setRequired(true), + ), + ) + .addSubcommand((sub: any) => + sub + .setName('remove') + .setDescription('Remove an auto role.') + .addStringOption((option: any) => + option.setName('role').setDescription('The auto role to remove').setAutocomplete(true).setRequired(true), + ), + ) + .addSubcommand((sub: any) => sub.setName('list').setDescription('List all auto roles.')), + ); + } + + public override async autocompleteRun(interaction: Command.AutocompleteInteraction) { + if (!interaction.guildId) { + await interaction.respond([]); + return; + } + + const focusedOption = interaction.options.getFocused(true); + + if (interaction.options.getSubcommand() !== 'remove' || focusedOption.name !== 'role') { + await interaction.respond([]); + return; + } + + const autoRoles = await getAutoRoles(interaction.guildId); + const choices = autoRoles.slice(0, 25).map((autoRole) => ({ + name: interaction.guild?.roles.cache.get(autoRole.roleId)?.name ?? autoRole.roleId, + value: autoRole.id, + })); + + await interaction.respond(choices); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const subcommand = interaction.options.getSubcommand(); + + if (subcommand === 'add') { + const role = interaction.options.getRole('role', true); + const botRole = interaction.options.getBoolean('bot_role', true); + + try { + await createAutoRole( + interaction.guildId, + interaction.guild.name, + role.id, + botRole, + interaction.client.application.entitlements, + ); + await interaction.reply({ + content: `${emojis.rightArrow2} Added auto role ${role} (Bot Role: ${botRole}).`, + flags: MessageFlags.Ephemeral, + }); + } catch (err) { + if (err instanceof LimitError) { + if (err.showQuestUnlimitedPrompt) { + await interaction.reply({ + content: `${emojis.questUnlimited2} ${err.message} Unlock unlimited auto roles with QuestUnlimited.`, + components: getQuestUnlimitedPurchaseComponents(interaction.client.application.id), + flags: MessageFlags.Ephemeral, + }); + return; + } + + await interaction.reply({ + content: `${emojis.rightArrow2} ${err.message}`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + console.error(err); + + await interaction.reply({ + content: `${emojis.rightArrow2} That role is already an auto role in this server.`, + flags: MessageFlags.Ephemeral, + }); + } + } + + if (subcommand === 'remove') { + const autoRoleId = interaction.options.getString('role', true); + const autoRole = await getAutoRole(autoRoleId); + + if (!autoRole) { + await interaction.reply({ + content: `${emojis.rightArrow2} That auto role no longer exists.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + await removeAutoRole(autoRole.id); + await interaction.reply({ + content: `${emojis.rightArrow2} Removed auto role for <@&${autoRole.roleId}>.`, + flags: MessageFlags.Ephemeral, + }); + } + + if (subcommand === 'list') { + const autoRoles = await getAutoRoles(interaction.guildId); + if (autoRoles.length === 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} There are no auto roles set up in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const autoRoleList = autoRoles + .map((autoRole) => { + const role = interaction.guild?.roles.cache.get(autoRole.roleId); + const roleName = role ? `<@&${role.id}>` : `Unknown Role (${autoRole.roleId})`; + const botRoleText = autoRole.botRole ? ' (Bot Role)' : ''; + return `${emojis.rightArrow1} ${roleName}${botRoleText}`; + }) + .join('\n'); + + await interaction.reply({ + content: `**Auto Roles:**\n${autoRoleList}`, + flags: MessageFlags.Ephemeral, + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/ban/ban.ts b/apps/bot/src/commands/moderation/ban/ban.ts index b70ecf0..a699f0b 100644 --- a/apps/bot/src/commands/moderation/ban/ban.ts +++ b/apps/bot/src/commands/moderation/ban/ban.ts @@ -1,169 +1,155 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import ms, { type StringValue } from 'ms'; import { applyBan, createBan } from '#lib/bans.js'; import { emojis } from '#utils/emoji.js'; export class BanCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('ban') - .setDescription('Ban someone from the discord server.') - .addUserOption((option: any) => - option.setName('member').setDescription('Select a member to ban').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for their ban') - ) - .addStringOption((option: any) => - option.setName('duration').setDescription('Provide a duration for their ban (if needed)') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.BanMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to ban members.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const targetMember = interaction.options.getMember('member') as GuildMember; - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - - const durationStr = interaction.options.getString('duration') as StringValue; - const duration = durationStr ? ms(durationStr) : null; - const expiresAt = duration ? new Date(Date.now() + duration) : null; - - if (!targetMember) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user is not in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.user.id) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot ban yourself.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.guild.ownerId) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot ban the server owner.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!targetMember.bannable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot ban this user.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Ban') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to ban <@${targetMember.id}> for reason: ${reason}?`, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - try { - await createBan( - interaction.guild.id, - interaction.guild.name, - targetMember.id, - expiresAt, - reason - ); - await applyBan(interaction.guild, targetMember.id, reason); - await targetMember - .send( - `You have been banned from **${interaction.guild.name}**.\nReason: ${reason}${ - expiresAt ? `\nExpires: ` : '' - }` - ) - .catch(() => {}); - await confirmation.update({ - content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been banned with reason: ${reason}`, - components: [] - }); - } catch (err) { - console.error(err); - await confirmation.update({ - content: `${emojis.rightArrow2} Failed to ban <@${targetMember.user.id}> with reason: ${reason}`, - components: [] - }); - } - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch (err) { - console.error(err); - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('ban') + .setDescription('Ban someone from the discord server.') + .addUserOption((option: any) => + option.setName('member').setDescription('Select a member to ban').setRequired(true), + ) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their ban')) + .addStringOption((option: any) => + option.setName('duration').setDescription('Provide a duration for their ban (if needed)'), + ), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.BanMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to ban members.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const targetMember = interaction.options.getMember('member') as GuildMember; + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + + const durationStr = interaction.options.getString('duration') as StringValue; + const duration = durationStr ? ms(durationStr) : null; + const expiresAt = duration ? new Date(Date.now() + duration) : null; + + if (!targetMember) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user is not in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.user.id) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot ban yourself.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.guild.ownerId) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot ban the server owner.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!targetMember.bannable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot ban this user.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Ban').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to ban <@${targetMember.id}> for reason: ${reason}?`, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + try { + await createBan(interaction.guild.id, interaction.guild.name, targetMember.id, expiresAt, reason); + await applyBan(interaction.guild, targetMember.id, reason); + await targetMember + .send( + `You have been banned from **${interaction.guild.name}**.\nReason: ${reason}${ + expiresAt ? `\nExpires: ` : '' + }`, + ) + .catch(() => {}); + await confirmation.update({ + content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been banned with reason: ${reason}`, + components: [], + }); + } catch (err) { + console.error(err); + await confirmation.update({ + content: `${emojis.rightArrow2} Failed to ban <@${targetMember.user.id}> with reason: ${reason}`, + components: [], + }); + } + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch (err) { + console.error(err); + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/ban/unban.ts b/apps/bot/src/commands/moderation/ban/unban.ts index 933f998..0e2195f 100644 --- a/apps/bot/src/commands/moderation/ban/unban.ts +++ b/apps/bot/src/commands/moderation/ban/unban.ts @@ -1,129 +1,121 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import { getBan, removeBan } from '#lib/bans.js'; import { emojis } from '#utils/emoji.js'; export class UnbanCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('unban') - .setDescription('Unban someone from the discord server.') - .addUserOption((option: any) => - option.setName('member').setDescription('The member to unban').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for their unban') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.BanMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to unban members.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const targetMember = interaction.options.getUser('member', true); - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - - const discordBan = await interaction.guild.bans.fetch(targetMember.id).catch(() => null); - const dbBan = await getBan(interaction.guild.id, targetMember.id); - - if (!discordBan && !dbBan) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user isn't banned.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Unban') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to unban <@${targetMember.id}> for reason: ${reason}?`, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - try { - await removeBan(interaction.guild, targetMember.id); - await targetMember - .send(`You have been unbanned in **${interaction.guild.name}**.\nReason: ${reason}`) - .catch(() => {}); - await confirmation.update({ - content: `${emojis.rightArrow2} <@${targetMember.id}> has been unbanned with reason: ${reason}`, - components: [] - }); - } catch (err) { - console.error(err); - await confirmation.update({ - content: `${emojis.rightArrow2} Failed to unban <@${targetMember.id}> with reason: ${reason}`, - components: [] - }); - } - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch (err) { - console.error(err); - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('unban') + .setDescription('Unban someone from the discord server.') + .addUserOption((option: any) => + option.setName('member').setDescription('The member to unban').setRequired(true), + ) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unban')), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.BanMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to unban members.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const targetMember = interaction.options.getUser('member', true); + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + + const discordBan = await interaction.guild.bans.fetch(targetMember.id).catch(() => null); + const dbBan = await getBan(interaction.guild.id, targetMember.id); + + if (!discordBan && !dbBan) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user isn't banned.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Unban').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to unban <@${targetMember.id}> for reason: ${reason}?`, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + try { + await removeBan(interaction.guild, targetMember.id); + await targetMember + .send(`You have been unbanned in **${interaction.guild.name}**.\nReason: ${reason}`) + .catch(() => {}); + await confirmation.update({ + content: `${emojis.rightArrow2} <@${targetMember.id}> has been unbanned with reason: ${reason}`, + components: [], + }); + } catch (err) { + console.error(err); + await confirmation.update({ + content: `${emojis.rightArrow2} Failed to unban <@${targetMember.id}> with reason: ${reason}`, + components: [], + }); + } + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch (err) { + console.error(err); + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/kick.ts b/apps/bot/src/commands/moderation/kick.ts index 4fd3c28..3f0513c 100644 --- a/apps/bot/src/commands/moderation/kick.ts +++ b/apps/bot/src/commands/moderation/kick.ts @@ -1,149 +1,141 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import { emojis } from '#utils/emoji.js'; export class KickCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('kick') - .setDescription('Kick someone from the discord server.') - .addUserOption((option: any) => - option.setName('member').setDescription('Select a member to kick').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for their kick') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.KickMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to kick members.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const targetMember = interaction.options.getMember('member'); - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - - if (!targetMember) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user is not in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.user.id) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot kick yourself.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.guild.ownerId) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot kick the server owner.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!targetMember.kickable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot kick this user.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Kick') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to kick <@${targetMember.user.id}> with reason: ${reason}?`, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - try { - await interaction.guild.members.kick(targetMember); - await targetMember - .send(`You have been kicked from **${interaction.guild.name}**.\nReason: ${reason}`) - .catch(() => {}); - await confirmation.update({ - content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been kicked with reason: ${reason}\nYou must have had a real ick towards that person.`, - components: [] - }); - } catch (err) { - console.error(err); - await confirmation.update({ - content: `${emojis.rightArrow2} Failed to kick <@${targetMember.user.id}> with reason: ${reason}\nYou must have had a real ick towards that person.`, - components: [] - }); - } - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch (err) { - console.error(err); - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('kick') + .setDescription('Kick someone from the discord server.') + .addUserOption((option: any) => + option.setName('member').setDescription('Select a member to kick').setRequired(true), + ) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their kick')), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.KickMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to kick members.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const targetMember = interaction.options.getMember('member'); + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + + if (!targetMember) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user is not in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.user.id) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot kick yourself.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.guild.ownerId) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot kick the server owner.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!targetMember.kickable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot kick this user.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Kick').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to kick <@${targetMember.user.id}> with reason: ${reason}?`, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + try { + await interaction.guild.members.kick(targetMember); + await targetMember + .send(`You have been kicked from **${interaction.guild.name}**.\nReason: ${reason}`) + .catch(() => {}); + await confirmation.update({ + content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been kicked with reason: ${reason}\nYou must have had a real ick towards that person.`, + components: [], + }); + } catch (err) { + console.error(err); + await confirmation.update({ + content: `${emojis.rightArrow2} Failed to kick <@${targetMember.user.id}> with reason: ${reason}\nYou must have had a real ick towards that person.`, + components: [], + }); + } + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch (err) { + console.error(err); + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/mute/mute.ts b/apps/bot/src/commands/moderation/mute/mute.ts index 101a264..d8960de 100644 --- a/apps/bot/src/commands/moderation/mute/mute.ts +++ b/apps/bot/src/commands/moderation/mute/mute.ts @@ -1,172 +1,156 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import ms, { type StringValue } from 'ms'; import { createMute, enforceMute } from '#lib/mutes.js'; import { emojis } from '#utils/emoji.js'; export class MuteCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('mute') - .setDescription('Mute someone in the discord server.') - .addUserOption((option: any) => - option.setName('member').setDescription('Select a member to mute').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('duration').setDescription('Specify a duration for the mute') - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for their mute') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to mute members.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const targetMember = interaction.options.getMember('member') as GuildMember; - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - const durationStr = interaction.options.getString('duration') as StringValue; - const duration = durationStr ? ms(durationStr) : null; - const expiresAt = duration ? new Date(Date.now() + duration) : null; - - if (!targetMember) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user is not in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (durationStr && (typeof duration !== 'number' || isNaN(duration))) { - await interaction.reply({ - content: `${emojis.rightArrow2} Invalid duration format.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.user.id) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot mute yourself.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.guild.ownerId) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot mute the server owner.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!targetMember.moderatable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot mute this user.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Mute') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to mute <@${targetMember.user.id}> with reason: ${reason}?`, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - await createMute( - interaction.guild.id, - interaction.guild.name, - targetMember.id, - expiresAt, - reason - ); - - await targetMember - .send( - `You have been muted in **${interaction.guild.name}**.\nReason: ${reason}${ - expiresAt ? `\nExpires: ` : '' - }` - ) - .catch(() => {}); - - await enforceMute(interaction.guild, targetMember.id); - await confirmation.update({ - content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been muted with reason: ${reason}${ - expiresAt ? `\nExpires: ` : '' - }`, - components: [] - }); - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch (err) { - console.error(err); - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('mute') + .setDescription('Mute someone in the discord server.') + .addUserOption((option: any) => + option.setName('member').setDescription('Select a member to mute').setRequired(true), + ) + .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the mute')) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their mute')), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to mute members.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const targetMember = interaction.options.getMember('member') as GuildMember; + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + const durationStr = interaction.options.getString('duration') as StringValue; + const duration = durationStr ? ms(durationStr) : null; + const expiresAt = duration ? new Date(Date.now() + duration) : null; + + if (!targetMember) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user is not in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (durationStr && (typeof duration !== 'number' || isNaN(duration))) { + await interaction.reply({ + content: `${emojis.rightArrow2} Invalid duration format.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.user.id) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot mute yourself.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.guild.ownerId) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot mute the server owner.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!targetMember.moderatable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot mute this user.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Mute').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to mute <@${targetMember.user.id}> with reason: ${reason}?`, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + await createMute(interaction.guild.id, interaction.guild.name, targetMember.id, expiresAt, reason); + + await targetMember + .send( + `You have been muted in **${interaction.guild.name}**.\nReason: ${reason}${ + expiresAt ? `\nExpires: ` : '' + }`, + ) + .catch(() => {}); + + await enforceMute(interaction.guild, targetMember.id); + await confirmation.update({ + content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been muted with reason: ${reason}${ + expiresAt ? `\nExpires: ` : '' + }`, + components: [], + }); + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch (err) { + console.error(err); + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/mute/unmute.ts b/apps/bot/src/commands/moderation/mute/unmute.ts index 2a79b6a..3788ce7 100644 --- a/apps/bot/src/commands/moderation/mute/unmute.ts +++ b/apps/bot/src/commands/moderation/mute/unmute.ts @@ -1,136 +1,125 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import { removeMute } from '#lib/mutes.js'; import { emojis } from '#utils/emoji.js'; export class UnmuteCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('unmute') - .setDescription('Unmute someone in the discord server.') - .addUserOption((option: any) => - option.setName('member').setDescription('Select a member to unmute').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for their unmute') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to unmute members.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const targetMember = interaction.options.getMember('member') as GuildMember; - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - - if (!targetMember) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user is not in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!targetMember.moderatable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot unmute this user.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Unmute') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to unmute <@${targetMember.user.id}> with reason: ${reason}?`, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - try { - await Promise.all([ - removeMute(interaction.guild.id, targetMember.id), - targetMember.timeout(null, reason) - ]); - await targetMember - .send(`You have been unmuted in **${interaction.guild.name}**.\nReason: ${reason}`) - .catch(() => {}); - await confirmation.update({ - content: `${emojis.rightArrow2} <@${targetMember.id}> has been unmuted. Reason: ${reason}`, - components: [] - }); - } catch (err) { - console.error(err); - await confirmation.update({ - content: `${emojis.rightArrow2} Failed to unmute <@${targetMember.id}> with reason: ${reason}`, - components: [] - }); - } - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('unmute') + .setDescription('Unmute someone in the discord server.') + .addUserOption((option: any) => + option.setName('member').setDescription('Select a member to unmute').setRequired(true), + ) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unmute')), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to unmute members.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const targetMember = interaction.options.getMember('member') as GuildMember; + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + + if (!targetMember) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user is not in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!targetMember.moderatable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot unmute this user.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Unmute').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to unmute <@${targetMember.user.id}> with reason: ${reason}?`, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + try { + await Promise.all([removeMute(interaction.guild.id, targetMember.id), targetMember.timeout(null, reason)]); + await targetMember + .send(`You have been unmuted in **${interaction.guild.name}**.\nReason: ${reason}`) + .catch(() => {}); + await confirmation.update({ + content: `${emojis.rightArrow2} <@${targetMember.id}> has been unmuted. Reason: ${reason}`, + components: [], + }); + } catch (err) { + console.error(err); + await confirmation.update({ + content: `${emojis.rightArrow2} Failed to unmute <@${targetMember.id}> with reason: ${reason}`, + components: [], + }); + } + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/nick.ts b/apps/bot/src/commands/moderation/nick.ts index 3c8e1f1..45285b1 100644 --- a/apps/bot/src/commands/moderation/nick.ts +++ b/apps/bot/src/commands/moderation/nick.ts @@ -3,83 +3,81 @@ import { GuildMember, MessageFlags, PermissionsBitField } from 'discord.js'; import { emojis } from '#utils/emoji.js'; export class NickCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('nick') - .setDescription("Change a member's nickname.") - .addUserOption((option: any) => - option.setName('member').setDescription('Select a member to change their nickname').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('nickname').setDescription('Nickname (leave empty to reset)') - ) - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('nick') + .setDescription("Change a member's nickname.") + .addUserOption((option: any) => + option.setName('member').setDescription('Select a member to change their nickname').setRequired(true), + ) + .addStringOption((option: any) => option.setName('nickname').setDescription('Nickname (leave empty to reset)')), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const member = interaction.member as GuildMember; + const member = interaction.member as GuildMember; - if (!member.permissions.has(PermissionsBitField.Flags.ManageNicknames)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage nicknames.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (!member.permissions.has(PermissionsBitField.Flags.ManageNicknames)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to manage nicknames.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const targetMember = interaction.options.getMember('member'); - const nickname = interaction.options.getString('nickname') ?? null; + const targetMember = interaction.options.getMember('member'); + const nickname = interaction.options.getString('nickname') ?? null; - if (!targetMember) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user is not in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (!targetMember) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user is not in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - if (targetMember.id === interaction.guild.ownerId) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot change the server owner's nickname.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (targetMember.id === interaction.guild.ownerId) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot change the server owner's nickname.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - if (!targetMember.manageable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot manage this member's nickname.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (!targetMember.manageable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot manage this member's nickname.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - try { - await targetMember.setNickname(nickname); - await interaction.reply({ - content: nickname - ? `${emojis.rightArrow2} Set <@${targetMember.user.id}>'s nickname to **${nickname}**.` - : `${emojis.rightArrow2} Reseted <@${targetMember.user.id}>'s nickname.`, - flags: MessageFlags.Ephemeral - }); - } catch { - await interaction.reply({ - content: `${emojis.rightArrow2} Failed to update <@${targetMember.user.id}>'s nickname.`, - flags: MessageFlags.Ephemeral - }); - } - } + try { + await targetMember.setNickname(nickname); + await interaction.reply({ + content: nickname + ? `${emojis.rightArrow2} Set <@${targetMember.user.id}>'s nickname to **${nickname}**.` + : `${emojis.rightArrow2} Reseted <@${targetMember.user.id}>'s nickname.`, + flags: MessageFlags.Ephemeral, + }); + } catch { + await interaction.reply({ + content: `${emojis.rightArrow2} Failed to update <@${targetMember.user.id}>'s nickname.`, + flags: MessageFlags.Ephemeral, + }); + } + } } diff --git a/apps/bot/src/commands/moderation/purge.ts b/apps/bot/src/commands/moderation/purge.ts index cb5220c..5c857f8 100644 --- a/apps/bot/src/commands/moderation/purge.ts +++ b/apps/bot/src/commands/moderation/purge.ts @@ -5,114 +5,112 @@ import { MessageFlags, PermissionsBitField } from 'discord.js'; const FOURTEEN_DAYS = 14 * 24 * 60 * 60 * 1000; export class PurgeCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('purge') - .setDescription('Purge messages from a channel.') - .addIntegerOption((option: any) => - option - .setName('amount') - .setDescription('The number of messages to purge') - .setRequired(true) - .setMinValue(1) - .setMaxValue(1000) - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member; - - if (!member || !('permissions' in member) || !member.permissions.has(PermissionsBitField.Flags.ManageMessages)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage messages.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const amount = interaction.options.getInteger('amount') ?? 0; - if (amount <= 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} Please provide a valid number of messages to purge.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const channel = interaction.channel; - if (!channel || !('messages' in channel)) { - await interaction.reply({ - content: `${emojis.rightArrow2} Unable to access channel messages.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - await interaction.deferReply({ ephemeral: true }); - await interaction.editReply(`${emojis.rightArrow2} Purging ${amount} messages...`); - - let remaining = amount; - let deletedTotal = 0; - - try { - while (remaining > 0) { - const fetchLimit = Math.min(remaining, 100); - const fetched = await channel.messages.fetch({ limit: fetchLimit as number }); - if (!fetched.size) break; - - const now = Date.now(); - const recentMessages = fetched.filter((message: any) => now - message.createdTimestamp < FOURTEEN_DAYS); - const oldMessages = fetched.filter((message: any) => now - message.createdTimestamp >= FOURTEEN_DAYS); - - if (recentMessages.size) { - const deleted = await channel.bulkDelete(recentMessages, true); - deletedTotal += deleted.size; - remaining -= deleted.size; - } - - if (oldMessages.size && remaining > 0) { - const messagesToDelete = oldMessages.first(Math.min(oldMessages.size, remaining)); - - for (const message of messagesToDelete) { - try { - await channel.messages.delete(message.id); - deletedTotal += 1; - remaining -= 1; - } catch (err) { - console.error('Failed to delete old message', err); - } - - if (remaining <= 0) break; - } - } - - await interaction.editReply( - `${emojis.rightArrow2} Purging messages... deleted ${deletedTotal}/${amount}` - ); - - if (recentMessages.size === 0 && oldMessages.size === 0) break; - } - - await interaction.editReply(`${emojis.rightArrow1} Successfully purged ${deletedTotal} messages.`); - } catch (err) { - console.error(err); - await interaction.editReply({ - content: `${emojis.rightArrow2} An error occurred while trying to purge messages.`, - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('purge') + .setDescription('Purge messages from a channel.') + .addIntegerOption((option: any) => + option + .setName('amount') + .setDescription('The number of messages to purge') + .setRequired(true) + .setMinValue(1) + .setMaxValue(1000), + ), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member; + + if (!member || !('permissions' in member) || !member.permissions.has(PermissionsBitField.Flags.ManageMessages)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to manage messages.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const amount = interaction.options.getInteger('amount') ?? 0; + if (amount <= 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} Please provide a valid number of messages to purge.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const channel = interaction.channel; + if (!channel || !('messages' in channel)) { + await interaction.reply({ + content: `${emojis.rightArrow2} Unable to access channel messages.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + await interaction.deferReply({ ephemeral: true }); + await interaction.editReply(`${emojis.rightArrow2} Purging ${amount} messages...`); + + let remaining = amount; + let deletedTotal = 0; + + try { + while (remaining > 0) { + const fetchLimit = Math.min(remaining, 100); + const fetched = await channel.messages.fetch({ limit: fetchLimit as number }); + if (!fetched.size) break; + + const now = Date.now(); + const recentMessages = fetched.filter((message: any) => now - message.createdTimestamp < FOURTEEN_DAYS); + const oldMessages = fetched.filter((message: any) => now - message.createdTimestamp >= FOURTEEN_DAYS); + + if (recentMessages.size) { + const deleted = await channel.bulkDelete(recentMessages, true); + deletedTotal += deleted.size; + remaining -= deleted.size; + } + + if (oldMessages.size && remaining > 0) { + const messagesToDelete = oldMessages.first(Math.min(oldMessages.size, remaining)); + + for (const message of messagesToDelete) { + try { + await channel.messages.delete(message.id); + deletedTotal += 1; + remaining -= 1; + } catch (err) { + console.error('Failed to delete old message', err); + } + + if (remaining <= 0) break; + } + } + + await interaction.editReply(`${emojis.rightArrow2} Purging messages... deleted ${deletedTotal}/${amount}`); + + if (recentMessages.size === 0 && oldMessages.size === 0) break; + } + + await interaction.editReply(`${emojis.rightArrow1} Successfully purged ${deletedTotal} messages.`); + } catch (err) { + console.error(err); + await interaction.editReply({ + content: `${emojis.rightArrow2} An error occurred while trying to purge messages.`, + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/slowmode.ts b/apps/bot/src/commands/moderation/slowmode.ts index c0be7ba..429fa2b 100644 --- a/apps/bot/src/commands/moderation/slowmode.ts +++ b/apps/bot/src/commands/moderation/slowmode.ts @@ -6,87 +6,87 @@ import { emojis } from '#utils/emoji.js'; const MAX_SLOWMODE_SECONDS = 21_600; export class SlowmodeCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('slowmode') - .setDescription('Set or clear the slowmode for the current channel.') - .addStringOption((option: any) => - option.setName('duration').setDescription('Provide a duration for slowmode, or leave blank to remove it') - ) - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('slowmode') + .setDescription('Set or clear the slowmode for the current channel.') + .addStringOption((option: any) => + option.setName('duration').setDescription('Provide a duration for slowmode, or leave blank to remove it'), + ), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const member = interaction.member; + const member = interaction.member; - if (!member || !('permissions' in member) || !member.permissions.has(PermissionsBitField.Flags.ManageChannels)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage channels.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (!member || !('permissions' in member) || !member.permissions.has(PermissionsBitField.Flags.ManageChannels)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to manage channels.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const channel = interaction.channel; + const channel = interaction.channel; - if (!channel || !('setRateLimitPerUser' in channel)) { - await interaction.reply({ - content: `${emojis.rightArrow2} This channel does not support slowmode.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (!channel || !('setRateLimitPerUser' in channel)) { + await interaction.reply({ + content: `${emojis.rightArrow2} This channel does not support slowmode.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const durationStr = interaction.options.getString('duration') as StringValue; - const durationMs = durationStr ? ms(durationStr) : null; + const durationStr = interaction.options.getString('duration') as StringValue; + const durationMs = durationStr ? ms(durationStr) : null; - if (durationStr && (typeof durationMs !== 'number' || Number.isNaN(durationMs))) { - await interaction.reply({ - content: `${emojis.rightArrow2} Invalid duration format.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (durationStr && (typeof durationMs !== 'number' || Number.isNaN(durationMs))) { + await interaction.reply({ + content: `${emojis.rightArrow2} Invalid duration format.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const slowmodeSeconds = durationStr ? Math.floor((durationMs ?? 0) / 1000) : 0; + const slowmodeSeconds = durationStr ? Math.floor((durationMs ?? 0) / 1000) : 0; - if (slowmodeSeconds < 0 || slowmodeSeconds > MAX_SLOWMODE_SECONDS) { - await interaction.reply({ - content: `${emojis.rightArrow2} Slowmode must be between 0 seconds and 6 hours.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (slowmodeSeconds < 0 || slowmodeSeconds > MAX_SLOWMODE_SECONDS) { + await interaction.reply({ + content: `${emojis.rightArrow2} Slowmode must be between 0 seconds and 6 hours.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - try { - await channel.setRateLimitPerUser(slowmodeSeconds); + try { + await channel.setRateLimitPerUser(slowmodeSeconds); - await interaction.reply({ - content: - slowmodeSeconds === 0 - ? `${emojis.rightArrow1} Slowmode cleared in <#${channel.id}>.` - : `${emojis.rightArrow1} Slowmode set to ${slowmodeSeconds} second${slowmodeSeconds === 1 ? '' : 's'} in <#${channel.id}>.`, - flags: MessageFlags.Ephemeral - }); - } catch (error) { - console.error(error); - await interaction.reply({ - content: `${emojis.rightArrow2} Failed to update slowmode for this channel.`, - flags: MessageFlags.Ephemeral - }); - } - } -} \ No newline at end of file + await interaction.reply({ + content: + slowmodeSeconds === 0 + ? `${emojis.rightArrow1} Slowmode cleared in <#${channel.id}>.` + : `${emojis.rightArrow1} Slowmode set to ${slowmodeSeconds} second${slowmodeSeconds === 1 ? '' : 's'} in <#${channel.id}>.`, + flags: MessageFlags.Ephemeral, + }); + } catch (error) { + console.error(error); + await interaction.reply({ + content: `${emojis.rightArrow2} Failed to update slowmode for this channel.`, + flags: MessageFlags.Ephemeral, + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/warn/unwarn.ts b/apps/bot/src/commands/moderation/warn/unwarn.ts index f3ec394..218dacd 100644 --- a/apps/bot/src/commands/moderation/warn/unwarn.ts +++ b/apps/bot/src/commands/moderation/warn/unwarn.ts @@ -1,130 +1,122 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import { getWarn, removeWarn } from '#lib/warns.js'; import { emojis } from '#utils/emoji.js'; export class UnwarnCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('unwarn') - .setDescription('Unwarn someone in the discord server.') - .addStringOption((option: any) => - option.setName('id').setDescription('The ID of the warn to remove').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for removing the warn') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to remove warns.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const warnId = interaction.options.getString('id', true); - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - - const warn = await getWarn(warnId, interaction.guild.id); - - if (!warn) { - await interaction.reply({ - content: `${emojis.rightArrow2} No warn found with that ID in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Unwarn') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to unwarn <@${warn.userId}> with reason: ${reason}?\n${emojis.rightArrow2} They were warned for: ${warn.reason} `, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - try { - await removeWarn(warn.id); - const user = await interaction.client.users.fetch(warn.userId); - await user - .send( - `Your warn for ${warn.reason} in **${interaction.guild.name}** has been removed.\nReason: ${reason}` - ) - .catch(() => {}); - await confirmation.update({ - content: `${emojis.rightArrow2} \`${warn.id}\` has been removed from <@${warn.userId}>. Reason: ${reason}`, - components: [] - }); - } catch (err) { - console.error(`Failed to remove warn ${warn.id}:`, err); - await confirmation.update({ - content: `${emojis.rightArrow2} Failed to remove warn \`${warn.id}\` from <@${warn.userId}>.`, - components: [] - }); - } - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('unwarn') + .setDescription('Unwarn someone in the discord server.') + .addStringOption((option: any) => + option.setName('id').setDescription('The ID of the warn to remove').setRequired(true), + ) + .addStringOption((option: any) => + option.setName('reason').setDescription('Provide a reason for removing the warn'), + ), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to remove warns.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const warnId = interaction.options.getString('id', true); + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + + const warn = await getWarn(warnId, interaction.guild.id); + + if (!warn) { + await interaction.reply({ + content: `${emojis.rightArrow2} No warn found with that ID in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Unwarn').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to unwarn <@${warn.userId}> with reason: ${reason}?\n${emojis.rightArrow2} They were warned for: ${warn.reason} `, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + try { + await removeWarn(warn.id); + const user = await interaction.client.users.fetch(warn.userId); + await user + .send(`Your warn for ${warn.reason} in **${interaction.guild.name}** has been removed.\nReason: ${reason}`) + .catch(() => {}); + await confirmation.update({ + content: `${emojis.rightArrow2} \`${warn.id}\` has been removed from <@${warn.userId}>. Reason: ${reason}`, + components: [], + }); + } catch (err) { + console.error(`Failed to remove warn ${warn.id}:`, err); + await confirmation.update({ + content: `${emojis.rightArrow2} Failed to remove warn \`${warn.id}\` from <@${warn.userId}>.`, + components: [], + }); + } + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/warn/warn.ts b/apps/bot/src/commands/moderation/warn/warn.ts index 5886066..b13d5d7 100644 --- a/apps/bot/src/commands/moderation/warn/warn.ts +++ b/apps/bot/src/commands/moderation/warn/warn.ts @@ -1,13 +1,13 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - Colors, - ButtonBuilder, - ButtonStyle, - EmbedBuilder, - GuildMember, - MessageFlags, - PermissionsBitField + ActionRowBuilder, + Colors, + ButtonBuilder, + ButtonStyle, + EmbedBuilder, + GuildMember, + MessageFlags, + PermissionsBitField, } from 'discord.js'; import ms, { type StringValue } from 'ms'; import { createWarn } from '#lib/warns.js'; @@ -15,185 +15,175 @@ import { logEmbed, truncate } from '#lib/logging.js'; import { emojis } from '#utils/emoji.js'; export class WarnCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('warn') - .setDescription('Warn someone in the discord server.') - .addUserOption((option: any) => - option.setName('member').setDescription('Select a member to warn').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for their warn') - ) - .addStringOption((option: any) => - option.setName('duration').setDescription('Specify a duration for the warn') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - - if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to warn members.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const targetMember = interaction.options.getMember('member') as GuildMember; - const reason = interaction.options.getString('reason') ?? 'No reason provided'; - const durationStr = interaction.options.getString('duration') as StringValue; - const duration = durationStr ? ms(durationStr) : null; - const expiresAt = duration ? new Date(Date.now() + duration) : null; - - if (durationStr && (typeof duration !== 'number' || isNaN(duration))) { - await interaction.reply({ - content: `${emojis.rightArrow2} Invalid duration format.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!targetMember) { - await interaction.reply({ - content: `${emojis.rightArrow2} That user is not in this server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.user.id) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot warn yourself.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (targetMember.id === interaction.guild.ownerId) { - await interaction.reply({ - content: `${emojis.rightArrow2} You cannot warn the server owner.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!targetMember.moderatable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot warn this user.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const confirm = new ButtonBuilder() - .setCustomId('confirm') - .setLabel('Confirm Warn') - .setStyle(ButtonStyle.Danger); - - const cancel = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(cancel, confirm); - - const response = await interaction.reply({ - content: `${emojis.rightArrow1} Are you sure you want to warn <@${targetMember.user.id}> with reason: ${reason}?`, - components: [row], - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const confirmation = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!confirmation) { - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (confirmation.customId === 'confirm') { - try { - await createWarn( - interaction.guild.id, - interaction.guild.name, - targetMember.id, - interaction.user.id, - reason, - expiresAt - ); - await targetMember - .send( - `You have been warned in **${interaction.guild.name}**.\nReason: ${reason}${ - expiresAt ? `\nExpires: ` : '' - }` - ) - .catch(() => {}); - - const embed = new EmbedBuilder() - .setTitle('Member Warned') - .setColor(Colors.Orange) - .addFields( - { name: 'Member', value: `<@${targetMember.id}>`, inline: true }, - { name: 'Moderator', value: `<@${interaction.user.id}>`, inline: true }, - { name: 'Reason', value: truncate(reason) || '-', inline: false } - ) - .setTimestamp(); - - if (expiresAt) { - embed.addFields({ - name: 'Expires', - value: ``, - inline: true - }); - } - - await logEmbed(interaction.guild, embed); - await confirmation.update({ - content: `${emojis.rightArrow2} <@${targetMember.id}> has been warned with reason: ${reason}`, - components: [] - }); - } catch (err) { - console.error(err); - await confirmation.update({ - content: `${emojis.rightArrow2} Failed to warn <@${targetMember.id}>`, - components: [] - }); - } - } else if (confirmation.customId === 'cancel') { - await confirmation.update({ - content: `${emojis.rightArrow2} Cancelled.`, - components: [] - }); - } - } catch (err) { - console.error(err); - await interaction.editReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('warn') + .setDescription('Warn someone in the discord server.') + .addUserOption((option: any) => + option.setName('member').setDescription('Select a member to warn').setRequired(true), + ) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their warn')) + .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the warn')), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + + if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to warn members.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const targetMember = interaction.options.getMember('member') as GuildMember; + const reason = interaction.options.getString('reason') ?? 'No reason provided'; + const durationStr = interaction.options.getString('duration') as StringValue; + const duration = durationStr ? ms(durationStr) : null; + const expiresAt = duration ? new Date(Date.now() + duration) : null; + + if (durationStr && (typeof duration !== 'number' || isNaN(duration))) { + await interaction.reply({ + content: `${emojis.rightArrow2} Invalid duration format.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!targetMember) { + await interaction.reply({ + content: `${emojis.rightArrow2} That user is not in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.user.id) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot warn yourself.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (targetMember.id === interaction.guild.ownerId) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot warn the server owner.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!targetMember.moderatable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot warn this user.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Warn').setStyle(ButtonStyle.Danger); + + const cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(cancel, confirm); + + const response = await interaction.reply({ + content: `${emojis.rightArrow1} Are you sure you want to warn <@${targetMember.user.id}> with reason: ${reason}?`, + components: [row], + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const confirmation = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!confirmation) { + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (confirmation.customId === 'confirm') { + try { + await createWarn( + interaction.guild.id, + interaction.guild.name, + targetMember.id, + interaction.user.id, + reason, + expiresAt, + ); + await targetMember + .send( + `You have been warned in **${interaction.guild.name}**.\nReason: ${reason}${ + expiresAt ? `\nExpires: ` : '' + }`, + ) + .catch(() => {}); + + const embed = new EmbedBuilder() + .setTitle('Member Warned') + .setColor(Colors.Orange) + .addFields( + { name: 'Member', value: `<@${targetMember.id}>`, inline: true }, + { name: 'Moderator', value: `<@${interaction.user.id}>`, inline: true }, + { name: 'Reason', value: truncate(reason) || '-', inline: false }, + ) + .setTimestamp(); + + if (expiresAt) { + embed.addFields({ + name: 'Expires', + value: ``, + inline: true, + }); + } + + await logEmbed(interaction.guild, embed); + await confirmation.update({ + content: `${emojis.rightArrow2} <@${targetMember.id}> has been warned with reason: ${reason}`, + components: [], + }); + } catch (err) { + console.error(err); + await confirmation.update({ + content: `${emojis.rightArrow2} Failed to warn <@${targetMember.id}>`, + components: [], + }); + } + } else if (confirmation.customId === 'cancel') { + await confirmation.update({ + content: `${emojis.rightArrow2} Cancelled.`, + components: [], + }); + } + } catch (err) { + console.error(err); + await interaction.editReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } +} diff --git a/apps/bot/src/commands/moderation/warn/warns.ts b/apps/bot/src/commands/moderation/warn/warns.ts index aa66846..b8ee9d3 100644 --- a/apps/bot/src/commands/moderation/warn/warns.ts +++ b/apps/bot/src/commands/moderation/warn/warns.ts @@ -4,63 +4,59 @@ import { getWarns } from '#lib/warns.js'; import { emojis } from '#utils/emoji.js'; export class WarnsCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('warns') - .setDescription('View (someones) warns.') - .addUserOption((option: any) => - option.setName('member').setDescription('Member to view warns of') - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const member = interaction.member as GuildMember; - const targetOption = interaction.options.getMember('member') as GuildMember; - - if (targetOption && targetOption.id !== interaction.user.id) { - if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to view other members' warns.`, - flags: MessageFlags.Ephemeral - }); - return; - } - } - - const targetMember = targetOption ?? member; - const active = await getWarns(interaction.guild.id, targetMember.id); - - if (active.length === 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} <@${targetMember.user.id}> has no active warns.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const lines = active.slice(0, 10).map((warn) => { - const expires = warn.expiresAt - ? `` - : 'Never'; - return `${emojis.rightArrow2} **${warn.reason ?? 'No reason provided'}** by <@${warn.moderatorId}>\n Expires: ${expires} \`${warn.id}\``; - }); - - const content = `${emojis.rightArrow1} ${active.length} active warn(s) for <@${targetMember.user.id}>:\n${lines.join('\n')}`; - - await interaction.reply({ content }); - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('warns') + .setDescription('View (someones) warns.') + .addUserOption((option: any) => option.setName('member').setDescription('Member to view warns of')), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const member = interaction.member as GuildMember; + const targetOption = interaction.options.getMember('member') as GuildMember; + + if (targetOption && targetOption.id !== interaction.user.id) { + if (!member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to view other members' warns.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + } + + const targetMember = targetOption ?? member; + const active = await getWarns(interaction.guild.id, targetMember.id); + + if (active.length === 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} <@${targetMember.user.id}> has no active warns.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const lines = active.slice(0, 10).map((warn) => { + const expires = warn.expiresAt ? `` : 'Never'; + return `${emojis.rightArrow2} **${warn.reason ?? 'No reason provided'}** by <@${warn.moderatorId}>\n Expires: ${expires} \`${warn.id}\``; + }); + + const content = `${emojis.rightArrow1} ${active.length} active warn(s) for <@${targetMember.user.id}>:\n${lines.join('\n')}`; + + await interaction.reply({ content }); + } +} diff --git a/apps/bot/src/commands/ping.ts b/apps/bot/src/commands/ping.ts index 8c060ee..8143fb2 100644 --- a/apps/bot/src/commands/ping.ts +++ b/apps/bot/src/commands/ping.ts @@ -2,26 +2,26 @@ import { Command } from '@sapphire/framework'; import { emojis } from '#utils/emoji.js'; export class PingCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('ping').setDescription("Return the bot's latency.") - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('ping').setDescription("Return the bot's latency."), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - await interaction.deferReply(); + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + await interaction.deferReply(); - const reply = await interaction.fetchReply(); + const reply = await interaction.fetchReply(); - const ping = reply.createdTimestamp - interaction.createdTimestamp; - const shardId = interaction.client.shard?.ids?.[0]; + const ping = reply.createdTimestamp - interaction.createdTimestamp; + const shardId = interaction.client.shard?.ids?.[0]; - await interaction.editReply( - `${emojis.rightArrow1} Client: ${ping}ms\n${emojis.rightArrow1} Websocket: ${interaction.client.ws.ping}ms\n${emojis.rightArrow2} Shard: #${typeof shardId === 'number' ? shardId : 'N/A'}` - ); - } -} \ No newline at end of file + await interaction.editReply( + `${emojis.rightArrow1} Client: ${ping}ms\n${emojis.rightArrow1} Websocket: ${interaction.client.ws.ping}ms\n${emojis.rightArrow2} Shard: #${typeof shardId === 'number' ? shardId : 'N/A'}`, + ); + } +} diff --git a/apps/bot/src/commands/promotion/bot.ts b/apps/bot/src/commands/promotion/bot.ts index 4e91ec0..95086ee 100644 --- a/apps/bot/src/commands/promotion/bot.ts +++ b/apps/bot/src/commands/promotion/bot.ts @@ -2,17 +2,17 @@ import { Command } from '@sapphire/framework'; import { emojis } from '#utils/emoji.js'; export class BotCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('bot').setDescription('Get a link to add the bot to your server!') - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('bot').setDescription('Get a link to add the bot to your server!'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/bot/invite`); - } -} \ No newline at end of file + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/bot/invite`); + } +} diff --git a/apps/bot/src/commands/promotion/discord.ts b/apps/bot/src/commands/promotion/discord.ts index 593c26c..d3eb143 100644 --- a/apps/bot/src/commands/promotion/discord.ts +++ b/apps/bot/src/commands/promotion/discord.ts @@ -2,17 +2,17 @@ import { Command } from '@sapphire/framework'; import { emojis } from '#utils/emoji.js'; export class DiscordCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('discord').setDescription('Get a link to the official Discord server!') - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('discord').setDescription('Get a link to the official Discord server!'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/discord`); - } -} \ No newline at end of file + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/discord`); + } +} diff --git a/apps/bot/src/commands/promotion/invite.ts b/apps/bot/src/commands/promotion/invite.ts index a4a1253..fbc22f7 100644 --- a/apps/bot/src/commands/promotion/invite.ts +++ b/apps/bot/src/commands/promotion/invite.ts @@ -2,17 +2,17 @@ import { Command } from '@sapphire/framework'; import { emojis } from '#utils/emoji.js'; export class InviteCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('invite').setDescription('Get a link to add the bot to your server!') - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('invite').setDescription('Get a link to add the bot to your server!'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/bot/invite`); - } -} \ No newline at end of file + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply(`${emojis.rightArrow1} https://duckorg.com/bot/invite`); + } +} diff --git a/apps/bot/src/commands/promotion/unlimited.ts b/apps/bot/src/commands/promotion/unlimited.ts index 524467a..14c3865 100644 --- a/apps/bot/src/commands/promotion/unlimited.ts +++ b/apps/bot/src/commands/promotion/unlimited.ts @@ -4,21 +4,21 @@ import { MessageFlags } from 'discord.js'; import { emojis } from '#utils/emoji.js'; export class QuestUnlimitedCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('unlimited').setDescription('Purchase Quest Unlimited!') - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('unlimited').setDescription('Purchase Quest Unlimited!'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply({ - content: `${emojis.questUnlimited2} Purchase Quest Unlimited below:`, - components: getQuestUnlimitedPurchaseComponents(interaction.client.application.id), - flags: MessageFlags.Ephemeral - }); - } -} \ No newline at end of file + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply({ + content: `${emojis.questUnlimited2} Purchase Quest Unlimited below:`, + components: getQuestUnlimitedPurchaseComponents(interaction.client.application.id), + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/apps/bot/src/commands/utility/confess.ts b/apps/bot/src/commands/utility/confess.ts index 108aeb4..0f10954 100644 --- a/apps/bot/src/commands/utility/confess.ts +++ b/apps/bot/src/commands/utility/confess.ts @@ -1,121 +1,141 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - EmbedBuilder, - LabelBuilder, - MessageFlags, - ModalBuilder, - TextInputBuilder, - TextInputStyle, - TextChannel + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + EmbedBuilder, + LabelBuilder, + MessageFlags, + ModalBuilder, + TextInputBuilder, + TextInputStyle, + TextChannel, } from 'discord.js'; import { getSettings } from '#lib/settings.js'; import { storeConfessionContext, isConfessionBlacklisted } from '#lib/confessions.js'; import { emojis } from '#utils/emoji.js'; export class ConfessCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(_registry: Command.Registry) { - _registry.registerChatInputCommand((builder: any) => - builder.setName('confess').setDescription('Create a confession') - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inGuild() || !interaction.guild) { - await interaction.reply({ content: `${emojis.rightArrow2} This command can only be used in a server.`, flags: MessageFlags.Ephemeral }); - return; - } - - const settings = await getSettings(interaction.guild.id, interaction.guild.name); - - if (settings.confessionEnabled === false) { - await interaction.reply({ content: `${emojis.rightArrow2} Confessions are disabled in this server.`, flags: MessageFlags.Ephemeral }); - return; - } - - if (!settings.confessionChannelId) { - await interaction.reply({ content: `${emojis.rightArrow2} Confessions are not configured in this server.`, flags: MessageFlags.Ephemeral }); - return; - } - - const blacklistEntry = await isConfessionBlacklisted(interaction.user.id); - if (blacklistEntry) { - await interaction.reply({ content: `${emojis.rightArrow2} You are blacklisted from confessions${blacklistEntry.reason ? ` reason: ${blacklistEntry.reason}` : ''}.`, flags: MessageFlags.Ephemeral }); - return; - } - - const confessionInput = new TextInputBuilder() - .setCustomId('confession-text') - .setStyle(TextInputStyle.Paragraph) - .setRequired(true) - .setMaxLength(1_000); - - const confessionLabel = new LabelBuilder().setLabel('Confession').setTextInputComponent(confessionInput); - - const modal = new ModalBuilder().setCustomId('create-confession-modal').setTitle('Create Confession').addLabelComponents(confessionLabel); - - await interaction.showModal(modal); - - let modalSubmit; - - try { - modalSubmit = await interaction.awaitModalSubmit({ - filter: (m: any) => m.customId === 'create-confession-modal' && m.user.id === interaction.user.id, - time: 60_000 - }); - await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); - } catch { - return; - } - - const confession = modalSubmit.fields.getTextInputValue('confession-text'); - - const confessionChannel = await interaction.guild.channels.fetch(settings.confessionChannelId).catch(() => null); - - if (!(confessionChannel instanceof TextChannel)) { - await modalSubmit.editReply({ content: `${emojis.rightArrow2} The configured confession channel is unavailable.` }); - return; - } - - const embed = new EmbedBuilder().setTitle('Confession').setDescription(confession).setTimestamp(); - - const message = await confessionChannel.send({ embeds: [embed] }); - - let thread; - - try { - const threadName = confession.replace(/\s+/g, ' ').slice(0, 10).toLowerCase() || 'confession'; - thread = await message.startThread({ name: `confession-${threadName}` }); - } catch (error) { - await message.delete().catch(() => null); - throw error; - } - - const reportButton = new ButtonBuilder().setCustomId(`report-confession:${message.id}`).setLabel('Report').setStyle(ButtonStyle.Danger); - const row = new ActionRowBuilder().addComponents(reportButton); - - await message.edit({ components: [row] }); - - try { - await storeConfessionContext({ - guildId: interaction.guild.id, - channelId: confessionChannel.id, - messageId: message.id, - threadId: thread.id, - creatorId: modalSubmit.user.id - }); - } catch (error) { - await thread.delete().catch(() => null); - await message.delete().catch(() => null); - throw error; - } - - await modalSubmit.editReply({ content: `${emojis.rightArrow2} Confession sent.` }); - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(_registry: Command.Registry) { + _registry.registerChatInputCommand((builder: any) => + builder.setName('confess').setDescription('Create a confession'), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inGuild() || !interaction.guild) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const settings = await getSettings(interaction.guild.id, interaction.guild.name); + + if (settings.confessionEnabled === false) { + await interaction.reply({ + content: `${emojis.rightArrow2} Confessions are disabled in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!settings.confessionChannelId) { + await interaction.reply({ + content: `${emojis.rightArrow2} Confessions are not configured in this server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const blacklistEntry = await isConfessionBlacklisted(interaction.user.id); + if (blacklistEntry) { + await interaction.reply({ + content: `${emojis.rightArrow2} You are blacklisted from confessions${blacklistEntry.reason ? ` reason: ${blacklistEntry.reason}` : ''}.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const confessionInput = new TextInputBuilder() + .setCustomId('confession-text') + .setStyle(TextInputStyle.Paragraph) + .setRequired(true) + .setMaxLength(1_000); + + const confessionLabel = new LabelBuilder().setLabel('Confession').setTextInputComponent(confessionInput); + + const modal = new ModalBuilder() + .setCustomId('create-confession-modal') + .setTitle('Create Confession') + .addLabelComponents(confessionLabel); + + await interaction.showModal(modal); + + let modalSubmit; + + try { + modalSubmit = await interaction.awaitModalSubmit({ + filter: (m: any) => m.customId === 'create-confession-modal' && m.user.id === interaction.user.id, + time: 60_000, + }); + await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); + } catch { + return; + } + + const confession = modalSubmit.fields.getTextInputValue('confession-text'); + + const confessionChannel = await interaction.guild.channels.fetch(settings.confessionChannelId).catch(() => null); + + if (!(confessionChannel instanceof TextChannel)) { + await modalSubmit.editReply({ + content: `${emojis.rightArrow2} The configured confession channel is unavailable.`, + }); + return; + } + + const embed = new EmbedBuilder().setTitle('Confession').setDescription(confession).setTimestamp(); + + const message = await confessionChannel.send({ embeds: [embed] }); + + let thread; + + try { + const threadName = confession.replace(/\s+/g, ' ').slice(0, 10).toLowerCase() || 'confession'; + thread = await message.startThread({ name: `confession-${threadName}` }); + } catch (error) { + await message.delete().catch(() => null); + throw error; + } + + const reportButton = new ButtonBuilder() + .setCustomId(`report-confession:${message.id}`) + .setLabel('Report') + .setStyle(ButtonStyle.Danger); + const row = new ActionRowBuilder().addComponents(reportButton); + + await message.edit({ components: [row] }); + + try { + await storeConfessionContext({ + guildId: interaction.guild.id, + channelId: confessionChannel.id, + messageId: message.id, + threadId: thread.id, + creatorId: modalSubmit.user.id, + }); + } catch (error) { + await thread.delete().catch(() => null); + await message.delete().catch(() => null); + throw error; + } + + await modalSubmit.editReply({ content: `${emojis.rightArrow2} Confession sent.` }); + } +} diff --git a/apps/bot/src/commands/utility/help.ts b/apps/bot/src/commands/utility/help.ts index 3981bb4..16009a2 100644 --- a/apps/bot/src/commands/utility/help.ts +++ b/apps/bot/src/commands/utility/help.ts @@ -3,37 +3,38 @@ import { emojis } from '#utils/emoji.js'; import { EmbedBuilder, MessageFlags } from 'discord.js'; export class HelpCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('help').setDescription("Show what the bot is capable of.") - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('help').setDescription('Show what the bot is capable of.'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const commands = this.container.stores.get('commands'); + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const commands = this.container.stores.get('commands'); - const commandList = Array.from(commands.values()) - .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '')) - .map((cmd) => { - const description = cmd.applicationCommandRegistry['apiCalls'][0]?.builtData.description ?? cmd.description; - const commandName = cmd.applicationCommandRegistry['apiCalls'][0]?.builtData.name ?? cmd.name; + const commandList = Array.from(commands.values()) + .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '')) + .map((cmd) => { + const description = cmd.applicationCommandRegistry['apiCalls'][0]?.builtData.description ?? cmd.description; + const commandName = cmd.applicationCommandRegistry['apiCalls'][0]?.builtData.name ?? cmd.name; - return `${emojis.rightArrow1} **/${commandName}** - ${description}`; - }) - .join('\n'); + return `${emojis.rightArrow1} **/${commandName}** - ${description}`; + }) + .join('\n'); - const embed = new EmbedBuilder() - .setTitle('Commands') - .setDescription(commandList) - .addFields({ name: 'Links', value: '**Status:** https://status.duckorg.com/\n**Official Discord Server:** https://discord.gg/F4HYE8frK2\n**Documentation:** https://docs.duckorg.com/' }); + const embed = new EmbedBuilder().setTitle('Commands').setDescription(commandList).addFields({ + name: 'Links', + value: + '**Status:** https://status.duckorg.com/\n**Official Discord Server:** https://discord.gg/F4HYE8frK2\n**Documentation:** https://docs.duckorg.com/', + }); - await interaction.reply({ - embeds: [embed], - flags: MessageFlags.Ephemeral - }); - } -} \ No newline at end of file + await interaction.reply({ + embeds: [embed], + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/apps/bot/src/commands/utility/reminder/reminder.ts b/apps/bot/src/commands/utility/reminder/reminder.ts index f217ed3..18a8fd0 100644 --- a/apps/bot/src/commands/utility/reminder/reminder.ts +++ b/apps/bot/src/commands/utility/reminder/reminder.ts @@ -6,128 +6,126 @@ import { LimitError } from '#lib/limits.js'; import { emojis } from '#utils/emoji.js'; export class ReminderCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('reminder') - .setDescription('Set reminders!') - .addSubcommand((sub: any) => - sub - .setName('add') - .setDescription('Set a new reminder.') - .addStringOption((option: any) => - option.setName('duration').setDescription('When to remind you').setRequired(true) - ) - .addStringOption((option: any) => - option.setName('message').setDescription('What to remind you about').setRequired(true) - ) - ) - .addSubcommand((sub: any) => - sub - .setName('remove') - .setDescription('Cancel a reminder.') - .addStringOption((option: any) => - option.setName('id').setDescription('The reminder ID').setRequired(true) - ) - ) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const subcommand = interaction.options.getSubcommand(); - - if (subcommand === 'add') { - const durationStr = interaction.options.getString('duration', true); - const message = interaction.options.getString('message', true); - - const duration = ms(durationStr as StringValue); - if (typeof duration !== 'number' || isNaN(duration) || duration <= 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} Invalid duration.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (duration > 31_536_000_000) { - await interaction.reply({ - content: `${emojis.rightArrow2} Reminder cannot be longer than 1 year.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const remindAt = new Date(Date.now() + duration); - - try { - const reminder = interaction.inCachedGuild() - ? await createReminder( - interaction.user.id, - message, - remindAt, - interaction.guild.id, - interaction.guild.name, - interaction.channelId - ) - : await createReminder(interaction.user.id, message, remindAt); - - const unix = Math.floor(remindAt.getTime() / 1000); - await interaction.reply({ - content: `${emojis.rightArrow2} Reminder set to go off in message: ${message}\nID: \`${reminder.id}\`` - }); - - setTimeout(() => { - interaction.deleteReply().catch(() => {}); - }, 5000); - return; - } catch (err) { - console.error(err); - if (err instanceof LimitError) { - await interaction.reply({ - content: `${emojis.rightArrow2} ${err.message}`, - flags: MessageFlags.Ephemeral - }); - return; - } - - throw err; - } - } - - if (subcommand === 'remove') { - const id = interaction.options.getString('id', true); - const reminder = await getReminder(id); - - if (!reminder) { - await interaction.reply({ - content: `${emojis.rightArrow2} No reminder found.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (reminder.userId !== interaction.user.id) { - await interaction.reply({ - content: `${emojis.rightArrow2} You can't remove other's reminders.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - await removeReminder(id); - await interaction.reply({ - content: `${emojis.rightArrow2} Reminder removed.`, - flags: MessageFlags.Ephemeral - }); - - setTimeout(() => { - interaction.deleteReply().catch(() => {}); - }, 5000); - return; - } - } -} \ No newline at end of file + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('reminder') + .setDescription('Set reminders!') + .addSubcommand((sub: any) => + sub + .setName('add') + .setDescription('Set a new reminder.') + .addStringOption((option: any) => + option.setName('duration').setDescription('When to remind you').setRequired(true), + ) + .addStringOption((option: any) => + option.setName('message').setDescription('What to remind you about').setRequired(true), + ), + ) + .addSubcommand((sub: any) => + sub + .setName('remove') + .setDescription('Cancel a reminder.') + .addStringOption((option: any) => option.setName('id').setDescription('The reminder ID').setRequired(true)), + ), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const subcommand = interaction.options.getSubcommand(); + + if (subcommand === 'add') { + const durationStr = interaction.options.getString('duration', true); + const message = interaction.options.getString('message', true); + + const duration = ms(durationStr as StringValue); + if (typeof duration !== 'number' || isNaN(duration) || duration <= 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} Invalid duration.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (duration > 31_536_000_000) { + await interaction.reply({ + content: `${emojis.rightArrow2} Reminder cannot be longer than 1 year.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const remindAt = new Date(Date.now() + duration); + + try { + const reminder = interaction.inCachedGuild() + ? await createReminder( + interaction.user.id, + message, + remindAt, + interaction.guild.id, + interaction.guild.name, + interaction.channelId, + ) + : await createReminder(interaction.user.id, message, remindAt); + + const unix = Math.floor(remindAt.getTime() / 1000); + await interaction.reply({ + content: `${emojis.rightArrow2} Reminder set to go off in message: ${message}\nID: \`${reminder.id}\``, + }); + + setTimeout(() => { + interaction.deleteReply().catch(() => {}); + }, 5000); + return; + } catch (err) { + console.error(err); + if (err instanceof LimitError) { + await interaction.reply({ + content: `${emojis.rightArrow2} ${err.message}`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + throw err; + } + } + + if (subcommand === 'remove') { + const id = interaction.options.getString('id', true); + const reminder = await getReminder(id); + + if (!reminder) { + await interaction.reply({ + content: `${emojis.rightArrow2} No reminder found.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (reminder.userId !== interaction.user.id) { + await interaction.reply({ + content: `${emojis.rightArrow2} You can't remove other's reminders.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + await removeReminder(id); + await interaction.reply({ + content: `${emojis.rightArrow2} Reminder removed.`, + flags: MessageFlags.Ephemeral, + }); + + setTimeout(() => { + interaction.deleteReply().catch(() => {}); + }, 5000); + return; + } + } +} diff --git a/apps/bot/src/commands/utility/reminder/reminders.ts b/apps/bot/src/commands/utility/reminder/reminders.ts index b18d610..22a1c7d 100644 --- a/apps/bot/src/commands/utility/reminder/reminders.ts +++ b/apps/bot/src/commands/utility/reminder/reminders.ts @@ -4,37 +4,37 @@ import { getReminders } from '#lib/reminders.js'; import { emojis } from '#utils/emoji.js'; export class RemindersCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('reminders').setDescription('List your current reminders.') - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('reminders').setDescription('List your current reminders.'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const reminders = interaction.inCachedGuild() - ? await getReminders(interaction.user.id, interaction.guild.id) - : await getReminders(interaction.user.id); + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const reminders = interaction.inCachedGuild() + ? await getReminders(interaction.user.id, interaction.guild.id) + : await getReminders(interaction.user.id); - if (reminders.length === 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} You have no active reminders${interaction.inCachedGuild() ? ' in this server' : ''}.`, - flags: MessageFlags.Ephemeral - }); - return; - } + if (reminders.length === 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} You have no active reminders${interaction.inCachedGuild() ? ' in this server' : ''}.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const lines = reminders.map((r) => { - const unix = Math.floor(r.remindAt.getTime() / 1000); - return ` | ${r.message}\n \`${r.id}\``; - }); + const lines = reminders.map((r) => { + const unix = Math.floor(r.remindAt.getTime() / 1000); + return ` | ${r.message}\n \`${r.id}\``; + }); - await interaction.reply({ - content: `${emojis.rightArrow2} Your reminders:\n${lines.join('\n')}`, - flags: MessageFlags.Ephemeral - }); - } -} \ No newline at end of file + await interaction.reply({ + content: `${emojis.rightArrow2} Your reminders:\n${lines.join('\n')}`, + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/apps/bot/src/commands/utility/settings.ts b/apps/bot/src/commands/utility/settings.ts index ba93d9a..a371194 100644 --- a/apps/bot/src/commands/utility/settings.ts +++ b/apps/bot/src/commands/utility/settings.ts @@ -1,17 +1,17 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - ChannelSelectMenuBuilder, - ChannelType, - type Guild, - InteractionContextType, - MessageFlags, - PermissionFlagsBits, - RoleSelectMenuBuilder, - StringSelectMenuBuilder, - StringSelectMenuOptionBuilder + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChannelSelectMenuBuilder, + ChannelType, + type Guild, + InteractionContextType, + MessageFlags, + PermissionFlagsBits, + RoleSelectMenuBuilder, + StringSelectMenuBuilder, + StringSelectMenuOptionBuilder, } from 'discord.js'; import { getSettings, type ServerSettings, updateSettings } from '#lib/settings.js'; import { emojis } from '#utils/emoji.js'; @@ -19,379 +19,368 @@ import { emojis } from '#utils/emoji.js'; const staleInteractionErrorCodes = new Set([10_015, 50_027, 10062]); function isStaleInteractionError(error: unknown): error is { code: number } { - return ( - typeof error === 'object' && - error !== null && - 'code' in error && - typeof error.code === 'number' && - staleInteractionErrorCodes.has(error.code) - ); + return ( + typeof error === 'object' && + error !== null && + 'code' in error && + typeof error.code === 'number' && + staleInteractionErrorCodes.has(error.code) + ); } function buildWelcomePanel(settings: ServerSettings, guild: Guild, status?: string) { - const currentChannelName = settings.welcomeChannelId - ? guild.channels.cache.get(settings.welcomeChannelId)?.name - : null; - - const toggleMenu = new StringSelectMenuBuilder() - .setCustomId('welcomeToggle') - .setPlaceholder(`${settings.welcomePeople ? 'Enabled' : 'Disabled'}`) - .addOptions( - new StringSelectMenuOptionBuilder() - .setLabel('Enable') - .setDescription('Send a message when a user joins the server.') - .setValue('enable'), - new StringSelectMenuOptionBuilder() - .setLabel('Disable') - .setDescription("Don't send a message when a user joins the server.") - .setValue('disable') - ); - - const channelMenu = new ChannelSelectMenuBuilder() - .setCustomId('welcomeChannel') - .setPlaceholder( - currentChannelName ? `#${currentChannelName}` : 'Select a channel for welcome messages' - ) - .setChannelTypes(ChannelType.GuildText); - - return { - content: status - ? `${emojis.rightArrow1} **Welcome** module:\n${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} **Welcome** module:`, - components: [ - new ActionRowBuilder().addComponents(toggleMenu), - new ActionRowBuilder().addComponents(channelMenu) - ] - }; + const currentChannelName = settings.welcomeChannelId + ? guild.channels.cache.get(settings.welcomeChannelId)?.name + : null; + + const toggleMenu = new StringSelectMenuBuilder() + .setCustomId('welcomeToggle') + .setPlaceholder(`${settings.welcomePeople ? 'Enabled' : 'Disabled'}`) + .addOptions( + new StringSelectMenuOptionBuilder() + .setLabel('Enable') + .setDescription('Send a message when a user joins the server.') + .setValue('enable'), + new StringSelectMenuOptionBuilder() + .setLabel('Disable') + .setDescription("Don't send a message when a user joins the server.") + .setValue('disable'), + ); + + const channelMenu = new ChannelSelectMenuBuilder() + .setCustomId('welcomeChannel') + .setPlaceholder(currentChannelName ? `#${currentChannelName}` : 'Select a channel for welcome messages') + .setChannelTypes(ChannelType.GuildText); + + return { + content: status + ? `${emojis.rightArrow1} **Welcome** module:\n${emojis.rightArrow2} ${status}` + : `${emojis.rightArrow1} **Welcome** module:`, + components: [ + new ActionRowBuilder().addComponents(toggleMenu), + new ActionRowBuilder().addComponents(channelMenu), + ], + }; } function buildTicketPanel(settings: ServerSettings, guild: Guild, status?: string) { - const currentCategoryName = settings.ticketCategoryId - ? guild.channels.cache.get(settings.ticketCategoryId)?.name - : null; - - const categoryMenu = new ChannelSelectMenuBuilder() - .setCustomId('ticketCategory') - .setPlaceholder(currentCategoryName ?? 'Select a category for tickets') - .setChannelTypes(ChannelType.GuildCategory); - - const removeButton = new ButtonBuilder() - .setCustomId('ticketCategoryRemove') - .setLabel('Remove Category') - .setStyle(ButtonStyle.Danger) - .setDisabled(!settings.ticketCategoryId); - - const currentStaffRole = settings.staffRole - ? guild.roles.cache.get(settings.staffRole)?.name - : null; - - const staffRole = new RoleSelectMenuBuilder() - .setCustomId('staffRole') - .setPlaceholder(currentStaffRole ?? 'Select a ticket staff role'); - - const removeStaffRoleButton = new ButtonBuilder() - .setCustomId('removeStaffRole') - .setLabel('Remove Staff Role') - .setStyle(ButtonStyle.Danger) - .setDisabled(!settings.staffRole); - - const currentTranscriptChannelName = settings.ticketTranscriptChannelId - ? guild.channels.cache.get(settings.ticketTranscriptChannelId)?.name - : null; - - const ticketTranscriptChannel = new ChannelSelectMenuBuilder() - .setCustomId('ticketTranscriptChannel') - .setPlaceholder(currentTranscriptChannelName ? `#${currentTranscriptChannelName}` : 'Select a channel for ticket transcripts') - .setChannelTypes(ChannelType.GuildText); - - const removeTranscriptChannelButton = new ButtonBuilder() - .setCustomId('removeTranscriptChannel') - .setLabel('Remove Transcript Channel') - .setStyle(ButtonStyle.Danger) - .setDisabled(!settings.ticketTranscriptChannelId); - - return { - content: status - ? `${emojis.rightArrow1} **Tickets** module:\n${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} **Tickets** module:`, - components: [ - new ActionRowBuilder().addComponents(categoryMenu), - new ActionRowBuilder().addComponents(staffRole), - new ActionRowBuilder().addComponents(ticketTranscriptChannel), - new ActionRowBuilder().addComponents(removeButton, removeStaffRoleButton, removeTranscriptChannelButton) - ] - }; + const currentCategoryName = settings.ticketCategoryId + ? guild.channels.cache.get(settings.ticketCategoryId)?.name + : null; + + const categoryMenu = new ChannelSelectMenuBuilder() + .setCustomId('ticketCategory') + .setPlaceholder(currentCategoryName ?? 'Select a category for tickets') + .setChannelTypes(ChannelType.GuildCategory); + + const removeButton = new ButtonBuilder() + .setCustomId('ticketCategoryRemove') + .setLabel('Remove Category') + .setStyle(ButtonStyle.Danger) + .setDisabled(!settings.ticketCategoryId); + + const currentStaffRole = settings.staffRole ? guild.roles.cache.get(settings.staffRole)?.name : null; + + const staffRole = new RoleSelectMenuBuilder() + .setCustomId('staffRole') + .setPlaceholder(currentStaffRole ?? 'Select a ticket staff role'); + + const removeStaffRoleButton = new ButtonBuilder() + .setCustomId('removeStaffRole') + .setLabel('Remove Staff Role') + .setStyle(ButtonStyle.Danger) + .setDisabled(!settings.staffRole); + + const currentTranscriptChannelName = settings.ticketTranscriptChannelId + ? guild.channels.cache.get(settings.ticketTranscriptChannelId)?.name + : null; + + const ticketTranscriptChannel = new ChannelSelectMenuBuilder() + .setCustomId('ticketTranscriptChannel') + .setPlaceholder( + currentTranscriptChannelName ? `#${currentTranscriptChannelName}` : 'Select a channel for ticket transcripts', + ) + .setChannelTypes(ChannelType.GuildText); + + const removeTranscriptChannelButton = new ButtonBuilder() + .setCustomId('removeTranscriptChannel') + .setLabel('Remove Transcript Channel') + .setStyle(ButtonStyle.Danger) + .setDisabled(!settings.ticketTranscriptChannelId); + + return { + content: status + ? `${emojis.rightArrow1} **Tickets** module:\n${emojis.rightArrow2} ${status}` + : `${emojis.rightArrow1} **Tickets** module:`, + components: [ + new ActionRowBuilder().addComponents(categoryMenu), + new ActionRowBuilder().addComponents(staffRole), + new ActionRowBuilder().addComponents(ticketTranscriptChannel), + new ActionRowBuilder().addComponents( + removeButton, + removeStaffRoleButton, + removeTranscriptChannelButton, + ), + ], + }; } function buildLoggingPanel(settings: ServerSettings, guild: Guild, status?: string) { - const currentChannelName = settings.loggingChannelId - ? guild.channels.cache.get(settings.loggingChannelId)?.name - : null; - - const toggleMenu = new StringSelectMenuBuilder() - .setCustomId('loggingToggle') - .setPlaceholder(`${settings.loggingEnabled ? 'Enabled' : 'Disabled'}`) - .addOptions( - new StringSelectMenuOptionBuilder() - .setLabel('Enable') - .setDescription('Log all server events.') - .setValue('enable'), - new StringSelectMenuOptionBuilder() - .setLabel('Disable') - .setDescription("Don't log any server events.") - .setValue('disable') - ); - - const channelMenu = new ChannelSelectMenuBuilder() - .setCustomId('loggingChannel') - .setPlaceholder( - currentChannelName ? `#${currentChannelName}` : 'Select a channel for logging messages' - ) - .setChannelTypes(ChannelType.GuildText); - - return { - content: status - ? `${emojis.rightArrow1} **Logging** module:\n${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} **Logging** module:`, - components: [ - new ActionRowBuilder().addComponents(toggleMenu), - new ActionRowBuilder().addComponents(channelMenu) - ] - }; + const currentChannelName = settings.loggingChannelId + ? guild.channels.cache.get(settings.loggingChannelId)?.name + : null; + + const toggleMenu = new StringSelectMenuBuilder() + .setCustomId('loggingToggle') + .setPlaceholder(`${settings.loggingEnabled ? 'Enabled' : 'Disabled'}`) + .addOptions( + new StringSelectMenuOptionBuilder() + .setLabel('Enable') + .setDescription('Log all server events.') + .setValue('enable'), + new StringSelectMenuOptionBuilder() + .setLabel('Disable') + .setDescription("Don't log any server events.") + .setValue('disable'), + ); + + const channelMenu = new ChannelSelectMenuBuilder() + .setCustomId('loggingChannel') + .setPlaceholder(currentChannelName ? `#${currentChannelName}` : 'Select a channel for logging messages') + .setChannelTypes(ChannelType.GuildText); + + return { + content: status + ? `${emojis.rightArrow1} **Logging** module:\n${emojis.rightArrow2} ${status}` + : `${emojis.rightArrow1} **Logging** module:`, + components: [ + new ActionRowBuilder().addComponents(toggleMenu), + new ActionRowBuilder().addComponents(channelMenu), + ], + }; } function buildConfessionPanel(settings: ServerSettings, guild: Guild, status?: string) { - const currentChannelName = settings.confessionChannelId - ? guild.channels.cache.get(settings.confessionChannelId)?.name - : null; - - const toggleMenu = new StringSelectMenuBuilder() - .setCustomId('confessionToggle') - .setPlaceholder(`${settings.confessionEnabled ? 'Enabled' : 'Disabled'}`) - .addOptions( - new StringSelectMenuOptionBuilder() - .setLabel('Enable') - .setDescription('Enable confessions for this server.') - .setValue('enable'), - new StringSelectMenuOptionBuilder() - .setLabel('Disable') - .setDescription('Disable confessions for this server.') - .setValue('disable') - ); - - const channelMenu = new ChannelSelectMenuBuilder() - .setCustomId('confessionChannel') - .setPlaceholder(currentChannelName ? `#${currentChannelName}` : 'Select a channel for confessions') - .setChannelTypes(ChannelType.GuildText); - - return { - content: status - ? `${emojis.rightArrow1} **Confessions** module: + const currentChannelName = settings.confessionChannelId + ? guild.channels.cache.get(settings.confessionChannelId)?.name + : null; + + const toggleMenu = new StringSelectMenuBuilder() + .setCustomId('confessionToggle') + .setPlaceholder(`${settings.confessionEnabled ? 'Enabled' : 'Disabled'}`) + .addOptions( + new StringSelectMenuOptionBuilder() + .setLabel('Enable') + .setDescription('Enable confessions for this server.') + .setValue('enable'), + new StringSelectMenuOptionBuilder() + .setLabel('Disable') + .setDescription('Disable confessions for this server.') + .setValue('disable'), + ); + + const channelMenu = new ChannelSelectMenuBuilder() + .setCustomId('confessionChannel') + .setPlaceholder(currentChannelName ? `#${currentChannelName}` : 'Select a channel for confessions') + .setChannelTypes(ChannelType.GuildText); + + return { + content: status + ? `${emojis.rightArrow1} **Confessions** module: ${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} **Confessions** module:`, - components: [ - new ActionRowBuilder().addComponents(toggleMenu), - new ActionRowBuilder().addComponents(channelMenu) - ] - }; + : `${emojis.rightArrow1} **Confessions** module:`, + components: [ + new ActionRowBuilder().addComponents(toggleMenu), + new ActionRowBuilder().addComponents(channelMenu), + ], + }; } async function normalizeTicketSettings(guildId: string, guild: Guild, settings: ServerSettings) { - if (!settings.ticketCategoryId) return settings; + if (!settings.ticketCategoryId) return settings; - const ticketCategory = - guild.channels.cache.get(settings.ticketCategoryId) ?? - (await guild.channels.fetch(settings.ticketCategoryId).catch(() => null)); + const ticketCategory = + guild.channels.cache.get(settings.ticketCategoryId) ?? + (await guild.channels.fetch(settings.ticketCategoryId).catch(() => null)); - if (ticketCategory?.type === ChannelType.GuildCategory) return settings; + if (ticketCategory?.type === ChannelType.GuildCategory) return settings; - return updateSettings(guildId, guild.name, { ticketCategoryId: null }); + return updateSettings(guildId, guild.name, { ticketCategoryId: null }); } export class SettingsCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('settings') - .setDescription("Configure the bot's settings for this server.") - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) - .setContexts(InteractionContextType.Guild) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const safeEditReply = async ( - options: Parameters[0] - ) => { - try { - await interaction.editReply(options); - } catch (error) { - if (isStaleInteractionError(error)) return; - throw error; - } - }; - - const settingMenu = new StringSelectMenuBuilder() - .setCustomId('settingOption') - .setPlaceholder('Select a setting to modify') - .addOptions( - new StringSelectMenuOptionBuilder() - .setLabel('Welcome Message') - .setDescription('Send a message when a user joins the server.') - .setValue('welcome'), - new StringSelectMenuOptionBuilder() - .setLabel('Tickets') - .setDescription('Configure where tickets are created.') - .setValue('tickets'), - new StringSelectMenuOptionBuilder() - .setLabel('Logging') - .setDescription('Configure server channel logging.') - .setValue('logging') - , - new StringSelectMenuOptionBuilder() - .setLabel('Confessions') - .setDescription('Configure where confessions are posted and whether they are enabled.') - .setValue('confessions') - ); - - const response = await interaction.reply({ - components: [new ActionRowBuilder().addComponents(settingMenu)], - flags: MessageFlags.Ephemeral, - withResponse: true - }); - - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - try { - const settingChoice = await import('#utils/collectors.js').then((m) => - m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }) - ); - - if (!settingChoice) { - await safeEditReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - return; - } - - if (!settingChoice.isStringSelectMenu()) return; - - const guildId = interaction.guildId; - const guild = interaction.guild; - - if (!guildId || !guild) { - await settingChoice.update({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - components: [] - }); - return; - } - - const settings = await normalizeTicketSettings( - guildId, - guild, - await getSettings(guildId, guild.name) - ); - - if (settingChoice.values[0] === 'welcome') { - await settingChoice.update(buildWelcomePanel(settings, guild)); - } else if (settingChoice.values[0] === 'tickets') { - await settingChoice.update(buildTicketPanel(settings, guild)); - } else if (settingChoice.values[0] === 'logging') { - await settingChoice.update(buildLoggingPanel(settings, guild)); - } else if (settingChoice.values[0] === 'confessions') { - await settingChoice.update(buildConfessionPanel(settings, guild)); - } else { - return; - } - - const collector = settingChoice.message.createMessageComponentCollector({ - filter: collectorFilter, - time: 60_000 - }); - - collector.on('collect', async (i) => { - if (i.customId === 'welcomeToggle' && i.isStringSelectMenu()) { - const enable = i.values[0] === 'enable'; - const next = await updateSettings(guildId, guild.name, { welcomePeople: enable }); - - await i.update( - buildWelcomePanel(next, guild, `Welcome module **${enable ? 'enabled' : 'disabled'}**.`) - ); - } else if (i.customId === 'welcomeChannel' && i.isChannelSelectMenu()) { - const channelId = i.values[0]; - const next = await updateSettings(guildId, guild.name, { welcomeChannelId: channelId }); - - await i.update(buildWelcomePanel(next, guild, `Welcome channel set to <#${channelId}>.`)); - } else if (i.customId === 'ticketCategory' && i.isChannelSelectMenu()) { - const categoryId = i.values[0]; - const next = await updateSettings(guildId, guild.name, { ticketCategoryId: categoryId }); - - await i.update(buildTicketPanel(next, guild, `Ticket category set to <#${categoryId}>.`)); - } else if (i.customId === 'ticketCategoryRemove' && i.isButton()) { - const next = await updateSettings(guildId, guild.name, { ticketCategoryId: null }); - - await i.update(buildTicketPanel(next, guild, 'Ticket category removed.')); - } else if (i.customId === 'staffRole' && i.isRoleSelectMenu()) { - const roleId = i.values[0]; - const next = await updateSettings(guildId, guild.name, { staffRole: roleId }); - - await i.update(buildTicketPanel(next, guild, `Ticket staff role set to <@&${roleId}>.`)); - } else if (i.customId === 'removeStaffRole' && i.isButton()) { - const next = await updateSettings(guildId, guild.name, { staffRole: null }); - - await i.update(buildTicketPanel(next, guild, 'Ticket staff role removed.')); - } else if (i.customId === 'ticketTranscriptChannel' && i.isChannelSelectMenu()) { - const channelId = i.values[0]; - const next = await updateSettings(guildId, guild.name, { ticketTranscriptChannelId: channelId }); - - await i.update(buildTicketPanel(next, guild, `Ticket transcript channel set to <#${channelId}>.`)); - } else if (i.customId === 'removeTranscriptChannel' && i.isButton()) { - const next = await updateSettings(guildId, guild.name, { ticketTranscriptChannelId: null }); - - await i.update(buildTicketPanel(next, guild, 'Ticket transcript channel removed.')); - } else if (i.customId === 'loggingToggle' && i.isStringSelectMenu()) { - const enable = i.values[0] === 'enable'; - const next = await updateSettings(guildId, guild.name, { loggingEnabled: enable }); - - await i.update( - buildLoggingPanel(next, guild, `Logging module **${enable ? 'enabled' : 'disabled'}**.`) - ); - } else if (i.customId === 'loggingChannel' && i.isChannelSelectMenu()) { - const channelId = i.values[0]; - const next = await updateSettings(guildId, guild.name, { loggingChannelId: channelId }); - - await i.update(buildLoggingPanel(next, guild, `Logging channel set to <#${channelId}>.`)); - } else if (i.customId === 'confessionToggle' && i.isStringSelectMenu()) { - const enable = i.values[0] === 'enable'; - const next = await updateSettings(guildId, guild.name, { confessionEnabled: enable }); - - await i.update(buildConfessionPanel(next, guild, `Confessions **${enable ? 'enabled' : 'disabled'}**.`)); - } else if (i.customId === 'confessionChannel' && i.isChannelSelectMenu()) { - const channelId = i.values[0]; - const next = await updateSettings(guildId, guild.name, { confessionChannelId: channelId }); - - await i.update(buildConfessionPanel(next, guild, `Confession channel set to <#${channelId}>.`)); - } - }); - - collector.on('end', async () => { - await safeEditReply({ - content: `${emojis.rightArrow2} Closed.`, - components: [] - }); - }); - } catch (err) { - console.error(err); - await safeEditReply({ - content: `${emojis.rightArrow2} No response within a minute or errored.`, - components: [] - }); - } - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('settings') + .setDescription("Configure the bot's settings for this server.") + .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) + .setContexts(InteractionContextType.Guild), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const safeEditReply = async (options: Parameters[0]) => { + try { + await interaction.editReply(options); + } catch (error) { + if (isStaleInteractionError(error)) return; + throw error; + } + }; + + const settingMenu = new StringSelectMenuBuilder() + .setCustomId('settingOption') + .setPlaceholder('Select a setting to modify') + .addOptions( + new StringSelectMenuOptionBuilder() + .setLabel('Welcome Message') + .setDescription('Send a message when a user joins the server.') + .setValue('welcome'), + new StringSelectMenuOptionBuilder() + .setLabel('Tickets') + .setDescription('Configure where tickets are created.') + .setValue('tickets'), + new StringSelectMenuOptionBuilder() + .setLabel('Logging') + .setDescription('Configure server channel logging.') + .setValue('logging'), + new StringSelectMenuOptionBuilder() + .setLabel('Confessions') + .setDescription('Configure where confessions are posted and whether they are enabled.') + .setValue('confessions'), + ); + + const response = await interaction.reply({ + components: [new ActionRowBuilder().addComponents(settingMenu)], + flags: MessageFlags.Ephemeral, + withResponse: true, + }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + try { + const settingChoice = await import('#utils/collectors.js').then((m) => + m.awaitMessageComponentSafe(response.resource!.message!, { filter: collectorFilter, time: 60_000 }), + ); + + if (!settingChoice) { + await safeEditReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + return; + } + + if (!settingChoice.isStringSelectMenu()) return; + + const guildId = interaction.guildId; + const guild = interaction.guild; + + if (!guildId || !guild) { + await settingChoice.update({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + components: [], + }); + return; + } + + const settings = await normalizeTicketSettings(guildId, guild, await getSettings(guildId, guild.name)); + + if (settingChoice.values[0] === 'welcome') { + await settingChoice.update(buildWelcomePanel(settings, guild)); + } else if (settingChoice.values[0] === 'tickets') { + await settingChoice.update(buildTicketPanel(settings, guild)); + } else if (settingChoice.values[0] === 'logging') { + await settingChoice.update(buildLoggingPanel(settings, guild)); + } else if (settingChoice.values[0] === 'confessions') { + await settingChoice.update(buildConfessionPanel(settings, guild)); + } else { + return; + } + + const collector = settingChoice.message.createMessageComponentCollector({ + filter: collectorFilter, + time: 60_000, + }); + + collector.on('collect', async (i) => { + if (i.customId === 'welcomeToggle' && i.isStringSelectMenu()) { + const enable = i.values[0] === 'enable'; + const next = await updateSettings(guildId, guild.name, { welcomePeople: enable }); + + await i.update(buildWelcomePanel(next, guild, `Welcome module **${enable ? 'enabled' : 'disabled'}**.`)); + } else if (i.customId === 'welcomeChannel' && i.isChannelSelectMenu()) { + const channelId = i.values[0]; + const next = await updateSettings(guildId, guild.name, { welcomeChannelId: channelId }); + + await i.update(buildWelcomePanel(next, guild, `Welcome channel set to <#${channelId}>.`)); + } else if (i.customId === 'ticketCategory' && i.isChannelSelectMenu()) { + const categoryId = i.values[0]; + const next = await updateSettings(guildId, guild.name, { ticketCategoryId: categoryId }); + + await i.update(buildTicketPanel(next, guild, `Ticket category set to <#${categoryId}>.`)); + } else if (i.customId === 'ticketCategoryRemove' && i.isButton()) { + const next = await updateSettings(guildId, guild.name, { ticketCategoryId: null }); + + await i.update(buildTicketPanel(next, guild, 'Ticket category removed.')); + } else if (i.customId === 'staffRole' && i.isRoleSelectMenu()) { + const roleId = i.values[0]; + const next = await updateSettings(guildId, guild.name, { staffRole: roleId }); + + await i.update(buildTicketPanel(next, guild, `Ticket staff role set to <@&${roleId}>.`)); + } else if (i.customId === 'removeStaffRole' && i.isButton()) { + const next = await updateSettings(guildId, guild.name, { staffRole: null }); + + await i.update(buildTicketPanel(next, guild, 'Ticket staff role removed.')); + } else if (i.customId === 'ticketTranscriptChannel' && i.isChannelSelectMenu()) { + const channelId = i.values[0]; + const next = await updateSettings(guildId, guild.name, { ticketTranscriptChannelId: channelId }); + + await i.update(buildTicketPanel(next, guild, `Ticket transcript channel set to <#${channelId}>.`)); + } else if (i.customId === 'removeTranscriptChannel' && i.isButton()) { + const next = await updateSettings(guildId, guild.name, { ticketTranscriptChannelId: null }); + + await i.update(buildTicketPanel(next, guild, 'Ticket transcript channel removed.')); + } else if (i.customId === 'loggingToggle' && i.isStringSelectMenu()) { + const enable = i.values[0] === 'enable'; + const next = await updateSettings(guildId, guild.name, { loggingEnabled: enable }); + + await i.update(buildLoggingPanel(next, guild, `Logging module **${enable ? 'enabled' : 'disabled'}**.`)); + } else if (i.customId === 'loggingChannel' && i.isChannelSelectMenu()) { + const channelId = i.values[0]; + const next = await updateSettings(guildId, guild.name, { loggingChannelId: channelId }); + + await i.update(buildLoggingPanel(next, guild, `Logging channel set to <#${channelId}>.`)); + } else if (i.customId === 'confessionToggle' && i.isStringSelectMenu()) { + const enable = i.values[0] === 'enable'; + const next = await updateSettings(guildId, guild.name, { confessionEnabled: enable }); + + await i.update(buildConfessionPanel(next, guild, `Confessions **${enable ? 'enabled' : 'disabled'}**.`)); + } else if (i.customId === 'confessionChannel' && i.isChannelSelectMenu()) { + const channelId = i.values[0]; + const next = await updateSettings(guildId, guild.name, { confessionChannelId: channelId }); + + await i.update(buildConfessionPanel(next, guild, `Confession channel set to <#${channelId}>.`)); + } + }); + + collector.on('end', async () => { + await safeEditReply({ + content: `${emojis.rightArrow2} Closed.`, + components: [], + }); + }); + } catch (err) { + console.error(err); + await safeEditReply({ + content: `${emojis.rightArrow2} No response within a minute or errored.`, + components: [], + }); + } + } } diff --git a/apps/bot/src/commands/utility/setup.ts b/apps/bot/src/commands/utility/setup.ts index cc5f278..0909133 100644 --- a/apps/bot/src/commands/utility/setup.ts +++ b/apps/bot/src/commands/utility/setup.ts @@ -1,16 +1,16 @@ import { Command } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - ChannelSelectMenuBuilder, - ChannelType, - InteractionContextType, - type Message, - MessageFlags, - type MessageComponentInteraction, - PermissionFlagsBits, - RoleSelectMenuBuilder + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChannelSelectMenuBuilder, + ChannelType, + InteractionContextType, + type Message, + MessageFlags, + type MessageComponentInteraction, + PermissionFlagsBits, + RoleSelectMenuBuilder, } from 'discord.js'; import { getSettings, updateSettings } from '#lib/settings.js'; import { emojis } from '#utils/emoji.js'; @@ -19,611 +19,573 @@ import { awaitMessageComponentSafe } from '#utils/collectors.js'; const staleInteractionErrorCodes = new Set([10_015, 50_027, 10062]); function isStaleInteractionError(error: unknown): error is { code: number } { - return ( - typeof error === 'object' && - error !== null && - 'code' in error && - typeof error.code === 'number' && - staleInteractionErrorCodes.has(error.code) - ); + return ( + typeof error === 'object' && + error !== null && + 'code' in error && + typeof error.code === 'number' && + staleInteractionErrorCodes.has(error.code) + ); } const STEP_TIMEOUT = 90_000; function yesNoRow() { - return new ActionRowBuilder().addComponents( - new ButtonBuilder().setCustomId('setup_yes').setLabel('Yes, enable it').setStyle(ButtonStyle.Success), - new ButtonBuilder().setCustomId('setup_skip').setLabel('Skip').setStyle(ButtonStyle.Secondary) - ); + return new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('setup_yes').setLabel('Yes, enable it').setStyle(ButtonStyle.Success), + new ButtonBuilder().setCustomId('setup_skip').setLabel('Skip').setStyle(ButtonStyle.Secondary), + ); } function nextSkipRow() { - return new ActionRowBuilder().addComponents( - new ButtonBuilder().setCustomId('setup_next').setLabel('Next').setStyle(ButtonStyle.Primary), - new ButtonBuilder().setCustomId('setup_skip').setLabel('Skip this feature').setStyle(ButtonStyle.Secondary) - ); + return new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('setup_next').setLabel('Next').setStyle(ButtonStyle.Primary), + new ButtonBuilder().setCustomId('setup_skip').setLabel('Skip this feature').setStyle(ButtonStyle.Secondary), + ); } async function runCollector( - message: Message, - filter: (i: any) => boolean, - timeout: number, - handler: (i: MessageComponentInteraction, stop: () => void) => Promise + message: Message, + filter: (i: any) => boolean, + timeout: number, + handler: (i: MessageComponentInteraction, stop: () => void) => Promise, ): Promise { - return new Promise((resolve) => { - const collector = message.createMessageComponentCollector({ filter, time: timeout }); - let stopped = false; - - const stop = () => { - if (stopped) return; - stopped = true; - collector.stop('done'); - }; - - collector.on('collect', async (i) => { - await handler(i, stop); - }); - - collector.on('end', (_, reason) => { - resolve(reason === 'done'); - }); - }); + return new Promise((resolve) => { + const collector = message.createMessageComponentCollector({ filter, time: timeout }); + let stopped = false; + + const stop = () => { + if (stopped) return; + stopped = true; + collector.stop('done'); + }; + + collector.on('collect', async (i) => { + await handler(i, stop); + }); + + collector.on('end', (_, reason) => { + resolve(reason === 'done'); + }); + }); } export class SetupCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } - - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('setup') - .setDescription('Guided setup to configure the bot for this server.') - .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) - .setContexts(InteractionContextType.Guild) - ); - } - - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - if (!interaction.inCachedGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This command can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const { guildId, guild } = interaction; - const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; - - const safeEditReply = async ( - options: Parameters[0] - ) => { - try { - await interaction.editReply(options); - } catch (error) { - if (isStaleInteractionError(error)) return; - throw error; - } - }; - - // initial menu - const response = await interaction.reply({ - content: [ - `**Server Setup**`, - `${emojis.rightArrow1} This wizard will walk you through configuring the bot's features.`, - `${emojis.rightArrow1} You can adjust anything later with \`/settings\`.`, - `**Please put the newly created Quest role at the top of the role list!**` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setCustomId('setup_start') - .setLabel('Get Started') - .setStyle(ButtonStyle.Success), - new ButtonBuilder() - .setCustomId('setup_cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary) - ) - ], - flags: MessageFlags.Ephemeral, - withResponse: true - }); - - const message = response.resource!.message!; - - const startChoice = await awaitMessageComponentSafe(message, { - filter: collectorFilter, - time: STEP_TIMEOUT - }); - - if (!startChoice || startChoice.customId === 'setup_cancel') { - await safeEditReply({ content: `${emojis.rightArrow2} Setup cancelled.`, components: [] }); - return; - } - - let settings = await getSettings(guildId, guild.name); - const summary: string[] = []; - - // 1. welcome messages - await startChoice.update({ - content: [ - `**Setup (1/4) Welcome Messages**`, - `${emojis.rightArrow1} Would you like to send a welcome message when someone joins?` - ].join('\n'), - components: [yesNoRow()] - }); - - const welcomeFeatureChoice = await awaitMessageComponentSafe(message, { - filter: collectorFilter, - time: STEP_TIMEOUT - }); - - if (!welcomeFeatureChoice) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (welcomeFeatureChoice.customId === 'setup_yes') { - let welcomeChannelId: string | null = null; - - const buildWelcomeConfigPanel = (status?: string) => ({ - content: [ - `**Setup (1/4) Welcome Messages**`, - `${emojis.rightArrow1} Select the channel for welcome messages.`, - status - ? `${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} Click **Next** when ready.` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId('setup_welcome_channel') - .setPlaceholder( - welcomeChannelId - ? `${guild.channels.cache.get(welcomeChannelId)?.name ?? 'selected'}` - : 'Select a channel' - ) - .setChannelTypes(ChannelType.GuildText) - ), - nextSkipRow() - ] - }); - - await welcomeFeatureChoice.update(buildWelcomeConfigPanel()); - - const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { - if (i.customId === 'setup_welcome_channel' && i.isChannelSelectMenu()) { - welcomeChannelId = i.values[0]; - await i.update( - buildWelcomeConfigPanel(`Welcome channel set to <#${welcomeChannelId}>. Click **Next** to continue.`) - ); - } else if (i.customId === 'setup_next' && i.isButton()) { - await i.deferUpdate(); - stop(); - } else if (i.customId === 'setup_skip' && i.isButton()) { - welcomeChannelId = null; - await i.deferUpdate(); - stop(); - } - }); - - if (!completed) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (welcomeChannelId) { - settings = await updateSettings(guildId, guild.name, { - welcomePeople: true, - welcomeChannelId - }); - summary.push(`${emojis.rightArrow2} **Welcome Messages** enabled in <#${welcomeChannelId}>`); - } else { - summary.push(`${emojis.rightArrow2} **Welcome Messages** skipped`); - } - } else { - await welcomeFeatureChoice.deferUpdate(); - summary.push(`${emojis.rightArrow2} **Welcome Messages** skipped`); - } - - // 2: tickets - await safeEditReply({ - content: [ - `**Setup (2/4) Tickets**`, - `${emojis.rightArrow1} Would you like to enable tickets?` - ].join('\n'), - components: [yesNoRow()] - }); - - const ticketsFeatureChoice = await awaitMessageComponentSafe(message, { - filter: collectorFilter, - time: STEP_TIMEOUT - }); - - if (!ticketsFeatureChoice) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (ticketsFeatureChoice.customId === 'setup_yes') { - let ticketCategoryId: string | null = null; - let staffRoleId: string | null = null; - let transcriptChannelId: string | null = null; - - const buildTicketConfigPanel = (status?: string) => ({ - content: [ - `**Setup (2/4) Tickets**`, - `${emojis.rightArrow1} Configure the ticket system below. Staff role and transcript channel are optional.`, - status - ? `${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} Click **Next** when ready.` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId('setup_ticket_category') - .setPlaceholder( - ticketCategoryId - ? `#${guild.channels.cache.get(ticketCategoryId)?.name ?? 'selected'}` - : 'Select a ticket category (required)' - ) - .setChannelTypes(ChannelType.GuildCategory) - ), - new ActionRowBuilder().addComponents( - new RoleSelectMenuBuilder() - .setCustomId('setup_ticket_staff_role') - .setPlaceholder( - staffRoleId - ? guild.roles.cache.get(staffRoleId)?.name ?? 'selected' - : 'Select a staff role (optional)' - ) - ), - new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId('setup_ticket_transcript') - .setPlaceholder( - transcriptChannelId - ? `#${guild.channels.cache.get(transcriptChannelId)?.name ?? 'selected'}` - : 'Select a transcript channel (optional)' - ) - .setChannelTypes(ChannelType.GuildText) - ), - nextSkipRow() - ] - }); - - await ticketsFeatureChoice.update(buildTicketConfigPanel()); - - const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { - if (i.customId === 'setup_ticket_category' && i.isChannelSelectMenu()) { - ticketCategoryId = i.values[0]; - await i.update(buildTicketConfigPanel(`Ticket category set to <#${ticketCategoryId}>.`)); - } else if (i.customId === 'setup_ticket_staff_role' && i.isRoleSelectMenu()) { - staffRoleId = i.values[0]; - await i.update(buildTicketConfigPanel(`Staff role set to <@&${staffRoleId}>.`)); - } else if (i.customId === 'setup_ticket_transcript' && i.isChannelSelectMenu()) { - transcriptChannelId = i.values[0]; - await i.update(buildTicketConfigPanel(`Transcript channel set to <#${transcriptChannelId}>.`)); - } else if (i.customId === 'setup_next' && i.isButton()) { - await i.deferUpdate(); - stop(); - } else if (i.customId === 'setup_skip' && i.isButton()) { - ticketCategoryId = null; - staffRoleId = null; - transcriptChannelId = null; - await i.deferUpdate(); - stop(); - } - }); - - if (!completed) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (ticketCategoryId) { - settings = await updateSettings(guildId, guild.name, { - ticketCategoryId, - staffRole: staffRoleId, - ticketTranscriptChannelId: transcriptChannelId - }); - summary.push(`${emojis.rightArrow2} **Tickets** enabled`); - - // sub-panel: post ticket panel - await safeEditReply({ - content: [ - `**Setup (2/4) Ticket Panel**`, - `${emojis.rightArrow1} Would you like to post the ticket creation panel in a channel?`, - `${emojis.rightArrow1} Members click a button in that channel to open a ticket.` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setCustomId('setup_yes') - .setLabel('Yes!') - .setStyle(ButtonStyle.Success), - new ButtonBuilder() - .setCustomId('setup_skip') - .setLabel('Skip') - .setStyle(ButtonStyle.Secondary) - ) - ] - }); - - const panelChoice = await awaitMessageComponentSafe(message, { - filter: collectorFilter, - time: STEP_TIMEOUT - }); - - if (!panelChoice) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (panelChoice.customId === 'setup_yes') { - let panelChannelId: string | null = null; - - const buildPanelChannelPanel = (status?: string) => ({ - content: [ - `**Setup (2/4) Ticket Panel**`, - `${emojis.rightArrow1} Select the channel to post the ticket creation panel in.`, - status - ? `${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} Click **Send Panel** when ready.` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId('setup_panel_channel') - .setPlaceholder( - panelChannelId - ? `#${guild.channels.cache.get(panelChannelId)?.name ?? 'selected'}` - : 'Select a channel' - ) - .setChannelTypes(ChannelType.GuildText) - ), - new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setCustomId('setup_send') - .setLabel('Send Panel') - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId('setup_skip') - .setLabel('Skip') - .setStyle(ButtonStyle.Secondary) - ) - ] - }); - - await panelChoice.update(buildPanelChannelPanel()); - - await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { - if (i.customId === 'setup_panel_channel' && i.isChannelSelectMenu()) { - panelChannelId = i.values[0]; - await i.update( - buildPanelChannelPanel( - `Panel will be sent in <#${panelChannelId}>. Click **Send Panel** to post it.` - ) - ); - } else if (i.customId === 'setup_send' && i.isButton()) { - if (panelChannelId) { - const panelChannel = guild.channels.cache.get(panelChannelId); - if (panelChannel?.isTextBased()) { - await panelChannel.send({ - content: '**Create a ticket by clicking the button below!**', - components: [ - new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setCustomId('create-ticket') - .setLabel('Create Ticket') - .setStyle(ButtonStyle.Success) - ) - ] - }); - } - } - await i.deferUpdate(); - stop(); - } else if (i.customId === 'setup_skip' && i.isButton()) { - await i.deferUpdate(); - stop(); - } - }); - } else { - await panelChoice.deferUpdate(); - } - } else { - summary.push(`${emojis.rightArrow2} **Tickets** skipped`); - } - } else { - await ticketsFeatureChoice.deferUpdate(); - summary.push(`${emojis.rightArrow2} **Tickets** skipped`); - } - - // 3: logging - await safeEditReply({ - content: [ - `**Setup (3/4) Logging**`, - `${emojis.rightArrow1} Would you like to log server events (bans, kicks, message deletions, etc.) in a channel?` - ].join('\n'), - components: [yesNoRow()] - }); - - const loggingFeatureChoice = await awaitMessageComponentSafe(message, { - filter: collectorFilter, - time: STEP_TIMEOUT - }); - - if (!loggingFeatureChoice) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (loggingFeatureChoice.customId === 'setup_yes') { - let loggingChannelId: string | null = null; - - const buildLoggingConfigPanel = (status?: string) => ({ - content: [ - `**Setup (3/4) Logging**`, - `${emojis.rightArrow1} Select the channel where server events will be logged.`, - status - ? `${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} Click **Next** when ready.` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId('setup_logging_channel') - .setPlaceholder( - loggingChannelId - ? `#${guild.channels.cache.get(loggingChannelId)?.name ?? 'selected'}` - : 'Select a channel' - ) - .setChannelTypes(ChannelType.GuildText) - ), - nextSkipRow() - ] - }); - - await loggingFeatureChoice.update(buildLoggingConfigPanel()); - - const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { - if (i.customId === 'setup_logging_channel' && i.isChannelSelectMenu()) { - loggingChannelId = i.values[0]; - await i.update( - buildLoggingConfigPanel( - `Logging channel set to <#${loggingChannelId}>. Click **Next** to continue.` - ) - ); - } else if (i.customId === 'setup_next' && i.isButton()) { - await i.deferUpdate(); - stop(); - } else if (i.customId === 'setup_skip' && i.isButton()) { - loggingChannelId = null; - await i.deferUpdate(); - stop(); - } - }); - - if (!completed) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (loggingChannelId) { - settings = await updateSettings(guildId, guild.name, { - loggingEnabled: true, - loggingChannelId - }); - summary.push(`${emojis.rightArrow2} **Logging** enabled, channel: <#${loggingChannelId}>`); - } else { - summary.push(`${emojis.rightArrow1} **Logging** skipped`); - } - } else { - await loggingFeatureChoice.deferUpdate(); - summary.push(`${emojis.rightArrow1} **Logging** skipped`); - } - - // 4: confessions - await safeEditReply({ - content: [ - `**Setup (4/4) Confessions**`, - `${emojis.rightArrow1} Would you like to enable confessions?` - ].join('\n'), - components: [yesNoRow()] - }); - - const confessionsFeatureChoice = await awaitMessageComponentSafe(message, { - filter: collectorFilter, - time: STEP_TIMEOUT - }); - - if (!confessionsFeatureChoice) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (confessionsFeatureChoice.customId === 'setup_yes') { - let confessionChannelId: string | null = null; - - const buildConfessionConfigPanel = (status?: string) => ({ - content: [ - `**Setup (4/4) Confessions**`, - `${emojis.rightArrow1} Select the channel where anonymous confessions will be posted.`, - status - ? `${emojis.rightArrow2} ${status}` - : `${emojis.rightArrow1} Click **Next** when ready.` - ].join('\n'), - components: [ - new ActionRowBuilder().addComponents( - new ChannelSelectMenuBuilder() - .setCustomId('setup_confession_channel') - .setPlaceholder( - confessionChannelId - ? `#${guild.channels.cache.get(confessionChannelId)?.name ?? 'selected'}` - : 'Select a channel' - ) - .setChannelTypes(ChannelType.GuildText) - ), - nextSkipRow() - ] - }); - - await confessionsFeatureChoice.update(buildConfessionConfigPanel()); - - const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { - if (i.customId === 'setup_confession_channel' && i.isChannelSelectMenu()) { - confessionChannelId = i.values[0]; - await i.update( - buildConfessionConfigPanel( - `Confession channel set to <#${confessionChannelId}>. Click **Next** to continue.` - ) - ); - } else if (i.customId === 'setup_next' && i.isButton()) { - await i.deferUpdate(); - stop(); - } else if (i.customId === 'setup_skip' && i.isButton()) { - confessionChannelId = null; - await i.deferUpdate(); - stop(); - } - }); - - if (!completed) { - await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); - return; - } - - if (confessionChannelId) { - settings = await updateSettings(guildId, guild.name, { - confessionEnabled: true, - confessionChannelId - }); - summary.push(`${emojis.rightArrow2} **Confessions** enabled in <#${confessionChannelId}>`); - } else { - summary.push(`${emojis.rightArrow2} **Confessions** skipped`); - } - } else { - await confessionsFeatureChoice.deferUpdate(); - summary.push(`${emojis.rightArrow2} **Confessions** skipped`); - } - - await safeEditReply({ - content: [ - `**Here's what was configured:**`, - ...summary, - '', - `**What's next?**`, - `${emojis.rightArrow1} Use \`/automod add\` to block words in your server.`, - `${emojis.rightArrow1} Use \`/autorole add\` to assign roles to new members automatically.`, - `${emojis.rightArrow1} Use \`/settings\` to adjust any of these at any time.` - ].join('\n'), - components: [] - }); - - void settings; - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('setup') + .setDescription('Guided setup to configure the bot for this server.') + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) + .setContexts(InteractionContextType.Guild), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This command can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const { guildId, guild } = interaction; + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + const safeEditReply = async (options: Parameters[0]) => { + try { + await interaction.editReply(options); + } catch (error) { + if (isStaleInteractionError(error)) return; + throw error; + } + }; + + // initial menu + const response = await interaction.reply({ + content: [ + `**Server Setup**`, + `${emojis.rightArrow1} This wizard will walk you through configuring the bot's features.`, + `${emojis.rightArrow1} You can adjust anything later with \`/settings\`.`, + `**Please put the newly created Quest role at the top of the role list!**`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('setup_start').setLabel('Get Started').setStyle(ButtonStyle.Success), + new ButtonBuilder().setCustomId('setup_cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary), + ), + ], + flags: MessageFlags.Ephemeral, + withResponse: true, + }); + + const message = response.resource!.message!; + + const startChoice = await awaitMessageComponentSafe(message, { + filter: collectorFilter, + time: STEP_TIMEOUT, + }); + + if (!startChoice || startChoice.customId === 'setup_cancel') { + await safeEditReply({ content: `${emojis.rightArrow2} Setup cancelled.`, components: [] }); + return; + } + + let settings = await getSettings(guildId, guild.name); + const summary: string[] = []; + + // 1. welcome messages + await startChoice.update({ + content: [ + `**Setup (1/4) Welcome Messages**`, + `${emojis.rightArrow1} Would you like to send a welcome message when someone joins?`, + ].join('\n'), + components: [yesNoRow()], + }); + + const welcomeFeatureChoice = await awaitMessageComponentSafe(message, { + filter: collectorFilter, + time: STEP_TIMEOUT, + }); + + if (!welcomeFeatureChoice) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (welcomeFeatureChoice.customId === 'setup_yes') { + let welcomeChannelId: string | null = null; + + const buildWelcomeConfigPanel = (status?: string) => ({ + content: [ + `**Setup (1/4) Welcome Messages**`, + `${emojis.rightArrow1} Select the channel for welcome messages.`, + status ? `${emojis.rightArrow2} ${status}` : `${emojis.rightArrow1} Click **Next** when ready.`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId('setup_welcome_channel') + .setPlaceholder( + welcomeChannelId + ? `${guild.channels.cache.get(welcomeChannelId)?.name ?? 'selected'}` + : 'Select a channel', + ) + .setChannelTypes(ChannelType.GuildText), + ), + nextSkipRow(), + ], + }); + + await welcomeFeatureChoice.update(buildWelcomeConfigPanel()); + + const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { + if (i.customId === 'setup_welcome_channel' && i.isChannelSelectMenu()) { + welcomeChannelId = i.values[0]; + await i.update( + buildWelcomeConfigPanel(`Welcome channel set to <#${welcomeChannelId}>. Click **Next** to continue.`), + ); + } else if (i.customId === 'setup_next' && i.isButton()) { + await i.deferUpdate(); + stop(); + } else if (i.customId === 'setup_skip' && i.isButton()) { + welcomeChannelId = null; + await i.deferUpdate(); + stop(); + } + }); + + if (!completed) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (welcomeChannelId) { + settings = await updateSettings(guildId, guild.name, { + welcomePeople: true, + welcomeChannelId, + }); + summary.push(`${emojis.rightArrow2} **Welcome Messages** enabled in <#${welcomeChannelId}>`); + } else { + summary.push(`${emojis.rightArrow2} **Welcome Messages** skipped`); + } + } else { + await welcomeFeatureChoice.deferUpdate(); + summary.push(`${emojis.rightArrow2} **Welcome Messages** skipped`); + } + + // 2: tickets + await safeEditReply({ + content: [`**Setup (2/4) Tickets**`, `${emojis.rightArrow1} Would you like to enable tickets?`].join('\n'), + components: [yesNoRow()], + }); + + const ticketsFeatureChoice = await awaitMessageComponentSafe(message, { + filter: collectorFilter, + time: STEP_TIMEOUT, + }); + + if (!ticketsFeatureChoice) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (ticketsFeatureChoice.customId === 'setup_yes') { + let ticketCategoryId: string | null = null; + let staffRoleId: string | null = null; + let transcriptChannelId: string | null = null; + + const buildTicketConfigPanel = (status?: string) => ({ + content: [ + `**Setup (2/4) Tickets**`, + `${emojis.rightArrow1} Configure the ticket system below. Staff role and transcript channel are optional.`, + status ? `${emojis.rightArrow2} ${status}` : `${emojis.rightArrow1} Click **Next** when ready.`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId('setup_ticket_category') + .setPlaceholder( + ticketCategoryId + ? `#${guild.channels.cache.get(ticketCategoryId)?.name ?? 'selected'}` + : 'Select a ticket category (required)', + ) + .setChannelTypes(ChannelType.GuildCategory), + ), + new ActionRowBuilder().addComponents( + new RoleSelectMenuBuilder() + .setCustomId('setup_ticket_staff_role') + .setPlaceholder( + staffRoleId + ? (guild.roles.cache.get(staffRoleId)?.name ?? 'selected') + : 'Select a staff role (optional)', + ), + ), + new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId('setup_ticket_transcript') + .setPlaceholder( + transcriptChannelId + ? `#${guild.channels.cache.get(transcriptChannelId)?.name ?? 'selected'}` + : 'Select a transcript channel (optional)', + ) + .setChannelTypes(ChannelType.GuildText), + ), + nextSkipRow(), + ], + }); + + await ticketsFeatureChoice.update(buildTicketConfigPanel()); + + const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { + if (i.customId === 'setup_ticket_category' && i.isChannelSelectMenu()) { + ticketCategoryId = i.values[0]; + await i.update(buildTicketConfigPanel(`Ticket category set to <#${ticketCategoryId}>.`)); + } else if (i.customId === 'setup_ticket_staff_role' && i.isRoleSelectMenu()) { + staffRoleId = i.values[0]; + await i.update(buildTicketConfigPanel(`Staff role set to <@&${staffRoleId}>.`)); + } else if (i.customId === 'setup_ticket_transcript' && i.isChannelSelectMenu()) { + transcriptChannelId = i.values[0]; + await i.update(buildTicketConfigPanel(`Transcript channel set to <#${transcriptChannelId}>.`)); + } else if (i.customId === 'setup_next' && i.isButton()) { + await i.deferUpdate(); + stop(); + } else if (i.customId === 'setup_skip' && i.isButton()) { + ticketCategoryId = null; + staffRoleId = null; + transcriptChannelId = null; + await i.deferUpdate(); + stop(); + } + }); + + if (!completed) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (ticketCategoryId) { + settings = await updateSettings(guildId, guild.name, { + ticketCategoryId, + staffRole: staffRoleId, + ticketTranscriptChannelId: transcriptChannelId, + }); + summary.push(`${emojis.rightArrow2} **Tickets** enabled`); + + // sub-panel: post ticket panel + await safeEditReply({ + content: [ + `**Setup (2/4) Ticket Panel**`, + `${emojis.rightArrow1} Would you like to post the ticket creation panel in a channel?`, + `${emojis.rightArrow1} Members click a button in that channel to open a ticket.`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('setup_yes').setLabel('Yes!').setStyle(ButtonStyle.Success), + new ButtonBuilder().setCustomId('setup_skip').setLabel('Skip').setStyle(ButtonStyle.Secondary), + ), + ], + }); + + const panelChoice = await awaitMessageComponentSafe(message, { + filter: collectorFilter, + time: STEP_TIMEOUT, + }); + + if (!panelChoice) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (panelChoice.customId === 'setup_yes') { + let panelChannelId: string | null = null; + + const buildPanelChannelPanel = (status?: string) => ({ + content: [ + `**Setup (2/4) Ticket Panel**`, + `${emojis.rightArrow1} Select the channel to post the ticket creation panel in.`, + status ? `${emojis.rightArrow2} ${status}` : `${emojis.rightArrow1} Click **Send Panel** when ready.`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId('setup_panel_channel') + .setPlaceholder( + panelChannelId + ? `#${guild.channels.cache.get(panelChannelId)?.name ?? 'selected'}` + : 'Select a channel', + ) + .setChannelTypes(ChannelType.GuildText), + ), + new ActionRowBuilder().addComponents( + new ButtonBuilder().setCustomId('setup_send').setLabel('Send Panel').setStyle(ButtonStyle.Primary), + new ButtonBuilder().setCustomId('setup_skip').setLabel('Skip').setStyle(ButtonStyle.Secondary), + ), + ], + }); + + await panelChoice.update(buildPanelChannelPanel()); + + await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { + if (i.customId === 'setup_panel_channel' && i.isChannelSelectMenu()) { + panelChannelId = i.values[0]; + await i.update( + buildPanelChannelPanel(`Panel will be sent in <#${panelChannelId}>. Click **Send Panel** to post it.`), + ); + } else if (i.customId === 'setup_send' && i.isButton()) { + if (panelChannelId) { + const panelChannel = guild.channels.cache.get(panelChannelId); + if (panelChannel?.isTextBased()) { + await panelChannel.send({ + content: '**Create a ticket by clicking the button below!**', + components: [ + new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId('create-ticket') + .setLabel('Create Ticket') + .setStyle(ButtonStyle.Success), + ), + ], + }); + } + } + await i.deferUpdate(); + stop(); + } else if (i.customId === 'setup_skip' && i.isButton()) { + await i.deferUpdate(); + stop(); + } + }); + } else { + await panelChoice.deferUpdate(); + } + } else { + summary.push(`${emojis.rightArrow2} **Tickets** skipped`); + } + } else { + await ticketsFeatureChoice.deferUpdate(); + summary.push(`${emojis.rightArrow2} **Tickets** skipped`); + } + + // 3: logging + await safeEditReply({ + content: [ + `**Setup (3/4) Logging**`, + `${emojis.rightArrow1} Would you like to log server events (bans, kicks, message deletions, etc.) in a channel?`, + ].join('\n'), + components: [yesNoRow()], + }); + + const loggingFeatureChoice = await awaitMessageComponentSafe(message, { + filter: collectorFilter, + time: STEP_TIMEOUT, + }); + + if (!loggingFeatureChoice) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (loggingFeatureChoice.customId === 'setup_yes') { + let loggingChannelId: string | null = null; + + const buildLoggingConfigPanel = (status?: string) => ({ + content: [ + `**Setup (3/4) Logging**`, + `${emojis.rightArrow1} Select the channel where server events will be logged.`, + status ? `${emojis.rightArrow2} ${status}` : `${emojis.rightArrow1} Click **Next** when ready.`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId('setup_logging_channel') + .setPlaceholder( + loggingChannelId + ? `#${guild.channels.cache.get(loggingChannelId)?.name ?? 'selected'}` + : 'Select a channel', + ) + .setChannelTypes(ChannelType.GuildText), + ), + nextSkipRow(), + ], + }); + + await loggingFeatureChoice.update(buildLoggingConfigPanel()); + + const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { + if (i.customId === 'setup_logging_channel' && i.isChannelSelectMenu()) { + loggingChannelId = i.values[0]; + await i.update( + buildLoggingConfigPanel(`Logging channel set to <#${loggingChannelId}>. Click **Next** to continue.`), + ); + } else if (i.customId === 'setup_next' && i.isButton()) { + await i.deferUpdate(); + stop(); + } else if (i.customId === 'setup_skip' && i.isButton()) { + loggingChannelId = null; + await i.deferUpdate(); + stop(); + } + }); + + if (!completed) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (loggingChannelId) { + settings = await updateSettings(guildId, guild.name, { + loggingEnabled: true, + loggingChannelId, + }); + summary.push(`${emojis.rightArrow2} **Logging** enabled, channel: <#${loggingChannelId}>`); + } else { + summary.push(`${emojis.rightArrow1} **Logging** skipped`); + } + } else { + await loggingFeatureChoice.deferUpdate(); + summary.push(`${emojis.rightArrow1} **Logging** skipped`); + } + + // 4: confessions + await safeEditReply({ + content: [`**Setup (4/4) Confessions**`, `${emojis.rightArrow1} Would you like to enable confessions?`].join( + '\n', + ), + components: [yesNoRow()], + }); + + const confessionsFeatureChoice = await awaitMessageComponentSafe(message, { + filter: collectorFilter, + time: STEP_TIMEOUT, + }); + + if (!confessionsFeatureChoice) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (confessionsFeatureChoice.customId === 'setup_yes') { + let confessionChannelId: string | null = null; + + const buildConfessionConfigPanel = (status?: string) => ({ + content: [ + `**Setup (4/4) Confessions**`, + `${emojis.rightArrow1} Select the channel where anonymous confessions will be posted.`, + status ? `${emojis.rightArrow2} ${status}` : `${emojis.rightArrow1} Click **Next** when ready.`, + ].join('\n'), + components: [ + new ActionRowBuilder().addComponents( + new ChannelSelectMenuBuilder() + .setCustomId('setup_confession_channel') + .setPlaceholder( + confessionChannelId + ? `#${guild.channels.cache.get(confessionChannelId)?.name ?? 'selected'}` + : 'Select a channel', + ) + .setChannelTypes(ChannelType.GuildText), + ), + nextSkipRow(), + ], + }); + + await confessionsFeatureChoice.update(buildConfessionConfigPanel()); + + const completed = await runCollector(message, collectorFilter, STEP_TIMEOUT, async (i, stop) => { + if (i.customId === 'setup_confession_channel' && i.isChannelSelectMenu()) { + confessionChannelId = i.values[0]; + await i.update( + buildConfessionConfigPanel( + `Confession channel set to <#${confessionChannelId}>. Click **Next** to continue.`, + ), + ); + } else if (i.customId === 'setup_next' && i.isButton()) { + await i.deferUpdate(); + stop(); + } else if (i.customId === 'setup_skip' && i.isButton()) { + confessionChannelId = null; + await i.deferUpdate(); + stop(); + } + }); + + if (!completed) { + await safeEditReply({ content: `${emojis.rightArrow2} Setup timed out.`, components: [] }); + return; + } + + if (confessionChannelId) { + settings = await updateSettings(guildId, guild.name, { + confessionEnabled: true, + confessionChannelId, + }); + summary.push(`${emojis.rightArrow2} **Confessions** enabled in <#${confessionChannelId}>`); + } else { + summary.push(`${emojis.rightArrow2} **Confessions** skipped`); + } + } else { + await confessionsFeatureChoice.deferUpdate(); + summary.push(`${emojis.rightArrow2} **Confessions** skipped`); + } + + await safeEditReply({ + content: [ + `**Here's what was configured:**`, + ...summary, + '', + `**What's next?**`, + `${emojis.rightArrow1} Use \`/automod add\` to block words in your server.`, + `${emojis.rightArrow1} Use \`/autorole add\` to assign roles to new members automatically.`, + `${emojis.rightArrow1} Use \`/settings\` to adjust any of these at any time.`, + ].join('\n'), + components: [], + }); + + void settings; + } } diff --git a/apps/bot/src/commands/utility/setupTickets.ts b/apps/bot/src/commands/utility/setupTickets.ts index d1b7f91..3d8f30e 100644 --- a/apps/bot/src/commands/utility/setupTickets.ts +++ b/apps/bot/src/commands/utility/setupTickets.ts @@ -1,53 +1,53 @@ import { Command } from '@sapphire/framework'; import { emojis } from '#utils/emoji.js'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - ChannelType, - MessageFlags, - PermissionFlagsBits + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChannelType, + MessageFlags, + PermissionFlagsBits, } from 'discord.js'; export class SetupTicketsCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder - .setName('setup-tickets') - .setDescription('Post the ticket panel in a channel.') - .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) - .addChannelOption((option: any) => - option - .setName('channel') - .setDescription('The channel where the ticket panel should be posted') - .addChannelTypes(ChannelType.GuildText) - .setRequired(true) - ) - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('setup-tickets') + .setDescription('Post the ticket panel in a channel.') + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) + .addChannelOption((option: any) => + option + .setName('channel') + .setDescription('The channel where the ticket panel should be posted') + .addChannelTypes(ChannelType.GuildText) + .setRequired(true), + ), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const channel = interaction.options.getChannel('channel', true, [ChannelType.GuildText]); + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const channel = interaction.options.getChannel('channel', true, [ChannelType.GuildText]); - const button = new ButtonBuilder() - .setCustomId('create-ticket') - .setLabel('Create Ticket') - .setStyle(ButtonStyle.Success); + const button = new ButtonBuilder() + .setCustomId('create-ticket') + .setLabel('Create Ticket') + .setStyle(ButtonStyle.Success); - const row = new ActionRowBuilder().addComponents(button); + const row = new ActionRowBuilder().addComponents(button); - await channel.send({ - content: `**Create a ticket by clicking the button below!**`, - components: [row] - }); + await channel.send({ + content: `**Create a ticket by clicking the button below!**`, + components: [row], + }); - await interaction.reply({ - content: `${emojis.rightArrow2} Ticket panel sent in ${channel}.`, - flags: MessageFlags.Ephemeral - }); - } + await interaction.reply({ + content: `${emojis.rightArrow2} Ticket panel sent in ${channel}.`, + flags: MessageFlags.Ephemeral, + }); + } } diff --git a/apps/bot/src/commands/utility/user.ts b/apps/bot/src/commands/utility/user.ts index f81dbd8..25e6504 100644 --- a/apps/bot/src/commands/utility/user.ts +++ b/apps/bot/src/commands/utility/user.ts @@ -2,19 +2,17 @@ import { Command } from '@sapphire/framework'; import { emojis } from '#utils/emoji.js'; export class UserCommand extends Command { - public constructor(context: Command.LoaderContext, options: Command.Options) { - super(context, { ...options, preconditions: ['devMode'] }); - } + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => - builder.setName('user').setDescription('Provides information about the user.') - ); - } + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder.setName('user').setDescription('Provides information about the user.'), + ); + } - public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - await interaction.reply( - `${emojis.rightArrow2} This command was run by **${interaction.user.username}**.` - ); - } -} \ No newline at end of file + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + await interaction.reply(`${emojis.rightArrow2} This command was run by **${interaction.user.username}**.`); + } +} diff --git a/apps/bot/src/index.ts b/apps/bot/src/index.ts index 2e89817..4d38b49 100644 --- a/apps/bot/src/index.ts +++ b/apps/bot/src/index.ts @@ -1,30 +1,24 @@ import process from 'node:process'; import { fileURLToPath } from 'node:url'; -import { - ApplicationCommandRegistries, - RegisterBehavior, - SapphireClient -} from '@sapphire/framework'; +import { ApplicationCommandRegistries, RegisterBehavior, SapphireClient } from '@sapphire/framework'; import { GatewayIntentBits, Partials } from 'discord.js'; -ApplicationCommandRegistries.setDefaultBehaviorWhenNotIdentical( - RegisterBehavior.BulkOverwrite -); +ApplicationCommandRegistries.setDefaultBehaviorWhenNotIdentical(RegisterBehavior.BulkOverwrite); const client = new SapphireClient({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildModeration, - GatewayIntentBits.GuildExpressions - ], - partials: [Partials.Message, Partials.Channel], - presence: { - status: 'online' - }, - baseUserDirectory: fileURLToPath(new URL('.', import.meta.url)) + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildModeration, + GatewayIntentBits.GuildExpressions, + ], + partials: [Partials.Message, Partials.Channel], + presence: { + status: 'online', + }, + baseUserDirectory: fileURLToPath(new URL('.', import.meta.url)), }); void client.login(process.env.DISCORD_TOKEN); diff --git a/apps/bot/src/interaction-handlers/confession/confessionHandler.ts b/apps/bot/src/interaction-handlers/confession/confessionHandler.ts index 9ea77ad..91359a4 100644 --- a/apps/bot/src/interaction-handlers/confession/confessionHandler.ts +++ b/apps/bot/src/interaction-handlers/confession/confessionHandler.ts @@ -1,416 +1,410 @@ import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - EmbedBuilder, - LabelBuilder, - MessageFlags, - ModalBuilder, - TextChannel, - TextInputBuilder, - TextInputStyle, - type ButtonInteraction, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + EmbedBuilder, + LabelBuilder, + MessageFlags, + ModalBuilder, + TextChannel, + TextInputBuilder, + TextInputStyle, + type ButtonInteraction, } from 'discord.js'; import { - getModeratorIds, - buildConfessionLink, - getConfessionContext, - removeConfessionContext, - storeConfessionContext + getModeratorIds, + buildConfessionLink, + getConfessionContext, + removeConfessionContext, + storeConfessionContext, } from '#lib/confessions.js'; import { getSettings } from '#lib/settings.js'; import { emojis } from '#utils/emoji.js'; interface ParsedConfessionButton { - action: string; - messageId?: string; - guildId?: string; - channelId?: string; + action: string; + messageId?: string; + guildId?: string; + channelId?: string; } function parseConfessionButton(customId: string): ParsedConfessionButton { - const [action, ...parts] = customId.split(':'); - const result: ParsedConfessionButton = { action }; + const [action, ...parts] = customId.split(':'); + const result: ParsedConfessionButton = { action }; - if (action === 'delete-confession' && parts.length >= 3) { - [result.guildId, result.channelId, result.messageId] = parts; - } else if (parts.length > 0) { - [result.messageId] = parts; - } + if (action === 'delete-confession' && parts.length >= 3) { + [result.guildId, result.channelId, result.messageId] = parts; + } else if (parts.length > 0) { + [result.messageId] = parts; + } - return result; + return result; } function createTextInputModal(customId: string, title: string, inputId: string, label: string) { - const input = new TextInputBuilder() - .setCustomId(inputId) - .setStyle(TextInputStyle.Paragraph) - .setRequired(true) - .setMaxLength(1_000); - - return new ModalBuilder() - .setCustomId(customId) - .setTitle(title) - .addLabelComponents(new LabelBuilder().setLabel(label).setTextInputComponent(input)); + const input = new TextInputBuilder() + .setCustomId(inputId) + .setStyle(TextInputStyle.Paragraph) + .setRequired(true) + .setMaxLength(1_000); + + return new ModalBuilder() + .setCustomId(customId) + .setTitle(title) + .addLabelComponents(new LabelBuilder().setLabel(label).setTextInputComponent(input)); } async function fetchConfessionChannel(interaction: ButtonInteraction, channelId: string, guildId?: string) { - try { - let channel = null; - - if (guildId) { - const guild = await interaction.client.guilds.fetch(guildId).catch(() => null); - if (guild) { - channel = await guild.channels.fetch(channelId).catch(() => null); - } - } else if (interaction.inGuild() && interaction.guild) { - channel = await interaction.guild.channels.fetch(channelId).catch(() => null); - } - - if (!channel) { - channel = await interaction.client.channels.fetch(channelId).catch(() => null); - } - - return channel?.isTextBased() ? channel : null; - } catch { - return null; - } + try { + let channel = null; + + if (guildId) { + const guild = await interaction.client.guilds.fetch(guildId).catch(() => null); + if (guild) { + channel = await guild.channels.fetch(channelId).catch(() => null); + } + } else if (interaction.inGuild() && interaction.guild) { + channel = await interaction.guild.channels.fetch(channelId).catch(() => null); + } + + if (!channel) { + channel = await interaction.client.channels.fetch(channelId).catch(() => null); + } + + return channel?.isTextBased() ? channel : null; + } catch { + return null; + } } export class ConfessionButtonHandler extends InteractionHandler { - public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { - super(ctx, { - ...options, - interactionHandlerType: InteractionHandlerTypes.Button - }); - } - - public override parse(interaction: ButtonInteraction) { - if ( - interaction.customId !== 'create-confession' && - !interaction.customId.startsWith('report-confession:') && - !interaction.customId.startsWith('delete-confession:') - ) { - return this.none(); - } - - return this.some(); - } - - public async run(interaction: ButtonInteraction) { - if (interaction.customId === 'create-confession') { - await this.handleCreateConfession(interaction); - return; - } - - const parsed = parseConfessionButton(interaction.customId); - - if (parsed.action === 'report-confession') { - await this.handleReportConfession(interaction, parsed); - return; - } - - if (parsed.action === 'delete-confession') { - await this.handleDeleteConfession(interaction, parsed); - } - } - - private async handleCreateConfession(interaction: ButtonInteraction) { - if (!interaction.inGuild() || !interaction.guild) { - await interaction.reply({ - content: `${emojis.rightArrow2} This button can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const settings = await getSettings(interaction.guild.id, interaction.guild.name); - - if (!settings.confessionChannelId) { - await interaction.reply({ - content: `${emojis.rightArrow2} Confessions are not configured yet.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const modal = createTextInputModal('create-confession-modal', 'Create Confession', 'confession-text', 'Confession'); - await interaction.showModal(modal); - - try { - const modalSubmit = await interaction.awaitModalSubmit({ - filter: (modal) => - modal.customId === 'create-confession-modal' && modal.user.id === interaction.user.id, - time: 60_000 - }); - await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); - - const confession = modalSubmit.fields.getTextInputValue('confession-text'); - const confessionChannel = await interaction.guild.channels - .fetch(settings.confessionChannelId) - .catch(() => null); - - if (!(confessionChannel instanceof TextChannel)) { - await modalSubmit.editReply({ - content: `${emojis.rightArrow2} The configured confession channel is unavailable.` - }); - return; - } - - const embed = new EmbedBuilder() - .setTitle('Confession') - .setDescription(confession) - .setTimestamp(); - - const message = await confessionChannel.send({ embeds: [embed] }); - - try { - const threadName = confession.replace(/\s+/g, ' ').slice(0, 10).toLowerCase() || 'confession'; - const thread = await message.startThread({ name: `confession-${threadName}` }); - - const reportButton = new ButtonBuilder() - .setCustomId(`report-confession:${message.id}`) - .setLabel('Report') - .setStyle(ButtonStyle.Danger); - - await message.edit({ components: [new ActionRowBuilder().addComponents(reportButton)] }); - - await storeConfessionContext({ - guildId: interaction.guild.id, - channelId: confessionChannel.id, - messageId: message.id, - threadId: thread.id, - creatorId: modalSubmit.user.id - }); - - await modalSubmit.editReply({ - content: `${emojis.rightArrow1} Confession sent.` - }); - } catch (error) { - await message.delete().catch(() => null); - throw error; - } - } catch { - return; - } - } - - private async handleReportConfession(interaction: ButtonInteraction, parsed: ParsedConfessionButton) { - if (!interaction.inGuild() || !interaction.guild || !parsed.messageId) { - await interaction.reply({ - content: `${emojis.rightArrow2} This confession cannot be reported right now.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const context = await getConfessionContext(parsed.messageId); - - if (!context) { - await interaction.reply({ - content: `${emojis.rightArrow2} This confession is no longer available.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const moderators = getModeratorIds(); - - if (moderators.length === 0) { - await interaction.reply({ - content: `${emojis.rightArrow2} No bot moderators are configured.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const modal = createTextInputModal( - `report-confession-modal:${parsed.messageId}`, - 'Report Confession', - 'confession-report-reason', - 'Reason' - ); - - await interaction.showModal(modal); - - let modalSubmit; - - try { - modalSubmit = await interaction.awaitModalSubmit({ - filter: (modal) => - modal.customId === `report-confession-modal:${parsed.messageId}` && modal.user.id === interaction.user.id, - time: 60_000 - }); - } catch { - return; - } - - const reason = modalSubmit.fields.getTextInputValue('confession-report-reason'); - await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); - - const channel = await fetchConfessionChannel(interaction, context.channelId); - - if (!channel) { - console.error('Confession channel fetch failed', { channelId: context.channelId, context }); - await modalSubmit.editReply({ - content: `${emojis.rightArrow2} The confession channel (<#${context.channelId}>) is no longer available.` - }); - return; - } - - const message = await channel.messages.fetch(context.messageId).catch(() => null); - - if (!message) { - await modalSubmit.editReply({ - content: `${emojis.rightArrow2} That confession no longer exists.` - }); - return; - } - - const deleteButton = new ButtonBuilder() - .setCustomId(`delete-confession:${context.guildId}:${context.channelId}:${context.messageId}`) - .setLabel('Delete Confession') - .setStyle(ButtonStyle.Danger); - - const confessionText = message.embeds[0]?.description ?? 'No confession content was found.'; - const link = buildConfessionLink(context.guildId, context.channelId, context.messageId); - - let confessorDisplay = 'Unknown'; - if (context.creatorId) { - const confessorUser = await interaction.client.users.fetch(context.creatorId).catch(() => null); - confessorDisplay = confessorUser ? `${confessorUser.tag} (${confessorUser.id})` : context.creatorId; - } - - const reportEmbed = new EmbedBuilder() - .setTitle('Confession Reported') - .addFields( - { name: 'Guild', value: `${interaction.guild.name} (${interaction.guild.id})` }, - { name: 'Channel', value: `<#${context.channelId}>` }, - { name: 'Reported by', value: `${modalSubmit.user.tag} (${modalSubmit.user.id})` }, - { name: 'Confessor', value: confessorDisplay }, - { name: 'Reason', value: reason }, - { name: 'Confession', value: confessionText.slice(0, 1024) }, - { name: 'Link', value: link } - ) - .setTimestamp(); - - const deliveries = await Promise.allSettled( - moderators.map((moderatorId) => this.sendReportToModerator(interaction, moderatorId, reportEmbed, deleteButton)) - ); - - const delivered = deliveries.some((result) => result.status === 'fulfilled'); - - if (!delivered) { - await modalSubmit.editReply({ - content: `${emojis.rightArrow2} I could not contact any configured moderators.` - }); - return; - } - - await modalSubmit.editReply({ - content: `${emojis.rightArrow1} Your report was sent to the bot moderators.` - }); - } - - private async sendReportToModerator( - interaction: ButtonInteraction, - moderatorId: string, - reportEmbed: EmbedBuilder, - deleteButton: ButtonBuilder - ) { - const user = await interaction.client.users.fetch(moderatorId); - const row = new ActionRowBuilder().addComponents(deleteButton); - await user.send({ embeds: [reportEmbed], components: [row] }); - } - - private async handleDeleteConfession(interaction: ButtonInteraction, parsed: ParsedConfessionButton) { - if (interaction.inGuild() || !parsed.messageId) { - await interaction.reply({ - content: `${emojis.rightArrow2} This action can only be used from a moderator DM.` - }); - return; - } - - const context = - parsed.guildId && parsed.channelId && parsed.messageId - ? { guildId: parsed.guildId, channelId: parsed.channelId, messageId: parsed.messageId, threadId: '' } - : await getConfessionContext(parsed.messageId); - - if (!context) { - await interaction.reply({ - content: `${emojis.rightArrow2} This confession is no longer available.` - }); - return; - } - - const moderatorIds = getModeratorIds(); - - if (!moderatorIds.includes(interaction.user.id)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You are not configured as a bot moderator.` - }); - return; - } - - const channel = await fetchConfessionChannel(interaction, context.channelId, context.guildId); - - if (!channel) { - console.error('Confession channel fetch failed (delete flow)', { - channelId: context.channelId, - guildId: context.guildId, - context - }); - - await removeConfessionContext(context.messageId); - - await interaction.reply({ - content: `${emojis.rightArrow2} The confession channel (<#${context.channelId}>) is no longer available, but the confession has been removed from records.` - }); - return; - } - - const message = await channel.messages.fetch(context.messageId).catch(() => null); - - if (!message) { - await removeConfessionContext(context.messageId); - - await interaction.reply({ - content: `${emojis.rightArrow2} That confession no longer exists, but the record has been cleaned up.` - }); - return; - } - - const deletedEmbed = new EmbedBuilder() - .setTitle('Confession') - .setDescription('This confession was deleted by global moderators.') - .setColor(0xed4245) - .setTimestamp(); - - try { - await message.edit({ embeds: [deletedEmbed], components: [] }); - } catch { - await interaction.reply({ - content: `${emojis.rightArrow2} I could not update the confession message.` - }); - return; - } - - try { - if (context.threadId) { - const thread = await interaction.client.channels.fetch(context.threadId).catch(() => null); - if (thread && typeof (thread as any).setName === 'function') { - await (thread as any).setName('confession-deleted').catch(() => null); - } - } - } catch (error) { - console.error('Failed to rename confession thread', { threadId: context.threadId, error }); - } - - await removeConfessionContext(context.messageId); - - await interaction.reply({ - content: `${emojis.rightArrow1} Confession marked as deleted.` - }); - } -} \ No newline at end of file + public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { + super(ctx, { + ...options, + interactionHandlerType: InteractionHandlerTypes.Button, + }); + } + + public override parse(interaction: ButtonInteraction) { + if ( + interaction.customId !== 'create-confession' && + !interaction.customId.startsWith('report-confession:') && + !interaction.customId.startsWith('delete-confession:') + ) { + return this.none(); + } + + return this.some(); + } + + public async run(interaction: ButtonInteraction) { + if (interaction.customId === 'create-confession') { + await this.handleCreateConfession(interaction); + return; + } + + const parsed = parseConfessionButton(interaction.customId); + + if (parsed.action === 'report-confession') { + await this.handleReportConfession(interaction, parsed); + return; + } + + if (parsed.action === 'delete-confession') { + await this.handleDeleteConfession(interaction, parsed); + } + } + + private async handleCreateConfession(interaction: ButtonInteraction) { + if (!interaction.inGuild() || !interaction.guild) { + await interaction.reply({ + content: `${emojis.rightArrow2} This button can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const settings = await getSettings(interaction.guild.id, interaction.guild.name); + + if (!settings.confessionChannelId) { + await interaction.reply({ + content: `${emojis.rightArrow2} Confessions are not configured yet.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const modal = createTextInputModal('create-confession-modal', 'Create Confession', 'confession-text', 'Confession'); + await interaction.showModal(modal); + + try { + const modalSubmit = await interaction.awaitModalSubmit({ + filter: (modal) => modal.customId === 'create-confession-modal' && modal.user.id === interaction.user.id, + time: 60_000, + }); + await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); + + const confession = modalSubmit.fields.getTextInputValue('confession-text'); + const confessionChannel = await interaction.guild.channels.fetch(settings.confessionChannelId).catch(() => null); + + if (!(confessionChannel instanceof TextChannel)) { + await modalSubmit.editReply({ + content: `${emojis.rightArrow2} The configured confession channel is unavailable.`, + }); + return; + } + + const embed = new EmbedBuilder().setTitle('Confession').setDescription(confession).setTimestamp(); + + const message = await confessionChannel.send({ embeds: [embed] }); + + try { + const threadName = confession.replace(/\s+/g, ' ').slice(0, 10).toLowerCase() || 'confession'; + const thread = await message.startThread({ name: `confession-${threadName}` }); + + const reportButton = new ButtonBuilder() + .setCustomId(`report-confession:${message.id}`) + .setLabel('Report') + .setStyle(ButtonStyle.Danger); + + await message.edit({ components: [new ActionRowBuilder().addComponents(reportButton)] }); + + await storeConfessionContext({ + guildId: interaction.guild.id, + channelId: confessionChannel.id, + messageId: message.id, + threadId: thread.id, + creatorId: modalSubmit.user.id, + }); + + await modalSubmit.editReply({ + content: `${emojis.rightArrow1} Confession sent.`, + }); + } catch (error) { + await message.delete().catch(() => null); + throw error; + } + } catch { + return; + } + } + + private async handleReportConfession(interaction: ButtonInteraction, parsed: ParsedConfessionButton) { + if (!interaction.inGuild() || !interaction.guild || !parsed.messageId) { + await interaction.reply({ + content: `${emojis.rightArrow2} This confession cannot be reported right now.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const context = await getConfessionContext(parsed.messageId); + + if (!context) { + await interaction.reply({ + content: `${emojis.rightArrow2} This confession is no longer available.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const moderators = getModeratorIds(); + + if (moderators.length === 0) { + await interaction.reply({ + content: `${emojis.rightArrow2} No bot moderators are configured.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const modal = createTextInputModal( + `report-confession-modal:${parsed.messageId}`, + 'Report Confession', + 'confession-report-reason', + 'Reason', + ); + + await interaction.showModal(modal); + + let modalSubmit; + + try { + modalSubmit = await interaction.awaitModalSubmit({ + filter: (modal) => + modal.customId === `report-confession-modal:${parsed.messageId}` && modal.user.id === interaction.user.id, + time: 60_000, + }); + } catch { + return; + } + + const reason = modalSubmit.fields.getTextInputValue('confession-report-reason'); + await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); + + const channel = await fetchConfessionChannel(interaction, context.channelId); + + if (!channel) { + console.error('Confession channel fetch failed', { channelId: context.channelId, context }); + await modalSubmit.editReply({ + content: `${emojis.rightArrow2} The confession channel (<#${context.channelId}>) is no longer available.`, + }); + return; + } + + const message = await channel.messages.fetch(context.messageId).catch(() => null); + + if (!message) { + await modalSubmit.editReply({ + content: `${emojis.rightArrow2} That confession no longer exists.`, + }); + return; + } + + const deleteButton = new ButtonBuilder() + .setCustomId(`delete-confession:${context.guildId}:${context.channelId}:${context.messageId}`) + .setLabel('Delete Confession') + .setStyle(ButtonStyle.Danger); + + const confessionText = message.embeds[0]?.description ?? 'No confession content was found.'; + const link = buildConfessionLink(context.guildId, context.channelId, context.messageId); + + let confessorDisplay = 'Unknown'; + if (context.creatorId) { + const confessorUser = await interaction.client.users.fetch(context.creatorId).catch(() => null); + confessorDisplay = confessorUser ? `${confessorUser.tag} (${confessorUser.id})` : context.creatorId; + } + + const reportEmbed = new EmbedBuilder() + .setTitle('Confession Reported') + .addFields( + { name: 'Guild', value: `${interaction.guild.name} (${interaction.guild.id})` }, + { name: 'Channel', value: `<#${context.channelId}>` }, + { name: 'Reported by', value: `${modalSubmit.user.tag} (${modalSubmit.user.id})` }, + { name: 'Confessor', value: confessorDisplay }, + { name: 'Reason', value: reason }, + { name: 'Confession', value: confessionText.slice(0, 1024) }, + { name: 'Link', value: link }, + ) + .setTimestamp(); + + const deliveries = await Promise.allSettled( + moderators.map((moderatorId) => this.sendReportToModerator(interaction, moderatorId, reportEmbed, deleteButton)), + ); + + const delivered = deliveries.some((result) => result.status === 'fulfilled'); + + if (!delivered) { + await modalSubmit.editReply({ + content: `${emojis.rightArrow2} I could not contact any configured moderators.`, + }); + return; + } + + await modalSubmit.editReply({ + content: `${emojis.rightArrow1} Your report was sent to the bot moderators.`, + }); + } + + private async sendReportToModerator( + interaction: ButtonInteraction, + moderatorId: string, + reportEmbed: EmbedBuilder, + deleteButton: ButtonBuilder, + ) { + const user = await interaction.client.users.fetch(moderatorId); + const row = new ActionRowBuilder().addComponents(deleteButton); + await user.send({ embeds: [reportEmbed], components: [row] }); + } + + private async handleDeleteConfession(interaction: ButtonInteraction, parsed: ParsedConfessionButton) { + if (interaction.inGuild() || !parsed.messageId) { + await interaction.reply({ + content: `${emojis.rightArrow2} This action can only be used from a moderator DM.`, + }); + return; + } + + const context = + parsed.guildId && parsed.channelId && parsed.messageId + ? { guildId: parsed.guildId, channelId: parsed.channelId, messageId: parsed.messageId, threadId: '' } + : await getConfessionContext(parsed.messageId); + + if (!context) { + await interaction.reply({ + content: `${emojis.rightArrow2} This confession is no longer available.`, + }); + return; + } + + const moderatorIds = getModeratorIds(); + + if (!moderatorIds.includes(interaction.user.id)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You are not configured as a bot moderator.`, + }); + return; + } + + const channel = await fetchConfessionChannel(interaction, context.channelId, context.guildId); + + if (!channel) { + console.error('Confession channel fetch failed (delete flow)', { + channelId: context.channelId, + guildId: context.guildId, + context, + }); + + await removeConfessionContext(context.messageId); + + await interaction.reply({ + content: `${emojis.rightArrow2} The confession channel (<#${context.channelId}>) is no longer available, but the confession has been removed from records.`, + }); + return; + } + + const message = await channel.messages.fetch(context.messageId).catch(() => null); + + if (!message) { + await removeConfessionContext(context.messageId); + + await interaction.reply({ + content: `${emojis.rightArrow2} That confession no longer exists, but the record has been cleaned up.`, + }); + return; + } + + const deletedEmbed = new EmbedBuilder() + .setTitle('Confession') + .setDescription('This confession was deleted by global moderators.') + .setColor(0xed4245) + .setTimestamp(); + + try { + await message.edit({ embeds: [deletedEmbed], components: [] }); + } catch { + await interaction.reply({ + content: `${emojis.rightArrow2} I could not update the confession message.`, + }); + return; + } + + try { + if (context.threadId) { + const thread = await interaction.client.channels.fetch(context.threadId).catch(() => null); + if (thread && typeof (thread as any).setName === 'function') { + await (thread as any).setName('confession-deleted').catch(() => null); + } + } + } catch (error) { + console.error('Failed to rename confession thread', { threadId: context.threadId, error }); + } + + await removeConfessionContext(context.messageId); + + await interaction.reply({ + content: `${emojis.rightArrow1} Confession marked as deleted.`, + }); + } +} diff --git a/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts b/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts index e4d1913..b20925c 100644 --- a/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts +++ b/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts @@ -1,13 +1,13 @@ import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework'; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - ChannelType, - LabelBuilder, - MessageFlags, - ModalBuilder, - PermissionFlagsBits + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChannelType, + LabelBuilder, + MessageFlags, + ModalBuilder, + PermissionFlagsBits, } from 'discord.js'; import { TextInputBuilder, TextInputStyle, type ButtonInteraction } from 'discord.js'; import { getSettings, updateSettings } from '#lib/settings.js'; @@ -15,147 +15,144 @@ import { createTicket, removeTicket, setTicketChannelId } from '#lib/tickets.js' import { emojis } from '#utils/emoji.js'; export class ButtonHandler extends InteractionHandler { - public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { - super(ctx, { - ...options, - interactionHandlerType: InteractionHandlerTypes.Button - }); - } - - public override parse(interaction: ButtonInteraction) { - if (interaction.customId !== 'create-ticket') return this.none(); - - return this.some(); - } - - public async run(interaction: ButtonInteraction) { - if (!interaction.inGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This button can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!interaction.guild) { - await interaction.reply({ - content: `${emojis.rightArrow2} Failed to create ticket.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - const reasonInput = new TextInputBuilder() - .setCustomId('ticket-reason') - .setStyle(TextInputStyle.Paragraph) - .setRequired(true) - .setMaxLength(1_000); - - const reasonLabel = new LabelBuilder() - .setLabel('Reason') - .setTextInputComponent(reasonInput); - - const modal = new ModalBuilder() - .setCustomId('create-ticket-modal') - .setTitle('Create Ticket') - .addLabelComponents(reasonLabel); - - await interaction.showModal(modal); - - const modalSubmit = await interaction.awaitModalSubmit({ - filter: (modalInteraction) => - modalInteraction.customId === 'create-ticket-modal' && - modalInteraction.user.id === interaction.user.id, - time: 60_000 - }); - - const reason = modalSubmit.fields.getTextInputValue('ticket-reason'); - const settings = await getSettings(interaction.guild.id, interaction.guild.name); - let parent: string | undefined; - - if (settings.ticketCategoryId) { - const ticketCategory = - interaction.guild.channels.cache.get(settings.ticketCategoryId) ?? - (await interaction.guild.channels.fetch(settings.ticketCategoryId).catch(() => null)); - - if (ticketCategory?.type === ChannelType.GuildCategory) { - parent = ticketCategory.id; - } else { - await updateSettings(interaction.guild.id, interaction.guild.name, { ticketCategoryId: null }); - } - } - - const ticket = await createTicket(interaction.guild.id, interaction.guild.name, interaction.user.id, reason); - - const permissionOverwrites = [ - { - id: interaction.guild.id, - deny: [PermissionFlagsBits.ViewChannel] - }, - { - id: interaction.user.id, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.ReadMessageHistory - ] - }, - { - id: interaction.client.user.id, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.ReadMessageHistory, - PermissionFlagsBits.ManageChannels - ] - } - ] as any[]; - - const staffRoleId = settings.staffRole; - const staffRoleExists = typeof staffRoleId === 'string' && interaction.guild.roles.cache.has(staffRoleId); - - if (staffRoleExists) { - permissionOverwrites.push({ - id: staffRoleId, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.ReadMessageHistory - ] - }); - } - - const channel = await interaction.guild.channels - .create({ - name: `${ticket.ticketNumber}-${interaction.user.username}`, - type: ChannelType.GuildText, - parent, - permissionOverwrites - }) - .catch(async (error) => { - await removeTicket(ticket.id).catch(() => null); - throw error; - }); - - await setTicketChannelId(ticket.id, channel.id); - - await modalSubmit.reply({ - content: `${emojis.rightArrow2} Created ticket <#${channel.id}>!`, - flags: MessageFlags.Ephemeral - }); - - const closeButton = new ButtonBuilder() - .setCustomId('remove-ticket') - .setLabel('Close Ticket') - .setStyle(ButtonStyle.Danger); - - const closeRow = new ActionRowBuilder().addComponents(closeButton); - - const staffMention = staffRoleExists ? `<@&${staffRoleId}> ` : ''; - - await channel.send({ - content: `${staffMention}<@${interaction.user.id}>, your ticket has been created!\n**Reason:** ${reason}`, - components: [closeRow] - }); - } + public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { + super(ctx, { + ...options, + interactionHandlerType: InteractionHandlerTypes.Button, + }); + } + + public override parse(interaction: ButtonInteraction) { + if (interaction.customId !== 'create-ticket') return this.none(); + + return this.some(); + } + + public async run(interaction: ButtonInteraction) { + if (!interaction.inGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This button can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!interaction.guild) { + await interaction.reply({ + content: `${emojis.rightArrow2} Failed to create ticket.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const reasonInput = new TextInputBuilder() + .setCustomId('ticket-reason') + .setStyle(TextInputStyle.Paragraph) + .setRequired(true) + .setMaxLength(1_000); + + const reasonLabel = new LabelBuilder().setLabel('Reason').setTextInputComponent(reasonInput); + + const modal = new ModalBuilder() + .setCustomId('create-ticket-modal') + .setTitle('Create Ticket') + .addLabelComponents(reasonLabel); + + await interaction.showModal(modal); + + const modalSubmit = await interaction.awaitModalSubmit({ + filter: (modalInteraction) => + modalInteraction.customId === 'create-ticket-modal' && modalInteraction.user.id === interaction.user.id, + time: 60_000, + }); + + const reason = modalSubmit.fields.getTextInputValue('ticket-reason'); + const settings = await getSettings(interaction.guild.id, interaction.guild.name); + let parent: string | undefined; + + if (settings.ticketCategoryId) { + const ticketCategory = + interaction.guild.channels.cache.get(settings.ticketCategoryId) ?? + (await interaction.guild.channels.fetch(settings.ticketCategoryId).catch(() => null)); + + if (ticketCategory?.type === ChannelType.GuildCategory) { + parent = ticketCategory.id; + } else { + await updateSettings(interaction.guild.id, interaction.guild.name, { ticketCategoryId: null }); + } + } + + const ticket = await createTicket(interaction.guild.id, interaction.guild.name, interaction.user.id, reason); + + const permissionOverwrites = [ + { + id: interaction.guild.id, + deny: [PermissionFlagsBits.ViewChannel], + }, + { + id: interaction.user.id, + allow: [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ReadMessageHistory, + ], + }, + { + id: interaction.client.user.id, + allow: [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ReadMessageHistory, + PermissionFlagsBits.ManageChannels, + ], + }, + ] as any[]; + + const staffRoleId = settings.staffRole; + const staffRoleExists = typeof staffRoleId === 'string' && interaction.guild.roles.cache.has(staffRoleId); + + if (staffRoleExists) { + permissionOverwrites.push({ + id: staffRoleId, + allow: [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ReadMessageHistory, + ], + }); + } + + const channel = await interaction.guild.channels + .create({ + name: `${ticket.ticketNumber}-${interaction.user.username}`, + type: ChannelType.GuildText, + parent, + permissionOverwrites, + }) + .catch(async (error) => { + await removeTicket(ticket.id).catch(() => null); + throw error; + }); + + await setTicketChannelId(ticket.id, channel.id); + + await modalSubmit.reply({ + content: `${emojis.rightArrow2} Created ticket <#${channel.id}>!`, + flags: MessageFlags.Ephemeral, + }); + + const closeButton = new ButtonBuilder() + .setCustomId('remove-ticket') + .setLabel('Close Ticket') + .setStyle(ButtonStyle.Danger); + + const closeRow = new ActionRowBuilder().addComponents(closeButton); + + const staffMention = staffRoleExists ? `<@&${staffRoleId}> ` : ''; + + await channel.send({ + content: `${staffMention}<@${interaction.user.id}>, your ticket has been created!\n**Reason:** ${reason}`, + components: [closeRow], + }); + } } diff --git a/apps/bot/src/interaction-handlers/ticket/removeTicketHandler.ts b/apps/bot/src/interaction-handlers/ticket/removeTicketHandler.ts index 3cbd53f..150e5f2 100644 --- a/apps/bot/src/interaction-handlers/ticket/removeTicketHandler.ts +++ b/apps/bot/src/interaction-handlers/ticket/removeTicketHandler.ts @@ -6,155 +6,159 @@ import { getTicketId, removeTicket } from '#lib/tickets.js'; import { getSettings } from '#lib/settings.js'; async function generateTranscript(channel: TextChannel, ticket: any): Promise { - const messages = new Map(); - let lastId: string | undefined; - - while (true) { - const fetched = await channel.messages.fetch({ limit: 100, before: lastId }); - if (fetched.size === 0) break; - fetched.forEach(msg => messages.set(msg.id, msg)); - lastId = fetched.last()?.id; - } - - const sortedMessages = Array.from(messages.values()).reverse(); - - let transcript = `Ticket <${ticket.ticketNumber}>-<@${ticket.userId}> Transcript\n`; - transcript += `Created: ${ticket.createdAt.toLocaleString()}\n`; - transcript += `User: <@${ticket.userId}>\n`; - if (ticket.reason) { - transcript += `Reason: ${ticket.reason}\n`; - } - transcript += `${'='.repeat(50)}\n\n`; - - for (const message of sortedMessages) { - const timestamp = message.createdAt.toLocaleString(); - const author = message.author.tag; - const content = message.content || '[No text content]'; - - transcript += `[${timestamp}] ${author}: ${content}\n`; - - if (message.attachments.size > 0) { - transcript += ` Attachments: ${Array.from(message.attachments.values()).map((a: any) => a.url).join(', ')}\n`; - } - } - - return transcript; + const messages = new Map(); + let lastId: string | undefined; + + while (true) { + const fetched = await channel.messages.fetch({ limit: 100, before: lastId }); + if (fetched.size === 0) break; + fetched.forEach((msg) => messages.set(msg.id, msg)); + lastId = fetched.last()?.id; + } + + const sortedMessages = Array.from(messages.values()).reverse(); + + let transcript = `Ticket <${ticket.ticketNumber}>-<@${ticket.userId}> Transcript\n`; + transcript += `Created: ${ticket.createdAt.toLocaleString()}\n`; + transcript += `User: <@${ticket.userId}>\n`; + if (ticket.reason) { + transcript += `Reason: ${ticket.reason}\n`; + } + transcript += `${'='.repeat(50)}\n\n`; + + for (const message of sortedMessages) { + const timestamp = message.createdAt.toLocaleString(); + const author = message.author.tag; + const content = message.content || '[No text content]'; + + transcript += `[${timestamp}] ${author}: ${content}\n`; + + if (message.attachments.size > 0) { + transcript += ` Attachments: ${Array.from(message.attachments.values()) + .map((a: any) => a.url) + .join(', ')}\n`; + } + } + + return transcript; } export class ButtonHandler extends InteractionHandler { - public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { - super(ctx, { - ...options, - interactionHandlerType: InteractionHandlerTypes.Button - }); - } - - public override parse(interaction: ButtonInteraction) { - if ( - interaction.customId !== 'remove-ticket' && - interaction.customId !== 'confirm-remove-ticket' && - interaction.customId !== 'cancel-remove-ticket' - ) { - return this.none(); - } - - return this.some(); - } - - public async run(interaction: ButtonInteraction) { - if (!interaction.inGuild()) { - await interaction.reply({ - content: `${emojis.rightArrow2} This button can only be used in a server.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (!interaction.guild) { - await interaction.reply({ - content: `${emojis.rightArrow2} Failed to remove ticket.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (interaction.customId === 'cancel-remove-ticket') { - await interaction.update({ - content: `${emojis.rightArrow2} Ticket closure cancelled.`, - components: [] - }); - return; - } - - const channel = interaction.channel; - - if (!channel || !('deletable' in channel) || !channel.deletable) { - await interaction.reply({ - content: `${emojis.rightArrow2} I cannot delete this channel.`, - flags: MessageFlags.Ephemeral - }); - return; - } - - if (interaction.customId === 'remove-ticket') { - const confirmButton = new ButtonBuilder() - .setCustomId('confirm-remove-ticket') - .setLabel('Confirm Close') - .setStyle(ButtonStyle.Danger); - - const cancelButton = new ButtonBuilder() - .setCustomId('cancel-remove-ticket') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); - - const row = new ActionRowBuilder().addComponents(confirmButton, cancelButton); - - await interaction.reply({ - content: `${emojis.rightArrow2} Are you sure you want to close this ticket?`, - components: [row], - flags: MessageFlags.Ephemeral - }); - return; - } - - await interaction.update({ - content: `${emojis.rightArrow2} Closing ticket...`, - components: [] - }); - - const ticket = await getTicketId(interaction.guild.id, channel.id); - - try { - if (ticket && channel.isTextBased()) { - const settings = await getSettings(interaction.guild.id, interaction.guild.name); - - // Send transcript if configured - if (settings.ticketTranscriptChannelId) { - const transcriptChannel = await interaction.guild.channels.fetch(settings.ticketTranscriptChannelId).catch(() => null); - - if (transcriptChannel && transcriptChannel.type === ChannelType.GuildText) { - try { - const transcript = await generateTranscript(channel as TextChannel, ticket); - const attachment = new AttachmentBuilder(Buffer.from(transcript), { - name: `ticket-${ticket.ticketNumber}-transcript.txt` - }); - - await (transcriptChannel as TextChannel).send({ - content: `📋 **Ticket #${ticket.ticketNumber}** transcript - Closed by ${interaction.user.tag}`, - files: [attachment] - }); - } catch (transcriptErr) { - console.error('Failed to send ticket transcript:', transcriptErr); - } - } - } - - await removeTicket(ticket.id); - } - - await channel.delete(`Ticket closed by ${interaction.user.tag}.`); - } catch (err) { - console.log(err); - } - } + public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { + super(ctx, { + ...options, + interactionHandlerType: InteractionHandlerTypes.Button, + }); + } + + public override parse(interaction: ButtonInteraction) { + if ( + interaction.customId !== 'remove-ticket' && + interaction.customId !== 'confirm-remove-ticket' && + interaction.customId !== 'cancel-remove-ticket' + ) { + return this.none(); + } + + return this.some(); + } + + public async run(interaction: ButtonInteraction) { + if (!interaction.inGuild()) { + await interaction.reply({ + content: `${emojis.rightArrow2} This button can only be used in a server.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (!interaction.guild) { + await interaction.reply({ + content: `${emojis.rightArrow2} Failed to remove ticket.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (interaction.customId === 'cancel-remove-ticket') { + await interaction.update({ + content: `${emojis.rightArrow2} Ticket closure cancelled.`, + components: [], + }); + return; + } + + const channel = interaction.channel; + + if (!channel || !('deletable' in channel) || !channel.deletable) { + await interaction.reply({ + content: `${emojis.rightArrow2} I cannot delete this channel.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (interaction.customId === 'remove-ticket') { + const confirmButton = new ButtonBuilder() + .setCustomId('confirm-remove-ticket') + .setLabel('Confirm Close') + .setStyle(ButtonStyle.Danger); + + const cancelButton = new ButtonBuilder() + .setCustomId('cancel-remove-ticket') + .setLabel('Cancel') + .setStyle(ButtonStyle.Secondary); + + const row = new ActionRowBuilder().addComponents(confirmButton, cancelButton); + + await interaction.reply({ + content: `${emojis.rightArrow2} Are you sure you want to close this ticket?`, + components: [row], + flags: MessageFlags.Ephemeral, + }); + return; + } + + await interaction.update({ + content: `${emojis.rightArrow2} Closing ticket...`, + components: [], + }); + + const ticket = await getTicketId(interaction.guild.id, channel.id); + + try { + if (ticket && channel.isTextBased()) { + const settings = await getSettings(interaction.guild.id, interaction.guild.name); + + // Send transcript if configured + if (settings.ticketTranscriptChannelId) { + const transcriptChannel = await interaction.guild.channels + .fetch(settings.ticketTranscriptChannelId) + .catch(() => null); + + if (transcriptChannel && transcriptChannel.type === ChannelType.GuildText) { + try { + const transcript = await generateTranscript(channel as TextChannel, ticket); + const attachment = new AttachmentBuilder(Buffer.from(transcript), { + name: `ticket-${ticket.ticketNumber}-transcript.txt`, + }); + + await (transcriptChannel as TextChannel).send({ + content: `📋 **Ticket #${ticket.ticketNumber}** transcript - Closed by ${interaction.user.tag}`, + files: [attachment], + }); + } catch (transcriptErr) { + console.error('Failed to send ticket transcript:', transcriptErr); + } + } + } + + await removeTicket(ticket.id); + } + + await channel.delete(`Ticket closed by ${interaction.user.tag}.`); + } catch (err) { + console.log(err); + } + } } diff --git a/apps/bot/src/lib/automod.ts b/apps/bot/src/lib/automod.ts index 9eafb24..307f2e3 100644 --- a/apps/bot/src/lib/automod.ts +++ b/apps/bot/src/lib/automod.ts @@ -3,76 +3,76 @@ import { hasQuestUnlimitedAccess, LIMITS_ENABLED, LimitError } from './limits.js import type { EntitlementManager } from 'discord.js'; export class DuplicateAutoModError extends Error { - public constructor() { - super('That word is already blocked in this server.'); - this.name = 'DuplicateAutoModError'; - } + public constructor() { + super('That word is already blocked in this server.'); + this.name = 'DuplicateAutoModError'; + } } export async function createAutoMod( - guildId: string, - guildName: string, - word: string, - entitlements?: EntitlementManager + guildId: string, + guildName: string, + word: string, + entitlements?: EntitlementManager, ) { - const hasUnlimitedAccess = entitlements ? await hasQuestUnlimitedAccess(entitlements, guildId) : false; + const hasUnlimitedAccess = entitlements ? await hasQuestUnlimitedAccess(entitlements, guildId) : false; - if (LIMITS_ENABLED && !hasUnlimitedAccess) { - const autoModCount = await prisma.autoMod.count({ where: { guildId } }); + if (LIMITS_ENABLED && !hasUnlimitedAccess) { + const autoModCount = await prisma.autoMod.count({ where: { guildId } }); - if (autoModCount >= 10) { - throw new LimitError('A guild can only have up to 10 automod rules.', true); - } - } + if (autoModCount >= 10) { + throw new LimitError('A guild can only have up to 10 automod rules.', true); + } + } - if (guildId && guildName) { - await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName } - }); + if (guildId && guildName) { + await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); - try { - return await prisma.autoMod.create({ - data: { guildId, word } - }); - } catch (error) { - if ((error as { code?: string }).code === 'P2002') { - throw new DuplicateAutoModError(); - } + try { + return await prisma.autoMod.create({ + data: { guildId, word }, + }); + } catch (error) { + if ((error as { code?: string }).code === 'P2002') { + throw new DuplicateAutoModError(); + } - throw error; - } - } + throw error; + } + } - try { - return await prisma.autoMod.create({ - data: { guildId, word } - }); - } catch (error) { - if ((error as { code?: string }).code === 'P2002') { - throw new DuplicateAutoModError(); - } + try { + return await prisma.autoMod.create({ + data: { guildId, word }, + }); + } catch (error) { + if ((error as { code?: string }).code === 'P2002') { + throw new DuplicateAutoModError(); + } - throw error; - } + throw error; + } } export async function getAutoMods(guildId: string) { - return prisma.autoMod.findMany({ - where: { guildId }, - orderBy: { createdAt: 'asc' } - }); + return prisma.autoMod.findMany({ + where: { guildId }, + orderBy: { createdAt: 'asc' }, + }); } export async function removeAutoMod(autoModId: string) { - return prisma.autoMod.delete({ where: { id: autoModId } }); + return prisma.autoMod.delete({ where: { id: autoModId } }); } export async function clearAutoMods(guildId: string) { - return prisma.autoMod.deleteMany({ where: { guildId } }); + return prisma.autoMod.deleteMany({ where: { guildId } }); } export async function getAutoMod(autoModId: string) { - return prisma.autoMod.findUnique({ where: { id: autoModId } }); -} \ No newline at end of file + return prisma.autoMod.findUnique({ where: { id: autoModId } }); +} diff --git a/apps/bot/src/lib/autorole.ts b/apps/bot/src/lib/autorole.ts index afd4daf..f189726 100644 --- a/apps/bot/src/lib/autorole.ts +++ b/apps/bot/src/lib/autorole.ts @@ -3,63 +3,63 @@ import { hasQuestUnlimitedAccess, LIMITS_ENABLED, LimitError } from './limits.js import type { EntitlementManager } from 'discord.js'; export async function createAutoRole( - guildId: string, - guildName: string, - roleId: string, - botRole?: boolean, - entitlements?: EntitlementManager + guildId: string, + guildName: string, + roleId: string, + botRole?: boolean, + entitlements?: EntitlementManager, ) { - const hasUnlimitedAccess = entitlements ? await hasQuestUnlimitedAccess(entitlements, guildId) : false; + const hasUnlimitedAccess = entitlements ? await hasQuestUnlimitedAccess(entitlements, guildId) : false; - if (LIMITS_ENABLED && !hasUnlimitedAccess) { - const autoRoleCount = await prisma.autoRole.count({ where: { guildId } }); + if (LIMITS_ENABLED && !hasUnlimitedAccess) { + const autoRoleCount = await prisma.autoRole.count({ where: { guildId } }); - if (autoRoleCount >= 5) { - throw new LimitError('A guild can only have up to 5 auto roles.', true); - } - } + if (autoRoleCount >= 5) { + throw new LimitError('A guild can only have up to 5 auto roles.', true); + } + } - if (guildId && guildName) { - await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName } - }); - } + if (guildId && guildName) { + await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); + } - return prisma.autoRole.upsert({ - where: { - guildId_roleId: { - guildId, - roleId - } - }, - create: { - guildId, - roleId, - botRole - }, - update: { - botRole - } - }); + return prisma.autoRole.upsert({ + where: { + guildId_roleId: { + guildId, + roleId, + }, + }, + create: { + guildId, + roleId, + botRole, + }, + update: { + botRole, + }, + }); } export async function getAutoRoles(guildId: string) { - return prisma.autoRole.findMany({ - where: { guildId }, - orderBy: { createdAt: 'asc' } - }); + return prisma.autoRole.findMany({ + where: { guildId }, + orderBy: { createdAt: 'asc' }, + }); } export async function removeAutoRole(autoRoleId: string) { - return prisma.autoRole.delete({ where: { id: autoRoleId } }); + return prisma.autoRole.delete({ where: { id: autoRoleId } }); } export async function clearAutoRoles(guildId: string) { - return prisma.autoRole.deleteMany({ where: { guildId } }); + return prisma.autoRole.deleteMany({ where: { guildId } }); } export async function getAutoRole(autoRoleId: string) { - return prisma.autoRole.findUnique({ where: { id: autoRoleId } }); -} \ No newline at end of file + return prisma.autoRole.findUnique({ where: { id: autoRoleId } }); +} diff --git a/apps/bot/src/lib/bans.ts b/apps/bot/src/lib/bans.ts index 37d95aa..f2520d6 100644 --- a/apps/bot/src/lib/bans.ts +++ b/apps/bot/src/lib/bans.ts @@ -1,85 +1,82 @@ -import { prisma } from "./prisma.js"; +import { prisma } from './prisma.js'; import { Guild, PermissionFlagsBits, Client } from 'discord.js'; export async function createBan( - guildId: string, - guildName: string, - userId: string, - expiresAt: Date | null, - reason?: string, + guildId: string, + guildName: string, + userId: string, + expiresAt: Date | null, + reason?: string, ) { - await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName }, - }); - return prisma.ban.upsert({ - where: { guildId_userId: { guildId, userId } }, - create: { guildId, userId, expiresAt, reason }, - update: { expiresAt, reason }, - }); + await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); + return prisma.ban.upsert({ + where: { guildId_userId: { guildId, userId } }, + create: { guildId, userId, expiresAt, reason }, + update: { expiresAt, reason }, + }); } export async function clearBans(guildId: string, userId: string) { - return prisma.ban.deleteMany({ - where: { guildId, userId }, - }); + return prisma.ban.deleteMany({ + where: { guildId, userId }, + }); } export async function getBan(guildId: string, userId: string) { - return prisma.ban.findUnique({ - where: { guildId_userId: { guildId, userId } }, - }); + return prisma.ban.findUnique({ + where: { guildId_userId: { guildId, userId } }, + }); } export async function getBans() { - return prisma.ban.findMany({ - where: { - OR: [ - { expiresAt: null }, - { expiresAt: { gt: new Date() } }, - ], - }, - }); + return prisma.ban.findMany({ + where: { + OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }], + }, + }); } export async function applyBan(guild: Guild, userId: string, reason?: string): Promise { - const me = guild.members.me; - if (!me?.permissions.has(PermissionFlagsBits.BanMembers)) return false; + const me = guild.members.me; + if (!me?.permissions.has(PermissionFlagsBits.BanMembers)) return false; - try { - await guild.bans.create(userId, { reason: reason ?? undefined }); - return true; - } catch { - return false; - } + try { + await guild.bans.create(userId, { reason: reason ?? undefined }); + return true; + } catch { + return false; + } } export async function removeBan(guild: Guild, userId: string): Promise { - const me = guild.members.me; - if (!me?.permissions.has(PermissionFlagsBits.BanMembers)) return false; + const me = guild.members.me; + if (!me?.permissions.has(PermissionFlagsBits.BanMembers)) return false; - try { - await guild.bans.remove(userId); - } catch {} - - await clearBans(guild.id, userId); - return true; + try { + await guild.bans.remove(userId); + } catch {} + + await clearBans(guild.id, userId); + return true; } export async function purgeExpiredBans(client: Client) { - const expired = await prisma.ban.findMany({ - where: { - expiresAt: { not: null, lte: new Date() }, - }, - }); + const expired = await prisma.ban.findMany({ + where: { + expiresAt: { not: null, lte: new Date() }, + }, + }); - for (const ban of expired) { - const guild = client.guilds.cache.get(ban.guildId); - if (guild) { - await removeBan(guild, ban.userId); - } else { - await prisma.ban.delete({ where: { id: ban.id } }).catch(() => {}); - } - } + for (const ban of expired) { + const guild = client.guilds.cache.get(ban.guildId); + if (guild) { + await removeBan(guild, ban.userId); + } else { + await prisma.ban.delete({ where: { id: ban.id } }).catch(() => {}); + } + } } diff --git a/apps/bot/src/lib/confessions.ts b/apps/bot/src/lib/confessions.ts index 5bc67f2..66d3091 100644 --- a/apps/bot/src/lib/confessions.ts +++ b/apps/bot/src/lib/confessions.ts @@ -1,78 +1,85 @@ -import { prisma } from "./prisma.js"; +import { prisma } from './prisma.js'; export type ConfessionContext = { - guildId: string; - channelId: string; - messageId: string; - threadId: string; - creatorId?: string; + guildId: string; + channelId: string; + messageId: string; + threadId: string; + creatorId?: string; }; export function getModeratorIds() { - return [...new Set((process.env.MODERATORS ?? '').split(',').map((id) => id.trim()).filter(Boolean))]; + return [ + ...new Set( + (process.env.MODERATORS ?? '') + .split(',') + .map((id) => id.trim()) + .filter(Boolean), + ), + ]; } export function buildConfessionLink(guildId: string, channelId: string, messageId: string) { - return `https://discord.com/channels/${guildId}/${channelId}/${messageId}`; + return `https://discord.com/channels/${guildId}/${channelId}/${messageId}`; } export async function storeConfessionContext(context: ConfessionContext) { - await prisma.confession.upsert({ - where: { messageId: context.messageId }, - create: context, - update: context, - }); + await prisma.confession.upsert({ + where: { messageId: context.messageId }, + create: context, + update: context, + }); } export async function getConfessionContext(messageId: string) { - return prisma.confession.findUnique({ - where: { messageId }, - select: { - guildId: true, - channelId: true, - messageId: true, - threadId: true, - creatorId: true, - }, - }); + return prisma.confession.findUnique({ + where: { messageId }, + select: { + guildId: true, + channelId: true, + messageId: true, + threadId: true, + creatorId: true, + }, + }); } export async function removeConfessionContext(messageId: string) { - await prisma.confession.deleteMany({ - where: { messageId }, - }); + await prisma.confession.deleteMany({ + where: { messageId }, + }); } export async function removeConfessionContexts(messageIds: string[]) { - if (messageIds.length === 0) return; + if (messageIds.length === 0) return; - await prisma.confession.deleteMany({ - where: { - messageId: { - in: messageIds, - }, - }, - }); + await prisma.confession.deleteMany({ + where: { + messageId: { + in: messageIds, + }, + }, + }); } export async function removeConfessionContextsByChannel(channelId: string) { - await prisma.confession.deleteMany({ - where: { channelId }, - }); + await prisma.confession.deleteMany({ + where: { channelId }, + }); } export async function isConfessionBlacklisted(userId: string) { - return prisma.confessionBlacklist.findUnique({ where: { userId } }); + return prisma.confessionBlacklist.findUnique({ where: { userId } }); } export async function addConfessionBlacklist(userId: string, createdBy: string, reason?: string) { - return prisma.confessionBlacklist.upsert({ - where: { userId }, - create: { userId, createdBy, reason }, - update: { createdBy, reason }, - }); + return prisma.confessionBlacklist.upsert({ + where: { userId }, + create: { userId, createdBy, reason }, + update: { createdBy, reason }, + }); } export async function removeConfessionBlacklist(userId: string) { - return prisma.confessionBlacklist.deleteMany({ where: { userId } }); -} \ No newline at end of file + return prisma.confessionBlacklist.deleteMany({ where: { userId } }); +} diff --git a/apps/bot/src/lib/limits.ts b/apps/bot/src/lib/limits.ts index a138c60..7c8024a 100644 --- a/apps/bot/src/lib/limits.ts +++ b/apps/bot/src/lib/limits.ts @@ -5,36 +5,39 @@ export const LIMITS_ENABLED = process.env.LIMITS === 'true'; export const QUEST_UNLIMITED_SKU_ID = '1502381886025240788'; export class LimitError extends Error { - public constructor(message: string, public readonly showQuestUnlimitedPrompt = false) { - super(message); - this.name = 'LimitError'; - } + public constructor( + message: string, + public readonly showQuestUnlimitedPrompt = false, + ) { + super(message); + this.name = 'LimitError'; + } } export async function hasQuestUnlimitedAccess(entitlements: EntitlementManager, guildId: string) { - try { - const guildEntitlements = await entitlements.fetch({ - guild: guildId, - skus: [QUEST_UNLIMITED_SKU_ID], - excludeEnded: true, - excludeDeleted: true - }); + try { + const guildEntitlements = await entitlements.fetch({ + guild: guildId, + skus: [QUEST_UNLIMITED_SKU_ID], + excludeEnded: true, + excludeDeleted: true, + }); - return guildEntitlements.size > 0; - } catch { - return false; - } + return guildEntitlements.size > 0; + } catch { + return false; + } } export function getQuestUnlimitedUrl(applicationId: string) { - return `https://discord.com/application-directory/${applicationId}/store/${QUEST_UNLIMITED_SKU_ID}`; + return `https://discord.com/application-directory/${applicationId}/store/${QUEST_UNLIMITED_SKU_ID}`; } export function getQuestUnlimitedPurchaseComponents(applicationId: string) { - const purchaseButton = new ButtonBuilder() - .setLabel('Upgrade to Quest Unlimited') - .setStyle(ButtonStyle.Link) - .setURL(getQuestUnlimitedUrl(applicationId)); + const purchaseButton = new ButtonBuilder() + .setLabel('Upgrade to Quest Unlimited') + .setStyle(ButtonStyle.Link) + .setURL(getQuestUnlimitedUrl(applicationId)); - return [new ActionRowBuilder().addComponents(purchaseButton)]; -} \ No newline at end of file + return [new ActionRowBuilder().addComponents(purchaseButton)]; +} diff --git a/apps/bot/src/lib/logging.ts b/apps/bot/src/lib/logging.ts index a940030..e9a068b 100644 --- a/apps/bot/src/lib/logging.ts +++ b/apps/bot/src/lib/logging.ts @@ -2,46 +2,45 @@ import { AuditLogEvent, EmbedBuilder, type Guild } from 'discord.js'; import { getSettings } from '#lib/settings.js'; export async function logEmbed(guild: Guild, embed: EmbedBuilder) { - const settings = await getSettings(guild.id, guild.name).catch((err) => { - console.error(err); - return null; - }); + const settings = await getSettings(guild.id, guild.name).catch((err) => { + console.error(err); + return null; + }); - if (!settings || !settings.loggingEnabled || !settings.loggingChannelId) return; + if (!settings || !settings.loggingEnabled || !settings.loggingChannelId) return; - const channel = await guild.channels.fetch(settings.loggingChannelId).catch(() => null); - if (!channel?.isTextBased() || !channel.isSendable()) return; + const channel = await guild.channels.fetch(settings.loggingChannelId).catch(() => null); + if (!channel?.isTextBased() || !channel.isSendable()) return; - await channel.send({ embeds: [embed] }).catch((err) => console.error(err)); + await channel.send({ embeds: [embed] }).catch((err) => console.error(err)); } export async function isLoggingChannel(guild: Guild, channelId: string | null | undefined) { - if (!channelId) return false; + if (!channelId) return false; - const settings = await getSettings(guild.id, guild.name).catch((err) => { - console.error(err); - return null; - }); + const settings = await getSettings(guild.id, guild.name).catch((err) => { + console.error(err); + return null; + }); - return settings?.loggingEnabled && settings.loggingChannelId === channelId; + return settings?.loggingEnabled && settings.loggingChannelId === channelId; } export async function getRecentAuditLogEntry(guild: Guild, type: AuditLogEvent, targetId: string) { - const auditLogs = await guild.fetchAuditLogs({ type, limit: 5 }).catch((err) => { - if (err?.code !== 10004) console.error(err); - return null; - }); - - if (!auditLogs) return null; - - return ( - auditLogs.entries.find( - (entry) => entry.targetId === targetId && Date.now() - entry.createdTimestamp < 5_000 - ) ?? null - ); + const auditLogs = await guild.fetchAuditLogs({ type, limit: 5 }).catch((err) => { + if (err?.code !== 10004) console.error(err); + return null; + }); + + if (!auditLogs) return null; + + return ( + auditLogs.entries.find((entry) => entry.targetId === targetId && Date.now() - entry.createdTimestamp < 5_000) ?? + null + ); } export function truncate(text: string | null | undefined, length = 1900) { - if (!text) return ''; - return text.length > length ? `${text.slice(0, length)}…` : text; + if (!text) return ''; + return text.length > length ? `${text.slice(0, length)}…` : text; } diff --git a/apps/bot/src/lib/mutes.ts b/apps/bot/src/lib/mutes.ts index 7f6e49a..e10e9b5 100644 --- a/apps/bot/src/lib/mutes.ts +++ b/apps/bot/src/lib/mutes.ts @@ -1,64 +1,59 @@ -import { prisma } from "./prisma.js"; +import { prisma } from './prisma.js'; import { Guild } from 'discord.js'; export async function createMute( - guildId: string, - guildName: string, - userId: string, - expiresAt: Date | null, - reason?: string, + guildId: string, + guildName: string, + userId: string, + expiresAt: Date | null, + reason?: string, ) { - await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName }, - }); - return prisma.mute.upsert({ - where: { guildId_userId: { guildId, userId } }, - create: { guildId, userId, expiresAt, reason }, - update: { expiresAt, reason }, - }); + await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); + return prisma.mute.upsert({ + where: { guildId_userId: { guildId, userId } }, + create: { guildId, userId, expiresAt, reason }, + update: { expiresAt, reason }, + }); } export async function removeMute(guildId: string, userId: string) { - return prisma.mute.deleteMany({ - where: { guildId, userId }, - }); + return prisma.mute.deleteMany({ + where: { guildId, userId }, + }); } export async function getMute(guildId: string, userId: string) { - return prisma.mute.findUnique({ - where: { guildId_userId: { guildId, userId } }, - }); + return prisma.mute.findUnique({ + where: { guildId_userId: { guildId, userId } }, + }); } export async function getActiveMutes() { - return prisma.mute.findMany({ - where: { - OR: [ - { expiresAt: null }, - { expiresAt: { gt: new Date() } }, - ], - }, - }); + return prisma.mute.findMany({ + where: { + OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }], + }, + }); } export async function enforceMute(guild: Guild, userId: string): Promise { - const mute = await getMute(guild.id, userId); - if (!mute) return false; - - if (mute.expiresAt !== null && mute.expiresAt <= new Date()) { - await removeMute(guild.id, userId); - return false; - } - - const member = await guild.members.fetch(userId).catch(() => null); - if (!member || !member.moderatable) return false; - - const remaining = mute.expiresAt - ? Math.min(mute.expiresAt.getTime() - Date.now(), 2419200000) - : 2419200000; + const mute = await getMute(guild.id, userId); + if (!mute) return false; - await member.timeout(remaining, mute.reason ?? '').catch(() => {}); - return true; + if (mute.expiresAt !== null && mute.expiresAt <= new Date()) { + await removeMute(guild.id, userId); + return false; + } + + const member = await guild.members.fetch(userId).catch(() => null); + if (!member || !member.moderatable) return false; + + const remaining = mute.expiresAt ? Math.min(mute.expiresAt.getTime() - Date.now(), 2419200000) : 2419200000; + + await member.timeout(remaining, mute.reason ?? '').catch(() => {}); + return true; } diff --git a/apps/bot/src/lib/prisma.ts b/apps/bot/src/lib/prisma.ts index e913567..fe564d3 100644 --- a/apps/bot/src/lib/prisma.ts +++ b/apps/bot/src/lib/prisma.ts @@ -1,16 +1,16 @@ -import { PrismaClient } from "#prisma/client.js"; -import { PrismaPg } from "@prisma/adapter-pg"; +import { PrismaClient } from '#prisma/client.js'; +import { PrismaPg } from '@prisma/adapter-pg'; const globalForPrisma = globalThis as unknown as { - prisma: PrismaClient | undefined; + prisma: PrismaClient | undefined; }; function createPrismaClient() { - const adapter = new PrismaPg({ - connectionString: process.env.DATABASE_URL, - }); - return new PrismaClient({ adapter }); + const adapter = new PrismaPg({ + connectionString: process.env.DATABASE_URL, + }); + return new PrismaClient({ adapter }); } export const prisma = globalForPrisma.prisma ?? createPrismaClient(); -if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; +if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma; diff --git a/apps/bot/src/lib/reminderEvent.ts b/apps/bot/src/lib/reminderEvent.ts index f6fc9ec..dbeb374 100644 --- a/apps/bot/src/lib/reminderEvent.ts +++ b/apps/bot/src/lib/reminderEvent.ts @@ -3,54 +3,56 @@ import { emojis } from '#utils/emoji.js'; import { getDueReminders, removeReminder } from './reminders.js'; function ownerShardId(snowflake: string, totalShards: number) { - return Number((BigInt(snowflake) >> 22n) % BigInt(totalShards)); + return Number((BigInt(snowflake) >> 22n) % BigInt(totalShards)); } export function reminderScheduler(client: Client) { - const checkReminders = async () => { - try { - const due = await getDueReminders(); - const totalShards = client.shard?.count ?? 1; - const shardId = client.shard?.ids[0] ?? 0; + const checkReminders = async () => { + try { + const due = await getDueReminders(); + const totalShards = client.shard?.count ?? 1; + const shardId = client.shard?.ids[0] ?? 0; - for (const reminder of due) { - // each shard handles its reminders for its own guild - const targetShard = ownerShardId(reminder.guildId ?? reminder.userId, totalShards); - if (targetShard !== shardId) continue; + for (const reminder of due) { + // each shard handles its reminders for its own guild + const targetShard = ownerShardId(reminder.guildId ?? reminder.userId, totalShards); + if (targetShard !== shardId) continue; - try { - let sent = false; - if (reminder.channelId) { - const channel = client.channels.cache.get(reminder.channelId); - if (channel?.isSendable()) { - await channel.send({ - content: `${emojis.rightArrow2} <@${reminder.userId}> reminder: ${reminder.message ?? 'No message provided'}`, - }); - sent = true; - } - } - if (!sent) { - await dmUser(client, reminder.userId, reminder.message); - } + try { + let sent = false; + if (reminder.channelId) { + const channel = client.channels.cache.get(reminder.channelId); + if (channel?.isSendable()) { + await channel.send({ + content: `${emojis.rightArrow2} <@${reminder.userId}> reminder: ${reminder.message ?? 'No message provided'}`, + }); + sent = true; + } + } + if (!sent) { + await dmUser(client, reminder.userId, reminder.message); + } - await removeReminder(reminder.id); - } catch (err) { - console.error(err); - } - } - } catch (err) { - console.error(err); - } - }; - checkReminders(); - setInterval(checkReminders, 30_000); + await removeReminder(reminder.id); + } catch (err) { + console.error(err); + } + } + } catch (err) { + console.error(err); + } + }; + checkReminders(); + setInterval(checkReminders, 30_000); } -async function dmUser(client: Client, userId: string, message: string ){ - const user = await client.users.fetch(userId).catch(() => null); - if (!user) return; - - await user.send({ - content: `${emojis.rightArrow2} <@${userId}> reminder: ${message}`, - }).catch(() => {}); +async function dmUser(client: Client, userId: string, message: string) { + const user = await client.users.fetch(userId).catch(() => null); + if (!user) return; + + await user + .send({ + content: `${emojis.rightArrow2} <@${userId}> reminder: ${message}`, + }) + .catch(() => {}); } diff --git a/apps/bot/src/lib/reminders.ts b/apps/bot/src/lib/reminders.ts index cf8bcaf..6d6da64 100644 --- a/apps/bot/src/lib/reminders.ts +++ b/apps/bot/src/lib/reminders.ts @@ -2,57 +2,57 @@ import { prisma } from './prisma.js'; import { LIMITS_ENABLED, LimitError } from './limits.js'; export async function createReminder( - userId: string, - message: string, - remindAt: Date, - guildId?: string, - guildName?: string, - channelId?: string, + userId: string, + message: string, + remindAt: Date, + guildId?: string, + guildName?: string, + channelId?: string, ) { - if (LIMITS_ENABLED) { - const reminderCount = await prisma.reminder.count({ where: { userId } }); - - if (reminderCount >= 5) { - throw new LimitError('You can only have up to 5 reminders.'); - } - } - - if (guildId && guildName) { - await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName }, - }); - return prisma.reminder.create({ - data: { guildId, userId, channelId, message, remindAt }, - }); - } - return prisma.reminder.create({ - data: { userId, channelId, message, remindAt }, - }); + if (LIMITS_ENABLED) { + const reminderCount = await prisma.reminder.count({ where: { userId } }); + + if (reminderCount >= 5) { + throw new LimitError('You can only have up to 5 reminders.'); + } + } + + if (guildId && guildName) { + await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); + return prisma.reminder.create({ + data: { guildId, userId, channelId, message, remindAt }, + }); + } + return prisma.reminder.create({ + data: { userId, channelId, message, remindAt }, + }); } -export async function getReminders( userId: string, guildId?: string) { - return prisma.reminder.findMany({ - where: { userId, guildId }, - orderBy: { remindAt: 'asc' }, - }); +export async function getReminders(userId: string, guildId?: string) { + return prisma.reminder.findMany({ + where: { userId, guildId }, + orderBy: { remindAt: 'asc' }, + }); } export async function removeReminder(reminderId: string) { - return prisma.reminder.delete({ where: { id: reminderId } }); + return prisma.reminder.delete({ where: { id: reminderId } }); } export async function clearReminders(guildId: string, userId: string) { - return prisma.reminder.deleteMany({ where: { guildId, userId } }); + return prisma.reminder.deleteMany({ where: { guildId, userId } }); } export async function getReminder(reminderId: string) { - return prisma.reminder.findUnique({ where: { id: reminderId } }); + return prisma.reminder.findUnique({ where: { id: reminderId } }); } export async function getDueReminders() { - return prisma.reminder.findMany({ - where: { remindAt: { lte: new Date() } }, - }); + return prisma.reminder.findMany({ + where: { remindAt: { lte: new Date() } }, + }); } diff --git a/apps/bot/src/lib/settings.ts b/apps/bot/src/lib/settings.ts index ecf10a2..a8af210 100644 --- a/apps/bot/src/lib/settings.ts +++ b/apps/bot/src/lib/settings.ts @@ -1,57 +1,57 @@ -import { Prisma } from "#prisma/client.js"; -import { prisma } from "./prisma.js"; +import { Prisma } from '#prisma/client.js'; +import { prisma } from './prisma.js'; export type ServerSettings = { - welcomePeople: boolean; - welcomeChannelId: string | null; - ticketCategoryId: string | null; - ticketTranscriptChannelId?: string | null; - staffRole: string | null; - confessionChannelId: string | null; - confessionEnabled: boolean; - loggingEnabled?: boolean; - loggingChannelId?: string | null; + welcomePeople: boolean; + welcomeChannelId: string | null; + ticketCategoryId: string | null; + ticketTranscriptChannelId?: string | null; + staffRole: string | null; + confessionChannelId: string | null; + confessionEnabled: boolean; + loggingEnabled?: boolean; + loggingChannelId?: string | null; }; export const DefaultSettings: ServerSettings = { - welcomePeople: false, - welcomeChannelId: null, - ticketCategoryId: null, - ticketTranscriptChannelId: null, - staffRole: null, - confessionChannelId: null, - confessionEnabled: false, - loggingEnabled: false, - loggingChannelId: null, + welcomePeople: false, + welcomeChannelId: null, + ticketCategoryId: null, + ticketTranscriptChannelId: null, + staffRole: null, + confessionChannelId: null, + confessionEnabled: false, + loggingEnabled: false, + loggingChannelId: null, }; export async function getSettings(guildId: string, guildName: string): Promise { - const row = await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName, settings: DefaultSettings as Prisma.InputJsonValue }, - update: { name: guildName }, - }); - return { ...DefaultSettings, ...(row.settings as Partial) }; + const row = await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName, settings: DefaultSettings as Prisma.InputJsonValue }, + update: { name: guildName }, + }); + return { ...DefaultSettings, ...(row.settings as Partial) }; } export async function updateSettings( - guildId: string, - guildName: string, - patch: Partial, + guildId: string, + guildName: string, + patch: Partial, ): Promise { - const row = await prisma.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName, settings: DefaultSettings as Prisma.InputJsonValue }, - update: { name: guildName }, - }); + const row = await prisma.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName, settings: DefaultSettings as Prisma.InputJsonValue }, + update: { name: guildName }, + }); - const current = { ...DefaultSettings, ...(row.settings as Partial) }; - const next = { ...current, ...patch }; + const current = { ...DefaultSettings, ...(row.settings as Partial) }; + const next = { ...current, ...patch }; - await prisma.server.update({ - where: { id: guildId }, - data: { name: guildName, settings: next as Prisma.InputJsonValue }, - }); + await prisma.server.update({ + where: { id: guildId }, + data: { name: guildName, settings: next as Prisma.InputJsonValue }, + }); - return next; + return next; } diff --git a/apps/bot/src/lib/tickets.ts b/apps/bot/src/lib/tickets.ts index 823a00e..bbad4f6 100644 --- a/apps/bot/src/lib/tickets.ts +++ b/apps/bot/src/lib/tickets.ts @@ -1,71 +1,66 @@ -import { prisma } from "./prisma.js"; +import { prisma } from './prisma.js'; -export async function createTicket( - guildId: string, - guildName: string, - userId: string, - reason: string, -) { - return prisma.$transaction(async (tx) => { - await tx.server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName }, - }); +export async function createTicket(guildId: string, guildName: string, userId: string, reason: string) { + return prisma.$transaction(async (tx) => { + await tx.server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); - const server = await tx.server.update({ - where: { id: guildId }, - data: { - nextTicketNumber: { - increment: 1, - }, - }, - select: { - nextTicketNumber: true, - }, - }); + const server = await tx.server.update({ + where: { id: guildId }, + data: { + nextTicketNumber: { + increment: 1, + }, + }, + select: { + nextTicketNumber: true, + }, + }); - return tx.ticket.create({ - data: { - guildId, - ticketNumber: server.nextTicketNumber - 1, - userId, - reason, - }, - }); - }); + return tx.ticket.create({ + data: { + guildId, + ticketNumber: server.nextTicketNumber - 1, + userId, + reason, + }, + }); + }); } export async function setTicketChannelId(ticketId: string, channelId: string) { - return prisma.ticket.update({ - where: { id: ticketId }, - data: { channelId }, - }); + return prisma.ticket.update({ + where: { id: ticketId }, + data: { channelId }, + }); } export async function getTickets(guildId: string, userId: string) { - return prisma.ticket.findMany({ - where: { guildId, userId }, - orderBy: { createdAt: 'desc' }, - }); + return prisma.ticket.findMany({ + where: { guildId, userId }, + orderBy: { createdAt: 'desc' }, + }); } export async function removeTicket(ticketId: string) { - return prisma.ticket.delete({ where: { id: ticketId } }); + return prisma.ticket.delete({ where: { id: ticketId } }); } export async function clearTickets(guildId: string, userId: string) { - return prisma.ticket.deleteMany({ where: { guildId, userId } }); + return prisma.ticket.deleteMany({ where: { guildId, userId } }); } export async function getTicket(ticketId: string, guildId: string) { - const ticket = await prisma.ticket.findUnique({ where: { id: ticketId } }); - if (!ticket || ticket.guildId !== guildId) return null; - return ticket; + const ticket = await prisma.ticket.findUnique({ where: { id: ticketId } }); + if (!ticket || ticket.guildId !== guildId) return null; + return ticket; } export async function getTicketId(guildId: string, channelId: string) { - return prisma.ticket.findFirst({ - where: { guildId, channelId } - }); + return prisma.ticket.findFirst({ + where: { guildId, channelId }, + }); } diff --git a/apps/bot/src/lib/warns.ts b/apps/bot/src/lib/warns.ts index dcd61fb..110557a 100644 --- a/apps/bot/src/lib/warns.ts +++ b/apps/bot/src/lib/warns.ts @@ -1,51 +1,51 @@ -import { prisma } from "./prisma.js"; +import { prisma } from './prisma.js'; export async function createWarn( - guildId: string, - guildName: string, - userId: string, - moderatorId: string, - reason: string, - expiresAt: Date | null = null, + guildId: string, + guildName: string, + userId: string, + moderatorId: string, + reason: string, + expiresAt: Date | null = null, ) { - return prisma.$transaction(async (tx) => { - await (tx as any).server.upsert({ - where: { id: guildId }, - create: { id: guildId, name: guildName }, - update: { name: guildName }, - }); - return (tx as any).warn.create({ - data: { guildId, userId, moderatorId, reason, expiresAt }, - }); - }); + return prisma.$transaction(async (tx) => { + await (tx as any).server.upsert({ + where: { id: guildId }, + create: { id: guildId, name: guildName }, + update: { name: guildName }, + }); + return (tx as any).warn.create({ + data: { guildId, userId, moderatorId, reason, expiresAt }, + }); + }); } export async function getWarns(guildId: string, userId: string) { - return prisma.warn.findMany({ - where: { guildId, userId }, - orderBy: { createdAt: 'desc' }, - }); + return prisma.warn.findMany({ + where: { guildId, userId }, + orderBy: { createdAt: 'desc' }, + }); } export async function removeWarn(warnId: string) { - return prisma.warn.delete({ where: { id: warnId } }); + return prisma.warn.delete({ where: { id: warnId } }); } export async function clearWarns(guildId: string, userId: string) { - return prisma.warn.deleteMany({ where: { guildId, userId } }); + return prisma.warn.deleteMany({ where: { guildId, userId } }); } export async function getWarn(warnId: string, guildId: string) { - const warn = await prisma.warn.findUnique({ where: { id: warnId } }); - if (!warn || warn.guildId !== guildId) return null; - return warn; + const warn = await prisma.warn.findUnique({ where: { id: warnId } }); + if (!warn || warn.guildId !== guildId) return null; + return warn; } export async function purgeExpiredWarns(gracePeriodDays = 30) { - const cutoff = new Date(Date.now() - gracePeriodDays * 24 * 60 * 60 * 1000); - return prisma.warn.deleteMany({ - where: { - expiresAt: { not: null, lte: cutoff }, - }, - }); + const cutoff = new Date(Date.now() - gracePeriodDays * 24 * 60 * 60 * 1000); + return prisma.warn.deleteMany({ + where: { + expiresAt: { not: null, lte: cutoff }, + }, + }); } diff --git a/apps/bot/src/lib/welcomeModule.ts b/apps/bot/src/lib/welcomeModule.ts index b6ef297..c3243a4 100644 --- a/apps/bot/src/lib/welcomeModule.ts +++ b/apps/bot/src/lib/welcomeModule.ts @@ -6,39 +6,35 @@ const ownerDmCooldown = new Map(); const DM_COOLDOWN = 24 * 60 * 60 * 1000; // 24h export async function sendWelcome(member: GuildMember): Promise { - const settings = await getSettings(member.guild.id, member.guild.name); - if (!settings.welcomePeople || !settings.welcomeChannelId) return; + const settings = await getSettings(member.guild.id, member.guild.name); + if (!settings.welcomePeople || !settings.welcomeChannelId) return; - const channel = await member.guild.channels - .fetch(settings.welcomeChannelId) - .catch(() => null); - if (!channel?.isTextBased() || !channel.isSendable()) return; + const channel = await member.guild.channels.fetch(settings.welcomeChannelId).catch(() => null); + if (!channel?.isTextBased() || !channel.isSendable()) return; - try { - await channel.send( - `${emojis.rightArrow1} Welcome to **${member.guild.name}**, <@${member.user.id}>!`, - ); - } catch (err) { - if (err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.MissingPermissions) { - await notifyOwner(member, channel.id); - return; - } - console.error(`[welcomeModule] Failed to send in ${member.guild.id}#${channel.id}:`, err); - } + try { + await channel.send(`${emojis.rightArrow1} Welcome to **${member.guild.name}**, <@${member.user.id}>!`); + } catch (err) { + if (err instanceof DiscordAPIError && err.code === RESTJSONErrorCodes.MissingPermissions) { + await notifyOwner(member, channel.id); + return; + } + console.error(`[welcomeModule] Failed to send in ${member.guild.id}#${channel.id}:`, err); + } } async function notifyOwner(member: GuildMember, channelId: string): Promise { - const guild = member.guild; - const last = ownerDmCooldown.get(guild.id) ?? 0; - if (Date.now() - last < DM_COOLDOWN) return; - ownerDmCooldown.set(guild.id, Date.now()); + const guild = member.guild; + const last = ownerDmCooldown.get(guild.id) ?? 0; + if (Date.now() - last < DM_COOLDOWN) return; + ownerDmCooldown.set(guild.id, Date.now()); - try { - const owner = await guild.fetchOwner(); - await owner.send( - `${emojis.rightArrow2} I couldn't send a welcome message in **${guild.name}** because I'm missing permissions in <#${channelId}>. Make sure I have permission to send messages there!` - ); - } catch (err) { - console.warn(`[welcomeModule] Couldn't DM owner of ${guild.id}:`, err); - } -} \ No newline at end of file + try { + const owner = await guild.fetchOwner(); + await owner.send( + `${emojis.rightArrow2} I couldn't send a welcome message in **${guild.name}** because I'm missing permissions in <#${channelId}>. Make sure I have permission to send messages there!`, + ); + } catch (err) { + console.warn(`[welcomeModule] Couldn't DM owner of ${guild.id}:`, err); + } +} diff --git a/apps/bot/src/listeners/channelCreate.ts b/apps/bot/src/listeners/channelCreate.ts index 7d86d60..f67c516 100644 --- a/apps/bot/src/listeners/channelCreate.ts +++ b/apps/bot/src/listeners/channelCreate.ts @@ -3,37 +3,37 @@ import { AuditLogEvent, EmbedBuilder, Events, type Channel } from 'discord.js'; import { getRecentAuditLogEntry, isLoggingChannel, logEmbed } from '#lib/logging.js'; export class ChannelCreateListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.ChannelCreate - }); - } - - public async run(channel: Channel) { - if (!('guild' in channel) || !channel.guild) return; - - if (await isLoggingChannel(channel.guild, channel.id)) return; - - const channelId = channel.id; - const typeLabel = String(channel.type); - - const embed = new EmbedBuilder() - .setTitle('Channel Created') - .setColor(0x77DD76) - .addFields( - { name: 'Channel', value: `<#${channelId}>`, inline: true }, - { name: 'Type', value: typeLabel, inline: true } - ) - .setTimestamp(); - - const auditEntry = await getRecentAuditLogEntry(channel.guild, AuditLogEvent.ChannelCreate, channel.id); - - if (auditEntry?.executor) { - const moderatorLabel = auditEntry.executor.tag ?? auditEntry.executor.username ?? auditEntry.executor.id; - embed.addFields({ name: 'Moderator', value: moderatorLabel, inline: true }); - } - - await logEmbed(channel.guild, embed); - } -} \ No newline at end of file + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.ChannelCreate, + }); + } + + public async run(channel: Channel) { + if (!('guild' in channel) || !channel.guild) return; + + if (await isLoggingChannel(channel.guild, channel.id)) return; + + const channelId = channel.id; + const typeLabel = String(channel.type); + + const embed = new EmbedBuilder() + .setTitle('Channel Created') + .setColor(0x77dd76) + .addFields( + { name: 'Channel', value: `<#${channelId}>`, inline: true }, + { name: 'Type', value: typeLabel, inline: true }, + ) + .setTimestamp(); + + const auditEntry = await getRecentAuditLogEntry(channel.guild, AuditLogEvent.ChannelCreate, channel.id); + + if (auditEntry?.executor) { + const moderatorLabel = auditEntry.executor.tag ?? auditEntry.executor.username ?? auditEntry.executor.id; + embed.addFields({ name: 'Moderator', value: moderatorLabel, inline: true }); + } + + await logEmbed(channel.guild, embed); + } +} diff --git a/apps/bot/src/listeners/channelDelete.ts b/apps/bot/src/listeners/channelDelete.ts index bdc21c6..d41ac83 100644 --- a/apps/bot/src/listeners/channelDelete.ts +++ b/apps/bot/src/listeners/channelDelete.ts @@ -4,40 +4,36 @@ import { removeConfessionContextsByChannel } from '#lib/confessions.js'; import { getRecentAuditLogEntry, isLoggingChannel, logEmbed } from '#lib/logging.js'; export class ChannelDeleteListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.ChannelDelete - }); - } - - public async run(channel: Channel) { - if (!('guild' in channel) || !channel.guild) return; - - await removeConfessionContextsByChannel(channel.id).catch(() => null); - - if (await isLoggingChannel(channel.guild, channel.id)) return; - - const channelLabel = channel.toString() || 'Unknown'; - const typeLabel = String(channel.type); - const fields: APIEmbedField[] = [ - { name: 'Channel', value: `${channelLabel} (${channel.id})`, inline: true }, - { name: 'Type', value: typeLabel, inline: true } - ]; - - const embed = new EmbedBuilder() - .setTitle('Channel Deleted') - .setColor(0xFF6962) - .addFields(fields) - .setTimestamp(); - - const auditEntry = await getRecentAuditLogEntry(channel.guild, AuditLogEvent.ChannelDelete, channel.id); - - if (auditEntry?.executor) { - const moderatorLabel = String(auditEntry.executor.tag ?? auditEntry.executor.username ?? auditEntry.executor.id); - embed.addFields({ name: 'Moderator', value: moderatorLabel, inline: true }); - } - - await logEmbed(channel.guild, embed); - } -} \ No newline at end of file + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.ChannelDelete, + }); + } + + public async run(channel: Channel) { + if (!('guild' in channel) || !channel.guild) return; + + await removeConfessionContextsByChannel(channel.id).catch(() => null); + + if (await isLoggingChannel(channel.guild, channel.id)) return; + + const channelLabel = channel.toString() || 'Unknown'; + const typeLabel = String(channel.type); + const fields: APIEmbedField[] = [ + { name: 'Channel', value: `${channelLabel} (${channel.id})`, inline: true }, + { name: 'Type', value: typeLabel, inline: true }, + ]; + + const embed = new EmbedBuilder().setTitle('Channel Deleted').setColor(0xff6962).addFields(fields).setTimestamp(); + + const auditEntry = await getRecentAuditLogEntry(channel.guild, AuditLogEvent.ChannelDelete, channel.id); + + if (auditEntry?.executor) { + const moderatorLabel = String(auditEntry.executor.tag ?? auditEntry.executor.username ?? auditEntry.executor.id); + embed.addFields({ name: 'Moderator', value: moderatorLabel, inline: true }); + } + + await logEmbed(channel.guild, embed); + } +} diff --git a/apps/bot/src/listeners/chatInputDenied.ts b/apps/bot/src/listeners/chatInputDenied.ts index c1f292f..96017e0 100644 --- a/apps/bot/src/listeners/chatInputDenied.ts +++ b/apps/bot/src/listeners/chatInputDenied.ts @@ -2,19 +2,19 @@ import { Listener, type ChatInputCommandDeniedPayload, type UserError } from '@s import { MessageFlags } from 'discord.js'; export class ChatInputCommandDeniedListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: 'chatInputCommandDenied' }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: 'chatInputCommandDenied' }); + } - public override async run(error: UserError, { interaction }: ChatInputCommandDeniedPayload) { - if (interaction.deferred || interaction.replied) { - await interaction.editReply({ content: error.message }); - return; - } + public override async run(error: UserError, { interaction }: ChatInputCommandDeniedPayload) { + if (interaction.deferred || interaction.replied) { + await interaction.editReply({ content: error.message }); + return; + } - await interaction.reply({ - content: error.message, - flags: MessageFlags.Ephemeral, - }); - } -} \ No newline at end of file + await interaction.reply({ + content: error.message, + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/apps/bot/src/listeners/contextMenuDenied.ts b/apps/bot/src/listeners/contextMenuDenied.ts index f0b8e85..0d97620 100644 --- a/apps/bot/src/listeners/contextMenuDenied.ts +++ b/apps/bot/src/listeners/contextMenuDenied.ts @@ -2,19 +2,19 @@ import { Listener, type ContextMenuCommandDeniedPayload, type UserError } from ' import { MessageFlags } from 'discord.js'; export class ContextMenuCommandDeniedListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: 'contextMenuCommandDenied' }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: 'contextMenuCommandDenied' }); + } - public override async run(error: UserError, { interaction }: ContextMenuCommandDeniedPayload) { - if (interaction.deferred || interaction.replied) { - await interaction.editReply({ content: error.message }); - return; - } + public override async run(error: UserError, { interaction }: ContextMenuCommandDeniedPayload) { + if (interaction.deferred || interaction.replied) { + await interaction.editReply({ content: error.message }); + return; + } - await interaction.reply({ - content: error.message, - flags: MessageFlags.Ephemeral, - }); - } -} \ No newline at end of file + await interaction.reply({ + content: error.message, + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/apps/bot/src/listeners/guildBanAdd.ts b/apps/bot/src/listeners/guildBanAdd.ts index c0020bf..b376760 100644 --- a/apps/bot/src/listeners/guildBanAdd.ts +++ b/apps/bot/src/listeners/guildBanAdd.ts @@ -3,33 +3,33 @@ import { AuditLogEvent, Colors, EmbedBuilder, Events, type GuildBan } from 'disc import { getRecentAuditLogEntry, logEmbed } from '#lib/logging.js'; export class GuildBanAddListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.GuildBanAdd - }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.GuildBanAdd, + }); + } - public async run(ban: GuildBan) { - const auditEntry = await getRecentAuditLogEntry(ban.guild, AuditLogEvent.MemberBanAdd, ban.user.id); + public async run(ban: GuildBan) { + const auditEntry = await getRecentAuditLogEntry(ban.guild, AuditLogEvent.MemberBanAdd, ban.user.id); - const embed = new EmbedBuilder() - .setTitle('Member Banned') - .setColor(Colors.DarkRed) - .addFields( - { name: 'Member', value: `${ban.user.tag} (${ban.user.id})`, inline: false }, - { name: 'Username', value: ban.user.toString(), inline: true } - ) - .setTimestamp(); + const embed = new EmbedBuilder() + .setTitle('Member Banned') + .setColor(Colors.DarkRed) + .addFields( + { name: 'Member', value: `${ban.user.tag} (${ban.user.id})`, inline: false }, + { name: 'Username', value: ban.user.toString(), inline: true }, + ) + .setTimestamp(); - if (auditEntry?.executor) { - embed.addFields({ name: 'Moderator', value: `${auditEntry.executor.tag}`, inline: true }); - } + if (auditEntry?.executor) { + embed.addFields({ name: 'Moderator', value: `${auditEntry.executor.tag}`, inline: true }); + } - if (auditEntry?.reason) { - embed.addFields({ name: 'Reason', value: auditEntry.reason, inline: false }); - } + if (auditEntry?.reason) { + embed.addFields({ name: 'Reason', value: auditEntry.reason, inline: false }); + } - await logEmbed(ban.guild, embed); - } -} \ No newline at end of file + await logEmbed(ban.guild, embed); + } +} diff --git a/apps/bot/src/listeners/guildCreate.ts b/apps/bot/src/listeners/guildCreate.ts index 005141c..83bfa30 100644 --- a/apps/bot/src/listeners/guildCreate.ts +++ b/apps/bot/src/listeners/guildCreate.ts @@ -2,24 +2,26 @@ import { Listener } from '@sapphire/framework'; import { AuditLogEvent, EmbedBuilder, Events, PermissionFlagsBits, type Guild } from 'discord.js'; export class GuildCreateListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: Events.GuildCreate }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: Events.GuildCreate }); + } - public async run(guild: Guild) { - if (!guild.members.me?.permissions.has(PermissionFlagsBits.ViewAuditLog)) return; + public async run(guild: Guild) { + if (!guild.members.me?.permissions.has(PermissionFlagsBits.ViewAuditLog)) return; - const logs = await guild.fetchAuditLogs({ type: AuditLogEvent.BotAdd, limit: 5 }).catch(() => null); - const entry = logs?.entries.find((e) => e.target?.id === guild.client.user.id); - const adder = entry?.executor; + const logs = await guild.fetchAuditLogs({ type: AuditLogEvent.BotAdd, limit: 5 }).catch(() => null); + const entry = logs?.entries.find((e) => e.target?.id === guild.client.user.id); + const adder = entry?.executor; - if (!adder) return; + if (!adder) return; - const embed = new EmbedBuilder() - .setColor(0xffffff) - .setTitle('Thanks for adding me!') - .setDescription(`I'm here to replace your other bot's and help improve your server!\n\nTo get started you can use the \`/setup\` command to help configure your server.\nIf you know how I work and want to configure me you can run \`/help\` for a list of all commands.\n\nIf you have any questions or need help, feel free to join the support server by using the \`/discord\` command.`); + const embed = new EmbedBuilder() + .setColor(0xffffff) + .setTitle('Thanks for adding me!') + .setDescription( + `I'm here to replace your other bot's and help improve your server!\n\nTo get started you can use the \`/setup\` command to help configure your server.\nIf you know how I work and want to configure me you can run \`/help\` for a list of all commands.\n\nIf you have any questions or need help, feel free to join the support server by using the \`/discord\` command.`, + ); - await adder.send({ embeds: [embed] }).catch(() => null); - } + await adder.send({ embeds: [embed] }).catch(() => null); + } } diff --git a/apps/bot/src/listeners/guildDelete.ts b/apps/bot/src/listeners/guildDelete.ts index 1629eb2..7024be5 100644 --- a/apps/bot/src/listeners/guildDelete.ts +++ b/apps/bot/src/listeners/guildDelete.ts @@ -3,21 +3,23 @@ import { EmbedBuilder, Events, type Guild } from 'discord.js'; import { prisma } from '#lib/prisma.js'; export class GuildDeleteListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: Events.GuildDelete }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: Events.GuildDelete }); + } - public async run(guild: Guild) { - await prisma.server.delete({ where: { id: guild.id } }).catch(() => null); + public async run(guild: Guild) { + await prisma.server.delete({ where: { id: guild.id } }).catch(() => null); - const owner = await guild.client.users.fetch(guild.ownerId).catch(() => null); - if (!owner) return; + const owner = await guild.client.users.fetch(guild.ownerId).catch(() => null); + if (!owner) return; - const embed = new EmbedBuilder() - .setColor(0xffffff) - .setTitle('Sorry to see you go!') - .setDescription(`If you had any issues or feedback, feel free to join the support server by using the \`/discord\` command.\n\nWe'd also appreciate it if you could fill out our feedback form at https://duckorg.com/feedback/questbot.`); + const embed = new EmbedBuilder() + .setColor(0xffffff) + .setTitle('Sorry to see you go!') + .setDescription( + `If you had any issues or feedback, feel free to join the support server by using the \`/discord\` command.\n\nWe'd also appreciate it if you could fill out our feedback form at https://duckorg.com/feedback/questbot.`, + ); - await owner.send({ embeds: [embed] }).catch(() => null); - } + await owner.send({ embeds: [embed] }).catch(() => null); + } } diff --git a/apps/bot/src/listeners/guildEmojisUpdate.ts b/apps/bot/src/listeners/guildEmojisUpdate.ts index fe316ad..2290e6c 100644 --- a/apps/bot/src/listeners/guildEmojisUpdate.ts +++ b/apps/bot/src/listeners/guildEmojisUpdate.ts @@ -3,29 +3,29 @@ import { EmbedBuilder, Colors, type GuildEmoji, type Collection, type Guild } fr import { logEmbed } from '#lib/logging.js'; export class GuildEmojisUpdateListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: 'guildEmojisUpdate' as any }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: 'guildEmojisUpdate' as any }); + } - public async run(guild: Guild, oldEmojis: Collection, newEmojis: Collection) { - const created = newEmojis.filter((e) => !oldEmojis.has(e.id)); - const deleted = oldEmojis.filter((e) => !newEmojis.has(e.id)); - const updated = newEmojis.filter((e) => { - const old = oldEmojis.get(e.id); - return old && (old.name !== e.name || old.animated !== e.animated); - }); + public async run(guild: Guild, oldEmojis: Collection, newEmojis: Collection) { + const created = newEmojis.filter((e) => !oldEmojis.has(e.id)); + const deleted = oldEmojis.filter((e) => !newEmojis.has(e.id)); + const updated = newEmojis.filter((e) => { + const old = oldEmojis.get(e.id); + return old && (old.name !== e.name || old.animated !== e.animated); + }); - if (created.size === 0 && deleted.size === 0 && updated.size === 0) return; + if (created.size === 0 && deleted.size === 0 && updated.size === 0) return; - const embed = new EmbedBuilder().setTitle('Guild Emojis Updated').setColor(Colors.Blue).setTimestamp(); + const embed = new EmbedBuilder().setTitle('Guild Emojis Updated').setColor(Colors.Blue).setTimestamp(); - if (created.size > 0) - embed.addFields({ name: `Created (${created.size})`, value: created.map((e) => `${e}`).join(' ' ) }); - if (deleted.size > 0) - embed.addFields({ name: `Deleted (${deleted.size})`, value: deleted.map((e) => e.name).join(', ') }); - if (updated.size > 0) - embed.addFields({ name: `Updated (${updated.size})`, value: updated.map((e) => e.name).join(', ') }); + if (created.size > 0) + embed.addFields({ name: `Created (${created.size})`, value: created.map((e) => `${e}`).join(' ') }); + if (deleted.size > 0) + embed.addFields({ name: `Deleted (${deleted.size})`, value: deleted.map((e) => e.name).join(', ') }); + if (updated.size > 0) + embed.addFields({ name: `Updated (${updated.size})`, value: updated.map((e) => e.name).join(', ') }); - await logEmbed(guild, embed); - } + await logEmbed(guild, embed); + } } diff --git a/apps/bot/src/listeners/guildMemberAdd.ts b/apps/bot/src/listeners/guildMemberAdd.ts index 3bd7fa6..55c616e 100644 --- a/apps/bot/src/listeners/guildMemberAdd.ts +++ b/apps/bot/src/listeners/guildMemberAdd.ts @@ -5,38 +5,38 @@ import { getAutoRoles } from '#lib/autorole.js'; import { sendWelcome } from '#lib/welcomeModule.js'; export class GuildMemberAddListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.GuildMemberAdd - }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.GuildMemberAdd, + }); + } - public async run(member: GuildMember) { - const botMember = member.guild.members.me; + public async run(member: GuildMember) { + const botMember = member.guild.members.me; - if (!botMember?.permissions.has(PermissionFlagsBits.ManageRoles)) { - await enforceMute(member.guild, member.id).catch((err) => console.error(err)); - await sendWelcome(member).catch((err) => console.error(err)); - return; - } + if (!botMember?.permissions.has(PermissionFlagsBits.ManageRoles)) { + await enforceMute(member.guild, member.id).catch((err) => console.error(err)); + await sendWelcome(member).catch((err) => console.error(err)); + return; + } - const autoRoles = await getAutoRoles(member.guild.id).catch((err) => { - console.error(err); - return []; - }); + const autoRoles = await getAutoRoles(member.guild.id).catch((err) => { + console.error(err); + return []; + }); - const rolesToAdd = autoRoles - .filter((autoRole) => Boolean(autoRole.botRole) === member.user.bot) - .map((autoRole) => member.guild.roles.cache.get(autoRole.roleId)) - .filter((role): role is NonNullable => Boolean(role?.editable)) - .map((role) => role.id); + const rolesToAdd = autoRoles + .filter((autoRole) => Boolean(autoRole.botRole) === member.user.bot) + .map((autoRole) => member.guild.roles.cache.get(autoRole.roleId)) + .filter((role): role is NonNullable => Boolean(role?.editable)) + .map((role) => role.id); - if (rolesToAdd.length > 0) { - await member.roles.add(rolesToAdd).catch((err) => console.error(err)); - } + if (rolesToAdd.length > 0) { + await member.roles.add(rolesToAdd).catch((err) => console.error(err)); + } - await enforceMute(member.guild, member.id).catch((err) => console.error(err)); - await sendWelcome(member).catch((err) => console.error(err)); - } -} \ No newline at end of file + await enforceMute(member.guild, member.id).catch((err) => console.error(err)); + await sendWelcome(member).catch((err) => console.error(err)); + } +} diff --git a/apps/bot/src/listeners/guildMemberRemove.ts b/apps/bot/src/listeners/guildMemberRemove.ts index 8446411..c91652a 100644 --- a/apps/bot/src/listeners/guildMemberRemove.ts +++ b/apps/bot/src/listeners/guildMemberRemove.ts @@ -3,36 +3,36 @@ import { AuditLogEvent, Colors, EmbedBuilder, Events, type GuildMember } from 'd import { getRecentAuditLogEntry, logEmbed } from '#lib/logging.js'; export class GuildMemberRemoveListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.GuildMemberRemove - }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.GuildMemberRemove, + }); + } - public async run(member: GuildMember) { - const banEntry = await getRecentAuditLogEntry(member.guild, AuditLogEvent.MemberBanAdd, member.id); - if (banEntry) return; + public async run(member: GuildMember) { + const banEntry = await getRecentAuditLogEntry(member.guild, AuditLogEvent.MemberBanAdd, member.id); + if (banEntry) return; - const kickEntry = await getRecentAuditLogEntry(member.guild, AuditLogEvent.MemberKick, member.id); + const kickEntry = await getRecentAuditLogEntry(member.guild, AuditLogEvent.MemberKick, member.id); - const embed = new EmbedBuilder() - .setTitle(kickEntry ? 'Member Kicked' : 'Member Left') - .setColor(kickEntry ? 0xFF6962 : Colors.Grey) - .addFields( - { name: 'Member', value: `${member.user.tag} (${member.id})`, inline: false }, - { name: 'Username', value: member.user.toString(), inline: true } - ) - .setTimestamp(); + const embed = new EmbedBuilder() + .setTitle(kickEntry ? 'Member Kicked' : 'Member Left') + .setColor(kickEntry ? 0xff6962 : Colors.Grey) + .addFields( + { name: 'Member', value: `${member.user.tag} (${member.id})`, inline: false }, + { name: 'Username', value: member.user.toString(), inline: true }, + ) + .setTimestamp(); - if (kickEntry?.executor) { - embed.addFields({ name: 'Moderator', value: `${kickEntry.executor.tag}`, inline: true }); - } + if (kickEntry?.executor) { + embed.addFields({ name: 'Moderator', value: `${kickEntry.executor.tag}`, inline: true }); + } - if (kickEntry?.reason) { - embed.addFields({ name: 'Reason', value: kickEntry.reason, inline: false }); - } + if (kickEntry?.reason) { + embed.addFields({ name: 'Reason', value: kickEntry.reason, inline: false }); + } - await logEmbed(member.guild, embed); - } -} \ No newline at end of file + await logEmbed(member.guild, embed); + } +} diff --git a/apps/bot/src/listeners/guildMemberUpdate.ts b/apps/bot/src/listeners/guildMemberUpdate.ts index a55cfff..8856b61 100644 --- a/apps/bot/src/listeners/guildMemberUpdate.ts +++ b/apps/bot/src/listeners/guildMemberUpdate.ts @@ -3,47 +3,47 @@ import { AuditLogEvent, Colors, EmbedBuilder, Events, type GuildMember } from 'd import { getRecentAuditLogEntry, logEmbed } from '#lib/logging.js'; export class GuildMemberUpdateListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.GuildMemberUpdate - }); - } - - public async run(oldMember: GuildMember, newMember: GuildMember) { - const beforeTimeout = oldMember.communicationDisabledUntilTimestamp ?? null; - const afterTimeout = newMember.communicationDisabledUntilTimestamp ?? null; - - if (Boolean(beforeTimeout) === Boolean(afterTimeout)) return; - - const auditEntry = await getRecentAuditLogEntry(newMember.guild, AuditLogEvent.MemberUpdate, newMember.id); - - const timeoutAdded = !beforeTimeout && afterTimeout; - const embed = new EmbedBuilder() - .setTitle(timeoutAdded ? 'Member Timed Out' : 'Timeout Removed') - .setColor(timeoutAdded ? Colors.Orange : 0x77DD76) - .addFields( - { name: 'Member', value: `${newMember.user.tag} (${newMember.id})`, inline: false }, - { name: 'Username', value: newMember.user.toString(), inline: true } - ) - .setTimestamp(); - - if (auditEntry?.executor) { - embed.addFields({ name: 'Moderator', value: `${auditEntry.executor.tag}`, inline: true }); - } - - if (auditEntry?.reason) { - embed.addFields({ name: 'Reason', value: auditEntry.reason, inline: false }); - } - - if (afterTimeout) { - embed.addFields({ - name: 'Expires', - value: ``, - inline: true - }); - } - - await logEmbed(newMember.guild, embed); - } -} \ No newline at end of file + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.GuildMemberUpdate, + }); + } + + public async run(oldMember: GuildMember, newMember: GuildMember) { + const beforeTimeout = oldMember.communicationDisabledUntilTimestamp ?? null; + const afterTimeout = newMember.communicationDisabledUntilTimestamp ?? null; + + if (Boolean(beforeTimeout) === Boolean(afterTimeout)) return; + + const auditEntry = await getRecentAuditLogEntry(newMember.guild, AuditLogEvent.MemberUpdate, newMember.id); + + const timeoutAdded = !beforeTimeout && afterTimeout; + const embed = new EmbedBuilder() + .setTitle(timeoutAdded ? 'Member Timed Out' : 'Timeout Removed') + .setColor(timeoutAdded ? Colors.Orange : 0x77dd76) + .addFields( + { name: 'Member', value: `${newMember.user.tag} (${newMember.id})`, inline: false }, + { name: 'Username', value: newMember.user.toString(), inline: true }, + ) + .setTimestamp(); + + if (auditEntry?.executor) { + embed.addFields({ name: 'Moderator', value: `${auditEntry.executor.tag}`, inline: true }); + } + + if (auditEntry?.reason) { + embed.addFields({ name: 'Reason', value: auditEntry.reason, inline: false }); + } + + if (afterTimeout) { + embed.addFields({ + name: 'Expires', + value: ``, + inline: true, + }); + } + + await logEmbed(newMember.guild, embed); + } +} diff --git a/apps/bot/src/listeners/messageCommandDenied.ts b/apps/bot/src/listeners/messageCommandDenied.ts index f2abcc6..b6e2989 100644 --- a/apps/bot/src/listeners/messageCommandDenied.ts +++ b/apps/bot/src/listeners/messageCommandDenied.ts @@ -1,11 +1,11 @@ import { Listener, type MessageCommandDeniedPayload, type UserError } from '@sapphire/framework'; export class MessageCommandDeniedListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: 'messageCommandDenied' }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: 'messageCommandDenied' }); + } - public override async run(error: UserError, { message }: MessageCommandDeniedPayload) { - await message.reply({ content: error.message }); - } -} \ No newline at end of file + public override async run(error: UserError, { message }: MessageCommandDeniedPayload) { + await message.reply({ content: error.message }); + } +} diff --git a/apps/bot/src/listeners/messageCreate.ts b/apps/bot/src/listeners/messageCreate.ts index d49fedc..2539e59 100644 --- a/apps/bot/src/listeners/messageCreate.ts +++ b/apps/bot/src/listeners/messageCreate.ts @@ -3,42 +3,48 @@ import { Events, type Message } from 'discord.js'; import { getAutoMods } from '#lib/automod.js'; export class MessageCreateListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - event: Events.MessageCreate - }); - } - - public async run(message: Message) { - if (message.author.bot) return; - if (!message.guild) return; - - const autoMods = await getAutoMods(message.guild.id); - const content = message.content.toLowerCase(); - - for (const autoMod of autoMods) { - if (content.includes(autoMod.word.toLowerCase())) { - - await message.delete().catch((err) => console.error(err)); - - const channel = message.channel; - if (!channel.isTextBased() || !channel.isSendable()) return; - - await channel.send(`<@${message.author.id}>, that word is not allowed here!`).catch((err) => { - console.error(err); - }); - - break; - } - } - - const moderatorIds = [...new Set((process.env.MODERATORS ?? '').split(',').map((id) => id.trim()).filter(Boolean))]; - - if (moderatorIds.includes(message.author.id)) { - if (content.includes('<@1494686224508522579>')) { - await message.reply('Why hello there!').catch((err) => console.error(err)); - } - } - } -} \ No newline at end of file + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.MessageCreate, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + if (!message.guild) return; + + const autoMods = await getAutoMods(message.guild.id); + const content = message.content.toLowerCase(); + + for (const autoMod of autoMods) { + if (content.includes(autoMod.word.toLowerCase())) { + await message.delete().catch((err) => console.error(err)); + + const channel = message.channel; + if (!channel.isTextBased() || !channel.isSendable()) return; + + await channel.send(`<@${message.author.id}>, that word is not allowed here!`).catch((err) => { + console.error(err); + }); + + break; + } + } + + const moderatorIds = [ + ...new Set( + (process.env.MODERATORS ?? '') + .split(',') + .map((id) => id.trim()) + .filter(Boolean), + ), + ]; + + if (moderatorIds.includes(message.author.id)) { + if (content.includes('<@1494686224508522579>')) { + await message.reply('Why hello there!').catch((err) => console.error(err)); + } + } + } +} diff --git a/apps/bot/src/listeners/messageDelete.ts b/apps/bot/src/listeners/messageDelete.ts index ee7b355..5df9e89 100644 --- a/apps/bot/src/listeners/messageDelete.ts +++ b/apps/bot/src/listeners/messageDelete.ts @@ -4,27 +4,30 @@ import { removeConfessionContext } from '#lib/confessions.js'; import { isLoggingChannel, logEmbed, truncate } from '#lib/logging.js'; export class MessageDeleteListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: Events.MessageDelete }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: Events.MessageDelete }); + } - public async run(message: Message | PartialMessage) { - const guild = message.guild; - if (!guild) return; - if (await isLoggingChannel(guild, message.channel?.id)) return; + public async run(message: Message | PartialMessage) { + const guild = message.guild; + if (!guild) return; + if (await isLoggingChannel(guild, message.channel?.id)) return; - const embed = new EmbedBuilder() - .setTitle('Message Deleted') - .setColor(0xFF6962) - .addFields( - { name: 'Channel', value: message.channel?.toString() ?? 'Unknown', inline: true }, - { name: 'Author', value: message.author?.tag ?? 'Unknown', inline: true }, - { name: 'Content', value: truncate(message instanceof Object ? (message as Message).content : undefined, 1024) || '-' } - ) - .setFooter({ text: `ID: ${message.id}` }) - .setTimestamp(); + const embed = new EmbedBuilder() + .setTitle('Message Deleted') + .setColor(0xff6962) + .addFields( + { name: 'Channel', value: message.channel?.toString() ?? 'Unknown', inline: true }, + { name: 'Author', value: message.author?.tag ?? 'Unknown', inline: true }, + { + name: 'Content', + value: truncate(message instanceof Object ? (message as Message).content : undefined, 1024) || '-', + }, + ) + .setFooter({ text: `ID: ${message.id}` }) + .setTimestamp(); - await removeConfessionContext(message.id).catch(() => null); - await logEmbed(guild, embed); - } + await removeConfessionContext(message.id).catch(() => null); + await logEmbed(guild, embed); + } } diff --git a/apps/bot/src/listeners/messageDeleteBulk.ts b/apps/bot/src/listeners/messageDeleteBulk.ts index 8547fa2..fb49e5b 100644 --- a/apps/bot/src/listeners/messageDeleteBulk.ts +++ b/apps/bot/src/listeners/messageDeleteBulk.ts @@ -4,28 +4,28 @@ import { removeConfessionContexts } from '#lib/confessions.js'; import { isLoggingChannel, logEmbed } from '#lib/logging.js'; export class MessageDeleteBulkListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: 'messageDeleteBulk' as any }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: 'messageDeleteBulk' as any }); + } - public async run(messages: Collection) { - const first = messages.first(); - const guild = first?.guild; - if (!guild) return; - if (await isLoggingChannel(guild, first?.channel?.id)) return; + public async run(messages: Collection) { + const first = messages.first(); + const guild = first?.guild; + if (!guild) return; + if (await isLoggingChannel(guild, first?.channel?.id)) return; - const channel = first?.channel?.toString() ?? 'Unknown'; + const channel = first?.channel?.toString() ?? 'Unknown'; - const embed = new EmbedBuilder() - .setTitle('Bulk Messages Deleted') - .setColor(0xFF6962) - .addFields( - { name: 'Channel', value: channel, inline: true }, - { name: 'Count', value: `${messages.size}`, inline: true } - ) - .setTimestamp(); + const embed = new EmbedBuilder() + .setTitle('Bulk Messages Deleted') + .setColor(0xff6962) + .addFields( + { name: 'Channel', value: channel, inline: true }, + { name: 'Count', value: `${messages.size}`, inline: true }, + ) + .setTimestamp(); - await removeConfessionContexts([...messages.keys()]).catch(() => null); - await logEmbed(guild, embed); - } + await removeConfessionContexts([...messages.keys()]).catch(() => null); + await logEmbed(guild, embed); + } } diff --git a/apps/bot/src/listeners/messageUpdate.ts b/apps/bot/src/listeners/messageUpdate.ts index 8b67e78..d2658e7 100644 --- a/apps/bot/src/listeners/messageUpdate.ts +++ b/apps/bot/src/listeners/messageUpdate.ts @@ -3,34 +3,34 @@ import { EmbedBuilder, type Message } from 'discord.js'; import { isLoggingChannel, logEmbed, truncate } from '#lib/logging.js'; export class MessageUpdateListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { ...options, event: 'messageUpdate' as any }); - } + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { ...options, event: 'messageUpdate' as any }); + } - public async run(oldMessage: unknown, newMessage: unknown) { - const oldMsg = oldMessage as Message | null; - const newMsg = newMessage as Message; - const guild = newMsg.guild ?? oldMsg?.guild; - if (!guild) return; - if (await isLoggingChannel(guild, newMsg.channel?.id ?? oldMsg?.channel?.id)) return; + public async run(oldMessage: unknown, newMessage: unknown) { + const oldMsg = oldMessage as Message | null; + const newMsg = newMessage as Message; + const guild = newMsg.guild ?? oldMsg?.guild; + if (!guild) return; + if (await isLoggingChannel(guild, newMsg.channel?.id ?? oldMsg?.channel?.id)) return; - const oldContent = oldMsg?.content ?? ''; - const newContent = newMsg.content ?? ''; + const oldContent = oldMsg?.content ?? ''; + const newContent = newMsg.content ?? ''; - if (oldContent === newContent) return; + if (oldContent === newContent) return; - const embed = new EmbedBuilder() - .setTitle('Message Edited') - .setColor(0xFAC898) - .addFields( - { name: 'Channel', value: newMsg.channel?.toString() ?? 'Unknown', inline: true }, - { name: 'Author', value: newMsg.author?.tag ?? oldMsg?.author?.tag ?? 'Unknown', inline: true }, - { name: 'Before', value: truncate(oldMsg?.content, 1023) || '-' }, - { name: 'After', value: truncate(newMsg.content, 1023) || '-' } - ) - .setFooter({ text: `ID: ${newMsg.id}` }) - .setTimestamp(); + const embed = new EmbedBuilder() + .setTitle('Message Edited') + .setColor(0xfac898) + .addFields( + { name: 'Channel', value: newMsg.channel?.toString() ?? 'Unknown', inline: true }, + { name: 'Author', value: newMsg.author?.tag ?? oldMsg?.author?.tag ?? 'Unknown', inline: true }, + { name: 'Before', value: truncate(oldMsg?.content, 1023) || '-' }, + { name: 'After', value: truncate(newMsg.content, 1023) || '-' }, + ) + .setFooter({ text: `ID: ${newMsg.id}` }) + .setTimestamp(); - await logEmbed(guild, embed); - } + await logEmbed(guild, embed); + } } diff --git a/apps/bot/src/listeners/ready.ts b/apps/bot/src/listeners/ready.ts index b1eab8a..4c5d853 100644 --- a/apps/bot/src/listeners/ready.ts +++ b/apps/bot/src/listeners/ready.ts @@ -7,44 +7,47 @@ import { reminderScheduler } from '#lib/reminderEvent.js'; import { purgeExpiredWarns } from '#lib/warns.js'; export class ReadyListener extends Listener { - public constructor(context: Listener.LoaderContext, options: Listener.Options) { - super(context, { - ...options, - once: true, - event: Events.ClientReady - }); - } - - public async run(client: Client) { - console.log(`Ready! Logged in as ${client.user.tag}`); - - client.user.setActivity({ - name: `/setup! | Shard ${client.shard?.ids?.[0] ?? 0}`, - type: ActivityType.Custom - }); - - heartbeat(client); - reminderScheduler(client); - - const enforceMutes = async () => { - const mutes = await getActiveMutes(); - for (const mute of mutes) { - const guild = client.guilds.cache.get(mute.guildId); - if (guild) await enforceMute(guild, mute.userId).catch((err) => console.error(err)); - } - }; - - await enforceMutes().catch((err) => console.error(err)); - purgeExpiredWarns().catch((err) => console.error(err)); - purgeExpiredBans(client).catch((err) => console.error(err)); - - setInterval(() => { - purgeExpiredWarns().catch((err) => console.error(err)); - purgeExpiredBans(client).catch((err) => console.error(err)); - }, 60 * 1000); // 1 min - - setInterval(() => { - enforceMutes().catch((err) => console.error(err)); - }, 30 * 60 * 1000); // 30 min - } -} \ No newline at end of file + public constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + once: true, + event: Events.ClientReady, + }); + } + + public async run(client: Client) { + console.log(`Ready! Logged in as ${client.user.tag}`); + + client.user.setActivity({ + name: `/setup! | Shard ${client.shard?.ids?.[0] ?? 0}`, + type: ActivityType.Custom, + }); + + heartbeat(client); + reminderScheduler(client); + + const enforceMutes = async () => { + const mutes = await getActiveMutes(); + for (const mute of mutes) { + const guild = client.guilds.cache.get(mute.guildId); + if (guild) await enforceMute(guild, mute.userId).catch((err) => console.error(err)); + } + }; + + await enforceMutes().catch((err) => console.error(err)); + purgeExpiredWarns().catch((err) => console.error(err)); + purgeExpiredBans(client).catch((err) => console.error(err)); + + setInterval(() => { + purgeExpiredWarns().catch((err) => console.error(err)); + purgeExpiredBans(client).catch((err) => console.error(err)); + }, 60 * 1000); // 1 min + + setInterval( + () => { + enforceMutes().catch((err) => console.error(err)); + }, + 30 * 60 * 1000, + ); // 30 min + } +} diff --git a/apps/bot/src/preconditions/devMode.ts b/apps/bot/src/preconditions/devMode.ts index 55474b2..2d1dea9 100644 --- a/apps/bot/src/preconditions/devMode.ts +++ b/apps/bot/src/preconditions/devMode.ts @@ -2,37 +2,37 @@ import { Precondition } from '@sapphire/framework'; import type { CommandInteraction, Message, ContextMenuCommandInteraction } from 'discord.js'; const DEV_IDS = new Set( - (process.env['DEVIDS'] ?? '') - .split(',') - .map((id) => id.trim()) - .filter(Boolean) + (process.env['DEVIDS'] ?? '') + .split(',') + .map((id) => id.trim()) + .filter(Boolean), ); const DEV_MODE = process.env['DEV'] === 'true'; export class devModePrecondition extends Precondition { - public override chatInputRun(interaction: CommandInteraction) { - return this.check(interaction.user.id); - } + public override chatInputRun(interaction: CommandInteraction) { + return this.check(interaction.user.id); + } - public override messageRun(message: Message) { - return this.check(message.author.id); - } + public override messageRun(message: Message) { + return this.check(message.author.id); + } - public override contextMenuRun(interaction: ContextMenuCommandInteraction) { - return this.check(interaction.user.id); - } + public override contextMenuRun(interaction: ContextMenuCommandInteraction) { + return this.check(interaction.user.id); + } - private check(userId: string) { - if (!DEV_MODE) return this.ok(); - if (DEV_IDS.has(userId)) return this.ok(); - return this.error({ - message: 'Please use the Official Quest Bot.\n\nThis bot is currently undergoing testing by a developer.' - }); - } + private check(userId: string) { + if (!DEV_MODE) return this.ok(); + if (DEV_IDS.has(userId)) return this.ok(); + return this.error({ + message: 'Please use the Official Quest Bot.\n\nThis bot is currently undergoing testing by a developer.', + }); + } } declare module '@sapphire/framework' { - interface Preconditions { - devMode: never; - } -} \ No newline at end of file + interface Preconditions { + devMode: never; + } +} diff --git a/apps/bot/src/preconditions/globalModerator.ts b/apps/bot/src/preconditions/globalModerator.ts index 7c7c883..a54cc0d 100644 --- a/apps/bot/src/preconditions/globalModerator.ts +++ b/apps/bot/src/preconditions/globalModerator.ts @@ -3,27 +3,27 @@ import type { ChatInputCommandInteraction, ContextMenuCommandInteraction, Messag import { getModeratorIds } from '#lib/confessions.js'; export class globalModeratorPrecondition extends AllFlowsPrecondition { - public override chatInputRun(interaction: ChatInputCommandInteraction) { - return this.check(interaction.user.id); - } + public override chatInputRun(interaction: ChatInputCommandInteraction) { + return this.check(interaction.user.id); + } - public override contextMenuRun(interaction: ContextMenuCommandInteraction) { - return this.check(interaction.user.id); - } + public override contextMenuRun(interaction: ContextMenuCommandInteraction) { + return this.check(interaction.user.id); + } - public override messageRun(message: Message) { - return this.check(message.author.id); - } + public override messageRun(message: Message) { + return this.check(message.author.id); + } - private check(userId: string) { - return getModeratorIds().includes(userId) - ? this.ok() - : this.error({ message: 'This command is restricted to bot moderators.' }); - } + private check(userId: string) { + return getModeratorIds().includes(userId) + ? this.ok() + : this.error({ message: 'This command is restricted to bot moderators.' }); + } } declare module '@sapphire/framework' { - interface Preconditions { - globalModerator: never; - } -} \ No newline at end of file + interface Preconditions { + globalModerator: never; + } +} diff --git a/apps/bot/src/sharder.ts b/apps/bot/src/sharder.ts index e81f67f..e1cbcba 100644 --- a/apps/bot/src/sharder.ts +++ b/apps/bot/src/sharder.ts @@ -19,7 +19,7 @@ if (totalShards !== undefined) { const manager = new ShardingManager('./dist/index.js', { token: process.env.DISCORD_TOKEN, - ...(totalShards ? { totalShards } : {}) + ...(totalShards ? { totalShards } : {}), }); manager.on('shardCreate', (shard) => { diff --git a/apps/bot/src/util/collectors.ts b/apps/bot/src/util/collectors.ts index cc27871..75a9793 100644 --- a/apps/bot/src/util/collectors.ts +++ b/apps/bot/src/util/collectors.ts @@ -1,30 +1,30 @@ import type { Message, MessageComponentInteraction } from 'discord.js'; export async function awaitMessageComponentSafe( - message: Message, - options: { filter?: (i: any) => boolean; time?: number } + message: Message, + options: { filter?: (i: any) => boolean; time?: number }, ): Promise { - return new Promise((resolve) => { - const collector = message.createMessageComponentCollector({ - filter: options.filter ?? (() => true), - time: options.time ?? 60_000 - } as any); - collector.on('error', (err: unknown) => { - console.debug('[awaitMessageComponentSafe] collector error', err); - resolve(null); - }); + return new Promise((resolve) => { + const collector = message.createMessageComponentCollector({ + filter: options.filter ?? (() => true), + time: options.time ?? 60_000, + } as any); + collector.on('error', (err: unknown) => { + console.debug('[awaitMessageComponentSafe] collector error', err); + resolve(null); + }); - collector.on('collect', (i: MessageComponentInteraction) => { - collector.stop('collected'); - resolve(i); - }); + collector.on('collect', (i: MessageComponentInteraction) => { + collector.stop('collected'); + resolve(i); + }); - collector.on('end', (collected: any, reason: string) => { - if (reason === 'time' || collected.size === 0) { - resolve(null); - } - }); - }); + collector.on('end', (collected: any, reason: string) => { + if (reason === 'time' || collected.size === 0) { + resolve(null); + } + }); + }); } export default awaitMessageComponentSafe; diff --git a/apps/bot/src/util/emoji.ts b/apps/bot/src/util/emoji.ts index 163b725..31e0287 100644 --- a/apps/bot/src/util/emoji.ts +++ b/apps/bot/src/util/emoji.ts @@ -1,7 +1,7 @@ export const emojis = { - // formatting emojis - upArrow1: '<:UpArrow1:1494777244386721992>', - rightArrow1: '<:RightArrow2:1494777243359117382>', - rightArrow2: '<:RightArrow:1494777242075529266>', - questUnlimited2: '<:QuestUnlimited2:1501690572870647888>' -} + // formatting emojis + upArrow1: '<:UpArrow1:1494777244386721992>', + rightArrow1: '<:RightArrow2:1494777243359117382>', + rightArrow2: '<:RightArrow:1494777242075529266>', + questUnlimited2: '<:QuestUnlimited2:1501690572870647888>', +}; diff --git a/apps/bot/src/util/heartbeat.ts b/apps/bot/src/util/heartbeat.ts index 76ebe54..7a7798b 100644 --- a/apps/bot/src/util/heartbeat.ts +++ b/apps/bot/src/util/heartbeat.ts @@ -1,30 +1,33 @@ import type { Client } from 'discord.js'; export function heartbeat(client: Client) { - const pushURLs = process.env.KUMA_PUSH_URL?.split(',').map((u) => u.trim()).filter(Boolean) ?? []; - const shardId = client.shard?.ids?.[0] ?? 0; - const pushURL = pushURLs[shardId]; + const pushURLs = + process.env.KUMA_PUSH_URL?.split(',') + .map((u) => u.trim()) + .filter(Boolean) ?? []; + const shardId = client.shard?.ids?.[0] ?? 0; + const pushURL = pushURLs[shardId]; - const push = async () => { - if (!pushURL || !client.isReady()) return; + const push = async () => { + if (!pushURL || !client.isReady()) return; - try { - const url = new URL(pushURL); - url.searchParams.set('ping', String(Math.max(0, client.ws.ping))); - url.searchParams.set('status', 'up'); + try { + const url = new URL(pushURL); + url.searchParams.set('ping', String(Math.max(0, client.ws.ping))); + url.searchParams.set('status', 'up'); - const response = await fetch(url, { signal: AbortSignal.timeout(10_000) }); - if (!response.ok) { - console.error(`[heartbeat] Shard ${shardId} push failed: ${response.status}`); - } - } catch (err) { - console.error(`[heartbeat] Shard ${shardId} push error:`, err); - } - }; + const response = await fetch(url, { signal: AbortSignal.timeout(10_000) }); + if (!response.ok) { + console.error(`[heartbeat] Shard ${shardId} push failed: ${response.status}`); + } + } catch (err) { + console.error(`[heartbeat] Shard ${shardId} push error:`, err); + } + }; - const loop = async () => { - await push(); - setTimeout(loop, 60_000); - }; - void loop(); -} \ No newline at end of file + const loop = async () => { + await push(); + setTimeout(loop, 60_000); + }; + void loop(); +} diff --git a/apps/bot/tsconfig.eslint.json b/apps/bot/tsconfig.eslint.json deleted file mode 100644 index ae192e2..0000000 --- a/apps/bot/tsconfig.eslint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig.json", - "extends": "./tsconfig.json", - "compilerOptions": { - "allowJs": true - }, - "include": ["*.ts", "*.tsx", "*.js", "*.cjs", "*.mjs", "src", "bin"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 850f204..ddd0569 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,18 +64,6 @@ importers: concurrently: specifier: ^9.2.1 version: 9.2.1 - eslint: - specifier: ^9.39.4 - version: 9.39.4(jiti@2.7.0) - eslint-config-neon: - specifier: ^0.2.9 - version: 0.2.9(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2)(typescript@5.9.3) - eslint-formatter-compact: - specifier: ^8.40.0 - version: 8.40.0 - eslint-formatter-pretty: - specifier: ^7.1.0 - version: 7.1.0 prettier: specifier: ^3.8.3 version: 3.8.3 @@ -88,108 +76,6 @@ importers: packages: - '@angular-eslint/bundled-angular-compiler@20.7.0': - resolution: {integrity: sha512-9KPz24YoiL0SvTtTX6sd1zmysU5cKOCcmpEiXkCoO3L2oYZGlVxmMT4hfSaHMt8qmfvV2KzQMoR6DZM84BwRzQ==} - - '@angular-eslint/eslint-plugin-template@20.7.0': - resolution: {integrity: sha512-WFmvW2vBR6ExsSKEaActQTteyw6ikWyuJau9XmWEPFd+2eusEt/+wO21ybjDn3uc5FTp1IcdhfYy+U5OdDjH5w==} - peerDependencies: - '@angular-eslint/template-parser': 20.7.0 - '@typescript-eslint/types': ^7.11.0 || ^8.0.0 - '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@angular-eslint/eslint-plugin@20.7.0': - resolution: {integrity: sha512-aHH2YTiaonojsKN+y2z4IMugCwdsH/dYIjYBig6kfoSPyf9rGK4zx+gnNGq/pGRjF3bOYrmFgIviYpQVb80inQ==} - peerDependencies: - '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@angular-eslint/template-parser@20.7.0': - resolution: {integrity: sha512-CVskZnF38IIxVVlKWi1VCz7YH/gHMJu2IY9bD1AVoBBGIe0xA4FRXJkW2Y+EDs9vQqZTkZZljhK5gL65Ro1PeQ==} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@angular-eslint/utils@20.7.0': - resolution: {integrity: sha512-B6EJHbsk2W/lnS3kS/gm56VGvX735419z/DzgbRDcOvqMGMLwD1ILzv5OTEcL1rzpnB0AHW+IxOu6y/aCzSNUA==} - peerDependencies: - '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@astrojs/compiler@3.0.1': - resolution: {integrity: sha512-z97oYbdebO5aoWzuJ/8q5hLK232+17KcLZ7cJ8BCWk6+qNzVxn/gftC0KzMBUTD8WAaBkPpNSQK6PXLnNrZ0CA==} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - '@discordjs/builders@1.14.1': resolution: {integrity: sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==} engines: {node: '>=16.11.0'} @@ -240,104 +126,15 @@ packages: '@electric-sql/pglite@0.4.1': resolution: {integrity: sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - - '@es-joy/jsdoccomment@0.78.0': - resolution: {integrity: sha512-rQkU5u8hNAq2NVRzHnIUUvR6arbO0b6AOlvpTNS48CkiKSn/xtNfOzBK23JE4SiW89DgvU7GtxLVgV4Vn2HBAw==} - engines: {node: '>=20.11.0'} - - '@es-joy/resolve.exports@1.2.0': - resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} - engines: {node: '>=10'} - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/compat@1.4.1': - resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.40 || 9 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.15.2': - resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.3.5': - resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@hono/node-server@1.19.11': resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} - engines: {node: '>=18.18.0'} - - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -491,96 +288,9 @@ packages: cpu: [x64] os: [win32] - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} - '@microsoft/tsdoc-config@0.17.1': - resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} - - '@microsoft/tsdoc@0.15.1': - resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} - - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - - '@next/eslint-plugin-next@15.5.18': - resolution: {integrity: sha512-w4MYq8M26a8PNrfto0JosLf5/3ssln1rsyP96g2DkC8uFVymStM5DLSz5ElxxrPRg2XnTMnFo3kREFlhYvxhWw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@npmcli/config@8.3.4': - resolution: {integrity: sha512-01rtHedemDNhUXdicU7s+QYz/3JyV5Naj84cvdXGH4mgCdL+agmSYaLF4LUG4vMCLzhBO8YtS0gPpH1FGvbgAw==} - engines: {node: ^16.14.0 || >=18.0.0} - - '@npmcli/git@5.0.8': - resolution: {integrity: sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==} - engines: {node: ^16.14.0 || >=18.0.0} - - '@npmcli/map-workspaces@3.0.6': - resolution: {integrity: sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - '@npmcli/name-from-folder@2.0.0': - resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - '@npmcli/package-json@5.2.1': - resolution: {integrity: sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ==} - engines: {node: ^16.14.0 || >=18.0.0} - - '@npmcli/promise-spawn@7.0.2': - resolution: {integrity: sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==} - engines: {node: ^16.14.0 || >=18.0.0} - - '@package-json/types@0.0.12': - resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@prisma/adapter-pg@7.8.0': resolution: {integrity: sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==} @@ -782,31 +492,9 @@ packages: resolution: {integrity: sha512-QGLdC9+pT74Zd7aaObqn0EUfq40c4dyTL65pFnkM6WO1QYN7Yg/s4CdH+CXmx0Zcu6wcfCWILSftXPMosJHP5A==} engines: {node: '>=v14.0.0'} - '@sindresorhus/base62@1.0.0': - resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} - engines: {node: '>=18'} - '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@stylistic/eslint-plugin-jsx@4.4.1': - resolution: {integrity: sha512-83SInq4u7z71vWwGG+6ViOtlOmZ6tSrDkMPhrvdBBTGMLA0gs22WSdhQ4vZP3oJ5Xg4ythvqeUiFSedvVxzhyA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=9.0.0' - - '@stylistic/eslint-plugin-ts@4.4.1': - resolution: {integrity: sha512-2r6cLcmdF6til66lx8esBYvBvsn7xCmLT50gw/n1rGGlTq/OxeNjBIh4c3VEaDGMa/5TybrZTia6sQUHdIWx1w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=9.0.0' - - '@stylistic/eslint-plugin@5.10.0': - resolution: {integrity: sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^9.0.0 || ^10.0.0 - '@turbo/darwin-64@2.9.14': resolution: {integrity: sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==} cpu: [x64] @@ -837,45 +525,6 @@ packages: cpu: [arm64] os: [win32] - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - - '@types/concat-stream@2.0.3': - resolution: {integrity: sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ==} - - '@types/debug@4.1.13': - resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} - - '@types/eslint@9.6.1': - resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - - '@types/esrecurse@4.3.1': - resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - - '@types/estree-jsx@1.0.5': - resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/is-empty@1.2.3': - resolution: {integrity: sha512-4J1l5d79hoIvsrKh5VUKVRA1aIdsOb10Hu5j3J2VfP/msDnfTdGPmNp2E1Wg+vs97Bktzo+MZePFFXSGoykYJw==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/lodash.merge@4.6.9': - resolution: {integrity: sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==} - - '@types/lodash@4.17.24': - resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -891,5881 +540,1251 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@types/semver@7.7.1': - resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/sharp@0.32.0': resolution: {integrity: sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==} deprecated: This is a stub types definition. sharp provides its own type definitions, so you do not need this installed. - '@types/supports-color@8.1.3': - resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==} - - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.35': - resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - - '@typescript-eslint/eslint-plugin@8.59.3': - resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.59.3 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/experimental-utils@5.62.0': - resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - - '@typescript-eslint/parser@8.59.3': - resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + '@vladfrangu/async_event_emitter@2.4.7': + resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@typescript-eslint/project-service@8.59.3': - resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - '@typescript-eslint/scope-manager@5.62.0': - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} - '@typescript-eslint/scope-manager@8.59.3': - resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} - '@typescript-eslint/tsconfig-utils@8.59.3': - resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} - '@typescript-eslint/type-utils@8.59.3': - resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} - '@typescript-eslint/types@5.62.0': - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + better-result@2.9.2: + resolution: {integrity: sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==} - '@typescript-eslint/types@8.59.3': - resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} - '@typescript-eslint/typescript-estree@5.62.0': - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: - typescript: '*' + magicast: '*' peerDependenciesMeta: - typescript: + magicast: optional: true - '@typescript-eslint/typescript-estree@8.59.3': - resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} - '@typescript-eslint/utils@5.62.0': - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + chart.js@4.5.1: + resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} + engines: {pnpm: '>=8'} - '@typescript-eslint/utils@8.59.3': - resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} - '@typescript-eslint/visitor-keys@5.62.0': - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} - '@typescript-eslint/visitor-keys@8.59.3': - resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} - cpu: [arm] - os: [android] + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} - cpu: [arm64] - os: [android] + concurrently@9.2.1: + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} + engines: {node: '>=18'} + hasBin: true - '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} - cpu: [arm64] - os: [darwin] + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} - cpu: [x64] - os: [darwin] + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} - '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} - cpu: [x64] - os: [freebsd] + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} - cpu: [arm] - os: [linux] + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} - cpu: [arm] - os: [linux] + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} - cpu: [arm64] - os: [linux] - libc: [glibc] + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} - cpu: [arm64] - os: [linux] - libc: [musl] + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} - cpu: [riscv64] - os: [linux] - libc: [glibc] + discord-api-types@0.38.47: + resolution: {integrity: sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==} - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} - cpu: [riscv64] - os: [linux] - libc: [musl] + discord.js@14.26.4: + resolution: {integrity: sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==} + engines: {node: '>=18'} - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} - cpu: [s390x] - os: [linux] - libc: [glibc] + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} - cpu: [x64] - os: [linux] - libc: [glibc] + effect@3.20.0: + resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==} - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} - cpu: [x64] - os: [linux] - libc: [musl] + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} - cpu: [arm64] - os: [win32] + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} - cpu: [ia32] - os: [win32] + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} - cpu: [x64] - os: [win32] + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - '@vladfrangu/async_event_emitter@2.4.7': - resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - - abbrev@2.0.0: - resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - ansi-escapes@7.3.0: - resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} - engines: {node: '>=18'} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} - are-docs-informative@0.0.2: - resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} - engines: {node: '>=14'} + giget@3.2.0: + resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} + hasBin: true - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} + graphmatch@1.1.1: + resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} + hono@4.12.19: + resolution: {integrity: sha512-xa3eYXYXx68XTT4hZ7dRzsXBhaq85ToSrlUJNoR0gwz/1Ap/CNwX47wfvV7pc/xWhjKVVkLT7zBJy8chhNguqQ==} + engines: {node: '>=16.9.0'} - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} - ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - astro-eslint-parser@1.4.0: - resolution: {integrity: sha512-+QDcgc7e+au6EZ0YjMmRRjNoQo5bDMlaR45aWDoFsuxQTCM9qmCHRoiKJPELgckJ8Wmr7vcfpa9eCDHBFh6G4w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - astrojs-compiler-sync@1.1.1: - resolution: {integrity: sha512-0mKvB9sDQRIZPsEJadw6OaFbGJ92cJPPR++ICca9XEyiUAZqgVuk25jNmzHPT0KF80rI94trSZrUR5iHFXGGOQ==} - engines: {node: ^18.18.0 || >=20.9.0} - peerDependencies: - '@astrojs/compiler': '>=0.27.0' + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - aws-ssl-profiles@1.1.2: - resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} - engines: {node: '>= 6.0.0'} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - axe-core@4.11.4: - resolution: {integrity: sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==} - engines: {node: '>=4'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} + lru-cache@11.3.6: + resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} + engines: {node: 20 || >=22} - bail@2.0.2: - resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + magic-bytes.js@1.13.0: + resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==} - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.29: - resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} - engines: {node: '>=6.0.0'} - hasBin: true + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} - bent@7.3.12: - resolution: {integrity: sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - better-result@2.9.2: - resolution: {integrity: sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==} + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + pg-cloudflare@1.3.0: + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} + pg-connection-string@2.12.0: + resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} - builtin-modules@5.2.0: - resolution: {integrity: sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==} - engines: {node: '>=18.20'} + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.13.0: + resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} + peerDependencies: + pg: '>=8.0' - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} + pg-protocol@1.13.0: + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - bytesish@0.4.4: - resolution: {integrity: sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==} + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} - c12@3.3.4: - resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} + engines: {node: '>= 16.0.0'} peerDependencies: - magicast: '*' + pg-native: '>=3.0.1' peerDependenciesMeta: - magicast: + pg-native: optional: true - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - call-bind@1.0.9: - resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} - engines: {node: '>= 0.4'} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + postgres-array@3.0.4: + resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} + engines: {node: '>=12'} - caniuse-lite@1.0.30001792: - resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} - caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + postgres@3.4.7: + resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} + engines: {node: '>=12'} - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + engines: {node: '>=14'} + hasBin: true - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + prisma@7.8.0: + resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + hasBin: true + peerDependencies: + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' + peerDependenciesMeta: + better-sqlite3: + optional: true + typescript: + optional: true - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} - character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} + peerDependencies: + react: ^19.2.5 - chart.js@4.5.1: - resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} - engines: {pnpm: '>=8'} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} + engines: {node: '>=0.10.0'} - chokidar@5.0.0: - resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} - ci-info@4.4.0: - resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} - engines: {node: '>=8'} + remeda@2.33.4: + resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} - clean-regexp@1.0.0: - resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} - engines: {node: '>=4'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + rimraf@6.1.3: + resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} + engines: {node: 20 || >=22} + hasBin: true - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} - engines: {node: '>= 12.0.0'} - - comment-parser@1.4.6: - resolution: {integrity: sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==} - engines: {node: '>= 12.0.0'} - - common-tags@1.8.2: - resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} - engines: {node: '>=4.0.0'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concat-stream@2.0.0: - resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} - engines: {'0': node >= 6.0} - - concurrently@9.2.1: - resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} - engines: {node: '>=18'} - hasBin: true - - confbox@0.2.4: - resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - core-js-compat@3.49.0: - resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - decamelize@5.0.1: - resolution: {integrity: sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==} + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} engines: {node: '>=10'} + hasBin: true - decode-named-character-reference@1.3.0: - resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - deepmerge-ts@7.1.5: - resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} - engines: {node: '>=16.0.0'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - defu@6.1.7: - resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} - - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - discord-api-types@0.38.47: - resolution: {integrity: sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==} - - discord.js@14.26.4: - resolution: {integrity: sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==} - engines: {node: '>=18'} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - dotenv@17.4.2: - resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - effect@3.20.0: - resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==} - - electron-to-chromium@1.5.357: - resolution: {integrity: sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==} - - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - empathic@2.0.0: - resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - enhanced-resolve@5.21.3: - resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} - engines: {node: '>=10.13.0'} - - entities@7.0.1: - resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} - engines: {node: '>=0.12'} - - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - environment@1.1.0: - resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} - engines: {node: '>=18'} - - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - - es-abstract@1.24.2: - resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-iterator-helpers@1.3.2: - resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - eslint-compat-utils@0.5.1: - resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} - engines: {node: '>=12'} - peerDependencies: - eslint: '>=6.0.0' + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true - eslint-compat-utils@0.6.5: - resolution: {integrity: sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==} - engines: {node: '>=12'} - peerDependencies: - eslint: '>=6.0.0' + ts-mixer@6.0.4: + resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - eslint-config-neon@0.2.9: - resolution: {integrity: sha512-1+l4fSVkc9KAJtQMl4hxPLlOODt4auKNBGAkDzSSnUr4sQExp48zGjExSH+lW5Y3obpAvLLUhsHbofGjvpD9yA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - eslint-config-prettier@10.1.8: - resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + turbo@2.9.14: + resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} hasBin: true - peerDependencies: - eslint: '>=7.0.0' - eslint-etc@5.2.1: - resolution: {integrity: sha512-lFJBSiIURdqQKq9xJhvSJFyPA+VeTh5xvk24e8pxVL7bwLBtGF60C/KRkLTMrvCZ6DA3kbPuYhLWY0TZMlqTsg==} - peerDependencies: - eslint: ^8.0.0 - typescript: '>=4.0.0' + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true - eslint-formatter-compact@8.40.0: - resolution: {integrity: sha512-cwGUs113TgmTQXecx5kfRjB7m0y2wkDLSadPTE2pK6M/wO4N8PjmUaoWOFNCP9MHgsiZwgqd5bZFnDCnszC56Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true - eslint-formatter-pretty@7.1.0: - resolution: {integrity: sha512-iyPrgpwKC3MMM75Wxn0VouD89HolpG+BL95NOxgwOWO0R+Omapo7gFX2xcGVsUDS7KiXLtDuynLbNbOARSE7YA==} - engines: {node: '>=18'} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - eslint-import-context@0.1.9: - resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - peerDependencies: - unrs-resolver: ^1.0.0 - peerDependenciesMeta: - unrs-resolver: - optional: true + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - eslint-import-resolver-typescript@4.4.4: - resolution: {integrity: sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==} - engines: {node: ^16.17.0 || >=18.6.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true + undici@6.24.1: + resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} + engines: {node: '>=18.17'} - eslint-mdx@3.7.0: - resolution: {integrity: sha512-QpPdJ6EeFthHuIrfgnWneZgwwFNOLFj/nf2jg/tOTBoiUnqNTxUUpTGAn0ZFHYEh5htVVoe5kjvD02oKtxZGeA==} - engines: {node: '>=18.0.0'} + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} peerDependencies: - eslint: '>=8.0.0' - remark-lint-file-extension: '*' + typescript: '>=5' peerDependenciesMeta: - remark-lint-file-extension: + typescript: optional: true - eslint-plugin-astro@1.7.0: - resolution: {integrity: sha512-89xpAn528UKCdmyysbg0AHHqi6sqcK89wXnJIpu4F0mFBN03zATEBNK7pRtMfl6gwtMOm5ECXs+Wz5qDHhwTFw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=8.57.0' + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true - eslint-plugin-cypress@5.3.0: - resolution: {integrity: sha512-qjHF2Sdi3VkXSMnfQeUqsbYnessgc6T2dus/Q1U+e5102GpPy9eLd8MWW2Xp2SS9bMpPNLnSHwktMhCKr0dIBg==} - peerDependencies: - eslint: '>=9' + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} - eslint-plugin-es-x@7.8.0: - resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} - engines: {node: ^14.18.0 || >=16.0.0} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + engines: {node: '>=10.0.0'} peerDependencies: - eslint: '>=8' + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - eslint-plugin-import-x@4.16.2: - resolution: {integrity: sha512-rM9K8UBHcWKpzQzStn1YRN2T5NvdeIfSVoKu/lKF41znQXHAUcBbYXe5wd6GNjZjTrP7viQ49n1D83x/2gYgIw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} peerDependencies: - '@typescript-eslint/utils': ^8.56.0 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - eslint-import-resolver-node: '*' + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: - '@typescript-eslint/utils': + bufferutil: optional: true - eslint-import-resolver-node: + utf-8-validate: optional: true - eslint-plugin-jsdoc@61.7.1: - resolution: {integrity: sha512-36DpldF95MlTX//n3/naULFVt8d1cV4jmSkx7ZKrE9ikkKHAgMLesuWp1SmwpVwAs5ndIM6abKd6PeOYZUgdWg==} - engines: {node: '>=20.11.0'} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} - eslint-plugin-jsx-a11y@6.10.2: - resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} - eslint-plugin-mdx@3.7.0: - resolution: {integrity: sha512-JXaaQPnKqyti/QSOSQDThLV1EemHm/Fe2l/nMKH0vmhvmABtN/yV/9+GtKgh8UTZwrwuTfQq1HW5eR8HXneNLA==} - engines: {node: '>=18.0.0'} - peerDependencies: - eslint: '>=8.0.0' + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} - eslint-plugin-n@17.24.0: - resolution: {integrity: sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=8.23.0' + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} - eslint-plugin-promise@7.3.0: - resolution: {integrity: sha512-6uGiOR0INuujr6PEQmeSSP7GbIMJ/ebEXXiEzb/nOj68LknH5Pxzb/AbZivmr6VE6TkTE8rTjRK9zhKpK6HsRA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + zeptomatch@2.1.0: + resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} - eslint-plugin-react-hooks@7.1.1: - resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - eslint-plugin-react-refresh@0.4.26: - resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} - peerDependencies: - eslint: '>=8.40' +snapshots: - eslint-plugin-react@7.37.5: - resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + '@discordjs/builders@1.14.1': + dependencies: + '@discordjs/formatters': 0.6.2 + '@discordjs/util': 1.2.0 + '@sapphire/shapeshift': 4.0.0 + discord-api-types: 0.38.47 + fast-deep-equal: 3.1.3 + ts-mixer: 6.0.4 + tslib: 2.8.1 - eslint-plugin-rxjs-angular@2.0.1: - resolution: {integrity: sha512-HJ/JHhjDJKyFUmM8o7rS91WNkNv7W7Z/okR5X3hqG7tKVMLOJi4T63Aa74ECuCdowmdfW75p2RrW4R8WeoZIKQ==} - peerDependencies: - eslint: ^8.0.0 - typescript: '>=4.0.0' + '@discordjs/collection@1.5.3': {} - eslint-plugin-rxjs@5.0.3: - resolution: {integrity: sha512-fcVkqLmYLRfRp+ShafjpUKuaZ+cw/sXAvM5dfSxiEr7M28QZ/NY7vaOr09FB4rSaZsQyLBnNPh5SL+4EgKjh8Q==} - peerDependencies: - eslint: ^8.0.0 - typescript: '>=4.0.0' - - eslint-plugin-sonarjs@3.0.7: - resolution: {integrity: sha512-62jB20krIPvcwBLAyG3VVKa2ce2j2lL1yCb8Y0ylMRR/dLvCCTiQx8gQbXb+G81k1alPZ2/I3muZinqWQdBbzw==} - peerDependencies: - eslint: ^8.0.0 || ^9.0.0 - - eslint-plugin-svelte3@4.0.0: - resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==} - peerDependencies: - eslint: '>=8.0.0' - svelte: ^3.2.0 - - eslint-plugin-tsdoc@0.4.0: - resolution: {integrity: sha512-MT/8b4aKLdDClnS8mP3R/JNjg29i0Oyqd/0ym6NnQf+gfKbJJ4ZcSh2Bs1H0YiUMTBwww5JwXGTWot/RwyJ7aQ==} - - eslint-plugin-typescript-sort-keys@3.3.0: - resolution: {integrity: sha512-bRW3Rc/VNdrSP9OoY5wgjjaXCOOkZKpzvl/Mk6l8Sg8CMehVIcg9K4y33l+ZcZiknpl0aR6rKusxuCJNGZWmVw==} - engines: {node: '>= 16'} - peerDependencies: - '@typescript-eslint/parser': '>=6' - eslint: ^7 || ^8 - typescript: ^3 || ^4 || ^5 - - eslint-plugin-unicorn@61.0.2: - resolution: {integrity: sha512-zLihukvneYT7f74GNbVJXfWIiNQmkc/a9vYBTE4qPkQZswolWNdu+Wsp9sIXno1JOzdn6OUwLPd19ekXVkahRA==} - engines: {node: ^20.10.0 || >=21.0.0} - peerDependencies: - eslint: '>=9.29.0' - - eslint-plugin-vue@10.9.1: - resolution: {integrity: sha512-cHB0Tf4Duvzwecwd/AqWzZvF/QszE13BhjVUpVXWCy9AeMR5GjkAjP3i85vqgLgOuTmkHR1OJ5oMeqLHtuw8zg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 - '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-eslint-parser: ^10.3.0 - peerDependenciesMeta: - '@stylistic/eslint-plugin': - optional: true - '@typescript-eslint/parser': - optional: true - - eslint-rule-docs@1.1.235: - resolution: {integrity: sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==} - - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-scope@9.1.2: - resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - espree@11.2.0: - resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-util-is-identifier-name@3.0.0: - resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} - - estree-util-visit@2.0.0: - resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up-simple@1.0.1: - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} - engines: {node: '>=18'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - generate-function@2.3.1: - resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} - - generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-east-asian-width@1.6.0: - resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} - engines: {node: '>=18'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-port-please@3.2.0: - resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - - get-tsconfig@4.14.0: - resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} - - giget@3.2.0: - resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} - hasBin: true - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - - glob@13.0.6: - resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} - engines: {node: 18 || 20 || >=22} - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - - globals@16.5.0: - resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} - engines: {node: '>=18'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - grammex@3.1.12: - resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} - - graphmatch@1.1.1: - resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-flag@5.0.1: - resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} - engines: {node: '>=12'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} - engines: {node: '>= 0.4'} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - hono@4.12.19: - resolution: {integrity: sha512-xa3eYXYXx68XTT4hZ7dRzsXBhaq85ToSrlUJNoR0gwz/1Ap/CNwX47wfvV7pc/xWhjKVVkLT7zBJy8chhNguqQ==} - engines: {node: '>=16.9.0'} - - hosted-git-info@7.0.2: - resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} - engines: {node: ^16.14.0 || >=18.0.0} - - html-entities@2.6.0: - resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} - - http-status-codes@2.3.0: - resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@6.0.2: - resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - import-meta-resolve@4.2.0: - resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@4.1.3: - resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - irregular-plurals@3.5.0: - resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} - engines: {node: '>=8'} - - is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - - is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-builtin-module@5.0.0: - resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} - engines: {node: '>=18.20'} - - is-bun-module@2.0.0: - resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - - is-empty@1.2.0: - resolution: {integrity: sha512-F2FnH/otLNJv0J6wc73A5Xo7oHLNnqplYqZhUu01tD54DIPvxIRSTSLkrUB/M0nHO4vo1O9PDfN4KoTxCzLh/w==} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-unicode-supported@2.1.0: - resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} - engines: {node: '>=18'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isexe@3.1.5: - resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} - engines: {node: '>=18'} - - iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - - jju@1.4.0: - resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsdoc-type-pratt-parser@7.0.0: - resolution: {integrity: sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA==} - engines: {node: '>=20.0.0'} - - jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} - engines: {node: '>=6'} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-parse-even-better-errors@3.0.2: - resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsx-ast-utils-x@0.1.0: - resolution: {integrity: sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - - language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lines-and-columns@2.0.4: - resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - load-plugin@6.0.3: - resolution: {integrity: sha512-kc0X2FEUZr145odl68frm+lMJuQ23+rTXYmR6TImqPtbpmXC4vVXbWKDQ9IzndA0HfyQamWfKLhzsqGSTxE63w==} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.snakecase@4.1.1: - resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - - lodash@4.18.1: - resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - - log-symbols@7.0.1: - resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} - engines: {node: '>=18'} - - long@5.3.2: - resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - - longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@11.3.6: - resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} - engines: {node: 20 || >=22} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lru.min@1.1.4: - resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} - engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - - magic-bytes.js@1.13.0: - resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdast-util-from-markdown@2.0.3: - resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} - - mdast-util-mdx-expression@2.0.1: - resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} - - mdast-util-mdx-jsx@3.2.0: - resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} - - mdast-util-mdx@3.0.0: - resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} - - mdast-util-mdxjs-esm@2.0.1: - resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} - - mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - - mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} - - mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - - micromark-extension-mdx-expression@3.0.1: - resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} - - micromark-extension-mdx-jsx@3.0.2: - resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} - - micromark-extension-mdx-md@2.0.0: - resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} - - micromark-extension-mdxjs-esm@3.0.0: - resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} - - micromark-extension-mdxjs@3.0.0: - resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} - - micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} - - micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} - - micromark-factory-mdx-expression@2.0.3: - resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} - - micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} - - micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} - - micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} - - micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} - - micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} - - micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} - - micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-events-to-acorn@2.0.3: - resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} - - micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - - micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} - - micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - minimatch@10.1.2: - resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} - engines: {node: 20 || >=22} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mysql2@3.15.3: - resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} - engines: {node: '>= 8.0'} - - named-placeholders@1.1.6: - resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} - engines: {node: '>=8.0.0'} - - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - napi-postinstall@0.3.4: - resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true - - natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - node-exports-info@1.6.0: - resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} - engines: {node: '>= 0.4'} - - node-releases@2.0.44: - resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} - - nopt@7.2.1: - resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - - normalize-package-data@6.0.2: - resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} - engines: {node: ^16.14.0 || >=18.0.0} - - npm-install-checks@6.3.0: - resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - npm-normalize-package-bin@3.0.1: - resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - npm-package-arg@11.0.3: - resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} - engines: {node: ^16.14.0 || >=18.0.0} - - npm-pick-manifest@9.1.0: - resolution: {integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==} - engines: {node: ^16.14.0 || >=18.0.0} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-deep-merge@2.0.0: - resolution: {integrity: sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} - - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} - - parse-imports-exports@0.2.4: - resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} - - parse-json@7.1.1: - resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} - engines: {node: '>=16'} - - parse-statements@1.0.11: - resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-scurry@2.0.2: - resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} - engines: {node: 18 || 20 || >=22} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - perfect-debounce@2.1.0: - resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} - - pg-cloudflare@1.3.0: - resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - - pg-connection-string@2.12.0: - resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-pool@3.13.0: - resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} - peerDependencies: - pg: '>=8.0' - - pg-protocol@1.13.0: - resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - pg@8.20.0: - resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pkg-types@2.3.1: - resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} - - plur@5.1.0: - resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} - engines: {node: '>=4'} - - postcss@8.5.14: - resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} - engines: {node: ^10 || ^12 || >=14} - - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-array@3.0.4: - resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} - engines: {node: '>=12'} - - postgres-bytea@1.0.1: - resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} - engines: {node: '>=0.10.0'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - - postgres@3.4.7: - resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} - engines: {node: '>=12'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} - engines: {node: '>=14'} - hasBin: true - - prisma@7.8.0: - resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} - engines: {node: ^20.19 || ^22.12 || >=24.0} - hasBin: true - peerDependencies: - better-sqlite3: '>=9.0.0' - typescript: '>=5.4.0' - peerDependenciesMeta: - better-sqlite3: - optional: true - typescript: - optional: true - - proc-log@4.2.0: - resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true - - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - - proper-lockfile@4.1.2: - resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - rc9@3.0.1: - resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} - - react-dom@19.2.5: - resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} - peerDependencies: - react: ^19.2.5 - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} - engines: {node: '>=0.10.0'} - - read-package-json-fast@3.0.2: - resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@5.0.0: - resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} - engines: {node: '>= 20.19.0'} - - refa@0.12.1: - resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - - regexp-ast-analysis@0.7.1: - resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - regexp-tree@0.1.27: - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} - hasBin: true - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - regjsparser@0.12.0: - resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} - hasBin: true - - remark-mdx@3.1.1: - resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} - - remark-parse@11.0.0: - resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} - - remark-stringify@11.0.0: - resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - - remeda@2.33.4: - resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - requireindex@1.2.0: - resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} - engines: {node: '>=0.10.5'} - - reserved-identifiers@1.2.0: - resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} - engines: {node: '>=18'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} - hasBin: true - - resolve@2.0.0-next.7: - resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} - engines: {node: '>= 0.4'} - hasBin: true - - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@6.1.3: - resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} - engines: {node: 20 || >=22} - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - rxjs-report-usage@1.0.6: - resolution: {integrity: sha512-omv1DIv5z1kV+zDAEjaDjWSkx8w5TbFp5NZoPwUipwzYVcor/4So9ZU3bUyQ1c8lxY5Q0Es/ztWW7PGjY7to0Q==} - hasBin: true - - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - - safe-array-concat@1.1.4: - resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} - engines: {node: '>=0.4'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - scslre@0.3.0: - resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} - engines: {node: ^14.0.0 || >=16.0.0} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} - engines: {node: '>=10'} - hasBin: true - - seq-queue@0.0.5: - resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-expression-parse@4.0.0: - resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - - spdx-license-ids@3.0.23: - resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} - - stable-hash-x@0.2.0: - resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} - engines: {node: '>=12.0.0'} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string-width@6.1.0: - resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} - engines: {node: '>=16'} - - string-width@8.2.1: - resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} - engines: {node: '>=20'} - - string.prototype.includes@2.0.1: - resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} - engines: {node: '>= 0.4'} - - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-indent@4.1.1: - resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} - engines: {node: '>=12'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@10.2.2: - resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} - engines: {node: '>=18'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - - supports-hyperlinks@4.4.0: - resolution: {integrity: sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==} - engines: {node: '>=20'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - svelte@3.59.2: - resolution: {integrity: sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==} - engines: {node: '>= 8'} - - synckit@0.11.12: - resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} - engines: {node: ^14.18.0 || >=16.0.0} - - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - to-valid-identifier@1.0.0: - resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} - engines: {node: '>=20'} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - trough@2.2.0: - resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - ts-declaration-location@1.0.7: - resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} - peerDependencies: - typescript: '>=4.0.0' - - ts-mixer@6.0.4: - resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsutils-etc@1.4.2: - resolution: {integrity: sha512-2Dn5SxTDOu6YWDNKcx1xu2YUy6PUeKrWZB/x2cQ8vY2+iz3JRembKn/iZ0JLT1ZudGNwQQvtFX9AwvRHbXuPUg==} - hasBin: true - peerDependencies: - tsutils: ^3.0.0 - typescript: '>=4.0.0' - - tsutils@3.21.0: - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - - turbo@2.9.14: - resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} - hasBin: true - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - - typescript-eslint@8.59.3: - resolution: {integrity: sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici-types@7.24.6: - resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - - undici@6.24.1: - resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} - engines: {node: '>=18.17'} - - unified-engine@11.2.2: - resolution: {integrity: sha512-15g/gWE7qQl9tQ3nAEbMd5h9HV1EACtFs6N9xaRBZICoCwnNGbal1kOs++ICf4aiTdItZxU2s/kYWhW7htlqJg==} - - unified@11.0.5: - resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - - unist-util-inspect@8.1.0: - resolution: {integrity: sha512-mOlg8Mp33pR0eeFpo5d2902ojqFFOKMMG2hF8bmH7ZlhnmjFgh0NI3/ZDwdaBJNbvrS7LZFVrBVtIE9KZ9s7vQ==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position-from-estree@2.0.0: - resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.1.0: - resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} - - unrs-resolver@1.11.1: - resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - valibot@1.2.0: - resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} - peerDependencies: - typescript: '>=5' - peerDependenciesMeta: - typescript: - optional: true - - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile-reporter@8.1.1: - resolution: {integrity: sha512-qxRZcnFSQt6pWKn3PAk81yLK2rO2i7CDXpy8v8ZquiEOMLSnPw6BMSi9Y1sUCwGGl7a9b3CJT1CKpnRF7pp66g==} - - vfile-sort@4.0.0: - resolution: {integrity: sha512-lffPI1JrbHDTToJwcq0rl6rBmkjQmMuXkAxsZPRS9DXbaJQvc642eCg6EGxcX2i1L+esbuhq+2l9tBll5v8AeQ==} - - vfile-statistics@3.0.0: - resolution: {integrity: sha512-/qlwqwWBWFOmpXujL/20P+Iuydil0rZZNglR+VNm6J0gpLHwuVM5s7g2TfVoswbXjZ4HuIhLMySEyIw5i7/D8w==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - vue-eslint-parser@10.4.0: - resolution: {integrity: sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - - walk-up-path@3.0.1: - resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} - - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - which@4.0.0: - resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} - engines: {node: ^16.13.0 || >=18.0.0} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.20.1: - resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - yoctocolors@2.1.2: - resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} - engines: {node: '>=18'} - - zeptomatch@2.1.0: - resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@angular-eslint/bundled-angular-compiler@20.7.0': {} - - '@angular-eslint/eslint-plugin-template@20.7.0(@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.7.0 - '@angular-eslint/template-parser': 20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@angular-eslint/utils': 20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - aria-query: 5.3.2 - axobject-query: 4.1.0 - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 - - '@angular-eslint/eslint-plugin@20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.7.0 - '@angular-eslint/utils': 20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - - '@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.7.0 - eslint: 9.39.4(jiti@2.7.0) - eslint-scope: 9.1.2 - typescript: 5.9.3 - - '@angular-eslint/utils@20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.7.0 - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 - - '@astrojs/compiler@3.0.1': {} - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.3': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@discordjs/builders@1.14.1': - dependencies: - '@discordjs/formatters': 0.6.2 - '@discordjs/util': 1.2.0 - '@sapphire/shapeshift': 4.0.0 - discord-api-types: 0.38.47 - fast-deep-equal: 3.1.3 - ts-mixer: 6.0.4 - tslib: 2.8.1 - - '@discordjs/collection@1.5.3': {} - - '@discordjs/collection@2.1.1': {} - - '@discordjs/core@2.4.0': - dependencies: - '@discordjs/rest': 2.6.1 - '@discordjs/util': 1.2.0 - '@discordjs/ws': 2.0.4 - '@sapphire/snowflake': 3.5.5 - '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.47 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@discordjs/formatters@0.6.2': - dependencies: - discord-api-types: 0.38.47 - - '@discordjs/rest@2.6.1': - dependencies: - '@discordjs/collection': 2.1.1 - '@discordjs/util': 1.2.0 - '@sapphire/async-queue': 1.5.5 - '@sapphire/snowflake': 3.5.5 - '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.47 - magic-bytes.js: 1.13.0 - tslib: 2.8.1 - undici: 6.24.1 - - '@discordjs/util@1.2.0': - dependencies: - discord-api-types: 0.38.47 - - '@discordjs/ws@1.2.3': - dependencies: - '@discordjs/collection': 2.1.1 - '@discordjs/rest': 2.6.1 - '@discordjs/util': 1.2.0 - '@sapphire/async-queue': 1.5.5 - '@types/ws': 8.18.1 - '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.47 - tslib: 2.8.1 - ws: 8.20.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@discordjs/ws@2.0.4': - dependencies: - '@discordjs/collection': 2.1.1 - '@discordjs/rest': 2.6.1 - '@discordjs/util': 1.2.0 - '@sapphire/async-queue': 1.5.5 - '@types/ws': 8.18.1 - '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.47 - tslib: 2.8.1 - ws: 8.20.1 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@electric-sql/pglite-socket@0.1.1(@electric-sql/pglite@0.4.1)': - dependencies: - '@electric-sql/pglite': 0.4.1 - - '@electric-sql/pglite-tools@0.3.1(@electric-sql/pglite@0.4.1)': - dependencies: - '@electric-sql/pglite': 0.4.1 - - '@electric-sql/pglite@0.4.1': {} - - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@es-joy/jsdoccomment@0.78.0': - dependencies: - '@types/estree': 1.0.9 - '@typescript-eslint/types': 8.59.3 - comment-parser: 1.4.1 - esquery: 1.7.0 - jsdoc-type-pratt-parser: 7.0.0 - - '@es-joy/resolve.exports@1.2.0': {} - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': - dependencies: - eslint: 9.39.4(jiti@2.7.0) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/compat@1.4.1(eslint@9.39.4(jiti@2.7.0))': - dependencies: - '@eslint/core': 0.17.0 - optionalDependencies: - eslint: 9.39.4(jiti@2.7.0) - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.15.2': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.3.5': - dependencies: - '@eslint/core': 0.15.2 - levn: 0.4.1 - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@hono/node-server@1.19.11(hono@4.12.19)': - dependencies: - hono: 4.12.19 - - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 - - '@humanfs/node@0.16.8': - dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 - '@humanwhocodes/retry': 0.4.3 - - '@humanfs/types@0.15.0': {} - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@img/colour@1.1.0': {} - - '@img/sharp-darwin-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 - optional: true - - '@img/sharp-darwin-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm@1.2.4': - optional: true - - '@img/sharp-libvips-linux-ppc64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-riscv64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-s390x@1.2.4': - optional: true - - '@img/sharp-libvips-linux-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - optional: true - - '@img/sharp-linux-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 - optional: true - - '@img/sharp-linux-arm@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 - optional: true - - '@img/sharp-linux-ppc64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 - optional: true - - '@img/sharp-linux-riscv64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 - optional: true - - '@img/sharp-linux-s390x@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 - optional: true - - '@img/sharp-linux-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - optional: true - - '@img/sharp-wasm32@0.34.5': - dependencies: - '@emnapi/runtime': 1.10.0 - optional: true - - '@img/sharp-win32-arm64@0.34.5': - optional: true - - '@img/sharp-win32-ia32@0.34.5': - optional: true - - '@img/sharp-win32-x64@0.34.5': - optional: true - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@kurkle/color@0.3.4': {} - - '@microsoft/tsdoc-config@0.17.1': - dependencies: - '@microsoft/tsdoc': 0.15.1 - ajv: 8.12.0 - jju: 1.4.0 - resolve: 1.22.12 - - '@microsoft/tsdoc@0.15.1': {} - - '@napi-rs/wasm-runtime@0.2.12': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - - '@next/eslint-plugin-next@15.5.18': - dependencies: - fast-glob: 3.3.1 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@npmcli/config@8.3.4': - dependencies: - '@npmcli/map-workspaces': 3.0.6 - '@npmcli/package-json': 5.2.1 - ci-info: 4.4.0 - ini: 4.1.3 - nopt: 7.2.1 - proc-log: 4.2.0 - semver: 7.8.0 - walk-up-path: 3.0.1 - transitivePeerDependencies: - - bluebird - - '@npmcli/git@5.0.8': - dependencies: - '@npmcli/promise-spawn': 7.0.2 - ini: 4.1.3 - lru-cache: 10.4.3 - npm-pick-manifest: 9.1.0 - proc-log: 4.2.0 - promise-inflight: 1.0.1 - promise-retry: 2.0.1 - semver: 7.8.0 - which: 4.0.0 - transitivePeerDependencies: - - bluebird - - '@npmcli/map-workspaces@3.0.6': - dependencies: - '@npmcli/name-from-folder': 2.0.0 - glob: 10.5.0 - minimatch: 9.0.9 - read-package-json-fast: 3.0.2 - - '@npmcli/name-from-folder@2.0.0': {} - - '@npmcli/package-json@5.2.1': - dependencies: - '@npmcli/git': 5.0.8 - glob: 10.5.0 - hosted-git-info: 7.0.2 - json-parse-even-better-errors: 3.0.2 - normalize-package-data: 6.0.2 - proc-log: 4.2.0 - semver: 7.8.0 - transitivePeerDependencies: - - bluebird - - '@npmcli/promise-spawn@7.0.2': - dependencies: - which: 4.0.0 - - '@package-json/types@0.0.12': {} - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@pkgr/core@0.2.9': {} - - '@prisma/adapter-pg@7.8.0': - dependencies: - '@prisma/driver-adapter-utils': 7.8.0 - '@types/pg': 8.20.0 - pg: 8.20.0 - postgres-array: 3.0.4 - transitivePeerDependencies: - - pg-native - - '@prisma/client-runtime-utils@7.8.0': {} - - '@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)': - dependencies: - '@prisma/client-runtime-utils': 7.8.0 - optionalDependencies: - prisma: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - typescript: 5.9.3 - - '@prisma/config@7.8.0': - dependencies: - c12: 3.3.4 - deepmerge-ts: 7.1.5 - effect: 3.20.0 - empathic: 2.0.0 - transitivePeerDependencies: - - magicast - - '@prisma/debug@7.2.0': {} - - '@prisma/debug@7.8.0': {} - - '@prisma/dev@0.24.3(typescript@5.9.3)': - dependencies: - '@electric-sql/pglite': 0.4.1 - '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) - '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) - '@hono/node-server': 1.19.11(hono@4.12.19) - '@prisma/get-platform': 7.2.0 - '@prisma/query-plan-executor': 7.2.0 - '@prisma/streams-local': 0.1.2 - foreground-child: 3.3.1 - get-port-please: 3.2.0 - hono: 4.12.19 - http-status-codes: 2.3.0 - pathe: 2.0.3 - proper-lockfile: 4.1.2 - remeda: 2.33.4 - std-env: 3.10.0 - valibot: 1.2.0(typescript@5.9.3) - zeptomatch: 2.1.0 - transitivePeerDependencies: - - typescript - - '@prisma/driver-adapter-utils@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - - '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} - - '@prisma/engines@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a - '@prisma/fetch-engine': 7.8.0 - '@prisma/get-platform': 7.8.0 - - '@prisma/fetch-engine@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a - '@prisma/get-platform': 7.8.0 - - '@prisma/get-platform@7.2.0': - dependencies: - '@prisma/debug': 7.2.0 - - '@prisma/get-platform@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - - '@prisma/query-plan-executor@7.2.0': {} - - '@prisma/streams-local@0.1.2': - dependencies: - ajv: 8.20.0 - better-result: 2.9.2 - env-paths: 3.0.0 - proper-lockfile: 4.1.2 - - '@prisma/studio-core@0.27.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-toggle': 1.1.10(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@types/react': 19.2.14 - chart.js: 4.5.1 - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - transitivePeerDependencies: - - '@types/react-dom' - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-primitive@2.1.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-toggle@1.1.10(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@sapphire/async-queue@1.5.5': {} - - '@sapphire/discord-utilities@3.5.0': - dependencies: - discord-api-types: 0.38.47 - - '@sapphire/discord-utilities@4.0.0': - dependencies: - discord-api-types: 0.38.47 - - '@sapphire/discord.js-utilities@7.3.3': - dependencies: - '@sapphire/discord-utilities': 3.5.0 - '@sapphire/duration': 1.2.0 - '@sapphire/utilities': 3.18.2 - tslib: 2.8.1 - - '@sapphire/duration@1.2.0': {} - - '@sapphire/framework@5.5.0': - dependencies: - '@discordjs/builders': 1.14.1 - '@sapphire/discord-utilities': 4.0.0 - '@sapphire/discord.js-utilities': 7.3.3 - '@sapphire/lexure': 1.1.12 - '@sapphire/pieces': 4.4.1 - '@sapphire/ratelimits': 2.4.11 - '@sapphire/result': 2.8.0 - '@sapphire/stopwatch': 1.5.4 - '@sapphire/utilities': 3.18.2 - - '@sapphire/lexure@1.1.12': - dependencies: - '@sapphire/result': 2.8.0 - - '@sapphire/pieces@4.4.1': - dependencies: - '@discordjs/collection': 2.1.1 - '@sapphire/utilities': 3.18.2 - tslib: 2.8.1 - - '@sapphire/ratelimits@2.4.11': {} - - '@sapphire/result@2.8.0': {} - - '@sapphire/shapeshift@4.0.0': - dependencies: - fast-deep-equal: 3.1.3 - lodash: 4.18.1 - - '@sapphire/snowflake@3.5.3': {} - - '@sapphire/snowflake@3.5.5': {} - - '@sapphire/stopwatch@1.5.4': - dependencies: - tslib: 2.8.1 - - '@sapphire/ts-config@5.0.3': - dependencies: - tslib: 2.8.1 - typescript: 5.4.5 - - '@sapphire/utilities@3.18.2': {} - - '@sindresorhus/base62@1.0.0': {} - - '@standard-schema/spec@1.1.0': {} - - '@stylistic/eslint-plugin-jsx@4.4.1(eslint@9.39.4(jiti@2.7.0))': - dependencies: - eslint: 9.39.4(jiti@2.7.0) - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - estraverse: 5.3.0 - picomatch: 4.0.4 - - '@stylistic/eslint-plugin-ts@4.4.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.7.0))': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/types': 8.59.3 - eslint: 9.39.4(jiti@2.7.0) - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - estraverse: 5.3.0 - picomatch: 4.0.4 - - '@turbo/darwin-64@2.9.14': - optional: true - - '@turbo/darwin-arm64@2.9.14': - optional: true - - '@turbo/linux-64@2.9.14': - optional: true - - '@turbo/linux-arm64@2.9.14': - optional: true - - '@turbo/windows-64@2.9.14': - optional: true - - '@turbo/windows-arm64@2.9.14': - optional: true - - '@tybys/wasm-util@0.10.2': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/concat-stream@2.0.3': - dependencies: - '@types/node': 22.19.19 - - '@types/debug@4.1.13': - dependencies: - '@types/ms': 2.1.0 - - '@types/eslint@9.6.1': - dependencies: - '@types/estree': 1.0.9 - '@types/json-schema': 7.0.15 - - '@types/esrecurse@4.3.1': {} - - '@types/estree-jsx@1.0.5': - dependencies: - '@types/estree': 1.0.9 - - '@types/estree@1.0.9': {} - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/is-empty@1.2.3': {} - - '@types/json-schema@7.0.15': {} - - '@types/lodash.merge@4.6.9': - dependencies: - '@types/lodash': 4.17.24 - - '@types/lodash@4.17.24': {} - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/ms@2.1.0': {} - - '@types/node@22.19.19': - dependencies: - undici-types: 6.21.0 - - '@types/node@25.8.0': - dependencies: - undici-types: 7.24.6 - - '@types/pg@8.20.0': - dependencies: - '@types/node': 22.19.19 - pg-protocol: 1.13.0 - pg-types: 2.2.0 - - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - - '@types/semver@7.7.1': {} - - '@types/sharp@0.32.0': - dependencies: - sharp: 0.34.5 - - '@types/supports-color@8.1.3': {} - - '@types/unist@2.0.11': {} - - '@types/unist@3.0.3': {} - - '@types/ws@8.18.1': - dependencies: - '@types/node': 25.8.0 - - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@17.0.35': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/type-utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.3 - eslint: 9.39.4(jiti@2.7.0) - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/experimental-utils@5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.3 - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.59.3(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - - '@typescript-eslint/scope-manager@8.59.3': - dependencies: - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/visitor-keys': 8.59.3 - - '@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@5.62.0': {} - - '@typescript-eslint/types@8.59.3': {} - - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.3 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.8.0 - tsutils: 3.21.0(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@8.59.3(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.59.3(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/visitor-keys': 8.59.3 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.8.0 - tinyglobby: 0.2.16 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@types/json-schema': 7.0.15 - '@types/semver': 7.7.1 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - eslint-scope: 5.1.1 - semver: 7.8.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - eslint-visitor-keys: 3.4.3 - - '@typescript-eslint/visitor-keys@8.59.3': - dependencies: - '@typescript-eslint/types': 8.59.3 - eslint-visitor-keys: 5.0.1 - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - optional: true - - '@unrs/resolver-binding-android-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - dependencies: - '@napi-rs/wasm-runtime': 0.2.12 - optional: true - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - optional: true - - '@vladfrangu/async_event_emitter@2.4.7': {} - - abbrev@2.0.0: {} - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.12.0: - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-escapes@7.3.0: - dependencies: - environment: 1.1.0 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.3: {} - - are-docs-informative@0.0.2: {} - - argparse@2.0.1: {} - - aria-query@5.3.2: {} - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-includes@3.1.9: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - is-string: 1.1.1 - math-intrinsics: 1.1.0 - - array-union@2.1.0: {} - - array.prototype.findlast@1.2.5: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - - array.prototype.flat@1.3.3: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-shim-unscopables: 1.1.0 - - array.prototype.flatmap@1.3.3: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-shim-unscopables: 1.1.0 - - array.prototype.tosorted@1.1.4: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-shim-unscopables: 1.1.0 - - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - ast-types-flow@0.0.8: {} - - astro-eslint-parser@1.4.0: - dependencies: - '@astrojs/compiler': 3.0.1 - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - astrojs-compiler-sync: 1.1.1(@astrojs/compiler@3.0.1) - debug: 4.4.3 - entities: 7.0.1 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - fast-glob: 3.3.3 - is-glob: 4.0.3 - semver: 7.8.0 - transitivePeerDependencies: - - supports-color - - astrojs-compiler-sync@1.1.1(@astrojs/compiler@3.0.1): - dependencies: - '@astrojs/compiler': 3.0.1 - synckit: 0.11.12 - - async-function@1.0.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - aws-ssl-profiles@1.1.2: {} - - axe-core@4.11.4: {} - - axobject-query@4.1.0: {} - - bail@2.0.2: {} - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - baseline-browser-mapping@2.10.29: {} - - bent@7.3.12: - dependencies: - bytesish: 0.4.4 - caseless: 0.12.0 - is-stream: 2.0.1 - - better-result@2.9.2: {} - - boolbase@1.0.0: {} - - brace-expansion@1.1.14: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.1.0: - dependencies: - balanced-match: 1.0.2 - - brace-expansion@5.0.6: - dependencies: - balanced-match: 4.0.4 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.2: - dependencies: - baseline-browser-mapping: 2.10.29 - caniuse-lite: 1.0.30001792 - electron-to-chromium: 1.5.357 - node-releases: 2.0.44 - update-browserslist-db: 1.2.3(browserslist@4.28.2) - - buffer-from@1.1.2: {} - - builtin-modules@3.3.0: {} - - builtin-modules@5.2.0: {} - - bytes@3.1.2: {} - - bytesish@0.4.4: {} - - c12@3.3.4: - dependencies: - chokidar: 5.0.0 - confbox: 0.2.4 - defu: 6.1.7 - dotenv: 17.4.2 - exsolve: 1.0.8 - giget: 3.2.0 - jiti: 2.7.0 - ohash: 2.0.11 - pathe: 2.0.3 - perfect-debounce: 2.1.0 - pkg-types: 2.3.1 - rc9: 3.0.1 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.9: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - caniuse-lite@1.0.30001792: {} - - caseless@0.12.0: {} - - ccount@2.0.1: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.6.2: {} - - change-case@5.4.4: {} - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - character-entities@2.0.2: {} - - character-reference-invalid@2.0.1: {} - - chart.js@4.5.1: - dependencies: - '@kurkle/color': 0.3.4 - - chokidar@5.0.0: - dependencies: - readdirp: 5.0.0 - - ci-info@4.4.0: {} - - clean-regexp@1.0.0: - dependencies: - escape-string-regexp: 1.0.5 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - comment-parser@1.4.1: {} - - comment-parser@1.4.6: {} - - common-tags@1.8.2: {} - - concat-map@0.0.1: {} - - concat-stream@2.0.0: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 3.6.2 - typedarray: 0.0.6 - - concurrently@9.2.1: - dependencies: - chalk: 4.1.2 - rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - - confbox@0.2.4: {} - - convert-source-map@2.0.0: {} - - core-js-compat@3.49.0: - dependencies: - browserslist: 4.28.2 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - cssesc@3.0.0: {} - - csstype@3.2.3: {} - - damerau-levenshtein@1.0.8: {} - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decamelize@5.0.1: {} - - decode-named-character-reference@1.3.0: - dependencies: - character-entities: 2.0.2 - - deep-is@0.1.4: {} - - deepmerge-ts@7.1.5: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - defu@6.1.7: {} - - denque@2.1.0: {} - - dequal@2.0.3: {} - - destr@2.0.5: {} - - detect-libc@2.1.2: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - discord-api-types@0.38.47: {} - - discord.js@14.26.4: - dependencies: - '@discordjs/builders': 1.14.1 - '@discordjs/collection': 1.5.3 - '@discordjs/formatters': 0.6.2 - '@discordjs/rest': 2.6.1 - '@discordjs/util': 1.2.0 - '@discordjs/ws': 1.2.3 - '@sapphire/snowflake': 3.5.3 - discord-api-types: 0.38.47 - fast-deep-equal: 3.1.3 - lodash.snakecase: 4.1.1 - magic-bytes.js: 1.13.0 - tslib: 2.8.1 - undici: 6.24.1 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - dotenv@17.4.2: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - eastasianwidth@0.2.0: {} - - effect@3.20.0: - dependencies: - '@standard-schema/spec': 1.1.0 - fast-check: 3.23.2 - - electron-to-chromium@1.5.357: {} - - emoji-regex@10.6.0: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - empathic@2.0.0: {} - - enhanced-resolve@5.21.3: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.3 - - entities@7.0.1: {} - - env-paths@3.0.0: {} - - environment@1.1.0: {} - - err-code@2.0.3: {} - - error-ex@1.3.4: - dependencies: - is-arrayish: 0.2.1 - - es-abstract@1.24.2: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.9 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.3 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.4 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.20 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-iterator-helpers@1.3.2: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-set-tostringtag: 2.1.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - internal-slot: 1.1.0 - iterator.prototype: 1.1.5 - math-intrinsics: 1.1.0 - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.3 - - es-shim-unscopables@1.1.0: - dependencies: - hasown: 2.0.3 - - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - escalade@3.2.0: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - - eslint-compat-utils@0.5.1(eslint@9.39.4(jiti@2.7.0)): - dependencies: - eslint: 9.39.4(jiti@2.7.0) - semver: 7.8.0 - - eslint-compat-utils@0.6.5(eslint@9.39.4(jiti@2.7.0)): - dependencies: - eslint: 9.39.4(jiti@2.7.0) - semver: 7.8.0 - - eslint-config-neon@0.2.9(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2)(typescript@5.9.3): - dependencies: - '@angular-eslint/eslint-plugin': 20.7.0(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@angular-eslint/eslint-plugin-template': 20.7.0(@angular-eslint/template-parser@20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/types@8.59.3)(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@angular-eslint/template-parser': 20.7.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@eslint/compat': 1.4.1(eslint@9.39.4(jiti@2.7.0)) - '@next/eslint-plugin-next': 15.5.18 - '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4(jiti@2.7.0)) - '@stylistic/eslint-plugin-jsx': 4.4.1(eslint@9.39.4(jiti@2.7.0)) - '@stylistic/eslint-plugin-ts': 4.4.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@types/lodash.merge': 4.6.9 - '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - astro-eslint-parser: 1.4.0 - eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@2.7.0)) - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) - eslint-mdx: 3.7.0(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-astro: 1.7.0(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-cypress: 5.3.0(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-jsdoc: 61.7.1(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-mdx: 3.7.0(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-n: 17.24.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint-plugin-promise: 7.3.0(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react-refresh: 0.4.26(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-rxjs: 5.0.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint-plugin-rxjs-angular: 2.0.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint-plugin-sonarjs: 3.0.7(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-svelte3: 4.0.0(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2) - eslint-plugin-tsdoc: 0.4.0 - eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint-plugin-unicorn: 61.0.2(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-vue: 10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.7.0)))(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.7.0))) - globals: 16.5.0 - lodash.merge: 4.6.2 - typescript-eslint: 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.7.0)) - transitivePeerDependencies: - - '@typescript-eslint/types' - - '@typescript-eslint/utils' - - bluebird - - eslint - - eslint-import-resolver-node - - eslint-plugin-import - - remark-lint-file-extension - - supports-color - - svelte - - typescript - - eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)): - dependencies: - eslint: 9.39.4(jiti@2.7.0) - - eslint-etc@5.2.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): - dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - tsutils: 3.21.0(typescript@5.9.3) - tsutils-etc: 1.4.2(tsutils@3.21.0(typescript@5.9.3))(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-formatter-compact@8.40.0: {} - - eslint-formatter-pretty@7.1.0: - dependencies: - '@types/eslint': 9.6.1 - ansi-escapes: 7.3.0 - chalk: 5.6.2 - eslint-rule-docs: 1.1.235 - log-symbols: 7.0.1 - plur: 5.1.0 - string-width: 8.2.1 - supports-hyperlinks: 4.4.0 - - eslint-import-context@0.1.9(unrs-resolver@1.11.1): - dependencies: - get-tsconfig: 4.14.0 - stable-hash-x: 0.2.0 - optionalDependencies: - unrs-resolver: 1.11.1 - - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): - dependencies: - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - get-tsconfig: 4.14.0 - is-bun-module: 2.0.0 - stable-hash-x: 0.2.0 - tinyglobby: 0.2.16 - unrs-resolver: 1.11.1 - optionalDependencies: - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)) - transitivePeerDependencies: - - supports-color - - eslint-mdx@3.7.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint: 9.39.4(jiti@2.7.0) - espree: 10.4.0 - estree-util-visit: 2.0.0 - remark-mdx: 3.1.1 - remark-parse: 11.0.0 - remark-stringify: 11.0.0 - synckit: 0.11.12 - unified: 11.0.5 - unified-engine: 11.2.2 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - transitivePeerDependencies: - - bluebird - - supports-color - - eslint-plugin-astro@1.7.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.59.3 - astro-eslint-parser: 1.4.0 - eslint: 9.39.4(jiti@2.7.0) - eslint-compat-utils: 0.6.5(eslint@9.39.4(jiti@2.7.0)) - globals: 16.5.0 - postcss: 8.5.14 - postcss-selector-parser: 7.1.1 - transitivePeerDependencies: - - supports-color - - eslint-plugin-cypress@5.3.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - eslint: 9.39.4(jiti@2.7.0) - globals: 16.5.0 - - eslint-plugin-es-x@7.8.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@eslint-community/regexpp': 4.12.2 - eslint: 9.39.4(jiti@2.7.0) - eslint-compat-utils: 0.5.1(eslint@9.39.4(jiti@2.7.0)) - - eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@package-json/types': 0.0.12 - '@typescript-eslint/types': 8.59.3 - comment-parser: 1.4.6 - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - is-glob: 4.0.3 - minimatch: 10.2.5 - semver: 7.8.0 - stable-hash-x: 0.2.0 - unrs-resolver: 1.11.1 - optionalDependencies: - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - transitivePeerDependencies: - - supports-color - - eslint-plugin-jsdoc@61.7.1(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@es-joy/jsdoccomment': 0.78.0 - '@es-joy/resolve.exports': 1.2.0 - are-docs-informative: 0.0.2 - comment-parser: 1.4.1 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint: 9.39.4(jiti@2.7.0) - espree: 11.2.0 - esquery: 1.7.0 - html-entities: 2.6.0 - object-deep-merge: 2.0.0 - parse-imports-exports: 0.2.4 - semver: 7.8.0 - spdx-expression-parse: 4.0.0 - to-valid-identifier: 1.0.0 - transitivePeerDependencies: - - supports-color - - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): - dependencies: - aria-query: 5.3.2 - array-includes: 3.1.9 - array.prototype.flatmap: 1.3.3 - ast-types-flow: 0.0.8 - axe-core: 4.11.4 - axobject-query: 4.1.0 - damerau-levenshtein: 1.0.8 - emoji-regex: 9.2.2 - eslint: 9.39.4(jiti@2.7.0) - hasown: 2.0.3 - jsx-ast-utils: 3.3.5 - language-tags: 1.0.9 - minimatch: 3.1.5 - object.fromentries: 2.0.8 - safe-regex-test: 1.1.0 - string.prototype.includes: 2.0.1 - - eslint-plugin-mdx@3.7.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - eslint: 9.39.4(jiti@2.7.0) - eslint-mdx: 3.7.0(eslint@9.39.4(jiti@2.7.0)) - mdast-util-from-markdown: 2.0.3 - mdast-util-mdx: 3.0.0 - micromark-extension-mdxjs: 3.0.0 - remark-mdx: 3.1.1 - remark-parse: 11.0.0 - remark-stringify: 11.0.0 - synckit: 0.11.12 - unified: 11.0.5 - vfile: 6.0.3 - transitivePeerDependencies: - - bluebird - - remark-lint-file-extension - - supports-color - - eslint-plugin-n@17.24.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - enhanced-resolve: 5.21.3 - eslint: 9.39.4(jiti@2.7.0) - eslint-plugin-es-x: 7.8.0(eslint@9.39.4(jiti@2.7.0)) - get-tsconfig: 4.14.0 - globals: 15.15.0 - globrex: 0.1.2 - ignore: 5.3.2 - semver: 7.8.0 - ts-declaration-location: 1.0.7(typescript@5.9.3) - transitivePeerDependencies: - - typescript - - eslint-plugin-promise@7.3.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - eslint: 9.39.4(jiti@2.7.0) + '@discordjs/collection@2.1.1': {} - eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + '@discordjs/core@2.4.0': dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - eslint: 9.39.4(jiti@2.7.0) - hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) + '@discordjs/rest': 2.6.1 + '@discordjs/util': 1.2.0 + '@discordjs/ws': 2.0.4 + '@sapphire/snowflake': 3.5.5 + '@vladfrangu/async_event_emitter': 2.4.7 + discord-api-types: 0.38.47 transitivePeerDependencies: - - supports-color - - eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@2.7.0)): - dependencies: - eslint: 9.39.4(jiti@2.7.0) + - bufferutil + - utf-8-validate - eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): - dependencies: - array-includes: 3.1.9 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.3 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.3.2 - eslint: 9.39.4(jiti@2.7.0) - estraverse: 5.3.0 - hasown: 2.0.3 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.5 - object.entries: 1.1.9 - object.fromentries: 2.0.8 - object.values: 1.2.1 - prop-types: 15.8.1 - resolve: 2.0.0-next.7 - semver: 6.3.1 - string.prototype.matchall: 4.0.12 - string.prototype.repeat: 1.0.0 - - eslint-plugin-rxjs-angular@2.0.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + '@discordjs/formatters@0.6.2': dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - common-tags: 1.8.2 - eslint: 9.39.4(jiti@2.7.0) - eslint-etc: 5.2.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - requireindex: 1.2.0 - tslib: 2.8.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + discord-api-types: 0.38.47 - eslint-plugin-rxjs@5.0.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + '@discordjs/rest@2.6.1': dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - common-tags: 1.8.2 - decamelize: 5.0.1 - eslint: 9.39.4(jiti@2.7.0) - eslint-etc: 5.2.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - requireindex: 1.2.0 - rxjs-report-usage: 1.0.6 + '@discordjs/collection': 2.1.1 + '@discordjs/util': 1.2.0 + '@sapphire/async-queue': 1.5.5 + '@sapphire/snowflake': 3.5.5 + '@vladfrangu/async_event_emitter': 2.4.7 + discord-api-types: 0.38.47 + magic-bytes.js: 1.13.0 tslib: 2.8.1 - tsutils: 3.21.0(typescript@5.9.3) - tsutils-etc: 1.4.2(tsutils@3.21.0(typescript@5.9.3))(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-sonarjs@3.0.7(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@eslint-community/regexpp': 4.12.2 - builtin-modules: 3.3.0 - bytes: 3.1.2 - eslint: 9.39.4(jiti@2.7.0) - functional-red-black-tree: 1.0.1 - jsx-ast-utils-x: 0.1.0 - lodash.merge: 4.6.2 - minimatch: 10.1.2 - scslre: 0.3.0 - semver: 7.7.4 - typescript: 5.9.3 - - eslint-plugin-svelte3@4.0.0(eslint@9.39.4(jiti@2.7.0))(svelte@3.59.2): - dependencies: - eslint: 9.39.4(jiti@2.7.0) - svelte: 3.59.2 - - eslint-plugin-tsdoc@0.4.0: - dependencies: - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - - eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): - dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - json-schema: 0.4.0 - natural-compare-lite: 1.4.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-unicorn@61.0.2(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@eslint/plugin-kit': 0.3.5 - change-case: 5.4.4 - ci-info: 4.4.0 - clean-regexp: 1.0.0 - core-js-compat: 3.49.0 - eslint: 9.39.4(jiti@2.7.0) - esquery: 1.7.0 - find-up-simple: 1.0.1 - globals: 16.5.0 - indent-string: 5.0.0 - is-builtin-module: 5.0.0 - jsesc: 3.1.0 - pluralize: 8.0.0 - regexp-tree: 0.1.27 - regjsparser: 0.12.0 - semver: 7.8.0 - strip-indent: 4.1.1 - - eslint-plugin-vue@10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@9.39.4(jiti@2.7.0)))(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.7.0))): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - eslint: 9.39.4(jiti@2.7.0) - natural-compare: 1.4.0 - nth-check: 2.1.1 - postcss-selector-parser: 7.1.1 - semver: 7.8.0 - vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@2.7.0)) - xml-name-validator: 4.0.0 - optionalDependencies: - '@stylistic/eslint-plugin': 5.10.0(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - - eslint-rule-docs@1.1.235: {} - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 + undici: 6.24.1 - eslint-scope@9.1.2: + '@discordjs/util@1.2.0': dependencies: - '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.9 - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint-visitor-keys@5.0.1: {} + discord-api-types: 0.38.47 - eslint@9.39.4(jiti@2.7.0): + '@discordjs/ws@1.2.3': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.7.0 + '@discordjs/collection': 2.1.1 + '@discordjs/rest': 2.6.1 + '@discordjs/util': 1.2.0 + '@sapphire/async-queue': 1.5.5 + '@types/ws': 8.18.1 + '@vladfrangu/async_event_emitter': 2.4.7 + discord-api-types: 0.38.47 + tslib: 2.8.1 + ws: 8.20.0 transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - - espree@11.2.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 5.0.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@4.3.0: {} - - estraverse@5.3.0: {} - - estree-util-is-identifier-name@3.0.0: {} - - estree-util-visit@2.0.0: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/unist': 3.0.3 - - esutils@2.0.3: {} - - exsolve@1.0.8: {} - - extend@3.0.2: {} - - fast-check@3.23.2: - dependencies: - pure-rand: 6.1.0 - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.1: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.1.2: {} - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up-simple@1.0.1: {} - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - fs.realpath@1.0.0: {} - - function-bind@1.1.2: {} - - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.3 - is-callable: 1.2.7 - - functional-red-black-tree@1.0.1: {} - - functions-have-names@1.2.3: {} - - generate-function@2.3.1: - dependencies: - is-property: 1.0.2 - - generator-function@2.0.1: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-east-asian-width@1.6.0: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.3 - math-intrinsics: 1.1.0 - - get-port-please@3.2.0: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - get-tsconfig@4.14.0: - dependencies: - resolve-pkg-maps: 1.0.0 - - giget@3.2.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@13.0.6: - dependencies: - minimatch: 10.2.5 - minipass: 7.1.3 - path-scurry: 2.0.2 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - - globals@14.0.0: {} - - globals@15.15.0: {} - - globals@16.5.0: {} - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 + - bufferutil + - utf-8-validate - globby@11.1.0: + '@discordjs/ws@2.0.4': dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - globrex@0.1.2: {} - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - grammex@3.1.12: {} - - graphmatch@1.1.1: {} - - has-bigints@1.1.0: {} - - has-flag@4.0.0: {} - - has-flag@5.0.1: {} + '@discordjs/collection': 2.1.1 + '@discordjs/rest': 2.6.1 + '@discordjs/util': 1.2.0 + '@sapphire/async-queue': 1.5.5 + '@types/ws': 8.18.1 + '@vladfrangu/async_event_emitter': 2.4.7 + discord-api-types: 0.38.47 + tslib: 2.8.1 + ws: 8.20.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate - has-property-descriptors@1.0.2: + '@electric-sql/pglite-socket@0.1.1(@electric-sql/pglite@0.4.1)': dependencies: - es-define-property: 1.0.1 + '@electric-sql/pglite': 0.4.1 - has-proto@1.2.0: + '@electric-sql/pglite-tools@0.3.1(@electric-sql/pglite@0.4.1)': dependencies: - dunder-proto: 1.0.1 + '@electric-sql/pglite': 0.4.1 - has-symbols@1.1.0: {} + '@electric-sql/pglite@0.4.1': {} - has-tostringtag@1.0.2: + '@emnapi/runtime@1.10.0': dependencies: - has-symbols: 1.1.0 + tslib: 2.8.1 + optional: true - hasown@2.0.3: + '@hono/node-server@1.19.11(hono@4.12.19)': dependencies: - function-bind: 1.1.2 + hono: 4.12.19 - hermes-estree@0.25.1: {} + '@img/colour@1.1.0': {} - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true - hono@4.12.19: {} + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true - hosted-git-info@7.0.2: - dependencies: - lru-cache: 10.4.3 + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true - html-entities@2.6.0: {} + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true - http-status-codes@2.3.0: {} + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true - ignore@5.3.2: {} + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true - ignore@6.0.2: {} + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true - ignore@7.0.5: {} + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true - import-meta-resolve@4.2.0: {} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true - imurmurhash@0.1.4: {} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true - indent-string@5.0.0: {} + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true - inherits@2.0.4: {} + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true - ini@4.1.3: {} + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.3 - side-channel: 1.1.0 + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true - irregular-plurals@3.5.0: {} + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true - is-alphabetical@2.0.1: {} + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true - is-alphanumerical@2.0.1: - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true - is-array-buffer@3.0.5: + '@img/sharp-wasm32@0.34.5': dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-arrayish@0.2.1: {} + '@emnapi/runtime': 1.10.0 + optional: true - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 + '@img/sharp-win32-arm64@0.34.5': + optional: true - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 + '@img/sharp-win32-ia32@0.34.5': + optional: true - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 + '@img/sharp-win32-x64@0.34.5': + optional: true - is-builtin-module@5.0.0: - dependencies: - builtin-modules: 5.2.0 + '@kurkle/color@0.3.4': {} - is-bun-module@2.0.0: + '@prisma/adapter-pg@7.8.0': dependencies: - semver: 7.8.0 - - is-callable@1.2.7: {} + '@prisma/driver-adapter-utils': 7.8.0 + '@types/pg': 8.20.0 + pg: 8.20.0 + postgres-array: 3.0.4 + transitivePeerDependencies: + - pg-native - is-core-module@2.16.2: - dependencies: - hasown: 2.0.3 + '@prisma/client-runtime-utils@7.8.0': {} - is-data-view@1.0.2: + '@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 + '@prisma/client-runtime-utils': 7.8.0 + optionalDependencies: + prisma: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + typescript: 5.9.3 - is-date-object@1.1.0: + '@prisma/config@7.8.0': dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 + c12: 3.3.4 + deepmerge-ts: 7.1.5 + effect: 3.20.0 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast - is-decimal@2.0.1: {} + '@prisma/debug@7.2.0': {} - is-empty@1.2.0: {} + '@prisma/debug@7.8.0': {} - is-extglob@2.1.1: {} + '@prisma/dev@0.24.3(typescript@5.9.3)': + dependencies: + '@electric-sql/pglite': 0.4.1 + '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) + '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) + '@hono/node-server': 1.19.11(hono@4.12.19) + '@prisma/get-platform': 7.2.0 + '@prisma/query-plan-executor': 7.2.0 + '@prisma/streams-local': 0.1.2 + foreground-child: 3.3.1 + get-port-please: 3.2.0 + hono: 4.12.19 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.33.4 + std-env: 3.10.0 + valibot: 1.2.0(typescript@5.9.3) + zeptomatch: 2.1.0 + transitivePeerDependencies: + - typescript - is-finalizationregistry@1.1.1: + '@prisma/driver-adapter-utils@7.8.0': dependencies: - call-bound: 1.0.4 + '@prisma/debug': 7.8.0 - is-fullwidth-code-point@3.0.0: {} + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} - is-generator-function@1.1.2: + '@prisma/engines@7.8.0': dependencies: - call-bound: 1.0.4 - generator-function: 2.0.1 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/fetch-engine': 7.8.0 + '@prisma/get-platform': 7.8.0 - is-glob@4.0.3: + '@prisma/fetch-engine@7.8.0': dependencies: - is-extglob: 2.1.1 - - is-hexadecimal@2.0.1: {} - - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/get-platform': 7.8.0 - is-number-object@1.1.1: + '@prisma/get-platform@7.2.0': dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-number@7.0.0: {} + '@prisma/debug': 7.2.0 - is-plain-obj@4.1.0: {} + '@prisma/get-platform@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 - is-property@1.0.2: {} + '@prisma/query-plan-executor@7.2.0': {} - is-regex@1.2.1: + '@prisma/streams-local@0.1.2': dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.3 - - is-set@2.0.3: {} + ajv: 8.20.0 + better-result: 2.9.2 + env-paths: 3.0.0 + proper-lockfile: 4.1.2 - is-shared-array-buffer@1.0.4: + '@prisma/studio-core@0.27.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - call-bound: 1.0.4 + '@radix-ui/react-toggle': 1.1.10(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@types/react': 19.2.14 + chart.js: 4.5.1 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + transitivePeerDependencies: + - '@types/react-dom' - is-stream@2.0.1: {} + '@radix-ui/primitive@1.1.3': {} - is-string@1.1.1: + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 + react: 19.2.5 + optionalDependencies: + '@types/react': 19.2.14 - is-symbol@1.1.1: + '@radix-ui/react-primitive@2.1.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 - is-typed-array@1.1.15: + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.5)': dependencies: - which-typed-array: 1.1.20 - - is-unicode-supported@2.1.0: {} - - is-weakmap@2.0.2: {} + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + '@types/react': 19.2.14 - is-weakref@1.1.1: + '@radix-ui/react-toggle@1.1.10(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - call-bound: 1.0.4 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 - is-weakset@2.0.4: + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - isexe@3.1.5: {} + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + '@types/react': 19.2.14 - iterator.prototype@1.1.5: - dependencies: - define-data-property: 1.1.4 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - has-symbols: 1.1.0 - set-function-name: 2.0.2 - - jackspeak@3.4.3: + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@isaacs/cliui': 8.0.2 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - jiti@2.7.0: {} - - jju@1.4.0: {} - - js-tokens@4.0.0: {} + '@types/react': 19.2.14 - js-yaml@4.1.1: + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - argparse: 2.0.1 - - jsdoc-type-pratt-parser@7.0.0: {} - - jsesc@3.0.2: {} - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-parse-even-better-errors@3.0.2: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-schema@0.4.0: {} - - json-stable-stringify-without-jsonify@1.0.1: {} + react: 19.2.5 + optionalDependencies: + '@types/react': 19.2.14 - json5@2.2.3: {} + '@sapphire/async-queue@1.5.5': {} - jsx-ast-utils-x@0.1.0: {} + '@sapphire/discord-utilities@3.5.0': + dependencies: + discord-api-types: 0.38.47 - jsx-ast-utils@3.3.5: + '@sapphire/discord-utilities@4.0.0': dependencies: - array-includes: 3.1.9 - array.prototype.flat: 1.3.3 - object.assign: 4.1.7 - object.values: 1.2.1 + discord-api-types: 0.38.47 - keyv@4.5.4: + '@sapphire/discord.js-utilities@7.3.3': dependencies: - json-buffer: 3.0.1 + '@sapphire/discord-utilities': 3.5.0 + '@sapphire/duration': 1.2.0 + '@sapphire/utilities': 3.18.2 + tslib: 2.8.1 - kleur@3.0.3: {} + '@sapphire/duration@1.2.0': {} - language-subtag-registry@0.3.23: {} + '@sapphire/framework@5.5.0': + dependencies: + '@discordjs/builders': 1.14.1 + '@sapphire/discord-utilities': 4.0.0 + '@sapphire/discord.js-utilities': 7.3.3 + '@sapphire/lexure': 1.1.12 + '@sapphire/pieces': 4.4.1 + '@sapphire/ratelimits': 2.4.11 + '@sapphire/result': 2.8.0 + '@sapphire/stopwatch': 1.5.4 + '@sapphire/utilities': 3.18.2 - language-tags@1.0.9: + '@sapphire/lexure@1.1.12': dependencies: - language-subtag-registry: 0.3.23 + '@sapphire/result': 2.8.0 - levn@0.4.1: + '@sapphire/pieces@4.4.1': dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 + '@discordjs/collection': 2.1.1 + '@sapphire/utilities': 3.18.2 + tslib: 2.8.1 - lines-and-columns@2.0.4: {} + '@sapphire/ratelimits@2.4.11': {} - load-plugin@6.0.3: - dependencies: - '@npmcli/config': 8.3.4 - import-meta-resolve: 4.2.0 - transitivePeerDependencies: - - bluebird + '@sapphire/result@2.8.0': {} - locate-path@6.0.0: + '@sapphire/shapeshift@4.0.0': dependencies: - p-locate: 5.0.0 + fast-deep-equal: 3.1.3 + lodash: 4.18.1 - lodash.merge@4.6.2: {} + '@sapphire/snowflake@3.5.3': {} - lodash.snakecase@4.1.1: {} + '@sapphire/snowflake@3.5.5': {} - lodash@4.18.1: {} + '@sapphire/stopwatch@1.5.4': + dependencies: + tslib: 2.8.1 - log-symbols@7.0.1: + '@sapphire/ts-config@5.0.3': dependencies: - is-unicode-supported: 2.1.0 - yoctocolors: 2.1.2 + tslib: 2.8.1 + typescript: 5.4.5 - long@5.3.2: {} + '@sapphire/utilities@3.18.2': {} - longest-streak@3.1.0: {} + '@standard-schema/spec@1.1.0': {} - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 + '@turbo/darwin-64@2.9.14': + optional: true - lru-cache@10.4.3: {} + '@turbo/darwin-arm64@2.9.14': + optional: true - lru-cache@11.3.6: {} + '@turbo/linux-64@2.9.14': + optional: true - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 + '@turbo/linux-arm64@2.9.14': + optional: true - lru.min@1.1.4: {} + '@turbo/windows-64@2.9.14': + optional: true - magic-bytes.js@1.13.0: {} + '@turbo/windows-arm64@2.9.14': + optional: true - math-intrinsics@1.1.0: {} + '@types/ms@2.1.0': {} - mdast-util-from-markdown@2.0.3: + '@types/node@22.19.19': dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.2 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-decode-string: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color + undici-types: 6.21.0 - mdast-util-mdx-expression@2.0.1: + '@types/node@25.8.0': dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color + undici-types: 7.24.6 - mdast-util-mdx-jsx@3.2.0: + '@types/pg@8.20.0': dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 - stringify-entities: 4.0.4 - unist-util-stringify-position: 4.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color + '@types/node': 22.19.19 + pg-protocol: 1.13.0 + pg-types: 2.2.0 - mdast-util-mdx@3.0.0: + '@types/react@19.2.14': dependencies: - mdast-util-from-markdown: 2.0.3 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color + csstype: 3.2.3 - mdast-util-mdxjs-esm@2.0.1: + '@types/sharp@0.32.0': dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color + sharp: 0.34.5 - mdast-util-phrasing@4.1.0: + '@types/ws@8.18.1': dependencies: - '@types/mdast': 4.0.4 - unist-util-is: 6.0.1 + '@types/node': 25.8.0 - mdast-util-to-markdown@2.1.2: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - longest-streak: 3.1.0 - mdast-util-phrasing: 4.1.0 - mdast-util-to-string: 4.0.0 - micromark-util-classify-character: 2.0.1 - micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.1.0 - zwitch: 2.0.4 - - mdast-util-to-string@4.0.0: + '@vladfrangu/async_event_emitter@2.4.7': {} + + ajv@8.20.0: dependencies: - '@types/mdast': 4.0.4 + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 - merge2@1.4.1: {} + ansi-regex@5.0.1: {} - micromark-core-commonmark@2.0.3: - dependencies: - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-factory-destination: 2.0.1 - micromark-factory-label: 2.0.1 - micromark-factory-space: 2.0.1 - micromark-factory-title: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-html-tag-name: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-mdx-expression@3.0.1: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - micromark-factory-mdx-expression: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-mdx-jsx@3.0.2: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - micromark-factory-mdx-expression: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - vfile-message: 4.0.3 - - micromark-extension-mdx-md@2.0.0: + ansi-styles@4.3.0: dependencies: - micromark-util-types: 2.0.2 + color-convert: 2.0.1 - micromark-extension-mdxjs-esm@3.0.0: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-position-from-estree: 2.0.0 - vfile-message: 4.0.3 - - micromark-extension-mdxjs@3.0.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - micromark-extension-mdx-expression: 3.0.1 - micromark-extension-mdx-jsx: 3.0.2 - micromark-extension-mdx-md: 2.0.0 - micromark-extension-mdxjs-esm: 3.0.0 - micromark-util-combine-extensions: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-destination@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + aws-ssl-profiles@1.1.2: {} - micromark-factory-label@2.0.1: - dependencies: - devlop: 1.1.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + balanced-match@4.0.4: {} - micromark-factory-mdx-expression@2.0.3: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-position-from-estree: 2.0.0 - vfile-message: 4.0.3 - - micromark-factory-space@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-types: 2.0.2 + better-result@2.9.2: {} - micromark-factory-title@2.0.1: + brace-expansion@5.0.6: dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + balanced-match: 4.0.4 - micromark-factory-whitespace@2.0.1: + c12@3.3.4: dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.4.2 + exsolve: 1.0.8 + giget: 3.2.0 + jiti: 2.7.0 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.1 + rc9: 3.0.1 - micromark-util-character@2.1.1: + chalk@4.1.2: dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + ansi-styles: 4.3.0 + supports-color: 7.2.0 - micromark-util-chunked@2.0.1: + chart.js@4.5.1: dependencies: - micromark-util-symbol: 2.0.1 + '@kurkle/color': 0.3.4 - micromark-util-classify-character@2.0.1: + chokidar@5.0.0: dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + readdirp: 5.0.0 - micromark-util-combine-extensions@2.0.1: + cliui@8.0.1: dependencies: - micromark-util-chunked: 2.0.1 - micromark-util-types: 2.0.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 - micromark-util-decode-numeric-character-reference@2.0.2: + color-convert@2.0.1: dependencies: - micromark-util-symbol: 2.0.1 + color-name: 1.1.4 + + color-name@1.1.4: {} - micromark-util-decode-string@2.0.1: + concurrently@9.2.1: dependencies: - decode-named-character-reference: 1.3.0 - micromark-util-character: 2.1.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-symbol: 2.0.1 + chalk: 4.1.2 + rxjs: 7.8.2 + shell-quote: 1.8.3 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 - micromark-util-encode@2.0.1: {} + confbox@0.2.4: {} - micromark-util-events-to-acorn@2.0.3: + cross-spawn@7.0.6: dependencies: - '@types/estree': 1.0.9 - '@types/unist': 3.0.3 - devlop: 1.1.0 - estree-util-visit: 2.0.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - vfile-message: 4.0.3 + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 - micromark-util-html-tag-name@2.0.1: {} + csstype@3.2.3: {} - micromark-util-normalize-identifier@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 + deepmerge-ts@7.1.5: {} - micromark-util-resolve-all@2.0.1: - dependencies: - micromark-util-types: 2.0.2 + defu@6.1.7: {} - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 + denque@2.1.0: {} - micromark-util-subtokenize@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + destr@2.0.5: {} - micromark-util-symbol@2.0.1: {} + detect-libc@2.1.2: {} - micromark-util-types@2.0.2: {} + discord-api-types@0.38.47: {} - micromark@4.0.2: + discord.js@14.26.4: dependencies: - '@types/debug': 4.1.13 - debug: 4.4.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-combine-extensions: 2.0.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-encode: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + '@discordjs/builders': 1.14.1 + '@discordjs/collection': 1.5.3 + '@discordjs/formatters': 0.6.2 + '@discordjs/rest': 2.6.1 + '@discordjs/util': 1.2.0 + '@discordjs/ws': 1.2.3 + '@sapphire/snowflake': 3.5.3 + discord-api-types: 0.38.47 + fast-deep-equal: 3.1.3 + lodash.snakecase: 4.1.1 + magic-bytes.js: 1.13.0 + tslib: 2.8.1 + undici: 6.24.1 transitivePeerDependencies: - - supports-color + - bufferutil + - utf-8-validate - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 + dotenv@17.4.2: {} - minimatch@10.1.2: + effect@3.20.0: dependencies: - '@isaacs/brace-expansion': 5.0.1 + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.6 + emoji-regex@8.0.0: {} - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 + empathic@2.0.0: {} - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.0 + env-paths@3.0.0: {} - minipass@7.1.3: {} + escalade@3.2.0: {} - ms@2.1.3: {} + exsolve@1.0.8: {} - mysql2@3.15.3: + fast-check@3.23.2: dependencies: - aws-ssl-profiles: 1.1.2 - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.7.2 - long: 5.3.2 - lru.min: 1.1.4 - named-placeholders: 1.1.6 - seq-queue: 0.0.5 - sqlstring: 2.3.3 + pure-rand: 6.1.0 - named-placeholders@1.1.6: - dependencies: - lru.min: 1.1.4 + fast-deep-equal@3.1.3: {} - nanoid@3.3.12: {} + fast-uri@3.1.2: {} - napi-postinstall@0.3.4: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 - natural-compare-lite@1.4.0: {} + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 - natural-compare@1.4.0: {} + get-caller-file@2.0.5: {} - node-exports-info@1.6.0: - dependencies: - array.prototype.flatmap: 1.3.3 - es-errors: 1.3.0 - object.entries: 1.1.9 - semver: 6.3.1 + get-port-please@3.2.0: {} - node-releases@2.0.44: {} + giget@3.2.0: {} - nopt@7.2.1: + glob@13.0.6: dependencies: - abbrev: 2.0.0 + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 - normalize-package-data@6.0.2: - dependencies: - hosted-git-info: 7.0.2 - semver: 7.8.0 - validate-npm-package-license: 3.0.4 + graceful-fs@4.2.11: {} - npm-install-checks@6.3.0: - dependencies: - semver: 7.8.0 + grammex@3.1.12: {} - npm-normalize-package-bin@3.0.1: {} + graphmatch@1.1.1: {} - npm-package-arg@11.0.3: - dependencies: - hosted-git-info: 7.0.2 - proc-log: 4.2.0 - semver: 7.8.0 - validate-npm-package-name: 5.0.1 + has-flag@4.0.0: {} - npm-pick-manifest@9.1.0: - dependencies: - npm-install-checks: 6.3.0 - npm-normalize-package-bin: 3.0.1 - npm-package-arg: 11.0.3 - semver: 7.8.0 + hono@4.12.19: {} + + http-status-codes@2.3.0: {} - nth-check@2.1.1: + iconv-lite@0.7.2: dependencies: - boolbase: 1.0.0 + safer-buffer: 2.1.2 - object-assign@4.1.1: {} + is-fullwidth-code-point@3.0.0: {} - object-deep-merge@2.0.0: {} + is-property@1.0.2: {} - object-inspect@1.13.4: {} + isexe@2.0.0: {} - object-keys@1.1.1: {} + jiti@2.7.0: {} - object.assign@4.1.7: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - object.entries@1.1.9: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 + json-schema-traverse@1.0.0: {} - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + lodash.snakecase@4.1.1: {} - object.values@1.2.1: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 + lodash@4.18.1: {} - ohash@2.0.11: {} + long@5.3.2: {} - once@1.4.0: - dependencies: - wrappy: 1.0.2 + lru-cache@11.3.6: {} - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 + lru.min@1.1.4: {} - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 + magic-bytes.js@1.13.0: {} - p-locate@5.0.0: + minimatch@10.2.5: dependencies: - p-limit: 3.1.0 + brace-expansion: 5.0.6 - package-json-from-dist@1.0.1: {} + minipass@7.1.3: {} - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 + ms@2.1.3: {} - parse-entities@4.0.2: - dependencies: - '@types/unist': 2.0.11 - character-entities-legacy: 3.0.0 - character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.3.0 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - is-hexadecimal: 2.0.1 - - parse-imports-exports@0.2.4: + mysql2@3.15.3: dependencies: - parse-statements: 1.0.11 + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + seq-queue: 0.0.5 + sqlstring: 2.3.3 - parse-json@7.1.1: + named-placeholders@1.1.6: dependencies: - '@babel/code-frame': 7.29.0 - error-ex: 1.3.4 - json-parse-even-better-errors: 3.0.2 - lines-and-columns: 2.0.4 - type-fest: 3.13.1 - - parse-statements@1.0.11: {} + lru.min: 1.1.4 - path-exists@4.0.0: {} + ohash@2.0.11: {} - path-is-absolute@1.0.1: {} + package-json-from-dist@1.0.1: {} path-key@3.1.1: {} - path-parse@1.0.7: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - path-scurry@2.0.2: dependencies: lru-cache: 11.3.6 minipass: 7.1.3 - path-type@4.0.0: {} - pathe@2.0.3: {} perfect-debounce@2.1.0: {} @@ -6805,37 +1824,12 @@ snapshots: dependencies: split2: 4.2.0 - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - pkg-types@2.3.1: dependencies: confbox: 0.2.4 exsolve: 1.0.8 pathe: 2.0.3 - plur@5.1.0: - dependencies: - irregular-plurals: 3.5.0 - - pluralize@8.0.0: {} - - possible-typed-array-names@1.1.0: {} - - postcss-selector-parser@7.1.1: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss@8.5.14: - dependencies: - nanoid: 3.3.12 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postgres-array@2.0.0: {} postgres-array@3.0.4: {} @@ -6850,8 +1844,6 @@ snapshots: postgres@3.4.7: {} - prelude-ls@1.2.1: {} - prettier@3.8.3: {} prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): @@ -6871,38 +1863,14 @@ snapshots: - react - react-dom - proc-log@4.2.0: {} - - promise-inflight@1.0.1: {} - - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - proper-lockfile@4.1.2: dependencies: graceful-fs: 4.2.11 retry: 0.12.0 signal-exit: 3.0.7 - punycode@2.3.1: {} - pure-rand@6.1.0: {} - queue-microtask@1.2.3: {} - rc9@3.0.1: dependencies: defu: 6.1.7 @@ -6913,200 +1881,35 @@ snapshots: react: 19.2.5 scheduler: 0.27.0 - react-is@16.13.1: {} - react@19.2.5: {} - read-package-json-fast@3.0.2: - dependencies: - json-parse-even-better-errors: 3.0.2 - npm-normalize-package-bin: 3.0.1 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - readdirp@5.0.0: {} - refa@0.12.1: - dependencies: - '@eslint-community/regexpp': 4.12.2 - - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regexp-ast-analysis@0.7.1: - dependencies: - '@eslint-community/regexpp': 4.12.2 - refa: 0.12.1 - - regexp-tree@0.1.27: {} - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - - regjsparser@0.12.0: - dependencies: - jsesc: 3.0.2 - - remark-mdx@3.1.1: - dependencies: - mdast-util-mdx: 3.0.0 - micromark-extension-mdxjs: 3.0.0 - transitivePeerDependencies: - - supports-color - - remark-parse@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 - micromark-util-types: 2.0.2 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-stringify@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-to-markdown: 2.1.2 - unified: 11.0.5 - remeda@2.33.4: {} require-directory@2.1.1: {} require-from-string@2.0.2: {} - requireindex@1.2.0: {} - - reserved-identifiers@1.2.0: {} - - resolve-from@4.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - resolve@1.22.12: - dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - resolve@2.0.0-next.7: - dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - node-exports-info: 1.6.0 - object-keys: 1.1.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - retry@0.12.0: {} - reusify@1.1.0: {} - rimraf@6.1.3: dependencies: glob: 13.0.6 package-json-from-dist: 1.0.1 - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - rxjs-report-usage@1.0.6: - dependencies: - '@babel/parser': 7.29.3 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - bent: 7.3.12 - chalk: 4.1.2 - glob: 7.2.3 - prompts: 2.4.2 - transitivePeerDependencies: - - supports-color - rxjs@7.8.2: dependencies: tslib: 2.8.1 - safe-array-concat@1.1.4: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 - - safe-buffer@5.2.1: {} - - safe-push-apply@1.0.0: - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - safer-buffer@2.1.2: {} scheduler@0.27.0: {} - scslre@0.3.0: - dependencies: - '@eslint-community/regexpp': 4.12.2 - refa: 0.12.1 - regexp-ast-analysis: 0.7.1 - - semver@6.3.1: {} - - semver@7.7.4: {} - semver@7.8.0: {} seq-queue@0.0.5: {} - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - sharp@0.34.5: dependencies: '@img/colour': 1.1.0 @@ -7146,172 +1949,26 @@ snapshots: shell-quote@1.8.3: {} - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - signal-exit@3.0.7: {} signal-exit@4.1.0: {} - sisteransi@1.0.5: {} - - slash@3.0.0: {} - - source-map-js@1.2.1: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.23 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.23 - - spdx-expression-parse@4.0.0: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.23 - - spdx-license-ids@3.0.23: {} - split2@4.2.0: {} sqlstring@2.3.3: {} - stable-hash-x@0.2.0: {} - std-env@3.10.0: {} - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 - - string-width@6.1.0: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 10.6.0 - strip-ansi: 7.2.0 - - string-width@8.2.1: - dependencies: - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 - - string.prototype.includes@2.0.1: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - - string.prototype.matchall@4.0.12: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-symbols: 1.1.0 - internal-slot: 1.1.0 - regexp.prototype.flags: 1.5.4 - set-function-name: 2.0.2 - side-channel: 1.1.0 - - string.prototype.repeat@1.0.0: - dependencies: - define-properties: 1.2.1 - es-abstract: 1.24.2 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-indent@4.1.1: {} - - strip-json-comments@3.1.1: {} - - supports-color@10.2.2: {} - supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -7320,68 +1977,12 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-color@9.4.0: {} - - supports-hyperlinks@4.4.0: - dependencies: - has-flag: 5.0.1 - supports-color: 10.2.2 - - supports-preserve-symlinks-flag@1.0.0: {} - - svelte@3.59.2: {} - - synckit@0.11.12: - dependencies: - '@pkgr/core': 0.2.9 - - tapable@2.3.3: {} - - tinyglobby@0.2.16: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - to-valid-identifier@1.0.0: - dependencies: - '@sindresorhus/base62': 1.0.0 - reserved-identifiers: 1.2.0 - tree-kill@1.2.2: {} - trough@2.2.0: {} - - ts-api-utils@2.5.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - ts-declaration-location@1.0.7(typescript@5.9.3): - dependencies: - picomatch: 4.0.4 - typescript: 5.9.3 - ts-mixer@6.0.4: {} - tslib@1.14.1: {} - tslib@2.8.1: {} - tsutils-etc@1.4.2(tsutils@3.21.0(typescript@5.9.3))(typescript@5.9.3): - dependencies: - '@types/yargs': 17.0.35 - tsutils: 3.21.0(typescript@5.9.3) - typescript: 5.9.3 - yargs: 17.7.2 - - tsutils@3.21.0(typescript@5.9.3): - dependencies: - tslib: 1.14.1 - typescript: 5.9.3 - turbo@2.9.14: optionalDependencies: '@turbo/darwin-64': 2.9.14 @@ -7391,310 +1992,38 @@ snapshots: '@turbo/windows-64': 2.9.14 '@turbo/windows-arm64': 2.9.14 - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@3.13.1: {} - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.9 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.9 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.9 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - - typedarray@0.0.6: {} - - typescript-eslint@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - typescript@5.4.5: {} typescript@5.9.3: {} - unbox-primitive@1.1.0: - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - undici-types@6.21.0: {} undici-types@7.24.6: {} undici@6.24.1: {} - unified-engine@11.2.2: - dependencies: - '@types/concat-stream': 2.0.3 - '@types/debug': 4.1.13 - '@types/is-empty': 1.2.3 - '@types/node': 22.19.19 - '@types/unist': 3.0.3 - concat-stream: 2.0.0 - debug: 4.4.3 - extend: 3.0.2 - glob: 10.5.0 - ignore: 6.0.2 - is-empty: 1.2.0 - is-plain-obj: 4.1.0 - load-plugin: 6.0.3 - parse-json: 7.1.1 - trough: 2.2.0 - unist-util-inspect: 8.1.0 - vfile: 6.0.3 - vfile-message: 4.0.3 - vfile-reporter: 8.1.1 - vfile-statistics: 3.0.0 - yaml: 2.9.0 - transitivePeerDependencies: - - bluebird - - supports-color - - unified@11.0.5: - dependencies: - '@types/unist': 3.0.3 - bail: 2.0.2 - devlop: 1.1.0 - extend: 3.0.2 - is-plain-obj: 4.1.0 - trough: 2.2.0 - vfile: 6.0.3 - - unist-util-inspect@8.1.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position-from-estree@2.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.1.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - unrs-resolver@1.11.1: - dependencies: - napi-postinstall: 0.3.4 - optionalDependencies: - '@unrs/resolver-binding-android-arm-eabi': 1.11.1 - '@unrs/resolver-binding-android-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-x64': 1.11.1 - '@unrs/resolver-binding-freebsd-x64': 1.11.1 - '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 - '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 - '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-musl': 1.11.1 - '@unrs/resolver-binding-wasm32-wasi': 1.11.1 - '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 - '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 - '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - util-deprecate@1.0.2: {} - valibot@1.2.0(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - validate-npm-package-name@5.0.1: {} - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile-reporter@8.1.1: - dependencies: - '@types/supports-color': 8.1.3 - string-width: 6.1.0 - supports-color: 9.4.0 - unist-util-stringify-position: 4.0.0 - vfile: 6.0.3 - vfile-message: 4.0.3 - vfile-sort: 4.0.0 - vfile-statistics: 3.0.0 - - vfile-sort@4.0.0: - dependencies: - vfile: 6.0.3 - vfile-message: 4.0.3 - - vfile-statistics@3.0.0: - dependencies: - vfile: 6.0.3 - vfile-message: 4.0.3 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.7.0)): - dependencies: - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - espree: 11.2.0 - esquery: 1.7.0 - semver: 7.8.0 - transitivePeerDependencies: - - supports-color - - walk-up-path@3.0.1: {} - - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.2 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.20 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-typed-array@1.1.20: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.9 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@2.0.2: dependencies: isexe: 2.0.0 - which@4.0.0: - dependencies: - isexe: 3.1.5 - - word-wrap@1.2.5: {} - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - - wrappy@1.0.2: {} - ws@8.20.0: {} ws@8.20.1: {} - xml-name-validator@4.0.0: {} - xtend@4.0.2: {} y18n@5.0.8: {} - yallist@3.1.1: {} - - yaml@2.9.0: {} - yargs-parser@21.1.1: {} yargs@17.7.2: @@ -7707,19 +2036,9 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yocto-queue@0.1.0: {} - - yoctocolors@2.1.2: {} - zeptomatch@2.1.0: dependencies: grammex: 3.1.12 graphmatch: 1.1.1 - zod-validation-error@4.0.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - zod@4.4.3: {} - - zwitch@2.0.4: {} From efc0219d3ba3173d295dd68684b1cc66d6c05329 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 21:37:11 +0200 Subject: [PATCH 11/50] chore: add dependabot config --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..def5cdf --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + groups: + dependencies: + update-types: + - "minor" + - "patch" From ee05d09a773f01f156cf7cf40644d1db7a6e871b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 19:45:13 +0000 Subject: [PATCH 12/50] chore(deps-dev): bump typescript from 5.9.3 to 6.0.3 Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 6.0.3. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.9.3...v6.0.3) --- updated-dependencies: - dependency-name: typescript dependency-version: 6.0.3 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- apps/bot/package.json | 2 +- pnpm-lock.yaml | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index 32b4c41..e3ce216 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -34,7 +34,7 @@ "concurrently": "^9.2.1", "prettier": "^3.8.3", "rimraf": "^6.1.3", - "typescript": "~5.9.3" + "typescript": "~6.0.3" }, "engines": { "node": ">=22.12.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddd0569..b603e7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,7 +26,7 @@ importers: version: 7.8.0 '@prisma/client': specifier: ^7.8.0 - version: 7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3) + version: 7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3) '@sapphire/framework': specifier: ^5.5.0 version: 5.5.0 @@ -44,7 +44,7 @@ importers: version: 2.1.3 prisma: specifier: ^7.8.0 - version: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3) sharp: specifier: ^0.34.5 version: 0.34.5 @@ -71,8 +71,8 @@ importers: specifier: ^6.1.3 version: 6.1.3 typescript: - specifier: ~5.9.3 - version: 5.9.3 + specifier: ~6.0.3 + version: 6.0.3 packages: @@ -1012,8 +1012,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true @@ -1296,12 +1296,12 @@ snapshots: '@prisma/client-runtime-utils@7.8.0': {} - '@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client@7.8.0(prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3)': dependencies: '@prisma/client-runtime-utils': 7.8.0 optionalDependencies: - prisma: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - typescript: 5.9.3 + prisma: 7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3) + typescript: 6.0.3 '@prisma/config@7.8.0': dependencies: @@ -1316,7 +1316,7 @@ snapshots: '@prisma/debug@7.8.0': {} - '@prisma/dev@0.24.3(typescript@5.9.3)': + '@prisma/dev@0.24.3(typescript@6.0.3)': dependencies: '@electric-sql/pglite': 0.4.1 '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) @@ -1333,7 +1333,7 @@ snapshots: proper-lockfile: 4.1.2 remeda: 2.33.4 std-env: 3.10.0 - valibot: 1.2.0(typescript@5.9.3) + valibot: 1.2.0(typescript@6.0.3) zeptomatch: 2.1.0 transitivePeerDependencies: - typescript @@ -1846,16 +1846,16 @@ snapshots: prettier@3.8.3: {} - prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + prisma@7.8.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3): dependencies: '@prisma/config': 7.8.0 - '@prisma/dev': 0.24.3(typescript@5.9.3) + '@prisma/dev': 0.24.3(typescript@6.0.3) '@prisma/engines': 7.8.0 '@prisma/studio-core': 0.27.3(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) mysql2: 3.15.3 postgres: 3.4.7 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -1994,7 +1994,7 @@ snapshots: typescript@5.4.5: {} - typescript@5.9.3: {} + typescript@6.0.3: {} undici-types@6.21.0: {} @@ -2002,9 +2002,9 @@ snapshots: undici@6.24.1: {} - valibot@1.2.0(typescript@5.9.3): + valibot@1.2.0(typescript@6.0.3): optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 which@2.0.2: dependencies: From 1073e7ee427e5d022d3648dc8f013cc4eb36c59e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 19:45:40 +0000 Subject: [PATCH 13/50] chore(deps-dev): bump @types/node from 22.19.19 to 25.8.0 Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.19 to 25.8.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.8.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- apps/bot/package.json | 2 +- pnpm-lock.yaml | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index 32b4c41..8a30071 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@sapphire/ts-config": "^5.0.3", - "@types/node": "^22.19.19", + "@types/node": "^25.8.0", "@types/sharp": "^0.32.0", "concurrently": "^9.2.1", "prettier": "^3.8.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddd0569..a502f40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,8 +56,8 @@ importers: specifier: ^5.0.3 version: 5.0.3 '@types/node': - specifier: ^22.19.19 - version: 22.19.19 + specifier: ^25.8.0 + version: 25.8.0 '@types/sharp': specifier: ^0.32.0 version: 0.32.0 @@ -528,9 +528,6 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@22.19.19': - resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} - '@types/node@25.8.0': resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} @@ -1017,9 +1014,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} @@ -1525,17 +1519,13 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@22.19.19': - dependencies: - undici-types: 6.21.0 - '@types/node@25.8.0': dependencies: undici-types: 7.24.6 '@types/pg@8.20.0': dependencies: - '@types/node': 22.19.19 + '@types/node': 25.8.0 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -1996,8 +1986,6 @@ snapshots: typescript@5.9.3: {} - undici-types@6.21.0: {} - undici-types@7.24.6: {} undici@6.24.1: {} From 71d943b1a0fc1644088bb68c3c40e1b5a8a6752b Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 21:45:44 +0200 Subject: [PATCH 14/50] fix: security patch --- apps/bot/src/commands/moderation/autorole/autorole.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/bot/src/commands/moderation/autorole/autorole.ts b/apps/bot/src/commands/moderation/autorole/autorole.ts index 022fec8..fd879e0 100644 --- a/apps/bot/src/commands/moderation/autorole/autorole.ts +++ b/apps/bot/src/commands/moderation/autorole/autorole.ts @@ -1,5 +1,5 @@ import { Command } from '@sapphire/framework'; -import { MessageFlags } from 'discord.js'; +import { MessageFlags, PermissionsBitField } from 'discord.js'; import { createAutoRole, getAutoRole, getAutoRoles, removeAutoRole } from '#lib/autorole.js'; import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js'; import { emojis } from '#utils/emoji.js'; @@ -71,6 +71,14 @@ export class AutoRoleCommand extends Command { return; } + if (!interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to manage auto roles.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + const subcommand = interaction.options.getSubcommand(); if (subcommand === 'add') { From 520f9756df75264b587d3190b9117809804253fe Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 22:16:34 +0200 Subject: [PATCH 15/50] fix: security vuln --- .github/workflows/deploy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index d267227..25d87a8 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -17,6 +17,7 @@ jobs: if: > (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') || (github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && github.event.workflow_run.head_branch == 'main') steps: - name: Check out repository From cfa9e204a88263680bbb46f8ccd3a87d945cb81c Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 22:39:12 +0200 Subject: [PATCH 16/50] fix(autorole): security vuln --- .../commands/moderation/autorole/autorole.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/bot/src/commands/moderation/autorole/autorole.ts b/apps/bot/src/commands/moderation/autorole/autorole.ts index fd879e0..8a3f8d2 100644 --- a/apps/bot/src/commands/moderation/autorole/autorole.ts +++ b/apps/bot/src/commands/moderation/autorole/autorole.ts @@ -1,5 +1,5 @@ import { Command } from '@sapphire/framework'; -import { MessageFlags, PermissionsBitField } from 'discord.js'; +import { MessageFlags, PermissionFlagsBits } from 'discord.js'; import { createAutoRole, getAutoRole, getAutoRoles, removeAutoRole } from '#lib/autorole.js'; import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js'; import { emojis } from '#utils/emoji.js'; @@ -14,6 +14,7 @@ export class AutoRoleCommand extends Command { builder .setName('autorole') .setDescription('Automatically assign roles to new members!') + .setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles) .addSubcommand((sub: any) => sub .setName('add') @@ -71,20 +72,28 @@ export class AutoRoleCommand extends Command { return; } - if (!interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) { - await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage auto roles.`, - flags: MessageFlags.Ephemeral, - }); - return; - } - const subcommand = interaction.options.getSubcommand(); if (subcommand === 'add') { const role = interaction.options.getRole('role', true); const botRole = interaction.options.getBoolean('bot_role', true); + if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles)) { + await interaction.reply({ + content: `${emojis.rightArrow2} You do not have permission to configure auto roles.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + if (interaction.member.roles.highest.position <= role.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You can only configure auto roles for roles below your highest role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + try { await createAutoRole( interaction.guildId, @@ -128,7 +137,7 @@ export class AutoRoleCommand extends Command { const autoRoleId = interaction.options.getString('role', true); const autoRole = await getAutoRole(autoRoleId); - if (!autoRole) { + if (!autoRole || autoRole.guildId !== interaction.guildId) { await interaction.reply({ content: `${emojis.rightArrow2} That auto role no longer exists.`, flags: MessageFlags.Ephemeral, From c89fbd44fbd0d035005be4e4b6299021e2525895 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 22:41:03 +0200 Subject: [PATCH 17/50] fix: security vulns --- apps/bot/src/commands/utility/reminder/reminder.ts | 1 + .../bot/src/interaction-handlers/ticket/createTicketHandler.ts | 3 +++ apps/bot/src/lib/reminderEvent.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/apps/bot/src/commands/utility/reminder/reminder.ts b/apps/bot/src/commands/utility/reminder/reminder.ts index 18a8fd0..80846ba 100644 --- a/apps/bot/src/commands/utility/reminder/reminder.ts +++ b/apps/bot/src/commands/utility/reminder/reminder.ts @@ -76,6 +76,7 @@ export class ReminderCommand extends Command { const unix = Math.floor(remindAt.getTime() / 1000); await interaction.reply({ content: `${emojis.rightArrow2} Reminder set to go off in message: ${message}\nID: \`${reminder.id}\``, + allowedMentions: { parse: [] }, }); setTimeout(() => { diff --git a/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts b/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts index b20925c..c5a8c27 100644 --- a/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts +++ b/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts @@ -153,6 +153,9 @@ export class ButtonHandler extends InteractionHandler { await channel.send({ content: `${staffMention}<@${interaction.user.id}>, your ticket has been created!\n**Reason:** ${reason}`, components: [closeRow], + allowedMentions: { + users: [interaction.user.id], + }, }); } } diff --git a/apps/bot/src/lib/reminderEvent.ts b/apps/bot/src/lib/reminderEvent.ts index dbeb374..d07a6cf 100644 --- a/apps/bot/src/lib/reminderEvent.ts +++ b/apps/bot/src/lib/reminderEvent.ts @@ -25,6 +25,7 @@ export function reminderScheduler(client: Client) { if (channel?.isSendable()) { await channel.send({ content: `${emojis.rightArrow2} <@${reminder.userId}> reminder: ${reminder.message ?? 'No message provided'}`, + allowedMentions: { users: [reminder.userId] }, }); sent = true; } @@ -53,6 +54,7 @@ async function dmUser(client: Client, userId: string, message: string) { await user .send({ content: `${emojis.rightArrow2} <@${userId}> reminder: ${message}`, + allowedMentions: { users: [userId] }, }) .catch(() => {}); } From 5d69beabfcbac4b3dfb64a2a771db0c4b3c91259 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 23:06:47 +0200 Subject: [PATCH 18/50] style: update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index f4d91d6..2c5f74f 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,12 @@ Feel free to open a pull request! Just make sure to follow the guidelines at [CO 5. Run the development server with `pnpm dev` 6. The bot will register commands automatically on startup. +# Security + +Quest Bot undergoes frequent security audits that help it stay safe! + +If you ever find a security vulnerabitity, do not hesitate to make a report! We are more than happy to review it. + # License This project is licensed under the Affero GNU General Public License v3.0 (AGPL-3.0). See LICENSE for more details. From 799705ad5967ca1837ec60dfe29b8884d732e8bf Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 23:42:49 +0200 Subject: [PATCH 19/50] fix: setting perm --- apps/bot/src/commands/utility/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/src/commands/utility/settings.ts b/apps/bot/src/commands/utility/settings.ts index a371194..febd4b5 100644 --- a/apps/bot/src/commands/utility/settings.ts +++ b/apps/bot/src/commands/utility/settings.ts @@ -218,7 +218,7 @@ export class SettingsCommand extends Command { builder .setName('settings') .setDescription("Configure the bot's settings for this server.") - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) .setContexts(InteractionContextType.Guild), ); } From 7bd1c913295358c773ef7eaf830bb8e803ea3729 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Sun, 17 May 2026 23:55:00 +0200 Subject: [PATCH 20/50] fix: ping on reason --- apps/bot/src/commands/moderation/ban/ban.ts | 3 +++ apps/bot/src/commands/moderation/kick.ts | 3 +++ apps/bot/src/commands/moderation/mute/mute.ts | 2 ++ apps/bot/src/commands/moderation/mute/unmute.ts | 3 +++ apps/bot/src/commands/moderation/warn/warn.ts | 3 +++ 5 files changed, 14 insertions(+) diff --git a/apps/bot/src/commands/moderation/ban/ban.ts b/apps/bot/src/commands/moderation/ban/ban.ts index a699f0b..f16c8cf 100644 --- a/apps/bot/src/commands/moderation/ban/ban.ts +++ b/apps/bot/src/commands/moderation/ban/ban.ts @@ -97,6 +97,7 @@ export class BanCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to ban <@${targetMember.id}> for reason: ${reason}?`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [row], withResponse: true, }); @@ -129,12 +130,14 @@ export class BanCommand extends Command { .catch(() => {}); await confirmation.update({ content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been banned with reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } catch (err) { console.error(err); await confirmation.update({ content: `${emojis.rightArrow2} Failed to ban <@${targetMember.user.id}> with reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } diff --git a/apps/bot/src/commands/moderation/kick.ts b/apps/bot/src/commands/moderation/kick.ts index 3f0513c..b8c2853 100644 --- a/apps/bot/src/commands/moderation/kick.ts +++ b/apps/bot/src/commands/moderation/kick.ts @@ -88,6 +88,7 @@ export class KickCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to kick <@${targetMember.user.id}> with reason: ${reason}?`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [row], withResponse: true, }); @@ -115,12 +116,14 @@ export class KickCommand extends Command { .catch(() => {}); await confirmation.update({ content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been kicked with reason: ${reason}\nYou must have had a real ick towards that person.`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } catch (err) { console.error(err); await confirmation.update({ content: `${emojis.rightArrow2} Failed to kick <@${targetMember.user.id}> with reason: ${reason}\nYou must have had a real ick towards that person.`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } diff --git a/apps/bot/src/commands/moderation/mute/mute.ts b/apps/bot/src/commands/moderation/mute/mute.ts index d8960de..b30f271 100644 --- a/apps/bot/src/commands/moderation/mute/mute.ts +++ b/apps/bot/src/commands/moderation/mute/mute.ts @@ -102,6 +102,7 @@ export class MuteCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to mute <@${targetMember.user.id}> with reason: ${reason}?`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [row], withResponse: true, }); @@ -137,6 +138,7 @@ export class MuteCommand extends Command { content: `${emojis.rightArrow2} <@${targetMember.user.id}> has been muted with reason: ${reason}${ expiresAt ? `\nExpires: ` : '' }`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } else if (confirmation.customId === 'cancel') { diff --git a/apps/bot/src/commands/moderation/mute/unmute.ts b/apps/bot/src/commands/moderation/mute/unmute.ts index 3788ce7..1ed3b9f 100644 --- a/apps/bot/src/commands/moderation/mute/unmute.ts +++ b/apps/bot/src/commands/moderation/mute/unmute.ts @@ -73,6 +73,7 @@ export class UnmuteCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to unmute <@${targetMember.user.id}> with reason: ${reason}?`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [row], withResponse: true, }); @@ -100,12 +101,14 @@ export class UnmuteCommand extends Command { .catch(() => {}); await confirmation.update({ content: `${emojis.rightArrow2} <@${targetMember.id}> has been unmuted. Reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } catch (err) { console.error(err); await confirmation.update({ content: `${emojis.rightArrow2} Failed to unmute <@${targetMember.id}> with reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } diff --git a/apps/bot/src/commands/moderation/warn/warn.ts b/apps/bot/src/commands/moderation/warn/warn.ts index b13d5d7..0a1dc79 100644 --- a/apps/bot/src/commands/moderation/warn/warn.ts +++ b/apps/bot/src/commands/moderation/warn/warn.ts @@ -105,6 +105,7 @@ export class WarnCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to warn <@${targetMember.user.id}> with reason: ${reason}?`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [row], withResponse: true, }); @@ -163,12 +164,14 @@ export class WarnCommand extends Command { await logEmbed(interaction.guild, embed); await confirmation.update({ content: `${emojis.rightArrow2} <@${targetMember.id}> has been warned with reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } catch (err) { console.error(err); await confirmation.update({ content: `${emojis.rightArrow2} Failed to warn <@${targetMember.id}>`, + allowedMentions: { parse: [], users: [targetMember.user.id] }, components: [], }); } From 135d2a6dcb57b4146eaa621cf48f863772d99ffa Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 08:16:05 +0200 Subject: [PATCH 21/50] refactor(confessions): remove dead create-confession button handler --- .../confession/confessionHandler.ts | 83 ------------------- 1 file changed, 83 deletions(-) diff --git a/apps/bot/src/interaction-handlers/confession/confessionHandler.ts b/apps/bot/src/interaction-handlers/confession/confessionHandler.ts index 91359a4..11cfa10 100644 --- a/apps/bot/src/interaction-handlers/confession/confessionHandler.ts +++ b/apps/bot/src/interaction-handlers/confession/confessionHandler.ts @@ -7,7 +7,6 @@ import { LabelBuilder, MessageFlags, ModalBuilder, - TextChannel, TextInputBuilder, TextInputStyle, type ButtonInteraction, @@ -17,9 +16,7 @@ import { buildConfessionLink, getConfessionContext, removeConfessionContext, - storeConfessionContext, } from '#lib/confessions.js'; -import { getSettings } from '#lib/settings.js'; import { emojis } from '#utils/emoji.js'; interface ParsedConfessionButton { @@ -88,7 +85,6 @@ export class ConfessionButtonHandler extends InteractionHandler { public override parse(interaction: ButtonInteraction) { if ( - interaction.customId !== 'create-confession' && !interaction.customId.startsWith('report-confession:') && !interaction.customId.startsWith('delete-confession:') ) { @@ -99,11 +95,6 @@ export class ConfessionButtonHandler extends InteractionHandler { } public async run(interaction: ButtonInteraction) { - if (interaction.customId === 'create-confession') { - await this.handleCreateConfession(interaction); - return; - } - const parsed = parseConfessionButton(interaction.customId); if (parsed.action === 'report-confession') { @@ -116,80 +107,6 @@ export class ConfessionButtonHandler extends InteractionHandler { } } - private async handleCreateConfession(interaction: ButtonInteraction) { - if (!interaction.inGuild() || !interaction.guild) { - await interaction.reply({ - content: `${emojis.rightArrow2} This button can only be used in a server.`, - flags: MessageFlags.Ephemeral, - }); - return; - } - - const settings = await getSettings(interaction.guild.id, interaction.guild.name); - - if (!settings.confessionChannelId) { - await interaction.reply({ - content: `${emojis.rightArrow2} Confessions are not configured yet.`, - flags: MessageFlags.Ephemeral, - }); - return; - } - - const modal = createTextInputModal('create-confession-modal', 'Create Confession', 'confession-text', 'Confession'); - await interaction.showModal(modal); - - try { - const modalSubmit = await interaction.awaitModalSubmit({ - filter: (modal) => modal.customId === 'create-confession-modal' && modal.user.id === interaction.user.id, - time: 60_000, - }); - await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); - - const confession = modalSubmit.fields.getTextInputValue('confession-text'); - const confessionChannel = await interaction.guild.channels.fetch(settings.confessionChannelId).catch(() => null); - - if (!(confessionChannel instanceof TextChannel)) { - await modalSubmit.editReply({ - content: `${emojis.rightArrow2} The configured confession channel is unavailable.`, - }); - return; - } - - const embed = new EmbedBuilder().setTitle('Confession').setDescription(confession).setTimestamp(); - - const message = await confessionChannel.send({ embeds: [embed] }); - - try { - const threadName = confession.replace(/\s+/g, ' ').slice(0, 10).toLowerCase() || 'confession'; - const thread = await message.startThread({ name: `confession-${threadName}` }); - - const reportButton = new ButtonBuilder() - .setCustomId(`report-confession:${message.id}`) - .setLabel('Report') - .setStyle(ButtonStyle.Danger); - - await message.edit({ components: [new ActionRowBuilder().addComponents(reportButton)] }); - - await storeConfessionContext({ - guildId: interaction.guild.id, - channelId: confessionChannel.id, - messageId: message.id, - threadId: thread.id, - creatorId: modalSubmit.user.id, - }); - - await modalSubmit.editReply({ - content: `${emojis.rightArrow1} Confession sent.`, - }); - } catch (error) { - await message.delete().catch(() => null); - throw error; - } - } catch { - return; - } - } - private async handleReportConfession(interaction: ButtonInteraction, parsed: ParsedConfessionButton) { if (!interaction.inGuild() || !interaction.guild || !parsed.messageId) { await interaction.reply({ From c574aadc9be21ce8c4c5da1b87fb4d88f1dff029 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 09:03:24 +0200 Subject: [PATCH 22/50] fix: forgotten 2 cmds that need mention silencing --- apps/bot/src/commands/moderation/ban/unban.ts | 3 +++ apps/bot/src/commands/moderation/warn/unwarn.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/bot/src/commands/moderation/ban/unban.ts b/apps/bot/src/commands/moderation/ban/unban.ts index 0e2195f..943977a 100644 --- a/apps/bot/src/commands/moderation/ban/unban.ts +++ b/apps/bot/src/commands/moderation/ban/unban.ts @@ -68,6 +68,7 @@ export class UnbanCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to unban <@${targetMember.id}> for reason: ${reason}?`, + allowedMentions: { parse: [], users: [targetMember.id] }, components: [row], withResponse: true, }); @@ -95,12 +96,14 @@ export class UnbanCommand extends Command { .catch(() => {}); await confirmation.update({ content: `${emojis.rightArrow2} <@${targetMember.id}> has been unbanned with reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.id] }, components: [], }); } catch (err) { console.error(err); await confirmation.update({ content: `${emojis.rightArrow2} Failed to unban <@${targetMember.id}> with reason: ${reason}`, + allowedMentions: { parse: [], users: [targetMember.id] }, components: [], }); } diff --git a/apps/bot/src/commands/moderation/warn/unwarn.ts b/apps/bot/src/commands/moderation/warn/unwarn.ts index 218dacd..682eb33 100644 --- a/apps/bot/src/commands/moderation/warn/unwarn.ts +++ b/apps/bot/src/commands/moderation/warn/unwarn.ts @@ -69,6 +69,7 @@ export class UnwarnCommand extends Command { const response = await interaction.reply({ content: `${emojis.rightArrow1} Are you sure you want to unwarn <@${warn.userId}> with reason: ${reason}?\n${emojis.rightArrow2} They were warned for: ${warn.reason} `, + allowedMentions: { parse: [], users: [warn.userId] }, components: [row], withResponse: true, }); @@ -97,12 +98,14 @@ export class UnwarnCommand extends Command { .catch(() => {}); await confirmation.update({ content: `${emojis.rightArrow2} \`${warn.id}\` has been removed from <@${warn.userId}>. Reason: ${reason}`, + allowedMentions: { parse: [], users: [warn.userId] }, components: [], }); } catch (err) { console.error(`Failed to remove warn ${warn.id}:`, err); await confirmation.update({ content: `${emojis.rightArrow2} Failed to remove warn \`${warn.id}\` from <@${warn.userId}>.`, + allowedMentions: { parse: [], users: [warn.userId] }, components: [], }); } From 64c8e79abe547b14bf259cb746162f9d53d528cd Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 09:04:52 +0200 Subject: [PATCH 23/50] fix(automod): check guild --- apps/bot/src/commands/moderation/automod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts index 11b0996..7c569e2 100644 --- a/apps/bot/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -144,7 +144,7 @@ export class AutoModCommand extends Command { const autoModId = interaction.options.getString('word', true); const autoMod = await getAutoMod(autoModId); - if (!autoMod) { + if (!autoMod || autoMod.guildId !== interaction.guildId) { await interaction.reply({ content: `${emojis.rightArrow2} That blocked word doesn't exist.`, flags: MessageFlags.Ephemeral, From 025bae1ece0bfd9f3be769c0ed1b3909a4e1caba Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 09:50:47 +0200 Subject: [PATCH 24/50] chore(bot): prepare package for npm --- apps/bot/LICENSE | 1 + apps/bot/README.md | 1 + apps/bot/package.json | 33 ++++++++++++++++++++++++++------- 3 files changed, 28 insertions(+), 7 deletions(-) create mode 120000 apps/bot/LICENSE create mode 120000 apps/bot/README.md diff --git a/apps/bot/LICENSE b/apps/bot/LICENSE new file mode 120000 index 0000000..30cff74 --- /dev/null +++ b/apps/bot/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/apps/bot/README.md b/apps/bot/README.md new file mode 120000 index 0000000..fe84005 --- /dev/null +++ b/apps/bot/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/apps/bot/package.json b/apps/bot/package.json index 589a1d4..0e5a0e5 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -1,18 +1,37 @@ { "$schema": "https://json.schemastore.org/package.json", - "name": "@quest/bot", - "version": "0.1.0", - "private": true, + "name": "@duckorganization/questbot", + "version": "0.1.2", + "private": false, "type": "module", + "description": "A Discord bot built with Sapphire framework", + "license": "AGPL-3.0-or-later", + "author": "Duck Organization", + "repository": { + "type": "git", + "url": "git+https://github.com/duck-organization/quest-bot.git" + }, + "main": "./dist/index.js", + "bin": { + "questbot": "./dist/sharder.js" + }, + "files": [ + "dist", + "prisma/schema.prisma", + "README.md", + "LICENSE" + ], "scripts": { "build": "rimraf dist && prisma generate && tsc", "lint": "prettier --check .", "format": "prettier --write .", "predev": "pnpm build", - "start": "node --env-file-if-exists=../../.env dist/sharder.js", - "dev": "concurrently \"tsc --watch\" \"node --watch --env-file-if-exists=../../.env dist/index.js\"", + "start": "node --env-file-if-exists=.env dist/sharder.js", + "dev": "concurrently \"tsc --watch\" \"node --watch --env-file-if-exists=.env dist/index.js\"", "db:push": "prisma db push", - "db:generate": "prisma generate" + "db:generate": "prisma generate", + "postinstall": "prisma generate", + "prepublishOnly": "pnpm build" }, "dependencies": { "@discordjs/core": "^2.4.0", @@ -44,4 +63,4 @@ "#lib/*": "./dist/lib/*", "#prisma/*": "./dist/generated/prisma/*" } -} +} \ No newline at end of file From 72d959c81255699db826d32729e9f280370dc28c Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 09:57:51 +0200 Subject: [PATCH 25/50] fix(docker): update package filter to renamed package name --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6bb318a..297e73a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ COPY apps/bot/prisma ./apps/bot/prisma/ RUN pnpm install --frozen-lockfile COPY . . -RUN pnpm --filter @quest/bot build +RUN pnpm --filter @duckorganization/questbot build FROM node:24-alpine WORKDIR /app @@ -22,8 +22,8 @@ COPY pnpm-workspace.yaml ./ COPY apps/bot/package.json ./apps/bot/package.json COPY apps/bot/prisma.config.ts ./apps/bot/prisma.config.ts COPY apps/bot/prisma ./apps/bot/prisma/ -RUN pnpm install --prod --frozen-lockfile --filter @quest/bot +RUN pnpm install --prod --frozen-lockfile --filter @duckorganization/questbot COPY --from=builder /app/apps/bot/dist ./apps/bot/dist -CMD ["sh", "-c", "pnpm --filter @quest/bot db:push && pnpm --filter @quest/bot start"] +CMD ["sh", "-c", "pnpm --filter @duckorganization/questbot db:push && pnpm --filter @duckorganization/questbot start"] From 6439c654896f16597b19d9e17b54baec02e00436 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 11:16:50 +0200 Subject: [PATCH 26/50] fix: sharder script --- apps/bot/src/sharder.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/bot/src/sharder.ts b/apps/bot/src/sharder.ts index e1cbcba..50a8e9e 100644 --- a/apps/bot/src/sharder.ts +++ b/apps/bot/src/sharder.ts @@ -1,3 +1,4 @@ +#!/usr/bin/env node import process from 'node:process'; import { ShardingManager } from 'discord.js'; From 5095be4946150a17cadcb907e16dce674f0a5834 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 11:17:16 +0200 Subject: [PATCH 27/50] fix: upd package version --- apps/bot/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index 0e5a0e5..a60c3c1 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@duckorganization/questbot", - "version": "0.1.2", + "version": "0.1.3", "private": false, "type": "module", "description": "A Discord bot built with Sapphire framework", From b0d4bdcf63a1aa9217373ada259c3b693987a12a Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 11:25:10 +0200 Subject: [PATCH 28/50] fix: shard file processing --- apps/bot/src/sharder.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/bot/src/sharder.ts b/apps/bot/src/sharder.ts index 50a8e9e..4a8d8c0 100644 --- a/apps/bot/src/sharder.ts +++ b/apps/bot/src/sharder.ts @@ -1,6 +1,11 @@ #!/usr/bin/env node import process from 'node:process'; import { ShardingManager } from 'discord.js'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const shardFile = join(__dirname, 'index.js'); const shardCountEnv = process.env.SHARD_COUNT; let totalShards: number | 'auto' | undefined; @@ -18,7 +23,7 @@ if (totalShards !== undefined) { console.log('No shard count provided using what Discord recommends.'); } -const manager = new ShardingManager('./dist/index.js', { +const manager = new ShardingManager(shardFile, { token: process.env.DISCORD_TOKEN, ...(totalShards ? { totalShards } : {}), }); From 58c2a78d3ad41207658a1cedc03ca21f4d8a627d Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 11:34:32 +0200 Subject: [PATCH 29/50] fix: env loading --- apps/bot/package.json | 2 +- apps/bot/src/sharder.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index a60c3c1..503bfc9 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@duckorganization/questbot", - "version": "0.1.3", + "version": "0.1.4", "private": false, "type": "module", "description": "A Discord bot built with Sapphire framework", diff --git a/apps/bot/src/sharder.ts b/apps/bot/src/sharder.ts index 4a8d8c0..22f7457 100644 --- a/apps/bot/src/sharder.ts +++ b/apps/bot/src/sharder.ts @@ -1,5 +1,6 @@ #!/usr/bin/env node import process from 'node:process'; +import 'dotenv/config'; import { ShardingManager } from 'discord.js'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; From 62cdebb92cbc6a6862c5fd9b5d72b2bba4646f0f Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 12:04:34 +0200 Subject: [PATCH 30/50] chore: mark questbot package as private --- apps/bot/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index 503bfc9..d74ab57 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -1,8 +1,8 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@duckorganization/questbot", - "version": "0.1.4", - "private": false, + "version": "0.1.5", + "private": true, "type": "module", "description": "A Discord bot built with Sapphire framework", "license": "AGPL-3.0-or-later", From e66eae7ccfb9f5f4b38bfa3441efc78911f74a78 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 12:18:30 +0200 Subject: [PATCH 31/50] fix: role hierarchy --- apps/bot/src/commands/moderation/ban/ban.ts | 8 ++++++++ apps/bot/src/commands/moderation/kick.ts | 8 ++++++++ apps/bot/src/commands/moderation/mute/mute.ts | 8 ++++++++ apps/bot/src/commands/moderation/mute/unmute.ts | 8 ++++++++ apps/bot/src/commands/moderation/nick.ts | 8 ++++++++ apps/bot/src/commands/moderation/warn/warn.ts | 8 ++++++++ 6 files changed, 48 insertions(+) diff --git a/apps/bot/src/commands/moderation/ban/ban.ts b/apps/bot/src/commands/moderation/ban/ban.ts index f16c8cf..292d57e 100644 --- a/apps/bot/src/commands/moderation/ban/ban.ts +++ b/apps/bot/src/commands/moderation/ban/ban.ts @@ -81,6 +81,14 @@ export class BanCommand extends Command { return; } + if (member.roles.highest.position <= targetMember.roles.highest.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot moderate someone with a higher or equal role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + if (!targetMember.bannable) { await interaction.reply({ content: `${emojis.rightArrow2} I cannot ban this user.`, diff --git a/apps/bot/src/commands/moderation/kick.ts b/apps/bot/src/commands/moderation/kick.ts index b8c2853..f836822 100644 --- a/apps/bot/src/commands/moderation/kick.ts +++ b/apps/bot/src/commands/moderation/kick.ts @@ -72,6 +72,14 @@ export class KickCommand extends Command { return; } + if (member.roles.highest.position <= targetMember.roles.highest.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot moderate someone with a higher or equal role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + if (!targetMember.kickable) { await interaction.reply({ content: `${emojis.rightArrow2} I cannot kick this user.`, diff --git a/apps/bot/src/commands/moderation/mute/mute.ts b/apps/bot/src/commands/moderation/mute/mute.ts index b30f271..5c90f33 100644 --- a/apps/bot/src/commands/moderation/mute/mute.ts +++ b/apps/bot/src/commands/moderation/mute/mute.ts @@ -86,6 +86,14 @@ export class MuteCommand extends Command { return; } + if (member.roles.highest.position <= targetMember.roles.highest.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot moderate someone with a higher or equal role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + if (!targetMember.moderatable) { await interaction.reply({ content: `${emojis.rightArrow2} I cannot mute this user.`, diff --git a/apps/bot/src/commands/moderation/mute/unmute.ts b/apps/bot/src/commands/moderation/mute/unmute.ts index 1ed3b9f..6ca504f 100644 --- a/apps/bot/src/commands/moderation/mute/unmute.ts +++ b/apps/bot/src/commands/moderation/mute/unmute.ts @@ -57,6 +57,14 @@ export class UnmuteCommand extends Command { return; } + if (member.roles.highest.position <= targetMember.roles.highest.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot moderate someone with a higher or equal role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + if (!targetMember.moderatable) { await interaction.reply({ content: `${emojis.rightArrow2} I cannot unmute this user.`, diff --git a/apps/bot/src/commands/moderation/nick.ts b/apps/bot/src/commands/moderation/nick.ts index 45285b1..10ca73e 100644 --- a/apps/bot/src/commands/moderation/nick.ts +++ b/apps/bot/src/commands/moderation/nick.ts @@ -57,6 +57,14 @@ export class NickCommand extends Command { return; } + if (member.roles.highest.position <= targetMember.roles.highest.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot moderate someone with a higher or equal role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + if (!targetMember.manageable) { await interaction.reply({ content: `${emojis.rightArrow2} I cannot manage this member's nickname.`, diff --git a/apps/bot/src/commands/moderation/warn/warn.ts b/apps/bot/src/commands/moderation/warn/warn.ts index 0a1dc79..7cd8645 100644 --- a/apps/bot/src/commands/moderation/warn/warn.ts +++ b/apps/bot/src/commands/moderation/warn/warn.ts @@ -89,6 +89,14 @@ export class WarnCommand extends Command { return; } + if (member.roles.highest.position <= targetMember.roles.highest.position) { + await interaction.reply({ + content: `${emojis.rightArrow2} You cannot moderate someone with a higher or equal role.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + if (!targetMember.moderatable) { await interaction.reply({ content: `${emojis.rightArrow2} I cannot warn this user.`, From 98ab8315b52c54d3018cacb2509b8dea52384e4b Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 12:20:09 +0200 Subject: [PATCH 32/50] fix: permission checks purge/slowmode --- apps/bot/src/commands/moderation/purge.ts | 16 ++++++++-------- apps/bot/src/commands/moderation/slowmode.ts | 11 +++++------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/bot/src/commands/moderation/purge.ts b/apps/bot/src/commands/moderation/purge.ts index 5c857f8..f723f53 100644 --- a/apps/bot/src/commands/moderation/purge.ts +++ b/apps/bot/src/commands/moderation/purge.ts @@ -35,28 +35,28 @@ export class PurgeCommand extends Command { } const member = interaction.member; + const channel = interaction.channel; - if (!member || !('permissions' in member) || !member.permissions.has(PermissionsBitField.Flags.ManageMessages)) { + if (!channel || !('messages' in channel)) { await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage messages.`, + content: `${emojis.rightArrow2} Unable to access channel messages.`, flags: MessageFlags.Ephemeral, }); return; } - const amount = interaction.options.getInteger('amount') ?? 0; - if (amount <= 0) { + if (!member || !('permissions' in member) || !channel.permissionsFor(member)?.has(PermissionsBitField.Flags.ManageMessages)) { await interaction.reply({ - content: `${emojis.rightArrow2} Please provide a valid number of messages to purge.`, + content: `${emojis.rightArrow2} You do not have permission to manage messages.`, flags: MessageFlags.Ephemeral, }); return; } - const channel = interaction.channel; - if (!channel || !('messages' in channel)) { + const amount = interaction.options.getInteger('amount') ?? 0; + if (amount <= 0) { await interaction.reply({ - content: `${emojis.rightArrow2} Unable to access channel messages.`, + content: `${emojis.rightArrow2} Please provide a valid number of messages to purge.`, flags: MessageFlags.Ephemeral, }); return; diff --git a/apps/bot/src/commands/moderation/slowmode.ts b/apps/bot/src/commands/moderation/slowmode.ts index 429fa2b..f661c9d 100644 --- a/apps/bot/src/commands/moderation/slowmode.ts +++ b/apps/bot/src/commands/moderation/slowmode.ts @@ -31,20 +31,19 @@ export class SlowmodeCommand extends Command { } const member = interaction.member; + const channel = interaction.channel; - if (!member || !('permissions' in member) || !member.permissions.has(PermissionsBitField.Flags.ManageChannels)) { + if (!channel || !('setRateLimitPerUser' in channel)) { await interaction.reply({ - content: `${emojis.rightArrow2} You do not have permission to manage channels.`, + content: `${emojis.rightArrow2} This channel does not support slowmode.`, flags: MessageFlags.Ephemeral, }); return; } - const channel = interaction.channel; - - if (!channel || !('setRateLimitPerUser' in channel)) { + if (!member || !('permissions' in member) || !channel.permissionsFor(member)?.has(PermissionsBitField.Flags.ManageChannels)) { await interaction.reply({ - content: `${emojis.rightArrow2} This channel does not support slowmode.`, + content: `${emojis.rightArrow2} You do not have permission to manage channels.`, flags: MessageFlags.Ephemeral, }); return; From 76df5610435a32fe6beeb67f72764077b5b75486 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Mon, 18 May 2026 12:21:17 +0200 Subject: [PATCH 33/50] fix: automod empty character --- apps/bot/src/commands/moderation/automod.ts | 9 +++++++++ apps/bot/src/lib/automod.ts | 4 ++++ apps/bot/src/listeners/messageCreate.ts | 1 + 3 files changed, 14 insertions(+) diff --git a/apps/bot/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts index 7c569e2..4a896b4 100644 --- a/apps/bot/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -77,6 +77,15 @@ export class AutoModCommand extends Command { if (subcommand === 'add') { const word = interaction.options.getString('word', true).trim().toLowerCase(); + + if (!word) { + await interaction.reply({ + content: `${emojis.rightArrow2} The word cannot be empty or contain only whitespace.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + try { await createAutoMod( interaction.guildId, diff --git a/apps/bot/src/lib/automod.ts b/apps/bot/src/lib/automod.ts index 307f2e3..9b44058 100644 --- a/apps/bot/src/lib/automod.ts +++ b/apps/bot/src/lib/automod.ts @@ -15,6 +15,10 @@ export async function createAutoMod( word: string, entitlements?: EntitlementManager, ) { + if (!word || !word.trim()) { + throw new Error('Automod word cannot be empty.'); + } + const hasUnlimitedAccess = entitlements ? await hasQuestUnlimitedAccess(entitlements, guildId) : false; if (LIMITS_ENABLED && !hasUnlimitedAccess) { diff --git a/apps/bot/src/listeners/messageCreate.ts b/apps/bot/src/listeners/messageCreate.ts index 2539e59..86f5003 100644 --- a/apps/bot/src/listeners/messageCreate.ts +++ b/apps/bot/src/listeners/messageCreate.ts @@ -18,6 +18,7 @@ export class MessageCreateListener extends Listener const content = message.content.toLowerCase(); for (const autoMod of autoMods) { + if (!autoMod.word.trim()) continue; if (content.includes(autoMod.word.toLowerCase())) { await message.delete().catch((err) => console.error(err)); From f091712a8fea5fb7689ca7490377bd0717627c88 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 09:07:15 +0200 Subject: [PATCH 34/50] feat: /togif --- apps/bot/package.json | 5 +- .../src/commands/utility/{ => fun}/confess.ts | 0 apps/bot/src/commands/utility/fun/toGif.ts | 92 +++++++++++++++++++ apps/bot/src/sharder.ts | 1 - 4 files changed, 94 insertions(+), 4 deletions(-) rename apps/bot/src/commands/utility/{ => fun}/confess.ts (100%) create mode 100644 apps/bot/src/commands/utility/fun/toGif.ts diff --git a/apps/bot/package.json b/apps/bot/package.json index d74ab57..3f32214 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -26,8 +26,8 @@ "lint": "prettier --check .", "format": "prettier --write .", "predev": "pnpm build", - "start": "node --env-file-if-exists=.env dist/sharder.js", - "dev": "concurrently \"tsc --watch\" \"node --watch --env-file-if-exists=.env dist/index.js\"", + "start": "node --env-file-if-exists=../../.env dist/sharder.js", + "dev": "concurrently \"tsc --watch\" \"node --watch --env-file-if-exists=../../.env dist/index.js\"", "db:push": "prisma db push", "db:generate": "prisma generate", "postinstall": "prisma generate", @@ -40,7 +40,6 @@ "@sapphire/framework": "^5.5.0", "@types/ms": "^2.1.0", "discord.js": "^14.26.4", - "dotenv": "^17.4.2", "ms": "^2.1.3", "prisma": "^7.8.0", "sharp": "^0.34.5", diff --git a/apps/bot/src/commands/utility/confess.ts b/apps/bot/src/commands/utility/fun/confess.ts similarity index 100% rename from apps/bot/src/commands/utility/confess.ts rename to apps/bot/src/commands/utility/fun/confess.ts diff --git a/apps/bot/src/commands/utility/fun/toGif.ts b/apps/bot/src/commands/utility/fun/toGif.ts new file mode 100644 index 0000000..df26634 --- /dev/null +++ b/apps/bot/src/commands/utility/fun/toGif.ts @@ -0,0 +1,92 @@ +import { Command } from '@sapphire/framework'; +import { AttachmentBuilder, MessageFlags } from 'discord.js'; +import sharp from 'sharp'; +import { emojis } from '#utils/emoji.js'; + +const ALLOWED_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp']); +const MAX_SIZE = 20 * 1024 * 1024; + +function isSafeUrl(raw: string): boolean { + let url: URL; + try { url = new URL(raw); } catch { return false; } + if (url.protocol !== 'https:') return false; + const host = url.hostname; + if (/^(localhost|127\.|0\.0\.0\.0|::1|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|169\.254\.)/.test(host)) return false; + return true; +} + +export class ToGifCommand extends Command { + public constructor(context: Command.LoaderContext, options: Command.Options) { + super(context, { ...options, preconditions: ['devMode'] }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder: any) => + builder + .setName('togif') + .setDescription('Convert a PNG, JPEG, or WEBP image URL to a GIF.') + .addStringOption((option: any) => + option.setName('url').setDescription('The image URL to convert.').setRequired(true), + ), + ); + } + + public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const url = interaction.options.getString('url', true); + + if (!isSafeUrl(url)) { + await interaction.reply({ content: `${emojis.rightArrow1} Only HTTPS is supported.`, flags: MessageFlags.Ephemeral }); + return; + } + + await interaction.deferReply(); + + let response: Response; + try { + response = await fetch(url); + } catch { + await interaction.editReply(`${emojis.rightArrow1} Failed to fetch the URL.`); + return; + } + + if (!isSafeUrl(response.url)) { + await interaction.editReply(`${emojis.rightArrow1} Redirected to a blocked URL.`); + return; + } + + if (!response.ok) { + await interaction.editReply(`${emojis.rightArrow1} Could not retrieve the image (HTTP ${response.status}).`); + return; + } + + const contentType = response.headers.get('content-type')?.split(';')[0].trim() ?? ''; + if (!ALLOWED_TYPES.has(contentType)) { + await interaction.editReply(`${emojis.rightArrow1} Only PNG, JPEG, and WEBP images are supported.`); + return; + } + + const contentLength = response.headers.get('content-length'); + if (contentLength && parseInt(contentLength, 10) > MAX_SIZE) { + await interaction.editReply(`${emojis.rightArrow1} Image exceeds the 20 MB size limit.`); + return; + } + + const arrayBuffer = await response.arrayBuffer(); + if (arrayBuffer.byteLength > MAX_SIZE) { + await interaction.editReply(`${emojis.rightArrow1} Image exceeds the 20 MB size limit.`); + return; + } + const inputBuffer = Buffer.from(arrayBuffer); + + let gifBuffer: Buffer; + try { + gifBuffer = await sharp(inputBuffer).gif().toBuffer(); + } catch { + await interaction.editReply(`${emojis.rightArrow1} Failed to convert the image to GIF.`); + return; + } + + const attachment = new AttachmentBuilder(gifBuffer, { name: 'toGif.gif' }); + await interaction.editReply({ files: [attachment] }); + } +} diff --git a/apps/bot/src/sharder.ts b/apps/bot/src/sharder.ts index 22f7457..4a8d8c0 100644 --- a/apps/bot/src/sharder.ts +++ b/apps/bot/src/sharder.ts @@ -1,6 +1,5 @@ #!/usr/bin/env node import process from 'node:process'; -import 'dotenv/config'; import { ShardingManager } from 'discord.js'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; From cb9fa9cf2c99a654cced4f065cd908e7313f5405 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 07:08:38 +0000 Subject: [PATCH 35/50] chore(deps): bump ws from 8.20.0 to 8.20.1 Bumps [ws](https://github.com/websockets/ws) from 8.20.0 to 8.20.1. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.20.0...8.20.1) --- updated-dependencies: - dependency-name: ws dependency-version: 8.20.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- pnpm-lock.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0010590..a44195a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,9 +36,6 @@ importers: discord.js: specifier: ^14.26.4 version: 14.26.4 - dotenv: - specifier: ^17.4.2 - version: 17.4.2 ms: specifier: ^2.1.3 version: 2.1.3 From 4264c91b7179120b4028932dd1f0a8e323e6902e Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 09:08:51 +0200 Subject: [PATCH 36/50] fix: upd modules + pnpm version --- package.json | 2 +- pnpm-lock.yaml | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 8744e86..13f1343 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "quest-bot-workspace", "version": "0.1.0", "private": true, - "packageManager": "pnpm@10.33.3", + "packageManager": "pnpm@11.1.3+sha512.c85357fe17ca12dd23dd7071822666dfd7e3cb76fe214e3370b5ea2fb34f2a231185509b63e717f3cd0acb38dd3f8d82bcd5e8172400ae678b70ea4fbed0896d", "scripts": { "build": "turbo run build", "dev": "turbo run dev", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0010590..a44195a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,9 +36,6 @@ importers: discord.js: specifier: ^14.26.4 version: 14.26.4 - dotenv: - specifier: ^17.4.2 - version: 17.4.2 ms: specifier: ^2.1.3 version: 2.1.3 From da6aae89cae7b7cc4038211e0e204dedcea2cf57 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 09:11:04 +0200 Subject: [PATCH 37/50] fix: remove stale dotenv --- apps/bot/prisma.config.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/bot/prisma.config.ts b/apps/bot/prisma.config.ts index b60c396..82530a4 100644 --- a/apps/bot/prisma.config.ts +++ b/apps/bot/prisma.config.ts @@ -1,6 +1,3 @@ -// This file was generated by Prisma, and assumes you have installed the following: -// npm install --save-dev prisma dotenv -import 'dotenv/config'; import { defineConfig } from 'prisma/config'; export default defineConfig({ From f270d81038b925fefe3bde38d527bfdaf0fa84a1 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 09:35:20 +0200 Subject: [PATCH 38/50] fix: max reminder length --- apps/bot/src/commands/utility/reminder/reminder.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/bot/src/commands/utility/reminder/reminder.ts b/apps/bot/src/commands/utility/reminder/reminder.ts index 80846ba..b869079 100644 --- a/apps/bot/src/commands/utility/reminder/reminder.ts +++ b/apps/bot/src/commands/utility/reminder/reminder.ts @@ -42,6 +42,14 @@ export class ReminderCommand extends Command { const durationStr = interaction.options.getString('duration', true); const message = interaction.options.getString('message', true); + if (message.length > 1000) { + await interaction.reply({ + content: `${emojis.rightArrow2} Reminder message cannot exceed 1K characters.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + const duration = ms(durationStr as StringValue); if (typeof duration !== 'number' || isNaN(duration) || duration <= 0) { await interaction.reply({ From 3154de1cb9bea7663f9f48c7908954b0f24ff140 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 09:47:50 +0200 Subject: [PATCH 39/50] fix: limit directly from dc --- .../globalModeration/confessionBlacklist.ts | 2 +- apps/bot/src/commands/moderation/automod.ts | 4 ++-- .../src/commands/moderation/autorole/autorole.ts | 2 +- apps/bot/src/commands/moderation/ban/ban.ts | 4 ++-- apps/bot/src/commands/moderation/ban/unban.ts | 2 +- apps/bot/src/commands/moderation/kick.ts | 2 +- apps/bot/src/commands/moderation/mute/mute.ts | 4 ++-- apps/bot/src/commands/moderation/mute/unmute.ts | 2 +- apps/bot/src/commands/moderation/nick.ts | 2 +- apps/bot/src/commands/moderation/slowmode.ts | 2 +- apps/bot/src/commands/moderation/warn/unwarn.ts | 4 ++-- apps/bot/src/commands/moderation/warn/warn.ts | 4 ++-- apps/bot/src/commands/utility/fun/toGif.ts | 2 +- apps/bot/src/commands/utility/reminder/reminder.ts | 14 +++----------- 14 files changed, 21 insertions(+), 29 deletions(-) diff --git a/apps/bot/src/commands/globalModeration/confessionBlacklist.ts b/apps/bot/src/commands/globalModeration/confessionBlacklist.ts index a2cace6..ae74503 100644 --- a/apps/bot/src/commands/globalModeration/confessionBlacklist.ts +++ b/apps/bot/src/commands/globalModeration/confessionBlacklist.ts @@ -20,7 +20,7 @@ export class ConfessionBlacklistCommand extends Command { .setName('add') .setDescription('Blacklist a user from making confessions') .addUserOption((opt: any) => opt.setName('user').setDescription('User to blacklist').setRequired(true)) - .addStringOption((opt: any) => opt.setName('reason').setDescription('Reason').setRequired(false)), + .addStringOption((opt: any) => opt.setName('reason').setDescription('Reason').setMaxLength(512).setRequired(false)), ) .addSubcommand((sub: any) => sub diff --git a/apps/bot/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts index 4a896b4..d4aae31 100644 --- a/apps/bot/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -19,7 +19,7 @@ export class AutoModCommand extends Command { .setName('add') .setDescription('Create a new automod rule.') .addStringOption((option: any) => - option.setName('word').setDescription('The word to block').setRequired(true), + option.setName('word').setDescription('The word to block').setRequired(true).setMaxLength(100), ), ) .addSubcommand((sub: any) => @@ -27,7 +27,7 @@ export class AutoModCommand extends Command { .setName('remove') .setDescription('Remove words from the automod list.') .addStringOption((option: any) => - option.setName('word').setDescription('The word to remove').setAutocomplete(true).setRequired(true), + option.setName('word').setDescription('The word to remove').setAutocomplete(true).setRequired(true).setMaxLength(36), ), ) .addSubcommand((sub: any) => sub.setName('list').setDescription('List all blocked words.')), diff --git a/apps/bot/src/commands/moderation/autorole/autorole.ts b/apps/bot/src/commands/moderation/autorole/autorole.ts index 8a3f8d2..b3caa9f 100644 --- a/apps/bot/src/commands/moderation/autorole/autorole.ts +++ b/apps/bot/src/commands/moderation/autorole/autorole.ts @@ -34,7 +34,7 @@ export class AutoRoleCommand extends Command { .setName('remove') .setDescription('Remove an auto role.') .addStringOption((option: any) => - option.setName('role').setDescription('The auto role to remove').setAutocomplete(true).setRequired(true), + option.setName('role').setDescription('The auto role to remove').setAutocomplete(true).setRequired(true).setMaxLength(36), ), ) .addSubcommand((sub: any) => sub.setName('list').setDescription('List all auto roles.')), diff --git a/apps/bot/src/commands/moderation/ban/ban.ts b/apps/bot/src/commands/moderation/ban/ban.ts index 292d57e..5a871d0 100644 --- a/apps/bot/src/commands/moderation/ban/ban.ts +++ b/apps/bot/src/commands/moderation/ban/ban.ts @@ -24,9 +24,9 @@ export class BanCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('Select a member to ban').setRequired(true), ) - .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their ban')) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their ban').setMaxLength(512)) .addStringOption((option: any) => - option.setName('duration').setDescription('Provide a duration for their ban (if needed)'), + option.setName('duration').setDescription('Provide a duration for their ban (if needed)').setMaxLength(20), ), ); } diff --git a/apps/bot/src/commands/moderation/ban/unban.ts b/apps/bot/src/commands/moderation/ban/unban.ts index 943977a..512c6db 100644 --- a/apps/bot/src/commands/moderation/ban/unban.ts +++ b/apps/bot/src/commands/moderation/ban/unban.ts @@ -23,7 +23,7 @@ export class UnbanCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('The member to unban').setRequired(true), ) - .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unban')), + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unban').setMaxLength(512)), ); } diff --git a/apps/bot/src/commands/moderation/kick.ts b/apps/bot/src/commands/moderation/kick.ts index f836822..fd4b841 100644 --- a/apps/bot/src/commands/moderation/kick.ts +++ b/apps/bot/src/commands/moderation/kick.ts @@ -22,7 +22,7 @@ export class KickCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('Select a member to kick').setRequired(true), ) - .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their kick')), + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their kick').setMaxLength(512)), ); } diff --git a/apps/bot/src/commands/moderation/mute/mute.ts b/apps/bot/src/commands/moderation/mute/mute.ts index 5c90f33..638febd 100644 --- a/apps/bot/src/commands/moderation/mute/mute.ts +++ b/apps/bot/src/commands/moderation/mute/mute.ts @@ -24,8 +24,8 @@ export class MuteCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('Select a member to mute').setRequired(true), ) - .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the mute')) - .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their mute')), + .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the mute').setMaxLength(20)) + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their mute').setMaxLength(512)), ); } diff --git a/apps/bot/src/commands/moderation/mute/unmute.ts b/apps/bot/src/commands/moderation/mute/unmute.ts index 6ca504f..5e2548f 100644 --- a/apps/bot/src/commands/moderation/mute/unmute.ts +++ b/apps/bot/src/commands/moderation/mute/unmute.ts @@ -23,7 +23,7 @@ export class UnmuteCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('Select a member to unmute').setRequired(true), ) - .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unmute')), + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unmute').setMaxLength(512)), ); } diff --git a/apps/bot/src/commands/moderation/nick.ts b/apps/bot/src/commands/moderation/nick.ts index 10ca73e..c5030d7 100644 --- a/apps/bot/src/commands/moderation/nick.ts +++ b/apps/bot/src/commands/moderation/nick.ts @@ -15,7 +15,7 @@ export class NickCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('Select a member to change their nickname').setRequired(true), ) - .addStringOption((option: any) => option.setName('nickname').setDescription('Nickname (leave empty to reset)')), + .addStringOption((option: any) => option.setName('nickname').setDescription('Nickname (leave empty to reset)').setMaxLength(32)), ); } diff --git a/apps/bot/src/commands/moderation/slowmode.ts b/apps/bot/src/commands/moderation/slowmode.ts index f661c9d..b161d3e 100644 --- a/apps/bot/src/commands/moderation/slowmode.ts +++ b/apps/bot/src/commands/moderation/slowmode.ts @@ -16,7 +16,7 @@ export class SlowmodeCommand extends Command { .setName('slowmode') .setDescription('Set or clear the slowmode for the current channel.') .addStringOption((option: any) => - option.setName('duration').setDescription('Provide a duration for slowmode, or leave blank to remove it'), + option.setName('duration').setDescription('Provide a duration for slowmode, or leave blank to remove it').setMaxLength(20), ), ); } diff --git a/apps/bot/src/commands/moderation/warn/unwarn.ts b/apps/bot/src/commands/moderation/warn/unwarn.ts index 682eb33..28ae75b 100644 --- a/apps/bot/src/commands/moderation/warn/unwarn.ts +++ b/apps/bot/src/commands/moderation/warn/unwarn.ts @@ -21,10 +21,10 @@ export class UnwarnCommand extends Command { .setName('unwarn') .setDescription('Unwarn someone in the discord server.') .addStringOption((option: any) => - option.setName('id').setDescription('The ID of the warn to remove').setRequired(true), + option.setName('id').setDescription('The ID of the warn to remove').setRequired(true).setMaxLength(36), ) .addStringOption((option: any) => - option.setName('reason').setDescription('Provide a reason for removing the warn'), + option.setName('reason').setDescription('Provide a reason for removing the warn').setMaxLength(512), ), ); } diff --git a/apps/bot/src/commands/moderation/warn/warn.ts b/apps/bot/src/commands/moderation/warn/warn.ts index 7cd8645..f55b189 100644 --- a/apps/bot/src/commands/moderation/warn/warn.ts +++ b/apps/bot/src/commands/moderation/warn/warn.ts @@ -27,8 +27,8 @@ export class WarnCommand extends Command { .addUserOption((option: any) => option.setName('member').setDescription('Select a member to warn').setRequired(true), ) - .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their warn')) - .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the warn')), + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their warn').setMaxLength(512)) + .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the warn').setMaxLength(20)), ); } diff --git a/apps/bot/src/commands/utility/fun/toGif.ts b/apps/bot/src/commands/utility/fun/toGif.ts index df26634..9a9c22a 100644 --- a/apps/bot/src/commands/utility/fun/toGif.ts +++ b/apps/bot/src/commands/utility/fun/toGif.ts @@ -26,7 +26,7 @@ export class ToGifCommand extends Command { .setName('togif') .setDescription('Convert a PNG, JPEG, or WEBP image URL to a GIF.') .addStringOption((option: any) => - option.setName('url').setDescription('The image URL to convert.').setRequired(true), + option.setName('url').setDescription('The image URL to convert.').setRequired(true).setMaxLength(512), ), ); } diff --git a/apps/bot/src/commands/utility/reminder/reminder.ts b/apps/bot/src/commands/utility/reminder/reminder.ts index b869079..fb5e978 100644 --- a/apps/bot/src/commands/utility/reminder/reminder.ts +++ b/apps/bot/src/commands/utility/reminder/reminder.ts @@ -20,17 +20,17 @@ export class ReminderCommand extends Command { .setName('add') .setDescription('Set a new reminder.') .addStringOption((option: any) => - option.setName('duration').setDescription('When to remind you').setRequired(true), + option.setName('duration').setDescription('When to remind you').setRequired(true).setMaxLength(20), ) .addStringOption((option: any) => - option.setName('message').setDescription('What to remind you about').setRequired(true), + option.setName('message').setDescription('What to remind you about').setRequired(true).setMaxLength(1000), ), ) .addSubcommand((sub: any) => sub .setName('remove') .setDescription('Cancel a reminder.') - .addStringOption((option: any) => option.setName('id').setDescription('The reminder ID').setRequired(true)), + .addStringOption((option: any) => option.setName('id').setDescription('The reminder ID').setRequired(true).setMaxLength(36)), ), ); } @@ -42,14 +42,6 @@ export class ReminderCommand extends Command { const durationStr = interaction.options.getString('duration', true); const message = interaction.options.getString('message', true); - if (message.length > 1000) { - await interaction.reply({ - content: `${emojis.rightArrow2} Reminder message cannot exceed 1K characters.`, - flags: MessageFlags.Ephemeral, - }); - return; - } - const duration = ms(durationStr as StringValue); if (typeof duration !== 'number' || isNaN(duration) || duration <= 0) { await interaction.reply({ From c6f0f5982db0e83f510381efcbe2d008591fe49a Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 10:01:19 +0200 Subject: [PATCH 40/50] style(toGif): message --- apps/bot/src/commands/utility/fun/toGif.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/src/commands/utility/fun/toGif.ts b/apps/bot/src/commands/utility/fun/toGif.ts index 9a9c22a..69446cb 100644 --- a/apps/bot/src/commands/utility/fun/toGif.ts +++ b/apps/bot/src/commands/utility/fun/toGif.ts @@ -35,7 +35,7 @@ export class ToGifCommand extends Command { const url = interaction.options.getString('url', true); if (!isSafeUrl(url)) { - await interaction.reply({ content: `${emojis.rightArrow1} Only HTTPS is supported.`, flags: MessageFlags.Ephemeral }); + await interaction.reply({ content: `${emojis.rightArrow1} URL not valid, HTTPS required.`, flags: MessageFlags.Ephemeral }); return; } From 687f41a54d64e7c454d82d20b5902da2cce1b2ac Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 14:52:37 +0200 Subject: [PATCH 41/50] style(readme): update image --- .github/assets/LargeDuckBanner.png | Bin 0 -> 11042 bytes .github/assets/LargeDuckBannerWhite.png | Bin 9948 -> 0 bytes README.md | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 .github/assets/LargeDuckBanner.png delete mode 100644 .github/assets/LargeDuckBannerWhite.png diff --git a/.github/assets/LargeDuckBanner.png b/.github/assets/LargeDuckBanner.png new file mode 100644 index 0000000000000000000000000000000000000000..120cd5a83c36409520f91c0ab4d15fcd1a93df38 GIT binary patch literal 11042 zcmeHtc{r3``1do`5-M4Src!o^35|VckVsOAv1FUkX6!{{h=w}^;U?b#p?XE8X96Z7OK#Xo2UjZ*dd~aO643u%f>1`_&$Afl zu~po|ix!eSNl9=06ZeZ*@YWnU8mwe~C@1)2LFToFyo6!?L2KcpjT0I-E-mk0)-xLQ zIeBSyQ2L~Fh}WY_6S9|hkLNtCjm#QMeL${~YP-GpFEi1yJ3J7HMPk#DE_NyoAK!l& zhN)ImU>RW%^<%y`-Cv-20I(UQa^b%(A}4ZqxL@}3-Q+frQIXuG0L=HAL%8j39wlyb zN$(POTENL&dE5rzhaBKGIY<9K{CC0r2Fc%z@fQrZc=#7R|1t&`2LF#N8AJpr_M;zz zI^u3wYKL;F4WL+Q`!C$&1sdhJy!w3n>tjJmcHpS16Laoe!eQX7vhn8sW#xulcHvvo z0>DGv|E^x~q7K*4=kd7C)PZ`&XlO+>V|mPTxt_zGRR$V9K^d;$?|8xSd_3!S0*1!M zmg~~yM+kvK)x?cr0pNL)SU4EJ7g~}FfZYJuMF<9%n5Tw}5&}KxRo3*arSqgdyHHd> zi*#u48hUNY2>uPCZZ6#hiJTWRhd3M)Gb**O9~})@EUroQksj7oF}@^s?gH6FLfK|7 zB0ZSap)u4`XgQQT9iC~-h-%13;9XR9O)YP!KGcpig*1E;$^$;S#6KZV>h^YIY9P~o z;G-*k+?vw?H&A7lfrewYgg|H3MW-90Kx9gVpb}8@OMCeX*$k%(70%Y5oUagj zN2k*VW)+&m0 zEqv$tFuY`Dn1}VPkMmDhW}ibDCD2lc!+rWC{>TGuK2!cj7RYG3eg1*|v1&(jvJ_X( zi)W)x+*4lEO?jQ!@;msQNA)ekQJDQ>D0fVC(1Q*!Vxe>fV@T`7TX}UoibO~*a zzTJ_m0RX4tK{0nKNvI~@BwQYAM+~dcLlzj1(fmhk zume|D7L<>79+`xiS;(7HVp?;Xeb~WiYgenY#?Vs#=iftjCpx~w4&IORNma713-Naj zyLg4bK&2k#K(YGafB;}Ol;A25i7tf}dA3o|v z6Z18`vj>?PH3MNNFd(mvNX)y%1HF~TT|G!^>*m>`fN z0nXrx&kl2g-g>IE{eXEwMxM3bpoc}=b%f6NZY8`~w$+1wBc^n*I3obKlMI^Sdo8Sm z&)Te*^ws#P(W~}t7sYV44yk*{;@sSaG&?sZLIfxLv1uYM&7j+`Zll*a7gWr5UjO&t zUemCaBxVJYR3)xp)-IA8Oy9rFf^tGfHOg7x*zY+nGl1+s(H>cooN`yDiOVdq=Z!1q zuIpg%T=Z*OAsGGQYs%E{?7ZiiI!hv43~@dd6CqXnNc@`Iw8>&PMADJSRpMppH$ zz2*aI3UKU0^b~UGGfEQx#&c#R0k0y1E`#4o2STP>Q%Jej#dT?8zAb)kqss$vWJ`Or ze+eluAyMe|c+l3}Hj)i)Gh((gyGH)|fK5-;akN4jByvPPho?bG%(^^T7vnCJmo0VQ zci2&Vps>v9E$l!%_JIiE)uCQgdfC&{ll36lInhoe%RikB@2bo3A9g|o?z+o}vdm52 zmbxwgEQx>~oALVdEr!J7rW|ilI^7a-Y(a^Bo??8-S$tzpUfjd2z<7g-C10Ifohzpg z`>U1_3wXyp#)#1L=GRT*24tOFda$DsCwHjvO{fj^o}1m#p&rE^8+@9wt(((gRShK4 z^cdINwI8+C%B-18PvtKx4aegMPek@*3ITV#i2Q0LVtKSKCThI@O*zR)zZ%`FWb&u% z)GyV9dZ#7Fp(Fii#u62QXWoZz{)s(BfI%8^y`Sy}+VeBp=Y4mXUM7A0z(F|KUsC_| zYPa z+-WD5Q<1?X3Dh$7LQf&a&hX6uv~ee;#8Ybc&{Xu3fxM`J0)cNOP2J@}X{|(wAp?=_dBGj^0B-QR_}!_7FW-NjG4ThDGN)~|14(iG$iMyP+wS^A|&|O@0)L+ ztrXqUXQyc5s1k7J0vBBMf_?g-aa8&Y$OgT`99{So{2CwG=eqhpS6r1z&l&Rm>bW^T z#3MwX0(NFKXf$YW-Ym*~N;lc-b>!#5+Q(HQn8nqRz_9~xNWT?0i}hCuztas&lbbQE zCTjk%FQqDfob%2h$=-AtNO4utY%fpygsfRhMtu`o;A=IUaJ2&pAd{$(=^hu-s=8H zlmZywzz821L{Op^xG>{a0@Hs(l()1@apjBZ^X4B=X+!tGPLMLb+g9skXZ5@-Q`ck; zz$+r?Zv_>38ghNWfIj{8>xY~X*FI2CaFz^~sA%1tb#f(awG(68cIFMGd%vSeaQq`( z!NoI+hB+oVGpk;SIas5CFgEICY|~G&zw~PXppc6UNzO)2$~}+HBuGQ8g3=etpW;`v z<<0T3vL3&N-o|6wlA0C`Wzs+;L9E2EMj&yqBgzsgb~Z!HXMsBsTsQvo*}TcKSm3|v zcLXPy>(-ZRj?Z28*<9c+ARZhMydbu(dX?>aQ^)k|LC{ZzT%ObeF~j-BDM2(iRxr;( zNZk&7s80S7DeEFRb$+S^gR-buHu-a@!C6Zgt6U2|13VN4ai{kv*{twc`dyFt6Tgtn|Tzp9mm`OAH5$yKH{SN)1?hSqO>8?Mk;Yy>p>%_jB2@ z5|YzR6O?w6L7(Z!vFW^^jJjGC+uClhLIrZR68tuv6|H7(uPpfe$}u;yFX59fG?w1& zKK-*UlwoC$7705{&XqPur3iN7U=eeDIEp=}q7DNq$@=dB2gCCpk`)Rw<>BSxXn2<9 zIf4x_EI7aIwr|~iC5iqcXgvHK$r0`}_#-ldVq4IH0H;d4#l&_7^sxcJwPm14nAM%&=||& z|Bedq^6dNZLh4G2!bB;Nxq$SR{kp;4*{;YZBc0Z|>1uq9sy&#+ZDMn!VyOOX;4e^@ zitdbYc_VaK01)Bsn5SaGg$hMOO8btb8PYY?9_=Q`sk~pm;8L_yk#gTijVlgske`G90ni5}nspx@B3bNww_9)QxRJ|3kvYa{oIq2}f5EGOmk~Ao! zp#apnXOnbXN2<{9rlZ(z9{;X=*6jU+{7>1at0&!_iNhx@!&Ek%6=A>%H;A7f4P}jd z39fjdDEsD_&{b1}>5Djp{xka0nT@;if~5wlf?gj5#b2=VP|8vt3VbRok!w`*{90SG z0wevUmhVjaWrT&$fpq#plpCA1^5;8=u1H~5`>)+U5)j|QTBR&6GeY*Mh!;v@Ami~| zEmyANYJ2`hmzXu99p4qr4|oRxsrL)^xvu&g^91BXvZH;B<@MJvWKlgf6YdS%HA>xery! zU480YHuR;dW1F%0TRW=sWoe-QIF~3a?oDr^cflv$GZil84M4w(Op!Lf2tpMJatHFl@66FfG2 z8)ol1#<}aB0CVjcdUrKpa4%OEe%vDxkI(jT?6Jy zi9mO`=y`QDg{&R--;K}>ehYQE2Ho%^_Smr`N-OKpK6N|O98XGUMBku&#QJ(|v|$)1 zl2A`?ncC2TSBzeX$M=1B-FoZ^$TMt|;#SB%LV3qVB|2!D*^GagLB#s{F~Gr+ zyTxKplOi_B@7~S#v8Q^}yNj)>2W$P?F8Jnjdm~KaLw2-7D}=gRE6!c$3ua47xitT% zQf%JXSJF2Ls%X^HFAW+WB(?yD6wvFMm*r(S3*Qy~tP2*`aW?0S$fY}NeS_v;CQY|e zDDoKnGQdqk2j9q&%y7~t{;2f@Yoxf<-^5;+LQcQX7=2I_TZinEQ#ou?>zBXBarc2p zTd?ZhAPYtie|noJ47)rQwj^+|B@u$xAs@NhR&(4z(^jp!ZnGyXO+BWz-~$WH z&qhyY&77b4-EN~2I#xIMWWfVx!f!nYA5)y?(=p!cL(cibV!qSWZ%xd1DRxVpoK^=M z`oK`>!cx665PxFLG{b2dzNmlK_%ytI9}4|js2Rs9=7d+DLF7geKI~jxpe|^?c);|l z6I*?vLwy?f-R4V>ch`QmYPdSEBnCMUnVsgqOoKh7Y{T3iqiJJjkoG@y^p1oosjVGn z4pzET=#-&%rc-dA|@joHTo`JajBXTuk?A6n{XA)^ucd7WhtuTXJ z^AVB%?YGx7TiN~DIfZr^|5nzq+NZV8jBsGcR)VozRaaM6Wl|b}^i(uvBqR+f8#86t zpUU)^jpS%Tnce9_T0I(7R}-Ww^AGtv?Mo&mn5Ntk(T@=6Ewk4Eiom?N!K^iDCz|YR zlCA5Wh?$x7-dN}fnD`O*i(%M-nU~b?XqS&ql||q=^BwM}TcZ)Ib@dKZ8yy_lZgG;E zd77Z#bt{QnZDqG25>K$uk7)%8GPHiei&)F))$pf9uMUN#@Bt<<;7Fb6Kglu)ff?K9 z@#fmWYuNcN<@d_8mN5A-vD@cOljHi{2tGHMaHT^#zFHNkY2ROHI<}xZC+;Dpkp^|% zDI!{UEeUn&xR@vgOouFlS{G^M1SHheaEa7ZtzC`YwG-)!?#CRAv|S0~jXZ*Bpl@2D zZbk%9u562P=zgIr%(QOV(q*^%QH9no!`7x+28P_2#lj^c#6(c=;dZK7=mE?vTb(2B zW8}%Hst#1xnkbGXb42BUXR+=+_c>w$t(oMEYtW!aPwp4pX*ti<6<;p=Cr=P&>G6)6 z#VRK@jXjJ=%AYYE;i$vJ^`pE>FpGVqrBg^@px5XUzXSe0iCi}6dR&^_#|a?VGU)^A zsXAr2L0Rd=m-y`AMp2n+dMR<(;y9}DV%`^O?Ops#s%RnOvu!x~3}Wa00^ScmzY7Sl+OlN445zmE=i=Cad&Fv; zASS)tCfB2d4MIVcVk^pHw?AQOZ>8aJ5$A6nDa^(}=h)64Ge`wqyylsKS+&g{wPm6z ztxYiH-6GIvSEbZ4zOnsEz>o>J&I+uR$*S8zFYb8*fyoNs+ZR2Ntmw3OcCt9e6)#z!#J?cJiy!U8pK-SeRnvNDMHud^#}&mGY~4+e$= zJX=#e@3;E`W8{{p0Pla=W+~d9om*`C)`@P=p|-Hd2`@#xRnB7n}IlOrS;Y<}}YRlw} z$WCwzX|5mh75FIf-#X#T;fA>uoTXyPidPvq%ni?VSY_y~wF{nBnv^2<#V4k!8*_=T zE1UgXqK38bXSN$F!xG{>5MJi;W}@-(Yhy{Oh2&`!G?`y|Lm4hPpL;5v1)mpbvYXLFb&}^1Cwg@ zW4SSigQ`7|8KsLLj{B;NET>XR7rOFVUnzE<{y_E3xtR*b>7tp!9Q8MziN&J5C;Ixp zz(wTgN6{Q#4k;b$n=Qw~V_B>-svfhmE_1{Zkz^hRNhnBYf-H8L_4ahM!ai|?Z-2L5 zLd2RyC~NK={VNAuUwobTQo=qYxbX6PyuE9?<1@&Gee%Xp2^oAkCmm0%`YB-^rAL`| z*{s)6QpXi0oPE|cYp?}EBUG(_Yekm|s4}*nZSFri_jL;_Ygx7a@YeVm+Re~z?A=Qn zZ4#|m8j|-8dH{5gD1>FAc8h)+kdyFViL@bg8wSVPv&SV~99h4r@`?V!^6=GbUoLu2 z7%ZL=caQVaKf&i5vIZ6nE5zp|g!F}8#Calw)zcf>_)zvE>vN!Z9Lh()tGDM$@SzN9 z$7Ra{gj&~O>X_lT+a*JWXBO45mc&`Zw5Zv!f71WyDBlTt{*D^Bwb_Q9>6kTsuqO26%fHVcZa~b-x*YD zwTf!qOn4}pwG}fNLS%%Q#svxm3Qi-BZa?XiRH5x0|IMf=b-u2NXx?HHB!q9fHltJ< z(bGA~@8wyY6}R|-BJLV=o{gyuHNokQ82gBe?9I3;@mS0Zuj6fHbghkY&c#665*uC3n^GgaM6dzu0yca_Jjs`>O=i1glVbi7Jx^-o?zTHo8MSVK>5w=rs-O^?}j zXa0V3zc3Y7H;jZt_F_GOkNS3@WtCSW#s(+tFI4q|flFDmM?HM1Z0>LTf>0+$W1!+K zM@HYLo3!`t))!f5@lW|cinAej4F;DGqSs9f0<01LKl~o(>{Oe6Id+kyF#g$HS)VaGx2rYBalh99^wYCSI6indwyAc z(%d(Q6ny1e`ipwB{7ZIIMITaP1p;6}nf4JQW&w&n{Px>&s2#Jem$>>YsC8z+%oTR% zhWJJ;q9+|5ctrZ(djfg>=MBKYjtfncou**ljZvy8D1Yf{SR#kq8@>|XDA3aFDk4yEUj_gUaf|qZ$KSI% z-t~sBw>3sPmy-L~arp=Ua0mkjlR6e_?0jq^Q9oDSP!l|)ahuzfoDTbz`xqzv!_Fd| zyEPRej%I;xlnS}YtyK9Z&SQmr8-lRF{_X-Dj*WW+YXalNOrUs!M?Z=Zz~O{j*Vv-r zY`@_8*R?irxg3_!*&V#fYjv>uT<|1FB;-f;9|Nudt^egjOKBkdeowI89>BmNCN!4b zh?#K4Pt^%+(rY^?9Ke{RmQ)+`wSMk{XxMK7jgJH z4GG?c;udnF(QBD_a=|&_LP2&G^fs+NFk+d-)M#3+&)D3W<}Itp6r+sFN6(<`g4orb z5t3I;!OA&604uPd2Y{1z9td*Vzb9Y*p7sI5;O_~izemFUf&sV@E@@|h2>llrxl8c> d_c6$CFkr11JI7g&+~iKy$k5E7zwnJ{XYBI_2eIGOJjbBC=5 z?g9X}H2`or^6`Lo{`YJU1O6Njx#RQ*0EGWO`f`}uy|@nE`Gd1C(_H+U@&ZsZtl8~iZ*$-OWy;I^-K;Jy61EKdNqtaMfe|w!> z#MKiwA2P;H7~NNy$g_JI*yi(1F}Ygup)KuQd-k^ZjHb-|?MyjaWa?fjWsSGo(Dbt5 zbx8=l z7~#5Hel0bK&JBF4JjHpmV!Z!xYtYZOgq{Ps`s$OU0HBbo-E9r3dwD=LxSoWhKHiIo zQZAd`^FHx^hd(I|VW?nh`dK_2KzP4!EVzPDCE5o4;&ju4n-JTi z-TWfh2mI^`Zm2gcB;I1n2mt)e;vvAwUnwO>q83`W!%VM(A9@Ny6faxyDQB zB8R^a9fRMD%Atu(R}eP~ml;tMj%h;eWl(@-BLTBVT?{D9D{Vy@d#{!l77q(*{2{jC z1?$DJIGig2wxhN9fI{1-Le4Hf{^6*MG1(=Img_A&Y(_RuB|Cobb)0fo5@WIMZBJ3X zco~R^!aslzU@sFqu9vpjI~Z$zbE?=wgsiw;f8pA6twqGkF%yW5^07*A;7w&99{SmN z+qf>K7?;njEuWNLpYWhQGvzhn?BLUV=`zHVmCyJ`YyEX2yOV^d_F3PqWVt+sobDau zVJIkkm++VAR|7)TEy}}_cRw`wOn!C3U1UBoU%{bOTtAvr8q0~HN4SK*ksaTW+bKq) zPKojIclkEUs%jbl2FkNPu~Vdo|X(HJ7GI_*ZIL z**2Bs3jq2jj#U7)IxAz*;eR%6)L*!p8ui+;@5EcOT`C077dv_=9%&Y;H-=2O8}P4j zog*e;L9l3*7XZ}G>vPAG9mh?Z4VIJolRr=IdLCf+Cj+!Q@frZo0FtaQTC*+3zhcls zC6z)b!275@i|v#$Q$0B$j<0hR^3yBpojziiqphZn;u_4`+nd~)uZw^UJ(^8kQJ9FN z&OL^WHI3k{2R%_M7AGB(wsyob8T>~iR(Gk6ZN2vKs{!>z&2!$wYOax*9`ys1Ly&#E zmaNDVo2h<6t{gWg`&hsnZ~UrGy01p0H+gz)?jE+L;bMv@$cj+Ow7>-d%U1%-hZOFB z6y2njGjy;v=Df-?4{KPn3$z7o%@Mo7In>;E;Y;|ImK`)G_3;VUumOW%QtB)TxkgZ_D3T4@pIRBO@jTAr$Rlq$x*WJl z9GNA6ZJkoyYSAqcS&OCrUchH8h4;>_59yZd?d_2r+!2geVqaQX^NX2t=^@9B=EQ3mID-ik_X;IgUG!y{QgAVY*Qw~bYy>RH#!|zp0lVUR6(Io ze*f%F{1b`KASf#WG zrZ>>-JsVr#u?TYBkcQ6mn*P?_*0KeR7Y*IY8{?XO0C zd^#Md)K5P5@fq1uwmh@gHQH(R8)sqfO5+A(Bn~69DS*kU)fLXtrnIWOU=&kG;`D@Y=P^4S`=CI*3?1ltlxW!LRp~ADDbeb zvmhl-q|``=@dlJ#GO()l`?11^dgR(Sn*Ra{ogdBYonSk<=?za_xzWaogu6tK(j4UD zVwCMeVk{Q-E|sx0Qck>8O!;CpOjqq#c%MSO7<_ygKeNGHRAd*2e<0jXD_vpAp%$;T zviGha_Pgz`Pdy<>xOu}Vd58O0K|6}Eyyl;Z`MA#}VMRXUu;@V0JyMkieyF6aV z>vsa5BjtXAAb ziY|A*U8wFLO#j232rbKZGqQdah9kylDF3rX0{8KD-P;4r2T#iGtaJ$@fW{oj3c%XE z8uvxWyBMcCXh5S<+mxp~DJRBIsuC4;4$tWnCQbgWO<0&M) z+AA$9&`$pZ%UR5?U{dG>t<=>D$PmK&)MIiZ;PK?hALmGy-L$+t%DRZQzH}-L=4n)+ zn-tv*t7uF?-oH|=2)(gH>FMSq6>xnL-`4#{@riLnZuGeLaVw4qZcaPE$M_7%GA-Xi zVW@of6UBJ6GtLH8-IC%KTi5EdrZ;gry3YBTqdT1ERl~+5YiJVe<9(qo##9|bqoz)q zypF{<;!mLVFEF5d>)7<0QM10(DT@%tT+m4hW+Y~s8O*2%cPjTOGJkyKY7|De4bgdS z*CnB!{S?pNuG!s4GfH{P(N%V2X<5ph>n@)T4xA!d#@e|(a?oe(t75b##JhbTjhlHdi7Lh|1O%J$>C+|<~HY96tLY|FM- zAyx$^{m)y76??_bSBanRMrhrUQC?sz#J%nz62Y4PGk9&dQSzp>`ML)WkH z+ail5;aXKn{(s3g$4}+99j_1Kpxv$nxAE_I9X!r;G|lR0TIkt4sr(L%6v@79>9kr( zCb}&)lTE1!pQcFuC?AjU70yrR0wR#0jeKh_|6WBR zUCL%y4nE7?mW^>m=$sH?`69%LXySo3#l0y%S^vpY0LO4y?1=40o;!2C2hM6Oa|5Sr zBWRI-0zpSO1(9n*1Y1kpu|}5yF#1U|-!JMb7HPv_|GX{#8A>ncT;;Q>H!$br;RMD{ z7jo)9VO^P-ADXe#?Ot8R=T=TZeh3x{UqPg^idYdFyP}O}o5#fGe77|aBx;$94B)8F zAqRxZbo$VFpPb3>3Hl(yfJ5myy+nt)cNeG@ODC=BW7wNwv8RrX1k$ACRa1pP@y+Py z=nOb&U|`_O)M@u)wPv({%mV7-KUj!qlbnwEoUgzwq_D=oJuO1l`O82=!O_Ius<4qY z=EC~Aitg@W#srB}5TlC}FA_HTZBdx3cQBu(e5t&?fyZD)Bi?oRlvd``Zy6QLOK#PU zAYaxcj_jJG0)y~{Sx14IgGZrq1{2Ksk|&T(7sZkmEmpiM_@ zD9~CmEz=+YAZl-J5C{BieaMmIy%2Ptu5*Bd$Dmw;Jzz6HGcFmr#i{v z=83cl5>h+m{Vwvm0RYH>G8yf1dly3r=R!2ji8uIZYTVG!$gWE7B}#k1pT*O+6tKKk z=vQ4GBxSGh0s0`V75&-}s;AOnr9UWJUovDeeyXKZNYo<=pnLGH?Z~ke#_iG56(Zli zZh{>-ki|uP9JJAQ76W7V3W#~nx$H4~_TAykRr4OAd;vvfOPV&VJn%j=I2f1+KT?xb z@t5J~XpDq83ggaXPQNt>!w^rq)kPWALO4f)+Qjm2Lz7q+b0c#NM@A14IOB!>0F`5Q zaKMb)u?eXC5zYAZE8u-g_5av}L;B%r0m4ZV#WwnY`SAl2uj1-Nh5o?HpVe4$SGwU6fIQ%kBBOe|c$NZMXrd0%6 zXORmbo*W+K6`;h99i7u$a!lsio4sIo!F17Z(T*gmvTjDwA!QB^;c>Z=p6e*Si` zjST%*b){~*g&t|?vN_7Wl=h~7k7Yx`ctCNMjtPP>!qi10wPJ`+JnASs`P+37tduGRJ>uIra&>y|Ly^fOQ^PS6 zlvvN_zTlu-JWD8crJHC(>y~E)qf1~_~%_y_USBU1x+6*VMlEOWQ~Se)|7Z$&`B;2LMcg;m!Z3jSQmlgWmp8~OhBhCd zZ4eLXvTVHzpF#>R9^ZUoo>MTba0{_rMP2#PDj_LZCb*%H+5RNRMiQA+J~v%ECTF;deM8?~!a1mdckJZ;e&~oe4R+u%7{U>Ltg)!?`m`|ufO8tc~X<%2x{F# zp&IO;lz+#zyz?kWPRaq|A9E|v@Rj6ADSQ~J1pX?hx6QKgZ#8pfw+8BYan2uHrN9Jt zJ7||z54?6SvAKWYo>B>iRjF~C1j&!V2k%?6QX_YWUtxIE zmK{ZhedmL=K^679q;eGF2Fmyxg&b@v8PhpFBT?&hmoF^WQujsFM&nMRV^MgUm%^&e zIA~?lS0tRh4}2Z}vJ z1@1+unBcRwb&fY$LJ+i*{LZ%-zFBdX{kbbXnBvk7s-O(2%9yzTd${g}=kNZB_Ua(a zO6-`TyO`aInz|iaYB3gP!Snlu<(tqSYPWde;Sa(3LVMwt1GzRWzx?`_>76%|T;Zb| z3^wwRF-Yqrns(F>5xRVhHYm6J87t2`QDa2na-Y^IM@;LBPLrQasjagiV!;L>*(4vo zFp03w0jW}evjxc8q2qhy^ZXwz9Ry1Yub3j|yR(+}+n4h3Zyu~l8j zIIZV;Y$*|c+nmX=$t?C9;dWga3vJyrR5ZPi<`^rV(((>ABZ(VF_bfdjX~6J)U$lrn zd0kH_qm|-9@J%l~wZ)A$@yTG;wR|FnhY%Qoe?1$EJ~5Vwu{m7ad2qI5NuOaH*Q}oMxH#skn8@2$jMUeK zVn@%*ufNm@+Y9cng0@5PYcVA1)?R5|y zAG!yh%?0&?hBWxf1{4Yc&XpoSEmxm=mRD7s-eJA;(BYm&?C-eQKIH>uE|{rtsQ1q%^M#^#L=6mB(L?v{6orzn~>*W%j&678y7bcm-V58SzI}hP5u=3 zw<%DeWz%cT7T#FiArVd6285OawPR1f_|;gV_{-8Y%@R&4%??@l_nikB@5ckScw__hxAH;|=a8V?+7^Q4Y#}twQ;4=VPSL?gfYt^^D3gt&m zj6gN@*@HF8GIKOlEYlL^FgYU zPYbFK>%(2s*H}xm$1RnHO{tGrT}tHNuhJjcS(4UZ7jNCLr0l}Qgzye>5y7n;uDIl8 z5k>=o1S-xzEu(2e&(YxU9EinpGe*S-hS8OR@ZzmaKVSQ9;u+@&ZLamZ^WFV)IS@MZz9TE;cwx&?$TE! z+LXGqfe7=?o=z6MKzra}U+rc=!M1a^w_uG!_ZC*2rZY1gRtYT|3xy4Pm)twU%@=%x zi?%&km%4gqvl_GjkL!~|JYAL=dr-~g%nY>jWAk0Oj@C}%YLjH}GdTqmxBBiDSb&KI z-~D7?0)29V(JqfCB0rI>e}B;m7ODQA*j@=1n$%rwe3&Ssah;%a)gf}}`rjMmrTE5W zIb3yQtI!pGO)JWcUJ0Q#2l9Y~5f{{P3i&wh@VzvwEqFL|X(9R#`kxN?E%h?I6Cadg zLhUF<_3aF7NS_p(y7uWOZ~I>9jkE2tl35ozk8C= zMX&+_5zPtMn;bbW>!g-wyMpQ}R-JskN(CcuWZ>m$T5lf8-31;JL55qu6J zg?e<1fx*sI(t@w+fVr^>gAfhGqcH1 zz{1K?>*Zx$ecn8+nO5}s=+i{(SfKU`D*fs+MLX9T7mIvnBf;`?vgHkU zZAc0~wN~j}xJ_E4n0@A}`Z2*oAFB@jN6qZXvg9p^&+p=b3~CjzdO)Et_~v6m6HGka z)}k}8`-UTdU@g7T1olVc_PG95cfU3wpOO&S&#tnfTRc=e8P>IL`k9G3zMYu8twzW1 z6X>K5H#|irqGthM_Ak)a$v`joNt&zjHGXN{$3)2Lc-gw<498x(Gl-;^WeiXpxQW;K zE#&Vy;^B-MmdW8UYrr-eAUCd9D2hla2jmM!@$higMtDx`!c;$f+vjeY3Xvm zn@<1D9!wdGa{tQNkteDW}H5l!5vnNL_31c2pdVAr*I{+EMSr-LQh z=2RkF-SQptYB%@}=G!$en7I7KU709YvNT(f=z-$1igZzp7jFz#8vTN^(y?j ziD{hEGm>g$m_5}vu(7hE5G&(WsSY;f#}dHjqNmFm4Sm3WKU67#GT=&RZ?x{jxy1de zJ7eXq+-y0U9_MyDMpCM8=cm-x5ErtbSUHwJn`O)|9{V6T&S? zVxmbgbZ3V{_N6zYxtA{;Dwdafo$Jg$RxDLQu(cMIDkFCOV>Vg>qVeD7KLq|m;6DWZ ee?*{lC77d64RE`y@zm((d?rSgx2g?2p8g+ax|#_9 diff --git a/README.md b/README.md index 2c5f74f..bfb3a81 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
- Duck Organization Banner + Duck Organization Banner --- From 55b3fc269bb0e0b51003f2e4344fa7852127e391 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Tue, 19 May 2026 18:31:10 +0200 Subject: [PATCH 42/50] feat: image logging --- apps/bot/src/listeners/messageDelete.ts | 12 ++++++++---- apps/bot/src/listeners/messageUpdate.ts | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/bot/src/listeners/messageDelete.ts b/apps/bot/src/listeners/messageDelete.ts index 5df9e89..608650a 100644 --- a/apps/bot/src/listeners/messageDelete.ts +++ b/apps/bot/src/listeners/messageDelete.ts @@ -13,16 +13,20 @@ export class MessageDeleteListener extends Listener if (!guild) return; if (await isLoggingChannel(guild, message.channel?.id)) return; + const content = message instanceof Object ? (message as Message).content : undefined; + const imageUrls = [...message.attachments.values()] + .filter((attachment) => attachment.contentType?.startsWith('image/')) + .map((attachment) => attachment.url); + const contentParts = [content, ...imageUrls].filter(Boolean) as string[]; + const contentValue = truncate(contentParts.join('\n'), 1024) || '-'; + const embed = new EmbedBuilder() .setTitle('Message Deleted') .setColor(0xff6962) .addFields( { name: 'Channel', value: message.channel?.toString() ?? 'Unknown', inline: true }, { name: 'Author', value: message.author?.tag ?? 'Unknown', inline: true }, - { - name: 'Content', - value: truncate(message instanceof Object ? (message as Message).content : undefined, 1024) || '-', - }, + { name: 'Content', value: contentValue }, ) .setFooter({ text: `ID: ${message.id}` }) .setTimestamp(); diff --git a/apps/bot/src/listeners/messageUpdate.ts b/apps/bot/src/listeners/messageUpdate.ts index d2658e7..ab60dec 100644 --- a/apps/bot/src/listeners/messageUpdate.ts +++ b/apps/bot/src/listeners/messageUpdate.ts @@ -19,14 +19,27 @@ export class MessageUpdateListener extends Listener { if (oldContent === newContent) return; + const oldImageUrls = [...(oldMsg?.attachments.values() ?? [])] + .filter((attachment) => attachment.contentType?.startsWith('image/')) + .map((attachment) => attachment.url); + const newImageUrls = [...newMsg.attachments.values()] + .filter((attachment) => attachment.contentType?.startsWith('image/')) + .map((attachment) => attachment.url); + + const beforeParts = [oldMsg?.content, ...oldImageUrls].filter(Boolean) as string[]; + const afterParts = [newMsg.content, ...newImageUrls].filter(Boolean) as string[]; + + const beforeValue = truncate(beforeParts.join('\n'), 1024) || '-'; + const afterValue = truncate(afterParts.join('\n'), 1024) || '-'; + const embed = new EmbedBuilder() .setTitle('Message Edited') .setColor(0xfac898) .addFields( { name: 'Channel', value: newMsg.channel?.toString() ?? 'Unknown', inline: true }, { name: 'Author', value: newMsg.author?.tag ?? oldMsg?.author?.tag ?? 'Unknown', inline: true }, - { name: 'Before', value: truncate(oldMsg?.content, 1023) || '-' }, - { name: 'After', value: truncate(newMsg.content, 1023) || '-' }, + { name: 'Before', value: beforeValue }, + { name: 'After', value: afterValue }, ) .setFooter({ text: `ID: ${newMsg.id}` }) .setTimestamp(); From e7a2438b9b34c2447d77c23e0c010a6094c36051 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Wed, 20 May 2026 14:49:24 +0200 Subject: [PATCH 43/50] style(contributing): commit message update --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1935a3..a37b6d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ When committing code you take *full* responsibility for what you are committing. Please submit pull requests to the `dev` branch, unless this is a feature which requires a separate branch. Make sure to test the code you have made before creating a pull request. -Format for commit messages, fix|upd|chore|dockerfile: (change made). +Use conventional commit messages for all commits. > [!NOTE] > When contributing to this project you agree that you have all rights to the content you have contributed and that these align with the projects license. From 129a617a56a48d86d45e19712c6026e26e2ead74 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Wed, 20 May 2026 21:07:03 +0200 Subject: [PATCH 44/50] fix: small bugs + style --- CONTRIBUTING.md | 4 ++-- apps/bot/prisma.config.ts | 3 ++- apps/bot/src/commands/utility/reminder/reminder.ts | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a37b6d7..a88986e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Quest Bot -Contributing to Quest Bot requires basic knowledge of TypeScript, Discord.JS and prisma. +Contributing to Quest Bot requires basic knowledge of TypeScript, Discord.JS and Prisma. ## AI Rules @@ -15,6 +15,6 @@ Make sure to test the code you have made before creating a pull request. Use conventional commit messages for all commits. > [!NOTE] -> When contributing to this project you agree that you have all rights to the content you have contributed and that these align with the projects license. +> When contributing to this project you agree that you have all rights to the content you have contributed and that these align with the project's license. ## Thanks for your interest! ❤️ diff --git a/apps/bot/prisma.config.ts b/apps/bot/prisma.config.ts index 82530a4..cdf363d 100644 --- a/apps/bot/prisma.config.ts +++ b/apps/bot/prisma.config.ts @@ -1,3 +1,4 @@ +/// import { defineConfig } from 'prisma/config'; export default defineConfig({ @@ -6,6 +7,6 @@ export default defineConfig({ path: 'prisma/migrations', }, datasource: { - url: process.env['DATABASE_URL'], + url: process.env['DATABASE_URL'] ?? '', }, }); diff --git a/apps/bot/src/commands/utility/reminder/reminder.ts b/apps/bot/src/commands/utility/reminder/reminder.ts index fb5e978..315e693 100644 --- a/apps/bot/src/commands/utility/reminder/reminder.ts +++ b/apps/bot/src/commands/utility/reminder/reminder.ts @@ -1,5 +1,5 @@ import { Command } from '@sapphire/framework'; -import { MessageFlags } from 'discord.js'; +import { MessageFlags, SlashCommandBuilder } from 'discord.js'; import ms, { type StringValue } from 'ms'; import { createReminder, getReminder, removeReminder } from '#lib/reminders.js'; import { LimitError } from '#lib/limits.js'; @@ -11,7 +11,7 @@ export class ReminderCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder: any) => + registry.registerChatInputCommand((builder: SlashCommandBuilder) => builder .setName('reminder') .setDescription('Set reminders!') @@ -75,7 +75,7 @@ export class ReminderCommand extends Command { const unix = Math.floor(remindAt.getTime() / 1000); await interaction.reply({ - content: `${emojis.rightArrow2} Reminder set to go off in message: ${message}\nID: \`${reminder.id}\``, + content: `${emojis.rightArrow2} Reminder set to go off in . Message: ${message}\nID: \`${reminder.id}\``, allowedMentions: { parse: [] }, }); @@ -111,7 +111,7 @@ export class ReminderCommand extends Command { if (reminder.userId !== interaction.user.id) { await interaction.reply({ - content: `${emojis.rightArrow2} You can't remove other's reminders.`, + content: `${emojis.rightArrow2} You can't remove others' reminders.`, flags: MessageFlags.Ephemeral, }); return; From 3770ac8b8eb5dcfb007135d3a1e66f42b0e79a79 Mon Sep 17 00:00:00 2001 From: UnbraveChimp Date: Wed, 20 May 2026 21:23:39 +0200 Subject: [PATCH 45/50] feat: security.md Signed-off-by: UnbraveChimp --- SECURITY.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..12de714 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| --------- | ------------------ | +| 1.1.5 < | :white_check_mark: | +| < 1.1.5 | :x: | + +## Unsupported types of vulnerabilities + +| Type | Supported | +| ------------- | ------------------ | +| Rate limits | :x: | +| Limits | :x: | +| DDOS/DOS | :x: | + +If it is *critical* please submit it. + +## Reporting a Vulnerability + +Please report vulnerabilties through Github Advisories. + +Don't be afraid to report a vulnerability! If we have to close it there are no consequences! + +If a vulnerability is of high severity it will be looked into reasonably fast. +Vulnerabilties get accepted and denied all the time, if your vulnerability is denied +and you believe it was denied falsely than you can either reopen it or create a new one +if it is of high priority. From 8f2748aba28b4f6cb0bc45a90b099c24d578071e Mon Sep 17 00:00:00 2001 From: UnbraveChimp Date: Wed, 20 May 2026 21:27:06 +0200 Subject: [PATCH 46/50] style: funding Signed-off-by: UnbraveChimp --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index f3d79b9..b1a62b4 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: duck-organization, UnbraveChimp +github: duck-organization patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username From a4efc275af9c54fd76070b8f8484ef7357cd925c Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Thu, 21 May 2026 15:30:53 +0200 Subject: [PATCH 47/50] fix(warns): reply ephemeral --- apps/bot/src/commands/moderation/warn/warns.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bot/src/commands/moderation/warn/warns.ts b/apps/bot/src/commands/moderation/warn/warns.ts index b8ee9d3..e5fbd24 100644 --- a/apps/bot/src/commands/moderation/warn/warns.ts +++ b/apps/bot/src/commands/moderation/warn/warns.ts @@ -57,6 +57,6 @@ export class WarnsCommand extends Command { const content = `${emojis.rightArrow1} ${active.length} active warn(s) for <@${targetMember.user.id}>:\n${lines.join('\n')}`; - await interaction.reply({ content }); + await interaction.reply({ content, flags: MessageFlags.Ephemeral }); } } From 699eade86bb4b9ed6bf78ba70681192a4d284451 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Thu, 21 May 2026 15:42:50 +0200 Subject: [PATCH 48/50] fix: pages for automod and autorole --- apps/bot/src/commands/moderation/automod.ts | 63 ++++++++++++++- .../commands/moderation/autorole/autorole.ts | 76 ++++++++++++++++--- 2 files changed, 124 insertions(+), 15 deletions(-) diff --git a/apps/bot/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts index d4aae31..cb04600 100644 --- a/apps/bot/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -1,8 +1,9 @@ import { Command } from '@sapphire/framework'; -import { MessageFlags, PermissionsBitField } from 'discord.js'; +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags, PermissionsBitField } from 'discord.js'; import { createAutoMod, DuplicateAutoModError, getAutoMod, getAutoMods, removeAutoMod } from '#lib/automod.js'; import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js'; import { emojis } from '#utils/emoji.js'; +import { awaitMessageComponentSafe } from '#utils/collectors.js'; export class AutoModCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { @@ -142,11 +143,65 @@ export class AutoModCommand extends Command { return; } - const wordList = autoMods.map((autoMod) => `${emojis.rightArrow1} ${autoMod.word}`).join('\n'); - await interaction.reply({ - content: `**Blocked Words:**\n${wordList}`, + const totalPages = Math.ceil(autoMods.length / 10); + let page = 0; + + const buildContent = (page: number) => { + const slice = autoMods.slice(page * 10, (page + 1) * 10); + const wordList = slice.map((autoMod) => `${emojis.rightArrow1} ${autoMod.word}`).join('\n'); + return `**Blocked Words** (Page ${page + 1}/${totalPages}):\n${wordList}`; + }; + + const buildRow = (page: number) => + new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId('prev') + .setLabel('<') + .setStyle(ButtonStyle.Primary) + .setDisabled(page === 0), + new ButtonBuilder() + .setCustomId('next') + .setLabel('>') + .setStyle(ButtonStyle.Primary) + .setDisabled(page >= totalPages - 1), + ); + + if (totalPages === 1) { + await interaction.reply({ + content: buildContent(0), + flags: MessageFlags.Ephemeral, + }); + return; + } + + const response = await interaction.reply({ + content: buildContent(page), + components: [buildRow(page)], flags: MessageFlags.Ephemeral, + withResponse: true, }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + while (true) { + const btn = await awaitMessageComponentSafe(response.resource!.message!, { + filter: collectorFilter, + time: 60_000, + }); + + if (!btn) { + await interaction.editReply({ components: [] }); + break; + } + + if (btn.customId === 'prev') page = Math.max(0, page - 1); + if (btn.customId === 'next') page = Math.min(totalPages - 1, page + 1); + + await btn.update({ + content: buildContent(page), + components: [buildRow(page)], + }); + } } if (subcommand === 'remove') { diff --git a/apps/bot/src/commands/moderation/autorole/autorole.ts b/apps/bot/src/commands/moderation/autorole/autorole.ts index b3caa9f..cd6c733 100644 --- a/apps/bot/src/commands/moderation/autorole/autorole.ts +++ b/apps/bot/src/commands/moderation/autorole/autorole.ts @@ -1,8 +1,9 @@ import { Command } from '@sapphire/framework'; -import { MessageFlags, PermissionFlagsBits } from 'discord.js'; +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags, PermissionFlagsBits } from 'discord.js'; import { createAutoRole, getAutoRole, getAutoRoles, removeAutoRole } from '#lib/autorole.js'; import { getQuestUnlimitedPurchaseComponents, LimitError } from '#lib/limits.js'; import { emojis } from '#utils/emoji.js'; +import { awaitMessageComponentSafe } from '#utils/collectors.js'; export class AutoRoleCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { @@ -162,19 +163,72 @@ export class AutoRoleCommand extends Command { return; } - const autoRoleList = autoRoles - .map((autoRole) => { - const role = interaction.guild?.roles.cache.get(autoRole.roleId); - const roleName = role ? `<@&${role.id}>` : `Unknown Role (${autoRole.roleId})`; - const botRoleText = autoRole.botRole ? ' (Bot Role)' : ''; - return `${emojis.rightArrow1} ${roleName}${botRoleText}`; - }) - .join('\n'); + const totalPages = Math.ceil(autoRoles.length / 10); + let page = 0; + + const buildContent = (page: number) => { + const slice = autoRoles.slice(page * 10, (page + 1) * 10); + const roleList = slice + .map((autoRole) => { + const role = interaction.guild?.roles.cache.get(autoRole.roleId); + const roleName = role ? `<@&${role.id}>` : `Unknown Role (${autoRole.roleId})`; + const botRoleText = autoRole.botRole ? ' (Bot Role)' : ''; + return `${emojis.rightArrow1} ${roleName}${botRoleText}`; + }) + .join('\n'); + return `**Auto Roles** (Page ${page + 1}/${totalPages}):\n${roleList}`; + }; + + const buildRow = (page: number) => + new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId('prev') + .setLabel('<') + .setStyle(ButtonStyle.Primary) + .setDisabled(page === 0), + new ButtonBuilder() + .setCustomId('next') + .setLabel('>') + .setStyle(ButtonStyle.Primary) + .setDisabled(page >= totalPages - 1), + ); - await interaction.reply({ - content: `**Auto Roles:**\n${autoRoleList}`, + if (totalPages === 1) { + await interaction.reply({ + content: buildContent(0), + flags: MessageFlags.Ephemeral, + }); + return; + } + + const response = await interaction.reply({ + content: buildContent(page), + components: [buildRow(page)], flags: MessageFlags.Ephemeral, + withResponse: true, }); + + const collectorFilter = (i: { user: { id: string } }) => i.user.id === interaction.user.id; + + while (true) { + const btn = await awaitMessageComponentSafe(response.resource!.message!, { + filter: collectorFilter, + time: 60_000, + }); + + if (!btn) { + await interaction.editReply({ components: [] }); + break; + } + + if (btn.customId === 'prev') page = Math.max(0, page - 1); + if (btn.customId === 'next') page = Math.min(totalPages - 1, page + 1); + + await btn.update({ + content: buildContent(page), + components: [buildRow(page)], + }); + } } } } From efa2a7d734f1479b80636c6b66c27477aa23cc79 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Thu, 21 May 2026 20:34:14 +0200 Subject: [PATCH 49/50] fix: togif --- SECURITY.md | 7 ++- apps/bot/package.json | 3 +- apps/bot/src/commands/utility/fun/toGif.ts | 35 ++++--------- apps/bot/src/lib/safeFetch.ts | 58 ++++++++++++++++++++++ package.json | 2 +- pnpm-lock.yaml | 29 +++++++---- 6 files changed, 91 insertions(+), 43 deletions(-) create mode 100644 apps/bot/src/lib/safeFetch.ts diff --git a/SECURITY.md b/SECURITY.md index 12de714..cd70be7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,10 +2,9 @@ ## Supported Versions -| Version | Supported | -| --------- | ------------------ | -| 1.1.5 < | :white_check_mark: | -| < 1.1.5 | :x: | +| Version | Supported | +| ------------ | ------------------ | +| Latest Tag | :white_check_mark: | ## Unsupported types of vulnerabilities diff --git a/apps/bot/package.json b/apps/bot/package.json index 3f32214..32b9976 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -40,15 +40,16 @@ "@sapphire/framework": "^5.5.0", "@types/ms": "^2.1.0", "discord.js": "^14.26.4", + "ipaddr.js": "^2.4.0", "ms": "^2.1.3", "prisma": "^7.8.0", "sharp": "^0.34.5", + "undici": "^8.3.0", "zod": "^4.4.3" }, "devDependencies": { "@sapphire/ts-config": "^5.0.3", "@types/node": "^25.8.0", - "@types/sharp": "^0.32.0", "concurrently": "^9.2.1", "prettier": "^3.8.3", "rimraf": "^6.1.3", diff --git a/apps/bot/src/commands/utility/fun/toGif.ts b/apps/bot/src/commands/utility/fun/toGif.ts index 69446cb..ae53fc2 100644 --- a/apps/bot/src/commands/utility/fun/toGif.ts +++ b/apps/bot/src/commands/utility/fun/toGif.ts @@ -1,20 +1,12 @@ import { Command } from '@sapphire/framework'; -import { AttachmentBuilder, MessageFlags } from 'discord.js'; +import { AttachmentBuilder } from 'discord.js'; import sharp from 'sharp'; import { emojis } from '#utils/emoji.js'; +import { safeFetch, SafeFetchError } from '#lib/safeFetch.js'; const ALLOWED_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp']); const MAX_SIZE = 20 * 1024 * 1024; -function isSafeUrl(raw: string): boolean { - let url: URL; - try { url = new URL(raw); } catch { return false; } - if (url.protocol !== 'https:') return false; - const host = url.hostname; - if (/^(localhost|127\.|0\.0\.0\.0|::1|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|169\.254\.)/.test(host)) return false; - return true; -} - export class ToGifCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, preconditions: ['devMode'] }); @@ -34,23 +26,14 @@ export class ToGifCommand extends Command { public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { const url = interaction.options.getString('url', true); - if (!isSafeUrl(url)) { - await interaction.reply({ content: `${emojis.rightArrow1} URL not valid, HTTPS required.`, flags: MessageFlags.Ephemeral }); - return; - } - await interaction.deferReply(); - let response: Response; + let response; try { - response = await fetch(url); - } catch { - await interaction.editReply(`${emojis.rightArrow1} Failed to fetch the URL.`); - return; - } - - if (!isSafeUrl(response.url)) { - await interaction.editReply(`${emojis.rightArrow1} Redirected to a blocked URL.`); + response = await safeFetch(url); + } catch (err) { + const msg = err instanceof SafeFetchError ? err.message : 'Failed to fetch the URL.'; + await interaction.editReply(`${emojis.rightArrow1} ${msg}`); return; } @@ -80,7 +63,7 @@ export class ToGifCommand extends Command { let gifBuffer: Buffer; try { - gifBuffer = await sharp(inputBuffer).gif().toBuffer(); + gifBuffer = await sharp(inputBuffer, { failOn: 'error' }).gif().toBuffer(); } catch { await interaction.editReply(`${emojis.rightArrow1} Failed to convert the image to GIF.`); return; @@ -89,4 +72,4 @@ export class ToGifCommand extends Command { const attachment = new AttachmentBuilder(gifBuffer, { name: 'toGif.gif' }); await interaction.editReply({ files: [attachment] }); } -} +} \ No newline at end of file diff --git a/apps/bot/src/lib/safeFetch.ts b/apps/bot/src/lib/safeFetch.ts new file mode 100644 index 0000000..bebe053 --- /dev/null +++ b/apps/bot/src/lib/safeFetch.ts @@ -0,0 +1,58 @@ +import { lookup } from 'node:dns/promises'; +import { Agent, fetch as undiciFetch, type RequestInit, type Response } from 'undici'; +import ipaddr from 'ipaddr.js'; + +const MAX_REDIRECTS = 3; +const TIMEOUT_MS = 10_000; + +export class SafeFetchError extends Error {} + +async function resolveSafe(hostname: string): Promise<{ address: string; family: 4 | 6 }> { + const records = ipaddr.isValid(hostname) + ? [{ address: hostname, family: (ipaddr.parse(hostname).kind() === 'ipv4' ? 4 : 6) as 4 | 6 }] + : (await lookup(hostname, { all: true })).map(r => ({ address: r.address, family: r.family as 4 | 6 })); + + for (const { address } of records) { + if (ipaddr.parse(address).range() !== 'unicast') { + throw new SafeFetchError(`Blocked address range for ${hostname}`); + } + } + return records[0]; +} + +function validate(url: URL) { + if (url.protocol !== 'https:') throw new SafeFetchError('HTTPS required.'); + if (url.port && url.port !== '443') throw new SafeFetchError('Port 443 only.'); +} + +export async function safeFetch(raw: string, init: RequestInit = {}): Promise { + let url: URL; + try { url = new URL(raw); } catch { throw new SafeFetchError('Invalid URL.'); } + + for (let i = 0; i <= MAX_REDIRECTS; i++) { + validate(url); + const { address, family } = await resolveSafe(url.hostname); + + const dispatcher = new Agent({ + connect: { lookup: (_h, _o, cb) => cb(null, address, family) }, + headersTimeout: TIMEOUT_MS, + bodyTimeout: TIMEOUT_MS + }); + + const res = await undiciFetch(url, { + ...init, + redirect: 'manual', + signal: AbortSignal.timeout(TIMEOUT_MS), + dispatcher + }).catch(() => { throw new SafeFetchError('Request failed.'); }); + + if (res.status >= 300 && res.status < 400) { + const loc = res.headers.get('location'); + if (!loc) return res; + url = new URL(loc, url); + continue; + } + return res; + } + throw new SafeFetchError('Too many redirects.'); +} \ No newline at end of file diff --git a/package.json b/package.json index 13f1343..8156e2e 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "quest-bot-workspace", "version": "0.1.0", "private": true, - "packageManager": "pnpm@11.1.3+sha512.c85357fe17ca12dd23dd7071822666dfd7e3cb76fe214e3370b5ea2fb34f2a231185509b63e717f3cd0acb38dd3f8d82bcd5e8172400ae678b70ea4fbed0896d", + "packageManager": "pnpm@11.2.2+sha512.36e6621fad506178936455e70247b8808ef4ec25797a9f437a93281a020484e2607f6a469a22e982987c3dbb8866e3071514ab10a4a1749e06edcd1ec118436f", "scripts": { "build": "turbo run build", "dev": "turbo run dev", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a44195a..9b80237 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,9 @@ importers: discord.js: specifier: ^14.26.4 version: 14.26.4 + ipaddr.js: + specifier: ^2.4.0 + version: 2.4.0 ms: specifier: ^2.1.3 version: 2.1.3 @@ -45,6 +48,9 @@ importers: sharp: specifier: ^0.34.5 version: 0.34.5 + undici: + specifier: ^8.3.0 + version: 8.3.0 zod: specifier: ^4.4.3 version: 4.4.3 @@ -55,9 +61,6 @@ importers: '@types/node': specifier: ^25.8.0 version: 25.8.0 - '@types/sharp': - specifier: ^0.32.0 - version: 0.32.0 concurrently: specifier: ^9.2.1 version: 9.2.1 @@ -534,10 +537,6 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@types/sharp@0.32.0': - resolution: {integrity: sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==} - deprecated: This is a stub types definition. sharp provides its own type definitions, so you do not need this installed. - '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -723,6 +722,10 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} + ipaddr.js@2.4.0: + resolution: {integrity: sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==} + engines: {node: '>= 10'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -1018,6 +1021,10 @@ packages: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} + undici@8.3.0: + resolution: {integrity: sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==} + engines: {node: '>=22.19.0'} + valibot@1.2.0: resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} peerDependencies: @@ -1530,10 +1537,6 @@ snapshots: dependencies: csstype: 3.2.3 - '@types/sharp@0.32.0': - dependencies: - sharp: 0.34.5 - '@types/ws@8.18.1': dependencies: '@types/node': 25.8.0 @@ -1715,6 +1718,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ipaddr.js@2.4.0: {} + is-fullwidth-code-point@3.0.0: {} is-property@1.0.2: {} @@ -1987,6 +1992,8 @@ snapshots: undici@6.24.1: {} + undici@8.3.0: {} + valibot@1.2.0(typescript@6.0.3): optionalDependencies: typescript: 6.0.3 From c3ada7c417a050f1250b54c48405e58c711cc125 Mon Sep 17 00:00:00 2001 From: unbravechimp Date: Thu, 21 May 2026 21:11:29 +0200 Subject: [PATCH 50/50] fix: togif safefetch --- apps/bot/package.json | 2 +- apps/bot/src/lib/safeFetch.ts | 27 +++++++++++---------------- pnpm-lock.yaml | 9 --------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/apps/bot/package.json b/apps/bot/package.json index 32b9976..86c17fd 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -44,7 +44,7 @@ "ms": "^2.1.3", "prisma": "^7.8.0", "sharp": "^0.34.5", - "undici": "^8.3.0", + "zod": "^4.4.3" }, "devDependencies": { diff --git a/apps/bot/src/lib/safeFetch.ts b/apps/bot/src/lib/safeFetch.ts index bebe053..a363b86 100644 --- a/apps/bot/src/lib/safeFetch.ts +++ b/apps/bot/src/lib/safeFetch.ts @@ -1,5 +1,4 @@ import { lookup } from 'node:dns/promises'; -import { Agent, fetch as undiciFetch, type RequestInit, type Response } from 'undici'; import ipaddr from 'ipaddr.js'; const MAX_REDIRECTS = 3; @@ -7,17 +6,20 @@ const TIMEOUT_MS = 10_000; export class SafeFetchError extends Error {} -async function resolveSafe(hostname: string): Promise<{ address: string; family: 4 | 6 }> { +async function assertSafeHost(hostname: string): Promise { const records = ipaddr.isValid(hostname) - ? [{ address: hostname, family: (ipaddr.parse(hostname).kind() === 'ipv4' ? 4 : 6) as 4 | 6 }] - : (await lookup(hostname, { all: true })).map(r => ({ address: r.address, family: r.family as 4 | 6 })); + ? [{ address: hostname }] + : await lookup(hostname, { all: true }); + + if (records.length === 0) { + throw new SafeFetchError(`No DNS records for ${hostname}`); + } for (const { address } of records) { if (ipaddr.parse(address).range() !== 'unicast') { throw new SafeFetchError(`Blocked address range for ${hostname}`); } } - return records[0]; } function validate(url: URL) { @@ -31,20 +33,13 @@ export async function safeFetch(raw: string, init: RequestInit = {}): Promise cb(null, address, family) }, - headersTimeout: TIMEOUT_MS, - bodyTimeout: TIMEOUT_MS - }); + await assertSafeHost(url.hostname); - const res = await undiciFetch(url, { + const res = await fetch(url, { ...init, redirect: 'manual', - signal: AbortSignal.timeout(TIMEOUT_MS), - dispatcher - }).catch(() => { throw new SafeFetchError('Request failed.'); }); + signal: AbortSignal.timeout(TIMEOUT_MS) + }).catch(() => {throw new SafeFetchError('Request failed.');}); if (res.status >= 300 && res.status < 400) { const loc = res.headers.get('location'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b80237..bf582b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,9 +48,6 @@ importers: sharp: specifier: ^0.34.5 version: 0.34.5 - undici: - specifier: ^8.3.0 - version: 8.3.0 zod: specifier: ^4.4.3 version: 4.4.3 @@ -1021,10 +1018,6 @@ packages: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} - undici@8.3.0: - resolution: {integrity: sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==} - engines: {node: '>=22.19.0'} - valibot@1.2.0: resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} peerDependencies: @@ -1992,8 +1985,6 @@ snapshots: undici@6.24.1: {} - undici@8.3.0: {} - valibot@1.2.0(typescript@6.0.3): optionalDependencies: typescript: 6.0.3